diff --git a/Builds/VisualStudio2015/RippleD.vcxproj b/Builds/VisualStudio2015/RippleD.vcxproj
index 04a250ef0..c33a87d7b 100644
--- a/Builds/VisualStudio2015/RippleD.vcxproj
+++ b/Builds/VisualStudio2015/RippleD.vcxproj
@@ -1964,6 +1964,8 @@
+
+
@@ -2156,6 +2158,8 @@
+
+
@@ -2176,6 +2180,10 @@
True
True
+
+ True
+ True
+
True
True
@@ -2214,18 +2222,12 @@
-
- True
- True
-
True
True
-
-
diff --git a/Builds/VisualStudio2015/RippleD.vcxproj.filters b/Builds/VisualStudio2015/RippleD.vcxproj.filters
index 8e33c75f1..e70a976ba 100644
--- a/Builds/VisualStudio2015/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2015/RippleD.vcxproj.filters
@@ -2697,6 +2697,9 @@
ripple\basics
+
+ ripple\basics
+
ripple\basics
@@ -2871,6 +2874,9 @@
ripple\crypto
+
+ ripple\crypto
+
ripple\crypto
@@ -2892,6 +2898,9 @@
ripple\crypto\impl
+
+ ripple\crypto\impl
+
ripple\crypto\impl
@@ -2925,18 +2934,12 @@
ripple\crypto\impl
-
- ripple\crypto\impl
-
ripple\crypto\impl
ripple\crypto
-
- ripple\crypto
-
ripple\crypto
diff --git a/src/ripple/app/main/Application.cpp b/src/ripple/app/main/Application.cpp
index 3a8f38cc8..4ed53bddd 100644
--- a/src/ripple/app/main/Application.cpp
+++ b/src/ripple/app/main/Application.cpp
@@ -70,7 +70,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -844,7 +844,7 @@ public:
{
if (timer == m_entropyTimer)
{
- add_entropy (nullptr, 0);
+ crypto_prng().mix_entropy ();
return;
}
diff --git a/src/ripple/app/main/Main.cpp b/src/ripple/app/main/Main.cpp
index 28bbde2d1..4bb64f93d 100644
--- a/src/ripple/app/main/Main.cpp
+++ b/src/ripple/app/main/Main.cpp
@@ -29,7 +29,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -44,7 +44,6 @@
#include
#include
#include
-#include
#include
#if defined(BEAST_LINUX) || defined(BEAST_MAC) || defined(BEAST_BSD)
@@ -113,7 +112,7 @@ void startServer (Application& app)
// Try to write out some entropy to use the next time we start.
auto entropy = getEntropyFile (app.config());
if (!entropy.empty ())
- stir_entropy (entropy.string ());
+ crypto_prng().save_state(entropy.string ());
}
void printHelp (const po::options_description& desc)
@@ -189,30 +188,6 @@ int run (int argc, char** argv)
setCallingThreadName ("main");
- {
- // We want to seed the RNG early. We acquire a small amount of
- // questionable quality entropy from the current time and our
- // environment block which will get stirred into the RNG pool
- // along with high-quality entropy from the system.
- struct entropy_t
- {
- std::uint64_t timestamp;
- std::size_t tid;
- std::uintptr_t ptr[4];
- };
-
- auto entropy = std::make_unique ();
-
- entropy->timestamp = beast::Time::currentTimeMillis ();
- entropy->tid = std::hash () (std::this_thread::get_id ());
- entropy->ptr[0] = reinterpret_cast(entropy.get ());
- entropy->ptr[1] = reinterpret_cast(&argc);
- entropy->ptr[2] = reinterpret_cast(argv);
- entropy->ptr[3] = reinterpret_cast(argv[0]);
-
- add_entropy (entropy.get (), sizeof (entropy_t));
- }
-
po::variables_map vm;
std::string importText;
@@ -333,10 +308,12 @@ int run (int argc, char** argv)
config->LEDGER_HISTORY = 0;
}
- // Use any previously available entropy to stir the pool
- auto entropy = getEntropyFile (*config);
- if (!entropy.empty ())
- stir_entropy (entropy.string ());
+ {
+ // Stir any previously saved entropy into the pool:
+ auto entropy = getEntropyFile (*config);
+ if (!entropy.empty ())
+ crypto_prng().load_state(entropy.string ());
+ }
if (vm.count ("start"))
config->START_UP = Config::FRESH;
diff --git a/src/ripple/app/misc/NetworkOPs.cpp b/src/ripple/app/misc/NetworkOPs.cpp
index 6aced831e..5752aaa56 100644
--- a/src/ripple/app/misc/NetworkOPs.cpp
+++ b/src/ripple/app/misc/NetworkOPs.cpp
@@ -45,6 +45,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -53,7 +54,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -70,6 +71,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -2528,7 +2530,10 @@ bool NetworkOPsImp::subServer (InfoSub::ref isrListener, Json::Value& jvResult,
jvResult[jss::stand_alone] = m_standalone;
// CHECKME: is it necessary to provide a random number here?
- random_fill (uRandom.begin (), uRandom.size ());
+ beast::rngfill (
+ uRandom.begin(),
+ uRandom.size(),
+ crypto_prng());
jvResult[jss::random] = to_string (uRandom);
jvResult[jss::server_status] = strOperatingMode ();
diff --git a/src/ripple/basics/random.h b/src/ripple/basics/random.h
new file mode 100644
index 000000000..3734afe68
--- /dev/null
+++ b/src/ripple/basics/random.h
@@ -0,0 +1,202 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012, 2013 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef RIPPLE_BASICS_RANDOM_H_INCLUDED
+#define RIPPLE_BASICS_RANDOM_H_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace ripple {
+
+static_assert (
+ std::is_integral ::value &&
+ std::is_unsigned ::value,
+ "The Ripple default PRNG engine must return an unsigned integral type.");
+
+static_assert (
+ std::numeric_limits::max() >=
+ std::numeric_limits::max(),
+ "The Ripple default PRNG engine return must be at least 64 bits wide.");
+
+namespace detail {
+
+
+// Determines if a type can be called like an Engine
+template
+using is_engine =
+ beast::is_call_possible;
+}
+
+/** 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 ()
+{
+ static
+ boost::thread_specific_ptr engine;
+
+ if (!engine.get())
+ {
+ std::random_device rng;
+
+ std::uint64_t seed = rng();
+
+ for (int i = 0; i < 6; ++i)
+ {
+ if (seed == 0)
+ seed = rng();
+
+ seed ^= (seed << (7 - i)) * rng();
+ }
+
+ engine.reset (new 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 only cryptographicallys secure if the PRNG engine 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
+std::enable_if_t<
+ std::is_integral::value &&
+ detail::is_engine::value,
+Integral>
+rand_int (
+ Engine& engine,
+ Integral min,
+ Integral max)
+{
+ assert (max > min);
+
+ // 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(min, max)(engine);
+}
+
+template
+std::enable_if_t::value, Integral>
+rand_int (
+ Integral min,
+ Integral max)
+{
+ return rand_int (default_prng(), min, max);
+}
+
+template
+std::enable_if_t<
+ std::is_integral::value &&
+ detail::is_engine::value,
+Integral>
+rand_int (
+ Engine& engine,
+ Integral max)
+{
+ return rand_int (engine, Integral(0), max);
+}
+
+template
+std::enable_if_t::value, Integral>
+rand_int (Integral max)
+{
+ return rand_int (default_prng(), max);
+}
+
+template
+std::enable_if_t<
+ std::is_integral::value &&
+ detail::is_engine::value,
+Integral>
+rand_int (
+ Engine& engine)
+{
+ return rand_int (
+ engine,
+ std::numeric_limits::max());
+}
+
+template
+std::enable_if_t::value, Integral>
+rand_int ()
+{
+ return rand_int (
+ default_prng(),
+ std::numeric_limits::max());
+}
+/** @} */
+
+/** Return a random boolean value */
+/** @{ */
+template
+inline
+bool
+rand_bool (Engine& engine)
+{
+ return rand_int (engine, 1) == 1;
+}
+
+inline
+bool
+rand_bool ()
+{
+ return rand_bool (default_prng());
+}
+/** @} */
+
+} // ripple
+
+#endif // RIPPLE_BASICS_RANDOM_H_INCLUDED
diff --git a/src/ripple/core/impl/SNTPClock.cpp b/src/ripple/core/impl/SNTPClock.cpp
index c12c6fba1..740fcb6d8 100644
--- a/src/ripple/core/impl/SNTPClock.cpp
+++ b/src/ripple/core/impl/SNTPClock.cpp
@@ -20,7 +20,7 @@
#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -351,12 +351,16 @@ public:
return;
}
- ip::udp::resolver::iterator sel = it;
+ assert (it != ip::udp::resolver::iterator());
+
+ auto sel = it;
int i = 1;
while (++it != ip::udp::resolver::iterator())
- if ((rand () % ++i) == 0)
+ {
+ if (rand_int (i++) == 0)
sel = it;
+ }
if (sel != ip::udp::resolver::iterator ())
{
@@ -374,7 +378,7 @@ public:
query.replied = false;
query.sent = now;
- random_fill (&query.nonce);
+ query.nonce = rand_int();
reinterpret_cast (SNTPQueryData)[NTP_OFF_XMITTS_INT] = static_cast (time (nullptr)) + NTP_UNIX_OFFSET;
reinterpret_cast (SNTPQueryData)[NTP_OFF_XMITTS_FRAC] = query.nonce;
socket_.async_send_to(buffer(SNTPQueryData, 48),
diff --git a/src/ripple/crypto/RandomNumbers.h b/src/ripple/crypto/RandomNumbers.h
deleted file mode 100644
index eef8c04a3..000000000
--- a/src/ripple/crypto/RandomNumbers.h
+++ /dev/null
@@ -1,67 +0,0 @@
-//------------------------------------------------------------------------------
-/*
- This file is part of rippled: https://github.com/ripple/rippled
- Copyright (c) 2012, 2013 Ripple Labs Inc.
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-//==============================================================================
-
-#ifndef RIPPLE_CRYPTO_RANDOMNUMBERS_H_INCLUDED
-#define RIPPLE_CRYPTO_RANDOMNUMBERS_H_INCLUDED
-
-#include
-#include
-
-namespace ripple {
-
-/** Stir the RNG using entropy from stable storage.
-
- @param file the file from which state is loaded and into
- which it is saved.
-
- @return true if the pool has sufficient entropy; false
- otherwise.
-*/
-bool stir_entropy (std::string file);
-
-/** Adds entropy to the RNG pool.
-
- @param buffer An optional buffer that contains random data.
- @param count The size of the buffer, in bytes (or 0).
-
- This can be called multiple times to stir entropy into the pool
- without any locks.
-*/
-void add_entropy (void* buffer = nullptr, int count = 0);
-
-/** Generate random bytes, suitable for cryptography. */
-/**@{*/
-/**
- @param buffer The place to store the bytes.
- @param count The number of bytes to generate.
-*/
-void random_fill (void* buffer, int count);
-
-/** Fills a POD object with random data */
-template ::value>>
-void
-random_fill (T* object)
-{
- random_fill (object, sizeof (T));
-}
-/**@}*/
-
-}
-
-#endif
diff --git a/src/ripple/crypto/csprng.h b/src/ripple/crypto/csprng.h
new file mode 100644
index 000000000..736f00127
--- /dev/null
+++ b/src/ripple/crypto/csprng.h
@@ -0,0 +1,109 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012, 2013 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef RIPPLE_CRYPTO_RANDOM_H_INCLUDED
+#define RIPPLE_CRYPTO_RANDOM_H_INCLUDED
+
+#include
+#include
+#include
+
+namespace ripple {
+
+/** A cryptographically secure random number engine
+
+ The engine is thread-safe (it uses a lock to serialize
+ access) and will, automatically, mix in some randomness
+ from std::random_device.
+
+ Meets the requirements of UniformRandomNumberEngine
+*/
+class csprng_engine
+{
+private:
+ std::mutex mutex_;
+
+ void
+ mix (
+ void* buffer,
+ std::size_t count,
+ double bitsPerByte);
+
+public:
+ using result_type = std::uint64_t;
+
+ csprng_engine(csprng_engine const&) = delete;
+ csprng_engine& operator=(csprng_engine const&) = delete;
+
+ csprng_engine(csprng_engine&&) = delete;
+ csprng_engine& operator=(csprng_engine&&) = delete;
+
+ csprng_engine ();
+ ~csprng_engine ();
+
+ /** Mix entropy into the pool */
+ void
+ mix_entropy (void* buffer = nullptr, std::size_t count = 0);
+
+ /** Load entropy from the specified file */
+ void
+ load_state (std::string const& file);
+
+ /** Save entropy to the specified file */
+ void
+ save_state (std::string const& file);
+
+ /** Generate a random integer */
+ result_type
+ operator()();
+
+ /** Fill a buffer with the requested amount of random data */
+ void
+ operator()(void *ptr, std::size_t count);
+
+ /* The smallest possible value that can be returned */
+ static constexpr
+ result_type
+ min()
+ {
+ return std::numeric_limits::min();
+ }
+
+ /* The largest possible value that can be returned */
+ static constexpr
+ result_type
+ max()
+ {
+ return std::numeric_limits::max();
+ }
+};
+
+/** The default cryptographically secure PRNG
+
+ Use this when you need to generate random numbers or
+ data that will be used for encryption or passed into
+ cryptographic routines.
+
+ This meets the requirements of UniformRandomNumberEngine
+*/
+csprng_engine& crypto_prng();
+
+}
+
+#endif
diff --git a/src/ripple/crypto/impl/ECIES.cpp b/src/ripple/crypto/impl/ECIES.cpp
index ef6e08bc0..8e1588a33 100644
--- a/src/ripple/crypto/impl/ECIES.cpp
+++ b/src/ripple/crypto/impl/ECIES.cpp
@@ -22,7 +22,8 @@
#include
#include
#include
-#include
+#include
+#include
#include
#include
#include
@@ -142,7 +143,10 @@ Blob encryptECIES (uint256 const& secretKey, Blob const& publicKey, Blob const&
{
ECIES_ENC_IV_TYPE iv;
- random_fill (iv.begin (), ECIES_ENC_BLK_SIZE);
+ beast::rngfill (
+ iv.begin (),
+ ECIES_ENC_BLK_SIZE,
+ crypto_prng());
ECIES_ENC_KEY_TYPE secret;
ECIES_HMAC_KEY_TYPE hmacKey;
diff --git a/src/ripple/crypto/impl/RandomNumbers.cpp b/src/ripple/crypto/impl/RandomNumbers.cpp
deleted file mode 100644
index 1c287a8ea..000000000
--- a/src/ripple/crypto/impl/RandomNumbers.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-//------------------------------------------------------------------------------
-/*
- This file is part of rippled: https://github.com/ripple/rippled
- Copyright (c) 2012, 2013 Ripple Labs Inc.
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-//==============================================================================
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace ripple {
-
-bool stir_entropy (std::string file)
-{
- // First, we attempt to stir any existing saved entropy
- // into the pool: no use letting it go to waste.
- RAND_load_file (file.c_str (), 1024);
-
- // And now, we extract some entropy out, and save it for
- // the future. If the quality of the entropy isn't great
- // then we let the user know.
- return RAND_write_file (file.c_str ()) != -1;
-}
-
-void add_entropy (void* buffer, int count)
-{
- assert (buffer == nullptr || count != 0);
-
- // If we are passed data in we use it but conservatively estimate that it
- // contains only around 2 bits of entropy per byte.
- if (buffer != nullptr && count != 0)
- RAND_add (buffer, count, count / 4.0);
-
- // And try to add some entropy from the system
- unsigned int rdbuf[32];
-
- std::random_device rd;
-
- for (auto& x : rdbuf)
- x = rd ();
-
- // In all our supported platforms, std::random_device is non-deterministic
- // but we conservatively estimate it has around 4 bits of entropy per byte.
- RAND_add (rdbuf, sizeof (rdbuf), sizeof (rdbuf) / 2.0);
-}
-
-void random_fill (void* buffer, int count)
-{
- assert (count > 0);
-
- if (RAND_bytes (reinterpret_cast (buffer), count) != 1)
- Throw ("Insufficient entropy in pool.");
-}
-
-}
diff --git a/src/ripple/crypto/impl/csprng.cpp b/src/ripple/crypto/impl/csprng.cpp
new file mode 100644
index 000000000..648abf4fe
--- /dev/null
+++ b/src/ripple/crypto/impl/csprng.cpp
@@ -0,0 +1,138 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012, 2013 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace ripple {
+
+void
+csprng_engine::mix (
+ void* data, std::size_t size, double bitsPerByte)
+{
+ assert (data != nullptr);
+ assert (size != 0);
+ assert (bitsPerByte != 0);
+
+ std::lock_guard lock (mutex_);
+ RAND_add (data, size, (size * bitsPerByte) / 8.0);
+}
+
+csprng_engine::csprng_engine ()
+{
+ mix_entropy ();
+}
+
+csprng_engine::~csprng_engine ()
+{
+ RAND_cleanup ();
+}
+
+void
+csprng_engine::load_state (std::string const& file)
+{
+ if (!file.empty())
+ {
+ std::lock_guard lock (mutex_);
+ RAND_load_file (file.c_str (), 1024);
+ RAND_write_file (file.c_str ());
+ }
+}
+
+void
+csprng_engine::save_state (std::string const& file)
+{
+ if (!file.empty())
+ {
+ std::lock_guard lock (mutex_);
+ RAND_write_file (file.c_str ());
+ }
+}
+
+void
+csprng_engine::mix_entropy (void* buffer, std::size_t count)
+{
+ std::array entropy;
+
+ {
+ // On every platform we support, std::random_device
+ // is non-deterministic and should provide some good
+ // quality entropy.
+ std::random_device rd;
+
+ for (auto& e : entropy)
+ e = rd();
+ }
+
+ // Assume 2 bits per byte for the system entropy:
+ mix (
+ entropy.data(),
+ entropy.size() * sizeof(std::random_device::result_type),
+ 2.0);
+
+ // We want to be extremely conservative about estimating
+ // how much entropy the buffer the user gives us contains
+ // and assume only 0.5 bits of entropy per byte:
+ if (buffer != nullptr && count != 0)
+ mix (buffer, count, 0.5);
+}
+
+csprng_engine::result_type
+csprng_engine::operator()()
+{
+ result_type ret;
+
+ std::lock_guard lock (mutex_);
+
+ auto const result = RAND_bytes (
+ reinterpret_cast(&ret),
+ sizeof(ret));
+
+ if (result == 0)
+ Throw ("Insufficient entropy");
+
+ return ret;
+}
+
+void
+csprng_engine::operator()(void *ptr, std::size_t count)
+{
+ std::lock_guard lock (mutex_);
+
+ auto const result = RAND_bytes (
+ reinterpret_cast(ptr),
+ count);
+
+ if (result != 1)
+ Throw ("Insufficient entropy");
+}
+
+csprng_engine& crypto_prng()
+{
+ static csprng_engine engine;
+ return engine;
+}
+
+}
diff --git a/src/ripple/nodestore/tests/Backend.test.cpp b/src/ripple/nodestore/tests/Backend.test.cpp
index c97e356ca..a8296d4bf 100644
--- a/src/ripple/nodestore/tests/Backend.test.cpp
+++ b/src/ripple/nodestore/tests/Backend.test.cpp
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
namespace ripple {
namespace NodeStore {
@@ -31,8 +32,10 @@ namespace NodeStore {
class Backend_test : public TestBase
{
public:
- void testBackend (std::string const& type, std::int64_t const seedValue,
- int numObjectsToTest = 2000)
+ void testBackend (
+ std::string const& type,
+ std::uint64_t const seedValue,
+ int numObjectsToTest = 2000)
{
DummyScheduler scheduler;
@@ -43,9 +46,11 @@ public:
params.set ("type", type);
params.set ("path", path.getFullPathName ().toStdString ());
+ beast::xor_shift_engine rng (seedValue);
+
// Create a batch
- Batch batch;
- createPredictableBatch (batch, numObjectsToTest, seedValue);
+ auto batch = createPredictableBatch (
+ numObjectsToTest, rng());
beast::Journal j;
@@ -66,8 +71,11 @@ public:
{
// Reorder and read the copy again
+ std::shuffle (
+ batch.begin(),
+ batch.end(),
+ rng);
Batch copy;
- beast::UnitTestUtilities::repeatableShuffle (batch.size (), batch, seedValue);
fetchCopyOfBatch (*backend, ©, batch);
expect (areBatchesEqual (batch, copy), "Should be equal");
}
@@ -92,7 +100,7 @@ public:
void run ()
{
- int const seedValue = 50;
+ std::uint64_t const seedValue = 50;
testBackend ("nudb", seedValue);
diff --git a/src/ripple/nodestore/tests/Base.test.h b/src/ripple/nodestore/tests/Base.test.h
index a4db232c1..52918b63d 100644
--- a/src/ripple/nodestore/tests/Base.test.h
+++ b/src/ripple/nodestore/tests/Base.test.h
@@ -21,9 +21,11 @@
#define RIPPLE_NODESTORE_BASE_H_INCLUDED
#include
+#include
#include
#include
-#include
+#include
+#include
#include
#include
@@ -66,61 +68,47 @@ class TestBase : public beast::unit_test::suite
public:
// Tunable parameters
//
- enum
- {
- maxPayloadBytes = 2000,
- numObjectsToTest = 2000
- };
-
- // Creates predictable objects
- class PredictableObjectFactory
- {
- public:
- explicit PredictableObjectFactory (std::int64_t seedValue)
- : r (seedValue)
- {
- }
-
- std::shared_ptr createObject ()
- {
- NodeObjectType type;
- switch (r.nextInt (4))
- {
- case 0: type = hotLEDGER; break;
- case 2: type = hotACCOUNT_NODE; break;
- case 3: type = hotTRANSACTION_NODE; break;
- default:
- case 1: // was hotTRANSACTION
- type = hotUNKNOWN;
- break;
- };
-
- uint256 hash;
- r.fillBitsRandomly (hash.begin (), hash.size ());
-
- int const payloadBytes = 1 + r.nextInt (maxPayloadBytes);
-
- Blob data (payloadBytes);
-
- r.fillBitsRandomly (data.data (), payloadBytes);
-
- return NodeObject::createObject(type, std::move(data), hash);
- }
-
- private:
- beast::Random r;
- };
+ static std::size_t const minPayloadBytes = 1;
+ static std::size_t const maxPayloadBytes = 2000;
+ static int const numObjectsToTest = 2000;
public:
- // Create a predictable batch of objects
- static void createPredictableBatch(Batch& batch, int numObjects,
- std::int64_t seedValue) {
+ // Create a predictable batch of objects
+ static
+ Batch createPredictableBatch(
+ int numObjects, std::uint64_t seed)
+ {
+ Batch batch;
batch.reserve (numObjects);
- PredictableObjectFactory factory (seedValue);
+ beast::xor_shift_engine rng (seed);
for (int i = 0; i < numObjects; ++i)
- batch.push_back (factory.createObject ());
+ {
+ NodeObjectType type;
+
+ switch (rand_int(rng, 3))
+ {
+ case 0: type = hotLEDGER; break;
+ case 1: type = hotACCOUNT_NODE; break;
+ case 2: type = hotTRANSACTION_NODE; break;
+ case 3: type = hotUNKNOWN; break;
+ }
+
+ uint256 hash;
+ beast::rngfill (hash.begin(), hash.size(), rng);
+
+ Blob blob (
+ rand_int(rng,
+ minPayloadBytes, maxPayloadBytes));
+ beast::rngfill (blob.data(), blob.size(), rng);
+
+ batch.push_back (
+ NodeObject::createObject(
+ type, std::move(blob), hash));
+ }
+
+ return batch;
}
// Compare two batches for equality
diff --git a/src/ripple/nodestore/tests/Basics.test.cpp b/src/ripple/nodestore/tests/Basics.test.cpp
index 0d9f6079c..7bbc320c6 100644
--- a/src/ripple/nodestore/tests/Basics.test.cpp
+++ b/src/ripple/nodestore/tests/Basics.test.cpp
@@ -33,31 +33,31 @@ class NodeStoreBasic_test : public TestBase
{
public:
// Make sure predictable object generation works!
- void testBatches (std::int64_t const seedValue)
+ void testBatches (std::uint64_t const seedValue)
{
testcase ("batch");
- Batch batch1;
- createPredictableBatch (batch1, numObjectsToTest, seedValue);
+ auto batch1 = createPredictableBatch (
+ numObjectsToTest, seedValue);
- Batch batch2;
- createPredictableBatch (batch2, numObjectsToTest, seedValue);
+ auto batch2 = createPredictableBatch (
+ numObjectsToTest, seedValue);
expect (areBatchesEqual (batch1, batch2), "Should be equal");
- Batch batch3;
- createPredictableBatch (batch3, numObjectsToTest, seedValue+1);
+ auto batch3 = createPredictableBatch (
+ numObjectsToTest, seedValue + 1);
expect (! areBatchesEqual (batch1, batch3), "Should not be equal");
}
// Checks encoding/decoding blobs
- void testBlobs (std::int64_t const seedValue)
+ void testBlobs (std::uint64_t const seedValue)
{
testcase ("encoding");
- Batch batch;
- createPredictableBatch (batch, numObjectsToTest, seedValue);
+ auto batch = createPredictableBatch (
+ numObjectsToTest, seedValue);
EncodedBlob encoded;
for (int i = 0; i < batch.size (); ++i)
@@ -79,7 +79,7 @@ public:
void run ()
{
- std::int64_t const seedValue = 50;
+ std::uint64_t const seedValue = 50;
testBatches (seedValue);
diff --git a/src/ripple/nodestore/tests/Database.test.cpp b/src/ripple/nodestore/tests/Database.test.cpp
index 2b163cb9a..9cfecf041 100644
--- a/src/ripple/nodestore/tests/Database.test.cpp
+++ b/src/ripple/nodestore/tests/Database.test.cpp
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
namespace ripple {
namespace NodeStore {
@@ -40,8 +41,8 @@ public:
srcParams.set ("path", node_db.getFullPathName ().toStdString ());
// Create a batch
- Batch batch;
- createPredictableBatch (batch, numObjectsToTest, seedValue);
+ auto batch = createPredictableBatch (
+ numObjectsToTest, seedValue);
beast::Journal j;
@@ -102,9 +103,11 @@ public:
nodeParams.set ("type", type);
nodeParams.set ("path", node_db.getFullPathName ().toStdString ());
+ beast::xor_shift_engine rng (seedValue);
+
// Create a batch
- Batch batch;
- createPredictableBatch (batch, numObjectsToTest, seedValue);
+ auto batch = createPredictableBatch (
+ numObjectsToTest, rng());
beast::Journal j;
@@ -125,8 +128,11 @@ public:
{
// Reorder and read the copy again
+ std::shuffle (
+ batch.begin(),
+ batch.end(),
+ rng);
Batch copy;
- beast::UnitTestUtilities::repeatableShuffle (batch.size (), batch, seedValue);
fetchCopyOfBatch (*db, ©, batch);
expect (areBatchesEqual (batch, copy), "Should be equal");
}
diff --git a/src/ripple/overlay/impl/PeerImp.cpp b/src/ripple/overlay/impl/PeerImp.cpp
index f9065eadf..ec71fc3a3 100644
--- a/src/ripple/overlay/impl/PeerImp.cpp
+++ b/src/ripple/overlay/impl/PeerImp.cpp
@@ -32,6 +32,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -546,7 +547,7 @@ PeerImp::onTimer (error_code const& ec)
{
// Make sequence unpredictable enough that a peer
// can't fake their latency
- lastPingSeq_ = (rand() % 65536);
+ lastPingSeq_ = rand_int (65535);
lastPingTime_ = clock_type::now();
protocol::TMPing message;
@@ -2371,23 +2372,21 @@ PeerImp::getScore (bool haveItem) const
{
// Random component of score, used to break ties and avoid
// overloading the "best" peer
- static const int spRandom = 10000;
+ static const int spRandomMax = 9999;
// Score for being very likely to have the thing we are
- // look for
- // Should be roughly spRandom
- static const int spHaveItem = 10000;
+ // look for; should be roughly spRandomMax
+ static const int spHaveItem = 10000;
- // Score reduction for each millisecond of latency
- // Should be roughly spRandom divided by
- // the maximum reasonable latency
- static const int spLatency = 30;
+ // Score reduction for each millisecond of latency; should
+ // be roughly spRandomMax divided by the maximum reasonable
+ // latency
+ static const int spLatency = 30;
- // Penalty for unknown latency
- // Should be roughly spRandom
- static const int spNoLatency = 8000;
+ // Penalty for unknown latency; should be roughly spRandomMax
+ static const int spNoLatency = 8000;
- int score = rand() % spRandom;
+ int score = rand_int(spRandomMax);
if (haveItem)
score += spHaveItem;
@@ -2395,9 +2394,9 @@ PeerImp::getScore (bool haveItem) const
std::chrono::milliseconds latency;
{
std::lock_guard sl (recentLock_);
-
latency = latency_;
}
+
if (latency != std::chrono::milliseconds (-1))
score -= latency.count() * spLatency;
else
diff --git a/src/ripple/peerfinder/impl/Counts.h b/src/ripple/peerfinder/impl/Counts.h
index 01f5a774c..e980d6770 100644
--- a/src/ripple/peerfinder/impl/Counts.h
+++ b/src/ripple/peerfinder/impl/Counts.h
@@ -20,10 +20,10 @@
#ifndef RIPPLE_PEERFINDER_COUNTS_H_INCLUDED
#define RIPPLE_PEERFINDER_COUNTS_H_INCLUDED
+#include
#include
#include
#include
-#include
namespace ripple {
namespace PeerFinder {
@@ -46,14 +46,9 @@ public:
, m_acceptCount (0)
, m_closingCount (0)
{
-#if 1
- std::random_device rd;
- std::mt19937 gen (rd());
m_roundingThreshold =
- std::generate_canonical (gen);
-#else
- m_roundingThreshold = Random::getSystemRandom().nextDouble();
-#endif
+ std::generate_canonical (
+ default_prng());
}
//--------------------------------------------------------------------------
diff --git a/src/ripple/protocol/impl/RippleAddress.cpp b/src/ripple/protocol/impl/RippleAddress.cpp
index 838d26d04..799ff7de9 100644
--- a/src/ripple/protocol/impl/RippleAddress.cpp
+++ b/src/ripple/protocol/impl/RippleAddress.cpp
@@ -20,11 +20,12 @@
#include
#include
#include
+#include
#include
#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -32,6 +33,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -740,7 +742,10 @@ void RippleAddress::setSeedRandom ()
// XXX Maybe we should call MakeNewKey
uint128 key;
- random_fill (key.begin (), key.size ());
+ beast::rngfill (
+ key.begin(),
+ key.size(),
+ crypto_prng());
RippleAddress::setSeed (key);
}
diff --git a/src/ripple/protocol/impl/SecretKey.cpp b/src/ripple/protocol/impl/SecretKey.cpp
index 2db662859..2c6cab916 100644
--- a/src/ripple/protocol/impl/SecretKey.cpp
+++ b/src/ripple/protocol/impl/SecretKey.cpp
@@ -23,8 +23,9 @@
#include
#include
#include
-#include
+#include
#include
+#include
#include
#include
@@ -150,7 +151,10 @@ Seed
randomSeed()
{
std::uint8_t buf[16];
- random_fill(buf, sizeof(buf));
+ beast::rngfill(
+ buf,
+ sizeof(buf),
+ crypto_prng());
Seed seed(Slice{ buf, sizeof(buf) });
beast::secure_erase(buf, sizeof(buf));
return seed;
@@ -170,7 +174,10 @@ SecretKey
randomSecretKey()
{
std::uint8_t buf[32];
- random_fill(buf, sizeof(buf));
+ beast::rngfill(
+ buf,
+ sizeof(buf),
+ crypto_prng());
SecretKey sk(Slice{ buf, sizeof(buf) });
beast::secure_erase(buf, sizeof(buf));
return sk;
diff --git a/src/ripple/protocol/tests/STAmount.test.cpp b/src/ripple/protocol/tests/STAmount.test.cpp
index 63a05d0cd..1a496fa8d 100644
--- a/src/ripple/protocol/tests/STAmount.test.cpp
+++ b/src/ripple/protocol/tests/STAmount.test.cpp
@@ -19,6 +19,7 @@
#include
#include
+#include
#include
#include
#include
@@ -407,9 +408,7 @@ public:
for (int i = 0; i < 16; ++i)
{
- std::uint64_t r = rand ();
- r <<= 32;
- r |= rand ();
+ std::uint64_t r = rand_int();
b.setuint64 (r);
if (b.getuint64 () != r)
@@ -458,7 +457,11 @@ public:
roundTest (7, 11, 44);
for (int i = 0; i <= 100000; ++i)
- mulTest (rand () % 10000000, rand () % 10000000);
+ {
+ mulTest (
+ rand_int(10000000),
+ rand_int(10000000));
+ }
}
//--------------------------------------------------------------------------
@@ -484,12 +487,6 @@ public:
expect (bigDsmall == zero, "small/big != 0: " + bigDsmall.getText ());
-#if 0
- // TODO(tom): this test makes no sense - we should have no way to have
- // the currency not be XRP while the account is XRP.
- bigDsmall = divide (smallValue, bigNative, noCurrency(), xrpAccount ());
-#endif
-
expect (bigDsmall == zero,
"small/bigNative != 0: " + bigDsmall.getText ());
diff --git a/src/ripple/resource/tests/Logic.test.cpp b/src/ripple/resource/tests/Logic.test.cpp
index 15ea9b25e..5e7f9e95d 100644
--- a/src/ripple/resource/tests/Logic.test.cpp
+++ b/src/ripple/resource/tests/Logic.test.cpp
@@ -19,9 +19,9 @@
#include
#include
+#include
#include
#include
-#include
#include
namespace ripple {
@@ -60,16 +60,15 @@ public:
void createGossip (Gossip& gossip)
{
- beast::Random r;
- int const v (10 + r.nextInt (10));
- int const n (10 + r.nextInt (10));
+ int const v (10 + rand_int(9));
+ int const n (10 + rand_int(9));
gossip.items.reserve (n);
for (int i = 0; i < n; ++i)
{
Gossip::Item item;
- item.balance = 100 + r.nextInt (500);
+ item.balance = 100 + rand_int(499);
item.address = beast::IP::Endpoint (
- beast::IP::AddressV4 (207, 127, 82, v + i));
+ beast::IP::AddressV4 (192, 0, 2, v + i));
gossip.items.push_back (item);
}
}
@@ -84,7 +83,7 @@ public:
Charge const fee (dropThreshold + 1);
beast::IP::Endpoint const addr (
- beast::IP::Endpoint::from_string ("207.127.82.2"));
+ beast::IP::Endpoint::from_string ("192.0.2.2"));
{
Consumer c (logic.newInboundEndpoint (addr));
@@ -191,7 +190,7 @@ public:
Gossip::Item item;
item.balance = 100;
item.address = beast::IP::Endpoint (
- beast::IP::AddressV4 (207, 127, 82, 1));
+ beast::IP::AddressV4 (192, 0, 2, 1));
g.items.push_back (item);
logic.importConsumers ("g", g);
@@ -206,7 +205,7 @@ public:
TestLogic logic (j);
{
- beast::IP::Endpoint address (beast::IP::Endpoint::from_string ("207.127.82.1"));
+ beast::IP::Endpoint address (beast::IP::Endpoint::from_string ("192.0.2.1"));
Consumer c (logic.newInboundEndpoint (address));
Charge fee (1000);
j.info <<
@@ -222,7 +221,7 @@ public:
}
{
- beast::IP::Endpoint address (beast::IP::Endpoint::from_string ("207.127.82.2"));
+ beast::IP::Endpoint address (beast::IP::Endpoint::from_string ("192.0.2.2"));
Consumer c (logic.newInboundEndpoint (address));
Charge fee (1000);
j.info <<
diff --git a/src/ripple/rpc/handlers/Random.cpp b/src/ripple/rpc/handlers/Random.cpp
index e57e84d04..484584835 100644
--- a/src/ripple/rpc/handlers/Random.cpp
+++ b/src/ripple/rpc/handlers/Random.cpp
@@ -18,12 +18,13 @@
//==============================================================================
#include
-#include
+#include
#include
#include
#include
#include
#include
+#include
namespace ripple {
@@ -42,7 +43,10 @@ Json::Value doRandom (RPC::Context& context)
try
{
uint256 rand;
- random_fill (rand.begin (), rand.size ());
+ beast::rngfill (
+ rand.begin(),
+ rand.size(),
+ crypto_prng());
Json::Value jvResult;
jvResult[jss::random] = to_string (rand);
diff --git a/src/ripple/shamap/impl/SHAMapNodeID.cpp b/src/ripple/shamap/impl/SHAMapNodeID.cpp
index 0e3547f80..f688bd502 100644
--- a/src/ripple/shamap/impl/SHAMapNodeID.cpp
+++ b/src/ripple/shamap/impl/SHAMapNodeID.cpp
@@ -19,7 +19,7 @@
#include
#include
-#include
+#include
#include
#include
#include
diff --git a/src/ripple/shamap/impl/SHAMapSync.cpp b/src/ripple/shamap/impl/SHAMapSync.cpp
index 738be14d3..087a8dff9 100644
--- a/src/ripple/shamap/impl/SHAMapSync.cpp
+++ b/src/ripple/shamap/impl/SHAMapSync.cpp
@@ -18,6 +18,7 @@
//==============================================================================
#include
+#include
#include
#include
#include
@@ -162,7 +163,7 @@ SHAMap::getMissingNodes(std::vector& nodeIDs, std::vector
// (randomly selected) inner node. This increases the likelihood
// that the two threads will produce different request sets (which is
// more efficient than sending identical requests).
- int firstChild = rand() % 256;
+ int firstChild = rand_int(255);
int currentChild = 0;
bool fullBelow = true;
@@ -212,7 +213,7 @@ SHAMap::getMissingNodes(std::vector& nodeIDs, std::vector
// Switch to processing the child node
node = static_cast(d);
nodeID = childID;
- firstChild = rand() % 256;
+ firstChild = rand_int(255);
currentChild = 0;
fullBelow = true;
}
diff --git a/src/ripple/shamap/tests/FetchPack.test.cpp b/src/ripple/shamap/tests/FetchPack.test.cpp
index c8fcd0109..73aa9663f 100644
--- a/src/ripple/shamap/tests/FetchPack.test.cpp
+++ b/src/ripple/shamap/tests/FetchPack.test.cpp
@@ -22,10 +22,11 @@
#include
#include
#include
+#include
#include
#include
#include
-#include