Skip to content

sdrapkin/SecurityDriven.FastGuid

Repository files navigation

FastGuid NuGet

10 times faster than Guid.NewGuid()

  • High-performance, cryptographically strong GUID generation
  • Database-optimized GUIDs for SQL Server and PostgreSQL
  • RFC 9562 compliant Version 7 UUID generation and extraction
  • AWS Lambda SnapStart and VM-Fork cloning mitigation
  • Fast random byte filling
  • Fastest .NET random string generation
  • .NET 5.0+ support (compatible with older .NET Frameworks)

Install

dotnet add package FastGuid

Static APIs for GUIDs and random data generation

  • Guid FastGuid.NewGuid()
    • Returns a cryptographically random GUID.
    • ~10x (900%) faster than Guid.NewGuid().
  • FastGuid.Fill(Span<byte> data)
    • Fills a span with cryptographically strong random bytes.
    • ~1.5x (50%) to 9x (800%) faster for <512 bytes, otherwise calls RandomNumberGenerator.Fill()

Static APIs for SQL Server- and PostgreSQL-optimized GUIDs

  • Guid FastGuid.NewSqlServerGuid()

    • Returns a new Guid optimized for use as a SQL Server clustered key.
    • Guid structure is [8 random bytes] [8 bytes of SQL-Server-ordered DateTime.UtcNow]
    • Each Guid is sequential across 100-nanosecond UtcNow precision limits.
    • 64-bit cryptographic randomness adds uniqueness for timestamp collisions and provides reasonable unguessability and protection against online brute-force attacks.
  • Guid FastGuid.NewPostgreSqlGuid()

    • Returns a new Guid optimized for use as a PostgreSQL primary key or index.
    • Guid structure is [8 bytes of PostgreSQL-ordered DateTime.UtcNow] [8 random bytes]
    • Each Guid is sequential across 100-nanosecond UtcNow precision limits.
    • 64-bit cryptographic randomness adds uniqueness for timestamp collisions and provides reasonable unguessability and protection against online brute-force attacks.
  • Helper methods for Guids generated by NewSqlServerGuid():

    • DateTime FastGuid.SqlServer.GetTimestamp(Guid guid)
      • Extracts SqlServer Guid creation timestamp (UTC). Full DateTime.UtcNow precision.
    • Guid FastGuid.SqlServer.MinGuidForTimestamp(DateTime timestampUtc)
    • Guid FastGuid.SqlServer.MaxGuidForTimestamp(DateTime timestampUtc)
      • Return the smallest/largest Guid for a given timestamp (useful for time-based SQL-Server range searches).
  • Helper methods for Guids generated by NewPostgreSqlGuid():

    • DateTime FastGuid.PostgreSql.GetTimestamp(Guid guid)
      • Extracts PostgreSQL Guid creation timestamp (UTC). Full DateTime.UtcNow precision.
    • Guid FastGuid.PostgreSql.MinGuidForTimestamp(DateTime timestampUtc)
    • Guid FastGuid.PostgreSql.MaxGuidForTimestamp(DateTime timestampUtc)
      • Return the smallest/largest Guid for a given timestamp (useful for time-based PostgreSQL range searches).

Static APIs for fast random string generation (new)

  • string FastGuid.StringGen.Text16(int length)
    • Generates a random string using the Base16 (hex) alphabet.
  • string FastGuid.StringGen.Text32(int length)
    • Generates a random string using the Base32 alphabet (RFC 4648).
  • string FastGuid.StringGen.Text32c(int length)
    • Generates a random string using the Crockford Base32 alphabet.
  • string FastGuid.StringGen.Text64(int length)
    • Generates a random string using the Base64 alphabet (RFC 4648).
  • string FastGuid.StringGen.Text64Url(int length)
    • Generates a random string using the Base64Url alphabet (RFC 4648, URL-safe).
  • All methods use cryptographically strong randomness and are suitable for passwords, tokens, keys, and identifiers.

Fast GUID-to-string and string-to-GUID conversion (new)

