code wiki / (root) / nx_install_hash_test.nx

nx_install_hash_test.nx source

↩ module page · 203 lines · 9068 B

1// nx_install_hash_test.nx -- smoke for nx_install_hash SA-7 partial. 2// 3// Exercises: 4// 1. Bad-input gates 5// 2. Tampered plan refused (canary stomp -> NX_HASH_BAD_PLAN) 6// 3. REPRODUCIBILITY gate: two plans with identical content -> same hash 7// 4. SENSITIVITY gates: change any content field -> different hash 8// (probe field, calibration field, policy field, n_selected, 9// total_cost, verdict, variant_id) 10// 5. EXCLUSION gates: change excluded fields (ts_us, canaries- 11// gating-aside) -> same hash 12// 6. nx_install_hash_eq positive + negative 13// 14// SA-7 partial verification gate per NISHI_SELF_ASSEMBLY_ROADMAP.md 15// ยง8: "Reproducibility gate -- same target + same source corpus + 16// same selector version -> same install_hash across two independent 17// runs on different days". This test proves the deterministic 18// property; cross-day persistence is a future smoke composing 19// nx_fact_log + nx_install_hash. 20 21import "nx_syscalls.nx" 22import "nx_probe.nx" 23import "nx_calibrate.nx" 24import "nx_select.nx" 25import "nx_select_joint.nx" 26import "nx_install_plan.nx" 27import "nx_install_hash.nx" 28 29func _make_probe() -> *NxProbeRecord { 30 let p: *NxProbeRecord = nx_probe_new() 31 p.actual_isa_family = NX_ISA_RV64 32 p.actual_endianness = NX_ENDIAN_LITTLE 33 p.actual_pointer_width_bits = 64 34 p.actual_page_size_bytes = 4096 35 p.actual_mmap_works = 1 36 p.actual_write_works = 1 37 p.actual_mono_clock_works = 1 38 return p 39} 40 41func _make_calib() -> *NxCalibrationRecord { 42 let c: *NxCalibrationRecord = nx_calibrate_new() 43 c.int_alu_ps_per_op = 500 44 c.mem_ns_per_access_l1 = 5 45 c.mem_ns_per_access_l2 = 20 46 c.mem_ns_per_access_ram = 300 47 c.mem_bw_mib_per_s = 5000 48 c.syscall_ns_clock_gettime = 50 49 c.syscall_ns_mmap = 1000 50 c.inferred_tier = NX_TIER_INF_LAPTOP 51 return c 52} 53 54// Build a 3-element selected_variant_ids array. 55func _make_plan_with_ids(probe: *NxProbeRecord, calib: *NxCalibrationRecord, 56 policy: *NxPolicy, id0: i64, id1: i64, id2: i64, 57 verdict: i64) -> *NxInstallPlan { 58 // Construct manifests reflecting the desired variant_ids; build 59 // 1-candidate-per-node arrays so the selector deterministically 60 // picks them. 61 let m0: *NxManifest = nx_manifest_new( 62 100, id0, nx_isa_bit(NX_ISA_RV64), 0, 4096, 63 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC, 100, 0, 0, 0) 64 let m1: *NxManifest = nx_manifest_new( 65 100, id1, nx_isa_bit(NX_ISA_RV64), 0, 4096, 66 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC, 100, 0, 0, 0) 67 let m2: *NxManifest = nx_manifest_new( 68 100, id2, nx_isa_bit(NX_ISA_RV64), 0, 4096, 69 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC, 100, 0, 0, 0) 70 71 let p0: *i64 = (sys_mmap(8)) as *i64 72 p0[0] = m0 as i64 73 let p1: *i64 = (sys_mmap(8)) as *i64 74 p1[0] = m1 as i64 75 let p2: *i64 = (sys_mmap(8)) as *i64 76 p2[0] = m2 as i64 77 let n0: *NxJointNode = nx_joint_node_new(100, p0, 1) 78 let n1: *NxJointNode = nx_joint_node_new(200, p1, 1) 79 let n2: *NxJointNode = nx_joint_node_new(300, p2, 1) 80 let nodes_arr: *i64 = (sys_mmap(24)) as *i64 81 nodes_arr[0] = n0 as i64 82 nodes_arr[1] = n1 as i64 83 nodes_arr[2] = n2 as i64 84 85 let sel: *i64 = (sys_mmap(24)) as *i64 86 sel[0] = 0 87 sel[1] = 0 88 sel[2] = 0 89 90 let plan: *NxInstallPlan = nx_install_plan_new() 91 nx_install_plan_capture(plan, probe, calib, policy, 92 nodes_arr, 3, sel, 300, verdict) 93 return plan 94} 95 96func main() -> i64 { 97 let probe: *NxProbeRecord = _make_probe() 98 let calib: *NxCalibrationRecord = _make_calib() 99 let policy: *NxPolicy = nx_policy_throughput_default() 100 101 // ----- 1. Bad-input gates ----- 102 let null_plan: *NxInstallPlan = (0 as i64) as *NxInstallPlan 103 let digest_buf: *u8 = sys_mmap(64) 104 let rc_np: i64 = nx_install_hash_compute(null_plan, digest_buf) 105 if rc_np != NX_HASH_BAD_PLAN { return 1 } 106 107 let plan_a: *NxInstallPlan = _make_plan_with_ids(probe, calib, policy, 108 1001, 1002, 1003, 109 NX_PLAN_VERDICT_OK) 110 let null_out: *u8 = (0 as i64) as *u8 111 let rc_no: i64 = nx_install_hash_compute(plan_a, null_out) 112 if rc_no != NX_HASH_BAD_OUT { return 2 } 113 114 // ----- 2. Refuse tampered plan ----- 115 let tampered: *NxInstallPlan = _make_plan_with_ids(probe, calib, policy, 116 1001, 1002, 1003, 117 NX_PLAN_VERDICT_OK) 118 tampered.canary_post = 0xDEADBEEF 119 let dig_t: *u8 = sys_mmap(64) 120 let rc_t: i64 = nx_install_hash_compute(tampered, dig_t) 121 if rc_t != NX_HASH_BAD_PLAN { return 3 } 122 123 // ----- 3. REPRODUCIBILITY: two identical plans -> same hash ----- 124 let plan_b: *NxInstallPlan = _make_plan_with_ids(probe, calib, policy, 125 1001, 1002, 1003, 126 NX_PLAN_VERDICT_OK) 127 let dig_a: *u8 = sys_mmap(64) 128 let dig_b: *u8 = sys_mmap(64) 129 if nx_install_hash_compute(plan_a, dig_a) != NX_HASH_OK { return 4 } 130 if nx_install_hash_compute(plan_b, dig_b) != NX_HASH_OK { return 5 } 131 if nx_install_hash_eq(dig_a, dig_b) != 1 { return 6 } 132 133 // ----- 4a. SENSITIVITY: change probe field -> different hash ----- 134 let probe2: *NxProbeRecord = _make_probe() 135 probe2.actual_page_size_bytes = 16384 // CHANGED 136 let plan_pp: *NxInstallPlan = _make_plan_with_ids(probe2, calib, policy, 137 1001, 1002, 1003, 138 NX_PLAN_VERDICT_OK) 139 let dig_pp: *u8 = sys_mmap(64) 140 if nx_install_hash_compute(plan_pp, dig_pp) != NX_HASH_OK { return 7 } 141 if nx_install_hash_eq(dig_a, dig_pp) != 0 { return 8 } 142 143 // ----- 4b. SENSITIVITY: change calibration field -> different hash ----- 144 let calib2: *NxCalibrationRecord = _make_calib() 145 calib2.mem_bw_mib_per_s = 9999 // CHANGED 146 let plan_cc: *NxInstallPlan = _make_plan_with_ids(probe, calib2, policy, 147 1001, 1002, 1003, 148 NX_PLAN_VERDICT_OK) 149 let dig_cc: *u8 = sys_mmap(64) 150 if nx_install_hash_compute(plan_cc, dig_cc) != NX_HASH_OK { return 9 } 151 if nx_install_hash_eq(dig_a, dig_cc) != 0 { return 10 } 152 153 // ----- 4c. SENSITIVITY: change policy field -> different hash ----- 154 let policy2: *NxPolicy = nx_policy_energy_default() // different defaults 155 let plan_pol: *NxInstallPlan = _make_plan_with_ids(probe, calib, policy2, 156 1001, 1002, 1003, 157 NX_PLAN_VERDICT_OK) 158 let dig_pol: *u8 = sys_mmap(64) 159 if nx_install_hash_compute(plan_pol, dig_pol) != NX_HASH_OK { return 11 } 160 if nx_install_hash_eq(dig_a, dig_pol) != 0 { return 12 } 161 162 // ----- 4d. SENSITIVITY: change a variant_id -> different hash ----- 163 let plan_v: *NxInstallPlan = _make_plan_with_ids(probe, calib, policy, 164 1001, 9999, 1003, 165 NX_PLAN_VERDICT_OK) 166 let dig_v: *u8 = sys_mmap(64) 167 if nx_install_hash_compute(plan_v, dig_v) != NX_HASH_OK { return 13 } 168 if nx_install_hash_eq(dig_a, dig_v) != 0 { return 14 } 169 170 // ----- 4e. SENSITIVITY: change verdict -> different hash ----- 171 let plan_vr: *NxInstallPlan = _make_plan_with_ids(probe, calib, policy, 172 1001, 1002, 1003, 173 NX_PLAN_VERDICT_PARTIAL) 174 let dig_vr: *u8 = sys_mmap(64) 175 if nx_install_hash_compute(plan_vr, dig_vr) != NX_HASH_OK { return 15 } 176 if nx_install_hash_eq(dig_a, dig_vr) != 0 { return 16 } 177 178 // ----- 5. EXCLUSION: change excluded fields -> same hash ----- 179 // ts_us is excluded by design. Stomp it on plan_a (after capture 180 // already populated it) and re-hash; must equal the prior hash. 181 plan_a.ts_us = 9999999999 182 let dig_a_post: *u8 = sys_mmap(64) 183 if nx_install_hash_compute(plan_a, dig_a_post) != NX_HASH_OK { return 17 } 184 if nx_install_hash_eq(dig_a, dig_a_post) != 1 { return 18 } 185 186 // Also restore plan_a's ts so subsequent tests don't drift. 187 // (Not strictly needed; just hygiene.) 188 189 // ----- 6. Digest equality helpers ----- 190 // Trivially equal: two zero buffers. 191 let zero1: *u8 = sys_mmap(64) 192 let zero2: *u8 = sys_mmap(64) 193 if nx_install_hash_eq(zero1, zero2) != 1 { return 19 } 194 // One bit different -> not equal. 195 zero1[5] = 1 as u8 196 if nx_install_hash_eq(zero1, zero2) != 0 { return 20 } 197 // Null pointer rejected. 198 let nullp: *u8 = (0 as i64) as *u8 199 if nx_install_hash_eq(nullp, zero2) != 0 { return 21 } 200 if nx_install_hash_eq(zero1, nullp) != 0 { return 22 } 201 202 return 0 203}