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