Bitcoin Core  28.1.0
P2P Digital Currency
random_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017-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 <random.h>
6 
7 #include <test/util/random.h>
9 #include <util/time.h>
10 
11 #include <boost/test/unit_test.hpp>
12 
13 #include <algorithm>
14 #include <random>
15 
16 BOOST_FIXTURE_TEST_SUITE(random_tests, BasicTestingSetup)
17 
18 BOOST_AUTO_TEST_CASE(osrandom_tests)
19 {
21 }
22 
23 BOOST_AUTO_TEST_CASE(fastrandom_tests_deterministic)
24 {
25  // Check that deterministic FastRandomContexts are deterministic
27  FastRandomContext ctx1{true};
28  FastRandomContext ctx2{true};
29 
30  {
31  BOOST_CHECK_EQUAL(FastRandomContext().rand<uint64_t>(), uint64_t{9330418229102544152u});
32  BOOST_CHECK_EQUAL(FastRandomContext().rand<int>(), int{618925161});
33  BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::microseconds>(1h).count(), 1271170921);
34  BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count(), 2803534);
35 
36  BOOST_CHECK_EQUAL(FastRandomContext().rand<uint64_t>(), uint64_t{10170981140880778086u});
37  BOOST_CHECK_EQUAL(FastRandomContext().rand<int>(), int{1689082725});
38  BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::microseconds>(1h).count(), 2464643716);
39  BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count(), 2312205);
40 
41  BOOST_CHECK_EQUAL(FastRandomContext().rand<uint64_t>(), uint64_t{5689404004456455543u});
42  BOOST_CHECK_EQUAL(FastRandomContext().rand<int>(), int{785839937});
43  BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::microseconds>(1h).count(), 93558804);
44  BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count(), 507022);
45  }
46 
47  {
48  constexpr SteadySeconds time_point{1s};
49  FastRandomContext ctx{true};
50  BOOST_CHECK_EQUAL(7, ctx.rand_uniform_delay(time_point, 9s).time_since_epoch().count());
51  BOOST_CHECK_EQUAL(-6, ctx.rand_uniform_delay(time_point, -9s).time_since_epoch().count());
52  BOOST_CHECK_EQUAL(1, ctx.rand_uniform_delay(time_point, 0s).time_since_epoch().count());
53  BOOST_CHECK_EQUAL(4652286523065884857, ctx.rand_uniform_delay(time_point, 9223372036854775807s).time_since_epoch().count());
54  BOOST_CHECK_EQUAL(-8813961240025683129, ctx.rand_uniform_delay(time_point, -9223372036854775807s).time_since_epoch().count());
55  BOOST_CHECK_EQUAL(26443, ctx.rand_uniform_delay(time_point, 9h).time_since_epoch().count());
56  }
57  BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
58  BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
59  BOOST_CHECK_EQUAL(ctx1.rand64(), ctx2.rand64());
60  BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));
61  BOOST_CHECK(ctx1.randbytes(17) == ctx2.randbytes(17));
62  BOOST_CHECK(ctx1.rand256() == ctx2.rand256());
63  BOOST_CHECK_EQUAL(ctx1.randbits(7), ctx2.randbits(7));
64  BOOST_CHECK(ctx1.randbytes(128) == ctx2.randbytes(128));
65  BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
66  BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));
67  BOOST_CHECK(ctx1.rand256() == ctx2.rand256());
68  BOOST_CHECK(ctx1.randbytes(50) == ctx2.randbytes(50));
69  {
70  struct MicroClock {
71  using duration = std::chrono::microseconds;
72  };
73  FastRandomContext ctx{true};
74  // Check with clock type
75  BOOST_CHECK_EQUAL(47222, ctx.rand_uniform_duration<MicroClock>(1s).count());
76  // Check with time-point type
77  BOOST_CHECK_EQUAL(2782, ctx.rand_uniform_duration<SteadySeconds>(9h).count());
78  }
79 }
80 
81 BOOST_AUTO_TEST_CASE(fastrandom_tests_nondeterministic)
82 {
83  // Check that a nondeterministic ones are not
84  {
85  BOOST_CHECK(FastRandomContext().rand<uint64_t>() != uint64_t{9330418229102544152u});
86  BOOST_CHECK(FastRandomContext().rand<int>() != int{618925161});
87  BOOST_CHECK(FastRandomContext().randrange<std::chrono::microseconds>(1h).count() != 1271170921);
88  BOOST_CHECK(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count() != 2803534);
89 
90  BOOST_CHECK(FastRandomContext().rand<uint64_t>() != uint64_t{10170981140880778086u});
91  BOOST_CHECK(FastRandomContext().rand<int>() != int{1689082725});
92  BOOST_CHECK(FastRandomContext().randrange<std::chrono::microseconds>(1h).count() != 2464643716);
93  BOOST_CHECK(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count() != 2312205);
94 
95  BOOST_CHECK(FastRandomContext().rand<uint64_t>() != uint64_t{5689404004456455543u});
96  BOOST_CHECK(FastRandomContext().rand<int>() != int{785839937});
97  BOOST_CHECK(FastRandomContext().randrange<std::chrono::microseconds>(1h).count() != 93558804);
98  BOOST_CHECK(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count() != 507022);
99  }
100 
101  {
102  FastRandomContext ctx3, ctx4;
103  BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal
104  }
105  {
106  FastRandomContext ctx3, ctx4;
107  BOOST_CHECK(ctx3.rand256() != ctx4.rand256());
108  }
109  {
110  FastRandomContext ctx3, ctx4;
111  BOOST_CHECK(ctx3.randbytes(7) != ctx4.randbytes(7));
112  }
113 }
114 
115 BOOST_AUTO_TEST_CASE(fastrandom_randbits)
116 {
117  FastRandomContext ctx1;
118  FastRandomContext ctx2;
119  for (int bits = 0; bits < 63; ++bits) {
120  for (int j = 0; j < 1000; ++j) {
121  uint64_t rangebits = ctx1.randbits(bits);
122  BOOST_CHECK_EQUAL(rangebits >> bits, 0U);
123  uint64_t range = (uint64_t{1}) << bits | rangebits;
124  uint64_t rand = ctx2.randrange(range);
125  BOOST_CHECK(rand < range);
126  }
127  }
128 }
129 
131 BOOST_AUTO_TEST_CASE(randbits_test)
132 {
133  FastRandomContext ctx_lens;
134  FastRandomContext ctx_test1(true), ctx_test2(true);
135  int ctx_test_bitsleft{0};
136 
137  // Run the entire test 5 times.
138  for (int i = 0; i < 5; ++i) {
139  // count (first) how often it has occurred, and (second) how often it was true:
140  // - for every bit position, in every requested bits count (0 + 1 + 2 + ... + 64 = 2080)
141  // - for every value of ctx_test_bitsleft (0..63 = 64)
142  std::vector<std::pair<uint64_t, uint64_t>> seen(2080 * 64);
143  while (true) {
144  // Loop 1000 times, just to not continuously check std::all_of.
145  for (int j = 0; j < 1000; ++j) {
146  // Decide on a number of bits to request (0 through 64, inclusive; don't use randbits/randrange).
147  int bits = ctx_lens.rand64() % 65;
148  // Generate that many bits.
149  uint64_t gen = ctx_test1.randbits(bits);
150  // For certain bits counts, also test randbits<Bits> and compare.
151  uint64_t gen2;
152  if (bits == 0) {
153  gen2 = ctx_test2.randbits<0>();
154  } else if (bits == 1) {
155  gen2 = ctx_test2.randbits<1>();
156  } else if (bits == 7) {
157  gen2 = ctx_test2.randbits<7>();
158  } else if (bits == 32) {
159  gen2 = ctx_test2.randbits<32>();
160  } else if (bits == 51) {
161  gen2 = ctx_test2.randbits<51>();
162  } else if (bits == 64) {
163  gen2 = ctx_test2.randbits<64>();
164  } else {
165  gen2 = ctx_test2.randbits(bits);
166  }
167  BOOST_CHECK_EQUAL(gen, gen2);
168  // Make sure the result is in range.
169  if (bits < 64) BOOST_CHECK_EQUAL(gen >> bits, 0);
170  // Mark all the seen bits in the output.
171  for (int bit = 0; bit < bits; ++bit) {
172  int idx = bit + (bits * (bits - 1)) / 2 + 2080 * ctx_test_bitsleft;
173  seen[idx].first += 1;
174  seen[idx].second += (gen >> bit) & 1;
175  }
176  // Update ctx_test_bitself.
177  if (bits > ctx_test_bitsleft) {
178  ctx_test_bitsleft = ctx_test_bitsleft + 64 - bits;
179  } else {
180  ctx_test_bitsleft -= bits;
181  }
182  }
183  // Loop until every bit position/combination is seen 242 times.
184  if (std::all_of(seen.begin(), seen.end(), [](const auto& x) { return x.first >= 242; })) break;
185  }
186  // Check that each bit appears within 7.78 standard deviations of 50%
187  // (each will fail with P < 1/(2080 * 64 * 10^9)).
188  for (const auto& val : seen) {
189  assert(fabs(val.first * 0.5 - val.second) < sqrt(val.first * 0.25) * 7.78);
190  }
191  }
192 }
193 
195 BOOST_AUTO_TEST_CASE(stdrandom_test)
196 {
197  FastRandomContext ctx;
198  std::uniform_int_distribution<int> distribution(3, 9);
199  for (int i = 0; i < 100; ++i) {
200  int x = distribution(ctx);
201  BOOST_CHECK(x >= 3);
202  BOOST_CHECK(x <= 9);
203 
204  std::vector<int> test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
205  std::shuffle(test.begin(), test.end(), ctx);
206  for (int j = 1; j <= 10; ++j) {
207  BOOST_CHECK(std::find(test.begin(), test.end(), j) != test.end());
208  }
209  }
210 }
211 
213 BOOST_AUTO_TEST_CASE(shuffle_stat_test)
214 {
215  FastRandomContext ctx(true);
216  uint32_t counts[5 * 5 * 5 * 5 * 5] = {0};
217  for (int i = 0; i < 12000; ++i) {
218  int data[5] = {0, 1, 2, 3, 4};
219  std::shuffle(std::begin(data), std::end(data), ctx);
220  int pos = data[0] + data[1] * 5 + data[2] * 25 + data[3] * 125 + data[4] * 625;
221  ++counts[pos];
222  }
223  unsigned int sum = 0;
224  double chi_score = 0.0;
225  for (int i = 0; i < 5 * 5 * 5 * 5 * 5; ++i) {
226  int i1 = i % 5, i2 = (i / 5) % 5, i3 = (i / 25) % 5, i4 = (i / 125) % 5, i5 = i / 625;
227  uint32_t count = counts[i];
228  if (i1 == i2 || i1 == i3 || i1 == i4 || i1 == i5 || i2 == i3 || i2 == i4 || i2 == i5 || i3 == i4 || i3 == i5 || i4 == i5) {
229  BOOST_CHECK(count == 0);
230  } else {
231  chi_score += ((count - 100.0) * (count - 100.0)) / 100.0;
232  BOOST_CHECK(count > 50);
233  BOOST_CHECK(count < 150);
234  sum += count;
235  }
236  }
237  BOOST_CHECK(chi_score > 58.1411); // 99.9999% confidence interval
238  BOOST_CHECK(chi_score < 210.275);
239  BOOST_CHECK_EQUAL(sum, 12000U);
240 }
241 
242 BOOST_AUTO_TEST_CASE(xoroshiro128plusplus_reference_values)
243 {
244  // numbers generated from reference implementation
245  InsecureRandomContext rng(0);
246  BOOST_TEST(0x6f68e1e7e2646ee1 == rng());
247  BOOST_TEST(0xbf971b7f454094ad == rng());
248  BOOST_TEST(0x48f2de556f30de38 == rng());
249  BOOST_TEST(0x6ea7c59f89bbfc75 == rng());
250 
251  // seed with a random number
252  rng.Reseed(0x1a26f3fa8546b47a);
253  BOOST_TEST(0xc8dc5e08d844ac7d == rng());
254  BOOST_TEST(0x5b5f1f6d499dad1b == rng());
255  BOOST_TEST(0xbeb0031f93313d6f == rng());
256  BOOST_TEST(0xbfbcf4f43a264497 == rng());
257 }
258 
std::vector< B > randbytes(size_t len) noexcept
Generate random bytes.
Definition: random.h:297
assert(!tx.IsCoinBase())
constexpr void Reseed(uint64_t seedval) noexcept
Definition: random.h:432
std::chrono::time_point< std::chrono::steady_clock, std::chrono::seconds > SteadySeconds
Definition: time.h:26
BOOST_AUTO_TEST_CASE(osrandom_tests)
Basic testing setup.
Definition: setup_common.h:64
volatile double sum
Definition: examples.cpp:10
Fast randomness source.
Definition: random.h:376
BOOST_AUTO_TEST_SUITE_END()
xoroshiro128++ PRNG.
Definition: random.h:415
void SeedRandomForTest(SeedRand seedtype)
Seed the RNG for testing.
Definition: random.cpp:18
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:18
uint64_t randbits(int bits) noexcept
Generate a random (bits)-bit integer.
Definition: random.h:204
uint256 rand256() noexcept
generate a random uint256.
Definition: random.h:308
I randrange(I range) noexcept
Generate a random integer in the range [0..range), with range > 0.
Definition: random.h:254
static int count
Seed with a compile time constant of zeros.
uint64_t rand64() noexcept
Generate a random 64-bit integer.
Definition: random.h:395
bool Random_SanityCheck()
Check that OS randomness is available and returning the requested number of bytes.
Definition: random.cpp:714
#define BOOST_CHECK(expr)
Definition: object.cpp:17