|
|
@ -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(); |
|
|
|
|
|
|
|
} |
|
|
|