nx_emitted_substrate_test.nx source
↩ module page · 217 lines · 9026 B
1// nx_emitted_substrate_test.nx -- smoke for Phase 5 substrate
2// emission.
3//
4// Exercises:
5// 1. Allocation + canary + initial state
6// 2. Add 3 expected hashes
7// 3. Duplicate add rejected
8// 4. Sign + verify roundtrip
9// 5. Frozen-after-sign: add_expected refused after signing
10// 6. Tamper detection: mutate target_tier / n_expected / a
11// stored hash field -> verify returns BAD_SIG
12// 7. Wrong pub key -> BAD_SIG
13// 8. populate downstream manifest from emitted record
14// 9. Bad-input gates + canary tamper
15
16import "nx_syscalls.nx"
17import "nx_blob_store.nx"
18import "nx_substrate_manifest.nx"
19import "nx_emitted_substrate.nx"
20
21// RFC 8032 §7.1 Test 1 keypair (same as the Ed25519-sign test).
22func _rfc_priv(buf: *u8) -> i64 {
23 buf[0] = 0x9d as u8; buf[1] = 0x61 as u8
24 buf[2] = 0xb1 as u8; buf[3] = 0x9d as u8
25 buf[4] = 0xef as u8; buf[5] = 0xfd as u8
26 buf[6] = 0x5a as u8; buf[7] = 0x60 as u8
27 buf[8] = 0xba as u8; buf[9] = 0x84 as u8
28 buf[10] = 0x4a as u8; buf[11] = 0xf4 as u8
29 buf[12] = 0x92 as u8; buf[13] = 0xec as u8
30 buf[14] = 0x2c as u8; buf[15] = 0xc4 as u8
31 buf[16] = 0x44 as u8; buf[17] = 0x49 as u8
32 buf[18] = 0xc5 as u8; buf[19] = 0x69 as u8
33 buf[20] = 0x7b as u8; buf[21] = 0x32 as u8
34 buf[22] = 0x69 as u8; buf[23] = 0x19 as u8
35 buf[24] = 0x70 as u8; buf[25] = 0x3b as u8
36 buf[26] = 0xac as u8; buf[27] = 0x03 as u8
37 buf[28] = 0x1c as u8; buf[29] = 0xae as u8
38 buf[30] = 0x7f as u8; buf[31] = 0x60 as u8
39 return 0
40}
41
42func _rfc_pub(buf: *u8) -> i64 {
43 buf[0] = 0xd7 as u8; buf[1] = 0x5a as u8
44 buf[2] = 0x98 as u8; buf[3] = 0x01 as u8
45 buf[4] = 0x82 as u8; buf[5] = 0xb1 as u8
46 buf[6] = 0x0a as u8; buf[7] = 0xb7 as u8
47 buf[8] = 0xd5 as u8; buf[9] = 0x4b as u8
48 buf[10] = 0xfe as u8; buf[11] = 0xd3 as u8
49 buf[12] = 0xc9 as u8; buf[13] = 0x64 as u8
50 buf[14] = 0x07 as u8; buf[15] = 0x3a as u8
51 buf[16] = 0x0e as u8; buf[17] = 0xe1 as u8
52 buf[18] = 0x72 as u8; buf[19] = 0xf3 as u8
53 buf[20] = 0xda as u8; buf[21] = 0xa6 as u8
54 buf[22] = 0x23 as u8; buf[23] = 0x25 as u8
55 buf[24] = 0xaf as u8; buf[25] = 0x02 as u8
56 buf[26] = 0x1a as u8; buf[27] = 0x68 as u8
57 buf[28] = 0xf7 as u8; buf[29] = 0x07 as u8
58 buf[30] = 0x51 as u8; buf[31] = 0x1a as u8
59 return 0
60}
61
62// Construct a synthetic 32-byte "emitter install_hash" — same shape
63// as a real install_hash would be after nx_install_hash_compute.
64func _make_emitter_hash(buf: *u8) -> i64 {
65 var i: i64 = 0
66 while i < 32 {
67 buf[i] = ((i * 11) & 255) as u8
68 i = i + 1
69 }
70 return 0
71}
72
73func _fill(buf: *u8, len: i64, seed: i64) -> i64 {
74 var i: i64 = 0
75 while i < len {
76 buf[i] = (((i * 29) + seed) & 255) as u8
77 i = i + 1
78 }
79 return 0
80}
81
82func _hash_of(bytes: *u8, len: i64) -> *NxBlobHash {
83 let s: *NxBlobStore = nx_blob_store_new()
84 let h: *NxBlobHash = nx_blob_hash_new()
85 nx_blob_store_put(s, bytes, len, h)
86 return h
87}
88
89func main() -> i64 {
90 let priv: *u8 = sys_mmap(64)
91 _rfc_priv(priv)
92 let pub: *u8 = sys_mmap(64)
93 _rfc_pub(pub)
94 let emitter_hash: *u8 = sys_mmap(64)
95 _make_emitter_hash(emitter_hash)
96
97 // ----- 1. Allocation + initial state -----
98 let r: *NxEmittedSubstrate = nx_emitted_substrate_new(
99 emitter_hash, NX_TIER_INF_MOBILE, NX_ISA_RV64)
100 if nx_emitted_substrate_is_valid(r) != 1 { return 1 }
101 if nx_emitted_substrate_n_expected(r) != 0 { return 2 }
102 if nx_emitted_substrate_is_signed(r) != 0 { return 3 }
103 if r.target_tier != NX_TIER_INF_MOBILE { return 4 }
104 if r.target_isa != NX_ISA_RV64 { return 5 }
105
106 // ----- 2. Add 3 expected hashes -----
107 let p1: *u8 = sys_mmap(64)
108 _fill(p1, 32, 1)
109 let h1: *NxBlobHash = _hash_of(p1, 32)
110 let p2: *u8 = sys_mmap(64)
111 _fill(p2, 32, 2)
112 let h2: *NxBlobHash = _hash_of(p2, 32)
113 let p3: *u8 = sys_mmap(64)
114 _fill(p3, 32, 3)
115 let h3: *NxBlobHash = _hash_of(p3, 32)
116
117 if nx_emitted_substrate_add_expected(r, h1) != NX_EMIT_OK { return 6 }
118 if nx_emitted_substrate_add_expected(r, h2) != NX_EMIT_OK { return 7 }
119 if nx_emitted_substrate_add_expected(r, h3) != NX_EMIT_OK { return 8 }
120 if nx_emitted_substrate_n_expected(r) != 3 { return 9 }
121
122 // ----- 3. Duplicate rejected -----
123 if nx_emitted_substrate_add_expected(r, h1) != NX_EMIT_DUPLICATE { return 10 }
124 if nx_emitted_substrate_n_expected(r) != 3 { return 11 } // unchanged
125
126 // ----- 4. Sign + verify -----
127 if nx_emitted_substrate_sign(r, priv) != NX_EMIT_OK { return 12 }
128 if nx_emitted_substrate_is_signed(r) != 1 { return 13 }
129 if nx_emitted_substrate_verify_sig(r, pub) != NX_EMIT_OK { return 14 }
130
131 // ----- 5. Frozen after sign: add_expected refused -----
132 let h_late: *NxBlobHash = nx_blob_hash_new()
133 h_late.w0 = 0xCAFE
134 h_late.w1 = 0xBABE
135 if nx_emitted_substrate_add_expected(r, h_late) != NX_EMIT_TAMPER { return 15 }
136 if nx_emitted_substrate_n_expected(r) != 3 { return 16 } // unchanged
137
138 // ----- 6. Tamper detection: mutate target_tier -----
139 let orig_tier: i64 = r.target_tier
140 r.target_tier = NX_TIER_INF_HPC
141 if nx_emitted_substrate_verify_sig(r, pub) != NX_EMIT_BAD_SIG { return 17 }
142 r.target_tier = orig_tier
143 if nx_emitted_substrate_verify_sig(r, pub) != NX_EMIT_OK { return 18 }
144
145 // Mutate a stored hash field directly.
146 let h_first: *NxBlobHash = (r.expected_hashes_ptrs[0]) as *NxBlobHash
147 let orig_w0: i64 = h_first.w0
148 h_first.w0 = h_first.w0 ^ 1 // flip 1 bit
149 if nx_emitted_substrate_verify_sig(r, pub) != NX_EMIT_BAD_SIG { return 19 }
150 h_first.w0 = orig_w0
151 if nx_emitted_substrate_verify_sig(r, pub) != NX_EMIT_OK { return 20 }
152
153 // Mutate ts_emit_us -- captured in canonical bytes; signature catches.
154 let orig_ts: i64 = r.ts_emit_us
155 r.ts_emit_us = r.ts_emit_us + 1
156 if nx_emitted_substrate_verify_sig(r, pub) != NX_EMIT_BAD_SIG { return 21 }
157 r.ts_emit_us = orig_ts
158 if nx_emitted_substrate_verify_sig(r, pub) != NX_EMIT_OK { return 22 }
159
160 // ----- 7. Wrong pub key -----
161 let wrong_pub: *u8 = sys_mmap(64)
162 var w: i64 = 0
163 while w < 32 {
164 wrong_pub[w] = pub[w]
165 w = w + 1
166 }
167 wrong_pub[0] = ((wrong_pub[0] as i64) ^ 1) as u8
168 let rc_wp: i64 = nx_emitted_substrate_verify_sig(r, wrong_pub)
169 if rc_wp == NX_EMIT_OK { return 23 }
170 // BAD_SIG (math fails) or BAD_INPUT (decompress fails) both
171 // acceptable refusals.
172
173 // ----- 8. Populate downstream manifest from the verified record -----
174 let downstream_store: *NxBlobStore = nx_blob_store_new()
175 let downstream_manifest: *NxSubstrateManifest = nx_substrate_manifest_new(downstream_store)
176 if nx_emitted_substrate_to_manifest(r, downstream_manifest) != NX_EMIT_OK { return 24 }
177 if downstream_manifest.n_expected != 3 { return 25 }
178 if nx_substrate_manifest_n_missing(downstream_manifest) != 3 { return 26 }
179 // Downstream ingests the 3 payloads -> manifest completes.
180 if nx_substrate_manifest_ingest(downstream_manifest, h1, p1, 32) != NX_SM_INGESTED { return 27 }
181 if nx_substrate_manifest_ingest(downstream_manifest, h2, p2, 32) != NX_SM_INGESTED { return 28 }
182 if nx_substrate_manifest_ingest(downstream_manifest, h3, p3, 32) != NX_SM_INGESTED { return 29 }
183 if nx_substrate_manifest_is_complete(downstream_manifest) != 1 { return 30 }
184
185 // ----- 9. Bad-input gates -----
186 let null_hash: *u8 = (0 as i64) as *u8
187 let null_emit: *NxEmittedSubstrate = (0 as i64) as *NxEmittedSubstrate
188 // null emitter_install_hash -> new returns null
189 if (nx_emitted_substrate_new(null_hash, 0, 0) as i64) != 0 { return 31 }
190 // null hash in add_expected
191 let null_h: *NxBlobHash = (0 as i64) as *NxBlobHash
192 if nx_emitted_substrate_add_expected(null_emit, h1) != NX_EMIT_TAMPER { return 32 }
193 // sign with null priv
194 if nx_emitted_substrate_sign(r, null_hash) != NX_EMIT_BAD_INPUT { return 33 }
195 // verify with null pub
196 if nx_emitted_substrate_verify_sig(r, null_hash) != NX_EMIT_BAD_INPUT { return 34 }
197
198 // ----- 10. Canary tamper -----
199 let tamper_emitter: *u8 = sys_mmap(64)
200 _make_emitter_hash(tamper_emitter)
201 let tr: *NxEmittedSubstrate = nx_emitted_substrate_new(
202 tamper_emitter, NX_TIER_INF_MOBILE, NX_ISA_RV64)
203 nx_emitted_substrate_add_expected(tr, h1)
204 tr.canary_post = 0xDEADBEEF
205 if nx_emitted_substrate_is_valid(tr) != 0 { return 35 }
206 if nx_emitted_substrate_add_expected(tr, h2) != NX_EMIT_TAMPER { return 36 }
207 if nx_emitted_substrate_sign(tr, priv) != NX_EMIT_TAMPER { return 37 }
208 if nx_emitted_substrate_verify_sig(tr, pub) != NX_EMIT_TAMPER { return 38 }
209 if nx_emitted_substrate_n_expected(tr) != -1 { return 39 }
210
211 // ----- 11. Sealed-enum gate -----
212 if nx_emit_verdict_is_valid(NX_EMIT_OK) != 1 { return 40 }
213 if nx_emit_verdict_is_valid(-1) != 0 { return 41 }
214 if nx_emit_verdict_is_valid(NX_EMIT_N) != 0 { return 42 }
215
216 return 0
217}