code wiki / _hdl_build / nx_canon_bin_gate.nx
nx_canon_bin_gate.nx source
↩ module page · 85 lines · 5818 B
1// nx_canon_bin_gate.nx -- prove the binary-safe canonical primitive (the gap in the substrate). Asserts:
2// BINARY-SAFE : a value containing 0x00 bytes round-trips at FULL length (string-only canon_encode truncates it).
3// CANONICAL : the same fields in DIFFERENT insertion order encode to BYTE-IDENTICAL output (=> identical CID).
4// CID : cid_of (the REUSED substrate sha256 CID) is well-formed + deterministic.
5// DECODE : canon_decode_bin recovers every field; the binary value (via offset+len, IN-buffer) matches.
6// GREEN = the substrate now has a binary-safe canonical record (additive sibling; media can be a first-class value).
7// expect_exit: 0 license_tier: ORIGINAL
8import "nx_syscalls.nx"
9import "nx_canon_bin.nx"
10import "nx_canon_cid.nx"
11import "nx_gate_verdict.nx"
12
13func gp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
14func gnum(v0: i64) -> i64 { var v: i64=v0; if v<0 { sys_write(1,"-" as *u8,1); v=0-v } let b: *u8=sys_mmap(24); var k: i64=0; if v==0 {b[0]=48 as u8;k=1} while v>0 {b[k]=(48+(v%10)) as u8; v=v/10; k=k+1} let o: *u8=sys_mmap(24); var j: i64=0; while j<k {o[j]=b[k-1-j];j=j+1} sys_write(1,o,k); return 0 }
15func gstreq(a: *u8, b: *u8) -> i64 { var i: i64=0; while a[i]!=(0 as u8){ if a[i]!=b[i]{return 0} i=i+1 } if b[i]!=(0 as u8){return 0} return 1 }
16
17func main() -> i64 {
18 gp("=== nx_canon_bin_gate: binary-safe canonical records (substrate sibling) ===\n" as *u8)
19
20 // a binary value with EMBEDDED NUL bytes (the thing string-only canon_encode cannot carry)
21 let blob: *u8 = sys_mmap(16)
22 blob[0]=1 as u8; blob[1]=0 as u8; blob[2]=255 as u8; blob[3]=0 as u8; blob[4]=66 as u8 // 01 00 FF 00 42, len 5
23
24 // order A: zzz, @kind, blob, name
25 let kA: *i64 = sys_mmap(64) as *i64; let vA: *i64 = sys_mmap(64) as *i64; let lA: *i64 = sys_mmap(64) as *i64
26 kA[0]="zzz\x00" as *u8 as i64; vA[0]="last\x00" as *u8 as i64; lA[0]=4
27 kA[1]="@kind\x00" as *u8 as i64; vA[1]="media\x00" as *u8 as i64; lA[1]=5
28 kA[2]="blob\x00" as *u8 as i64; vA[2]=blob as i64; lA[2]=5
29 kA[3]="name\x00" as *u8 as i64; vA[3]="Alice\x00" as *u8 as i64; lA[3]=5
30 // order B: reversed
31 let kB: *i64 = sys_mmap(64) as *i64; let vB: *i64 = sys_mmap(64) as *i64; let lB: *i64 = sys_mmap(64) as *i64
32 kB[0]="name\x00" as *u8 as i64; vB[0]="Alice\x00" as *u8 as i64; lB[0]=5
33 kB[1]="blob\x00" as *u8 as i64; vB[1]=blob as i64; lB[1]=5
34 kB[2]="@kind\x00" as *u8 as i64; vB[2]="media\x00" as *u8 as i64; lB[2]=5
35 kB[3]="zzz\x00" as *u8 as i64; vB[3]="last\x00" as *u8 as i64; lB[3]=4
36
37 let eA: *u8 = sys_mmap(4096); let nA: i64 = canon_encode_bin(kA, vA, lA, 4, eA)
38 let eB: *u8 = sys_mmap(4096); let nB: i64 = canon_encode_bin(kB, vB, lB, 4, eB)
39
40 // canonical: same fields, any order -> identical bytes
41 var canon_eq: i64 = 1
42 if nA != nB { canon_eq = 0 } else { var i: i64=0; while i<nA { if eA[i]!=eB[i] { canon_eq=0; i=nA } else { i=i+1 } } }
43
44 // binary-safe: extract the blob, must be FULL length 5 (string-only would stop at the first 0x00 => len 1)
45 let got: *u8 = sys_mmap(64); let gl: i64 = canon_get_bin(eA, nA, "blob\x00" as *u8, got, 64)
46 var blob_ok: i64 = 0
47 if gl == 5 { if got[0]==(1 as u8) { if got[1]==(0 as u8) { if got[2]==(255 as u8) { if got[3]==(0 as u8) { if got[4]==(66 as u8) { blob_ok=1 } } } } } }
48
49 // string field round-trips
50 let nm: *u8 = sys_mmap(64); canon_get_bin(eA, nA, "name\x00" as *u8, nm, 64); nm[5]=0 as u8
51
52 // CID reuse (substrate sha256) + determinism
53 let cid1: *u8 = sys_mmap(80); cid_of(eA, nA, cid1)
54 let cid2: *u8 = sys_mmap(80); cid_of(eB, nB, cid2)
55 var cid_eq: i64 = 0; if gstreq(cid1, cid2) == 1 { cid_eq = 1 }
56
57 // full decode: 4 fields; locate blob by offset+len IN buffer
58 let dk: *i64 = sys_mmap(64) as *i64; let dvo: *i64 = sys_mmap(64) as *i64; let dvl: *i64 = sys_mmap(64) as *i64
59 let nf: i64 = canon_decode_bin(eA, nA, dk, dvo, dvl, 16)
60 var dec_blob_ok: i64 = 0
61 var di: i64 = 0
62 while di < nf { if gstreq((dk[di]) as *u8, "blob\x00" as *u8) == 1 { if dvl[di]==5 { if eA[dvo[di]+2]==(255 as u8) { dec_blob_ok=1 } } di=nf } else { di=di+1 } }
63
64 gp(" bytes=" as *u8); gnum(nA); gp(" blob_len=" as *u8); gnum(gl); gp(" canonical_eq=" as *u8); gnum(canon_eq)
65 gp(" cid=" as *u8); gp(cid1); gp(" cid_eq=" as *u8); gnum(cid_eq); gp(" nfields=" as *u8); gnum(nf); gp("\n" as *u8)
66
67 var pass: i64 = 0; var fail: i64 = 0
68 if blob_ok == 1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL binary-value-not-preserved (NUL truncation)\n" as *u8) }
69 if gstreq(nm, "Alice" as *u8) == 1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL string-field-roundtrip\n" as *u8) }
70 if canon_eq == 1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL not-canonical (insertion order leaked)\n" as *u8) }
71 if cid_eq == 1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL cid-order-dependent\n" as *u8) }
72 if nf == 4 { pass=pass+1 } else { fail=fail+1; gp(" FAIL decode-nfields!=4\n" as *u8) }
73 if dec_blob_ok == 1 { pass=pass+1 } else { fail=fail+1; gp(" FAIL decode-blob-mismatch\n" as *u8) }
74
75 gp("CANON-BIN-GATE pass=" as *u8); gnum(pass); gp(" fail=" as *u8); gnum(fail)
76 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
77 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
78 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
79 let ctr__dry: *i64 = gv_ctr()
80 ctr__dry[0] = pass
81 ctr__dry[1] = pass + fail
82 let rc__dry: i64 = gv_verdict("CANON-BIN-GATE" as *u8, ctr__dry, "binary-safe canonical record; same CID as the substrate; order-independent)" as *u8)
83 sys_exit(rc__dry)
84 return rc__dry
85}