aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatt Corallo <git@bluematt.me>2019-11-23 11:42:23 -0500
committerMatt Corallo <git@bluematt.me>2019-11-23 16:06:34 -0500
commit02d8c56a18b9a2960888d6ec1209955105bae847 (patch)
tree9013a23918ed55059a39fa56ae93ef6951456607 /src
parent33c103e2fe67e32e9f4e783fa243dd2bba6b1682 (diff)
downloadbitcoin-02d8c56a18b9a2960888d6ec1209955105bae847.tar.xz
Seed RNG with precision timestamps on receipt of net messages.
Diffstat (limited to 'src')
-rw-r--r--src/net.cpp10
-rw-r--r--src/random.cpp33
-rw-r--r--src/random.h8
3 files changed, 51 insertions, 0 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 84692d2a79..99dae88bab 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -16,6 +16,7 @@
#include <crypto/sha256.h>
#include <netbase.h>
#include <net_permissions.h>
+#include <random.h>
#include <scheduler.h>
#include <ui_interface.h>
#include <util/strencodings.h>
@@ -445,6 +446,9 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false, block_relay_only);
pnode->AddRef();
+ // We're making a new connection, harvest entropy from the time (and our peer count)
+ RandAddEvent((uint32_t)id);
+
return pnode;
}
@@ -693,6 +697,9 @@ CNetMessage V1TransportDeserializer::GetMessage(const CMessageHeader::MessageSta
msg.m_message_size = hdr.nMessageSize;
msg.m_raw_message_size = hdr.nMessageSize + CMessageHeader::HEADER_SIZE;
+ // We just received a message off the wire, harvest entropy from the time (and the message checksum)
+ RandAddEvent(ReadLE32(hash.begin()));
+
msg.m_valid_checksum = (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) == 0);
if (!msg.m_valid_checksum) {
LogPrint(BCLog::NET, "CHECKSUM ERROR (%s, %u bytes), expected %s was %s\n",
@@ -1017,6 +1024,9 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
LOCK(cs_vNodes);
vNodes.push_back(pnode);
}
+
+ // We received a new connection, harvest entropy from the time (and our peer count)
+ RandAddEvent((uint32_t)id);
}
void CConnman::DisconnectNodes()
diff --git a/src/random.cpp b/src/random.cpp
index 47d76d8700..09777237c2 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -6,6 +6,7 @@
#include <random.h>
#include <compat/cpuid.h>
+#include <crypto/sha256.h>
#include <crypto/sha512.h>
#include <support/cleanse.h>
#ifdef WIN32
@@ -449,6 +450,23 @@ 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
{
unsigned char buffer[32];
@@ -460,6 +478,9 @@ static void SeedSlow(CSHA512& hasher) noexcept
GetOSRand(buffer);
hasher.Write(buffer, sizeof(buffer));
+ // Add the events hasher into the mix
+ SeedEvents(hasher);
+
// High-precision timestamp.
//
// 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)
// High-precision timestamp
SeedTimestamp(hasher);
+ // Add the events hasher into the mix
+ SeedEvents(hasher);
+
// Dynamic environment data (performance monitoring, ...)
auto old_size = hasher.Size();
RandAddDynamicEnv(hasher);
@@ -553,6 +577,15 @@ void GetRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNG
void GetStrongRandBytes(unsigned char* buf, int num) noexcept { ProcRand(buf, num, RNGLevel::SLOW); }
void RandAddPeriodic() { 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));
+}
+
bool g_mock_deterministic_tests{false};
uint64_t GetRand(uint64_t nMax) noexcept
diff --git a/src/random.h b/src/random.h
index 2d8ab085e3..b6e70fcb1f 100644
--- a/src/random.h
+++ b/src/random.h
@@ -90,6 +90,14 @@ void GetStrongRandBytes(unsigned char* buf, int num) noexcept;
void RandAddPeriodic();
/**
+ * Gathers entropy from the low bits of the time at which events occur. Should
+ * be called with a uint32_t describing the event at the time an event occurs.
+ *
+ * Thread-safe.
+ */
+void RandAddEvent(const uint32_t event_info);
+
+/**
* Fast randomness source. This is seeded once with secure random data, but
* is completely deterministic and does not gather more entropy after that.
*