diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -86,7 +85,6 @@ } SHA256AutoDetect(); - RandomInit(); ECC_Start(); SetupEnvironment(); diff --git a/src/random.h b/src/random.h --- a/src/random.h +++ b/src/random.h @@ -190,7 +190,12 @@ */ 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 diff --git a/src/random.cpp b/src/random.cpp --- a/src/random.cpp +++ b/src/random.cpp @@ -82,13 +82,24 @@ static void RDRandInit() { uint32_t eax, ebx, ecx, edx; if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx & CPUID_F1_ECX_RDRAND)) { - LogPrintf("Using RdRand as an additional entropy source\n"); rdrand_supported = true; } hwrand_initialized.store(true); } + +static void RDRandReport() { + assert(hwrand_initialized.load(std::memory_order_relaxed)); + if (rdrand_supported) { + // This must be done in a separate function, as HWRandInit() may be + // indirectly called from global constructors, before logging is + // initialized. + LogPrintf("Using RdRand as an additional entropy source\n"); + } +} + #else static void RDRandInit() {} +static void RDRandReport() {} #endif static bool GetHWRand(uint8_t *ent32) { @@ -289,6 +300,24 @@ } } +namespace { +struct RNGState { + Mutex m_mutex; + uint8_t m_state[32] = {0}; + uint64_t m_counter = 0; + + explicit RNGState() { RDRandInit(); } +}; + +RNGState &GetRNGState() { + // This C++11 idiom relies on the guarantee that static variable are + // initialized on first call, even when multiple parallel calls are + // permitted. + static std::unique_ptr g_rng{new RNGState()}; + return *g_rng; +} +} // namespace + static void AddDataToRng(void *data, size_t len); void RandAddSeedSleep() { @@ -304,27 +333,27 @@ memory_cleanse(&nPerfCounter2, sizeof(nPerfCounter2)); } -static Mutex cs_rng_state; -static uint8_t rng_state[32] = {0}; -static uint64_t rng_counter = 0; - static void AddDataToRng(void *data, size_t len) { + RNGState &rng = GetRNGState(); + CSHA512 hasher; hasher.Write((const uint8_t *)&len, sizeof(len)); hasher.Write((const uint8_t *)data, len); uint8_t buf[64]; { - WAIT_LOCK(cs_rng_state, lock); - hasher.Write(rng_state, sizeof(rng_state)); - hasher.Write((const uint8_t *)&rng_counter, sizeof(rng_counter)); - ++rng_counter; + WAIT_LOCK(rng.m_mutex, lock); + hasher.Write(rng.m_state, sizeof(rng.m_state)); + hasher.Write((const uint8_t *)&rng.m_counter, sizeof(rng.m_counter)); + ++rng.m_counter; hasher.Finalize(buf); - memcpy(rng_state, buf + 32, 32); + memcpy(rng.m_state, buf + 32, 32); } memory_cleanse(buf, 64); } void GetStrongRandBytes(uint8_t *out, int num) { + RNGState &rng = GetRNGState(); + assert(num <= 32); CSHA512 hasher; uint8_t buf[64]; @@ -345,12 +374,12 @@ // Combine with and update state { - WAIT_LOCK(cs_rng_state, lock); - hasher.Write(rng_state, sizeof(rng_state)); - hasher.Write((const uint8_t *)&rng_counter, sizeof(rng_counter)); - ++rng_counter; + WAIT_LOCK(rng.m_mutex, lock); + hasher.Write(rng.m_state, sizeof(rng.m_state)); + hasher.Write((const uint8_t *)&rng.m_counter, sizeof(rng.m_counter)); + ++rng.m_counter; hasher.Finalize(buf); - memcpy(rng_state, buf + 32, 32); + memcpy(rng.m_state, buf + 32, 32); } // Produce output @@ -494,5 +523,8 @@ } void RandomInit() { - RDRandInit(); + // Invoke RNG code to trigger initialization (if not already performed) + GetRNGState(); + + RDRandReport(); } diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -45,7 +45,6 @@ strprintf("%lu_%i", static_cast(GetTime()), int(InsecureRandRange(1 << 30)))) { SHA256AutoDetect(); - RandomInit(); ECC_Start(); SetupEnvironment(); SetupNetworking();