Improve the situation with #9881 - Use unpredictableSeed in randomUUID() (#10671)

This commit is contained in:
Elias Batek 2025-03-17 23:10:26 +01:00 committed by GitHub
parent e1d9d0208b
commit b150fde4da
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1204,32 +1204,55 @@ public struct UUID
* *
* This function is not supported at compile time. * This function is not supported at compile time.
* *
* Bugs:
* $(LINK2
* https://github.com/dlang/phobos/issues/9881
* Issue #9881 - Randomness in UUID generation is insufficient
* )
*
* Warning:
* $(B This function must not be used for cryptographic purposes.)
* UUIDs generated by this function do not have sufficient randomness
* for all use cases.
* This especially applies to the overload that accepts a caller-provided RNG.
* At the moment, Phobos does not provide a $(I cryptographically-secure
* pseudo-random number generator (CSPRNG)) that could be supplied to this
* function.
*
* While the function overload with no parameters will attempt to use the
* system CSPRNG where available and implemented, there are no guarantees.
* See $(REF unpredictableSeed, std, random) for details.
*
* Params: * Params:
* randomGen = uniform RNG * randomGen = uniform RNG
* See_Also: $(REF isUniformRNG, std,random) * See_Also: $(REF isUniformRNG, std,random)
*/ */
@nogc nothrow @safe UUID randomUUID() @nogc nothrow @safe UUID randomUUID()
{ {
import std.random : rndGen; import std.conv : bitCast;
// A PRNG with fewer than `n` bytes of state cannot produce import std.random : unpredictableSeed;
// every distinct `n` byte sequence.
static if (typeof(rndGen).sizeof >= UUID.sizeof) enum bufferSize = UUID.data.sizeof;
{ ubyte[bufferSize] data;
return randomUUID(rndGen);
} static assert(ulong.sizeof * 2 == bufferSize);
else const half1 = unpredictableSeed!ulong();
{ const half2 = unpredictableSeed!ulong();
import std.random : unpredictableSeed, Xorshift192;
static assert(Xorshift192.sizeof >= UUID.sizeof); data[0 .. ulong.sizeof] = (() @trusted => half1.bitCast!(ubyte[ulong.sizeof]))();
static Xorshift192 rng; data[ulong.sizeof .. $] = (() @trusted => half2.bitCast!(ubyte[ulong.sizeof]))();
static bool initialized;
if (!initialized) // set variant
{ // must be 0b_10xxxxxx
rng.seed(unpredictableSeed); data[8] &= 0b_10_111111;
initialized = true; data[8] |= 0b_10_000000;
}
return randomUUID(rng); // set version
} // must be 0b_0100xxxx
data[6] &= 0b_0100_1111;
data[6] |= 0b_0100_0000;
return UUID(data);
} }
/// ditto /// ditto