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