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 16*a970610aSStefan Eßer * Copyright (c) 2018-2024 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 */ 6978bc019dSStefan Eßer static BcRandState 7078bc019dSStefan Eßer bc_rand_addition(uint_fast64_t a, uint_fast64_t b) 7178bc019dSStefan Eßer { 7250696a6eSStefan Eßer BcRandState res; 7350696a6eSStefan Eßer 7450696a6eSStefan Eßer res.lo = a + b; 7550696a6eSStefan Eßer res.hi = (res.lo < a); 7650696a6eSStefan Eßer 7750696a6eSStefan Eßer return res; 7850696a6eSStefan Eßer } 7950696a6eSStefan Eßer 8044d4804dSStefan Eßer /** 8144d4804dSStefan Eßer * Adds two 128-bit values and discards the overflow. 8244d4804dSStefan Eßer * @param a The first operand. 8344d4804dSStefan Eßer * @param b The second operand. 8444d4804dSStefan Eßer * @return The sum, without overflow. 8544d4804dSStefan Eßer */ 8678bc019dSStefan Eßer static BcRandState 8778bc019dSStefan Eßer bc_rand_addition2(BcRandState a, BcRandState b) 8878bc019dSStefan Eßer { 8950696a6eSStefan Eßer BcRandState temp, res; 9050696a6eSStefan Eßer 9150696a6eSStefan Eßer res = bc_rand_addition(a.lo, b.lo); 9250696a6eSStefan Eßer temp = bc_rand_addition(a.hi, b.hi); 9350696a6eSStefan Eßer res.hi += temp.lo; 9450696a6eSStefan Eßer 9550696a6eSStefan Eßer return res; 9650696a6eSStefan Eßer } 9750696a6eSStefan Eßer 9844d4804dSStefan Eßer /** 9944d4804dSStefan Eßer * Multiplies two 64-bit values and preserves the overflow. 10044d4804dSStefan Eßer * @param a The first operand. 10144d4804dSStefan Eßer * @param b The second operand. 10244d4804dSStefan Eßer * @return The product, including overflow. 10344d4804dSStefan Eßer */ 10478bc019dSStefan Eßer static BcRandState 10578bc019dSStefan Eßer bc_rand_multiply(uint_fast64_t a, uint_fast64_t b) 10678bc019dSStefan Eßer { 10750696a6eSStefan Eßer uint_fast64_t al, ah, bl, bh, c0, c1, c2, c3; 10850696a6eSStefan Eßer BcRandState carry, res; 10950696a6eSStefan Eßer 11050696a6eSStefan Eßer al = BC_RAND_TRUNC32(a); 11150696a6eSStefan Eßer ah = BC_RAND_CHOP32(a); 11250696a6eSStefan Eßer bl = BC_RAND_TRUNC32(b); 11350696a6eSStefan Eßer bh = BC_RAND_CHOP32(b); 11450696a6eSStefan Eßer 11550696a6eSStefan Eßer c0 = al * bl; 11650696a6eSStefan Eßer c1 = al * bh; 11750696a6eSStefan Eßer c2 = ah * bl; 11850696a6eSStefan Eßer c3 = ah * bh; 11950696a6eSStefan Eßer 12050696a6eSStefan Eßer carry = bc_rand_addition(c1, c2); 12150696a6eSStefan Eßer 12250696a6eSStefan Eßer res = bc_rand_addition(c0, (BC_RAND_TRUNC32(carry.lo)) << 32); 12350696a6eSStefan Eßer res.hi += BC_RAND_CHOP32(carry.lo) + c3 + (carry.hi << 32); 12450696a6eSStefan Eßer 12550696a6eSStefan Eßer return res; 12650696a6eSStefan Eßer } 12750696a6eSStefan Eßer 12844d4804dSStefan Eßer /** 12944d4804dSStefan Eßer * Multiplies two 128-bit values and discards the overflow. 13044d4804dSStefan Eßer * @param a The first operand. 13144d4804dSStefan Eßer * @param b The second operand. 13244d4804dSStefan Eßer * @return The product, without overflow. 13344d4804dSStefan Eßer */ 13478bc019dSStefan Eßer static BcRandState 13578bc019dSStefan Eßer bc_rand_multiply2(BcRandState a, BcRandState b) 13678bc019dSStefan Eßer { 13750696a6eSStefan Eßer BcRandState c0, c1, c2, carry; 13850696a6eSStefan Eßer 13950696a6eSStefan Eßer c0 = bc_rand_multiply(a.lo, b.lo); 14050696a6eSStefan Eßer c1 = bc_rand_multiply(a.lo, b.hi); 14150696a6eSStefan Eßer c2 = bc_rand_multiply(a.hi, b.lo); 14250696a6eSStefan Eßer 14350696a6eSStefan Eßer carry = bc_rand_addition2(c1, c2); 14450696a6eSStefan Eßer carry.hi = carry.lo; 14550696a6eSStefan Eßer carry.lo = 0; 14650696a6eSStefan Eßer 14750696a6eSStefan Eßer return bc_rand_addition2(c0, carry); 14850696a6eSStefan Eßer } 14950696a6eSStefan Eßer 15050696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 15150696a6eSStefan Eßer 15244d4804dSStefan Eßer /** 15344d4804dSStefan Eßer * Marks a PRNG as modified. This is important for properly maintaining the 15444d4804dSStefan Eßer * stack of PRNG's. 15544d4804dSStefan Eßer * @param r The PRNG to mark as modified. 15644d4804dSStefan Eßer */ 15778bc019dSStefan Eßer static void 15878bc019dSStefan Eßer bc_rand_setModified(BcRNGData* r) 15978bc019dSStefan Eßer { 16050696a6eSStefan Eßer #if BC_RAND_BUILTIN 16150696a6eSStefan Eßer r->inc |= (BcRandState) 1UL; 16250696a6eSStefan Eßer #else // BC_RAND_BUILTIN 16350696a6eSStefan Eßer r->inc.lo |= (uint_fast64_t) 1UL; 16450696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 16550696a6eSStefan Eßer } 16650696a6eSStefan Eßer 16744d4804dSStefan Eßer /** 16844d4804dSStefan Eßer * Marks a PRNG as not modified. This is important for properly maintaining the 16944d4804dSStefan Eßer * stack of PRNG's. 17044d4804dSStefan Eßer * @param r The PRNG to mark as not modified. 17144d4804dSStefan Eßer */ 17278bc019dSStefan Eßer static void 17378bc019dSStefan Eßer bc_rand_clearModified(BcRNGData* r) 17478bc019dSStefan Eßer { 17550696a6eSStefan Eßer #if BC_RAND_BUILTIN 17650696a6eSStefan Eßer r->inc &= ~((BcRandState) 1UL); 17750696a6eSStefan Eßer #else // BC_RAND_BUILTIN 17850696a6eSStefan Eßer r->inc.lo &= ~(1UL); 17950696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 18050696a6eSStefan Eßer } 18150696a6eSStefan Eßer 18244d4804dSStefan Eßer /** 18344d4804dSStefan Eßer * Copies a PRNG to another and marks the copy as modified if it already was or 18444d4804dSStefan Eßer * marks it modified if it already was. 18544d4804dSStefan Eßer * @param d The destination PRNG. 18644d4804dSStefan Eßer * @param s The source PRNG. 18744d4804dSStefan Eßer */ 18878bc019dSStefan Eßer static void 18978bc019dSStefan Eßer bc_rand_copy(BcRNGData* d, BcRNGData* s) 19078bc019dSStefan Eßer { 19150696a6eSStefan Eßer bool unmod = BC_RAND_NOTMODIFIED(d); 19278bc019dSStefan Eßer 19378bc019dSStefan Eßer // NOLINTNEXTLINE 19450696a6eSStefan Eßer memcpy(d, s, sizeof(BcRNGData)); 19578bc019dSStefan Eßer 19650696a6eSStefan Eßer if (!unmod) bc_rand_setModified(d); 19750696a6eSStefan Eßer else if (!BC_RAND_NOTMODIFIED(s)) bc_rand_clearModified(d); 19850696a6eSStefan Eßer } 19950696a6eSStefan Eßer 2007e5c51e5SStefan Eßer #ifndef _WIN32 20144d4804dSStefan Eßer 20244d4804dSStefan Eßer /** 20344d4804dSStefan Eßer * Reads random data from a file. 20444d4804dSStefan Eßer * @param ptr A pointer to the file, as a void pointer. 20544d4804dSStefan Eßer * @return The random data as an unsigned long. 20644d4804dSStefan Eßer */ 20778bc019dSStefan Eßer static ulong 20878bc019dSStefan Eßer bc_rand_frand(void* ptr) 20978bc019dSStefan Eßer { 21050696a6eSStefan Eßer ulong buf[1]; 21150696a6eSStefan Eßer int fd; 21250696a6eSStefan Eßer ssize_t nread; 21350696a6eSStefan Eßer 21450696a6eSStefan Eßer assert(ptr != NULL); 21550696a6eSStefan Eßer 21650696a6eSStefan Eßer fd = *((int*) ptr); 21750696a6eSStefan Eßer 21850696a6eSStefan Eßer nread = read(fd, buf, sizeof(ulong)); 21950696a6eSStefan Eßer 22010328f8bSStefan Eßer if (BC_ERR(nread != sizeof(ulong))) bc_vm_fatalError(BC_ERR_FATAL_IO_ERR); 22150696a6eSStefan Eßer 22250696a6eSStefan Eßer return *((ulong*) buf); 22350696a6eSStefan Eßer } 2247e5c51e5SStefan Eßer #else // _WIN32 22544d4804dSStefan Eßer 22644d4804dSStefan Eßer /** 22744d4804dSStefan Eßer * Reads random data from BCryptGenRandom(). 22844d4804dSStefan Eßer * @param ptr An unused parameter. 22944d4804dSStefan Eßer * @return The random data as an unsigned long. 23044d4804dSStefan Eßer */ 23178bc019dSStefan Eßer static ulong 23278bc019dSStefan Eßer bc_rand_winrand(void* ptr) 23378bc019dSStefan Eßer { 2347e5c51e5SStefan Eßer ulong buf[1]; 2357e5c51e5SStefan Eßer NTSTATUS s; 2367e5c51e5SStefan Eßer 2377e5c51e5SStefan Eßer BC_UNUSED(ptr); 2387e5c51e5SStefan Eßer 2397e5c51e5SStefan Eßer buf[0] = 0; 2407e5c51e5SStefan Eßer 24144d4804dSStefan Eßer s = BCryptGenRandom(NULL, (char*) buf, sizeof(ulong), 24244d4804dSStefan Eßer BCRYPT_USE_SYSTEM_PREFERRED_RNG); 2437e5c51e5SStefan Eßer 2447e5c51e5SStefan Eßer if (BC_ERR(!BCRYPT_SUCCESS(s))) buf[0] = 0; 2457e5c51e5SStefan Eßer 2467e5c51e5SStefan Eßer return buf[0]; 2477e5c51e5SStefan Eßer } 2487e5c51e5SStefan Eßer #endif // _WIN32 24950696a6eSStefan Eßer 25044d4804dSStefan Eßer /** 25144d4804dSStefan Eßer * Reads random data from rand(), byte-by-byte because rand() is only guaranteed 25244d4804dSStefan Eßer * to return 15 bits of random data. This is the final fallback and is not 25344d4804dSStefan Eßer * preferred as it is possible to access cryptographically-secure PRNG's on most 25444d4804dSStefan Eßer * systems. 25544d4804dSStefan Eßer * @param ptr An unused parameter. 25644d4804dSStefan Eßer * @return The random data as an unsigned long. 25744d4804dSStefan Eßer */ 25878bc019dSStefan Eßer static ulong 25978bc019dSStefan Eßer bc_rand_rand(void* ptr) 26078bc019dSStefan Eßer { 26150696a6eSStefan Eßer size_t i; 26250696a6eSStefan Eßer ulong res = 0; 26350696a6eSStefan Eßer 26450696a6eSStefan Eßer BC_UNUSED(ptr); 26550696a6eSStefan Eßer 26644d4804dSStefan Eßer // Fill up the unsigned long byte-by-byte. 26750696a6eSStefan Eßer for (i = 0; i < sizeof(ulong); ++i) 26878bc019dSStefan Eßer { 26950696a6eSStefan Eßer res |= ((ulong) (rand() & BC_RAND_SRAND_BITS)) << (i * CHAR_BIT); 27078bc019dSStefan Eßer } 27150696a6eSStefan Eßer 27250696a6eSStefan Eßer return res; 27350696a6eSStefan Eßer } 27450696a6eSStefan Eßer 27544d4804dSStefan Eßer /** 27644d4804dSStefan Eßer * Returns the actual increment of the PRNG, including the required last odd 27744d4804dSStefan Eßer * bit. 27844d4804dSStefan Eßer * @param r The PRNG. 27944d4804dSStefan Eßer * @return The increment of the PRNG, including the last odd bit. 28044d4804dSStefan Eßer */ 28178bc019dSStefan Eßer static BcRandState 28278bc019dSStefan Eßer bc_rand_inc(BcRNGData* r) 28378bc019dSStefan Eßer { 28450696a6eSStefan Eßer BcRandState inc; 28550696a6eSStefan Eßer 28650696a6eSStefan Eßer #if BC_RAND_BUILTIN 28750696a6eSStefan Eßer inc = r->inc | 1; 28850696a6eSStefan Eßer #else // BC_RAND_BUILTIN 28950696a6eSStefan Eßer inc.lo = r->inc.lo | 1; 29050696a6eSStefan Eßer inc.hi = r->inc.hi; 29150696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 29250696a6eSStefan Eßer 29350696a6eSStefan Eßer return inc; 29450696a6eSStefan Eßer } 29550696a6eSStefan Eßer 29644d4804dSStefan Eßer /** 29744d4804dSStefan Eßer * Sets up the increment for the PRNG. 29844d4804dSStefan Eßer * @param r The PRNG whose increment will be set up. 29944d4804dSStefan Eßer */ 30078bc019dSStefan Eßer static void 30178bc019dSStefan Eßer bc_rand_setupInc(BcRNGData* r) 30278bc019dSStefan Eßer { 30350696a6eSStefan Eßer #if BC_RAND_BUILTIN 30450696a6eSStefan Eßer r->inc <<= 1UL; 30550696a6eSStefan Eßer #else // BC_RAND_BUILTIN 30650696a6eSStefan Eßer r->inc.hi <<= 1UL; 30750696a6eSStefan Eßer r->inc.hi |= (r->inc.lo & (1UL << (BC_LONG_BIT - 1))) >> (BC_LONG_BIT - 1); 30850696a6eSStefan Eßer r->inc.lo <<= 1UL; 30950696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 31050696a6eSStefan Eßer } 31150696a6eSStefan Eßer 31244d4804dSStefan Eßer /** 31344d4804dSStefan Eßer * Seeds the state of a PRNG. 31444d4804dSStefan Eßer * @param state The return parameter; the state to seed. 31544d4804dSStefan Eßer * @param val1 The lower half of the state. 31644d4804dSStefan Eßer * @param val2 The upper half of the state. 31744d4804dSStefan Eßer */ 31878bc019dSStefan Eßer static void 31978bc019dSStefan Eßer bc_rand_seedState(BcRandState* state, ulong val1, ulong val2) 32078bc019dSStefan Eßer { 32150696a6eSStefan Eßer #if BC_RAND_BUILTIN 32250696a6eSStefan Eßer *state = ((BcRandState) val1) | ((BcRandState) val2) << (BC_LONG_BIT); 32350696a6eSStefan Eßer #else // BC_RAND_BUILTIN 32450696a6eSStefan Eßer state->lo = val1; 32550696a6eSStefan Eßer state->hi = val2; 32650696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 32750696a6eSStefan Eßer } 32850696a6eSStefan Eßer 32944d4804dSStefan Eßer /** 33044d4804dSStefan Eßer * Seeds a PRNG. 33144d4804dSStefan Eßer * @param r The return parameter; the PRNG to seed. 33244d4804dSStefan Eßer * @param state1 The lower half of the state. 33344d4804dSStefan Eßer * @param state2 The upper half of the state. 33444d4804dSStefan Eßer * @param inc1 The lower half of the increment. 33544d4804dSStefan Eßer * @param inc2 The upper half of the increment. 33644d4804dSStefan Eßer */ 33778bc019dSStefan Eßer static void 33878bc019dSStefan Eßer bc_rand_seedRNG(BcRNGData* r, ulong state1, ulong state2, ulong inc1, 33978bc019dSStefan Eßer ulong inc2) 34050696a6eSStefan Eßer { 34150696a6eSStefan Eßer bc_rand_seedState(&r->state, state1, state2); 34250696a6eSStefan Eßer bc_rand_seedState(&r->inc, inc1, inc2); 34344d4804dSStefan Eßer bc_rand_setupInc(r); 34450696a6eSStefan Eßer } 34550696a6eSStefan Eßer 34644d4804dSStefan Eßer /** 34744d4804dSStefan Eßer * Fills a PRNG with random data to seed it. 34844d4804dSStefan Eßer * @param r The PRNG. 34944d4804dSStefan Eßer * @param fulong The function to fill an unsigned long. 35044d4804dSStefan Eßer * @param ptr The parameter to pass to @a fulong. 35144d4804dSStefan Eßer */ 35278bc019dSStefan Eßer static void 35378bc019dSStefan Eßer bc_rand_fill(BcRNGData* r, BcRandUlong fulong, void* ptr) 35478bc019dSStefan Eßer { 35550696a6eSStefan Eßer ulong state1, state2, inc1, inc2; 35650696a6eSStefan Eßer 35750696a6eSStefan Eßer state1 = fulong(ptr); 35850696a6eSStefan Eßer state2 = fulong(ptr); 35950696a6eSStefan Eßer 36050696a6eSStefan Eßer inc1 = fulong(ptr); 36150696a6eSStefan Eßer inc2 = fulong(ptr); 36250696a6eSStefan Eßer 36350696a6eSStefan Eßer bc_rand_seedRNG(r, state1, state2, inc1, inc2); 36450696a6eSStefan Eßer } 36550696a6eSStefan Eßer 36644d4804dSStefan Eßer /** 36744d4804dSStefan Eßer * Executes the "step" portion of a PCG udpate. 36844d4804dSStefan Eßer * @param r The PRNG. 36944d4804dSStefan Eßer */ 37078bc019dSStefan Eßer static void 37178bc019dSStefan Eßer bc_rand_step(BcRNGData* r) 37278bc019dSStefan Eßer { 37350696a6eSStefan Eßer BcRandState temp = bc_rand_mul2(r->state, bc_rand_multiplier); 37450696a6eSStefan Eßer r->state = bc_rand_add2(temp, bc_rand_inc(r)); 37550696a6eSStefan Eßer } 37650696a6eSStefan Eßer 37744d4804dSStefan Eßer /** 37844d4804dSStefan Eßer * Returns the new output of PCG. 37944d4804dSStefan Eßer * @param r The PRNG. 38044d4804dSStefan Eßer * @return The new output from the PRNG. 38144d4804dSStefan Eßer */ 38278bc019dSStefan Eßer static BcRand 38378bc019dSStefan Eßer bc_rand_output(BcRNGData* r) 38478bc019dSStefan Eßer { 38550696a6eSStefan Eßer return BC_RAND_ROT(BC_RAND_FOLD(r->state), BC_RAND_ROTAMT(r->state)); 38650696a6eSStefan Eßer } 38750696a6eSStefan Eßer 38844d4804dSStefan Eßer /** 38944d4804dSStefan Eßer * Seeds every PRNG on the PRNG stack between the top and @a idx that has not 39044d4804dSStefan Eßer * been seeded. 39144d4804dSStefan Eßer * @param r The PRNG stack. 39244d4804dSStefan Eßer * @param rng The PRNG on the top of the stack. Must have been seeded. 39344d4804dSStefan Eßer */ 39478bc019dSStefan Eßer static void 39578bc019dSStefan Eßer bc_rand_seedZeroes(BcRNG* r, BcRNGData* rng, size_t idx) 39678bc019dSStefan Eßer { 39750696a6eSStefan Eßer BcRNGData* rng2; 39850696a6eSStefan Eßer 39944d4804dSStefan Eßer // Just return if there are none to do. 40050696a6eSStefan Eßer if (r->v.len <= idx) return; 40150696a6eSStefan Eßer 40244d4804dSStefan Eßer // Get the first PRNG that might need to be seeded. 40350696a6eSStefan Eßer rng2 = bc_vec_item_rev(&r->v, idx); 40450696a6eSStefan Eßer 40544d4804dSStefan Eßer // Does it need seeding? Then it, and maybe more, do. 40678bc019dSStefan Eßer if (BC_RAND_ZERO(rng2)) 40778bc019dSStefan Eßer { 40850696a6eSStefan Eßer size_t i; 40944d4804dSStefan Eßer 41044d4804dSStefan Eßer // Seed the ones that need seeding. 41150696a6eSStefan Eßer for (i = 1; i < r->v.len; ++i) 41278bc019dSStefan Eßer { 41350696a6eSStefan Eßer bc_rand_copy(bc_vec_item_rev(&r->v, i), rng); 41450696a6eSStefan Eßer } 41550696a6eSStefan Eßer } 41678bc019dSStefan Eßer } 41750696a6eSStefan Eßer 41878bc019dSStefan Eßer void 41978bc019dSStefan Eßer bc_rand_srand(BcRNGData* rng) 42078bc019dSStefan Eßer { 4217e5c51e5SStefan Eßer int fd = 0; 42250696a6eSStefan Eßer 42350696a6eSStefan Eßer BC_SIG_LOCK; 42450696a6eSStefan Eßer 4257e5c51e5SStefan Eßer #ifndef _WIN32 42644d4804dSStefan Eßer 42744d4804dSStefan Eßer // Try /dev/urandom first. 42850696a6eSStefan Eßer fd = open("/dev/urandom", O_RDONLY); 42950696a6eSStefan Eßer 43078bc019dSStefan Eßer if (BC_NO_ERR(fd >= 0)) 43178bc019dSStefan Eßer { 43250696a6eSStefan Eßer bc_rand_fill(rng, bc_rand_frand, &fd); 43350696a6eSStefan Eßer close(fd); 43450696a6eSStefan Eßer } 43578bc019dSStefan Eßer else 43678bc019dSStefan Eßer { 43744d4804dSStefan Eßer // Try /dev/random second. 43810328f8bSStefan Eßer fd = open("/dev/random", O_RDONLY); 43910328f8bSStefan Eßer 44078bc019dSStefan Eßer if (BC_NO_ERR(fd >= 0)) 44178bc019dSStefan Eßer { 44210328f8bSStefan Eßer bc_rand_fill(rng, bc_rand_frand, &fd); 44310328f8bSStefan Eßer close(fd); 44410328f8bSStefan Eßer } 44510328f8bSStefan Eßer } 4467e5c51e5SStefan Eßer #else // _WIN32 44744d4804dSStefan Eßer // Try BCryptGenRandom first. 4487e5c51e5SStefan Eßer bc_rand_fill(rng, bc_rand_winrand, NULL); 4497e5c51e5SStefan Eßer #endif // _WIN32 45050696a6eSStefan Eßer 45144d4804dSStefan Eßer // Fallback to rand() until the thing is seeded. 45278bc019dSStefan Eßer while (BC_ERR(BC_RAND_ZERO(rng))) 45378bc019dSStefan Eßer { 45478bc019dSStefan Eßer bc_rand_fill(rng, bc_rand_rand, NULL); 45578bc019dSStefan Eßer } 45650696a6eSStefan Eßer 45750696a6eSStefan Eßer BC_SIG_UNLOCK; 45850696a6eSStefan Eßer } 45950696a6eSStefan Eßer 46044d4804dSStefan Eßer /** 46144d4804dSStefan Eßer * Propagates a change to the PRNG to all PRNG's in the stack that should have 46244d4804dSStefan Eßer * it. The ones that should have it are laid out in the manpages. 46344d4804dSStefan Eßer * @param r The PRNG stack. 46444d4804dSStefan Eßer * @param rng The PRNG that will be used to seed the others. 46544d4804dSStefan Eßer */ 46678bc019dSStefan Eßer static void 46778bc019dSStefan Eßer bc_rand_propagate(BcRNG* r, BcRNGData* rng) 46878bc019dSStefan Eßer { 46944d4804dSStefan Eßer // Just return if there are none to do. 47050696a6eSStefan Eßer if (r->v.len <= 1) return; 47150696a6eSStefan Eßer 47244d4804dSStefan Eßer // If the PRNG has not been modified... 47378bc019dSStefan Eßer if (BC_RAND_NOTMODIFIED(rng)) 47478bc019dSStefan Eßer { 47550696a6eSStefan Eßer size_t i; 47650696a6eSStefan Eßer bool go = true; 47750696a6eSStefan Eßer 47844d4804dSStefan Eßer // Find the first PRNG that is modified and seed the others. 47978bc019dSStefan Eßer for (i = 1; go && i < r->v.len; ++i) 48078bc019dSStefan Eßer { 48150696a6eSStefan Eßer BcRNGData* rng2 = bc_vec_item_rev(&r->v, i); 48244d4804dSStefan Eßer 48350696a6eSStefan Eßer go = BC_RAND_NOTMODIFIED(rng2); 48444d4804dSStefan Eßer 48550696a6eSStefan Eßer bc_rand_copy(rng2, rng); 48650696a6eSStefan Eßer } 48750696a6eSStefan Eßer 48844d4804dSStefan Eßer // Seed everything else. 48950696a6eSStefan Eßer bc_rand_seedZeroes(r, rng, i); 49050696a6eSStefan Eßer } 49144d4804dSStefan Eßer // Seed everything. 49250696a6eSStefan Eßer else bc_rand_seedZeroes(r, rng, 1); 49350696a6eSStefan Eßer } 49450696a6eSStefan Eßer 49578bc019dSStefan Eßer BcRand 49678bc019dSStefan Eßer bc_rand_int(BcRNG* r) 49778bc019dSStefan Eßer { 49844d4804dSStefan Eßer // Get the actual PRNG. 49950696a6eSStefan Eßer BcRNGData* rng = bc_vec_top(&r->v); 50010041e99SStefan Eßer BcRand res; 50150696a6eSStefan Eßer 50244d4804dSStefan Eßer // Make sure the PRNG is seeded. 50350696a6eSStefan Eßer if (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_srand(rng); 50450696a6eSStefan Eßer 50510041e99SStefan Eßer BC_SIG_LOCK; 50610041e99SStefan Eßer 50710041e99SStefan Eßer // This is the important part of the PRNG. This is the stuff from PCG. 50850696a6eSStefan Eßer bc_rand_step(rng); 50950696a6eSStefan Eßer bc_rand_propagate(r, rng); 51010041e99SStefan Eßer res = bc_rand_output(rng); 51150696a6eSStefan Eßer 51210041e99SStefan Eßer BC_SIG_UNLOCK; 51310041e99SStefan Eßer 51410041e99SStefan Eßer return res; 51550696a6eSStefan Eßer } 51650696a6eSStefan Eßer 51778bc019dSStefan Eßer BcRand 51878bc019dSStefan Eßer bc_rand_bounded(BcRNG* r, BcRand bound) 51978bc019dSStefan Eßer { 52076238846SStefan Eßer BcRand rand; 52176238846SStefan Eßer BcRand threshold; 52276238846SStefan Eßer 52344d4804dSStefan Eßer // Calculate the threshold below which we have to try again. 52476238846SStefan Eßer threshold = (0 - bound) % bound; 52550696a6eSStefan Eßer 52678bc019dSStefan Eßer do 52778bc019dSStefan Eßer { 52850696a6eSStefan Eßer rand = bc_rand_int(r); 52978bc019dSStefan Eßer } 53078bc019dSStefan Eßer while (rand < threshold); 53150696a6eSStefan Eßer 53250696a6eSStefan Eßer return rand % bound; 53350696a6eSStefan Eßer } 53450696a6eSStefan Eßer 53578bc019dSStefan Eßer void 53678bc019dSStefan Eßer bc_rand_seed(BcRNG* r, ulong state1, ulong state2, ulong inc1, ulong inc2) 53750696a6eSStefan Eßer { 53844d4804dSStefan Eßer // Get the actual PRNG. 53950696a6eSStefan Eßer BcRNGData* rng = bc_vec_top(&r->v); 54050696a6eSStefan Eßer 54144d4804dSStefan Eßer // Seed and set up the PRNG's increment. 54250696a6eSStefan Eßer bc_rand_seedState(&rng->inc, inc1, inc2); 54344d4804dSStefan Eßer bc_rand_setupInc(rng); 54450696a6eSStefan Eßer bc_rand_setModified(rng); 54550696a6eSStefan Eßer 54644d4804dSStefan Eßer // If the state is 0, use the increment as the state. Otherwise, seed it 54744d4804dSStefan Eßer // with the state. 54878bc019dSStefan Eßer if (!state1 && !state2) 54978bc019dSStefan Eßer { 55078bc019dSStefan Eßer // NOLINTNEXTLINE 55150696a6eSStefan Eßer memcpy(&rng->state, &rng->inc, sizeof(BcRandState)); 55250696a6eSStefan Eßer bc_rand_step(rng); 55350696a6eSStefan Eßer } 55450696a6eSStefan Eßer else bc_rand_seedState(&rng->state, state1, state2); 55550696a6eSStefan Eßer 55644d4804dSStefan Eßer // Propagate the change to PRNG's that need it. 55750696a6eSStefan Eßer bc_rand_propagate(r, rng); 55850696a6eSStefan Eßer } 55950696a6eSStefan Eßer 56044d4804dSStefan Eßer /** 56144d4804dSStefan Eßer * Returns the increment in the PRNG *without* the odd bit and also with being 56244d4804dSStefan Eßer * shifted one bit down. 56344d4804dSStefan Eßer * @param r The PRNG. 56444d4804dSStefan Eßer * @return The increment without the odd bit and with being shifted one bit 56544d4804dSStefan Eßer * down. 56644d4804dSStefan Eßer */ 56778bc019dSStefan Eßer static BcRandState 56878bc019dSStefan Eßer bc_rand_getInc(BcRNGData* r) 56978bc019dSStefan Eßer { 57050696a6eSStefan Eßer BcRandState res; 57150696a6eSStefan Eßer 57250696a6eSStefan Eßer #if BC_RAND_BUILTIN 57350696a6eSStefan Eßer res = r->inc >> 1; 57450696a6eSStefan Eßer #else // BC_RAND_BUILTIN 57550696a6eSStefan Eßer res = r->inc; 57650696a6eSStefan Eßer res.lo >>= 1; 57750696a6eSStefan Eßer res.lo |= (res.hi & 1) << (BC_LONG_BIT - 1); 57850696a6eSStefan Eßer res.hi >>= 1; 57950696a6eSStefan Eßer #endif // BC_RAND_BUILTIN 58050696a6eSStefan Eßer 58150696a6eSStefan Eßer return res; 58250696a6eSStefan Eßer } 58350696a6eSStefan Eßer 58478bc019dSStefan Eßer void 58578bc019dSStefan Eßer bc_rand_getRands(BcRNG* r, BcRand* s1, BcRand* s2, BcRand* i1, BcRand* i2) 58650696a6eSStefan Eßer { 58750696a6eSStefan Eßer BcRandState inc; 58850696a6eSStefan Eßer BcRNGData* rng = bc_vec_top(&r->v); 58950696a6eSStefan Eßer 59050696a6eSStefan Eßer if (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_srand(rng); 59150696a6eSStefan Eßer 59244d4804dSStefan Eßer // Get the increment. 59350696a6eSStefan Eßer inc = bc_rand_getInc(rng); 59450696a6eSStefan Eßer 59544d4804dSStefan Eßer // Chop the state. 59650696a6eSStefan Eßer *s1 = BC_RAND_TRUNC(rng->state); 59750696a6eSStefan Eßer *s2 = BC_RAND_CHOP(rng->state); 59850696a6eSStefan Eßer 59944d4804dSStefan Eßer // Chop the increment. 60050696a6eSStefan Eßer *i1 = BC_RAND_TRUNC(inc); 60150696a6eSStefan Eßer *i2 = BC_RAND_CHOP(inc); 60250696a6eSStefan Eßer } 60350696a6eSStefan Eßer 60478bc019dSStefan Eßer void 60578bc019dSStefan Eßer bc_rand_push(BcRNG* r) 60678bc019dSStefan Eßer { 60744d4804dSStefan Eßer BcRNGData* rng = bc_vec_pushEmpty(&r->v); 60844d4804dSStefan Eßer 60944d4804dSStefan Eßer // Make sure the PRNG is properly zeroed because that marks it as needing to 61044d4804dSStefan Eßer // be seeded. 61178bc019dSStefan Eßer // NOLINTNEXTLINE 61244d4804dSStefan Eßer memset(rng, 0, sizeof(BcRNGData)); 61344d4804dSStefan Eßer 61444d4804dSStefan Eßer // If there is another item, copy it too. 61544d4804dSStefan Eßer if (r->v.len > 1) bc_rand_copy(rng, bc_vec_item_rev(&r->v, 1)); 61650696a6eSStefan Eßer } 61750696a6eSStefan Eßer 61878bc019dSStefan Eßer void 61978bc019dSStefan Eßer bc_rand_pop(BcRNG* r, bool reset) 62078bc019dSStefan Eßer { 62150696a6eSStefan Eßer bc_vec_npop(&r->v, reset ? r->v.len - 1 : 1); 62250696a6eSStefan Eßer } 62350696a6eSStefan Eßer 62478bc019dSStefan Eßer void 62578bc019dSStefan Eßer bc_rand_init(BcRNG* r) 62678bc019dSStefan Eßer { 62750696a6eSStefan Eßer BC_SIG_ASSERT_LOCKED; 62844d4804dSStefan Eßer bc_vec_init(&r->v, sizeof(BcRNGData), BC_DTOR_NONE); 62950696a6eSStefan Eßer bc_rand_push(r); 63050696a6eSStefan Eßer } 63150696a6eSStefan Eßer 63244d4804dSStefan Eßer #if BC_RAND_USE_FREE 63378bc019dSStefan Eßer void 63478bc019dSStefan Eßer bc_rand_free(BcRNG* r) 63578bc019dSStefan Eßer { 63650696a6eSStefan Eßer BC_SIG_ASSERT_LOCKED; 63750696a6eSStefan Eßer bc_vec_free(&r->v); 63850696a6eSStefan Eßer } 63944d4804dSStefan Eßer #endif // BC_RAND_USE_FREE 64050696a6eSStefan Eßer 64144d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 642