code wiki / _hdl_build / nx_pub_reader_receipt.nx
nx_pub_reader_receipt.nx source
↩ module page · 105 lines · 6997 B
1// nx_pub_reader_receipt.nx -- get a SIGNED, VERIFIABLE DEPLOYMENT RECEIPT from the Nishi Publisher for the
2// reader/shelf artifacts (operator 2026-06-21: "pass to the nishi publisher and get a receipt it deployed").
3// USES the publisher's existing S-class receipt system (nx_pub_receipt: Ed25519-signed, non-repudiable, DSN
4// status, return-and-report) -- does NOT rebuild it. For each artifact the publisher already promoted to the
5// reader liveroot, this: (1) re-hashes the LIVE bytes (sha256), (2) cross-checks that sha against the publisher's
6// verify-then-promote LEDGER record, (3) rcpt_emit's a SIGNED "PUBLISHED" receipt keyed by content-sha+dest,
7// (4) rcpt_query's it back (the return loop), (5) rcpt_verify_line checks the Ed25519 signature (non-repudiation).
8// Durable signed receipts -> knowledge/publish/reader-receipts.tsv. expect_exit: 0 license_tier: ORIGINAL
9// LEAN imports (operator: "keep going" -- the 926KB organ hit an nx_cc big-organ compile-fail; this needs only
10// sha256 + a ledger read, NOT the whole publisher pipeline, so drop nx_publisher = much smaller asm, compiles):
11import "nx_sha256.nx" // sha256_digest
12import "nx_pub_receipt.nx" // rcpt_emit / rcpt_query / rcpt_verify_line / rcpt_is_published / rc_hexenc / RC_*
13import "nx_ed25519_signature.nx" // ed25519_pub_from_priv
14import "nx_syscalls.nx"
15
16func r_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
17func r_n(v: i64) -> i64 { var m: i64=v; if m<0{r_w("-" as *u8);m=0-m} let t:*u8=sys_mmap(24); var k:i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i:i64=0; let o:*u8=sys_mmap(24); while i<k{o[i]=t[k-1-i];i=i+1} sys_write(1,o,k); return 0 }
18func r_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
19func r_hexeq(a: *u8, b: *u8) -> i64 { var i: i64=0; while 1==1 { if a[i]!=b[i] {return 0} if a[i]==(0 as u8) {return 1} i=i+1 } return 1 }
20
21// sha256 of the file at path -> 64 lowercase hex into outhex; 1 if read+hashed, 0 if missing. (replaces pub_sha_file)
22func sha_hex(path: *u8, outhex: *u8) -> i64 {
23 let lp: *i64 = sys_mmap(8) as *i64; lp[0]=0
24 let data: *u8 = sys_read_file(path, lp)
25 if (data as i64) == 0 { outhex[0]=0 as u8; return 0 }
26 let dig: *u8 = sys_mmap(40)
27 sha256_digest(data, lp[0], dig)
28 rc_hexenc(dig, 32, outhex)
29 return 1
30}
31// latest ledger sha for dest (TSV: field0=sha, field1=dest) -> outsha; 1 if found. (replaces pub_audit_query)
32func ledger_sha(ledpath: *u8, dest: *u8, outsha: *u8) -> i64 {
33 let lp: *i64 = sys_mmap(8) as *i64; lp[0]=0
34 let buf: *u8 = sys_read_file(ledpath, lp)
35 outsha[0]=0 as u8
36 if (buf as i64)==0 { return 0 }
37 let n: i64 = lp[0]
38 let dl: i64 = r_slen(dest)
39 var found: i64 = 0
40 var i: i64 = 0
41 while i < n {
42 var le: i64 = i; while le < n { if buf[le]==(10 as u8) { break } le=le+1 }
43 var t0: i64 = i; while t0 < le { if buf[t0]==(9 as u8) { break } t0=t0+1 }
44 var t1: i64 = t0+1; while t1 < le { if buf[t1]==(9 as u8) { break } t1=t1+1 }
45 if (t1 - (t0+1)) == dl {
46 var k: i64=0; var m: i64=1
47 while k < dl { if buf[t0+1+k] != dest[k] { m=0; k=dl } else { k=k+1 } }
48 if m == 1 { var o: i64=0; var pp: i64=i; while pp < t0 { outsha[o]=buf[pp]; o=o+1; pp=pp+1 } outsha[o]=0 as u8; found=1 }
49 }
50 i = le+1
51 }
52 return found
53}
54
55// emit + return-and-report a signed PUBLISHED receipt for one already-deployed artifact. returns 1 iff the live
56// bytes match the ledger (verified deploy) AND the receipt reads back PUBLISHED AND its signature verifies.
57func receipt_for(rcptfile: *u8, priv: *u8, pub: *u8, ledger: *u8, dest: *u8, livepath: *u8, now: i64) -> i64 {
58 let sha: *u8 = sys_mmap(72)
59 if sha_hex(livepath, sha) == 0 { r_w(" LIVE-MISSING: " as *u8); r_w(dest); r_w("\n" as *u8); return 0 }
60 let lsha: *u8 = sys_mmap(72); lsha[0]=0 as u8
61 let q: i64 = ledger_sha(ledger, dest, lsha) // the publisher's verify-then-promote record (lean read)
62 var verify: *u8 = "MISMATCH" as *u8
63 if q == 1 { if r_hexeq(sha, lsha) == 1 { verify = "MATCH" as *u8 } }
64 rcpt_emit(rcptfile, priv, "PUBLISHED" as *u8, "nishi-reader" as *u8, sha, dest, "nishifamily/reader-live" as *u8, verify, now)
65 let rl: *u8 = sys_mmap(2048); rcpt_query(rcptfile, sha, dest, rl, 2048); let rll: i64 = r_slen(rl)
66 let sigok: i64 = rcpt_verify_line(pub, rl, rll)
67 let isp: i64 = rcpt_is_published(rcptfile, sha, dest)
68 r_w(" >>> RECEIPT " as *u8); r_w(dest); r_w("\n" as *u8)
69 r_w(" " as *u8); r_w(rl); r_w("\n" as *u8)
70 r_w(" live-bytes-vs-ledger=" as *u8); r_w(verify); r_w(" published=" as *u8); r_n(isp); r_w(" signature-verified=" as *u8); r_n(sigok); r_w("\n" as *u8)
71 if isp == 1 { if sigok == 1 { if r_hexeq(verify, "MATCH" as *u8) == 1 { return 1 } } }
72 return 0
73}
74
75func main() -> i64 {
76 r_w("=== NISHI PUBLISHER -- SIGNED DEPLOYMENT RECEIPT (reader/shelf return-and-report) ===\n" as *u8)
77 let rcptfile: *u8 = "knowledge/publish/reader-receipts.tsv" as *u8
78 let ledger: *u8 = "knowledge/publish/reader-ledger.tsv\x00" as *u8
79 // publisher signing key (deterministic local-liveroot key, as in nx_pub_receipt_loop); pub derived for verify.
80 let priv: *u8 = sys_mmap(32); var i: i64=0; while i<32 { priv[i]=(i+7) as u8; i=i+1 }
81 let pub: *u8 = sys_mmap(32); ed25519_pub_from_priv(priv, pub)
82 let now: i64 = sys_now_realtime_sec()
83
84 // arrays + a single call site = lower register pressure (works around the nx_cc regalloc "empty .s" on this organ)
85 let dests: *i64 = sys_mmap(64) as *i64
86 let lives: *i64 = sys_mmap(64) as *i64
87 dests[0] = "library_shelf.html\x00" as *u8 as i64; lives[0] = "knowledge/publish/reader-live/library_shelf.html\x00" as *u8 as i64
88 dests[1] = "reader_static_nishi_fixture.html\x00" as *u8 as i64; lives[1] = "knowledge/publish/reader-live/reader_static_nishi_fixture.html\x00" as *u8 as i64
89 dests[2] = "reader/nishi_fixture/cover.png\x00" as *u8 as i64; lives[2] = "knowledge/publish/reader-live/reader/nishi_fixture/cover.png\x00" as *u8 as i64
90 dests[3] = "reader/nishi_fixture/fig1.png\x00" as *u8 as i64; lives[3] = "knowledge/publish/reader-live/reader/nishi_fixture/fig1.png\x00" as *u8 as i64
91 var ok: i64 = 0
92 var ai: i64 = 0
93 while ai < 4 {
94 ok = ok + receipt_for(rcptfile, priv, pub, ledger, dests[ai] as *u8, lives[ai] as *u8, now)
95 ai = ai + 1
96 }
97
98 r_w("----\n" as *u8)
99 r_w("verdict: " as *u8)
100 if ok == 4 { r_w("DEPLOYED 4/4 -- each receipt PUBLISHED, live-bytes==ledger-sha, Ed25519 signature verified\n" as *u8) }
101 else { r_w("INCOMPLETE " as *u8); r_n(ok); r_w("/4\n" as *u8) }
102 r_w("durable signed receipts -> knowledge/publish/reader-receipts.tsv (query any back with rcpt_query; verify with the publisher pubkey)\n" as *u8)
103 if ok == 4 { sys_exit(0); return 0 }
104 sys_exit(1); return 1
105}