Reduce calls to std::random_device:

Existing per-thread PRNGs are individually initialized using calls
to std::random_device.

If merged, this commit will use a single PRNG, initialized from
std::random_device on startup, to seed the thread-specific PRNGs.

Acknowledgements:
    Thomas Snider, who reported this issue to Ripple on April 8, 2020.
This commit is contained in:
Nik Bougalis
2020-04-08 21:11:03 -07:00
parent b96ef6adb8
commit 284ed38471

View File

@@ -21,13 +21,13 @@
#define RIPPLE_BASICS_RANDOM_H_INCLUDED
#include <ripple/beast/xor_shift_engine.h>
#include <boost/thread/tss.hpp>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <random>
#include <limits>
#include <mutex>
#include <ripple/beast/cxx17/type_traits.h> // <type_traits>
namespace ripple {
@@ -67,27 +67,30 @@ inline
beast::xor_shift_engine&
default_prng ()
{
static
boost::thread_specific_ptr<beast::xor_shift_engine> engine;
if (!engine.get())
// This is used to seed the thread-specific PRNGs on demand
static beast::xor_shift_engine seeder = []
{
std::random_device rng;
std::uniform_int_distribution<std::uint64_t> distribution{1};
return beast::xor_shift_engine(distribution(rng));
}();
std::uint64_t seed = rng();
// This protects the seeder
static std::mutex m;
for (int i = 0; i < 6; ++i)
// The thread-specific PRNGs:
thread_local beast::xor_shift_engine engine = []
{
std::uint64_t seed;
{
if (seed == 0)
seed = rng();
seed ^= (seed << (7 - i)) * rng();
std::lock_guard lk(m);
std::uniform_int_distribution<std::uint64_t> distribution{1};
seed = distribution(seeder);
}
return beast::xor_shift_engine{seed};
}();
engine.reset (new beast::xor_shift_engine (seed));
}
return *engine;
return engine;
}
/** Return a uniformly distributed random integer.
@@ -100,8 +103,8 @@ default_prng ()
The randomness is generated by the specified engine (or
the default engine if one is not specified). The result
is only cryptographicallys secure if the PRNG engine is
cryptographically secure.
is cryptographically secure only when the engine passed
into the function is cryptographically secure.
@note The range is always a closed interval, so calling
rand_int(-5, 15) can return any integer in the