1 /* 2 * ***************************************************************************** 3 * 4 * Parts of this code are adapted from the following: 5 * 6 * PCG, A Family of Better Random Number Generators. 7 * 8 * You can find the original source code at: 9 * https://github.com/imneme/pcg-c 10 * 11 * ----------------------------------------------------------------------------- 12 * 13 * This code is under the following license: 14 * 15 * Copyright (c) 2014-2017 Melissa O'Neill and PCG Project contributors 16 * Copyright (c) 2018-2024 Gavin D. Howard and contributors. 17 * 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: 24 * 25 * The above copyright notice and this permission notice shall be included in 26 * all copies or substantial portions of the Software. 27 * 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 34 * SOFTWARE. 35 * 36 * ***************************************************************************** 37 * 38 * Code for the RNG. 39 * 40 */ 41 42 #include <assert.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <time.h> 46 #include <fcntl.h> 47 48 #ifndef _WIN32 49 #include <unistd.h> 50 #else // _WIN32 51 #include <Windows.h> 52 #include <bcrypt.h> 53 #endif // _WIN32 54 55 #include <status.h> 56 #include <rand.h> 57 #include <vm.h> 58 59 #if BC_ENABLE_EXTRA_MATH 60 61 #if !BC_RAND_BUILTIN 62 63 /** 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. 68 */ 69 static BcRandState 70 bc_rand_addition(uint_fast64_t a, uint_fast64_t b) 71 { 72 BcRandState res; 73 74 res.lo = a + b; 75 res.hi = (res.lo < a); 76 77 return res; 78 } 79 80 /** 81 * Adds two 128-bit values and discards the overflow. 82 * @param a The first operand. 83 * @param b The second operand. 84 * @return The sum, without overflow. 85 */ 86 static BcRandState 87 bc_rand_addition2(BcRandState a, BcRandState b) 88 { 89 BcRandState temp, res; 90 91 res = bc_rand_addition(a.lo, b.lo); 92 temp = bc_rand_addition(a.hi, b.hi); 93 res.hi += temp.lo; 94 95 return res; 96 } 97 98 /** 99 * Multiplies two 64-bit values and preserves the overflow. 100 * @param a The first operand. 101 * @param b The second operand. 102 * @return The product, including overflow. 103 */ 104 static BcRandState 105 bc_rand_multiply(uint_fast64_t a, uint_fast64_t b) 106 { 107 uint_fast64_t al, ah, bl, bh, c0, c1, c2, c3; 108 BcRandState carry, res; 109 110 al = BC_RAND_TRUNC32(a); 111 ah = BC_RAND_CHOP32(a); 112 bl = BC_RAND_TRUNC32(b); 113 bh = BC_RAND_CHOP32(b); 114 115 c0 = al * bl; 116 c1 = al * bh; 117 c2 = ah * bl; 118 c3 = ah * bh; 119 120 carry = bc_rand_addition(c1, c2); 121 122 res = bc_rand_addition(c0, (BC_RAND_TRUNC32(carry.lo)) << 32); 123 res.hi += BC_RAND_CHOP32(carry.lo) + c3 + (carry.hi << 32); 124 125 return res; 126 } 127 128 /** 129 * Multiplies two 128-bit values and discards the overflow. 130 * @param a The first operand. 131 * @param b The second operand. 132 * @return The product, without overflow. 133 */ 134 static BcRandState 135 bc_rand_multiply2(BcRandState a, BcRandState b) 136 { 137 BcRandState c0, c1, c2, carry; 138 139 c0 = bc_rand_multiply(a.lo, b.lo); 140 c1 = bc_rand_multiply(a.lo, b.hi); 141 c2 = bc_rand_multiply(a.hi, b.lo); 142 143 carry = bc_rand_addition2(c1, c2); 144 carry.hi = carry.lo; 145 carry.lo = 0; 146 147 return bc_rand_addition2(c0, carry); 148 } 149 150 #endif // BC_RAND_BUILTIN 151 152 /** 153 * Marks a PRNG as modified. This is important for properly maintaining the 154 * stack of PRNG's. 155 * @param r The PRNG to mark as modified. 156 */ 157 static void 158 bc_rand_setModified(BcRNGData* r) 159 { 160 #if BC_RAND_BUILTIN 161 r->inc |= (BcRandState) 1UL; 162 #else // BC_RAND_BUILTIN 163 r->inc.lo |= (uint_fast64_t) 1UL; 164 #endif // BC_RAND_BUILTIN 165 } 166 167 /** 168 * Marks a PRNG as not modified. This is important for properly maintaining the 169 * stack of PRNG's. 170 * @param r The PRNG to mark as not modified. 171 */ 172 static void 173 bc_rand_clearModified(BcRNGData* r) 174 { 175 #if BC_RAND_BUILTIN 176 r->inc &= ~((BcRandState) 1UL); 177 #else // BC_RAND_BUILTIN 178 r->inc.lo &= ~(1UL); 179 #endif // BC_RAND_BUILTIN 180 } 181 182 /** 183 * Copies a PRNG to another and marks the copy as modified if it already was or 184 * marks it modified if it already was. 185 * @param d The destination PRNG. 186 * @param s The source PRNG. 187 */ 188 static void 189 bc_rand_copy(BcRNGData* d, BcRNGData* s) 190 { 191 bool unmod = BC_RAND_NOTMODIFIED(d); 192 193 // NOLINTNEXTLINE 194 memcpy(d, s, sizeof(BcRNGData)); 195 196 if (!unmod) bc_rand_setModified(d); 197 else if (!BC_RAND_NOTMODIFIED(s)) bc_rand_clearModified(d); 198 } 199 200 #ifndef _WIN32 201 202 /** 203 * Reads random data from a file. 204 * @param ptr A pointer to the file, as a void pointer. 205 * @return The random data as an unsigned long. 206 */ 207 static ulong 208 bc_rand_frand(void* ptr) 209 { 210 ulong buf[1]; 211 int fd; 212 ssize_t nread; 213 214 assert(ptr != NULL); 215 216 fd = *((int*) ptr); 217 218 nread = read(fd, buf, sizeof(ulong)); 219 220 if (BC_ERR(nread != sizeof(ulong))) bc_vm_fatalError(BC_ERR_FATAL_IO_ERR); 221 222 return *((ulong*) buf); 223 } 224 #else // _WIN32 225 226 /** 227 * Reads random data from BCryptGenRandom(). 228 * @param ptr An unused parameter. 229 * @return The random data as an unsigned long. 230 */ 231 static ulong 232 bc_rand_winrand(void* ptr) 233 { 234 ulong buf[1]; 235 NTSTATUS s; 236 237 BC_UNUSED(ptr); 238 239 buf[0] = 0; 240 241 s = BCryptGenRandom(NULL, (char*) buf, sizeof(ulong), 242 BCRYPT_USE_SYSTEM_PREFERRED_RNG); 243 244 if (BC_ERR(!BCRYPT_SUCCESS(s))) buf[0] = 0; 245 246 return buf[0]; 247 } 248 #endif // _WIN32 249 250 /** 251 * Reads random data from rand(), byte-by-byte because rand() is only guaranteed 252 * to return 15 bits of random data. This is the final fallback and is not 253 * preferred as it is possible to access cryptographically-secure PRNG's on most 254 * systems. 255 * @param ptr An unused parameter. 256 * @return The random data as an unsigned long. 257 */ 258 static ulong 259 bc_rand_rand(void* ptr) 260 { 261 size_t i; 262 ulong res = 0; 263 264 BC_UNUSED(ptr); 265 266 // Fill up the unsigned long byte-by-byte. 267 for (i = 0; i < sizeof(ulong); ++i) 268 { 269 res |= ((ulong) (rand() & BC_RAND_SRAND_BITS)) << (i * CHAR_BIT); 270 } 271 272 return res; 273 } 274 275 /** 276 * Returns the actual increment of the PRNG, including the required last odd 277 * bit. 278 * @param r The PRNG. 279 * @return The increment of the PRNG, including the last odd bit. 280 */ 281 static BcRandState 282 bc_rand_inc(BcRNGData* r) 283 { 284 BcRandState inc; 285 286 #if BC_RAND_BUILTIN 287 inc = r->inc | 1; 288 #else // BC_RAND_BUILTIN 289 inc.lo = r->inc.lo | 1; 290 inc.hi = r->inc.hi; 291 #endif // BC_RAND_BUILTIN 292 293 return inc; 294 } 295 296 /** 297 * Sets up the increment for the PRNG. 298 * @param r The PRNG whose increment will be set up. 299 */ 300 static void 301 bc_rand_setupInc(BcRNGData* r) 302 { 303 #if BC_RAND_BUILTIN 304 r->inc <<= 1UL; 305 #else // BC_RAND_BUILTIN 306 r->inc.hi <<= 1UL; 307 r->inc.hi |= (r->inc.lo & (1UL << (BC_LONG_BIT - 1))) >> (BC_LONG_BIT - 1); 308 r->inc.lo <<= 1UL; 309 #endif // BC_RAND_BUILTIN 310 } 311 312 /** 313 * Seeds the state of a PRNG. 314 * @param state The return parameter; the state to seed. 315 * @param val1 The lower half of the state. 316 * @param val2 The upper half of the state. 317 */ 318 static void 319 bc_rand_seedState(BcRandState* state, ulong val1, ulong val2) 320 { 321 #if BC_RAND_BUILTIN 322 *state = ((BcRandState) val1) | ((BcRandState) val2) << (BC_LONG_BIT); 323 #else // BC_RAND_BUILTIN 324 state->lo = val1; 325 state->hi = val2; 326 #endif // BC_RAND_BUILTIN 327 } 328 329 /** 330 * Seeds a PRNG. 331 * @param r The return parameter; the PRNG to seed. 332 * @param state1 The lower half of the state. 333 * @param state2 The upper half of the state. 334 * @param inc1 The lower half of the increment. 335 * @param inc2 The upper half of the increment. 336 */ 337 static void 338 bc_rand_seedRNG(BcRNGData* r, ulong state1, ulong state2, ulong inc1, 339 ulong inc2) 340 { 341 bc_rand_seedState(&r->state, state1, state2); 342 bc_rand_seedState(&r->inc, inc1, inc2); 343 bc_rand_setupInc(r); 344 } 345 346 /** 347 * Fills a PRNG with random data to seed it. 348 * @param r The PRNG. 349 * @param fulong The function to fill an unsigned long. 350 * @param ptr The parameter to pass to @a fulong. 351 */ 352 static void 353 bc_rand_fill(BcRNGData* r, BcRandUlong fulong, void* ptr) 354 { 355 ulong state1, state2, inc1, inc2; 356 357 state1 = fulong(ptr); 358 state2 = fulong(ptr); 359 360 inc1 = fulong(ptr); 361 inc2 = fulong(ptr); 362 363 bc_rand_seedRNG(r, state1, state2, inc1, inc2); 364 } 365 366 /** 367 * Executes the "step" portion of a PCG udpate. 368 * @param r The PRNG. 369 */ 370 static void 371 bc_rand_step(BcRNGData* r) 372 { 373 BcRandState temp = bc_rand_mul2(r->state, bc_rand_multiplier); 374 r->state = bc_rand_add2(temp, bc_rand_inc(r)); 375 } 376 377 /** 378 * Returns the new output of PCG. 379 * @param r The PRNG. 380 * @return The new output from the PRNG. 381 */ 382 static BcRand 383 bc_rand_output(BcRNGData* r) 384 { 385 return BC_RAND_ROT(BC_RAND_FOLD(r->state), BC_RAND_ROTAMT(r->state)); 386 } 387 388 /** 389 * Seeds every PRNG on the PRNG stack between the top and @a idx that has not 390 * been seeded. 391 * @param r The PRNG stack. 392 * @param rng The PRNG on the top of the stack. Must have been seeded. 393 */ 394 static void 395 bc_rand_seedZeroes(BcRNG* r, BcRNGData* rng, size_t idx) 396 { 397 BcRNGData* rng2; 398 399 // Just return if there are none to do. 400 if (r->v.len <= idx) return; 401 402 // Get the first PRNG that might need to be seeded. 403 rng2 = bc_vec_item_rev(&r->v, idx); 404 405 // Does it need seeding? Then it, and maybe more, do. 406 if (BC_RAND_ZERO(rng2)) 407 { 408 size_t i; 409 410 // Seed the ones that need seeding. 411 for (i = 1; i < r->v.len; ++i) 412 { 413 bc_rand_copy(bc_vec_item_rev(&r->v, i), rng); 414 } 415 } 416 } 417 418 void 419 bc_rand_srand(BcRNGData* rng) 420 { 421 int fd = 0; 422 423 BC_SIG_LOCK; 424 425 #ifndef _WIN32 426 427 // Try /dev/urandom first. 428 fd = open("/dev/urandom", O_RDONLY); 429 430 if (BC_NO_ERR(fd >= 0)) 431 { 432 bc_rand_fill(rng, bc_rand_frand, &fd); 433 close(fd); 434 } 435 else 436 { 437 // Try /dev/random second. 438 fd = open("/dev/random", O_RDONLY); 439 440 if (BC_NO_ERR(fd >= 0)) 441 { 442 bc_rand_fill(rng, bc_rand_frand, &fd); 443 close(fd); 444 } 445 } 446 #else // _WIN32 447 // Try BCryptGenRandom first. 448 bc_rand_fill(rng, bc_rand_winrand, NULL); 449 #endif // _WIN32 450 451 // Fallback to rand() until the thing is seeded. 452 while (BC_ERR(BC_RAND_ZERO(rng))) 453 { 454 bc_rand_fill(rng, bc_rand_rand, NULL); 455 } 456 457 BC_SIG_UNLOCK; 458 } 459 460 /** 461 * Propagates a change to the PRNG to all PRNG's in the stack that should have 462 * it. The ones that should have it are laid out in the manpages. 463 * @param r The PRNG stack. 464 * @param rng The PRNG that will be used to seed the others. 465 */ 466 static void 467 bc_rand_propagate(BcRNG* r, BcRNGData* rng) 468 { 469 // Just return if there are none to do. 470 if (r->v.len <= 1) return; 471 472 // If the PRNG has not been modified... 473 if (BC_RAND_NOTMODIFIED(rng)) 474 { 475 size_t i; 476 bool go = true; 477 478 // Find the first PRNG that is modified and seed the others. 479 for (i = 1; go && i < r->v.len; ++i) 480 { 481 BcRNGData* rng2 = bc_vec_item_rev(&r->v, i); 482 483 go = BC_RAND_NOTMODIFIED(rng2); 484 485 bc_rand_copy(rng2, rng); 486 } 487 488 // Seed everything else. 489 bc_rand_seedZeroes(r, rng, i); 490 } 491 // Seed everything. 492 else bc_rand_seedZeroes(r, rng, 1); 493 } 494 495 BcRand 496 bc_rand_int(BcRNG* r) 497 { 498 // Get the actual PRNG. 499 BcRNGData* rng = bc_vec_top(&r->v); 500 BcRand res; 501 502 // Make sure the PRNG is seeded. 503 if (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_srand(rng); 504 505 BC_SIG_LOCK; 506 507 // This is the important part of the PRNG. This is the stuff from PCG. 508 bc_rand_step(rng); 509 bc_rand_propagate(r, rng); 510 res = bc_rand_output(rng); 511 512 BC_SIG_UNLOCK; 513 514 return res; 515 } 516 517 BcRand 518 bc_rand_bounded(BcRNG* r, BcRand bound) 519 { 520 BcRand rand; 521 BcRand threshold; 522 523 // Calculate the threshold below which we have to try again. 524 threshold = (0 - bound) % bound; 525 526 do 527 { 528 rand = bc_rand_int(r); 529 } 530 while (rand < threshold); 531 532 return rand % bound; 533 } 534 535 void 536 bc_rand_seed(BcRNG* r, ulong state1, ulong state2, ulong inc1, ulong inc2) 537 { 538 // Get the actual PRNG. 539 BcRNGData* rng = bc_vec_top(&r->v); 540 541 // Seed and set up the PRNG's increment. 542 bc_rand_seedState(&rng->inc, inc1, inc2); 543 bc_rand_setupInc(rng); 544 bc_rand_setModified(rng); 545 546 // If the state is 0, use the increment as the state. Otherwise, seed it 547 // with the state. 548 if (!state1 && !state2) 549 { 550 // NOLINTNEXTLINE 551 memcpy(&rng->state, &rng->inc, sizeof(BcRandState)); 552 bc_rand_step(rng); 553 } 554 else bc_rand_seedState(&rng->state, state1, state2); 555 556 // Propagate the change to PRNG's that need it. 557 bc_rand_propagate(r, rng); 558 } 559 560 /** 561 * Returns the increment in the PRNG *without* the odd bit and also with being 562 * shifted one bit down. 563 * @param r The PRNG. 564 * @return The increment without the odd bit and with being shifted one bit 565 * down. 566 */ 567 static BcRandState 568 bc_rand_getInc(BcRNGData* r) 569 { 570 BcRandState res; 571 572 #if BC_RAND_BUILTIN 573 res = r->inc >> 1; 574 #else // BC_RAND_BUILTIN 575 res = r->inc; 576 res.lo >>= 1; 577 res.lo |= (res.hi & 1) << (BC_LONG_BIT - 1); 578 res.hi >>= 1; 579 #endif // BC_RAND_BUILTIN 580 581 return res; 582 } 583 584 void 585 bc_rand_getRands(BcRNG* r, BcRand* s1, BcRand* s2, BcRand* i1, BcRand* i2) 586 { 587 BcRandState inc; 588 BcRNGData* rng = bc_vec_top(&r->v); 589 590 if (BC_ERR(BC_RAND_ZERO(rng))) bc_rand_srand(rng); 591 592 // Get the increment. 593 inc = bc_rand_getInc(rng); 594 595 // Chop the state. 596 *s1 = BC_RAND_TRUNC(rng->state); 597 *s2 = BC_RAND_CHOP(rng->state); 598 599 // Chop the increment. 600 *i1 = BC_RAND_TRUNC(inc); 601 *i2 = BC_RAND_CHOP(inc); 602 } 603 604 void 605 bc_rand_push(BcRNG* r) 606 { 607 BcRNGData* rng = bc_vec_pushEmpty(&r->v); 608 609 // Make sure the PRNG is properly zeroed because that marks it as needing to 610 // be seeded. 611 // NOLINTNEXTLINE 612 memset(rng, 0, sizeof(BcRNGData)); 613 614 // If there is another item, copy it too. 615 if (r->v.len > 1) bc_rand_copy(rng, bc_vec_item_rev(&r->v, 1)); 616 } 617 618 void 619 bc_rand_pop(BcRNG* r, bool reset) 620 { 621 bc_vec_npop(&r->v, reset ? r->v.len - 1 : 1); 622 } 623 624 void 625 bc_rand_init(BcRNG* r) 626 { 627 BC_SIG_ASSERT_LOCKED; 628 bc_vec_init(&r->v, sizeof(BcRNGData), BC_DTOR_NONE); 629 bc_rand_push(r); 630 } 631 632 #if BC_RAND_USE_FREE 633 void 634 bc_rand_free(BcRNG* r) 635 { 636 BC_SIG_ASSERT_LOCKED; 637 bc_vec_free(&r->v); 638 } 639 #endif // BC_RAND_USE_FREE 640 641 #endif // BC_ENABLE_EXTRA_MATH 642