nx_spore_up_lifecycle_test.nx source
↩ module page · 266 lines · 12917 B
1// nx_spore_up_lifecycle_test.nx -- FULL 5-phase ecosystem evolution
2// lifecycle in ONE main().
3//
4// This is the closure-proof demo: every phase that's been shipped
5// composes through a single program. The chain of demonstrations:
6// v1 nx_spore_up_test.nx -- SA arc on real measurements
7// v2 nx_spore_up_network_test.nx -- v1 + Phase 2 network ingest
8// v3 (THIS FILE) -- v1 + v2 + Phase 5 reproduce
9//
10// Lifecycle in one main():
11// Phase 1 (Spore) -- synthetic upstream spore declares
12// expected substrate hashes
13// Phase 2 (Network) -- mock peer delivers blobs; manifest
14// verifies + ingests; adversarial peer
15// push attempt caught
16// Phase 3 (Substrate) -- SA arc assembles on real on-device
17// probe + calibration
18// Phase 4 (Seed) -- install_hash + Ed25519-signed +
19// journaled
20// Phase 5 (Reproduce) -- emit new spore for downstream device;
21// sign + verify; populate downstream
22// NxSubstrateManifest from the emitted
23// record; downstream ingests its
24// first blob
25//
26// Honest scope:
27// PROVEN: all 5 phases compose in code; chain runs end-to-end on
28// real on-device probe/calibration; Ed25519 signing closes both
29// the Phase 4 install attestation and the Phase 5 emit record;
30// adversarial peer push attempts at Phase 2 are caught by
31// nx_substrate_manifest dual-verification.
32//
33// NOT PROVEN: real network transport (HTTPS / serial / USB),
34// Stage0 hex0 seed bootstrap (SA-9), AVR codegen for Arduino
35// targets (EM-10), real-hardware demo (EM-12). These remain
36// honest queued milestones per
37// NISHI_ECOSYSTEM_EVOLUTION_ROADMAP.md.
38
39import "nx_syscalls.nx"
40import "nx_probe.nx"
41import "nx_calibrate.nx"
42import "nx_select.nx"
43import "nx_select_joint.nx"
44import "nx_install_plan.nx"
45import "nx_install_hash.nx"
46import "nx_install_pipeline.nx"
47import "nx_install_attest_signed.nx"
48import "nx_blob_store.nx"
49import "nx_journal_log.nx"
50import "nx_substrate_manifest.nx"
51import "nx_emitted_substrate.nx"
52
53const SCHEMA_INSTALL_HASH: i64 = 1001
54
55// RFC 8032 §7.1 Test 1 keypair -- the upstream emitter that minted
56// the spore THIS device is germinating from. In real spore-up the
57// operator provides their own keys.
58func _upstream_priv(buf: *u8) -> i64 {
59 buf[0]=0x9d as u8; buf[1]=0x61 as u8; buf[2]=0xb1 as u8; buf[3]=0x9d as u8
60 buf[4]=0xef as u8; buf[5]=0xfd as u8; buf[6]=0x5a as u8; buf[7]=0x60 as u8
61 buf[8]=0xba as u8; buf[9]=0x84 as u8; buf[10]=0x4a as u8; buf[11]=0xf4 as u8
62 buf[12]=0x92 as u8; buf[13]=0xec as u8; buf[14]=0x2c as u8; buf[15]=0xc4 as u8
63 buf[16]=0x44 as u8; buf[17]=0x49 as u8; buf[18]=0xc5 as u8; buf[19]=0x69 as u8
64 buf[20]=0x7b as u8; buf[21]=0x32 as u8; buf[22]=0x69 as u8; buf[23]=0x19 as u8
65 buf[24]=0x70 as u8; buf[25]=0x3b as u8; buf[26]=0xac as u8; buf[27]=0x03 as u8
66 buf[28]=0x1c as u8; buf[29]=0xae as u8; buf[30]=0x7f as u8; buf[31]=0x60 as u8
67 return 0
68}
69
70func _upstream_pub(buf: *u8) -> i64 {
71 buf[0]=0xd7 as u8; buf[1]=0x5a as u8; buf[2]=0x98 as u8; buf[3]=0x01 as u8
72 buf[4]=0x82 as u8; buf[5]=0xb1 as u8; buf[6]=0x0a as u8; buf[7]=0xb7 as u8
73 buf[8]=0xd5 as u8; buf[9]=0x4b as u8; buf[10]=0xfe as u8; buf[11]=0xd3 as u8
74 buf[12]=0xc9 as u8; buf[13]=0x64 as u8; buf[14]=0x07 as u8; buf[15]=0x3a as u8
75 buf[16]=0x0e as u8; buf[17]=0xe1 as u8; buf[18]=0x72 as u8; buf[19]=0xf3 as u8
76 buf[20]=0xda as u8; buf[21]=0xa6 as u8; buf[22]=0x23 as u8; buf[23]=0x25 as u8
77 buf[24]=0xaf as u8; buf[25]=0x02 as u8; buf[26]=0x1a as u8; buf[27]=0x68 as u8
78 buf[28]=0xf7 as u8; buf[29]=0x07 as u8; buf[30]=0x51 as u8; buf[31]=0x1a as u8
79 return 0
80}
81
82func _fill(buf: *u8, len: i64, seed: i64) -> i64 {
83 var i: i64 = 0
84 while i < len {
85 buf[i] = (((i * 23) + seed) & 255) as u8
86 i = i + 1
87 }
88 return 0
89}
90
91func _hash_of(bytes: *u8, len: i64) -> *NxBlobHash {
92 let s: *NxBlobStore = nx_blob_store_new()
93 let h: *NxBlobHash = nx_blob_hash_new()
94 nx_blob_store_put(s, bytes, len, h)
95 return h
96}
97
98func _mk(variant_id: i64, cost: i64, in_lay: i64, out_lay: i64) -> *NxManifest {
99 let m: *NxManifest = nx_manifest_new(
100 100, variant_id,
101 nx_isa_bit(NX_ISA_RV64) | nx_isa_bit(NX_ISA_X86_64),
102 0, 4096,
103 NX_TIER_INF_UNKNOWN, NX_TIER_INF_HPC,
104 cost, 0, 0, 0)
105 nx_manifest_set_layout(m, in_lay, out_lay)
106 return m
107}
108
109func main() -> i64 {
110 let upstream_priv: *u8 = sys_mmap(64)
111 _upstream_priv(upstream_priv)
112 let upstream_pub: *u8 = sys_mmap(64)
113 _upstream_pub(upstream_pub)
114
115 // ========================================================
116 // PHASE 1 -- Upstream substrate emitted a spore for us. In
117 // real spore-up the upstream device runs nx_emitted_substrate
118 // before transmission; here we simulate by building the same
119 // record locally and signing with the upstream key.
120 // ========================================================
121 let pA: *u8 = sys_mmap(64)
122 _fill(pA, 32, 1)
123 let hA: *NxBlobHash = _hash_of(pA, 32)
124 let pB: *u8 = sys_mmap(64)
125 _fill(pB, 32, 2)
126 let hB: *NxBlobHash = _hash_of(pB, 32)
127 let pC: *u8 = sys_mmap(64)
128 _fill(pC, 32, 3)
129 let hC: *NxBlobHash = _hash_of(pC, 32)
130
131 let upstream_install_hash: *u8 = sys_mmap(64)
132 var i: i64 = 0
133 while i < 32 {
134 upstream_install_hash[i] = ((i * 13 + 100) & 255) as u8
135 i = i + 1
136 }
137
138 let emitted: *NxEmittedSubstrate = nx_emitted_substrate_new(
139 upstream_install_hash, NX_TIER_INF_LAPTOP, NX_ISA_RV64)
140 if nx_emitted_substrate_add_expected(emitted, hA) != NX_EMIT_OK { return 1 }
141 if nx_emitted_substrate_add_expected(emitted, hB) != NX_EMIT_OK { return 2 }
142 if nx_emitted_substrate_add_expected(emitted, hC) != NX_EMIT_OK { return 3 }
143 if nx_emitted_substrate_sign(emitted, upstream_priv) != NX_EMIT_OK { return 4 }
144
145 // ========================================================
146 // PHASE 2 -- Verify the emitted-spore + populate manifest +
147 // ingest blobs with adversarial defense.
148 // ========================================================
149 if nx_emitted_substrate_verify_sig(emitted, upstream_pub) != NX_EMIT_OK { return 5 }
150
151 let local_store: *NxBlobStore = nx_blob_store_new()
152 let manifest: *NxSubstrateManifest = nx_substrate_manifest_new(local_store)
153 if nx_emitted_substrate_to_manifest(emitted, manifest) != NX_EMIT_OK { return 6 }
154 if manifest.n_expected != 3 { return 7 }
155
156 // Mock peer delivers blob A.
157 if nx_substrate_manifest_ingest(manifest, hA, pA, 32) != NX_SM_INGESTED { return 8 }
158 // Adversarial: peer pushes evil payload not in spore's set -> refused.
159 let pE: *u8 = sys_mmap(64)
160 _fill(pE, 32, 9999)
161 let hE: *NxBlobHash = _hash_of(pE, 32)
162 if nx_substrate_manifest_ingest(manifest, hE, pE, 32) != NX_SM_NOT_IN_MANIFEST { return 9 }
163 // Peer delivers blobs B + C correctly.
164 if nx_substrate_manifest_ingest(manifest, hB, pB, 32) != NX_SM_INGESTED { return 10 }
165 if nx_substrate_manifest_ingest(manifest, hC, pC, 32) != NX_SM_INGESTED { return 11 }
166 if nx_substrate_manifest_is_complete(manifest) != 1 { return 12 }
167
168 // ========================================================
169 // PHASE 3 -- SA arc assembly on real on-device measurements.
170 // ========================================================
171 let probe: *NxProbeRecord = nx_probe_new()
172 if nx_probe_run(probe) != 0 { return 13 }
173 if probe.actual_isa_family != NX_ISA_RV64 { return 14 }
174
175 let calib: *NxCalibrationRecord = nx_calibrate_new()
176 if nx_calibrate_run(calib) != 0 { return 15 }
177 if calib.mem_bw_mib_per_s <= 0 { return 16 }
178
179 let m_a: *NxManifest = _mk(8001, 300, NX_LAYOUT_OPAQUE_PASS, NX_LAYOUT_COL_MAJOR)
180 let m_b: *NxManifest = _mk(8002, 200, NX_LAYOUT_COL_MAJOR, NX_LAYOUT_COL_MAJOR)
181 let m_c: *NxManifest = _mk(8003, 100, NX_LAYOUT_COL_MAJOR, NX_LAYOUT_OPAQUE_PASS)
182 let a_ptrs: *i64 = (sys_mmap(8)) as *i64
183 a_ptrs[0] = m_a as i64
184 let b_ptrs: *i64 = (sys_mmap(8)) as *i64
185 b_ptrs[0] = m_b as i64
186 let c_ptrs: *i64 = (sys_mmap(8)) as *i64
187 c_ptrs[0] = m_c as i64
188 let nodes: *i64 = (sys_mmap(24)) as *i64
189 nodes[0] = (nx_joint_node_new(100, a_ptrs, 1)) as i64
190 nodes[1] = (nx_joint_node_new(200, b_ptrs, 1)) as i64
191 nodes[2] = (nx_joint_node_new(300, c_ptrs, 1)) as i64
192
193 let policy: *NxPolicy = nx_policy_throughput_default()
194 let plan: *NxInstallPlan = nx_install_plan_new()
195 let install_hash: *u8 = sys_mmap(64)
196 if nx_install_pipeline_run_with_inputs(probe, calib, policy,
197 nodes, 3, plan, install_hash)
198 != NX_PIPELINE_OK { return 17 }
199 if plan.n_selected != 3 { return 18 }
200
201 // ========================================================
202 // PHASE 4 -- Seed: install_hash + Ed25519 sign + journal.
203 //
204 // Note: this device uses the upstream's key for THIS smoke (in
205 // real spore-up the operator provides their device's own key;
206 // upstream and downstream keys are typically different).
207 // ========================================================
208 let my_priv: *u8 = upstream_priv // shorthand for the smoke
209 let my_pub: *u8 = upstream_pub
210
211 let my_sig: *u8 = sys_mmap(128)
212 if nx_install_sign(install_hash, my_priv, my_sig) != NX_INSTALL_SIG_OK { return 19 }
213 if nx_install_verify_sig(install_hash, my_pub, my_sig) != NX_INSTALL_SIG_OK { return 20 }
214
215 let jlog: *NxJournalLog = nx_journal_log_new(local_store)
216 let seq: i64 = nx_journal_log_append(jlog, install_hash, 32, SCHEMA_INSTALL_HASH)
217 if seq != 0 { return 21 }
218 if nx_journal_log_verify_chain(jlog) != -1 { return 22 }
219
220 // ========================================================
221 // PHASE 5 -- Reproduce: emit a new spore for a downstream
222 // device. The expected blob set for the downstream is the
223 // SAME hashes we just verified + assembled from (this device
224 // is now an upstream for the next).
225 // ========================================================
226 let downstream_spore: *NxEmittedSubstrate = nx_emitted_substrate_new(
227 install_hash, NX_TIER_INF_LAPTOP, NX_ISA_RV64)
228 if nx_emitted_substrate_add_expected(downstream_spore, hA) != NX_EMIT_OK { return 23 }
229 if nx_emitted_substrate_add_expected(downstream_spore, hB) != NX_EMIT_OK { return 24 }
230 if nx_emitted_substrate_add_expected(downstream_spore, hC) != NX_EMIT_OK { return 25 }
231 if nx_emitted_substrate_sign(downstream_spore, my_priv) != NX_EMIT_OK { return 26 }
232
233 // Verify the emitted spore against our pub key (sanity: we
234 // signed it; verifying with our own pub must succeed).
235 if nx_emitted_substrate_verify_sig(downstream_spore, my_pub) != NX_EMIT_OK { return 27 }
236
237 // Simulate downstream: receive the emitted spore, verify, build
238 // a fresh manifest, ingest first blob. This is the receiver's
239 // first step in their own Phase 2 -- proves the emit→receive
240 // handoff works in code.
241 let downstream_store: *NxBlobStore = nx_blob_store_new()
242 let downstream_manifest: *NxSubstrateManifest = nx_substrate_manifest_new(downstream_store)
243 if nx_emitted_substrate_verify_sig(downstream_spore, my_pub) != NX_EMIT_OK { return 28 }
244 if nx_emitted_substrate_to_manifest(downstream_spore, downstream_manifest) != NX_EMIT_OK { return 29 }
245 if downstream_manifest.n_expected != 3 { return 30 }
246 if nx_substrate_manifest_ingest(downstream_manifest, hA, pA, 32) != NX_SM_INGESTED { return 31 }
247 if downstream_manifest.n_received != 1 { return 32 }
248
249 // ========================================================
250 // Operator-visible signal: all 5 phases composed end-to-end.
251 // ========================================================
252 // "SPORE UP FULL LIFECYCLE COMPLETE\n" -- 33 bytes.
253 let tag: *u8 = sys_mmap(64)
254 tag[0]=83 as u8; tag[1]=80 as u8; tag[2]=79 as u8; tag[3]=82 as u8 // "SPOR"
255 tag[4]=69 as u8; tag[5]=32 as u8; tag[6]=85 as u8; tag[7]=80 as u8 // "E UP"
256 tag[8]=32 as u8; tag[9]=70 as u8; tag[10]=85 as u8; tag[11]=76 as u8 // " FUL"
257 tag[12]=76 as u8; tag[13]=32 as u8; tag[14]=76 as u8; tag[15]=73 as u8 // "L LI"
258 tag[16]=70 as u8; tag[17]=69 as u8; tag[18]=67 as u8; tag[19]=89 as u8 // "FECY"
259 tag[20]=67 as u8; tag[21]=76 as u8; tag[22]=69 as u8; tag[23]=32 as u8 // "CLE "
260 tag[24]=67 as u8; tag[25]=79 as u8; tag[26]=77 as u8; tag[27]=80 as u8 // "COMP"
261 tag[28]=76 as u8; tag[29]=69 as u8; tag[30]=84 as u8; tag[31]=69 as u8 // "LETE"
262 tag[32]=10 as u8 // "\n"
263 sys_write(1, tag, 33)
264
265 return 0
266}