Faster secp256k1_rand_int implementation

This commit is contained in:
Pieter Wuille 2015-10-18 03:58:23 +02:00
parent 251b1a62d3
commit f684d7d987
1 changed files with 28 additions and 7 deletions

View File

@ -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);
}
}
}