Unpredictable number generator.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
genchacha20
LICENSE
README.md
chacha20.go
chacha20_core.go
chacha20_test.go
unpredictable.go

README.md

Unpredictable number generator

This is a Go implementation of the same algorithm as implemented by OpenBSD arc4random().

Naming

The package is called "unpredictable" to point out the fact that we provide unpredictable numbers, not "random". My reasoning is that the word "random" has been so badly misused within computer science that it today means "perfectly predictable" with the added assumption that each run of a program will produce the exact same sequence. Therefore I chose the name "unpredictable" to point out that we are not "random". The word "unpredictable" is hopefully less ambiguous and any suggestion to make the returned numbers predictable can be deflected by saying that the API is supposed to return unpredictable numbers, it's right there in the name.

API

Currently there are three APIs provided:

  • A math/rand.Source which we can get by calling unpredictable.NewMathRandSource(). It provides the interface that math/rand expects, but the Seed() function causes a panic, since we want to provide unpredictable numbers, not random.

  • An io.Reader which we can get by calling unpredictable.NewReader()

  • unpredictable.Read() which is like a normal io.Reader. This is goroutine safe.

Correctness

The implementation has been tested against OpenBSD arc4random. When both generators are fed the exact same entropy they generate the same byte sequence for at least 1680000 bytes (number chosen since the only interesting special case in the OpenBSD arc4random happens at 1600000 bytes). Any bugs in here are likely to show up there too.

Performance

When plugged into math/rand each call to Int63 takes 27ns/op on my machine. This compared to the default math.random source which take 8ns/op and compared to buffered C.arc4random calls at 35ns/op. See my test repository for more details.

When used as an io.Reader this looks even better. math/rand can pump 430MB/s on my MacBook, unpredictable does 460MB/s.

Entropy source

Our entropy comes from "crypto/rand" which is hopefully of high enough quality (just slow).

Additional safety

As opposed to the OpenBSD implementation we don't have fork detection (not sure how to approach that in Go) and locking is up to the user.