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