6 #include <bitcoin-build-config.h> 21 #include <util/time.h> 36 #if defined(HAVE_GETRANDOM) || (defined(HAVE_GETENTROPY_RAND) && defined(__APPLE__)) 37 #include <sys/random.h> 40 #ifdef HAVE_SYSCTL_ARND 41 #include <sys/sysctl.h> 51 static const int NUM_OS_RANDOM_BYTES = 32;
54 [[noreturn]]
void RandFailure()
56 LogError(
"Failed to read randomness, aborting\n");
60 inline int64_t GetPerformanceCounter() noexcept
64 #if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) 66 #elif !defined(_MSC_VER) && defined(__i386__) 68 __asm__
volatile (
"rdtsc" :
"=A"(r));
70 #elif !defined(_MSC_VER) && (defined(__x86_64__) || defined(__amd64__)) 71 uint64_t r1 = 0, r2 = 0;
72 __asm__
volatile (
"rdtsc" :
"=a"(r1),
"=d"(r2));
73 return (r2 << 32) | r1;
76 return std::chrono::high_resolution_clock::now().time_since_epoch().count();
81 bool g_rdrand_supported =
false;
82 bool g_rdseed_supported =
false;
83 constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000;
84 constexpr uint32_t CPUID_F7_EBX_RDSEED = 0x00040000;
86 static_assert(CPUID_F1_ECX_RDRAND == bit_RDRND,
"Unexpected value for bit_RDRND");
89 static_assert(CPUID_F7_EBX_RDSEED == bit_RDSEED,
"Unexpected value for bit_RDSEED");
92 void InitHardwareRand()
94 uint32_t eax, ebx, ecx, edx;
95 GetCPUID(1, 0, eax, ebx, ecx, edx);
96 if (ecx & CPUID_F1_ECX_RDRAND) {
97 g_rdrand_supported =
true;
99 GetCPUID(7, 0, eax, ebx, ecx, edx);
100 if (ebx & CPUID_F7_EBX_RDSEED) {
101 g_rdseed_supported =
true;
105 void ReportHardwareRand()
109 if (g_rdseed_supported) {
110 LogInfo(
"Using RdSeed as an additional entropy source");
112 if (g_rdrand_supported) {
113 LogInfo(
"Using RdRand as an additional entropy source");
121 uint64_t GetRdRand() noexcept
129 uint32_t r1 = 0, r2 = 0;
130 for (
int i = 0; i < 10; ++i) {
131 __asm__
volatile (
".byte 0x0f, 0xc7, 0xf0; setc %1" :
"=a"(r1),
"=q"(ok) ::
"cc");
134 for (
int i = 0; i < 10; ++i) {
135 __asm__
volatile (
".byte 0x0f, 0xc7, 0xf0; setc %1" :
"=a"(r2),
"=q"(ok) ::
"cc");
138 return (((uint64_t)r2) << 32) | r1;
139 #elif defined(__x86_64__) || defined(__amd64__) 142 for (
int i = 0; i < 10; ++i) {
143 __asm__
volatile (
".byte 0x48, 0x0f, 0xc7, 0xf0; setc %1" :
"=a"(r1),
"=q"(ok) ::
"cc");
148 #error "RdRand is only supported on x86 and x86_64" 156 uint64_t GetRdSeed() noexcept
164 __asm__
volatile (
".byte 0x0f, 0xc7, 0xf8; setc %1" :
"=a"(r1),
"=q"(ok) ::
"cc");
166 __asm__
volatile (
"pause");
169 __asm__
volatile (
".byte 0x0f, 0xc7, 0xf8; setc %1" :
"=a"(r2),
"=q"(ok) ::
"cc");
171 __asm__
volatile (
"pause");
173 return (((uint64_t)r2) << 32) | r1;
174 #elif defined(__x86_64__) || defined(__amd64__) 178 __asm__
volatile (
".byte 0x48, 0x0f, 0xc7, 0xf8; setc %1" :
"=a"(r1),
"=q"(ok) ::
"cc");
180 __asm__
volatile (
"pause");
184 #error "RdSeed is only supported on x86 and x86_64" 194 void InitHardwareRand() {}
195 void ReportHardwareRand() {}
199 void SeedHardwareFast(
CSHA512& hasher) noexcept {
200 #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) 201 if (g_rdrand_supported) {
202 uint64_t
out = GetRdRand();
203 hasher.Write((
const unsigned char*)&
out,
sizeof(
out));
210 void SeedHardwareSlow(
CSHA512& hasher) noexcept {
211 #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) 214 if (g_rdseed_supported) {
215 for (
int i = 0; i < 4; ++i) {
216 uint64_t
out = GetRdSeed();
217 hasher.Write((
const unsigned char*)&
out,
sizeof(
out));
223 if (g_rdrand_supported) {
224 for (
int i = 0; i < 4; ++i) {
226 for (
int j = 0; j < 1024; ++j)
out ^= GetRdRand();
227 hasher.Write((
const unsigned char*)&
out,
sizeof(
out));
235 void Strengthen(
const unsigned char (&seed)[32], SteadyClock::duration dur,
CSHA512& hasher) noexcept
238 inner_hasher.
Write(seed,
sizeof(seed));
241 unsigned char buffer[64];
242 const auto stop{SteadyClock::now() + dur};
244 for (
int i = 0; i < 1000; ++i) {
246 inner_hasher.
Reset();
247 inner_hasher.
Write(buffer,
sizeof(buffer));
250 int64_t perf = GetPerformanceCounter();
251 hasher.Write((
const unsigned char*)&perf,
sizeof(perf));
252 }
while (SteadyClock::now() <
stop);
256 hasher.Write(buffer,
sizeof(buffer));
258 inner_hasher.
Reset();
266 [[maybe_unused]]
void GetDevURandom(
unsigned char *ent32)
268 int f = open(
"/dev/urandom", O_RDONLY);
274 ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);
275 if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {
280 }
while (have < NUM_OS_RANDOM_BYTES);
286 void GetOSRand(
unsigned char *ent32)
289 constexpr uint32_t STATUS_SUCCESS{0x00000000};
290 NTSTATUS status = BCryptGenRandom(NULL,
293 BCRYPT_USE_SYSTEM_PREFERRED_RNG);
295 if (status != STATUS_SUCCESS) {
298 #elif defined(HAVE_GETRANDOM) 304 if (getrandom(ent32, NUM_OS_RANDOM_BYTES, 0) != NUM_OS_RANDOM_BYTES) {
307 #elif defined(__OpenBSD__) 314 arc4random_buf(ent32, NUM_OS_RANDOM_BYTES);
315 #elif defined(HAVE_GETENTROPY_RAND) && defined(__APPLE__) 316 if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
319 #elif defined(HAVE_SYSCTL_ARND) 323 static int name[2] = {CTL_KERN, KERN_ARND};
326 size_t len = NUM_OS_RANDOM_BYTES - have;
327 if (sysctl(
name, std::size(
name), ent32 + have, &len,
nullptr, 0) != 0) {
331 }
while (have < NUM_OS_RANDOM_BYTES);
336 GetDevURandom(ent32);
350 unsigned char m_state[32]
GUARDED_BY(m_mutex) = {0};
352 bool m_strongly_seeded
GUARDED_BY(m_mutex) =
false;
356 std::optional<ChaCha20> m_deterministic_prng
GUARDED_BY(m_mutex);
358 Mutex m_events_mutex;
367 ~RNGState() =
default;
371 LOCK(m_events_mutex);
373 m_events_hasher.Write((
const unsigned char *)&event_info,
sizeof(event_info));
376 uint32_t perfcounter = (GetPerformanceCounter() & 0xffffffff);
377 m_events_hasher.Write((
const unsigned char*)&perfcounter,
sizeof(perfcounter));
387 LOCK(m_events_mutex);
389 unsigned char events_hash[32];
390 m_events_hasher.Finalize(events_hash);
391 hasher.Write(events_hash, 32);
394 m_events_hasher.Reset();
395 m_events_hasher.Write(events_hash, 32);
415 unsigned char buf[64];
416 static_assert(
sizeof(buf) ==
CSHA512::OUTPUT_SIZE,
"Buffer needs to have hasher's output size");
420 ret = (m_strongly_seeded |= strong_seed);
422 hasher.Write(m_state, 32);
424 hasher.Write((
const unsigned char*)&m_counter,
sizeof(m_counter));
427 hasher.Finalize(buf);
429 memcpy(m_state, buf + 32, 32);
431 if (!always_use_real_rng && m_deterministic_prng.has_value()) [[unlikely]] {
433 m_deterministic_prng->Keystream(std::as_writable_bytes(std::span{buf, num}));
450 RNGState& GetRNGState() noexcept
454 static std::vector<RNGState, secure_allocator<RNGState>> g_rng(1);
463 void SeedTimestamp(
CSHA512& hasher) noexcept
465 int64_t perfcounter = GetPerformanceCounter();
466 hasher.Write((
const unsigned char*)&perfcounter,
sizeof(perfcounter));
469 void SeedFast(
CSHA512& hasher) noexcept
471 unsigned char buffer[32];
474 const unsigned char* ptr = buffer;
475 hasher.Write((
const unsigned char*)&ptr,
sizeof(ptr));
478 SeedHardwareFast(hasher);
481 SeedTimestamp(hasher);
484 void SeedSlow(
CSHA512& hasher, RNGState& rng) noexcept
486 unsigned char buffer[32];
493 hasher.Write(buffer,
sizeof(buffer));
496 rng.SeedEvents(hasher);
502 SeedTimestamp(hasher);
506 void SeedStrengthen(
CSHA512& hasher, RNGState& rng, SteadyClock::duration dur) noexcept
510 unsigned char strengthen_seed[32];
511 rng.MixExtract(strengthen_seed,
sizeof(strengthen_seed),
CSHA512(hasher),
false,
true);
513 Strengthen(strengthen_seed, dur, hasher);
516 void SeedPeriodic(
CSHA512& hasher, RNGState& rng) noexcept
522 SeedTimestamp(hasher);
525 rng.SeedEvents(hasher);
528 auto old_size = hasher.Size();
530 LogDebug(
BCLog::RAND,
"Feeding %i bytes of dynamic environment data into RNG\n", hasher.Size() - old_size);
533 SeedStrengthen(hasher, rng, 10ms);
536 void SeedStartup(
CSHA512& hasher, RNGState& rng) noexcept
539 SeedHardwareSlow(hasher);
542 SeedSlow(hasher, rng);
545 auto old_size = hasher.Size();
550 LogDebug(
BCLog::RAND,
"Feeding %i bytes of environment data into RNG\n", hasher.Size() - old_size);
553 SeedStrengthen(hasher, rng, 100ms);
562 void ProcRand(
unsigned char*
out,
int num,
RNGLevel level,
bool always_use_real_rng) noexcept
565 RNGState& rng = GetRNGState();
575 SeedSlow(hasher, rng);
577 case RNGLevel::PERIODIC:
578 SeedPeriodic(hasher, rng);
583 if (!rng.MixExtract(
out, num, std::move(hasher),
false, always_use_real_rng)) {
586 SeedStartup(startup_hasher, rng);
587 rng.MixExtract(
out, num, std::move(startup_hasher),
true, always_use_real_rng);
597 GetRNGState().MakeDeterministic(seed);
604 ProcRand(bytes.data(), bytes.size(), RNGLevel::FAST,
false);
609 ProcRand(bytes.data(), bytes.size(), RNGLevel::SLOW,
true);
614 ProcRand(
nullptr, 0, RNGLevel::PERIODIC,
false);
617 void RandAddEvent(
const uint32_t event_info) noexcept { GetRNGState().AddEvent(event_info); }
628 if (requires_seed) RandomSeed();
629 rng.Keystream(output);
637 requires_seed =
false;
643 uint64_t start = GetPerformanceCounter();
649 static constexpr
int MAX_TRIES{1024};
650 uint8_t
data[NUM_OS_RANDOM_BYTES];
651 bool overwritten[NUM_OS_RANDOM_BYTES] = {};
656 memset(
data, 0, NUM_OS_RANDOM_BYTES);
658 for (
int x=0; x < NUM_OS_RANDOM_BYTES; ++x) {
659 overwritten[x] |= (
data[x] != 0);
663 for (
int x=0; x < NUM_OS_RANDOM_BYTES; ++x) {
664 if (overwritten[x]) {
665 num_overwritten += 1;
670 }
while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES);
671 if (num_overwritten != NUM_OS_RANDOM_BYTES)
return false;
674 std::this_thread::sleep_for(std::chrono::milliseconds(1));
675 uint64_t
stop = GetPerformanceCounter();
676 if (
stop == start)
return false;
680 to_add.
Write((
const unsigned char*)&start,
sizeof(start));
682 GetRNGState().MixExtract(
nullptr, 0, std::move(to_add),
false,
true);
687 static constexpr std::array<std::byte, ChaCha20::KEYLEN>
ZERO_KEY{};
699 ProcRand(
nullptr, 0, RNGLevel::FAST,
true);
701 ReportHardwareRand();
715 return -std::log1p((uniform >> 11) * -0x1.0p-53);
void RandomInit()
Overall design of the RNG and entropy sources.
auto MakeByteSpan(const V &v) noexcept
void RandAddEvent(const uint32_t event_info) noexcept
Gathers entropy from the low bits of the time at which events occur.
void MakeRandDeterministicDANGEROUS(const uint256 &seed) noexcept
Internal function to set g_determinstic_rng.
memcpy(result.begin(), stream.data(), stream.size())
void RandAddPeriodic() noexcept
Gather entropy from various expensive sources, and feed them to the PRNG state.
FastRandomContext(bool fDeterministic=false) noexcept
Construct a FastRandomContext with GetRandHash()-based entropy (or zero key if fDeterministic).
void fillrand(std::span< std::byte > output) noexcept
Fill a byte span with random bytes.
void Finalize(unsigned char hash[OUTPUT_SIZE])
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
void GetRandBytes(std::span< unsigned char > bytes) noexcept
Generate random data via the internal PRNG.
void Reseed(const uint256 &seed) noexcept
Reseed with explicit seed (only for testing).
static constexpr size_t OUTPUT_SIZE
static constexpr std::array< std::byte, ChaCha20::KEYLEN > ZERO_KEY
void GetStrongRandBytes(std::span< unsigned char > bytes) noexcept
Gather entropy from various sources, feed it into the internal PRNG, and generate random data using i...
#define LogDebug(category,...)
#define EXCLUSIVE_LOCKS_REQUIRED(...)
std::atomic< bool > g_used_g_prng
CSHA512 & Write(const unsigned char *data, size_t len)
uint256 GetRandHash() noexcept
Generate a random uint256.
void SetKey(std::span< const std::byte > key) noexcept
Set 32-byte key, and seek to nonce 0 and block position 0.
A hasher class for SHA-512.
A hasher class for SHA-256.
void RandAddStaticEnv(CSHA512 &hasher)
Gather non-cryptographic environment data that does not change over time.
void RandomSeed() noexcept
bool Random_SanityCheck()
Check that OS randomness is available and returning the requested number of bytes.
double MakeExponentiallyDistributed(uint64_t uniform) noexcept
Given a uniformly random uint64_t, return an exponentially distributed double with mean 1...
void RandAddDynamicEnv(CSHA512 &hasher)
Gather non-cryptographic environment data that changes over time.