nx_etg_probe_cpu_test.nx source
↩ module page · 183 lines · 8881 B
1// nx_etg_probe_cpu_test.nx -- KAT for E3 first real CPU probe.
2//
3// Verifies:
4// T1 Classifier taxonomy: each NX_ETG_OUTCOME_* the classifier
5// can emit is reachable on a deterministic synthetic input.
6// T2 Boundary cases: claim==0, measured==0 -> INCONCLUSIVE.
7// T3 CONFIRMED band: measured within (claim - low%, claim + high%).
8// T4 FALSIFIED: measured > claim * (1 + high/1000).
9// T5 VENDOR_LIED_OMISSION: measured < claim * (1 - low/1000).
10// T6 Real probe end-to-end: invokes nx_calibrate_run on qemu-RV64
11// with a deliberately permissive claim (100,000 ns) and asserts
12// the emitted entry is valid + the outcome is one of the
13// allowed verdicts (CONFIRMED / VENDOR_LIED_OMISSION / FALSIFIED).
14// The exact value of measured is non-deterministic under qemu,
15// so we don't assert on it -- we assert the PIPELINE is real.
16
17import "nx_syscalls.nx"
18import "nx_calibrate.nx"
19import "nx_etg.nx"
20import "nx_etg_probe_cpu.nx"
21
22func main() -> i64 {
23 // ----- T2 Boundary inconclusives -----
24 let o_zc: i64 = nx_etg_classify_outcome(0, 100, 100, 100)
25 if o_zc != NX_ETG_OUTCOME_INCONCLUSIVE { return 1 }
26 let o_zm: i64 = nx_etg_classify_outcome(100, 0, 100, 100)
27 if o_zm != NX_ETG_OUTCOME_INCONCLUSIVE { return 2 }
28
29 // ----- T3 CONFIRMED band -----
30 // claim 100, low 10%, high 10% -> CONFIRMED band [90, 110].
31 let o_eq: i64 = nx_etg_classify_outcome(100, 100, 100, 100)
32 if o_eq != NX_ETG_OUTCOME_CONFIRMED { return 10 }
33 let o_lo_in: i64 = nx_etg_classify_outcome(100, 91, 100, 100)
34 if o_lo_in != NX_ETG_OUTCOME_CONFIRMED { return 11 }
35 let o_hi_in: i64 = nx_etg_classify_outcome(100, 109, 100, 100)
36 if o_hi_in != NX_ETG_OUTCOME_CONFIRMED { return 12 }
37
38 // ----- T4 FALSIFIED above tolerance -----
39 let o_fal: i64 = nx_etg_classify_outcome(100, 150, 100, 100)
40 if o_fal != NX_ETG_OUTCOME_FALSIFIED { return 20 }
41 // Just above the boundary: 111 > 110 (= 100 * 1.10).
42 let o_fal_edge: i64 = nx_etg_classify_outcome(100, 111, 100, 100)
43 if o_fal_edge != NX_ETG_OUTCOME_FALSIFIED { return 21 }
44
45 // ----- T5 VENDOR_LIED_OMISSION below tolerance -----
46 let o_lied: i64 = nx_etg_classify_outcome(100, 50, 100, 100)
47 if o_lied != NX_ETG_OUTCOME_VENDOR_LIED_OMISSION { return 30 }
48 // Just below the boundary: 89 < 90 (= 100 * 0.90).
49 let o_lied_edge: i64 = nx_etg_classify_outcome(100, 89, 100, 100)
50 if o_lied_edge != NX_ETG_OUTCOME_VENDOR_LIED_OMISSION { return 31 }
51
52 // ----- T1 Taxonomy reachability (covered by T2-T5) -----
53 // Already exercised: INCONCLUSIVE, CONFIRMED, FALSIFIED, VENDOR_LIED_OMISSION.
54 // Remaining outcomes (THROTTLED / FUSED_OFF / RECLAIMED / etc.) require
55 // probe-family-specific classifier extensions; queued per per-probe brick.
56
57 // ----- T6 Real probe end-to-end on qemu-RV64 -----
58 let e_buf: *u8 = sys_mmap(128)
59 let e: *NxEtgEntry = e_buf as *NxEtgEntry
60 // Claim 100_000 ns (100 μs) -- generous so qemu measurement
61 // doesn't FALSIFY by exceeding tolerance. Tolerances 90% / 90%
62 // so the band is very wide; expected outcomes are CONFIRMED or
63 // VENDOR_LIED_OMISSION on qemu (which is much faster than 100μs
64 // for a clock_gettime syscall).
65 let outcome: i64 = nx_etg_probe_cpu_syscall_roundtrip(
66 100000, // claim_ns: 100 μs
67 900, // low_thresh_per_1000 = 90% (claim*0.10 = 10_000 ns floor)
68 900, // high_thresh_per_1000 = 90%
69 e,
70 0xC0DEC0DE, // silicon serial (synthetic for KAT)
71 1, // selector version
72 20260520 // timestamp Q14 (2026-05-20 sentinel)
73 )
74 // Outcome must be one of the valid verdicts the classifier can emit.
75 if nx_etg_outcome_is_valid(outcome) != 1 { return 40 }
76 // Outcome must specifically be CONFIRMED, VENDOR_LIED_OMISSION,
77 // FALSIFIED, or INCONCLUSIVE (the four the classifier can emit
78 // from a clean run).
79 var ok: i64 = 0
80 if outcome == NX_ETG_OUTCOME_CONFIRMED { ok = 1 }
81 if outcome == NX_ETG_OUTCOME_VENDOR_LIED_OMISSION { ok = 1 }
82 if outcome == NX_ETG_OUTCOME_FALSIFIED { ok = 1 }
83 if outcome == NX_ETG_OUTCOME_INCONCLUSIVE { ok = 1 }
84 if ok != 1 { return 41 }
85 // Entry was written with the claim we passed.
86 if e.claim_value != 100000 { return 42 }
87 if e.probe_kind != NX_ETG_PROBE_CPU_SYSCALL { return 43 }
88 if e.claim_source != NX_ETG_CLAIM_VENDOR_DOC { return 44 }
89 if e.silicon_serial_hash != 0xC0DEC0DE { return 45 }
90 if e.outcome != outcome { return 46 }
91 // Attestation hash deterministic + non-zero.
92 if e.attestation_hash == 0 { return 47 }
93
94 // ----- T7 Real probe: int_alu dependent-chain throughput -----
95 let e7_buf: *u8 = sys_mmap(128)
96 let e7: *NxEtgEntry = e7_buf as *NxEtgEntry
97 // Generous claim 100,000 ps/op (= 100 ns/op) with wide tolerance.
98 // qemu emulation makes ADD considerably slower than native silicon
99 // but the measured value should still be a positive integer.
100 let outcome7: i64 = nx_etg_probe_cpu_int_alu(
101 100000, 990, 9000, e7, 0xC0DEC0DE, 1, 20260520
102 )
103 if nx_etg_outcome_is_valid(outcome7) != 1 { return 50 }
104 if e7.probe_kind != NX_ETG_PROBE_CPU_ISA { return 51 }
105 if e7.claim_source != NX_ETG_CLAIM_VENDOR_DOC { return 52 }
106 if e7.claim_value != 100000 { return 53 }
107 if e7.measurement_value <= 0 { return 54 }
108 if e7.outcome != outcome7 { return 55 }
109 if e7.attestation_hash == 0 { return 56 }
110
111 // ----- T8 Real probe: linear memory-copy bandwidth -----
112 let e8_buf: *u8 = sys_mmap(128)
113 let e8: *NxEtgEntry = e8_buf as *NxEtgEntry
114 // Claim 100 MiB/s with wide tolerance band; qemu emulation is much
115 // slower than native, so we accept any outcome and just gate on
116 // pipeline validity.
117 let outcome8: i64 = nx_etg_probe_cpu_mem_bw(
118 100, 900, 9000, e8, 0xC0DEC0DE, 1, 20260520
119 )
120 if nx_etg_outcome_is_valid(outcome8) != 1 { return 60 }
121 if e8.probe_kind != NX_ETG_PROBE_STORAGE_RAM { return 61 }
122 if e8.claim_source != NX_ETG_CLAIM_VENDOR_DOC { return 62 }
123 if e8.claim_value != 100 { return 63 }
124 if e8.measurement_value < 0 { return 64 }
125 if e8.outcome != outcome8 { return 65 }
126 if e8.attestation_hash == 0 { return 66 }
127
128 // T9 cross-probe-attestation: e (syscall) and e7 (int_alu) carry
129 // different probe_kinds + measurement_values + outcomes -> their
130 // attestation hashes differ (no cross-probe aliasing).
131 if e.attestation_hash == e7.attestation_hash { return 70 }
132 if e7.attestation_hash == e8.attestation_hash { return 71 }
133 if e.attestation_hash == e8.attestation_hash { return 72 }
134
135 // ----- T10 Real probe: L1 cache latency -----
136 let e10_buf: *u8 = sys_mmap(128)
137 let e10: *NxEtgEntry = e10_buf as *NxEtgEntry
138 // Claim 100 ns with very wide tolerance. Real L1 hit latency
139 // on native silicon is ~1-2 ns; under qemu it's much higher.
140 let outcome10: i64 = nx_etg_probe_cpu_cache_l1(
141 100, 990, 9000, e10, 0xC0DEC0DE, 1, 20260520
142 )
143 if nx_etg_outcome_is_valid(outcome10) != 1 { return 80 }
144 if e10.probe_kind != NX_ETG_PROBE_CPU_CACHE { return 81 }
145 if e10.measurement_value < 0 { return 82 }
146 if e10.outcome != outcome10 { return 83 }
147
148 // ----- T11 Real probe: L2 cache latency -----
149 let e11_buf: *u8 = sys_mmap(128)
150 let e11: *NxEtgEntry = e11_buf as *NxEtgEntry
151 let outcome11: i64 = nx_etg_probe_cpu_cache_l2(
152 100, 990, 9000, e11, 0xC0DEC0DE, 1, 20260520
153 )
154 if nx_etg_outcome_is_valid(outcome11) != 1 { return 90 }
155 if e11.probe_kind != NX_ETG_PROBE_CPU_CACHE { return 91 }
156 if e11.measurement_value < 0 { return 92 }
157
158 // ----- T12 Real probe: RAM access latency -----
159 let e12_buf: *u8 = sys_mmap(128)
160 let e12: *NxEtgEntry = e12_buf as *NxEtgEntry
161 let outcome12: i64 = nx_etg_probe_cpu_cache_ram(
162 100, 990, 9000, e12, 0xC0DEC0DE, 1, 20260520
163 )
164 if nx_etg_outcome_is_valid(outcome12) != 1 { return 100 }
165 if e12.probe_kind != NX_ETG_PROBE_STORAGE_RAM { return 101 }
166 if e12.measurement_value < 0 { return 102 }
167
168 // ----- T13 Cache hierarchy monotone sanity: L1 <= L2 <= RAM -----
169 // The substrate's empirical measurement of the cache hierarchy
170 // should observe L1 latency <= L2 latency <= RAM latency. If
171 // the silicon (or qemu) reports otherwise, the cost model picks
172 // it up via INCONCLUSIVE classification across replicas. For
173 // this KAT we just sanity-check the ordering is plausible
174 // (not strict equality, since qemu noise can flip nearby tiers).
175 if e10.measurement_value > 0 {
176 if e12.measurement_value > 0 {
177 // L1 should be no slower than RAM by a wide margin.
178 if e10.measurement_value > e12.measurement_value * 2 { return 110 }
179 }
180 }
181
182 return 0
183}