code wiki / (root) / nx_id.nx

nx_id.nx source

↩ module page · 194 lines · 7011 B

1// nx_id.nx -- monotonic IDs and 128-bit content addresses. 2// 3// Three ID surfaces, each with explicit guarantees: 4// 5// nx_seqid_next(ctx) monotonic 64-bit, unique per ctx since 6// construction. Use for spans, requests, 7// tasks -- any ordering you only need 8// within one process lifetime. 9// 10// nx_uuid7(ctx) time-ordered 128-bit ID, RFC 9562 layout 11// draft (UUIDv7). Two i64 outputs. The 12// 48 high bits are unix-ms timestamp, 13// remaining 80 bits are random+counter. 14// Use across process boundaries when you 15// need both ordering AND collision-resist. 16// 17// nx_xid_blake_short 8-byte digest of an arbitrary byte 18// buffer using a tiny mixing function 19// (xxhash-style). Use for content 20// addressing where full SHA-256 is 21// overkill. NOT cryptographic. For 22// crypto use sha256.nx / sha512.nx. 23// 24// Why this file exists separately: 25// ID generation is touched by every observability module 26// (nx_log seq, nx_trace span_id, nx_metrics labels) and every 27// IPC layer (request_id headers). Centralising the policy 28// prevents drift -- e.g. one module producing 64-bit decimal, 29// another 128-bit hex, another timestamp-prefixed. All flow 30// through these three primitives. 31// 32// Design references: 33// RFC 9562 (UUIDv7) -- time-ordered v7 layout 34// Twitter Snowflake -- 64-bit time+machine+seq id 35// ULID spec -- Crockford-base32 26-char id 36// xxHash3 -- non-crypto fast mixing function 37 38// nx_safety_envelope: 39// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 40// sil_target: SIL1 41// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 42// verdict: NOT_YET_EVALUATED 43 44import "syscalls.nx" 45import "nx_time.nx" 46const NX_MAGIC_1000000: i64 = 1000000 47 48struct NxIdCtx { 49 seq: i64, // monotonic counter for nx_seqid_next 50 state: i64, // PRNG state for uuid7 random tail 51} 52 53const NX_IDCTX_BYTES: i64 = 16 54 55// --- construction -------------------------------------------------- 56 57func nx_id_new(seed: i64) -> *NxIdCtx { 58 let raw: *u8 = sys_mmap(NX_IDCTX_BYTES) 59 let c: *NxIdCtx = raw as *NxIdCtx 60 c.seq = 0 61 c.state = seed 62 if c.state == 0 { c.state = 0x9E3779B97F4A7C15 } 63 return c 64} 65 66// --- xorshift64 PRNG (private, deterministic if seeded same way) ---- 67 68func nx_id_xorshift(ctx: *NxIdCtx) -> i64 { 69 var x: i64 = ctx.state 70 x = x ^ (x << 13) 71 x = x ^ (x >> 7) 72 x = x ^ (x << 17) 73 ctx.state = x 74 return x 75} 76 77// --- monotonic 64-bit sequence id --------------------------------- 78 79func nx_seqid_next(ctx: *NxIdCtx) -> i64 { 80 let v: i64 = ctx.seq + 1 81 ctx.seq = v 82 return v 83} 84 85// --- 128-bit time-ordered id (UUIDv7-like) ------------------------- 86 87// Returns the high 64 bits of a UUIDv7-shaped id (timestamp + seq). 88// Caller pairs with nx_uuid7_lo to get the full 128-bit value. 89// 90// Layout (high 64 bits): 91// bits [63:16] unix-ms timestamp (48 bits) 92// bits [15:12] version = 7 93// bits [11:0] first 12 bits of monotonic seq (collision tail) 94func nx_uuid7_hi(ctx: *NxIdCtx) -> i64 { 95 let now_ns: i64 = nx_clock_now_ns() 96 let now_ms: i64 = now_ns / NX_MAGIC_1000000 97 let ts48: i64 = now_ms - (now_ms / 0x1000000000000) * 0x1000000000000 98 let seq: i64 = nx_seqid_next(ctx) 99 let seq12: i64 = seq - (seq / 0x1000) * 0x1000 100 let version: i64 = 7 101 return (ts48 << 16) | (version << 12) | seq12 102} 103 104// Returns the low 64 bits of the same UUIDv7. Variant + 62 bits 105// random. Variant per RFC 9562 = 0b10xx in the top two bits. 106func nx_uuid7_lo(ctx: *NxIdCtx) -> i64 { 107 let r: i64 = nx_id_xorshift(ctx) 108 // Mask off variant nibble (top 2 bits) then OR in 0b10. 109 let variant_mask: i64 = 0x3FFFFFFFFFFFFFFF // clear top 2 bits 110 let variant_set: i64 = 0x8000000000000000 // 0b10xx... in top 2 bits 111 return (r & variant_mask) | variant_set 112} 113 114// --- xid: short non-crypto 8-byte content address ----------------- 115 116// xxhash-style mixing. Good distribution, fast, deterministic. 117// NOT collision-resistant under adversarial input -- for that use 118// sha256_digest from sha256.nx. 119func nx_xid_short(buf: *u8, len: i64) -> i64 { 120 var h: i64 = 0x9E3779B97F4A7C15 121 var i: i64 = 0 122 while i < len { 123 let b: i64 = buf[i] 124 h = h ^ b 125 h = h * 0x100000001B3 126 // Rotate-left 13 (manual: i64 has no rol intrinsic yet). 127 let lo: i64 = (h << 13) 128 let hi: i64 = (h >> 51) & 0x1FFF 129 h = lo | hi 130 i = i + 1 131 } 132 // Final avalanche. 133 h = h ^ (h >> 33) 134 h = h * 0xC6BC279692B5C323 135 h = h ^ (h >> 33) 136 return h 137} 138 139// --- self-test ------------------------------------------------------ 140 141func main() -> i64 { 142 let ctx: *NxIdCtx = nx_id_new(0xCAFEBABE) 143 144 // Sequence id is monotonic + starts at 1. 145 let s1: i64 = nx_seqid_next(ctx) 146 let s2: i64 = nx_seqid_next(ctx) 147 let s3: i64 = nx_seqid_next(ctx) 148 if s1 != 1 { return __syscall(93, 10, 0, 0, 0, 0, 0) } 149 if s2 != 2 { return __syscall(93, 11, 0, 0, 0, 0, 0) } 150 if s3 != 3 { return __syscall(93, 12, 0, 0, 0, 0, 0) } 151 if s2 <= s1 { return __syscall(93, 13, 0, 0, 0, 0, 0) } 152 153 // UUID7 hi has version nibble = 7 in bits [15:12]. 154 let hi: i64 = nx_uuid7_hi(ctx) 155 let version_nib: i64 = (hi >> 12) & 0xF 156 if version_nib != 7 { return __syscall(93, 20, 0, 0, 0, 0, 0) } 157 158 // UUID7 lo has variant 10xx in top two bits. 159 let lo: i64 = nx_uuid7_lo(ctx) 160 let variant_top: i64 = (lo >> 62) & 0x3 161 if variant_top != 2 { return __syscall(93, 21, 0, 0, 0, 0, 0) } 162 163 // xid: deterministic for same input. 164 let payload1: *u8 = sys_mmap(16) 165 payload1[0] = 0x4E 166 payload1[1] = 0x49 167 payload1[2] = 0x53 168 payload1[3] = 0x48 169 payload1[4] = 0x49 170 let h_a: i64 = nx_xid_short(payload1, 5) 171 let h_b: i64 = nx_xid_short(payload1, 5) 172 if h_a != h_b { return __syscall(93, 30, 0, 0, 0, 0, 0) } 173 174 // xid: differs for different input (collision-very-unlikely-not-impossible). 175 let payload2: *u8 = sys_mmap(16) 176 payload2[0] = 0x4E 177 payload2[1] = 0x49 178 payload2[2] = 0x53 179 payload2[3] = 0x48 180 payload2[4] = 0x49 181 payload2[5] = 0x21 // ! 182 let h_c: i64 = nx_xid_short(payload2, 6) 183 if h_c == h_a { return __syscall(93, 31, 0, 0, 0, 0, 0) } 184 185 // Two distinct ctxs with same seed produce identical xorshift 186 // sequences -- this is a feature for replay debugging. 187 let ctx2: *NxIdCtx = nx_id_new(0xCAFEBABE) 188 let r1: i64 = nx_id_xorshift(ctx) // not equal: ctx has consumed state via uuid7 189 let r2: i64 = nx_id_xorshift(ctx2) // first draw 190 // We deliberately don't compare these -- the test is just 191 // that the function runs without crashing. 192 193 return 0 194}