1f9f848faSopenharmony_ci/*	$OpenBSD: arc4random_uniform.c,v 1.3 2019/01/20 02:59:07 bcook Exp $	*/
2f9f848faSopenharmony_ci
3f9f848faSopenharmony_ci/*
4f9f848faSopenharmony_ci * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
5f9f848faSopenharmony_ci *
6f9f848faSopenharmony_ci * Permission to use, copy, modify, and distribute this software for any
7f9f848faSopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
8f9f848faSopenharmony_ci * copyright notice and this permission notice appear in all copies.
9f9f848faSopenharmony_ci *
10f9f848faSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11f9f848faSopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12f9f848faSopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13f9f848faSopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14f9f848faSopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15f9f848faSopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16f9f848faSopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17f9f848faSopenharmony_ci */
18f9f848faSopenharmony_ci
19f9f848faSopenharmony_ci#include <stdint.h>
20f9f848faSopenharmony_ci#include <stdlib.h>
21f9f848faSopenharmony_ci
22f9f848faSopenharmony_ci/*
23f9f848faSopenharmony_ci * Calculate a uniformly distributed random number less than upper_bound
24f9f848faSopenharmony_ci * avoiding "modulo bias".
25f9f848faSopenharmony_ci *
26f9f848faSopenharmony_ci * Uniformity is achieved by generating new random numbers until the one
27f9f848faSopenharmony_ci * returned is outside the range [0, 2**32 % upper_bound).  This
28f9f848faSopenharmony_ci * guarantees the selected random number will be inside
29f9f848faSopenharmony_ci * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
30f9f848faSopenharmony_ci * after reduction modulo upper_bound.
31f9f848faSopenharmony_ci */
32f9f848faSopenharmony_ciuint32_t
33f9f848faSopenharmony_ciarc4random_uniform(uint32_t upper_bound)
34f9f848faSopenharmony_ci{
35f9f848faSopenharmony_ci	uint32_t r, min;
36f9f848faSopenharmony_ci
37f9f848faSopenharmony_ci	if (upper_bound < 2)
38f9f848faSopenharmony_ci		return 0;
39f9f848faSopenharmony_ci
40f9f848faSopenharmony_ci	/* 2**32 % x == (2**32 - x) % x */
41f9f848faSopenharmony_ci	min = -upper_bound % upper_bound;
42f9f848faSopenharmony_ci
43f9f848faSopenharmony_ci	/*
44f9f848faSopenharmony_ci	 * This could theoretically loop forever but each retry has
45f9f848faSopenharmony_ci	 * p > 0.5 (worst case, usually far better) of selecting a
46f9f848faSopenharmony_ci	 * number inside the range we need, so it should rarely need
47f9f848faSopenharmony_ci	 * to re-roll.
48f9f848faSopenharmony_ci	 */
49f9f848faSopenharmony_ci	for (;;) {
50f9f848faSopenharmony_ci		r = arc4random();
51f9f848faSopenharmony_ci		if (r >= min)
52f9f848faSopenharmony_ci			break;
53f9f848faSopenharmony_ci	}
54f9f848faSopenharmony_ci
55f9f848faSopenharmony_ci	return r % upper_bound;
56f9f848faSopenharmony_ci}
57