@@ -65,6 +65,64 @@ static inline int64_t GetPerformanceCounter()
65
65
#endif
66
66
}
67
67
68
+
69
+ #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
70
+ static std::atomic<bool > hwrand_initialized{false };
71
+ static bool rdrand_supported = false ;
72
+ static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000 ;
73
+ static void RDRandInit ()
74
+ {
75
+ // ! When calling cpuid function #1, ecx register will have this set if RDRAND is available.
76
+ // Avoid clobbering ebx, as that is used for PIC on x86.
77
+ uint32_t eax, tmp, ecx, edx;
78
+ __asm__ (" mov %%ebx, %1; cpuid; mov %1, %%ebx" : " =a" (eax), " =g" (tmp), " =c" (ecx), " =d" (edx) : " a" (1 ));
79
+ if (ecx & CPUID_F1_ECX_RDRAND) {
80
+ LogPrintf (" Using RdRand as entropy source\n " );
81
+ rdrand_supported = true ;
82
+ }
83
+ hwrand_initialized.store (true );
84
+ }
85
+ #else
86
+ static void RDRandInit () {}
87
+ #endif
88
+
89
+ static bool GetHWRand (unsigned char * ent32) {
90
+ #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
91
+ assert (hwrand_initialized.load (std::memory_order_relaxed));
92
+ if (rdrand_supported) {
93
+ uint8_t ok;
94
+ // Not all assemblers support the rdrand instruction, write it in hex.
95
+ #ifdef __i386__
96
+ for (int iter = 0 ; iter < 4 ; ++iter) {
97
+ uint32_t r1, r2;
98
+ __asm__ volatile (" .byte 0x0f, 0xc7, 0xf0;" // rdrand %eax
99
+ " .byte 0x0f, 0xc7, 0xf2;" // rdrand %edx
100
+ " setc %2" :
101
+ " =a" (r1), " =d" (r2), " =q" (ok) :: " cc" );
102
+ if (!ok) return false ;
103
+ WriteLE32 (ent32 + 8 * iter, r1);
104
+ WriteLE32 (ent32 + 8 * iter + 4 , r2);
105
+ }
106
+ #else
107
+ uint64_t r1, r2, r3, r4;
108
+ __asm__ volatile (" .byte 0x48, 0x0f, 0xc7, 0xf0, " // rdrand %rax
109
+ " 0x48, 0x0f, 0xc7, 0xf3, " // rdrand %rbx
110
+ " 0x48, 0x0f, 0xc7, 0xf1, " // rdrand %rcx
111
+ " 0x48, 0x0f, 0xc7, 0xf2; " // rdrand %rdx
112
+ " setc %4" :
113
+ " =a" (r1), " =b" (r2), " =c" (r3), " =d" (r4), " =q" (ok) :: " cc" );
114
+ if (!ok) return false ;
115
+ WriteLE64 (ent32, r1);
116
+ WriteLE64 (ent32 + 8 , r2);
117
+ WriteLE64 (ent32 + 16 , r3);
118
+ WriteLE64 (ent32 + 24 , r4);
119
+ #endif
120
+ return true ;
121
+ }
122
+ #endif
123
+ return false ;
124
+ }
125
+
68
126
void RandAddSeed ()
69
127
{
70
128
// Seed with CPU performance counter
@@ -255,6 +313,11 @@ void GetStrongRandBytes(unsigned char* out, int num)
255
313
GetOSRand (buf);
256
314
hasher.Write (buf, 32 );
257
315
316
+ // Third source: HW RNG, if available.
317
+ if (GetHWRand (buf)) {
318
+ hasher.Write (buf, 32 );
319
+ }
320
+
258
321
// Combine with and update state
259
322
{
260
323
std::unique_lock<std::mutex> lock (cs_rng_state);
@@ -381,3 +444,8 @@ FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDete
381
444
uint256 seed;
382
445
rng.SetKey (seed.begin (), 32 );
383
446
}
447
+
448
+ void RandomInit ()
449
+ {
450
+ RDRandInit ();
451
+ }
0 commit comments