Bitcoin Core  27.99.0
P2P Digital Currency
random.h
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2022 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #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 
75 /* ============================= INITIALIZATION AND ADDING ENTROPY ============================= */
76 
83 void RandomInit();
84 
90 void RandAddPeriodic() noexcept;
91 
98 void RandAddEvent(const 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 
117 void GetRandBytes(Span<unsigned char> bytes) noexcept;
118 
129 void GetStrongRandBytes(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 
146 template<typename T>
147 concept RandomNumberGenerator = requires(T& rng, 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 
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 
162 double MakeExponentiallyDistributed(uint64_t uniform) noexcept;
163 
173 template<typename T>
175 {
176 private:
177  uint64_t bitbuf{0};
178  int bitbuf_size{0};
179 
185  RandomNumberGenerator auto& Impl() noexcept { return static_cast<T&>(*this); }
186 
187 protected:
188  constexpr void FlushCache() noexcept
189  {
190  bitbuf = 0;
191  bitbuf_size = 0;
192  }
193 
194 public:
195  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;
201  RandomMixin& operator=(RandomMixin&&) = delete;
202 
204  uint64_t randbits(int bits) noexcept
205  {
206  Assume(bits <= 64);
207  // Requests for the full 64 bits are passed through.
208  if (bits == 64) return Impl().rand64();
209  uint64_t ret;
210  if (bits <= bitbuf_size) {
211  // If there is enough entropy left in bitbuf, return its bottom bits bits.
212  ret = bitbuf;
213  bitbuf >>= bits;
214  bitbuf_size -= bits;
215  } 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  uint64_t gen = Impl().rand64();
220  ret = (gen << bitbuf_size) | bitbuf;
221  bitbuf = gen >> (bits - bitbuf_size);
222  bitbuf_size = 64 + bitbuf_size - bits;
223  }
224  // Return the bottom bits bits of ret.
225  return ret & ((uint64_t{1} << bits) - 1);
226  }
227 
229  template<int Bits>
230  uint64_t randbits() noexcept
231  {
232  static_assert(Bits >= 0 && Bits <= 64);
233  if constexpr (Bits == 64) {
234  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  }
251 
253  template<std::integral I>
254  I randrange(I range) noexcept
255  {
256  static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
257  Assume(range > 0);
258  uint64_t maxval = range - 1U;
259  int bits = std::bit_width(maxval);
260  while (true) {
261  uint64_t ret = Impl().randbits(bits);
262  if (ret <= maxval) return ret;
263  }
264  }
265 
267  void fillrand(Span<std::byte> span) noexcept
268  {
269  while (span.size() >= 8) {
270  uint64_t gen = Impl().rand64();
271  WriteLE64(UCharCast(span.data()), gen);
272  span = span.subspan(8);
273  }
274  if (span.size() >= 4) {
275  uint32_t gen = Impl().rand32();
276  WriteLE32(UCharCast(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 
286  template<std::integral I>
287  I rand() noexcept
288  {
289  static_assert(std::numeric_limits<I>::max() <= std::numeric_limits<uint64_t>::max());
290  static constexpr auto BITS = std::bit_width(uint64_t(std::numeric_limits<I>::max()));
291  static_assert(std::numeric_limits<I>::max() == std::numeric_limits<uint64_t>::max() >> (64 - BITS));
292  return I(Impl().template randbits<BITS>());
293  }
294 
296  template <BasicByte B = unsigned char>
297  std::vector<B> randbytes(size_t len) noexcept
298  {
299  std::vector<B> ret(len);
300  Impl().fillrand(MakeWritableByteSpan(ret));
301  return ret;
302  }
303 
305  uint32_t rand32() noexcept { return Impl().template randbits<32>(); }
306 
308  uint256 rand256() noexcept
309  {
310  uint256 ret;
311  Impl().fillrand(MakeWritableByteSpan(ret));
312  return ret;
313  }
314 
316  bool randbool() noexcept { return Impl().template randbits<1>(); }
317 
319  template <typename Tp>
320  Tp rand_uniform_delay(const Tp& time, typename Tp::duration range) noexcept
321  {
322  return time + Impl().template rand_uniform_duration<Tp>(range);
323  }
324 
326  template <typename Chrono> requires StdChronoDuration<typename Chrono::duration>
327  typename Chrono::duration rand_uniform_duration(typename Chrono::duration range) noexcept
328  {
329  using Dur = typename Chrono::duration;
330  return range.count() > 0 ? /* interval [0..range) */ Dur{Impl().randrange(range.count())} :
331  range.count() < 0 ? /* interval (range..0] */ -Dur{Impl().randrange(-range.count())} :
332  /* interval [0..0] */ Dur{0};
333  };
334 
336  template <StdChronoDuration Dur>
337  Dur randrange(typename std::common_type_t<Dur> range) noexcept
338  // Having the compiler infer the template argument from the function argument
339  // is dangerous, because the desired return value generally has a different
340  // type than the function argument. So std::common_type is used to force the
341  // call site to specify the type of the return value.
342  {
343  return Dur{Impl().randrange(range.count())};
344  }
345 
356  std::chrono::microseconds rand_exp_duration(std::chrono::microseconds mean) noexcept
357  {
358  using namespace std::chrono_literals;
359  auto unscaled = MakeExponentiallyDistributed(Impl().rand64());
360  return std::chrono::duration_cast<std::chrono::microseconds>(unscaled * mean + 0.5us);
361  }
362 
363  // Compatibility with the UniformRandomBitGenerator concept
364  typedef uint64_t result_type;
365  static constexpr uint64_t min() noexcept { return 0; }
366  static constexpr uint64_t max() noexcept { return std::numeric_limits<uint64_t>::max(); }
367  inline uint64_t operator()() noexcept { return Impl().rand64(); }
368 };
369 
376 class FastRandomContext : public RandomMixin<FastRandomContext>
377 {
378 private:
381 
382  void RandomSeed() noexcept;
383 
384 public:
386  explicit FastRandomContext(bool fDeterministic = false) noexcept;
387 
389  explicit FastRandomContext(const uint256& seed) noexcept;
390 
392  void Reseed(const uint256& seed) noexcept;
393 
395  uint64_t rand64() noexcept
396  {
397  if (requires_seed) RandomSeed();
398  std::array<std::byte, 8> buf;
399  rng.Keystream(buf);
400  return ReadLE64(UCharCast(buf.data()));
401  }
402 
404  void fillrand(Span<std::byte> output) noexcept;
405 };
406 
415 class InsecureRandomContext : public RandomMixin<InsecureRandomContext>
416 {
417  uint64_t m_s0;
418  uint64_t m_s1;
419 
420  [[nodiscard]] constexpr static uint64_t SplitMix64(uint64_t& seedval) noexcept
421  {
422  uint64_t z = (seedval += 0x9e3779b97f4a7c15);
423  z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
424  z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
425  return z ^ (z >> 31);
426  }
427 
428 public:
429  constexpr explicit InsecureRandomContext(uint64_t seedval) noexcept
430  : m_s0(SplitMix64(seedval)), m_s1(SplitMix64(seedval)) {}
431 
432  constexpr void Reseed(uint64_t seedval) noexcept
433  {
434  FlushCache();
435  m_s0 = SplitMix64(seedval);
436  m_s1 = SplitMix64(seedval);
437  }
438 
439  constexpr uint64_t rand64() noexcept
440  {
441  uint64_t s0 = m_s0, s1 = m_s1;
442  const uint64_t result = std::rotl(s0 + s1, 17) + s0;
443  s1 ^= s0;
444  m_s0 = std::rotl(s0, 49) ^ s1 ^ (s1 << 21);
445  m_s1 = std::rotl(s1, 28);
446  return result;
447  }
448 };
449 
450 
451 /* ==================== CONVENIENCE FUNCTIONS FOR COMMONLY USED RANDOMNESS ==================== */
452 
454 inline uint256 GetRandHash() noexcept
455 {
456  uint256 hash;
457  GetRandBytes(hash);
458  return hash;
459 }
460 
461 /* ============================= MISCELLANEOUS TEST-ONLY FUNCTIONS ============================= */
462 
466 bool Random_SanityCheck();
467 
468 #endif // BITCOIN_RANDOM_H
int ret
#define Assume(val)
Assume is the identity function.
Definition: check.h:89
Unrestricted ChaCha20 cipher.
Definition: chacha20.h:78
void Keystream(Span< std::byte > out) noexcept
outputs the keystream to out.
Definition: chacha20.cpp:282
Fast randomness source.
Definition: random.h:377
ChaCha20 rng
Definition: random.h:380
bool requires_seed
Definition: random.h:379
xoroshiro128++ PRNG.
Definition: random.h:416
constexpr uint64_t rand64() noexcept
Definition: random.h:439
constexpr void Reseed(uint64_t seedval) noexcept
Definition: random.h:432
constexpr InsecureRandomContext(uint64_t seedval) noexcept
Definition: random.h:429
constexpr static uint64_t SplitMix64(uint64_t &seedval) noexcept
Definition: random.h:420
Mixin class that provides helper randomness functions.
Definition: random.h:175
static constexpr uint64_t max() noexcept
Definition: random.h:366
constexpr RandomMixin() noexcept=default
Dur randrange(typename std::common_type_t< Dur > range) noexcept
Generate a uniform random duration in the range [0..max).
Definition: random.h:337
void fillrand(Span< std::byte > span) noexcept
Fill a Span with random bytes.
Definition: random.h:267
Tp rand_uniform_delay(const Tp &time, typename Tp::duration range) noexcept
Return the time point advanced by a uniform random duration.
Definition: random.h:320
I randrange(I range) noexcept
Generate a random integer in the range [0..range), with range > 0.
Definition: random.h:254
int bitbuf_size
Definition: random.h:178
uint256 rand256() noexcept
generate a random uint256.
Definition: random.h:308
uint64_t result_type
Definition: random.h:364
uint64_t bitbuf
Definition: random.h:177
RandomNumberGenerator auto & Impl() noexcept
Access the underlying generator.
Definition: random.h:185
bool randbool() noexcept
Generate a random boolean.
Definition: random.h:316
I rand() noexcept
Generate a random integer in its entire (non-negative) range.
Definition: random.h:287
constexpr void FlushCache() noexcept
Definition: random.h:188
std::chrono::microseconds rand_exp_duration(std::chrono::microseconds mean) noexcept
Return a duration sampled from an exponential distribution (https://en.wikipedia.org/wiki/Exponential...
Definition: random.h:356
static constexpr uint64_t min() noexcept
Definition: random.h:365
std::vector< B > randbytes(size_t len) noexcept
Generate random bytes.
Definition: random.h:297
uint32_t rand32() noexcept
Generate a random 32-bit integer.
Definition: random.h:305
uint64_t randbits() noexcept
Same as above, but with compile-time fixed bits count.
Definition: random.h:230
requires StdChronoDuration< typename Chrono::duration > Chrono::duration rand_uniform_duration(typename Chrono::duration range) noexcept
Generate a uniform random duration in the range from 0 (inclusive) to range (exclusive).
Definition: random.h:327
uint64_t operator()() noexcept
Definition: random.h:367
A Span is an object that can refer to a contiguous sequence of objects.
Definition: span.h:98
256-bit opaque blob.
Definition: uint256.h:127
static uint64_t ReadLE64(const unsigned char *ptr)
Definition: common.h:27
static void WriteLE32(unsigned char *ptr, uint32_t x)
Definition: common.h:40
static void WriteLE64(unsigned char *ptr, uint64_t x)
Definition: common.h:46
void GetRandBytes(Span< unsigned char > bytes) noexcept
Generate random data via the internal PRNG.
Definition: random.cpp:675
void RandAddPeriodic() noexcept
Gather entropy from various expensive sources, and feed them to the PRNG state.
Definition: random.cpp:685
concept StdChronoDuration
A concept for C++ std::chrono durations.
Definition: random.h:156
void GetStrongRandBytes(Span< unsigned char > bytes) noexcept
Gather entropy from various sources, feed it into the internal PRNG, and generate random data using i...
Definition: random.cpp:680
bool Random_SanityCheck()
Check that OS randomness is available and returning the requested number of bytes.
Definition: random.cpp:714
uint256 GetRandHash() noexcept
Generate a random uint256.
Definition: random.h:454
void RandomInit()
Overall design of the RNG and entropy sources.
Definition: random.cpp:769
concept RandomNumberGenerator
A concept for RandomMixin-based random number generators.
Definition: random.h:147
void RandAddEvent(const uint32_t event_info) noexcept
Gathers entropy from the low bits of the time at which events occur.
Definition: random.cpp:690
double MakeExponentiallyDistributed(uint64_t uniform) noexcept
Given a uniformly random uint64_t, return an exponentially distributed double with mean 1.
Definition: random.cpp:777
unsigned char * UCharCast(char *c)
Definition: span.h:288
Span< std::byte > MakeWritableByteSpan(V &&v) noexcept
Definition: span.h:282
static SECP256K1_INLINE uint64_t rotl(const uint64_t x, int k)
Definition: testrand_impl.h:39