Skip to content

Commit 5f05b27

Browse files
martinussipa
andcommitted
Add xoroshiro128++ PRNG
Xoroshiro128++ is a fast non-cryptographic random generator. Reference implementation is available at https://prng.di.unimi.it/ Co-Authored-By: Pieter Wuille <[email protected]>
1 parent 12ff724 commit 5f05b27

File tree

5 files changed

+106
-2
lines changed

5 files changed

+106
-2
lines changed

src/Makefile.test.include

+2-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ BITCOIN_TESTS =\
162162
test/validation_flush_tests.cpp \
163163
test/validation_tests.cpp \
164164
test/validationinterface_tests.cpp \
165-
test/versionbits_tests.cpp
165+
test/versionbits_tests.cpp \
166+
test/xoroshiro128plusplus_tests.cpp
166167

167168
if ENABLE_WALLET
168169
BITCOIN_TESTS += \

src/Makefile.test_util.include

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ TEST_UTIL_H = \
1818
test/util/str.h \
1919
test/util/transaction_utils.h \
2020
test/util/txmempool.h \
21-
test/util/validation.h
21+
test/util/validation.h \
22+
test/util/xoroshiro128plusplus.h
2223

2324
if ENABLE_WALLET
2425
TEST_UTIL_H += wallet/test/util.h

src/test/util/xoroshiro128plusplus.h

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright (c) 2022 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_TEST_UTIL_XOROSHIRO128PLUSPLUS_H
6+
#define BITCOIN_TEST_UTIL_XOROSHIRO128PLUSPLUS_H
7+
8+
#include <cstdint>
9+
#include <limits>
10+
11+
/** xoroshiro128++ PRNG. Extremely fast, not appropriate for cryptographic purposes.
12+
*
13+
* Memory footprint is 128bit, period is 2^128 - 1.
14+
* This class is not thread-safe.
15+
*
16+
* Reference implementation available at https://prng.di.unimi.it/xoroshiro128plusplus.c
17+
* See https://prng.di.unimi.it/
18+
*/
19+
class XoRoShiRo128PlusPlus
20+
{
21+
uint64_t m_s0;
22+
uint64_t m_s1;
23+
24+
[[nodiscard]] constexpr static uint64_t rotl(uint64_t x, int n)
25+
{
26+
return (x << n) | (x >> (64 - n));
27+
}
28+
29+
[[nodiscard]] constexpr static uint64_t SplitMix64(uint64_t& seedval) noexcept
30+
{
31+
uint64_t z = (seedval += UINT64_C(0x9e3779b97f4a7c15));
32+
z = (z ^ (z >> 30U)) * UINT64_C(0xbf58476d1ce4e5b9);
33+
z = (z ^ (z >> 27U)) * UINT64_C(0x94d049bb133111eb);
34+
return z ^ (z >> 31U);
35+
}
36+
37+
public:
38+
using result_type = uint64_t;
39+
40+
constexpr explicit XoRoShiRo128PlusPlus(uint64_t seedval) noexcept
41+
: m_s0(SplitMix64(seedval)), m_s1(SplitMix64(seedval))
42+
{
43+
}
44+
45+
// no copy - that is dangerous, we don't want accidentally copy the RNG and then have two streams
46+
// with exactly the same results. If you need a copy, call copy().
47+
XoRoShiRo128PlusPlus(const XoRoShiRo128PlusPlus&) = delete;
48+
XoRoShiRo128PlusPlus& operator=(const XoRoShiRo128PlusPlus&) = delete;
49+
50+
// allow moves
51+
XoRoShiRo128PlusPlus(XoRoShiRo128PlusPlus&&) = default;
52+
XoRoShiRo128PlusPlus& operator=(XoRoShiRo128PlusPlus&&) = default;
53+
54+
~XoRoShiRo128PlusPlus() = default;
55+
56+
constexpr result_type operator()() noexcept
57+
{
58+
uint64_t s0 = m_s0, s1 = m_s1;
59+
const uint64_t result = rotl(s0 + s1, 17) + s0;
60+
s1 ^= s0;
61+
m_s0 = rotl(s0, 49) ^ s1 ^ (s1 << 21);
62+
m_s1 = rotl(s1, 28);
63+
return result;
64+
}
65+
66+
static constexpr result_type min() noexcept { return std::numeric_limits<result_type>::min(); }
67+
static constexpr result_type max() noexcept { return std::numeric_limits<result_type>::max(); }
68+
static constexpr double entropy() noexcept { return 0.0; }
69+
};
70+
71+
#endif // BITCOIN_TEST_UTIL_XOROSHIRO128PLUSPLUS_H
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright (c) 2022 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <test/util/setup_common.h>
6+
#include <test/util/xoroshiro128plusplus.h>
7+
8+
#include <boost/test/unit_test.hpp>
9+
10+
BOOST_FIXTURE_TEST_SUITE(xoroshiro128plusplus_tests, BasicTestingSetup)
11+
12+
BOOST_AUTO_TEST_CASE(reference_values)
13+
{
14+
// numbers generated from reference implementation
15+
XoRoShiRo128PlusPlus rng(0);
16+
BOOST_TEST(0x6f68e1e7e2646ee1 == rng());
17+
BOOST_TEST(0xbf971b7f454094ad == rng());
18+
BOOST_TEST(0x48f2de556f30de38 == rng());
19+
BOOST_TEST(0x6ea7c59f89bbfc75 == rng());
20+
21+
// seed with a random number
22+
rng = XoRoShiRo128PlusPlus(0x1a26f3fa8546b47a);
23+
BOOST_TEST(0xc8dc5e08d844ac7d == rng());
24+
BOOST_TEST(0x5b5f1f6d499dad1b == rng());
25+
BOOST_TEST(0xbeb0031f93313d6f == rng());
26+
BOOST_TEST(0xbfbcf4f43a264497 == rng());
27+
}
28+
29+
BOOST_AUTO_TEST_SUITE_END()

test/sanitizer_suppressions/ubsan

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ unsigned-integer-overflow:policy/fees.cpp
5353
unsigned-integer-overflow:prevector.h
5454
unsigned-integer-overflow:script/interpreter.cpp
5555
unsigned-integer-overflow:txmempool.cpp
56+
unsigned-integer-overflow:xoroshiro128plusplus.h
5657
implicit-integer-sign-change:compat/stdin.cpp
5758
implicit-integer-sign-change:compressor.h
5859
implicit-integer-sign-change:crypto/
@@ -69,3 +70,4 @@ shift-base:crypto/
6970
shift-base:hash.cpp
7071
shift-base:streams.h
7172
shift-base:util/bip32.cpp
73+
shift-base:xoroshiro128plusplus.h

0 commit comments

Comments
 (0)