code wiki / (root) / nx_ed25519_arith_test.nx

nx_ed25519_arith_test.nx source

↩ module page · 110 lines · 3641 B

1// nx_ed25519_arith_test.nx -- KAT for Edwards-curve arithmetic. 2// 3// Verifies: 4// A. Identity point (0, 1, 1, 0) compresses to canonical y=1, 5// sign-x=0 encoding (byte 0 = 0x01, all others 0) 6// B. P + (-P) == identity (via compressed equality) 7// C. P + identity == P (identity is the additive neutral) 8// D. double(B) == B + B (where B = Ed25519 basepoint) 9// E. double(B) is on the curve 10// F. Triple via add(double(B), B) == B + B + B (associativity check) 11// G. Compress(decompress(B_bytes)) == B_bytes (round-trip via the 12// basepoint canonical encoding 5866...66) 13// 14// expect_exit: 0 15// license_tier: ORIGINAL 16 17import "nx_syscalls.nx" 18import "nx_x25519.nx" 19import "nx_ed25519_field.nx" 20import "nx_ed25519_point.nx" 21import "nx_ed25519_arith.nx" 22 23func main() -> i64 { 24 // ---- Test A: identity encoding ---- 25 let id_pt: *GeP3 = ge_p3_alloc() 26 ge_p3_identity(id_pt) 27 let id_bytes: *u8 = sys_mmap(32) 28 ge_p3_compress(id_bytes, id_pt) 29 // Expected: byte 0 = 0x01 (y=1 LE), bytes 1..31 all 0 (sign bit = 0 since x=0) 30 if (id_bytes[0] & 0xff) != 0x01 { return 1 } 31 var ic: i64 = 1 32 while ic < 32 { 33 if (id_bytes[ic] & 0xff) != 0 { return 2 } 34 ic = ic + 1 35 } 36 37 // ---- Test B: P + (-P) == identity ---- 38 // Use Ed25519 basepoint as P 39 let bp_bytes: *u8 = sys_mmap(64) 40 bp_bytes[0] = 0x58 41 var bi: i64 = 1 42 while bi < 32 { 43 bp_bytes[bi] = 0x66 44 bi = bi + 1 45 } 46 let B: *GeP3 = ge_p3_alloc() 47 let dc1: i64 = ge_p3_decompress(B, bp_bytes) 48 if dc1 != NX_GE_VERDICT_OK { return 10 } 49 50 let neg_B: *GeP3 = ge_p3_alloc() 51 ge_p3_negate(neg_B, B) 52 53 let sum_zero: *GeP3 = ge_p3_alloc() 54 ge_p3_add(sum_zero, B, neg_B) 55 56 if ge_p3_equal(sum_zero, id_pt) != 1 { return 20 } 57 58 // ---- Test C: P + identity == P ---- 59 let p_plus_id: *GeP3 = ge_p3_alloc() 60 ge_p3_add(p_plus_id, B, id_pt) 61 if ge_p3_equal(p_plus_id, B) != 1 { return 30 } 62 63 // ---- Test D: double(B) == B + B ---- 64 let dB: *GeP3 = ge_p3_alloc() 65 ge_p3_double(dB, B) 66 let BplusB: *GeP3 = ge_p3_alloc() 67 ge_p3_add(BplusB, B, B) 68 if ge_p3_equal(dB, BplusB) != 1 { return 40 } 69 70 // ---- Test E: double(B) is on the curve ---- 71 // ge_p3_on_curve only handles Z=1; normalize dB by compress + decompress 72 let dB_bytes: *u8 = sys_mmap(32) 73 ge_p3_compress(dB_bytes, dB) 74 let dB_norm: *GeP3 = ge_p3_alloc() 75 let dc2: i64 = ge_p3_decompress(dB_norm, dB_bytes) 76 if dc2 != NX_GE_VERDICT_OK { return 50 } 77 if ge_p3_on_curve(dB_norm) != 1 { return 51 } 78 79 // ---- Test F: 3B via two paths ---- 80 // Path 1: 2B + B = (double(B)) + B 81 let tripleA: *GeP3 = ge_p3_alloc() 82 ge_p3_add(tripleA, dB, B) 83 // Path 2: (B + B) + B 84 let tripleB: *GeP3 = ge_p3_alloc() 85 ge_p3_add(tripleB, BplusB, B) 86 if ge_p3_equal(tripleA, tripleB) != 1 { return 60 } 87 88 // ---- Test G: B round-trips through compress(decompress) ---- 89 let B_round: *u8 = sys_mmap(32) 90 ge_p3_compress(B_round, B) 91 var ri: i64 = 0 92 while ri < 32 { 93 if (B_round[ri] & 0xff) != (bp_bytes[ri] & 0xff) { return 70 + (ri & 0x1f) } 94 ri = ri + 1 95 } 96 97 // ---- Test H: double(identity) == identity ---- 98 let dId: *GeP3 = ge_p3_alloc() 99 ge_p3_double(dId, id_pt) 100 if ge_p3_equal(dId, id_pt) != 1 { return 110 } 101 102 // ---- Test I: 4P via double(double(P)) == 2*(2*P) ---- 103 let ddB: *GeP3 = ge_p3_alloc() 104 ge_p3_double(ddB, dB) // 4B = double(2B) 105 let twice_dB: *GeP3 = ge_p3_alloc() 106 ge_p3_add(twice_dB, dB, dB) // 4B = 2B + 2B 107 if ge_p3_equal(ddB, twice_dB) != 1 { return 120 } 108 109 return 0 110}