Coverage Report

Created: 2026-04-29 19:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/tmp/bitcoin/src/random.h
Line
Count
Source
1
// Copyright (c) 2009-2010 Satoshi Nakamoto
2
// Copyright (c) 2009-present 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
#ifndef BITCOIN_RANDOM_H
7
#define BITCOIN_RANDOM_H
8
9
#include <crypto/chacha20.h>
10
#include <crypto/common.h>
11
#include <span.h>
12
#include <uint256.h>
13
#include <util/check.h>
14
15
#include <bit>
16
#include <cassert>
17
#include <chrono>
18
#include <concepts>
19
#include <cstdint>
20
#include <limits>
21
#include <type_traits>
22
#include <vector>
23
24
/**
25
 * Overall design of the RNG and entropy sources.
26
 *
27
 * We maintain a single global 256-bit RNG state for all high-quality randomness.
28
 * The following (classes of) functions interact with that state by mixing in new
29
 * entropy, and optionally extracting random output from it:
30
 *
31
 * - GetRandBytes, GetRandHash, GetRandDur, as well as construction of FastRandomContext
32
 *   objects, perform 'fast' seeding, consisting of mixing in:
33
 *   - A stack pointer (indirectly committing to calling thread and call stack)
34
 *   - A high-precision timestamp (rdtsc when available, c++ high_resolution_clock otherwise)
35
 *   - 64 bits from the hardware RNG (rdrand) when available.
36
 *   These entropy sources are very fast, and only designed to protect against situations
37
 *   where a VM state restore/copy results in multiple systems with the same randomness.
38
 *   FastRandomContext on the other hand does not protect against this once created, but
39
 *   is even faster (and acceptable to use inside tight loops).
40
 *
41
 * - The GetStrongRandBytes() function performs 'slow' seeding, including everything
42
 *   that fast seeding includes, but additionally:
43
 *   - OS entropy (/dev/urandom, getrandom(), ...). The application will terminate if
44
 *     this entropy source fails.
45
 *   - Another high-precision timestamp (indirectly committing to a benchmark of all the
46
 *     previous sources).
47
 *   These entropy sources are slower, but designed to make sure the RNG state contains
48
 *   fresh data that is unpredictable to attackers.
49
 *
50
 * - RandAddPeriodic() seeds everything that fast seeding includes, but additionally:
51
 *   - A high-precision timestamp
52
 *   - Dynamic environment data (clocks, resource usage, ...)
53
 *   - Strengthen the entropy for 10 ms using repeated SHA512.
54
 *   This is run once every minute.
55
 *
56
 * - On first use of the RNG (regardless of what function is called first), all entropy
57
 *   sources used in the 'slow' seeder are included, but also:
58
 *   - 256 bits from the hardware RNG (rdseed or rdrand) when available.
59
 *   - Dynamic environment data (performance monitoring, ...)
60
 *   - Static environment data
61
 *   - Strengthen the entropy for 100 ms using repeated SHA512.
62
 *
63
 * When mixing in new entropy, H = SHA512(entropy || old_rng_state) is computed, and
64
 * (up to) the first 32 bytes of H are produced as output, while the last 32 bytes
65
 * become the new RNG state.
66
 *
67
 * During tests, the RNG can be put into a special deterministic mode, in which the output
68
 * of all RNG functions, with the exception of GetStrongRandBytes(), is replaced with the
69
 * output of a deterministic RNG. This deterministic RNG does not gather entropy, and is
70
 * unaffected by RandAddPeriodic() or RandAddEvent(). It produces pseudorandom data that
71
 * only depends on the seed it was initialized with, possibly until it is reinitialized.
72
*/
73
74
75
/* ============================= INITIALIZATION AND ADDING ENTROPY ============================= */
76
77
/**
78
 * Initialize global RNG state and log any CPU features that are used.
79
 *
80
 * Calling this function is optional. RNG state will be initialized when first
81
 * needed if it is not called.
82
 */
83
void RandomInit();
84
85
/**
86
 * Gather entropy from various expensive sources, and feed them to the PRNG state.
87
 *
88
 * Thread-safe.
89
 */
90
void RandAddPeriodic() noexcept;
91
92
/**
93
 * Gathers entropy from the low bits of the time at which events occur. Should
94
 * be called with a uint32_t describing the event at the time an event occurs.
95
 *
96
 * Thread-safe.
97
 */
98
void RandAddEvent(uint32_t event_info) noexcept;
99
100
101
/* =========================== BASE RANDOMNESS GENERATION FUNCTIONS ===========================
102
 *
103
 * All produced randomness is eventually generated by one of these functions.
104
 */
105
106
/**
107
 * Generate random data via the internal PRNG.
108
 *
109
 * These functions are designed to be fast (sub microsecond), but do not necessarily
110
 * meaningfully add entropy to the PRNG state.
111
 *
112
 * In test mode (see SeedRandomForTest in src/test/util/random.h), the normal PRNG state is
113
 * bypassed, and a deterministic, seeded, PRNG is used instead.
114
 *
115
 * Thread-safe.
116
 */
117
void GetRandBytes(std::span<unsigned char> bytes) noexcept;
118
119
/**
120
 * Gather entropy from various sources, feed it into the internal PRNG, and
121
 * generate random data using it.
122
 *
123
 * This function will cause failure whenever the OS RNG fails.
124
 *
125
 * The normal PRNG is never bypassed here, even in test mode.
126
 *
127
 * Thread-safe.
128
 */
129
void GetStrongRandBytes(std::span<unsigned char> bytes) noexcept;
130
131
132
/* ============================= RANDOM NUMBER GENERATION CLASSES =============================
133
 *
134
 * In this section, 3 classes are defined:
135
 * - RandomMixin:            a base class that adds functionality to all RNG classes.
136
 * - FastRandomContext:      a cryptographic RNG (seeded through GetRandBytes in its default
137
 *                           constructor).
138
 * - InsecureRandomContext:  a non-cryptographic, very fast, RNG.
139
 */
