code wiki / (root) / nx_spore_sign_gate.nx

nx_spore_sign_gate.nx source

↩ module page · 122 lines · 6283 B

1// nx_spore_sign_gate.nx -- spore-cas-signed: Ed25519 PROVENANCE over the germination seed. 2// Per-piece FNV hashes (the manifest) prove each piece's integrity; THIS proves the WHOLE 3// seed's PROVENANCE: the manifest is Ed25519-SIGNED, and a forged/altered seed -- or a 4// signature from the wrong key -- is REJECTED before germination (charter: Ed25519-signed 5// manifest gated by operator_root_pk). 6// 7// SIGN -- ed25519_sign_full(priv, manifest_bytes) -> 64B sig; emit .sig sidecar. 8// VERIFY -- ed25519_verify_full(pub, manifest_bytes, sig) == OK (1). 9// NEG-1 -- tamper one manifest byte -> verify == BAD (0) [forged seed rejected]. 10// NEG-2 -- verify with a DIFFERENT pubkey -> BAD (0) [only the real key validates]. 11// verdict GREEN iff OK + both NEG rejected. 12// 13// Composes the KAT-verified Ed25519 (nx_ed25519_signature, RFC 8032) over the real seed 14// artifact knowledge/registry/germination_manifest.tsv (from nx_spore_manifest_gate). 15// Build/run (nxc2 cwd): _offc/nx_sov_build_run.elf nx_spore_sign_gate 16// genealogy_id: nishi_spore_seed_portability_charter (spore-cas-signed) 17 18import "nx_syscalls.nx" 19import "nx_ed25519_signature.nx" 20import "nx_gate_verdict.nx" 21 22const SIG_PATH: *u8 = "knowledge/registry/germination_manifest.sig" 23const MAN_PATH: *u8 = "knowledge/registry/germination_manifest.tsv" 24 25func g_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 26func g_puts(s: *u8) -> i64 { sys_write(1, s, g_slen(s)); return 0 } 27func g_puts_fd(fd: i64, s: *u8) -> i64 { sys_write(fd, s, g_slen(s)); return 0 } 28func g_putn(fd: i64, v: i64) -> i64 { 29 let bb: *u8 = sys_mmap(28) 30 var m: i64 = v 31 if m < 0 { m = 0 - m; sys_write(fd, "-" as *u8, 1) } 32 let t: *u8 = sys_mmap(28) 33 var k: i64 = 0 34 if m == 0 { t[0] = 48; k = 1 } 35 while m > 0 { t[k] = 48 + (m % 10); m = m / 10; k = k + 1 } 36 var i: i64 = 0 37 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 38 sys_write(fd, bb, k) 39 return 0 40} 41 42func main() -> i64 { 43 g_puts("================================================================\n" as *u8) 44 g_puts(" SEED SIGNING -- Ed25519 provenance over germination_manifest.tsv;\n" as *u8) 45 g_puts(" forged seed or wrong-key signature is rejected before germination.\n" as *u8) 46 g_puts("================================================================\n" as *u8) 47 48 // ---- deterministic test keypair (32-byte seed) ---- 49 let priv: *u8 = sys_mmap(32) 50 var i: i64 = 0 51 while i < 32 { priv[i] = (i + 1) & 0xff; i = i + 1 } 52 let pub: *u8 = sys_mmap(32) 53 if ed25519_pub_from_priv(priv, pub) != 0 { g_puts(" FAIL: pub_from_priv\n" as *u8); sys_exit(10); return 10 } 54 55 // ---- read the seed manifest (the message to sign) ---- 56 let lenp: *i64 = sys_mmap(8) as *i64 57 let msg: *u8 = sys_read_file(MAN_PATH, lenp) 58 let mlen: i64 = *lenp 59 if (msg as i64) == 0 { g_puts(" FAIL: manifest unreadable (run nx_spore_manifest_gate first)\n" as *u8); sys_exit(11); return 11 } 60 if mlen <= 0 { g_puts(" FAIL: empty manifest\n" as *u8); sys_exit(11); return 11 } 61 g_puts(" manifest bytes=" as *u8); g_putn(1, mlen); g_puts("\n" as *u8) 62 63 // ---- SIGN + emit the .sig sidecar (the signed-seed artifact) ---- 64 let sig: *u8 = sys_mmap(64) 65 if ed25519_sign_full(priv, msg, mlen, sig) != 0 { g_puts(" FAIL: sign\n" as *u8); sys_exit(12); return 12 } 66 let sfd: i64 = sys_openat_wr(SIG_PATH, 0x1a4) 67 if sfd >= 0 { sys_write(sfd, sig, 64); sys_close(sfd); g_puts(" signed -> " as *u8); g_puts(SIG_PATH); g_puts(" (64B)\n" as *u8) } 68 69 // ---- POSITIVE verify ---- 70 let v_ok: i64 = ed25519_verify_full(pub, msg, mlen, sig) 71 g_puts("\n [+] verify valid-sig: " as *u8); g_putn(1, v_ok) 72 if v_ok == NX_ED25519_SIG_OK { g_puts(" OK\n" as *u8) } else { g_puts(" UNEXPECTED-BAD\n" as *u8) } 73 74 // ---- NEG-1: tamper one manifest byte -> verify must FAIL ---- 75 let tam: *u8 = sys_mmap(mlen + 16) 76 var c: i64 = 0 77 while c < mlen { tam[c] = msg[c]; c = c + 1 } 78 tam[0] = (tam[0] ^ 1) as u8 79 let v_tam: i64 = ed25519_verify_full(pub, tam, mlen, sig) 80 var tam_rej: i64 = 0 81 g_puts(" [-] verify tampered-seed: " as *u8); g_putn(1, v_tam) 82 if v_tam != NX_ED25519_SIG_OK { tam_rej = 1; g_puts(" REJECTED (forged seed caught)\n" as *u8) } else { g_puts(" ACCEPTED?! broken\n" as *u8) } 83 84 // ---- NEG-2: wrong key -> verify must FAIL ---- 85 let priv2: *u8 = sys_mmap(32) 86 i = 0 87 while i < 32 { priv2[i] = (i + 7) & 0xff; i = i + 1 } 88 let pub2: *u8 = sys_mmap(32) 89 ed25519_pub_from_priv(priv2, pub2) 90 let v_wk: i64 = ed25519_verify_full(pub2, msg, mlen, sig) 91 var wk_rej: i64 = 0 92 g_puts(" [-] verify wrong-key: " as *u8); g_putn(1, v_wk) 93 if v_wk != NX_ED25519_SIG_OK { wk_rej = 1; g_puts(" REJECTED (only the real key validates)\n" as *u8) } else { g_puts(" ACCEPTED?! broken\n" as *u8) } 94 95 // ---- verdict (sealed) ---- 96 var green: i64 = 1 97 if v_ok != NX_ED25519_SIG_OK { green = 0 } 98 if tam_rej != 1 { green = 0 } 99 if wk_rej != 1 { green = 0 } 100 101 let lfd: i64 = sys_openat_append("knowledge/status/spore_germ.log" as *u8, 0x1a4) 102 if lfd >= 0 { 103 g_puts_fd(lfd, "SPORESIGN-GATE epoch=" as *u8); g_putn(lfd, sys_now_realtime_sec()) 104 g_puts_fd(lfd, " manifest_bytes=" as *u8); g_putn(lfd, mlen) 105 g_puts_fd(lfd, " verify_ok=" as *u8); g_putn(lfd, v_ok) 106 g_puts_fd(lfd, " tamper_rejected=" as *u8); g_putn(lfd, tam_rej) 107 g_puts_fd(lfd, " wrongkey_rejected=" as *u8); g_putn(lfd, wk_rej) 108 if green == 1 { g_puts_fd(lfd, " verdict=GREEN\n" as *u8) } else { g_puts_fd(lfd, " verdict=RED\n" as *u8) } 109 sys_close(lfd) 110 } 111 112 g_puts("----------------------------------------------------------------\n" as *u8) 113 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 114 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 115 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 116 let ctr__dry: *i64 = gv_ctr() 117 ctr__dry[0] = green 118 ctr__dry[1] = 1 119 let rc__dry: i64 = gv_verdict("SPORE-SIGN-GATE" as *u8, ctr__dry, "the seed is Ed25519-signed; a forged seed and a" as *u8) 120 sys_exit(rc__dry) 121 return rc__dry 122}