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