Sprinkle some sweet noexcepts over the RNG code

This commit is contained in:
Pieter Wuille 2018-12-17 15:11:33 -08:00
parent 4ea8e50837
commit a1f252eda8
2 changed files with 46 additions and 31 deletions

View file

@ -55,7 +55,7 @@
std::abort(); std::abort();
} }
static inline int64_t GetPerformanceCounter() static inline int64_t GetPerformanceCounter() noexcept
{ {
// Read the hardware time stamp counter when available. // Read the hardware time stamp counter when available.
// See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information. // See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information.
@ -105,7 +105,7 @@ static void InitHardwareRand() {}
static void ReportHardwareRand() {} static void ReportHardwareRand() {}
#endif #endif
static bool GetHardwareRand(unsigned char* ent32) { static bool GetHardwareRand(unsigned char* ent32) noexcept {
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
if (rdrand_supported) { if (rdrand_supported) {
uint8_t ok; uint8_t ok;
@ -285,7 +285,7 @@ struct RNGState {
bool m_strongly_seeded GUARDED_BY(m_mutex) = false; bool m_strongly_seeded GUARDED_BY(m_mutex) = false;
std::unique_ptr<Mutex[]> m_mutex_openssl; std::unique_ptr<Mutex[]> m_mutex_openssl;
RNGState() RNGState() noexcept
{ {
InitHardwareRand(); InitHardwareRand();
@ -313,7 +313,7 @@ struct RNGState {
* *
* If this function has never been called with strong_seed = true, false is returned. * If this function has never been called with strong_seed = true, false is returned.
*/ */
bool MixExtract(unsigned char* out, size_t num, CSHA512&& hasher, bool strong_seed) bool MixExtract(unsigned char* out, size_t num, CSHA512&& hasher, bool strong_seed) noexcept
{ {
assert(num <= 32); assert(num <= 32);
unsigned char buf[64]; unsigned char buf[64];
@ -344,7 +344,7 @@ struct RNGState {
} }
}; };
RNGState& GetRNGState() RNGState& GetRNGState() noexcept
{ {
// This C++11 idiom relies on the guarantee that static variable are initialized // This C++11 idiom relies on the guarantee that static variable are initialized
// on first call, even when multiple parallel calls are permitted. // on first call, even when multiple parallel calls are permitted.
@ -364,13 +364,28 @@ void LockingCallbackOpenSSL(int mode, int i, const char* file, int line) NO_THRE
} }
} }
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(); int64_t perfcounter = GetPerformanceCounter();
hasher.Write((const unsigned char*)&perfcounter, sizeof(perfcounter)); hasher.Write((const unsigned char*)&perfcounter, sizeof(perfcounter));
} }
static void SeedFast(CSHA512& hasher) static void SeedFast(CSHA512& hasher) noexcept
{ {
unsigned char buffer[32]; unsigned char buffer[32];
@ -386,7 +401,7 @@ static void SeedFast(CSHA512& hasher)
SeedTimestamp(hasher); SeedTimestamp(hasher);
} }
static void SeedSlow(CSHA512& hasher) static void SeedSlow(CSHA512& hasher) noexcept
{ {
unsigned char buffer[32]; unsigned char buffer[32];
@ -426,7 +441,7 @@ static void SeedSleep(CSHA512& hasher)
RandAddSeedPerfmon(hasher); RandAddSeedPerfmon(hasher);
} }
static void SeedStartup(CSHA512& hasher) static void SeedStartup(CSHA512& hasher) noexcept
{ {
#ifdef WIN32 #ifdef WIN32
RAND_screen(); RAND_screen();
@ -482,11 +497,11 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level)
} }
} }
void GetRandBytes(unsigned char* buf, int num) { ProcRand(buf, num, RNGLevel::FAST); } void GetRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::FAST); }
void GetStrongRandBytes(unsigned char* buf, int num) { ProcRand(buf, num, RNGLevel::SLOW); } void GetStrongRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::SLOW); }
void RandAddSeedSleep() { ProcRand(nullptr, 0, RNGLevel::SLEEP); } void RandAddSeedSleep() { ProcRand(nullptr, 0, RNGLevel::SLEEP); }
uint64_t GetRand(uint64_t nMax) uint64_t GetRand(uint64_t nMax) noexcept
{ {
if (nMax == 0) if (nMax == 0)
return 0; return 0;
@ -501,12 +516,12 @@ uint64_t GetRand(uint64_t nMax)
return (nRand % nMax); return (nRand % nMax);
} }
int GetRandInt(int nMax) int GetRandInt(int nMax) noexcept
{ {
return GetRand(nMax); return GetRand(nMax);
} }
uint256 GetRandHash() uint256 GetRandHash() noexcept
{ {
uint256 hash; uint256 hash;
GetRandBytes((unsigned char*)&hash, sizeof(hash)); GetRandBytes((unsigned char*)&hash, sizeof(hash));
@ -520,7 +535,7 @@ void FastRandomContext::RandomSeed()
requires_seed = false; requires_seed = false;
} }
uint256 FastRandomContext::rand256() uint256 FastRandomContext::rand256() noexcept
{ {
if (bytebuf_size < 32) { if (bytebuf_size < 32) {
FillByteBuffer(); FillByteBuffer();
@ -541,7 +556,7 @@ std::vector<unsigned char> FastRandomContext::randbytes(size_t len)
return ret; return ret;
} }
FastRandomContext::FastRandomContext(const uint256& seed) : requires_seed(false), bytebuf_size(0), bitbuf_size(0) FastRandomContext::FastRandomContext(const uint256& seed) noexcept : requires_seed(false), bytebuf_size(0), bitbuf_size(0)
{ {
rng.SetKey(seed.begin(), 32); rng.SetKey(seed.begin(), 32);
} }
@ -592,7 +607,7 @@ bool Random_SanityCheck()
return true; return true;
} }
FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0) FastRandomContext::FastRandomContext(bool fDeterministic) noexcept : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0)
{ {
if (!fDeterministic) { if (!fDeterministic) {
return; return;

View file

@ -21,10 +21,10 @@
* *
* Thread-safe. * Thread-safe.
*/ */
void GetRandBytes(unsigned char* buf, int num); void GetRandBytes(unsigned char* buf, int num) noexcept;
uint64_t GetRand(uint64_t nMax); uint64_t GetRand(uint64_t nMax) noexcept;
int GetRandInt(int nMax); int GetRandInt(int nMax) noexcept;
uint256 GetRandHash(); uint256 GetRandHash() noexcept;
/** /**
* Gather entropy from various sources, feed it into the internal PRNG, and * Gather entropy from various sources, feed it into the internal PRNG, and
@ -34,7 +34,7 @@ uint256 GetRandHash();
* *
* Thread-safe. * 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. * Sleep for 1ms, gather entropy from various sources, and feed them to the PRNG state.
@ -78,10 +78,10 @@ private:
} }
public: public:
explicit FastRandomContext(bool fDeterministic = false); explicit FastRandomContext(bool fDeterministic = false) noexcept;
/** Initialize with explicit seed (only for testing) */ /** 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). // Do not permit copying a FastRandomContext (move it, or create a new one to get reseeded).
FastRandomContext(const FastRandomContext&) = delete; FastRandomContext(const FastRandomContext&) = delete;
@ -92,7 +92,7 @@ public:
FastRandomContext& operator=(FastRandomContext&& from) noexcept; FastRandomContext& operator=(FastRandomContext&& from) noexcept;
/** Generate a random 64-bit integer. */ /** Generate a random 64-bit integer. */
uint64_t rand64() uint64_t rand64() noexcept
{ {
if (bytebuf_size < 8) FillByteBuffer(); if (bytebuf_size < 8) FillByteBuffer();
uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size); uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size);
@ -101,7 +101,7 @@ public:
} }
/** Generate a random (bits)-bit integer. */ /** Generate a random (bits)-bit integer. */
uint64_t randbits(int bits) { uint64_t randbits(int bits) noexcept {
if (bits == 0) { if (bits == 0) {
return 0; return 0;
} else if (bits > 32) { } else if (bits > 32) {
@ -116,7 +116,7 @@ public:
} }
/** Generate a random integer in the range [0..range). */ /** Generate a random integer in the range [0..range). */
uint64_t randrange(uint64_t range) uint64_t randrange(uint64_t range) noexcept
{ {
--range; --range;
int bits = CountBits(range); int bits = CountBits(range);
@ -130,19 +130,19 @@ public:
std::vector<unsigned char> randbytes(size_t len); std::vector<unsigned char> randbytes(size_t len);
/** Generate a random 32-bit integer. */ /** Generate a random 32-bit integer. */
uint32_t rand32() { return randbits(32); } uint32_t rand32() noexcept { return randbits(32); }
/** generate a random uint256. */ /** generate a random uint256. */
uint256 rand256(); uint256 rand256() noexcept;
/** Generate a random boolean. */ /** Generate a random boolean. */
bool randbool() { return randbits(1); } bool randbool() noexcept { return randbits(1); }
// Compatibility with the C++11 UniformRandomBitGenerator concept // Compatibility with the C++11 UniformRandomBitGenerator concept
typedef uint64_t result_type; typedef uint64_t result_type;
static constexpr uint64_t min() { return 0; } static constexpr uint64_t min() { return 0; }
static constexpr uint64_t max() { return std::numeric_limits<uint64_t>::max(); } static constexpr uint64_t max() { return std::numeric_limits<uint64_t>::max(); }
inline uint64_t operator()() { return rand64(); } inline uint64_t operator()() noexcept { return rand64(); }
}; };
/** More efficient than using std::shuffle on a FastRandomContext. /** More efficient than using std::shuffle on a FastRandomContext.