nx_install_attest_test.nx source
↩ module page · 238 lines · 9302 B
1// nx_install_attest_test.nx -- smoke for nx_install_attest helpers.
2//
3// Exercises:
4// 1. Hex encode produces 64 ASCII lowercase chars for a known digest
5// 2. Hex encode/decode roundtrip on random digest
6// 3. Hex decode tolerates both lowercase a-f AND uppercase A-F
7// 4. Hex decode rejects invalid chars (space, 'g', '-', etc.)
8// 5. Bad-input gates (null in / null out for both encode + decode)
9// 6. verify_against on matching digest -> VERIFIED
10// 7. verify_against on mismatched digest -> TAMPERED
11// 8. verify_against on null plan / canary-stomped plan -> BAD_INPUT
12// 9. verify_against integration with the pipeline: pipeline ->
13// hash A; later verify_against(plan, A) -> VERIFIED
14// 10. Sealed-enum gate
15
16import "nx_syscalls.nx"
17import "nx_probe.nx"
18import "nx_calibrate.nx"
19import "nx_select.nx"
20import "nx_select_joint.nx"
21import "nx_install_plan.nx"
22import "nx_install_hash.nx"
23import "nx_install_pipeline.nx"
24import "nx_install_attest.nx"
25
26func _make_probe() -> *NxProbeRecord {
27 let p: *NxProbeRecord = nx_probe_new()
28 p.actual_isa_family = NX_ISA_RV64
29 p.actual_endianness = NX_ENDIAN_LITTLE
30 p.actual_pointer_width_bits = 64
31 p.actual_page_size_bytes = 4096
32 p.actual_mmap_works = 1
33 p.actual_write_works = 1
34 p.actual_mono_clock_works = 1
35 return p
36}
37
38func _make_calib() -> *NxCalibrationRecord {
39 let c: *NxCalibrationRecord = nx_calibrate_new()
40 c.int_alu_ps_per_op = 500
41 c.mem_ns_per_access_l1 = 5
42 c.mem_ns_per_access_l2 = 20
43 c.mem_ns_per_access_ram = 300
44 c.mem_bw_mib_per_s = 5000
45 c.syscall_ns_clock_gettime = 50
46 c.syscall_ns_mmap = 1000
47 c.inferred_tier = NX_TIER_INF_LAPTOP
48 return c
49}
50
51func _mk(variant_id: i64, cost: i64, in_lay: i64, out_lay: i64) -> *NxManifest {
52 let m: *NxManifest = nx_manifest_new(
53 100, variant_id,
54 nx_isa_bit(NX_ISA_RV64),
55 0, 4096,
56 NX_TIER_INF_MOBILE, NX_TIER_INF_HPC,
57 cost, 0, 0, 0)
58 nx_manifest_set_layout(m, in_lay, out_lay)
59 return m
60}
61
62func main() -> i64 {
63 // ----- 1. Hex encode of a known 32-byte digest -----
64 // Digest = 0x00 0x01 0x02 ... 0x1F (32 bytes). Hex must be
65 // "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f".
66 let dig: *u8 = sys_mmap(64)
67 var i: i64 = 0
68 while i < 32 {
69 dig[i] = (i & 255) as u8
70 i = i + 1
71 }
72 let hex_out: *u8 = sys_mmap(128)
73 if nx_install_hash_to_hex(dig, hex_out) != NX_HEX_OK { return 1 }
74
75 // Spot-check a few positions. Byte 0 = 0x00 -> "00".
76 if (hex_out[0] as i64) != 48 { return 2 } // '0'
77 if (hex_out[1] as i64) != 48 { return 3 }
78 // Byte 1 = 0x01 -> "01".
79 if (hex_out[2] as i64) != 48 { return 4 }
80 if (hex_out[3] as i64) != 49 { return 5 } // '1'
81 // Byte 10 = 0x0A -> "0a".
82 if (hex_out[20] as i64) != 48 { return 6 }
83 if (hex_out[21] as i64) != 97 { return 7 } // 'a'
84 // Byte 15 = 0x0F -> "0f".
85 if (hex_out[30] as i64) != 48 { return 8 }
86 if (hex_out[31] as i64) != 102 { return 9 } // 'f'
87 // Byte 16 = 0x10 -> "10".
88 if (hex_out[32] as i64) != 49 { return 10 }
89 if (hex_out[33] as i64) != 48 { return 11 }
90 // Byte 31 = 0x1F -> "1f".
91 if (hex_out[62] as i64) != 49 { return 12 }
92 if (hex_out[63] as i64) != 102 { return 13 }
93
94 // ----- 2. Roundtrip: encode then decode -----
95 let dig_back: *u8 = sys_mmap(64)
96 if nx_install_hash_from_hex(hex_out, dig_back) != NX_HEX_OK { return 14 }
97 var k: i64 = 0
98 while k < 32 {
99 if (dig_back[k] as i64) != (dig[k] as i64) { return 15 }
100 k = k + 1
101 }
102
103 // ----- 3. Uppercase A-F tolerance -----
104 // Build "DEADBEEF..." style hex with uppercase letters.
105 let up_hex: *u8 = sys_mmap(128)
106 // First fill with valid uppercase hex sequence representing
107 // bytes 0xDE, 0xAD, 0xBE, 0xEF repeated.
108 var j: i64 = 0
109 while j < 32 {
110 let m: i64 = j % 4
111 if m == 0 {
112 up_hex[j * 2 + 0] = 68 as u8 // 'D'
113 up_hex[j * 2 + 1] = 69 as u8 // 'E'
114 }
115 if m == 1 {
116 up_hex[j * 2 + 0] = 65 as u8 // 'A'
117 up_hex[j * 2 + 1] = 68 as u8 // 'D'
118 }
119 if m == 2 {
120 up_hex[j * 2 + 0] = 66 as u8 // 'B'
121 up_hex[j * 2 + 1] = 69 as u8 // 'E'
122 }
123 if m == 3 {
124 up_hex[j * 2 + 0] = 69 as u8 // 'E'
125 up_hex[j * 2 + 1] = 70 as u8 // 'F'
126 }
127 j = j + 1
128 }
129 let up_dig: *u8 = sys_mmap(64)
130 if nx_install_hash_from_hex(up_hex, up_dig) != NX_HEX_OK { return 16 }
131 // Spot-check: byte 0 should be 0xDE = 222.
132 if (up_dig[0] as i64) != 222 { return 17 }
133 if (up_dig[1] as i64) != 173 { return 18 } // 0xAD
134 if (up_dig[2] as i64) != 190 { return 19 } // 0xBE
135 if (up_dig[3] as i64) != 239 { return 20 } // 0xEF
136
137 // ----- 4. Bad-char rejection -----
138 // Stomp one position with ' ' (space) -- not a hex digit.
139 let bad_hex: *u8 = sys_mmap(128)
140 var m2: i64 = 0
141 while m2 < 64 {
142 bad_hex[m2] = 48 as u8 // '0'
143 m2 = m2 + 1
144 }
145 bad_hex[10] = 32 as u8 // ' '
146 let bad_dig: *u8 = sys_mmap(64)
147 if nx_install_hash_from_hex(bad_hex, bad_dig) != NX_HEX_BAD_CHAR { return 21 }
148
149 // Stomp with 'g' (just past 'f').
150 bad_hex[10] = 103 as u8 // 'g'
151 if nx_install_hash_from_hex(bad_hex, bad_dig) != NX_HEX_BAD_CHAR { return 22 }
152
153 // Stomp with '-'.
154 bad_hex[10] = 45 as u8 // '-'
155 if nx_install_hash_from_hex(bad_hex, bad_dig) != NX_HEX_BAD_CHAR { return 23 }
156
157 // ----- 5. Null-pointer gates -----
158 let np: *u8 = (0 as i64) as *u8
159 if nx_install_hash_to_hex(np, hex_out) != NX_HEX_BAD_INPUT { return 24 }
160 if nx_install_hash_to_hex(dig, np) != NX_HEX_BAD_INPUT { return 25 }
161 if nx_install_hash_from_hex(np, dig_back) != NX_HEX_BAD_INPUT { return 26 }
162 if nx_install_hash_from_hex(hex_out, np) != NX_HEX_BAD_INPUT { return 27 }
163
164 // ----- 6 & 7. verify_against via the pipeline -----
165 // Build a real plan + hash via the orchestrator, then verify.
166 let probe: *NxProbeRecord = _make_probe()
167 let calib: *NxCalibrationRecord = _make_calib()
168 let policy: *NxPolicy = nx_policy_throughput_default()
169
170 let a_med_col: *NxManifest = _mk(2002, 300, NX_LAYOUT_OPAQUE_PASS, NX_LAYOUT_COL_MAJOR)
171 let b_med_col: *NxManifest = _mk(2102, 200, NX_LAYOUT_COL_MAJOR, NX_LAYOUT_COL_MAJOR)
172 let c_col: *NxManifest = _mk(2201, 100, NX_LAYOUT_COL_MAJOR, NX_LAYOUT_OPAQUE_PASS)
173 let a_ptrs: *i64 = (sys_mmap(8)) as *i64
174 a_ptrs[0] = a_med_col as i64
175 let b_ptrs: *i64 = (sys_mmap(8)) as *i64
176 b_ptrs[0] = b_med_col as i64
177 let c_ptrs: *i64 = (sys_mmap(8)) as *i64
178 c_ptrs[0] = c_col as i64
179 let chain: *i64 = (sys_mmap(24)) as *i64
180 chain[0] = (nx_joint_node_new(100, a_ptrs, 1)) as i64
181 chain[1] = (nx_joint_node_new(200, b_ptrs, 1)) as i64
182 chain[2] = (nx_joint_node_new(300, c_ptrs, 1)) as i64
183
184 let plan: *NxInstallPlan = nx_install_plan_new()
185 let hash_a: *u8 = sys_mmap(64)
186 if nx_install_pipeline_run_with_inputs(probe, calib, policy,
187 chain, 3, plan, hash_a)
188 != NX_PIPELINE_OK { return 28 }
189
190 // Same plan + same hash -> VERIFIED.
191 if nx_install_hash_verify_against(plan, hash_a)
192 != NX_ATTEST_VERIFIED { return 29 }
193
194 // Different digest -> TAMPERED.
195 let hash_diff: *u8 = sys_mmap(64)
196 var dh: i64 = 0
197 while dh < 32 {
198 hash_diff[dh] = 0 as u8
199 dh = dh + 1
200 }
201 hash_diff[0] = 1 as u8 // first byte differs
202 if nx_install_hash_verify_against(plan, hash_diff)
203 != NX_ATTEST_TAMPERED { return 30 }
204
205 // ----- 8. verify_against bad input -----
206 let null_plan: *NxInstallPlan = (0 as i64) as *NxInstallPlan
207 if nx_install_hash_verify_against(null_plan, hash_a)
208 != NX_ATTEST_BAD_INPUT { return 31 }
209 if nx_install_hash_verify_against(plan, np)
210 != NX_ATTEST_BAD_INPUT { return 32 }
211
212 // Canary-stomped plan -> BAD_INPUT (refused to recompute).
213 plan.canary_post = 0xDEADBEEF
214 if nx_install_hash_verify_against(plan, hash_a)
215 != NX_ATTEST_BAD_INPUT { return 33 }
216
217 // ----- 9. End-to-end attest loop: hex roundtrip + verify -----
218 // Rebuild plan, capture hash, encode to hex, decode back to
219 // binary, verify the round-tripped binary still matches.
220 let plan2: *NxInstallPlan = nx_install_plan_new()
221 let hash_b: *u8 = sys_mmap(64)
222 if nx_install_pipeline_run_with_inputs(probe, calib, policy,
223 chain, 3, plan2, hash_b)
224 != NX_PIPELINE_OK { return 34 }
225 let hex_b: *u8 = sys_mmap(128)
226 if nx_install_hash_to_hex(hash_b, hex_b) != NX_HEX_OK { return 35 }
227 let hash_b_back: *u8 = sys_mmap(64)
228 if nx_install_hash_from_hex(hex_b, hash_b_back) != NX_HEX_OK { return 36 }
229 if nx_install_hash_verify_against(plan2, hash_b_back)
230 != NX_ATTEST_VERIFIED { return 37 }
231
232 // ----- 10. Sealed-enum gates -----
233 if nx_attest_verdict_is_valid(NX_ATTEST_VERIFIED) != 1 { return 38 }
234 if nx_attest_verdict_is_valid(-1) != 0 { return 39 }
235 if nx_attest_verdict_is_valid(NX_ATTEST_N) != 0 { return 40 }
236
237 return 0
238}