2022-12-24 23:49:50 +00:00
|
|
|
// Copyright (c) 2017-2022 The Bitcoin Core developers
|
2017-02-21 17:36:37 +01:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
2017-11-10 13:57:53 +13:00
|
|
|
#include <random.h>
|
2017-02-21 17:36:37 +01:00
|
|
|
|
2023-01-22 09:57:19 -08:00
|
|
|
#include <test/util/random.h>
|
2019-11-05 15:18:59 -05:00
|
|
|
#include <test/util/setup_common.h>
|
2023-03-23 12:23:29 +01:00
|
|
|
#include <util/time.h>
|
2017-02-21 17:36:37 +01:00
|
|
|
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
|
2018-03-20 19:10:39 -07:00
|
|
|
#include <algorithm>
|
2020-04-16 13:11:54 -04:00
|
|
|
#include <random>
|
2018-03-20 19:10:39 -07:00
|
|
|
|
2017-02-21 17:36:37 +01:00
|
|
|
BOOST_FIXTURE_TEST_SUITE(random_tests, BasicTestingSetup)
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(osrandom_tests)
|
|
|
|
{
|
2017-02-22 08:02:50 +01:00
|
|
|
BOOST_CHECK(Random_SanityCheck());
|
2017-02-21 17:36:37 +01:00
|
|
|
}
|
|
|
|
|
tests: overhaul deterministic test randomness
The existing code provides two randomness mechanisms for test purposes:
- g_insecure_rand_ctx (with its wrappers InsecureRand*), which during tests is
initialized using either zeros (SeedRand::ZEROS), or using environment-provided
randomness (SeedRand::SEED).
- g_mock_deterministic_tests, which controls some (but not all) of the normal
randomness output if set, but then makes it extremely predictable (identical
output repeatedly).
Replace this with a single mechanism, which retains the SeedRand modes to control
all randomness. There is a new internal deterministic PRNG inside the random
module, which is used in GetRandBytes() when in test mode, and which is also used
to initialize g_insecure_rand_ctx. This means that during tests, all random numbers
are made deterministic. There is one exception, GetStrongRandBytes(), which even
in test mode still uses the normal PRNG state.
This probably opens the door to removing a lot of the ad-hoc "deterministic" mode
functions littered through the codebase (by simply running relevant tests in
SeedRand::ZEROS mode), but this isn't done yet.
2024-03-10 19:49:42 -04:00
|
|
|
BOOST_AUTO_TEST_CASE(fastrandom_tests_deterministic)
|
2017-02-15 17:45:22 -08:00
|
|
|
{
|
|
|
|
// Check that deterministic FastRandomContexts are deterministic
|
tests: overhaul deterministic test randomness
The existing code provides two randomness mechanisms for test purposes:
- g_insecure_rand_ctx (with its wrappers InsecureRand*), which during tests is
initialized using either zeros (SeedRand::ZEROS), or using environment-provided
randomness (SeedRand::SEED).
- g_mock_deterministic_tests, which controls some (but not all) of the normal
randomness output if set, but then makes it extremely predictable (identical
output repeatedly).
Replace this with a single mechanism, which retains the SeedRand modes to control
all randomness. There is a new internal deterministic PRNG inside the random
module, which is used in GetRandBytes() when in test mode, and which is also used
to initialize g_insecure_rand_ctx. This means that during tests, all random numbers
are made deterministic. There is one exception, GetStrongRandBytes(), which even
in test mode still uses the normal PRNG state.
This probably opens the door to removing a lot of the ad-hoc "deterministic" mode
functions littered through the codebase (by simply running relevant tests in
SeedRand::ZEROS mode), but this isn't done yet.
2024-03-10 19:49:42 -04:00
|
|
|
SeedRandomForTest(SeedRand::ZEROS);
|
|
|
|
FastRandomContext ctx1{true};
|
|
|
|
FastRandomContext ctx2{true};
|
|
|
|
|
|
|
|
{
|
2024-06-27 11:40:00 -04:00
|
|
|
BOOST_CHECK_EQUAL(FastRandomContext().rand<uint64_t>(), uint64_t{9330418229102544152u});
|
|
|
|
BOOST_CHECK_EQUAL(FastRandomContext().rand<int>(), int{618925161});
|
2024-03-11 10:17:20 -04:00
|
|
|
BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::microseconds>(1h).count(), 1271170921);
|
|
|
|
BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count(), 2803534);
|
tests: overhaul deterministic test randomness
The existing code provides two randomness mechanisms for test purposes:
- g_insecure_rand_ctx (with its wrappers InsecureRand*), which during tests is
initialized using either zeros (SeedRand::ZEROS), or using environment-provided
randomness (SeedRand::SEED).
- g_mock_deterministic_tests, which controls some (but not all) of the normal
randomness output if set, but then makes it extremely predictable (identical
output repeatedly).
Replace this with a single mechanism, which retains the SeedRand modes to control
all randomness. There is a new internal deterministic PRNG inside the random
module, which is used in GetRandBytes() when in test mode, and which is also used
to initialize g_insecure_rand_ctx. This means that during tests, all random numbers
are made deterministic. There is one exception, GetStrongRandBytes(), which even
in test mode still uses the normal PRNG state.
This probably opens the door to removing a lot of the ad-hoc "deterministic" mode
functions littered through the codebase (by simply running relevant tests in
SeedRand::ZEROS mode), but this isn't done yet.
2024-03-10 19:49:42 -04:00
|
|
|
|
2024-06-27 11:40:00 -04:00
|
|
|
BOOST_CHECK_EQUAL(FastRandomContext().rand<uint64_t>(), uint64_t{10170981140880778086u});
|
|
|
|
BOOST_CHECK_EQUAL(FastRandomContext().rand<int>(), int{1689082725});
|
2024-03-11 10:17:20 -04:00
|
|
|
BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::microseconds>(1h).count(), 2464643716);
|
|
|
|
BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count(), 2312205);
|
tests: overhaul deterministic test randomness
The existing code provides two randomness mechanisms for test purposes:
- g_insecure_rand_ctx (with its wrappers InsecureRand*), which during tests is
initialized using either zeros (SeedRand::ZEROS), or using environment-provided
randomness (SeedRand::SEED).
- g_mock_deterministic_tests, which controls some (but not all) of the normal
randomness output if set, but then makes it extremely predictable (identical
output repeatedly).
Replace this with a single mechanism, which retains the SeedRand modes to control
all randomness. There is a new internal deterministic PRNG inside the random
module, which is used in GetRandBytes() when in test mode, and which is also used
to initialize g_insecure_rand_ctx. This means that during tests, all random numbers
are made deterministic. There is one exception, GetStrongRandBytes(), which even
in test mode still uses the normal PRNG state.
This probably opens the door to removing a lot of the ad-hoc "deterministic" mode
functions littered through the codebase (by simply running relevant tests in
SeedRand::ZEROS mode), but this isn't done yet.
2024-03-10 19:49:42 -04:00
|
|
|
|
2024-06-27 11:40:00 -04:00
|
|
|
BOOST_CHECK_EQUAL(FastRandomContext().rand<uint64_t>(), uint64_t{5689404004456455543u});
|
|
|
|
BOOST_CHECK_EQUAL(FastRandomContext().rand<int>(), int{785839937});
|
2024-03-11 10:17:20 -04:00
|
|
|
BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::microseconds>(1h).count(), 93558804);
|
|
|
|
BOOST_CHECK_EQUAL(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count(), 507022);
|
2019-02-01 17:06:32 -05:00
|
|
|
}
|
tests: overhaul deterministic test randomness
The existing code provides two randomness mechanisms for test purposes:
- g_insecure_rand_ctx (with its wrappers InsecureRand*), which during tests is
initialized using either zeros (SeedRand::ZEROS), or using environment-provided
randomness (SeedRand::SEED).
- g_mock_deterministic_tests, which controls some (but not all) of the normal
randomness output if set, but then makes it extremely predictable (identical
output repeatedly).
Replace this with a single mechanism, which retains the SeedRand modes to control
all randomness. There is a new internal deterministic PRNG inside the random
module, which is used in GetRandBytes() when in test mode, and which is also used
to initialize g_insecure_rand_ctx. This means that during tests, all random numbers
are made deterministic. There is one exception, GetStrongRandBytes(), which even
in test mode still uses the normal PRNG state.
This probably opens the door to removing a lot of the ad-hoc "deterministic" mode
functions littered through the codebase (by simply running relevant tests in
SeedRand::ZEROS mode), but this isn't done yet.
2024-03-10 19:49:42 -04:00
|
|
|
|
2022-04-08 12:56:25 +02:00
|
|
|
{
|
|
|
|
constexpr SteadySeconds time_point{1s};
|
|
|
|
FastRandomContext ctx{true};
|
|
|
|
BOOST_CHECK_EQUAL(7, ctx.rand_uniform_delay(time_point, 9s).time_since_epoch().count());
|
|
|
|
BOOST_CHECK_EQUAL(-6, ctx.rand_uniform_delay(time_point, -9s).time_since_epoch().count());
|
|
|
|
BOOST_CHECK_EQUAL(1, ctx.rand_uniform_delay(time_point, 0s).time_since_epoch().count());
|
2024-03-10 10:16:30 -04:00
|
|
|
BOOST_CHECK_EQUAL(4652286523065884857, ctx.rand_uniform_delay(time_point, 9223372036854775807s).time_since_epoch().count());
|
|
|
|
BOOST_CHECK_EQUAL(-8813961240025683129, ctx.rand_uniform_delay(time_point, -9223372036854775807s).time_since_epoch().count());
|
|
|
|
BOOST_CHECK_EQUAL(26443, ctx.rand_uniform_delay(time_point, 9h).time_since_epoch().count());
|
2022-04-08 12:56:25 +02:00
|
|
|
}
|
2017-02-15 17:45:22 -08:00
|
|
|
BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
|
|
|
|
BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
|
|
|
|
BOOST_CHECK_EQUAL(ctx1.rand64(), ctx2.rand64());
|
|
|
|
BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));
|
2017-05-02 11:04:31 -07:00
|
|
|
BOOST_CHECK(ctx1.randbytes(17) == ctx2.randbytes(17));
|
|
|
|
BOOST_CHECK(ctx1.rand256() == ctx2.rand256());
|
2017-02-15 17:45:22 -08:00
|
|
|
BOOST_CHECK_EQUAL(ctx1.randbits(7), ctx2.randbits(7));
|
2017-05-02 11:04:31 -07:00
|
|
|
BOOST_CHECK(ctx1.randbytes(128) == ctx2.randbytes(128));
|
2017-02-15 17:45:22 -08:00
|
|
|
BOOST_CHECK_EQUAL(ctx1.rand32(), ctx2.rand32());
|
|
|
|
BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));
|
2017-05-02 11:04:31 -07:00
|
|
|
BOOST_CHECK(ctx1.rand256() == ctx2.rand256());
|
|
|
|
BOOST_CHECK(ctx1.randbytes(50) == ctx2.randbytes(50));
|
2022-05-10 09:08:49 +02:00
|
|
|
{
|
|
|
|
struct MicroClock {
|
|
|
|
using duration = std::chrono::microseconds;
|
|
|
|
};
|
|
|
|
FastRandomContext ctx{true};
|
|
|
|
// Check with clock type
|
|
|
|
BOOST_CHECK_EQUAL(47222, ctx.rand_uniform_duration<MicroClock>(1s).count());
|
|
|
|
// Check with time-point type
|
|
|
|
BOOST_CHECK_EQUAL(2782, ctx.rand_uniform_duration<SteadySeconds>(9h).count());
|
|
|
|
}
|
tests: overhaul deterministic test randomness
The existing code provides two randomness mechanisms for test purposes:
- g_insecure_rand_ctx (with its wrappers InsecureRand*), which during tests is
initialized using either zeros (SeedRand::ZEROS), or using environment-provided
randomness (SeedRand::SEED).
- g_mock_deterministic_tests, which controls some (but not all) of the normal
randomness output if set, but then makes it extremely predictable (identical
output repeatedly).
Replace this with a single mechanism, which retains the SeedRand modes to control
all randomness. There is a new internal deterministic PRNG inside the random
module, which is used in GetRandBytes() when in test mode, and which is also used
to initialize g_insecure_rand_ctx. This means that during tests, all random numbers
are made deterministic. There is one exception, GetStrongRandBytes(), which even
in test mode still uses the normal PRNG state.
This probably opens the door to removing a lot of the ad-hoc "deterministic" mode
functions littered through the codebase (by simply running relevant tests in
SeedRand::ZEROS mode), but this isn't done yet.
2024-03-10 19:49:42 -04:00
|
|
|
}
|
2017-02-21 17:36:37 +01:00
|
|
|
|
tests: overhaul deterministic test randomness
The existing code provides two randomness mechanisms for test purposes:
- g_insecure_rand_ctx (with its wrappers InsecureRand*), which during tests is
initialized using either zeros (SeedRand::ZEROS), or using environment-provided
randomness (SeedRand::SEED).
- g_mock_deterministic_tests, which controls some (but not all) of the normal
randomness output if set, but then makes it extremely predictable (identical
output repeatedly).
Replace this with a single mechanism, which retains the SeedRand modes to control
all randomness. There is a new internal deterministic PRNG inside the random
module, which is used in GetRandBytes() when in test mode, and which is also used
to initialize g_insecure_rand_ctx. This means that during tests, all random numbers
are made deterministic. There is one exception, GetStrongRandBytes(), which even
in test mode still uses the normal PRNG state.
This probably opens the door to removing a lot of the ad-hoc "deterministic" mode
functions littered through the codebase (by simply running relevant tests in
SeedRand::ZEROS mode), but this isn't done yet.
2024-03-10 19:49:42 -04:00
|
|
|
BOOST_AUTO_TEST_CASE(fastrandom_tests_nondeterministic)
|
|
|
|
{
|
2017-02-15 17:45:22 -08:00
|
|
|
// Check that a nondeterministic ones are not
|
tests: overhaul deterministic test randomness
The existing code provides two randomness mechanisms for test purposes:
- g_insecure_rand_ctx (with its wrappers InsecureRand*), which during tests is
initialized using either zeros (SeedRand::ZEROS), or using environment-provided
randomness (SeedRand::SEED).
- g_mock_deterministic_tests, which controls some (but not all) of the normal
randomness output if set, but then makes it extremely predictable (identical
output repeatedly).
Replace this with a single mechanism, which retains the SeedRand modes to control
all randomness. There is a new internal deterministic PRNG inside the random
module, which is used in GetRandBytes() when in test mode, and which is also used
to initialize g_insecure_rand_ctx. This means that during tests, all random numbers
are made deterministic. There is one exception, GetStrongRandBytes(), which even
in test mode still uses the normal PRNG state.
This probably opens the door to removing a lot of the ad-hoc "deterministic" mode
functions littered through the codebase (by simply running relevant tests in
SeedRand::ZEROS mode), but this isn't done yet.
2024-03-10 19:49:42 -04:00
|
|
|
{
|
2024-06-27 11:40:00 -04:00
|
|
|
BOOST_CHECK(FastRandomContext().rand<uint64_t>() != uint64_t{9330418229102544152u});
|
|
|
|
BOOST_CHECK(FastRandomContext().rand<int>() != int{618925161});
|
2024-03-11 10:17:20 -04:00
|
|
|
BOOST_CHECK(FastRandomContext().randrange<std::chrono::microseconds>(1h).count() != 1271170921);
|
|
|
|
BOOST_CHECK(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count() != 2803534);
|
tests: overhaul deterministic test randomness
The existing code provides two randomness mechanisms for test purposes:
- g_insecure_rand_ctx (with its wrappers InsecureRand*), which during tests is
initialized using either zeros (SeedRand::ZEROS), or using environment-provided
randomness (SeedRand::SEED).
- g_mock_deterministic_tests, which controls some (but not all) of the normal
randomness output if set, but then makes it extremely predictable (identical
output repeatedly).
Replace this with a single mechanism, which retains the SeedRand modes to control
all randomness. There is a new internal deterministic PRNG inside the random
module, which is used in GetRandBytes() when in test mode, and which is also used
to initialize g_insecure_rand_ctx. This means that during tests, all random numbers
are made deterministic. There is one exception, GetStrongRandBytes(), which even
in test mode still uses the normal PRNG state.
This probably opens the door to removing a lot of the ad-hoc "deterministic" mode
functions littered through the codebase (by simply running relevant tests in
SeedRand::ZEROS mode), but this isn't done yet.
2024-03-10 19:49:42 -04:00
|
|
|
|
2024-06-27 11:40:00 -04:00
|
|
|
BOOST_CHECK(FastRandomContext().rand<uint64_t>() != uint64_t{10170981140880778086u});
|
|
|
|
BOOST_CHECK(FastRandomContext().rand<int>() != int{1689082725});
|
2024-03-11 10:17:20 -04:00
|
|
|
BOOST_CHECK(FastRandomContext().randrange<std::chrono::microseconds>(1h).count() != 2464643716);
|
|
|
|
BOOST_CHECK(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count() != 2312205);
|
tests: overhaul deterministic test randomness
The existing code provides two randomness mechanisms for test purposes:
- g_insecure_rand_ctx (with its wrappers InsecureRand*), which during tests is
initialized using either zeros (SeedRand::ZEROS), or using environment-provided
randomness (SeedRand::SEED).
- g_mock_deterministic_tests, which controls some (but not all) of the normal
randomness output if set, but then makes it extremely predictable (identical
output repeatedly).
Replace this with a single mechanism, which retains the SeedRand modes to control
all randomness. There is a new internal deterministic PRNG inside the random
module, which is used in GetRandBytes() when in test mode, and which is also used
to initialize g_insecure_rand_ctx. This means that during tests, all random numbers
are made deterministic. There is one exception, GetStrongRandBytes(), which even
in test mode still uses the normal PRNG state.
This probably opens the door to removing a lot of the ad-hoc "deterministic" mode
functions littered through the codebase (by simply running relevant tests in
SeedRand::ZEROS mode), but this isn't done yet.
2024-03-10 19:49:42 -04:00
|
|
|
|
2024-06-27 11:40:00 -04:00
|
|
|
BOOST_CHECK(FastRandomContext().rand<uint64_t>() != uint64_t{5689404004456455543u});
|
|
|
|
BOOST_CHECK(FastRandomContext().rand<int>() != int{785839937});
|
2024-03-11 10:17:20 -04:00
|
|
|
BOOST_CHECK(FastRandomContext().randrange<std::chrono::microseconds>(1h).count() != 93558804);
|
|
|
|
BOOST_CHECK(FastRandomContext().randrange<std::chrono::milliseconds>(1h).count() != 507022);
|
2019-02-01 17:06:32 -05:00
|
|
|
}
|
tests: overhaul deterministic test randomness
The existing code provides two randomness mechanisms for test purposes:
- g_insecure_rand_ctx (with its wrappers InsecureRand*), which during tests is
initialized using either zeros (SeedRand::ZEROS), or using environment-provided
randomness (SeedRand::SEED).
- g_mock_deterministic_tests, which controls some (but not all) of the normal
randomness output if set, but then makes it extremely predictable (identical
output repeatedly).
Replace this with a single mechanism, which retains the SeedRand modes to control
all randomness. There is a new internal deterministic PRNG inside the random
module, which is used in GetRandBytes() when in test mode, and which is also used
to initialize g_insecure_rand_ctx. This means that during tests, all random numbers
are made deterministic. There is one exception, GetStrongRandBytes(), which even
in test mode still uses the normal PRNG state.
This probably opens the door to removing a lot of the ad-hoc "deterministic" mode
functions littered through the codebase (by simply running relevant tests in
SeedRand::ZEROS mode), but this isn't done yet.
2024-03-10 19:49:42 -04:00
|
|
|
|
2018-10-31 14:25:11 -07:00
|
|
|
{
|
|
|
|
FastRandomContext ctx3, ctx4;
|
|
|
|
BOOST_CHECK(ctx3.rand64() != ctx4.rand64()); // extremely unlikely to be equal
|
|
|
|
}
|
|
|
|
{
|
|
|
|
FastRandomContext ctx3, ctx4;
|
|
|
|
BOOST_CHECK(ctx3.rand256() != ctx4.rand256());
|
|
|
|
}
|
|
|
|
{
|
|
|
|
FastRandomContext ctx3, ctx4;
|
|
|
|
BOOST_CHECK(ctx3.randbytes(7) != ctx4.randbytes(7));
|
|
|
|
}
|
2017-02-15 17:45:22 -08:00
|
|
|
}
|
|
|
|
|
2017-02-25 12:16:58 -08:00
|
|
|
BOOST_AUTO_TEST_CASE(fastrandom_randbits)
|
|
|
|
{
|
|
|
|
FastRandomContext ctx1;
|
|
|
|
FastRandomContext ctx2;
|
|
|
|
for (int bits = 0; bits < 63; ++bits) {
|
|
|
|
for (int j = 0; j < 1000; ++j) {
|
|
|
|
uint64_t rangebits = ctx1.randbits(bits);
|
2018-04-09 16:50:19 +09:00
|
|
|
BOOST_CHECK_EQUAL(rangebits >> bits, 0U);
|
2021-12-18 12:50:58 -05:00
|
|
|
uint64_t range = (uint64_t{1}) << bits | rangebits;
|
2017-02-25 12:16:58 -08:00
|
|
|
uint64_t rand = ctx2.randrange(range);
|
|
|
|
BOOST_CHECK(rand < range);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-10 10:16:30 -04:00
|
|
|
/** Verify that RandomMixin::randbits returns 0 and 1 for every requested bit. */
|
|
|
|
BOOST_AUTO_TEST_CASE(randbits_test)
|
|
|
|
{
|
|
|
|
FastRandomContext ctx_lens; //!< RNG for producing the lengths requested from ctx_test.
|
2024-03-10 12:38:14 -04:00
|
|
|
FastRandomContext ctx_test1(true), ctx_test2(true); //!< The RNGs being tested.
|
2024-03-10 10:16:30 -04:00
|
|
|
int ctx_test_bitsleft{0}; //!< (Assumed value of) ctx_test::bitbuf_len
|
|
|
|
|
|
|
|
// Run the entire test 5 times.
|
|
|
|
for (int i = 0; i < 5; ++i) {
|
|
|
|
// count (first) how often it has occurred, and (second) how often it was true:
|
|
|
|
// - for every bit position, in every requested bits count (0 + 1 + 2 + ... + 64 = 2080)
|
|
|
|
// - for every value of ctx_test_bitsleft (0..63 = 64)
|
|
|
|
std::vector<std::pair<uint64_t, uint64_t>> seen(2080 * 64);
|
|
|
|
while (true) {
|
|
|
|
// Loop 1000 times, just to not continuously check std::all_of.
|
|
|
|
for (int j = 0; j < 1000; ++j) {
|
|
|
|
// Decide on a number of bits to request (0 through 64, inclusive; don't use randbits/randrange).
|
|
|
|
int bits = ctx_lens.rand64() % 65;
|
|
|
|
// Generate that many bits.
|
2024-03-10 12:38:14 -04:00
|
|
|
uint64_t gen = ctx_test1.randbits(bits);
|
|
|
|
// For certain bits counts, also test randbits<Bits> and compare.
|
|
|
|
uint64_t gen2;
|
|
|
|
if (bits == 0) {
|
|
|
|
gen2 = ctx_test2.randbits<0>();
|
|
|
|
} else if (bits == 1) {
|
|
|
|
gen2 = ctx_test2.randbits<1>();
|
|
|
|
} else if (bits == 7) {
|
|
|
|
gen2 = ctx_test2.randbits<7>();
|
|
|
|
} else if (bits == 32) {
|
|
|
|
gen2 = ctx_test2.randbits<32>();
|
|
|
|
} else if (bits == 51) {
|
|
|
|
gen2 = ctx_test2.randbits<51>();
|
|
|
|
} else if (bits == 64) {
|
|
|
|
gen2 = ctx_test2.randbits<64>();
|
|
|
|
} else {
|
|
|
|
gen2 = ctx_test2.randbits(bits);
|
|
|
|
}
|
|
|
|
BOOST_CHECK_EQUAL(gen, gen2);
|
2024-03-10 10:16:30 -04:00
|
|
|
// Make sure the result is in range.
|
|
|
|
if (bits < 64) BOOST_CHECK_EQUAL(gen >> bits, 0);
|
|
|
|
// Mark all the seen bits in the output.
|
|
|
|
for (int bit = 0; bit < bits; ++bit) {
|
|
|
|
int idx = bit + (bits * (bits - 1)) / 2 + 2080 * ctx_test_bitsleft;
|
|
|
|
seen[idx].first += 1;
|
|
|
|
seen[idx].second += (gen >> bit) & 1;
|
|
|
|
}
|
|
|
|
// Update ctx_test_bitself.
|
|
|
|
if (bits > ctx_test_bitsleft) {
|
|
|
|
ctx_test_bitsleft = ctx_test_bitsleft + 64 - bits;
|
|
|
|
} else {
|
|
|
|
ctx_test_bitsleft -= bits;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Loop until every bit position/combination is seen 242 times.
|
|
|
|
if (std::all_of(seen.begin(), seen.end(), [](const auto& x) { return x.first >= 242; })) break;
|
|
|
|
}
|
|
|
|
// Check that each bit appears within 7.78 standard deviations of 50%
|
|
|
|
// (each will fail with P < 1/(2080 * 64 * 10^9)).
|
|
|
|
for (const auto& val : seen) {
|
|
|
|
assert(fabs(val.first * 0.5 - val.second) < sqrt(val.first * 0.25) * 7.78);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-05 19:52:33 +00:00
|
|
|
/** Does-it-compile test for compatibility with standard library RNG interface. */
|
2018-03-20 19:10:39 -07:00
|
|
|
BOOST_AUTO_TEST_CASE(stdrandom_test)
|
|
|
|
{
|
|
|
|
FastRandomContext ctx;
|
|
|
|
std::uniform_int_distribution<int> distribution(3, 9);
|
|
|
|
for (int i = 0; i < 100; ++i) {
|
|
|
|
int x = distribution(ctx);
|
|
|
|
BOOST_CHECK(x >= 3);
|
|
|
|
BOOST_CHECK(x <= 9);
|
|
|
|
|
2020-04-27 11:57:21 -04:00
|
|
|
std::vector<int> test{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
2018-03-20 19:10:39 -07:00
|
|
|
std::shuffle(test.begin(), test.end(), ctx);
|
|
|
|
for (int j = 1; j <= 10; ++j) {
|
|
|
|
BOOST_CHECK(std::find(test.begin(), test.end(), j) != test.end());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-31 15:42:03 -07:00
|
|
|
/** Test that Shuffle reaches every permutation with equal probability. */
|
|
|
|
BOOST_AUTO_TEST_CASE(shuffle_stat_test)
|
|
|
|
{
|
|
|
|
FastRandomContext ctx(true);
|
|
|
|
uint32_t counts[5 * 5 * 5 * 5 * 5] = {0};
|
|
|
|
for (int i = 0; i < 12000; ++i) {
|
|
|
|
int data[5] = {0, 1, 2, 3, 4};
|
2024-07-05 10:45:54 -04:00
|
|
|
std::shuffle(std::begin(data), std::end(data), ctx);
|
2018-10-31 15:42:03 -07:00
|
|
|
int pos = data[0] + data[1] * 5 + data[2] * 25 + data[3] * 125 + data[4] * 625;
|
|
|
|
++counts[pos];
|
|
|
|
}
|
|
|
|
unsigned int sum = 0;
|
|
|
|
double chi_score = 0.0;
|
|
|
|
for (int i = 0; i < 5 * 5 * 5 * 5 * 5; ++i) {
|
|
|
|
int i1 = i % 5, i2 = (i / 5) % 5, i3 = (i / 25) % 5, i4 = (i / 125) % 5, i5 = i / 625;
|
|
|
|
uint32_t count = counts[i];
|
|
|
|
if (i1 == i2 || i1 == i3 || i1 == i4 || i1 == i5 || i2 == i3 || i2 == i4 || i2 == i5 || i3 == i4 || i3 == i5 || i4 == i5) {
|
|
|
|
BOOST_CHECK(count == 0);
|
|
|
|
} else {
|
|
|
|
chi_score += ((count - 100.0) * (count - 100.0)) / 100.0;
|
|
|
|
BOOST_CHECK(count > 50);
|
|
|
|
BOOST_CHECK(count < 150);
|
|
|
|
sum += count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BOOST_CHECK(chi_score > 58.1411); // 99.9999% confidence interval
|
|
|
|
BOOST_CHECK(chi_score < 210.275);
|
2020-02-27 15:20:31 -08:00
|
|
|
BOOST_CHECK_EQUAL(sum, 12000U);
|
2018-10-31 15:42:03 -07:00
|
|
|
}
|
|
|
|
|
2024-03-10 14:50:20 -04:00
|
|
|
BOOST_AUTO_TEST_CASE(xoroshiro128plusplus_reference_values)
|
|
|
|
{
|
|
|
|
// numbers generated from reference implementation
|
2024-03-10 15:16:20 -04:00
|
|
|
InsecureRandomContext rng(0);
|
2024-03-10 14:50:20 -04:00
|
|
|
BOOST_TEST(0x6f68e1e7e2646ee1 == rng());
|
|
|
|
BOOST_TEST(0xbf971b7f454094ad == rng());
|
|
|
|
BOOST_TEST(0x48f2de556f30de38 == rng());
|
|
|
|
BOOST_TEST(0x6ea7c59f89bbfc75 == rng());
|
|
|
|
|
|
|
|
// seed with a random number
|
2024-05-31 10:39:23 -04:00
|
|
|
rng.Reseed(0x1a26f3fa8546b47a);
|
2024-03-10 14:50:20 -04:00
|
|
|
BOOST_TEST(0xc8dc5e08d844ac7d == rng());
|
|
|
|
BOOST_TEST(0x5b5f1f6d499dad1b == rng());
|
|
|
|
BOOST_TEST(0xbeb0031f93313d6f == rng());
|
|
|
|
BOOST_TEST(0xbfbcf4f43a264497 == rng());
|
|
|
|
}
|
|
|
|
|
2017-02-15 17:45:22 -08:00
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|