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}