140
141
// Forward declaration of RandomMixin, used in RandomNumberGenerator concept.
142
template<typename T>
143
class RandomMixin;
144
145
/** A concept for RandomMixin-based random number generators. */
146
template<typename T>
147
concept RandomNumberGenerator = requires(T& rng, std::span<std::byte> s) {
148
    // A random number generator must provide rand64().
149
    { rng.rand64() } noexcept -> std::same_as<uint64_t>;
150
    // A random number generator must derive from RandomMixin, which adds other rand* functions.
151
    requires std::derived_from<std::remove_reference_t<T>, RandomMixin<std::remove_reference_t<T>>>;
152
};
153
154
/** A concept for C++ std::chrono durations. */
155
template<typename T>
156
concept StdChronoDuration = requires {
157
    []<class Rep, class Period>(std::type_identity<std::chrono::duration<Rep, Period>>){}(
158
        std::type_identity<T>());
159
};
160
161
/** Given a uniformly random uint64_t, return an exponentially distributed double with mean 1. */
162
double MakeExponentiallyDistributed(uint64_t uniform) noexcept;
163
164
/** Mixin class that provides helper randomness functions.
165
 *
166
 * Intended to be used through CRTP: https://en.cppreference.com/w/cpp/language/crtp.
167
 * An RNG class FunkyRNG would derive publicly from RandomMixin<FunkyRNG>. This permits
168
 * RandomMixin from accessing the derived class's rand64() function, while also allowing
169
 * the derived class to provide more.
170
 *
171
 * The derived class must satisfy the RandomNumberGenerator concept.
172
 */
