@@ -65,6 +65,64 @@ static inline int64_t GetPerformanceCounter()
6565#endif
6666}
6767
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+
68126void RandAddSeed ()
69127{
70128 // Seed with CPU performance counter
@@ -257,6 +315,11 @@ void GetStrongRandBytes(unsigned char* out, int num)
257315 GetOSRand (buf);
258316 hasher.Write (buf, 32 );
259317
318+ // Third source: HW RNG, if available.
319+ if (GetHWRand (buf)) {
320+ hasher.Write (buf, 32 );
321+ }
322+
260323 // Combine with and update state
261324 {
262325 std::unique_lock<std::mutex> lock (cs_rng_state);
@@ -383,3 +446,8 @@ FastRandomContext::FastRandomContext(bool fDeterministic) : requires_seed(!fDete
383446 uint256 seed;
384447 rng.SetKey (seed.begin (), 32 );
385448}
449+
450+ void RandomInit ()
451+ {
452+ RDRandInit ();
453+ }
0 commit comments