diff --git a/src/random.h b/src/random.h --- a/src/random.h +++ b/src/random.h @@ -13,6 +13,53 @@ #include #include +/** + * 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. * diff --git a/src/random.cpp b/src/random.cpp --- a/src/random.cpp +++ b/src/random.cpp @@ -297,6 +297,15 @@ 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. + */ uint8_t 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;