This is a proposal for the operation of our internal random number generator.
Clear classification of what use case uses which interface:
- Random numbers whose security is critical (private keys, seeds, encryption keys) use the
GetStrongRandBytes
function, which draws from our own RNG state, after mixing in “slow” entropy (see further). - Non-critical random numbers that are infrequently needed use the
GetRandBytes
class of functions (designed to work in ~microsecond time), which draw from our own RNG state after mixing in “fast” entropy. - Non-critical random numbers needed inside tight loops use a local
FastRandomContext
(which produces cryptographically secure random numbers, but is only seeded once - using theGetRandBytes
level (see previous bullet point).
To assist in generation, we have 3 levels of seeding:
- fast This is automatically invoked by
GetRandBytes
, and mixes in things like stack pointer and high-precision timestamp. - medium This is automatically invoked by
GetStrongRandBytes
, and mixes in everything fast seeding mixes in, as well as all external sources of entropy (rdrand, getrandom, /dev/urandom, …). - slow This is automatically invoked once at startup, and can be invoked periodically by the scheduler thread when idle. It mixes in everything the slow seeding mixes in, as well as OS environment data, performance monitoring data if available, and time the duration of sleeps.
Initially “medium” and “slow” can include OpenSSL as an entropy source, and when sufficiently many replacements are added, it can be dropped.