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}