Sprinkle some sweet noexcepts over the RNG code
This commit is contained in:
parent
4ea8e50837
commit
a1f252eda8
2 changed files with 46 additions and 31 deletions
|
@ -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;
|
||||||
|
|
28
src/random.h
28
src/random.h
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue