1*50696a6eSStefan Eßer /* 2*50696a6eSStefan Eßer * ***************************************************************************** 3*50696a6eSStefan Eßer * 4*50696a6eSStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 5*50696a6eSStefan Eßer * 6*50696a6eSStefan Eßer * Copyright (c) 2018-2019 Gavin D. Howard and contributors. 7*50696a6eSStefan Eßer * 8*50696a6eSStefan Eßer * Redistribution and use in source and binary forms, with or without 9*50696a6eSStefan Eßer * modification, are permitted provided that the following conditions are met: 10*50696a6eSStefan Eßer * 11*50696a6eSStefan Eßer * * Redistributions of source code must retain the above copyright notice, this 12*50696a6eSStefan Eßer * list of conditions and the following disclaimer. 13*50696a6eSStefan Eßer * 14*50696a6eSStefan Eßer * * Redistributions in binary form must reproduce the above copyright notice, 15*50696a6eSStefan Eßer * this list of conditions and the following disclaimer in the documentation 16*50696a6eSStefan Eßer * and/or other materials provided with the distribution. 17*50696a6eSStefan Eßer * 18*50696a6eSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19*50696a6eSStefan Eßer * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*50696a6eSStefan Eßer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*50696a6eSStefan Eßer * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22*50696a6eSStefan Eßer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23*50696a6eSStefan Eßer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24*50696a6eSStefan Eßer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25*50696a6eSStefan Eßer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26*50696a6eSStefan Eßer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27*50696a6eSStefan Eßer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*50696a6eSStefan Eßer * POSSIBILITY OF SUCH DAMAGE. 29*50696a6eSStefan Eßer * 30*50696a6eSStefan Eßer * ***************************************************************************** 31*50696a6eSStefan Eßer * 32*50696a6eSStefan Eßer * Parts of this code are adapted from the following: 33*50696a6eSStefan Eßer * 34*50696a6eSStefan Eßer * PCG, A Family of Better Random Number Generators. 35*50696a6eSStefan Eßer * 36*50696a6eSStefan Eßer * You can find the original source code at: 37*50696a6eSStefan Eßer * https://github.com/imneme/pcg-c 38*50696a6eSStefan Eßer * 39*50696a6eSStefan Eßer * ----------------------------------------------------------------------------- 40*50696a6eSStefan Eßer * 41*50696a6eSStefan Eßer * Parts of this code are also under the following license: 42*50696a6eSStefan Eßer * 43*50696a6eSStefan Eßer * Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors 44*50696a6eSStefan Eßer * 45*50696a6eSStefan Eßer * Permission is hereby granted, free of charge, to any person obtaining a copy 46*50696a6eSStefan Eßer * of this software and associated documentation files (the "Software"), to deal 47*50696a6eSStefan Eßer * in the Software without restriction, including without limitation the rights 48*50696a6eSStefan Eßer * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 49*50696a6eSStefan Eßer * copies of the Software, and to permit persons to whom the Software is 50*50696a6eSStefan Eßer * furnished to do so, subject to the following conditions: 51*50696a6eSStefan Eßer * 52*50696a6eSStefan Eßer * The above copyright notice and this permission notice shall be included in 53*50696a6eSStefan Eßer * all copies or substantial portions of the Software. 54*50696a6eSStefan Eßer * 55*50696a6eSStefan Eßer * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 56*50696a6eSStefan Eßer * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 57*50696a6eSStefan Eßer * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 58*50696a6eSStefan Eßer * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 59*50696a6eSStefan Eßer * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 60*50696a6eSStefan Eßer * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 61*50696a6eSStefan Eßer * SOFTWARE. 62*50696a6eSStefan Eßer * 63*50696a6eSStefan Eßer * ***************************************************************************** 64*50696a6eSStefan Eßer * 65*50696a6eSStefan Eßer * Code for the RNG. 66*50696a6eSStefan Eßer * 67*50696a6eSStefan Eßer */ 68*50696a6eSStefan Eßer 69*50696a6eSStefan Eßer #include <assert.h> 70*50696a6eSStefan Eßer #include <stdlib.h> 71*50696a6eSStefan Eßer #include <string.h> 72*50696a6eSStefan Eßer #include <time.h> 73*50696a6eSStefan Eßer #include <fcntl.h> 74*50696a6eSStefan Eßer #include <unistd.h> 75*50696a6eSStefan Eßer 76*50696a6eSStefan Eßer #include <status.h> 77*50696a6eSStefan Eßer #include <rand.h> 78*50696a6eSStefan Eßer #include <vm.h> 79*50696a6eSStefan Eßer 80*50696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 81*50696a6eSStefan Eßer 82*50696a6eSStefan Eßer #if !BC_RAND_BUILTIN 83*50696a6eSStefan Eßer 84*50696a6eSStefan Eßer static BcRandState bc_rand_addition(uint_fast64_t a, uint_fast64_t b) { 85*50696a6eSStefan Eßer 86*50696a6eSStefan Eßer BcRandState res; 87*50696a6eSStefan Eßer 88*50696a6eSStefan Eßer res.lo = a + b; 89*50696a6eSStefan Eßer res.hi = (res.lo < a); 90*50696a6eSStefan Eßer 91*50696a6eSStefan Eßer return res; 92*50696a6eSStefan Eßer } 93*50696a6eSStefan Eßer 94*50696a6eSStefan Eßer static BcRandState bc_rand_addition2(BcRandState a, BcRandState b) { 95*50696a6eSStefan Eßer 96*50696a6eSStefan Eßer BcRandState temp, res; 97*50696a6eSStefan Eßer 98*50696a6eSStefan Eßer res = bc_rand_addition(a.lo, b.lo); 99*50696a6eSStefan Eßer temp = bc_rand_addition(a.hi, b.hi); 100*50696a6eSStefan Eßer res.hi += temp.lo; 101*50696a6eSStefan Eßer 102*50696a6eSStefan Eßer return res; 103*50696a6eSStefan Eßer } 104*50696a6eSStefan Eßer 105*50696a6eSStefan Eßer static BcRandState bc_rand_multiply(uint_fast64_t a, uint_fast64_t b) { 106*50696a6eSStefan Eßer 107*50696a6eSStefan Eßer uint_fast64_t al, ah, bl, bh, c0, c1, c2, c3; 108*50696a6eSStefan Eßer BcRandState carry, res; 109*50696a6eSStefan Eßer 110*50696a6eSStefan Eßer al = BC_RAND_TRUNC32(a); 111*50696a6eSStefan Eßer ah = BC_RAND_CHOP32(a); 112*50696a6eSStefan Eßer bl = BC_RAND_TRUNC32(b); 113*50696a6eSStefan Eßer bh = BC_RAND_CHOP32(b); 114*50696a6eSStefan Eßer 115*50696a6eSStefan Eßer c0 = al * bl; 116*50696a6eSStefan Eßer c1 = al * bh; 117*50696a6eSStefan Eßer c2 = ah * bl; 118*50696a6eSStefan Eßer c3 = ah * bh; 119*50696a6eSStefan Eßer 120*50696a6eSStefan Eßer carry = bc_rand_addition(c1, c2); 121*50696a6eSStefan Eßer 122*50696a6eSStefan Eßer res = bc_rand_addition(c0, (BC_RAND_TRUNC32(carry.lo)) << 32); 123*50696a6eSStefan Eßer res.hi += BC_RAND_CHOP32(carry.lo) + c3 + (carry.hi << 32); 124*50696a6eSStefan Eßer 125*50696a6eSStefan Eßer return res; 126*50696a6eSStefan Eßer } 127*50696a6eSStefan Eßer 128*50696a6eSStefan Eßer static BcRandState bc_rand_multiply2(BcRandState a, BcRandState b) { 129*50696a6eSStefan Eßer 130*50696a6eSStefan Eßer BcRandState c0, c1, c2, carry; 131*50696a6eSStefan Eßer 132*50696a6eSStefan Eßer c0 = bc_rand_multiply(a.lo, b.lo); 133*50696a6eSStefan Eßer c1 = bc_rand_multiply(a.lo, b.hi); 134*50696a6eSStefan Eßer c2 = bc_rand_multiply(a.hi, b.lo); 135*50696a6eSStefan Eßer 136*50696a6eSStefan Eßer carry = bc_rand_addition2(c1, c2); 137*50696a6eSStefan Eßer carry.hi = carry.lo; 138*50696a6eSStefan Eßer carry.lo = 0; 139*50696a6eSStefan Eßer 140*50696a6eSStefan Eßer return bc_rand_addition2(c0, carry); 141*50696a6eSStefan Eßer } 142*50696a6eSStefan Eßer 143*50696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 144*50696a6eSStefan Eßer 145*50696a6eSStefan Eßer static void bc_rand_setModified(BcRNGData *r) { 146*50696a6eSStefan Eßer 147*50696a6eSStefan Eßer #if BC_RAND_BUILTIN 148*50696a6eSStefan Eßer r->inc |= (BcRandState) 1UL; 149*50696a6eSStefan Eßer #else // BC_RAND_BUILTIN 150*50696a6eSStefan Eßer r->inc.lo |= (uint_fast64_t) 1UL; 151*50696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 152*50696a6eSStefan Eßer } 153*50696a6eSStefan Eßer 154*50696a6eSStefan Eßer static void bc_rand_clearModified(BcRNGData *r) { 155*50696a6eSStefan Eßer 156*50696a6eSStefan Eßer #if BC_RAND_BUILTIN 157*50696a6eSStefan Eßer r->inc &= ~((BcRandState) 1UL); 158*50696a6eSStefan Eßer #else // BC_RAND_BUILTIN 159*50696a6eSStefan Eßer r->inc.lo &= ~(1UL); 160*50696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 161*50696a6eSStefan Eßer } 162*50696a6eSStefan Eßer 163*50696a6eSStefan Eßer static void bc_rand_copy(BcRNGData *d, BcRNGData *s) { 164*50696a6eSStefan Eßer bool unmod = BC_RAND_NOTMODIFIED(d); 165*50696a6eSStefan Eßer memcpy(d, s, sizeof(BcRNGData)); 166*50696a6eSStefan Eßer if (!unmod) bc_rand_setModified(d); 167*50696a6eSStefan Eßer else if (!BC_RAND_NOTMODIFIED(s)) bc_rand_clearModified(d); 168*50696a6eSStefan Eßer } 169*50696a6eSStefan Eßer 170*50696a6eSStefan Eßer static ulong bc_rand_frand(void *ptr) { 171*50696a6eSStefan Eßer 172*50696a6eSStefan Eßer ulong buf[1]; 173*50696a6eSStefan Eßer int fd; 174*50696a6eSStefan Eßer ssize_t nread; 175*50696a6eSStefan Eßer 176*50696a6eSStefan Eßer assert(ptr != NULL); 177*50696a6eSStefan Eßer 178*50696a6eSStefan Eßer fd = *((int*) ptr); 179*50696a6eSStefan Eßer 180*50696a6eSStefan Eßer nread = read(fd, buf, sizeof(ulong)); 181*50696a6eSStefan Eßer 182*50696a6eSStefan Eßer if (BC_ERR(nread != sizeof(ulong))) bc_vm_err(BC_ERR_FATAL_IO_ERR); 183*50696a6eSStefan Eßer 184*50696a6eSStefan Eßer return *((ulong*) buf); 185*50696a6eSStefan Eßer } 186*50696a6eSStefan Eßer 187*50696a6eSStefan Eßer static ulong bc_rand_rand(void *ptr) { 188*50696a6eSStefan Eßer 189*50696a6eSStefan Eßer size_t i; 190*50696a6eSStefan Eßer ulong res = 0; 191*50696a6eSStefan Eßer 192*50696a6eSStefan Eßer BC_UNUSED(ptr); 193*50696a6eSStefan Eßer 194*50696a6eSStefan Eßer for (i = 0; i < sizeof(ulong); ++i) 195*50696a6eSStefan Eßer res |= ((ulong) (rand() & BC_RAND_SRAND_BITS)) << (i * CHAR_BIT); 196*50696a6eSStefan Eßer 197*50696a6eSStefan Eßer return res; 198*50696a6eSStefan Eßer } 199*50696a6eSStefan Eßer 200*50696a6eSStefan Eßer static BcRandState bc_rand_inc(BcRNGData *r) { 201*50696a6eSStefan Eßer 202*50696a6eSStefan Eßer BcRandState inc; 203*50696a6eSStefan Eßer 204*50696a6eSStefan Eßer #if BC_RAND_BUILTIN 205*50696a6eSStefan Eßer inc = r->inc | 1; 206*50696a6eSStefan Eßer #else // BC_RAND_BUILTIN 207*50696a6eSStefan Eßer inc.lo = r->inc.lo | 1; 208*50696a6eSStefan Eßer inc.hi = r->inc.hi; 209*50696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 210*50696a6eSStefan Eßer 211*50696a6eSStefan Eßer return inc; 212*50696a6eSStefan Eßer } 213*50696a6eSStefan Eßer 214*50696a6eSStefan Eßer static void bc_rand_setInc(BcRNGData *r) { 215*50696a6eSStefan Eßer 216*50696a6eSStefan Eßer #if BC_RAND_BUILTIN 217*50696a6eSStefan Eßer r->inc <<= 1UL; 218*50696a6eSStefan Eßer #else // BC_RAND_BUILTIN 219*50696a6eSStefan Eßer r->inc.hi <<= 1UL; 220*50696a6eSStefan Eßer r->inc.hi |= (r->inc.lo & (1UL << (BC_LONG_BIT - 1))) >> (BC_LONG_BIT - 1); 221*50696a6eSStefan Eßer r->inc.lo <<= 1UL; 222*50696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 223*50696a6eSStefan Eßer } 224*50696a6eSStefan Eßer 225*50696a6eSStefan Eßer static void bc_rand_seedState(BcRandState *state, ulong val1, ulong val2) { 226*50696a6eSStefan Eßer 227*50696a6eSStefan Eßer #if BC_RAND_BUILTIN 228*50696a6eSStefan Eßer *state = ((BcRandState) val1) | ((BcRandState) val2) << (BC_LONG_BIT); 229*50696a6eSStefan Eßer #else // BC_RAND_BUILTIN 230*50696a6eSStefan Eßer state->lo = val1; 231*50696a6eSStefan Eßer state->hi = val2; 232*50696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 233*50696a6eSStefan Eßer } 234*50696a6eSStefan Eßer 235*50696a6eSStefan Eßer static void bc_rand_seedRNG(BcRNGData *r, ulong state1, ulong state2, 236*50696a6eSStefan Eßer ulong inc1, ulong inc2) 237*50696a6eSStefan Eßer { 238*50696a6eSStefan Eßer bc_rand_seedState(&r->state, state1, state2); 239*50696a6eSStefan Eßer bc_rand_seedState(&r->inc, inc1, inc2); 240*50696a6eSStefan Eßer bc_rand_setInc(r); 241*50696a6eSStefan Eßer } 242*50696a6eSStefan Eßer 243*50696a6eSStefan Eßer static void bc_rand_fill(BcRNGData *r, BcRandUlong fulong, void *ptr) { 244*50696a6eSStefan Eßer 245*50696a6eSStefan Eßer ulong state1, state2, inc1, inc2; 246*50696a6eSStefan Eßer 247*50696a6eSStefan Eßer state1 = fulong(ptr); 248*50696a6eSStefan Eßer state2 = fulong(ptr); 249*50696a6eSStefan Eßer 250*50696a6eSStefan Eßer inc1 = fulong(ptr); 251*50696a6eSStefan Eßer inc2 = fulong(ptr); 252*50696a6eSStefan Eßer 253*50696a6eSStefan Eßer bc_rand_seedRNG(r, state1, state2, inc1, inc2); 254*50696a6eSStefan Eßer } 255*50696a6eSStefan Eßer 256*50696a6eSStefan Eßer static void bc_rand_step(BcRNGData *r) { 257*50696a6eSStefan Eßer BcRandState temp = bc_rand_mul2(r->state, bc_rand_multiplier); 258*50696a6eSStefan Eßer r->state = bc_rand_add2(temp, bc_rand_inc(r)); 259*50696a6eSStefan Eßer } 260*50696a6eSStefan Eßer 261*50696a6eSStefan Eßer static BcRand bc_rand_output(BcRNGData *r) { 262*50696a6eSStefan Eßer return BC_RAND_ROT(BC_RAND_FOLD(r->state), BC_RAND_ROTAMT(r->state)); 263*50696a6eSStefan Eßer } 264*50696a6eSStefan Eßer 265*50696a6eSStefan Eßer static void bc_rand_seedZeroes(BcRNG *r, BcRNGData *rng, size_t idx) { 266*50696a6eSStefan Eßer 267*50696a6eSStefan Eßer BcRNGData *rng2; 268*50696a6eSStefan Eßer 269*50696a6eSStefan Eßer if (r->v.len <= idx) return; 270*50696a6eSStefan Eßer 271*50696a6eSStefan Eßer rng2 = bc_vec_item_rev(&r->v, idx); 272*50696a6eSStefan Eßer 273*50696a6eSStefan Eßer if (BC_RAND_ZERO(rng2)) { 274*50696a6eSStefan Eßer size_t i; 275*50696a6eSStefan Eßer for (i = 1; i < r->v.len; ++i) 276*50696a6eSStefan Eßer bc_rand_copy(bc_vec_item_rev(&r->v, i), rng); 277*50696a6eSStefan Eßer } 278*50696a6eSStefan Eßer } 279*50696a6eSStefan Eßer 280*50696a6eSStefan Eßer void bc_rand_srand(BcRNGData *rng) { 281*50696a6eSStefan Eßer 282*50696a6eSStefan Eßer int fd; 283*50696a6eSStefan Eßer 284*50696a6eSStefan Eßer BC_SIG_LOCK; 285*50696a6eSStefan Eßer 286*50696a6eSStefan Eßer fd = open("/dev/urandom", O_RDONLY); 287*50696a6eSStefan Eßer 288*50696a6eSStefan Eßer if (BC_NO_ERR(fd >= 0)) { 289*50696a6eSStefan Eßer bc_rand_fill(rng, bc_rand_frand, &fd); 290*50696a6eSStefan Eßer close(fd); 291*50696a6eSStefan Eßer } 292*50696a6eSStefan Eßer 293*50696a6eSStefan Eßer while (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_fill(rng, bc_rand_rand, NULL); 294*50696a6eSStefan Eßer 295*50696a6eSStefan Eßer BC_SIG_UNLOCK; 296*50696a6eSStefan Eßer } 297*50696a6eSStefan Eßer 298*50696a6eSStefan Eßer static void bc_rand_propagate(BcRNG *r, BcRNGData *rng) { 299*50696a6eSStefan Eßer 300*50696a6eSStefan Eßer if (r->v.len <= 1) return; 301*50696a6eSStefan Eßer 302*50696a6eSStefan Eßer if (BC_RAND_NOTMODIFIED(rng)) { 303*50696a6eSStefan Eßer 304*50696a6eSStefan Eßer size_t i; 305*50696a6eSStefan Eßer bool go = true; 306*50696a6eSStefan Eßer 307*50696a6eSStefan Eßer for (i = 1; go && i < r->v.len; ++i) { 308*50696a6eSStefan Eßer BcRNGData *rng2 = bc_vec_item_rev(&r->v, i); 309*50696a6eSStefan Eßer go = BC_RAND_NOTMODIFIED(rng2); 310*50696a6eSStefan Eßer bc_rand_copy(rng2, rng); 311*50696a6eSStefan Eßer } 312*50696a6eSStefan Eßer 313*50696a6eSStefan Eßer bc_rand_seedZeroes(r, rng, i); 314*50696a6eSStefan Eßer } 315*50696a6eSStefan Eßer else bc_rand_seedZeroes(r, rng, 1); 316*50696a6eSStefan Eßer } 317*50696a6eSStefan Eßer 318*50696a6eSStefan Eßer BcRand bc_rand_int(BcRNG *r) { 319*50696a6eSStefan Eßer 320*50696a6eSStefan Eßer BcRNGData *rng = bc_vec_top(&r->v); 321*50696a6eSStefan Eßer 322*50696a6eSStefan Eßer if (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_srand(rng); 323*50696a6eSStefan Eßer 324*50696a6eSStefan Eßer bc_rand_step(rng); 325*50696a6eSStefan Eßer bc_rand_propagate(r, rng); 326*50696a6eSStefan Eßer 327*50696a6eSStefan Eßer return bc_rand_output(rng); 328*50696a6eSStefan Eßer } 329*50696a6eSStefan Eßer 330*50696a6eSStefan Eßer BcRand bc_rand_bounded(BcRNG *r, BcRand bound) { 331*50696a6eSStefan Eßer 332*50696a6eSStefan Eßer BcRand rand, threshold = (0 - bound) % bound; 333*50696a6eSStefan Eßer 334*50696a6eSStefan Eßer do { 335*50696a6eSStefan Eßer rand = bc_rand_int(r); 336*50696a6eSStefan Eßer } while (rand < threshold); 337*50696a6eSStefan Eßer 338*50696a6eSStefan Eßer return rand % bound; 339*50696a6eSStefan Eßer } 340*50696a6eSStefan Eßer 341*50696a6eSStefan Eßer void bc_rand_seed(BcRNG *r, ulong state1, ulong state2, ulong inc1, ulong inc2) 342*50696a6eSStefan Eßer { 343*50696a6eSStefan Eßer BcRNGData *rng = bc_vec_top(&r->v); 344*50696a6eSStefan Eßer 345*50696a6eSStefan Eßer bc_rand_seedState(&rng->inc, inc1, inc2); 346*50696a6eSStefan Eßer bc_rand_setInc(rng); 347*50696a6eSStefan Eßer bc_rand_setModified(rng); 348*50696a6eSStefan Eßer 349*50696a6eSStefan Eßer if (!state1 && !state2) { 350*50696a6eSStefan Eßer memcpy(&rng->state, &rng->inc, sizeof(BcRandState)); 351*50696a6eSStefan Eßer bc_rand_step(rng); 352*50696a6eSStefan Eßer } 353*50696a6eSStefan Eßer else bc_rand_seedState(&rng->state, state1, state2); 354*50696a6eSStefan Eßer 355*50696a6eSStefan Eßer bc_rand_propagate(r, rng); 356*50696a6eSStefan Eßer } 357*50696a6eSStefan Eßer 358*50696a6eSStefan Eßer static BcRandState bc_rand_getInc(BcRNGData *r) { 359*50696a6eSStefan Eßer 360*50696a6eSStefan Eßer BcRandState res; 361*50696a6eSStefan Eßer 362*50696a6eSStefan Eßer #if BC_RAND_BUILTIN 363*50696a6eSStefan Eßer res = r->inc >> 1; 364*50696a6eSStefan Eßer #else // BC_RAND_BUILTIN 365*50696a6eSStefan Eßer res = r->inc; 366*50696a6eSStefan Eßer res.lo >>= 1; 367*50696a6eSStefan Eßer res.lo |= (res.hi & 1) << (BC_LONG_BIT - 1); 368*50696a6eSStefan Eßer res.hi >>= 1; 369*50696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 370*50696a6eSStefan Eßer 371*50696a6eSStefan Eßer return res; 372*50696a6eSStefan Eßer } 373*50696a6eSStefan Eßer 374*50696a6eSStefan Eßer void bc_rand_getRands(BcRNG *r, BcRand *s1, BcRand *s2, BcRand *i1, BcRand *i2) 375*50696a6eSStefan Eßer { 376*50696a6eSStefan Eßer BcRandState inc; 377*50696a6eSStefan Eßer BcRNGData *rng = bc_vec_top(&r->v); 378*50696a6eSStefan Eßer 379*50696a6eSStefan Eßer if (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_srand(rng); 380*50696a6eSStefan Eßer 381*50696a6eSStefan Eßer inc = bc_rand_getInc(rng); 382*50696a6eSStefan Eßer 383*50696a6eSStefan Eßer *s1 = BC_RAND_TRUNC(rng->state); 384*50696a6eSStefan Eßer *s2 = BC_RAND_CHOP(rng->state); 385*50696a6eSStefan Eßer 386*50696a6eSStefan Eßer *i1 = BC_RAND_TRUNC(inc); 387*50696a6eSStefan Eßer *i2 = BC_RAND_CHOP(inc); 388*50696a6eSStefan Eßer } 389*50696a6eSStefan Eßer 390*50696a6eSStefan Eßer void bc_rand_push(BcRNG *r) { 391*50696a6eSStefan Eßer BcRNGData rng; 392*50696a6eSStefan Eßer memset(&rng, 0, sizeof(BcRNGData)); 393*50696a6eSStefan Eßer if (r->v.len > 0) bc_rand_copy(&rng, bc_vec_top(&r->v)); 394*50696a6eSStefan Eßer bc_vec_push(&r->v, &rng); 395*50696a6eSStefan Eßer } 396*50696a6eSStefan Eßer 397*50696a6eSStefan Eßer void bc_rand_pop(BcRNG *r, bool reset) { 398*50696a6eSStefan Eßer bc_vec_npop(&r->v, reset ? r->v.len - 1 : 1); 399*50696a6eSStefan Eßer } 400*50696a6eSStefan Eßer 401*50696a6eSStefan Eßer void bc_rand_init(BcRNG *r) { 402*50696a6eSStefan Eßer BC_SIG_ASSERT_LOCKED; 403*50696a6eSStefan Eßer bc_vec_init(&r->v, sizeof(BcRNGData), NULL); 404*50696a6eSStefan Eßer bc_rand_push(r); 405*50696a6eSStefan Eßer } 406*50696a6eSStefan Eßer 407*50696a6eSStefan Eßer #ifndef NDEBUG 408*50696a6eSStefan Eßer void bc_rand_free(BcRNG *r) { 409*50696a6eSStefan Eßer BC_SIG_ASSERT_LOCKED; 410*50696a6eSStefan Eßer bc_vec_free(&r->v); 411*50696a6eSStefan Eßer } 412*50696a6eSStefan Eßer #endif // NDEBUG 413*50696a6eSStefan Eßer 414*50696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND 415