6#include <bitcoin-build-config.h>
37#if defined(HAVE_GETRANDOM) || (defined(HAVE_GETENTROPY_RAND) && defined(__APPLE__))
38#include <sys/random.h>
41#ifdef HAVE_SYSCTL_ARND
42#include <sys/sysctl.h>
44#if defined(HAVE_STRONG_GETAUXVAL) && defined(__aarch64__)
55static const int NUM_OS_RANDOM_BYTES = 32;
58[[noreturn]]
void RandFailure()
60 LogError(
"Failed to read randomness, aborting\n");
64inline int64_t GetPerformanceCounter() noexcept
68#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
70#elif !defined(_MSC_VER) && defined(__i386__)
72 __asm__
volatile (
"rdtsc" :
"=A"(r));
74#elif !defined(_MSC_VER) && (defined(__x86_64__) || defined(__amd64__))
75 uint64_t r1 = 0, r2 = 0;
76 __asm__
volatile (
"rdtsc" :
"=a"(r1),
"=d"(r2));
77 return (r2 << 32) | r1;
80 return std::chrono::high_resolution_clock::now().time_since_epoch().count();
85bool g_rdrand_supported =
false;
86bool g_rdseed_supported =
false;
87constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000;
88constexpr uint32_t CPUID_F7_EBX_RDSEED = 0x00040000;
90static_assert(CPUID_F1_ECX_RDRAND == bit_RDRND,
"Unexpected value for bit_RDRND");
93static_assert(CPUID_F7_EBX_RDSEED == bit_RDSEED,
"Unexpected value for bit_RDSEED");
96void InitHardwareRand()
98 uint32_t eax, ebx, ecx, edx;
99 GetCPUID(1, 0, eax, ebx, ecx, edx);
100 if (ecx & CPUID_F1_ECX_RDRAND) {
101 g_rdrand_supported =
true;
103 GetCPUID(7, 0, eax, ebx, ecx, edx);
104 if (ebx & CPUID_F7_EBX_RDSEED) {
105 g_rdseed_supported =
true;
109void ReportHardwareRand()
113 if (g_rdseed_supported) {
114 LogPrintf(
"Using RdSeed as an additional entropy source\n");
116 if (g_rdrand_supported) {
117 LogPrintf(
"Using RdRand as an additional entropy source\n");
125uint64_t GetRdRand() noexcept
133 uint32_t r1 = 0, r2 = 0;
134 for (
int i = 0; i < 10; ++i) {
135 __asm__
volatile (
".byte 0x0f, 0xc7, 0xf0; setc %1" :
"=a"(r1),
"=q"(ok) ::
"cc");
138 for (
int i = 0; i < 10; ++i) {
139 __asm__
volatile (
".byte 0x0f, 0xc7, 0xf0; setc %1" :
"=a"(r2),
"=q"(ok) ::
"cc");
142 return (((uint64_t)r2) << 32) | r1;
143#elif defined(__x86_64__) || defined(__amd64__)
146 for (
int i = 0; i < 10; ++i) {
147 __asm__
volatile (
".byte 0x48, 0x0f, 0xc7, 0xf0; setc %1" :
"=a"(r1),
"=q"(ok) ::
"cc");
152#error "RdRand is only supported on x86 and x86_64"
160uint64_t GetRdSeed() noexcept
168 __asm__
volatile (
".byte 0x0f, 0xc7, 0xf8; setc %1" :
"=a"(r1),
"=q"(ok) ::
"cc");
170 __asm__
volatile (
"pause");
173 __asm__
volatile (
".byte 0x0f, 0xc7, 0xf8; setc %1" :
"=a"(r2),
"=q"(ok) ::
"cc");
175 __asm__
volatile (
"pause");
177 return (((uint64_t)r2) << 32) | r1;
178#elif defined(__x86_64__) || defined(__amd64__)
182 __asm__
volatile (
".byte 0x48, 0x0f, 0xc7, 0xf8; setc %1" :
"=a"(r1),
"=q"(ok) ::
"cc");
184 __asm__
volatile (
"pause");
188#error "RdSeed is only supported on x86 and x86_64"
192#elif defined(__aarch64__) && defined(HWCAP2_RNG)
194bool g_rndr_supported =
false;
196void InitHardwareRand()
198 if (getauxval(AT_HWCAP2) & HWCAP2_RNG) {
199 g_rndr_supported =
true;
203void ReportHardwareRand()
207 if (g_rndr_supported) {
208 LogPrintf(
"Using RNDR and RNDRRS as additional entropy sources\n");
216uint64_t GetRNDR() noexcept
222 __asm__
volatile(
"mrs %0, s3_3_c2_c4_0; cset %w1, ne;"
223 :
"=r"(r1),
"=r"(ok)::
"cc");
225 __asm__
volatile(
"yield");
234uint64_t GetRNDRRS() noexcept
240 __asm__
volatile(
"mrs %0, s3_3_c2_c4_1; cset %w1, ne;"
241 :
"=r"(r1),
"=r"(ok)::
"cc");
243 __asm__
volatile(
"yield");
254void InitHardwareRand() {}
255void ReportHardwareRand() {}
259void SeedHardwareFast(
CSHA512& hasher)
noexcept {
260#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
261 if (g_rdrand_supported) {
262 uint64_t
out = GetRdRand();
263 hasher.Write((
const unsigned char*)&
out,
sizeof(
out));
266#elif defined(__aarch64__) && defined(HWCAP2_RNG)
267 if (g_rndr_supported) {
268 uint64_t
out = GetRNDR();
269 hasher.Write((
const unsigned char*)&
out,
sizeof(
out));
276void SeedHardwareSlow(
CSHA512& hasher)
noexcept {
277#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
280 if (g_rdseed_supported) {
281 for (
int i = 0; i < 4; ++i) {
282 uint64_t
out = GetRdSeed();
283 hasher.Write((
const unsigned char*)&
out,
sizeof(
out));
289 if (g_rdrand_supported) {
290 for (
int i = 0; i < 4; ++i) {
292 for (
int j = 0; j < 1024; ++j)
out ^= GetRdRand();
293 hasher.Write((
const unsigned char*)&
out,
sizeof(
out));
297#elif defined(__aarch64__) && defined(HWCAP2_RNG)
298 if (g_rndr_supported) {
299 for (
int i = 0; i < 4; ++i) {
300 uint64_t
out = GetRNDRRS();
301 hasher.Write((
const unsigned char*)&
out,
sizeof(
out));
309void Strengthen(
const unsigned char (&seed)[32], SteadyClock::duration dur,
CSHA512& hasher)
noexcept
312 inner_hasher.
Write(seed,
sizeof(seed));
315 unsigned char buffer[64];
316 const auto stop{SteadyClock::now() + dur};
318 for (
int i = 0; i < 1000; ++i) {
320 inner_hasher.
Reset();
321 inner_hasher.
Write(buffer,
sizeof(buffer));
324 int64_t perf = GetPerformanceCounter();
325 hasher.Write((
const unsigned char*)&perf,
sizeof(perf));
326 }
while (SteadyClock::now() <
stop);
330 hasher.Write(buffer,
sizeof(buffer));
332 inner_hasher.
Reset();
340[[maybe_unused]]
void GetDevURandom(
unsigned char *ent32)
342 int f = open(
"/dev/urandom", O_RDONLY);
348 ssize_t n = read(f, ent32 + have, NUM_OS_RANDOM_BYTES - have);
349 if (n <= 0 || n + have > NUM_OS_RANDOM_BYTES) {
354 }
while (have < NUM_OS_RANDOM_BYTES);
360void GetOSRand(
unsigned char *ent32)
363 HCRYPTPROV hProvider;
364 int ret = CryptAcquireContextW(&hProvider,
nullptr,
nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
368 ret = CryptGenRandom(hProvider, NUM_OS_RANDOM_BYTES, ent32);
372 CryptReleaseContext(hProvider, 0);
373#elif defined(HAVE_GETRANDOM)
379 if (getrandom(ent32, NUM_OS_RANDOM_BYTES, 0) != NUM_OS_RANDOM_BYTES) {
382#elif defined(__OpenBSD__)
389 arc4random_buf(ent32, NUM_OS_RANDOM_BYTES);
390#elif defined(HAVE_GETENTROPY_RAND) && defined(__APPLE__)
391 if (getentropy(ent32, NUM_OS_RANDOM_BYTES) != 0) {
394#elif defined(HAVE_SYSCTL_ARND)
398 static int name[2] = {CTL_KERN, KERN_ARND};
401 size_t len = NUM_OS_RANDOM_BYTES - have;
402 if (sysctl(
name, std::size(
name), ent32 + have, &len,
nullptr, 0) != 0) {
406 }
while (have < NUM_OS_RANDOM_BYTES);
411 GetDevURandom(ent32);
425 unsigned char m_state[32]
GUARDED_BY(m_mutex) = {0};
427 bool m_strongly_seeded
GUARDED_BY(m_mutex) =
false;
431 std::optional<ChaCha20> m_deterministic_prng
GUARDED_BY(m_mutex);
433 Mutex m_events_mutex;
442 ~RNGState() =
default;
446 LOCK(m_events_mutex);
448 m_events_hasher.Write((
const unsigned char *)&event_info,
sizeof(event_info));
451 uint32_t perfcounter = (GetPerformanceCounter() & 0xffffffff);
452 m_events_hasher.Write((
const unsigned char*)&perfcounter,
sizeof(perfcounter));
462 LOCK(m_events_mutex);
464 unsigned char 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);
490 unsigned char buf[64];
491 static_assert(
sizeof(buf) ==
CSHA512::OUTPUT_SIZE,
"Buffer needs to have hasher's output size");
495 ret = (m_strongly_seeded |= strong_seed);
497 hasher.Write(m_state, 32);
499 hasher.Write((
const unsigned char*)&m_counter,
sizeof(m_counter));
502 hasher.Finalize(buf);
504 memcpy(m_state, buf + 32, 32);
506 if (!always_use_real_rng && m_deterministic_prng.has_value()) [[unlikely]] {
516 memcpy(
out, buf, num);
525RNGState& GetRNGState() noexcept
529 static std::vector<RNGState, secure_allocator<RNGState>> g_rng(1);
538void SeedTimestamp(
CSHA512& hasher)
noexcept
540 int64_t perfcounter = GetPerformanceCounter();
541 hasher.Write((
const unsigned char*)&perfcounter,
sizeof(perfcounter));
544void SeedFast(
CSHA512& hasher)
noexcept
546 unsigned char buffer[32];
549 const unsigned char* ptr = buffer;
550 hasher.Write((
const unsigned char*)&ptr,
sizeof(ptr));
553 SeedHardwareFast(hasher);
556 SeedTimestamp(hasher);
559void SeedSlow(
CSHA512& hasher, RNGState& rng)
noexcept
561 unsigned char buffer[32];
568 hasher.Write(buffer,
sizeof(buffer));
571 rng.SeedEvents(hasher);
577 SeedTimestamp(hasher);
581void SeedStrengthen(
CSHA512& hasher, RNGState& rng, SteadyClock::duration dur)
noexcept
585 unsigned char strengthen_seed[32];
586 rng.MixExtract(strengthen_seed,
sizeof(strengthen_seed),
CSHA512(hasher),
false,
true);
588 Strengthen(strengthen_seed, dur, hasher);
591void SeedPeriodic(
CSHA512& hasher, RNGState& rng)
noexcept
597 SeedTimestamp(hasher);
600 rng.SeedEvents(hasher);
603 auto old_size = hasher.Size();
605 LogDebug(
BCLog::RAND,
"Feeding %i bytes of dynamic environment data into RNG\n", hasher.Size() - old_size);
608 SeedStrengthen(hasher, rng, 10ms);
611void SeedStartup(
CSHA512& hasher, RNGState& rng)
noexcept
614 SeedHardwareSlow(hasher);
617 SeedSlow(hasher, rng);
620 auto old_size = hasher.Size();
625 LogDebug(
BCLog::RAND,
"Feeding %i bytes of environment data into RNG\n", hasher.Size() - old_size);
628 SeedStrengthen(hasher, rng, 100ms);
637void ProcRand(
unsigned char*
out,
int num, RNGLevel level,
bool always_use_real_rng)
noexcept
640 RNGState& rng = GetRNGState();
650 SeedSlow(hasher, rng);
652 case RNGLevel::PERIODIC:
653 SeedPeriodic(hasher, rng);
658 if (!rng.MixExtract(
out, num, std::move(hasher),
false, always_use_real_rng)) {
661 SeedStartup(startup_hasher, rng);
662 rng.MixExtract(
out, num, std::move(startup_hasher),
true, always_use_real_rng);
672 GetRNGState().MakeDeterministic(seed);
679 ProcRand(bytes.data(), bytes.size(), RNGLevel::FAST,
false);
684 ProcRand(bytes.data(), bytes.size(), RNGLevel::SLOW,
true);
689 ProcRand(
nullptr, 0, RNGLevel::PERIODIC,
false);
692void RandAddEvent(
const uint32_t event_info)
noexcept { GetRNGState().AddEvent(event_info); }
703 if (requires_seed) RandomSeed();
704 rng.Keystream(output);
712 requires_seed =
false;
718 uint64_t start = GetPerformanceCounter();
724 static constexpr int MAX_TRIES{1024};
725 uint8_t
data[NUM_OS_RANDOM_BYTES];
726 bool overwritten[NUM_OS_RANDOM_BYTES] = {};
731 memset(
data, 0, NUM_OS_RANDOM_BYTES);
733 for (
int x=0; x < NUM_OS_RANDOM_BYTES; ++x) {
734 overwritten[x] |= (
data[x] != 0);
738 for (
int x=0; x < NUM_OS_RANDOM_BYTES; ++x) {
739 if (overwritten[x]) {
740 num_overwritten += 1;
745 }
while (num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES);
746 if (num_overwritten != NUM_OS_RANDOM_BYTES)
return false;
749 std::this_thread::sleep_for(std::chrono::milliseconds(1));
750 uint64_t
stop = GetPerformanceCounter();
751 if (
stop == start)
return false;
755 to_add.
Write((
const unsigned char*)&start,
sizeof(start));
757 GetRNGState().MixExtract(
nullptr, 0, std::move(to_add),
false,
true);
762static constexpr std::array<std::byte, ChaCha20::KEYLEN>
ZERO_KEY{};
774 ProcRand(
nullptr, 0, RNGLevel::FAST,
true);
776 ReportHardwareRand();
790 return -std::log1p((uniform >> 11) * -0x1.0p-53);
A hasher class for SHA-256.
A hasher class for SHA-512.
static constexpr size_t OUTPUT_SIZE
void Finalize(unsigned char hash[OUTPUT_SIZE])
CSHA512 & Write(const unsigned char *data, size_t len)
void SetKey(Span< const std::byte > key) noexcept
Set 32-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 LogDebug(category,...)
void GetRandBytes(Span< unsigned char > bytes) noexcept
Generate random data via the internal PRNG.
std::atomic< bool > g_used_g_prng
void RandAddPeriodic() noexcept
Gather entropy from various expensive sources, and feed them to the PRNG state.
void GetStrongRandBytes(Span< unsigned char > bytes) noexcept
Gather entropy from various sources, feed it into the internal PRNG, and generate random data using i...
bool Random_SanityCheck()
Check that OS randomness is available and returning the requested number of bytes.
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.
uint256 GetRandHash() noexcept
Generate a random uint256.
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(...)