LCOV - code coverage report
Current view: top level - src - random.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 241 273 88.3 %
Date: 2025-02-23 09:33:43 Functions: 35 38 92.1 %

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

Generated by: LCOV version 1.14