From 5f05975677e3593647f82b6083787d88f76b6fa7 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 18 Oct 2015 03:58:23 +0200 Subject: [PATCH] Faster secp256k1_rand_int implementation --- src/testrand_impl.h | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/testrand_impl.h b/src/testrand_impl.h index 057dc5408a..d45d2400cc 100644 --- a/src/testrand_impl.h +++ b/src/testrand_impl.h @@ -45,19 +45,40 @@ static uint32_t secp256k1_rand_bits(int bits) { } static uint32_t secp256k1_rand_int(uint32_t range) { + /* We want a uniform integer between 0 and range-1, inclusive. + * B is the smallest number such that range <= 2**B. + * two mechanisms implemented here: + * - generate B bits numbers until one below range is found, and return it + * - find the largest multiple M of range that is <= 2**(B+A), generate B+A + * bits numbers until one below M is found, and return it modulo range + * The second mechanism consumes A more bits of entropy in every iteration, + * but may need fewer iterations due to M being closer to 2**(B+A) then + * range is to 2**B. The array below (indexed by B) contains a 0 when the + * first mechanism is to be used, and the number A otherwise. + */ + 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; - uint32_t ret = range - 1; if (range <= 1) { return 0; } - while (ret > 0) { - ret >>= 1; + trange = range - 1; + while (trange > 0) { + trange >>= 1; bits++; } - while (1) { - ret = secp256k1_rand_bits(bits); - if (ret < range) { - return ret; + if (addbits[bits]) { + bits = bits + addbits[bits]; + mult = ((~((uint32_t)0)) >> (32 - bits)) / range; + trange = range * mult; + } else { + trange = range; + mult = 1; + } + while(1) { + uint32_t x = secp256k1_rand_bits(bits); + if (x < trange) { + return (mult == 1) ? x : (x % range); } } }