Skip to content

Commit 4191963

Browse files
committed
Merge #17573: Seed RNG with precision timestamps on receipt of net messages.
02d8c56 Seed RNG with precision timestamps on receipt of net messages. (Matt Corallo) Pull request description: See title. Exposes a generic dead-simple "SeedEvent" interface, but currently just used for net messages. ACKs for top commit: sipa: utACK bitcoin/bitcoin@02d8c56 laanwj: ACK 02d8c56 meshcollider: utACK 02d8c56 Tree-SHA512: 28eb39a201ee2b13393c5c64dbf7c1913f3482f095969ef5141bfe549ce77dd63bb5f14738f6eedb296c686ea36014aa157b9c5e8059710a318590f30e9caa14
2 parents dcbe024 + 02d8c56 commit 4191963

File tree

3 files changed

+51
-0
lines changed

3 files changed

+51
-0
lines changed

src/net.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <crypto/sha256.h>
1717
#include <netbase.h>
1818
#include <net_permissions.h>
19+
#include <random.h>
1920
#include <scheduler.h>
2021
#include <ui_interface.h>
2122
#include <util/strencodings.h>
@@ -445,6 +446,9 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
445446
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false, block_relay_only);
446447
pnode->AddRef();
447448

449+
// We're making a new connection, harvest entropy from the time (and our peer count)
450+
RandAddEvent((uint32_t)id);
451+
448452
return pnode;
449453
}
450454

@@ -693,6 +697,9 @@ CNetMessage V1TransportDeserializer::GetMessage(const CMessageHeader::MessageSta
693697
msg.m_message_size = hdr.nMessageSize;
694698
msg.m_raw_message_size = hdr.nMessageSize + CMessageHeader::HEADER_SIZE;
695699

700+
// We just received a message off the wire, harvest entropy from the time (and the message checksum)
701+
RandAddEvent(ReadLE32(hash.begin()));
702+
696703
msg.m_valid_checksum = (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) == 0);
697704
if (!msg.m_valid_checksum) {
698705
LogPrint(BCLog::NET, "CHECKSUM ERROR (%s, %u bytes), expected %s was %s\n",
@@ -1017,6 +1024,9 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
10171024
LOCK(cs_vNodes);
10181025
vNodes.push_back(pnode);
10191026
}
1027+
1028+
// We received a new connection, harvest entropy from the time (and our peer count)
1029+
RandAddEvent((uint32_t)id);
10201030
}
10211031

10221032
void CConnman::DisconnectNodes()

src/random.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <random.h>
77

88
#include <compat/cpuid.h>
9+
#include <crypto/sha256.h>
910
#include <crypto/sha512.h>
1011
#include <support/cleanse.h>
1112
#ifdef WIN32
@@ -449,6 +450,23 @@ static void SeedFast(CSHA512& hasher) noexcept
449450
SeedTimestamp(hasher);
450451
}
451452

453+
// We use only SHA256 for the events hashing to get the ASM speedups we have for SHA256,
454+
// since we want it to be fast as network peers may be able to trigger it repeatedly.
455+
static Mutex events_mutex;
456+
static CSHA256 events_hasher;
457+
static void SeedEvents(CSHA512& hasher)
458+
{
459+
LOCK(events_mutex);
460+
461+
unsigned char events_hash[32];
462+
events_hasher.Finalize(events_hash);
463+
hasher.Write(events_hash, 32);
464+
465+
// Re-initialize the hasher with the finalized state to use later.
466+
events_hasher.Reset();
467+
events_hasher.Write(events_hash, 32);
468+
}
469+
452470
static void SeedSlow(CSHA512& hasher) noexcept
453471
{
454472
unsigned char buffer[32];
@@ -460,6 +478,9 @@ static void SeedSlow(CSHA512& hasher) noexcept
460478
GetOSRand(buffer);
461479
hasher.Write(buffer, sizeof(buffer));
462480

481+
// Add the events hasher into the mix
482+
SeedEvents(hasher);
483+
463484
// High-precision timestamp.
464485
//
465486
// Note that we also commit to a timestamp in the Fast seeder, so we indirectly commit to a
@@ -485,6 +506,9 @@ static void SeedPeriodic(CSHA512& hasher, RNGState& rng)
485506
// High-precision timestamp
486507
SeedTimestamp(hasher);
487508

509+
// Add the events hasher into the mix
510+
SeedEvents(hasher);
511+
488512
// Dynamic environment data (performance monitoring, ...)
489513
auto old_size = hasher.Size();
490514
RandAddDynamicEnv(hasher);
@@ -553,6 +577,15 @@ void GetRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNG
553577
void GetStrongRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::SLOW); }
554578
void RandAddPeriodic() { ProcRand(nullptr, 0, RNGLevel::PERIODIC); }
555579

580+
void RandAddEvent(const uint32_t event_info) {
581+
LOCK(events_mutex);
582+
events_hasher.Write((const unsigned char *)&event_info, sizeof(event_info));
583+
// Get the low four bytes of the performance counter. This translates to roughly the
584+
// subsecond part.
585+
uint32_t perfcounter = (GetPerformanceCounter() & 0xffffffff);
586+
events_hasher.Write((const unsigned char*)&perfcounter, sizeof(perfcounter));
587+
}
588+
556589
bool g_mock_deterministic_tests{false};
557590

558591
uint64_t GetRand(uint64_t nMax) noexcept

src/random.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,14 @@ void GetStrongRandBytes(unsigned char* buf, int num) noexcept;
8989
*/
9090
void RandAddPeriodic();
9191

92+
/**
93+
* Gathers entropy from the low bits of the time at which events occur. Should
94+
* be called with a uint32_t describing the event at the time an event occurs.
95+
*
96+
* Thread-safe.
97+
*/
98+
void RandAddEvent(const uint32_t event_info);
99+
92100
/**
93101
* Fast randomness source. This is seeded once with secure random data, but
94102
* is completely deterministic and does not gather more entropy after that.

0 commit comments

Comments
 (0)