From f544094d5e1ee627ebd34542aead7bf1241fae19 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Tue, 2 May 2017 18:21:33 -0700 Subject: [PATCH 1/3] Use hardware timestamps in RNG seeding --- src/random.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/random.cpp b/src/random.cpp index 6187f1629..40879e873 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -16,6 +16,7 @@ #include #include +#include #ifndef WIN32 #include @@ -43,15 +44,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() From 33f853d8d88917b145e2793bf8eb1b4e3790e7e7 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 5 May 2017 11:32:06 -0700 Subject: [PATCH 2/3] Test that GetPerformanceCounter() increments --- src/random.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/random.cpp b/src/random.cpp index 40879e873..8107cb310 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #ifndef WIN32 #include @@ -262,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. @@ -288,7 +291,14 @@ 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; + + return true; } FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0) From 2c0a6f157da3c6bb3b0a1e77f003caf0d9cb9d6c Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 5 May 2017 11:45:37 -0700 Subject: [PATCH 3/3] Use sanity check timestamps as entropy --- src/random.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/random.cpp b/src/random.cpp index 8107cb310..805d7d387 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -298,6 +298,10 @@ bool Random_SanityCheck() 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; }