* Fast randomness source. This is seeded once with secure random data, but * is completely deterministic and does not gather more entropy after that. * * This class is not thread-safe. */
| 129 | * This class is not thread-safe. |
| 130 | */ |
| 131 | class FastRandomContext |
| 132 | { |
| 133 | private: |
| 134 | bool requires_seed; |
| 135 | ChaCha20 rng; |
| 136 | |
| 137 | unsigned char bytebuf[64]; |
| 138 | int bytebuf_size; |
| 139 | |
| 140 | uint64_t bitbuf; |
| 141 | int bitbuf_size; |
| 142 | |
| 143 | void RandomSeed(); |
| 144 | |
| 145 | void FillByteBuffer() |
| 146 | { |
| 147 | if (requires_seed) { |
| 148 | RandomSeed(); |
| 149 | } |
| 150 | rng.Keystream(bytebuf, sizeof(bytebuf)); |
| 151 | bytebuf_size = sizeof(bytebuf); |
| 152 | } |
| 153 | |
| 154 | void FillBitBuffer() |
| 155 | { |
| 156 | bitbuf = rand64(); |
| 157 | bitbuf_size = 64; |
| 158 | } |
| 159 | |
| 160 | public: |
| 161 | explicit FastRandomContext(bool fDeterministic = false) noexcept; |
| 162 | |
| 163 | /** Initialize with explicit seed (only for testing) */ |
| 164 | explicit FastRandomContext(const uint256& seed) noexcept; |
| 165 | |
| 166 | // Do not permit copying a FastRandomContext (move it, or create a new one to get reseeded). |
| 167 | FastRandomContext(const FastRandomContext&) = delete; |
| 168 | FastRandomContext(FastRandomContext&&) = delete; |
| 169 | FastRandomContext& operator=(const FastRandomContext&) = delete; |
| 170 | |
| 171 | /** Move a FastRandomContext. If the original one is used again, it will be reseeded. */ |
| 172 | FastRandomContext& operator=(FastRandomContext&& from) noexcept; |
| 173 | |
| 174 | /** Generate a random 64-bit integer. */ |
| 175 | uint64_t rand64() noexcept |
| 176 | { |
| 177 | if (bytebuf_size < 8) FillByteBuffer(); |
| 178 | uint64_t ret = ReadLE64(bytebuf + 64 - bytebuf_size); |
| 179 | bytebuf_size -= 8; |
| 180 | return ret; |
| 181 | } |
| 182 | |
| 183 | /** Generate a random (bits)-bit integer. */ |
| 184 | uint64_t randbits(int bits) noexcept |
| 185 | { |
| 186 | if (bits == 0) { |
| 187 | return 0; |
| 188 | } else if (bits > 32) { |
no outgoing calls