Skip to content

Commit

Permalink
Automatically initialize RNG on first use.
Browse files Browse the repository at this point in the history
  • Loading branch information
sipa authored and Fuzzbawls committed Apr 14, 2021
1 parent 1a5dbc5 commit d76ee83
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 21 deletions.
68 changes: 50 additions & 18 deletions src/random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ static inline int64_t GetPerformanceCounter()
#endif
}


#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
static std::atomic<bool> hwrand_initialized{false};
static bool rdrand_supported = false;
Expand All @@ -83,13 +82,24 @@ static void RDRandInit()
{
uint32_t eax, ebx, ecx, edx;
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && (ecx & CPUID_F1_ECX_RDRAND)) {
LogPrintf("Using RdRand as an additional entropy source\n");
rdrand_supported = true;
}
hwrand_initialized.store(true);
}

static void RDRandReport()
{
assert(hwrand_initialized.load(std::memory_order_relaxed));
if (rdrand_supported) {
// This must be done in a separate function, as HWRandInit() may be indirectly called
// from global constructors, before logging is initialized.
LogPrintf("Using RdRand as an additional entropy source\n");
}
}

#else
static void RDRandInit() {}
static void RDRandReport() {}
#endif

static bool GetHWRand(unsigned char* ent32) {
Expand Down Expand Up @@ -279,6 +289,26 @@ void GetRandBytes(unsigned char* buf, int num)
}
}

namespace {
struct RNGState {
Mutex m_mutex;
unsigned char m_state[32] = {0};
uint64_t m_counter = 0;

explicit RNGState() {
RDRandInit();
}
};

RNGState& GetRNGState()
{
// This C++11 idiom relies on the guarantee that static variable are initialized
// on first call, even when multiple parallel calls are permitted.
static std::unique_ptr<RNGState> g_rng{new RNGState()};
return *g_rng;
}
}

static void AddDataToRng(void* data, size_t len);

void RandAddSeedSleep()
Expand All @@ -295,29 +325,28 @@ void RandAddSeedSleep()
memory_cleanse(&nPerfCounter2, sizeof(nPerfCounter2));
}


static std::mutex cs_rng_state;
static unsigned char rng_state[32] = {0};
static uint64_t rng_counter = 0;

static void AddDataToRng(void* data, size_t len) {
RNGState& rng = GetRNGState();

CSHA512 hasher;
hasher.Write((const unsigned char*)&len, sizeof(len));
hasher.Write((const unsigned char*)data, len);
unsigned char buf[64];
{
std::unique_lock<std::mutex> lock(cs_rng_state);
hasher.Write(rng_state, sizeof(rng_state));
hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter));
++rng_counter;
WAIT_LOCK(rng.m_mutex, lock);
hasher.Write(rng.m_state, sizeof(rng.m_state));
hasher.Write((const unsigned char*)&rng.m_counter, sizeof(rng.m_counter));
++rng.m_counter;
hasher.Finalize(buf);
memcpy(rng_state, buf + 32, 32);
memcpy(rng.m_state, buf + 32, 32);
}
memory_cleanse(buf, 64);
}

void GetStrongRandBytes(unsigned char* out, int num)
{
RNGState& rng = GetRNGState();

assert(num <= 32);
CSHA512 hasher;
unsigned char buf[64];
Expand All @@ -338,12 +367,12 @@ void GetStrongRandBytes(unsigned char* out, int num)

// Combine with and update state
{
std::unique_lock<std::mutex> lock(cs_rng_state);
hasher.Write(rng_state, sizeof(rng_state));
hasher.Write((const unsigned char*)&rng_counter, sizeof(rng_counter));
++rng_counter;
WAIT_LOCK(rng.m_mutex, lock);
hasher.Write(rng.m_state, sizeof(rng.m_state));
hasher.Write((const unsigned char*)&rng.m_counter, sizeof(rng.m_counter));
++rng.m_counter;
hasher.Finalize(buf);
memcpy(rng_state, buf + 32, 32);
memcpy(rng.m_state, buf + 32, 32);
}

// Produce output
Expand Down Expand Up @@ -480,5 +509,8 @@ FastRandomContext& FastRandomContext::operator=(FastRandomContext&& from) noexce

void RandomInit()
{
RDRandInit();
// Invoke RNG code to trigger initialization (if not already performed)
GetRNGState();

RDRandReport();
}
7 changes: 6 additions & 1 deletion src/random.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,12 @@ void GetOSRand(unsigned char *ent32);
*/
bool Random_SanityCheck();

/** Initialize the RNG. */
/**
* Initialize global RNG state and log any CPU features that are used.
*
* Calling this function is optional. RNG state will be initialized when first
* needed if it is not called.
*/
void RandomInit();

#endif // BITCOIN_RANDOM_H
2 changes: 0 additions & 2 deletions src/test/test_pivx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#include "evo/evodb.h"
#include "miner.h"
#include "net_processing.h"
#include "random.h"
#include "rpc/server.h"
#include "rpc/register.h"
#include "script/sigcache.h"
Expand Down Expand Up @@ -40,7 +39,6 @@ std::ostream& operator<<(std::ostream& os, const uint256& num)

BasicTestingSetup::BasicTestingSetup()
{
RandomInit();
ECC_Start();
SetupEnvironment();
InitSignatureCache();
Expand Down

0 comments on commit d76ee83

Please sign in to comment.