aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2019-01-13 10:51:17 -0800
committerPieter Wuille <pieter.wuille@gmail.com>2019-01-16 16:35:54 -0800
commit223de8d94d6522f795ec3c2e7db27469f24aa68c (patch)
tree60448895cf16e6ea5fef6dba41253bcc06208a9a /src
parentf2e60ca98530e0a865ff6c6fd3c5633aec11a515 (diff)
Document RNG design in random.h
Diffstat (limited to 'src')
-rw-r--r--src/random.cpp8
-rw-r--r--src/random.h43
2 files changed, 51 insertions, 0 deletions
diff --git a/src/random.cpp b/src/random.cpp
index 4cd6c9ddc1..3b7f7910b0 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -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;
diff --git a/src/random.h b/src/random.h
index 038e3ecd78..4c73f3822a 100644
--- a/src/random.h
+++ b/src/random.h
@@ -14,6 +14,49 @@
#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.
*
* These functions are designed to be fast (sub microsecond), but do not necessarily