From 2a61122b5e8f89484dcc88dfd5f6c11de2d8c95a Mon Sep 17 00:00:00 2001 From: Alejandro Colomar Date: Mon, 30 Jan 2023 13:13:36 +0100 Subject: [PATCH] Unoptimize the higher part of the domain of csrand_uniform() __int128, which is needed for optimizing that part of the range, is not always available. We need the unoptimized version for portability reasons. Closes: Fixes: 1a0e13f94edc ("Optimize csrand_uniform()") Reported-by: Adam Sampson Cc: Iker Pedrosa Signed-off-by: Alejandro Colomar --- libmisc/csrand.c | 58 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/libmisc/csrand.c b/libmisc/csrand.c index d4dabe54..2557fac8 100644 --- a/libmisc/csrand.c +++ b/libmisc/csrand.c @@ -9,17 +9,23 @@ #ident "$Id$" #include +#include #include #include #include #if HAVE_SYS_RANDOM_H #include #endif +#include "bit.h" #include "defines.h" #include "prototypes.h" #include "shadowlog.h" +static uint32_t csrand_uniform32(uint32_t n); +static unsigned long csrand_uniform_slow(unsigned long n); + + /* * Return a uniformly-distributed CS random u_long value. */ @@ -69,16 +75,37 @@ fail: /* * Return a uniformly-distributed CS random value in the interval [0, n-1]. - * - * Fast Random Integer Generation in an Interval - * ACM Transactions on Modeling and Computer Simulation 29 (1), 2019 - * */ unsigned long csrand_uniform(unsigned long n) { - unsigned long bound, rem; - unsigned __int128 r, mult; + if (n == 0 || n > UINT32_MAX) + return csrand_uniform_slow(n); + + return csrand_uniform32(n); +} + + +/* + * Return a uniformly-distributed CS random value in the interval [min, max]. + */ +unsigned long +csrand_interval(unsigned long min, unsigned long max) +{ + return csrand_uniform(max - min + 1) + min; +} + + +/* + * Fast Random Integer Generation in an Interval + * ACM Transactions on Modeling and Computer Simulation 29 (1), 2019 + * + */ +static uint32_t +csrand_uniform32(uint32_t n) +{ + uint32_t bound, rem; + uint64_t r, mult; if (n == 0) return csrand(); @@ -97,11 +124,18 @@ csrand_uniform(unsigned long n) } -/* - * Return a uniformly-distributed CS random value in the interval [min, max]. - */ -unsigned long -csrand_interval(unsigned long min, unsigned long max) +static unsigned long +csrand_uniform_slow(unsigned long n) { - return csrand_uniform(max - min + 1) + min; + unsigned long r, max, mask; + + max = n - 1; + mask = bit_ceil_wrapul(n) - 1; + + do { + r = csrand(); + r &= mask; // optimization + } while (r > max); // p = ((mask+1) % n) / (mask+1); W.C.: p=0.5 + + return r; }