Add csrand_uniform()
This API is similar to arc4random_uniform(3). However, for an input of
0, this function is equivalent to csrand(), while arc4random_uniform(0)
returns 0.
This function will be used to reimplement csrand_interval() as a wrapper
around this one.
The current implementation of csrand_interval() doesn't produce very good
random numbers. It has a bias. And that comes from performing some
unnecessary floating-point calculations that overcomplicate the problem.
Looping until the random number hits within bounds is unbiased, and
truncating unwanted bits makes the overhead of the loop very small.
We could reduce loop overhead even more, by keeping unused bits of the
random number, if the width of the mask is not greater than
ULONG_WIDTH/2, however, that complicates the code considerably, and I
prefer to be a bit slower but have simple code.
BTW, Björn really deserves the copyright for csrand() (previously known
as read_random_bytes()), since he rewrote it almost from scratch last
year, and I kept most of its contents. Since he didn't put himself in
the copyright back then, and BSD-3-Clause doesn't allow me to attribute
derived works, I won't add his name, but if he asks, he should be put in
the copyright too.
Cc: "Jason A. Donenfeld" <Jason@zx2c4.com>
Cc: Cristian Rodríguez <crrodriguez@opensuse.org>
Cc: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Cc: Björn Esser <besser82@fedoraproject.org>
Cc: Yann Droneaud <ydroneaud@opteya.com>
Cc: Joseph Myers <joseph@codesourcery.com>
Cc: Sam James <sam@gentoo.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2022-12-31 00:16:09 +05:30
|
|
|
/*
|
|
|
|
* SPDX-FileCopyrightText: Alejandro Colomar <alx@kernel.org>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
*/
|
|
|
|
|
2022-12-31 00:16:09 +05:30
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#ident "$Id$"
|
|
|
|
|
|
|
|
#include <limits.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#if HAVE_SYS_RANDOM_H
|
|
|
|
#include <sys/random.h>
|
|
|
|
#endif
|
|
|
|
#include "bit.h"
|
|
|
|
#include "prototypes.h"
|
|
|
|
#include "shadowlog.h"
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return a uniformly-distributed CS random u_long value.
|
|
|
|
*/
|
|
|
|
unsigned long
|
|
|
|
csrand(void)
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
unsigned long r;
|
|
|
|
|
|
|
|
#ifdef HAVE_GETENTROPY
|
|
|
|
/* getentropy may exist but lack kernel support. */
|
|
|
|
if (getentropy(&r, sizeof(r)) == 0)
|
|
|
|
return r;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_GETRANDOM
|
|
|
|
/* Likewise getrandom. */
|
|
|
|
if (getrandom(&r, sizeof(r), 0) == sizeof(r))
|
|
|
|
return r;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_ARC4RANDOM_BUF
|
|
|
|
/* arc4random_buf can never fail. */
|
|
|
|
arc4random_buf(&r, sizeof(r));
|
|
|
|
return r;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Use /dev/urandom as a last resort. */
|
|
|
|
fp = fopen("/dev/urandom", "r");
|
|
|
|
if (NULL == fp) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fread(&r, sizeof(r), 1, fp) != 1) {
|
|
|
|
fclose(fp);
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
return r;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
fprintf(log_get_logfd(), _("Unable to obtain random bytes.\n"));
|
|
|
|
exit(1);
|
|
|
|
}
|
Add csrand_uniform()
This API is similar to arc4random_uniform(3). However, for an input of
0, this function is equivalent to csrand(), while arc4random_uniform(0)
returns 0.
This function will be used to reimplement csrand_interval() as a wrapper
around this one.
The current implementation of csrand_interval() doesn't produce very good
random numbers. It has a bias. And that comes from performing some
unnecessary floating-point calculations that overcomplicate the problem.
Looping until the random number hits within bounds is unbiased, and
truncating unwanted bits makes the overhead of the loop very small.
We could reduce loop overhead even more, by keeping unused bits of the
random number, if the width of the mask is not greater than
ULONG_WIDTH/2, however, that complicates the code considerably, and I
prefer to be a bit slower but have simple code.
BTW, Björn really deserves the copyright for csrand() (previously known
as read_random_bytes()), since he rewrote it almost from scratch last
year, and I kept most of its contents. Since he didn't put himself in
the copyright back then, and BSD-3-Clause doesn't allow me to attribute
derived works, I won't add his name, but if he asks, he should be put in
the copyright too.
Cc: "Jason A. Donenfeld" <Jason@zx2c4.com>
Cc: Cristian Rodríguez <crrodriguez@opensuse.org>
Cc: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Cc: Björn Esser <besser82@fedoraproject.org>
Cc: Yann Droneaud <ydroneaud@opteya.com>
Cc: Joseph Myers <joseph@codesourcery.com>
Cc: Sam James <sam@gentoo.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2022-12-31 00:16:09 +05:30
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
2022-12-31 00:16:09 +05:30
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|