Skip to content

Commit

Permalink
Fix Issue 18596: unpredictableSeed could use something better than Mi…
Browse files Browse the repository at this point in the history
…nstdRand0

Use arc4random when available, otherwise replace MinstdRand0
with xorshift64*/32.
  • Loading branch information
n8sh committed Mar 12, 2018
1 parent 3609d72 commit bfaf31c
Showing 1 changed file with 94 additions and 10 deletions.
104 changes: 94 additions & 10 deletions std/random.d
Expand Up @@ -1290,6 +1290,74 @@ alias Xorshift = Xorshift128; /// ditto
}
}

version (CRuntime_Bionic)
version = SecureARC4Random; // ChaCha20
version (OSX)
version = SecureARC4Random; // AES
version (OpenBSD)
version = SecureARC4Random; // ChaCha20
version (NetBSD)
version = SecureARC4Random; // ChaCha20

version (CRuntime_UClibc)
version = LegacyARC4Random; // ARC4
version (FreeBSD)
version = LegacyARC4Random; // ARC4
version (DragonFlyBSD)
version = LegacyARC4Random; // ARC4
version (BSD)
version = LegacyARC4Random; // Unknown implementation

// For the current purpose of unpredictableSeed the difference between
// a secure arc4random implementation and a legacy implementation is
// unimportant. The source code documents this distinction in case in the
// future Phobos is altered to require cryptographically secure sources
// of randomness, and also so other people reading this source code (as
// Phobos is often looked to as an example of good D programming practices)
// do not mistakenly use insecure versions of arc4random in contexts where
// crypographically secure sources of randomness are needed.

// Performance note: ChaCha20 is about 70% faster than ARC4, contrary to
// what one might assume from it being more secure.

version (SecureARC4Random)
version = AnyARC4Random;
version (LegacyARC4Random)
version = AnyARC4Random;

version (AnyARC4Random)
{
extern(C) private @nogc nothrow
{
uint arc4random() @safe;
}
}
else
{
private ulong _seeder; // 0 indicates uninitialized.

private ulong bootstrapSeed() @nogc nothrow @trusted
{
pragma (inline, false);
ulong result = void;
enum ulong m = 0xc6a4_a793_5bd1_e995UL; // MurmurHash2_64A constant.
void updateResult(ulong x)
{
x *= m;
x = (x ^ (x >>> 47)) * m;
result = (result ^ x) * m;
}

import core.thread : getpid;
import core.time : MonoTime;

update_result(cast(ulong) &_seeder); // Distinct for each thread.
update_result(cast(ulong) getpid());
update_result(cast(ulong) MonoTime.currTime.ticks);
result = (result ^ (result >>> 47)) * m;
return result ^ (result >>> 47);
}
}

/**
A "good" seed for initializing random number engines. Initializing
Expand All @@ -1299,19 +1367,35 @@ random number sequences every run.
Returns:
A single unsigned integer seed value, different on each successive call
*/
@property uint unpredictableSeed() @trusted nothrow @nogc
@property uint unpredictableSeed() @nogc nothrow @trusted
{
import core.thread : Thread, getpid, MonoTime;
static bool seeded;
static MinstdRand0 rand;
if (!seeded)
version (AnyARC4Random)
{
return arc4random();
}
else
{
uint threadID = cast(uint) cast(void*) Thread.getThis();
rand.seed((getpid() + threadID) ^ cast(uint) MonoTime.currTime.ticks);
seeded = true;
import core.time : MonoTime;
ulong x = _seeder;
if (x == 0) // 0 means uninitialized (update can never transition non-zero to zero).
x = bootstrapSeed();
// State is updated with a 64-bit xorshift. Output is produced
// by multiplying state by a constant to eliminate linear artifacts
// except in the low-order bits. This approach appears in "Numerical
// Recipes 3rd edition" (2007). The specific constants used here are
// taken from "An experimental exploration of Marsaglia’s xorshift
// generators, scrambled" (Vigna 2016).
x ^= x >>> 12;
x ^= x << 25;
x ^= x >>> 37;
_seeder = x;
enum ulong mult = 2_685_821_657_736_338_717UL;
// As we don't need all 64 bits use the highest bits
// because they have better statistical properties.
// Finally the result is combined with the clock.
return cast(uint) ((x * mult) >>> 32)
^ cast(uint) MonoTime.currTime.ticks;
}
rand.popFront();
return cast(uint) (MonoTime.currTime.ticks ^ rand.front);
}

///
Expand Down

0 comments on commit bfaf31c

Please sign in to comment.