aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2018-12-17 16:48:21 -0800
committerPieter Wuille <pieter.wuille@gmail.com>2019-01-16 15:46:27 -0800
commit05fde14e3afe6f7156ebb6df6cd0e3ae12635b89 (patch)
treecd906acda4ca6c7233b9d4776e1fc129c6dbdfed
parent2d1cc5093949f8ea9487a68724162c8b39035ad8 (diff)
Automatically initialize RNG on first use.
-rw-r--r--src/bench/bench_bitcoin.cpp2
-rw-r--r--src/random.cpp68
-rw-r--r--src/random.h7
-rw-r--r--src/test/test_bitcoin.cpp1
4 files changed, 56 insertions, 22 deletions
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index 32faba86b4..b804a84478 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -6,7 +6,6 @@
#include <crypto/sha256.h>
#include <key.h>
-#include <random.h>
#include <util/system.h>
#include <util/strencodings.h>
#include <validation.h>
@@ -67,7 +66,6 @@ int main(int argc, char** argv)
const fs::path bench_datadir{SetDataDir()};
SHA256AutoDetect();
- RandomInit();
ECC_Start();
SetupEnvironment();
diff --git a/src/random.cpp b/src/random.cpp
index 7dacc477d4..caeb87ff05 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -74,7 +74,6 @@ static inline int64_t GetPerformanceCounter()
#endif
}
-
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
static std::atomic<bool> hwrand_initialized{false};
static bool rdrand_supported = false;
@@ -83,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(unsigned char* ent32) {
@@ -279,6 +289,26 @@ void GetRandBytes(unsigned char* buf, int num)
}
}
+namespace {
+struct RNGState {
+ Mutex m_mutex;
+ unsigned char 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<RNGState> g_rng{new RNGState()};
+ return *g_rng;
+}
+}
+
static void AddDataToRng(void* data, size_t len);
void RandAddSeedSleep()
@@ -295,29 +325,28 @@ void RandAddSeedSleep()
memory_cleanse(&nPerfCounter2, sizeof(nPerfCounter2));
}
-
-static Mutex cs_rng_state;
-static unsigned char 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 unsigned char*)&len, sizeof(len));
hasher.Write((const unsigned char*)data, len);
unsigned char buf[64];
{
- WAIT_LOCK(cs_rng_state, lock);
- hasher.Write(rng_state, sizeof(rng_state));
- hasher.Write((const unsigned char*)&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 unsigned char*)&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(unsigned char* out, int num)
{
+ RNGState& rng = GetRNGState();
+
assert(num <= 32);
CSHA512 hasher;
unsigned char buf[64];
@@ -338,12 +367,12 @@ void GetStrongRandBytes(unsigned char* out, int num)
// Combine with and update state
{
- WAIT_LOCK(cs_rng_state, lock);
- hasher.Write(rng_state, sizeof(rng_state));
- hasher.Write((const unsigned char*)&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 unsigned char*)&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
@@ -480,5 +509,8 @@ FastRandomContext& FastRandomContext::operator=(FastRandomContext&& from) noexce
void RandomInit()
{
- RDRandInit();
+ // Invoke RNG code to trigger initialization (if not already performed)
+ GetRNGState();
+
+ RDRandReport();
}
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
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 858bb512fc..23b2076041 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -49,7 +49,6 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
: m_path_root(fs::temp_directory_path() / "test_bitcoin" / strprintf("%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(1 << 30))))
{
SHA256AutoDetect();
- RandomInit();
ECC_Start();
SetupEnvironment();
SetupNetworking();