https://github.com/lukechampine/frand
A fast userspace CSPRNG
https://github.com/lukechampine/frand
chacha csprng rng
Last synced: over 1 year ago
JSON representation
A fast userspace CSPRNG
- Host: GitHub
- URL: https://github.com/lukechampine/frand
- Owner: lukechampine
- License: mit
- Created: 2019-07-01T03:45:25.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2024-10-07T18:20:46.000Z (almost 2 years ago)
- Last Synced: 2025-03-31T05:04:14.529Z (over 1 year ago)
- Topics: chacha, csprng, rng
- Language: Go
- Homepage:
- Size: 35.2 KB
- Stars: 89
- Watchers: 8
- Forks: 11
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
frand
-----
[](https://godoc.org/lukechampine.com/frand)
[](https://goreportcard.com/report/lukechampine.com/frand)
```
go get lukechampine.com/frand
```
`frand` is a fast CSPRNG in userspace, implemented as a lightweight wrapper
around the [`(math/rand/v2).ChaCha8`](https://go.dev/src/math/rand/v2/chacha8.go) generator. The initial
cipher key is derived from the kernel CSPRNG, after which [no new entropy is
ever mixed in](https://blog.cr.yp.to/20140205-entropy.html).
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](https://blog.cr.yp.to/20170723-random.html).
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](https://github.com/lukechampine/frand/blob/3f951cc7c03d029aba12f89106666489fd8c769b/README.md).
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](https://stackoverflow.com/questions/52184366/why-does-hashmap-need-a-cryptographically-secure-hashing-function).
Substituting `frand` for `math/rand` would avoid both of these outcomes.