commit 2c91330dd68064e402e8eceea3df9474bb7afd48
Author: Pieter Wuille
Date: Mon Mar 11 14:10:44 2024 -0400
random: cleanup order, comments, static
diff --git a/src/random.cpp b/src/random.cpp
index cb5c127e0d..21a08c7fd3 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -45,13 +45,23 @@
#include
#endif
-[[noreturn]] static void RandFailure()
+namespace {
+
+/* Number of random bytes returned by GetOSRand.
+ * When changing this constant make sure to change all call sites, and make
+ * sure that the underlying OS APIs for all platforms support the number.
+ * (many cap out at 256 bytes).
+ */
+static const int NUM_OS_RANDOM_BYTES = 32;
+
+
+[[noreturn]] void RandFailure()
{
LogPrintf("Failed to read randomness, aborting\n");
std::abort();
}
-static inline int64_t GetPerformanceCounter() noexcept
+inline int64_t GetPerformanceCounter() noexcept
{
// Read the hardware time stamp counter when available.
// See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information.
@@ -72,10 +82,10 @@ static inline int64_t GetPerformanceCounter() noexcept
}
#ifdef HAVE_GETCPUID
-static bool g_rdrand_supported = false;
-static bool g_rdseed_supported = false;
-static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000;
-static constexpr uint32_t CPUID_F7_EBX_RDSEED = 0x00040000;
+bool g_rdrand_supported = false;
+bool g_rdseed_supported = false;
+constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000;
+constexpr uint32_t CPUID_F7_EBX_RDSEED = 0x00040000;
#ifdef bit_RDRND
static_assert(CPUID_F1_ECX_RDRAND == bit_RDRND, "Unexpected value for bit_RDRND");
#endif
@@ -83,7 +93,7 @@ static_assert(CPUID_F1_ECX_RDRAND == bit_RDRND, "Unexpected value for bit_RDRND"
static_assert(CPUID_F7_EBX_RDSEED == bit_RDSEED, "Unexpected value for bit_RDSEED");
#endif
-static void InitHardwareRand()
+void InitHardwareRand()
{
uint32_t eax, ebx, ecx, edx;
GetCPUID(1, 0, eax, ebx, ecx, edx);
@@ -96,7 +106,7 @@ static void InitHardwareRand()
}
}
-static void ReportHardwareRand()
+void ReportHardwareRand()
{
// This must be done in a separate function, as InitHardwareRand() may be indirectly called
// from global constructors, before logging is initialized.
@@ -112,7 +122,7 @@ static void ReportHardwareRand()
*
* Must only be called when RdRand is supported.
*/
-static uint64_t GetRdRand() noexcept
+uint64_t GetRdRand() noexcept
{
// RdRand may very rarely fail. Invoke it up to 10 times in a loop to reduce this risk.
#ifdef __i386__
@@ -147,7 +157,7 @@ static uint64_t GetRdRand() noexcept
*
* Must only be called when RdSeed is supported.
*/
-static uint64_t GetRdSeed() noexcept
+uint64_t GetRdSeed() noexcept
{
// RdSeed may fail when the HW RNG is overloaded. Loop indefinitely until enough entropy is gathered,
// but pause after every failure.
@@ -181,16 +191,16 @@ static uint64_t GetRdSeed() noexcept
#elif defined(__aarch64__) && defined(HWCAP2_RNG)
-static bool g_rndr_supported = false;
+bool g_rndr_supported = false;
-static void InitHardwareRand()
+void InitHardwareRand()
{
if (getauxval(AT_HWCAP2) & HWCAP2_RNG) {
g_rndr_supported = true;
}
}
-static void ReportHardwareRand()
+void ReportHardwareRand()
{
// This must be done in a separate function, as InitHardwareRand() may be indirectly called
// from global constructors, before logging is initialized.
@@ -203,7 +213,7 @@ static void ReportHardwareRand()
*
* Must only be called when RNDR is supported.
*/
-static uint64_t GetRNDR() noexcept
+uint64_t GetRNDR() noexcept
{
uint8_t ok;
uint64_t r1;
@@ -221,7 +231,7 @@ static uint64_t GetRNDR() noexcept
*
* Must only be called when RNDRRS is supported.
*/
-static uint64_t GetRNDRRS() noexcept
+uint64_t GetRNDRRS() noexcept
{
uint8_t ok;
uint64_t r1;
@@ -241,12 +251,12 @@ static uint64_t GetRNDRRS() noexcept
* Slower sources should probably be invoked separately, and/or only from
* RandAddPeriodic (which is called once a minute).
*/
-static void InitHardwareRand() {}
-static void ReportHardwareRand() {}
+void InitHardwareRand() {}
+void ReportHardwareRand() {}
#endif
/** Add 64 bits of entropy gathered from hardware to hasher. Do nothing if not supported. */
-static void SeedHardwareFast(CSHA512& hasher) noexcept {
+void SeedHardwareFast(CSHA512& hasher) noexcept {
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
if (g_rdrand_supported) {
uint64_t out = GetRdRand();
@@ -263,7 +273,7 @@ static void SeedHardwareFast(CSHA512& hasher) noexcept {
}
/** Add 256 bits of entropy gathered from hardware to hasher. Do nothing if not supported. */
-static void SeedHardwareSlow(CSHA512& hasher) noexcept {
+void SeedHardwareSlow(CSHA512& hasher) noexcept {
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
// When we want 256 bits of entropy, prefer RdSeed over RdRand, as it's
// guaranteed to produce independent randomness on every call.
@@ -296,7 +306,7 @@ static void SeedHardwareSlow(CSHA512& hasher) noexcept {
}
/** Use repeated SHA512 to strengthen the randomness in seed32, and feed into hasher. */
-static void Strengthen(const unsigned char (&seed)[32], SteadyClock::duration dur, CSHA512& hasher) noexcept
+void Strengthen(const unsigned char (&seed)[32], SteadyClock::duration dur, CSHA512& hasher) noexcept
{
CSHA512 inner_hasher;
inner_hasher.Write(seed, sizeof(seed));
@@ -327,7 +337,7 @@ static void Strengthen(const unsigned char (&seed)[32], SteadyClock::duration du
/** Fallback: get 32 bytes of system entropy from /dev/urandom. The most
* compatible way to get cryptographic randomness on UNIX-ish platforms.
*/
-[[maybe_unused]] static void GetDevURandom(unsigned char *ent32)
+[[maybe_unused]] void GetDevURandom(unsigned char *ent32)
{
int f = open("/dev/urandom", O_RDONLY);
if (f == -1) {
@@ -402,8 +412,6 @@ void GetOSRand(unsigned char *ent32)
#endif
}
-namespace {
-
class RNGState {
Mutex m_mutex;
/* The RNG state consists of 256 bits of entropy, taken from the output of
@@ -521,20 +529,19 @@ RNGState& GetRNGState() noexcept
static std::vector> g_rng(1);
return g_rng[0];
}
-}
/* A note on the use of noexcept in the seeding functions below:
*
* None of the RNG code should ever throw any exception.
*/
-static void SeedTimestamp(CSHA512& hasher) noexcept
+void SeedTimestamp(CSHA512& hasher) noexcept
{
int64_t perfcounter = GetPerformanceCounter();
hasher.Write((const unsigned char*)&perfcounter, sizeof(perfcounter));
}
-static void SeedFast(CSHA512& hasher) noexcept
+void SeedFast(CSHA512& hasher) noexcept
{
unsigned char buffer[32];
@@ -549,7 +556,7 @@ static void SeedFast(CSHA512& hasher) noexcept
SeedTimestamp(hasher);
}
-static void SeedSlow(CSHA512& hasher, RNGState& rng) noexcept
+void SeedSlow(CSHA512& hasher, RNGState& rng) noexcept
{
unsigned char buffer[32];
@@ -571,7 +578,7 @@ static void SeedSlow(CSHA512& hasher, RNGState& rng) noexcept
}
/** Extract entropy from rng, strengthen it, and feed it into hasher. */
-static void SeedStrengthen(CSHA512& hasher, RNGState& rng, SteadyClock::duration dur) noexcept
+void SeedStrengthen(CSHA512& hasher, RNGState& rng, SteadyClock::duration dur) noexcept
{
// Generate 32 bytes of entropy from the RNG, and a copy of the entropy already in hasher.
// Never use the deterministic PRNG for this, as the result is only used internally.
@@ -581,7 +588,7 @@ static void SeedStrengthen(CSHA512& hasher, RNGState& rng, SteadyClock::duration
Strengthen(strengthen_seed, dur, hasher);
}
-static void SeedPeriodic(CSHA512& hasher, RNGState& rng) noexcept
+void SeedPeriodic(CSHA512& hasher, RNGState& rng) noexcept
{
// Everything that the 'fast' seeder includes
SeedFast(hasher);
@@ -601,7 +608,7 @@ static void SeedPeriodic(CSHA512& hasher, RNGState& rng) noexcept
SeedStrengthen(hasher, rng, 10ms);
}
-static void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept
+void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept
{
// Gather 256 bits of hardware randomness, if available
SeedHardwareSlow(hasher);
@@ -627,7 +634,7 @@ enum class RNGLevel {
PERIODIC, //!< Called by RandAddPeriodic()
};
-static void ProcRand(unsigned char* out, int num, RNGLevel level, bool always_use_real_rng) noexcept
+void ProcRand(unsigned char* out, int num, RNGLevel level, bool always_use_real_rng) noexcept
{
// Make sure the RNG is initialized first (as all Seed* function possibly need hwrand to be available).
RNGState& rng = GetRNGState();
@@ -656,6 +663,9 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level, bool always_us
}
}
+} // namespace
+
+
/** Internal function to set g_determinstic_rng. Only accessed from tests. */
void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept
{
@@ -679,13 +689,6 @@ void RandAddPeriodic() noexcept
void RandAddEvent(const uint32_t event_info) noexcept { GetRNGState().AddEvent(event_info); }
-uint256 GetRandHash() noexcept
-{
- uint256 hash;
- GetRandBytes(hash);
- return hash;
-}
-
void FastRandomContext::RandomSeed() noexcept
{
uint256 seed = GetRandHash();
diff --git a/src/random.h b/src/random.h
index 821c84fce3..ea517d2d2e 100644
--- a/src/random.h
+++ b/src/random.h
@@ -28,8 +28,8 @@
* The following (classes of) functions interact with that state by mixing in new
* entropy, and optionally extracting random output from it:
*
- * - The GetRand*() class of functions, as well as construction of FastRandomContext objects,
- * perform 'fast' seeding, consisting of mixing in:
+ * - GetRandBytes, GetRandHash, GetRandDur, as well as construction of FastRandomContext
+ * objects, perform 'fast' seeding, consisting of mixing in:
* - A stack pointer (indirectly committing to calling thread and call stack)
* - A high-precision timestamp (rdtsc when available, c++ high_resolution_clock otherwise)
* - 64 bits from the hardware RNG (rdrand) when available.
@@ -38,7 +38,7 @@
* FastRandomContext on the other hand does not protect against this once created, but
* is even faster (and acceptable to use inside tight loops).
*
- * - The GetStrongRand*() class of function perform 'slow' seeding, including everything
+ * - The GetStrongRandBytes() function performs 'slow' seeding, including everything
* that fast seeding includes, but additionally:
* - OS entropy (/dev/urandom, getrandom(), ...). The application will terminate if
* this entropy source fails.
@@ -53,12 +53,12 @@
* - Strengthen the entropy for 10 ms using repeated SHA512.
* This is run once every minute.
*
- * On first use of the RNG (regardless of what function is called first), all entropy
- * sources used in the 'slow' seeder are included, but also:
- * - 256 bits from the hardware RNG (rdseed or rdrand) when available.
- * - Dynamic environment data (performance monitoring, ...)
- * - Static environment data
- * - Strengthen the entropy for 100 ms using repeated SHA512.
+ * - On first use of the RNG (regardless of what function is called first), all entropy
+ * sources used in the 'slow' seeder are included, but also:
+ * - 256 bits from the hardware RNG (rdseed or rdrand) when available.
+ * - Dynamic environment data (performance monitoring, ...)
+ * - Static environment data
+ * - Strengthen the entropy for 100 ms using repeated SHA512.
*
* When mixing in new entropy, H = SHA512(entropy || old_rng_state) is computed, and
* (up to) the first 32 bytes of H are produced as output, while the last 32 bytes
@@ -71,42 +71,72 @@
* only depends on the seed it was initialized with, possibly until it is reinitialized.
*/
+
+/* ============================= INITIALIZATION AND ADDING ENTROPY ============================= */
+
+/**
+ * Initialize global RNG state and log any CPU features that are used.
+ *
+ * Calling this function is optional. RNG state will be initialized when first
+ * needed if it is not called.
+ */
+void RandomInit();
+
+/**
+ * Gather entropy from various expensive sources, and feed them to the PRNG state.
+ *
+ * Thread-safe.
+ */
+void RandAddPeriodic() noexcept;
+
+/**
+ * Gathers entropy from the low bits of the time at which events occur. Should
+ * be called with a uint32_t describing the event at the time an event occurs.
+ *
+ * Thread-safe.
+ */
+void RandAddEvent(const uint32_t event_info) noexcept;
+
+
+/* =========================== BASE RANDOMNESS GENERATION FUNCTIONS ===========================
+ *
+ * All produced randomness is eventually generated by one of these functions.
+ */
+
/**
* Generate random data via the internal PRNG.
*
* These functions are designed to be fast (sub microsecond), but do not necessarily
* meaningfully add entropy to the PRNG state.
*
+ * In test mode (see SeedRandomForTest in src/test/util/random.h), the normal PRNG state is
+ * bypassed, and a deterministic, seeded, PRNG is used instead.
+ *
* Thread-safe.
*/
void GetRandBytes(Span bytes) noexcept;
-uint256 GetRandHash() noexcept;
-
/**
* Gather entropy from various sources, feed it into the internal PRNG, and
* generate random data using it.
*
* This function will cause failure whenever the OS RNG fails.
*
+ * The normal PRNG is never bypassed here, even in test mode.
+ *
* Thread-safe.
*/
void GetStrongRandBytes(Span bytes) noexcept;
-/**
- * Gather entropy from various expensive sources, and feed them to the PRNG state.
- *
- * Thread-safe.
- */
-void RandAddPeriodic() noexcept;
-/**
- * Gathers entropy from the low bits of the time at which events occur. Should
- * be called with a uint32_t describing the event at the time an event occurs.
+/* ============================= RANDOM NUMBER GENERATION CLASSES =============================
*
- * Thread-safe.
+ * In this section, 3 classes are defined:
+ * - RandomMixin: a base class that adds functionality to all RNG classes.
+ * - FastRandomContext: a cryptographic RNG (seeded through GetRandBytes in its default
+ * constructor).
+ * - InsecureRandomContext: a non-cryptographic, very fast, RNG.
*/
-void RandAddEvent(const uint32_t event_info) noexcept;
// Forward declaration of RandomMixin, used in RandomNumberGenerator concept.
template
@@ -430,6 +460,17 @@ public:
}
};
+
+/* ==================== CONVENIENCE FUNCTIONS FOR COMMONLY USED RANDOMNESS ==================== */
+
+/** Generate a random uint256. */
+inline uint256 GetRandHash() noexcept
+{
+ uint256 hash;
+ GetRandBytes(hash);
+ return hash;
+}
+
/** More efficient than using std::shuffle on a FastRandomContext.
*
* This is more efficient as std::shuffle will consume entropy in groups of
@@ -453,29 +494,11 @@ void Shuffle(I first, I last, R&& rng)
}
}
-/* Number of random bytes returned by GetOSRand.
- * When changing this constant make sure to change all call sites, and make
- * sure that the underlying OS APIs for all platforms support the number.
- * (many cap out at 256 bytes).
- */
-static const int NUM_OS_RANDOM_BYTES = 32;
-
-/** Get 32 bytes of system entropy. Do not use this in application code: use
- * GetStrongRandBytes instead.
- */
-void GetOSRand(unsigned char* ent32);
+/* ============================= MISCELLANEOUS TEST-ONLY FUNCTIONS ============================= */
/** Check that OS randomness is available and returning the requested number
* of bytes.
*/
bool Random_SanityCheck();
-/**
- * Initialize global RNG state and log any CPU features that are used.
- *
- * Calling this function is optional. RNG state will be initialized when first
- * needed if it is not called.
- */
-void RandomInit();
-
#endif // BITCOIN_RANDOM_H
diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp
index 906fbb4afa..fc22daeb57 100644
--- a/src/test/cuckoocache_tests.cpp
+++ b/src/test/cuckoocache_tests.cpp
@@ -33,7 +33,7 @@ BOOST_AUTO_TEST_SUITE(cuckoocache_tests);
/* Test that no values not inserted into the cache are read out of it.
*
- * There are no repeats in the first 200000 insecure_GetRandHash calls
+ * There are no repeats in the first 200000 InsecureRand256() calls
*/
BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes)
{