@@ -143,6 +143,34 @@ static bool GetHardwareRand(unsigned char* ent32) noexcept {
143
143
return false ;
144
144
}
145
145
146
+ /* * Use repeated SHA512 to strengthen the randomness in seed32, and feed into hasher. */
147
+ static void Strengthen (const unsigned char (&seed)[32], int microseconds, CSHA512& hasher) noexcept
148
+ {
149
+ CSHA512 inner_hasher;
150
+ inner_hasher.Write (seed, sizeof (seed));
151
+
152
+ // Hash loop
153
+ unsigned char buffer[64 ];
154
+ int64_t stop = GetTimeMicros () + microseconds;
155
+ do {
156
+ for (int i = 0 ; i < 1000 ; ++i) {
157
+ inner_hasher.Finalize (buffer);
158
+ inner_hasher.Reset ();
159
+ inner_hasher.Write (buffer, sizeof (buffer));
160
+ }
161
+ // Benchmark operation and feed it into outer hasher.
162
+ int64_t perf = GetPerformanceCounter ();
163
+ hasher.Write ((const unsigned char *)&perf, sizeof (perf));
164
+ } while (GetTimeMicros () < stop);
165
+
166
+ // Produce output from inner state and feed it to outer hasher.
167
+ inner_hasher.Finalize (buffer);
168
+ hasher.Write (buffer, sizeof (buffer));
169
+ // Try to clean up.
170
+ inner_hasher.Reset ();
171
+ memory_cleanse (buffer, sizeof (buffer));
172
+ }
173
+
146
174
static void RandAddSeedPerfmon (CSHA512& hasher)
147
175
{
148
176
#ifdef WIN32
@@ -436,7 +464,23 @@ static void SeedSlow(CSHA512& hasher) noexcept
436
464
SeedTimestamp (hasher);
437
465
}
438
466
439
- static void SeedSleep (CSHA512& hasher)
467
+ /* * Extract entropy from rng, strengthen it, and feed it into hasher. */
468
+ static void SeedStrengthen (CSHA512& hasher, RNGState& rng) noexcept
469
+ {
470
+ static std::atomic<int64_t > last_strengthen{0 };
471
+ int64_t last_time = last_strengthen.load ();
472
+ int64_t current_time = GetTimeMicros ();
473
+ if (current_time > last_time + 60000000 ) { // Only run once a minute
474
+ // Generate 32 bytes of entropy from the RNG, and a copy of the entropy already in hasher.
475
+ unsigned char strengthen_seed[32 ];
476
+ rng.MixExtract (strengthen_seed, sizeof (strengthen_seed), CSHA512 (hasher), false );
477
+ // Strengthen it for 10ms (100ms on first run), and feed it into hasher.
478
+ Strengthen (strengthen_seed, last_time == 0 ? 100000 : 10000 , hasher);
479
+ last_strengthen = current_time;
480
+ }
481
+ }
482
+
483
+ static void SeedSleep (CSHA512& hasher, RNGState& rng)
440
484
{
441
485
// Everything that the 'fast' seeder includes
442
486
SeedFast (hasher);
@@ -452,9 +496,12 @@ static void SeedSleep(CSHA512& hasher)
452
496
453
497
// Windows performance monitor data (once every 10 minutes)
454
498
RandAddSeedPerfmon (hasher);
499
+
500
+ // Strengthen every minute
501
+ SeedStrengthen (hasher, rng);
455
502
}
456
503
457
- static void SeedStartup (CSHA512& hasher) noexcept
504
+ static void SeedStartup (CSHA512& hasher, RNGState& rng ) noexcept
458
505
{
459
506
#ifdef WIN32
460
507
RAND_screen ();
@@ -465,6 +512,9 @@ static void SeedStartup(CSHA512& hasher) noexcept
465
512
466
513
// Windows performance monitor data.
467
514
RandAddSeedPerfmon (hasher);
515
+
516
+ // Strengthen
517
+ SeedStrengthen (hasher, rng);
468
518
}
469
519
470
520
enum class RNGLevel {
@@ -489,15 +539,15 @@ static void ProcRand(unsigned char* out, int num, RNGLevel level)
489
539
SeedSlow (hasher);
490
540
break ;
491
541
case RNGLevel::SLEEP:
492
- SeedSleep (hasher);
542
+ SeedSleep (hasher, rng );
493
543
break ;
494
544
}
495
545
496
546
// Combine with and update state
497
547
if (!rng.MixExtract (out, num, std::move (hasher), false )) {
498
548
// On the first invocation, also seed with SeedStartup().
499
549
CSHA512 startup_hasher;
500
- SeedStartup (startup_hasher);
550
+ SeedStartup (startup_hasher, rng );
501
551
rng.MixExtract (out, num, std::move (startup_hasher), true );
502
552
}
503
553
0 commit comments