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