nx_fec_xor_test.nx source
↩ module page · 90 lines · 3668 B
1// nx_fec_xor_test.nx -- 1:1 KAT for sovereign XOR FEC (nx_fec_xor.nx).
2// Encode a known LxD grid, then prove: row parity recovers random loss,
3// 2-D peeling recovers a burst row-only can't, an over-budget loss is
4// HONESTLY unrecoverable (reported, never corrupted), and redundancy is
5// sized adaptively from the loss estimate.
6//
7// expect_exit: 0
8// license_tier: ORIGINAL
9
10import "nx_fec_xor.nx"
11
12const KL: i64 = 4 // columns
13const KD: i64 = 3 // rows
14const KS: i64 = 4 // bytes/packet
15// K = 12 source packets
16
17func main() -> i64 {
18 let K: i64 = KL * KD
19 let golden: *u8 = sys_mmap(K * KS)
20 let src: *u8 = sys_mmap(K * KS)
21 let rows: *u8 = sys_mmap(KD * KS)
22 let cols: *u8 = sys_mmap(KL * KS)
23 let present: *i64 = sys_mmap(K * 8) as *i64
24 let rp: *i64 = sys_mmap(KD * 8) as *i64
25 let cp: *i64 = sys_mmap(KL * 8) as *i64
26
27 // fill golden with distinct data
28 var i: i64 = 0
29 while i < K * KS { golden[i] = ((i * 7 + 1) & 0xff) as u8; i = i + 1 }
30 // copy -> src, encode repairs from the clean grid
31 i = 0
32 while i < K * KS { src[i] = golden[i]; i = i + 1 }
33 fec_encode_rows(src, KL, KD, KS, rows)
34 fec_encode_cols(src, KL, KD, KS, cols)
35 // repairs all present in every test
36 i = 0
37 while i < KD { rp[i] = 1; i = i + 1 }
38 i = 0
39 while i < KL { cp[i] = 1; i = i + 1 }
40
41 // ---- T1: row parity recovers 1 RANDOM loss per row ----
42 fec_reset(golden, src, present, K, KS)
43 fec_drop(src, present, 2, KS) // row0
44 fec_drop(src, present, 5, KS) // row1
45 fec_drop(src, present, 9, KS) // row2
46 if fec_decode_2d(src, KL, KD, KS, present, rows, rp, cols, cp) != 0 { return 1 }
47 if fec_cmp(golden, src, K * KS) != 0 { return 2 }
48
49 // ---- T2: 2-D peeling recovers a BURST row-parity alone cannot ----
50 fec_reset(golden, src, present, K, KS)
51 fec_drop(src, present, 5, KS) // row1 col1
52 fec_drop(src, present, 6, KS) // row1 col2 (2 in row1 -> rows stuck)
53 if fec_decode_2d(src, KL, KD, KS, present, rows, rp, cols, cp) != 0 { return 3 }
54 if fec_cmp(golden, src, K * KS) != 0 { return 4 }
55
56 // ---- T3: over-budget 2x2 block -> HONESTLY unrecoverable (no corrupt) ----
57 fec_reset(golden, src, present, K, KS)
58 fec_drop(src, present, 5, KS); fec_drop(src, present, 6, KS) // row1 col1,2
59 fec_drop(src, present, 9, KS); fec_drop(src, present, 10, KS) // row2 col1,2
60 if fec_decode_2d(src, KL, KD, KS, present, rows, rp, cols, cp) != 4 { return 5 }
61
62 // ---- T4: adaptive redundancy sized from the loss estimate ----
63 if fec_scheme_for_loss(0) != FEC_NONE { return 6 }
64 if fec_scheme_for_loss(3) != FEC_ROW { return 7 }
65 if fec_scheme_for_loss(10) != FEC_2D { return 8 }
66 if fec_overhead_pct(FEC_ROW, KL, KD) != 25 { return 9 } // 3 row repairs / 12 = 25%
67 if fec_overhead_pct(FEC_2D, KL, KD) != 58 { return 10 } // (3+4)/12 = 58%
68
69 sys_write(1, "FEC-XOR KAT PASS (row recovers random loss, 2-D recovers burst, honest unrecoverable, adaptive sizing)\n", 102)
70 return 0
71}
72
73// helpers (defined after main; prepass registers them)
74func fec_reset(golden: *u8, src: *u8, present: *i64, K: i64, S: i64) -> i64 {
75 var i: i64 = 0
76 while i < K * S { src[i] = golden[i]; i = i + 1 }
77 i = 0
78 while i < K { present[i] = 1; i = i + 1 }
79 return 0
80}
81func fec_drop(src: *u8, present: *i64, idx: i64, S: i64) -> i64 {
82 fec_zero(fec_pkt(src, idx, S), S) // simulate loss = zeroed payload
83 present[idx] = 0
84 return 0
85}
86func fec_cmp(a: *u8, b: *u8, n: i64) -> i64 {
87 var i: i64 = 0
88 while i < n { if (a[i] & 0xff) != (b[i] & 0xff) { return 1 } i = i + 1 }
89 return 0
90}