173
template<typename T>
174
class RandomMixin
175
{
176
private:
177
    uint64_t bitbuf{0};
178
    int bitbuf_size{0};
179
180
    /** Access the underlying generator.
181
     *
182
     * This also enforces the RandomNumberGenerator concept. We cannot declare that in the template
183
     * (no template<RandomNumberGenerator T>) because the type isn't fully instantiated yet there.
184
     */
185
515M
    RandomNumberGenerator auto& Impl() noexcept { return static_cast<T&>(*this); }
RandomMixin<FastRandomContext>::Impl()
Line
Count
Source
185
499M
    RandomNumberGenerator auto& Impl() noexcept { return static_cast<T&>(*this); }
RandomMixin<InsecureRandomContext>::Impl()
Line
Count
Source
185
15.5M
    RandomNumberGenerator auto& Impl() noexcept { return static_cast<T&>(*this); }
186
187
protected:
188
    constexpr void FlushCache() noexcept
189
749
    {
190
749
        bitbuf = 0;
191
749
        bitbuf_size = 0;
192
749
    }
RandomMixin<InsecureRandomContext>::FlushCache()
Line
Count
Source
189
1
    {
190
1
        bitbuf = 0;
191
1
        bitbuf_size = 0;
192
1
    }
RandomMixin<FastRandomContext>::FlushCache()
Line
Count
Source
189
748
    {
190
748
        bitbuf = 0;
191
748
        bitbuf_size = 0;
192
748
    }
193
194
public:
195
2.66M
    constexpr RandomMixin() noexcept = default;
RandomMixin<InsecureRandomContext>::RandomMixin()
Line
Count
Source
195
191k
    constexpr RandomMixin() noexcept = default;
RandomMixin<FastRandomContext>::RandomMixin()
Line
Count
Source
195
2.47M
    constexpr RandomMixin() noexcept = default;
196
197
    // Do not permit copying or moving an RNG.
198
    RandomMixin(const RandomMixin&) = delete;
199
    RandomMixin& operator=(const RandomMixin&) = delete;
200
    RandomMixin(RandomMixin&&) = delete;
201
    RandomMixin& operator=(RandomMixin&&) = delete;
202
203
    /** Generate a random (bits)-bit integer. */
204
    uint64_t randbits(int bits) noexcept
205
40.5M
    {
206
40.5M
        Assume(bits <= 64);
207
        // Requests for the full 64 bits are passed through.
208
40.5M
        if (bits == 64) return Impl().rand64();
209
39.8M
        uint64_t ret;
210
39.8M
        if (bits <= bitbuf_size) {
211
            // If there is enough entropy left in bitbuf, return its bottom bits bits.
212
31.8M
            ret = bitbuf;
213
31.8M
            bitbuf >>= bits;
214
31.8M
            bitbuf_size -= bits;
215
31.8M
        } else {
216
            // If not, return all of bitbuf, supplemented with the (bits - bitbuf_size) bottom
217
            // bits of a newly generated 64-bit number on top. The remainder of that generated
218
            // number becomes the new bitbuf.
219
8.00M
            uint64_t gen = Impl().rand64();
220
8.00M
            ret = (gen << bitbuf_size) | bitbuf;
221
8.00M
            bitbuf = gen >> (bits - bitbuf_size);
222
8.00M
            bitbuf_size = 64 + bitbuf_size - bits;
223
8.00M
        }
224
        // Return the bottom bits bits of ret.
225
39.8M
        return ret & ((uint64_t{1} << bits) - 1);
226
40.5M
    }
RandomMixin<FastRandomContext>::randbits(int)
Line
Count
Source
205
27.8M
    {
206
27.8M
        Assume(bits <= 64);
207
        // Requests for the full 64 bits are passed through.
208
27.8M
        if (bits == 64) return Impl().rand64();
209
27.2M
        uint64_t ret;
210
27.2M
        if (bits <= bitbuf_size) {
211
            // If there is enough entropy left in bitbuf, return its bottom bits bits.
212
19.6M
            ret = bitbuf;
213
19.6M
            bitbuf >>= bits;
214
19.6M
            bitbuf_size -= bits;
215
19.6M
        } else {
216
            // If not, return all of bitbuf, supplemented with the (bits - bitbuf_size) bottom
217
            // bits of a newly generated 64-bit number on top. The remainder of that generated
218
            // number becomes the new bitbuf.
219
7.53M
            uint64_t gen = Impl().rand64();
220
7.53M
            ret = (gen << bitbuf_size) | bitbuf;
221
7.53M
            bitbuf = gen >> (bits - bitbuf_size);
222
7.53M
            bitbuf_size = 64 + bitbuf_size - bits;
223
7.53M
        }
224
        // Return the bottom bits bits of ret.
225
27.2M
        return ret & ((uint64_t{1} << bits) - 1);
226
27.8M
    }
RandomMixin<InsecureRandomContext>::randbits(int)
Line
Count
Source
205
12.6M
    {
206
12.6M
        Assume(bits <= 64);
207
        // Requests for the full 64 bits are passed through.
208
12.6M
        if (bits == 64) return Impl().rand64();
209
12.6M
        uint64_t ret;
210
12.6M
        if (bits <= bitbuf_size) {
211
            // If there is enough entropy left in bitbuf, return its bottom bits bits.
212
12.2M
            ret = bitbuf;
213
12.2M
            bitbuf >>= bits;
214
12.2M
            bitbuf_size -= bits;
215
12.2M
        } else {
216
            // If not, return all of bitbuf, supplemented with the (bits - bitbuf_size) bottom
217
            // bits of a newly generated 64-bit number on top. The remainder of that generated
218
            // number becomes the new bitbuf.
219
472k
            uint64_t gen = Impl().rand64();
220
472k
            ret = (gen << bitbuf_size) | bitbuf;
221
472k
            bitbuf = gen >> (bits - bitbuf_size);
222
472k
            bitbuf_size = 64 + bitbuf_size - bits;
223
472k
        }
224
        // Return the bottom bits bits of ret.
225
12.6M
        return ret & ((uint64_t{1} << bits) - 1);
226
12.6M
    }
227
228
    /** Same as above, but with compile-time fixed bits count. */
229
    template<int Bits>
230
    uint64_t randbits() noexcept
231
465M
    {
232
465M
        static_assert(Bits >= 0 && Bits <= 64);
233
465M
        if constexpr (Bits == 64) {
234
96.0k
            return Impl().rand64();
235
465M
        } else {
236
465M
            uint64_t ret;
237
465M
            if (Bits <= bitbuf_size) {
238
449M
                ret = bitbuf;
239
449M
                bitbuf >>= Bits;
240
449M
                bitbuf_size -= Bits;
241
449M
            } else {
242
15.7M
                uint64_t gen = Impl().rand64();
243
15.7M
                ret = (gen << bitbuf_size) | bitbuf;
244
15.7M
                bitbuf = gen >> (Bits - bitbuf_size);
245
15.7M
                bitbuf_size = 64 + bitbuf_size - Bits;
246
15.7M
            }
247
465M
            constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
248
465M
            return ret & MASK;
249
465M
        }
250
465M
    }
unsigned long RandomMixin<InsecureRandomContext>::randbits<1>()
Line
Count
Source
231
4.08M
    {
232
4.08M
        static_assert(Bits >= 0 && Bits <= 64);
233
        if constexpr (Bits == 64) {
234
            return Impl().rand64();
235
4.08M
        } else {
236
4.08M
            uint64_t ret;
237
4.08M
            if (Bits <= bitbuf_size) {
238
3.95M
                ret = bitbuf;
239
3.95M
                bitbuf >>= Bits;
240
3.95M
                bitbuf_size -= Bits;
241
3.95M
            } else {
242
136k
                uint64_t gen = Impl().rand64();
243
136k
                ret = (gen << bitbuf_size) | bitbuf;
244
136k
                bitbuf = gen >> (Bits - bitbuf_size);
245
136k
                bitbuf_size = 64 + bitbuf_size - Bits;
246
136k
            }
247
4.08M
            constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
248
4.08M
            return ret & MASK;
249
4.08M
        }
250
4.08M
    }
unsigned long RandomMixin<FastRandomContext>::randbits<1>()
Line
Count
Source
231
443M
    {
232
443M
        static_assert(Bits >= 0 && Bits <= 64);
233
        if constexpr (Bits == 64) {
234
            return Impl().rand64();
235
443M
        } else {
236
443M
            uint64_t ret;
237
443M
            if (Bits <= bitbuf_size) {
238
436M
                ret = bitbuf;
239
436M
                bitbuf >>= Bits;
240
436M
                bitbuf_size -= Bits;
241
436M
            } else {
242
6.93M
                uint64_t gen = Impl().rand64();
243
6.93M
                ret = (gen << bitbuf_size) | bitbuf;
244
6.93M
                bitbuf = gen >> (Bits - bitbuf_size);
245
6.93M
                bitbuf_size = 64 + bitbuf_size - Bits;
246
6.93M
            }
247
443M
            constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
248
443M
            return ret & MASK;
249
443M
        }
250
443M
    }
unsigned long RandomMixin<FastRandomContext>::randbits<32>()
Line
Count
Source
231
16.8M
    {
232
16.8M
        static_assert(Bits >= 0 && Bits <= 64);
233
        if constexpr (Bits == 64) {
234
            return Impl().rand64();
235
16.8M
        } else {
236
16.8M
            uint64_t ret;
237
16.8M
            if (Bits <= bitbuf_size) {
238
8.34M
                ret = bitbuf;
239
8.34M
                bitbuf >>= Bits;
240
8.34M
                bitbuf_size -= Bits;
241
8.51M
            } else {
242
8.51M
                uint64_t gen = Impl().rand64();
243
8.51M
                ret = (gen << bitbuf_size) | bitbuf;
244
8.51M
                bitbuf = gen >> (Bits - bitbuf_size);
245
8.51M
                bitbuf_size = 64 + bitbuf_size - Bits;
246
8.51M
            }
247
16.8M
            constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
248
16.8M
            return ret & MASK;
249
16.8M
        }
250
16.8M
    }
unsigned long RandomMixin<FastRandomContext>::randbits<3>()
Line
Count
Source
231
40
    {
232
40
        static_assert(Bits >= 0 && Bits <= 64);
233
        if constexpr (Bits == 64) {
234
            return Impl().rand64();
235
40
        } else {
236
40
            uint64_t ret;
237
40
            if (Bits <= bitbuf_size) {
238
37
                ret = bitbuf;
239
37
                bitbuf >>= Bits;
240
37
                bitbuf_size -= Bits;
241
37
            } else {
242
3
                uint64_t gen = Impl().rand64();
243
3
                ret = (gen << bitbuf_size) | bitbuf;
244
3
                bitbuf = gen >> (Bits - bitbuf_size);
245
3
                bitbuf_size = 64 + bitbuf_size - Bits;
246
3
            }
247
40
            constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
248
40
            return ret & MASK;
249
40
        }
250
40
    }
unsigned long RandomMixin<FastRandomContext>::randbits<4>()
Line
Count
Source
231
20
    {
232
20
        static_assert(Bits >= 0 && Bits <= 64);
233
        if constexpr (Bits == 64) {
234
            return Impl().rand64();
235
20
        } else {
236
20
            uint64_t ret;
237
20
            if (Bits <= bitbuf_size) {
238
19
                ret = bitbuf;
239
19
                bitbuf >>= Bits;
240
19
                bitbuf_size -= Bits;
241
19
            } else {
242
1
                uint64_t gen = Impl().rand64();
243
1
                ret = (gen << bitbuf_size) | bitbuf;
244
1
                bitbuf = gen >> (Bits - bitbuf_size);
245
1
                bitbuf_size = 64 + bitbuf_size - Bits;
246
1
            }
247
20
            constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
248
20
            return ret & MASK;
249
20
        }
250
20
    }
unsigned long RandomMixin<FastRandomContext>::randbits<31>()
Line
Count
Source
231
16
    {
232
16
        static_assert(Bits >= 0 && Bits <= 64);
233
        if constexpr (Bits == 64) {
234
            return Impl().rand64();
235
16
        } else {
236
16
            uint64_t ret;
237
16
            if (Bits <= bitbuf_size) {
238
4
                ret = bitbuf;
239
4
                bitbuf >>= Bits;
240
4
                bitbuf_size -= Bits;
241
12
            } else {
242
12
                uint64_t gen = Impl().rand64();
243
12
                ret = (gen << bitbuf_size) | bitbuf;
244
12
                bitbuf = gen >> (Bits - bitbuf_size);
245
12
                bitbuf_size = 64 + bitbuf_size - Bits;
246
12
            }
247
16
            constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
248
16
            return ret & MASK;
249
16
        }
250
16
    }
unsigned long RandomMixin<FastRandomContext>::randbits<0>()
Line
Count
Source
231
95.9k
    {
232
95.9k
        static_assert(Bits >= 0 && Bits <= 64);
233
        if constexpr (Bits == 64) {
234
            return Impl().rand64();
235
95.9k
        } else {
236
95.9k
            uint64_t ret;
237
95.9k
            if (Bits <= bitbuf_size) {
238
95.9k
                ret = bitbuf;
239
95.9k
                bitbuf >>= Bits;
240
95.9k
                bitbuf_size -= Bits;
241
95.9k
            } else {
242
0
                uint64_t gen = Impl().rand64();
243
0
                ret = (gen << bitbuf_size) | bitbuf;
244
0
                bitbuf = gen >> (Bits - bitbuf_size);
245
0
                bitbuf_size = 64 + bitbuf_size - Bits;
246
0
            }
247
95.9k
            constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
248
95.9k
            return ret & MASK;
249
95.9k
        }
250
95.9k
    }
unsigned long RandomMixin<FastRandomContext>::randbits<7>()
Line
Count
Source
231
96.3k
    {
232
96.3k
        static_assert(Bits >= 0 && Bits <= 64);
233
        if constexpr (Bits == 64) {
234
            return Impl().rand64();
235
96.3k
        } else {
236
96.3k
            uint64_t ret;
237
96.3k
            if (Bits <= bitbuf_size) {
238
85.7k
                ret = bitbuf;
239
85.7k
                bitbuf >>= Bits;
240
85.7k
                bitbuf_size -= Bits;
241
85.7k
            } else {
242
10.5k
                uint64_t gen = Impl().rand64();
243
10.5k
                ret = (gen << bitbuf_size) | bitbuf;
244
10.5k
                bitbuf = gen >> (Bits - bitbuf_size);
245
10.5k
                bitbuf_size = 64 + bitbuf_size - Bits;
246
10.5k
            }
247
96.3k
            constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
248
96.3k
            return ret & MASK;
249
96.3k
        }
250
96.3k
    }
unsigned long RandomMixin<FastRandomContext>::randbits<51>()
Line
Count
Source
231
96.3k
    {
232
96.3k
        static_assert(Bits >= 0 && Bits <= 64);
233
        if constexpr (Bits == 64) {
234
            return Impl().rand64();
235
96.3k
        } else {
236
96.3k
            uint64_t ret;
237
96.3k
            if (Bits <= bitbuf_size) {
238
19.4k
                ret = bitbuf;
239
19.4k
                bitbuf >>= Bits;
240
19.4k
                bitbuf_size -= Bits;
241
76.9k
            } else {
242
76.9k
                uint64_t gen = Impl().rand64();
243
76.9k
                ret = (gen << bitbuf_size) | bitbuf;
244
76.9k
                bitbuf = gen >> (Bits - bitbuf_size);
245
76.9k
                bitbuf_size = 64 + bitbuf_size - Bits;
246
76.9k
            }
247
96.3k
            constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
248
96.3k
            return ret & MASK;
249
96.3k
        }
250
96.3k
    }
unsigned long RandomMixin<FastRandomContext>::randbits<64>()
Line
Count
Source
231
96.0k
    {
232
96.0k
        static_assert(Bits >= 0 && Bits <= 64);
233
96.0k
        if constexpr (Bits == 64) {
234
96.0k
            return Impl().rand64();
235
        } else {
236
            uint64_t ret;
237
            if (Bits <= bitbuf_size) {
238
                ret = bitbuf;
239
                bitbuf >>= Bits;
240
                bitbuf_size -= Bits;
241
            } else {
242
                uint64_t gen = Impl().rand64();
243
                ret = (gen << bitbuf_size) | bitbuf;
244
                bitbuf = gen >> (Bits - bitbuf_size);
245
                bitbuf_size = 64 + bitbuf_size - Bits;
246
            }
247
            constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
248
            return ret & MASK;
249
        }
250
96.0k
    }
unsigned long RandomMixin<FastRandomContext>::randbits<63>()
Line
Count
Source
231
1
    {
232
1
        static_assert(Bits >= 0 && Bits <= 64);
233
        if constexpr (Bits == 64) {
234
            return Impl().rand64();
235
1
        } else {
236
1
            uint64_t ret;
237
1
            if (Bits <= bitbuf_size) {
238
0
                ret = bitbuf;
239
0
                bitbuf >>= Bits;
240
0
                bitbuf_size -= Bits;
241
1
            } else {
242
1
                uint64_t gen = Impl().rand64();
243
1
                ret = (gen << bitbuf_size) | bitbuf;
244
1
                bitbuf = gen >> (Bits - bitbuf_size);
245
1
                bitbuf_size = 64 + bitbuf_size - Bits;
246
1
            }
247
1
            constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
248
1
            return ret & MASK;
249
1
        }
250
1
    }
unsigned long RandomMixin<FastRandomContext>::randbits<27>()
Line
Count
Source
231
64.0k
    {
232
64.0k
        static_assert(Bits >= 0 && Bits <= 64);
233
        if constexpr (Bits == 64) {
234
            return Impl().rand64();
235
64.0k
        } else {
236
64.0k
            uint64_t ret;
237
64.0k
            if (Bits <= bitbuf_size) {
238
37.0k
                ret = bitbuf;
239
37.0k
                bitbuf >>= Bits;
240
37.0k
                bitbuf_size -= Bits;
241
37.0k
            } else {
242
27.0k
                uint64_t gen = Impl().rand64();
243
27.0k
                ret = (gen << bitbuf_size) | bitbuf;
244
27.0k
                bitbuf = gen >> (Bits - bitbuf_size);
245
27.0k
                bitbuf_size = 64 + bitbuf_size - Bits;
246
27.0k
            }
247
64.0k
            constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
248
64.0k
            return ret & MASK;
249
64.0k
        }
250
64.0k
    }
unsigned long RandomMixin<FastRandomContext>::randbits<16>()
Line
Count
Source
231
1.51k
    {
232
1.51k
        static_assert(Bits >= 0 && Bits <= 64);
233
        if constexpr (Bits == 64) {
234
            return Impl().rand64();
235
1.51k
        } else {
236
1.51k
            uint64_t ret;
237
1.51k
            if (Bits <= bitbuf_size) {
238
0
                ret = bitbuf;
239
0
                bitbuf >>= Bits;
240
0
                bitbuf_size -= Bits;
241
1.51k
            } else {
242
1.51k
                uint64_t gen = Impl().rand64();
243
1.51k
                ret = (gen << bitbuf_size) | bitbuf;
244
1.51k
                bitbuf = gen >> (Bits - bitbuf_size);
245
1.51k
                bitbuf_size = 64 + bitbuf_size - Bits;
246
1.51k
            }
247
1.51k
            constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
248
1.51k
            return ret & MASK;
249
1.51k
        }
250
1.51k
    }
unsigned long RandomMixin<FastRandomContext>::randbits<30>()
Line
Count
Source
231
409
    {
232
409
        static_assert(Bits >= 0 && Bits <= 64);
233
        if constexpr (Bits == 64) {
234
            return Impl().rand64();
235
409
        } else {
236
409
            uint64_t ret;
237
409
            if (Bits <= bitbuf_size) {
238
217
                ret = bitbuf;
239
217
                bitbuf >>= Bits;
240
217
                bitbuf_size -= Bits;
241
217
            } else {
242
192
                uint64_t gen = Impl().rand64();
243
192
                ret = (gen << bitbuf_size) | bitbuf;
244
192
                bitbuf = gen >> (Bits - bitbuf_size);
245
192
                bitbuf_size = 64 + bitbuf_size - Bits;
246
192
            }
247
409
            constexpr uint64_t MASK = (uint64_t{1} << Bits) - 1;
248
409
            return ret & MASK;
249
409
        }
250
409
    }
251
252
    /** Generate a random integer in the range [0..range), with range > 0. */
253
    template<std::integral I>
254
    I randrange(I range) noexcept
255
19.1M
    {
256
19.1M
        static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
257
19.1M
        Assume(range > 0);
258
19.1M
        uint64_t maxval = range - 1U;
259
19.1M
        int bits = std::bit_width(maxval);
260
24.8M
        while (true) {
261
24.8M
            uint64_t ret = Impl().randbits(bits);
262
24.8M
            if (ret <= maxval) return ret;
263
24.8M
        }
264
19.1M
    }
int RandomMixin<FastRandomContext>::randrange<int>(int)
Line
Count
Source
255
5.25M
    {
256
5.25M
        static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
257
5.25M
        Assume(range > 0);
258
5.25M
        uint64_t maxval = range - 1U;
259
5.25M
        int bits = std::bit_width(maxval);
260
7.43M
        while (true) {
261
7.43M
            uint64_t ret = Impl().randbits(bits);
262
7.43M
            if (ret <= maxval) return ret;
263
7.43M
        }
264
5.25M
    }
unsigned long RandomMixin<FastRandomContext>::randrange<unsigned long>(unsigned long)
Line
Count
Source
255
2.25M
    {
256
2.25M
        static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
257
2.25M
        Assume(range > 0);
258
2.25M
        uint64_t maxval = range - 1U;
259
2.25M
        int bits = std::bit_width(maxval);
260
3.67M
        while (true) {
261
3.67M
            uint64_t ret = Impl().randbits(bits);
262
3.67M
            if (ret <= maxval) return ret;
263
3.67M
        }
264
2.25M
    }
unsigned int RandomMixin<FastRandomContext>::randrange<unsigned int>(unsigned int)
Line
Count
Source
255
470k
    {
256
470k
        static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
257
470k
        Assume(range > 0);
258
470k
        uint64_t maxval = range - 1U;
259
470k
        int bits = std::bit_width(maxval);
260
612k
        while (true) {
261
612k
            uint64_t ret = Impl().randbits(bits);
262
612k
            if (ret <= maxval) return ret;
263
612k
        }
264
470k
    }
unsigned int RandomMixin<InsecureRandomContext>::randrange<unsigned int>(unsigned int)
Line
Count
Source
255
6.38M
    {
256
6.38M
        static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
257
6.38M
        Assume(range > 0);
258
6.38M
        uint64_t maxval = range - 1U;
259
6.38M
        int bits = std::bit_width(maxval);
260
6.90M
        while (true) {
261
6.90M
            uint64_t ret = Impl().randbits(bits);
262
6.90M
            if (ret <= maxval) return ret;
263
6.90M
        }
264
6.38M
    }
unsigned char RandomMixin<InsecureRandomContext>::randrange<unsigned char>(unsigned char)
Line
Count
Source
255
4.45M
    {
256
4.45M
        static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
257
4.45M
        Assume(range > 0);
258
4.45M
        uint64_t maxval = range - 1U;
259
4.45M
        int bits = std::bit_width(maxval);
260
5.77M
        while (true) {
261
5.77M
            uint64_t ret = Impl().randbits(bits);
262
5.77M
            if (ret <= maxval) return ret;
263
5.77M
        }
264
4.45M
    }
long RandomMixin<FastRandomContext>::randrange<long>(long)
Line
Count
Source
255
343k
    {
256
343k
        static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
257
343k
        Assume(range > 0);
258
343k
        uint64_t maxval = range - 1U;
259
343k
        int bits = std::bit_width(maxval);
260
415k
        while (true) {
261
415k
            uint64_t ret = Impl().randbits(bits);
262
415k
            if (ret <= maxval) return ret;
263
415k
        }
264
343k
    }
265
266
    /** Fill a span with random bytes. */
267
    void fillrand(std::span<std::byte> span) noexcept
268
    {
269
        while (span.size() >= 8) {
270
            uint64_t gen = Impl().rand64();
271
            WriteLE64(span.data(), gen);
272
            span = span.subspan(8);
273
        }
274
        if (span.size() >= 4) {
275
            uint32_t gen = Impl().rand32();
276
            WriteLE32(span.data(), gen);
277
            span = span.subspan(4);
278
        }
279
        while (span.size()) {
280
            span[0] = std::byte(Impl().template randbits<8>());
281
            span = span.subspan(1);
282
        }
283
    }
284
285
    /** Generate a random integer in its entire (non-negative) range. */
286
    template<std::integral I>
287
    I rand() noexcept
288
170k
    {
289
170k
        static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
290
170k
        static constexpr auto BITS = std::bit_width(uint64_t(std::numeric_limits<I>::max()));
291
170k
        static_assert(std::numeric_limits<I>::max() == std::numeric_limits<uint64_t>::max() >> (64 - BITS));
292
170k
        return I(Impl().template randbits<BITS>());
293
170k
    }
unsigned long RandomMixin<FastRandomContext>::rand<unsigned long>()
Line
Count
Source
288
6
    {
289
6
        static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
290
6
        static constexpr auto BITS = std::bit_width(uint64_t(std::numeric_limits<I>::max()));
291
6
        static_assert(std::numeric_limits<I>::max() == std::numeric_limits<uint64_t>::max() >> (64 - BITS));
292
6
        return I(Impl().template randbits<BITS>());
293
6
    }
int RandomMixin<FastRandomContext>::rand<int>()
Line
Count
Source
288
16
    {
289
16
        static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
290
16
        static constexpr auto BITS = std::bit_width(uint64_t(std::numeric_limits<I>::max()));
291
16
        static_assert(std::numeric_limits<I>::max() == std::numeric_limits<uint64_t>::max() >> (64 - BITS));
292
16
        return I(Impl().template randbits<BITS>());
293
16
    }
long RandomMixin<FastRandomContext>::rand<long>()
Line
Count
Source
288
1
    {
289
1
        static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
290
1
        static constexpr auto BITS = std::bit_width(uint64_t(std::numeric_limits<I>::max()));
291
1
        static_assert(std::numeric_limits<I>::max() == std::numeric_limits<uint64_t>::max() >> (64 - BITS));
292
1
        return I(Impl().template randbits<BITS>());
293
1
    }
signed char RandomMixin<FastRandomContext>::rand<signed char>()
Line
Count
Source
288
10
    {
289
10
        static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
290
10
        static constexpr auto BITS = std::bit_width(uint64_t(std::numeric_limits<I>::max()));
291
10
        static_assert(std::numeric_limits<I>::max() == std::numeric_limits<uint64_t>::max() >> (64 - BITS));
292
10
        return I(Impl().template randbits<BITS>());
293
10
    }
unsigned short RandomMixin<FastRandomContext>::rand<unsigned short>()
Line
Count
Source
288
1.51k
    {
289
1.51k
        static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
290
1.51k
        static constexpr auto BITS = std::bit_width(uint64_t(std::numeric_limits<I>::max()));
291
1.51k
        static_assert(std::numeric_limits<I>::max() == std::numeric_limits<uint64_t>::max() >> (64 - BITS));
292
1.51k
        return I(Impl().template randbits<BITS>());
293
1.51k
    }
unsigned int RandomMixin<FastRandomContext>::rand<unsigned int>()
Line
Count
Source
288
169k
    {
289
169k
        static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
290
169k
        static constexpr auto BITS = std::bit_width(uint64_t(std::numeric_limits<I>::max()));
291
169k
        static_assert(std::numeric_limits<I>::max() == std::numeric_limits<uint64_t>::max() >> (64 - BITS));
292
169k
        return I(Impl().template randbits<BITS>());
293
169k
    }
294
295
    /** Generate random bytes. */
296
    template <BasicByte B = unsigned char>
297
    std::vector<B> randbytes(size_t len) noexcept
298
54.9k
    {
299
54.9k
        std::vector<B> ret(len);
300
54.9k
        Impl().fillrand(MakeWritableByteSpan(ret));
301
54.9k
        return ret;
302
54.9k
    }
std::vector<unsigned char, std::allocator<unsigned char>> RandomMixin<FastRandomContext>::randbytes<unsigned char>(unsigned long)
Line
Count
Source
298
54.8k
    {
299
54.8k
        std::vector<B> ret(len);
300
54.8k
        Impl().fillrand(MakeWritableByteSpan(ret));
301
54.8k
        return ret;
302
54.8k
    }
std::vector<std::byte, std::allocator<std::byte>> RandomMixin<FastRandomContext>::randbytes<std::byte>(unsigned long)
Line
Count
Source
298
104
    {
299
104
        std::vector<B> ret(len);
300
104
        Impl().fillrand(MakeWritableByteSpan(ret));
301
104
        return ret;
302
104
    }
303
304
    /** Generate fixed-size random bytes. */
305
    template <size_t N, BasicByte B = std::byte>
306
    std::array<B, N> randbytes() noexcept
307
1.47k
    {
308
1.47k
        std::array<B, N> ret;
309
1.47k
        Impl().fillrand(MakeWritableByteSpan(ret));
310
1.47k
        return ret;
311
1.47k
    }
std::array<std::byte, 17ul> RandomMixin<FastRandomContext>::randbytes<17ul, std::byte>()
Line
Count
Source
307
1
    {
308
1
        std::array<B, N> ret;
309
1
        Impl().fillrand(MakeWritableByteSpan(ret));
310
1
        return ret;
311
1
    }
std::array<std::byte, 8ul> RandomMixin<FastRandomContext>::randbytes<8ul, std::byte>()
Line
Count
Source
307
1.47k
    {
308
1.47k
        std::array<B, N> ret;
309
1.47k
        Impl().fillrand(MakeWritableByteSpan(ret));
310
1.47k
        return ret;
311
1.47k
    }
312
313
    /** Generate a random 32-bit integer. */
314
16.5M
    uint32_t rand32() noexcept { return Impl().template randbits<32>(); }
315
316
    /** generate a random uint256. */
317
    uint256 rand256() noexcept
318
1.30M
    {
319
1.30M
        uint256 ret;
320
1.30M
        Impl().fillrand(MakeWritableByteSpan(ret));
321
1.30M
        return ret;
322
1.30M
    }
323
324
    /** Generate a random boolean. */
325
446M
    bool randbool() noexcept { return Impl().template randbits<1>(); }
RandomMixin<InsecureRandomContext>::randbool()
Line
Count
Source
325
2.29M
    bool randbool() noexcept { return Impl().template randbits<1>(); }
RandomMixin<FastRandomContext>::randbool()
Line
Count
Source
325
443M
    bool randbool() noexcept { return Impl().template randbits<1>(); }
326
327
    /** Return the time point advanced by a uniform random duration. */
328
    template <typename Tp>
329
    Tp rand_uniform_delay(const Tp& time, typename Tp::duration range) noexcept
330
5.28k
    {
331
5.28k
        return time + Impl().template rand_uniform_duration<Tp>(range);
332
5.28k
    }
std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1l>>> RandomMixin<FastRandomContext>::rand_uniform_delay<std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1l>>>>(std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1l>>> const&, std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1l>>>::duration)
Line
Count
Source
330
6
    {
331
6
        return time + Impl().template rand_uniform_duration<Tp>(range);
332
6
    }
Unexecuted instantiation: std::chrono::time_point<NodeClock, std::chrono::duration<long, std::ratio<1l, 1l>>> RandomMixin<FastRandomContext>::rand_uniform_delay<std::chrono::time_point<NodeClock, std::chrono::duration<long, std::ratio<1l, 1l>>>>(std::chrono::time_point<NodeClock, std::chrono::duration<long, std::ratio<1l, 1l>>> const&, std::chrono::time_point<NodeClock, std::chrono::duration<long, std::ratio<1l, 1l>>>::duration)
std::chrono::time_point<NodeClock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>> RandomMixin<FastRandomContext>::rand_uniform_delay<std::chrono::time_point<NodeClock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>>>(std::chrono::time_point<NodeClock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>> const&, std::chrono::time_point<NodeClock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>>::duration)
Line
Count
Source
330
5.27k
    {
331
5.27k
        return time + Impl().template rand_uniform_duration<Tp>(range);
332
5.27k
    }
333
334
    /** Generate a uniform random duration in the range from 0 (inclusive) to range (exclusive). */
335
    template <typename Chrono> requires StdChronoDuration<typename Chrono::duration>
336
    typename Chrono::duration rand_uniform_duration(typename Chrono::duration range) noexcept
337
5.28k
    {
338
5.28k
        using Dur = typename Chrono::duration;
339
5.28k
        return range.count() > 0 ? /* interval [0..range) */ Dur{Impl().randrange(range.count())} :
340
5.28k
               range.count() < 0 ? /* interval (range..0] */ -Dur{Impl().randrange(-range.count())} :
341
3
                                   /* interval [0..0] */ Dur{0};
342
5.28k
    };
random_tests.cpp:random_tests::fastrandom_tests_deterministic::test_method()::MicroClock::duration RandomMixin<FastRandomContext>::rand_uniform_duration<random_tests::fastrandom_tests_deterministic::test_method()::MicroClock>(random_tests::fastrandom_tests_deterministic::test_method()::MicroClock::duration)
Line
Count
Source
337
1
    {
338
1
        using Dur = typename Chrono::duration;
339
1
        return range.count() > 0 ? /* interval [0..range) */ Dur{Impl().randrange(range.count())} :
340
1
               range.count() < 0 ? /* interval (range..0] */ -Dur{Impl().randrange(-range.count())} :
341
0
                                   /* interval [0..0] */ Dur{0};
342
1
    };
std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1l>>>::duration RandomMixin<FastRandomContext>::rand_uniform_duration<std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1l>>>>(std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1l>>>::duration)
Line
Count
Source
337
7
    {
338
7
        using Dur = typename Chrono::duration;
339
7
        return range.count() > 0 ? /* interval [0..range) */ Dur{Impl().randrange(range.count())} :
340
7
               range.count() < 0 ? /* interval (range..0] */ -Dur{Impl().randrange(-range.count())} :
341
3
                                   /* interval [0..0] */ Dur{0};
342
7
    };
Unexecuted instantiation: std::chrono::time_point<NodeClock, std::chrono::duration<long, std::ratio<1l, 1l>>>::duration RandomMixin<FastRandomContext>::rand_uniform_duration<std::chrono::time_point<NodeClock, std::chrono::duration<long, std::ratio<1l, 1l>>>>(std::chrono::time_point<NodeClock, std::chrono::duration<long, std::ratio<1l, 1l>>>::duration)
Unexecuted instantiation: std::chrono::_V2::steady_clock::duration RandomMixin<FastRandomContext>::rand_uniform_duration<std::chrono::_V2::steady_clock>(std::chrono::_V2::steady_clock::duration)
std::chrono::time_point<NodeClock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>>::duration RandomMixin<FastRandomContext>::rand_uniform_duration<std::chrono::time_point<NodeClock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>>>(std::chrono::time_point<NodeClock, std::chrono::duration<long, std::ratio<1l, 1000000000l>>>::duration)
Line
Count
Source
337
5.27k
    {
338
5.27k
        using Dur = typename Chrono::duration;
339
5.27k
        return range.count() > 0 ? /* interval [0..range) */ Dur{Impl().randrange(range.count())} :
340
5.27k
               range.count() < 0 ? /* interval (range..0] */ -Dur{Impl().randrange(-range.count())} :
341
0
                                   /* interval [0..0] */ Dur{0};
342
5.27k
    };
343
344
    /** Generate a uniform random duration in the range [0..max). Precondition: max.count() > 0 */
345
    template <StdChronoDuration Dur>
346
    Dur randrange(std::common_type_t<Dur> range) noexcept
347
    // Having the compiler infer the template argument from the function argument
348
    // is dangerous, because the desired return value generally has a different
349
    // type than the function argument. So std::common_type is used to force the
350
    // call site to specify the type of the return value.
351
3.04k
    {
352
3.04k
        return Dur{Impl().randrange(range.count())};
353
3.04k
    }
std::chrono::duration<long, std::ratio<1l, 1000000l>> RandomMixin<FastRandomContext>::randrange<std::chrono::duration<long, std::ratio<1l, 1000000l>>>(std::common_type<std::chrono::duration<long, std::ratio<1l, 1000000l>>>::type)
Line
Count
Source
351
2.03k
    {
352
2.03k
        return Dur{Impl().randrange(range.count())};
353
2.03k
    }
std::chrono::duration<long, std::ratio<1l, 1000l>> RandomMixin<FastRandomContext>::randrange<std::chrono::duration<long, std::ratio<1l, 1000l>>>(std::common_type<std::chrono::duration<long, std::ratio<1l, 1000l>>>::type)
Line
Count
Source
351
1.00k
    {
352
1.00k
        return Dur{Impl().randrange(range.count())};
353
1.00k
    }
354
355
    /**
356
     * Return a duration sampled from an exponential distribution
357
     * (https://en.wikipedia.org/wiki/Exponential_distribution). Successive events
358
     * whose intervals are distributed according to this form a memoryless Poisson
359
     * process. This should be used for repeated network events (e.g. sending a
360
     * certain type of message) to minimize leaking information to observers.
361
     *
362
     * The probability of an event occurring before time x is 1 - e^-(x/a) where a
363
     * is the average interval between events.
364
     * */
365
    std::chrono::microseconds rand_exp_duration(std::chrono::microseconds mean) noexcept
366
11.3k
    {
367
11.3k
        using namespace std::chrono_literals;
368
11.3k
        auto unscaled = MakeExponentiallyDistributed(Impl().rand64());
369
11.3k
        return std::chrono::duration_cast<std::chrono::microseconds>(unscaled * mean + 0.5us);
370
11.3k
    }
371
372
    // Compatibility with the UniformRandomBitGenerator concept
373
    typedef uint64_t result_type;
374
320k
    static constexpr uint64_t min() noexcept { return 0; }
375
320k
    static constexpr uint64_t max() noexcept { return std::numeric_limits<uint64_t>::max(); }
376
1.95M
    inline uint64_t operator()() noexcept { return Impl().rand64(); }
RandomMixin<FastRandomContext>::operator()()
Line
Count
Source
376
1.95M
    inline uint64_t operator()() noexcept { return Impl().rand64(); }
RandomMixin<InsecureRandomContext>::operator()()
Line
Count
Source
376
8
    inline uint64_t operator()() noexcept { return Impl().rand64(); }
377
};
378
379
/**
380
 * Fast randomness source. This is seeded once with secure random data, but
381
 * is completely deterministic and does not gather more entropy after that.
382
 *
383
 * This class is not thread-safe.
384
 */
