1 /* $OpenBSD: ec_point_conversion.c,v 1.15 2024/01/18 16:49:40 tb Exp $ */ 2 /* 3 * Copyright (c) 2021 Theo Buehler <tb@openbsd.org> 4 * Copyright (c) 2021 Joel Sing <jsing@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <err.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 23 #include <openssl/bn.h> 24 #include <openssl/ec.h> 25 #include <openssl/objects.h> 26 27 int forms[] = { 28 POINT_CONVERSION_COMPRESSED, 29 POINT_CONVERSION_UNCOMPRESSED, 30 POINT_CONVERSION_HYBRID, 31 }; 32 33 static const size_t N_FORMS = sizeof(forms) / sizeof(forms[0]); 34 #define N_RANDOM_POINTS 10 35 36 static const char * 37 form2str(int form) 38 { 39 switch (form) { 40 case POINT_CONVERSION_COMPRESSED: 41 return "compressed form"; 42 case POINT_CONVERSION_UNCOMPRESSED: 43 return "uncompressed form"; 44 case POINT_CONVERSION_HYBRID: 45 return "hybrid form"; 46 default: 47 return "unknown form"; 48 } 49 } 50 51 static void 52 hexdump(const unsigned char *buf, size_t len) 53 { 54 size_t i; 55 56 for (i = 1; i <= len; i++) 57 fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n"); 58 if (len % 8) 59 fprintf(stderr, "\n"); 60 } 61 62 static int 63 roundtrip(EC_GROUP *group, EC_POINT *point, int form, BIGNUM *x, BIGNUM *y) 64 { 65 BIGNUM *x_out = NULL, *y_out = NULL; 66 size_t len; 67 uint8_t *buf = NULL; 68 int failed = 1; 69 70 if ((len = EC_POINT_point2oct(group, point, form, NULL, 0, NULL)) == 0) 71 errx(1, "point2oct"); 72 if ((buf = malloc(len)) == NULL) 73 errx(1, "malloc"); 74 if (EC_POINT_point2oct(group, point, form, buf, len, NULL) != len) 75 errx(1, "point2oct"); 76 77 if (!EC_POINT_oct2point(group, point, buf, len, NULL)) 78 errx(1, "%s oct2point", form2str(form)); 79 80 if ((x_out = BN_new()) == NULL) 81 errx(1, "new x_out"); 82 if ((y_out = BN_new()) == NULL) 83 errx(1, "new y_out"); 84 85 if (!EC_POINT_get_affine_coordinates(group, point, x_out, y_out, NULL)) 86 errx(1, "get affine"); 87 88 if (BN_cmp(x, x_out) != 0) { 89 warnx("%s: x", form2str(form)); 90 goto err; 91 } 92 if (BN_cmp(y, y_out) != 0) { 93 warnx("%s: y", form2str(form)); 94 goto err; 95 } 96 97 failed = 0; 98 99 err: 100 if (failed) 101 hexdump(buf, len); 102 103 free(buf); 104 BN_free(x_out); 105 BN_free(y_out); 106 107 return failed; 108 } 109 110 /* XXX This only tests multiples of the generator for now... */ 111 static int 112 test_random_points_on_curve(EC_builtin_curve *curve) 113 { 114 EC_GROUP *group; 115 BIGNUM *order = NULL; 116 BIGNUM *random; 117 BIGNUM *x, *y; 118 size_t i, j; 119 int failed = 0; 120 121 if ((group = EC_GROUP_new_by_curve_name(curve->nid)) == NULL) 122 errx(1, "EC_GROUP_new_by_curve_name(%s)", 123 OBJ_nid2sn(curve->nid)); 124 125 if ((order = BN_new()) == NULL) 126 errx(1, "BN_new order"); 127 if ((random = BN_new()) == NULL) 128 errx(1, "BN_new random"); 129 if ((x = BN_new()) == NULL) 130 errx(1, "BN_new x"); 131 if ((y = BN_new()) == NULL) 132 errx(1, "BN_new y"); 133 134 if (!EC_GROUP_get_order(group, order, NULL)) 135 errx(1, "EC_group_get_order"); 136 137 for (i = 0; i < N_RANDOM_POINTS; i++) { 138 EC_POINT *random_point; 139 140 do { 141 if (!BN_rand_range(random, order)) 142 errx(1, "BN_rand_range"); 143 } while (BN_is_zero(random)); 144 145 if ((random_point = EC_POINT_new(group)) == NULL) 146 errx(1, "EC_POINT_new"); 147 148 if (!EC_POINT_mul(group, random_point, random, NULL, NULL, NULL)) 149 errx(1, "EC_POINT_mul"); 150 151 if (EC_POINT_is_at_infinity(group, random_point)) { 152 EC_POINT_free(random_point); 153 154 warnx("info: got infinity"); 155 fprintf(stderr, "random = "); 156 BN_print_fp(stderr, random); 157 fprintf(stderr, "\n"); 158 159 continue; 160 } 161 162 if (!EC_POINT_get_affine_coordinates(group, random_point, 163 x, y, NULL)) 164 errx(1, "EC_POINT_get_affine_coordinates"); 165 166 for (j = 0; j < N_FORMS; j++) 167 failed |= roundtrip(group, random_point, forms[j], x, y); 168 169 EC_POINT_free(random_point); 170 } 171 172 BN_free(order); 173 BN_free(random); 174 BN_free(x); 175 BN_free(y); 176 EC_GROUP_free(group); 177 178 return failed; 179 } 180 181 static int 182 test_random_points(void) 183 { 184 EC_builtin_curve *all_curves = NULL; 185 size_t ncurves = 0; 186 size_t curve_id; 187 int failed = 0; 188 189 ncurves = EC_get_builtin_curves(NULL, 0); 190 if ((all_curves = calloc(ncurves, sizeof(EC_builtin_curve))) == NULL) 191 err(1, "calloc builtin curves"); 192 EC_get_builtin_curves(all_curves, ncurves); 193 194 for (curve_id = 0; curve_id < ncurves; curve_id++) 195 failed |= test_random_points_on_curve(&all_curves[curve_id]); 196 197 fprintf(stderr, "%s %s\n", __func__, failed ? ": FAILED" : ""); 198 199 free(all_curves); 200 return failed; 201 } 202 203 static const struct point_conversion { 204 const char *description; 205 int nid; 206 uint8_t octets[256]; 207 uint8_t octets_len; 208 int valid; 209 } point_conversions[] = { 210 /* XXX - now that sect571 is no longer tested, add another test? */ 211 { 212 .description = "point at infinity on secp256r1", 213 .nid = NID_X9_62_prime256v1, 214 .octets = { 0x00 }, 215 .octets_len = 1, 216 .valid = 1, 217 }, 218 { 219 .description = "point at infinity on secp256r1 (flipped y_bit)", 220 .nid = NID_X9_62_prime256v1, 221 .octets = { 0x01 }, 222 .octets_len = 1, 223 .valid = 0, 224 }, 225 { 226 .description = "zero x compressed point on secp256r1", 227 .nid = NID_X9_62_prime256v1, 228 .octets = { 229 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 231 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 232 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 233 0x00, 234 }, 235 .octets_len = 33, 236 .valid = 1, 237 }, 238 { 239 .description = 240 "zero x compressed point on secp256r1 (flipped y_bit)", 241 .nid = NID_X9_62_prime256v1, 242 .octets = { 243 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 244 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 245 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 246 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 247 0x00, 248 }, 249 .octets_len = 33, 250 .valid = 1, 251 }, 252 { 253 .description = "generic compressed point on secp256r1", 254 .nid = NID_X9_62_prime256v1, 255 .octets = { 256 0x03, 0xa3, 0x96, 0xa0, 0x42, 0x73, 0x1a, 0x8b, 257 0x90, 0xd8, 0xcb, 0xae, 0xda, 0x1b, 0x23, 0x11, 258 0x77, 0x5f, 0x6a, 0x4c, 0xb4, 0x57, 0xbf, 0xe0, 259 0x65, 0xd4, 0x09, 0x11, 0x5f, 0x54, 0xe4, 0xee, 260 0xdd, 261 }, 262 .octets_len = 33, 263 .valid = 1, 264 }, 265 { 266 .description = 267 "generic compressed point on secp256r1 (flipped y_bit)", 268 .nid = NID_X9_62_prime256v1, 269 .octets = { 270 0x02, 0xa3, 0x96, 0xa0, 0x42, 0x73, 0x1a, 0x8b, 271 0x90, 0xd8, 0xcb, 0xae, 0xda, 0x1b, 0x23, 0x11, 272 0x77, 0x5f, 0x6a, 0x4c, 0xb4, 0x57, 0xbf, 0xe0, 273 0x65, 0xd4, 0x09, 0x11, 0x5f, 0x54, 0xe4, 0xee, 274 0xdd, 275 }, 276 .octets_len = 33, 277 .valid = 1, 278 }, 279 { 280 .description = "zero x uncompressed point #1 on secp256r1", 281 .nid = NID_X9_62_prime256v1, 282 .octets = { 283 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 284 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 285 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 287 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 288 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 289 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 290 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 291 0xf4, 292 }, 293 .octets_len = 65, 294 .valid = 1, 295 }, 296 { 297 .description = 298 "zero x uncompressed point #1 on secp256r1 (flipped y_bit)", 299 .nid = NID_X9_62_prime256v1, 300 .octets = { 301 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 302 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 304 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 305 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 306 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 307 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 308 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 309 0xf4, 310 }, 311 .octets_len = 65, 312 .valid = 0, 313 }, 314 { 315 .description = "zero x uncompressed point #2 on secp256r1", 316 .nid = NID_X9_62_prime256v1, 317 .octets = { 318 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 319 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 320 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 321 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 322 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 323 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 324 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 325 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 326 0x0b, 327 }, 328 .octets_len = 65, 329 .valid = 1, 330 }, 331 { 332 .description = 333 "zero x uncompressed point #2 on secp256r1 (flipped y_bit)", 334 .nid = NID_X9_62_prime256v1, 335 .octets = { 336 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 337 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 338 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 339 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 340 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 341 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 342 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 343 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 344 0x0b, 345 }, 346 .octets_len = 65, 347 .valid = 0, 348 }, 349 { 350 .description = "generic uncompressed point on secp256r1", 351 .nid = NID_X9_62_prime256v1, 352 .octets = { 353 0x04, 0x23, 0xe5, 0x85, 0xa5, 0x4b, 0xda, 0x34, 354 0x7e, 0xe5, 0x65, 0x53, 0x7f, 0x3b, 0xce, 0xe4, 355 0x54, 0xd8, 0xa4, 0x5a, 0x53, 0x4b, 0xb0, 0x4c, 356 0xb9, 0x31, 0x09, 0x29, 0xa2, 0x03, 0x4c, 0x73, 357 0x20, 0xd2, 0xc6, 0x17, 0xca, 0xe3, 0xcf, 0xc2, 358 0xd8, 0x31, 0xfe, 0xf1, 0x7c, 0x6f, 0x9d, 0x7a, 359 0x01, 0x7c, 0x34, 0x65, 0x42, 0x05, 0xaf, 0xcc, 360 0x04, 0xa3, 0x2f, 0x44, 0x14, 0xbe, 0xd8, 0xc2, 361 0x03, 362 }, 363 .octets_len = 65, 364 .valid = 1, 365 }, 366 { 367 .description = 368 "generic uncompressed point on secp256r1 (flipped y_bit)", 369 .nid = NID_X9_62_prime256v1, 370 .octets = { 371 0x05, 0x23, 0xe5, 0x85, 0xa5, 0x4b, 0xda, 0x34, 372 0x7e, 0xe5, 0x65, 0x53, 0x7f, 0x3b, 0xce, 0xe4, 373 0x54, 0xd8, 0xa4, 0x5a, 0x53, 0x4b, 0xb0, 0x4c, 374 0xb9, 0x31, 0x09, 0x29, 0xa2, 0x03, 0x4c, 0x73, 375 0x20, 0xd2, 0xc6, 0x17, 0xca, 0xe3, 0xcf, 0xc2, 376 0xd8, 0x31, 0xfe, 0xf1, 0x7c, 0x6f, 0x9d, 0x7a, 377 0x01, 0x7c, 0x34, 0x65, 0x42, 0x05, 0xaf, 0xcc, 378 0x04, 0xa3, 0x2f, 0x44, 0x14, 0xbe, 0xd8, 0xc2, 379 0x03, 380 }, 381 .octets_len = 65, 382 .valid = 0, 383 }, 384 { 385 .description = "zero x hybrid point #1 on secp256r1", 386 .nid = NID_X9_62_prime256v1, 387 .octets = { 388 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 389 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 390 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 391 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 392 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 393 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 394 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 395 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 396 0xf4, 397 }, 398 .octets_len = 65, 399 .valid = 1, 400 }, 401 { 402 .description = 403 "zero x hybrid point #1 on secp256r1 (flipped y_bit)", 404 .nid = NID_X9_62_prime256v1, 405 .octets = { 406 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 407 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 408 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 409 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 410 0x00, 0x66, 0x48, 0x5c, 0x78, 0x0e, 0x2f, 0x83, 411 0xd7, 0x24, 0x33, 0xbd, 0x5d, 0x84, 0xa0, 0x6b, 412 0xb6, 0x54, 0x1c, 0x2a, 0xf3, 0x1d, 0xae, 0x87, 413 0x17, 0x28, 0xbf, 0x85, 0x6a, 0x17, 0x4f, 0x93, 414 0xf4, 415 }, 416 .octets_len = 65, 417 .valid = 0, 418 }, 419 { 420 .description = "zero x hybrid point #2 on secp256r1", 421 .nid = NID_X9_62_prime256v1, 422 .octets = { 423 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 424 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 425 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 426 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 427 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 428 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 429 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 430 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 431 0x0b, 432 }, 433 .octets_len = 65, 434 .valid = 1, 435 }, 436 { 437 .description = 438 "zero x hybrid point #2 on secp256r1 (flipped y_bit)", 439 .nid = NID_X9_62_prime256v1, 440 .octets = { 441 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 442 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 443 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 444 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 445 0x00, 0x99, 0xb7, 0xa3, 0x86, 0xf1, 0xd0, 0x7c, 446 0x29, 0xdb, 0xcc, 0x42, 0xa2, 0x7b, 0x5f, 0x94, 447 0x49, 0xab, 0xe3, 0xd5, 0x0d, 0xe2, 0x51, 0x78, 448 0xe8, 0xd7, 0x40, 0x7a, 0x95, 0xe8, 0xb0, 0x6c, 449 0x0b, 450 }, 451 .octets_len = 65, 452 .valid = 0, 453 }, 454 { 455 .description = "generic hybrid point on secp256r1", 456 .nid = NID_X9_62_prime256v1, 457 .octets = { 458 0x07, 0x38, 0xb2, 0x98, 0x38, 0x21, 0x6b, 0xec, 459 0x87, 0xcf, 0x50, 0xbb, 0x65, 0x11, 0x96, 0x63, 460 0xf3, 0x90, 0x64, 0xc3, 0x5c, 0x59, 0xa5, 0x6f, 461 0xaf, 0x56, 0x2a, 0x0c, 0xc0, 0x3a, 0x9b, 0x92, 462 0x85, 0x95, 0x54, 0xf3, 0x08, 0x0f, 0x78, 0x59, 463 0xa2, 0x44, 0x2f, 0x19, 0x5d, 0xd5, 0xcd, 0xf6, 464 0xa5, 0xbe, 0x2f, 0x83, 0x70, 0x94, 0xf5, 0xcd, 465 0x8c, 0x40, 0x7f, 0xd8, 0x97, 0x92, 0x14, 0xf7, 466 0xc5, 467 }, 468 .octets_len = 65, 469 .valid = 1, 470 }, 471 { 472 .description = 473 "generic hybrid point on secp256r1 (flipped y_bit)", 474 .nid = NID_X9_62_prime256v1, 475 .octets = { 476 0x06, 0x38, 0xb2, 0x98, 0x38, 0x21, 0x6b, 0xec, 477 0x87, 0xcf, 0x50, 0xbb, 0x65, 0x11, 0x96, 0x63, 478 0xf3, 0x90, 0x64, 0xc3, 0x5c, 0x59, 0xa5, 0x6f, 479 0xaf, 0x56, 0x2a, 0x0c, 0xc0, 0x3a, 0x9b, 0x92, 480 0x85, 0x95, 0x54, 0xf3, 0x08, 0x0f, 0x78, 0x59, 481 0xa2, 0x44, 0x2f, 0x19, 0x5d, 0xd5, 0xcd, 0xf6, 482 0xa5, 0xbe, 0x2f, 0x83, 0x70, 0x94, 0xf5, 0xcd, 483 0x8c, 0x40, 0x7f, 0xd8, 0x97, 0x92, 0x14, 0xf7, 484 0xc5, 485 }, 486 .octets_len = 65, 487 .valid = 0, 488 }, 489 }; 490 491 static const size_t N_POINT_CONVERSIONS = 492 sizeof(point_conversions) / sizeof(point_conversions[0]); 493 494 static int 495 point_conversion_form_y_bit(const struct point_conversion *test) 496 { 497 EC_GROUP *group = NULL; 498 EC_POINT *point = NULL; 499 int ret; 500 int failed = 0; 501 502 if ((group = EC_GROUP_new_by_curve_name(test->nid)) == NULL) 503 errx(1, "group"); 504 if ((point = EC_POINT_new(group)) == NULL) 505 errx(1, "point"); 506 507 ret = EC_POINT_oct2point(group, point, test->octets, test->octets_len, 508 NULL); 509 if (ret != test->valid) { 510 fprintf(stderr, "%s want %d got %d\n", test->description, 511 test->valid, ret); 512 failed |= 1; 513 } 514 515 EC_GROUP_free(group); 516 EC_POINT_free(point); 517 518 return failed; 519 } 520 521 static int 522 test_point_conversions(void) 523 { 524 size_t i; 525 int failed = 0; 526 527 for (i = 0; i < N_POINT_CONVERSIONS; i++) 528 failed |= point_conversion_form_y_bit(&point_conversions[i]); 529 530 fprintf(stderr, "%s %s\n", __func__, failed ? ": FAILED" : ""); 531 532 return failed; 533 } 534 535 int 536 main(int argc, char **argv) 537 { 538 int failed = 0; 539 540 failed |= test_random_points(); 541 failed |= test_point_conversions(); 542 543 return failed; 544 } 545