nx_ecdsa_p384_bisect_test.nx source
↩ module page · 241 lines · 8191 B
1// nx_ecdsa_p384_bisect_test.nx -- bisect the verify failure on
2// RFC 6979 §A.2.6. Compares each substrate intermediate to the
3// Python golden bytes. Exit code identifies the first divergent
4// step.
5//
6// Step verdicts (returned as exit code):
7// 0 -- all steps match (verify would pass)
8// 1 -- s_inv diverges (p384_modn_inv broken at this scale)
9// 2 -- u1 diverges (p384_modn_mul broken or e_n wrong)
10// 3 -- u2 diverges (same primitives, different input)
11// 4 -- u1G.x diverges (scalar_mul or point_add broken)
12// 5 -- u2Q.x diverges (same scalar_mul, non-G base)
13//
14// expect_exit: 0
15// license_tier: ORIGINAL
16
17import "nx_syscalls.nx"
18import "nx_u384.nx"
19import "nx_p384_field.nx"
20import "nx_p384_field_mul.nx"
21import "nx_p384_field_inv.nx"
22import "nx_p384_modn.nx"
23import "nx_p384_point.nx"
24import "nx_p384_point_add.nx"
25import "nx_p384_scalar_mul.nx"
26import "nx_ecdsa_p384.nx"
27
28func dump_hex(label0: i64, label1: i64, buf: *i64) -> i64 {
29 let lab: *u8 = sys_mmap(8)
30 lab[0]=label0 as u8; lab[1]=label1 as u8; lab[2]=0x3D
31 sys_write(2, lab, 3)
32 var li: i64 = 11
33 while li >= 0 {
34 var bi: i64 = 0
35 while bi < 4 {
36 let b: i64 = (buf[li] >> ((3 - bi) * 8)) & 0xff
37 let hi: i64 = (b >> 4) & 0xf
38 let lo: i64 = b & 0xf
39 let chh: *u8 = sys_mmap(8)
40 if hi < 10 { chh[0] = (0x30 + hi) as u8 } else { chh[0] = (0x61 + hi - 10) as u8 }
41 if lo < 10 { chh[1] = (0x30 + lo) as u8 } else { chh[1] = (0x61 + lo - 10) as u8 }
42 sys_write(2, chh, 2)
43 bi = bi + 1
44 }
45 li = li - 1
46 }
47 let nl: *u8 = sys_mmap(8); nl[0]=0x0A; sys_write(2, nl, 1)
48 return 0
49}
50
51func limbs_eq(a: *i64, b: *i64) -> i64 {
52 var i: i64 = 0
53 while i < 12 {
54 if (a[i] & 0xFFFFFFFF) != (b[i] & 0xFFFFFFFF) { return 0 }
55 i = i + 1
56 }
57 return 1
58}
59
60func main() -> i64 {
61 // ---- Load inputs ----
62 let pub_x: *i64 = u384_alloc()
63 pub_x[0]=0x5480BC13; pub_x[1]=0x64A25451; pub_x[2]=0x90558660; pub_x[3]=0xDEF8F0EA
64 pub_x[4]=0x6B300C64; pub_x[5]=0x06AAE528; pub_x[6]=0xAE92E02E; pub_x[7]=0xDA9A8BC4
65 pub_x[8]=0x9F427FA5; pub_x[9]=0x56861802; pub_x[10]=0x5B4E19A4; pub_x[11]=0xEC3A4E41
66
67 let pub_y: *i64 = u384_alloc()
68 pub_y[0]=0x33264720; pub_y[1]=0x7344FD25; pub_y[2]=0x3AE0D4FE; pub_y[3]=0x288B231C
69 pub_y[4]=0x3F1C9DB1; pub_y[5]=0xF54CA84B; pub_y[6]=0x67F9DFB9; pub_y[7]=0x6708A593
70 pub_y[8]=0xC0C62189; pub_y[9]=0x4EA8EF9A; pub_y[10]=0x2D7D5724; pub_y[11]=0x8015D9B7
71
72 let e: *i64 = u384_alloc()
73 e[0]=0x62ADD1BF; e[1]=0x62113D8A; e[2]=0x68E98915; e[3]=0x1A831D02
74 e[4]=0x94F41FC7; e[5]=0xE2ADE1D6; e[6]=0xAA9B6EC1; e[7]=0xAF2BDBE1
75
76 let sig_r: *i64 = u384_alloc()
77 sig_r[0]=0x6D8FB2CD; sig_r[1]=0x2FA2B3C3; sig_r[2]=0xE63355D9; sig_r[3]=0xBDE1E888
78 sig_r[4]=0x1D3DAA33; sig_r[5]=0x354B63A2; sig_r[6]=0x98D4EA8E; sig_r[7]=0x0C570C6F
79 sig_r[8]=0xF99AF8B3; sig_r[9]=0x392D03C5; sig_r[10]=0x013C7FA1; sig_r[11]=0x21B13D1E
80
81 let sig_s: *i64 = u384_alloc()
82 sig_s[0]=0xA4FA0AB0; sig_s[1]=0xC0CB8668; sig_s[2]=0xCD1AC42E; sig_s[3]=0xEFDC63EC
83 sig_s[4]=0xA7D1FEEB; sig_s[5]=0x5DB2266F; sig_s[6]=0xCA67E3D4; sig_s[7]=0x32068A10
84 sig_s[8]=0x38916746; sig_s[9]=0xF4BD77CB; sig_s[10]=0xB107745B; sig_s[11]=0xF3AA443F
85
86 // ---- STEP 1: s_inv = s^(-1) mod n ----
87 let s_inv: *i64 = u384_alloc()
88 p384_modn_inv(s_inv, sig_s)
89 dump_hex(0x53, 0x49, s_inv)
90
91 let exp_s_inv: *i64 = u384_alloc()
92 exp_s_inv[0]=0xe78e2687
93 exp_s_inv[1]=0x831fb3fe
94 exp_s_inv[2]=0x62385ee3
95 exp_s_inv[3]=0xaf3e45c1
96 exp_s_inv[4]=0xfabb0e2f
97 exp_s_inv[5]=0x83e00ecf
98 exp_s_inv[6]=0x0ee27ee4
99 exp_s_inv[7]=0x8c968272
100 exp_s_inv[8]=0x72039531
101 exp_s_inv[9]=0xb57d6d77
102 exp_s_inv[10]=0xbeec8854
103 exp_s_inv[11]=0xe6cb2626
104 if limbs_eq(s_inv, exp_s_inv) != 1 { return 1 }
105
106 // ---- STEP 2: u1 = e_n * s_inv mod n ----
107 let e_n: *i64 = u384_alloc()
108 p384_modn_reduce(e_n, e)
109 let u1: *i64 = u384_alloc()
110 p384_modn_mul(u1, e_n, s_inv)
111 dump_hex(0x55, 0x31, u1)
112
113 let exp_u1: *i64 = u384_alloc()
114 exp_u1[0]=0xc5e00ea7
115 exp_u1[1]=0x066146d0
116 exp_u1[2]=0xb0054274
117 exp_u1[3]=0xd654dcc9
118 exp_u1[4]=0x357ff82f
119 exp_u1[5]=0xe784cad5
120 exp_u1[6]=0x41ebcc1c
121 exp_u1[7]=0x66552301
122 exp_u1[8]=0x77b78df4
123 exp_u1[9]=0xcc728ec1
124 exp_u1[10]=0xb913ac04
125 exp_u1[11]=0xf3574de6
126 if limbs_eq(u1, exp_u1) != 1 { return 2 }
127
128 // ---- STEP 3: u2 = r * s_inv mod n ----
129 let u2: *i64 = u384_alloc()
130 p384_modn_mul(u2, sig_r, s_inv)
131 dump_hex(0x55, 0x32, u2)
132
133 let exp_u2: *i64 = u384_alloc()
134 exp_u2[0]=0xee3a224e
135 exp_u2[1]=0x898092eb
136 exp_u2[2]=0x3c02fc43
137 exp_u2[3]=0x435e1d63
138 exp_u2[4]=0xd8c5f562
139 exp_u2[5]=0x85fa3dcc
140 exp_u2[6]=0x09a6ea23
141 exp_u2[7]=0xcf5641a1
142 exp_u2[8]=0xf9783c07
143 exp_u2[9]=0x7e854369
144 exp_u2[10]=0xf3af5e11
145 exp_u2[11]=0x1fcfa37d
146 if limbs_eq(u2, exp_u2) != 1 { return 3 }
147
148 // ---- STEP 4: u1*G ---- ORCHESTRATOR MODE: leave Jacobian ----
149 let G: *P384Point = p384_point_alloc()
150 p384_point_load_g(G)
151 let u1G: *P384Point = p384_point_alloc()
152 p384_scalar_mul(u1G, u1, G)
153 // ORCHESTRATOR DOES NOT to_affine HERE -- snapshot a copy for affine check
154 let u1G_aff: *P384Point = p384_point_alloc()
155 p384_point_copy(u1G_aff, u1G)
156 p384_point_to_affine(u1G_aff)
157 dump_hex(0x47, 0x58, u1G_aff.x)
158
159 let exp_u1G_x: *i64 = u384_alloc()
160 exp_u1G_x[0]=0x5ce352f3
161 exp_u1G_x[1]=0x3f6a4b93
162 exp_u1G_x[2]=0x1615d28c
163 exp_u1G_x[3]=0x0ec5746d
164 exp_u1G_x[4]=0x7cebcfd6
165 exp_u1G_x[5]=0xabfeb127
166 exp_u1G_x[6]=0x8ce6be30
167 exp_u1G_x[7]=0x5632cb7a
168 exp_u1G_x[8]=0x1a016ef0
169 exp_u1G_x[9]=0xe8906341
170 exp_u1G_x[10]=0xba788535
171 exp_u1G_x[11]=0xd64326e9
172 if limbs_eq(u1G_aff.x, exp_u1G_x) != 1 { return 4 }
173
174 // ---- STEP 5: u2*Q ---- ORCHESTRATOR MODE: leave Jacobian ----
175 let Q: *P384Point = p384_point_alloc()
176 p384_point_set_affine(Q, pub_x, pub_y)
177 let u2Q: *P384Point = p384_point_alloc()
178 p384_scalar_mul(u2Q, u2, Q)
179 let u2Q_aff: *P384Point = p384_point_alloc()
180 p384_point_copy(u2Q_aff, u2Q)
181 p384_point_to_affine(u2Q_aff)
182 dump_hex(0x51, 0x58, u2Q_aff.x)
183
184 let exp_u2Q_x: *i64 = u384_alloc()
185 exp_u2Q_x[0]=0xced576e0
186 exp_u2Q_x[1]=0xeb337a17
187 exp_u2Q_x[2]=0x3ea103a6
188 exp_u2Q_x[3]=0xaa404121
189 exp_u2Q_x[4]=0x6feff612
190 exp_u2Q_x[5]=0x1c097d31
191 exp_u2Q_x[6]=0xa59259b7
192 exp_u2Q_x[7]=0x1808dcde
193 exp_u2Q_x[8]=0xd987cde4
194 exp_u2Q_x[9]=0x69c1180e
195 exp_u2Q_x[10]=0x3daea37a
196 exp_u2Q_x[11]=0x922ade62
197 if limbs_eq(u2Q_aff.x, exp_u2Q_x) != 1 { return 5 }
198
199 // ---- STEP 6: R = u1G + u2Q ---- JACOBIAN INPUTS to point_add ----
200 // This mirrors the orchestrator (which doesn't to_affine before add).
201 let R: *P384Point = p384_point_alloc()
202 p384_point_add(R, u1G, u2Q)
203 p384_point_to_affine(R)
204 dump_hex(0x52, 0x58, R.x)
205
206 let exp_R_x: *i64 = u384_alloc()
207 exp_R_x[0]=0x6D8FB2CD
208 exp_R_x[1]=0x2FA2B3C3
209 exp_R_x[2]=0xE63355D9
210 exp_R_x[3]=0xBDE1E888
211 exp_R_x[4]=0x1D3DAA33
212 exp_R_x[5]=0x354B63A2
213 exp_R_x[6]=0x98D4EA8E
214 exp_R_x[7]=0x0C570C6F
215 exp_R_x[8]=0xF99AF8B3
216 exp_R_x[9]=0x392D03C5
217 exp_R_x[10]=0x013C7FA1
218 exp_R_x[11]=0x21B13D1E
219 if limbs_eq(R.x, exp_R_x) != 1 { return 6 }
220
221 // ---- STEP 7: mirror orchestrator's final modn_eq check ----
222 // Goal: verify orchestrator's "modn_eq(v, sig_r)" returns 1.
223 let v: *i64 = u384_alloc()
224 p384_modn_reduce(v, R.x)
225 dump_hex(0x56, 0x58, v) // "VX=" v post-reduce
226
227 if p384_modn_eq(v, sig_r) != 1 { return 7 }
228
229 // ---- STEP 8: call orchestrator with SAME inputs ----
230 let orc: i64 = nx_ecdsa_p384_verify(pub_x, pub_y, e, sig_r, sig_s)
231 let lab2: *u8 = sys_mmap(8)
232 lab2[0]=0x4F; lab2[1]=0x52; lab2[2]=0x3D // "OR="
233 sys_write(2, lab2, 3)
234 let d: *u8 = sys_mmap(8)
235 d[0] = (0x30 + orc) as u8
236 sys_write(2, d, 1)
237 let nl: *u8 = sys_mmap(8); nl[0]=0x0A; sys_write(2, nl, 1)
238 if orc != NX_ECDSA_P384_OK { return 8 }
239
240 return 0
241}