45
45
#include < sys/auxv.h>
46
46
#endif
47
47
48
- [[noreturn]] static void RandFailure ()
48
+ namespace {
49
+
50
+ /* Number of random bytes returned by GetOSRand.
51
+ * When changing this constant make sure to change all call sites, and make
52
+ * sure that the underlying OS APIs for all platforms support the number.
53
+ * (many cap out at 256 bytes).
54
+ */
55
+ static const int NUM_OS_RANDOM_BYTES = 32 ;
56
+
57
+
58
+ [[noreturn]] void RandFailure ()
49
59
{
50
60
LogPrintf (" Failed to read randomness, aborting\n " );
51
61
std::abort ();
52
62
}
53
63
54
- static inline int64_t GetPerformanceCounter () noexcept
64
+ inline int64_t GetPerformanceCounter () noexcept
55
65
{
56
66
// Read the hardware time stamp counter when available.
57
67
// See https://en.wikipedia.org/wiki/Time_Stamp_Counter for more information.
@@ -72,18 +82,18 @@ static inline int64_t GetPerformanceCounter() noexcept
72
82
}
73
83
74
84
#ifdef HAVE_GETCPUID
75
- static bool g_rdrand_supported = false ;
76
- static bool g_rdseed_supported = false ;
77
- static constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000 ;
78
- static constexpr uint32_t CPUID_F7_EBX_RDSEED = 0x00040000 ;
85
+ bool g_rdrand_supported = false ;
86
+ bool g_rdseed_supported = false ;
87
+ constexpr uint32_t CPUID_F1_ECX_RDRAND = 0x40000000 ;
88
+ constexpr uint32_t CPUID_F7_EBX_RDSEED = 0x00040000 ;
79
89
#ifdef bit_RDRND
80
90
static_assert (CPUID_F1_ECX_RDRAND == bit_RDRND, " Unexpected value for bit_RDRND" );
81
91
#endif
82
92
#ifdef bit_RDSEED
83
93
static_assert (CPUID_F7_EBX_RDSEED == bit_RDSEED, " Unexpected value for bit_RDSEED" );
84
94
#endif
85
95
86
- static void InitHardwareRand ()
96
+ void InitHardwareRand ()
87
97
{
88
98
uint32_t eax, ebx, ecx, edx;
89
99
GetCPUID (1 , 0 , eax, ebx, ecx, edx);
@@ -96,7 +106,7 @@ static void InitHardwareRand()
96
106
}
97
107
}
98
108
99
- static void ReportHardwareRand ()
109
+ void ReportHardwareRand ()
100
110
{
101
111
// This must be done in a separate function, as InitHardwareRand() may be indirectly called
102
112
// from global constructors, before logging is initialized.
@@ -112,7 +122,7 @@ static void ReportHardwareRand()
112
122
*
113
123
* Must only be called when RdRand is supported.
114
124
*/
115
- static uint64_t GetRdRand () noexcept
125
+ uint64_t GetRdRand () noexcept
116
126
{
117
127
// RdRand may very rarely fail. Invoke it up to 10 times in a loop to reduce this risk.
118
128
#ifdef __i386__
@@ -147,7 +157,7 @@ static uint64_t GetRdRand() noexcept
147
157
*
148
158
* Must only be called when RdSeed is supported.
149
159
*/
150
- static uint64_t GetRdSeed () noexcept
160
+ uint64_t GetRdSeed () noexcept
151
161
{
152
162
// RdSeed may fail when the HW RNG is overloaded. Loop indefinitely until enough entropy is gathered,
153
163
// but pause after every failure.
@@ -181,16 +191,16 @@ static uint64_t GetRdSeed() noexcept
181
191
182
192
#elif defined(__aarch64__) && defined(HWCAP2_RNG)
183
193
184
- static bool g_rndr_supported = false ;
194
+ bool g_rndr_supported = false ;
185
195
186
- static void InitHardwareRand ()
196
+ void InitHardwareRand ()
187
197
{
188
198
if (getauxval (AT_HWCAP2) & HWCAP2_RNG) {
189
199
g_rndr_supported = true ;
190
200
}
191
201
}
192
202
193
- static void ReportHardwareRand ()
203
+ void ReportHardwareRand ()
194
204
{
195
205
// This must be done in a separate function, as InitHardwareRand() may be indirectly called
196
206
// from global constructors, before logging is initialized.
@@ -203,7 +213,7 @@ static void ReportHardwareRand()
203
213
*
204
214
* Must only be called when RNDR is supported.
205
215
*/
206
- static uint64_t GetRNDR () noexcept
216
+ uint64_t GetRNDR () noexcept
207
217
{
208
218
uint8_t ok;
209
219
uint64_t r1;
@@ -221,7 +231,7 @@ static uint64_t GetRNDR() noexcept
221
231
*
222
232
* Must only be called when RNDRRS is supported.
223
233
*/
224
- static uint64_t GetRNDRRS () noexcept
234
+ uint64_t GetRNDRRS () noexcept
225
235
{
226
236
uint8_t ok;
227
237
uint64_t r1;
@@ -241,12 +251,12 @@ static uint64_t GetRNDRRS() noexcept
241
251
* Slower sources should probably be invoked separately, and/or only from
242
252
* RandAddPeriodic (which is called once a minute).
243
253
*/
244
- static void InitHardwareRand () {}
245
- static void ReportHardwareRand () {}
254
+ void InitHardwareRand () {}
255
+ void ReportHardwareRand () {}
246
256
#endif
247
257
248
258
/* * Add 64 bits of entropy gathered from hardware to hasher. Do nothing if not supported. */
249
- static void SeedHardwareFast (CSHA512& hasher) noexcept {
259
+ void SeedHardwareFast (CSHA512& hasher) noexcept {
250
260
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
251
261
if (g_rdrand_supported) {
252
262
uint64_t out = GetRdRand ();
@@ -263,7 +273,7 @@ static void SeedHardwareFast(CSHA512& hasher) noexcept {
263
273
}
264
274
265
275
/* * Add 256 bits of entropy gathered from hardware to hasher. Do nothing if not supported. */
266
- static void SeedHardwareSlow (CSHA512& hasher) noexcept {
276
+ void SeedHardwareSlow (CSHA512& hasher) noexcept {
267
277
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
268
278
// When we want 256 bits of entropy, prefer RdSeed over RdRand, as it's
269
279
// guaranteed to produce independent randomness on every call.
@@ -296,7 +306,7 @@ static void SeedHardwareSlow(CSHA512& hasher) noexcept {
296
306
}
297
307
298
308
/* * Use repeated SHA512 to strengthen the randomness in seed32, and feed into hasher. */
299
- static void Strengthen (const unsigned char (&seed)[32], SteadyClock::duration dur, CSHA512& hasher) noexcept
309
+ void Strengthen (const unsigned char (&seed)[32], SteadyClock::duration dur, CSHA512& hasher) noexcept
300
310
{
301
311
CSHA512 inner_hasher;
302
312
inner_hasher.Write (seed, sizeof (seed));
@@ -327,7 +337,7 @@ static void Strengthen(const unsigned char (&seed)[32], SteadyClock::duration du
327
337
/* * Fallback: get 32 bytes of system entropy from /dev/urandom. The most
328
338
* compatible way to get cryptographic randomness on UNIX-ish platforms.
329
339
*/
330
- [[maybe_unused]] static void GetDevURandom (unsigned char *ent32)
340
+ [[maybe_unused]] void GetDevURandom (unsigned char *ent32)
331
341
{
332
342
int f = open (" /dev/urandom" , O_RDONLY);
333
343
if (f == -1 ) {
@@ -402,8 +412,6 @@ void GetOSRand(unsigned char *ent32)
402
412
#endif
403
413
}
404
414
405
- namespace {
406
-
407
415
class RNGState {
408
416
Mutex m_mutex;
409
417
/* The RNG state consists of 256 bits of entropy, taken from the output of
@@ -521,20 +529,19 @@ RNGState& GetRNGState() noexcept
521
529
static std::vector<RNGState, secure_allocator<RNGState>> g_rng (1 );
522
530
return g_rng[0 ];
523
531
}
524
- }
525
532
526
533
/* A note on the use of noexcept in the seeding functions below:
527
534
*
528
535
* None of the RNG code should ever throw any exception.
529
536
*/
530
537
531
- static void SeedTimestamp (CSHA512& hasher) noexcept
538
+ void SeedTimestamp (CSHA512& hasher) noexcept
532
539
{
533
540
int64_t perfcounter = GetPerformanceCounter ();
534
541
hasher.Write ((const unsigned char *)&perfcounter, sizeof (perfcounter));
535
542
}
536
543
537
- static void SeedFast (CSHA512& hasher) noexcept
544
+ void SeedFast (CSHA512& hasher) noexcept
538
545
{
539
546
unsigned char buffer[32 ];
540
547
@@ -549,7 +556,7 @@ static void SeedFast(CSHA512& hasher) noexcept
549
556
SeedTimestamp (hasher);
550
557
}
551
558
552
- static void SeedSlow (CSHA512& hasher, RNGState& rng) noexcept
559
+ void SeedSlow (CSHA512& hasher, RNGState& rng) noexcept
553
560
{
554
561
unsigned char buffer[32 ];
555
562
@@ -571,7 +578,7 @@ static void SeedSlow(CSHA512& hasher, RNGState& rng) noexcept
571
578
}
572
579
573
580
/* * Extract entropy from rng, strengthen it, and feed it into hasher. */
574
- static void SeedStrengthen (CSHA512& hasher, RNGState& rng, SteadyClock::duration dur) noexcept
581
+ void SeedStrengthen (CSHA512& hasher, RNGState& rng, SteadyClock::duration dur) noexcept
575
582
{
576
583
// Generate 32 bytes of entropy from the RNG, and a copy of the entropy already in hasher.
577
584
// Never use the deterministic PRNG for this, as the result is only used internally.
@@ -581,7 +588,7 @@ static void SeedStrengthen(CSHA512& hasher, RNGState& rng, SteadyClock::duration
581
588
Strengthen (strengthen_seed, dur, hasher);
582
589
}
583
590
584
- static void SeedPeriodic (CSHA512& hasher, RNGState& rng) noexcept
591
+ void SeedPeriodic (CSHA512& hasher, RNGState& rng) noexcept
585
592
{
586
593
// Everything that the 'fast' seeder includes
587
594
SeedFast (hasher);
@@ -601,7 +608,7 @@ static void SeedPeriodic(CSHA512& hasher, RNGState& rng) noexcept
601
608
SeedStrengthen (hasher, rng, 10ms);
602
609
}
603
610
604
- static void SeedStartup (CSHA512& hasher, RNGState& rng) noexcept
611
+ void SeedStartup (CSHA512& hasher, RNGState& rng) noexcept
605
612
{
606
613
// Gather 256 bits of hardware randomness, if available
607
614
SeedHardwareSlow (hasher);
@@ -627,7 +634,7 @@ enum class RNGLevel {
627
634
PERIODIC, // !< Called by RandAddPeriodic()
628
635
};
629
636
630
- static void ProcRand (unsigned char * out, int num, RNGLevel level, bool always_use_real_rng) noexcept
637
+ void ProcRand (unsigned char * out, int num, RNGLevel level, bool always_use_real_rng) noexcept
631
638
{
632
639
// Make sure the RNG is initialized first (as all Seed* function possibly need hwrand to be available).
633
640
RNGState& rng = GetRNGState ();
@@ -656,6 +663,9 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level, bool always_us
656
663
}
657
664
}
658
665
666
+ } // namespace
667
+
668
+
659
669
/* * Internal function to set g_determinstic_rng. Only accessed from tests. */
660
670
void MakeRandDeterministicDANGEROUS (const uint256& seed) noexcept
661
671
{
@@ -679,13 +689,6 @@ void RandAddPeriodic() noexcept
679
689
680
690
void RandAddEvent (const uint32_t event_info) noexcept { GetRNGState ().AddEvent (event_info); }
681
691
682
- uint256 GetRandHash () noexcept
683
- {
684
- uint256 hash;
685
- GetRandBytes (hash);
686
- return hash;
687
- }
688
-
689
692
void FastRandomContext::RandomSeed () noexcept
690
693
{
691
694
uint256 seed = GetRandHash ();
0 commit comments