nx_p256_point_test.nx source
↩ module page · 133 lines · 5306 B
1// nx_p256_point_test.nx -- KAT for P-256 point operations.
2//
3// Verifies:
4// - p256_point_load_b matches FIPS 186-5 §D.2.4 constant b
5// - p256_point_load_g produces a G that satisfies y^2 = x^3 - 3x + b
6// - infinity is on-curve by convention
7// - set_affine + to_affine round-trips coordinates
8// - point_double(infinity) = infinity
9// - point_double(G) is on curve, != G, != infinity
10// - point_double then point_double produces 4G also on curve
11// - point_eq self-equality + infinity vs finite
12// - aliasing (out == in_pt) in point_double
13// - perturbed point (G with x flipped) fails on_curve
14//
15// expect_exit: 0
16// license_tier: ORIGINAL
17
18import "nx_syscalls.nx"
19import "nx_u256.nx"
20import "nx_p256_field.nx"
21import "nx_p256_field_mul.nx"
22import "nx_p256_field_inv.nx"
23import "nx_p256_point.nx"
24
25func main() -> i64 {
26 // ---- Test A: load_b byte-exact (BE bytes against FIPS 186-5) ----
27 let b_8: *i64 = u256_alloc()
28 p256_point_load_b(b_8)
29 let b_bytes: *u8 = sys_mmap(32)
30 u256_store_be(b_bytes, b_8)
31 // Expected BE: 5A C6 35 D8 AA 3A 93 E7 B3 EB BD 55 76 98 86 BC
32 // 65 1D 06 B0 CC 53 B0 F6 3B CE 3C 3E 27 D2 60 4B
33 if (b_bytes[0] & 0xff) != 0x5A { return 1 }
34 if (b_bytes[7] & 0xff) != 0xE7 { return 2 }
35 if (b_bytes[15] & 0xff) != 0xBC { return 3 }
36 if (b_bytes[23] & 0xff) != 0xF6 { return 4 }
37 if (b_bytes[31] & 0xff) != 0x4B { return 5 }
38
39 // ---- Test B: G on curve ----
40 let G: *P256Point = p256_point_alloc()
41 p256_point_load_g(G)
42 if p256_point_on_curve(G) != 1 { return 10 }
43
44 // ---- Test C: Gx + Gy byte-exact ----
45 let gx_bytes: *u8 = sys_mmap(32)
46 let gy_bytes: *u8 = sys_mmap(32)
47 u256_store_be(gx_bytes, G.x)
48 u256_store_be(gy_bytes, G.y)
49 // Expected Gx BE: 6B 17 D1 F2 ... D8 98 C2 96
50 if (gx_bytes[0] & 0xff) != 0x6B { return 20 }
51 if (gx_bytes[3] & 0xff) != 0xF2 { return 21 }
52 if (gx_bytes[28] & 0xff) != 0xD8 { return 22 }
53 if (gx_bytes[31] & 0xff) != 0x96 { return 23 }
54 // Expected Gy BE: 4F E3 42 E2 ... 37 BF 51 F5
55 if (gy_bytes[0] & 0xff) != 0x4F { return 24 }
56 if (gy_bytes[3] & 0xff) != 0xE2 { return 25 }
57 if (gy_bytes[28] & 0xff) != 0x37 { return 26 }
58 if (gy_bytes[31] & 0xff) != 0xF5 { return 27 }
59
60 // ---- Test D: infinity is on-curve by convention ----
61 let O: *P256Point = p256_point_alloc()
62 p256_point_zero(O)
63 if p256_point_is_infinity(O) != 1 { return 30 }
64 if p256_point_on_curve(O) != 1 { return 31 }
65
66 // ---- Test E: set_affine + to_affine round-trip ----
67 let H: *P256Point = p256_point_alloc()
68 p256_point_set_affine(H, G.x, G.y)
69 p256_point_to_affine(H)
70 if p256_field_eq(H.x, G.x) != 1 { return 40 }
71 if p256_field_eq(H.y, G.y) != 1 { return 41 }
72 if u256_is_zero(H.z) == 1 { return 42 }
73 let one: *i64 = u256_alloc()
74 p256_field_one(one)
75 if p256_field_eq(H.z, one) != 1 { return 43 }
76
77 // ---- Test F: point_double(infinity) = infinity ----
78 let two_O: *P256Point = p256_point_alloc()
79 p256_point_double(two_O, O)
80 if p256_point_is_infinity(two_O) != 1 { return 50 }
81
82 // ---- Test G: 2G is on curve, != infinity, != G ----
83 let two_G: *P256Point = p256_point_alloc()
84 p256_point_double(two_G, G)
85 if p256_point_is_infinity(two_G) == 1 { return 60 }
86 p256_point_to_affine(two_G)
87 if p256_point_on_curve(two_G) != 1 { return 61 }
88 if p256_point_eq(two_G, G) == 1 { return 62 }
89
90 // ---- Test H: 4G = double(2G) is on curve, != 2G ----
91 let four_G: *P256Point = p256_point_alloc()
92 p256_point_double(four_G, two_G)
93 p256_point_to_affine(four_G)
94 if p256_point_on_curve(four_G) != 1 { return 70 }
95 if p256_point_eq(four_G, two_G) == 1 { return 71 }
96 if p256_point_eq(four_G, G) == 1 { return 72 }
97
98 // ---- Test I: 8G also on curve ----
99 let eight_G: *P256Point = p256_point_alloc()
100 p256_point_double(eight_G, four_G)
101 p256_point_to_affine(eight_G)
102 if p256_point_on_curve(eight_G) != 1 { return 80 }
103
104 // ---- Test J: point_eq for finite vs infinity ----
105 if p256_point_eq(G, O) == 1 { return 90 }
106 if p256_point_eq(O, G) == 1 { return 91 }
107 if p256_point_eq(O, O) != 1 { return 92 }
108 if p256_point_eq(G, G) != 1 { return 93 }
109
110 // ---- Test K: aliasing -- point_double(P, P) in-place ----
111 let P: *P256Point = p256_point_alloc()
112 p256_point_copy(P, G)
113 p256_point_double(P, P) // P := 2*P (in-place)
114 p256_point_to_affine(P)
115 if p256_point_on_curve(P) != 1 { return 100 }
116 if p256_point_eq(P, two_G) != 1 { return 101 }
117
118 // ---- Test L: perturbed point fails on_curve ----
119 let BAD: *P256Point = p256_point_alloc()
120 p256_point_copy(BAD, G)
121 BAD.x[0] = (BAD.x[0] ^ 1) & 0xFFFFFFFF // flip LSB of x
122 if p256_point_on_curve(BAD) == 1 { return 110 }
123
124 // ---- Test M: verdict gate ----
125 if nx_p256_point_verdict_is_valid(NX_P256_POINT_OK) != 1 { return 120 }
126 if nx_p256_point_verdict_is_valid(NX_P256_POINT_BAD) != 1 { return 121 }
127 if nx_p256_point_verdict_is_valid(NX_P256_POINT_VERDICT_N) != 0 { return 122 }
128 if nx_p256_point_verdict_is_valid(0) != 0 { return 123 }
129 if nx_p256_point_verdict_is_valid(0 - 1) != 0 { return 124 }
130 if nx_p256_point_verdict_is_valid(999) != 0 { return 125 }
131
132 return 0
133}