diff --git a/src/random.cpp b/src/random.cpp index 47c305153d..8191ad98b8 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -365,6 +365,9 @@ class RNGState { uint64_t m_counter GUARDED_BY(m_mutex) = 0; bool m_strongly_seeded GUARDED_BY(m_mutex) = false; + Mutex m_events_mutex; + CSHA256 m_events_hasher GUARDED_BY(m_events_mutex); + public: RNGState() noexcept { @@ -375,6 +378,35 @@ public: { } + void AddEvent(uint32_t event_info) noexcept + { + LOCK(m_events_mutex); + + m_events_hasher.Write((const unsigned char *)&event_info, sizeof(event_info)); + // Get the low four bytes of the performance counter. This translates to roughly the + // subsecond part. + uint32_t perfcounter = (GetPerformanceCounter() & 0xffffffff); + m_events_hasher.Write((const unsigned char*)&perfcounter, sizeof(perfcounter)); + } + + /** + * Feed (the hash of) all events added through AddEvent() to hasher. + */ + void SeedEvents(CSHA512& hasher) noexcept + { + // We use only SHA256 for the events hashing to get the ASM speedups we have for SHA256, + // since we want it to be fast as network peers may be able to trigger it repeatedly. + LOCK(m_events_mutex); + + unsigned char events_hash[32]; + m_events_hasher.Finalize(events_hash); + hasher.Write(events_hash, 32); + + // Re-initialize the hasher with the finalized state to use later. + m_events_hasher.Reset(); + m_events_hasher.Write(events_hash, 32); + } + /** Extract up to 32 bytes of entropy from the RNG state, mixing in new entropy from hasher. * * If this function has never been called with strong_seed = true, false is returned. @@ -445,24 +477,7 @@ static void SeedFast(CSHA512& hasher) noexcept SeedTimestamp(hasher); } -// We use only SHA256 for the events hashing to get the ASM speedups we have for SHA256, -// since we want it to be fast as network peers may be able to trigger it repeatedly. -static Mutex events_mutex; -static CSHA256 events_hasher; -static void SeedEvents(CSHA512& hasher) -{ - LOCK(events_mutex); - - unsigned char events_hash[32]; - events_hasher.Finalize(events_hash); - hasher.Write(events_hash, 32); - - // Re-initialize the hasher with the finalized state to use later. - events_hasher.Reset(); - events_hasher.Write(events_hash, 32); -} - -static void SeedSlow(CSHA512& hasher) noexcept +static void SeedSlow(CSHA512& hasher, RNGState& rng) noexcept { unsigned char buffer[32]; @@ -474,7 +489,7 @@ static void SeedSlow(CSHA512& hasher) noexcept hasher.Write(buffer, sizeof(buffer)); // Add the events hasher into the mix - SeedEvents(hasher); + rng.SeedEvents(hasher); // High-precision timestamp. // @@ -502,7 +517,7 @@ static void SeedPeriodic(CSHA512& hasher, RNGState& rng) noexcept SeedTimestamp(hasher); // Add the events hasher into the mix - SeedEvents(hasher); + rng.SeedEvents(hasher); // Dynamic environment data (performance monitoring, ...) auto old_size = hasher.Size(); @@ -519,7 +534,7 @@ static void SeedStartup(CSHA512& hasher, RNGState& rng) noexcept SeedHardwareSlow(hasher); // Everything that the 'slow' seeder includes. - SeedSlow(hasher); + SeedSlow(hasher, rng); // Dynamic environment data (performance monitoring, ...) auto old_size = hasher.Size(); @@ -539,7 +554,7 @@ enum class RNGLevel { PERIODIC, //!< Called by RandAddPeriodic() }; -static void ProcRand(unsigned char* out, int num, RNGLevel level) +static void ProcRand(unsigned char* out, int num, RNGLevel level) noexcept { // Make sure the RNG is initialized first (as all Seed* function possibly need hwrand to be available). RNGState& rng = GetRNGState(); @@ -552,7 +567,7 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level) SeedFast(hasher); break; case RNGLevel::SLOW: - SeedSlow(hasher); + SeedSlow(hasher, rng); break; case RNGLevel::PERIODIC: SeedPeriodic(hasher, rng); @@ -581,15 +596,7 @@ std::chrono::milliseconds GetRandMillis(std::chrono::milliseconds duration_max) void GetRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::FAST); } void GetStrongRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::SLOW); } void RandAddPeriodic() noexcept { ProcRand(nullptr, 0, RNGLevel::PERIODIC); } - -void RandAddEvent(const uint32_t event_info) { - LOCK(events_mutex); - events_hasher.Write((const unsigned char *)&event_info, sizeof(event_info)); - // Get the low four bytes of the performance counter. This translates to roughly the - // subsecond part. - uint32_t perfcounter = (GetPerformanceCounter() & 0xffffffff); - events_hasher.Write((const unsigned char*)&perfcounter, sizeof(perfcounter)); -} +void RandAddEvent(const uint32_t event_info) noexcept { GetRNGState().AddEvent(event_info); } bool g_mock_deterministic_tests{false}; diff --git a/src/random.h b/src/random.h index 4bb90c42aa..648aa16e23 100644 --- a/src/random.h +++ b/src/random.h @@ -98,7 +98,7 @@ void RandAddPeriodic() noexcept; * * Thread-safe. */ -void RandAddEvent(const uint32_t event_info); +void RandAddEvent(const uint32_t event_info) noexcept; /** * Fast randomness source. This is seeded once with secure random data, but