New fast extension methods for efficient conversion between GUIDs and compact Base64Url strings:

  • string Guid.ToBase64Url()

    • Converts a Guid to a 22-character Base64Url string (URL-safe, no padding).
    • Useful for compact GUID-as-string identifiers in URLs, tokens, or text fields.
  • Guid string.FromBase64Url()

    • Converts a 22-character Base64Url string back to a Guid.
    • Throws ArgumentException if the input is invalid.
  • bool GuidExtensions.TryFromBase64Url(ReadOnlySpan<char> base64Url, out Guid guid)

    • Tries to convert a Base64Url string to a Guid.
    • Returns true if successful, false otherwise (never throws).

Static APIs for RFC 9562 Compliant UUIDv7 (new)

Faster and more capable Version 7 UUID generation than System.Guid.CreateVersion7(), with support for DateTime and DateTimeOffset timestamps, and timestamp extraction.

  • Guid FastGuid.UUID.CreateVersion7()
    • Returns an RFC 9562 compliant UUIDv7 with embedded UTC timestamp.
    • Faster alternative to System.Guid.CreateVersion7().
  • Guid FastGuid.UUID.CreateVersion7(DateTimeOffset timestamp)
  • CreateVersion7(DateTime utcTimestamp)
    • Generate UUIDv7 pinned to a specific UTC timestamp.
  • DateTime FastGuid.UUID.ExtractDateTimeV7(Guid guidv7)
    • Extracts the embedded UTC timestamp out of a valid UUIDv7 with 1-millisecond precision. Throws on invalid formats.
  • bool FastGuid.UUID.TryExtractDateTimeV7(Guid guidv7, out DateTime timestamp)
    • Non-throwing UUIDv7 timestamp extraction. Returns true if successful.

Warning

While compliant with RFC standards, UUIDv7 identifiers generate high data page fragmentation when used as primary/clustered keys inside relational databases. For database keys, use FastGuid.NewSqlServerGuid() or FastGuid.NewPostgreSqlGuid() instead.

☁️ AWS SnapStart / VM-Forking (serverless & cloud-native)

In virtualized serverless execution environments like AWS Lambda (SnapStart), micro-VM instances can be snapshot-frozen and cloned across multiple instances simultaneously. If left unmanaged, standard thread-local random buffers could produce identical sequences of identifiers across different machines, causing catastrophic cryptographic collisions.

FastGuid mitigates this entirely using an atomic Global Epoch Verification Pattern.

To guarantee that no pre-snapshot buffered randomness is ever reused after a restore operation, simply trigger FastGuid.Reset() inside your platform's post-restore lifecycle hook:

// Register this action within your AWS Lambda RegisterAfterRestore hook
public void OnAwsSnapStartRestore()
{
    SecurityDriven.FastGuid.Reset();
}

API Summary

