2 * *****************************************************************************
4 * Parts of this code are adapted from the following:
6 * PCG, A Family of Better Random Number Generators.
8 * You can find the original source code at:
9 * https://github.com/imneme/pcg-c
11 * -----------------------------------------------------------------------------
13 * This code is under the following license:
15 * Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors
16 * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
18 * Permission is hereby granted, free of charge, to any person obtaining a copy
19 * of this software and associated documentation files (the "Software"), to deal
20 * in the Software without restriction, including without limitation the rights
21 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22 * copies of the Software, and to permit persons to whom the Software is
23 * furnished to do so, subject to the following conditions:
25 * The above copyright notice and this permission notice shall be included in
26 * all copies or substantial portions of the Software.
28 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36 * *****************************************************************************
59 #if BC_ENABLE_EXTRA_MATH
64 * Adds two 64-bit values and preserves the overflow.
65 * @param a The first operand.
66 * @param b The second operand.
67 * @return The sum, including overflow.
69 static BcRandState bc_rand_addition(uint_fast64_t a, uint_fast64_t b) {
74 res.hi = (res.lo < a);
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.
85 static BcRandState bc_rand_addition2(BcRandState a, BcRandState b) {
87 BcRandState temp, res;
89 res = bc_rand_addition(a.lo, b.lo);
90 temp = bc_rand_addition(a.hi, b.hi);
97 * Multiplies two 64-bit values and preserves the overflow.
98 * @param a The first operand.
99 * @param b The second operand.
100 * @return The product, including overflow.
102 static BcRandState bc_rand_multiply(uint_fast64_t a, uint_fast64_t b) {
104 uint_fast64_t al, ah, bl, bh, c0, c1, c2, c3;
105 BcRandState carry, res;
107 al = BC_RAND_TRUNC32(a);
108 ah = BC_RAND_CHOP32(a);
109 bl = BC_RAND_TRUNC32(b);
110 bh = BC_RAND_CHOP32(b);
117 carry = bc_rand_addition(c1, c2);
119 res = bc_rand_addition(c0, (BC_RAND_TRUNC32(carry.lo)) << 32);
120 res.hi += BC_RAND_CHOP32(carry.lo) + c3 + (carry.hi << 32);
126 * Multiplies two 128-bit values and discards the overflow.
127 * @param a The first operand.
128 * @param b The second operand.
129 * @return The product, without overflow.
131 static BcRandState bc_rand_multiply2(BcRandState a, BcRandState b) {
133 BcRandState c0, c1, c2, carry;
135 c0 = bc_rand_multiply(a.lo, b.lo);
136 c1 = bc_rand_multiply(a.lo, b.hi);
137 c2 = bc_rand_multiply(a.hi, b.lo);
139 carry = bc_rand_addition2(c1, c2);
143 return bc_rand_addition2(c0, carry);
146 #endif // BC_RAND_BUILTIN
149 * Marks a PRNG as modified. This is important for properly maintaining the
151 * @param r The PRNG to mark as modified.
153 static void bc_rand_setModified(BcRNGData *r) {
156 r->inc |= (BcRandState) 1UL;
157 #else // BC_RAND_BUILTIN
158 r->inc.lo |= (uint_fast64_t) 1UL;
159 #endif // BC_RAND_BUILTIN
163 * Marks a PRNG as not modified. This is important for properly maintaining the
165 * @param r The PRNG to mark as not modified.
167 static void bc_rand_clearModified(BcRNGData *r) {
170 r->inc &= ~((BcRandState) 1UL);
171 #else // BC_RAND_BUILTIN
173 #endif // BC_RAND_BUILTIN
177 * Copies a PRNG to another and marks the copy as modified if it already was or
178 * marks it modified if it already was.
179 * @param d The destination PRNG.
180 * @param s The source PRNG.
182 static void bc_rand_copy(BcRNGData *d, BcRNGData *s) {
183 bool unmod = BC_RAND_NOTMODIFIED(d);
184 memcpy(d, s, sizeof(BcRNGData));
185 if (!unmod) bc_rand_setModified(d);
186 else if (!BC_RAND_NOTMODIFIED(s)) bc_rand_clearModified(d);
192 * Reads random data from a file.
193 * @param ptr A pointer to the file, as a void pointer.
194 * @return The random data as an unsigned long.
196 static ulong bc_rand_frand(void* ptr) {
206 nread = read(fd, buf, sizeof(ulong));
208 if (BC_ERR(nread != sizeof(ulong))) bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
210 return *((ulong*)buf);
215 * Reads random data from BCryptGenRandom().
216 * @param ptr An unused parameter.
217 * @return The random data as an unsigned long.
219 static ulong bc_rand_winrand(void *ptr) {
228 s = BCryptGenRandom(NULL, (char*) buf, sizeof(ulong),
229 BCRYPT_USE_SYSTEM_PREFERRED_RNG);
231 if (BC_ERR(!BCRYPT_SUCCESS(s))) buf[0] = 0;
238 * Reads random data from rand(), byte-by-byte because rand() is only guaranteed
239 * to return 15 bits of random data. This is the final fallback and is not
240 * preferred as it is possible to access cryptographically-secure PRNG's on most
242 * @param ptr An unused parameter.
243 * @return The random data as an unsigned long.
245 static ulong bc_rand_rand(void *ptr) {
252 // Fill up the unsigned long byte-by-byte.
253 for (i = 0; i < sizeof(ulong); ++i)
254 res |= ((ulong) (rand() & BC_RAND_SRAND_BITS)) << (i * CHAR_BIT);
260 * Returns the actual increment of the PRNG, including the required last odd
263 * @return The increment of the PRNG, including the last odd bit.
265 static BcRandState bc_rand_inc(BcRNGData *r) {
271 #else // BC_RAND_BUILTIN
272 inc.lo = r->inc.lo | 1;
274 #endif // BC_RAND_BUILTIN
280 * Sets up the increment for the PRNG.
281 * @param r The PRNG whose increment will be set up.
283 static void bc_rand_setupInc(BcRNGData *r) {
287 #else // BC_RAND_BUILTIN
289 r->inc.hi |= (r->inc.lo & (1UL << (BC_LONG_BIT - 1))) >> (BC_LONG_BIT - 1);
291 #endif // BC_RAND_BUILTIN
295 * Seeds the state of a PRNG.
296 * @param state The return parameter; the state to seed.
297 * @param val1 The lower half of the state.
298 * @param val2 The upper half of the state.
300 static void bc_rand_seedState(BcRandState *state, ulong val1, ulong val2) {
303 *state = ((BcRandState) val1) | ((BcRandState) val2) << (BC_LONG_BIT);
304 #else // BC_RAND_BUILTIN
307 #endif // BC_RAND_BUILTIN
312 * @param r The return parameter; the PRNG to seed.
313 * @param state1 The lower half of the state.
314 * @param state2 The upper half of the state.
315 * @param inc1 The lower half of the increment.
316 * @param inc2 The upper half of the increment.
318 static void bc_rand_seedRNG(BcRNGData *r, ulong state1, ulong state2,
319 ulong inc1, ulong inc2)
321 bc_rand_seedState(&r->state, state1, state2);
322 bc_rand_seedState(&r->inc, inc1, inc2);
327 * Fills a PRNG with random data to seed it.
329 * @param fulong The function to fill an unsigned long.
330 * @param ptr The parameter to pass to @a fulong.
332 static void bc_rand_fill(BcRNGData *r, BcRandUlong fulong, void *ptr) {
334 ulong state1, state2, inc1, inc2;
336 state1 = fulong(ptr);
337 state2 = fulong(ptr);
342 bc_rand_seedRNG(r, state1, state2, inc1, inc2);
346 * Executes the "step" portion of a PCG udpate.
349 static void bc_rand_step(BcRNGData *r) {
350 BcRandState temp = bc_rand_mul2(r->state, bc_rand_multiplier);
351 r->state = bc_rand_add2(temp, bc_rand_inc(r));
355 * Returns the new output of PCG.
357 * @return The new output from the PRNG.
359 static BcRand bc_rand_output(BcRNGData *r) {
360 return BC_RAND_ROT(BC_RAND_FOLD(r->state), BC_RAND_ROTAMT(r->state));
364 * Seeds every PRNG on the PRNG stack between the top and @a idx that has not
366 * @param r The PRNG stack.
367 * @param rng The PRNG on the top of the stack. Must have been seeded.
369 static void bc_rand_seedZeroes(BcRNG *r, BcRNGData *rng, size_t idx) {
373 // Just return if there are none to do.
374 if (r->v.len <= idx) return;
376 // Get the first PRNG that might need to be seeded.
377 rng2 = bc_vec_item_rev(&r->v, idx);
379 // Does it need seeding? Then it, and maybe more, do.
380 if (BC_RAND_ZERO(rng2)) {
384 // Seed the ones that need seeding.
385 for (i = 1; i < r->v.len; ++i)
386 bc_rand_copy(bc_vec_item_rev(&r->v, i), rng);
390 void bc_rand_srand(BcRNGData *rng) {
398 // Try /dev/urandom first.
399 fd = open("/dev/urandom", O_RDONLY);
401 if (BC_NO_ERR(fd >= 0)) {
402 bc_rand_fill(rng, bc_rand_frand, &fd);
407 // Try /dev/random second.
408 fd = open("/dev/random", O_RDONLY);
410 if (BC_NO_ERR(fd >= 0)) {
411 bc_rand_fill(rng, bc_rand_frand, &fd);
416 // Try BCryptGenRandom first.
417 bc_rand_fill(rng, bc_rand_winrand, NULL);
420 // Fallback to rand() until the thing is seeded.
421 while (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_fill(rng, bc_rand_rand, NULL);
427 * Propagates a change to the PRNG to all PRNG's in the stack that should have
428 * it. The ones that should have it are laid out in the manpages.
429 * @param r The PRNG stack.
430 * @param rng The PRNG that will be used to seed the others.
432 static void bc_rand_propagate(BcRNG *r, BcRNGData *rng) {
434 // Just return if there are none to do.
435 if (r->v.len <= 1) return;
437 // If the PRNG has not been modified...
438 if (BC_RAND_NOTMODIFIED(rng)) {
443 // Find the first PRNG that is modified and seed the others.
444 for (i = 1; go && i < r->v.len; ++i) {
446 BcRNGData *rng2 = bc_vec_item_rev(&r->v, i);
448 go = BC_RAND_NOTMODIFIED(rng2);
450 bc_rand_copy(rng2, rng);
453 // Seed everything else.
454 bc_rand_seedZeroes(r, rng, i);
457 else bc_rand_seedZeroes(r, rng, 1);
460 BcRand bc_rand_int(BcRNG *r) {
462 // Get the actual PRNG.
463 BcRNGData *rng = bc_vec_top(&r->v);
465 // Make sure the PRNG is seeded.
466 if (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_srand(rng);
468 // This is the important part of the PRNG. This is the stuff from PCG,
469 // including the return statement.
471 bc_rand_propagate(r, rng);
473 return bc_rand_output(rng);
476 BcRand bc_rand_bounded(BcRNG *r, BcRand bound) {
478 // Calculate the threshold below which we have to try again.
479 BcRand rand, threshold = (0 - bound) % bound;
482 rand = bc_rand_int(r);
483 } while (rand < threshold);
488 void bc_rand_seed(BcRNG *r, ulong state1, ulong state2, ulong inc1, ulong inc2)
490 // Get the actual PRNG.
491 BcRNGData *rng = bc_vec_top(&r->v);
493 // Seed and set up the PRNG's increment.
494 bc_rand_seedState(&rng->inc, inc1, inc2);
495 bc_rand_setupInc(rng);
496 bc_rand_setModified(rng);
498 // If the state is 0, use the increment as the state. Otherwise, seed it
500 if (!state1 && !state2) {
501 memcpy(&rng->state, &rng->inc, sizeof(BcRandState));
504 else bc_rand_seedState(&rng->state, state1, state2);
506 // Propagate the change to PRNG's that need it.
507 bc_rand_propagate(r, rng);
511 * Returns the increment in the PRNG *without* the odd bit and also with being
512 * shifted one bit down.
514 * @return The increment without the odd bit and with being shifted one bit
517 static BcRandState bc_rand_getInc(BcRNGData *r) {
523 #else // BC_RAND_BUILTIN
526 res.lo |= (res.hi & 1) << (BC_LONG_BIT - 1);
528 #endif // BC_RAND_BUILTIN
533 void bc_rand_getRands(BcRNG *r, BcRand *s1, BcRand *s2, BcRand *i1, BcRand *i2)
536 BcRNGData *rng = bc_vec_top(&r->v);
538 if (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_srand(rng);
540 // Get the increment.
541 inc = bc_rand_getInc(rng);
544 *s1 = BC_RAND_TRUNC(rng->state);
545 *s2 = BC_RAND_CHOP(rng->state);
547 // Chop the increment.
548 *i1 = BC_RAND_TRUNC(inc);
549 *i2 = BC_RAND_CHOP(inc);
552 void bc_rand_push(BcRNG *r) {
554 BcRNGData *rng = bc_vec_pushEmpty(&r->v);
556 // Make sure the PRNG is properly zeroed because that marks it as needing to
558 memset(rng, 0, sizeof(BcRNGData));
560 // If there is another item, copy it too.
561 if (r->v.len > 1) bc_rand_copy(rng, bc_vec_item_rev(&r->v, 1));
564 void bc_rand_pop(BcRNG *r, bool reset) {
565 bc_vec_npop(&r->v, reset ? r->v.len - 1 : 1);
568 void bc_rand_init(BcRNG *r) {
569 BC_SIG_ASSERT_LOCKED;
570 bc_vec_init(&r->v, sizeof(BcRNGData), BC_DTOR_NONE);
575 void bc_rand_free(BcRNG *r) {
576 BC_SIG_ASSERT_LOCKED;
579 #endif // BC_RAND_USE_FREE
581 #endif // BC_ENABLE_EXTRA_MATH