diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp index c4e3fd5d034..6e5ced4b3c7 100644 --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -5,10 +5,12 @@ #include "bench.h" // for BenchRunner #include "key.h" // for ECC_Start, ECC_Stop #include "util.h" // for SetupEnvironment, fPrintToDebugLog +#include "random.h" int main(int argc, char** argv) { + RandomInit(); ECC_Start(); SetupEnvironment(); fPrintToDebugLog = false; // don't want to write to debug.log file diff --git a/src/init.cpp b/src/init.cpp index a39713d4a72..d6c224a1013 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1188,6 +1188,7 @@ bool AppInitSanityChecks() // ********************************************************* Step 4: sanity checks // Initialize elliptic curve code + RandomInit(); ECC_Start(); globalVerifyHandle.reset(new ECCVerifyHandle()); diff --git a/src/random.cpp b/src/random.cpp index 8e10bd77d07..46d046f71b3 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -37,6 +37,10 @@ #include #endif +#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) +#include +#endif + #include #include @@ -66,6 +70,61 @@ static inline int64_t GetPerformanceCounter() #endif } + +#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) +static std::atomic hwrand_initialized{false}; +static bool rdrand_supported = false; +static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000; +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); +} +#else +static void RDRandInit() {} +#endif + +static bool GetHWRand(unsigned char* ent32) { +#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) + assert(hwrand_initialized.load(std::memory_order_relaxed)); + if (rdrand_supported) { + uint8_t ok; + // Not all assemblers support the rdrand instruction, write it in hex. +#ifdef __i386__ + for (int iter = 0; iter < 4; ++iter) { + uint32_t r1, r2; + __asm__ volatile (".byte 0x0f, 0xc7, 0xf0;" // rdrand %eax + ".byte 0x0f, 0xc7, 0xf2;" // rdrand %edx + "setc %2" : + "=a"(r1), "=d"(r2), "=q"(ok) :: "cc"); + if (!ok) return false; + WriteLE32(ent32 + 8 * iter, r1); + WriteLE32(ent32 + 8 * iter + 4, r2); + } +#else + uint64_t r1, r2, r3, r4; + __asm__ volatile (".byte 0x48, 0x0f, 0xc7, 0xf0, " // rdrand %rax + "0x48, 0x0f, 0xc7, 0xf3, " // rdrand %rbx + "0x48, 0x0f, 0xc7, 0xf1, " // rdrand %rcx + "0x48, 0x0f, 0xc7, 0xf2; " // rdrand %rdx + "setc %4" : + "=a"(r1), "=b"(r2), "=c"(r3), "=d"(r4), "=q"(ok) :: "cc"); + if (!ok) return false; + WriteLE64(ent32, r1); + WriteLE64(ent32 + 8, r2); + WriteLE64(ent32 + 16, r3); + WriteLE64(ent32 + 24, r4); +#endif + return true; + } +#endif + return false; +} + void RandAddSeed() { // Seed with CPU performance counter @@ -228,6 +287,11 @@ void GetStrongRandBytes(unsigned char* out, int num) GetOSRand(buf); hasher.Write(buf, 32); + // Third source: HW RNG, if available. + if (GetHWRand(buf)) { + hasher.Write(buf, 32); + } + // Produce output hasher.Finalize(buf); memcpy(out, buf, num); @@ -345,3 +409,8 @@ FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDete uint256 seed; rng.SetKey(seed.begin(), 32); } + +void RandomInit() +{ + RDRandInit(); +} diff --git a/src/random.h b/src/random.h index f8e2e0dc555..b35cf51a166 100644 --- a/src/random.h +++ b/src/random.h @@ -133,4 +133,7 @@ void GetOSRand(unsigned char *ent32); */ bool Random_SanityCheck(); +/** Initialize the RNG. */ +void RandomInit(); + #endif // BITCOIN_RANDOM_H diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index b85f61132e8..a3459726caa 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -43,6 +43,7 @@ static const int COINBASE_MATURITY = 60*4; // 4 hours of blocks BasicTestingSetup::BasicTestingSetup(const std::string& chainName) { + RandomInit(); ECC_Start(); SetupEnvironment(); SetupNetworking();