Go

Compare math/rand, math/rand/v2 and crypto/rand. What changed about seeding in Go 1.20 and 1.22, and when must you use crypto/rand?

Question 535MediumGo 1.22 to 1.25

math/rand and math/rand/v2 are fast pseudo-random generators whose output can be predicted. crypto/rand reads from the OS CSPRNG (getrandom, BCryptGenRandom and so on).

  • Go 1.20: the global math/rand source is seeded randomly at startup, so programs no longer produce the same sequence on every run by default. rand.Seed is deprecated.
  • Go 1.22: adds math/rand/v2. It has no global Seed at all, names like IntN and Uint64, a generic rand.N, and the better PCG and ChaCha8 sources. The global generator is ChaCha8-based and safe for concurrent use.
  • Go 1.24: the top-level math/rand.Seed becomes a no-op unless GODEBUG=randseednop=0. For reproducible sequences, create your own generator with rand.New(src).
import (
	crand "crypto/rand"
	"math/rand/v2"
	"time"
)

n := rand.IntN(100)                 // [0,100)
jitter := rand.N(500 * time.Millisecond) // generic over integer types, incl. Duration
r := rand.New(rand.NewPCG(1, 2))    // deterministic stream for tests/simulations
_ = r.IntN(10)

token := crand.Text()               // Go 1.24: 26-char base32 secure string
key := make([]byte, 32)
crand.Read(key)                     // Go 1.24+: never returns an error (crashes on failure)

When you must use crypto/rand: session IDs, API tokens, password-reset links, keys, nonces, salts, and anything an attacker gains from guessing. math/rand is for jitter, shuffling, sampling and simulations. crypto/rand.Int gives you an unbiased big integer in a range.

More on More Standard Library Essentials

All 16 More Standard Library Essentials questions