go get lukechampine.com/frand
frand
is a fast CSPRNG in userspace, implemented as a lightweight wrapper
around the (math/rand/v2).ChaCha8
generator. The initial
cipher key is derived from the kernel CSPRNG, after which no new entropy is
ever mixed in.
The primary advantage of frand
over crypto/rand
is speed: when generating
large amounts of random data, frand
is 20x faster than crypto/rand
, and over
100x faster when generating data in parallel. frand
is also far more
convenient to use than crypto/rand
, as its methods cannot return errors, and
helper methods such as Intn
and Perm
are provided. In short, it is as fast
and convenient as math/rand
, but far more secure.
frand
was previously implemented as a FKE-CSPRNG.
Since the addition of ChaCha8
in Go 1.23, this is no longer necessary, as the
stdlib generator is equally fast and secure. If you're curious about the old
implementation, you can read about it here.
Calls to global functions like Read
and Intn
are serviced by a sync.Pool
of generators derived from the master generator. This allows frand
to scale
near-linearly across CPU cores, which is what makes it so much faster than
crypto/rand
and math/rand
in parallel benchmarks.
This is a slightly hot take, but I do not believe there is a meaningful
difference in security between using crypto/rand
and a crypto/rand
-seeded
ChaCha8 generator. There are caveats, of course: for example, since the
generator is in userspace, it is somewhat easier to access its internal state
and predict future. But if an attacker can access the internal state of your
program, surely you have bigger fish to fry. If crypto/rand
makes you feel
safer, great, use it. But I don't think it's actually any more secure.
Even if you aren't comfortable using frand
for critical secrets, you should
still use it everywhere you would normally use an insecure PRNG like
math/rand
. Go programmers frequently use math/rand
because it is faster and
more convenient than crypto/rand
, and only use crypto/rand
when "true"
randomness is required. This is an unfortunate state of affairs, because misuse
of math/rand
can lead to bugs or vulnerabilities. For example, using
math/rand
to generate "random" test cases will produce identical coverage from
run-to-run if the generator is left unseeded. More seriously, using math/rand
to salt a hash table may make your program vulnerable to denial of service attacks.
Substituting frand
for math/rand
would avoid both of these outcomes.