code wiki / (root) / nx_install_attest_test.nx

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}