385
class FastRandomContext : public RandomMixin<FastRandomContext>
386
{
387
private:
388
    bool requires_seed;
389
    ChaCha20 rng;
390
391
    void RandomSeed() noexcept;
392
393
public:
394
    /** Construct a FastRandomContext with GetRandHash()-based entropy (or zero key if fDeterministic). */
395
    explicit FastRandomContext(bool fDeterministic = false) noexcept;
396
397
    /** Initialize with explicit seed (only for testing) */
398
    explicit FastRandomContext(const uint256& seed) noexcept;
399
400
    /** Reseed with explicit seed (only for testing). */
401
    void Reseed(const uint256& seed) noexcept;
402
403
    /** Generate a random 64-bit integer. */
404
    uint64_t rand64() noexcept
405
33.8M
    {
406
33.8M
        if (requires_seed) RandomSeed();
407
33.8M
        std::array<std::byte, 8> buf;
408
33.8M
        rng.Keystream(buf);
409
33.8M
        return ReadLE64(buf.data());
410
33.8M
    }
411
412
    /** Fill a byte span with random bytes. This overrides the RandomMixin version. */
413
    void fillrand(std::span<std::byte> output) noexcept;
414
};
415
416
/** xoroshiro128++ PRNG. Extremely fast, not appropriate for cryptographic purposes.
417
 *
418
 * Memory footprint is very small, period is 2^128 - 1.
419
 * This class is not thread-safe.
420
 *
421
 * Reference implementation available at https://prng.di.unimi.it/xoroshiro128plusplus.c
422
 * See https://prng.di.unimi.it/
423
 */
