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.
*
* 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:
* randomGen = uniform RNG
* See_Also: $(REF isUniformRNG, std,random)
*/
@nogc nothrow @safe UUID randomUUID()
{
import std.random : rndGen;
// A PRNG with fewer than `n` bytes of state cannot produce
// every distinct `n` byte sequence.
static if (typeof(rndGen).sizeof >= UUID.sizeof)
{
return randomUUID(rndGen);
}
else
{
import std.random : unpredictableSeed, Xorshift192;
static assert(Xorshift192.sizeof >= UUID.sizeof);
static Xorshift192 rng;
static bool initialized;
if (!initialized)
{
rng.seed(unpredictableSeed);
initialized = true;
}
return randomUUID(rng);
}
import std.conv : bitCast;
import std.random : unpredictableSeed;
enum bufferSize = UUID.data.sizeof;
ubyte[bufferSize] data;
static assert(ulong.sizeof * 2 == bufferSize);
const half1 = unpredictableSeed!ulong();
const half2 = unpredictableSeed!ulong();
data[0 .. ulong.sizeof] = (() @trusted => half1.bitCast!(ubyte[ulong.sizeof]))();
data[ulong.sizeof .. $] = (() @trusted => half2.bitCast!(ubyte[ulong.sizeof]))();
// set variant
// must be 0b_10xxxxxx
data[8] &= 0b_10_111111;
data[8] |= 0b_10_000000;
// set version
// must be 0b_0100xxxx
data[6] &= 0b_0100_1111;
data[6] |= 0b_0100_0000;
return UUID(data);
}
/// ditto