mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 18:45:52 +00:00
Per XLS-0095, we are taking steps to rename ripple(d) to xrpl(d). This change specifically removes all copyright notices referencing Ripple, XRPLF, and certain affiliated contributors upon mutual agreement, so the notice in the LICENSE.md file applies throughout. Copyright notices referencing external contributions remain as-is. Duplicate verbiage is also removed.
192 lines
5.3 KiB
C++
192 lines
5.3 KiB
C++
#ifndef XRPL_BASICS_RANDOM_H_INCLUDED
|
|
#define XRPL_BASICS_RANDOM_H_INCLUDED
|
|
|
|
#include <xrpl/beast/utility/instrumentation.h>
|
|
#include <xrpl/beast/xor_shift_engine.h>
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <limits>
|
|
#include <mutex>
|
|
#include <random>
|
|
#include <type_traits>
|
|
|
|
namespace ripple {
|
|
|
|
#ifndef __INTELLISENSE__
|
|
static_assert(
|
|
std::is_integral<beast::xor_shift_engine::result_type>::value &&
|
|
std::is_unsigned<beast::xor_shift_engine::result_type>::value,
|
|
"The Ripple default PRNG engine must return an unsigned integral type.");
|
|
|
|
static_assert(
|
|
std::numeric_limits<beast::xor_shift_engine::result_type>::max() >=
|
|
std::numeric_limits<std::uint64_t>::max(),
|
|
"The Ripple default PRNG engine return must be at least 64 bits wide.");
|
|
#endif
|
|
|
|
namespace detail {
|
|
|
|
// Determines if a type can be called like an Engine
|
|
template <class Engine, class Result = typename Engine::result_type>
|
|
using is_engine = std::is_invocable_r<Result, Engine>;
|
|
} // namespace detail
|
|
|
|
/** Return the default random engine.
|
|
|
|
This engine is guaranteed to be deterministic, but by
|
|
default will be randomly seeded. It is NOT cryptographically
|
|
secure and MUST NOT be used to generate randomness that
|
|
will be used for keys, secure cookies, IVs, padding, etc.
|
|
|
|
Each thread gets its own instance of the engine which
|
|
will be randomly seeded.
|
|
*/
|
|
inline beast::xor_shift_engine&
|
|
default_prng()
|
|
{
|
|
// 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));
|
|
}();
|
|
|
|
// This protects the seeder
|
|
static std::mutex m;
|
|
|
|
// The thread-specific PRNGs:
|
|
thread_local beast::xor_shift_engine engine = [] {
|
|
std::uint64_t seed;
|
|
{
|
|
std::lock_guard lk(m);
|
|
std::uniform_int_distribution<std::uint64_t> distribution{1};
|
|
seed = distribution(seeder);
|
|
}
|
|
return beast::xor_shift_engine{seed};
|
|
}();
|
|
|
|
return engine;
|
|
}
|
|
|
|
/** Return a uniformly distributed random integer.
|
|
|
|
@param min The smallest value to return. If not specified
|
|
the value defaults to 0.
|
|
@param max The largest value to return. If not specified
|
|
the value defaults to the largest value that
|
|
can be represented.
|
|
|
|
The randomness is generated by the specified engine (or
|
|
the default engine if one is not specified). The result
|
|
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
|
|
closed interval [-5, 15]; similarly, calling
|
|
rand_int(7) can return any integer in the closed
|
|
interval [0, 7].
|
|
*/
|
|
/** @{ */
|
|
template <class Engine, class Integral>
|
|
std::enable_if_t<
|
|
std::is_integral<Integral>::value && detail::is_engine<Engine>::value,
|
|
Integral>
|
|
rand_int(Engine& engine, Integral min, Integral max)
|
|
{
|
|
XRPL_ASSERT(max > min, "ripple::rand_int : max over min inputs");
|
|
|
|
// This should have no state and constructing it should
|
|
// be very cheap. If that turns out not to be the case
|
|
// it could be hand-optimized.
|
|
return std::uniform_int_distribution<Integral>(min, max)(engine);
|
|
}
|
|
|
|
template <class Integral>
|
|
std::enable_if_t<std::is_integral<Integral>::value, Integral>
|
|
rand_int(Integral min, Integral max)
|
|
{
|
|
return rand_int(default_prng(), min, max);
|
|
}
|
|
|
|
template <class Engine, class Integral>
|
|
std::enable_if_t<
|
|
std::is_integral<Integral>::value && detail::is_engine<Engine>::value,
|
|
Integral>
|
|
rand_int(Engine& engine, Integral max)
|
|
{
|
|
return rand_int(engine, Integral(0), max);
|
|
}
|
|
|
|
template <class Integral>
|
|
std::enable_if_t<std::is_integral<Integral>::value, Integral>
|
|
rand_int(Integral max)
|
|
{
|
|
return rand_int(default_prng(), max);
|
|
}
|
|
|
|
template <class Integral, class Engine>
|
|
std::enable_if_t<
|
|
std::is_integral<Integral>::value && detail::is_engine<Engine>::value,
|
|
Integral>
|
|
rand_int(Engine& engine)
|
|
{
|
|
return rand_int(engine, std::numeric_limits<Integral>::max());
|
|
}
|
|
|
|
template <class Integral = int>
|
|
std::enable_if_t<std::is_integral<Integral>::value, Integral>
|
|
rand_int()
|
|
{
|
|
return rand_int(default_prng(), std::numeric_limits<Integral>::max());
|
|
}
|
|
/** @} */
|
|
|
|
/** Return a random byte */
|
|
/** @{ */
|
|
template <class Byte, class Engine>
|
|
std::enable_if_t<
|
|
(std::is_same<Byte, unsigned char>::value ||
|
|
std::is_same<Byte, std::uint8_t>::value) &&
|
|
detail::is_engine<Engine>::value,
|
|
Byte>
|
|
rand_byte(Engine& engine)
|
|
{
|
|
return static_cast<Byte>(rand_int<Engine, std::uint32_t>(
|
|
engine,
|
|
std::numeric_limits<Byte>::min(),
|
|
std::numeric_limits<Byte>::max()));
|
|
}
|
|
|
|
template <class Byte = std::uint8_t>
|
|
std::enable_if_t<
|
|
(std::is_same<Byte, unsigned char>::value ||
|
|
std::is_same<Byte, std::uint8_t>::value),
|
|
Byte>
|
|
rand_byte()
|
|
{
|
|
return rand_byte<Byte>(default_prng());
|
|
}
|
|
/** @} */
|
|
|
|
/** Return a random boolean value */
|
|
/** @{ */
|
|
template <class Engine>
|
|
inline bool
|
|
rand_bool(Engine& engine)
|
|
{
|
|
return rand_int(engine, 1) == 1;
|
|
}
|
|
|
|
inline bool
|
|
rand_bool()
|
|
{
|
|
return rand_bool(default_prng());
|
|
}
|
|
/** @} */
|
|
|
|
} // namespace ripple
|
|
|
|
#endif // XRPL_BASICS_RANDOM_H_INCLUDED
|