Changeset View
Changeset View
Standalone View
Standalone View
src/random.cpp
Show First 20 Lines • Show All 551 Lines • ▼ Show 20 Lines | static void SeedSlow(CSHA512 &hasher) noexcept { | ||||
// | // | ||||
// Note that we also commit to a timestamp in the Fast seeder, so we | // Note that we also commit to a timestamp in the Fast seeder, so we | ||||
// indirectly commit to a benchmark of all the entropy gathering sources in | // indirectly commit to a benchmark of all the entropy gathering sources in | ||||
// this function). | // this function). | ||||
SeedTimestamp(hasher); | SeedTimestamp(hasher); | ||||
} | } | ||||
/** Extract entropy from rng, strengthen it, and feed it into hasher. */ | /** Extract entropy from rng, strengthen it, and feed it into hasher. */ | ||||
static void SeedStrengthen(CSHA512 &hasher, RNGState &rng) noexcept { | static void SeedStrengthen(CSHA512 &hasher, RNGState &rng, | ||||
static std::atomic<int64_t> last_strengthen{0}; | int microseconds) noexcept { | ||||
int64_t last_time = last_strengthen.load(); | |||||
int64_t current_time = GetTimeMicros(); | |||||
// Only run once a minute | |||||
if (current_time > last_time + 60000000) { | |||||
// Generate 32 bytes of entropy from the RNG, and a copy of the entropy | // Generate 32 bytes of entropy from the RNG, and a copy of the entropy | ||||
// already in hasher. | // already in hasher. | ||||
uint8_t strengthen_seed[32]; | uint8_t strengthen_seed[32]; | ||||
rng.MixExtract(strengthen_seed, sizeof(strengthen_seed), | rng.MixExtract(strengthen_seed, sizeof(strengthen_seed), CSHA512(hasher), | ||||
CSHA512(hasher), false); | false); | ||||
// Strengthen it for 10ms (100ms on first run), and feed it into hasher. | // Strengthen the seed, and feed it into hasher. | ||||
Strengthen(strengthen_seed, last_time == 0 ? 100000 : 10000, hasher); | Strengthen(strengthen_seed, microseconds, hasher); | ||||
last_strengthen = current_time; | |||||
} | |||||
} | } | ||||
static void SeedSleep(CSHA512 &hasher, RNGState &rng) { | static void SeedPeriodic(CSHA512 &hasher, RNGState &rng) { | ||||
// Everything that the 'fast' seeder includes | // Everything that the 'fast' seeder includes | ||||
SeedFast(hasher); | SeedFast(hasher); | ||||
// High-precision timestamp | // High-precision timestamp | ||||
SeedTimestamp(hasher); | SeedTimestamp(hasher); | ||||
// Sleep for 1ms | // Dynamic environment data (performance monitoring, ...) | ||||
MilliSleep(1); | |||||
// High-precision timestamp after sleeping (as we commit to both the time | |||||
// before and after, this measures the delay) | |||||
SeedTimestamp(hasher); | |||||
// Dynamic environment data (performance monitoring, ...; once every 10 | |||||
// minutes) | |||||
RandAddDynamicEnv(hasher); | RandAddDynamicEnv(hasher); | ||||
// Strengthen | // Strengthen for 10ms | ||||
SeedStrengthen(hasher, rng); | SeedStrengthen(hasher, rng, 10000); | ||||
} | } | ||||
static void SeedStartup(CSHA512 &hasher, RNGState &rng) noexcept { | static void SeedStartup(CSHA512 &hasher, RNGState &rng) noexcept { | ||||
// Gather 256 bits of hardware randomness, if available | // Gather 256 bits of hardware randomness, if available | ||||
SeedHardwareSlow(hasher); | SeedHardwareSlow(hasher); | ||||
// Everything that the 'slow' seeder includes. | // Everything that the 'slow' seeder includes. | ||||
SeedSlow(hasher); | SeedSlow(hasher); | ||||
// Dynamic environment data | // Dynamic environment data (performance monitoring, ...) | ||||
RandAddDynamicEnv(hasher); | RandAddDynamicEnv(hasher); | ||||
// Static environment data | // Static environment data | ||||
RandAddStaticEnv(hasher); | RandAddStaticEnv(hasher); | ||||
// Strengthen | // Strengthen for 100ms | ||||
SeedStrengthen(hasher, rng); | SeedStrengthen(hasher, rng, 100000); | ||||
} | } | ||||
enum class RNGLevel { | enum class RNGLevel { | ||||
FAST, //!< Automatically called by GetRandBytes | FAST, //!< Automatically called by GetRandBytes | ||||
SLOW, //!< Automatically called by GetStrongRandBytes | SLOW, //!< Automatically called by GetStrongRandBytes | ||||
SLEEP, //!< Called by RandAddSeedSleep() | PERIODIC, //!< Called by RandAddPeriodic() | ||||
}; | }; | ||||
static void ProcRand(uint8_t *out, int num, RNGLevel level) { | static void ProcRand(uint8_t *out, int num, RNGLevel level) { | ||||
// Make sure the RNG is initialized first (as all Seed* function possibly | // Make sure the RNG is initialized first (as all Seed* function possibly | ||||
// need hwrand to be available). | // need hwrand to be available). | ||||
RNGState &rng = GetRNGState(); | RNGState &rng = GetRNGState(); | ||||
assert(num <= 32); | assert(num <= 32); | ||||
CSHA512 hasher; | CSHA512 hasher; | ||||
switch (level) { | switch (level) { | ||||
case RNGLevel::FAST: | case RNGLevel::FAST: | ||||
SeedFast(hasher); | SeedFast(hasher); | ||||
break; | break; | ||||
case RNGLevel::SLOW: | case RNGLevel::SLOW: | ||||
SeedSlow(hasher); | SeedSlow(hasher); | ||||
break; | break; | ||||
case RNGLevel::SLEEP: | case RNGLevel::PERIODIC: | ||||
SeedSleep(hasher, rng); | SeedPeriodic(hasher, rng); | ||||
break; | break; | ||||
} | } | ||||
// Combine with and update state | // Combine with and update state | ||||
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, rng); | SeedStartup(startup_hasher, rng); | ||||
Show All 11 Lines | |||||
} | } | ||||
void GetRandBytes(uint8_t *buf, int num) noexcept { | void GetRandBytes(uint8_t *buf, int num) noexcept { | ||||
ProcRand(buf, num, RNGLevel::FAST); | ProcRand(buf, num, RNGLevel::FAST); | ||||
} | } | ||||
void GetStrongRandBytes(uint8_t *buf, int num) noexcept { | void GetStrongRandBytes(uint8_t *buf, int num) noexcept { | ||||
ProcRand(buf, num, RNGLevel::SLOW); | ProcRand(buf, num, RNGLevel::SLOW); | ||||
} | } | ||||
void RandAddSeedSleep() { | void RandAddPeriodic() { | ||||
ProcRand(nullptr, 0, RNGLevel::SLEEP); | ProcRand(nullptr, 0, RNGLevel::PERIODIC); | ||||
} | } | ||||
bool g_mock_deterministic_tests{false}; | bool g_mock_deterministic_tests{false}; | ||||
uint64_t GetRand(uint64_t nMax) noexcept { | uint64_t GetRand(uint64_t nMax) noexcept { | ||||
return FastRandomContext(g_mock_deterministic_tests).randrange(nMax); | return FastRandomContext(g_mock_deterministic_tests).randrange(nMax); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 133 Lines • Show Last 20 Lines |