Faster secp256k1_rand_int implementation

This commit is contained in:
Pieter Wuille
2015-10-18 03:58:23 +02:00
parent 251b1a62d3
commit f684d7d987

View File

@ -45,19 +45,40 @@ static uint32_t secp256k1_rand_bits(int bits) {
} }
static uint32_t secp256k1_rand_int(uint32_t range) { 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; int bits = 0;
uint32_t ret = range - 1;
if (range <= 1) { if (range <= 1) {
return 0; return 0;
} }
while (ret > 0) { trange = range - 1;
ret >>= 1; while (trange > 0) {
trange >>= 1;
bits++; bits++;
} }
while (1) { if (addbits[bits]) {
ret = secp256k1_rand_bits(bits); bits = bits + addbits[bits];
if (ret < range) { mult = ((~((uint32_t)0)) >> (32 - bits)) / range;
return ret; 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);
} }
} }
} }