xref: /freebsd/contrib/bc/src/rand.c (revision 10041e99a0c29c9f99c4148fc173bb12dd26aa8d)
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