Skip to content

Commit bc64b5a

Browse files
committed
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
2 parents 776ba23 + 2c0a6f1 commit bc64b5a

File tree

1 file changed

+30
-8
lines changed

1 file changed

+30
-8
lines changed

src/random.cpp

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
#include <stdlib.h>
1818
#include <limits>
19+
#include <chrono>
20+
#include <thread>
1921

2022
#ifndef WIN32
2123
#include <sys/time.h>
@@ -43,15 +45,22 @@ static void RandFailure()
4345

4446
static inline int64_t GetPerformanceCounter()
4547
{
46-
int64_t nCounter = 0;
47-
#ifdef WIN32
48-
QueryPerformanceCounter((LARGE_INTEGER*)&nCounter);
48+
// Read the hardware time stamp counter when available.
49+
// See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information.
50+
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
51+
return __rdtsc();
52+
#elif !defined(_MSC_VER) && defined(__i386__)
53+
uint64_t r = 0;
54+
__asm__ volatile ("rdtsc" : "=A"(r)); // Constrain the r variable to the eax:edx pair.
55+
return r;
56+
#elif !defined(_MSC_VER) && (defined(__x86_64__) || defined(__amd64__))
57+
uint64_t r1 = 0, r2 = 0;
58+
__asm__ volatile ("rdtsc" : "=a"(r1), "=d"(r2)); // Constrain r1 to rax and r2 to rdx.
59+
return (r2 << 32) | r1;
4960
#else
50-
timeval t;
51-
gettimeofday(&t, NULL);
52-
nCounter = (int64_t)(t.tv_sec * 1000000 + t.tv_usec);
61+
// Fall back to using C++11 clock (usually microsecond or nanosecond precision)
62+
return std::chrono::high_resolution_clock::now().time_since_epoch().count();
5363
#endif
54-
return nCounter;
5564
}
5665

5766
void RandAddSeed()
@@ -254,6 +263,8 @@ FastRandomContext::FastRandomContext(const uint256& seed) : requires_seed(false)
254263

255264
bool Random_SanityCheck()
256265
{
266+
uint64_t start = GetPerformanceCounter();
267+
257268
/* This does not measure the quality of randomness, but it does test that
258269
* OSRandom() overwrites all 32 bytes of the output given a maximum
259270
* number of tries.
@@ -280,7 +291,18 @@ bool Random_SanityCheck()
280291

281292
tries += 1;
282293
} while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES);
283-
return (num_overwritten == NUM_OS_RANDOM_BYTES); /* If this failed, bailed out after too many tries */
294+
if (num_overwritten != NUM_OS_RANDOM_BYTES) return false; /* If this failed, bailed out after too many tries */
295+
296+
// Check that GetPerformanceCounter increases at least during a GetOSRand() call + 1ms sleep.
297+
std::this_thread::sleep_for(std::chrono::milliseconds(1));
298+
uint64_t stop = GetPerformanceCounter();
299+
if (stop == start) return false;
300+
301+
// We called GetPerformanceCounter. Use it as entropy.
302+
RAND_add((const unsigned char*)&start, sizeof(start), 1);
303+
RAND_add((const unsigned char*)&stop, sizeof(stop), 1);
304+
305+
return true;
284306
}
285307

286308
FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDeterministic), bytebuf_size(0), bitbuf_size(0)

0 commit comments

Comments
 (0)