nx_ecdsa_p256_test.nx source
↩ module page · 141 lines · 7011 B
1// nx_ecdsa_p256_test.nx -- KAT for ECDSA signature verification.
2//
3// Test vector: RFC 6979 §A.2.5 (NIST P-256 + SHA-256, msg = "sample")
4//
5// Pubkey:
6// x = 60FED4BA255A9D31C961EB74C6356D68
7// C049B8923B61FA6CE669622E60F29FB6
8// y = 7903FE1008B8BC99A41AE9E95628BC64
9// F2F1B20C2D7E9F5177A3C294D4462299
10//
11// msg = "sample"
12// SHA-256(msg) = AF2BDBE1AA9B6EC1E2ADE1D694F41FC7
13// 1A831D0268E9891562113D8A62ADD1BF
14//
15// Sig (deterministic per RFC 6979):
16// r = EFD48B2AACB6A8FD1140DD9CD45E81D6
17// 9D2C877B56AAF991C34D0EA84EAF3716
18// s = F7CB1C942D657C41D436C7A1B6E29F65
19// F3E900DBB9AFF4064DC4AB2F843ACDA8
20//
21// expect_exit: 0
22// license_tier: ORIGINAL
23
24import "nx_syscalls.nx"
25import "nx_u256.nx"
26import "nx_p256_field.nx"
27import "nx_p256_modn.nx"
28import "nx_ecdsa_p256.nx"
29
30func main() -> i64 {
31 // ---- Build all RFC 6979 §A.2.5 inputs as BE byte buffers ----
32
33 // Pubkey x
34 let qx_bytes: *u8 = sys_mmap(32)
35 qx_bytes[0] = 0x60; qx_bytes[1] = 0xFE; qx_bytes[2] = 0xD4; qx_bytes[3] = 0xBA
36 qx_bytes[4] = 0x25; qx_bytes[5] = 0x5A; qx_bytes[6] = 0x9D; qx_bytes[7] = 0x31
37 qx_bytes[8] = 0xC9; qx_bytes[9] = 0x61; qx_bytes[10] = 0xEB; qx_bytes[11] = 0x74
38 qx_bytes[12] = 0xC6; qx_bytes[13] = 0x35; qx_bytes[14] = 0x6D; qx_bytes[15] = 0x68
39 qx_bytes[16] = 0xC0; qx_bytes[17] = 0x49; qx_bytes[18] = 0xB8; qx_bytes[19] = 0x92
40 qx_bytes[20] = 0x3B; qx_bytes[21] = 0x61; qx_bytes[22] = 0xFA; qx_bytes[23] = 0x6C
41 qx_bytes[24] = 0xE6; qx_bytes[25] = 0x69; qx_bytes[26] = 0x62; qx_bytes[27] = 0x2E
42 qx_bytes[28] = 0x60; qx_bytes[29] = 0xF2; qx_bytes[30] = 0x9F; qx_bytes[31] = 0xB6
43
44 // Pubkey y
45 let qy_bytes: *u8 = sys_mmap(32)
46 qy_bytes[0] = 0x79; qy_bytes[1] = 0x03; qy_bytes[2] = 0xFE; qy_bytes[3] = 0x10
47 qy_bytes[4] = 0x08; qy_bytes[5] = 0xB8; qy_bytes[6] = 0xBC; qy_bytes[7] = 0x99
48 qy_bytes[8] = 0xA4; qy_bytes[9] = 0x1A; qy_bytes[10] = 0xE9; qy_bytes[11] = 0xE9
49 qy_bytes[12] = 0x56; qy_bytes[13] = 0x28; qy_bytes[14] = 0xBC; qy_bytes[15] = 0x64
50 qy_bytes[16] = 0xF2; qy_bytes[17] = 0xF1; qy_bytes[18] = 0xB2; qy_bytes[19] = 0x0C
51 qy_bytes[20] = 0x2D; qy_bytes[21] = 0x7E; qy_bytes[22] = 0x9F; qy_bytes[23] = 0x51
52 qy_bytes[24] = 0x77; qy_bytes[25] = 0xA3; qy_bytes[26] = 0xC2; qy_bytes[27] = 0x94
53 qy_bytes[28] = 0xD4; qy_bytes[29] = 0x46; qy_bytes[30] = 0x22; qy_bytes[31] = 0x99
54
55 // SHA-256("sample")
56 let e_bytes: *u8 = sys_mmap(32)
57 e_bytes[0] = 0xAF; e_bytes[1] = 0x2B; e_bytes[2] = 0xDB; e_bytes[3] = 0xE1
58 e_bytes[4] = 0xAA; e_bytes[5] = 0x9B; e_bytes[6] = 0x6E; e_bytes[7] = 0xC1
59 e_bytes[8] = 0xE2; e_bytes[9] = 0xAD; e_bytes[10] = 0xE1; e_bytes[11] = 0xD6
60 e_bytes[12] = 0x94; e_bytes[13] = 0xF4; e_bytes[14] = 0x1F; e_bytes[15] = 0xC7
61 e_bytes[16] = 0x1A; e_bytes[17] = 0x83; e_bytes[18] = 0x1D; e_bytes[19] = 0x02
62 e_bytes[20] = 0x68; e_bytes[21] = 0xE9; e_bytes[22] = 0x89; e_bytes[23] = 0x15
63 e_bytes[24] = 0x62; e_bytes[25] = 0x11; e_bytes[26] = 0x3D; e_bytes[27] = 0x8A
64 e_bytes[28] = 0x62; e_bytes[29] = 0xAD; e_bytes[30] = 0xD1; e_bytes[31] = 0xBF
65
66 // Signature r
67 let r_bytes: *u8 = sys_mmap(32)
68 r_bytes[0] = 0xEF; r_bytes[1] = 0xD4; r_bytes[2] = 0x8B; r_bytes[3] = 0x2A
69 r_bytes[4] = 0xAC; r_bytes[5] = 0xB6; r_bytes[6] = 0xA8; r_bytes[7] = 0xFD
70 r_bytes[8] = 0x11; r_bytes[9] = 0x40; r_bytes[10] = 0xDD; r_bytes[11] = 0x9C
71 r_bytes[12] = 0xD4; r_bytes[13] = 0x5E; r_bytes[14] = 0x81; r_bytes[15] = 0xD6
72 r_bytes[16] = 0x9D; r_bytes[17] = 0x2C; r_bytes[18] = 0x87; r_bytes[19] = 0x7B
73 r_bytes[20] = 0x56; r_bytes[21] = 0xAA; r_bytes[22] = 0xF9; r_bytes[23] = 0x91
74 r_bytes[24] = 0xC3; r_bytes[25] = 0x4D; r_bytes[26] = 0x0E; r_bytes[27] = 0xA8
75 r_bytes[28] = 0x4E; r_bytes[29] = 0xAF; r_bytes[30] = 0x37; r_bytes[31] = 0x16
76
77 // Signature s
78 let s_bytes: *u8 = sys_mmap(32)
79 s_bytes[0] = 0xF7; s_bytes[1] = 0xCB; s_bytes[2] = 0x1C; s_bytes[3] = 0x94
80 s_bytes[4] = 0x2D; s_bytes[5] = 0x65; s_bytes[6] = 0x7C; s_bytes[7] = 0x41
81 s_bytes[8] = 0xD4; s_bytes[9] = 0x36; s_bytes[10] = 0xC7; s_bytes[11] = 0xA1
82 s_bytes[12] = 0xB6; s_bytes[13] = 0xE2; s_bytes[14] = 0x9F; s_bytes[15] = 0x65
83 s_bytes[16] = 0xF3; s_bytes[17] = 0xE9; s_bytes[18] = 0x00; s_bytes[19] = 0xDB
84 s_bytes[20] = 0xB9; s_bytes[21] = 0xAF; s_bytes[22] = 0xF4; s_bytes[23] = 0x06
85 s_bytes[24] = 0x4D; s_bytes[25] = 0xC4; s_bytes[26] = 0xAB; s_bytes[27] = 0x2F
86 s_bytes[28] = 0x84; s_bytes[29] = 0x3A; s_bytes[30] = 0xCD; s_bytes[31] = 0xA8
87
88 // Load into U256 limbs
89 let qx: *i64 = u256_alloc()
90 let qy: *i64 = u256_alloc()
91 let e: *i64 = u256_alloc()
92 let r: *i64 = u256_alloc()
93 let s: *i64 = u256_alloc()
94 u256_load_be(qx, qx_bytes)
95 u256_load_be(qy, qy_bytes)
96 u256_load_be(e, e_bytes)
97 u256_load_be(r, r_bytes)
98 u256_load_be(s, s_bytes)
99
100 // ---- Test A: positive verify -- RFC 6979 §A.2.5 sig is valid ----
101 // <-- THE BIG ONE: first end-to-end ECDSA-P256 verify in our substrate
102 let v: i64 = nx_ecdsa_p256_verify(qx, qy, e, r, s)
103 if v != NX_ECDSA_OK { return 1 }
104
105 // ---- Test B: range check -- r = 0 rejected ----
106 let zero: *i64 = u256_alloc()
107 u256_zero(zero)
108 if nx_ecdsa_p256_verify(qx, qy, e, zero, s) != NX_ECDSA_BAD_R_RANGE { return 10 }
109
110 // ---- Test C: range check -- s = 0 rejected ----
111 if nx_ecdsa_p256_verify(qx, qy, e, r, zero) != NX_ECDSA_BAD_S_RANGE { return 20 }
112
113 // ---- Test D: range check -- r = n rejected ----
114 let n: *i64 = u256_alloc()
115 p256_modn_load_n(n)
116 if nx_ecdsa_p256_verify(qx, qy, e, n, s) != NX_ECDSA_BAD_R_RANGE { return 30 }
117
118 // ---- Test E: range check -- s = n rejected ----
119 if nx_ecdsa_p256_verify(qx, qy, e, r, n) != NX_ECDSA_BAD_S_RANGE { return 40 }
120
121 // ---- Test F: off-curve pubkey rejected ----
122 let qx_bad: *i64 = u256_alloc()
123 u256_copy(qx_bad, qx)
124 qx_bad[0] = qx_bad[0] ^ 1 // flip LSB of x
125 if nx_ecdsa_p256_verify(qx_bad, qy, e, r, s) != NX_ECDSA_PUBKEY_NOT_ON_CURVE { return 50 }
126
127 // ---- Test G: verdict gate ----
128 if nx_ecdsa_p256_verdict_is_valid(NX_ECDSA_OK) != 1 { return 60 }
129 if nx_ecdsa_p256_verdict_is_valid(NX_ECDSA_BAD_R_RANGE) != 1 { return 61 }
130 if nx_ecdsa_p256_verdict_is_valid(NX_ECDSA_BAD_S_RANGE) != 1 { return 62 }
131 if nx_ecdsa_p256_verdict_is_valid(NX_ECDSA_PUBKEY_NOT_ON_CURVE) != 1 { return 63 }
132 if nx_ecdsa_p256_verdict_is_valid(NX_ECDSA_PUBKEY_INFINITY) != 1 { return 64 }
133 if nx_ecdsa_p256_verdict_is_valid(NX_ECDSA_INFINITY_RESULT) != 1 { return 65 }
134 if nx_ecdsa_p256_verdict_is_valid(NX_ECDSA_BAD_SIG) != 1 { return 66 }
135 if nx_ecdsa_p256_verdict_is_valid(NX_ECDSA_VERDICT_N) != 0 { return 67 }
136 if nx_ecdsa_p256_verdict_is_valid(0) != 0 { return 68 }
137 if nx_ecdsa_p256_verdict_is_valid(0 - 1) != 0 { return 69 }
138 if nx_ecdsa_p256_verdict_is_valid(999) != 0 { return 70 }
139
140 return 0
141}