code wiki / _hdl_build / nx_nbk.nx

nx_nbk.nx source

↩ module page · 149 lines · 7008 B

1// ⚠ DEPRECATED 2026-06-22 (audit: DUPLICATE) -- the OWNED content-addressed container ALREADY EXISTS as the 2// sovereign storage substrate: nx_canon_cid (byte-deterministic NXR1 + CID=nxc1-+sha256) + nx_uxf_cid (multicodec 3// profiles incl. UXF_ARCHIVE=5 + UXF_MEDIA=3) + nx_uxf_decode (tolerant reader). This file reinvented that with a 4// WEAKER djb2 CID and non-canonical ordering. DO NOT build further on nx_nbk. The reader/media bundling rung must 5// be a UXF_ARCHIVE packer that reuses nx_canon_cid + nx_uxf_cid (entry-name -> bytes), NOT a new format. Kept only 6// as a reference for that rebuild. (operator: "we already built a format, audit so we avoid duplicates.") 7// 8// nx_nbk.nx -- the SOVEREIGN NISHI BOOK container (.nbk): the superior media format WE OWN that every lock-in 9// format (EPUB / MOBI / AZW / PDF) migrates INTO. One self-contained, content-addressed, integrity-verified file. 10// Format SSOT (this library; pack + reader + gate all import it so they cannot disagree). 11// 12// LAYOUT: header(32) | payloads (concatenated) | directory 13// header: "NXBK"(4) ver(1)=1 flags(3)=0 | nentries(BE u32 @8) | dir_offset(BE u32 @12) | cid(BE u64 @16) | rsvd(8) 14// payload: each entry's raw bytes, back to back, starting at offset 32 15// dir: nentries records: name_len(BE u16) name(bytes) data_off(BE u32) data_len(BE u32) entry_hash(BE u64) 16// 17// WHY SUPERIOR (vs MOBI/EPUB, which have ZERO content integrity + can carry DRM): 18// - content-addressed: cid = djb2 over ALL payloads -> a corrupted/tampered byte is DETECTED (nbk_check) 19// - per-entry integrity: each entry carries its own hash -> pinpoints which part corrupted 20// - NO DRM by construction: a format we own cannot lock us out of our own device 21// - deterministic: same inputs -> byte-identical .nbk -> reproducible, auditable CID 22// - streamable: the directory is self-describing -> read any entry by offset without scanning the whole file 23// (djb2 cid here is a fast content-id + corruption detector; a cryptographic CID (sha256/blake3) is a hardening rung.) 24// license_tier: ORIGINAL 25import "nx_syscalls.nx" 26const K_MAGIC_5381: i64 = 5381 27const K_MAGIC_67108864: i64 = 67108864 28 29func nbk_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 30func nbk_djb2(p: *u8, n: i64) -> i64 { var h: i64=K_MAGIC_5381; var i: i64=0; while i<n { h = ((h<<5)+h) + (p[i] as i64); i=i+1 } return h } 31 32func nbk_put16(m: *u8, o: i64, v: i64) -> i64 { m[o]=((v>>8)&0xff) as u8; m[o+1]=(v&0xff) as u8; return o+2 } 33func nbk_put32(m: *u8, o: i64, v: i64) -> i64 { m[o]=((v>>24)&0xff) as u8; m[o+1]=((v>>16)&0xff) as u8; m[o+2]=((v>>8)&0xff) as u8; m[o+3]=(v&0xff) as u8; return o+4 } 34// extract 8 bytes MSB-first using only >>8 steps (sign-correct via &0xff) -- nxasm mis-handles shift immediates >=32. 35func nbk_put64(m: *u8, o: i64, v: i64) -> i64 { 36 var x: i64 = v 37 var i: i64 = 0 38 while i < 8 { m[o + 7 - i] = (x & 0xff) as u8; x = x >> 8; i = i + 1 } 39 return o + 8 40} 41func nbk_be16(b: *u8, o: i64) -> i64 { return ((b[o] as i64)<<8) | (b[o+1] as i64) } 42func nbk_be32(b: *u8, o: i64) -> i64 { return ((b[o] as i64)<<24)|((b[o+1] as i64)<<16)|((b[o+2] as i64)<<8)|(b[o+3] as i64) } 43func nbk_be64(b: *u8, o: i64) -> i64 { var v: i64=0; var i: i64=0; while i<8 { v = (v<<8) | (b[o+i] as i64); i=i+1 } return v } 44 45// pack `count` entries (names[i]=*u8 name, datas[i]=*u8 bytes, lens[i]=len) into a .nbk at `path`. returns total bytes. 46func nbk_pack(path: *u8, names: *i64, datas: *i64, lens: *i64, count: i64) -> i64 { 47 let m: *u8 = sys_mmap(K_MAGIC_67108864) // 64 MiB working buffer 48 let offs: *i64 = sys_mmap(count*8 + 8) as *i64 49 let hsh: *i64 = sys_mmap(count*8 + 8) as *i64 50 var o: i64 = 32 // payloads start after the 32-byte header 51 var cid: i64 = K_MAGIC_5381 52 var ci: i64 = 0 53 while ci < count { 54 offs[ci] = o 55 let d: *u8 = datas[ci] as *u8 56 let l: i64 = lens[ci] 57 var k: i64 = 0 58 while k < l { m[o] = d[k]; cid = ((cid<<5)+cid) + (d[k] as i64); o = o+1; k = k+1 } 59 hsh[ci] = nbk_djb2(d, l) 60 ci = ci + 1 61 } 62 let diroff: i64 = o 63 ci = 0 64 while ci < count { 65 let nm: *u8 = names[ci] as *u8 66 let nl: i64 = nbk_slen(nm) 67 o = nbk_put16(m, o, nl) 68 var j: i64 = 0; while j < nl { m[o]=nm[j]; o=o+1; j=j+1 } 69 o = nbk_put32(m, o, offs[ci]) 70 o = nbk_put32(m, o, lens[ci]) 71 o = nbk_put64(m, o, hsh[ci]) 72 ci = ci + 1 73 } 74 // header 75 m[0]=78 as u8; m[1]=88 as u8; m[2]=66 as u8; m[3]=75 as u8 // "NXBK" 76 m[4]=1 as u8; m[5]=0 as u8; m[6]=0 as u8; m[7]=0 as u8 // ver 1 77 nbk_put32(m, 8, count) 78 nbk_put32(m, 12, diroff) 79 nbk_put64(m, 16, cid) 80 nbk_put64(m, 24, 0) 81 let fd: i64 = sys_openat_wr(path, 0x1a4) 82 if fd < 0 { return 0-1 } 83 sys_write(fd, m, o); sys_close(fd) 84 return o 85} 86 87// verify a loaded .nbk: magic ok + recomputed cid == stored cid + every entry hash matches. 1 ok, 0 corrupt/-bad. 88func nbk_check(m: *u8, n: i64) -> i64 { 89 if n < 32 { return 0 } 90 if m[0]!=(78 as u8) { return 0 } 91 if m[1]!=(88 as u8) { return 0 } 92 if m[2]!=(66 as u8) { return 0 } 93 if m[3]!=(75 as u8) { return 0 } 94 let count: i64 = nbk_be32(m, 8) 95 let diroff: i64 = nbk_be32(m, 12) 96 let cid: i64 = nbk_be64(m, 16) 97 if diroff > n { return 0 } 98 var c: i64 = K_MAGIC_5381 99 var i: i64 = 32 100 while i < diroff { c = ((c<<5)+c) + (m[i] as i64); i=i+1 } 101 if c != cid { return 0 } 102 var p: i64 = diroff 103 var e: i64 = 0 104 while e < count { 105 if p + 2 > n { return 0 } 106 let nl: i64 = nbk_be16(m, p) 107 p = p + 2 + nl 108 if p + 16 > n { return 0 } 109 let doff: i64 = nbk_be32(m, p) 110 let dlen: i64 = nbk_be32(m, p+4) 111 let h: i64 = nbk_be64(m, p+8) 112 p = p + 16 113 if doff + dlen > n { return 0 } 114 if nbk_djb2((m as i64 + doff) as *u8, dlen) != h { return 0 } 115 e = e + 1 116 } 117 return 1 118} 119 120// extract the entry named `name` from a loaded .nbk into out (cap). returns entry length, or -1 if absent. 121func nbk_get(m: *u8, n: i64, name: *u8, out: *u8, cap: i64) -> i64 { 122 if n < 32 { return 0-1 } 123 let count: i64 = nbk_be32(m, 8) 124 let diroff: i64 = nbk_be32(m, 12) 125 let want: i64 = nbk_slen(name) 126 var p: i64 = diroff 127 var e: i64 = 0 128 while e < count { 129 if p + 2 > n { return 0-1 } 130 let nl: i64 = nbk_be16(m, p) 131 let np: i64 = p + 2 132 let doff: i64 = nbk_be32(m, p+2+nl) 133 let dlen: i64 = nbk_be32(m, p+2+nl+4) 134 var mt: i64 = 0 135 if nl == want { 136 mt = 1 137 var k: i64 = 0 138 while k < nl { if m[np+k] != name[k] { mt=0; k=nl } else { k=k+1 } } 139 } 140 if mt == 1 { 141 var w: i64 = 0 142 while w < dlen { if w < cap { out[w] = m[doff+w] } w = w + 1 } 143 return dlen 144 } 145 p = p + 2 + nl + 16 146 e = e + 1 147 } 148 return 0-1 149}