diff --git a/lib/prototypes.h b/lib/prototypes.h index 3a04faa8..722d6d98 100644 --- a/lib/prototypes.h +++ b/lib/prototypes.h @@ -358,6 +358,7 @@ extern void pw_free (/*@out@*/ /*@only@*/struct passwd *pwent); /* csrand.c */ unsigned long csrand (void); +unsigned long csrand_uniform (unsigned long n); /* remove_tree.c */ extern int remove_tree (const char *root, bool remove_root); diff --git a/libmisc/csrand.c b/libmisc/csrand.c index a0237850..0cc99972 100644 --- a/libmisc/csrand.c +++ b/libmisc/csrand.c @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: Alejandro Colomar + * + * SPDX-License-Identifier: BSD-3-Clause + */ + #include #ident "$Id$" @@ -59,3 +65,23 @@ fail: fprintf(log_get_logfd(), _("Unable to obtain random bytes.\n")); exit(1); } + + +/* + * Return a uniformly-distributed CS random value in the interval [0, n-1]. + */ +unsigned long +csrand_uniform(unsigned long n) +{ + 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; +}