code wiki / (root) / nx_p256_point_test.nx

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}