code wiki / (root) / nx_spore_up_lifecycle_test.nx

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}