Simplify test PRNG implementation

This commit is contained in:
Pieter Wuille 2023-05-10 10:40:08 -04:00
parent fb5bfa4eed
commit 6ec3731e8c

View File

@ -16,8 +16,6 @@
#include "util.h" #include "util.h"
static uint64_t secp256k1_test_state[4]; static uint64_t secp256k1_test_state[4];
static uint64_t secp256k1_test_rng_integer;
static int secp256k1_test_rng_integer_bits_left = 0;
SECP256K1_INLINE static void secp256k1_testrand_seed(const unsigned char *seed16) { SECP256K1_INLINE static void secp256k1_testrand_seed(const unsigned char *seed16) {
static const unsigned char PREFIX[19] = "secp256k1 test init"; static const unsigned char PREFIX[19] = "secp256k1 test init";
@ -36,7 +34,6 @@ SECP256K1_INLINE static void secp256k1_testrand_seed(const unsigned char *seed16
for (j = 0; j < 8; ++j) s = (s << 8) | out32[8*i + j]; for (j = 0; j < 8; ++j) s = (s << 8) | out32[8*i + j];
secp256k1_test_state[i] = s; secp256k1_test_state[i] = s;
} }
secp256k1_test_rng_integer_bits_left = 0;
} }
SECP256K1_INLINE static uint64_t rotl(const uint64_t x, int k) { SECP256K1_INLINE static uint64_t rotl(const uint64_t x, int k) {
@ -57,58 +54,30 @@ SECP256K1_INLINE static uint64_t secp256k1_testrand64(void) {
} }
SECP256K1_INLINE static uint64_t secp256k1_testrand_bits(int bits) { SECP256K1_INLINE static uint64_t secp256k1_testrand_bits(int bits) {
uint64_t ret; if (bits == 0) return 0;
if (secp256k1_test_rng_integer_bits_left < bits) { return secp256k1_testrand64() >> (64 - bits);
secp256k1_test_rng_integer = secp256k1_testrand64();
secp256k1_test_rng_integer_bits_left = 64;
}
ret = secp256k1_test_rng_integer;
secp256k1_test_rng_integer >>= bits;
secp256k1_test_rng_integer_bits_left -= bits;
ret &= ((~((uint64_t)0)) >> (64 - bits));
return ret;
} }
SECP256K1_INLINE static uint32_t secp256k1_testrand32(void) { SECP256K1_INLINE static uint32_t secp256k1_testrand32(void) {
return secp256k1_testrand_bits(32); return secp256k1_testrand64() >> 32;
} }
static uint32_t secp256k1_testrand_int(uint32_t range) { static uint32_t secp256k1_testrand_int(uint32_t range) {
/* We want a uniform integer between 0 and range-1, inclusive. uint32_t mask = 0;
* B is the smallest number such that range <= 2**B. uint32_t range_copy;
* two mechanisms implemented here: /* Reduce range by 1, changing its meaning to "maximum value". */
* - generate B bits numbers until one below range is found, and return it VERIFY_CHECK(range != 0);
* - find the largest multiple M of range that is <= 2**(B+A), generate B+A range -= 1;
* bits numbers until one below M is found, and return it modulo range /* Count the number of bits in range. */
* The second mechanism consumes A more bits of entropy in every iteration, range_copy = range;
* but may need fewer iterations due to M being closer to 2**(B+A) then while (range_copy) {
* range is to 2**B. The array below (indexed by B) contains a 0 when the mask = (mask << 1) | 1U;
* first mechanism is to be used, and the number A otherwise. range_copy >>= 1;
*/
static const int addbits[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0};
uint32_t trange, mult;
int bits = 0;
if (range <= 1) {
return 0;
}
trange = range - 1;
while (trange > 0) {
trange >>= 1;
bits++;
}
if (addbits[bits]) {
bits = bits + addbits[bits];
mult = ((~((uint32_t)0)) >> (32 - bits)) / range;
trange = range * mult;
} else {
trange = range;
mult = 1;
} }
/* Generation loop. */
while (1) { while (1) {
uint32_t x = secp256k1_testrand_bits(bits); uint32_t val = secp256k1_testrand64() & mask;
if (x < trange) { if (val <= range) return val;
return (mult == 1) ? x : (x % range);
}
} }
} }