Merge #10322: Use hardware timestamps in RNG seeding

2c0a6f1 Use sanity check timestamps as entropy (Pieter Wuille)
33f853d Test that GetPerformanceCounter() increments (Pieter Wuille)
f544094 Use hardware timestamps in RNG seeding (Pieter Wuille)

Tree-SHA512: ea96ff56d425b5dc693b4dd35c8aa64ba20a01b9bd7d2d65298ece623f434e8cfa190f9c0f9b76df8aa496547bfa64533eb751edec8401d09bd5ee3478928a59
This commit is contained in:
Pieter Wuille 2017-05-09 10:10:23 -07:00 committed by Pasta
parent 15f7f9c850
commit b13d92079d
No known key found for this signature in database
GPG Key ID: D362C9F7142766AE

View File

@ -16,6 +16,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <limits> #include <limits>
#include <chrono>
#include <thread>
#ifndef WIN32 #ifndef WIN32
#include <sys/time.h> #include <sys/time.h>
@ -43,15 +45,22 @@ static void RandFailure()
static inline int64_t GetPerformanceCounter() static inline int64_t GetPerformanceCounter()
{ {
int64_t nCounter = 0; // Read the hardware time stamp counter when available.
#ifdef WIN32 // See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information.
QueryPerformanceCounter((LARGE_INTEGER*)&nCounter); #if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
return __rdtsc();
#elif !defined(_MSC_VER) && defined(__i386__)
uint64_t r = 0;
__asm__ volatile ("rdtsc" : "=A"(r)); // Constrain the r variable to the eax:edx pair.
return r;
#elif !defined(_MSC_VER) && (defined(__x86_64__) || defined(__amd64__))
uint64_t r1 = 0, r2 = 0;
__asm__ volatile ("rdtsc" : "=a"(r1), "=d"(r2)); // Constrain r1 to rax and r2 to rdx.
return (r2 << 32) | r1;
#else #else
timeval t; // Fall back to using C++11 clock (usually microsecond or nanosecond precision)
gettimeofday(&t, NULL); return std::chrono::high_resolution_clock::now().time_since_epoch().count();
nCounter = (int64_t)(t.tv_sec * 1000000 + t.tv_usec);
#endif #endif
return nCounter;
} }
void RandAddSeed() void RandAddSeed()
@ -265,6 +274,8 @@ FastRandomContext::FastRandomContext(const uint256& seed) : requires_seed(false)
bool Random_SanityCheck() bool Random_SanityCheck()
{ {
uint64_t start = GetPerformanceCounter();
/* This does not measure the quality of randomness, but it does test that /* This does not measure the quality of randomness, but it does test that
* OSRandom() overwrites all 32 bytes of the output given a maximum * OSRandom() overwrites all 32 bytes of the output given a maximum
* number of tries. * number of tries.
@ -291,7 +302,18 @@ bool Random_SanityCheck()
tries += 1; tries += 1;
} while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES); } while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES);
return (num_overwritten == NUM_OS_RANDOM_BYTES); /* If this failed, bailed out after too many tries */ if (num_overwritten != NUM_OS_RANDOM_BYTES) return false; /* If this failed, bailed out after too many tries */
// Check that GetPerformanceCounter increases at least during a GetOSRand() call + 1ms sleep.
std::this_thread::sleep_for(std::chrono::milliseconds(1));
uint64_t stop = GetPerformanceCounter();
if (stop == start) return false;
// We called GetPerformanceCounter. Use it as entropy.
RAND_add((const unsigned char*)&start, sizeof(start), 1);
RAND_add((const unsigned char*)&stop, sizeof(stop), 1);
return true;
} }
FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0) FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0)