|
|
@ -143,6 +143,34 @@ static bool GetHardwareRand(unsigned char* ent32) noexcept {
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Use repeated SHA512 to strengthen the randomness in seed32, and feed into hasher. */
|
|
|
|
|
|
|
|
static void Strengthen(const unsigned char (&seed)[32], int microseconds, CSHA512& hasher) noexcept
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
CSHA512 inner_hasher;
|
|
|
|
|
|
|
|
inner_hasher.Write(seed, sizeof(seed));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Hash loop
|
|
|
|
|
|
|
|
unsigned char buffer[64];
|
|
|
|
|
|
|
|
int64_t stop = GetTimeMicros() + microseconds;
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
for (int i = 0; i < 1000; ++i) {
|
|
|
|
|
|
|
|
inner_hasher.Finalize(buffer);
|
|
|
|
|
|
|
|
inner_hasher.Reset();
|
|
|
|
|
|
|
|
inner_hasher.Write(buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Benchmark operation and feed it into outer hasher.
|
|
|
|
|
|
|
|
int64_t perf = GetPerformanceCounter();
|
|
|
|
|
|
|
|
hasher.Write((const unsigned char*)&perf, sizeof(perf));
|
|
|
|
|
|
|
|
} while (GetTimeMicros() < stop);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Produce output from inner state and feed it to outer hasher.
|
|
|
|
|
|
|
|
inner_hasher.Finalize(buffer);
|
|
|
|
|
|
|
|
hasher.Write(buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
// Try to clean up.
|
|
|
|
|
|
|
|
inner_hasher.Reset();
|
|
|
|
|
|
|
|
memory_cleanse(buffer, sizeof(buffer));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void RandAddSeedPerfmon(CSHA512& hasher)
|
|
|
|
static void RandAddSeedPerfmon(CSHA512& hasher)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
#ifdef WIN32
|
|
|
|
#ifdef WIN32
|
|
|
@ -436,7 +464,23 @@ static void SeedSlow(CSHA512& hasher) noexcept
|
|
|
|
SeedTimestamp(hasher);
|
|
|
|
SeedTimestamp(hasher);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void SeedSleep(CSHA512& hasher)
|
|
|
|
/** Extract entropy from rng, strengthen it, and feed it into hasher. */
|
|
|
|
|
|
|
|
static void SeedStrengthen(CSHA512& hasher, RNGState& rng) noexcept
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
static std::atomic<int64_t> last_strengthen{0};
|
|
|
|
|
|
|
|
int64_t last_time = last_strengthen.load();
|
|
|
|
|
|
|
|
int64_t current_time = GetTimeMicros();
|
|
|
|
|
|
|
|
if (current_time > last_time + 60000000) { // Only run once a minute
|
|
|
|
|
|
|
|
// Generate 32 bytes of entropy from the RNG, and a copy of the entropy already in hasher.
|
|
|
|
|
|
|
|
unsigned char strengthen_seed[32];
|
|
|
|
|
|
|
|
rng.MixExtract(strengthen_seed, sizeof(strengthen_seed), CSHA512(hasher), false);
|
|
|
|
|
|
|
|
// Strengthen it for 10ms (100ms on first run), and feed it into hasher.
|
|
|
|
|
|
|
|
Strengthen(strengthen_seed, last_time == 0 ? 100000 : 10000, hasher);
|
|
|
|
|
|
|
|
last_strengthen = current_time;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void SeedSleep(CSHA512& hasher, RNGState& rng)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// Everything that the 'fast' seeder includes
|
|
|
|
// Everything that the 'fast' seeder includes
|
|
|
|
SeedFast(hasher);
|
|
|
|
SeedFast(hasher);
|
|
|
@ -452,9 +496,12 @@ static void SeedSleep(CSHA512& hasher)
|
|
|
|
|
|
|
|
|
|
|
|
// Windows performance monitor data (once every 10 minutes)
|
|
|
|
// Windows performance monitor data (once every 10 minutes)
|
|
|
|
RandAddSeedPerfmon(hasher);
|
|
|
|
RandAddSeedPerfmon(hasher);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Strengthen every minute
|
|
|
|
|
|
|
|
SeedStrengthen(hasher, rng);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void SeedStartup(CSHA512& hasher) noexcept
|
|
|
|
static void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept
|
|
|
|
{
|
|
|
|
{
|
|
|
|
#ifdef WIN32
|
|
|
|
#ifdef WIN32
|
|
|
|
RAND_screen();
|
|
|
|
RAND_screen();
|
|
|
@ -465,6 +512,9 @@ static void SeedStartup(CSHA512& hasher) noexcept
|
|
|
|
|
|
|
|
|
|
|
|
// Windows performance monitor data.
|
|
|
|
// Windows performance monitor data.
|
|
|
|
RandAddSeedPerfmon(hasher);
|
|
|
|
RandAddSeedPerfmon(hasher);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Strengthen
|
|
|
|
|
|
|
|
SeedStrengthen(hasher, rng);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
enum class RNGLevel {
|
|
|
|
enum class RNGLevel {
|
|
|
@ -489,7 +539,7 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level)
|
|
|
|
SeedSlow(hasher);
|
|
|
|
SeedSlow(hasher);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case RNGLevel::SLEEP:
|
|
|
|
case RNGLevel::SLEEP:
|
|
|
|
SeedSleep(hasher);
|
|
|
|
SeedSleep(hasher, rng);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -497,7 +547,7 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level)
|
|
|
|
if (!rng.MixExtract(out, num, std::move(hasher), false)) {
|
|
|
|
if (!rng.MixExtract(out, num, std::move(hasher), false)) {
|
|
|
|
// On the first invocation, also seed with SeedStartup().
|
|
|
|
// On the first invocation, also seed with SeedStartup().
|
|
|
|
CSHA512 startup_hasher;
|
|
|
|
CSHA512 startup_hasher;
|
|
|
|
SeedStartup(startup_hasher);
|
|
|
|
SeedStartup(startup_hasher, rng);
|
|
|
|
rng.MixExtract(out, num, std::move(startup_hasher), true);
|
|
|
|
rng.MixExtract(out, num, std::move(startup_hasher), true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|