1 |
|
|
/* $OpenBSD: ec2_smpl.c,v 1.15 2017/01/29 17:49:23 beck Exp $ */ |
2 |
|
|
/* ==================================================================== |
3 |
|
|
* Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. |
4 |
|
|
* |
5 |
|
|
* The Elliptic Curve Public-Key Crypto Library (ECC Code) included |
6 |
|
|
* herein is developed by SUN MICROSYSTEMS, INC., and is contributed |
7 |
|
|
* to the OpenSSL project. |
8 |
|
|
* |
9 |
|
|
* The ECC Code is licensed pursuant to the OpenSSL open source |
10 |
|
|
* license provided below. |
11 |
|
|
* |
12 |
|
|
* The software is originally written by Sheueling Chang Shantz and |
13 |
|
|
* Douglas Stebila of Sun Microsystems Laboratories. |
14 |
|
|
* |
15 |
|
|
*/ |
16 |
|
|
/* ==================================================================== |
17 |
|
|
* Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. |
18 |
|
|
* |
19 |
|
|
* Redistribution and use in source and binary forms, with or without |
20 |
|
|
* modification, are permitted provided that the following conditions |
21 |
|
|
* are met: |
22 |
|
|
* |
23 |
|
|
* 1. Redistributions of source code must retain the above copyright |
24 |
|
|
* notice, this list of conditions and the following disclaimer. |
25 |
|
|
* |
26 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
27 |
|
|
* notice, this list of conditions and the following disclaimer in |
28 |
|
|
* the documentation and/or other materials provided with the |
29 |
|
|
* distribution. |
30 |
|
|
* |
31 |
|
|
* 3. All advertising materials mentioning features or use of this |
32 |
|
|
* software must display the following acknowledgment: |
33 |
|
|
* "This product includes software developed by the OpenSSL Project |
34 |
|
|
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)" |
35 |
|
|
* |
36 |
|
|
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
37 |
|
|
* endorse or promote products derived from this software without |
38 |
|
|
* prior written permission. For written permission, please contact |
39 |
|
|
* openssl-core@openssl.org. |
40 |
|
|
* |
41 |
|
|
* 5. Products derived from this software may not be called "OpenSSL" |
42 |
|
|
* nor may "OpenSSL" appear in their names without prior written |
43 |
|
|
* permission of the OpenSSL Project. |
44 |
|
|
* |
45 |
|
|
* 6. Redistributions of any form whatsoever must retain the following |
46 |
|
|
* acknowledgment: |
47 |
|
|
* "This product includes software developed by the OpenSSL Project |
48 |
|
|
* for use in the OpenSSL Toolkit (http://www.openssl.org/)" |
49 |
|
|
* |
50 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
51 |
|
|
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
52 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
53 |
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
54 |
|
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
55 |
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
56 |
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
57 |
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
58 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
59 |
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
60 |
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
61 |
|
|
* OF THE POSSIBILITY OF SUCH DAMAGE. |
62 |
|
|
* ==================================================================== |
63 |
|
|
* |
64 |
|
|
* This product includes cryptographic software written by Eric Young |
65 |
|
|
* (eay@cryptsoft.com). This product includes software written by Tim |
66 |
|
|
* Hudson (tjh@cryptsoft.com). |
67 |
|
|
* |
68 |
|
|
*/ |
69 |
|
|
|
70 |
|
|
#include <openssl/opensslconf.h> |
71 |
|
|
|
72 |
|
|
#include <openssl/err.h> |
73 |
|
|
|
74 |
|
|
#include "ec_lcl.h" |
75 |
|
|
|
76 |
|
|
#ifndef OPENSSL_NO_EC2M |
77 |
|
|
|
78 |
|
|
const EC_METHOD * |
79 |
|
|
EC_GF2m_simple_method(void) |
80 |
|
|
{ |
81 |
|
|
static const EC_METHOD ret = { |
82 |
|
|
.flags = EC_FLAGS_DEFAULT_OCT, |
83 |
|
|
.field_type = NID_X9_62_characteristic_two_field, |
84 |
|
|
.group_init = ec_GF2m_simple_group_init, |
85 |
|
|
.group_finish = ec_GF2m_simple_group_finish, |
86 |
|
|
.group_clear_finish = ec_GF2m_simple_group_clear_finish, |
87 |
|
|
.group_copy = ec_GF2m_simple_group_copy, |
88 |
|
|
.group_set_curve = ec_GF2m_simple_group_set_curve, |
89 |
|
|
.group_get_curve = ec_GF2m_simple_group_get_curve, |
90 |
|
|
.group_get_degree = ec_GF2m_simple_group_get_degree, |
91 |
|
|
.group_check_discriminant = |
92 |
|
|
ec_GF2m_simple_group_check_discriminant, |
93 |
|
|
.point_init = ec_GF2m_simple_point_init, |
94 |
|
|
.point_finish = ec_GF2m_simple_point_finish, |
95 |
|
|
.point_clear_finish = ec_GF2m_simple_point_clear_finish, |
96 |
|
|
.point_copy = ec_GF2m_simple_point_copy, |
97 |
|
|
.point_set_to_infinity = ec_GF2m_simple_point_set_to_infinity, |
98 |
|
|
.point_set_affine_coordinates = |
99 |
|
|
ec_GF2m_simple_point_set_affine_coordinates, |
100 |
|
|
.point_get_affine_coordinates = |
101 |
|
|
ec_GF2m_simple_point_get_affine_coordinates, |
102 |
|
|
.add = ec_GF2m_simple_add, |
103 |
|
|
.dbl = ec_GF2m_simple_dbl, |
104 |
|
|
.invert = ec_GF2m_simple_invert, |
105 |
|
|
.is_at_infinity = ec_GF2m_simple_is_at_infinity, |
106 |
|
|
.is_on_curve = ec_GF2m_simple_is_on_curve, |
107 |
|
|
.point_cmp = ec_GF2m_simple_cmp, |
108 |
|
|
.make_affine = ec_GF2m_simple_make_affine, |
109 |
|
|
.points_make_affine = ec_GF2m_simple_points_make_affine, |
110 |
|
|
|
111 |
|
|
/* |
112 |
|
|
* the following three method functions are defined in |
113 |
|
|
* ec2_mult.c |
114 |
|
|
*/ |
115 |
|
|
.mul = ec_GF2m_simple_mul, |
116 |
|
|
.precompute_mult = ec_GF2m_precompute_mult, |
117 |
|
|
.have_precompute_mult = ec_GF2m_have_precompute_mult, |
118 |
|
|
|
119 |
|
|
.field_mul = ec_GF2m_simple_field_mul, |
120 |
|
|
.field_sqr = ec_GF2m_simple_field_sqr, |
121 |
|
|
.field_div = ec_GF2m_simple_field_div, |
122 |
|
|
}; |
123 |
|
|
|
124 |
|
2032 |
return &ret; |
125 |
|
|
} |
126 |
|
|
|
127 |
|
|
|
128 |
|
|
/* Initialize a GF(2^m)-based EC_GROUP structure. |
129 |
|
|
* Note that all other members are handled by EC_GROUP_new. |
130 |
|
|
*/ |
131 |
|
|
int |
132 |
|
|
ec_GF2m_simple_group_init(EC_GROUP * group) |
133 |
|
|
{ |
134 |
|
3272 |
BN_init(&group->field); |
135 |
|
1636 |
BN_init(&group->a); |
136 |
|
1636 |
BN_init(&group->b); |
137 |
|
1636 |
return 1; |
138 |
|
|
} |
139 |
|
|
|
140 |
|
|
|
141 |
|
|
/* Free a GF(2^m)-based EC_GROUP structure. |
142 |
|
|
* Note that all other members are handled by EC_GROUP_free. |
143 |
|
|
*/ |
144 |
|
|
void |
145 |
|
|
ec_GF2m_simple_group_finish(EC_GROUP * group) |
146 |
|
|
{ |
147 |
|
3272 |
BN_free(&group->field); |
148 |
|
1636 |
BN_free(&group->a); |
149 |
|
1636 |
BN_free(&group->b); |
150 |
|
1636 |
} |
151 |
|
|
|
152 |
|
|
|
153 |
|
|
/* Clear and free a GF(2^m)-based EC_GROUP structure. |
154 |
|
|
* Note that all other members are handled by EC_GROUP_clear_free. |
155 |
|
|
*/ |
156 |
|
|
void |
157 |
|
|
ec_GF2m_simple_group_clear_finish(EC_GROUP * group) |
158 |
|
|
{ |
159 |
|
|
BN_clear_free(&group->field); |
160 |
|
|
BN_clear_free(&group->a); |
161 |
|
|
BN_clear_free(&group->b); |
162 |
|
|
group->poly[0] = 0; |
163 |
|
|
group->poly[1] = 0; |
164 |
|
|
group->poly[2] = 0; |
165 |
|
|
group->poly[3] = 0; |
166 |
|
|
group->poly[4] = 0; |
167 |
|
|
group->poly[5] = -1; |
168 |
|
|
} |
169 |
|
|
|
170 |
|
|
|
171 |
|
|
/* Copy a GF(2^m)-based EC_GROUP structure. |
172 |
|
|
* Note that all other members are handled by EC_GROUP_copy. |
173 |
|
|
*/ |
174 |
|
|
int |
175 |
|
|
ec_GF2m_simple_group_copy(EC_GROUP * dest, const EC_GROUP * src) |
176 |
|
|
{ |
177 |
|
|
int i; |
178 |
|
|
|
179 |
✗✓ |
1240 |
if (!BN_copy(&dest->field, &src->field)) |
180 |
|
|
return 0; |
181 |
✗✓ |
620 |
if (!BN_copy(&dest->a, &src->a)) |
182 |
|
|
return 0; |
183 |
✗✓ |
620 |
if (!BN_copy(&dest->b, &src->b)) |
184 |
|
|
return 0; |
185 |
|
620 |
dest->poly[0] = src->poly[0]; |
186 |
|
620 |
dest->poly[1] = src->poly[1]; |
187 |
|
620 |
dest->poly[2] = src->poly[2]; |
188 |
|
620 |
dest->poly[3] = src->poly[3]; |
189 |
|
620 |
dest->poly[4] = src->poly[4]; |
190 |
|
620 |
dest->poly[5] = src->poly[5]; |
191 |
✓✓✗✓
|
1562 |
if (bn_wexpand(&dest->a, (int) (dest->poly[0] + BN_BITS2 - 1) / BN_BITS2) == NULL) |
192 |
|
|
return 0; |
193 |
✓✓✗✓
|
1448 |
if (bn_wexpand(&dest->b, (int) (dest->poly[0] + BN_BITS2 - 1) / BN_BITS2) == NULL) |
194 |
|
|
return 0; |
195 |
✓✓ |
3940 |
for (i = dest->a.top; i < dest->a.dmax; i++) |
196 |
|
1350 |
dest->a.d[i] = 0; |
197 |
✓✓ |
2576 |
for (i = dest->b.top; i < dest->b.dmax; i++) |
198 |
|
668 |
dest->b.d[i] = 0; |
199 |
|
620 |
return 1; |
200 |
|
620 |
} |
201 |
|
|
|
202 |
|
|
|
203 |
|
|
/* Set the curve parameters of an EC_GROUP structure. */ |
204 |
|
|
int |
205 |
|
|
ec_GF2m_simple_group_set_curve(EC_GROUP * group, |
206 |
|
|
const BIGNUM * p, const BIGNUM * a, const BIGNUM * b, BN_CTX * ctx) |
207 |
|
|
{ |
208 |
|
|
int ret = 0, i; |
209 |
|
|
|
210 |
|
|
/* group->field */ |
211 |
✓✗ |
2152 |
if (!BN_copy(&group->field, p)) |
212 |
|
|
goto err; |
213 |
|
1076 |
i = BN_GF2m_poly2arr(&group->field, group->poly, 6) - 1; |
214 |
✗✓ |
1076 |
if ((i != 5) && (i != 3)) { |
215 |
|
|
ECerror(EC_R_UNSUPPORTED_FIELD); |
216 |
|
|
goto err; |
217 |
|
|
} |
218 |
|
|
/* group->a */ |
219 |
✓✗ |
1076 |
if (!BN_GF2m_mod_arr(&group->a, a, group->poly)) |
220 |
|
|
goto err; |
221 |
✓✓✓✗
|
2716 |
if (bn_wexpand(&group->a, (int) (group->poly[0] + BN_BITS2 - 1) / BN_BITS2) == NULL) |
222 |
|
|
goto err; |
223 |
✓✓ |
7252 |
for (i = group->a.top; i < group->a.dmax; i++) |
224 |
|
2550 |
group->a.d[i] = 0; |
225 |
|
|
|
226 |
|
|
/* group->b */ |
227 |
✓✗ |
1076 |
if (!BN_GF2m_mod_arr(&group->b, b, group->poly)) |
228 |
|
|
goto err; |
229 |
✓✓✓✗
|
2524 |
if (bn_wexpand(&group->b, (int) (group->poly[0] + BN_BITS2 - 1) / BN_BITS2) == NULL) |
230 |
|
|
goto err; |
231 |
✓✓ |
4648 |
for (i = group->b.top; i < group->b.dmax; i++) |
232 |
|
1248 |
group->b.d[i] = 0; |
233 |
|
|
|
234 |
|
1076 |
ret = 1; |
235 |
|
|
err: |
236 |
|
1076 |
return ret; |
237 |
|
|
} |
238 |
|
|
|
239 |
|
|
|
240 |
|
|
/* Get the curve parameters of an EC_GROUP structure. |
241 |
|
|
* If p, a, or b are NULL then there values will not be set but the method will return with success. |
242 |
|
|
*/ |
243 |
|
|
int |
244 |
|
|
ec_GF2m_simple_group_get_curve(const EC_GROUP *group, |
245 |
|
|
BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *ctx) |
246 |
|
|
{ |
247 |
|
|
int ret = 0; |
248 |
|
|
|
249 |
✓✓ |
1356 |
if (p != NULL) { |
250 |
✗✓ |
174 |
if (!BN_copy(p, &group->field)) |
251 |
|
|
return 0; |
252 |
|
|
} |
253 |
✓✗ |
678 |
if (a != NULL) { |
254 |
✓✗ |
678 |
if (!BN_copy(a, &group->a)) |
255 |
|
|
goto err; |
256 |
|
|
} |
257 |
✓✗ |
678 |
if (b != NULL) { |
258 |
✓✗ |
678 |
if (!BN_copy(b, &group->b)) |
259 |
|
|
goto err; |
260 |
|
|
} |
261 |
|
678 |
ret = 1; |
262 |
|
|
|
263 |
|
|
err: |
264 |
|
678 |
return ret; |
265 |
|
678 |
} |
266 |
|
|
|
267 |
|
|
|
268 |
|
|
/* Gets the degree of the field. For a curve over GF(2^m) this is the value m. */ |
269 |
|
|
int |
270 |
|
|
ec_GF2m_simple_group_get_degree(const EC_GROUP * group) |
271 |
|
|
{ |
272 |
|
6588 |
return BN_num_bits(&group->field) - 1; |
273 |
|
|
} |
274 |
|
|
|
275 |
|
|
|
276 |
|
|
/* Checks the discriminant of the curve. |
277 |
|
|
* y^2 + x*y = x^3 + a*x^2 + b is an elliptic curve <=> b != 0 (mod p) |
278 |
|
|
*/ |
279 |
|
|
int |
280 |
|
|
ec_GF2m_simple_group_check_discriminant(const EC_GROUP * group, BN_CTX * ctx) |
281 |
|
|
{ |
282 |
|
|
int ret = 0; |
283 |
|
|
BIGNUM *b; |
284 |
|
|
BN_CTX *new_ctx = NULL; |
285 |
|
|
|
286 |
✗✓ |
504 |
if (ctx == NULL) { |
287 |
|
|
ctx = new_ctx = BN_CTX_new(); |
288 |
|
|
if (ctx == NULL) { |
289 |
|
|
ECerror(ERR_R_MALLOC_FAILURE); |
290 |
|
|
goto err; |
291 |
|
|
} |
292 |
|
|
} |
293 |
|
252 |
BN_CTX_start(ctx); |
294 |
✓✗ |
252 |
if ((b = BN_CTX_get(ctx)) == NULL) |
295 |
|
|
goto err; |
296 |
|
|
|
297 |
✓✗ |
252 |
if (!BN_GF2m_mod_arr(b, &group->b, group->poly)) |
298 |
|
|
goto err; |
299 |
|
|
|
300 |
|
|
/* |
301 |
|
|
* check the discriminant: y^2 + x*y = x^3 + a*x^2 + b is an elliptic |
302 |
|
|
* curve <=> b != 0 (mod p) |
303 |
|
|
*/ |
304 |
✓✗ |
252 |
if (BN_is_zero(b)) |
305 |
|
|
goto err; |
306 |
|
|
|
307 |
|
252 |
ret = 1; |
308 |
|
|
|
309 |
|
|
err: |
310 |
✓✗ |
252 |
if (ctx != NULL) |
311 |
|
252 |
BN_CTX_end(ctx); |
312 |
|
252 |
BN_CTX_free(new_ctx); |
313 |
|
252 |
return ret; |
314 |
|
|
} |
315 |
|
|
|
316 |
|
|
|
317 |
|
|
/* Initializes an EC_POINT. */ |
318 |
|
|
int |
319 |
|
|
ec_GF2m_simple_point_init(EC_POINT * point) |
320 |
|
|
{ |
321 |
|
64324 |
BN_init(&point->X); |
322 |
|
32162 |
BN_init(&point->Y); |
323 |
|
32162 |
BN_init(&point->Z); |
324 |
|
32162 |
return 1; |
325 |
|
|
} |
326 |
|
|
|
327 |
|
|
|
328 |
|
|
/* Frees an EC_POINT. */ |
329 |
|
|
void |
330 |
|
|
ec_GF2m_simple_point_finish(EC_POINT * point) |
331 |
|
|
{ |
332 |
|
63140 |
BN_free(&point->X); |
333 |
|
31570 |
BN_free(&point->Y); |
334 |
|
31570 |
BN_free(&point->Z); |
335 |
|
31570 |
} |
336 |
|
|
|
337 |
|
|
|
338 |
|
|
/* Clears and frees an EC_POINT. */ |
339 |
|
|
void |
340 |
|
|
ec_GF2m_simple_point_clear_finish(EC_POINT * point) |
341 |
|
|
{ |
342 |
|
1184 |
BN_clear_free(&point->X); |
343 |
|
592 |
BN_clear_free(&point->Y); |
344 |
|
592 |
BN_clear_free(&point->Z); |
345 |
|
592 |
point->Z_is_one = 0; |
346 |
|
592 |
} |
347 |
|
|
|
348 |
|
|
|
349 |
|
|
/* Copy the contents of one EC_POINT into another. Assumes dest is initialized. */ |
350 |
|
|
int |
351 |
|
|
ec_GF2m_simple_point_copy(EC_POINT * dest, const EC_POINT * src) |
352 |
|
|
{ |
353 |
✗✓ |
21110 |
if (!BN_copy(&dest->X, &src->X)) |
354 |
|
|
return 0; |
355 |
✗✓ |
10555 |
if (!BN_copy(&dest->Y, &src->Y)) |
356 |
|
|
return 0; |
357 |
✗✓ |
10555 |
if (!BN_copy(&dest->Z, &src->Z)) |
358 |
|
|
return 0; |
359 |
|
10555 |
dest->Z_is_one = src->Z_is_one; |
360 |
|
|
|
361 |
|
10555 |
return 1; |
362 |
|
10555 |
} |
363 |
|
|
|
364 |
|
|
|
365 |
|
|
/* Set an EC_POINT to the point at infinity. |
366 |
|
|
* A point at infinity is represented by having Z=0. |
367 |
|
|
*/ |
368 |
|
|
int |
369 |
|
|
ec_GF2m_simple_point_set_to_infinity(const EC_GROUP * group, EC_POINT * point) |
370 |
|
|
{ |
371 |
|
7850 |
point->Z_is_one = 0; |
372 |
|
3925 |
BN_zero(&point->Z); |
373 |
|
3925 |
return 1; |
374 |
|
|
} |
375 |
|
|
|
376 |
|
|
|
377 |
|
|
/* Set the coordinates of an EC_POINT using affine coordinates. |
378 |
|
|
* Note that the simple implementation only uses affine coordinates. |
379 |
|
|
*/ |
380 |
|
|
int |
381 |
|
|
ec_GF2m_simple_point_set_affine_coordinates(const EC_GROUP * group, EC_POINT * point, |
382 |
|
|
const BIGNUM * x, const BIGNUM * y, BN_CTX * ctx) |
383 |
|
|
{ |
384 |
|
|
int ret = 0; |
385 |
✗✓ |
142156 |
if (x == NULL || y == NULL) { |
386 |
|
|
ECerror(ERR_R_PASSED_NULL_PARAMETER); |
387 |
|
|
return 0; |
388 |
|
|
} |
389 |
✓✗ |
71078 |
if (!BN_copy(&point->X, x)) |
390 |
|
|
goto err; |
391 |
|
71078 |
BN_set_negative(&point->X, 0); |
392 |
✓✗ |
71078 |
if (!BN_copy(&point->Y, y)) |
393 |
|
|
goto err; |
394 |
|
71078 |
BN_set_negative(&point->Y, 0); |
395 |
✓✗ |
71078 |
if (!BN_copy(&point->Z, BN_value_one())) |
396 |
|
|
goto err; |
397 |
|
71078 |
BN_set_negative(&point->Z, 0); |
398 |
|
71078 |
point->Z_is_one = 1; |
399 |
|
71078 |
ret = 1; |
400 |
|
|
|
401 |
|
|
err: |
402 |
|
71078 |
return ret; |
403 |
|
71078 |
} |
404 |
|
|
|
405 |
|
|
|
406 |
|
|
/* Gets the affine coordinates of an EC_POINT. |
407 |
|
|
* Note that the simple implementation only uses affine coordinates. |
408 |
|
|
*/ |
409 |
|
|
int |
410 |
|
|
ec_GF2m_simple_point_get_affine_coordinates(const EC_GROUP *group, |
411 |
|
|
const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx) |
412 |
|
|
{ |
413 |
|
|
int ret = 0; |
414 |
|
|
|
415 |
✗✓ |
5276 |
if (EC_POINT_is_at_infinity(group, point) > 0) { |
416 |
|
|
ECerror(EC_R_POINT_AT_INFINITY); |
417 |
|
|
return 0; |
418 |
|
|
} |
419 |
✗✓ |
2638 |
if (BN_cmp(&point->Z, BN_value_one())) { |
420 |
|
|
ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
421 |
|
|
return 0; |
422 |
|
|
} |
423 |
✓✗ |
2638 |
if (x != NULL) { |
424 |
✓✗ |
2638 |
if (!BN_copy(x, &point->X)) |
425 |
|
|
goto err; |
426 |
|
2638 |
BN_set_negative(x, 0); |
427 |
|
2638 |
} |
428 |
✓✓ |
2638 |
if (y != NULL) { |
429 |
✓✗ |
1420 |
if (!BN_copy(y, &point->Y)) |
430 |
|
|
goto err; |
431 |
|
1420 |
BN_set_negative(y, 0); |
432 |
|
1420 |
} |
433 |
|
2638 |
ret = 1; |
434 |
|
|
|
435 |
|
|
err: |
436 |
|
2638 |
return ret; |
437 |
|
2638 |
} |
438 |
|
|
|
439 |
|
|
/* Computes a + b and stores the result in r. r could be a or b, a could be b. |
440 |
|
|
* Uses algorithm A.10.2 of IEEE P1363. |
441 |
|
|
*/ |
442 |
|
|
int |
443 |
|
|
ec_GF2m_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, |
444 |
|
|
const EC_POINT *b, BN_CTX *ctx) |
445 |
|
|
{ |
446 |
|
|
BN_CTX *new_ctx = NULL; |
447 |
|
|
BIGNUM *x0, *y0, *x1, *y1, *x2, *y2, *s, *t; |
448 |
|
|
int ret = 0; |
449 |
|
|
|
450 |
✓✓ |
148188 |
if (EC_POINT_is_at_infinity(group, a) > 0) { |
451 |
✗✓ |
3879 |
if (!EC_POINT_copy(r, b)) |
452 |
|
|
return 0; |
453 |
|
3879 |
return 1; |
454 |
|
|
} |
455 |
✗✓ |
70215 |
if (EC_POINT_is_at_infinity(group, b) > 0) { |
456 |
|
|
if (!EC_POINT_copy(r, a)) |
457 |
|
|
return 0; |
458 |
|
|
return 1; |
459 |
|
|
} |
460 |
✗✓ |
70215 |
if (ctx == NULL) { |
461 |
|
|
ctx = new_ctx = BN_CTX_new(); |
462 |
|
|
if (ctx == NULL) |
463 |
|
|
return 0; |
464 |
|
|
} |
465 |
|
70215 |
BN_CTX_start(ctx); |
466 |
✓✗ |
70215 |
if ((x0 = BN_CTX_get(ctx)) == NULL) |
467 |
|
|
goto err; |
468 |
✓✗ |
70215 |
if ((y0 = BN_CTX_get(ctx)) == NULL) |
469 |
|
|
goto err; |
470 |
✓✗ |
70215 |
if ((x1 = BN_CTX_get(ctx)) == NULL) |
471 |
|
|
goto err; |
472 |
✓✗ |
70215 |
if ((y1 = BN_CTX_get(ctx)) == NULL) |
473 |
|
|
goto err; |
474 |
✓✗ |
70215 |
if ((x2 = BN_CTX_get(ctx)) == NULL) |
475 |
|
|
goto err; |
476 |
✓✗ |
70215 |
if ((y2 = BN_CTX_get(ctx)) == NULL) |
477 |
|
|
goto err; |
478 |
✓✗ |
70215 |
if ((s = BN_CTX_get(ctx)) == NULL) |
479 |
|
|
goto err; |
480 |
✓✗ |
70215 |
if ((t = BN_CTX_get(ctx)) == NULL) |
481 |
|
|
goto err; |
482 |
|
|
|
483 |
✓✗ |
70215 |
if (a->Z_is_one) { |
484 |
✓✗ |
70215 |
if (!BN_copy(x0, &a->X)) |
485 |
|
|
goto err; |
486 |
✓✗ |
70215 |
if (!BN_copy(y0, &a->Y)) |
487 |
|
|
goto err; |
488 |
|
|
} else { |
489 |
|
|
if (!EC_POINT_get_affine_coordinates_GF2m(group, a, x0, y0, ctx)) |
490 |
|
|
goto err; |
491 |
|
|
} |
492 |
✓✗ |
70215 |
if (b->Z_is_one) { |
493 |
✓✗ |
70215 |
if (!BN_copy(x1, &b->X)) |
494 |
|
|
goto err; |
495 |
✓✗ |
70215 |
if (!BN_copy(y1, &b->Y)) |
496 |
|
|
goto err; |
497 |
|
|
} else { |
498 |
|
|
if (!EC_POINT_get_affine_coordinates_GF2m(group, b, x1, y1, ctx)) |
499 |
|
|
goto err; |
500 |
|
|
} |
501 |
|
|
|
502 |
|
|
|
503 |
✓✓ |
70215 |
if (BN_GF2m_cmp(x0, x1)) { |
504 |
✓✗ |
24719 |
if (!BN_GF2m_add(t, x0, x1)) |
505 |
|
|
goto err; |
506 |
✓✗ |
24719 |
if (!BN_GF2m_add(s, y0, y1)) |
507 |
|
|
goto err; |
508 |
✓✗ |
24719 |
if (!group->meth->field_div(group, s, s, t, ctx)) |
509 |
|
|
goto err; |
510 |
✓✗ |
24719 |
if (!group->meth->field_sqr(group, x2, s, ctx)) |
511 |
|
|
goto err; |
512 |
✓✗ |
24719 |
if (!BN_GF2m_add(x2, x2, &group->a)) |
513 |
|
|
goto err; |
514 |
✓✗ |
24719 |
if (!BN_GF2m_add(x2, x2, s)) |
515 |
|
|
goto err; |
516 |
✓✗ |
24719 |
if (!BN_GF2m_add(x2, x2, t)) |
517 |
|
|
goto err; |
518 |
|
|
} else { |
519 |
✓✓✗✓
|
90669 |
if (BN_GF2m_cmp(y0, y1) || BN_is_zero(x1)) { |
520 |
✓✗ |
323 |
if (!EC_POINT_set_to_infinity(group, r)) |
521 |
|
|
goto err; |
522 |
|
|
ret = 1; |
523 |
|
323 |
goto err; |
524 |
|
|
} |
525 |
✓✗ |
45173 |
if (!group->meth->field_div(group, s, y1, x1, ctx)) |
526 |
|
|
goto err; |
527 |
✓✗ |
45173 |
if (!BN_GF2m_add(s, s, x1)) |
528 |
|
|
goto err; |
529 |
|
|
|
530 |
✓✗ |
45173 |
if (!group->meth->field_sqr(group, x2, s, ctx)) |
531 |
|
|
goto err; |
532 |
✓✗ |
45173 |
if (!BN_GF2m_add(x2, x2, s)) |
533 |
|
|
goto err; |
534 |
✓✗ |
45173 |
if (!BN_GF2m_add(x2, x2, &group->a)) |
535 |
|
|
goto err; |
536 |
|
|
} |
537 |
|
|
|
538 |
✓✗ |
69892 |
if (!BN_GF2m_add(y2, x1, x2)) |
539 |
|
|
goto err; |
540 |
✓✗ |
69892 |
if (!group->meth->field_mul(group, y2, y2, s, ctx)) |
541 |
|
|
goto err; |
542 |
✓✗ |
69892 |
if (!BN_GF2m_add(y2, y2, x2)) |
543 |
|
|
goto err; |
544 |
✓✗ |
69892 |
if (!BN_GF2m_add(y2, y2, y1)) |
545 |
|
|
goto err; |
546 |
|
|
|
547 |
✓✗ |
69892 |
if (!EC_POINT_set_affine_coordinates_GF2m(group, r, x2, y2, ctx)) |
548 |
|
|
goto err; |
549 |
|
|
|
550 |
|
69892 |
ret = 1; |
551 |
|
|
|
552 |
|
|
err: |
553 |
|
70215 |
BN_CTX_end(ctx); |
554 |
|
70215 |
BN_CTX_free(new_ctx); |
555 |
|
70215 |
return ret; |
556 |
|
74094 |
} |
557 |
|
|
|
558 |
|
|
|
559 |
|
|
/* Computes 2 * a and stores the result in r. r could be a. |
560 |
|
|
* Uses algorithm A.10.2 of IEEE P1363. |
561 |
|
|
*/ |
562 |
|
|
int |
563 |
|
|
ec_GF2m_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, |
564 |
|
|
BN_CTX *ctx) |
565 |
|
|
{ |
566 |
|
91852 |
return ec_GF2m_simple_add(group, r, a, a, ctx); |
567 |
|
|
} |
568 |
|
|
|
569 |
|
|
int |
570 |
|
|
ec_GF2m_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) |
571 |
|
|
{ |
572 |
✓✓✗✓
|
8836 |
if (EC_POINT_is_at_infinity(group, point) > 0 || BN_is_zero(&point->Y)) |
573 |
|
|
/* point is its own inverse */ |
574 |
|
269 |
return 1; |
575 |
|
|
|
576 |
✗✓ |
2766 |
if (!EC_POINT_make_affine(group, point, ctx)) |
577 |
|
|
return 0; |
578 |
|
2766 |
return BN_GF2m_add(&point->Y, &point->X, &point->Y); |
579 |
|
3035 |
} |
580 |
|
|
|
581 |
|
|
|
582 |
|
|
/* Indicates whether the given point is the point at infinity. */ |
583 |
|
|
int |
584 |
|
|
ec_GF2m_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) |
585 |
|
|
{ |
586 |
|
317896 |
return BN_is_zero(&point->Z); |
587 |
|
|
} |
588 |
|
|
|
589 |
|
|
|
590 |
|
|
/* Determines whether the given EC_POINT is an actual point on the curve defined |
591 |
|
|
* in the EC_GROUP. A point is valid if it satisfies the Weierstrass equation: |
592 |
|
|
* y^2 + x*y = x^3 + a*x^2 + b. |
593 |
|
|
*/ |
594 |
|
|
int |
595 |
|
|
ec_GF2m_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx) |
596 |
|
|
{ |
597 |
|
|
int ret = -1; |
598 |
|
|
BN_CTX *new_ctx = NULL; |
599 |
|
|
BIGNUM *lh, *y2; |
600 |
|
|
int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); |
601 |
|
|
int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); |
602 |
|
|
|
603 |
✗✓ |
1484 |
if (EC_POINT_is_at_infinity(group, point) > 0) |
604 |
|
|
return 1; |
605 |
|
|
|
606 |
|
742 |
field_mul = group->meth->field_mul; |
607 |
|
742 |
field_sqr = group->meth->field_sqr; |
608 |
|
|
|
609 |
|
|
/* only support affine coordinates */ |
610 |
✗✓ |
742 |
if (!point->Z_is_one) |
611 |
|
|
return -1; |
612 |
|
|
|
613 |
✗✓ |
742 |
if (ctx == NULL) { |
614 |
|
|
ctx = new_ctx = BN_CTX_new(); |
615 |
|
|
if (ctx == NULL) |
616 |
|
|
return -1; |
617 |
|
|
} |
618 |
|
742 |
BN_CTX_start(ctx); |
619 |
✓✗ |
742 |
if ((y2 = BN_CTX_get(ctx)) == NULL) |
620 |
|
|
goto err; |
621 |
✓✗ |
742 |
if ((lh = BN_CTX_get(ctx)) == NULL) |
622 |
|
|
goto err; |
623 |
|
|
|
624 |
|
|
/* |
625 |
|
|
* We have a curve defined by a Weierstrass equation y^2 + x*y = x^3 |
626 |
|
|
* + a*x^2 + b. <=> x^3 + a*x^2 + x*y + b + y^2 = 0 <=> ((x + a) * x |
627 |
|
|
* + y ) * x + b + y^2 = 0 |
628 |
|
|
*/ |
629 |
✓✗ |
742 |
if (!BN_GF2m_add(lh, &point->X, &group->a)) |
630 |
|
|
goto err; |
631 |
✓✗ |
742 |
if (!field_mul(group, lh, lh, &point->X, ctx)) |
632 |
|
|
goto err; |
633 |
✓✗ |
742 |
if (!BN_GF2m_add(lh, lh, &point->Y)) |
634 |
|
|
goto err; |
635 |
✓✗ |
742 |
if (!field_mul(group, lh, lh, &point->X, ctx)) |
636 |
|
|
goto err; |
637 |
✓✗ |
742 |
if (!BN_GF2m_add(lh, lh, &group->b)) |
638 |
|
|
goto err; |
639 |
✓✗ |
742 |
if (!field_sqr(group, y2, &point->Y, ctx)) |
640 |
|
|
goto err; |
641 |
✓✗ |
742 |
if (!BN_GF2m_add(lh, lh, y2)) |
642 |
|
|
goto err; |
643 |
|
742 |
ret = BN_is_zero(lh); |
644 |
|
|
err: |
645 |
✓✗ |
742 |
if (ctx) |
646 |
|
742 |
BN_CTX_end(ctx); |
647 |
|
742 |
BN_CTX_free(new_ctx); |
648 |
|
742 |
return ret; |
649 |
|
742 |
} |
650 |
|
|
|
651 |
|
|
|
652 |
|
|
/* Indicates whether two points are equal. |
653 |
|
|
* Return values: |
654 |
|
|
* -1 error |
655 |
|
|
* 0 equal (in affine coordinates) |
656 |
|
|
* 1 not equal |
657 |
|
|
*/ |
658 |
|
|
int |
659 |
|
|
ec_GF2m_simple_cmp(const EC_GROUP *group, const EC_POINT *a, |
660 |
|
|
const EC_POINT *b, BN_CTX *ctx) |
661 |
|
|
{ |
662 |
|
|
BIGNUM *aX, *aY, *bX, *bY; |
663 |
|
|
BN_CTX *new_ctx = NULL; |
664 |
|
|
int ret = -1; |
665 |
|
|
|
666 |
✓✓ |
1644 |
if (EC_POINT_is_at_infinity(group, a) > 0) { |
667 |
|
728 |
return EC_POINT_is_at_infinity(group, b) > 0 ? 0 : 1; |
668 |
|
|
} |
669 |
✗✓ |
368 |
if (EC_POINT_is_at_infinity(group, b) > 0) |
670 |
|
|
return 1; |
671 |
|
|
|
672 |
✓✗✓✗
|
736 |
if (a->Z_is_one && b->Z_is_one) { |
673 |
✓✓ |
1050 |
return ((BN_cmp(&a->X, &b->X) == 0) && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1; |
674 |
|
|
} |
675 |
|
|
if (ctx == NULL) { |
676 |
|
|
ctx = new_ctx = BN_CTX_new(); |
677 |
|
|
if (ctx == NULL) |
678 |
|
|
return -1; |
679 |
|
|
} |
680 |
|
|
BN_CTX_start(ctx); |
681 |
|
|
if ((aX = BN_CTX_get(ctx)) == NULL) |
682 |
|
|
goto err; |
683 |
|
|
if ((aY = BN_CTX_get(ctx)) == NULL) |
684 |
|
|
goto err; |
685 |
|
|
if ((bX = BN_CTX_get(ctx)) == NULL) |
686 |
|
|
goto err; |
687 |
|
|
if ((bY = BN_CTX_get(ctx)) == NULL) |
688 |
|
|
goto err; |
689 |
|
|
|
690 |
|
|
if (!EC_POINT_get_affine_coordinates_GF2m(group, a, aX, aY, ctx)) |
691 |
|
|
goto err; |
692 |
|
|
if (!EC_POINT_get_affine_coordinates_GF2m(group, b, bX, bY, ctx)) |
693 |
|
|
goto err; |
694 |
|
|
ret = ((BN_cmp(aX, bX) == 0) && BN_cmp(aY, bY) == 0) ? 0 : 1; |
695 |
|
|
|
696 |
|
|
err: |
697 |
|
|
if (ctx) |
698 |
|
|
BN_CTX_end(ctx); |
699 |
|
|
BN_CTX_free(new_ctx); |
700 |
|
|
return ret; |
701 |
|
548 |
} |
702 |
|
|
|
703 |
|
|
|
704 |
|
|
/* Forces the given EC_POINT to internally use affine coordinates. */ |
705 |
|
|
int |
706 |
|
|
ec_GF2m_simple_make_affine(const EC_GROUP * group, EC_POINT * point, BN_CTX * ctx) |
707 |
|
|
{ |
708 |
|
|
BN_CTX *new_ctx = NULL; |
709 |
|
|
BIGNUM *x, *y; |
710 |
|
|
int ret = 0; |
711 |
|
|
|
712 |
✗✓✗✗
|
46956 |
if (point->Z_is_one || EC_POINT_is_at_infinity(group, point) > 0) |
713 |
|
23478 |
return 1; |
714 |
|
|
|
715 |
|
|
if (ctx == NULL) { |
716 |
|
|
ctx = new_ctx = BN_CTX_new(); |
717 |
|
|
if (ctx == NULL) |
718 |
|
|
return 0; |
719 |
|
|
} |
720 |
|
|
BN_CTX_start(ctx); |
721 |
|
|
if ((x = BN_CTX_get(ctx)) == NULL) |
722 |
|
|
goto err; |
723 |
|
|
if ((y = BN_CTX_get(ctx)) == NULL) |
724 |
|
|
goto err; |
725 |
|
|
|
726 |
|
|
if (!EC_POINT_get_affine_coordinates_GF2m(group, point, x, y, ctx)) |
727 |
|
|
goto err; |
728 |
|
|
if (!BN_copy(&point->X, x)) |
729 |
|
|
goto err; |
730 |
|
|
if (!BN_copy(&point->Y, y)) |
731 |
|
|
goto err; |
732 |
|
|
if (!BN_one(&point->Z)) |
733 |
|
|
goto err; |
734 |
|
|
|
735 |
|
|
ret = 1; |
736 |
|
|
|
737 |
|
|
err: |
738 |
|
|
if (ctx) |
739 |
|
|
BN_CTX_end(ctx); |
740 |
|
|
BN_CTX_free(new_ctx); |
741 |
|
|
return ret; |
742 |
|
23478 |
} |
743 |
|
|
|
744 |
|
|
|
745 |
|
|
/* Forces each of the EC_POINTs in the given array to use affine coordinates. */ |
746 |
|
|
int |
747 |
|
|
ec_GF2m_simple_points_make_affine(const EC_GROUP *group, size_t num, |
748 |
|
|
EC_POINT *points[], BN_CTX *ctx) |
749 |
|
|
{ |
750 |
|
|
size_t i; |
751 |
|
|
|
752 |
✓✓ |
41982 |
for (i = 0; i < num; i++) { |
753 |
✗✓ |
20712 |
if (!group->meth->make_affine(group, points[i], ctx)) |
754 |
|
|
return 0; |
755 |
|
|
} |
756 |
|
|
|
757 |
|
186 |
return 1; |
758 |
|
186 |
} |
759 |
|
|
|
760 |
|
|
|
761 |
|
|
/* Wrapper to simple binary polynomial field multiplication implementation. */ |
762 |
|
|
int |
763 |
|
|
ec_GF2m_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, |
764 |
|
|
const BIGNUM *b, BN_CTX *ctx) |
765 |
|
|
{ |
766 |
|
11704668 |
return BN_GF2m_mod_mul_arr(r, a, b, group->poly, ctx); |
767 |
|
|
} |
768 |
|
|
|
769 |
|
|
|
770 |
|
|
/* Wrapper to simple binary polynomial field squaring implementation. */ |
771 |
|
|
int |
772 |
|
|
ec_GF2m_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, |
773 |
|
|
BN_CTX *ctx) |
774 |
|
|
{ |
775 |
|
9743546 |
return BN_GF2m_mod_sqr_arr(r, a, group->poly, ctx); |
776 |
|
|
} |
777 |
|
|
|
778 |
|
|
|
779 |
|
|
/* Wrapper to simple binary polynomial field division implementation. */ |
780 |
|
|
int |
781 |
|
|
ec_GF2m_simple_field_div(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, |
782 |
|
|
const BIGNUM *b, BN_CTX *ctx) |
783 |
|
|
{ |
784 |
|
147800 |
return BN_GF2m_mod_div(r, a, b, &group->field, ctx); |
785 |
|
|
} |
786 |
|
|
|
787 |
|
|
#endif |