diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2017-05-09 10:10:23 -0700 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2017-05-09 10:12:41 -0700 |
commit | bc64b5aa0fc543fe8fd3dbaec275f89df44dc409 (patch) | |
tree | 1b76638fea01faf488c9c2c2bc5fab3d678e64c1 /src | |
parent | 776ba233e939fe41a74c6b2632b93a0679a32c71 (diff) | |
parent | 2c0a6f157da3c6bb3b0a1e77f003caf0d9cb9d6c (diff) |
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
Diffstat (limited to 'src')
-rw-r--r-- | src/random.cpp | 38 |
1 files changed, 30 insertions, 8 deletions
diff --git a/src/random.cpp b/src/random.cpp index 6187f16290..805d7d3872 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -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) |