code wiki / _hdl_build / nx_evattest_cli.nx

nx_evattest_cli.nx source

↩ module page · 140 lines · 5836 B

1// nx_evattest_cli.nx -- the OPERATOR's tool for the human leg of the evidence law. 2// 3// The evidence law requires a human attestation before any domain can read PROVEN, and nx_evattest verifies 4// that attestation cryptographically. This is the other half: how a human actually mints one. 5// 6// ★THIS TOOL EXISTS SO THE OPERATOR CAN SIGN. It is deliberately NOT wired into any automated path, any 7// beat, or any agent workflow. An agent running `sign` against a human-role key would be certifying its own 8// work -- the precise thing require_human forbids -- and the verifier's role check is what makes that 9// forgery detectable rather than merely discouraged. Keep the human key somewhere the automation does not 10// operate, and never register a key the automation holds as role=human. 11// 12// VERBS 13// keygen <keyfile> -- 32 CSPRNG bytes -> keyfile (0600); prints ONLY the public key 14// pub <keyfile> -- print the public key hex for the registry 15// sign <keyfile> <class> <verdict> <scope> <signer> 16// -- print a complete signed attestation row on stdout 17// 18// The signed region is the CLAIM PREFIX (up to " pub="), so class/verdict/scope/signer/epoch are all 19// immutable under the signature. Redirect the row into knowledge/status/evclass_<domain>.conf. 20// license_tier: ORIGINAL expect_exit: 2 21import "nx_syscalls.nx" 22import "nx_evattest.nx" 23const K_MAGIC_8192: i64 = 8192 24 25func w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 26func hexw(src: *u8, n: i64) -> i64 { 27 let hexd: *u8 = "0123456789abcdef" 28 let o: *u8 = sys_mmap(n*2 + 8) 29 var i: i64 = 0 30 while i < n { 31 let b: i64 = src[i] as i64 32 o[i*2] = hexd[(b >> 4) & 15] 33 o[i*2+1] = hexd[b & 15] 34 i = i + 1 35 } 36 sys_write(1, o, n*2) 37 return 0 38} 39func catz(dst: *u8, off: i64, s: *u8) -> i64 { 40 var o: i64 = off 41 var i: i64 = 0 42 while s[i] != (0 as u8) { dst[o] = s[i]; o = o + 1; i = i + 1 } 43 return o 44} 45func catn(dst: *u8, off: i64, v: i64) -> i64 { 46 let t: *u8 = sys_mmap(28) 47 var m: i64 = v 48 var k: i64 = 0 49 if m == 0 { t[0] = 48 as u8; k = 1 } 50 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 51 var o: i64 = off 52 var z: i64 = k - 1 53 while z >= 0 { dst[o] = t[z]; o = o + 1; z = z - 1 } 54 return o 55} 56func readkey(path: *u8, out: *u8) -> i64 { 57 let fd: i64 = sys_openat_rd(path) 58 if fd < 0 { return 0 } 59 let n: i64 = sys_read(fd, out, 32) 60 sys_close(fd) 61 if n != 32 { return 0 } 62 return 1 63} 64func streq(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 } 65 66func main(argc: i64, argv: *i64) -> i64 { 67 if argc < 3 { 68 w("usage:\n nx_evattest_cli keygen <keyfile>\n nx_evattest_cli pub <keyfile>\n nx_evattest_cli sign <keyfile> <class> <verdict> <scope> <signer>\n" as *u8) 69 w("\nclass = human|llm|mech verdict = pass|fail\n" as *u8) 70 w("The human key belongs with the OPERATOR, not in any automated path.\n" as *u8) 71 sys_exit(2); return 2 72 } 73 let verb: *u8 = argv[1] as *u8 74 let kf: *u8 = argv[2] as *u8 75 let priv: *u8 = sys_mmap(32) 76 let pub: *u8 = sys_mmap(32) 77 78 if streq(verb, "keygen" as *u8) == 1 { 79 // Refuse to clobber an existing key: silently rotating a signing key invalidates every attestation 80 // it ever made, and doing that by accident is unrecoverable. 81 let ex: i64 = sys_openat_rd(kf) 82 if ex >= 0 { sys_close(ex); w("REFUSED: keyfile already exists -- refusing to overwrite a signing key\n" as *u8); sys_exit(4); return 4 } 83 let rfd: i64 = sys_openat_rd("/dev/urandom\x00" as *u8) 84 if rfd < 0 { w("cannot open /dev/urandom\n" as *u8); sys_exit(3); return 3 } 85 let got: i64 = sys_read(rfd, priv, 32) 86 sys_close(rfd) 87 if got != 32 { w("short read from /dev/urandom\n" as *u8); sys_exit(3); return 3 } 88 let fd: i64 = sys_openat_wr(kf, 0x180) // 0600 -- owner only 89 if fd < 0 { w("cannot write keyfile\n" as *u8); sys_exit(3); return 3 } 90 sys_write(fd, priv, 32) 91 sys_close(fd) 92 ed25519_pub_from_priv(priv, pub) 93 w("KEYGEN OK (private key written 0600; it is NEVER printed)\nregistry line -> role=human pub=" as *u8) 94 hexw(pub, 32) 95 w(" name=<your-name>\n" as *u8) 96 sys_exit(0); return 0 97 } 98 99 if readkey(kf, priv) == 0 { w("cannot read a 32-byte keyfile\n" as *u8); sys_exit(3); return 3 } 100 ed25519_pub_from_priv(priv, pub) 101 102 if streq(verb, "pub" as *u8) == 1 { 103 hexw(pub, 32) 104 w("\n" as *u8) 105 sys_exit(0); return 0 106 } 107 108 if streq(verb, "sign" as *u8) == 1 { 109 if argc < 7 { w("sign needs: <keyfile> <class> <verdict> <scope> <signer>\n" as *u8); sys_exit(2); return 2 } 110 let cls: *u8 = argv[3] as *u8 111 let vrd: *u8 = argv[4] as *u8 112 let scope: *u8 = argv[5] as *u8 113 let signer: *u8 = argv[6] as *u8 114 let row: *u8 = sys_mmap(K_MAGIC_8192) 115 var r: i64 = 0 116 r = catz(row, r, "class=" as *u8) 117 r = catz(row, r, cls) 118 r = catz(row, r, " verdict=" as *u8) 119 r = catz(row, r, vrd) 120 r = catz(row, r, " scope=" as *u8) 121 r = catz(row, r, scope) 122 r = catz(row, r, " signer=" as *u8) 123 r = catz(row, r, signer) 124 r = catz(row, r, " epoch=" as *u8) 125 r = catn(row, r, sys_now_realtime_sec()) 126 let sig: *u8 = sys_mmap(64) 127 ed25519_sign_full(priv, row, r, sig) 128 sys_write(1, row, r) 129 w(" pub=" as *u8) 130 hexw(pub, 32) 131 w(" sig=" as *u8) 132 hexw(sig, 64) 133 w("\n" as *u8) 134 sys_exit(0); return 0 135 } 136 137 w("unknown verb\n" as *u8) 138 sys_exit(2) 139 return 2 140}