]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/ec/ecp_smpl.c
Improve compatibility of point and curve checks
[thirdparty/openssl.git] / crypto / ec / ecp_smpl.c
CommitLineData
0f113f3e 1/*
edea42c6 2 * Copyright 2001-2017 The OpenSSL Project Authors. All Rights Reserved.
aa8f3d76 3 * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
f8fe20e0 4 *
aa6bb135
RS
5 * Licensed under the OpenSSL license (the "License"). You may not use
6 * this file except in compliance with the License. You can obtain a copy
7 * in the file LICENSE in the source distribution or at
8 * https://www.openssl.org/source/license.html
f8fe20e0 9 */
aa6bb135 10
60428dbf 11#include <openssl/err.h>
02cbedc3 12#include <openssl/symhacks.h>
60428dbf 13
f8fe20e0 14#include "ec_lcl.h"
0657bf9c 15
0657bf9c 16const EC_METHOD *EC_GFp_simple_method(void)
0f113f3e
MC
17{
18 static const EC_METHOD ret = {
19 EC_FLAGS_DEFAULT_OCT,
20 NID_X9_62_prime_field,
21 ec_GFp_simple_group_init,
22 ec_GFp_simple_group_finish,
23 ec_GFp_simple_group_clear_finish,
24 ec_GFp_simple_group_copy,
25 ec_GFp_simple_group_set_curve,
26 ec_GFp_simple_group_get_curve,
27 ec_GFp_simple_group_get_degree,
9ff9bccc 28 ec_group_simple_order_bits,
0f113f3e
MC
29 ec_GFp_simple_group_check_discriminant,
30 ec_GFp_simple_point_init,
31 ec_GFp_simple_point_finish,
32 ec_GFp_simple_point_clear_finish,
33 ec_GFp_simple_point_copy,
34 ec_GFp_simple_point_set_to_infinity,
35 ec_GFp_simple_set_Jprojective_coordinates_GFp,
36 ec_GFp_simple_get_Jprojective_coordinates_GFp,
37 ec_GFp_simple_point_set_affine_coordinates,
38 ec_GFp_simple_point_get_affine_coordinates,
39 0, 0, 0,
40 ec_GFp_simple_add,
41 ec_GFp_simple_dbl,
42 ec_GFp_simple_invert,
43 ec_GFp_simple_is_at_infinity,
44 ec_GFp_simple_is_on_curve,
45 ec_GFp_simple_cmp,
46 ec_GFp_simple_make_affine,
47 ec_GFp_simple_points_make_affine,
48 0 /* mul */ ,
49 0 /* precompute_mult */ ,
50 0 /* have_precompute_mult */ ,
51 ec_GFp_simple_field_mul,
52 ec_GFp_simple_field_sqr,
53 0 /* field_div */ ,
54 0 /* field_encode */ ,
55 0 /* field_decode */ ,
9ff9bccc
DSH
56 0, /* field_set_to_one */
57 ec_key_simple_priv2oct,
58 ec_key_simple_oct2priv,
59 0, /* set private */
60 ec_key_simple_generate_key,
61 ec_key_simple_check_key,
62 ec_key_simple_generate_public_key,
63 0, /* keycopy */
64 0, /* keyfinish */
65 ecdh_simple_compute_key
0f113f3e
MC
66 };
67
68 return &ret;
69}
60428dbf 70
3a83462d
MC
71/*
72 * Most method functions in this file are designed to work with
922fa76e
BM
73 * non-trivial representations of field elements if necessary
74 * (see ecp_mont.c): while standard modular addition and subtraction
75 * are used, the field_mul and field_sqr methods will be used for
76 * multiplication, and field_encode and field_decode (if defined)
77 * will be used for converting between representations.
3a83462d 78 *
922fa76e
BM
79 * Functions ec_GFp_simple_points_make_affine() and
80 * ec_GFp_simple_point_get_affine_coordinates() specifically assume
81 * that if a non-trivial representation is used, it is a Montgomery
82 * representation (i.e. 'encoding' means multiplying by some factor R).
83 */
84
60428dbf 85int ec_GFp_simple_group_init(EC_GROUP *group)
0f113f3e
MC
86{
87 group->field = BN_new();
88 group->a = BN_new();
89 group->b = BN_new();
90945fa3 90 if (group->field == NULL || group->a == NULL || group->b == NULL) {
a3853772
RS
91 BN_free(group->field);
92 BN_free(group->a);
93 BN_free(group->b);
0f113f3e
MC
94 return 0;
95 }
96 group->a_is_minus3 = 0;
97 return 1;
98}
60428dbf 99
bb62a8b0 100void ec_GFp_simple_group_finish(EC_GROUP *group)
0f113f3e
MC
101{
102 BN_free(group->field);
103 BN_free(group->a);
104 BN_free(group->b);
105}
bb62a8b0
BM
106
107void ec_GFp_simple_group_clear_finish(EC_GROUP *group)
0f113f3e
MC
108{
109 BN_clear_free(group->field);
110 BN_clear_free(group->a);
111 BN_clear_free(group->b);
112}
bb62a8b0
BM
113
114int ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src)
0f113f3e
MC
115{
116 if (!BN_copy(dest->field, src->field))
117 return 0;
118 if (!BN_copy(dest->a, src->a))
119 return 0;
120 if (!BN_copy(dest->b, src->b))
121 return 0;
bb62a8b0 122
0f113f3e 123 dest->a_is_minus3 = src->a_is_minus3;
bb62a8b0 124
0f113f3e
MC
125 return 1;
126}
bb62a8b0 127
35b73a1f 128int ec_GFp_simple_group_set_curve(EC_GROUP *group,
0f113f3e
MC
129 const BIGNUM *p, const BIGNUM *a,
130 const BIGNUM *b, BN_CTX *ctx)
131{
132 int ret = 0;
133 BN_CTX *new_ctx = NULL;
134 BIGNUM *tmp_a;
135
136 /* p must be a prime > 3 */
137 if (BN_num_bits(p) <= 2 || !BN_is_odd(p)) {
138 ECerr(EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE, EC_R_INVALID_FIELD);
139 return 0;
140 }
141
142 if (ctx == NULL) {
143 ctx = new_ctx = BN_CTX_new();
144 if (ctx == NULL)
145 return 0;
146 }
147
148 BN_CTX_start(ctx);
149 tmp_a = BN_CTX_get(ctx);
150 if (tmp_a == NULL)
151 goto err;
152
153 /* group->field */
154 if (!BN_copy(group->field, p))
155 goto err;
156 BN_set_negative(group->field, 0);
157
158 /* group->a */
159 if (!BN_nnmod(tmp_a, a, p, ctx))
160 goto err;
161 if (group->meth->field_encode) {
162 if (!group->meth->field_encode(group, group->a, tmp_a, ctx))
163 goto err;
164 } else if (!BN_copy(group->a, tmp_a))
165 goto err;
166
167 /* group->b */
168 if (!BN_nnmod(group->b, b, p, ctx))
169 goto err;
170 if (group->meth->field_encode)
171 if (!group->meth->field_encode(group, group->b, group->b, ctx))
172 goto err;
173
174 /* group->a_is_minus3 */
175 if (!BN_add_word(tmp_a, 3))
176 goto err;
177 group->a_is_minus3 = (0 == BN_cmp(tmp_a, group->field));
178
179 ret = 1;
60428dbf
BM
180
181 err:
0f113f3e 182 BN_CTX_end(ctx);
23a1d5e9 183 BN_CTX_free(new_ctx);
0f113f3e
MC
184 return ret;
185}
186
187int ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
188 BIGNUM *b, BN_CTX *ctx)
189{
190 int ret = 0;
191 BN_CTX *new_ctx = NULL;
192
193 if (p != NULL) {
194 if (!BN_copy(p, group->field))
195 return 0;
196 }
197
198 if (a != NULL || b != NULL) {
199 if (group->meth->field_decode) {
200 if (ctx == NULL) {
201 ctx = new_ctx = BN_CTX_new();
202 if (ctx == NULL)
203 return 0;
204 }
205 if (a != NULL) {
206 if (!group->meth->field_decode(group, a, group->a, ctx))
207 goto err;
208 }
209 if (b != NULL) {
210 if (!group->meth->field_decode(group, b, group->b, ctx))
211 goto err;
212 }
213 } else {
214 if (a != NULL) {
215 if (!BN_copy(a, group->a))
216 goto err;
217 }
218 if (b != NULL) {
219 if (!BN_copy(b, group->b))
220 goto err;
221 }
222 }
223 }
224
225 ret = 1;
60428dbf 226
0f113f3e 227 err:
23a1d5e9 228 BN_CTX_free(new_ctx);
0f113f3e
MC
229 return ret;
230}
60428dbf 231
7793f30e 232int ec_GFp_simple_group_get_degree(const EC_GROUP *group)
0f113f3e
MC
233{
234 return BN_num_bits(group->field);
235}
7793f30e 236
17d6bb81 237int ec_GFp_simple_group_check_discriminant(const EC_GROUP *group, BN_CTX *ctx)
0f113f3e
MC
238{
239 int ret = 0;
240 BIGNUM *a, *b, *order, *tmp_1, *tmp_2;
241 const BIGNUM *p = group->field;
242 BN_CTX *new_ctx = NULL;
243
244 if (ctx == NULL) {
245 ctx = new_ctx = BN_CTX_new();
246 if (ctx == NULL) {
247 ECerr(EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT,
248 ERR_R_MALLOC_FAILURE);
249 goto err;
250 }
251 }
252 BN_CTX_start(ctx);
253 a = BN_CTX_get(ctx);
254 b = BN_CTX_get(ctx);
255 tmp_1 = BN_CTX_get(ctx);
256 tmp_2 = BN_CTX_get(ctx);
257 order = BN_CTX_get(ctx);
258 if (order == NULL)
259 goto err;
260
261 if (group->meth->field_decode) {
262 if (!group->meth->field_decode(group, a, group->a, ctx))
263 goto err;
264 if (!group->meth->field_decode(group, b, group->b, ctx))
265 goto err;
266 } else {
267 if (!BN_copy(a, group->a))
268 goto err;
269 if (!BN_copy(b, group->b))
270 goto err;
271 }
272
50e735f9
MC
273 /*-
274 * check the discriminant:
275 * y^2 = x^3 + a*x + b is an elliptic curve <=> 4*a^3 + 27*b^2 != 0 (mod p)
276 * 0 =< a, b < p
277 */
0f113f3e
MC
278 if (BN_is_zero(a)) {
279 if (BN_is_zero(b))
280 goto err;
281 } else if (!BN_is_zero(b)) {
282 if (!BN_mod_sqr(tmp_1, a, p, ctx))
283 goto err;
284 if (!BN_mod_mul(tmp_2, tmp_1, a, p, ctx))
285 goto err;
286 if (!BN_lshift(tmp_1, tmp_2, 2))
287 goto err;
288 /* tmp_1 = 4*a^3 */
289
290 if (!BN_mod_sqr(tmp_2, b, p, ctx))
291 goto err;
292 if (!BN_mul_word(tmp_2, 27))
293 goto err;
294 /* tmp_2 = 27*b^2 */
295
296 if (!BN_mod_add(a, tmp_1, tmp_2, p, ctx))
297 goto err;
298 if (BN_is_zero(a))
299 goto err;
300 }
301 ret = 1;
af28dd6c 302
0f113f3e
MC
303 err:
304 if (ctx != NULL)
305 BN_CTX_end(ctx);
23a1d5e9 306 BN_CTX_free(new_ctx);
0f113f3e
MC
307 return ret;
308}
af28dd6c 309
60428dbf 310int ec_GFp_simple_point_init(EC_POINT *point)
0f113f3e
MC
311{
312 point->X = BN_new();
313 point->Y = BN_new();
314 point->Z = BN_new();
315 point->Z_is_one = 0;
316
90945fa3 317 if (point->X == NULL || point->Y == NULL || point->Z == NULL) {
23a1d5e9
RS
318 BN_free(point->X);
319 BN_free(point->Y);
320 BN_free(point->Z);
0f113f3e
MC
321 return 0;
322 }
323 return 1;
324}
60428dbf
BM
325
326void ec_GFp_simple_point_finish(EC_POINT *point)
0f113f3e
MC
327{
328 BN_free(point->X);
329 BN_free(point->Y);
330 BN_free(point->Z);
331}
60428dbf
BM
332
333void ec_GFp_simple_point_clear_finish(EC_POINT *point)
0f113f3e
MC
334{
335 BN_clear_free(point->X);
336 BN_clear_free(point->Y);
337 BN_clear_free(point->Z);
338 point->Z_is_one = 0;
339}
60428dbf
BM
340
341int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src)
0f113f3e
MC
342{
343 if (!BN_copy(dest->X, src->X))
344 return 0;
345 if (!BN_copy(dest->Y, src->Y))
346 return 0;
347 if (!BN_copy(dest->Z, src->Z))
348 return 0;
349 dest->Z_is_one = src->Z_is_one;
b14e6015 350 dest->curve_name = src->curve_name;
0f113f3e
MC
351
352 return 1;
353}
354
355int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group,
356 EC_POINT *point)
357{
358 point->Z_is_one = 0;
359 BN_zero(point->Z);
360 return 1;
361}
362
363int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *group,
364 EC_POINT *point,
365 const BIGNUM *x,
366 const BIGNUM *y,
367 const BIGNUM *z,
368 BN_CTX *ctx)
369{
370 BN_CTX *new_ctx = NULL;
371 int ret = 0;
372
373 if (ctx == NULL) {
374 ctx = new_ctx = BN_CTX_new();
375 if (ctx == NULL)
376 return 0;
377 }
378
379 if (x != NULL) {
380 if (!BN_nnmod(point->X, x, group->field, ctx))
381 goto err;
382 if (group->meth->field_encode) {
383 if (!group->meth->field_encode(group, point->X, point->X, ctx))
384 goto err;
385 }
386 }
387
388 if (y != NULL) {
389 if (!BN_nnmod(point->Y, y, group->field, ctx))
390 goto err;
391 if (group->meth->field_encode) {
392 if (!group->meth->field_encode(group, point->Y, point->Y, ctx))
393 goto err;
394 }
395 }
396
397 if (z != NULL) {
398 int Z_is_one;
399
400 if (!BN_nnmod(point->Z, z, group->field, ctx))
401 goto err;
402 Z_is_one = BN_is_one(point->Z);
403 if (group->meth->field_encode) {
404 if (Z_is_one && (group->meth->field_set_to_one != 0)) {
405 if (!group->meth->field_set_to_one(group, point->Z, ctx))
406 goto err;
407 } else {
408 if (!group->
409 meth->field_encode(group, point->Z, point->Z, ctx))
410 goto err;
411 }
412 }
413 point->Z_is_one = Z_is_one;
414 }
415
416 ret = 1;
417
bb62a8b0 418 err:
23a1d5e9 419 BN_CTX_free(new_ctx);
0f113f3e
MC
420 return ret;
421}
422
423int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group,
424 const EC_POINT *point,
425 BIGNUM *x, BIGNUM *y,
426 BIGNUM *z, BN_CTX *ctx)
427{
428 BN_CTX *new_ctx = NULL;
429 int ret = 0;
430
431 if (group->meth->field_decode != 0) {
432 if (ctx == NULL) {
433 ctx = new_ctx = BN_CTX_new();
434 if (ctx == NULL)
435 return 0;
436 }
437
438 if (x != NULL) {
439 if (!group->meth->field_decode(group, x, point->X, ctx))
440 goto err;
441 }
442 if (y != NULL) {
443 if (!group->meth->field_decode(group, y, point->Y, ctx))
444 goto err;
445 }
446 if (z != NULL) {
447 if (!group->meth->field_decode(group, z, point->Z, ctx))
448 goto err;
449 }
450 } else {
451 if (x != NULL) {
452 if (!BN_copy(x, point->X))
453 goto err;
454 }
455 if (y != NULL) {
456 if (!BN_copy(y, point->Y))
457 goto err;
458 }
459 if (z != NULL) {
460 if (!BN_copy(z, point->Z))
461 goto err;
462 }
463 }
464
465 ret = 1;
bb62a8b0 466
226cc7de 467 err:
23a1d5e9 468 BN_CTX_free(new_ctx);
0f113f3e
MC
469 return ret;
470}
471
472int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group,
473 EC_POINT *point,
474 const BIGNUM *x,
475 const BIGNUM *y, BN_CTX *ctx)
476{
477 if (x == NULL || y == NULL) {
478 /*
479 * unlike for projective coordinates, we do not tolerate this
480 */
481 ECerr(EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES,
482 ERR_R_PASSED_NULL_PARAMETER);
483 return 0;
484 }
485
486 return EC_POINT_set_Jprojective_coordinates_GFp(group, point, x, y,
487 BN_value_one(), ctx);
488}
489
490int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group,
491 const EC_POINT *point,
492 BIGNUM *x, BIGNUM *y,
493 BN_CTX *ctx)
494{
495 BN_CTX *new_ctx = NULL;
496 BIGNUM *Z, *Z_1, *Z_2, *Z_3;
497 const BIGNUM *Z_;
498 int ret = 0;
499
500 if (EC_POINT_is_at_infinity(group, point)) {
501 ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES,
502 EC_R_POINT_AT_INFINITY);
503 return 0;
504 }
505
506 if (ctx == NULL) {
507 ctx = new_ctx = BN_CTX_new();
508 if (ctx == NULL)
509 return 0;
510 }
511
512 BN_CTX_start(ctx);
513 Z = BN_CTX_get(ctx);
514 Z_1 = BN_CTX_get(ctx);
515 Z_2 = BN_CTX_get(ctx);
516 Z_3 = BN_CTX_get(ctx);
517 if (Z_3 == NULL)
518 goto err;
519
520 /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */
521
522 if (group->meth->field_decode) {
523 if (!group->meth->field_decode(group, Z, point->Z, ctx))
524 goto err;
525 Z_ = Z;
526 } else {
527 Z_ = point->Z;
528 }
529
530 if (BN_is_one(Z_)) {
531 if (group->meth->field_decode) {
532 if (x != NULL) {
533 if (!group->meth->field_decode(group, x, point->X, ctx))
534 goto err;
535 }
536 if (y != NULL) {
537 if (!group->meth->field_decode(group, y, point->Y, ctx))
538 goto err;
539 }
540 } else {
541 if (x != NULL) {
542 if (!BN_copy(x, point->X))
543 goto err;
544 }
545 if (y != NULL) {
546 if (!BN_copy(y, point->Y))
547 goto err;
548 }
549 }
550 } else {
551 if (!BN_mod_inverse(Z_1, Z_, group->field, ctx)) {
552 ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES,
553 ERR_R_BN_LIB);
554 goto err;
555 }
556
557 if (group->meth->field_encode == 0) {
558 /* field_sqr works on standard representation */
559 if (!group->meth->field_sqr(group, Z_2, Z_1, ctx))
560 goto err;
561 } else {
562 if (!BN_mod_sqr(Z_2, Z_1, group->field, ctx))
563 goto err;
564 }
565
566 if (x != NULL) {
567 /*
568 * in the Montgomery case, field_mul will cancel out Montgomery
569 * factor in X:
570 */
571 if (!group->meth->field_mul(group, x, point->X, Z_2, ctx))
572 goto err;
573 }
574
575 if (y != NULL) {
576 if (group->meth->field_encode == 0) {
577 /*
578 * field_mul works on standard representation
579 */
580 if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx))
581 goto err;
582 } else {
583 if (!BN_mod_mul(Z_3, Z_2, Z_1, group->field, ctx))
584 goto err;
585 }
586
587 /*
588 * in the Montgomery case, field_mul will cancel out Montgomery
589 * factor in Y:
590 */
591 if (!group->meth->field_mul(group, y, point->Y, Z_3, ctx))
592 goto err;
593 }
594 }
595
596 ret = 1;
226cc7de
BM
597
598 err:
0f113f3e 599 BN_CTX_end(ctx);
23a1d5e9 600 BN_CTX_free(new_ctx);
0f113f3e
MC
601 return ret;
602}
603
604int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
605 const EC_POINT *b, BN_CTX *ctx)
606{
607 int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
608 const BIGNUM *, BN_CTX *);
609 int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
610 const BIGNUM *p;
611 BN_CTX *new_ctx = NULL;
612 BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6;
613 int ret = 0;
614
615 if (a == b)
616 return EC_POINT_dbl(group, r, a, ctx);
617 if (EC_POINT_is_at_infinity(group, a))
618 return EC_POINT_copy(r, b);
619 if (EC_POINT_is_at_infinity(group, b))
620 return EC_POINT_copy(r, a);
621
622 field_mul = group->meth->field_mul;
623 field_sqr = group->meth->field_sqr;
624 p = group->field;
625
626 if (ctx == NULL) {
627 ctx = new_ctx = BN_CTX_new();
628 if (ctx == NULL)
629 return 0;
630 }
631
632 BN_CTX_start(ctx);
633 n0 = BN_CTX_get(ctx);
634 n1 = BN_CTX_get(ctx);
635 n2 = BN_CTX_get(ctx);
636 n3 = BN_CTX_get(ctx);
637 n4 = BN_CTX_get(ctx);
638 n5 = BN_CTX_get(ctx);
639 n6 = BN_CTX_get(ctx);
640 if (n6 == NULL)
641 goto end;
642
643 /*
644 * Note that in this function we must not read components of 'a' or 'b'
645 * once we have written the corresponding components of 'r'. ('r' might
646 * be one of 'a' or 'b'.)
647 */
648
649 /* n1, n2 */
650 if (b->Z_is_one) {
651 if (!BN_copy(n1, a->X))
652 goto end;
653 if (!BN_copy(n2, a->Y))
654 goto end;
655 /* n1 = X_a */
656 /* n2 = Y_a */
657 } else {
658 if (!field_sqr(group, n0, b->Z, ctx))
659 goto end;
660 if (!field_mul(group, n1, a->X, n0, ctx))
661 goto end;
662 /* n1 = X_a * Z_b^2 */
663
664 if (!field_mul(group, n0, n0, b->Z, ctx))
665 goto end;
666 if (!field_mul(group, n2, a->Y, n0, ctx))
667 goto end;
668 /* n2 = Y_a * Z_b^3 */
669 }
670
671 /* n3, n4 */
672 if (a->Z_is_one) {
673 if (!BN_copy(n3, b->X))
674 goto end;
675 if (!BN_copy(n4, b->Y))
676 goto end;
677 /* n3 = X_b */
678 /* n4 = Y_b */
679 } else {
680 if (!field_sqr(group, n0, a->Z, ctx))
681 goto end;
682 if (!field_mul(group, n3, b->X, n0, ctx))
683 goto end;
684 /* n3 = X_b * Z_a^2 */
685
686 if (!field_mul(group, n0, n0, a->Z, ctx))
687 goto end;
688 if (!field_mul(group, n4, b->Y, n0, ctx))
689 goto end;
690 /* n4 = Y_b * Z_a^3 */
691 }
692
693 /* n5, n6 */
694 if (!BN_mod_sub_quick(n5, n1, n3, p))
695 goto end;
696 if (!BN_mod_sub_quick(n6, n2, n4, p))
697 goto end;
698 /* n5 = n1 - n3 */
699 /* n6 = n2 - n4 */
700
701 if (BN_is_zero(n5)) {
702 if (BN_is_zero(n6)) {
703 /* a is the same point as b */
704 BN_CTX_end(ctx);
705 ret = EC_POINT_dbl(group, r, a, ctx);
706 ctx = NULL;
707 goto end;
708 } else {
709 /* a is the inverse of b */
710 BN_zero(r->Z);
711 r->Z_is_one = 0;
712 ret = 1;
713 goto end;
714 }
715 }
716
717 /* 'n7', 'n8' */
718 if (!BN_mod_add_quick(n1, n1, n3, p))
719 goto end;
720 if (!BN_mod_add_quick(n2, n2, n4, p))
721 goto end;
722 /* 'n7' = n1 + n3 */
723 /* 'n8' = n2 + n4 */
724
725 /* Z_r */
726 if (a->Z_is_one && b->Z_is_one) {
727 if (!BN_copy(r->Z, n5))
728 goto end;
729 } else {
730 if (a->Z_is_one) {
731 if (!BN_copy(n0, b->Z))
732 goto end;
733 } else if (b->Z_is_one) {
734 if (!BN_copy(n0, a->Z))
735 goto end;
736 } else {
737 if (!field_mul(group, n0, a->Z, b->Z, ctx))
738 goto end;
739 }
740 if (!field_mul(group, r->Z, n0, n5, ctx))
741 goto end;
742 }
743 r->Z_is_one = 0;
744 /* Z_r = Z_a * Z_b * n5 */
745
746 /* X_r */
747 if (!field_sqr(group, n0, n6, ctx))
748 goto end;
749 if (!field_sqr(group, n4, n5, ctx))
750 goto end;
751 if (!field_mul(group, n3, n1, n4, ctx))
752 goto end;
753 if (!BN_mod_sub_quick(r->X, n0, n3, p))
754 goto end;
755 /* X_r = n6^2 - n5^2 * 'n7' */
756
757 /* 'n9' */
758 if (!BN_mod_lshift1_quick(n0, r->X, p))
759 goto end;
760 if (!BN_mod_sub_quick(n0, n3, n0, p))
761 goto end;
762 /* n9 = n5^2 * 'n7' - 2 * X_r */
763
764 /* Y_r */
765 if (!field_mul(group, n0, n0, n6, ctx))
766 goto end;
767 if (!field_mul(group, n5, n4, n5, ctx))
768 goto end; /* now n5 is n5^3 */
769 if (!field_mul(group, n1, n2, n5, ctx))
770 goto end;
771 if (!BN_mod_sub_quick(n0, n0, n1, p))
772 goto end;
773 if (BN_is_odd(n0))
774 if (!BN_add(n0, n0, p))
775 goto end;
776 /* now 0 <= n0 < 2*p, and n0 is even */
777 if (!BN_rshift1(r->Y, n0))
778 goto end;
779 /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */
780
781 ret = 1;
60428dbf
BM
782
783 end:
0f113f3e
MC
784 if (ctx) /* otherwise we already called BN_CTX_end */
785 BN_CTX_end(ctx);
23a1d5e9 786 BN_CTX_free(new_ctx);
0f113f3e
MC
787 return ret;
788}
789
790int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
791 BN_CTX *ctx)
792{
793 int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
794 const BIGNUM *, BN_CTX *);
795 int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
796 const BIGNUM *p;
797 BN_CTX *new_ctx = NULL;
798 BIGNUM *n0, *n1, *n2, *n3;
799 int ret = 0;
800
801 if (EC_POINT_is_at_infinity(group, a)) {
802 BN_zero(r->Z);
803 r->Z_is_one = 0;
804 return 1;
805 }
806
807 field_mul = group->meth->field_mul;
808 field_sqr = group->meth->field_sqr;
809 p = group->field;
810
811 if (ctx == NULL) {
812 ctx = new_ctx = BN_CTX_new();
813 if (ctx == NULL)
814 return 0;
815 }
816
817 BN_CTX_start(ctx);
818 n0 = BN_CTX_get(ctx);
819 n1 = BN_CTX_get(ctx);
820 n2 = BN_CTX_get(ctx);
821 n3 = BN_CTX_get(ctx);
822 if (n3 == NULL)
823 goto err;
824
825 /*
826 * Note that in this function we must not read components of 'a' once we
827 * have written the corresponding components of 'r'. ('r' might the same
828 * as 'a'.)
829 */
830
831 /* n1 */
832 if (a->Z_is_one) {
833 if (!field_sqr(group, n0, a->X, ctx))
834 goto err;
835 if (!BN_mod_lshift1_quick(n1, n0, p))
836 goto err;
837 if (!BN_mod_add_quick(n0, n0, n1, p))
838 goto err;
839 if (!BN_mod_add_quick(n1, n0, group->a, p))
840 goto err;
841 /* n1 = 3 * X_a^2 + a_curve */
842 } else if (group->a_is_minus3) {
843 if (!field_sqr(group, n1, a->Z, ctx))
844 goto err;
845 if (!BN_mod_add_quick(n0, a->X, n1, p))
846 goto err;
847 if (!BN_mod_sub_quick(n2, a->X, n1, p))
848 goto err;
849 if (!field_mul(group, n1, n0, n2, ctx))
850 goto err;
851 if (!BN_mod_lshift1_quick(n0, n1, p))
852 goto err;
853 if (!BN_mod_add_quick(n1, n0, n1, p))
854 goto err;
35a1cc90
MC
855 /*-
856 * n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2)
857 * = 3 * X_a^2 - 3 * Z_a^4
858 */
0f113f3e
MC
859 } else {
860 if (!field_sqr(group, n0, a->X, ctx))
861 goto err;
862 if (!BN_mod_lshift1_quick(n1, n0, p))
863 goto err;
864 if (!BN_mod_add_quick(n0, n0, n1, p))
865 goto err;
866 if (!field_sqr(group, n1, a->Z, ctx))
867 goto err;
868 if (!field_sqr(group, n1, n1, ctx))
869 goto err;
870 if (!field_mul(group, n1, n1, group->a, ctx))
871 goto err;
872 if (!BN_mod_add_quick(n1, n1, n0, p))
873 goto err;
874 /* n1 = 3 * X_a^2 + a_curve * Z_a^4 */
875 }
876
877 /* Z_r */
878 if (a->Z_is_one) {
879 if (!BN_copy(n0, a->Y))
880 goto err;
881 } else {
882 if (!field_mul(group, n0, a->Y, a->Z, ctx))
883 goto err;
884 }
885 if (!BN_mod_lshift1_quick(r->Z, n0, p))
886 goto err;
887 r->Z_is_one = 0;
888 /* Z_r = 2 * Y_a * Z_a */
889
890 /* n2 */
891 if (!field_sqr(group, n3, a->Y, ctx))
892 goto err;
893 if (!field_mul(group, n2, a->X, n3, ctx))
894 goto err;
895 if (!BN_mod_lshift_quick(n2, n2, 2, p))
896 goto err;
897 /* n2 = 4 * X_a * Y_a^2 */
898
899 /* X_r */
900 if (!BN_mod_lshift1_quick(n0, n2, p))
901 goto err;
902 if (!field_sqr(group, r->X, n1, ctx))
903 goto err;
904 if (!BN_mod_sub_quick(r->X, r->X, n0, p))
905 goto err;
906 /* X_r = n1^2 - 2 * n2 */
907
908 /* n3 */
909 if (!field_sqr(group, n0, n3, ctx))
910 goto err;
911 if (!BN_mod_lshift_quick(n3, n0, 3, p))
912 goto err;
913 /* n3 = 8 * Y_a^4 */
914
915 /* Y_r */
916 if (!BN_mod_sub_quick(n0, n2, r->X, p))
917 goto err;
918 if (!field_mul(group, n0, n1, n0, ctx))
919 goto err;
920 if (!BN_mod_sub_quick(r->Y, n0, n3, p))
921 goto err;
922 /* Y_r = n1 * (n2 - X_r) - n3 */
923
924 ret = 1;
60428dbf
BM
925
926 err:
0f113f3e 927 BN_CTX_end(ctx);
23a1d5e9 928 BN_CTX_free(new_ctx);
0f113f3e
MC
929 return ret;
930}
60428dbf 931
bb62a8b0 932int ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx)
0f113f3e
MC
933{
934 if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(point->Y))
935 /* point is its own inverse */
936 return 1;
1d5bd6cf 937
0f113f3e
MC
938 return BN_usub(point->Y, group->field, point->Y);
939}
1d5bd6cf 940
60428dbf 941int ec_GFp_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point)
0f113f3e
MC
942{
943 return BN_is_zero(point->Z);
944}
945
946int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
947 BN_CTX *ctx)
948{
949 int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
950 const BIGNUM *, BN_CTX *);
951 int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
952 const BIGNUM *p;
953 BN_CTX *new_ctx = NULL;
954 BIGNUM *rh, *tmp, *Z4, *Z6;
955 int ret = -1;
956
957 if (EC_POINT_is_at_infinity(group, point))
958 return 1;
959
960 field_mul = group->meth->field_mul;
961 field_sqr = group->meth->field_sqr;
962 p = group->field;
963
964 if (ctx == NULL) {
965 ctx = new_ctx = BN_CTX_new();
966 if (ctx == NULL)
967 return -1;
968 }
969
970 BN_CTX_start(ctx);
971 rh = BN_CTX_get(ctx);
972 tmp = BN_CTX_get(ctx);
973 Z4 = BN_CTX_get(ctx);
974 Z6 = BN_CTX_get(ctx);
975 if (Z6 == NULL)
976 goto err;
977
35a1cc90
MC
978 /*-
979 * We have a curve defined by a Weierstrass equation
980 * y^2 = x^3 + a*x + b.
981 * The point to consider is given in Jacobian projective coordinates
982 * where (X, Y, Z) represents (x, y) = (X/Z^2, Y/Z^3).
983 * Substituting this and multiplying by Z^6 transforms the above equation into
984 * Y^2 = X^3 + a*X*Z^4 + b*Z^6.
985 * To test this, we add up the right-hand side in 'rh'.
986 */
0f113f3e
MC
987
988 /* rh := X^2 */
989 if (!field_sqr(group, rh, point->X, ctx))
990 goto err;
991
992 if (!point->Z_is_one) {
993 if (!field_sqr(group, tmp, point->Z, ctx))
994 goto err;
995 if (!field_sqr(group, Z4, tmp, ctx))
996 goto err;
997 if (!field_mul(group, Z6, Z4, tmp, ctx))
998 goto err;
999
1000 /* rh := (rh + a*Z^4)*X */
1001 if (group->a_is_minus3) {
1002 if (!BN_mod_lshift1_quick(tmp, Z4, p))
1003 goto err;
1004 if (!BN_mod_add_quick(tmp, tmp, Z4, p))
1005 goto err;
1006 if (!BN_mod_sub_quick(rh, rh, tmp, p))
1007 goto err;
1008 if (!field_mul(group, rh, rh, point->X, ctx))
1009 goto err;
1010 } else {
1011 if (!field_mul(group, tmp, Z4, group->a, ctx))
1012 goto err;
1013 if (!BN_mod_add_quick(rh, rh, tmp, p))
1014 goto err;
1015 if (!field_mul(group, rh, rh, point->X, ctx))
1016 goto err;
1017 }
1018
1019 /* rh := rh + b*Z^6 */
1020 if (!field_mul(group, tmp, group->b, Z6, ctx))
1021 goto err;
1022 if (!BN_mod_add_quick(rh, rh, tmp, p))
1023 goto err;
1024 } else {
1025 /* point->Z_is_one */
1026
1027 /* rh := (rh + a)*X */
1028 if (!BN_mod_add_quick(rh, rh, group->a, p))
1029 goto err;
1030 if (!field_mul(group, rh, rh, point->X, ctx))
1031 goto err;
1032 /* rh := rh + b */
1033 if (!BN_mod_add_quick(rh, rh, group->b, p))
1034 goto err;
1035 }
1036
1037 /* 'lh' := Y^2 */
1038 if (!field_sqr(group, tmp, point->Y, ctx))
1039 goto err;
1040
1041 ret = (0 == BN_ucmp(tmp, rh));
e869d4bd
BM
1042
1043 err:
0f113f3e 1044 BN_CTX_end(ctx);
23a1d5e9 1045 BN_CTX_free(new_ctx);
0f113f3e
MC
1046 return ret;
1047}
1048
1049int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
1050 const EC_POINT *b, BN_CTX *ctx)
1051{
35a1cc90
MC
1052 /*-
1053 * return values:
1054 * -1 error
1055 * 0 equal (in affine coordinates)
1056 * 1 not equal
1057 */
0f113f3e
MC
1058
1059 int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
1060 const BIGNUM *, BN_CTX *);
1061 int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
1062 BN_CTX *new_ctx = NULL;
1063 BIGNUM *tmp1, *tmp2, *Za23, *Zb23;
1064 const BIGNUM *tmp1_, *tmp2_;
1065 int ret = -1;
1066
1067 if (EC_POINT_is_at_infinity(group, a)) {
1068 return EC_POINT_is_at_infinity(group, b) ? 0 : 1;
1069 }
1070
1071 if (EC_POINT_is_at_infinity(group, b))
1072 return 1;
1073
1074 if (a->Z_is_one && b->Z_is_one) {
1075 return ((BN_cmp(a->X, b->X) == 0) && BN_cmp(a->Y, b->Y) == 0) ? 0 : 1;
1076 }
1077
1078 field_mul = group->meth->field_mul;
1079 field_sqr = group->meth->field_sqr;
1080
1081 if (ctx == NULL) {
1082 ctx = new_ctx = BN_CTX_new();
1083 if (ctx == NULL)
1084 return -1;
1085 }
1086
1087 BN_CTX_start(ctx);
1088 tmp1 = BN_CTX_get(ctx);
1089 tmp2 = BN_CTX_get(ctx);
1090 Za23 = BN_CTX_get(ctx);
1091 Zb23 = BN_CTX_get(ctx);
1092 if (Zb23 == NULL)
1093 goto end;
1094
35a1cc90
MC
1095 /*-
1096 * We have to decide whether
1097 * (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3),
1098 * or equivalently, whether
1099 * (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3).
1100 */
0f113f3e
MC
1101
1102 if (!b->Z_is_one) {
1103 if (!field_sqr(group, Zb23, b->Z, ctx))
1104 goto end;
1105 if (!field_mul(group, tmp1, a->X, Zb23, ctx))
1106 goto end;
1107 tmp1_ = tmp1;
1108 } else
1109 tmp1_ = a->X;
1110 if (!a->Z_is_one) {
1111 if (!field_sqr(group, Za23, a->Z, ctx))
1112 goto end;
1113 if (!field_mul(group, tmp2, b->X, Za23, ctx))
1114 goto end;
1115 tmp2_ = tmp2;
1116 } else
1117 tmp2_ = b->X;
1118
1119 /* compare X_a*Z_b^2 with X_b*Z_a^2 */
1120 if (BN_cmp(tmp1_, tmp2_) != 0) {
1121 ret = 1; /* points differ */
1122 goto end;
1123 }
1124
1125 if (!b->Z_is_one) {
1126 if (!field_mul(group, Zb23, Zb23, b->Z, ctx))
1127 goto end;
1128 if (!field_mul(group, tmp1, a->Y, Zb23, ctx))
1129 goto end;
1130 /* tmp1_ = tmp1 */
1131 } else
1132 tmp1_ = a->Y;
1133 if (!a->Z_is_one) {
1134 if (!field_mul(group, Za23, Za23, a->Z, ctx))
1135 goto end;
1136 if (!field_mul(group, tmp2, b->Y, Za23, ctx))
1137 goto end;
1138 /* tmp2_ = tmp2 */
1139 } else
1140 tmp2_ = b->Y;
1141
1142 /* compare Y_a*Z_b^3 with Y_b*Z_a^3 */
1143 if (BN_cmp(tmp1_, tmp2_) != 0) {
1144 ret = 1; /* points differ */
1145 goto end;
1146 }
1147
1148 /* points are equal */
1149 ret = 0;
bb62a8b0
BM
1150
1151 end:
0f113f3e 1152 BN_CTX_end(ctx);
23a1d5e9 1153 BN_CTX_free(new_ctx);
0f113f3e
MC
1154 return ret;
1155}
1156
1157int ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point,
1158 BN_CTX *ctx)
1159{
1160 BN_CTX *new_ctx = NULL;
1161 BIGNUM *x, *y;
1162 int ret = 0;
1163
1164 if (point->Z_is_one || EC_POINT_is_at_infinity(group, point))
1165 return 1;
1166
1167 if (ctx == NULL) {
1168 ctx = new_ctx = BN_CTX_new();
1169 if (ctx == NULL)
1170 return 0;
1171 }
1172
1173 BN_CTX_start(ctx);
1174 x = BN_CTX_get(ctx);
1175 y = BN_CTX_get(ctx);
1176 if (y == NULL)
1177 goto err;
1178
1179 if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx))
1180 goto err;
1181 if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx))
1182 goto err;
1183 if (!point->Z_is_one) {
1184 ECerr(EC_F_EC_GFP_SIMPLE_MAKE_AFFINE, ERR_R_INTERNAL_ERROR);
1185 goto err;
1186 }
1187
1188 ret = 1;
e869d4bd 1189
226cc7de 1190 err:
0f113f3e 1191 BN_CTX_end(ctx);
23a1d5e9 1192 BN_CTX_free(new_ctx);
0f113f3e
MC
1193 return ret;
1194}
1195
1196int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num,
1197 EC_POINT *points[], BN_CTX *ctx)
1198{
1199 BN_CTX *new_ctx = NULL;
1200 BIGNUM *tmp, *tmp_Z;
1201 BIGNUM **prod_Z = NULL;
1202 size_t i;
1203 int ret = 0;
1204
1205 if (num == 0)
1206 return 1;
1207
1208 if (ctx == NULL) {
1209 ctx = new_ctx = BN_CTX_new();
1210 if (ctx == NULL)
1211 return 0;
1212 }
1213
1214 BN_CTX_start(ctx);
1215 tmp = BN_CTX_get(ctx);
1216 tmp_Z = BN_CTX_get(ctx);
edea42c6 1217 if (tmp_Z == NULL)
0f113f3e
MC
1218 goto err;
1219
cbe29648 1220 prod_Z = OPENSSL_malloc(num * sizeof(prod_Z[0]));
0f113f3e
MC
1221 if (prod_Z == NULL)
1222 goto err;
1223 for (i = 0; i < num; i++) {
1224 prod_Z[i] = BN_new();
1225 if (prod_Z[i] == NULL)
1226 goto err;
1227 }
1228
1229 /*
1230 * Set each prod_Z[i] to the product of points[0]->Z .. points[i]->Z,
1231 * skipping any zero-valued inputs (pretend that they're 1).
1232 */
1233
1234 if (!BN_is_zero(points[0]->Z)) {
1235 if (!BN_copy(prod_Z[0], points[0]->Z))
1236 goto err;
1237 } else {
1238 if (group->meth->field_set_to_one != 0) {
1239 if (!group->meth->field_set_to_one(group, prod_Z[0], ctx))
1240 goto err;
1241 } else {
1242 if (!BN_one(prod_Z[0]))
1243 goto err;
1244 }
1245 }
1246
1247 for (i = 1; i < num; i++) {
1248 if (!BN_is_zero(points[i]->Z)) {
1249 if (!group->
1250 meth->field_mul(group, prod_Z[i], prod_Z[i - 1], points[i]->Z,
1251 ctx))
1252 goto err;
1253 } else {
1254 if (!BN_copy(prod_Z[i], prod_Z[i - 1]))
1255 goto err;
1256 }
1257 }
1258
1259 /*
1260 * Now use a single explicit inversion to replace every non-zero
1261 * points[i]->Z by its inverse.
1262 */
1263
1264 if (!BN_mod_inverse(tmp, prod_Z[num - 1], group->field, ctx)) {
1265 ECerr(EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE, ERR_R_BN_LIB);
1266 goto err;
1267 }
1268 if (group->meth->field_encode != 0) {
1269 /*
1270 * In the Montgomery case, we just turned R*H (representing H) into
1271 * 1/(R*H), but we need R*(1/H) (representing 1/H); i.e. we need to
1272 * multiply by the Montgomery factor twice.
1273 */
1274 if (!group->meth->field_encode(group, tmp, tmp, ctx))
1275 goto err;
1276 if (!group->meth->field_encode(group, tmp, tmp, ctx))
1277 goto err;
1278 }
1279
1280 for (i = num - 1; i > 0; --i) {
1281 /*
1282 * Loop invariant: tmp is the product of the inverses of points[0]->Z
1283 * .. points[i]->Z (zero-valued inputs skipped).
1284 */
1285 if (!BN_is_zero(points[i]->Z)) {
1286 /*
1287 * Set tmp_Z to the inverse of points[i]->Z (as product of Z
1288 * inverses 0 .. i, Z values 0 .. i - 1).
1289 */
1290 if (!group->
1291 meth->field_mul(group, tmp_Z, prod_Z[i - 1], tmp, ctx))
1292 goto err;
1293 /*
1294 * Update tmp to satisfy the loop invariant for i - 1.
1295 */
1296 if (!group->meth->field_mul(group, tmp, tmp, points[i]->Z, ctx))
1297 goto err;
1298 /* Replace points[i]->Z by its inverse. */
1299 if (!BN_copy(points[i]->Z, tmp_Z))
1300 goto err;
1301 }
1302 }
1303
1304 if (!BN_is_zero(points[0]->Z)) {
1305 /* Replace points[0]->Z by its inverse. */
1306 if (!BN_copy(points[0]->Z, tmp))
1307 goto err;
1308 }
1309
1310 /* Finally, fix up the X and Y coordinates for all points. */
1311
1312 for (i = 0; i < num; i++) {
1313 EC_POINT *p = points[i];
1314
1315 if (!BN_is_zero(p->Z)) {
1316 /* turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1) */
1317
1318 if (!group->meth->field_sqr(group, tmp, p->Z, ctx))
1319 goto err;
1320 if (!group->meth->field_mul(group, p->X, p->X, tmp, ctx))
1321 goto err;
1322
1323 if (!group->meth->field_mul(group, tmp, tmp, p->Z, ctx))
1324 goto err;
1325 if (!group->meth->field_mul(group, p->Y, p->Y, tmp, ctx))
1326 goto err;
1327
1328 if (group->meth->field_set_to_one != 0) {
1329 if (!group->meth->field_set_to_one(group, p->Z, ctx))
1330 goto err;
1331 } else {
1332 if (!BN_one(p->Z))
1333 goto err;
1334 }
1335 p->Z_is_one = 1;
1336 }
1337 }
1338
1339 ret = 1;
0fe73d6c 1340
48fe4d62 1341 err:
0f113f3e 1342 BN_CTX_end(ctx);
23a1d5e9 1343 BN_CTX_free(new_ctx);
0f113f3e
MC
1344 if (prod_Z != NULL) {
1345 for (i = 0; i < num; i++) {
1346 if (prod_Z[i] == NULL)
1347 break;
1348 BN_clear_free(prod_Z[i]);
1349 }
1350 OPENSSL_free(prod_Z);
1351 }
1352 return ret;
1353}
1354
1355int ec_GFp_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
1356 const BIGNUM *b, BN_CTX *ctx)
1357{
1358 return BN_mod_mul(r, a, b, group->field, ctx);
1359}
1360
1361int ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
1362 BN_CTX *ctx)
1363{
1364 return BN_mod_sqr(r, a, group->field, ctx);
1365}