Use only 10 bytes of RNG in Guid.CreateVersion7 on Unix#128055
Conversation
UUIDv7 only consumes 74 bits of randomness, all of which fit in the trailing 10 bytes of the GUID. The first 6 bytes are immediately overwritten with the unix_ts_ms timestamp, so generating them is wasted work. On Apple platforms CCRandomGenerateBytes has a fast path for requests <= 12 bytes, so cutting the request from 16 to 10 bytes hits that path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Note This benchmark request was generated with help from GitHub Copilot (AI-generated content). @EgorBot -osx_arm64 -osx_x64 -linux_x64 -linux_arm64 using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
BenchmarkSwitcher.FromAssembly(typeof(Bench).Assembly).Run(args);
public class Bench
{
[Benchmark]
public Guid CreateVersion7() => Guid.CreateVersion7();
} |
|
Tagging subscribers to this area: @dotnet/area-system-runtime |
There was a problem hiding this comment.
Pull request overview
This PR refactors Guid.CreateVersion7(DateTimeOffset) to use a new platform-specific CreateVersion7Random helper that only sources the random bytes actually consumed by UUIDv7, avoiding wasted RNG work for bytes that are immediately overwritten by the timestamp.
Changes:
- Updates
Guid.CreateVersion7(DateTimeOffset)to callCreateVersion7Random()after validating the timestamp. - Adds
CreateVersion7Random()implementations:- Windows: delegates to
NewGuid()(CoCreateGuid). - Unix/WASI: fills only bytes 6..15 with random data (10 bytes) instead of generating a full 16-byte GUID.
- Windows: delegates to
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/libraries/System.Private.CoreLib/src/System/Guid.cs | Switches v7 creation to use CreateVersion7Random() after timestamp validation; updates rationale comment. |
| src/libraries/System.Private.CoreLib/src/System/Guid.Unix.cs | Introduces a Unix/WASI helper that requests only 10 RNG bytes for v7. |
| src/libraries/System.Private.CoreLib/src/System/Guid.Windows.cs | Introduces a Windows helper that reuses NewGuid() for v7 randomness sourcing. |
|
I learned about the cache long ago when I looked at why Guid.NewGuid is slow on mac under XCode Instruments #106525 (comment) |
|
@EgorBo isn't that linked PR that is closed more or less the same thing as what is being proposed here? The conclusion at the time was
and
|
I found that thread after I filed the PR, but is there a lot of complexity here? |
|
Echoing my sentiment from the past... the fact that you need a |
Note
This PR was authored with help from GitHub Copilot (AI-generated content).
Guid.CreateVersion7only needs 74 bits of randomness (12 bits ofrand_a+ 62 bits ofrand_b), all of which live in the trailing 10 bytes of the GUID. The first 6 bytes are immediately overwritten with theunix_ts_mstimestamp, so any random bytes generated for them are wasted work.This PR introduces a small
CreateVersion7Randomhelper:GetCryptographicallySecureRandomBytes(orGetRandomByteson WASI), filling only bytes 6..15 of the result.CoCreateGuidviaNewGuid()(the existing comment notes this is faster thanBCryptGenRandomfor this size class).Motivation: on Apple platforms
CCRandomGenerateByteshas a fast path for requests<= 12bytes, so cutting the request from 16 to 10 bytes hits that path. Other Unix platforms benefit slightly from pulling less entropy from the kernel.Also moves the
ArgumentOutOfRangeException.ThrowIfNegative(unix_ts_ms, ...)check ahead of the RNG call so an invalid timestamp short-circuits without paying for entropy.No behavioral change: the randomness fed into
rand_a/rand_bis still cryptographically secure, the version/variant fields are still applied, and existing tests should continue to pass.I'll trigger @EgorBot on this PR for
-osx_arm64 -osx_x64 -linux_x64 -linux_arm64to confirm the speedup in a follow-up comment.Benchmark
Results
Apple M4 macos26:
Intel Core i5-8500B macos15: