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}