#!/usr/bin/env dotnet
#:property Optimize=true
#:property Nullable=enable
// uuid256.cs — reference implementation of README.md (UUID256, random layout) for .NET.
//
// Run (needs .NET 10 SDK, file-based app, no project file):
// dotnet run uuid256.cs # self-tests + exact duplicate check over 100,000,000 ids
// dotnet run uuid256.cs -- -n 5000000 -i 3 # 5e6 ids with 3 planted duplicates (proves detection)
// dotnet run uuid256.cs -- -g [count] # just print one (or count) new ids, nothing else
// Or as a library: copy the `Uuid256` struct below into any .NET 8+ project.
//
// Uuid256 id = Uuid256.NewUuid256(); // §5.1: 32 bytes from RandomNumberGenerator, ver=4/var=10
// string txt = id.ToString(); // §3.1: 16-8-8-8-24, lowercase, 68 chars
// Uuid256 b = Uuid256.Parse(txt); // §6: strict (ver/var checked); Parse(txt, strict:false) lenient
// id.TryWriteBytes(span32) / Uuid256.FromBytes(span32) — big-endian, byte 0 = most significant.
//
// Bulk check: all randomness from RandomNumberGenerator.Fill (§5.2 — OS CSPRNG) into 512 MB chunks,
// §4 applied to every id, then an O(n) counting sort on the top 24 random bits groups ids into 16M
// buckets and every pair inside a bucket is compared over all 32 bytes. Exact. RAM ≈ 36 B per id.
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Security.Cryptography;
// ============================================================================
// Spec §3–§6: the UUID256 value type
// ============================================================================
/// A 256-bit random unique identifier (README.md spec). Immutable value type, 32 bytes.
public readonly struct Uuid256 : IEquatable, IComparable
{
public const int Size = 32; // bytes
public const int TextLength = 68; // 64 hex + 4 hyphens
public const int VersionNumber = 4;
// Four big-endian 64-bit words: A = bytes 0..7 (text group 1), B = 8..15 (group 2 + first half of 3), ...
private readonly ulong _a, _b, _c, _d;
private Uuid256(ulong a, ulong b, ulong c, ulong d) { _a = a; _b = b; _c = c; _d = d; }
public static readonly Uuid256 Nil = default; // §8
public static readonly Uuid256 Max = new(ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue);
/// §4 — force version nibble (byte 12) and variant bits (byte 16) in a raw 32-byte buffer.
public static void SetVersionAndVariant(Span b)
{
b[12] = (byte)((b[12] & 0x0F) | (VersionNumber << 4)); // hex digit 24 = '4'
b[16] = (byte)((b[16] & 0x3F) | 0x80); // hex digit 32 in [89ab]
}
/// §5.1 — a new id straight from the OS CSPRNG.
public static Uuid256 NewUuid256()
{
Span b = stackalloc byte[Size];
RandomNumberGenerator.Fill(b);
SetVersionAndVariant(b);
return FromBytes(b);
}
/// Big-endian 32-byte encoding → value (no validation; use IsStrict to check ver/var).
public static Uuid256 FromBytes(ReadOnlySpan b)
{
if (b.Length != Size) throw new ArgumentException("UUID256 is exactly 32 bytes", nameof(b));
return new Uuid256(BinaryPrimitives.ReadUInt64BigEndian(b), BinaryPrimitives.ReadUInt64BigEndian(b[8..]),
BinaryPrimitives.ReadUInt64BigEndian(b[16..]), BinaryPrimitives.ReadUInt64BigEndian(b[24..]));
}
public bool TryWriteBytes(Span dst)
{
if (dst.Length < Size) return false;
BinaryPrimitives.WriteUInt64BigEndian(dst, _a); BinaryPrimitives.WriteUInt64BigEndian(dst[8..], _b);
BinaryPrimitives.WriteUInt64BigEndian(dst[16..], _c); BinaryPrimitives.WriteUInt64BigEndian(dst[24..], _d);
return true;
}
public byte[] ToByteArray() { var r = new byte[Size]; TryWriteBytes(r); return r; }
/// Version nibble (byte 12 high nibble); 4 for this spec.
public int Version => (int)((_b >> 28) & 0xF);
/// Variant bits (byte 16 top two bits); 0b10 for this spec.
public int Variant => (int)(_c >> 62);
/// §6 — ver == 4 && var == 10.
public bool IsStrict => Version == VersionNumber && Variant == 0b10;
/// §3.1 — canonical text: 16-8-8-8-24, lowercase.
public override string ToString()
{
return string.Create(TextLength, this, static (span, v) =>
{
Span b = stackalloc byte[Size];
v.TryWriteBytes(b);
ReadOnlySpan hex = "0123456789abcdef";
int o = 0;
for (int i = 0; i < Size; i++)
{
span[o++] = hex[b[i] >> 4];
span[o++] = hex[b[i] & 0xF];
if (i == 7 || i == 11 || i == 15 || i == 19) span[o++] = '-'; // after hex digits 16, 24, 32, 40
}
});
}
public enum ParseError { None, Length, Hyphen, Char, Version }
/// §6 — canonical (68) or compact (64) form, any case.
public static bool TryParse(ReadOnlySpan s, bool strict, out Uuid256 value, out ParseError error)
{
value = default; error = ParseError.None;
bool hyphenated;
if (s.Length == TextLength)
{
if (s[16] != '-' || s[25] != '-' || s[34] != '-' || s[43] != '-') { error = ParseError.Hyphen; return false; }
hyphenated = true;
}
else if (s.Length == 64) hyphenated = false;
else { error = ParseError.Length; return false; }
Span b = stackalloc byte[Size];
int nib = 0, bi = 0, cur = 0;
for (int i = 0; i < s.Length; i++)
{
if (hyphenated && (i == 16 || i == 25 || i == 34 || i == 43)) continue;
int v = HexVal(s[i]);
if (v < 0) { error = ParseError.Char; return false; }
cur = (cur << 4) | v;
if (++nib == 2) { b[bi++] = (byte)cur; nib = 0; cur = 0; }
}
var r = FromBytes(b);
if (strict && !r.IsStrict) { error = ParseError.Version; return false; }
value = r; return true;
}
public static bool TryParse(ReadOnlySpan s, out Uuid256 value) => TryParse(s, strict: true, out value, out _);
public static Uuid256 Parse(ReadOnlySpan s, bool strict = true)
=> TryParse(s, strict, out var v, out var e) ? v : throw new FormatException($"invalid UUID256 ({e})");
private static int HexVal(char c) => c switch { >= '0' and <= '9' => c - '0', >= 'a' and <= 'f' => c - 'a' + 10, >= 'A' and <= 'F' => c - 'A' + 10, _ => -1 };
// Equality / ordering: numeric = big-endian byte order = canonical-text order (§7.1)
public bool Equals(Uuid256 o) => _a == o._a && _b == o._b && _c == o._c && _d == o._d;
public override bool Equals(object? obj) => obj is Uuid256 o && Equals(o);
public override int GetHashCode() => HashCode.Combine(_a, _b, _c, _d);
public int CompareTo(Uuid256 o)
{
int c = _a.CompareTo(o._a); if (c != 0) return c;
c = _b.CompareTo(o._b); if (c != 0) return c;
c = _c.CompareTo(o._c); if (c != 0) return c;
return _d.CompareTo(o._d);
}
public static bool operator ==(Uuid256 x, Uuid256 y) => x.Equals(y);
public static bool operator !=(Uuid256 x, Uuid256 y) => !x.Equals(y);
}
// ============================================================================
// Program: self-tests + bulk exact duplicate check
// ============================================================================
static class Program
{
static int SelfTest()
{
int fails = 0;
var vectors = new[] {
("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", "0001020304050607-08090a0b-4c0d0e0f-90111213-1415161718191a1b1c1d1e1f"),
("fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0", "fffefdfcfbfaf9f8-f7f6f5f4-43f2f1f0-afeeedec-ebeae9e8e7e6e5e4e3e2e1e0"),
};
for (int i = 0; i < vectors.Length; i++)
{
var (raw, expected) = vectors[i];
byte[] b = Convert.FromHexString(raw);
Uuid256.SetVersionAndVariant(b);
var id = Uuid256.FromBytes(b);
string txt = id.ToString();
bool ok = txt == expected && id.IsStrict
&& Uuid256.Parse(txt) == id && Uuid256.Parse(txt.ToUpperInvariant()) == id
&& Uuid256.TryParse(raw, strict: false, out var lenient, out _) && !lenient.IsStrict // raw compact: lenient ok
&& !Uuid256.TryParse(raw, strict: true, out _, out var e) && e == Uuid256.ParseError.Version // strict rejects (ver != 4)
&& id.ToByteArray().AsSpan().SequenceEqual(b);
Console.WriteLine($" spec §11 vector {i + 1}: {(ok ? "PASS" : "FAIL")} {txt}");
if (!ok) fails++;
}
{
string nil = Uuid256.Nil.ToString();
bool ok = !Uuid256.TryParse("0001020304050607_08090a0b-4c0d0e0f-90111213-1415161718191a1b1c1d1e1f", true, out _, out var e1) && e1 == Uuid256.ParseError.Hyphen
&& !Uuid256.TryParse("0001020304050607-08090a0b-4c0d0e0f-90111213-1415161718191a1b1c1d1e1", true, out _, out var e2) && e2 == Uuid256.ParseError.Length
&& !Uuid256.TryParse("0001020304050607-08090a0b-4c0d0e0f-90111213-1415161718191a1b1c1d1e1g", true, out _, out var e3) && e3 == Uuid256.ParseError.Char
&& !Uuid256.TryParse(nil, true, out _, out var e4) && e4 == Uuid256.ParseError.Version
&& Uuid256.TryParse(nil, false, out var n2, out _) && n2 == Uuid256.Nil
&& Uuid256.Max.ToString() == new string('f', 16) + "-" + new string('f', 8) + "-" + new string('f', 8) + "-" + new string('f', 8) + "-" + new string('f', 24)
&& Uuid256.Nil.CompareTo(Uuid256.Max) < 0;
Console.WriteLine($" parser rules (§3.2/§6): {(ok ? "PASS" : "FAIL")}");
if (!ok) fails++;
}
for (int i = 0; i < 3; i++)
{
var id = Uuid256.NewUuid256(); string txt = id.ToString();
// string offsets: hex digit 24 → char 26 (after 2 hyphens), hex digit 32 → char 35 (after 3 hyphens)
bool ok = id.IsStrict && txt.Length == 68 && txt[26] == '4' && "89ab".Contains(txt[35]) && Uuid256.Parse(txt) == id;
Console.WriteLine($" NewUuid256(): {txt} {(ok ? "ok" : "BAD")}");
if (!ok) fails++;
}
return fails;
}
// ---- bulk storage: ids in 512 MB chunks (byte[] is limited to ~2 GB) --------------------------
const int ChunkBits = 24; // 2^24 ids × 32 B = 512 MB per chunk
const int ChunkIds = 1 << ChunkBits, ChunkMask = ChunkIds - 1;
static byte[][] BulkGenerate(long n)
{
int chunks = (int)((n + ChunkIds - 1) / ChunkIds);
var store = new byte[chunks][];
for (int c = 0; c < chunks; c++)
{
long idsHere = Math.Min(ChunkIds, n - (long)c * ChunkIds);
var buf = new byte[idsHere * Uuid256.Size];
RandomNumberGenerator.Fill(buf); // §5.2
for (int p = 0; p < buf.Length; p += Uuid256.Size) Uuid256.SetVersionAndVariant(buf.AsSpan(p, Uuid256.Size)); // §4
store[c] = buf;
}
return store;
}
static Span Id(byte[][] store, long i) => store[(int)(i >> ChunkBits)].AsSpan((int)(i & ChunkMask) * Uuid256.Size, Uuid256.Size);
static List<(long i, long j, Uuid256 id)> FindDuplicates(byte[][] store, long n)
{
const int BB = 24; const int NB = 1 << BB; // bucket = top 24 bits (bytes 0..2, all random)
var start = new int[NB + 1];
for (long i = 0; i < n; i++) { var s = Id(store, i); start[((s[0] << 16) | (s[1] << 8) | s[2]) + 1]++; }
for (int b = 0; b < NB; b++) start[b + 1] += start[b]; // exclusive prefix sums
var cursor = (int[])start.Clone();
var order = new int[n]; // n ≤ int.MaxValue for this harness
for (long i = 0; i < n; i++) { var s = Id(store, i); order[cursor[(s[0] << 16) | (s[1] << 8) | s[2]]++] = (int)i; }
var dups = new List<(long, long, Uuid256)>();
for (int b = 0; b < NB; b++)
{
int lo = start[b], hi = start[b + 1];
if (hi - lo < 2) continue;
for (int x = lo; x < hi; x++)
for (int y = x + 1; y < hi; y++) // buckets are tiny (n / 16M)
{
long i = order[x], j = order[y];
if (Id(store, i).SequenceEqual(Id(store, j)))
dups.Add((Math.Min(i, j), Math.Max(i, j), Uuid256.FromBytes(Id(store, i))));
}
}
return dups;
}
static int Main(string[] args)
{
long n = 100_000_000; int planted = 0;
if (args.Length >= 2 && (args[0] == "-p" || args[0] == "-P")) // parse mode: -p strict, -P lenient
{
if (Uuid256.TryParse(args[1], strict: args[0] == "-p", out var pv, out var pe)) { Console.WriteLine("ok " + Convert.ToHexString(pv.ToByteArray()).ToLowerInvariant()); return 0; }
Console.WriteLine("error " + pe.ToString().ToLowerInvariant()); return 1;
}
for (int i = 0; i < args.Length; i++)
{
if (args[i] == "-g") // just print ids: -g [count]
{
long count = i + 1 < args.Length && long.TryParse(args[i + 1], NumberStyles.None, CultureInfo.InvariantCulture, out var c) ? c : 1;
for (long k = 0; k < count; k++) Console.WriteLine(Uuid256.NewUuid256());
return 0;
}
if (args[i] == "-n" && i + 1 < args.Length && long.TryParse(args[i + 1], NumberStyles.None, CultureInfo.InvariantCulture, out var nv)) { n = nv; i++; }
else if (args[i] == "-i" && i + 1 < args.Length && int.TryParse(args[i + 1], NumberStyles.None, CultureInfo.InvariantCulture, out var iv)) { planted = iv; i++; }
else { Console.WriteLine("usage: dotnet run uuid256.cs -- [-g [count]] [-n count] [-i planted_dups] | -p|-P "); return 2; }
}
if (n < 2 || n > int.MaxValue || planted < 0 || planted > n / 2) { Console.WriteLine("-n must be 2..2147483647 and -i at most n/2"); return 2; }
string F(long v) => v.ToString("N0", CultureInfo.InvariantCulture);
Console.WriteLine("UUID256 reference implementation (C# / .NET) — README.md (256-bit random, 16-8-8-8-24 text)\n");
Console.WriteLine("Self-tests:");
if (SelfTest() > 0) { Console.WriteLine(" self-test FAILED — aborting"); return 1; }
var sw = Stopwatch.StartNew(); const int K = 1_000_000;
for (int i = 0; i < K; i++) Uuid256.NewUuid256();
double perCall = sw.Elapsed.TotalSeconds / K;
Console.WriteLine($"\nNewUuid256() per-call cost: {perCall * 1e6:F2} µs → {1 / perCall / 1e6:F2} M ids/s single-threaded " +
$"(1e9 ids would take ~{1e9 * perCall / 60:F0} min just to generate)");
Console.WriteLine($"\nBulk exact duplicate check: n={F(n)} ids, planted duplicates={planted}, RAM ~{n * 36 / 1e9:F1} GB");
sw.Restart();
var store = BulkGenerate(n);
var tGen = sw.Elapsed;
// planted duplicates: id[dst] := id[src] — sources evenly spaced over the lower half, each mirrored
// into the upper half, so all 2K positions are distinct and no source is itself a target (K <= n/2).
long plantStep = planted > 0 ? (n / 2) / planted : 0;
for (int k = 0; k < planted; k++)
{
long src = plantStep * k, dst = n - 1 - src;
Id(store, src).CopyTo(Id(store, dst));
Console.WriteLine($" planted: id[{F(dst)}] := id[{F(src)}]");
}
long bad = 0;
for (long i = 0; i < n; i++) { var s = Id(store, i); if ((s[12] >> 4) != Uuid256.VersionNumber || (s[16] >> 6) != 0b10) bad++; }
var dups = FindDuplicates(store, n);
var tAll = sw.Elapsed;
foreach (var (i, j, id) in dups) Console.WriteLine($" DUPLICATE id[{F(i)}] == id[{F(j)}] {id}");
long rtOk = 0, step = Math.Max(1, n / 1000);
for (long i = 0; i < n; i += step) { var id = Uuid256.FromBytes(Id(store, i)); if (Uuid256.Parse(id.ToString()) == id) rtOk++; }
Console.WriteLine("\n==== RESULT ====");
Console.WriteLine($"ids generated: {F(n)} (RandomNumberGenerator.Fill + §4 in {tGen.TotalSeconds:F1}s; bucket-sort+compare in {(tAll - tGen).TotalSeconds:F1}s)");
Console.WriteLine($"version/variant violations: {F(bad)}");
Console.WriteLine($"text round-trips (sampled): {F(rtOk)} ok");
Console.WriteLine($"FULL 256-bit DUPLICATES: {F(dups.Count)}" + (planted > 0 ? $" (planted: {planted} — {(dups.Count == planted ? "all detected" : "COUNT MISMATCH")})" : ""));
if (dups.Count == 0) Console.WriteLine($" → no duplicates among {F(n)} ids");
double log2p = 2 * Math.Log2(n) - 251;
Console.WriteLine($"expected P(any collision) §5.3: n²/2²⁵¹ ≈ 2^{log2p:F1} ≈ {Math.Pow(2, log2p):E1}");
return dups.Count == planted ? 0 : 1;
}
}