API Signature Description
Guid FastGuid.NewGuid() Returns a cryptographically strong random GUID.
void FastGuid.Fill(Span<byte> data) Fills a span with cryptographically strong random bytes.
void FastGuid.Reset() Invalidates all thread-local buffers (critical for cloud/Lambda VM-fork hooks).
Guid FastGuid.NewSqlServerGuid() Returns a GUID optimized for use as a SQL Server clustered key (uses current UTC timestamp).
Guid FastGuid.NewSqlServerGuid(DateTime timestampUtc) Returns a SQL Server-optimized GUID for a specific UTC timestamp.
Guid FastGuid.NewPostgreSqlGuid() Returns a GUID optimized for use as a PostgreSQL key (uses current UTC timestamp).
Guid FastGuid.NewPostgreSqlGuid(DateTime timestampUtc) Returns a PostgreSQL-optimized GUID for a specific UTC timestamp.
DateTime FastGuid.SqlServer.GetTimestamp(Guid guid) Extracts the creation timestamp (UTC) from a SQL Server GUID.
Guid FastGuid.SqlServer.MinGuidForTimestamp(DateTime timestampUtc) Returns the smallest SQL Server GUID for a given timestamp.
Guid FastGuid.SqlServer.MaxGuidForTimestamp(DateTime timestampUtc) Returns the largest SQL Server GUID for a given timestamp.
DateTime FastGuid.PostgreSql.GetTimestamp(Guid guid) Extracts the creation timestamp (UTC) from a PostgreSQL GUID.
Guid FastGuid.PostgreSql.MinGuidForTimestamp(DateTime timestampUtc) Returns the smallest PostgreSQL GUID for a given timestamp.
Guid FastGuid.PostgreSql.MaxGuidForTimestamp(DateTime timestampUtc) Returns the largest PostgreSQL GUID for a given timestamp.
Guid FastGuid.UUID.CreateVersion7() Returns an RFC 9562 compliant UUIDv7 with an embedded current UTC timestamp.
Guid FastGuid.UUID.CreateVersion7(DateTimeOffset timestamp) Generates an RFC 9562 compliant UUIDv7 pinned to a specific DateTimeOffset.
Guid FastGuid.UUID.CreateVersion7(DateTime utcTimestamp) Generates an RFC 9562 compliant UUIDv7 pinned to a specific UTC DateTime.
DateTime FastGuid.UUID.ExtractDateTimeV7(Guid guidv7) Extracts the embedded UTC timestamp from a valid UUIDv7 (1-ms precision). Throws on error.
bool FastGuid.UUID.TryExtractDateTimeV7(Guid guidv7, out DateTime timestamp) Tries to extract the UTC timestamp from a valid UUIDv7. Returns true if successful.
string FastGuid.StringGen.Text16(int length) Generates a random string using the Base16 (hex) alphabet.
string FastGuid.StringGen.Text32(int length) Generates a random string using the Base32 alphabet (RFC 4648).
string FastGuid.StringGen.Text32c(int length) Generates a random string using the Crockford Base32 alphabet.
string FastGuid.StringGen.Text64(int length) Generates a random string using the Base64 alphabet (RFC 4648).
string FastGuid.StringGen.Text64Url(int length) Generates a random string using the Base64Url alphabet (RFC 4648, URL-safe).
string Guid.ToBase64Url() (Guid extension) Converts a GUID to a 22-character Base64Url string (URL-safe, no padding).
Guid string.FromBase64Url() (string extension) Converts a 22-character Base64Url string back to a GUID.
bool GuidExtensions.TryFromBase64Url(ReadOnlySpan<char> base64Url, out Guid guid) Tries to convert a Base64Url string to a GUID. Returns true if successful, false otherwise.

Usage

Replace all calls to Guid.NewGuid() with FastGuid.NewGuid()

..from this:

Guid guid = Guid.NewGuid(); // your current code

..to this:

// using SecurityDriven;
Guid guid = FastGuid.NewGuid(); // 10x faster
  • Thread-safe
  • 128 bits of cryptographically strong randomness

Switch from this:

Span<byte> key = stackalloc byte[32];
RandomNumberGenerator.Fill(key); // 145 nanoseconds

..to this:

Span<byte> key = stackalloc byte[32];
FastGuid.Fill(key); // 20 nanoseconds (7x faster)

Important

Guid.CreateVersion7() causes page-fragmentation in SQL Server and PostgreSQL. DO NOT USE Guid.CreateVersion7() or FastGuid.UUID.CreateVersion7() for database Guids. Use FastGuid.NewSqlServerGuid() or FastGuid.NewPostgreSqlGuid() instead.

Benchmark #1:

public class Bench
{
	[Benchmark(Baseline = true)]
	public void FastGuid_NewGuid() // 12 calls
	{
		FastGuid.NewGuid(); FastGuid.NewGuid(); FastGuid.NewGuid(); FastGuid.NewGuid();
		FastGuid.NewGuid(); FastGuid.NewGuid(); FastGuid.NewGuid(); FastGuid.NewGuid();
		FastGuid.NewGuid(); FastGuid.NewGuid(); FastGuid.NewGuid(); FastGuid.NewGuid();
	}