424
class InsecureRandomContext : public RandomMixin<InsecureRandomContext>
425
{
426
    uint64_t m_s0;
427
    uint64_t m_s1;
428
429
    [[nodiscard]] constexpr static uint64_t SplitMix64(uint64_t& seedval) noexcept
430
382k
    {
431
382k
        uint64_t z = (seedval += 0x9e3779b97f4a7c15);
432
382k
        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
433
382k
        z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
434
382k
        return z ^ (z >> 31);
435
382k
    }
436
437
public:
438
    constexpr explicit InsecureRandomContext(uint64_t seedval) noexcept
439
191k
        : m_s0(SplitMix64(seedval)), m_s1(SplitMix64(seedval)) {}
440
441
    constexpr void Reseed(uint64_t seedval) noexcept
442
1
    {
443
1
        FlushCache();
444
1
        m_s0 = SplitMix64(seedval);
445
1
        m_s1 = SplitMix64(seedval);
446
1
    }
447
448
    constexpr uint64_t rand64() noexcept
449
14.3M
    {
450
14.3M
        uint64_t s0 = m_s0, s1 = m_s1;
451
14.3M
        const uint64_t result = std::rotl(s0 + s1, 17) + s0;
452
14.3M
        s1 ^= s0;
453
14.3M
        m_s0 = std::rotl(s0, 49) ^ s1 ^ (s1 << 21);
454
14.3M
        m_s1 = std::rotl(s1, 28);
455
14.3M
        return result;
456
14.3M
    }
457
};
458
459
460
/* ==================== CONVENIENCE FUNCTIONS FOR COMMONLY USED RANDOMNESS ==================== */
461
462
/** Generate a random uint256. */
463
inline uint256 GetRandHash() noexcept
464
1.90M
{
465
1.90M
    uint256 hash;
466
1.90M
    GetRandBytes(hash);
467
1.90M
    return hash;
468
1.90M
}
469
470
/* ============================= MISCELLANEOUS TEST-ONLY FUNCTIONS ============================= */
471
472
/** Check that OS randomness is available and returning the requested number
473
 * of bytes.
474
 */
475
bool Random_SanityCheck();
476
477
#endif // BITCOIN_RANDOM_H