35#ifdef HAVE_SYS_GETRANDOM
36#include <linux/random.h>
37#include <sys/syscall.h>
39#if defined(HAVE_GETENTROPY) || \
40 (defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX))
43#if defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
44#include <sys/random.h>
46#ifdef HAVE_SYSCTL_ARND
47#include <sys/sysctl.h>
51 LogPrintf(
"Failed to read randomness, aborting\n");
58#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
60#elif !defined(_MSC_VER) && defined(__i386__)
63 __asm__
volatile(
"rdtsc" :
"=A"(r));
65#elif !defined(_MSC_VER) && (defined(__x86_64__) || defined(__amd64__))
66 uint64_t r1 = 0, r2 = 0;
68 __asm__
volatile(
"rdtsc" :
"=a"(r1),
"=d"(r2));
69 return (r2 << 32) | r1;
73 return std::chrono::high_resolution_clock::now().time_since_epoch().count();
78static bool g_rdrand_supported =
false;
79static bool g_rdseed_supported =
false;
80static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000;
81static constexpr uint32_t CPUID_F7_EBX_RDSEED = 0x00040000;
83static_assert(CPUID_F1_ECX_RDRAND == bit_RDRND,
84 "Unexpected value for bit_RDRND");
87static_assert(CPUID_F7_EBX_RDSEED == bit_RDSEED,
88 "Unexpected value for bit_RDSEED");
92 uint32_t eax, ebx, ecx, edx;
93 GetCPUID(1, 0, eax, ebx, ecx, edx);
94 if (ecx & CPUID_F1_ECX_RDRAND) {
95 g_rdrand_supported =
true;
97 GetCPUID(7, 0, eax, ebx, ecx, edx);
98 if (ebx & CPUID_F7_EBX_RDSEED) {
99 g_rdseed_supported =
true;
107 if (g_rdseed_supported) {
108 LogPrintf(
"Using RdSeed as additional entropy source\n");
110 if (g_rdrand_supported) {
111 LogPrintf(
"Using RdRand as an additional entropy source\n");
120static uint64_t GetRdRand() noexcept {
128 uint32_t r1 = 0, r2 = 0;
129 for (
int i = 0; i < 10; ++i) {
131 __asm__
volatile(
".byte 0x0f, 0xc7, 0xf0; setc %1"
132 :
"=a"(r1),
"=q"(ok)::
"cc");
137 for (
int i = 0; i < 10; ++i) {
139 __asm__
volatile(
".byte 0x0f, 0xc7, 0xf0; setc %1"
140 :
"=a"(r2),
"=q"(ok)::
"cc");
145 return (uint64_t(r2) << 32) | r1;
146#elif defined(__x86_64__) || defined(__amd64__)
149 for (
int i = 0; i < 10; ++i) {
151 __asm__
volatile(
".byte 0x48, 0x0f, 0xc7, 0xf0; setc %1"
152 :
"=a"(r1),
"=q"(ok)::
"cc");
159#error "RdRand is only supported on x86 and x86_64"
168static uint64_t GetRdSeed() noexcept {
176 __asm__
volatile(
".byte 0x0f, 0xc7, 0xf8; setc %1"
177 :
"=a"(r1),
"=q"(ok)::
"cc");
181 __asm__
volatile(
"pause");
185 __asm__
volatile(
".byte 0x0f, 0xc7, 0xf8; setc %1"
186 :
"=a"(r2),
"=q"(ok)::
"cc");
190 __asm__
volatile(
"pause");
192 return (uint64_t(r2) << 32) | r1;
193#elif defined(__x86_64__) || defined(__amd64__)
198 __asm__
volatile(
".byte 0x48, 0x0f, 0xc7, 0xf8; setc %1"
199 :
"=a"(r1),
"=q"(ok)::
"cc");
203 __asm__
volatile(
"pause");
207#error "RdSeed is only supported on x86 and x86_64"
227#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
228 if (g_rdrand_supported) {
229 uint64_t out = GetRdRand();
230 hasher.Write((
const uint8_t *)&out,
sizeof(out));
241#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
244 if (g_rdseed_supported) {
245 for (
int i = 0; i < 4; ++i) {
246 uint64_t out = GetRdSeed();
247 hasher.Write((
const uint8_t *)&out,
sizeof(out));
253 if (g_rdrand_supported) {
254 for (
int i = 0; i < 4; ++i) {
256 for (
int j = 0; j < 1024; ++j) {
259 hasher.Write((
const uint8_t *)&out,
sizeof(out));
270static void Strengthen(
const uint8_t (&seed)[32], SteadyClock::duration dur,
273 inner_hasher.
Write(seed,
sizeof(seed));
278 const auto stop{SteadyClock::now() + dur};
280 for (
int i = 0; i < 1000; ++i) {
282 inner_hasher.
Reset();
283 inner_hasher.
Write(buffer,
sizeof(buffer));
287 hasher.Write((
const uint8_t *)&perf,
sizeof(perf));
288 }
while (SteadyClock::now() <
stop);
292 hasher.Write(buffer,
sizeof(buffer));
294 inner_hasher.
Reset();
304 int f = open(
"/dev/urandom", O_RDONLY);
324 HCRYPTPROV hProvider;
325 int ret = CryptAcquireContextW(&hProvider,
nullptr,
nullptr, PROV_RSA_FULL,
326 CRYPT_VERIFYCONTEXT);
334 CryptReleaseContext(hProvider, 0);
335#elif defined(HAVE_SYS_GETRANDOM)
344 if (rv < 0 && errno == ENOSYS) {
354#elif defined(HAVE_GETENTROPY) && defined(__OpenBSD__)
367#elif defined(HAVE_GETENTROPY_RAND) && defined(MAC_OSX)
376#elif defined(HAVE_SYSCTL_ARND)
381 static const int name[2] = {CTL_KERN, KERN_ARND};
385 if (sysctl(
name, std::size(
name), ent32 + have, &len,
nullptr, 0) !=
415 uint8_t m_state[32]
GUARDED_BY(m_mutex) = {0};
417 bool m_strongly_seeded
GUARDED_BY(m_mutex) =
false;
419 Mutex m_events_mutex;
425 ~RNGState() =
default;
427 void AddEvent(uint32_t event_info)
noexcept
429 LOCK(m_events_mutex);
431 m_events_hasher.Write((
const uint8_t *)&event_info,
sizeof(event_info));
435 m_events_hasher.Write((
const uint8_t *)&perfcounter,
436 sizeof(perfcounter));
442 void SeedEvents(
CSHA512 &hasher)
noexcept
447 LOCK(m_events_mutex);
449 uint8_t events_hash[32];
450 m_events_hasher.Finalize(events_hash);
451 hasher.Write(events_hash, 32);
454 m_events_hasher.Reset();
455 m_events_hasher.Write(events_hash, 32);
465 bool MixExtract(uint8_t *out,
size_t num,
CSHA512 &&hasher,
466 bool strong_seed)
noexcept
471 "Buffer needs to have hasher's output size");
475 ret = (m_strongly_seeded |= strong_seed);
477 hasher.Write(m_state, 32);
479 hasher.Write((
const uint8_t *)&m_counter,
sizeof(m_counter));
482 hasher.Finalize(buf);
484 memcpy(m_state, buf + 32, 32);
490 memcpy(out, buf, num);
499RNGState &GetRNGState() noexcept {
503 static std::vector<RNGState, secure_allocator<RNGState>> g_rng(1);
516 hasher.Write((
const uint8_t *)&perfcounter,
sizeof(perfcounter));
523 const uint8_t *ptr = buffer;
524 hasher.Write((
const uint8_t *)&ptr,
sizeof(ptr));
541 hasher.Write(buffer,
sizeof(buffer));
544 rng.SeedEvents(hasher);
556 SteadyClock::duration dur)
noexcept {
559 uint8_t strengthen_seed[32];
560 rng.MixExtract(strengthen_seed,
sizeof(strengthen_seed),
CSHA512(hasher),
574 rng.SeedEvents(hasher);
577 auto old_size = hasher.Size();
580 "Feeding %i bytes of dynamic environment data into RNG\n",
581 hasher.Size() - old_size);
595 auto old_size = hasher.Size();
601 hasher.Size() - old_size);
616 RNGState &rng = GetRNGState();
634 if (!rng.MixExtract(out, num, std::move(hasher),
false)) {
638 rng.MixExtract(out, num, std::move(startup_hasher),
true);
653 GetRNGState().AddEvent(event_info);
678 rng.Keystream(output);
682 : requires_seed(
false), rng(
MakeByteSpan(seed)), bitbuf_size(0) {}
692 static const ssize_t MAX_TRIES = 1024;
706 overwritten[x] |= (data[x] != 0);
711 if (overwritten[x]) {
712 num_overwritten += 1;
725 std::this_thread::sleep_for(std::chrono::milliseconds(1));
733 to_add.
Write((
const uint8_t *)&start,
sizeof(start));
735 GetRNGState().MixExtract(
nullptr, 0, std::move(to_add),
false);
740static constexpr std::array<std::byte, ChaCha20::KEYLEN>
ZERO_KEY{};
743 : requires_seed(!fDeterministic), rng(
ZERO_KEY), bitbuf_size(0) {
753 bitbuf = from.bitbuf;
754 bitbuf_size = from.bitbuf_size;
755 from.requires_seed =
true;
756 from.bitbuf_size = 0;
767std::chrono::microseconds
769 std::chrono::seconds average_interval) {
770 double unscaled = -std::log1p(
GetRand(uint64_t{1} << 48) *
771 -0.0000000000000035527136788 );
772 return now + std::chrono::duration_cast<std::chrono::microseconds>(
773 unscaled * average_interval + 0.5us);
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
void RandomSeed() noexcept
FastRandomContext & operator=(const FastRandomContext &)=delete
void fillrand(Span< std::byte > output) noexcept
Fill a byte Span with random bytes.
uint64_t randrange(uint64_t range) noexcept
Generate a random integer in the range [0..range).
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,...)
std::chrono::microseconds GetExponentialRand(std::chrono::microseconds now, std::chrono::seconds average_interval)
Return a timestamp in the future sampled from an exponential distribution (https://en....
static void ReportHardwareRand()
void GetRandBytes(Span< uint8_t > bytes) noexcept
Overall design of the RNG and entropy sources.
static void SeedStrengthen(CSHA512 &hasher, RNGState &rng, SteadyClock::duration dur) noexcept
Extract entropy from rng, strengthen it, and feed it into hasher.
static void SeedStartup(CSHA512 &hasher, RNGState &rng) noexcept
void RandAddPeriodic() noexcept
Gather entropy from various expensive sources, and feed them to the PRNG state.
bool g_mock_deterministic_tests
static void SeedFast(CSHA512 &hasher) noexcept
static void GetDevURandom(uint8_t *ent32)
Fallback: get 32 bytes of system entropy from /dev/urandom.
static void InitHardwareRand()
Access to other hardware random number generators could be added here later, assuming it is sufficien...
static void SeedHardwareFast(CSHA512 &hasher) noexcept
Add 64 bits of entropy gathered from hardware to hasher.
uint64_t GetRandInternal(uint64_t nMax) noexcept
Generate a uniform random integer in the range [0..range).
void GetOSRand(uint8_t *ent32)
Get 32 bytes of system entropy.
static void SeedTimestamp(CSHA512 &hasher) noexcept
A note on the use of noexcept in the seeding functions below:
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
uint256 GetRandHash() noexcept
void RandomInit()
Initialize global RNG state and log any CPU features that are used.
static void SeedPeriodic(CSHA512 &hasher, RNGState &rng) noexcept
static void ProcRand(uint8_t *out, int num, RNGLevel level) noexcept
void RandAddEvent(const uint32_t event_info) noexcept
Gathers entropy from the low bits of the time at which events occur.
static void RandFailure()
@ SLOW
Automatically called by GetStrongRandBytes.
@ PERIODIC
Called by RandAddPeriodic()
@ FAST
Automatically called by GetRandBytes.
static void SeedHardwareSlow(CSHA512 &hasher) noexcept
Add 256 bits of entropy gathered from hardware to hasher.
static void Strengthen(const uint8_t(&seed)[32], SteadyClock::duration dur, CSHA512 &hasher) noexcept
Use repeated SHA512 to strengthen the randomness in seed32, and feed into hasher.
static int64_t GetPerformanceCounter() noexcept
void GetStrongRandBytes(Span< uint8_t > bytes) noexcept
Gather entropy from various sources, feed it into the internal PRNG, and generate random data using i...
static void SeedSlow(CSHA512 &hasher, RNGState &rng) noexcept
static const int NUM_OS_RANDOM_BYTES
Number of random bytes returned by GetOSRand.
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
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< const std::byte > MakeByteSpan(V &&v) noexcept
#define EXCLUSIVE_LOCKS_REQUIRED(...)