blob: 57a9099def47407d40bb4f6c348aa378cca064db [file] [log] [blame]
Adam Langleyd9e397b2015-01-22 14:27:53 -08001/* Originally written by Bodo Moeller for the OpenSSL project.
2 * ====================================================================
3 * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
16 *
17 * 3. All advertising materials mentioning features or use of this
18 * software must display the following acknowledgment:
19 * "This product includes software developed by the OpenSSL Project
20 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21 *
22 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23 * endorse or promote products derived from this software without
24 * prior written permission. For written permission, please contact
25 * openssl-core@openssl.org.
26 *
27 * 5. Products derived from this software may not be called "OpenSSL"
28 * nor may "OpenSSL" appear in their names without prior written
29 * permission of the OpenSSL Project.
30 *
31 * 6. Redistributions of any form whatsoever must retain the following
32 * acknowledgment:
33 * "This product includes software developed by the OpenSSL Project
34 * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47 * OF THE POSSIBILITY OF SUCH DAMAGE.
48 * ====================================================================
49 *
50 * This product includes cryptographic software written by Eric Young
51 * (eay@cryptsoft.com). This product includes software written by Tim
52 * Hudson (tjh@cryptsoft.com).
53 *
54 */
55/* ====================================================================
56 * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
57 *
58 * Portions of the attached software ("Contribution") are developed by
59 * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
60 *
61 * The Contribution is licensed pursuant to the OpenSSL open source
62 * license provided above.
63 *
64 * The elliptic curve binary polynomial software is originally written by
65 * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
66 * Laboratories. */
67
68#include <openssl/ec.h>
69
70#include <string.h>
71
72#include <openssl/bn.h>
73#include <openssl/err.h>
74#include <openssl/mem.h>
75
76#include "internal.h"
Robert Sloan8ff03552017-06-14 12:40:58 -070077#include "../../internal.h"
Adam Langleyd9e397b2015-01-22 14:27:53 -080078
79
Robert Sloan8f860b12017-08-28 07:37:06 -070080// Most method functions in this file are designed to work with non-trivial
81// representations of field elements if necessary (see ecp_mont.c): while
82// standard modular addition and subtraction are used, the field_mul and
83// field_sqr methods will be used for multiplication, and field_encode and
84// field_decode (if defined) will be used for converting between
85// representations.
86//
87// Functions here specifically assume that if a non-trivial representation is
88// used, it is a Montgomery representation (i.e. 'encoding' means multiplying
89// by some factor R).
Adam Langleyd9e397b2015-01-22 14:27:53 -080090
91int ec_GFp_simple_group_init(EC_GROUP *group) {
92 BN_init(&group->field);
93 BN_init(&group->a);
94 BN_init(&group->b);
David Benjamin4969cc92016-04-22 15:02:23 -040095 BN_init(&group->one);
Adam Langleyd9e397b2015-01-22 14:27:53 -080096 group->a_is_minus3 = 0;
97 return 1;
98}
99
100void ec_GFp_simple_group_finish(EC_GROUP *group) {
101 BN_free(&group->field);
102 BN_free(&group->a);
103 BN_free(&group->b);
David Benjamin4969cc92016-04-22 15:02:23 -0400104 BN_free(&group->one);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800105}
106
Adam Langleyd9e397b2015-01-22 14:27:53 -0800107int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p,
108 const BIGNUM *a, const BIGNUM *b,
109 BN_CTX *ctx) {
110 int ret = 0;
111 BN_CTX *new_ctx = NULL;
112 BIGNUM *tmp_a;
113
Robert Sloan8f860b12017-08-28 07:37:06 -0700114 // p must be a prime > 3
Adam Langleyd9e397b2015-01-22 14:27:53 -0800115 if (BN_num_bits(p) <= 2 || !BN_is_odd(p)) {
Kenny Rootb8494592015-09-25 02:29:14 +0000116 OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FIELD);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800117 return 0;
118 }
119
120 if (ctx == NULL) {
121 ctx = new_ctx = BN_CTX_new();
Adam Langleye9ada862015-05-11 17:20:37 -0700122 if (ctx == NULL) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800123 return 0;
Adam Langleye9ada862015-05-11 17:20:37 -0700124 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800125 }
126
127 BN_CTX_start(ctx);
128 tmp_a = BN_CTX_get(ctx);
Adam Langleye9ada862015-05-11 17:20:37 -0700129 if (tmp_a == NULL) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800130 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700131 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800132
Robert Sloan8f860b12017-08-28 07:37:06 -0700133 // group->field
Adam Langleye9ada862015-05-11 17:20:37 -0700134 if (!BN_copy(&group->field, p)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800135 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700136 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800137 BN_set_negative(&group->field, 0);
Robert Sloanab8b8882018-03-26 11:39:51 -0700138 // Store the field in minimal form, so it can be used with |BN_ULONG| arrays.
139 bn_set_minimal_width(&group->field);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800140
Robert Sloan8f860b12017-08-28 07:37:06 -0700141 // group->a
Robert Sloanab8b8882018-03-26 11:39:51 -0700142 if (!BN_nnmod(tmp_a, a, &group->field, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800143 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700144 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800145 if (group->meth->field_encode) {
Adam Langleye9ada862015-05-11 17:20:37 -0700146 if (!group->meth->field_encode(group, &group->a, tmp_a, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800147 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700148 }
149 } else if (!BN_copy(&group->a, tmp_a)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800150 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700151 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800152
Robert Sloan8f860b12017-08-28 07:37:06 -0700153 // group->b
Robert Sloanab8b8882018-03-26 11:39:51 -0700154 if (!BN_nnmod(&group->b, b, &group->field, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800155 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700156 }
157 if (group->meth->field_encode &&
158 !group->meth->field_encode(group, &group->b, &group->b, ctx)) {
159 goto err;
160 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800161
Robert Sloan8f860b12017-08-28 07:37:06 -0700162 // group->a_is_minus3
Adam Langleye9ada862015-05-11 17:20:37 -0700163 if (!BN_add_word(tmp_a, 3)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800164 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700165 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800166 group->a_is_minus3 = (0 == BN_cmp(tmp_a, &group->field));
167
David Benjamin4969cc92016-04-22 15:02:23 -0400168 if (group->meth->field_encode != NULL) {
169 if (!group->meth->field_encode(group, &group->one, BN_value_one(), ctx)) {
170 goto err;
171 }
172 } else if (!BN_copy(&group->one, BN_value_one())) {
173 goto err;
174 }
175
Adam Langleyd9e397b2015-01-22 14:27:53 -0800176 ret = 1;
177
178err:
179 BN_CTX_end(ctx);
Adam Langleye9ada862015-05-11 17:20:37 -0700180 BN_CTX_free(new_ctx);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800181 return ret;
182}
183
184int ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
185 BIGNUM *b, BN_CTX *ctx) {
186 int ret = 0;
187 BN_CTX *new_ctx = NULL;
188
Adam Langleye9ada862015-05-11 17:20:37 -0700189 if (p != NULL && !BN_copy(p, &group->field)) {
190 return 0;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800191 }
192
193 if (a != NULL || b != NULL) {
194 if (group->meth->field_decode) {
195 if (ctx == NULL) {
196 ctx = new_ctx = BN_CTX_new();
Adam Langleye9ada862015-05-11 17:20:37 -0700197 if (ctx == NULL) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800198 return 0;
Adam Langleye9ada862015-05-11 17:20:37 -0700199 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800200 }
Adam Langleye9ada862015-05-11 17:20:37 -0700201 if (a != NULL && !group->meth->field_decode(group, a, &group->a, ctx)) {
202 goto err;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800203 }
Adam Langleye9ada862015-05-11 17:20:37 -0700204 if (b != NULL && !group->meth->field_decode(group, b, &group->b, ctx)) {
205 goto err;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800206 }
207 } else {
Adam Langleye9ada862015-05-11 17:20:37 -0700208 if (a != NULL && !BN_copy(a, &group->a)) {
209 goto err;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800210 }
Adam Langleye9ada862015-05-11 17:20:37 -0700211 if (b != NULL && !BN_copy(b, &group->b)) {
212 goto err;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800213 }
214 }
215 }
216
217 ret = 1;
218
219err:
Adam Langleye9ada862015-05-11 17:20:37 -0700220 BN_CTX_free(new_ctx);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800221 return ret;
222}
223
Kenny Roote99801b2015-11-06 15:31:15 -0800224unsigned ec_GFp_simple_group_get_degree(const EC_GROUP *group) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800225 return BN_num_bits(&group->field);
226}
227
Adam Langleyd9e397b2015-01-22 14:27:53 -0800228int ec_GFp_simple_point_init(EC_POINT *point) {
229 BN_init(&point->X);
230 BN_init(&point->Y);
231 BN_init(&point->Z);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800232
233 return 1;
234}
235
236void ec_GFp_simple_point_finish(EC_POINT *point) {
237 BN_free(&point->X);
238 BN_free(&point->Y);
239 BN_free(&point->Z);
240}
241
Adam Langleyd9e397b2015-01-22 14:27:53 -0800242int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) {
Adam Langleye9ada862015-05-11 17:20:37 -0700243 if (!BN_copy(&dest->X, &src->X) ||
244 !BN_copy(&dest->Y, &src->Y) ||
245 !BN_copy(&dest->Z, &src->Z)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800246 return 0;
Adam Langleye9ada862015-05-11 17:20:37 -0700247 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800248
249 return 1;
250}
251
252int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group,
253 EC_POINT *point) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800254 BN_zero(&point->Z);
255 return 1;
256}
257
David Benjamin4969cc92016-04-22 15:02:23 -0400258static int set_Jprojective_coordinate_GFp(const EC_GROUP *group, BIGNUM *out,
259 const BIGNUM *in, BN_CTX *ctx) {
260 if (in == NULL) {
261 return 1;
262 }
263 if (BN_is_negative(in) ||
264 BN_cmp(in, &group->field) >= 0) {
265 OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE);
266 return 0;
267 }
268 if (group->meth->field_encode) {
269 return group->meth->field_encode(group, out, in, ctx);
270 }
271 return BN_copy(out, in) != NULL;
272}
273
Robert Sloan0db7f542018-01-16 15:48:33 -0800274int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group,
275 EC_POINT *point, const BIGNUM *x,
276 const BIGNUM *y, BN_CTX *ctx) {
277 if (x == NULL || y == NULL) {
278 OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
279 return 0;
280 }
281
Adam Langleyd9e397b2015-01-22 14:27:53 -0800282 BN_CTX *new_ctx = NULL;
283 int ret = 0;
284
285 if (ctx == NULL) {
286 ctx = new_ctx = BN_CTX_new();
Adam Langleye9ada862015-05-11 17:20:37 -0700287 if (ctx == NULL) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800288 return 0;
Adam Langleye9ada862015-05-11 17:20:37 -0700289 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800290 }
291
David Benjamin4969cc92016-04-22 15:02:23 -0400292 if (!set_Jprojective_coordinate_GFp(group, &point->X, x, ctx) ||
293 !set_Jprojective_coordinate_GFp(group, &point->Y, y, ctx) ||
Robert Sloan0db7f542018-01-16 15:48:33 -0800294 !BN_copy(&point->Z, &group->one)) {
David Benjamin4969cc92016-04-22 15:02:23 -0400295 goto err;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800296 }
297
298 ret = 1;
299
300err:
Adam Langleye9ada862015-05-11 17:20:37 -0700301 BN_CTX_free(new_ctx);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800302 return ret;
303}
304
Adam Langleyd9e397b2015-01-22 14:27:53 -0800305int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
306 const EC_POINT *b, BN_CTX *ctx) {
307 int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *,
308 BN_CTX *);
309 int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
310 const BIGNUM *p;
311 BN_CTX *new_ctx = NULL;
312 BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6;
313 int ret = 0;
314
Adam Langleye9ada862015-05-11 17:20:37 -0700315 if (a == b) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800316 return EC_POINT_dbl(group, r, a, ctx);
Adam Langleye9ada862015-05-11 17:20:37 -0700317 }
318 if (EC_POINT_is_at_infinity(group, a)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800319 return EC_POINT_copy(r, b);
Adam Langleye9ada862015-05-11 17:20:37 -0700320 }
321 if (EC_POINT_is_at_infinity(group, b)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800322 return EC_POINT_copy(r, a);
Adam Langleye9ada862015-05-11 17:20:37 -0700323 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800324
325 field_mul = group->meth->field_mul;
326 field_sqr = group->meth->field_sqr;
327 p = &group->field;
328
329 if (ctx == NULL) {
330 ctx = new_ctx = BN_CTX_new();
Adam Langleye9ada862015-05-11 17:20:37 -0700331 if (ctx == NULL) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800332 return 0;
Adam Langleye9ada862015-05-11 17:20:37 -0700333 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800334 }
335
336 BN_CTX_start(ctx);
337 n0 = BN_CTX_get(ctx);
338 n1 = BN_CTX_get(ctx);
339 n2 = BN_CTX_get(ctx);
340 n3 = BN_CTX_get(ctx);
341 n4 = BN_CTX_get(ctx);
342 n5 = BN_CTX_get(ctx);
343 n6 = BN_CTX_get(ctx);
Adam Langleye9ada862015-05-11 17:20:37 -0700344 if (n6 == NULL) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800345 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700346 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800347
Robert Sloan8f860b12017-08-28 07:37:06 -0700348 // Note that in this function we must not read components of 'a' or 'b'
349 // once we have written the corresponding components of 'r'.
350 // ('r' might be one of 'a' or 'b'.)
Adam Langleyd9e397b2015-01-22 14:27:53 -0800351
Robert Sloan8f860b12017-08-28 07:37:06 -0700352 // n1, n2
David Benjamin4969cc92016-04-22 15:02:23 -0400353 int b_Z_is_one = BN_cmp(&b->Z, &group->one) == 0;
354
355 if (b_Z_is_one) {
Adam Langleye9ada862015-05-11 17:20:37 -0700356 if (!BN_copy(n1, &a->X) || !BN_copy(n2, &a->Y)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800357 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700358 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700359 // n1 = X_a
360 // n2 = Y_a
Adam Langleyd9e397b2015-01-22 14:27:53 -0800361 } else {
Adam Langleye9ada862015-05-11 17:20:37 -0700362 if (!field_sqr(group, n0, &b->Z, ctx) ||
363 !field_mul(group, n1, &a->X, n0, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800364 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700365 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700366 // n1 = X_a * Z_b^2
Adam Langleyd9e397b2015-01-22 14:27:53 -0800367
Adam Langleye9ada862015-05-11 17:20:37 -0700368 if (!field_mul(group, n0, n0, &b->Z, ctx) ||
369 !field_mul(group, n2, &a->Y, n0, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800370 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700371 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700372 // n2 = Y_a * Z_b^3
Adam Langleyd9e397b2015-01-22 14:27:53 -0800373 }
374
Robert Sloan8f860b12017-08-28 07:37:06 -0700375 // n3, n4
David Benjamin4969cc92016-04-22 15:02:23 -0400376 int a_Z_is_one = BN_cmp(&a->Z, &group->one) == 0;
377 if (a_Z_is_one) {
Adam Langleye9ada862015-05-11 17:20:37 -0700378 if (!BN_copy(n3, &b->X) || !BN_copy(n4, &b->Y)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800379 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700380 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700381 // n3 = X_b
382 // n4 = Y_b
Adam Langleyd9e397b2015-01-22 14:27:53 -0800383 } else {
Adam Langleye9ada862015-05-11 17:20:37 -0700384 if (!field_sqr(group, n0, &a->Z, ctx) ||
385 !field_mul(group, n3, &b->X, n0, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800386 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700387 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700388 // n3 = X_b * Z_a^2
Adam Langleyd9e397b2015-01-22 14:27:53 -0800389
Adam Langleye9ada862015-05-11 17:20:37 -0700390 if (!field_mul(group, n0, n0, &a->Z, ctx) ||
391 !field_mul(group, n4, &b->Y, n0, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800392 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700393 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700394 // n4 = Y_b * Z_a^3
Adam Langleyd9e397b2015-01-22 14:27:53 -0800395 }
396
Robert Sloan8f860b12017-08-28 07:37:06 -0700397 // n5, n6
Robert Sloanab8b8882018-03-26 11:39:51 -0700398 if (!bn_mod_sub_quick_ctx(n5, n1, n3, p, ctx) ||
399 !bn_mod_sub_quick_ctx(n6, n2, n4, p, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800400 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700401 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700402 // n5 = n1 - n3
403 // n6 = n2 - n4
Adam Langleyd9e397b2015-01-22 14:27:53 -0800404
405 if (BN_is_zero(n5)) {
406 if (BN_is_zero(n6)) {
Robert Sloan8f860b12017-08-28 07:37:06 -0700407 // a is the same point as b
Adam Langleyd9e397b2015-01-22 14:27:53 -0800408 BN_CTX_end(ctx);
409 ret = EC_POINT_dbl(group, r, a, ctx);
410 ctx = NULL;
411 goto end;
412 } else {
Robert Sloan8f860b12017-08-28 07:37:06 -0700413 // a is the inverse of b
Adam Langleyd9e397b2015-01-22 14:27:53 -0800414 BN_zero(&r->Z);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800415 ret = 1;
416 goto end;
417 }
418 }
419
Robert Sloan8f860b12017-08-28 07:37:06 -0700420 // 'n7', 'n8'
Robert Sloanab8b8882018-03-26 11:39:51 -0700421 if (!bn_mod_add_quick_ctx(n1, n1, n3, p, ctx) ||
422 !bn_mod_add_quick_ctx(n2, n2, n4, p, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800423 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700424 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700425 // 'n7' = n1 + n3
426 // 'n8' = n2 + n4
Adam Langleyd9e397b2015-01-22 14:27:53 -0800427
Robert Sloan8f860b12017-08-28 07:37:06 -0700428 // Z_r
David Benjamin4969cc92016-04-22 15:02:23 -0400429 if (a_Z_is_one && b_Z_is_one) {
Adam Langleye9ada862015-05-11 17:20:37 -0700430 if (!BN_copy(&r->Z, n5)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800431 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700432 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800433 } else {
David Benjamin4969cc92016-04-22 15:02:23 -0400434 if (a_Z_is_one) {
Adam Langleye9ada862015-05-11 17:20:37 -0700435 if (!BN_copy(n0, &b->Z)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800436 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700437 }
David Benjamin4969cc92016-04-22 15:02:23 -0400438 } else if (b_Z_is_one) {
Adam Langleye9ada862015-05-11 17:20:37 -0700439 if (!BN_copy(n0, &a->Z)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800440 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700441 }
442 } else if (!field_mul(group, n0, &a->Z, &b->Z, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800443 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700444 }
445 if (!field_mul(group, &r->Z, n0, n5, ctx)) {
446 goto end;
447 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800448 }
David Benjamin4969cc92016-04-22 15:02:23 -0400449
Robert Sloan8f860b12017-08-28 07:37:06 -0700450 // Z_r = Z_a * Z_b * n5
Adam Langleyd9e397b2015-01-22 14:27:53 -0800451
Robert Sloan8f860b12017-08-28 07:37:06 -0700452 // X_r
Adam Langleye9ada862015-05-11 17:20:37 -0700453 if (!field_sqr(group, n0, n6, ctx) ||
454 !field_sqr(group, n4, n5, ctx) ||
455 !field_mul(group, n3, n1, n4, ctx) ||
Robert Sloanab8b8882018-03-26 11:39:51 -0700456 !bn_mod_sub_quick_ctx(&r->X, n0, n3, p, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800457 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700458 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700459 // X_r = n6^2 - n5^2 * 'n7'
Adam Langleyd9e397b2015-01-22 14:27:53 -0800460
Robert Sloan8f860b12017-08-28 07:37:06 -0700461 // 'n9'
Robert Sloanab8b8882018-03-26 11:39:51 -0700462 if (!bn_mod_lshift1_quick_ctx(n0, &r->X, p, ctx) ||
463 !bn_mod_sub_quick_ctx(n0, n3, n0, p, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800464 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700465 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700466 // n9 = n5^2 * 'n7' - 2 * X_r
Adam Langleyd9e397b2015-01-22 14:27:53 -0800467
Robert Sloan8f860b12017-08-28 07:37:06 -0700468 // Y_r
Adam Langleye9ada862015-05-11 17:20:37 -0700469 if (!field_mul(group, n0, n0, n6, ctx) ||
470 !field_mul(group, n5, n4, n5, ctx)) {
Robert Sloan8f860b12017-08-28 07:37:06 -0700471 goto end; // now n5 is n5^3
Adam Langleye9ada862015-05-11 17:20:37 -0700472 }
473 if (!field_mul(group, n1, n2, n5, ctx) ||
Robert Sloanab8b8882018-03-26 11:39:51 -0700474 !bn_mod_sub_quick_ctx(n0, n0, n1, p, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800475 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700476 }
477 if (BN_is_odd(n0) && !BN_add(n0, n0, p)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800478 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700479 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700480 // now 0 <= n0 < 2*p, and n0 is even
Adam Langleye9ada862015-05-11 17:20:37 -0700481 if (!BN_rshift1(&r->Y, n0)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800482 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700483 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700484 // Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2
Adam Langleyd9e397b2015-01-22 14:27:53 -0800485
486 ret = 1;
487
488end:
Adam Langleye9ada862015-05-11 17:20:37 -0700489 if (ctx) {
Robert Sloan8f860b12017-08-28 07:37:06 -0700490 // otherwise we already called BN_CTX_end
Adam Langleyd9e397b2015-01-22 14:27:53 -0800491 BN_CTX_end(ctx);
Adam Langleye9ada862015-05-11 17:20:37 -0700492 }
493 BN_CTX_free(new_ctx);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800494 return ret;
495}
496
497int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
498 BN_CTX *ctx) {
499 int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *,
500 BN_CTX *);
501 int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
502 const BIGNUM *p;
503 BN_CTX *new_ctx = NULL;
504 BIGNUM *n0, *n1, *n2, *n3;
505 int ret = 0;
506
507 if (EC_POINT_is_at_infinity(group, a)) {
508 BN_zero(&r->Z);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800509 return 1;
510 }
511
512 field_mul = group->meth->field_mul;
513 field_sqr = group->meth->field_sqr;
514 p = &group->field;
515
516 if (ctx == NULL) {
517 ctx = new_ctx = BN_CTX_new();
Adam Langleye9ada862015-05-11 17:20:37 -0700518 if (ctx == NULL) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800519 return 0;
Adam Langleye9ada862015-05-11 17:20:37 -0700520 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800521 }
522
523 BN_CTX_start(ctx);
524 n0 = BN_CTX_get(ctx);
525 n1 = BN_CTX_get(ctx);
526 n2 = BN_CTX_get(ctx);
527 n3 = BN_CTX_get(ctx);
Adam Langleye9ada862015-05-11 17:20:37 -0700528 if (n3 == NULL) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800529 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700530 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800531
Robert Sloan8f860b12017-08-28 07:37:06 -0700532 // Note that in this function we must not read components of 'a'
533 // once we have written the corresponding components of 'r'.
534 // ('r' might the same as 'a'.)
Adam Langleyd9e397b2015-01-22 14:27:53 -0800535
Robert Sloan8f860b12017-08-28 07:37:06 -0700536 // n1
David Benjamin4969cc92016-04-22 15:02:23 -0400537 if (BN_cmp(&a->Z, &group->one) == 0) {
Adam Langleye9ada862015-05-11 17:20:37 -0700538 if (!field_sqr(group, n0, &a->X, ctx) ||
Robert Sloanab8b8882018-03-26 11:39:51 -0700539 !bn_mod_lshift1_quick_ctx(n1, n0, p, ctx) ||
540 !bn_mod_add_quick_ctx(n0, n0, n1, p, ctx) ||
541 !bn_mod_add_quick_ctx(n1, n0, &group->a, p, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800542 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700543 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700544 // n1 = 3 * X_a^2 + a_curve
Adam Langleyd9e397b2015-01-22 14:27:53 -0800545 } else if (group->a_is_minus3) {
Adam Langleye9ada862015-05-11 17:20:37 -0700546 if (!field_sqr(group, n1, &a->Z, ctx) ||
Robert Sloanab8b8882018-03-26 11:39:51 -0700547 !bn_mod_add_quick_ctx(n0, &a->X, n1, p, ctx) ||
548 !bn_mod_sub_quick_ctx(n2, &a->X, n1, p, ctx) ||
Adam Langleye9ada862015-05-11 17:20:37 -0700549 !field_mul(group, n1, n0, n2, ctx) ||
Robert Sloanab8b8882018-03-26 11:39:51 -0700550 !bn_mod_lshift1_quick_ctx(n0, n1, p, ctx) ||
551 !bn_mod_add_quick_ctx(n1, n0, n1, p, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800552 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700553 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700554 // n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2)
555 // = 3 * X_a^2 - 3 * Z_a^4
Adam Langleyd9e397b2015-01-22 14:27:53 -0800556 } else {
Adam Langleye9ada862015-05-11 17:20:37 -0700557 if (!field_sqr(group, n0, &a->X, ctx) ||
Robert Sloanab8b8882018-03-26 11:39:51 -0700558 !bn_mod_lshift1_quick_ctx(n1, n0, p, ctx) ||
559 !bn_mod_add_quick_ctx(n0, n0, n1, p, ctx) ||
Adam Langleye9ada862015-05-11 17:20:37 -0700560 !field_sqr(group, n1, &a->Z, ctx) ||
561 !field_sqr(group, n1, n1, ctx) ||
562 !field_mul(group, n1, n1, &group->a, ctx) ||
Robert Sloanab8b8882018-03-26 11:39:51 -0700563 !bn_mod_add_quick_ctx(n1, n1, n0, p, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800564 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700565 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700566 // n1 = 3 * X_a^2 + a_curve * Z_a^4
Adam Langleyd9e397b2015-01-22 14:27:53 -0800567 }
568
Robert Sloan8f860b12017-08-28 07:37:06 -0700569 // Z_r
David Benjamin4969cc92016-04-22 15:02:23 -0400570 if (BN_cmp(&a->Z, &group->one) == 0) {
Adam Langleye9ada862015-05-11 17:20:37 -0700571 if (!BN_copy(n0, &a->Y)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800572 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700573 }
574 } else if (!field_mul(group, n0, &a->Y, &a->Z, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800575 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700576 }
Robert Sloanab8b8882018-03-26 11:39:51 -0700577 if (!bn_mod_lshift1_quick_ctx(&r->Z, n0, p, ctx)) {
Adam Langleye9ada862015-05-11 17:20:37 -0700578 goto err;
579 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700580 // Z_r = 2 * Y_a * Z_a
Adam Langleyd9e397b2015-01-22 14:27:53 -0800581
Robert Sloan8f860b12017-08-28 07:37:06 -0700582 // n2
Adam Langleye9ada862015-05-11 17:20:37 -0700583 if (!field_sqr(group, n3, &a->Y, ctx) ||
584 !field_mul(group, n2, &a->X, n3, ctx) ||
Robert Sloanab8b8882018-03-26 11:39:51 -0700585 !bn_mod_lshift_quick_ctx(n2, n2, 2, p, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800586 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700587 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700588 // n2 = 4 * X_a * Y_a^2
Adam Langleyd9e397b2015-01-22 14:27:53 -0800589
Robert Sloan8f860b12017-08-28 07:37:06 -0700590 // X_r
Robert Sloanab8b8882018-03-26 11:39:51 -0700591 if (!bn_mod_lshift1_quick_ctx(n0, n2, p, ctx) ||
Adam Langleye9ada862015-05-11 17:20:37 -0700592 !field_sqr(group, &r->X, n1, ctx) ||
Robert Sloanab8b8882018-03-26 11:39:51 -0700593 !bn_mod_sub_quick_ctx(&r->X, &r->X, n0, p, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800594 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700595 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700596 // X_r = n1^2 - 2 * n2
Adam Langleyd9e397b2015-01-22 14:27:53 -0800597
Robert Sloan8f860b12017-08-28 07:37:06 -0700598 // n3
Adam Langleye9ada862015-05-11 17:20:37 -0700599 if (!field_sqr(group, n0, n3, ctx) ||
Robert Sloanab8b8882018-03-26 11:39:51 -0700600 !bn_mod_lshift_quick_ctx(n3, n0, 3, p, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800601 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700602 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700603 // n3 = 8 * Y_a^4
Adam Langleyd9e397b2015-01-22 14:27:53 -0800604
Robert Sloan8f860b12017-08-28 07:37:06 -0700605 // Y_r
Robert Sloanab8b8882018-03-26 11:39:51 -0700606 if (!bn_mod_sub_quick_ctx(n0, n2, &r->X, p, ctx) ||
Adam Langleye9ada862015-05-11 17:20:37 -0700607 !field_mul(group, n0, n1, n0, ctx) ||
Robert Sloanab8b8882018-03-26 11:39:51 -0700608 !bn_mod_sub_quick_ctx(&r->Y, n0, n3, p, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800609 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700610 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700611 // Y_r = n1 * (n2 - X_r) - n3
Adam Langleyd9e397b2015-01-22 14:27:53 -0800612
613 ret = 1;
614
615err:
616 BN_CTX_end(ctx);
Adam Langleye9ada862015-05-11 17:20:37 -0700617 BN_CTX_free(new_ctx);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800618 return ret;
619}
620
621int ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) {
Adam Langleye9ada862015-05-11 17:20:37 -0700622 if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(&point->Y)) {
Robert Sloan8f860b12017-08-28 07:37:06 -0700623 // point is its own inverse
Adam Langleyd9e397b2015-01-22 14:27:53 -0800624 return 1;
Adam Langleye9ada862015-05-11 17:20:37 -0700625 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800626
627 return BN_usub(&point->Y, &group->field, &point->Y);
628}
629
630int ec_GFp_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) {
David Benjamin4969cc92016-04-22 15:02:23 -0400631 return BN_is_zero(&point->Z);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800632}
633
634int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
635 BN_CTX *ctx) {
636 int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *,
637 BN_CTX *);
638 int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
639 const BIGNUM *p;
640 BN_CTX *new_ctx = NULL;
641 BIGNUM *rh, *tmp, *Z4, *Z6;
David Benjamin4969cc92016-04-22 15:02:23 -0400642 int ret = 0;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800643
Adam Langleye9ada862015-05-11 17:20:37 -0700644 if (EC_POINT_is_at_infinity(group, point)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800645 return 1;
Adam Langleye9ada862015-05-11 17:20:37 -0700646 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800647
648 field_mul = group->meth->field_mul;
649 field_sqr = group->meth->field_sqr;
650 p = &group->field;
651
652 if (ctx == NULL) {
653 ctx = new_ctx = BN_CTX_new();
Adam Langleye9ada862015-05-11 17:20:37 -0700654 if (ctx == NULL) {
David Benjamin4969cc92016-04-22 15:02:23 -0400655 return 0;
Adam Langleye9ada862015-05-11 17:20:37 -0700656 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800657 }
658
659 BN_CTX_start(ctx);
660 rh = BN_CTX_get(ctx);
661 tmp = BN_CTX_get(ctx);
662 Z4 = BN_CTX_get(ctx);
663 Z6 = BN_CTX_get(ctx);
Adam Langleye9ada862015-05-11 17:20:37 -0700664 if (Z6 == NULL) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800665 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700666 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800667
Robert Sloan8f860b12017-08-28 07:37:06 -0700668 // We have a curve defined by a Weierstrass equation
669 // y^2 = x^3 + a*x + b.
670 // The point to consider is given in Jacobian projective coordinates
671 // where (X, Y, Z) represents (x, y) = (X/Z^2, Y/Z^3).
672 // Substituting this and multiplying by Z^6 transforms the above equation
673 // into
674 // Y^2 = X^3 + a*X*Z^4 + b*Z^6.
675 // To test this, we add up the right-hand side in 'rh'.
Adam Langleyd9e397b2015-01-22 14:27:53 -0800676
Robert Sloan8f860b12017-08-28 07:37:06 -0700677 // rh := X^2
Adam Langleye9ada862015-05-11 17:20:37 -0700678 if (!field_sqr(group, rh, &point->X, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800679 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700680 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800681
David Benjamin4969cc92016-04-22 15:02:23 -0400682 if (BN_cmp(&point->Z, &group->one) != 0) {
Adam Langleye9ada862015-05-11 17:20:37 -0700683 if (!field_sqr(group, tmp, &point->Z, ctx) ||
684 !field_sqr(group, Z4, tmp, ctx) ||
685 !field_mul(group, Z6, Z4, tmp, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800686 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700687 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800688
Robert Sloan8f860b12017-08-28 07:37:06 -0700689 // rh := (rh + a*Z^4)*X
Adam Langleyd9e397b2015-01-22 14:27:53 -0800690 if (group->a_is_minus3) {
Robert Sloanab8b8882018-03-26 11:39:51 -0700691 if (!bn_mod_lshift1_quick_ctx(tmp, Z4, p, ctx) ||
692 !bn_mod_add_quick_ctx(tmp, tmp, Z4, p, ctx) ||
693 !bn_mod_sub_quick_ctx(rh, rh, tmp, p, ctx) ||
Adam Langleye9ada862015-05-11 17:20:37 -0700694 !field_mul(group, rh, rh, &point->X, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800695 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700696 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800697 } else {
Adam Langleye9ada862015-05-11 17:20:37 -0700698 if (!field_mul(group, tmp, Z4, &group->a, ctx) ||
Robert Sloanab8b8882018-03-26 11:39:51 -0700699 !bn_mod_add_quick_ctx(rh, rh, tmp, p, ctx) ||
Adam Langleye9ada862015-05-11 17:20:37 -0700700 !field_mul(group, rh, rh, &point->X, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800701 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700702 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800703 }
704
Robert Sloan8f860b12017-08-28 07:37:06 -0700705 // rh := rh + b*Z^6
Adam Langleye9ada862015-05-11 17:20:37 -0700706 if (!field_mul(group, tmp, &group->b, Z6, ctx) ||
Robert Sloanab8b8882018-03-26 11:39:51 -0700707 !bn_mod_add_quick_ctx(rh, rh, tmp, p, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800708 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700709 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800710 } else {
Robert Sloan8f860b12017-08-28 07:37:06 -0700711 // rh := (rh + a)*X
Robert Sloanab8b8882018-03-26 11:39:51 -0700712 if (!bn_mod_add_quick_ctx(rh, rh, &group->a, p, ctx) ||
Adam Langleye9ada862015-05-11 17:20:37 -0700713 !field_mul(group, rh, rh, &point->X, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800714 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700715 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700716 // rh := rh + b
Robert Sloanab8b8882018-03-26 11:39:51 -0700717 if (!bn_mod_add_quick_ctx(rh, rh, &group->b, p, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800718 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700719 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800720 }
721
Robert Sloan8f860b12017-08-28 07:37:06 -0700722 // 'lh' := Y^2
Adam Langleye9ada862015-05-11 17:20:37 -0700723 if (!field_sqr(group, tmp, &point->Y, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800724 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700725 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800726
727 ret = (0 == BN_ucmp(tmp, rh));
728
729err:
730 BN_CTX_end(ctx);
Adam Langleye9ada862015-05-11 17:20:37 -0700731 BN_CTX_free(new_ctx);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800732 return ret;
733}
734
735int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
736 const EC_POINT *b, BN_CTX *ctx) {
Robert Sloan8f860b12017-08-28 07:37:06 -0700737 // return values:
738 // -1 error
739 // 0 equal (in affine coordinates)
740 // 1 not equal
Adam Langleyd9e397b2015-01-22 14:27:53 -0800741
742 int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *,
743 BN_CTX *);
744 int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
745 BN_CTX *new_ctx = NULL;
746 BIGNUM *tmp1, *tmp2, *Za23, *Zb23;
747 const BIGNUM *tmp1_, *tmp2_;
748 int ret = -1;
749
Robert Sloan29c1d2c2017-10-30 14:10:28 -0700750 if (ec_GFp_simple_is_at_infinity(group, a)) {
751 return ec_GFp_simple_is_at_infinity(group, b) ? 0 : 1;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800752 }
753
Robert Sloan29c1d2c2017-10-30 14:10:28 -0700754 if (ec_GFp_simple_is_at_infinity(group, b)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800755 return 1;
Adam Langleye9ada862015-05-11 17:20:37 -0700756 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800757
David Benjamin4969cc92016-04-22 15:02:23 -0400758 int a_Z_is_one = BN_cmp(&a->Z, &group->one) == 0;
759 int b_Z_is_one = BN_cmp(&b->Z, &group->one) == 0;
760
761 if (a_Z_is_one && b_Z_is_one) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800762 return ((BN_cmp(&a->X, &b->X) == 0) && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1;
763 }
764
765 field_mul = group->meth->field_mul;
766 field_sqr = group->meth->field_sqr;
767
768 if (ctx == NULL) {
769 ctx = new_ctx = BN_CTX_new();
Adam Langleye9ada862015-05-11 17:20:37 -0700770 if (ctx == NULL) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800771 return -1;
Adam Langleye9ada862015-05-11 17:20:37 -0700772 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800773 }
774
775 BN_CTX_start(ctx);
776 tmp1 = BN_CTX_get(ctx);
777 tmp2 = BN_CTX_get(ctx);
778 Za23 = BN_CTX_get(ctx);
779 Zb23 = BN_CTX_get(ctx);
Adam Langleye9ada862015-05-11 17:20:37 -0700780 if (Zb23 == NULL) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800781 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700782 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800783
Robert Sloan8f860b12017-08-28 07:37:06 -0700784 // We have to decide whether
785 // (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3),
786 // or equivalently, whether
787 // (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3).
Adam Langleyd9e397b2015-01-22 14:27:53 -0800788
David Benjamin4969cc92016-04-22 15:02:23 -0400789 if (!b_Z_is_one) {
Adam Langleye9ada862015-05-11 17:20:37 -0700790 if (!field_sqr(group, Zb23, &b->Z, ctx) ||
791 !field_mul(group, tmp1, &a->X, Zb23, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800792 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700793 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800794 tmp1_ = tmp1;
Adam Langleye9ada862015-05-11 17:20:37 -0700795 } else {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800796 tmp1_ = &a->X;
Adam Langleye9ada862015-05-11 17:20:37 -0700797 }
David Benjamin4969cc92016-04-22 15:02:23 -0400798 if (!a_Z_is_one) {
Adam Langleye9ada862015-05-11 17:20:37 -0700799 if (!field_sqr(group, Za23, &a->Z, ctx) ||
800 !field_mul(group, tmp2, &b->X, Za23, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800801 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700802 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800803 tmp2_ = tmp2;
Adam Langleye9ada862015-05-11 17:20:37 -0700804 } else {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800805 tmp2_ = &b->X;
Adam Langleye9ada862015-05-11 17:20:37 -0700806 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800807
Robert Sloan8f860b12017-08-28 07:37:06 -0700808 // compare X_a*Z_b^2 with X_b*Z_a^2
Adam Langleyd9e397b2015-01-22 14:27:53 -0800809 if (BN_cmp(tmp1_, tmp2_) != 0) {
Robert Sloan8f860b12017-08-28 07:37:06 -0700810 ret = 1; // points differ
Adam Langleyd9e397b2015-01-22 14:27:53 -0800811 goto end;
812 }
813
814
David Benjamin4969cc92016-04-22 15:02:23 -0400815 if (!b_Z_is_one) {
Adam Langleye9ada862015-05-11 17:20:37 -0700816 if (!field_mul(group, Zb23, Zb23, &b->Z, ctx) ||
817 !field_mul(group, tmp1, &a->Y, Zb23, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800818 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700819 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700820 // tmp1_ = tmp1
Adam Langleye9ada862015-05-11 17:20:37 -0700821 } else {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800822 tmp1_ = &a->Y;
Adam Langleye9ada862015-05-11 17:20:37 -0700823 }
David Benjamin4969cc92016-04-22 15:02:23 -0400824 if (!a_Z_is_one) {
Adam Langleye9ada862015-05-11 17:20:37 -0700825 if (!field_mul(group, Za23, Za23, &a->Z, ctx) ||
826 !field_mul(group, tmp2, &b->Y, Za23, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800827 goto end;
Adam Langleye9ada862015-05-11 17:20:37 -0700828 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700829 // tmp2_ = tmp2
Adam Langleye9ada862015-05-11 17:20:37 -0700830 } else {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800831 tmp2_ = &b->Y;
Adam Langleye9ada862015-05-11 17:20:37 -0700832 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800833
Robert Sloan8f860b12017-08-28 07:37:06 -0700834 // compare Y_a*Z_b^3 with Y_b*Z_a^3
Adam Langleyd9e397b2015-01-22 14:27:53 -0800835 if (BN_cmp(tmp1_, tmp2_) != 0) {
Robert Sloan8f860b12017-08-28 07:37:06 -0700836 ret = 1; // points differ
Adam Langleyd9e397b2015-01-22 14:27:53 -0800837 goto end;
838 }
839
Robert Sloan8f860b12017-08-28 07:37:06 -0700840 // points are equal
Adam Langleyd9e397b2015-01-22 14:27:53 -0800841 ret = 0;
842
843end:
844 BN_CTX_end(ctx);
Adam Langleye9ada862015-05-11 17:20:37 -0700845 BN_CTX_free(new_ctx);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800846 return ret;
847}
848
849int ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point,
850 BN_CTX *ctx) {
851 BN_CTX *new_ctx = NULL;
852 BIGNUM *x, *y;
853 int ret = 0;
854
David Benjamin4969cc92016-04-22 15:02:23 -0400855 if (BN_cmp(&point->Z, &group->one) == 0 ||
856 EC_POINT_is_at_infinity(group, point)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800857 return 1;
Adam Langleye9ada862015-05-11 17:20:37 -0700858 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800859
860 if (ctx == NULL) {
861 ctx = new_ctx = BN_CTX_new();
Adam Langleye9ada862015-05-11 17:20:37 -0700862 if (ctx == NULL) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800863 return 0;
Adam Langleye9ada862015-05-11 17:20:37 -0700864 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800865 }
866
867 BN_CTX_start(ctx);
868 x = BN_CTX_get(ctx);
869 y = BN_CTX_get(ctx);
Adam Langleye9ada862015-05-11 17:20:37 -0700870 if (y == NULL) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800871 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700872 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800873
Adam Langleye9ada862015-05-11 17:20:37 -0700874 if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) ||
875 !EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800876 goto err;
Adam Langleye9ada862015-05-11 17:20:37 -0700877 }
David Benjamin4969cc92016-04-22 15:02:23 -0400878 if (BN_cmp(&point->Z, &group->one) != 0) {
Kenny Rootb8494592015-09-25 02:29:14 +0000879 OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800880 goto err;
881 }
882
883 ret = 1;
884
885err:
886 BN_CTX_end(ctx);
Adam Langleye9ada862015-05-11 17:20:37 -0700887 BN_CTX_free(new_ctx);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800888 return ret;
889}
890
891int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num,
892 EC_POINT *points[], BN_CTX *ctx) {
893 BN_CTX *new_ctx = NULL;
894 BIGNUM *tmp, *tmp_Z;
895 BIGNUM **prod_Z = NULL;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800896 int ret = 0;
897
898 if (num == 0) {
899 return 1;
900 }
901
902 if (ctx == NULL) {
903 ctx = new_ctx = BN_CTX_new();
904 if (ctx == NULL) {
905 return 0;
906 }
907 }
908
909 BN_CTX_start(ctx);
910 tmp = BN_CTX_get(ctx);
911 tmp_Z = BN_CTX_get(ctx);
912 if (tmp == NULL || tmp_Z == NULL) {
913 goto err;
914 }
915
916 prod_Z = OPENSSL_malloc(num * sizeof(prod_Z[0]));
917 if (prod_Z == NULL) {
918 goto err;
919 }
Robert Sloan69939df2017-01-09 10:53:07 -0800920 OPENSSL_memset(prod_Z, 0, num * sizeof(prod_Z[0]));
David Benjamin7c0d06c2016-08-11 13:26:41 -0400921 for (size_t i = 0; i < num; i++) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800922 prod_Z[i] = BN_new();
923 if (prod_Z[i] == NULL) {
924 goto err;
925 }
926 }
927
Robert Sloan8f860b12017-08-28 07:37:06 -0700928 // Set each prod_Z[i] to the product of points[0]->Z .. points[i]->Z,
929 // skipping any zero-valued inputs (pretend that they're 1).
Adam Langleyd9e397b2015-01-22 14:27:53 -0800930
931 if (!BN_is_zero(&points[0]->Z)) {
932 if (!BN_copy(prod_Z[0], &points[0]->Z)) {
933 goto err;
934 }
935 } else {
David Benjamin4969cc92016-04-22 15:02:23 -0400936 if (BN_copy(prod_Z[0], &group->one) == NULL) {
937 goto err;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800938 }
939 }
940
David Benjamin7c0d06c2016-08-11 13:26:41 -0400941 for (size_t i = 1; i < num; i++) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800942 if (!BN_is_zero(&points[i]->Z)) {
943 if (!group->meth->field_mul(group, prod_Z[i], prod_Z[i - 1],
944 &points[i]->Z, ctx)) {
945 goto err;
946 }
947 } else {
948 if (!BN_copy(prod_Z[i], prod_Z[i - 1])) {
949 goto err;
950 }
951 }
952 }
953
Robert Sloan8f860b12017-08-28 07:37:06 -0700954 // Now use a single explicit inversion to replace every non-zero points[i]->Z
955 // by its inverse. We use |BN_mod_inverse_odd| instead of doing a constant-
956 // time inversion using Fermat's Little Theorem because this function is
957 // usually only used for converting multiples of a public key point to
958 // affine, and a public key point isn't secret. If we were to use Fermat's
959 // Little Theorem then the cost of the inversion would usually be so high
960 // that converting the multiples to affine would be counterproductive.
David Benjaminc895d6b2016-08-11 13:26:41 -0400961 int no_inverse;
962 if (!BN_mod_inverse_odd(tmp, &no_inverse, prod_Z[num - 1], &group->field,
963 ctx)) {
Kenny Rootb8494592015-09-25 02:29:14 +0000964 OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800965 goto err;
966 }
967
968 if (group->meth->field_encode != NULL) {
Robert Sloan8f860b12017-08-28 07:37:06 -0700969 // In the Montgomery case, we just turned R*H (representing H)
970 // into 1/(R*H), but we need R*(1/H) (representing 1/H);
971 // i.e. we need to multiply by the Montgomery factor twice.
Adam Langleyd9e397b2015-01-22 14:27:53 -0800972 if (!group->meth->field_encode(group, tmp, tmp, ctx) ||
973 !group->meth->field_encode(group, tmp, tmp, ctx)) {
974 goto err;
975 }
976 }
977
David Benjamin7c0d06c2016-08-11 13:26:41 -0400978 for (size_t i = num - 1; i > 0; --i) {
Robert Sloan8f860b12017-08-28 07:37:06 -0700979 // Loop invariant: tmp is the product of the inverses of
980 // points[0]->Z .. points[i]->Z (zero-valued inputs skipped).
Adam Langleyd9e397b2015-01-22 14:27:53 -0800981 if (BN_is_zero(&points[i]->Z)) {
982 continue;
983 }
984
Robert Sloan8f860b12017-08-28 07:37:06 -0700985 // Set tmp_Z to the inverse of points[i]->Z (as product
986 // of Z inverses 0 .. i, Z values 0 .. i - 1).
Adam Langleyd9e397b2015-01-22 14:27:53 -0800987 if (!group->meth->field_mul(group, tmp_Z, prod_Z[i - 1], tmp, ctx) ||
Robert Sloan8f860b12017-08-28 07:37:06 -0700988 // Update tmp to satisfy the loop invariant for i - 1.
Adam Langleyd9e397b2015-01-22 14:27:53 -0800989 !group->meth->field_mul(group, tmp, tmp, &points[i]->Z, ctx) ||
Robert Sloan8f860b12017-08-28 07:37:06 -0700990 // Replace points[i]->Z by its inverse.
Adam Langleyd9e397b2015-01-22 14:27:53 -0800991 !BN_copy(&points[i]->Z, tmp_Z)) {
992 goto err;
993 }
994 }
995
Robert Sloan8f860b12017-08-28 07:37:06 -0700996 // Replace points[0]->Z by its inverse.
Adam Langleyd9e397b2015-01-22 14:27:53 -0800997 if (!BN_is_zero(&points[0]->Z) && !BN_copy(&points[0]->Z, tmp)) {
998 goto err;
999 }
1000
Robert Sloan8f860b12017-08-28 07:37:06 -07001001 // Finally, fix up the X and Y coordinates for all points.
David Benjamin7c0d06c2016-08-11 13:26:41 -04001002 for (size_t i = 0; i < num; i++) {
Adam Langleyd9e397b2015-01-22 14:27:53 -08001003 EC_POINT *p = points[i];
1004
1005 if (!BN_is_zero(&p->Z)) {
Robert Sloan8f860b12017-08-28 07:37:06 -07001006 // turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1).
Adam Langleyd9e397b2015-01-22 14:27:53 -08001007 if (!group->meth->field_sqr(group, tmp, &p->Z, ctx) ||
1008 !group->meth->field_mul(group, &p->X, &p->X, tmp, ctx) ||
1009 !group->meth->field_mul(group, tmp, tmp, &p->Z, ctx) ||
1010 !group->meth->field_mul(group, &p->Y, &p->Y, tmp, ctx)) {
1011 goto err;
1012 }
1013
David Benjamin4969cc92016-04-22 15:02:23 -04001014 if (BN_copy(&p->Z, &group->one) == NULL) {
1015 goto err;
Adam Langleyd9e397b2015-01-22 14:27:53 -08001016 }
Adam Langleyd9e397b2015-01-22 14:27:53 -08001017 }
1018 }
1019
1020 ret = 1;
1021
1022err:
1023 BN_CTX_end(ctx);
Adam Langleye9ada862015-05-11 17:20:37 -07001024 BN_CTX_free(new_ctx);
Adam Langleyd9e397b2015-01-22 14:27:53 -08001025 if (prod_Z != NULL) {
David Benjamin7c0d06c2016-08-11 13:26:41 -04001026 for (size_t i = 0; i < num; i++) {
Adam Langleyd9e397b2015-01-22 14:27:53 -08001027 if (prod_Z[i] == NULL) {
1028 break;
1029 }
1030 BN_clear_free(prod_Z[i]);
1031 }
1032 OPENSSL_free(prod_Z);
1033 }
1034
1035 return ret;
1036}
1037
1038int ec_GFp_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
1039 const BIGNUM *b, BN_CTX *ctx) {
1040 return BN_mod_mul(r, a, b, &group->field, ctx);
1041}
1042
1043int ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
1044 BN_CTX *ctx) {
1045 return BN_mod_sqr(r, a, &group->field, ctx);
1046}