Browse Source

Use rdrand as entropy source on supported platforms

0.15
Pieter Wuille 8 years ago
parent
commit
cb24c8539d
  1. 1
      src/init.cpp
  2. 68
      src/random.cpp
  3. 3
      src/random.h
  4. 1
      src/test/test_bitcoin.cpp

1
src/init.cpp

@ -1168,6 +1168,7 @@ bool AppInitSanityChecks()
// ********************************************************* Step 4: sanity checks // ********************************************************* Step 4: sanity checks
// Initialize elliptic curve code // Initialize elliptic curve code
RandomInit();
ECC_Start(); ECC_Start();
globalVerifyHandle.reset(new ECCVerifyHandle()); globalVerifyHandle.reset(new ECCVerifyHandle());

68
src/random.cpp

@ -65,6 +65,64 @@ static inline int64_t GetPerformanceCounter()
#endif #endif
} }
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
static std::atomic<bool> hwrand_initialized{false};
static bool rdrand_supported = false;
static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000;
static void RDRandInit()
{
//! When calling cpuid function #1, ecx register will have this set if RDRAND is available.
// Avoid clobbering ebx, as that is used for PIC on x86.
uint32_t eax, tmp, ecx, edx;
__asm__ ("mov %%ebx, %1; cpuid; mov %1, %%ebx": "=a"(eax), "=g"(tmp), "=c"(ecx), "=d"(edx) : "a"(1));
if (ecx & CPUID_F1_ECX_RDRAND) {
LogPrintf("Using RdRand as 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() void RandAddSeed()
{ {
// Seed with CPU performance counter // Seed with CPU performance counter
@ -255,6 +313,11 @@ void GetStrongRandBytes(unsigned char* out, int num)
GetOSRand(buf); GetOSRand(buf);
hasher.Write(buf, 32); hasher.Write(buf, 32);
// Third source: HW RNG, if available.
if (GetHWRand(buf)) {
hasher.Write(buf, 32);
}
// Combine with and update state // Combine with and update state
{ {
std::unique_lock<std::mutex> lock(cs_rng_state); std::unique_lock<std::mutex> lock(cs_rng_state);
@ -361,3 +424,8 @@ FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDete
uint256 seed; uint256 seed;
rng.SetKey(seed.begin(), 32); rng.SetKey(seed.begin(), 32);
} }
void RandomInit()
{
RDRandInit();
}

3
src/random.h

@ -134,4 +134,7 @@ void GetOSRand(unsigned char *ent32);
*/ */
bool Random_SanityCheck(); bool Random_SanityCheck();
/** Initialize the RNG. */
void RandomInit();
#endif // BITCOIN_RANDOM_H #endif // BITCOIN_RANDOM_H

1
src/test/test_bitcoin.cpp

@ -35,6 +35,7 @@ extern void noui_connect();
BasicTestingSetup::BasicTestingSetup(const std::string& chainName) BasicTestingSetup::BasicTestingSetup(const std::string& chainName)
{ {
RandomInit();
ECC_Start(); ECC_Start();
SetupEnvironment(); SetupEnvironment();
SetupNetworking(); SetupNetworking();

Loading…
Cancel
Save