@@ -74,7 +74,6 @@ static inline int64_t GetPerformanceCounter()
74
74
#endif
75
75
}
76
76
77
-
78
77
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
79
78
static std::atomic<bool > hwrand_initialized{false };
80
79
static bool rdrand_supported = false ;
@@ -83,13 +82,24 @@ static void RDRandInit()
83
82
{
84
83
uint32_t eax, ebx, ecx, edx;
85
84
if (__get_cpuid (1 , &eax, &ebx, &ecx, &edx) && (ecx & CPUID_F1_ECX_RDRAND)) {
86
- LogPrintf (" Using RdRand as an additional entropy source\n " );
87
85
rdrand_supported = true ;
88
86
}
89
87
hwrand_initialized.store (true );
90
88
}
89
+
90
+ static void RDRandReport ()
91
+ {
92
+ assert (hwrand_initialized.load (std::memory_order_relaxed));
93
+ if (rdrand_supported) {
94
+ // This must be done in a separate function, as HWRandInit() may be indirectly called
95
+ // from global constructors, before logging is initialized.
96
+ LogPrintf (" Using RdRand as an additional entropy source\n " );
97
+ }
98
+ }
99
+
91
100
#else
92
101
static void RDRandInit () {}
102
+ static void RDRandReport () {}
93
103
#endif
94
104
95
105
static bool GetHWRand (unsigned char * ent32) {
@@ -279,6 +289,26 @@ void GetRandBytes(unsigned char* buf, int num)
279
289
}
280
290
}
281
291
292
+ namespace {
293
+ struct RNGState {
294
+ Mutex m_mutex;
295
+ unsigned char m_state[32 ] = {0 };
296
+ uint64_t m_counter = 0 ;
297
+
298
+ explicit RNGState () {
299
+ RDRandInit ();
300
+ }
301
+ };
302
+
303
+ RNGState& GetRNGState ()
304
+ {
305
+ // This C++11 idiom relies on the guarantee that static variable are initialized
306
+ // on first call, even when multiple parallel calls are permitted.
307
+ static std::unique_ptr<RNGState> g_rng{new RNGState ()};
308
+ return *g_rng;
309
+ }
310
+ }
311
+
282
312
static void AddDataToRng (void * data, size_t len);
283
313
284
314
void RandAddSeedSleep ()
@@ -295,29 +325,28 @@ void RandAddSeedSleep()
295
325
memory_cleanse (&nPerfCounter2, sizeof (nPerfCounter2));
296
326
}
297
327
298
-
299
- static Mutex cs_rng_state;
300
- static unsigned char rng_state[32 ] = {0 };
301
- static uint64_t rng_counter = 0 ;
302
-
303
328
static void AddDataToRng (void * data, size_t len) {
329
+ RNGState& rng = GetRNGState ();
330
+
304
331
CSHA512 hasher;
305
332
hasher.Write ((const unsigned char *)&len, sizeof (len));
306
333
hasher.Write ((const unsigned char *)data, len);
307
334
unsigned char buf[64 ];
308
335
{
309
- WAIT_LOCK (cs_rng_state , lock);
310
- hasher.Write (rng_state , sizeof (rng_state ));
311
- hasher.Write ((const unsigned char *)&rng_counter , sizeof (rng_counter ));
312
- ++rng_counter ;
336
+ WAIT_LOCK (rng. m_mutex , lock);
337
+ hasher.Write (rng. m_state , sizeof (rng. m_state ));
338
+ hasher.Write ((const unsigned char *)&rng. m_counter , sizeof (rng. m_counter ));
339
+ ++rng. m_counter ;
313
340
hasher.Finalize (buf);
314
- memcpy (rng_state , buf + 32 , 32 );
341
+ memcpy (rng. m_state , buf + 32 , 32 );
315
342
}
316
343
memory_cleanse (buf, 64 );
317
344
}
318
345
319
346
void GetStrongRandBytes (unsigned char * out, int num)
320
347
{
348
+ RNGState& rng = GetRNGState ();
349
+
321
350
assert (num <= 32 );
322
351
CSHA512 hasher;
323
352
unsigned char buf[64 ];
@@ -338,12 +367,12 @@ void GetStrongRandBytes(unsigned char* out, int num)
338
367
339
368
// Combine with and update state
340
369
{
341
- WAIT_LOCK (cs_rng_state , lock);
342
- hasher.Write (rng_state , sizeof (rng_state ));
343
- hasher.Write ((const unsigned char *)&rng_counter , sizeof (rng_counter ));
344
- ++rng_counter ;
370
+ WAIT_LOCK (rng. m_mutex , lock);
371
+ hasher.Write (rng. m_state , sizeof (rng. m_state ));
372
+ hasher.Write ((const unsigned char *)&rng. m_counter , sizeof (rng. m_counter ));
373
+ ++rng. m_counter ;
345
374
hasher.Finalize (buf);
346
- memcpy (rng_state , buf + 32 , 32 );
375
+ memcpy (rng. m_state , buf + 32 , 32 );
347
376
}
348
377
349
378
// Produce output
@@ -480,5 +509,8 @@ FastRandomContext& FastRandomContext::operator=(FastRandomContext&& from) noexce
480
509
481
510
void RandomInit ()
482
511
{
483
- RDRandInit ();
512
+ // Invoke RNG code to trigger initialization (if not already performed)
513
+ GetRNGState ();
514
+
515
+ RDRandReport ();
484
516
}
0 commit comments