aboutsummaryrefslogtreecommitdiff
path: root/libphobos/src/std/random.d
diff options
context:
space:
mode:
Diffstat (limited to 'libphobos/src/std/random.d')
-rw-r--r--libphobos/src/std/random.d127
1 files changed, 125 insertions, 2 deletions
diff --git a/libphobos/src/std/random.d b/libphobos/src/std/random.d
index c221024..fb4e546 100644
--- a/libphobos/src/std/random.d
+++ b/libphobos/src/std/random.d
@@ -1772,11 +1772,74 @@ else
}
}
+version (linux)
+{
+ // `getrandom()` was introduced in Linux 3.17.
+
+ // Shim for missing bindings in druntime
+ version (none)
+ import core.sys.linux.sys.random : getrandom;
+ else
+ {
+ import core.sys.posix.sys.types : ssize_t;
+ extern extern(C) ssize_t getrandom(
+ void* buf,
+ size_t buflen,
+ uint flags,
+ ) @system nothrow @nogc;
+ }
+}
+
+version (Windows)
+{
+ pragma(lib, "Bcrypt.lib");
+
+ private bool bcryptGenRandom(T)(out T result) @trusted
+ {
+ import core.sys.windows.windef : PUCHAR, ULONG;
+ import core.sys.windows.ntdef : NT_SUCCESS;
+ import core.sys.windows.bcrypt : BCryptGenRandom, BCRYPT_USE_SYSTEM_PREFERRED_RNG;
+
+ const gotRandom = BCryptGenRandom(
+ null,
+ cast(PUCHAR) &result,
+ ULONG(T.sizeof),
+ BCRYPT_USE_SYSTEM_PREFERRED_RNG,
+ );
+
+ return NT_SUCCESS(gotRandom);
+ }
+}
+
/**
A "good" seed for initializing random number engines. Initializing
with $(D_PARAM unpredictableSeed) makes engines generate different
random number sequences every run.
+This function utilizes the system $(I cryptographically-secure pseudo-random
+number generator (CSPRNG)) or $(I pseudo-random number generator (PRNG))
+where available and implemented (currently `arc4random` on applicable BSD
+systems, `getrandom` on Linux or `BCryptGenRandom` on Windows) to generate
+“high quality” pseudo-random numbers – if possible.
+As a consequence, calling it may block under certain circumstances (typically
+during early boot when the system's entropy pool has not yet been
+initialized).
+
+On x86 CPU models which support the `RDRAND` instruction, that will be used
+when no more specialized randomness source is implemented.
+
+In the future, further platform-specific PRNGs may be incorporated.
+
+Warning:
+$(B This function must not be used for cryptographic purposes.)
+Despite being implemented for certain targets, there are no guarantees
+that it sources its randomness from a CSPRNG.
+The implementation also includes a fallback option that provides very little
+randomness and is used when no better source of randomness is available or
+integrated on the target system.
+As written earlier, this function only aims to provide randomness for seeding
+ordinary (non-cryptographic) PRNG engines.
+
Returns:
A single unsigned integer seed value, different on each successive call
Note:
@@ -1788,7 +1851,37 @@ how excellent the source of entropy is.
*/
@property uint unpredictableSeed() @trusted nothrow @nogc
{
- version (AnyARC4Random)
+ version (linux)
+ {
+ uint buffer;
+
+ /*
+ getrandom(2):
+ If the _urandom_ source has been initialized, reads of up to
+ 256 bytes will always return as many bytes as requested and
+ will not be interrupted by signals. No such guarantees apply
+ for larger buffer sizes.
+ */
+ static assert(buffer.sizeof <= 256);
+
+ const status = (() @trusted => getrandom(&buffer, buffer.sizeof, 0))();
+ assert(status == buffer.sizeof);
+
+ return buffer;
+ }
+ else version (Windows)
+ {
+ uint result;
+ if (!bcryptGenRandom!uint(result))
+ {
+ version (none)
+ return fallbackSeed();
+ else
+ assert(false, "BCryptGenRandom() failed.");
+ }
+ return result;
+ }
+ else version (AnyARC4Random)
{
return arc4random();
}
@@ -1837,7 +1930,37 @@ if (isUnsigned!UIntType)
/// ditto
@property UIntType unpredictableSeed() @nogc nothrow @trusted
{
- version (AnyARC4Random)
+ version (linux)
+ {
+ UIntType buffer;
+
+ /*
+ getrandom(2):
+ If the _urandom_ source has been initialized, reads of up to
+ 256 bytes will always return as many bytes as requested and
+ will not be interrupted by signals. No such guarantees apply
+ for larger buffer sizes.
+ */
+ static assert(buffer.sizeof <= 256);
+
+ const status = (() @trusted => getrandom(&buffer, buffer.sizeof, 0))();
+ assert(status == buffer.sizeof);
+
+ return buffer;
+ }
+ else version (Windows)
+ {
+ UIntType result;
+ if (!bcryptGenRandom!UIntType(result))
+ {
+ version (none)
+ return fallbackSeed();
+ else
+ assert(false, "BCryptGenRandom() failed.");
+ }
+ return result;
+ }
+ else version (AnyARC4Random)
{
static if (UIntType.sizeof <= uint.sizeof)
{