LCOV - code coverage report
Current view: top level - src - random.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 209 228 91.7 %
Date: 2026-06-25 07:23:43 Functions: 41 44 93.2 %

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

Generated by: LCOV version 1.16