diff options
author | Pieter Wuille <pieter@wuille.net> | 2024-03-10 15:16:20 -0400 |
---|---|---|
committer | Pieter Wuille <pieter@wuille.net> | 2024-07-01 10:26:46 -0400 |
commit | 6cfdc5b104caf9952393f9dac2a36539d964077f (patch) | |
tree | 1cef33e30adb25e9bef98e9eab2561d0c58f2f04 /src/random.h | |
parent | 8cc2f45065fc1864f879248d1e1444588e27076b (diff) |
random: convert XoRoShiRo128PlusPlus into full RNG
Convert XoRoShiRo128PlusPlus into a full RandomMixin-based RNG class,
providing all utility functionality that FastRandomContext has. In doing so,
it is renamed to InsecureRandomContext, highlighting its non-cryptographic
nature.
To do this, a fillrand fallback is added to RandomMixin (where it is used by
InsecureRandomContext), but FastRandomContext still uses its own fillrand.
Diffstat (limited to 'src/random.h')
-rw-r--r-- | src/random.h | 45 |
1 files changed, 28 insertions, 17 deletions
diff --git a/src/random.h b/src/random.h index e870867170..cdf2f3a66d 100644 --- a/src/random.h +++ b/src/random.h @@ -147,8 +147,6 @@ template<typename T> concept RandomNumberGenerator = requires(T& rng, Span<std::byte> s) { // A random number generator must provide rand64(). { rng.rand64() } noexcept -> std::same_as<uint64_t>; - // A random number generator must provide randfill(Span<std::byte>). - { rng.fillrand(s) } noexcept; // A random number generator must derive from RandomMixin, which adds other rand* functions. requires std::derived_from<std::remove_reference_t<T>, RandomMixin<std::remove_reference_t<T>>>; }; @@ -261,6 +259,25 @@ public: } } + /** Fill a Span with random bytes. */ + void fillrand(Span<std::byte> span) noexcept + { + while (span.size() >= 8) { + uint64_t gen = Impl().rand64(); + WriteLE64(UCharCast(span.data()), gen); + span = span.subspan(8); + } + if (span.size() >= 4) { + uint32_t gen = Impl().rand32(); + WriteLE32(UCharCast(span.data()), gen); + span = span.subspan(4); + } + while (span.size()) { + span[0] = std::byte(Impl().template randbits<8>()); + span = span.subspan(1); + } + } + /** Generate random bytes. */ template <BasicByte B = unsigned char> std::vector<B> randbytes(size_t len) noexcept @@ -345,19 +362,19 @@ public: return ReadLE64(UCharCast(buf.data())); } - /** Fill a byte Span with random bytes. */ + /** Fill a byte Span with random bytes. This overrides the RandomMixin version. */ void fillrand(Span<std::byte> output) noexcept; }; /** xoroshiro128++ PRNG. Extremely fast, not appropriate for cryptographic purposes. * - * Memory footprint is 128bit, period is 2^128 - 1. + * Memory footprint is very small, period is 2^128 - 1. * This class is not thread-safe. * * Reference implementation available at https://prng.di.unimi.it/xoroshiro128plusplus.c * See https://prng.di.unimi.it/ */ -class XoRoShiRo128PlusPlus +class InsecureRandomContext : public RandomMixin<InsecureRandomContext> { uint64_t m_s0; uint64_t m_s1; @@ -371,21 +388,19 @@ class XoRoShiRo128PlusPlus } public: - using result_type = uint64_t; - - constexpr explicit XoRoShiRo128PlusPlus(uint64_t seedval) noexcept + constexpr explicit InsecureRandomContext(uint64_t seedval) noexcept : m_s0(SplitMix64(seedval)), m_s1(SplitMix64(seedval)) {} // no copy - that is dangerous, we don't want accidentally copy the RNG and then have two streams // with exactly the same results. - XoRoShiRo128PlusPlus(const XoRoShiRo128PlusPlus&) = delete; - XoRoShiRo128PlusPlus& operator=(const XoRoShiRo128PlusPlus&) = delete; + InsecureRandomContext(const InsecureRandomContext&) = delete; + InsecureRandomContext& operator=(const InsecureRandomContext&) = delete; // allow moves - XoRoShiRo128PlusPlus(XoRoShiRo128PlusPlus&&) = default; - XoRoShiRo128PlusPlus& operator=(XoRoShiRo128PlusPlus&&) = default; + InsecureRandomContext(InsecureRandomContext&&) = default; + InsecureRandomContext& operator=(InsecureRandomContext&&) = default; - constexpr result_type operator()() noexcept + constexpr uint64_t rand64() noexcept { uint64_t s0 = m_s0, s1 = m_s1; const uint64_t result = std::rotl(s0 + s1, 17) + s0; @@ -394,10 +409,6 @@ public: m_s1 = std::rotl(s1, 28); return result; } - - static constexpr result_type min() noexcept { return std::numeric_limits<result_type>::min(); } - static constexpr result_type max() noexcept { return std::numeric_limits<result_type>::max(); } - static constexpr double entropy() noexcept { return 0.0; } }; /** More efficient than using std::shuffle on a FastRandomContext. |