diff --git a/src/random.h b/src/random.h --- a/src/random.h +++ b/src/random.h @@ -21,10 +21,10 @@ * * Thread-safe. */ -void GetRandBytes(uint8_t *buf, int num); -uint64_t GetRand(uint64_t nMax); -int GetRandInt(int nMax); -uint256 GetRandHash(); +void GetRandBytes(uint8_t *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 @@ * * Thread-safe. */ -void GetStrongRandBytes(uint8_t *buf, int num); +void GetStrongRandBytes(uint8_t *buf, int num) noexcept; /** * Sleep for 1ms, gather entropy from various sources, and feed them to the PRNG @@ -77,10 +77,10 @@ } 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). @@ -95,7 +95,7 @@ FastRandomContext &operator=(FastRandomContext &&from) noexcept; /** Generate a random 64-bit integer. */ - uint64_t rand64() { + uint64_t rand64() noexcept { if (bytebuf_size < 8) { FillByteBuffer(); } @@ -105,7 +105,7 @@ } /** 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) { @@ -122,7 +122,7 @@ } /** 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); while (true) { @@ -137,13 +137,13 @@ 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; @@ -151,7 +151,7 @@ static constexpr uint64_t max() { return std::numeric_limits::max(); } - inline uint64_t operator()() { return rand64(); } + inline uint64_t operator()() noexcept { return rand64(); } }; /** diff --git a/src/random.cpp b/src/random.cpp --- a/src/random.cpp +++ b/src/random.cpp @@ -54,7 +54,7 @@ std::abort(); } -static inline int64_t GetPerformanceCounter() { +static inline int64_t GetPerformanceCounter() noexcept { // Read the hardware time stamp counter when available. // See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information. #if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) @@ -109,7 +109,7 @@ static void ReportHardwareRand() {} #endif -static bool GetHardwareRand(uint8_t *ent32) { +static bool GetHardwareRand(uint8_t *ent32) noexcept { #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) assert(hwrand_initialized.load(std::memory_order_relaxed)); if (rdrand_supported) { @@ -303,7 +303,7 @@ bool m_strongly_seeded GUARDED_BY(m_mutex) = false; std::unique_ptr m_mutex_openssl; - RNGState() { + RNGState() noexcept { InitHardwareRand(); // Init OpenSSL library multithreading support @@ -335,7 +335,7 @@ * returned. */ bool MixExtract(uint8_t *out, size_t num, CSHA512 &&hasher, - bool strong_seed) { + bool strong_seed) noexcept { assert(num <= 32); uint8_t buf[64]; static_assert(sizeof(buf) == CSHA512::OUTPUT_SIZE, @@ -367,7 +367,7 @@ } }; -RNGState &GetRNGState() { +RNGState &GetRNGState() noexcept { // This C++11 idiom relies on the guarantee that static variable are // initialized on first call, even when multiple parallel calls are // permitted. @@ -387,12 +387,28 @@ } } -static void SeedTimestamp(CSHA512 &hasher) { +/** + * A note on the use of noexcept in the seeding functions below: + * + * None of the RNG code should ever throw any exception, with the sole exception + * of MilliSleep in SeedSleep, which can (and does) support interruptions which + * cause a boost::thread_interrupted to be thrown. + * + * This means that SeedSleep, and all functions that invoke it are throwing. + * However, we know that GetRandBytes() and GetStrongRandBytes() never trigger + * this sleeping logic, so they are noexcept. The same is true for all the + * GetRand*() functions that use GetRandBytes() indirectly. + * + * TODO: After moving away from interruptible boost-based thread management, + * everything can become noexcept here. + */ + +static void SeedTimestamp(CSHA512 &hasher) noexcept { int64_t perfcounter = GetPerformanceCounter(); hasher.Write((const uint8_t *)&perfcounter, sizeof(perfcounter)); } -static void SeedFast(CSHA512 &hasher) { +static void SeedFast(CSHA512 &hasher) noexcept { uint8_t buffer[32]; // Stack pointer to indirectly commit to thread/callstack @@ -409,7 +425,7 @@ SeedTimestamp(hasher); } -static void SeedSlow(CSHA512 &hasher) { +static void SeedSlow(CSHA512 &hasher) noexcept { uint8_t buffer[32]; // Everything that the 'fast' seeder includes @@ -449,7 +465,7 @@ RandAddSeedPerfmon(hasher); } -static void SeedStartup(CSHA512 &hasher) { +static void SeedStartup(CSHA512 &hasher) noexcept { #ifdef WIN32 RAND_screen(); #endif @@ -505,17 +521,17 @@ } } -void GetRandBytes(uint8_t *buf, int num) { +void GetRandBytes(uint8_t *buf, int num) noexcept { ProcRand(buf, num, RNGLevel::FAST); } -void GetStrongRandBytes(uint8_t *buf, int num) { +void GetStrongRandBytes(uint8_t *buf, int num) noexcept { ProcRand(buf, num, RNGLevel::SLOW); } void RandAddSeedSleep() { ProcRand(nullptr, 0, RNGLevel::SLEEP); } -uint64_t GetRand(uint64_t nMax) { +uint64_t GetRand(uint64_t nMax) noexcept { if (nMax == 0) { return 0; } @@ -530,11 +546,11 @@ return (nRand % nMax); } -int GetRandInt(int nMax) { +int GetRandInt(int nMax) noexcept { return GetRand(nMax); } -uint256 GetRandHash() { +uint256 GetRandHash() noexcept { uint256 hash; GetRandBytes((uint8_t *)&hash, sizeof(hash)); return hash; @@ -546,7 +562,7 @@ requires_seed = false; } -uint256 FastRandomContext::rand256() { +uint256 FastRandomContext::rand256() noexcept { if (bytebuf_size < 32) { FillByteBuffer(); } @@ -567,7 +583,7 @@ return ret; } -FastRandomContext::FastRandomContext(const uint256 &seed) +FastRandomContext::FastRandomContext(const uint256 &seed) noexcept : requires_seed(false), bytebuf_size(0), bitbuf_size(0) { rng.SetKey(seed.begin(), 32); } @@ -628,7 +644,7 @@ return true; } -FastRandomContext::FastRandomContext(bool fDeterministic) +FastRandomContext::FastRandomContext(bool fDeterministic) noexcept : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0) { if (!fDeterministic) { return;