diff options
author | Nick Mathewson <nickm@torproject.org> | 2019-02-06 12:51:50 -0500 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2019-02-14 09:26:40 -0500 |
commit | 622a9a8a364520f2f1d0294b8d4389f1b29ba376 (patch) | |
tree | bcc8bba11f1318c46373dd25447b6ab36c6d733f /src/lib | |
parent | a49149fc13e8b81e30df17579f19408ae8f4200f (diff) | |
download | tor-622a9a8a364520f2f1d0294b8d4389f1b29ba376.tar.gz tor-622a9a8a364520f2f1d0294b8d4389f1b29ba376.zip |
Extract the common body of our random-int functions into a macro
This is the second part of refactoring the random-int-in-range code.
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/crypt_ops/crypto_rand_numeric.c | 67 |
1 files changed, 40 insertions, 27 deletions
diff --git a/src/lib/crypt_ops/crypto_rand_numeric.c b/src/lib/crypt_ops/crypto_rand_numeric.c index 97fe3bd180..d07657440e 100644 --- a/src/lib/crypt_ops/crypto_rand_numeric.c +++ b/src/lib/crypt_ops/crypto_rand_numeric.c @@ -9,6 +9,39 @@ #include "lib/log/util_bug.h" /** + * Implementation macro: yields code that returns a uniform unbiased + * random number between 0 and limit. "type" is the type of the number to + * return; "maxval" is the largest possible value of "type"; and "fill_stmt" + * is a code snippet that fills an object named "val" with random bits. + **/ +#define IMPLEMENT_RAND_UNSIGNED(type, maxval, limit, fill_stmt) \ + do { \ + type val; \ + type cutoff; \ + tor_assert((limit) > 0); \ + \ + /* We ignore any values that are >= 'cutoff,' to avoid biasing */ \ + /* the distribution with clipping at the upper end of the type's */ \ + /* range. */ \ + cutoff = (maxval) - ((maxval)%(limit)); \ + while (1) { \ + fill_stmt; \ + if (val < cutoff) \ + return val % (limit); \ + } \ + } while (0) + +/** Helper: Return a pseudorandom integer chosen uniformly from the + * values between 0 and limit-1 inclusive. */ +static unsigned +crypto_rand_uint(unsigned limit) +{ + tor_assert(limit < UINT_MAX); + IMPLEMENT_RAND_UNSIGNED(unsigned, UINT_MAX, limit, + crypto_rand((char*)&val, sizeof(val))); +} + +/** * Return a pseudorandom integer, chosen uniformly from the values * between 0 and <b>max</b>-1 inclusive. <b>max</b> must be between 1 and * INT_MAX+1, inclusive. @@ -16,21 +49,13 @@ int crypto_rand_int(unsigned int max) { - unsigned int val; - unsigned int cutoff; + /* We can't use IMPLEMENT_RAND_UNSIGNED directly, since we're trying + * to return a signed type. Instead we make sure that the range is + * reasonable for a nonnegative int, use crypto_rand_uint(), and cast. + */ tor_assert(max <= ((unsigned int)INT_MAX)+1); - tor_assert(max > 0); /* don't div by 0 */ - /* We ignore any values that are >= 'cutoff,' to avoid biasing the - * distribution with clipping at the upper end of unsigned int's - * range. - */ - cutoff = UINT_MAX - (UINT_MAX%max); - while (1) { - crypto_rand((char*)&val, sizeof(val)); - if (val < cutoff) - return val % max; - } + return (int)crypto_rand_uint(max); } /** @@ -78,21 +103,9 @@ crypto_rand_time_range(time_t min, time_t max) uint64_t crypto_rand_uint64(uint64_t max) { - uint64_t val; - uint64_t cutoff; tor_assert(max < UINT64_MAX); - tor_assert(max > 0); /* don't div by 0 */ - - /* We ignore any values that are >= 'cutoff,' to avoid biasing the - * distribution with clipping at the upper end of unsigned int's - * range. - */ - cutoff = UINT64_MAX - (UINT64_MAX%max); - while (1) { - crypto_rand((char*)&val, sizeof(val)); - if (val < cutoff) - return val % max; - } + IMPLEMENT_RAND_UNSIGNED(uint64_t, UINT64_MAX, max, + crypto_rand((char*)&val, sizeof(val))); } /** |