code wiki / (root) / nx_uuid_v1.nx

nx_uuid_v1.nx source

↩ module page · 152 lines · 5288 B

1// uuid.nx -- UUID v4 (random) + v7 (time-ordered) generators. 2// 3// RFC 4122 (v4) + draft-ietf-uuidrev-rfc4122bis (v7). 16-byte 4// identifier, formatted as 36-char hex string with hyphens. 5// 6// v4 = 122 random bits + 6 deterministic version/variant bits. 7// Use when you don't need lexicographic time-ordering. 8// 9// v7 = 48-bit Unix ms timestamp prefix + 74 random bits + 6 10// version/variant bits. Sorts lexicographically by creation 11// time, which is huge for database indexes -- rows cluster 12// instead of scattering, and clustered B-trees stay warm. 13// Use in preference to v4 for new systems. 14// 15// Invariants: 16// U1 Every byte of the non-version/variant space is from 17// /dev/urandom (via rand.nx). No PRNG state persists; each 18// UUID is an independent sample. 19// U2 Version + variant bits exactly match the RFC specs at 20// byte positions 6 (version) and 8 (variant). 21// U3 v7 timestamp is milliseconds since epoch, big-endian in 22// bytes 0..5. Enables lexicographic time-ordering. 23// U4 Formatting is deterministic: lowercase hex, no prefix, 24// exact dash placement at 8-4-4-4-12 positions. 25 26// nx_safety_envelope: 27// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 28// sil_target: SIL1 29// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 30// verdict: NOT_YET_EVALUATED 31 32import "nx_syscalls.nx" 33import "nx_rand.nx" 34import "nx_hex_codec.nx" 35 36// ---- raw binary generators --------------------------------------- 37 38// Fill `out` with a fresh v4 UUID (16 bytes). out must point at 39// at least 16 bytes. Returns 0 on success, negative if rand fails. 40func uuid_v4_bytes(out: *u8) -> i64 { 41 let n: i64 = rand_bytes(out, 16) 42 if n != 16 { return -1 } 43 // Version = 4 in high nibble of byte 6. 44 out[6] = (out[6] & 0x0F) | 0x40 45 // Variant = RFC 4122 (10xx) in high bits of byte 8. 46 out[8] = (out[8] & 0x3F) | 0x80 47 return 0 48} 49 50// Fill `out` with a fresh v7 UUID. Bytes 0..5 = millisecond 51// Unix timestamp (big-endian). Bytes 6..15 = version/variant 52// bits + 74 random bits. Caller supplies `unix_ms`; runtime 53// captures it once instead of per-call to keep the function 54// usable in environments without monotonic clocks. 55func uuid_v7_bytes(unix_ms: i64, out: *u8) -> i64 { 56 // Fill low 10 bytes with randomness first. 57 let rand_part: *u8 = sys_mmap(10) 58 let n: i64 = rand_bytes(rand_part, 10) 59 if n != 10 { return -1 } 60 // Write timestamp big-endian bytes 0..5 (48 bits). 61 out[0] = (unix_ms >> 40) & 0xFF 62 out[1] = (unix_ms >> 32) & 0xFF 63 out[2] = (unix_ms >> 24) & 0xFF 64 out[3] = (unix_ms >> 16) & 0xFF 65 out[4] = (unix_ms >> 8) & 0xFF 66 out[5] = unix_ms & 0xFF 67 // Random bytes 6..15. 68 var i: i64 = 0 69 while i < 10 { 70 out[6 + i] = rand_part[i] 71 i = i + 1 72 } 73 // Version = 7 in high nibble of byte 6. 74 out[6] = (out[6] & 0x0F) | 0x70 75 // Variant = RFC 4122 (10xx) in high bits of byte 8. 76 out[8] = (out[8] & 0x3F) | 0x80 77 return 0 78} 79 80// ---- 36-char hex formatting -------------------------------------- 81// 82// Canonical format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 83// (8-4-4-4-12 lowercase hex digits). 84 85func uuid_format(bytes: *u8, out: *u8) -> i64 { 86 // Full hex of 16 bytes = 32 chars; format inserts 4 hyphens 87 // at positions 8, 13, 18, 23. 88 let hex_buf: *u8 = sys_mmap(32) 89 hex_encode(bytes, 16, hex_buf) 90 // Copy with hyphen insertions. 91 var src: i64 = 0 92 var dst: i64 = 0 93 while dst < 36 { 94 if dst == 8 { 95 out[dst] = 0x2D // '-' 96 dst = dst + 1 97 } else { 98 if dst == 13 { 99 out[dst] = 0x2D 100 dst = dst + 1 101 } else { 102 if dst == 18 { 103 out[dst] = 0x2D 104 dst = dst + 1 105 } else { 106 if dst == 23 { 107 out[dst] = 0x2D 108 dst = dst + 1 109 } else { 110 out[dst] = hex_buf[src] 111 src = src + 1 112 dst = dst + 1 113 } 114 } 115 } 116 } 117 } 118 return 36 119} 120 121// Convenience: generate v4 and format directly. `out` gets 36 122// bytes of ASCII hex + hyphens. Returns 36 on success, negative 123// on rand failure. 124func uuid_v4_string(out: *u8) -> i64 { 125 let bytes: *u8 = sys_mmap(16) 126 let rc: i64 = uuid_v4_bytes(bytes) 127 if rc < 0 { return rc } 128 return uuid_format(bytes, out) 129} 130 131func uuid_v7_string(unix_ms: i64, out: *u8) -> i64 { 132 let bytes: *u8 = sys_mmap(16) 133 let rc: i64 = uuid_v7_bytes(unix_ms, bytes) 134 if rc < 0 { return rc } 135 return uuid_format(bytes, out) 136} 137 138// Compile-only smoke. 139func main() -> i64 { 140 let out: *u8 = sys_mmap(64) 141 let rc: i64 = uuid_v4_string(out) 142 if rc != 36 { return 1 } 143 // Position 8 should be '-'. 144 if out[8] != 0x2D { return 2 } 145 if out[13] != 0x2D { return 3 } 146 if out[18] != 0x2D { return 4 } 147 if out[23] != 0x2D { return 5 } 148 // Byte 14 (first char of 3rd group) encodes version; should 149 // have the v4 bit (high nibble == '4' = 0x34). 150 if out[14] != 0x34 { return 6 } 151 return 0 152}