	[Benchmark]
	public void Guid_NewGuid() // 12 calls
	{
		Guid.NewGuid(); Guid.NewGuid(); Guid.NewGuid(); Guid.NewGuid();
		Guid.NewGuid(); Guid.NewGuid(); Guid.NewGuid(); Guid.NewGuid();
		Guid.NewGuid(); Guid.NewGuid(); Guid.NewGuid(); Guid.NewGuid();
	}
}//class Bench
BenchmarkDotNet=v0.13.2, OS=Windows 10 (10.0.19045.2364)
Intel Core i7-10510U CPU 1.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=7.0.101
  [Host] : .NET 7.0.1 (7.0.122.56804), X64 RyuJIT AVX2
Method Mean Error StdDev Ratio
FastGuid_NewGuid 116.6 ns 2.26 ns 5.19 ns 1.00
Guid_NewGuid 1,215.9 ns 23.85 ns 45.96 ns 10.39

Benchmark #2:

static long UtcNow() => DateTime.UtcNow.Ticks;
static long StopwatchDT() => Stopwatch.GetTimestamp();
static Guid Fast_Guid() => SecurityDriven.FastGuid.NewGuid();
static Guid Fast_UUID7() => SecurityDriven.FastGuid.UUID.CreateVersion7();
static Guid Fast_MSSqlGuid() => SecurityDriven.FastGuid.NewSqlServerGuid();
static Guid Fast_PGSqlGuid() => SecurityDriven.FastGuid.NewPostgreSqlGuid();
static Guid NewGuid4() => Guid.NewGuid();
static Guid NewGuid7() => Guid.CreateVersion7();
BenchmarkDotNet v0.15.1, Windows 11 (10.0.26200.8457)
Intel Core i7-10510U CPU 1.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK 11.0.100-preview.4.26230.115
  [Host] : .NET 10.0.8 (10.0.826.23019), X64 RyuJIT AVX2
Method Mean Error StdDev Ratio
UtcNow 25.65 ns 0.279 ns 0.233 ns 2.3x
StopwatchDT 15.26 ns 0.168 ns 0.149 ns 1.4x
Fast_Guid 11.29 ns 0.259 ns 0.299 ns 1.0x
Fast_UUID7 38.75 ns 0.719 ns 0.600 ns ~ 3x
Fast_MSSqlGuid 37.26 ns 0.455 ns 0.380 ns ~ 3x
Fast_PGSqlGuid 35.31 ns 0.516 ns 0.574 ns ~ 3x
NewGuid4 93.35 ns 1.652 ns 1.545 ns ~ 8x
NewGuid7 128.89 ns 2.132 ns 1.780 ns ~11x
image

Example: Fast random string generation

// Generate a 16-character random hexadecimal string
string hex = FastGuid.StringGen.Text16(16); // 64 bits of entropy

// Generate a 32-character random Base32 session identifier
string sessionId = FastGuid.StringGen.Text32(32); // 160 bits of entropy

// Generate a 32-character random Base64Url token
string token = FastGuid.StringGen.Text64Url(32); // 192 bits of entropy

Benchmark #3: Fast random string generation

static Guid FastGuid_NewGuid() => FastGuid.NewGuid();
static string FastGuid_StringGen_Text16_16() => FastGuid.StringGen.Text16(16);
static string FastGuid_StringGen_Text32_32() => FastGuid.StringGen.Text32(32);
static string FastGuid_StringGen_Text64Url_32() => FastGuid.StringGen.Text64Url(32);
BenchmarkDotNet v0.13.8, Windows 10 (10.0.19045.5917/22H2/2022Update)
Intel Core i7-10510U CPU 1.80GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK 10.0.100-preview.5.25277.114
  [Host] : .NET 10.0.0 (10.0.25.27814), X64 RyuJIT AVX2

image

Example: Extension methods for Guid

Guid guid1 = FastGuid.NewGuid();
string guidString = guid1.ToBase64Url(); // e.g. "Q29uZGVuc2VkQmFzZTY0VXJs"
Guid guid2 = guidString.FromBase64Url(); // round-trip; throws if guid string is invalid

if (guid1 != guid2) throw new InvalidOperationException(); // not going to happen

// Exception-free parsing:
if (GuidExtensions.TryFromBase64Url(guidString, out Guid validGuid))
{
	// validGuid is valid
}

About

Fast replacement for Guid.NewGuid().

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages