Skip to content

lukechampine/frand

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

frand

GoDoc Go Report Card

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.

Design

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.

Security

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.