2222#include < algorithm>
2323#include < cstring>
2424#include < smp>
25+ #define SHAKE_128_RATE (1600 -256 )/8
2526
2627struct alignas (SMP_ALIGN) rng_state
2728{
2829 uint64_t state[25 ];
30+ int64_t reseed_counter = 0 ;
31+ int32_t reseed_rounds = 0 ;
32+ delegate<void (uint64_t *)> reseed_callback = nullptr ;
2933};
3034static SMP::Array<rng_state> rng;
35+ // every RESEED_RATE bytes entropy is refilled
36+ static const int RESEED_RATE = 4096 ;
3137
3238static inline uint64_t rotate_left (uint64_t input, size_t rot) {
3339 return (input << rot) | (input >> (64 -rot));
@@ -114,8 +120,6 @@ static void keccak_1600_p(uint64_t A[25]) {
114120 }
115121}
116122
117- #define SHAKE_128_RATE (1600 -256 )/8
118-
119123static inline void xor_bytes (const uint8_t * in, uint8_t * out, size_t bytes)
120124 {
121125 for (size_t i = 0 ; i != bytes; ++i)
@@ -137,7 +141,17 @@ void rng_absorb(const void* input, size_t bytes)
137141 keccak_1600_p (PER_CPU (rng).state );
138142 absorbed += absorbing;
139143 }
144+ PER_CPU (rng).reseed_counter += RESEED_RATE * bytes;
145+ }
146+
147+ static void reseed_now ()
148+ {
149+ uint64_t value;
150+ for (int i = 0 ; i < PER_CPU (rng).reseed_rounds ; i++) {
151+ PER_CPU (rng).reseed_callback (&value);
152+ rng_absorb (&value, sizeof (value));
140153 }
154+ }
141155
142156void rng_extract (void * output, size_t bytes)
143157 {
@@ -150,4 +164,19 @@ void rng_extract(void* output, size_t bytes)
150164 keccak_1600_p (PER_CPU (rng).state );
151165 copied += copying;
152166 }
167+ // don't reseed if no callback to do so
168+ if (PER_CPU (rng).reseed_callback == nullptr ) return ;
169+ PER_CPU (rng).reseed_counter -= bytes;
170+ // reseed when below certain entropy
171+ if (PER_CPU (rng).reseed_counter < 0 ) {
172+ PER_CPU (rng).reseed_counter = 0 ;
173+ reseed_now ();
174+ }
153175 }
176+
177+ void rng_reseed_init (delegate<void (uint64_t *)> func, int rounds)
178+ {
179+ PER_CPU (rng).reseed_callback = func;
180+ PER_CPU (rng).reseed_rounds = rounds;
181+ reseed_now ();
182+ }
0 commit comments