150696a6eSStefan Eßer /* 250696a6eSStefan Eßer * ***************************************************************************** 350696a6eSStefan Eßer * 450696a6eSStefan Eßer * Parts of this code are adapted from the following: 550696a6eSStefan Eßer * 650696a6eSStefan Eßer * PCG, A Family of Better Random Number Generators. 750696a6eSStefan Eßer * 850696a6eSStefan Eßer * You can find the original source code at: 950696a6eSStefan Eßer * https://github.com/imneme/pcg-c 1050696a6eSStefan Eßer * 1150696a6eSStefan Eßer * ----------------------------------------------------------------------------- 1250696a6eSStefan Eßer * 1310328f8bSStefan Eßer * This code is under the following license: 1450696a6eSStefan Eßer * 1550696a6eSStefan Eßer * Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors 1610328f8bSStefan Eßer * Copyright (c) 2018-2021 Gavin D. Howard and contributors. 1750696a6eSStefan Eßer * 1850696a6eSStefan Eßer * Permission is hereby granted, free of charge, to any person obtaining a copy 1950696a6eSStefan Eßer * of this software and associated documentation files (the "Software"), to deal 2050696a6eSStefan Eßer * in the Software without restriction, including without limitation the rights 2150696a6eSStefan Eßer * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 2250696a6eSStefan Eßer * copies of the Software, and to permit persons to whom the Software is 2350696a6eSStefan Eßer * furnished to do so, subject to the following conditions: 2450696a6eSStefan Eßer * 2550696a6eSStefan Eßer * The above copyright notice and this permission notice shall be included in 2650696a6eSStefan Eßer * all copies or substantial portions of the Software. 2750696a6eSStefan Eßer * 2850696a6eSStefan Eßer * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2950696a6eSStefan Eßer * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 3050696a6eSStefan Eßer * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 3150696a6eSStefan Eßer * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 3250696a6eSStefan Eßer * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 3350696a6eSStefan Eßer * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3450696a6eSStefan Eßer * SOFTWARE. 3550696a6eSStefan Eßer * 3650696a6eSStefan Eßer * ***************************************************************************** 3750696a6eSStefan Eßer * 3850696a6eSStefan Eßer * Code for the RNG. 3950696a6eSStefan Eßer * 4050696a6eSStefan Eßer */ 4150696a6eSStefan Eßer 4250696a6eSStefan Eßer #include <assert.h> 4350696a6eSStefan Eßer #include <stdlib.h> 4450696a6eSStefan Eßer #include <string.h> 4550696a6eSStefan Eßer #include <time.h> 4650696a6eSStefan Eßer #include <fcntl.h> 477e5c51e5SStefan Eßer 487e5c51e5SStefan Eßer #ifndef _WIN32 4950696a6eSStefan Eßer #include <unistd.h> 507e5c51e5SStefan Eßer #else // _WIN32 517e5c51e5SStefan Eßer #include <Windows.h> 527e5c51e5SStefan Eßer #include <bcrypt.h> 537e5c51e5SStefan Eßer #endif // _WIN32 5450696a6eSStefan Eßer 5550696a6eSStefan Eßer #include <status.h> 5650696a6eSStefan Eßer #include <rand.h> 5750696a6eSStefan Eßer #include <vm.h> 5850696a6eSStefan Eßer 5944d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH 6050696a6eSStefan Eßer 6150696a6eSStefan Eßer #if !BC_RAND_BUILTIN 6250696a6eSStefan Eßer 6344d4804dSStefan Eßer /** 6444d4804dSStefan Eßer * Adds two 64-bit values and preserves the overflow. 6544d4804dSStefan Eßer * @param a The first operand. 6644d4804dSStefan Eßer * @param b The second operand. 6744d4804dSStefan Eßer * @return The sum, including overflow. 6844d4804dSStefan Eßer */ 6950696a6eSStefan Eßer static BcRandState bc_rand_addition(uint_fast64_t a, uint_fast64_t b) { 7050696a6eSStefan Eßer 7150696a6eSStefan Eßer BcRandState res; 7250696a6eSStefan Eßer 7350696a6eSStefan Eßer res.lo = a + b; 7450696a6eSStefan Eßer res.hi = (res.lo < a); 7550696a6eSStefan Eßer 7650696a6eSStefan Eßer return res; 7750696a6eSStefan Eßer } 7850696a6eSStefan Eßer 7944d4804dSStefan Eßer /** 8044d4804dSStefan Eßer * Adds two 128-bit values and discards the overflow. 8144d4804dSStefan Eßer * @param a The first operand. 8244d4804dSStefan Eßer * @param b The second operand. 8344d4804dSStefan Eßer * @return The sum, without overflow. 8444d4804dSStefan Eßer */ 8550696a6eSStefan Eßer static BcRandState bc_rand_addition2(BcRandState a, BcRandState b) { 8650696a6eSStefan Eßer 8750696a6eSStefan Eßer BcRandState temp, res; 8850696a6eSStefan Eßer 8950696a6eSStefan Eßer res = bc_rand_addition(a.lo, b.lo); 9050696a6eSStefan Eßer temp = bc_rand_addition(a.hi, b.hi); 9150696a6eSStefan Eßer res.hi += temp.lo; 9250696a6eSStefan Eßer 9350696a6eSStefan Eßer return res; 9450696a6eSStefan Eßer } 9550696a6eSStefan Eßer 9644d4804dSStefan Eßer /** 9744d4804dSStefan Eßer * Multiplies two 64-bit values and preserves the overflow. 9844d4804dSStefan Eßer * @param a The first operand. 9944d4804dSStefan Eßer * @param b The second operand. 10044d4804dSStefan Eßer * @return The product, including overflow. 10144d4804dSStefan Eßer */ 10250696a6eSStefan Eßer static BcRandState bc_rand_multiply(uint_fast64_t a, uint_fast64_t b) { 10350696a6eSStefan Eßer 10450696a6eSStefan Eßer uint_fast64_t al, ah, bl, bh, c0, c1, c2, c3; 10550696a6eSStefan Eßer BcRandState carry, res; 10650696a6eSStefan Eßer 10750696a6eSStefan Eßer al = BC_RAND_TRUNC32(a); 10850696a6eSStefan Eßer ah = BC_RAND_CHOP32(a); 10950696a6eSStefan Eßer bl = BC_RAND_TRUNC32(b); 11050696a6eSStefan Eßer bh = BC_RAND_CHOP32(b); 11150696a6eSStefan Eßer 11250696a6eSStefan Eßer c0 = al * bl; 11350696a6eSStefan Eßer c1 = al * bh; 11450696a6eSStefan Eßer c2 = ah * bl; 11550696a6eSStefan Eßer c3 = ah * bh; 11650696a6eSStefan Eßer 11750696a6eSStefan Eßer carry = bc_rand_addition(c1, c2); 11850696a6eSStefan Eßer 11950696a6eSStefan Eßer res = bc_rand_addition(c0, (BC_RAND_TRUNC32(carry.lo)) << 32); 12050696a6eSStefan Eßer res.hi += BC_RAND_CHOP32(carry.lo) + c3 + (carry.hi << 32); 12150696a6eSStefan Eßer 12250696a6eSStefan Eßer return res; 12350696a6eSStefan Eßer } 12450696a6eSStefan Eßer 12544d4804dSStefan Eßer /** 12644d4804dSStefan Eßer * Multiplies two 128-bit values and discards the overflow. 12744d4804dSStefan Eßer * @param a The first operand. 12844d4804dSStefan Eßer * @param b The second operand. 12944d4804dSStefan Eßer * @return The product, without overflow. 13044d4804dSStefan Eßer */ 13150696a6eSStefan Eßer static BcRandState bc_rand_multiply2(BcRandState a, BcRandState b) { 13250696a6eSStefan Eßer 13350696a6eSStefan Eßer BcRandState c0, c1, c2, carry; 13450696a6eSStefan Eßer 13550696a6eSStefan Eßer c0 = bc_rand_multiply(a.lo, b.lo); 13650696a6eSStefan Eßer c1 = bc_rand_multiply(a.lo, b.hi); 13750696a6eSStefan Eßer c2 = bc_rand_multiply(a.hi, b.lo); 13850696a6eSStefan Eßer 13950696a6eSStefan Eßer carry = bc_rand_addition2(c1, c2); 14050696a6eSStefan Eßer carry.hi = carry.lo; 14150696a6eSStefan Eßer carry.lo = 0; 14250696a6eSStefan Eßer 14350696a6eSStefan Eßer return bc_rand_addition2(c0, carry); 14450696a6eSStefan Eßer } 14550696a6eSStefan Eßer 14650696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 14750696a6eSStefan Eßer 14844d4804dSStefan Eßer /** 14944d4804dSStefan Eßer * Marks a PRNG as modified. This is important for properly maintaining the 15044d4804dSStefan Eßer * stack of PRNG's. 15144d4804dSStefan Eßer * @param r The PRNG to mark as modified. 15244d4804dSStefan Eßer */ 15350696a6eSStefan Eßer static void bc_rand_setModified(BcRNGData *r) { 15450696a6eSStefan Eßer 15550696a6eSStefan Eßer #if BC_RAND_BUILTIN 15650696a6eSStefan Eßer r->inc |= (BcRandState) 1UL; 15750696a6eSStefan Eßer #else // BC_RAND_BUILTIN 15850696a6eSStefan Eßer r->inc.lo |= (uint_fast64_t) 1UL; 15950696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 16050696a6eSStefan Eßer } 16150696a6eSStefan Eßer 16244d4804dSStefan Eßer /** 16344d4804dSStefan Eßer * Marks a PRNG as not modified. This is important for properly maintaining the 16444d4804dSStefan Eßer * stack of PRNG's. 16544d4804dSStefan Eßer * @param r The PRNG to mark as not modified. 16644d4804dSStefan Eßer */ 16750696a6eSStefan Eßer static void bc_rand_clearModified(BcRNGData *r) { 16850696a6eSStefan Eßer 16950696a6eSStefan Eßer #if BC_RAND_BUILTIN 17050696a6eSStefan Eßer r->inc &= ~((BcRandState) 1UL); 17150696a6eSStefan Eßer #else // BC_RAND_BUILTIN 17250696a6eSStefan Eßer r->inc.lo &= ~(1UL); 17350696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 17450696a6eSStefan Eßer } 17550696a6eSStefan Eßer 17644d4804dSStefan Eßer /** 17744d4804dSStefan Eßer * Copies a PRNG to another and marks the copy as modified if it already was or 17844d4804dSStefan Eßer * marks it modified if it already was. 17944d4804dSStefan Eßer * @param d The destination PRNG. 18044d4804dSStefan Eßer * @param s The source PRNG. 18144d4804dSStefan Eßer */ 18250696a6eSStefan Eßer static void bc_rand_copy(BcRNGData *d, BcRNGData *s) { 18350696a6eSStefan Eßer bool unmod = BC_RAND_NOTMODIFIED(d); 18450696a6eSStefan Eßer memcpy(d, s, sizeof(BcRNGData)); 18550696a6eSStefan Eßer if (!unmod) bc_rand_setModified(d); 18650696a6eSStefan Eßer else if (!BC_RAND_NOTMODIFIED(s)) bc_rand_clearModified(d); 18750696a6eSStefan Eßer } 18850696a6eSStefan Eßer 1897e5c51e5SStefan Eßer #ifndef _WIN32 19044d4804dSStefan Eßer 19144d4804dSStefan Eßer /** 19244d4804dSStefan Eßer * Reads random data from a file. 19344d4804dSStefan Eßer * @param ptr A pointer to the file, as a void pointer. 19444d4804dSStefan Eßer * @return The random data as an unsigned long. 19544d4804dSStefan Eßer */ 19650696a6eSStefan Eßer static ulong bc_rand_frand(void* ptr) { 19750696a6eSStefan Eßer 19850696a6eSStefan Eßer ulong buf[1]; 19950696a6eSStefan Eßer int fd; 20050696a6eSStefan Eßer ssize_t nread; 20150696a6eSStefan Eßer 20250696a6eSStefan Eßer assert(ptr != NULL); 20350696a6eSStefan Eßer 20450696a6eSStefan Eßer fd = *((int*)ptr); 20550696a6eSStefan Eßer 20650696a6eSStefan Eßer nread = read(fd, buf, sizeof(ulong)); 20750696a6eSStefan Eßer 20810328f8bSStefan Eßer if (BC_ERR(nread != sizeof(ulong))) bc_vm_fatalError(BC_ERR_FATAL_IO_ERR); 20950696a6eSStefan Eßer 21050696a6eSStefan Eßer return *((ulong*)buf); 21150696a6eSStefan Eßer } 2127e5c51e5SStefan Eßer #else // _WIN32 21344d4804dSStefan Eßer 21444d4804dSStefan Eßer /** 21544d4804dSStefan Eßer * Reads random data from BCryptGenRandom(). 21644d4804dSStefan Eßer * @param ptr An unused parameter. 21744d4804dSStefan Eßer * @return The random data as an unsigned long. 21844d4804dSStefan Eßer */ 2197e5c51e5SStefan Eßer static ulong bc_rand_winrand(void *ptr) { 2207e5c51e5SStefan Eßer 2217e5c51e5SStefan Eßer ulong buf[1]; 2227e5c51e5SStefan Eßer NTSTATUS s; 2237e5c51e5SStefan Eßer 2247e5c51e5SStefan Eßer BC_UNUSED(ptr); 2257e5c51e5SStefan Eßer 2267e5c51e5SStefan Eßer buf[0] = 0; 2277e5c51e5SStefan Eßer 22844d4804dSStefan Eßer s = BCryptGenRandom(NULL, (char*) buf, sizeof(ulong), 22944d4804dSStefan Eßer BCRYPT_USE_SYSTEM_PREFERRED_RNG); 2307e5c51e5SStefan Eßer 2317e5c51e5SStefan Eßer if (BC_ERR(!BCRYPT_SUCCESS(s))) buf[0] = 0; 2327e5c51e5SStefan Eßer 2337e5c51e5SStefan Eßer return buf[0]; 2347e5c51e5SStefan Eßer } 2357e5c51e5SStefan Eßer #endif // _WIN32 23650696a6eSStefan Eßer 23744d4804dSStefan Eßer /** 23844d4804dSStefan Eßer * Reads random data from rand(), byte-by-byte because rand() is only guaranteed 23944d4804dSStefan Eßer * to return 15 bits of random data. This is the final fallback and is not 24044d4804dSStefan Eßer * preferred as it is possible to access cryptographically-secure PRNG's on most 24144d4804dSStefan Eßer * systems. 24244d4804dSStefan Eßer * @param ptr An unused parameter. 24344d4804dSStefan Eßer * @return The random data as an unsigned long. 24444d4804dSStefan Eßer */ 24550696a6eSStefan Eßer static ulong bc_rand_rand(void *ptr) { 24650696a6eSStefan Eßer 24750696a6eSStefan Eßer size_t i; 24850696a6eSStefan Eßer ulong res = 0; 24950696a6eSStefan Eßer 25050696a6eSStefan Eßer BC_UNUSED(ptr); 25150696a6eSStefan Eßer 25244d4804dSStefan Eßer // Fill up the unsigned long byte-by-byte. 25350696a6eSStefan Eßer for (i = 0; i < sizeof(ulong); ++i) 25450696a6eSStefan Eßer res |= ((ulong) (rand() & BC_RAND_SRAND_BITS)) << (i * CHAR_BIT); 25550696a6eSStefan Eßer 25650696a6eSStefan Eßer return res; 25750696a6eSStefan Eßer } 25850696a6eSStefan Eßer 25944d4804dSStefan Eßer /** 26044d4804dSStefan Eßer * Returns the actual increment of the PRNG, including the required last odd 26144d4804dSStefan Eßer * bit. 26244d4804dSStefan Eßer * @param r The PRNG. 26344d4804dSStefan Eßer * @return The increment of the PRNG, including the last odd bit. 26444d4804dSStefan Eßer */ 26550696a6eSStefan Eßer static BcRandState bc_rand_inc(BcRNGData *r) { 26650696a6eSStefan Eßer 26750696a6eSStefan Eßer BcRandState inc; 26850696a6eSStefan Eßer 26950696a6eSStefan Eßer #if BC_RAND_BUILTIN 27050696a6eSStefan Eßer inc = r->inc | 1; 27150696a6eSStefan Eßer #else // BC_RAND_BUILTIN 27250696a6eSStefan Eßer inc.lo = r->inc.lo | 1; 27350696a6eSStefan Eßer inc.hi = r->inc.hi; 27450696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 27550696a6eSStefan Eßer 27650696a6eSStefan Eßer return inc; 27750696a6eSStefan Eßer } 27850696a6eSStefan Eßer 27944d4804dSStefan Eßer /** 28044d4804dSStefan Eßer * Sets up the increment for the PRNG. 28144d4804dSStefan Eßer * @param r The PRNG whose increment will be set up. 28244d4804dSStefan Eßer */ 28344d4804dSStefan Eßer static void bc_rand_setupInc(BcRNGData *r) { 28450696a6eSStefan Eßer 28550696a6eSStefan Eßer #if BC_RAND_BUILTIN 28650696a6eSStefan Eßer r->inc <<= 1UL; 28750696a6eSStefan Eßer #else // BC_RAND_BUILTIN 28850696a6eSStefan Eßer r->inc.hi <<= 1UL; 28950696a6eSStefan Eßer r->inc.hi |= (r->inc.lo & (1UL << (BC_LONG_BIT - 1))) >> (BC_LONG_BIT - 1); 29050696a6eSStefan Eßer r->inc.lo <<= 1UL; 29150696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 29250696a6eSStefan Eßer } 29350696a6eSStefan Eßer 29444d4804dSStefan Eßer /** 29544d4804dSStefan Eßer * Seeds the state of a PRNG. 29644d4804dSStefan Eßer * @param state The return parameter; the state to seed. 29744d4804dSStefan Eßer * @param val1 The lower half of the state. 29844d4804dSStefan Eßer * @param val2 The upper half of the state. 29944d4804dSStefan Eßer */ 30050696a6eSStefan Eßer static void bc_rand_seedState(BcRandState *state, ulong val1, ulong val2) { 30150696a6eSStefan Eßer 30250696a6eSStefan Eßer #if BC_RAND_BUILTIN 30350696a6eSStefan Eßer *state = ((BcRandState) val1) | ((BcRandState) val2) << (BC_LONG_BIT); 30450696a6eSStefan Eßer #else // BC_RAND_BUILTIN 30550696a6eSStefan Eßer state->lo = val1; 30650696a6eSStefan Eßer state->hi = val2; 30750696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 30850696a6eSStefan Eßer } 30950696a6eSStefan Eßer 31044d4804dSStefan Eßer /** 31144d4804dSStefan Eßer * Seeds a PRNG. 31244d4804dSStefan Eßer * @param r The return parameter; the PRNG to seed. 31344d4804dSStefan Eßer * @param state1 The lower half of the state. 31444d4804dSStefan Eßer * @param state2 The upper half of the state. 31544d4804dSStefan Eßer * @param inc1 The lower half of the increment. 31644d4804dSStefan Eßer * @param inc2 The upper half of the increment. 31744d4804dSStefan Eßer */ 31850696a6eSStefan Eßer static void bc_rand_seedRNG(BcRNGData *r, ulong state1, ulong state2, 31950696a6eSStefan Eßer ulong inc1, ulong inc2) 32050696a6eSStefan Eßer { 32150696a6eSStefan Eßer bc_rand_seedState(&r->state, state1, state2); 32250696a6eSStefan Eßer bc_rand_seedState(&r->inc, inc1, inc2); 32344d4804dSStefan Eßer bc_rand_setupInc(r); 32450696a6eSStefan Eßer } 32550696a6eSStefan Eßer 32644d4804dSStefan Eßer /** 32744d4804dSStefan Eßer * Fills a PRNG with random data to seed it. 32844d4804dSStefan Eßer * @param r The PRNG. 32944d4804dSStefan Eßer * @param fulong The function to fill an unsigned long. 33044d4804dSStefan Eßer * @param ptr The parameter to pass to @a fulong. 33144d4804dSStefan Eßer */ 33250696a6eSStefan Eßer static void bc_rand_fill(BcRNGData *r, BcRandUlong fulong, void *ptr) { 33350696a6eSStefan Eßer 33450696a6eSStefan Eßer ulong state1, state2, inc1, inc2; 33550696a6eSStefan Eßer 33650696a6eSStefan Eßer state1 = fulong(ptr); 33750696a6eSStefan Eßer state2 = fulong(ptr); 33850696a6eSStefan Eßer 33950696a6eSStefan Eßer inc1 = fulong(ptr); 34050696a6eSStefan Eßer inc2 = fulong(ptr); 34150696a6eSStefan Eßer 34250696a6eSStefan Eßer bc_rand_seedRNG(r, state1, state2, inc1, inc2); 34350696a6eSStefan Eßer } 34450696a6eSStefan Eßer 34544d4804dSStefan Eßer /** 34644d4804dSStefan Eßer * Executes the "step" portion of a PCG udpate. 34744d4804dSStefan Eßer * @param r The PRNG. 34844d4804dSStefan Eßer */ 34950696a6eSStefan Eßer static void bc_rand_step(BcRNGData *r) { 35050696a6eSStefan Eßer BcRandState temp = bc_rand_mul2(r->state, bc_rand_multiplier); 35150696a6eSStefan Eßer r->state = bc_rand_add2(temp, bc_rand_inc(r)); 35250696a6eSStefan Eßer } 35350696a6eSStefan Eßer 35444d4804dSStefan Eßer /** 35544d4804dSStefan Eßer * Returns the new output of PCG. 35644d4804dSStefan Eßer * @param r The PRNG. 35744d4804dSStefan Eßer * @return The new output from the PRNG. 35844d4804dSStefan Eßer */ 35950696a6eSStefan Eßer static BcRand bc_rand_output(BcRNGData *r) { 36050696a6eSStefan Eßer return BC_RAND_ROT(BC_RAND_FOLD(r->state), BC_RAND_ROTAMT(r->state)); 36150696a6eSStefan Eßer } 36250696a6eSStefan Eßer 36344d4804dSStefan Eßer /** 36444d4804dSStefan Eßer * Seeds every PRNG on the PRNG stack between the top and @a idx that has not 36544d4804dSStefan Eßer * been seeded. 36644d4804dSStefan Eßer * @param r The PRNG stack. 36744d4804dSStefan Eßer * @param rng The PRNG on the top of the stack. Must have been seeded. 36844d4804dSStefan Eßer */ 36950696a6eSStefan Eßer static void bc_rand_seedZeroes(BcRNG *r, BcRNGData *rng, size_t idx) { 37050696a6eSStefan Eßer 37150696a6eSStefan Eßer BcRNGData *rng2; 37250696a6eSStefan Eßer 37344d4804dSStefan Eßer // Just return if there are none to do. 37450696a6eSStefan Eßer if (r->v.len <= idx) return; 37550696a6eSStefan Eßer 37644d4804dSStefan Eßer // Get the first PRNG that might need to be seeded. 37750696a6eSStefan Eßer rng2 = bc_vec_item_rev(&r->v, idx); 37850696a6eSStefan Eßer 37944d4804dSStefan Eßer // Does it need seeding? Then it, and maybe more, do. 38050696a6eSStefan Eßer if (BC_RAND_ZERO(rng2)) { 38144d4804dSStefan Eßer 38250696a6eSStefan Eßer size_t i; 38344d4804dSStefan Eßer 38444d4804dSStefan Eßer // Seed the ones that need seeding. 38550696a6eSStefan Eßer for (i = 1; i < r->v.len; ++i) 38650696a6eSStefan Eßer bc_rand_copy(bc_vec_item_rev(&r->v, i), rng); 38750696a6eSStefan Eßer } 38850696a6eSStefan Eßer } 38950696a6eSStefan Eßer 39050696a6eSStefan Eßer void bc_rand_srand(BcRNGData *rng) { 39150696a6eSStefan Eßer 3927e5c51e5SStefan Eßer int fd = 0; 39350696a6eSStefan Eßer 39450696a6eSStefan Eßer BC_SIG_LOCK; 39550696a6eSStefan Eßer 3967e5c51e5SStefan Eßer #ifndef _WIN32 39744d4804dSStefan Eßer 39844d4804dSStefan Eßer // Try /dev/urandom first. 39950696a6eSStefan Eßer fd = open("/dev/urandom", O_RDONLY); 40050696a6eSStefan Eßer 40150696a6eSStefan Eßer if (BC_NO_ERR(fd >= 0)) { 40250696a6eSStefan Eßer bc_rand_fill(rng, bc_rand_frand, &fd); 40350696a6eSStefan Eßer close(fd); 40450696a6eSStefan Eßer } 40510328f8bSStefan Eßer else { 40610328f8bSStefan Eßer 40744d4804dSStefan Eßer // Try /dev/random second. 40810328f8bSStefan Eßer fd = open("/dev/random", O_RDONLY); 40910328f8bSStefan Eßer 41010328f8bSStefan Eßer if (BC_NO_ERR(fd >= 0)) { 41110328f8bSStefan Eßer bc_rand_fill(rng, bc_rand_frand, &fd); 41210328f8bSStefan Eßer close(fd); 41310328f8bSStefan Eßer } 41410328f8bSStefan Eßer } 4157e5c51e5SStefan Eßer #else // _WIN32 41644d4804dSStefan Eßer // Try BCryptGenRandom first. 4177e5c51e5SStefan Eßer bc_rand_fill(rng, bc_rand_winrand, NULL); 4187e5c51e5SStefan Eßer #endif // _WIN32 41950696a6eSStefan Eßer 42044d4804dSStefan Eßer // Fallback to rand() until the thing is seeded. 42150696a6eSStefan Eßer while (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_fill(rng, bc_rand_rand, NULL); 42250696a6eSStefan Eßer 42350696a6eSStefan Eßer BC_SIG_UNLOCK; 42450696a6eSStefan Eßer } 42550696a6eSStefan Eßer 42644d4804dSStefan Eßer /** 42744d4804dSStefan Eßer * Propagates a change to the PRNG to all PRNG's in the stack that should have 42844d4804dSStefan Eßer * it. The ones that should have it are laid out in the manpages. 42944d4804dSStefan Eßer * @param r The PRNG stack. 43044d4804dSStefan Eßer * @param rng The PRNG that will be used to seed the others. 43144d4804dSStefan Eßer */ 43250696a6eSStefan Eßer static void bc_rand_propagate(BcRNG *r, BcRNGData *rng) { 43350696a6eSStefan Eßer 43444d4804dSStefan Eßer // Just return if there are none to do. 43550696a6eSStefan Eßer if (r->v.len <= 1) return; 43650696a6eSStefan Eßer 43744d4804dSStefan Eßer // If the PRNG has not been modified... 43850696a6eSStefan Eßer if (BC_RAND_NOTMODIFIED(rng)) { 43950696a6eSStefan Eßer 44050696a6eSStefan Eßer size_t i; 44150696a6eSStefan Eßer bool go = true; 44250696a6eSStefan Eßer 44344d4804dSStefan Eßer // Find the first PRNG that is modified and seed the others. 44450696a6eSStefan Eßer for (i = 1; go && i < r->v.len; ++i) { 44544d4804dSStefan Eßer 44650696a6eSStefan Eßer BcRNGData *rng2 = bc_vec_item_rev(&r->v, i); 44744d4804dSStefan Eßer 44850696a6eSStefan Eßer go = BC_RAND_NOTMODIFIED(rng2); 44944d4804dSStefan Eßer 45050696a6eSStefan Eßer bc_rand_copy(rng2, rng); 45150696a6eSStefan Eßer } 45250696a6eSStefan Eßer 45344d4804dSStefan Eßer // Seed everything else. 45450696a6eSStefan Eßer bc_rand_seedZeroes(r, rng, i); 45550696a6eSStefan Eßer } 45644d4804dSStefan Eßer // Seed everything. 45750696a6eSStefan Eßer else bc_rand_seedZeroes(r, rng, 1); 45850696a6eSStefan Eßer } 45950696a6eSStefan Eßer 46050696a6eSStefan Eßer BcRand bc_rand_int(BcRNG *r) { 46150696a6eSStefan Eßer 46244d4804dSStefan Eßer // Get the actual PRNG. 46350696a6eSStefan Eßer BcRNGData *rng = bc_vec_top(&r->v); 464*10041e99SStefan Eßer BcRand res; 46550696a6eSStefan Eßer 46644d4804dSStefan Eßer // Make sure the PRNG is seeded. 46750696a6eSStefan Eßer if (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_srand(rng); 46850696a6eSStefan Eßer 469*10041e99SStefan Eßer BC_SIG_LOCK; 470*10041e99SStefan Eßer 471*10041e99SStefan Eßer // This is the important part of the PRNG. This is the stuff from PCG. 47250696a6eSStefan Eßer bc_rand_step(rng); 47350696a6eSStefan Eßer bc_rand_propagate(r, rng); 474*10041e99SStefan Eßer res = bc_rand_output(rng); 47550696a6eSStefan Eßer 476*10041e99SStefan Eßer BC_SIG_UNLOCK; 477*10041e99SStefan Eßer 478*10041e99SStefan Eßer return res; 47950696a6eSStefan Eßer } 48050696a6eSStefan Eßer 48150696a6eSStefan Eßer BcRand bc_rand_bounded(BcRNG *r, BcRand bound) { 48250696a6eSStefan Eßer 48344d4804dSStefan Eßer // Calculate the threshold below which we have to try again. 48450696a6eSStefan Eßer BcRand rand, threshold = (0 - bound) % bound; 48550696a6eSStefan Eßer 48650696a6eSStefan Eßer do { 48750696a6eSStefan Eßer rand = bc_rand_int(r); 48850696a6eSStefan Eßer } while (rand < threshold); 48950696a6eSStefan Eßer 49050696a6eSStefan Eßer return rand % bound; 49150696a6eSStefan Eßer } 49250696a6eSStefan Eßer 49350696a6eSStefan Eßer void bc_rand_seed(BcRNG *r, ulong state1, ulong state2, ulong inc1, ulong inc2) 49450696a6eSStefan Eßer { 49544d4804dSStefan Eßer // Get the actual PRNG. 49650696a6eSStefan Eßer BcRNGData *rng = bc_vec_top(&r->v); 49750696a6eSStefan Eßer 49844d4804dSStefan Eßer // Seed and set up the PRNG's increment. 49950696a6eSStefan Eßer bc_rand_seedState(&rng->inc, inc1, inc2); 50044d4804dSStefan Eßer bc_rand_setupInc(rng); 50150696a6eSStefan Eßer bc_rand_setModified(rng); 50250696a6eSStefan Eßer 50344d4804dSStefan Eßer // If the state is 0, use the increment as the state. Otherwise, seed it 50444d4804dSStefan Eßer // with the state. 50550696a6eSStefan Eßer if (!state1 && !state2) { 50650696a6eSStefan Eßer memcpy(&rng->state, &rng->inc, sizeof(BcRandState)); 50750696a6eSStefan Eßer bc_rand_step(rng); 50850696a6eSStefan Eßer } 50950696a6eSStefan Eßer else bc_rand_seedState(&rng->state, state1, state2); 51050696a6eSStefan Eßer 51144d4804dSStefan Eßer // Propagate the change to PRNG's that need it. 51250696a6eSStefan Eßer bc_rand_propagate(r, rng); 51350696a6eSStefan Eßer } 51450696a6eSStefan Eßer 51544d4804dSStefan Eßer /** 51644d4804dSStefan Eßer * Returns the increment in the PRNG *without* the odd bit and also with being 51744d4804dSStefan Eßer * shifted one bit down. 51844d4804dSStefan Eßer * @param r The PRNG. 51944d4804dSStefan Eßer * @return The increment without the odd bit and with being shifted one bit 52044d4804dSStefan Eßer * down. 52144d4804dSStefan Eßer */ 52250696a6eSStefan Eßer static BcRandState bc_rand_getInc(BcRNGData *r) { 52350696a6eSStefan Eßer 52450696a6eSStefan Eßer BcRandState res; 52550696a6eSStefan Eßer 52650696a6eSStefan Eßer #if BC_RAND_BUILTIN 52750696a6eSStefan Eßer res = r->inc >> 1; 52850696a6eSStefan Eßer #else // BC_RAND_BUILTIN 52950696a6eSStefan Eßer res = r->inc; 53050696a6eSStefan Eßer res.lo >>= 1; 53150696a6eSStefan Eßer res.lo |= (res.hi & 1) << (BC_LONG_BIT - 1); 53250696a6eSStefan Eßer res.hi >>= 1; 53350696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 53450696a6eSStefan Eßer 53550696a6eSStefan Eßer return res; 53650696a6eSStefan Eßer } 53750696a6eSStefan Eßer 53850696a6eSStefan Eßer void bc_rand_getRands(BcRNG *r, BcRand *s1, BcRand *s2, BcRand *i1, BcRand *i2) 53950696a6eSStefan Eßer { 54050696a6eSStefan Eßer BcRandState inc; 54150696a6eSStefan Eßer BcRNGData *rng = bc_vec_top(&r->v); 54250696a6eSStefan Eßer 54350696a6eSStefan Eßer if (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_srand(rng); 54450696a6eSStefan Eßer 54544d4804dSStefan Eßer // Get the increment. 54650696a6eSStefan Eßer inc = bc_rand_getInc(rng); 54750696a6eSStefan Eßer 54844d4804dSStefan Eßer // Chop the state. 54950696a6eSStefan Eßer *s1 = BC_RAND_TRUNC(rng->state); 55050696a6eSStefan Eßer *s2 = BC_RAND_CHOP(rng->state); 55150696a6eSStefan Eßer 55244d4804dSStefan Eßer // Chop the increment. 55350696a6eSStefan Eßer *i1 = BC_RAND_TRUNC(inc); 55450696a6eSStefan Eßer *i2 = BC_RAND_CHOP(inc); 55550696a6eSStefan Eßer } 55650696a6eSStefan Eßer 55750696a6eSStefan Eßer void bc_rand_push(BcRNG *r) { 55844d4804dSStefan Eßer 55944d4804dSStefan Eßer BcRNGData *rng = bc_vec_pushEmpty(&r->v); 56044d4804dSStefan Eßer 56144d4804dSStefan Eßer // Make sure the PRNG is properly zeroed because that marks it as needing to 56244d4804dSStefan Eßer // be seeded. 56344d4804dSStefan Eßer memset(rng, 0, sizeof(BcRNGData)); 56444d4804dSStefan Eßer 56544d4804dSStefan Eßer // If there is another item, copy it too. 56644d4804dSStefan Eßer if (r->v.len > 1) bc_rand_copy(rng, bc_vec_item_rev(&r->v, 1)); 56750696a6eSStefan Eßer } 56850696a6eSStefan Eßer 56950696a6eSStefan Eßer void bc_rand_pop(BcRNG *r, bool reset) { 57050696a6eSStefan Eßer bc_vec_npop(&r->v, reset ? r->v.len - 1 : 1); 57150696a6eSStefan Eßer } 57250696a6eSStefan Eßer 57350696a6eSStefan Eßer void bc_rand_init(BcRNG *r) { 57450696a6eSStefan Eßer BC_SIG_ASSERT_LOCKED; 57544d4804dSStefan Eßer bc_vec_init(&r->v, sizeof(BcRNGData), BC_DTOR_NONE); 57650696a6eSStefan Eßer bc_rand_push(r); 57750696a6eSStefan Eßer } 57850696a6eSStefan Eßer 57944d4804dSStefan Eßer #if BC_RAND_USE_FREE 58050696a6eSStefan Eßer void bc_rand_free(BcRNG *r) { 58150696a6eSStefan Eßer BC_SIG_ASSERT_LOCKED; 58250696a6eSStefan Eßer bc_vec_free(&r->v); 58350696a6eSStefan Eßer } 58444d4804dSStefan Eßer #endif // BC_RAND_USE_FREE 58550696a6eSStefan Eßer 58644d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 587