Browse Source

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
0.15
Pieter Wuille 8 years ago
parent
commit
bc64b5aa0f
No known key found for this signature in database
GPG Key ID: A636E97631F767E0
  1. 38
      src/random.cpp

38
src/random.cpp

@ -16,6 +16,8 @@ @@ -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() @@ -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) @@ -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() @@ -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)

Loading…
Cancel
Save