Branch data Line data Source code
1 : : // Copyright (c) 2009-2010 Satoshi Nakamoto
2 : : // Copyright (c) 2009-2022 The Bitcoin Core developers
3 : : // Distributed under the MIT software license, see the accompanying
4 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 : :
6 : : #include <random.h>
7 : :
8 : : #include <compat/compat.h>
9 : : #include <compat/cpuid.h>
10 : : #include <crypto/chacha20.h>
11 : : #include <crypto/sha256.h>
12 : : #include <crypto/sha512.h>
13 : : #include <logging.h>
14 : : #include <randomenv.h>
15 : : #include <span.h>
16 : : #include <support/allocators/secure.h>
17 : : #include <support/cleanse.h>
18 : : #include <sync.h>
19 : : #include <util/time.h>
20 : :
21 : : #include <array>
22 : : #include <cmath>
23 : : #include <cstdlib>
24 : : #include <thread>
25 : :
26 : : #ifdef WIN32
27 : : #include <windows.h>
28 : : #include <wincrypt.h>
29 : : #else
30 : : #include <fcntl.h>
31 : : #include <sys/time.h>
32 : : #endif
33 : :
34 : : #if defined(HAVE_GETRANDOM) || (defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX))
35 : : #include <sys/random.h>
36 : : #endif
37 : :
38 : : #ifdef HAVE_SYSCTL_ARND
39 : : #include <sys/sysctl.h>
40 : : #endif
41 : : #if defined(HAVE_STRONG_GETAUXVAL) && defined(__aarch64__)
42 : : #include <sys/auxv.h>
43 : : #endif
44 : :
45 : 0 : [[noreturn]] static void RandFailure()
46 : : {
47 [ # # ][ # # ]: 0 : LogPrintf("Failed to read randomness, aborting\n");
[ # # ]
48 : 0 : std::abort();
49 : 0 : }
50 : :
51 : 61 : static inline int64_t GetPerformanceCounter() noexcept
52 : : {
53 : : // Read the hardware time stamp counter when available.
54 : : // See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information.
55 : : #if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
56 : : return __rdtsc();
57 : : #elif !defined(_MSC_VER) && defined(__i386__)
58 : : uint64_t r = 0;
59 : : __asm__ volatile ("rdtsc" : "=A"(r)); // Constrain the r variable to the eax:edx pair.
60 : : return r;
61 : : #elif !defined(_MSC_VER) && (defined(__x86_64__) || defined(__amd64__))
62 : : uint64_t r1 = 0, r2 = 0;
63 : : __asm__ volatile ("rdtsc" : "=a"(r1), "=d"(r2)); // Constrain r1 to rax and r2 to rdx.
64 : : return (r2 << 32) | r1;
65 : : #else
66 : : // Fall back to using standard library clock (usually microsecond or nanosecond precision)
67 [ + - ]: 61 : return std::chrono::high_resolution_clock::now().time_since_epoch().count();
68 : : #endif
69 : : }
70 : :
71 : : #ifdef HAVE_GETCPUID
72 : : static bool g_rdrand_supported = false;
73 : : static bool g_rdseed_supported = false;
74 : : static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000;
75 : : static constexpr uint32_t CPUID_F7_EBX_RDSEED = 0x00040000;
76 : : #ifdef bit_RDRND
77 : : static_assert(CPUID_F1_ECX_RDRAND == bit_RDRND, "Unexpected value for bit_RDRND");
78 : : #endif
79 : : #ifdef bit_RDSEED
80 : : static_assert(CPUID_F7_EBX_RDSEED == bit_RDSEED, "Unexpected value for bit_RDSEED");
81 : : #endif
82 : :
83 : : static void InitHardwareRand()
84 : : {
85 : : uint32_t eax, ebx, ecx, edx;
86 : : GetCPUID(1, 0, eax, ebx, ecx, edx);
87 : : if (ecx & CPUID_F1_ECX_RDRAND) {
88 : : g_rdrand_supported = true;
89 : : }
90 : : GetCPUID(7, 0, eax, ebx, ecx, edx);
91 : : if (ebx & CPUID_F7_EBX_RDSEED) {
92 : : g_rdseed_supported = true;
93 : : }
94 : : }
95 : :
96 : : static void ReportHardwareRand()
97 : : {
98 : : // This must be done in a separate function, as InitHardwareRand() may be indirectly called
99 : : // from global constructors, before logging is initialized.
100 : : if (g_rdseed_supported) {
101 : : LogPrintf("Using RdSeed as an additional entropy source\n");
102 : : }
103 : : if (g_rdrand_supported) {
104 : : LogPrintf("Using RdRand as an additional entropy source\n");
105 : : }
106 : : }
107 : :
108 : : /** Read 64 bits of entropy using rdrand.
109 : : *
110 : : * Must only be called when RdRand is supported.
111 : : */
112 : : static uint64_t GetRdRand() noexcept
113 : : {
114 : : // RdRand may very rarely fail. Invoke it up to 10 times in a loop to reduce this risk.
115 : : #ifdef __i386__
116 : : uint8_t ok;
117 : : // Initialize to 0 to silence a compiler warning that r1 or r2 may be used
118 : : // uninitialized. Even if rdrand fails (!ok) it will set the output to 0,
119 : : // but there is no way that the compiler could know that.
120 : : uint32_t r1 = 0, r2 = 0;
121 : : for (int i = 0; i < 10; ++i) {
122 : : __asm__ volatile (".byte 0x0f, 0xc7, 0xf0; setc %1" : "=a"(r1), "=q"(ok) :: "cc"); // rdrand %eax
123 : : if (ok) break;
124 : : }
125 : : for (int i = 0; i < 10; ++i) {
126 : : __asm__ volatile (".byte 0x0f, 0xc7, 0xf0; setc %1" : "=a"(r2), "=q"(ok) :: "cc"); // rdrand %eax
127 : : if (ok) break;
128 : : }
129 : : return (((uint64_t)r2) << 32) | r1;
130 : : #elif defined(__x86_64__) || defined(__amd64__)
131 : : uint8_t ok;
132 : : uint64_t r1 = 0; // See above why we initialize to 0.
133 : : for (int i = 0; i < 10; ++i) {
134 : : __asm__ volatile (".byte 0x48, 0x0f, 0xc7, 0xf0; setc %1" : "=a"(r1), "=q"(ok) :: "cc"); // rdrand %rax
135 : : if (ok) break;
136 : : }
137 : : return r1;
138 : : #else
139 : : #error "RdRand is only supported on x86 and x86_64"
140 : : #endif
141 : : }
142 : :
143 : : /** Read 64 bits of entropy using rdseed.
144 : : *
145 : : * Must only be called when RdSeed is supported.
146 : : */
147 : : static uint64_t GetRdSeed() noexcept
148 : : {
149 : : // RdSeed may fail when the HW RNG is overloaded. Loop indefinitely until enough entropy is gathered,
150 : : // but pause after every failure.
151 : : #ifdef __i386__
152 : : uint8_t ok;
153 : : uint32_t r1, r2;
154 : : do {
155 : : __asm__ volatile (".byte 0x0f, 0xc7, 0xf8; setc %1" : "=a"(r1), "=q"(ok) :: "cc"); // rdseed %eax
156 : : if (ok) break;
157 : : __asm__ volatile ("pause");
158 : : } while(true);
159 : : do {
160 : : __asm__ volatile (".byte 0x0f, 0xc7, 0xf8; setc %1" : "=a"(r2), "=q"(ok) :: "cc"); // rdseed %eax
161 : : if (ok) break;
162 : : __asm__ volatile ("pause");
163 : : } while(true);
164 : : return (((uint64_t)r2) << 32) | r1;
165 : : #elif defined(__x86_64__) || defined(__amd64__)
166 : : uint8_t ok;
167 : : uint64_t r1;
168 : : do {
169 : : __asm__ volatile (".byte 0x48, 0x0f, 0xc7, 0xf8; setc %1" : "=a"(r1), "=q"(ok) :: "cc"); // rdseed %rax
170 : : if (ok) break;
171 : : __asm__ volatile ("pause");
172 : : } while(true);
173 : : return r1;
174 : : #else
175 : : #error "RdSeed is only supported on x86 and x86_64"
176 : : #endif
177 : : }
178 : :
179 : : #elif defined(__aarch64__) && defined(HWCAP2_RNG)
180 : :
181 : : static bool g_rndr_supported = false;
182 : :
183 : 2 : static void InitHardwareRand()
184 : : {
185 [ + - ]: 2 : if (getauxval(AT_HWCAP2) & HWCAP2_RNG) {
186 : 0 : g_rndr_supported = true;
187 : 0 : }
188 : 2 : }
189 : :
190 : 0 : static void ReportHardwareRand()
191 : : {
192 : : // This must be done in a separate function, as InitHardwareRand() may be indirectly called
193 : : // from global constructors, before logging is initialized.
194 [ # # ]: 0 : if (g_rndr_supported) {
195 [ # # ][ # # ]: 0 : LogPrintf("Using RNDR and RNDRRS as additional entropy sources\n");
[ # # ]
196 : 0 : }
197 : 0 : }
198 : :
199 : : /** Read 64 bits of entropy using rndr.
200 : : *
201 : : * Must only be called when RNDR is supported.
202 : : */
203 : 0 : static uint64_t GetRNDR() noexcept
204 : : {
205 : : uint8_t ok;
206 : : uint64_t r1;
207 : 0 : do {
208 : : // https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/RNDR--Random-Number
209 : 0 : __asm__ volatile("mrs %0, s3_3_c2_c4_0; cset %w1, ne;"
210 : : : "=r"(r1), "=r"(ok)::"cc");
211 [ # # ]: 0 : if (ok) break;
212 : 0 : __asm__ volatile("yield");
213 [ # # ]: 0 : } while (true);
214 : 0 : return r1;
215 : : }
216 : :
217 : : /** Read 64 bits of entropy using rndrrs.
218 : : *
219 : : * Must only be called when RNDRRS is supported.
220 : : */
221 : 0 : static uint64_t GetRNDRRS() noexcept
222 : : {
223 : : uint8_t ok;
224 : : uint64_t r1;
225 : 0 : do {
226 : : // https://developer.arm.com/documentation/ddi0601/2022-12/AArch64-Registers/RNDRRS--Reseeded-Random-Number
227 : 0 : __asm__ volatile("mrs %0, s3_3_c2_c4_1; cset %w1, ne;"
228 : : : "=r"(r1), "=r"(ok)::"cc");
229 [ # # ]: 0 : if (ok) break;
230 : 0 : __asm__ volatile("yield");
231 [ # # ]: 0 : } while (true);
232 : 0 : return r1;
233 : : }
234 : :
235 : : #else
236 : : /* Access to other hardware random number generators could be added here later,
237 : : * assuming it is sufficiently fast (in the order of a few hundred CPU cycles).
238 : : * Slower sources should probably be invoked separately, and/or only from
239 : : * RandAddPeriodic (which is called once a minute).
240 : : */
241 : : static void InitHardwareRand() {}
242 : : static void ReportHardwareRand() {}
243 : : #endif
244 : :
245 : : /** Add 64 bits of entropy gathered from hardware to hasher. Do nothing if not supported. */
246 : 5 : static void SeedHardwareFast(CSHA512& hasher) noexcept {
247 : : #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
248 : : if (g_rdrand_supported) {
249 : : uint64_t out = GetRdRand();
250 : : hasher.Write((const unsigned char*)&out, sizeof(out));
251 : : return;
252 : : }
253 : : #elif defined(__aarch64__) && defined(HWCAP2_RNG)
254 [ + - ]: 5 : if (g_rndr_supported) {
255 : 0 : uint64_t out = GetRNDR();
256 [ # # ]: 0 : hasher.Write((const unsigned char*)&out, sizeof(out));
257 : 0 : return;
258 : : }
259 : : #endif
260 : 5 : }
261 : :
262 : : /** Add 256 bits of entropy gathered from hardware to hasher. Do nothing if not supported. */
263 : 2 : static void SeedHardwareSlow(CSHA512& hasher) noexcept {
264 : : #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
265 : : // When we want 256 bits of entropy, prefer RdSeed over RdRand, as it's
266 : : // guaranteed to produce independent randomness on every call.
267 : : if (g_rdseed_supported) {
268 : : for (int i = 0; i < 4; ++i) {
269 : : uint64_t out = GetRdSeed();
270 : : hasher.Write((const unsigned char*)&out, sizeof(out));
271 : : }
272 : : return;
273 : : }
274 : : // When falling back to RdRand, XOR the result of 1024 results.
275 : : // This guarantees a reseeding occurs between each.
276 : : if (g_rdrand_supported) {
277 : : for (int i = 0; i < 4; ++i) {
278 : : uint64_t out = 0;
279 : : for (int j = 0; j < 1024; ++j) out ^= GetRdRand();
280 : : hasher.Write((const unsigned char*)&out, sizeof(out));
281 : : }
282 : : return;
283 : : }
284 : : #elif defined(__aarch64__) && defined(HWCAP2_RNG)
285 [ + - ]: 2 : if (g_rndr_supported) {
286 [ # # ]: 0 : for (int i = 0; i < 4; ++i) {
287 : 0 : uint64_t out = GetRNDRRS();
288 [ # # ]: 0 : hasher.Write((const unsigned char*)&out, sizeof(out));
289 : 0 : }
290 : 0 : return;
291 : : }
292 : : #endif
293 : 2 : }
294 : :
295 : : /** Use repeated SHA512 to strengthen the randomness in seed32, and feed into hasher. */
296 : 2 : static void Strengthen(const unsigned char (&seed)[32], SteadyClock::duration dur, CSHA512& hasher) noexcept
297 : : {
298 [ + - ]: 2 : CSHA512 inner_hasher;
299 [ + - ]: 2 : inner_hasher.Write(seed, sizeof(seed));
300 : :
301 : : // Hash loop
302 : : unsigned char buffer[64];
303 [ + - ]: 2 : const auto stop{SteadyClock::now() + dur};
304 : 2 : do {
305 [ + + ]: 54054 : for (int i = 0; i < 1000; ++i) {
306 [ + - ]: 54000 : inner_hasher.Finalize(buffer);
307 [ + - ]: 54000 : inner_hasher.Reset();
308 [ + - ]: 54000 : inner_hasher.Write(buffer, sizeof(buffer));
309 : 54000 : }
310 : : // Benchmark operation and feed it into outer hasher.
311 : 54 : int64_t perf = GetPerformanceCounter();
312 [ + - ]: 54 : hasher.Write((const unsigned char*)&perf, sizeof(perf));
313 [ + - ][ + + ]: 54 : } while (SteadyClock::now() < stop);
314 : :
315 : : // Produce output from inner state and feed it to outer hasher.
316 [ + - ]: 2 : inner_hasher.Finalize(buffer);
317 [ + - ]: 2 : hasher.Write(buffer, sizeof(buffer));
318 : : // Try to clean up.
319 [ + - ]: 2 : inner_hasher.Reset();
320 [ + - ]: 2 : memory_cleanse(buffer, sizeof(buffer));
321 : 2 : }
322 : :
323 : : #ifndef WIN32
324 : : /** Fallback: get 32 bytes of system entropy from /dev/urandom. The most
325 : : * compatible way to get cryptographic randomness on UNIX-ish platforms.
326 : : */
327 : : [[maybe_unused]] static void GetDevURandom(unsigned char *ent32)
328 : : {
329 : : int f = open("/dev/urandom", O_RDONLY);
330 : : if (f == -1) {
331 : : RandFailure();
332 : : }
333 : : int have = 0;
334 : : do {
335 : : ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);
336 : : if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {
337 : : close(f);
338 : : RandFailure();
339 : : }
340 : : have += n;
341 : : } while (have < NUM_OS_RANDOM_BYTES);
342 : : close(f);
343 : : }
344 : : #endif
345 : :
346 : : /** Get 32 bytes of system entropy. */
347 : 2 : void GetOSRand(unsigned char *ent32)
348 : : {
349 : : #if defined(WIN32)
350 : : HCRYPTPROV hProvider;
351 : : int ret = CryptAcquireContextW(&hProvider, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
352 : : if (!ret) {
353 : : RandFailure();
354 : : }
355 : : ret = CryptGenRandom(hProvider, NUM_OS_RANDOM_BYTES, ent32);
356 : : if (!ret) {
357 : : RandFailure();
358 : : }
359 : : CryptReleaseContext(hProvider, 0);
360 : : #elif defined(HAVE_GETRANDOM)
361 : : /* Linux. From the getrandom(2) man page:
362 : : * "If the urandom source has been initialized, reads of up to 256 bytes
363 : : * will always return as many bytes as requested and will not be
364 : : * interrupted by signals."
365 : : */
366 [ - + ]: 2 : if (getrandom(ent32, NUM_OS_RANDOM_BYTES, 0) != NUM_OS_RANDOM_BYTES) {
367 : 0 : RandFailure();
368 : : }
369 : : #elif defined(__OpenBSD__)
370 : : /* OpenBSD. From the arc4random(3) man page:
371 : : "Use of these functions is encouraged for almost all random number
372 : : consumption because the other interfaces are deficient in either
373 : : quality, portability, standardization, or availability."
374 : : The function call is always successful.
375 : : */
376 : : arc4random_buf(ent32, NUM_OS_RANDOM_BYTES);
377 : : #elif defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
378 : : if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
379 : : RandFailure();
380 : : }
381 : : #elif defined(HAVE_SYSCTL_ARND)
382 : : /* FreeBSD, NetBSD and similar. It is possible for the call to return less
383 : : * bytes than requested, so need to read in a loop.
384 : : */
385 : : static int name[2] = {CTL_KERN, KERN_ARND};
386 : : int have = 0;
387 : : do {
388 : : size_t len = NUM_OS_RANDOM_BYTES - have;
389 : : if (sysctl(name, std::size(name), ent32 + have, &len, nullptr, 0) != 0) {
390 : : RandFailure();
391 : : }
392 : : have += len;
393 : : } while (have < NUM_OS_RANDOM_BYTES);
394 : : #else
395 : : /* Fall back to /dev/urandom if there is no specific method implemented to
396 : : * get system entropy for this OS.
397 : : */
398 : : GetDevURandom(ent32);
399 : : #endif
400 : 2 : }
401 : :
402 : : namespace {
403 : :
404 : : class RNGState {
405 : : Mutex m_mutex;
406 : : /* The RNG state consists of 256 bits of entropy, taken from the output of
407 : : * one operation's SHA512 output, and fed as input to the next one.
408 : : * Carrying 256 bits of entropy should be sufficient to guarantee
409 : : * unpredictability as long as any entropy source was ever unpredictable
410 : : * to an attacker. To protect against situations where an attacker might
411 : : * observe the RNG's state, fresh entropy is always mixed when
412 : : * GetStrongRandBytes is called.
413 : : */
414 : 2 : unsigned char m_state[32] GUARDED_BY(m_mutex) = {0};
415 : 2 : uint64_t m_counter GUARDED_BY(m_mutex) = 0;
416 : 2 : bool m_strongly_seeded GUARDED_BY(m_mutex) = false;
417 : :
418 : : Mutex m_events_mutex;
419 : : CSHA256 m_events_hasher GUARDED_BY(m_events_mutex);
420 : :
421 : : public:
422 [ + - ]: 4 : RNGState() noexcept
423 : : {
424 [ + - ]: 2 : InitHardwareRand();
425 : 2 : }
426 : :
427 : 2 : ~RNGState() = default;
428 : :
429 : 0 : void AddEvent(uint32_t event_info) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_events_mutex)
430 : : {
431 [ # # ]: 0 : LOCK(m_events_mutex);
432 : :
433 [ # # ]: 0 : m_events_hasher.Write((const unsigned char *)&event_info, sizeof(event_info));
434 : : // Get the low four bytes of the performance counter. This translates to roughly the
435 : : // subsecond part.
436 : 0 : uint32_t perfcounter = (GetPerformanceCounter() & 0xffffffff);
437 [ # # ]: 0 : m_events_hasher.Write((const unsigned char*)&perfcounter, sizeof(perfcounter));
438 : 0 : }
439 : :
440 : : /**
441 : : * Feed (the hash of) all events added through AddEvent() to hasher.
442 : : */
443 : 2 : void SeedEvents(CSHA512& hasher) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_events_mutex)
444 : : {
445 : : // We use only SHA256 for the events hashing to get the ASM speedups we have for SHA256,
446 : : // since we want it to be fast as network peers may be able to trigger it repeatedly.
447 [ + - ][ + - ]: 2 : LOCK(m_events_mutex);
448 : :
449 : : unsigned char events_hash[32];
450 [ + - ]: 2 : m_events_hasher.Finalize(events_hash);
451 [ + - ]: 2 : hasher.Write(events_hash, 32);
452 : :
453 : : // Re-initialize the hasher with the finalized state to use later.
454 [ + - ]: 2 : m_events_hasher.Reset();
455 [ + - ]: 2 : m_events_hasher.Write(events_hash, 32);
456 : 2 : }
457 : :
458 : : /** Extract up to 32 bytes of entropy from the RNG state, mixing in new entropy from hasher.
459 : : *
460 : : * If this function has never been called with strong_seed = true, false is returned.
461 : : */
462 : 7 : bool MixExtract(unsigned char* out, size_t num, CSHA512&& hasher, bool strong_seed) noexcept EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
463 : : {
464 [ + - ]: 7 : assert(num <= 32);
465 : : unsigned char buf[64];
466 : : static_assert(sizeof(buf) == CSHA512::OUTPUT_SIZE, "Buffer needs to have hasher's output size");
467 : : bool ret;
468 : : {
469 [ + - ]: 7 : LOCK(m_mutex);
470 : 7 : ret = (m_strongly_seeded |= strong_seed);
471 : : // Write the current state of the RNG into the hasher
472 [ + - ]: 7 : hasher.Write(m_state, 32);
473 : : // Write a new counter number into the state
474 [ + - ]: 7 : hasher.Write((const unsigned char*)&m_counter, sizeof(m_counter));
475 : 7 : ++m_counter;
476 : : // Finalize the hasher
477 [ + - ]: 7 : hasher.Finalize(buf);
478 : : // Store the last 32 bytes of the hash output as new RNG state.
479 : 7 : memcpy(m_state, buf + 32, 32);
480 : 7 : }
481 : : // If desired, copy (up to) the first 32 bytes of the hash output as output.
482 [ - + ]: 7 : if (num) {
483 [ - + ]: 7 : assert(out != nullptr);
484 : 7 : memcpy(out, buf, num);
485 : 7 : }
486 : : // Best effort cleanup of internal state
487 [ + - ]: 7 : hasher.Reset();
488 [ + - ]: 7 : memory_cleanse(buf, 64);
489 : 7 : return ret;
490 : : }
491 : : };
492 : :
493 : 3 : RNGState& GetRNGState() noexcept
494 : : {
495 : : // This idiom relies on the guarantee that static variable are initialized
496 : : // on first call, even when multiple parallel calls are permitted.
497 [ + + ][ - + ]: 3 : static std::vector<RNGState, secure_allocator<RNGState>> g_rng(1);
[ + - ]
498 : 3 : return g_rng[0];
499 : : }
500 : : }
501 : :
502 : : /* A note on the use of noexcept in the seeding functions below:
503 : : *
504 : : * None of the RNG code should ever throw any exception.
505 : : */
506 : :
507 : 7 : static void SeedTimestamp(CSHA512& hasher) noexcept
508 : : {
509 : 7 : int64_t perfcounter = GetPerformanceCounter();
510 [ + - ]: 7 : hasher.Write((const unsigned char*)&perfcounter, sizeof(perfcounter));
511 : 7 : }
512 : :
513 : 5 : static void SeedFast(CSHA512& hasher) noexcept
514 : : {
515 : : unsigned char buffer[32];
516 : :
517 : : // Stack pointer to indirectly commit to thread/callstack
518 : 5 : const unsigned char* ptr = buffer;
519 [ + - ]: 5 : hasher.Write((const unsigned char*)&ptr, sizeof(ptr));
520 : :
521 : : // Hardware randomness is very fast when available; use it always.
522 : 5 : SeedHardwareFast(hasher);
523 : :
524 : : // High-precision timestamp
525 : 5 : SeedTimestamp(hasher);
526 : 5 : }
527 : :
528 : 2 : static void SeedSlow(CSHA512& hasher, RNGState& rng) noexcept
529 : : {
530 : : unsigned char buffer[32];
531 : :
532 : : // Everything that the 'fast' seeder includes
533 : 2 : SeedFast(hasher);
534 : :
535 : : // OS randomness
536 [ + - ]: 2 : GetOSRand(buffer);
537 [ + - ]: 2 : hasher.Write(buffer, sizeof(buffer));
538 : :
539 : : // Add the events hasher into the mix
540 : 2 : rng.SeedEvents(hasher);
541 : :
542 : : // High-precision timestamp.
543 : : //
544 : : // Note that we also commit to a timestamp in the Fast seeder, so we indirectly commit to a
545 : : // benchmark of all the entropy gathering sources in this function).
546 : 2 : SeedTimestamp(hasher);
547 : 2 : }
548 : :
549 : : /** Extract entropy from rng, strengthen it, and feed it into hasher. */
550 : 2 : static void SeedStrengthen(CSHA512& hasher, RNGState& rng, SteadyClock::duration dur) noexcept
551 : : {
552 : : // Generate 32 bytes of entropy from the RNG, and a copy of the entropy already in hasher.
553 : : unsigned char strengthen_seed[32];
554 : 2 : rng.MixExtract(strengthen_seed, sizeof(strengthen_seed), CSHA512(hasher), false);
555 : : // Strengthen the seed, and feed it into hasher.
556 : 2 : Strengthen(strengthen_seed, dur, hasher);
557 : 2 : }
558 : :
559 : 0 : static void SeedPeriodic(CSHA512& hasher, RNGState& rng) noexcept
560 : : {
561 : : // Everything that the 'fast' seeder includes
562 : 0 : SeedFast(hasher);
563 : :
564 : : // High-precision timestamp
565 : 0 : SeedTimestamp(hasher);
566 : :
567 : : // Add the events hasher into the mix
568 : 0 : rng.SeedEvents(hasher);
569 : :
570 : : // Dynamic environment data (performance monitoring, ...)
571 [ # # ]: 0 : auto old_size = hasher.Size();
572 [ # # ]: 0 : RandAddDynamicEnv(hasher);
573 [ # # ][ # # ]: 0 : LogPrint(BCLog::RAND, "Feeding %i bytes of dynamic environment data into RNG\n", hasher.Size() - old_size);
[ # # ][ # # ]
[ # # ][ # # ]
574 : :
575 : : // Strengthen for 10 ms
576 [ # # ][ # # ]: 0 : SeedStrengthen(hasher, rng, 10ms);
577 : 0 : }
578 : :
579 : 2 : static void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept
580 : : {
581 : : // Gather 256 bits of hardware randomness, if available
582 : 2 : SeedHardwareSlow(hasher);
583 : :
584 : : // Everything that the 'slow' seeder includes.
585 : 2 : SeedSlow(hasher, rng);
586 : :
587 : : // Dynamic environment data (performance monitoring, ...)
588 : 2 : auto old_size = hasher.Size();
589 [ + - ]: 2 : RandAddDynamicEnv(hasher);
590 : :
591 : : // Static environment data
592 [ + - ]: 2 : RandAddStaticEnv(hasher);
593 [ + - ][ - + ]: 2 : LogPrint(BCLog::RAND, "Feeding %i bytes of environment data into RNG\n", hasher.Size() - old_size);
[ # # ][ # # ]
[ # # ]
594 : :
595 : : // Strengthen for 100 ms
596 [ + - ][ + - ]: 2 : SeedStrengthen(hasher, rng, 100ms);
597 : 2 : }
598 : :
599 : : enum class RNGLevel {
600 : : FAST, //!< Automatically called by GetRandBytes
601 : : SLOW, //!< Automatically called by GetStrongRandBytes
602 : : PERIODIC, //!< Called by RandAddPeriodic()
603 : : };
604 : :
605 : 3 : static void ProcRand(unsigned char* out, int num, RNGLevel level) noexcept
606 : : {
607 : : // Make sure the RNG is initialized first (as all Seed* function possibly need hwrand to be available).
608 : 3 : RNGState& rng = GetRNGState();
609 : :
610 [ + - ]: 3 : assert(num <= 32);
611 : :
612 [ + - ]: 3 : CSHA512 hasher;
613 [ - + - - ]: 3 : switch (level) {
614 : : case RNGLevel::FAST:
615 : 3 : SeedFast(hasher);
616 : 3 : break;
617 : : case RNGLevel::SLOW:
618 : 0 : SeedSlow(hasher, rng);
619 : 0 : break;
620 : : case RNGLevel::PERIODIC:
621 : 0 : SeedPeriodic(hasher, rng);
622 : 0 : break;
623 : : }
624 : :
625 : : // Combine with and update state
626 [ + + ]: 3 : if (!rng.MixExtract(out, num, std::move(hasher), false)) {
627 : : // On the first invocation, also seed with SeedStartup().
628 [ + - ]: 2 : CSHA512 startup_hasher;
629 : 2 : SeedStartup(startup_hasher, rng);
630 : 2 : rng.MixExtract(out, num, std::move(startup_hasher), true);
631 : 2 : }
632 : 3 : }
633 : :
634 : 3 : void GetRandBytes(Span<unsigned char> bytes) noexcept { ProcRand(bytes.data(), bytes.size(), RNGLevel::FAST); }
635 : 0 : void GetStrongRandBytes(Span<unsigned char> bytes) noexcept { ProcRand(bytes.data(), bytes.size(), RNGLevel::SLOW); }
636 : 0 : void RandAddPeriodic() noexcept { ProcRand(nullptr, 0, RNGLevel::PERIODIC); }
637 : 0 : void RandAddEvent(const uint32_t event_info) noexcept { GetRNGState().AddEvent(event_info); }
638 : :
639 : : bool g_mock_deterministic_tests{false};
640 : :
641 : 0 : uint64_t GetRandInternal(uint64_t nMax) noexcept
642 : : {
643 : 0 : return FastRandomContext(g_mock_deterministic_tests).randrange(nMax);
644 : : }
645 : :
646 : 2 : uint256 GetRandHash() noexcept
647 : : {
648 [ + - ]: 2 : uint256 hash;
649 [ + - ]: 2 : GetRandBytes(hash);
650 : 2 : return hash;
651 : : }
652 : :
653 : 0 : void FastRandomContext::RandomSeed()
654 : : {
655 : 0 : uint256 seed = GetRandHash();
656 : 0 : rng.SetKey(MakeByteSpan(seed));
657 : 0 : requires_seed = false;
658 : 0 : }
659 : :
660 : 0 : uint256 FastRandomContext::rand256() noexcept
661 : : {
662 [ # # ]: 0 : if (requires_seed) RandomSeed();
663 [ # # ]: 0 : uint256 ret;
664 : 0 : rng.Keystream(MakeWritableByteSpan(ret));
665 : 0 : return ret;
666 : : }
667 : :
668 : : template <typename B>
669 : 0 : std::vector<B> FastRandomContext::randbytes(size_t len)
670 : : {
671 [ # # ][ # # ]: 0 : std::vector<B> ret(len);
672 [ # # ][ # # ]: 0 : fillrand(MakeWritableByteSpan(ret));
673 : 0 : return ret;
674 [ # # ][ # # ]: 0 : }
675 : : template std::vector<unsigned char> FastRandomContext::randbytes(size_t);
676 : : template std::vector<std::byte> FastRandomContext::randbytes(size_t);
677 : :
678 : 0 : void FastRandomContext::fillrand(Span<std::byte> output)
679 : : {
680 [ # # ]: 0 : if (requires_seed) RandomSeed();
681 : 0 : rng.Keystream(output);
682 : 0 : }
683 : :
684 : 0 : FastRandomContext::FastRandomContext(const uint256& seed) noexcept : requires_seed(false), rng(MakeByteSpan(seed)), bitbuf_size(0) {}
685 : :
686 : 0 : bool Random_SanityCheck()
687 : : {
688 : 0 : uint64_t start = GetPerformanceCounter();
689 : :
690 : : /* This does not measure the quality of randomness, but it does test that
691 : : * GetOSRand() overwrites all 32 bytes of the output given a maximum
692 : : * number of tries.
693 : : */
694 : : static constexpr int MAX_TRIES{1024};
695 : : uint8_t data[NUM_OS_RANDOM_BYTES];
696 : 0 : bool overwritten[NUM_OS_RANDOM_BYTES] = {}; /* Tracks which bytes have been overwritten at least once */
697 : : int num_overwritten;
698 : 0 : int tries = 0;
699 : : /* Loop until all bytes have been overwritten at least once, or max number tries reached */
700 : 0 : do {
701 : 0 : memset(data, 0, NUM_OS_RANDOM_BYTES);
702 : 0 : GetOSRand(data);
703 [ # # ]: 0 : for (int x=0; x < NUM_OS_RANDOM_BYTES; ++x) {
704 : 0 : overwritten[x] |= (data[x] != 0);
705 : 0 : }
706 : :
707 : 0 : num_overwritten = 0;
708 [ # # ]: 0 : for (int x=0; x < NUM_OS_RANDOM_BYTES; ++x) {
709 [ # # ]: 0 : if (overwritten[x]) {
710 : 0 : num_overwritten += 1;
711 : 0 : }
712 : 0 : }
713 : :
714 : 0 : tries += 1;
715 [ # # ][ # # ]: 0 : } while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES);
716 [ # # ]: 0 : if (num_overwritten != NUM_OS_RANDOM_BYTES) return false; /* If this failed, bailed out after too many tries */
717 : :
718 : : // Check that GetPerformanceCounter increases at least during a GetOSRand() call + 1ms sleep.
719 : 0 : std::this_thread::sleep_for(std::chrono::milliseconds(1));
720 : 0 : uint64_t stop = GetPerformanceCounter();
721 [ # # ]: 0 : if (stop == start) return false;
722 : :
723 : : // We called GetPerformanceCounter. Use it as entropy.
724 : 0 : CSHA512 to_add;
725 : 0 : to_add.Write((const unsigned char*)&start, sizeof(start));
726 : 0 : to_add.Write((const unsigned char*)&stop, sizeof(stop));
727 : 0 : GetRNGState().MixExtract(nullptr, 0, std::move(to_add), false);
728 : :
729 : 0 : return true;
730 : 0 : }
731 : :
732 : : static constexpr std::array<std::byte, ChaCha20::KEYLEN> ZERO_KEY{};
733 : :
734 [ + - ]: 4 : FastRandomContext::FastRandomContext(bool fDeterministic) noexcept : requires_seed(!fDeterministic), rng(ZERO_KEY), bitbuf_size(0)
735 : : {
736 : : // Note that despite always initializing with ZERO_KEY, requires_seed is set to true if not
737 : : // fDeterministic. That means the rng will be reinitialized with a secure random key upon first
738 : : // use.
739 : 4 : }
740 : :
741 : 0 : FastRandomContext& FastRandomContext::operator=(FastRandomContext&& from) noexcept
742 : : {
743 : 0 : requires_seed = from.requires_seed;
744 : 0 : rng = from.rng;
745 : 0 : bitbuf = from.bitbuf;
746 : 0 : bitbuf_size = from.bitbuf_size;
747 : 0 : from.requires_seed = true;
748 : 0 : from.bitbuf_size = 0;
749 : 0 : return *this;
750 : : }
751 : :
752 : 0 : void RandomInit()
753 : : {
754 : : // Invoke RNG code to trigger initialization (if not already performed)
755 : 0 : ProcRand(nullptr, 0, RNGLevel::FAST);
756 : :
757 : 0 : ReportHardwareRand();
758 : 0 : }
759 : :
760 : 0 : std::chrono::microseconds GetExponentialRand(std::chrono::microseconds now, std::chrono::seconds average_interval)
761 : : {
762 : 0 : double unscaled = -std::log1p(GetRand(uint64_t{1} << 48) * -0.0000000000000035527136788 /* -1/2^48 */);
763 : 0 : return now + std::chrono::duration_cast<std::chrono::microseconds>(unscaled * average_interval + 0.5us);
764 : : }
|