1 /++ 2 $(SCRIPT inhibitQuickIndex = 1;) 3 Uniform random engines. 4 5 $(B Sections:) 6 $(LINK2 #Convenience, Convenience) 7 • $(LINK2 #Entropy, Entropy) 8 • $(LINK2 #ThreadLocal, Thread-Local) 9 • $(LINK2 #Traits, Traits) 10 • $(LINK2 #CInterface, C Interface) 11 12 $(BOOKTABLE 13 14 $(LEADINGROW <a id="Convenience"></a>Convenience) 15 $(TR 16 $(RROW Random, Default random number _engine)) 17 $(RROW rne, Per-thread uniquely-seeded instance of default `Random`. Requires $(LINK2 https://en.wikipedia.org/wiki/Thread-local_storage, TLS).) 18 19 $(LEADINGROW <a id="Entropy"></a>Entropy) 20 $(TR 21 $(RROW unpredictableSeed, Seed of `size_t` using system entropy. May use `unpredictableSeed!UIntType` for unsigned integers of different sizes.) 22 $(RROW genRandomNonBlocking, Fills a buffer with system entropy, returning number of bytes copied or negative number on error) 23 $(RROW genRandomBlocking, Fills a buffer with system entropy, possibly waiting if the system believes it has insufficient entropy. Returns 0 on success.)) 24 25 $(LEADINGROW <a id="ThreadLocal"></a>Thread-Local (when $(LINK2 https://en.wikipedia.org/wiki/Thread-local_storage, TLS) enabled)) 26 $(TR 27 $(TR $(TDNW $(LREF threadLocal)`!(Engine)`) $(TD Per-thread uniquely-seeded instance of any specified `Engine`. Requires $(LINK2 https://en.wikipedia.org/wiki/Thread-local_storage, TLS).)) 28 $(TR $(TDNW $(LREF threadLocalPtr)`!(Engine)`) $(TD `@safe` pointer to `threadLocal!Engine`. Always initializes before return. $(I Warning: do not share between threads!))) 29 $(TR $(TDNW $(LREF threadLocalInitialized)`!(Engine)`) $(TD Explicitly manipulate "is seeded" flag for thread-local instance. Not needed by most library users.)) 30 $(TR $(TDNW $(LREF setThreadLocalSeed)`!(Engine, A...)`) $(TD Initialize thread-local `Engine` with a known seed rather than a random seed.)) 31 ) 32 33 $(LEADINGROW <a id="Traits"></a>Traits) 34 $(TR 35 $(RROW EngineReturnType, Get return type of random number _engine's `opCall()`) 36 $(RROW isRandomEngine, Check if is random number _engine) 37 $(RROW isSaturatedRandomEngine, Check if random number _engine `G` such that `G.max == EngineReturnType!(G).max`) 38 $(RROW preferHighBits, Are the high bits of the _engine's output known to have better statistical properties than the low bits?)) 39 40 $(LEADINGROW <a id="CInterface"></a>C Interface) 41 $(RROW mir_random_engine_ctor, Perform any necessary setup. Automatically called by DRuntime.) 42 $(RROW mir_random_engine_dtor, Release any resources. Automatically called by DRuntime.) 43 $(RROW mir_random_genRandomNonBlocking, External name for $(LREF genRandomNonBlocking)) 44 $(RROW mir_random_genRandomBlocking, External name for $(LREF genRandomBlocking)) 45 ) 46 47 Copyright: Ilya Yaroshenko 2016-. 48 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 49 Authors: Ilya Yaroshenko 50 51 Macros: 52 T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) 53 RROW = $(TR $(TDNW $(LREF $1)) $(TD $+)) 54 +/ 55 module mir.random.engine; 56 57 version (OSX) 58 version = Darwin; 59 else version (iOS) 60 version = Darwin; 61 else version (TVOS) 62 version = Darwin; 63 else version (WatchOS) 64 version = Darwin; 65 66 // A secure arc4random implementation that uses some modern algorithm rather 67 // than ARC4 may be used synonymously with non-blocking system entropy. 68 version (CRuntime_Bionic) 69 version = SecureARC4Random; // ChaCha20 70 version (Darwin) 71 version = SecureARC4Random; // AES 72 version (OpenBSD) 73 version = SecureARC4Random; // ChaCha20 74 version (NetBSD) 75 version = SecureARC4Random; // ChaCha20 76 77 // A legacy arc4random should not be used when cryptographic security 78 // is required but may used for `unpredictableSeed`. 79 version (CRuntime_UClibc) 80 version = LegacyARC4Random; // ARC4 81 version (FreeBSD) 82 version = LegacyARC4Random; // ARC4 83 version (DragonFlyBSD) 84 version = LegacyARC4Random; // ARC4 85 version (BSD) 86 version = LegacyARC4Random; // Unknown implementation 87 88 version (SecureARC4Random) 89 version = AnyARC4Random; 90 version (LegacyARC4Random) 91 version = AnyARC4Random; 92 93 version (D_betterC) 94 private enum bool THREAD_LOCAL_STORAGE_AVAILABLE = false; 95 else 96 private enum bool THREAD_LOCAL_STORAGE_AVAILABLE = __traits(compiles, { static size_t x = 0; }); 97 98 import std.traits; 99 100 import mir.random.engine.mersenne_twister; 101 102 /++ 103 Like `std.traits.ReturnType!T` but it works even if 104 T.opCall is a function template. 105 +/ 106 template EngineReturnType(T) 107 { 108 import std.traits : ReturnType; 109 static if (is(ReturnType!T)) 110 alias EngineReturnType = ReturnType!T; 111 else 112 alias EngineReturnType = typeof(T.init()); 113 } 114 115 /++ 116 Test if T is a random engine. 117 A type should define `enum isRandomEngine = true;` to be a random engine. 118 +/ 119 template isRandomEngine(T) 120 { 121 static if (is(typeof(T.isRandomEngine) : bool) && is(typeof(T.init()))) 122 { 123 private alias R = typeof(T.init()); 124 static if (T.isRandomEngine && isUnsigned!R) 125 enum isRandomEngine = is(typeof({ 126 enum max = T.max; 127 static assert(is(typeof(T.max) == R)); 128 })); 129 else enum isRandomEngine = false; 130 } 131 else enum isRandomEngine = false; 132 } 133 134 /++ 135 Test if T is a saturated random-bit generator. 136 A random number generator is saturated if `T.max == ReturnType!T.max`. 137 A type should define `enum isRandomEngine = true;` to be a random engine. 138 +/ 139 template isSaturatedRandomEngine(T) 140 { 141 static if (isRandomEngine!T) 142 enum isSaturatedRandomEngine = T.max == EngineReturnType!T.max; 143 else 144 enum isSaturatedRandomEngine = false; 145 } 146 147 /++ 148 Are the high bits of the engine's output known to have 149 better statistical properties than the low bits of the 150 output? This property is set by checking the value of 151 an optional enum named `preferHighBits`. If the property 152 is missing it is treated as false. 153 154 This should be specified as true for: 155 <ul> 156 <li>linear congruential generators with power-of-2 modulus</li> 157 <li>xorshift+ family</li> 158 <li>xorshift* family</li> 159 <li>in principle any generator whose final operation is something like 160 multiplication or addition in which the high bits depend on the low bits 161 but the low bits are unaffected by the high bits.</li> 162 </ul> 163 +/ 164 template preferHighBits(G) 165 if (isSaturatedRandomEngine!G) 166 { 167 static if (__traits(compiles, { enum bool e = G.preferHighBits; })) 168 private enum bool preferHighBits = G.preferHighBits; 169 else 170 private enum bool preferHighBits = false; 171 } 172 173 /* 174 * Marker indicating it's safe to construct from void 175 * (i.e. the constructor doesn't depend on the struct 176 * being in an initially valid state). 177 * Either checks an explicit flag `_isVoidInitOkay` 178 * or tests to make sure that the structure contains 179 * nothing that looks like a pointer or an index into 180 * an array. Also ensures that there is not an elaborate 181 * destructor since it could be called when the struct 182 * is in an invalid state. 183 * Non-public because we don't want to commit to this 184 * design. 185 */ 186 package template _isVoidInitOkay(G) if (isRandomEngine!G && is(G == struct)) 187 { 188 static if (is(typeof(G._isVoidInitOkay) : bool)) 189 enum bool _isVoidInitOkay = G._isVoidInitOkay; 190 else static if (!hasNested!G && !hasElaborateDestructor!G) 191 { 192 import std.meta : allSatisfy; 193 static if (allSatisfy!(isScalarType, FieldTypeTuple!G)) 194 //All members are scalars. 195 enum bool _isVoidInitOkay = true; 196 else static if (FieldTypeTuple!(G).length == 1 && isStaticArray!(FieldTypeTuple!(G)[0])) 197 //Only has one member which is a static array of scalars. 198 enum bool _isVoidInitOkay = isScalarType!(typeof(FieldTypeTuple!(G)[0].init[0])); 199 else 200 enum bool _isVoidInitOkay = false; 201 } 202 else 203 enum bool _isVoidInitOkay = false; 204 } 205 @nogc nothrow pure @safe version(mir_random_test) 206 { 207 import mir.random.engine.mersenne_twister: Mt19937, Mt19937_64; 208 //Ensure that this property is set for the Mersenne Twister, 209 //whose internal state is huge enough for this to potentially 210 //matter: 211 static assert(_isVoidInitOkay!Mt19937); 212 static assert(_isVoidInitOkay!Mt19937_64); 213 //Check that the property is set for a moderately-sized PRNG. 214 import mir.random.engine.xorshift: Xorshift1024StarPhi; 215 static assert(_isVoidInitOkay!Xorshift1024StarPhi); 216 //Check that PRNGs not explicitly marked as void-init safe 217 //can be inferred as such if they only have scalar fields. 218 import mir.random.engine.pcg: pcg32, pcg32_oneseq; 219 import mir.random.engine.splitmix: SplitMix64; 220 static assert(_isVoidInitOkay!pcg32); 221 static assert(_isVoidInitOkay!pcg32_oneseq); 222 static assert(_isVoidInitOkay!SplitMix64); 223 //Check that PRNGs not explicitly marked as void-init safe 224 //can be inferred as such if their only field is a static 225 //array of scalars. 226 import mir.random.engine.xorshift: Xorshift128, Xoroshiro128Plus; 227 static assert(_isVoidInitOkay!Xorshift128); 228 static assert(_isVoidInitOkay!Xoroshiro128Plus); 229 } 230 231 version (D_Ddoc) 232 { 233 /++ 234 A "good" seed for initializing random number engines. Initializing 235 with $(D_PARAM unpredictableSeed) makes engines generate different 236 random number sequences every run. 237 238 Returns: 239 A single unsigned integer seed value, different on each successive call 240 +/ 241 pragma(inline, true) 242 @property size_t unpredictableSeed() @trusted nothrow @nogc 243 { 244 return unpredictableSeed!size_t; 245 } 246 } 247 248 /// ditto 249 pragma(inline, true) 250 @property T unpredictableSeed(T = size_t)() @trusted nothrow @nogc 251 if (isUnsigned!T) 252 { 253 import mir.utility: _expect; 254 T seed = void; 255 version (AnyARC4Random) 256 { 257 // If we just need 32 bits it's faster to call arc4random() 258 // than arc4random_buf(&seed, seed.sizeof). 259 static if (T.sizeof <= uint.sizeof) 260 seed = cast(T) arc4random(); 261 else 262 arc4random_buf(&seed, seed.sizeof); 263 } 264 else if (_expect(genRandomNonBlocking(&seed, seed.sizeof) != T.sizeof, false)) 265 { 266 // fallback to old time/thread-based implementation in case of errors 267 seed = cast(T) fallbackSeed(); 268 } 269 return seed; 270 } 271 272 // Old name of `unpredictableSeedOf!T`. Undocumented but 273 // defined so existing code using mir.random won't break. 274 deprecated("Use unpredictableSeed!T instead of unpredictableSeedOf!T") 275 public alias unpredictableSeedOf(T) = unpredictableSeed!T; 276 277 version (mir_random_test) @nogc nothrow @safe unittest 278 { 279 // Check unpredictableSeed syntax works with or without parentheses. 280 auto a = unpredictableSeed; 281 auto b = unpredictableSeed!uint; 282 auto c = unpredictableSeed!ulong; 283 static assert(is(typeof(a) == size_t)); 284 static assert(is(typeof(b) == uint)); 285 static assert(is(typeof(c) == ulong)); 286 287 auto d = unpredictableSeed(); 288 auto f = unpredictableSeed!uint(); 289 auto g = unpredictableSeed!ulong(); 290 static assert(is(typeof(d) == size_t)); 291 static assert(is(typeof(f) == uint)); 292 static assert(is(typeof(g) == ulong)); 293 } 294 295 // Is llvm_readcyclecounter supported on this platform? 296 // We need to whitelist platforms where it is known to work because if it 297 // isn't supported it will compile but always return 0. 298 // https://llvm.org/docs/LangRef.html#llvm-readcyclecounter-intrinsic 299 version(LDC) 300 { 301 // The only architectures the documentation says are supported are 302 // x86 and Alpha. x86 uses RDTSC and Alpha uses RPCC. 303 version(X86_64) version = LLVMReadCycleCounter; 304 // Do *not* support 32-bit x86 because some x86 processors don't 305 // support `rdtsc` and because on x86 (but not x86-64) Linux 306 // `prctl` can disable a process's ability to use `rdtsc`. 307 else version(Alpha) version = LLVMReadCycleCounter; 308 } 309 310 311 pragma(inline, false) 312 private ulong fallbackSeed()() 313 { 314 // fallback to old time/thread-based implementation in case of errors 315 version(LLVMReadCycleCounter) 316 { 317 import ldc.intrinsics : llvm_readcyclecounter; 318 ulong ticks = llvm_readcyclecounter(); 319 } 320 else version(D_InlineAsm_X86_64) 321 { 322 // RDTSC takes around 22 clock cycles. 323 ulong ticks = void; 324 asm @nogc nothrow 325 { 326 rdtsc; 327 shl RDX, 32; 328 xor RDX, RAX; 329 mov ticks, RDX; 330 } 331 } 332 //else version(D_InlineAsm_X86) 333 //{ 334 // // We don't use `rdtsc` with version(D_InlineAsm_X86) because 335 // // some x86 processors don't support `rdtsc` and because on 336 // // x86 (but not x86-64) Linux `prctl` can disable a process's 337 // // ability to use `rdtsc`. 338 // static assert(0); 339 //} 340 else version(Windows) 341 { 342 import core.sys.windows.winbase : QueryPerformanceCounter; 343 ulong ticks = void; 344 QueryPerformanceCounter(cast(long*)&ticks); 345 } 346 else version(Darwin) 347 { 348 import core.time : mach_absolute_time; 349 ulong ticks = mach_absolute_time(); 350 } 351 else version(Posix) 352 { 353 import core.sys.posix.time : clock_gettime, CLOCK_MONOTONIC, timespec; 354 timespec ts = void; 355 const tserr = clock_gettime(CLOCK_MONOTONIC, &ts); 356 // Should never fail. Only allowed arror codes are 357 // EINVAL if the 1st argument is an invalid clock ID and 358 // EFAULT if the 2nd argument is an invalid address. 359 assert(tserr == 0, "Call to clock_gettime failed."); 360 ulong ticks = (cast(ulong) ts.tv_sec << 32) ^ ts.tv_nsec; 361 } 362 version(Posix) 363 { 364 import core.sys.posix.unistd : getpid; 365 import core.sys.posix.pthread : pthread_self; 366 auto pid = cast(uint) getpid; 367 auto tid = cast(uint) pthread_self(); 368 } 369 else 370 version(Windows) 371 { 372 import core.sys.windows.winbase : GetCurrentProcessId, GetCurrentThreadId; 373 auto pid = cast(uint) GetCurrentProcessId; 374 auto tid = cast(uint) GetCurrentThreadId; 375 } 376 ulong k = ((cast(ulong)pid << 32) ^ tid) + ticks; 377 k ^= k >> 33; 378 k *= 0xff51afd7ed558ccd; 379 k ^= k >> 33; 380 k *= 0xc4ceb9fe1a85ec53; 381 k ^= k >> 33; 382 return k; 383 } 384 385 /// 386 @safe version(mir_random_test) unittest 387 { 388 auto rnd = Random(unpredictableSeed); 389 auto n = rnd(); 390 static assert(is(typeof(n) == size_t)); 391 } 392 393 /++ 394 The "default", "favorite", "suggested" random number generator type on 395 the current platform. It is an alias for one of the 396 generators. You may want to use it if (1) you need to generate some 397 nice random numbers, and (2) you don't care for the minutiae of the 398 method being used. 399 +/ 400 static if (is(size_t == uint)) 401 alias Random = Mt19937; 402 else 403 alias Random = Mt19937_64; 404 405 /// 406 version(mir_random_test) unittest 407 { 408 import std.traits; 409 static assert(isSaturatedRandomEngine!Random); 410 static assert(is(EngineReturnType!Random == size_t)); 411 } 412 413 static if (THREAD_LOCAL_STORAGE_AVAILABLE) 414 { 415 /++ 416 Thread-local instance of the default $(LREF Random) allocated and seeded independently 417 for each thread. Requires $(LINK2 https://en.wikipedia.org/wiki/Thread-local_storage, TLS). 418 +/ 419 alias rne = threadLocal!Random; 420 /// 421 @nogc nothrow @safe version(mir_random_test) unittest 422 { 423 import mir.random; 424 import std.complex; 425 426 auto c = complex(rne.rand!real, rne.rand!real); 427 428 int[10] array; 429 foreach (ref e; array) 430 e = rne.rand!int; 431 auto picked = array[rne.randIndex(array.length)]; 432 } 433 434 private static struct TL(Engine) 435 if (isSaturatedRandomEngine!Engine && is(Engine == struct)) 436 { 437 static bool initialized; 438 static if (_isVoidInitOkay!Engine) 439 static Engine engine = void; 440 else static if (__traits(compiles, { Engine defaultConstructed; })) 441 static Engine engine; 442 else 443 static Engine engine = Engine.init; 444 445 static if (is(ucent) && is(typeof((ucent t) => Engine(t)))) 446 alias seed_t = ucent; 447 else static if (is(typeof((ulong t) => Engine(t)))) 448 alias seed_t = ulong; 449 else static if (is(typeof((uint t) => Engine(t)))) 450 alias seed_t = uint; 451 else 452 alias seed_t = EngineReturnType!Engine; 453 454 pragma(inline, false) // Usually called only once per thread. 455 private static void reseed() 456 { 457 engine.__ctor(unpredictableSeed!(seed_t)); 458 initialized = true; 459 } 460 } 461 /++ 462 `threadLocal!Engine` returns a reference to a thread-local instance of 463 the specified random number generator allocated and seeded uniquely 464 for each thread. Requires $(LINK2 https://en.wikipedia.org/wiki/Thread-local_storage, TLS). 465 466 `threadLocalPtr!Engine` is a pointer to the area of thread-local 467 storage used by `threadLocal!Engine`. This function is provided because 468 the compiler can infer it is `@safe`, unlike `&(threadLocal!Engine)`. 469 Like `threadLocal!Engine` this function will auto-initialize the engine. 470 $(I Do not share pointers returned by threadLocalPtr between 471 threads!) 472 473 `threadLocalInitialized!Engine` is a low-level way to explicitly change 474 the "initialized" flag used by `threadLocal!Engine` to determine whether 475 the Engine needs to be seeded. Setting this to `false` gives a way of 476 forcing the next call to `threadLocal!Engine` to reseed. In general this 477 is unnecessary but there are some specialized use cases where users have 478 requested this ability. 479 +/ 480 @property ref Engine threadLocal(Engine)() 481 if (isSaturatedRandomEngine!Engine && is(Engine == struct)) 482 { 483 version (DigitalMars) 484 pragma(inline);//DMD may fail to inline this. 485 else 486 pragma(inline, true); 487 import mir.utility: _expect; 488 if (_expect(!TL!Engine.initialized, false)) 489 { 490 TL!Engine.reseed(); 491 } 492 return TL!Engine.engine; 493 } 494 /// ditto 495 @property Engine* threadLocalPtr(Engine)() 496 if (isSaturatedRandomEngine!Engine && is(Engine == struct)) 497 { 498 version (DigitalMars) 499 pragma(inline);//DMD may fail to inline this. 500 else 501 pragma(inline, true); 502 import mir.utility: _expect; 503 if (_expect(!TL!Engine.initialized, false)) 504 { 505 TL!Engine.reseed(); 506 } 507 return &TL!Engine.engine; 508 } 509 /// ditto 510 @property ref bool threadLocalInitialized(Engine)() 511 if (isSaturatedRandomEngine!Engine && is(Engine == struct)) 512 { 513 version (DigitalMars) 514 pragma(inline);//DMD may fail to inline this. 515 else 516 pragma(inline, true); 517 return TL!Engine.initialized; 518 } 519 /// 520 @nogc nothrow @safe version(mir_random_test) unittest 521 { 522 import mir.random; 523 import mir.random.engine.xorshift; 524 525 alias gen = threadLocal!Xorshift1024StarPhi; 526 double x = gen.rand!double; 527 size_t i = gen.randIndex(100u); 528 ulong a = gen.rand!ulong; 529 } 530 /// 531 @nogc nothrow @safe version(mir_random_test) unittest 532 { 533 import mir.random; 534 //If you need a pointer to the engine, getting it like this is @safe: 535 Random* ptr = threadLocalPtr!Random; 536 } 537 /// 538 @nogc nothrow @safe version(mir_random_test) unittest 539 { 540 import mir.random; 541 import mir.random.engine.xorshift; 542 //If you need to mark the engine as uninitialized to force a reseed, 543 //you can do it like this: 544 threadLocalInitialized!Xorshift1024StarPhi = false; 545 } 546 /// 547 @nogc nothrow @safe version(mir_random_test) unittest 548 { 549 import mir.random; 550 import mir.random.engine.mersenne_twister; 551 //You can mark the engine as already initialized to skip 552 //automatic seeding then initialize it yourself, for instance 553 //if you want to use a known seed rather than a random one. 554 threadLocalInitialized!Mt19937 = true; 555 immutable uint[4] customSeed = [0x123, 0x234, 0x345, 0x456]; 556 threadLocal!Mt19937.__ctor(customSeed); 557 foreach(_; 0..999) 558 threadLocal!Mt19937.rand!uint; 559 assert(3460025646u == threadLocal!Mt19937.rand!uint); 560 } 561 /// 562 @nogc nothrow @safe version(mir_random_test) unittest 563 { 564 import mir.random; 565 import mir.random.engine.xorshift; 566 567 alias gen = threadLocal!Xorshift1024StarPhi; 568 569 //If you want to you can call the generator's opCall instead of using 570 //rand!T but it is somewhat clunky because of the ambiguity of 571 //@property syntax: () looks like optional function parentheses. 572 static assert(!__traits(compiles, {ulong x0 = gen();}));//<-- Won't work 573 static assert(is(typeof(gen()) == Xorshift1024StarPhi));//<-- because the type is this. 574 ulong x1 = gen.opCall();//<-- This works though. 575 ulong x2 = gen()();//<-- This also works. 576 577 //But instead of any of those you should really just use gen.rand!T. 578 ulong x3 = gen.rand!ulong; 579 } 580 // /// 581 // @nogc nothrow pure @safe version(mir_random_test) unittest 582 // { 583 // //If you want something like Phobos std.random.rndGen and 584 // //don't care about the specific algorithm you can do this: 585 // alias rndGen = threadLocal!Random; 586 // } 587 588 @nogc nothrow @system version(mir_random_test) unittest 589 { 590 //Verify Returns same instance every time per thread. 591 import mir.random; 592 import mir.random.engine.xorshift; 593 594 Xorshift1024StarPhi* addr = &(threadLocal!Xorshift1024StarPhi()); 595 Xorshift1024StarPhi* sameAddr = &(threadLocal!Xorshift1024StarPhi()); 596 assert(addr is sameAddr); 597 assert(sameAddr is threadLocalPtr!Xorshift1024StarPhi); 598 } 599 600 /++ 601 Sets or resets the _seed of `threadLocal!Engine` using the given arguments. 602 It is not necessary to call this except if you wish to ensure the 603 PRNG uses a known _seed. 604 +/ 605 void setThreadLocalSeed(Engine, A...)(auto ref A seed) 606 if (isSaturatedRandomEngine!Engine && is(Engine == struct) 607 && A.length >= 1 && is(typeof((ref A a) => Engine(a)))) 608 { 609 TL!Engine.initialized = true; 610 TL!Engine.engine.__ctor(seed); 611 } 612 /// 613 @nogc nothrow @system version(mir_random_test) unittest 614 { 615 import mir.random; 616 617 alias rnd = threadLocal!Random; 618 619 setThreadLocalSeed!Random(123); 620 immutable float x = rnd.rand!float; 621 622 assert(x != rnd.rand!float); 623 624 setThreadLocalSeed!Random(123); 625 immutable float y = rnd.rand!float; 626 627 assert(x == y); 628 } 629 } 630 else 631 { 632 static assert(!THREAD_LOCAL_STORAGE_AVAILABLE); 633 634 @property ref Random rne()() 635 { 636 static assert(0, "Thread-local storage not available!"); 637 } 638 639 template threadLocal(T) 640 { 641 static assert(0, "Thread-local storage not available!"); 642 } 643 644 template threadLocalPtr(T) 645 { 646 static assert(0, "Thread-local storage not available!"); 647 } 648 649 template threadLocalInitialized(T) 650 { 651 static assert(0, "Thread-local storage not available!"); 652 } 653 654 template setThreadLocalSeed(T, A...) 655 { 656 static assert(0, "Thread-local storage not available!"); 657 } 658 } 659 660 version(linux) 661 { 662 import mir.linux._asm.unistd; 663 enum bool LINUX_NR_GETRANDOM = (__traits(compiles, {enum e = NR_getrandom;})); 664 //If X86_64 or X86 are missing there is a problem with the library. 665 static if (!LINUX_NR_GETRANDOM) 666 { 667 version (X86_64) 668 static assert(0, "Missing linux syscall constants!"); 669 version (X86) 670 static assert(0, "Missing linux syscall constants!"); 671 } 672 } 673 else 674 enum bool LINUX_NR_GETRANDOM = false; 675 676 static if (LINUX_NR_GETRANDOM) 677 { 678 // getrandom was introduced in Linux 3.17 679 private __gshared bool getRandomFailedENOSYS = false; 680 681 private extern(C) int syscall(size_t ident, size_t n, size_t arg1, size_t arg2) @nogc nothrow; 682 683 /* 684 * Flags for getrandom(2) 685 * 686 * GRND_NONBLOCK Don't block and return EAGAIN instead 687 * GRND_RANDOM Use the /dev/random pool instead of /dev/urandom 688 */ 689 private enum GRND_NONBLOCK = 0x0001; 690 private enum GRND_RANDOM = 0x0002; 691 692 private enum GETRANDOM = NR_getrandom; 693 694 /* 695 http://man7.org/linux/man-pages/man2/getrandom.2.html 696 If the urandom source has been initialized, reads of up to 256 bytes 697 will always return as many bytes as requested and will not be 698 interrupted by signals. No such guarantees apply for larger buffer 699 sizes. 700 */ 701 private ptrdiff_t genRandomImplSysBlocking()(scope void* ptr, size_t len) @nogc nothrow @system 702 { 703 while (len > 0) 704 { 705 auto res = syscall(GETRANDOM, cast(size_t) ptr, len, 0); 706 if (res >= 0) 707 { 708 len -= res; 709 ptr += res; 710 } 711 else 712 { 713 return res; 714 } 715 } 716 return 0; 717 } 718 719 /* 720 * If the GRND_NONBLOCK flag is set, then 721 * getrandom() does not block in these cases, but instead 722 * immediately returns -1 with errno set to EAGAIN. 723 */ 724 private ptrdiff_t genRandomImplSysNonBlocking()(scope void* ptr, size_t len) @nogc nothrow @system 725 { 726 return syscall(GETRANDOM, cast(size_t) ptr, len, GRND_NONBLOCK); 727 } 728 } 729 730 version(AnyARC4Random) 731 extern(C) private @nogc nothrow 732 { 733 void arc4random_buf(scope void* buf, size_t nbytes) @system; 734 uint arc4random() @trusted; 735 } 736 737 version(Darwin) 738 { 739 //On Darwin /dev/random is identical to /dev/urandom (neither blocks 740 //when there is low system entropy) so there is no point mucking 741 //about with file descriptors. Just use arc4random_buf for both. 742 } 743 else version(Posix) 744 { 745 import core.stdc.stdio : fclose, feof, ferror, fopen, fread; 746 alias IOType = typeof(fopen("a", "b")); 747 private __gshared IOType fdRandom; 748 version (SecureARC4Random) 749 { 750 //Don't need /dev/urandom if we have arc4random_buf. 751 } 752 else 753 private __gshared IOType fdURandom; 754 755 756 /* The /dev/random device is a legacy interface which dates back to a 757 time where the cryptographic primitives used in the implementation of 758 /dev/urandom were not widely trusted. It will return random bytes 759 only within the estimated number of bits of fresh noise in the 760 entropy pool, blocking if necessary. /dev/random is suitable for 761 applications that need high quality randomness, and can afford 762 indeterminate delays. 763 764 When the entropy pool is empty, reads from /dev/random will block 765 until additional environmental noise is gathered. 766 */ 767 private ptrdiff_t genRandomImplFileBlocking()(scope void* ptr, size_t len) @nogc nothrow @system 768 { 769 if (fdRandom is null) 770 { 771 fdRandom = fopen("/dev/random", "r"); 772 if (fdRandom is null) 773 return -1; 774 } 775 776 while (len > 0) 777 { 778 auto res = fread(ptr, 1, len, fdRandom); 779 len -= res; 780 ptr += res; 781 // check for possible permanent errors 782 if (len != 0) 783 { 784 if (fdRandom.ferror) 785 return -1; 786 787 if (fdRandom.feof) 788 return -1; 789 } 790 } 791 792 return 0; 793 } 794 } 795 796 version (SecureARC4Random) 797 { 798 //Don't need /dev/urandom if we have arc4random_buf. 799 } 800 else version(Posix) 801 { 802 /** 803 When read, the /dev/urandom device returns random bytes using a 804 pseudorandom number generator seeded from the entropy pool. Reads 805 from this device do not block (i.e., the CPU is not yielded), but can 806 incur an appreciable delay when requesting large amounts of data. 807 When read during early boot time, /dev/urandom may return data prior 808 to the entropy pool being initialized. 809 */ 810 private ptrdiff_t genRandomImplFileNonBlocking()(scope void* ptr, size_t len) @nogc nothrow @system 811 { 812 if (fdURandom is null) 813 { 814 fdURandom = fopen("/dev/urandom", "r"); 815 if (fdURandom is null) 816 return -1; 817 } 818 819 auto res = fread(ptr, 1, len, fdURandom); 820 // check for possible errors 821 if (res != len) 822 { 823 if (fdURandom.ferror) 824 return -1; 825 826 if (fdURandom.feof) 827 return -1; 828 } 829 return res; 830 } 831 } 832 833 version(Windows) 834 { 835 // the wincrypt headers in druntime are broken for x64! 836 private alias ULONG_PTR = size_t; // uint in druntime 837 private alias BOOL = bool; 838 private alias DWORD = uint; 839 private alias LPCWSTR = wchar*; 840 private alias PBYTE = ubyte*; 841 private alias HCRYPTPROV = ULONG_PTR; 842 private alias LPCSTR = const(char)*; 843 844 private extern(Windows) BOOL CryptGenRandom(HCRYPTPROV, DWORD, PBYTE) @nogc @safe nothrow; 845 private extern(Windows) BOOL CryptAcquireContextA(HCRYPTPROV*, LPCSTR, LPCSTR, DWORD, DWORD) @nogc nothrow; 846 private extern(Windows) BOOL CryptAcquireContextW(HCRYPTPROV*, LPCWSTR, LPCWSTR, DWORD, DWORD) @nogc nothrow; 847 private extern(Windows) BOOL CryptReleaseContext(HCRYPTPROV, ULONG_PTR) @nogc nothrow; 848 849 private __gshared ULONG_PTR hProvider; 850 851 private auto initGetRandom()() @nogc @trusted nothrow 852 { 853 import core.sys.windows.winbase : GetLastError; 854 import core.sys.windows.winerror : NTE_BAD_KEYSET; 855 import core.sys.windows.wincrypt : PROV_RSA_FULL, CRYPT_NEWKEYSET, CRYPT_VERIFYCONTEXT, CRYPT_SILENT; 856 857 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa379886(v=vs.85).aspx 858 // For performance reasons, we recommend that you set the pszContainer 859 // parameter to NULL and the dwFlags parameter to CRYPT_VERIFYCONTEXT 860 // in all situations where you do not require a persisted key. 861 // CRYPT_SILENT is intended for use with applications for which the UI cannot be displayed by the CSP. 862 if (!CryptAcquireContextW(&hProvider, null, null, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) 863 { 864 if (GetLastError() == NTE_BAD_KEYSET) 865 { 866 // Attempt to create default container 867 if (!CryptAcquireContextA(&hProvider, null, null, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_SILENT)) 868 return 1; 869 } 870 else 871 { 872 return 1; 873 } 874 } 875 876 return 0; 877 } 878 } 879 880 /++ 881 Constructs the mir random seed generators. 882 This constructor needs to be called once $(I before) 883 other calls in `mir.random.engine`. 884 885 Automatically called by DRuntime. 886 +/ 887 extern(C) void mir_random_engine_ctor() @system nothrow @nogc 888 { 889 version(Windows) 890 { 891 if (hProvider == 0) 892 initGetRandom; 893 } 894 } 895 896 /++ 897 Destructs the mir random seed generators. 898 899 Automatically called by DRuntime. 900 +/ 901 extern(C) void mir_random_engine_dtor() @system nothrow @nogc 902 { 903 version(Windows) 904 { 905 if (hProvider > 0) 906 CryptReleaseContext(hProvider, 0); 907 } 908 else 909 version(Darwin) 910 { 911 912 } 913 else 914 version(Posix) 915 { 916 if (fdRandom !is null) 917 fdRandom.fclose; 918 919 version (SecureARC4Random) 920 { 921 //Don't need /dev/urandom if we have arc4random_buf. 922 } 923 else if (fdURandom !is null) 924 fdURandom.fclose; 925 } 926 } 927 928 929 version(D_BetterC) 930 { 931 pragma(crt_constructor) 932 extern(C) void mir_random_engine_ctor_() @system nothrow @nogc 933 { 934 mir_random_engine_ctor(); 935 } 936 937 pragma(crt_destructor) 938 extern(C) void mir_random_engine_dtor_() @system nothrow @nogc 939 { 940 mir_random_engine_dtor(); 941 } 942 } 943 else 944 { 945 /// Automatically calls the extern(C) module constructor 946 shared static this() 947 { 948 mir_random_engine_ctor(); 949 } 950 951 /// Automatically calls the extern(C) module destructor 952 shared static ~this() 953 { 954 mir_random_engine_dtor(); 955 } 956 } 957 958 /++ 959 Fills a buffer with random data. 960 If not enough entropy has been gathered, it will block. 961 962 Note that on Mac OS X this method will never block. 963 964 Params: 965 ptr = pointer to the buffer to fill 966 len = length of the buffer (in bytes) 967 968 Returns: 969 A non-zero integer if an error occurred. 970 +/ 971 extern(C) ptrdiff_t mir_random_genRandomBlocking(scope void* ptr , size_t len) @nogc nothrow @system 972 { 973 version(Windows) 974 { 975 static if (DWORD.max >= size_t.max) 976 while(!CryptGenRandom(hProvider, len, cast(PBYTE) ptr)) {} 977 else 978 while (len != 0) 979 { 980 import mir.utility : min; 981 const n = min(DWORD.max, len); 982 if (CryptGenRandom(hProvider, cast(DWORD) n, cast(PBYTE) ptr)) 983 { 984 len -= n; 985 } 986 } 987 return 0; 988 } 989 else version (Darwin) 990 { 991 arc4random_buf(ptr, len); 992 return 0; 993 } 994 else 995 { 996 static if (LINUX_NR_GETRANDOM) 997 if (!getRandomFailedENOSYS) // harmless data race 998 { 999 import core.stdc.errno; 1000 ptrdiff_t result = genRandomImplSysBlocking(ptr, len); 1001 if (result >= 0) 1002 return result; 1003 if (errno != ENOSYS) 1004 return result; 1005 getRandomFailedENOSYS = true; // harmless data race 1006 } 1007 return genRandomImplFileBlocking(ptr, len); 1008 } 1009 } 1010 1011 /// ditto 1012 alias genRandomBlocking = mir_random_genRandomBlocking; 1013 1014 /// ditto 1015 ptrdiff_t genRandomBlocking()(scope ubyte[] buffer) @nogc nothrow @trusted 1016 { 1017 pragma(inline, true); 1018 return mir_random_genRandomBlocking(buffer.ptr, buffer.length); 1019 } 1020 1021 /// 1022 @safe nothrow version(mir_random_test) unittest 1023 { 1024 ubyte[] buf = new ubyte[10]; 1025 genRandomBlocking(buf); 1026 1027 int sum; 1028 foreach (b; buf) 1029 sum += b; 1030 1031 assert(sum > 0, "Only zero points generated"); 1032 } 1033 1034 @nogc nothrow @safe version(mir_random_test) unittest 1035 { 1036 ubyte[10] buf; 1037 genRandomBlocking(buf); 1038 1039 int sum; 1040 foreach (b; buf) 1041 sum += b; 1042 1043 assert(sum > 0, "Only zero points generated"); 1044 } 1045 1046 /++ 1047 Fills a buffer with random data. 1048 If not enough entropy has been gathered, it won't block. 1049 Hence the error code should be inspected. 1050 1051 On Linux >= 3.17 genRandomNonBlocking is guaranteed to succeed for 256 bytes and 1052 fewer. 1053 1054 On Mac OS X, OpenBSD, and NetBSD genRandomNonBlocking is guaranteed to 1055 succeed for any number of bytes. 1056 1057 Params: 1058 buffer = the buffer to fill 1059 len = length of the buffer (in bytes) 1060 1061 Returns: 1062 The number of bytes filled - a negative number if an error occurred 1063 +/ 1064 extern(C) size_t mir_random_genRandomNonBlocking(scope void* ptr, size_t len) @nogc nothrow @system 1065 { 1066 version(Windows) 1067 { 1068 static if (DWORD.max < size_t.max) 1069 if (len > DWORD.max) 1070 len = DWORD.max; 1071 if (!CryptGenRandom(hProvider, cast(DWORD) len, cast(PBYTE) ptr)) 1072 return -1; 1073 return len; 1074 } 1075 else version(SecureARC4Random) 1076 { 1077 arc4random_buf(ptr, len); 1078 return len; 1079 } 1080 else 1081 { 1082 static if (LINUX_NR_GETRANDOM) 1083 if (!getRandomFailedENOSYS) // harmless data race 1084 { 1085 import core.stdc.errno; 1086 ptrdiff_t result = genRandomImplSysNonBlocking(ptr, len); 1087 if (result >= 0) 1088 return result; 1089 if (errno != ENOSYS) 1090 return result; 1091 getRandomFailedENOSYS = true; // harmless data race 1092 } 1093 return genRandomImplFileNonBlocking(ptr, len); 1094 } 1095 } 1096 /// ditto 1097 alias genRandomNonBlocking = mir_random_genRandomNonBlocking; 1098 /// ditto 1099 size_t genRandomNonBlocking()(scope ubyte[] buffer) @nogc nothrow @trusted 1100 { 1101 pragma(inline, true); 1102 return mir_random_genRandomNonBlocking(buffer.ptr, buffer.length); 1103 } 1104 1105 /// 1106 @safe nothrow version(mir_random_test) unittest 1107 { 1108 ubyte[] buf = new ubyte[10]; 1109 genRandomNonBlocking(buf); 1110 1111 int sum; 1112 foreach (b; buf) 1113 sum += b; 1114 1115 assert(sum > 0, "Only zero points generated"); 1116 } 1117 1118 @nogc nothrow @safe 1119 version(mir_random_test) unittest 1120 { 1121 ubyte[10] buf; 1122 genRandomNonBlocking(buf); 1123 1124 int sum; 1125 foreach (b; buf) 1126 sum += b; 1127 1128 assert(sum > 0, "Only zero points generated"); 1129 }