/*1* *****************************************************************************2*3* Parts of this code are adapted from the following:4*5* PCG, A Family of Better Random Number Generators.6*7* You can find the original source code at:8* https://github.com/imneme/pcg-c9*10* -----------------------------------------------------------------------------11*12* This code is under the following license:13*14* Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors15* Copyright (c) 2018-2025 Gavin D. Howard and contributors.16*17* Permission is hereby granted, free of charge, to any person obtaining a copy18* of this software and associated documentation files (the "Software"), to deal19* in the Software without restriction, including without limitation the rights20* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell21* copies of the Software, and to permit persons to whom the Software is22* furnished to do so, subject to the following conditions:23*24* The above copyright notice and this permission notice shall be included in25* all copies or substantial portions of the Software.26*27* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR28* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,29* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE30* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER31* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,32* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE33* SOFTWARE.34*35* *****************************************************************************36*37* Code for the RNG.38*39*/4041#include <assert.h>42#include <stdlib.h>43#include <string.h>44#include <time.h>45#include <fcntl.h>4647#ifndef _WIN3248#include <unistd.h>49#else // _WIN3250#include <Windows.h>51#include <bcrypt.h>52#endif // _WIN325354#include <status.h>55#include <rand.h>56#include <vm.h>5758#if BC_ENABLE_EXTRA_MATH5960#if !BC_RAND_BUILTIN6162/**63* Adds two 64-bit values and preserves the overflow.64* @param a The first operand.65* @param b The second operand.66* @return The sum, including overflow.67*/68static BcRandState69bc_rand_addition(uint_fast64_t a, uint_fast64_t b)70{71BcRandState res;7273res.lo = a + b;74res.hi = (res.lo < a);7576return res;77}7879/**80* Adds two 128-bit values and discards the overflow.81* @param a The first operand.82* @param b The second operand.83* @return The sum, without overflow.84*/85static BcRandState86bc_rand_addition2(BcRandState a, BcRandState b)87{88BcRandState temp, res;8990res = bc_rand_addition(a.lo, b.lo);91temp = bc_rand_addition(a.hi, b.hi);92res.hi += temp.lo;9394return res;95}9697/**98* Multiplies two 64-bit values and preserves the overflow.99* @param a The first operand.100* @param b The second operand.101* @return The product, including overflow.102*/103static BcRandState104bc_rand_multiply(uint_fast64_t a, uint_fast64_t b)105{106uint_fast64_t al, ah, bl, bh, c0, c1, c2, c3;107BcRandState carry, res;108109al = BC_RAND_TRUNC32(a);110ah = BC_RAND_CHOP32(a);111bl = BC_RAND_TRUNC32(b);112bh = BC_RAND_CHOP32(b);113114c0 = al * bl;115c1 = al * bh;116c2 = ah * bl;117c3 = ah * bh;118119carry = bc_rand_addition(c1, c2);120121res = bc_rand_addition(c0, (BC_RAND_TRUNC32(carry.lo)) << 32);122res.hi += BC_RAND_CHOP32(carry.lo) + c3 + (carry.hi << 32);123124return res;125}126127/**128* Multiplies two 128-bit values and discards the overflow.129* @param a The first operand.130* @param b The second operand.131* @return The product, without overflow.132*/133static BcRandState134bc_rand_multiply2(BcRandState a, BcRandState b)135{136BcRandState c0, c1, c2, carry;137138c0 = bc_rand_multiply(a.lo, b.lo);139c1 = bc_rand_multiply(a.lo, b.hi);140c2 = bc_rand_multiply(a.hi, b.lo);141142carry = bc_rand_addition2(c1, c2);143carry.hi = carry.lo;144carry.lo = 0;145146return bc_rand_addition2(c0, carry);147}148149#endif // BC_RAND_BUILTIN150151/**152* Marks a PRNG as modified. This is important for properly maintaining the153* stack of PRNG's.154* @param r The PRNG to mark as modified.155*/156static void157bc_rand_setModified(BcRNGData* r)158{159#if BC_RAND_BUILTIN160r->inc |= (BcRandState) 1UL;161#else // BC_RAND_BUILTIN162r->inc.lo |= (uint_fast64_t) 1UL;163#endif // BC_RAND_BUILTIN164}165166/**167* Marks a PRNG as not modified. This is important for properly maintaining the168* stack of PRNG's.169* @param r The PRNG to mark as not modified.170*/171static void172bc_rand_clearModified(BcRNGData* r)173{174#if BC_RAND_BUILTIN175r->inc &= ~((BcRandState) 1UL);176#else // BC_RAND_BUILTIN177r->inc.lo &= ~(1UL);178#endif // BC_RAND_BUILTIN179}180181/**182* Copies a PRNG to another and marks the copy as modified if it already was or183* marks it modified if it already was.184* @param d The destination PRNG.185* @param s The source PRNG.186*/187static void188bc_rand_copy(BcRNGData* d, BcRNGData* s)189{190bool unmod = BC_RAND_NOTMODIFIED(d);191192// NOLINTNEXTLINE193memcpy(d, s, sizeof(BcRNGData));194195if (!unmod) bc_rand_setModified(d);196else if (!BC_RAND_NOTMODIFIED(s)) bc_rand_clearModified(d);197}198199#ifndef _WIN32200201/**202* Reads random data from a file.203* @param ptr A pointer to the file, as a void pointer.204* @return The random data as an unsigned long.205*/206static ulong207bc_rand_frand(void* ptr)208{209ulong buf[1];210int fd;211ssize_t nread;212213assert(ptr != NULL);214215fd = *((int*) ptr);216217nread = read(fd, buf, sizeof(ulong));218219if (BC_ERR(nread != sizeof(ulong))) bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);220221return *((ulong*) buf);222}223#else // _WIN32224225/**226* Reads random data from BCryptGenRandom().227* @param ptr An unused parameter.228* @return The random data as an unsigned long.229*/230static ulong231bc_rand_winrand(void* ptr)232{233ulong buf[1];234NTSTATUS s;235236BC_UNUSED(ptr);237238buf[0] = 0;239240s = BCryptGenRandom(NULL, (char*) buf, sizeof(ulong),241BCRYPT_USE_SYSTEM_PREFERRED_RNG);242243if (BC_ERR(!BCRYPT_SUCCESS(s))) buf[0] = 0;244245return buf[0];246}247#endif // _WIN32248249/**250* Reads random data from rand(), byte-by-byte because rand() is only guaranteed251* to return 15 bits of random data. This is the final fallback and is not252* preferred as it is possible to access cryptographically-secure PRNG's on most253* systems.254* @param ptr An unused parameter.255* @return The random data as an unsigned long.256*/257static ulong258bc_rand_rand(void* ptr)259{260size_t i;261ulong res = 0;262263BC_UNUSED(ptr);264265// Fill up the unsigned long byte-by-byte.266for (i = 0; i < sizeof(ulong); ++i)267{268res |= ((ulong) (rand() & BC_RAND_SRAND_BITS)) << (i * CHAR_BIT);269}270271return res;272}273274/**275* Returns the actual increment of the PRNG, including the required last odd276* bit.277* @param r The PRNG.278* @return The increment of the PRNG, including the last odd bit.279*/280static BcRandState281bc_rand_inc(BcRNGData* r)282{283BcRandState inc;284285#if BC_RAND_BUILTIN286inc = r->inc | 1;287#else // BC_RAND_BUILTIN288inc.lo = r->inc.lo | 1;289inc.hi = r->inc.hi;290#endif // BC_RAND_BUILTIN291292return inc;293}294295/**296* Sets up the increment for the PRNG.297* @param r The PRNG whose increment will be set up.298*/299static void300bc_rand_setupInc(BcRNGData* r)301{302#if BC_RAND_BUILTIN303r->inc <<= 1UL;304#else // BC_RAND_BUILTIN305r->inc.hi <<= 1UL;306r->inc.hi |= (r->inc.lo & (1UL << (BC_LONG_BIT - 1))) >> (BC_LONG_BIT - 1);307r->inc.lo <<= 1UL;308#endif // BC_RAND_BUILTIN309}310311/**312* Seeds the state of a PRNG.313* @param state The return parameter; the state to seed.314* @param val1 The lower half of the state.315* @param val2 The upper half of the state.316*/317static void318bc_rand_seedState(BcRandState* state, ulong val1, ulong val2)319{320#if BC_RAND_BUILTIN321*state = ((BcRandState) val1) | ((BcRandState) val2) << (BC_LONG_BIT);322#else // BC_RAND_BUILTIN323state->lo = val1;324state->hi = val2;325#endif // BC_RAND_BUILTIN326}327328/**329* Seeds a PRNG.330* @param r The return parameter; the PRNG to seed.331* @param state1 The lower half of the state.332* @param state2 The upper half of the state.333* @param inc1 The lower half of the increment.334* @param inc2 The upper half of the increment.335*/336static void337bc_rand_seedRNG(BcRNGData* r, ulong state1, ulong state2, ulong inc1,338ulong inc2)339{340bc_rand_seedState(&r->state, state1, state2);341bc_rand_seedState(&r->inc, inc1, inc2);342bc_rand_setupInc(r);343}344345/**346* Fills a PRNG with random data to seed it.347* @param r The PRNG.348* @param fulong The function to fill an unsigned long.349* @param ptr The parameter to pass to @a fulong.350*/351static void352bc_rand_fill(BcRNGData* r, BcRandUlong fulong, void* ptr)353{354ulong state1, state2, inc1, inc2;355356state1 = fulong(ptr);357state2 = fulong(ptr);358359inc1 = fulong(ptr);360inc2 = fulong(ptr);361362bc_rand_seedRNG(r, state1, state2, inc1, inc2);363}364365/**366* Executes the "step" portion of a PCG udpate.367* @param r The PRNG.368*/369static void370bc_rand_step(BcRNGData* r)371{372BcRandState temp = bc_rand_mul2(r->state, bc_rand_multiplier);373r->state = bc_rand_add2(temp, bc_rand_inc(r));374}375376/**377* Returns the new output of PCG.378* @param r The PRNG.379* @return The new output from the PRNG.380*/381static BcRand382bc_rand_output(BcRNGData* r)383{384return BC_RAND_ROT(BC_RAND_FOLD(r->state), BC_RAND_ROTAMT(r->state));385}386387/**388* Seeds every PRNG on the PRNG stack between the top and @a idx that has not389* been seeded.390* @param r The PRNG stack.391* @param rng The PRNG on the top of the stack. Must have been seeded.392*/393static void394bc_rand_seedZeroes(BcRNG* r, BcRNGData* rng, size_t idx)395{396BcRNGData* rng2;397398// Just return if there are none to do.399if (r->v.len <= idx) return;400401// Get the first PRNG that might need to be seeded.402rng2 = bc_vec_item_rev(&r->v, idx);403404// Does it need seeding? Then it, and maybe more, do.405if (BC_RAND_ZERO(rng2))406{407size_t i;408409// Seed the ones that need seeding.410for (i = 1; i < r->v.len; ++i)411{412bc_rand_copy(bc_vec_item_rev(&r->v, i), rng);413}414}415}416417void418bc_rand_srand(BcRNGData* rng)419{420int fd = 0;421422BC_SIG_LOCK;423424#ifndef _WIN32425426// Try /dev/urandom first.427fd = open("/dev/urandom", O_RDONLY);428429if (BC_NO_ERR(fd >= 0))430{431bc_rand_fill(rng, bc_rand_frand, &fd);432close(fd);433}434else435{436// Try /dev/random second.437fd = open("/dev/random", O_RDONLY);438439if (BC_NO_ERR(fd >= 0))440{441bc_rand_fill(rng, bc_rand_frand, &fd);442close(fd);443}444}445#else // _WIN32446// Try BCryptGenRandom first.447bc_rand_fill(rng, bc_rand_winrand, NULL);448#endif // _WIN32449450// Fallback to rand() until the thing is seeded.451while (BC_ERR(BC_RAND_ZERO(rng)))452{453bc_rand_fill(rng, bc_rand_rand, NULL);454}455456BC_SIG_UNLOCK;457}458459/**460* Propagates a change to the PRNG to all PRNG's in the stack that should have461* it. The ones that should have it are laid out in the manpages.462* @param r The PRNG stack.463* @param rng The PRNG that will be used to seed the others.464*/465static void466bc_rand_propagate(BcRNG* r, BcRNGData* rng)467{468// Just return if there are none to do.469if (r->v.len <= 1) return;470471// If the PRNG has not been modified...472if (BC_RAND_NOTMODIFIED(rng))473{474size_t i;475bool go = true;476477// Find the first PRNG that is modified and seed the others.478for (i = 1; go && i < r->v.len; ++i)479{480BcRNGData* rng2 = bc_vec_item_rev(&r->v, i);481482go = BC_RAND_NOTMODIFIED(rng2);483484bc_rand_copy(rng2, rng);485}486487// Seed everything else.488bc_rand_seedZeroes(r, rng, i);489}490// Seed everything.491else bc_rand_seedZeroes(r, rng, 1);492}493494BcRand495bc_rand_int(BcRNG* r)496{497// Get the actual PRNG.498BcRNGData* rng = bc_vec_top(&r->v);499BcRand res;500501// Make sure the PRNG is seeded.502if (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_srand(rng);503504BC_SIG_LOCK;505506// This is the important part of the PRNG. This is the stuff from PCG.507bc_rand_step(rng);508bc_rand_propagate(r, rng);509res = bc_rand_output(rng);510511BC_SIG_UNLOCK;512513return res;514}515516BcRand517bc_rand_bounded(BcRNG* r, BcRand bound)518{519BcRand rand;520BcRand threshold;521522// Calculate the threshold below which we have to try again.523threshold = (0 - bound) % bound;524525do526{527rand = bc_rand_int(r);528}529while (rand < threshold);530531return rand % bound;532}533534void535bc_rand_seed(BcRNG* r, ulong state1, ulong state2, ulong inc1, ulong inc2)536{537// Get the actual PRNG.538BcRNGData* rng = bc_vec_top(&r->v);539540// Seed and set up the PRNG's increment.541bc_rand_seedState(&rng->inc, inc1, inc2);542bc_rand_setupInc(rng);543bc_rand_setModified(rng);544545// If the state is 0, use the increment as the state. Otherwise, seed it546// with the state.547if (!state1 && !state2)548{549// NOLINTNEXTLINE550memcpy(&rng->state, &rng->inc, sizeof(BcRandState));551bc_rand_step(rng);552}553else bc_rand_seedState(&rng->state, state1, state2);554555// Propagate the change to PRNG's that need it.556bc_rand_propagate(r, rng);557}558559/**560* Returns the increment in the PRNG *without* the odd bit and also with being561* shifted one bit down.562* @param r The PRNG.563* @return The increment without the odd bit and with being shifted one bit564* down.565*/566static BcRandState567bc_rand_getInc(BcRNGData* r)568{569BcRandState res;570571#if BC_RAND_BUILTIN572res = r->inc >> 1;573#else // BC_RAND_BUILTIN574res = r->inc;575res.lo >>= 1;576res.lo |= (res.hi & 1) << (BC_LONG_BIT - 1);577res.hi >>= 1;578#endif // BC_RAND_BUILTIN579580return res;581}582583void584bc_rand_getRands(BcRNG* r, BcRand* s1, BcRand* s2, BcRand* i1, BcRand* i2)585{586BcRandState inc;587BcRNGData* rng = bc_vec_top(&r->v);588589if (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_srand(rng);590591// Get the increment.592inc = bc_rand_getInc(rng);593594// Chop the state.595*s1 = BC_RAND_TRUNC(rng->state);596*s2 = BC_RAND_CHOP(rng->state);597598// Chop the increment.599*i1 = BC_RAND_TRUNC(inc);600*i2 = BC_RAND_CHOP(inc);601}602603void604bc_rand_push(BcRNG* r)605{606BcRNGData* rng = bc_vec_pushEmpty(&r->v);607608// Make sure the PRNG is properly zeroed because that marks it as needing to609// be seeded.610// NOLINTNEXTLINE611memset(rng, 0, sizeof(BcRNGData));612613// If there is another item, copy it too.614if (r->v.len > 1) bc_rand_copy(rng, bc_vec_item_rev(&r->v, 1));615}616617void618bc_rand_pop(BcRNG* r, bool reset)619{620bc_vec_npop(&r->v, reset ? r->v.len - 1 : 1);621}622623void624bc_rand_init(BcRNG* r)625{626BC_SIG_ASSERT_LOCKED;627bc_vec_init(&r->v, sizeof(BcRNGData), BC_DTOR_NONE);628bc_rand_push(r);629}630631#if BC_RAND_USE_FREE632void633bc_rand_free(BcRNG* r)634{635BC_SIG_ASSERT_LOCKED;636bc_vec_free(&r->v);637}638#endif // BC_RAND_USE_FREE639640#endif // BC_ENABLE_EXTRA_MATH641642643