|
6 | 6 | #ifndef BITCOIN_RANDOM_H |
7 | 7 | #define BITCOIN_RANDOM_H |
8 | 8 |
|
| 9 | +#include "crypto/chacha20.h" |
9 | 10 | #include "uint256.h" |
10 | 11 |
|
11 | 12 | #include <stdint.h> |
@@ -33,21 +34,68 @@ void GetStrongRandBytes(unsigned char* buf, int num); |
33 | 34 | * This class is not thread-safe. |
34 | 35 | */ |
35 | 36 | class FastRandomContext { |
| 37 | +private: |
| 38 | + bool requires_seed; |
| 39 | + ChaCha20 rng; |
| 40 | + |
| 41 | + unsigned char bytebuf[64]; |
| 42 | + int bytebuf_size; |
| 43 | + |
| 44 | + uint64_t bitbuf; |
| 45 | + int bitbuf_size; |
| 46 | + |
| 47 | + void RandomSeed(); |
| 48 | + |
| 49 | + void FillByteBuffer() |
| 50 | + { |
| 51 | + if (requires_seed) { |
| 52 | + RandomSeed(); |
| 53 | + } |
| 54 | + rng.Output(bytebuf, sizeof(bytebuf)); |
| 55 | + bytebuf_size = sizeof(bytebuf); |
| 56 | + } |
| 57 | + |
| 58 | + void FillBitBuffer() |
| 59 | + { |
| 60 | + bitbuf = rand64(); |
| 61 | + bitbuf_size = 64; |
| 62 | + } |
| 63 | + |
36 | 64 | public: |
37 | | - explicit FastRandomContext(bool fDeterministic=false); |
| 65 | + explicit FastRandomContext(bool fDeterministic = false); |
38 | 66 |
|
39 | | - uint32_t rand32() { |
40 | | - Rz = 36969 * (Rz & 65535) + (Rz >> 16); |
41 | | - Rw = 18000 * (Rw & 65535) + (Rw >> 16); |
42 | | - return (Rw << 16) + Rz; |
| 67 | + /** Initialize with explicit seed (only for testing) */ |
| 68 | + explicit FastRandomContext(const uint256& seed); |
| 69 | + |
| 70 | + /** Generate a random 64-bit integer. */ |
| 71 | + uint64_t rand64() |
| 72 | + { |
| 73 | + if (bytebuf_size < 8) FillByteBuffer(); |
| 74 | + uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size); |
| 75 | + bytebuf_size -= 8; |
| 76 | + return ret; |
43 | 77 | } |
44 | 78 |
|
45 | | - bool randbool() { |
46 | | - return rand32() & 1; |
| 79 | + /** Generate a random (bits)-bit integer. */ |
| 80 | + uint64_t randbits(int bits) { |
| 81 | + if (bits == 0) { |
| 82 | + return 0; |
| 83 | + } else if (bits > 32) { |
| 84 | + return rand64() >> (64 - bits); |
| 85 | + } else { |
| 86 | + if (bitbuf_size < bits) FillBitBuffer(); |
| 87 | + uint64_t ret = bitbuf & (~(uint64_t)0 >> (64 - bits)); |
| 88 | + bitbuf >>= bits; |
| 89 | + bitbuf_size -= bits; |
| 90 | + return ret; |
| 91 | + } |
47 | 92 | } |
48 | 93 |
|
49 | | - uint32_t Rz; |
50 | | - uint32_t Rw; |
| 94 | + /** Generate a random 32-bit integer. */ |
| 95 | + uint32_t rand32() { return randbits(32); } |
| 96 | + |
| 97 | + /** Generate a random boolean. */ |
| 98 | + bool randbool() { return randbits(1); } |
51 | 99 | }; |
52 | 100 |
|
53 | 101 | /* Number of random bytes returned by GetOSRand. |
|
0 commit comments