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}