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}