LCOV - code coverage report
Current view: top level - src - random.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 192 255 75.3 %
Date: 2023-10-05 12:38:51 Functions: 34 41 82.9 %
Branches: 84 224 37.5 %

           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                 :            : }

Generated by: LCOV version 1.14