]>
Commit | Line | Data |
---|---|---|
a41f32e6 PW |
1 | #include <assert.h> |
2 | ||
7a4b7691 PW |
3 | #include "impl/num.h" |
4 | #include "impl/field.h" | |
5 | #include "impl/group.h" | |
6 | #include "impl/ecmult.h" | |
7 | #include "impl/ecdsa.h" | |
d06e61cb | 8 | #include "impl/util.h" |
a41f32e6 | 9 | |
404c30a8 | 10 | static int count = 100; |
4adf6b2a | 11 | |
404c30a8 PW |
12 | /***** NUM TESTS *****/ |
13 | ||
3f44e1ad PW |
14 | void random_num_negate(secp256k1_num_t *num) { |
15 | if (secp256k1_rand32() & 1) | |
16 | secp256k1_num_negate(num); | |
17 | } | |
18 | ||
404c30a8 | 19 | void random_num_order_test(secp256k1_num_t *num) { |
d06e61cb PW |
20 | do { |
21 | unsigned char b32[32]; | |
22 | secp256k1_rand256_test(b32); | |
23 | secp256k1_num_set_bin(num, b32, 32); | |
24 | if (secp256k1_num_is_zero(num)) | |
25 | continue; | |
26 | if (secp256k1_num_cmp(num, &secp256k1_ge_consts->order) >= 0) | |
27 | continue; | |
28 | break; | |
29 | } while(1); | |
30 | } | |
31 | ||
404c30a8 PW |
32 | void random_num_order(secp256k1_num_t *num) { |
33 | do { | |
34 | unsigned char b32[32]; | |
35 | secp256k1_rand256(b32); | |
36 | secp256k1_num_set_bin(num, b32, 32); | |
37 | if (secp256k1_num_is_zero(num)) | |
38 | continue; | |
39 | if (secp256k1_num_cmp(num, &secp256k1_ge_consts->order) >= 0) | |
40 | continue; | |
41 | break; | |
42 | } while(1); | |
43 | } | |
44 | ||
45 | void test_num_copy_inc_cmp() { | |
46 | secp256k1_num_t n1,n2; | |
47 | secp256k1_num_init(&n1); | |
48 | secp256k1_num_init(&n2); | |
49 | random_num_order(&n1); | |
50 | secp256k1_num_copy(&n2, &n1); | |
51 | assert(secp256k1_num_cmp(&n1, &n2) == 0); | |
52 | assert(secp256k1_num_cmp(&n2, &n1) == 0); | |
53 | secp256k1_num_inc(&n2); | |
54 | assert(secp256k1_num_cmp(&n1, &n2) != 0); | |
55 | assert(secp256k1_num_cmp(&n2, &n1) != 0); | |
56 | secp256k1_num_free(&n1); | |
57 | secp256k1_num_free(&n2); | |
58 | } | |
59 | ||
404c30a8 PW |
60 | |
61 | void test_num_get_set_hex() { | |
62 | secp256k1_num_t n1,n2; | |
63 | secp256k1_num_init(&n1); | |
64 | secp256k1_num_init(&n2); | |
65 | random_num_order_test(&n1); | |
66 | char c[64]; | |
67 | secp256k1_num_get_hex(c, 64, &n1); | |
68 | secp256k1_num_set_hex(&n2, c, 64); | |
69 | assert(secp256k1_num_cmp(&n1, &n2) == 0); | |
70 | for (int i=0; i<64; i++) { | |
71 | // check whether the lower 4 bits correspond to the last hex character | |
72 | int low1 = secp256k1_num_shift(&n1, 4); | |
73 | int lowh = c[63]; | |
74 | int low2 = (lowh>>6)*9+(lowh-'0')&15; | |
75 | assert(low1 == low2); | |
76 | // shift bits off the hex representation, and compare | |
77 | memmove(c+1, c, 63); | |
78 | c[0] = '0'; | |
79 | secp256k1_num_set_hex(&n2, c, 64); | |
80 | assert(secp256k1_num_cmp(&n1, &n2) == 0); | |
81 | } | |
82 | secp256k1_num_free(&n2); | |
83 | secp256k1_num_free(&n1); | |
84 | } | |
85 | ||
86 | void test_num_get_set_bin() { | |
87 | secp256k1_num_t n1,n2; | |
88 | secp256k1_num_init(&n1); | |
89 | secp256k1_num_init(&n2); | |
90 | random_num_order_test(&n1); | |
91 | unsigned char c[32]; | |
92 | secp256k1_num_get_bin(c, 32, &n1); | |
93 | secp256k1_num_set_bin(&n2, c, 32); | |
94 | assert(secp256k1_num_cmp(&n1, &n2) == 0); | |
95 | for (int i=0; i<32; i++) { | |
96 | // check whether the lower 8 bits correspond to the last byte | |
97 | int low1 = secp256k1_num_shift(&n1, 8); | |
98 | int low2 = c[31]; | |
99 | assert(low1 == low2); | |
100 | // shift bits off the byte representation, and compare | |
101 | memmove(c+1, c, 31); | |
102 | c[0] = 0; | |
103 | secp256k1_num_set_bin(&n2, c, 32); | |
104 | assert(secp256k1_num_cmp(&n1, &n2) == 0); | |
105 | } | |
106 | secp256k1_num_free(&n2); | |
107 | secp256k1_num_free(&n1); | |
108 | } | |
109 | ||
404c30a8 PW |
110 | void run_num_int() { |
111 | secp256k1_num_t n1; | |
112 | secp256k1_num_init(&n1); | |
113 | for (int i=-255; i<256; i++) { | |
114 | unsigned char c1[3] = {}; | |
115 | c1[2] = abs(i); | |
116 | unsigned char c2[3] = {0x11,0x22,0x33}; | |
117 | secp256k1_num_set_int(&n1, i); | |
118 | secp256k1_num_get_bin(c2, 3, &n1); | |
119 | assert(memcmp(c1, c2, 3) == 0); | |
120 | } | |
121 | secp256k1_num_free(&n1); | |
122 | } | |
123 | ||
3f44e1ad PW |
124 | void test_num_negate() { |
125 | secp256k1_num_t n1; | |
126 | secp256k1_num_t n2; | |
127 | secp256k1_num_init(&n1); | |
128 | secp256k1_num_init(&n2); | |
129 | random_num_order_test(&n1); // n1 = R | |
130 | random_num_negate(&n1); | |
131 | secp256k1_num_copy(&n2, &n1); // n2 = R | |
132 | secp256k1_num_sub(&n1, &n2, &n1); // n1 = n2-n1 = 0 | |
133 | assert(secp256k1_num_is_zero(&n1)); | |
134 | secp256k1_num_copy(&n1, &n2); // n1 = R | |
135 | secp256k1_num_negate(&n1); // n1 = -R | |
136 | assert(!secp256k1_num_is_zero(&n1)); | |
137 | secp256k1_num_add(&n1, &n2, &n1); // n1 = n2+n1 = 0 | |
138 | assert(secp256k1_num_is_zero(&n1)); | |
139 | secp256k1_num_copy(&n1, &n2); // n1 = R | |
140 | secp256k1_num_negate(&n1); // n1 = -R | |
141 | assert(secp256k1_num_is_neg(&n1) != secp256k1_num_is_neg(&n2)); | |
142 | secp256k1_num_negate(&n1); // n1 = R | |
143 | assert(secp256k1_num_cmp(&n1, &n2) == 0); | |
144 | assert(secp256k1_num_is_neg(&n1) == secp256k1_num_is_neg(&n2)); | |
145 | secp256k1_num_free(&n2); | |
146 | secp256k1_num_free(&n1); | |
147 | } | |
148 | ||
149 | void test_num_add_sub() { | |
150 | secp256k1_num_t n1; | |
151 | secp256k1_num_t n2; | |
152 | secp256k1_num_init(&n1); | |
153 | secp256k1_num_init(&n2); | |
154 | random_num_order_test(&n1); // n1 = R1 | |
155 | random_num_negate(&n1); | |
156 | random_num_order_test(&n2); // n2 = R2 | |
157 | random_num_negate(&n2); | |
158 | secp256k1_num_t n1p2, n2p1, n1m2, n2m1; | |
159 | secp256k1_num_init(&n1p2); | |
160 | secp256k1_num_init(&n2p1); | |
161 | secp256k1_num_init(&n1m2); | |
162 | secp256k1_num_init(&n2m1); | |
163 | secp256k1_num_add(&n1p2, &n1, &n2); // n1p2 = R1 + R2 | |
164 | secp256k1_num_add(&n2p1, &n2, &n1); // n2p1 = R2 + R1 | |
165 | secp256k1_num_sub(&n1m2, &n1, &n2); // n1m2 = R1 - R2 | |
166 | secp256k1_num_sub(&n2m1, &n2, &n1); // n2m1 = R2 - R1 | |
167 | assert(secp256k1_num_cmp(&n1p2, &n2p1) == 0); | |
168 | assert(secp256k1_num_cmp(&n1p2, &n1m2) != 0); | |
169 | secp256k1_num_negate(&n2m1); // n2m1 = -R2 + R1 | |
170 | assert(secp256k1_num_cmp(&n2m1, &n1m2) == 0); | |
171 | assert(secp256k1_num_cmp(&n2m1, &n1) != 0); | |
172 | secp256k1_num_add(&n2m1, &n2m1, &n2); // n2m1 = -R2 + R1 + R2 = R1 | |
173 | assert(secp256k1_num_cmp(&n2m1, &n1) == 0); | |
174 | assert(secp256k1_num_cmp(&n2p1, &n1) != 0); | |
175 | secp256k1_num_sub(&n2p1, &n2p1, &n2); // n2p1 = R2 + R1 - R2 = R1 | |
176 | assert(secp256k1_num_cmp(&n2p1, &n1) == 0); | |
177 | secp256k1_num_free(&n2m1); | |
178 | secp256k1_num_free(&n1m2); | |
179 | secp256k1_num_free(&n2p1); | |
180 | secp256k1_num_free(&n1p2); | |
181 | secp256k1_num_free(&n2); | |
182 | secp256k1_num_free(&n1); | |
183 | } | |
184 | ||
185 | void run_num_smalltests() { | |
186 | for (int i=0; i<100*count; i++) { | |
187 | test_num_copy_inc_cmp(); | |
188 | test_num_get_set_hex(); | |
189 | test_num_get_set_bin(); | |
190 | test_num_negate(); | |
191 | test_num_add_sub(); | |
192 | } | |
193 | run_num_int(); | |
194 | } | |
195 | ||
404c30a8 | 196 | void run_ecmult_chain() { |
cbd3617e | 197 | // random starting point A (on the curve) |
910d0de4 PW |
198 | secp256k1_fe_t ax; secp256k1_fe_set_hex(&ax, "8b30bbe9ae2a990696b22f670709dff3727fd8bc04d3362c6c7bf458e2846004", 64); |
199 | secp256k1_fe_t ay; secp256k1_fe_set_hex(&ay, "a357ae915c4a65281309edf20504740f0eb3343990216b4f81063cb65f2f7e0f", 64); | |
f11ff5be | 200 | secp256k1_gej_t a; secp256k1_gej_set_xy(&a, &ax, &ay); |
cbd3617e | 201 | // two random initial factors xn and gn |
4adf6b2a PW |
202 | secp256k1_num_t xn; |
203 | secp256k1_num_init(&xn); | |
204 | secp256k1_num_set_hex(&xn, "84cc5452f7fde1edb4d38a8ce9b1b84ccef31f146e569be9705d357a42985407", 64); | |
205 | secp256k1_num_t gn; | |
206 | secp256k1_num_init(&gn); | |
207 | secp256k1_num_set_hex(&gn, "a1e58d22553dcd42b23980625d4c57a96e9323d42b3152e5ca2c3990edc7c9de", 64); | |
cbd3617e | 208 | // two small multipliers to be applied to xn and gn in every iteration: |
4adf6b2a PW |
209 | secp256k1_num_t xf; |
210 | secp256k1_num_init(&xf); | |
211 | secp256k1_num_set_hex(&xf, "1337", 4); | |
212 | secp256k1_num_t gf; | |
213 | secp256k1_num_init(&gf); | |
214 | secp256k1_num_set_hex(&gf, "7113", 4); | |
cbd3617e | 215 | // accumulators with the resulting coefficients to A and G |
4adf6b2a PW |
216 | secp256k1_num_t ae; |
217 | secp256k1_num_init(&ae); | |
218 | secp256k1_num_set_int(&ae, 1); | |
219 | secp256k1_num_t ge; | |
220 | secp256k1_num_init(&ge); | |
221 | secp256k1_num_set_int(&ge, 0); | |
cbd3617e | 222 | // the point being computed |
f11ff5be PW |
223 | secp256k1_gej_t x = a; |
224 | const secp256k1_num_t *order = &secp256k1_ge_consts->order; | |
404c30a8 | 225 | for (int i=0; i<200*count; i++) { |
14b195ee | 226 | // in each iteration, compute X = xn*X + gn*G; |
b1483f87 | 227 | secp256k1_ecmult(&x, &x, &xn, &gn); |
14b195ee PW |
228 | // also compute ae and ge: the actual accumulated factors for A and G |
229 | // if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G) | |
f11ff5be PW |
230 | secp256k1_num_mod_mul(&ae, &ae, &xn, order); |
231 | secp256k1_num_mod_mul(&ge, &ge, &xn, order); | |
4adf6b2a | 232 | secp256k1_num_add(&ge, &ge, &gn); |
2f9e831d | 233 | secp256k1_num_mod(&ge, order); |
14b195ee | 234 | // modify xn and gn |
f11ff5be PW |
235 | secp256k1_num_mod_mul(&xn, &xn, &xf, order); |
236 | secp256k1_num_mod_mul(&gn, &gn, &gf, order); | |
404c30a8 PW |
237 | |
238 | // verify | |
239 | if (i == 19999) { | |
240 | char res[132]; int resl = 132; | |
241 | secp256k1_gej_get_hex(res, &resl, &x); | |
242 | assert(strcmp(res, "(D6E96687F9B10D092A6F35439D86CEBEA4535D0D409F53586440BD74B933E830,B95CBCA2C77DA786539BE8FD53354D2D3B4F566AE658045407ED6015EE1B2A88)") == 0); | |
243 | } | |
4adf6b2a | 244 | } |
14b195ee | 245 | // redo the computation, but directly with the resulting ae and ge coefficients: |
b1483f87 | 246 | secp256k1_gej_t x2; secp256k1_ecmult(&x2, &a, &ae, &ge); |
404c30a8 | 247 | char res[132]; int resl = 132; |
f11ff5be | 248 | char res2[132]; int resl2 = 132; |
404c30a8 | 249 | secp256k1_gej_get_hex(res, &resl, &x); |
f11ff5be PW |
250 | secp256k1_gej_get_hex(res2, &resl2, &x2); |
251 | assert(strcmp(res, res2) == 0); | |
252 | assert(strlen(res) == 131); | |
4adf6b2a PW |
253 | secp256k1_num_free(&xn); |
254 | secp256k1_num_free(&gn); | |
255 | secp256k1_num_free(&xf); | |
256 | secp256k1_num_free(&gf); | |
257 | secp256k1_num_free(&ae); | |
258 | secp256k1_num_free(&ge); | |
a41f32e6 PW |
259 | } |
260 | ||
eb0be8ee | 261 | void test_point_times_order(const secp256k1_gej_t *point) { |
4e0ed539 | 262 | // either the point is not on the curve, or multiplying it by the order results in O |
eb0be8ee | 263 | if (!secp256k1_gej_is_valid(point)) |
4e0ed539 PW |
264 | return; |
265 | ||
f11ff5be | 266 | const secp256k1_num_t *order = &secp256k1_ge_consts->order; |
4adf6b2a PW |
267 | secp256k1_num_t zero; |
268 | secp256k1_num_init(&zero); | |
269 | secp256k1_num_set_int(&zero, 0); | |
f11ff5be | 270 | secp256k1_gej_t res; |
eb0be8ee | 271 | secp256k1_ecmult(&res, point, order, order); // calc res = order * point + order * G; |
f11ff5be | 272 | assert(secp256k1_gej_is_infinity(&res)); |
4adf6b2a | 273 | secp256k1_num_free(&zero); |
4e0ed539 PW |
274 | } |
275 | ||
404c30a8 | 276 | void run_point_times_order() { |
910d0de4 | 277 | secp256k1_fe_t x; secp256k1_fe_set_hex(&x, "02", 2); |
4e0ed539 | 278 | for (int i=0; i<500; i++) { |
764332d0 PW |
279 | secp256k1_ge_t p; secp256k1_ge_set_xo(&p, &x, 1); |
280 | secp256k1_gej_t j; secp256k1_gej_set_ge(&j, &p); | |
eb0be8ee | 281 | test_point_times_order(&j); |
910d0de4 | 282 | secp256k1_fe_sqr(&x, &x); |
4e0ed539 | 283 | } |
910d0de4 PW |
284 | char c[65]; int cl=65; |
285 | secp256k1_fe_get_hex(c, &cl, &x); | |
286 | assert(strcmp(c, "7603CB59B0EF6C63FE6084792A0C378CDB3233A80F8A9A09A877DEAD31B38C45") == 0); | |
4e0ed539 PW |
287 | } |
288 | ||
eb0be8ee | 289 | void test_wnaf(const secp256k1_num_t *number, int w) { |
4adf6b2a PW |
290 | secp256k1_num_t x, two, t; |
291 | secp256k1_num_init(&x); | |
292 | secp256k1_num_init(&two); | |
293 | secp256k1_num_init(&t); | |
294 | secp256k1_num_set_int(&x, 0); | |
295 | secp256k1_num_set_int(&two, 2); | |
898cecb3 | 296 | int wnaf[257]; |
eb0be8ee | 297 | int bits = secp256k1_ecmult_wnaf(wnaf, number, w); |
4e0ed539 | 298 | int zeroes = -1; |
b1483f87 | 299 | for (int i=bits-1; i>=0; i--) { |
4adf6b2a | 300 | secp256k1_num_mul(&x, &x, &two); |
b1483f87 | 301 | int v = wnaf[i]; |
4e0ed539 PW |
302 | if (v) { |
303 | assert(zeroes == -1 || zeroes >= w-1); // check that distance between non-zero elements is at least w-1 | |
304 | zeroes=0; | |
305 | assert((v & 1) == 1); // check non-zero elements are odd | |
306 | assert(v <= (1 << (w-1)) - 1); // check range below | |
307 | assert(v >= -(1 << (w-1)) - 1); // check range above | |
308 | } else { | |
309 | assert(zeroes != -1); // check that no unnecessary zero padding exists | |
310 | zeroes++; | |
311 | } | |
4adf6b2a PW |
312 | secp256k1_num_set_int(&t, v); |
313 | secp256k1_num_add(&x, &x, &t); | |
4e0ed539 | 314 | } |
eb0be8ee | 315 | assert(secp256k1_num_cmp(&x, number) == 0); // check that wnaf represents number |
4adf6b2a PW |
316 | secp256k1_num_free(&x); |
317 | secp256k1_num_free(&two); | |
318 | secp256k1_num_free(&t); | |
4e0ed539 PW |
319 | } |
320 | ||
404c30a8 | 321 | void run_wnaf() { |
d06e61cb | 322 | secp256k1_num_t n; |
4adf6b2a | 323 | secp256k1_num_init(&n); |
404c30a8 | 324 | for (int i=0; i<count; i++) { |
d06e61cb PW |
325 | random_num_order(&n); |
326 | if (i % 1) | |
327 | secp256k1_num_negate(&n); | |
eb0be8ee | 328 | test_wnaf(&n, 4+(i%10)); |
4e0ed539 | 329 | } |
4adf6b2a | 330 | secp256k1_num_free(&n); |
4e0ed539 | 331 | } |
a41f32e6 | 332 | |
0a07e62f | 333 | void test_ecdsa_sign_verify() { |
eb0be8ee | 334 | const secp256k1_ge_consts_t *c = secp256k1_ge_consts; |
4adf6b2a PW |
335 | secp256k1_num_t msg, key, nonce; |
336 | secp256k1_num_init(&msg); | |
404c30a8 | 337 | random_num_order_test(&msg); |
4adf6b2a | 338 | secp256k1_num_init(&key); |
404c30a8 | 339 | random_num_order_test(&key); |
4adf6b2a | 340 | secp256k1_num_init(&nonce); |
764332d0 PW |
341 | secp256k1_gej_t pubj; secp256k1_ecmult_gen(&pubj, &key); |
342 | secp256k1_ge_t pub; secp256k1_ge_set_gej(&pub, &pubj); | |
d41e93a5 PW |
343 | secp256k1_ecdsa_sig_t sig; |
344 | secp256k1_ecdsa_sig_init(&sig); | |
0a07e62f | 345 | do { |
404c30a8 | 346 | random_num_order_test(&nonce); |
d41e93a5 PW |
347 | } while(!secp256k1_ecdsa_sig_sign(&sig, &key, &msg, &nonce)); |
348 | assert(secp256k1_ecdsa_sig_verify(&sig, &pub, &msg)); | |
4adf6b2a | 349 | secp256k1_num_inc(&msg); |
d41e93a5 PW |
350 | assert(!secp256k1_ecdsa_sig_verify(&sig, &pub, &msg)); |
351 | secp256k1_ecdsa_sig_free(&sig); | |
4adf6b2a PW |
352 | secp256k1_num_free(&msg); |
353 | secp256k1_num_free(&key); | |
354 | secp256k1_num_free(&nonce); | |
0a07e62f PW |
355 | } |
356 | ||
404c30a8 PW |
357 | void run_ecdsa_sign_verify() { |
358 | for (int i=0; i<10*count; i++) { | |
0a07e62f PW |
359 | test_ecdsa_sign_verify(); |
360 | } | |
361 | } | |
362 | ||
404c30a8 PW |
363 | int main(int argc, char **argv) { |
364 | if (argc > 1) | |
3f44e1ad | 365 | count = strtol(argv[1], NULL, 0)*47; |
404c30a8 PW |
366 | |
367 | // initialize | |
910d0de4 | 368 | secp256k1_fe_start(); |
f11ff5be | 369 | secp256k1_ge_start(); |
b1483f87 | 370 | secp256k1_ecmult_start(); |
4adf6b2a | 371 | |
404c30a8 | 372 | // num tests |
3f44e1ad | 373 | run_num_smalltests(); |
404c30a8 PW |
374 | |
375 | // ecmult tests | |
376 | run_wnaf(); | |
377 | run_point_times_order(); | |
378 | run_ecmult_chain(); | |
379 | ||
380 | // ecdsa tests | |
381 | run_ecdsa_sign_verify(); | |
910d0de4 | 382 | |
404c30a8 | 383 | // shutdown |
b1483f87 | 384 | secp256k1_ecmult_stop(); |
f11ff5be | 385 | secp256k1_ge_stop(); |
910d0de4 | 386 | secp256k1_fe_stop(); |
a41f32e6 PW |
387 | return 0; |
388 | } |