code wiki / (root) / nx_spore_up_network_test.nx

nx_spore_up_network_test.nx source

↩ module page · 263 lines · 11363 B

1// nx_spore_up_network_test.nx -- full ecosystem evolution flow on 2// SYNTHETIC PEER. 3// 4// Extends the v1 spore-up demo (nx_spore_up_test.nx) to ADD the 5// NETWORK phase: spore declares a manifest of expected substrate 6// chunks; a mock peer "delivers" those chunks; manifest verifies 7// each; completion gates SA-arc assembly; install_hash journaled. 8// 9// This is the second of the spore-up demonstration pair: 10// v1 -- nx_spore_up_test.nx -- SA arc on real measurements 11// v2 -- THIS file -- v1 + network ingest via manifest 12// 13// Lifecycle modeled (per NISHI_ECOSYSTEM_EVOLUTION_ROADMAP.md): 14// Phase 1 (Spore) -- synthetic: spore-author declared 3 expected hashes 15// Phase 2 (Network) -- mock peer delivers blobs; manifest verifies + 16// ingests each; defenses (NOT_IN_MANIFEST + 17// HASH_MISMATCH) exercised 18// Phase 3 (Substrate)-- SA arc assembly on real measurements 19// Phase 4 (Seed) -- journal append of install_hash + verify_chain 20// Phase 5 (Reproduce)-- (queued; this demo does not yet emit a new spore) 21// 22// What this PROVES: 23// - Spore-declared expected manifest is enforced (peer cannot push 24// arbitrary content) 25// - Hash-verification on every received blob (corrupted transit 26// refused) 27// - Completion gate halts assembly until ALL expected blobs received 28// - SA arc still composes on top of the verified-substrate phase 29// - Full chain end-to-end: probe -> calibrate -> manifest-complete 30// -> selection -> plan -> hash -> journaled attestation 31// 32// What this does NOT yet prove (queued): 33// - REAL network transport (HTTPS / serial / USB) -- mock peer here 34// is in-memory 35// - Spore signing (Ed25519) -- composes at EM-9 36// - Stage0 hex0 bootstrap -- composes at SA-9 37// - AVR codegen / Arduino real hardware -- EM-10 / EM-12 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_blob_store.nx" 48import "nx_journal_log.nx" 49import "nx_substrate_manifest.nx" 50 51const SCHEMA_INSTALL_HASH: i64 = 1001 52 53// Compute a known hash for a known byte pattern via L0 store. Used 54// to prebuild the spore's "expected hashes" + the mock peer's 55// known content addresses. 56func _compute_hash(bytes: *u8, len: i64) -> *NxBlobHash { 57 let scratch: *NxBlobStore = nx_blob_store_new() 58 let h: *NxBlobHash = nx_blob_hash_new() 59 nx_blob_store_put(scratch, bytes, len, h) 60 return h 61} 62 63// Fill a buffer with a deterministic pattern keyed by `seed`. 64func _fill(buf: *u8, len: i64, seed: i64) -> i64 { 65 var i: i64 = 0 66 while i < len { 67 buf[i] = (((i * 19) + seed) & 255) as u8 68 i = i + 1 69 } 70 return 0 71} 72 73func _mk_manifest_variant(variant_id: i64, cost: i64, in_lay: i64, out_lay: i64) -> *NxManifest { 74 let m: *NxManifest = nx_manifest_new( 75 100, variant_id, 76 nx_isa_bit(NX_ISA_RV64) | nx_isa_bit(NX_ISA_X86_64), 77 0, 4096, 78 NX_TIER_INF_UNKNOWN, NX_TIER_INF_HPC, 79 cost, 0, 0, 0) 80 nx_manifest_set_layout(m, in_lay, out_lay) 81 return m 82} 83 84func main() -> i64 { 85 // ======================================================== 86 // PHASE 1 -- Spore-author declares 3 expected substrate blobs 87 // ======================================================== 88 // The "spore" carries a list of expected hashes. Here we 89 // synthesize that list by pre-computing hashes for 3 known 90 // payloads. 91 let payload_a: *u8 = sys_mmap(64) 92 _fill(payload_a, 32, 100) 93 let h_a: *NxBlobHash = _compute_hash(payload_a, 32) 94 95 let payload_b: *u8 = sys_mmap(64) 96 _fill(payload_b, 32, 200) 97 let h_b: *NxBlobHash = _compute_hash(payload_b, 32) 98 99 let payload_c: *u8 = sys_mmap(64) 100 _fill(payload_c, 32, 300) 101 let h_c: *NxBlobHash = _compute_hash(payload_c, 32) 102 103 // ======================================================== 104 // PHASE 2 -- Spore germinates: build manifest + ingest from 105 // a mock peer. 106 // ======================================================== 107 let main_store: *NxBlobStore = nx_blob_store_new() 108 let manifest: *NxSubstrateManifest = nx_substrate_manifest_new(main_store) 109 if nx_substrate_manifest_is_valid(manifest) != 1 { return 1 } 110 111 // Spore declares the expected set. 112 if nx_substrate_manifest_add_expected(manifest, h_a) != NX_SM_INGESTED { return 2 } 113 if nx_substrate_manifest_add_expected(manifest, h_b) != NX_SM_INGESTED { return 3 } 114 if nx_substrate_manifest_add_expected(manifest, h_c) != NX_SM_INGESTED { return 4 } 115 if nx_substrate_manifest_is_complete(manifest) != 0 { return 5 } 116 if nx_substrate_manifest_n_missing(manifest) != 3 { return 6 } 117 118 // Mock peer delivers blob A first. 119 if nx_substrate_manifest_ingest(manifest, h_a, payload_a, 32) != NX_SM_INGESTED { return 7 } 120 if nx_substrate_manifest_n_missing(manifest) != 2 { return 8 } 121 122 // ----- ADVERSARIAL: peer pushes a blob whose hash is NOT in 123 // the spore's expected set. Must be refused. ----- 124 let payload_evil: *u8 = sys_mmap(64) 125 _fill(payload_evil, 32, 9999) 126 let h_evil: *NxBlobHash = _compute_hash(payload_evil, 32) 127 if nx_substrate_manifest_ingest(manifest, h_evil, payload_evil, 32) != NX_SM_NOT_IN_MANIFEST { return 9 } 128 if manifest.n_rejected_unknown != 1 { return 10 } 129 130 // ----- ADVERSARIAL: peer claims to deliver blob B but actually 131 // sends C's bytes (transit corruption / replacement). Must be 132 // refused. ----- 133 if nx_substrate_manifest_ingest(manifest, h_b, payload_c, 32) != NX_SM_HASH_MISMATCH { return 11 } 134 if manifest.n_rejected_tamper != 1 { return 12 } 135 // Verifies that despite the rejection, the manifest's state is 136 // unchanged for blob B. 137 if manifest.received_flags[1] != 0 { return 13 } 138 if nx_substrate_manifest_n_missing(manifest) != 2 { return 14 } 139 140 // Peer recovers + delivers blob B correctly. 141 if nx_substrate_manifest_ingest(manifest, h_b, payload_b, 32) != NX_SM_INGESTED { return 15 } 142 if nx_substrate_manifest_n_missing(manifest) != 1 { return 16 } 143 144 // Peer delivers blob C. 145 if nx_substrate_manifest_ingest(manifest, h_c, payload_c, 32) != NX_SM_INGESTED { return 17 } 146 147 // ----- COMPLETION GATE ----- 148 if nx_substrate_manifest_is_complete(manifest) != 1 { return 18 } 149 if nx_substrate_manifest_n_missing(manifest) != 0 { return 19 } 150 151 // Every expected blob now in the L0 store, hash-verified. 152 if nx_blob_store_has(main_store, h_a) != 1 { return 20 } 153 if nx_blob_store_has(main_store, h_b) != 1 { return 21 } 154 if nx_blob_store_has(main_store, h_c) != 1 { return 22 } 155 156 // ======================================================== 157 // PHASE 3 -- Substrate assembly via the SA arc. 158 // ======================================================== 159 let probe: *NxProbeRecord = nx_probe_new() 160 if nx_probe_run(probe) != 0 { return 23 } 161 if probe.actual_isa_family != NX_ISA_RV64 { return 24 } 162 163 let calib: *NxCalibrationRecord = nx_calibrate_new() 164 if nx_calibrate_run(calib) != 0 { return 25 } 165 if calib.mem_bw_mib_per_s <= 0 { return 26 } 166 167 // Build a 3-node workload DAG (one variant per node for 168 // determinism; in real spore-up the variants would come from 169 // the verified blobs above). 170 let v_a: *NxManifest = _mk_manifest_variant(8001, 300, NX_LAYOUT_OPAQUE_PASS, NX_LAYOUT_COL_MAJOR) 171 let v_b: *NxManifest = _mk_manifest_variant(8002, 200, NX_LAYOUT_COL_MAJOR, NX_LAYOUT_COL_MAJOR) 172 let v_c: *NxManifest = _mk_manifest_variant(8003, 100, NX_LAYOUT_COL_MAJOR, NX_LAYOUT_OPAQUE_PASS) 173 let va_ptrs: *i64 = (sys_mmap(8)) as *i64 174 va_ptrs[0] = v_a as i64 175 let vb_ptrs: *i64 = (sys_mmap(8)) as *i64 176 vb_ptrs[0] = v_b as i64 177 let vc_ptrs: *i64 = (sys_mmap(8)) as *i64 178 vc_ptrs[0] = v_c as i64 179 let n_a: *NxJointNode = nx_joint_node_new(100, va_ptrs, 1) 180 let n_b: *NxJointNode = nx_joint_node_new(200, vb_ptrs, 1) 181 let n_c: *NxJointNode = nx_joint_node_new(300, vc_ptrs, 1) 182 let nodes: *i64 = (sys_mmap(24)) as *i64 183 nodes[0] = n_a as i64 184 nodes[1] = n_b as i64 185 nodes[2] = n_c as i64 186 187 let policy: *NxPolicy = nx_policy_throughput_default() 188 let plan: *NxInstallPlan = nx_install_plan_new() 189 let install_hash: *u8 = sys_mmap(64) 190 if nx_install_pipeline_run_with_inputs(probe, calib, policy, 191 nodes, 3, plan, install_hash) 192 != NX_PIPELINE_OK { return 27 } 193 if plan.n_selected != 3 { return 28 } 194 if plan.selection_verdict != NX_PLAN_VERDICT_OK { return 29 } 195 if nx_install_plan_variant_id_at(plan, 0) != 8001 { return 30 } 196 if nx_install_plan_variant_id_at(plan, 1) != 8002 { return 31 } 197 if nx_install_plan_variant_id_at(plan, 2) != 8003 { return 32 } 198 199 // ======================================================== 200 // PHASE 4 -- Seed: persistent journaled attestation. 201 // ======================================================== 202 let jlog: *NxJournalLog = nx_journal_log_new(main_store) 203 let seq: i64 = nx_journal_log_append(jlog, install_hash, 32, SCHEMA_INSTALL_HASH) 204 if seq != 0 { return 33 } 205 if nx_journal_log_verify_chain(jlog) != -1 { return 34 } 206 207 // Round-trip the journal entry, confirm bytes match install_hash. 208 let read_back: *u8 = sys_mmap(64) 209 let sid_out: *i64 = (sys_mmap(8)) as *i64 210 let n_read: i64 = nx_journal_log_read(jlog, 0, read_back, 64, sid_out) 211 if n_read != 32 { return 35 } 212 if *sid_out != SCHEMA_INSTALL_HASH { return 36 } 213 var k: i64 = 0 214 while k < 32 { 215 if (read_back[k] as i64) != (install_hash[k] as i64) { return 37 } 216 k = k + 1 217 } 218 219 // ----- Audit counters surfaced ----- 220 // Manifest rejected 2 attacks (1 unknown + 1 tamper); 3 blobs 221 // verified-and-stored. 222 if nx_substrate_manifest_n_rejected_unknown(manifest) != 1 { return 38 } 223 if nx_substrate_manifest_n_rejected_tamper(manifest) != 1 { return 39 } 224 if manifest.n_received != 3 { return 40 } 225 226 // ======================================================== 227 // PHASE 5 -- (queued) Reproduce: mature substrate would emit 228 // a new spore for downstream devices. Not yet implemented. 229 // ======================================================== 230 231 // ----- Operator-visible signal ----- 232 // "SPORE UP NETWORK COMPLETE\n" -- 26 bytes. 233 let tag: *u8 = sys_mmap(32) 234 tag[0] = 83 as u8 // 'S' 235 tag[1] = 80 as u8 // 'P' 236 tag[2] = 79 as u8 // 'O' 237 tag[3] = 82 as u8 // 'R' 238 tag[4] = 69 as u8 // 'E' 239 tag[5] = 32 as u8 // ' ' 240 tag[6] = 85 as u8 // 'U' 241 tag[7] = 80 as u8 // 'P' 242 tag[8] = 32 as u8 // ' ' 243 tag[9] = 78 as u8 // 'N' 244 tag[10] = 69 as u8 // 'E' 245 tag[11] = 84 as u8 // 'T' 246 tag[12] = 87 as u8 // 'W' 247 tag[13] = 79 as u8 // 'O' 248 tag[14] = 82 as u8 // 'R' 249 tag[15] = 75 as u8 // 'K' 250 tag[16] = 32 as u8 // ' ' 251 tag[17] = 67 as u8 // 'C' 252 tag[18] = 79 as u8 // 'O' 253 tag[19] = 77 as u8 // 'M' 254 tag[20] = 80 as u8 // 'P' 255 tag[21] = 76 as u8 // 'L' 256 tag[22] = 69 as u8 // 'E' 257 tag[23] = 84 as u8 // 'T' 258 tag[24] = 69 as u8 // 'E' 259 tag[25] = 10 as u8 // '\n' 260 sys_write(1, tag, 26) 261 262 return 0 263}