36#ifdef HAVE_SYS_GETRANDOM
37#include <linux/random.h>
38#include <sys/syscall.h>
40#if defined(HAVE_GETENTROPY) || \
41 (defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX))
44#if defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
45#include <sys/random.h>
47#ifdef HAVE_SYSCTL_ARND
48#include <sys/sysctl.h>
59const int NUM_OS_RANDOM_BYTES = 32;
61[[noreturn]]
void RandFailure() {
62 LogError(
"Failed to read randomness, aborting\n");
66inline int64_t GetPerformanceCounter() noexcept {
69#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
71#elif !defined(_MSC_VER) && defined(__i386__)
74 __asm__
volatile(
"rdtsc" :
"=A"(r));
76#elif !defined(_MSC_VER) && (defined(__x86_64__) || defined(__amd64__))
77 uint64_t r1 = 0, r2 = 0;
79 __asm__
volatile(
"rdtsc" :
"=a"(r1),
"=d"(r2));
80 return (r2 << 32) | r1;
84 return std::chrono::high_resolution_clock::now().time_since_epoch().count();
89bool g_rdrand_supported =
false;
90bool g_rdseed_supported =
false;
91constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000;
92constexpr uint32_t CPUID_F7_EBX_RDSEED = 0x00040000;
94static_assert(CPUID_F1_ECX_RDRAND == bit_RDRND,
95 "Unexpected value for bit_RDRND");
98static_assert(CPUID_F7_EBX_RDSEED == bit_RDSEED,
99 "Unexpected value for bit_RDSEED");
102void InitHardwareRand() {
103 uint32_t eax, ebx, ecx, edx;
104 GetCPUID(1, 0, eax, ebx, ecx, edx);
105 if (ecx & CPUID_F1_ECX_RDRAND) {
106 g_rdrand_supported =
true;
108 GetCPUID(7, 0, eax, ebx, ecx, edx);
109 if (ebx & CPUID_F7_EBX_RDSEED) {
110 g_rdseed_supported =
true;
114void ReportHardwareRand() {
118 if (g_rdseed_supported) {
119 LogPrintf(
"Using RdSeed as additional entropy source\n");
121 if (g_rdrand_supported) {
122 LogPrintf(
"Using RdRand as an additional entropy source\n");
131uint64_t GetRdRand() noexcept {
139 uint32_t r1 = 0, r2 = 0;
140 for (
int i = 0; i < 10; ++i) {
142 __asm__
volatile(
".byte 0x0f, 0xc7, 0xf0; setc %1"
143 :
"=a"(r1),
"=q"(ok)::
"cc");
148 for (
int i = 0; i < 10; ++i) {
150 __asm__
volatile(
".byte 0x0f, 0xc7, 0xf0; setc %1"
151 :
"=a"(r2),
"=q"(ok)::
"cc");
156 return (uint64_t(r2) << 32) | r1;
157#elif defined(__x86_64__) || defined(__amd64__)
160 for (
int i = 0; i < 10; ++i) {
162 __asm__
volatile(
".byte 0x48, 0x0f, 0xc7, 0xf0; setc %1"
163 :
"=a"(r1),
"=q"(ok)::
"cc");
170#error "RdRand is only supported on x86 and x86_64"
179uint64_t GetRdSeed() noexcept {
187 __asm__
volatile(
".byte 0x0f, 0xc7, 0xf8; setc %1"
188 :
"=a"(r1),
"=q"(ok)::
"cc");
192 __asm__
volatile(
"pause");
196 __asm__
volatile(
".byte 0x0f, 0xc7, 0xf8; setc %1"
197 :
"=a"(r2),
"=q"(ok)::
"cc");
201 __asm__
volatile(
"pause");
203 return (uint64_t(r2) << 32) | r1;
204#elif defined(__x86_64__) || defined(__amd64__)
209 __asm__
volatile(
".byte 0x48, 0x0f, 0xc7, 0xf8; setc %1"
210 :
"=a"(r1),
"=q"(ok)::
"cc");
214 __asm__
volatile(
"pause");
218#error "RdSeed is only supported on x86 and x86_64"
229void InitHardwareRand() {}
230void ReportHardwareRand() {}
237void SeedHardwareFast(
CSHA512 &hasher)
noexcept {
238#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
239 if (g_rdrand_supported) {
240 uint64_t out = GetRdRand();
241 hasher.Write((
const uint8_t *)&out,
sizeof(out));
251void SeedHardwareSlow(
CSHA512 &hasher)
noexcept {
252#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
255 if (g_rdseed_supported) {
256 for (
int i = 0; i < 4; ++i) {
257 uint64_t out = GetRdSeed();
258 hasher.Write((
const uint8_t *)&out,
sizeof(out));
264 if (g_rdrand_supported) {
265 for (
int i = 0; i < 4; ++i) {
267 for (
int j = 0; j < 1024; ++j) {
270 hasher.Write((
const uint8_t *)&out,
sizeof(out));
281void Strengthen(
const uint8_t (&seed)[32], SteadyClock::duration dur,
284 inner_hasher.
Write(seed,
sizeof(seed));
289 const auto stop{SteadyClock::now() + dur};
291 for (
int i = 0; i < 1000; ++i) {
293 inner_hasher.
Reset();
294 inner_hasher.
Write(buffer,
sizeof(buffer));
297 int64_t perf = GetPerformanceCounter();
298 hasher.Write((
const uint8_t *)&perf,
sizeof(perf));
299 }
while (SteadyClock::now() <
stop);
303 hasher.Write(buffer,
sizeof(buffer));
305 inner_hasher.
Reset();
314void GetDevURandom(uint8_t *ent32) {
315 int f = open(
"/dev/urandom", O_RDONLY);
321 ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);
322 if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {
327 }
while (have < NUM_OS_RANDOM_BYTES);
333void GetOSRand(uint8_t *ent32) {
335 HCRYPTPROV hProvider;
336 int ret = CryptAcquireContextW(&hProvider,
nullptr,
nullptr, PROV_RSA_FULL,
337 CRYPT_VERIFYCONTEXT);
341 ret = CryptGenRandom(hProvider, NUM_OS_RANDOM_BYTES, ent32);
345 CryptReleaseContext(hProvider, 0);
346#elif defined(HAVE_SYS_GETRANDOM)
353 int rv = syscall(SYS_getrandom, ent32, NUM_OS_RANDOM_BYTES, 0);
354 if (rv != NUM_OS_RANDOM_BYTES) {
355 if (rv < 0 && errno == ENOSYS) {
360 GetDevURandom(ent32);
365#elif defined(HAVE_GETENTROPY) && defined(__OpenBSD__)
373 if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
378#elif defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
382 if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
387#elif defined(HAVE_SYSCTL_ARND)
392 static const int name[2] = {CTL_KERN, KERN_ARND};
395 size_t len = NUM_OS_RANDOM_BYTES - have;
396 if (sysctl(
name, std::size(
name), ent32 + have, &len,
nullptr, 0) !=
401 }
while (have < NUM_OS_RANDOM_BYTES);
409 GetDevURandom(ent32);
424 uint8_t m_state[32]
GUARDED_BY(m_mutex) = {0};
426 bool m_strongly_seeded
GUARDED_BY(m_mutex) =
false;
432 std::optional<ChaCha20> m_deterministic_prng
GUARDED_BY(m_mutex);
434 Mutex m_events_mutex;
438 RNGState() noexcept { InitHardwareRand(); }
440 ~RNGState() =
default;
442 void AddEvent(uint32_t event_info)
noexcept
444 LOCK(m_events_mutex);
446 m_events_hasher.Write((
const uint8_t *)&event_info,
sizeof(event_info));
449 uint32_t perfcounter = (GetPerformanceCounter() & 0xffffffff);
450 m_events_hasher.Write((
const uint8_t *)&perfcounter,
451 sizeof(perfcounter));
457 void SeedEvents(
CSHA512 &hasher)
noexcept
462 LOCK(m_events_mutex);
464 uint8_t events_hash[32];
465 m_events_hasher.Finalize(events_hash);
466 hasher.Write(events_hash, 32);
469 m_events_hasher.Reset();
470 m_events_hasher.Write(events_hash, 32);
477 void MakeDeterministic(
const uint256 &seed)
noexcept
492 bool MixExtract(uint8_t *out,
size_t num,
CSHA512 &&hasher,
493 bool strong_seed,
bool always_use_real_rng)
noexcept
498 "Buffer needs to have hasher's output size");
502 ret = (m_strongly_seeded |= strong_seed);
504 hasher.Write(m_state, 32);
506 hasher.Write((
const uint8_t *)&m_counter,
sizeof(m_counter));
509 hasher.Finalize(buf);
511 memcpy(m_state, buf + 32, 32);
513 if (!always_use_real_rng && m_deterministic_prng.has_value())
517 m_deterministic_prng->Keystream(
527 memcpy(out, buf, num);
536RNGState &GetRNGState() noexcept {
540 static std::vector<RNGState, secure_allocator<RNGState>> g_rng(1);
550void SeedTimestamp(
CSHA512 &hasher)
noexcept {
551 int64_t perfcounter = GetPerformanceCounter();
552 hasher.Write((
const uint8_t *)&perfcounter,
sizeof(perfcounter));
555void SeedFast(
CSHA512 &hasher)
noexcept {
559 const uint8_t *ptr = buffer;
560 hasher.Write((
const uint8_t *)&ptr,
sizeof(ptr));
563 SeedHardwareFast(hasher);
566 SeedTimestamp(hasher);
569void SeedSlow(
CSHA512 &hasher, RNGState &rng)
noexcept {
577 hasher.Write(buffer,
sizeof(buffer));
580 rng.SeedEvents(hasher);
587 SeedTimestamp(hasher);
591void SeedStrengthen(
CSHA512 &hasher, RNGState &rng,
592 SteadyClock::duration dur)
noexcept {
597 uint8_t strengthen_seed[32];
598 rng.MixExtract(strengthen_seed,
sizeof(strengthen_seed),
CSHA512(hasher),
601 Strengthen(strengthen_seed, dur, hasher);
604void SeedPeriodic(
CSHA512 &hasher, RNGState &rng)
noexcept {
609 SeedTimestamp(hasher);
612 rng.SeedEvents(hasher);
615 auto old_size = hasher.Size();
618 "Feeding %i bytes of dynamic environment data into RNG\n",
619 hasher.Size() - old_size);
622 SeedStrengthen(hasher, rng, 10ms);
625void SeedStartup(
CSHA512 &hasher, RNGState &rng)
noexcept {
627 SeedHardwareSlow(hasher);
630 SeedSlow(hasher, rng);
633 auto old_size = hasher.Size();
639 hasher.Size() - old_size);
642 SeedStrengthen(hasher, rng, 100ms);
651void ProcRand(uint8_t *out,
int num, RNGLevel level,
652 bool always_use_real_rng)
noexcept {
655 RNGState &rng = GetRNGState();
665 SeedSlow(hasher, rng);
667 case RNGLevel::PERIODIC:
668 SeedPeriodic(hasher, rng);
673 if (!rng.MixExtract(out, num, std::move(hasher),
false,
674 always_use_real_rng)) {
677 SeedStartup(startup_hasher, rng);
678 rng.MixExtract(out, num, std::move(startup_hasher),
true,
679 always_use_real_rng);
687 GetRNGState().MakeDeterministic(seed);
691 ProcRand(bytes.data(), bytes.size(), RNGLevel::FAST,
696 ProcRand(bytes.data(), bytes.size(), RNGLevel::SLOW,
701 ProcRand(
nullptr, 0, RNGLevel::PERIODIC,
false);
705 GetRNGState().AddEvent(event_info);
718 rng.Keystream(output);
726 requires_seed =
false;
731 uint64_t start = GetPerformanceCounter();
738 static const ssize_t MAX_TRIES = 1024;
739 uint8_t data[NUM_OS_RANDOM_BYTES];
741 bool overwritten[NUM_OS_RANDOM_BYTES] = {};
749 memset(data, 0, NUM_OS_RANDOM_BYTES);
751 for (
int x = 0; x < NUM_OS_RANDOM_BYTES; ++x) {
752 overwritten[x] |= (data[x] != 0);
756 for (
int x = 0; x < NUM_OS_RANDOM_BYTES; ++x) {
757 if (overwritten[x]) {
758 num_overwritten += 1;
763 }
while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES);
765 if (num_overwritten != NUM_OS_RANDOM_BYTES) {
771 std::this_thread::sleep_for(std::chrono::milliseconds(1));
772 uint64_t
stop = GetPerformanceCounter();
779 to_add.
Write((
const uint8_t *)&start,
sizeof(start));
781 GetRNGState().MixExtract(
nullptr, 0, std::move(to_add),
false,
787static constexpr std::array<std::byte, ChaCha20::KEYLEN>
ZERO_KEY{};
790 : requires_seed(!fDeterministic), rng(
ZERO_KEY) {
798 ProcRand(
nullptr, 0, RNGLevel::FAST,
true);
800 ReportHardwareRand();
816 return -std::log1p((uniform >> 11) * -0x1.0p-53);
A hasher class for SHA-256.
A hasher class for SHA-512.
CSHA512 & Write(const uint8_t *data, size_t len)
static constexpr size_t OUTPUT_SIZE
void Finalize(uint8_t hash[OUTPUT_SIZE])
void SetKey(Span< const std::byte > key) noexcept
Set KEYLEN-byte key, and seek to nonce 0 and block position 0.
FastRandomContext(bool fDeterministic=false) noexcept
Construct a FastRandomContext with GetRandHash()-based entropy (or zero key if fDeterministic).
void RandomSeed() noexcept
void Reseed(const uint256 &seed) noexcept
Reseed with explicit seed (only for testing).
void fillrand(Span< std::byte > output) noexcept
Fill a byte Span with random bytes.
A Span is an object that can refer to a contiguous sequence of objects.
void memory_cleanse(void *ptr, size_t len)
Secure overwrite a buffer (possibly containing secret data) with zero-bytes.
#define LogPrint(category,...)
void GetRandBytes(Span< uint8_t > bytes) noexcept
================== BASE RANDOMNESS GENERATION FUNCTIONS ====================
void RandAddPeriodic() noexcept
Gather entropy from various expensive sources, and feed them to the PRNG state.
bool Random_SanityCheck()
=============== MISCELLANEOUS TEST-ONLY FUNCTIONS ======================
static constexpr std::array< std::byte, ChaCha20::KEYLEN > ZERO_KEY
void MakeRandDeterministicDANGEROUS(const uint256 &seed) noexcept
Internal function to set g_determinstic_rng.
void RandomInit()
Overall design of the RNG and entropy sources.
void RandAddEvent(const uint32_t event_info) noexcept
Gathers entropy from the low bits of the time at which events occur.
double MakeExponentiallyDistributed(uint64_t uniform) noexcept
Given a uniformly random uint64_t, return an exponentially distributed double with mean 1.
void GetStrongRandBytes(Span< uint8_t > bytes) noexcept
Gather entropy from various sources, feed it into the internal PRNG, and generate random data using i...
uint256 GetRandHash() noexcept
========== CONVENIENCE FUNCTIONS FOR COMMONLY USED RANDOMNESS ==========
void RandAddStaticEnv(CSHA512 &hasher)
Gather non-cryptographic environment data that does not change over time.
void RandAddDynamicEnv(CSHA512 &hasher)
Gather non-cryptographic environment data that changes over time.
Span< std::byte > AsWritableBytes(Span< T > s) noexcept
Span< const std::byte > MakeByteSpan(V &&v) noexcept
#define EXCLUSIVE_LOCKS_REQUIRED(...)