code wiki / (root) / nx_evoracle_emit.nx

nx_evoracle_emit.nx source

↩ module page · 168 lines · 7589 B

1// nx_evoracle_emit.nx -- THE MISSING PRODUCER for EV_CLASS_ORACLE (closes M3). 2// 3// EV_CLASS_ORACLE had exactly ONE consumer (nx_sota_status.nx:220) and NO producer, so an oracle 4// row was hand-typed prose: an agent could write `class=oracle ref=RFC7748` having compared 5// nothing. Without a second class no mechanical domain can reach min_classes=2, which is why the 6// board reads PROVEN 0/41 -- pinned by an EMPTY TABLE, not by any failed measurement. 7// 8// ★★★★★THE LAW THIS ENFORCES (nx_evoracle.nx): 9// AN ORACLE ATTESTATION MUST BE DERIVED FROM AN EXECUTION, NEVER DECLARED IN PROSE. 10// A signature buys attribution and tamper-evidence; it does NOT buy truth, because whoever holds 11// the key can sign a false claim. What buys truth is RE-DERIVABILITY. So this organ REFUSES to 12// accept a verdict as an argument -- it RUNS the named gate and reads the verdict off the actual 13// exit code, and it pins WHICH external vector block was compared by digesting that file. 14// 15// Anti-gaming properties, by construction rather than by promise: 16// - verdict is DERIVED (exit code), never passed in. There is no argument that can assert "pass". 17// - a missing or unreadable vector file REFUSES (exit 3). "It matched" is not evidence unless it 18// says what it matched. 19// - a gate that cannot be executed REFUSES (exit 4). A row is never written for a run that did 20// not happen -- the failure mode the whole evidence lane exists to kill. 21// - ref= carries authority + digest, so a later reader re-runs the comparison and gets the same 22// answer. The digest is FNV-1a 64: it pins WHICH block was used and detects drift. It is NOT 23// cryptographic and is not claimed to be -- tamper-resistance here comes from re-derivability, 24// not from the hash. 25// 26// nx_evoracle_emit <domain> <gate_elf> <vector_file> <authority> <scope> 27// license_tier: ORIGINAL layer: evidence module: nishi-core.evidence.evoracle_emit 28import "nx_syscalls.nx" 29 30const EO_MAXV: i64 = 4194304 31 32static EO_T: i64 33static EO_O: i64 34static EO_LINE: i64 35 36func eo_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 37func eo_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 38func eo_n(v: i64) -> i64 { 39 if EO_T == 0 { EO_T = sys_mmap(64) as i64; EO_O = sys_mmap(64) as i64 } 40 let t: *u8 = EO_T as *u8 41 let o: *u8 = EO_O as *u8 42 var m: i64=v; var k: i64=0 43 if m==0 { t[0]=48 as u8; k=1 } 44 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 45 var i: i64=0; while i<k { o[i]=t[k-1-i]; i=i+1 } 46 sys_write(1,o,k); return 0 47} 48 49func eo_cat(dst: *u8, off: i64, s: *u8) -> i64 { var o: i64=off; var i: i64=0; while s[i]!=(0 as u8){ dst[o]=s[i]; o=o+1; i=i+1 } return o } 50func eo_catn(dst: *u8, off: i64, v: i64) -> i64 { 51 if v == 0 { dst[off]=48 as u8; return off+1 } 52 if EO_T == 0 { EO_T = sys_mmap(64) as i64; EO_O = sys_mmap(64) as i64 } 53 let t: *u8 = EO_T as *u8 54 var m: i64=v; var k: i64=0 55 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 56 var o: i64=off; var i: i64=k-1; while i>=0 { dst[o]=t[i]; o=o+1; i=i-1 } 57 return o 58} 59// FNV-1a 64. Pins WHICH vector block was compared and detects drift. Not cryptographic; see header. 60func eo_catx(dst: *u8, off: i64, v: i64) -> i64 { 61 var o: i64 = off 62 var i: i64 = 60 63 while i >= 0 { 64 let nib: i64 = (v >> i) & 15 65 if nib < 10 { dst[o] = (48+nib) as u8 } else { dst[o] = (87+nib) as u8 } 66 o = o + 1 67 i = i - 4 68 } 69 return o 70} 71func eo_fnv(b: *u8, n: i64) -> i64 { 72 var h: i64 = 0x0CBF29CE484222325 73 var i: i64 = 0 74 while i < n { h = h ^ (b[i] as i64); h = h * 0x100000001B3; i = i + 1 } 75 return h 76} 77 78func main(argc: i64, argv: *i64) -> i64 { 79 if argc < 6 { 80 eo_p("usage: nx_evoracle_emit <domain> <gate_elf> <vector_file> <authority> <scope>\n" as *u8) 81 eo_p(" verdict is DERIVED from the gate's exit code and cannot be supplied as an argument.\n" as *u8) 82 sys_exit(2); return 2 83 } 84 let domain: *u8 = argv[1] as *u8 85 let gate: *u8 = argv[2] as *u8 86 let vecp: *u8 = argv[3] as *u8 87 let auth: *u8 = argv[4] as *u8 88 let scope: *u8 = argv[5] as *u8 89 90 // ---- 1. the external vector block must exist and be readable, or REFUSE ---- 91 let vfd: i64 = sys_openat_rd(vecp) 92 if vfd < 0 { 93 eo_p("REFUSED(3): vector file unreadable: " as *u8); eo_p(vecp) 94 eo_p("\n an oracle row must name WHAT it compared against; a missing block is not evidence.\n" as *u8) 95 sys_exit(3); return 3 96 } 97 let vbuf: *u8 = sys_mmap(EO_MAXV) 98 let vn: i64 = sys_read(vfd, vbuf, EO_MAXV) 99 sys_close(vfd) 100 if vn < 1 { 101 eo_p("REFUSED(3): vector file empty: " as *u8); eo_p(vecp); eo_p("\n" as *u8) 102 sys_exit(3); return 3 103 } 104 let dig: i64 = eo_fnv(vbuf, vn) 105 106 // ---- 2. RUN the gate. The verdict comes from here and nowhere else. ---- 107 eo_p("running gate: " as *u8); eo_p(gate); eo_p("\n" as *u8) 108 let pid: i64 = sys_fork() 109 if pid == 0 { 110 let av: *i64 = sys_mmap(32) as *i64 111 av[0] = gate as i64; av[1] = 0 112 let ev: *i64 = sys_mmap(16) as *i64 113 ev[0] = "PATH=/usr/bin:/bin" as *u8 as i64; ev[1] = 0 114 sys_execve(gate, av, ev) 115 sys_exit(127) 116 } 117 if pid < 0 { 118 eo_p("REFUSED(4): cannot fork to run the gate\n" as *u8); sys_exit(4); return 4 119 } 120 let st: *i64 = sys_mmap(64) as *i64 121 sys_wait4(pid, st, 0) 122 let rc: i64 = wait_exit_code(st[0]) 123 if rc == 127 { 124 eo_p("REFUSED(4): gate could not be executed: " as *u8); eo_p(gate) 125 eo_p("\n a row is NEVER written for a run that did not happen.\n" as *u8) 126 sys_exit(4); return 4 127 } 128 eo_p("gate exit code: " as *u8); eo_n(rc); eo_p("\n" as *u8) 129 130 // ---- 3. build the row. verdict DERIVED from rc. ---- 131 if EO_LINE == 0 { EO_LINE = sys_mmap(4096) as i64 } 132 let ln: *u8 = EO_LINE as *u8 133 var o: i64 = 0 134 o = eo_cat(ln, o, "class=oracle verdict=" as *u8) 135 if rc == 0 { o = eo_cat(ln, o, "pass" as *u8) } else { o = eo_cat(ln, o, "fail" as *u8) } 136 o = eo_cat(ln, o, " scope=" as *u8); o = eo_cat(ln, o, scope) 137 o = eo_cat(ln, o, " signer=" as *u8); o = eo_cat(ln, o, gate) 138 o = eo_cat(ln, o, " ref=" as *u8); o = eo_cat(ln, o, auth) 139 o = eo_cat(ln, o, "#fnv1a64:" as *u8); o = eo_catx(ln, o, dig) 140 o = eo_cat(ln, o, " vector=" as *u8); o = eo_cat(ln, o, vecp) 141 o = eo_cat(ln, o, " vbytes=" as *u8); o = eo_catn(ln, o, vn) 142 o = eo_cat(ln, o, " rc=" as *u8); o = eo_catn(ln, o, rc) 143 o = eo_cat(ln, o, " epoch=" as *u8); o = eo_catn(ln, o, sys_now_realtime_sec()) 144 ln[o] = 10 as u8; o = o + 1 145 146 // ---- 4. append to knowledge/status/evclass_<domain>.conf ---- 147 let path: *u8 = sys_mmap(512) 148 var po: i64 = 0 149 po = eo_cat(path, po, "knowledge/status/evclass_" as *u8) 150 po = eo_cat(path, po, domain) 151 po = eo_cat(path, po, ".conf" as *u8) 152 path[po] = 0 as u8 153 154 let ofd: i64 = sys_openat_append(path, 0x1a4) 155 if ofd < 0 { 156 eo_p("REFUSED(5): cannot open for append: " as *u8); eo_p(path) 157 eo_p("\n (does knowledge/status/ exist in this cwd?)\n" as *u8) 158 sys_exit(5); return 5 159 } 160 sys_write(ofd, ln, o) 161 sys_close(ofd) 162 163 eo_p("WROTE " as *u8); eo_p(path); eo_p("\n " as *u8) 164 sys_write(1, ln, o) 165 if rc == 0 { eo_p("EV-ORACLE-EMIT ok verdict=pass (DERIVED from exit code)\n" as *u8); sys_exit(0); return 0 } 166 eo_p("EV-ORACLE-EMIT ok verdict=fail (DERIVED from exit code -- recorded as DISSENT)\n" as *u8) 167 sys_exit(0); return 0 168}