summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2019-02-06 12:51:50 -0500
committerNick Mathewson <nickm@torproject.org>2019-02-14 09:26:40 -0500
commit622a9a8a364520f2f1d0294b8d4389f1b29ba376 (patch)
treebcc8bba11f1318c46373dd25447b6ab36c6d733f
parenta49149fc13e8b81e30df17579f19408ae8f4200f (diff)
downloadtor-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.
-rw-r--r--src/lib/crypt_ops/crypto_rand_numeric.c67
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)));
}
/**