From 05fde14e3afe6f7156ebb6df6cd0e3ae12635b89 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 17 Dec 2018 16:48:21 -0800 Subject: Automatically initialize RNG on first use. --- src/random.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/random.h') diff --git a/src/random.h b/src/random.h index 00e90abbc5..221545a8ef 100644 --- a/src/random.h +++ b/src/random.h @@ -178,7 +178,12 @@ void GetOSRand(unsigned char *ent32); */ bool Random_SanityCheck(); -/** Initialize the RNG. */ +/** + * Initialize global RNG state and log any CPU features that are used. + * + * Calling this function is optional. RNG state will be initialized when first + * needed if it is not called. + */ void RandomInit(); #endif // BITCOIN_RANDOM_H -- cgit v1.2.3 From 9d7032e4f066777c97c58b1394884716e213790a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 13 Dec 2018 18:37:29 -0800 Subject: Switch all RNG code to the built-in PRNG. It includes the following policy changes: * All GetRand* functions seed the stack pointer and rdrand result (in addition to the performance counter) * The periodic entropy added by the idle scheduler now seeds stack pointer, rdrand and perfmon data (once every 10 minutes) in addition to just a sleep timing. * The entropy added when calling GetStrongRandBytes no longer includes the once-per-10-minutes perfmon data on windows (it is moved to the idle scheduler instead, where latency matters less). Other changes: * OpenSSL is no longer seeded directly anywhere. Instead, any generated randomness through our own RNG is fed back to OpenSSL (after an additional hashing step to prevent leaking our RNG state). * Seeding that was previously done directly in RandAddSeedSleep is now moved to SeedSleep(), which is indirectly invoked through ProcRand from RandAddSeedSleep. * Seeding that was previously done directly in GetStrongRandBytes() is now moved to SeedSlow(), which is indirectly invoked through ProcRand from GetStrongRandBytes(). --- src/random.h | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'src/random.h') diff --git a/src/random.h b/src/random.h index 221545a8ef..592f36a406 100644 --- a/src/random.h +++ b/src/random.h @@ -13,11 +13,13 @@ #include #include -/* Seed OpenSSL PRNG with additional entropy data */ -void RandAddSeed(); - /** - * Functions to gather random data via the OpenSSL PRNG + * Generate random data via the internal PRNG. + * + * These functions are designed to be fast (sub microsecond), but do not necessarily + * meaningfully add entropy to the PRNG state. + * + * Thread-safe. */ void GetRandBytes(unsigned char* buf, int num); uint64_t GetRand(uint64_t nMax); @@ -25,21 +27,26 @@ int GetRandInt(int nMax); uint256 GetRandHash(); /** - * Add a little bit of randomness to the output of GetStrongRangBytes. - * This sleeps for a millisecond, so should only be called when there is - * no other work to be done. + * Gather entropy from various sources, feed it into the internal PRNG, and + * generate random data using it. + * + * This function will cause failure whenever the OS RNG fails. + * + * Thread-safe. */ -void RandAddSeedSleep(); +void GetStrongRandBytes(unsigned char* buf, int num); /** - * Function to gather random data from multiple sources, failing whenever any - * of those sources fail to provide a result. + * Sleep for 1ms, gather entropy from various sources, and feed them to the PRNG state. + * + * Thread-safe. */ -void GetStrongRandBytes(unsigned char* buf, int num); +void RandAddSeedSleep(); /** * Fast randomness source. This is seeded once with secure random data, but - * is completely deterministic and insecure after that. + * is completely deterministic and does not gather more entropy after that. + * * This class is not thread-safe. */ class FastRandomContext { -- cgit v1.2.3 From a1f252eda87356fa329c838a7bf569808489648f Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 17 Dec 2018 15:11:33 -0800 Subject: Sprinkle some sweet noexcepts over the RNG code --- src/random.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'src/random.h') diff --git a/src/random.h b/src/random.h index 592f36a406..038e3ecd78 100644 --- a/src/random.h +++ b/src/random.h @@ -21,10 +21,10 @@ * * Thread-safe. */ -void GetRandBytes(unsigned char* buf, int num); -uint64_t GetRand(uint64_t nMax); -int GetRandInt(int nMax); -uint256 GetRandHash(); +void GetRandBytes(unsigned char* buf, int num) noexcept; +uint64_t GetRand(uint64_t nMax) noexcept; +int GetRandInt(int nMax) noexcept; +uint256 GetRandHash() noexcept; /** * Gather entropy from various sources, feed it into the internal PRNG, and @@ -34,7 +34,7 @@ uint256 GetRandHash(); * * Thread-safe. */ -void GetStrongRandBytes(unsigned char* buf, int num); +void GetStrongRandBytes(unsigned char* buf, int num) noexcept; /** * Sleep for 1ms, gather entropy from various sources, and feed them to the PRNG state. @@ -78,10 +78,10 @@ private: } public: - explicit FastRandomContext(bool fDeterministic = false); + explicit FastRandomContext(bool fDeterministic = false) noexcept; /** Initialize with explicit seed (only for testing) */ - explicit FastRandomContext(const uint256& seed); + explicit FastRandomContext(const uint256& seed) noexcept; // Do not permit copying a FastRandomContext (move it, or create a new one to get reseeded). FastRandomContext(const FastRandomContext&) = delete; @@ -92,7 +92,7 @@ public: FastRandomContext& operator=(FastRandomContext&& from) noexcept; /** Generate a random 64-bit integer. */ - uint64_t rand64() + uint64_t rand64() noexcept { if (bytebuf_size < 8) FillByteBuffer(); uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size); @@ -101,7 +101,7 @@ public: } /** Generate a random (bits)-bit integer. */ - uint64_t randbits(int bits) { + uint64_t randbits(int bits) noexcept { if (bits == 0) { return 0; } else if (bits > 32) { @@ -116,7 +116,7 @@ public: } /** Generate a random integer in the range [0..range). */ - uint64_t randrange(uint64_t range) + uint64_t randrange(uint64_t range) noexcept { --range; int bits = CountBits(range); @@ -130,19 +130,19 @@ public: std::vector randbytes(size_t len); /** Generate a random 32-bit integer. */ - uint32_t rand32() { return randbits(32); } + uint32_t rand32() noexcept { return randbits(32); } /** generate a random uint256. */ - uint256 rand256(); + uint256 rand256() noexcept; /** Generate a random boolean. */ - bool randbool() { return randbits(1); } + bool randbool() noexcept { return randbits(1); } // Compatibility with the C++11 UniformRandomBitGenerator concept typedef uint64_t result_type; static constexpr uint64_t min() { return 0; } static constexpr uint64_t max() { return std::numeric_limits::max(); } - inline uint64_t operator()() { return rand64(); } + inline uint64_t operator()() noexcept { return rand64(); } }; /** More efficient than using std::shuffle on a FastRandomContext. -- cgit v1.2.3 From 223de8d94d6522f795ec3c2e7db27469f24aa68c Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 13 Jan 2019 10:51:17 -0800 Subject: Document RNG design in random.h --- src/random.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'src/random.h') diff --git a/src/random.h b/src/random.h index 038e3ecd78..4c73f3822a 100644 --- a/src/random.h +++ b/src/random.h @@ -13,6 +13,49 @@ #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. * -- cgit v1.2.3