Document RNG design in random.h

This commit is contained in:
Pieter Wuille 2019-01-13 10:51:17 -08:00
parent f2e60ca985
commit 223de8d94d
2 changed files with 51 additions and 0 deletions

View file

@ -282,6 +282,14 @@ namespace {
class RNGState {
Mutex m_mutex;
/* The RNG state consists of 256 bits of entropy, taken from the output of
* one operation's SHA512 output, and fed as input to the next one.
* Carrying 256 bits of entropy should be sufficient to guarantee
* unpredictability as long as any entropy source was ever unpredictable
* to an attacker. To protect against situations where an attacker might
* observe the RNG's state, fresh entropy is always mixed when
* GetStrongRandBytes is called.
*/
unsigned char m_state[32] GUARDED_BY(m_mutex) = {0};
uint64_t m_counter GUARDED_BY(m_mutex) = 0;
bool m_strongly_seeded GUARDED_BY(m_mutex) = false;

View file

@ -13,6 +13,49 @@
#include <stdint.h>
#include <limits>
/**
* Overall design of the RNG and entropy sources.
*
* We maintain a single global 256-bit RNG state for all high-quality randomness.
* The following (classes of) functions interact with that state by mixing in new
* entropy, and optionally extracting random output from it:
*
* - The GetRand*() class of functions, as well as construction of FastRandomContext objects,
* perform 'fast' seeding, consisting of mixing in:
* - A stack pointer (indirectly committing to calling thread and call stack)
* - A high-precision timestamp (rdtsc when available, c++ high_resolution_clock otherwise)
* - Hardware RNG (rdrand) when available.
* These entropy sources are very fast, and only designed to protect against situations
* where a VM state restore/copy results in multiple systems with the same randomness.
* FastRandomContext on the other hand does not protect against this once created, but
* is even faster (and acceptable to use inside tight loops).
*
* - The GetStrongRand*() class of function perform 'slow' seeding, including everything
* that fast seeding includes, but additionally:
* - OS entropy (/dev/urandom, getrandom(), ...). The application will terminate if
* this entropy source fails.
* - Bytes from OpenSSL's RNG (which itself may be seeded from various sources)
* - Another high-precision timestamp (indirectly committing to a benchmark of all the
* previous sources).
* These entropy sources are slower, but designed to make sure the RNG state contains
* fresh data that is unpredictable to attackers.
*
* - RandAddSeedSleep() seeds everything that fast seeding includes, but additionally:
* - A high-precision timestamp before and after sleeping 1ms.
* - (On Windows) Once every 10 minutes, performance monitoring data from the OS.
* These just exploit the fact the system is idle to improve the quality of the RNG
* slightly.
*
* On first use of the RNG (regardless of what function is called first), all entropy
* sources used in the 'slow' seeder are included, but also:
* - (On Windows) Performance monitoring data from the OS.
* - (On Windows) Through OpenSSL, the screen contents.
*
* When mixing in new entropy, H = SHA512(entropy || old_rng_state) is computed, and
* (up to) the first 32 bytes of H are produced as output, while the last 32 bytes
* become the new RNG state.
*/
/**
* Generate random data via the internal PRNG.
*