code wiki / (root) / nx_sovgit_obj.nx

nx_sovgit_obj.nx source

↩ module page · 219 lines · 8430 B

1// nx_sovgit_obj.nx -- SOVEREIGN GIT OBJECT STORE (roadmap rung X0). Content-addressed blob/tree/commit: 2// frame = "<type> <len>\0<content>" 3// id = SHA-256(frame) [git object-format=sha256, 64 lowercase hex] 4// loose = zlib(frame) at <objroot>/<id[0:2]>/<id[2:64]> 5// Reuses the sovereign substrate, no reinvention: sha256_digest (nx_sha256), dfe_compress (nx_deflate_enc, 6// raw deflate -> we wrap 0x78 0x01 + adler32), nx_zlib_inflate + adler32 (nx_zlib_wrap/nx_adler32). 7// Proven byte-exact against STOCK git 2.39 sha256 ids in nx_sovgit_obj_gate.nx. 8// license_tier: ORIGINAL 9import "nx_syscalls.nx" 10import "nx_sha256.nx" 11import "nx_deflate_enc.nx" 12import "nx_zlib_wrap.nx" 13import "nx_adler32.nx" 14const K_MAGIC_1040: i64 = 1040 15const K_MAGIC_65536: i64 = 65536 16const K_MAGIC_4096: i64 = 4096 17 18// ---- byte helpers ---- 19func sg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 20 21func sg_cpy(dst: *u8, dsto: i64, src: *u8, srco: i64, n: i64) -> i64 { 22 var i: i64 = 0 23 while i < n { dst[dsto + i] = src[srco + i]; i = i + 1 } 24 return dsto + n 25} 26 27// write decimal ascii of v (>= 0) into out at `at`; return new offset 28func sg_dec(out: *u8, at: i64, v: i64) -> i64 { 29 let tmp: *u8 = sys_mmap(32) 30 var x: i64 = v 31 var i: i64 = 31 32 if x == 0 { tmp[i] = 48 as u8; i = i - 1 } 33 while x > 0 { tmp[i] = (48 + x % 10) as u8; x = x / 10; i = i - 1 } 34 var a: i64 = at 35 var j: i64 = i + 1 36 while j < 32 { out[a] = tmp[j]; a = a + 1; j = j + 1 } 37 return a 38} 39 40// 32-byte digest -> 64 lowercase hex chars at out 41func sg_hex(dig: *u8, out: *u8) -> i64 { 42 var i: i64 = 0 43 while i < 32 { 44 let b: i64 = dig[i] as i64 45 let hi: i64 = (b >> 4) & 15 46 let lo: i64 = b & 15 47 var ch: i64 = 48 + hi 48 if hi > 9 { ch = 87 + hi } 49 out[i * 2] = ch as u8 50 var cl: i64 = 48 + lo 51 if lo > 9 { cl = 87 + lo } 52 out[i * 2 + 1] = cl as u8 53 i = i + 1 54 } 55 return 0 56} 57 58// big-endian u32 into out at `at` 59func sg_be32(out: *u8, at: i64, v: i64) -> i64 { 60 out[at] = ((v >> 24) & 255) as u8 61 out[at + 1] = ((v >> 16) & 255) as u8 62 out[at + 2] = ((v >> 8) & 255) as u8 63 out[at + 3] = (v & 255) as u8 64 return at + 4 65} 66 67// ---- git object framing ---- 68// "<typ> <clen>\0<content>" into out; return frame length. typ is NUL-terminated. 69func sg_frame(typ: *u8, content: *u8, clen: i64, out: *u8) -> i64 { 70 var o: i64 = 0 71 o = sg_cpy(out, o, typ, 0, sg_slen(typ)) 72 out[o] = 32 as u8; o = o + 1 73 o = sg_dec(out, o, clen) 74 out[o] = 0 as u8; o = o + 1 75 o = sg_cpy(out, o, content, 0, clen) 76 return o 77} 78 79// raw 32-byte object id of (typ, content) 80// bounded-VSZ 2026-07-20: the frame buffer is munmapped before return -- callers that hash one object 81// PER FILE (the sovereign pusher walking a tree) would otherwise leak sum(filesizes) of VSZ. 82func sg_oid_raw(typ: *u8, content: *u8, clen: i64, out32: *u8) -> i64 { 83 let fbuf: *u8 = sys_mmap(clen + 64) 84 let flen: i64 = sg_frame(typ, content, clen, fbuf) 85 sha256_digest(fbuf, flen, out32) 86 sys_munmap(fbuf, clen + 64) 87 return 0 88} 89 90// hex (64 chars) object id of (typ, content) 91func sg_oid_hex(typ: *u8, content: *u8, clen: i64, outhex: *u8) -> i64 { 92 let dig: *u8 = sys_mmap(32) 93 sg_oid_raw(typ, content, clen, dig) 94 sg_hex(dig, outhex) 95 return 0 96} 97 98// ---- zlib wrap (git loose object body) ---- 99// wrap `frame` (flen bytes) as a full zlib stream into zout; return zlib length. 100// ⚠CONTRACT: zout MUST be sized >= flen + (flen >> 1) + 64. Fixed-Huffman deflate EXPANDS 101// high-entropy input (literals >=144 cost 9 bits; worst case with 3-byte matches ~1.30x) -- 102// the old "flen + 128" contract overflowed on random/binary payloads >= ~256KB (caught by 103// round-trip probe 2026-07-20: firstdiff=0 err=adler from 262144 up; the sovgit big-blob bug). 104func sg_zwrap(frame: *u8, flen: i64, zout: *u8) -> i64 { 105 zout[0] = 0x78 as u8 106 zout[1] = 0x01 as u8 107 let body: *u8 = (zout as i64 + 2) as *u8 108 let clen: i64 = dfe_compress(frame, flen, body) 109 var zo: i64 = 2 + clen 110 sg_be32(zout, zo, adler32(frame, flen)); zo = zo + 4 111 return zo 112} 113 114// ---- loose object store ---- 115// path <objroot>/<hex[0:2]>/<hex[2:64]> into pbuf (NUL-terminated); return length. 116func sg_loose_path(objroot: *u8, hex: *u8, pbuf: *u8) -> i64 { 117 var o: i64 = sg_cpy(pbuf, 0, objroot, 0, sg_slen(objroot)) 118 pbuf[o] = 47 as u8; o = o + 1 119 pbuf[o] = hex[0]; o = o + 1 120 pbuf[o] = hex[1]; o = o + 1 121 pbuf[o] = 47 as u8; o = o + 1 122 var i: i64 = 2 123 while i < 64 { pbuf[o] = hex[i]; o = o + 1; i = i + 1 } 124 pbuf[o] = 0 as u8 125 return o 126} 127 128// write (typ, content) as a loose object under objroot; write 64-hex id to outhex; return 0 ok / negative err. 129// Bounded-VSZ: every internal mmap is munmapped (hot-loop callers -- pack unpack -- stay flat). 130// Short/failed writes return -2 (fail LOUD; a truncated loose object must never report ok). 131func sg_write_loose(objroot: *u8, typ: *u8, content: *u8, clen: i64, outhex: *u8) -> i64 { 132 sg_oid_hex(typ, content, clen, outhex) 133 let rl: i64 = sg_slen(objroot) 134 sys_mkdir(objroot, 0x1ed) 135 let dbuf: *u8 = sys_mmap(rl + 8) 136 var d: i64 = sg_cpy(dbuf, 0, objroot, 0, rl) 137 dbuf[d] = 47 as u8; d = d + 1 138 dbuf[d] = outhex[0]; d = d + 1 139 dbuf[d] = outhex[1]; d = d + 1 140 dbuf[d] = 0 as u8 141 sys_mkdir(dbuf, 0x1ed) 142 let fbuf: *u8 = sys_mmap(clen + 64) 143 let flen: i64 = sg_frame(typ, content, clen, fbuf) 144 let zcap: i64 = flen + (flen >> 1) + 128 145 let zbuf: *u8 = sys_mmap(zcap) 146 let zlen: i64 = sg_zwrap(fbuf, flen, zbuf) 147 let pbuf: *u8 = sys_mmap(rl + 80) 148 sg_loose_path(objroot, outhex, pbuf) 149 let fd: i64 = sys_openat_wr(pbuf, 0x1a4) 150 var ret: i64 = 0 151 if fd < 0 { ret = 0 - 1 } else { 152 let wn: i64 = sys_write(fd, zbuf, zlen) 153 if wn != zlen { ret = 0 - 2 } 154 sys_close(fd) 155 } 156 sys_munmap(dbuf, rl + 8) 157 sys_munmap(fbuf, clen + 64) 158 sys_munmap(zbuf, zcap) 159 sys_munmap(pbuf, rl + 80) 160 return ret 161} 162 163// read a loose object (64-hex id) under objroot; content -> out, type (NUL-term) -> typ_out; 164// return content length, or negative on error. 165// Inflate cap is INPUT-DERIVED (zlib expansion bounded ~1032x), clamped to the 64MiB object 166// envelope -- objects > 1MiB read correctly (the old fixed 1<<20 cap silently dropped them). 167// Bounded-VSZ: all mappings munmapped (a full-repo pack walk calls this per object). 168func sg_read_loose(objroot: *u8, hex: *u8, out: *u8, typ_out: *u8) -> i64 { 169 let pl: i64 = sg_slen(objroot) + 80 170 let pbuf: *u8 = sys_mmap(pl) 171 sg_loose_path(objroot, hex, pbuf) 172 let szp: *i64 = sys_mmap(16) as *i64 173 let zbuf: *u8 = sys_read_file(pbuf, szp) 174 sys_munmap(pbuf, pl) 175 if (zbuf as i64) == 0 { sys_munmap(szp as *u8, 16); return 0 - 1 } 176 let zn: i64 = szp[0] 177 sys_munmap(szp as *u8, 16) 178 var cap: i64 = zn * K_MAGIC_1040 + K_MAGIC_65536 179 if cap > (1 << 26) { cap = 1 << 26 } 180 let r: *NxZlibResult = nx_zlib_inflate(zbuf, zn, cap) 181 var ret: i64 = 0 - 2 182 if r.error_code == 0 { 183 let frame: *u8 = r.output_data 184 var i: i64 = 0 185 var t: i64 = 0 186 while frame[i] != (32 as u8) { typ_out[t] = frame[i]; t = t + 1; i = i + 1 } 187 typ_out[t] = 0 as u8 188 i = i + 1 189 var clen: i64 = 0 190 while frame[i] != (0 as u8) { clen = clen * 10 + ((frame[i] as i64) - 48); i = i + 1 } 191 i = i + 1 192 sg_cpy(out, 0, frame, i, clen) 193 ret = clen 194 } 195 if (r.output_data as i64) != 0 { sys_munmap(r.output_data, cap) } 196 sys_munmap(r as *u8, K_MAGIC_4096) 197 sys_munmap(zbuf, zn) 198 return ret 199} 200 201// ---- tree entry ---- 202// append "<mode> <name>\0<rawhash32>" to out at `at`; return new offset. mode/name are NUL-terminated. 203func sg_tree_entry(out: *u8, at: i64, mode: *u8, name: *u8, rawhash: *u8) -> i64 { 204 var o: i64 = sg_cpy(out, at, mode, 0, sg_slen(mode)) 205 out[o] = 32 as u8; o = o + 1 206 o = sg_cpy(out, o, name, 0, sg_slen(name)) 207 out[o] = 0 as u8; o = o + 1 208 o = sg_cpy(out, o, rawhash, 0, 32) 209 return o 210} 211 212// compile-only smoke: empty-blob id must begin with git's documented sha256 constant "47..." 213func main() -> i64 { 214 let hx: *u8 = sys_mmap(80) 215 sg_oid_hex("blob" as *u8, "" as *u8, 0, hx) 216 if hx[0] != (52 as u8) { return 1 } 217 if hx[1] != (55 as u8) { return 1 } 218 return 0 219}