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
commit bc64b5aa0f
No known key found for this signature in database
GPG key ID: A636E97631F767E0

View file

@ -16,6 +16,8 @@
#include <stdlib.h>
#include <limits>
#include <chrono>
#include <thread>
#ifndef WIN32
#include <sys/time.h>
@ -43,15 +45,22 @@ static void RandFailure()
static inline int64_t GetPerformanceCounter()
{
int64_t nCounter = 0;
#ifdef WIN32
QueryPerformanceCounter((LARGE_INTEGER*)&nCounter);
// Read the hardware time stamp counter when available.
// See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information.
#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
timeval t;
gettimeofday(&t, NULL);
nCounter = (int64_t)(t.tv_sec * 1000000 + t.tv_usec);
// Fall back to using C++11 clock (usually microsecond or nanosecond precision)
return std::chrono::high_resolution_clock::now().time_since_epoch().count();
#endif
return nCounter;
}
void RandAddSeed()
@ -254,6 +263,8 @@ FastRandomContext::FastRandomContext(const uint256& seed) : requires_seed(false)
bool Random_SanityCheck()
{
uint64_t start = GetPerformanceCounter();
/* This does not measure the quality of randomness, but it does test that
* OSRandom() overwrites all 32 bytes of the output given a maximum
* number of tries.
@ -280,7 +291,18 @@ bool Random_SanityCheck()
tries += 1;
} 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)