xref: /third_party/openssl/crypto/ec/ec2_smpl.c (revision e1051a39)
1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2002-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
4e1051a39Sopenharmony_ci *
5e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
6e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
7e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
8e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
9e1051a39Sopenharmony_ci */
10e1051a39Sopenharmony_ci
11e1051a39Sopenharmony_ci/*
12e1051a39Sopenharmony_ci * ECDSA low level APIs are deprecated for public use, but still ok for
13e1051a39Sopenharmony_ci * internal use.
14e1051a39Sopenharmony_ci */
15e1051a39Sopenharmony_ci#include "internal/deprecated.h"
16e1051a39Sopenharmony_ci
17e1051a39Sopenharmony_ci#include <openssl/err.h>
18e1051a39Sopenharmony_ci
19e1051a39Sopenharmony_ci#include "crypto/bn.h"
20e1051a39Sopenharmony_ci#include "ec_local.h"
21e1051a39Sopenharmony_ci
22e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_EC2M
23e1051a39Sopenharmony_ci
24e1051a39Sopenharmony_ci/*
25e1051a39Sopenharmony_ci * Initialize a GF(2^m)-based EC_GROUP structure. Note that all other members
26e1051a39Sopenharmony_ci * are handled by EC_GROUP_new.
27e1051a39Sopenharmony_ci */
28e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_group_init(EC_GROUP *group)
29e1051a39Sopenharmony_ci{
30e1051a39Sopenharmony_ci    group->field = BN_new();
31e1051a39Sopenharmony_ci    group->a = BN_new();
32e1051a39Sopenharmony_ci    group->b = BN_new();
33e1051a39Sopenharmony_ci
34e1051a39Sopenharmony_ci    if (group->field == NULL || group->a == NULL || group->b == NULL) {
35e1051a39Sopenharmony_ci        BN_free(group->field);
36e1051a39Sopenharmony_ci        BN_free(group->a);
37e1051a39Sopenharmony_ci        BN_free(group->b);
38e1051a39Sopenharmony_ci        return 0;
39e1051a39Sopenharmony_ci    }
40e1051a39Sopenharmony_ci    return 1;
41e1051a39Sopenharmony_ci}
42e1051a39Sopenharmony_ci
43e1051a39Sopenharmony_ci/*
44e1051a39Sopenharmony_ci * Free a GF(2^m)-based EC_GROUP structure. Note that all other members are
45e1051a39Sopenharmony_ci * handled by EC_GROUP_free.
46e1051a39Sopenharmony_ci */
47e1051a39Sopenharmony_civoid ossl_ec_GF2m_simple_group_finish(EC_GROUP *group)
48e1051a39Sopenharmony_ci{
49e1051a39Sopenharmony_ci    BN_free(group->field);
50e1051a39Sopenharmony_ci    BN_free(group->a);
51e1051a39Sopenharmony_ci    BN_free(group->b);
52e1051a39Sopenharmony_ci}
53e1051a39Sopenharmony_ci
54e1051a39Sopenharmony_ci/*
55e1051a39Sopenharmony_ci * Clear and free a GF(2^m)-based EC_GROUP structure. Note that all other
56e1051a39Sopenharmony_ci * members are handled by EC_GROUP_clear_free.
57e1051a39Sopenharmony_ci */
58e1051a39Sopenharmony_civoid ossl_ec_GF2m_simple_group_clear_finish(EC_GROUP *group)
59e1051a39Sopenharmony_ci{
60e1051a39Sopenharmony_ci    BN_clear_free(group->field);
61e1051a39Sopenharmony_ci    BN_clear_free(group->a);
62e1051a39Sopenharmony_ci    BN_clear_free(group->b);
63e1051a39Sopenharmony_ci    group->poly[0] = 0;
64e1051a39Sopenharmony_ci    group->poly[1] = 0;
65e1051a39Sopenharmony_ci    group->poly[2] = 0;
66e1051a39Sopenharmony_ci    group->poly[3] = 0;
67e1051a39Sopenharmony_ci    group->poly[4] = 0;
68e1051a39Sopenharmony_ci    group->poly[5] = -1;
69e1051a39Sopenharmony_ci}
70e1051a39Sopenharmony_ci
71e1051a39Sopenharmony_ci/*
72e1051a39Sopenharmony_ci * Copy a GF(2^m)-based EC_GROUP structure. Note that all other members are
73e1051a39Sopenharmony_ci * handled by EC_GROUP_copy.
74e1051a39Sopenharmony_ci */
75e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src)
76e1051a39Sopenharmony_ci{
77e1051a39Sopenharmony_ci    if (!BN_copy(dest->field, src->field))
78e1051a39Sopenharmony_ci        return 0;
79e1051a39Sopenharmony_ci    if (!BN_copy(dest->a, src->a))
80e1051a39Sopenharmony_ci        return 0;
81e1051a39Sopenharmony_ci    if (!BN_copy(dest->b, src->b))
82e1051a39Sopenharmony_ci        return 0;
83e1051a39Sopenharmony_ci    dest->poly[0] = src->poly[0];
84e1051a39Sopenharmony_ci    dest->poly[1] = src->poly[1];
85e1051a39Sopenharmony_ci    dest->poly[2] = src->poly[2];
86e1051a39Sopenharmony_ci    dest->poly[3] = src->poly[3];
87e1051a39Sopenharmony_ci    dest->poly[4] = src->poly[4];
88e1051a39Sopenharmony_ci    dest->poly[5] = src->poly[5];
89e1051a39Sopenharmony_ci    if (bn_wexpand(dest->a, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2) ==
90e1051a39Sopenharmony_ci        NULL)
91e1051a39Sopenharmony_ci        return 0;
92e1051a39Sopenharmony_ci    if (bn_wexpand(dest->b, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2) ==
93e1051a39Sopenharmony_ci        NULL)
94e1051a39Sopenharmony_ci        return 0;
95e1051a39Sopenharmony_ci    bn_set_all_zero(dest->a);
96e1051a39Sopenharmony_ci    bn_set_all_zero(dest->b);
97e1051a39Sopenharmony_ci    return 1;
98e1051a39Sopenharmony_ci}
99e1051a39Sopenharmony_ci
100e1051a39Sopenharmony_ci/* Set the curve parameters of an EC_GROUP structure. */
101e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_group_set_curve(EC_GROUP *group,
102e1051a39Sopenharmony_ci                                        const BIGNUM *p, const BIGNUM *a,
103e1051a39Sopenharmony_ci                                        const BIGNUM *b, BN_CTX *ctx)
104e1051a39Sopenharmony_ci{
105e1051a39Sopenharmony_ci    int ret = 0, i;
106e1051a39Sopenharmony_ci
107e1051a39Sopenharmony_ci    /* group->field */
108e1051a39Sopenharmony_ci    if (!BN_copy(group->field, p))
109e1051a39Sopenharmony_ci        goto err;
110e1051a39Sopenharmony_ci    i = BN_GF2m_poly2arr(group->field, group->poly, 6) - 1;
111e1051a39Sopenharmony_ci    if ((i != 5) && (i != 3)) {
112e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, EC_R_UNSUPPORTED_FIELD);
113e1051a39Sopenharmony_ci        goto err;
114e1051a39Sopenharmony_ci    }
115e1051a39Sopenharmony_ci
116e1051a39Sopenharmony_ci    /* group->a */
117e1051a39Sopenharmony_ci    if (!BN_GF2m_mod_arr(group->a, a, group->poly))
118e1051a39Sopenharmony_ci        goto err;
119e1051a39Sopenharmony_ci    if (bn_wexpand(group->a, (int)(group->poly[0] + BN_BITS2 - 1) / BN_BITS2)
120e1051a39Sopenharmony_ci        == NULL)
121e1051a39Sopenharmony_ci        goto err;
122e1051a39Sopenharmony_ci    bn_set_all_zero(group->a);
123e1051a39Sopenharmony_ci
124e1051a39Sopenharmony_ci    /* group->b */
125e1051a39Sopenharmony_ci    if (!BN_GF2m_mod_arr(group->b, b, group->poly))
126e1051a39Sopenharmony_ci        goto err;
127e1051a39Sopenharmony_ci    if (bn_wexpand(group->b, (int)(group->poly[0] + BN_BITS2 - 1) / BN_BITS2)
128e1051a39Sopenharmony_ci        == NULL)
129e1051a39Sopenharmony_ci        goto err;
130e1051a39Sopenharmony_ci    bn_set_all_zero(group->b);
131e1051a39Sopenharmony_ci
132e1051a39Sopenharmony_ci    ret = 1;
133e1051a39Sopenharmony_ci err:
134e1051a39Sopenharmony_ci    return ret;
135e1051a39Sopenharmony_ci}
136e1051a39Sopenharmony_ci
137e1051a39Sopenharmony_ci/*
138e1051a39Sopenharmony_ci * Get the curve parameters of an EC_GROUP structure. If p, a, or b are NULL
139e1051a39Sopenharmony_ci * then there values will not be set but the method will return with success.
140e1051a39Sopenharmony_ci */
141e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p,
142e1051a39Sopenharmony_ci                                        BIGNUM *a, BIGNUM *b, BN_CTX *ctx)
143e1051a39Sopenharmony_ci{
144e1051a39Sopenharmony_ci    int ret = 0;
145e1051a39Sopenharmony_ci
146e1051a39Sopenharmony_ci    if (p != NULL) {
147e1051a39Sopenharmony_ci        if (!BN_copy(p, group->field))
148e1051a39Sopenharmony_ci            return 0;
149e1051a39Sopenharmony_ci    }
150e1051a39Sopenharmony_ci
151e1051a39Sopenharmony_ci    if (a != NULL) {
152e1051a39Sopenharmony_ci        if (!BN_copy(a, group->a))
153e1051a39Sopenharmony_ci            goto err;
154e1051a39Sopenharmony_ci    }
155e1051a39Sopenharmony_ci
156e1051a39Sopenharmony_ci    if (b != NULL) {
157e1051a39Sopenharmony_ci        if (!BN_copy(b, group->b))
158e1051a39Sopenharmony_ci            goto err;
159e1051a39Sopenharmony_ci    }
160e1051a39Sopenharmony_ci
161e1051a39Sopenharmony_ci    ret = 1;
162e1051a39Sopenharmony_ci
163e1051a39Sopenharmony_ci err:
164e1051a39Sopenharmony_ci    return ret;
165e1051a39Sopenharmony_ci}
166e1051a39Sopenharmony_ci
167e1051a39Sopenharmony_ci/*
168e1051a39Sopenharmony_ci * Gets the degree of the field.  For a curve over GF(2^m) this is the value
169e1051a39Sopenharmony_ci * m.
170e1051a39Sopenharmony_ci */
171e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_group_get_degree(const EC_GROUP *group)
172e1051a39Sopenharmony_ci{
173e1051a39Sopenharmony_ci    return BN_num_bits(group->field) - 1;
174e1051a39Sopenharmony_ci}
175e1051a39Sopenharmony_ci
176e1051a39Sopenharmony_ci/*
177e1051a39Sopenharmony_ci * Checks the discriminant of the curve. y^2 + x*y = x^3 + a*x^2 + b is an
178e1051a39Sopenharmony_ci * elliptic curve <=> b != 0 (mod p)
179e1051a39Sopenharmony_ci */
180e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_group_check_discriminant(const EC_GROUP *group,
181e1051a39Sopenharmony_ci                                                 BN_CTX *ctx)
182e1051a39Sopenharmony_ci{
183e1051a39Sopenharmony_ci    int ret = 0;
184e1051a39Sopenharmony_ci    BIGNUM *b;
185e1051a39Sopenharmony_ci#ifndef FIPS_MODULE
186e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
187e1051a39Sopenharmony_ci
188e1051a39Sopenharmony_ci    if (ctx == NULL) {
189e1051a39Sopenharmony_ci        ctx = new_ctx = BN_CTX_new();
190e1051a39Sopenharmony_ci        if (ctx == NULL) {
191e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE);
192e1051a39Sopenharmony_ci            goto err;
193e1051a39Sopenharmony_ci        }
194e1051a39Sopenharmony_ci    }
195e1051a39Sopenharmony_ci#endif
196e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
197e1051a39Sopenharmony_ci    b = BN_CTX_get(ctx);
198e1051a39Sopenharmony_ci    if (b == NULL)
199e1051a39Sopenharmony_ci        goto err;
200e1051a39Sopenharmony_ci
201e1051a39Sopenharmony_ci    if (!BN_GF2m_mod_arr(b, group->b, group->poly))
202e1051a39Sopenharmony_ci        goto err;
203e1051a39Sopenharmony_ci
204e1051a39Sopenharmony_ci    /*
205e1051a39Sopenharmony_ci     * check the discriminant: y^2 + x*y = x^3 + a*x^2 + b is an elliptic
206e1051a39Sopenharmony_ci     * curve <=> b != 0 (mod p)
207e1051a39Sopenharmony_ci     */
208e1051a39Sopenharmony_ci    if (BN_is_zero(b))
209e1051a39Sopenharmony_ci        goto err;
210e1051a39Sopenharmony_ci
211e1051a39Sopenharmony_ci    ret = 1;
212e1051a39Sopenharmony_ci
213e1051a39Sopenharmony_ci err:
214e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
215e1051a39Sopenharmony_ci#ifndef FIPS_MODULE
216e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
217e1051a39Sopenharmony_ci#endif
218e1051a39Sopenharmony_ci    return ret;
219e1051a39Sopenharmony_ci}
220e1051a39Sopenharmony_ci
221e1051a39Sopenharmony_ci/* Initializes an EC_POINT. */
222e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_point_init(EC_POINT *point)
223e1051a39Sopenharmony_ci{
224e1051a39Sopenharmony_ci    point->X = BN_new();
225e1051a39Sopenharmony_ci    point->Y = BN_new();
226e1051a39Sopenharmony_ci    point->Z = BN_new();
227e1051a39Sopenharmony_ci
228e1051a39Sopenharmony_ci    if (point->X == NULL || point->Y == NULL || point->Z == NULL) {
229e1051a39Sopenharmony_ci        BN_free(point->X);
230e1051a39Sopenharmony_ci        BN_free(point->Y);
231e1051a39Sopenharmony_ci        BN_free(point->Z);
232e1051a39Sopenharmony_ci        return 0;
233e1051a39Sopenharmony_ci    }
234e1051a39Sopenharmony_ci    return 1;
235e1051a39Sopenharmony_ci}
236e1051a39Sopenharmony_ci
237e1051a39Sopenharmony_ci/* Frees an EC_POINT. */
238e1051a39Sopenharmony_civoid ossl_ec_GF2m_simple_point_finish(EC_POINT *point)
239e1051a39Sopenharmony_ci{
240e1051a39Sopenharmony_ci    BN_free(point->X);
241e1051a39Sopenharmony_ci    BN_free(point->Y);
242e1051a39Sopenharmony_ci    BN_free(point->Z);
243e1051a39Sopenharmony_ci}
244e1051a39Sopenharmony_ci
245e1051a39Sopenharmony_ci/* Clears and frees an EC_POINT. */
246e1051a39Sopenharmony_civoid ossl_ec_GF2m_simple_point_clear_finish(EC_POINT *point)
247e1051a39Sopenharmony_ci{
248e1051a39Sopenharmony_ci    BN_clear_free(point->X);
249e1051a39Sopenharmony_ci    BN_clear_free(point->Y);
250e1051a39Sopenharmony_ci    BN_clear_free(point->Z);
251e1051a39Sopenharmony_ci    point->Z_is_one = 0;
252e1051a39Sopenharmony_ci}
253e1051a39Sopenharmony_ci
254e1051a39Sopenharmony_ci/*
255e1051a39Sopenharmony_ci * Copy the contents of one EC_POINT into another.  Assumes dest is
256e1051a39Sopenharmony_ci * initialized.
257e1051a39Sopenharmony_ci */
258e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_point_copy(EC_POINT *dest, const EC_POINT *src)
259e1051a39Sopenharmony_ci{
260e1051a39Sopenharmony_ci    if (!BN_copy(dest->X, src->X))
261e1051a39Sopenharmony_ci        return 0;
262e1051a39Sopenharmony_ci    if (!BN_copy(dest->Y, src->Y))
263e1051a39Sopenharmony_ci        return 0;
264e1051a39Sopenharmony_ci    if (!BN_copy(dest->Z, src->Z))
265e1051a39Sopenharmony_ci        return 0;
266e1051a39Sopenharmony_ci    dest->Z_is_one = src->Z_is_one;
267e1051a39Sopenharmony_ci    dest->curve_name = src->curve_name;
268e1051a39Sopenharmony_ci
269e1051a39Sopenharmony_ci    return 1;
270e1051a39Sopenharmony_ci}
271e1051a39Sopenharmony_ci
272e1051a39Sopenharmony_ci/*
273e1051a39Sopenharmony_ci * Set an EC_POINT to the point at infinity. A point at infinity is
274e1051a39Sopenharmony_ci * represented by having Z=0.
275e1051a39Sopenharmony_ci */
276e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_point_set_to_infinity(const EC_GROUP *group,
277e1051a39Sopenharmony_ci                                              EC_POINT *point)
278e1051a39Sopenharmony_ci{
279e1051a39Sopenharmony_ci    point->Z_is_one = 0;
280e1051a39Sopenharmony_ci    BN_zero(point->Z);
281e1051a39Sopenharmony_ci    return 1;
282e1051a39Sopenharmony_ci}
283e1051a39Sopenharmony_ci
284e1051a39Sopenharmony_ci/*
285e1051a39Sopenharmony_ci * Set the coordinates of an EC_POINT using affine coordinates. Note that
286e1051a39Sopenharmony_ci * the simple implementation only uses affine coordinates.
287e1051a39Sopenharmony_ci */
288e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_point_set_affine_coordinates(const EC_GROUP *group,
289e1051a39Sopenharmony_ci                                                     EC_POINT *point,
290e1051a39Sopenharmony_ci                                                     const BIGNUM *x,
291e1051a39Sopenharmony_ci                                                     const BIGNUM *y,
292e1051a39Sopenharmony_ci                                                     BN_CTX *ctx)
293e1051a39Sopenharmony_ci{
294e1051a39Sopenharmony_ci    int ret = 0;
295e1051a39Sopenharmony_ci    if (x == NULL || y == NULL) {
296e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, ERR_R_PASSED_NULL_PARAMETER);
297e1051a39Sopenharmony_ci        return 0;
298e1051a39Sopenharmony_ci    }
299e1051a39Sopenharmony_ci
300e1051a39Sopenharmony_ci    if (!BN_copy(point->X, x))
301e1051a39Sopenharmony_ci        goto err;
302e1051a39Sopenharmony_ci    BN_set_negative(point->X, 0);
303e1051a39Sopenharmony_ci    if (!BN_copy(point->Y, y))
304e1051a39Sopenharmony_ci        goto err;
305e1051a39Sopenharmony_ci    BN_set_negative(point->Y, 0);
306e1051a39Sopenharmony_ci    if (!BN_copy(point->Z, BN_value_one()))
307e1051a39Sopenharmony_ci        goto err;
308e1051a39Sopenharmony_ci    BN_set_negative(point->Z, 0);
309e1051a39Sopenharmony_ci    point->Z_is_one = 1;
310e1051a39Sopenharmony_ci    ret = 1;
311e1051a39Sopenharmony_ci
312e1051a39Sopenharmony_ci err:
313e1051a39Sopenharmony_ci    return ret;
314e1051a39Sopenharmony_ci}
315e1051a39Sopenharmony_ci
316e1051a39Sopenharmony_ci/*
317e1051a39Sopenharmony_ci * Gets the affine coordinates of an EC_POINT. Note that the simple
318e1051a39Sopenharmony_ci * implementation only uses affine coordinates.
319e1051a39Sopenharmony_ci */
320e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_point_get_affine_coordinates(const EC_GROUP *group,
321e1051a39Sopenharmony_ci                                                     const EC_POINT *point,
322e1051a39Sopenharmony_ci                                                     BIGNUM *x, BIGNUM *y,
323e1051a39Sopenharmony_ci                                                     BN_CTX *ctx)
324e1051a39Sopenharmony_ci{
325e1051a39Sopenharmony_ci    int ret = 0;
326e1051a39Sopenharmony_ci
327e1051a39Sopenharmony_ci    if (EC_POINT_is_at_infinity(group, point)) {
328e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, EC_R_POINT_AT_INFINITY);
329e1051a39Sopenharmony_ci        return 0;
330e1051a39Sopenharmony_ci    }
331e1051a39Sopenharmony_ci
332e1051a39Sopenharmony_ci    if (BN_cmp(point->Z, BN_value_one())) {
333e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
334e1051a39Sopenharmony_ci        return 0;
335e1051a39Sopenharmony_ci    }
336e1051a39Sopenharmony_ci    if (x != NULL) {
337e1051a39Sopenharmony_ci        if (!BN_copy(x, point->X))
338e1051a39Sopenharmony_ci            goto err;
339e1051a39Sopenharmony_ci        BN_set_negative(x, 0);
340e1051a39Sopenharmony_ci    }
341e1051a39Sopenharmony_ci    if (y != NULL) {
342e1051a39Sopenharmony_ci        if (!BN_copy(y, point->Y))
343e1051a39Sopenharmony_ci            goto err;
344e1051a39Sopenharmony_ci        BN_set_negative(y, 0);
345e1051a39Sopenharmony_ci    }
346e1051a39Sopenharmony_ci    ret = 1;
347e1051a39Sopenharmony_ci
348e1051a39Sopenharmony_ci err:
349e1051a39Sopenharmony_ci    return ret;
350e1051a39Sopenharmony_ci}
351e1051a39Sopenharmony_ci
352e1051a39Sopenharmony_ci/*
353e1051a39Sopenharmony_ci * Computes a + b and stores the result in r.  r could be a or b, a could be
354e1051a39Sopenharmony_ci * b. Uses algorithm A.10.2 of IEEE P1363.
355e1051a39Sopenharmony_ci */
356e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_add(const EC_GROUP *group, EC_POINT *r,
357e1051a39Sopenharmony_ci                            const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx)
358e1051a39Sopenharmony_ci{
359e1051a39Sopenharmony_ci    BIGNUM *x0, *y0, *x1, *y1, *x2, *y2, *s, *t;
360e1051a39Sopenharmony_ci    int ret = 0;
361e1051a39Sopenharmony_ci#ifndef FIPS_MODULE
362e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
363e1051a39Sopenharmony_ci#endif
364e1051a39Sopenharmony_ci
365e1051a39Sopenharmony_ci    if (EC_POINT_is_at_infinity(group, a)) {
366e1051a39Sopenharmony_ci        if (!EC_POINT_copy(r, b))
367e1051a39Sopenharmony_ci            return 0;
368e1051a39Sopenharmony_ci        return 1;
369e1051a39Sopenharmony_ci    }
370e1051a39Sopenharmony_ci
371e1051a39Sopenharmony_ci    if (EC_POINT_is_at_infinity(group, b)) {
372e1051a39Sopenharmony_ci        if (!EC_POINT_copy(r, a))
373e1051a39Sopenharmony_ci            return 0;
374e1051a39Sopenharmony_ci        return 1;
375e1051a39Sopenharmony_ci    }
376e1051a39Sopenharmony_ci
377e1051a39Sopenharmony_ci#ifndef FIPS_MODULE
378e1051a39Sopenharmony_ci    if (ctx == NULL) {
379e1051a39Sopenharmony_ci        ctx = new_ctx = BN_CTX_new();
380e1051a39Sopenharmony_ci        if (ctx == NULL)
381e1051a39Sopenharmony_ci            return 0;
382e1051a39Sopenharmony_ci    }
383e1051a39Sopenharmony_ci#endif
384e1051a39Sopenharmony_ci
385e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
386e1051a39Sopenharmony_ci    x0 = BN_CTX_get(ctx);
387e1051a39Sopenharmony_ci    y0 = BN_CTX_get(ctx);
388e1051a39Sopenharmony_ci    x1 = BN_CTX_get(ctx);
389e1051a39Sopenharmony_ci    y1 = BN_CTX_get(ctx);
390e1051a39Sopenharmony_ci    x2 = BN_CTX_get(ctx);
391e1051a39Sopenharmony_ci    y2 = BN_CTX_get(ctx);
392e1051a39Sopenharmony_ci    s = BN_CTX_get(ctx);
393e1051a39Sopenharmony_ci    t = BN_CTX_get(ctx);
394e1051a39Sopenharmony_ci    if (t == NULL)
395e1051a39Sopenharmony_ci        goto err;
396e1051a39Sopenharmony_ci
397e1051a39Sopenharmony_ci    if (a->Z_is_one) {
398e1051a39Sopenharmony_ci        if (!BN_copy(x0, a->X))
399e1051a39Sopenharmony_ci            goto err;
400e1051a39Sopenharmony_ci        if (!BN_copy(y0, a->Y))
401e1051a39Sopenharmony_ci            goto err;
402e1051a39Sopenharmony_ci    } else {
403e1051a39Sopenharmony_ci        if (!EC_POINT_get_affine_coordinates(group, a, x0, y0, ctx))
404e1051a39Sopenharmony_ci            goto err;
405e1051a39Sopenharmony_ci    }
406e1051a39Sopenharmony_ci    if (b->Z_is_one) {
407e1051a39Sopenharmony_ci        if (!BN_copy(x1, b->X))
408e1051a39Sopenharmony_ci            goto err;
409e1051a39Sopenharmony_ci        if (!BN_copy(y1, b->Y))
410e1051a39Sopenharmony_ci            goto err;
411e1051a39Sopenharmony_ci    } else {
412e1051a39Sopenharmony_ci        if (!EC_POINT_get_affine_coordinates(group, b, x1, y1, ctx))
413e1051a39Sopenharmony_ci            goto err;
414e1051a39Sopenharmony_ci    }
415e1051a39Sopenharmony_ci
416e1051a39Sopenharmony_ci    if (BN_GF2m_cmp(x0, x1)) {
417e1051a39Sopenharmony_ci        if (!BN_GF2m_add(t, x0, x1))
418e1051a39Sopenharmony_ci            goto err;
419e1051a39Sopenharmony_ci        if (!BN_GF2m_add(s, y0, y1))
420e1051a39Sopenharmony_ci            goto err;
421e1051a39Sopenharmony_ci        if (!group->meth->field_div(group, s, s, t, ctx))
422e1051a39Sopenharmony_ci            goto err;
423e1051a39Sopenharmony_ci        if (!group->meth->field_sqr(group, x2, s, ctx))
424e1051a39Sopenharmony_ci            goto err;
425e1051a39Sopenharmony_ci        if (!BN_GF2m_add(x2, x2, group->a))
426e1051a39Sopenharmony_ci            goto err;
427e1051a39Sopenharmony_ci        if (!BN_GF2m_add(x2, x2, s))
428e1051a39Sopenharmony_ci            goto err;
429e1051a39Sopenharmony_ci        if (!BN_GF2m_add(x2, x2, t))
430e1051a39Sopenharmony_ci            goto err;
431e1051a39Sopenharmony_ci    } else {
432e1051a39Sopenharmony_ci        if (BN_GF2m_cmp(y0, y1) || BN_is_zero(x1)) {
433e1051a39Sopenharmony_ci            if (!EC_POINT_set_to_infinity(group, r))
434e1051a39Sopenharmony_ci                goto err;
435e1051a39Sopenharmony_ci            ret = 1;
436e1051a39Sopenharmony_ci            goto err;
437e1051a39Sopenharmony_ci        }
438e1051a39Sopenharmony_ci        if (!group->meth->field_div(group, s, y1, x1, ctx))
439e1051a39Sopenharmony_ci            goto err;
440e1051a39Sopenharmony_ci        if (!BN_GF2m_add(s, s, x1))
441e1051a39Sopenharmony_ci            goto err;
442e1051a39Sopenharmony_ci
443e1051a39Sopenharmony_ci        if (!group->meth->field_sqr(group, x2, s, ctx))
444e1051a39Sopenharmony_ci            goto err;
445e1051a39Sopenharmony_ci        if (!BN_GF2m_add(x2, x2, s))
446e1051a39Sopenharmony_ci            goto err;
447e1051a39Sopenharmony_ci        if (!BN_GF2m_add(x2, x2, group->a))
448e1051a39Sopenharmony_ci            goto err;
449e1051a39Sopenharmony_ci    }
450e1051a39Sopenharmony_ci
451e1051a39Sopenharmony_ci    if (!BN_GF2m_add(y2, x1, x2))
452e1051a39Sopenharmony_ci        goto err;
453e1051a39Sopenharmony_ci    if (!group->meth->field_mul(group, y2, y2, s, ctx))
454e1051a39Sopenharmony_ci        goto err;
455e1051a39Sopenharmony_ci    if (!BN_GF2m_add(y2, y2, x2))
456e1051a39Sopenharmony_ci        goto err;
457e1051a39Sopenharmony_ci    if (!BN_GF2m_add(y2, y2, y1))
458e1051a39Sopenharmony_ci        goto err;
459e1051a39Sopenharmony_ci
460e1051a39Sopenharmony_ci    if (!EC_POINT_set_affine_coordinates(group, r, x2, y2, ctx))
461e1051a39Sopenharmony_ci        goto err;
462e1051a39Sopenharmony_ci
463e1051a39Sopenharmony_ci    ret = 1;
464e1051a39Sopenharmony_ci
465e1051a39Sopenharmony_ci err:
466e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
467e1051a39Sopenharmony_ci#ifndef FIPS_MODULE
468e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
469e1051a39Sopenharmony_ci#endif
470e1051a39Sopenharmony_ci    return ret;
471e1051a39Sopenharmony_ci}
472e1051a39Sopenharmony_ci
473e1051a39Sopenharmony_ci/*
474e1051a39Sopenharmony_ci * Computes 2 * a and stores the result in r.  r could be a. Uses algorithm
475e1051a39Sopenharmony_ci * A.10.2 of IEEE P1363.
476e1051a39Sopenharmony_ci */
477e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_dbl(const EC_GROUP *group, EC_POINT *r,
478e1051a39Sopenharmony_ci                            const EC_POINT *a, BN_CTX *ctx)
479e1051a39Sopenharmony_ci{
480e1051a39Sopenharmony_ci    return ossl_ec_GF2m_simple_add(group, r, a, a, ctx);
481e1051a39Sopenharmony_ci}
482e1051a39Sopenharmony_ci
483e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_invert(const EC_GROUP *group, EC_POINT *point,
484e1051a39Sopenharmony_ci                               BN_CTX *ctx)
485e1051a39Sopenharmony_ci{
486e1051a39Sopenharmony_ci    if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(point->Y))
487e1051a39Sopenharmony_ci        /* point is its own inverse */
488e1051a39Sopenharmony_ci        return 1;
489e1051a39Sopenharmony_ci
490e1051a39Sopenharmony_ci    if (group->meth->make_affine == NULL
491e1051a39Sopenharmony_ci        || !group->meth->make_affine(group, point, ctx))
492e1051a39Sopenharmony_ci        return 0;
493e1051a39Sopenharmony_ci    return BN_GF2m_add(point->Y, point->X, point->Y);
494e1051a39Sopenharmony_ci}
495e1051a39Sopenharmony_ci
496e1051a39Sopenharmony_ci/* Indicates whether the given point is the point at infinity. */
497e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_is_at_infinity(const EC_GROUP *group,
498e1051a39Sopenharmony_ci                                       const EC_POINT *point)
499e1051a39Sopenharmony_ci{
500e1051a39Sopenharmony_ci    return BN_is_zero(point->Z);
501e1051a39Sopenharmony_ci}
502e1051a39Sopenharmony_ci
503e1051a39Sopenharmony_ci/*-
504e1051a39Sopenharmony_ci * Determines whether the given EC_POINT is an actual point on the curve defined
505e1051a39Sopenharmony_ci * in the EC_GROUP.  A point is valid if it satisfies the Weierstrass equation:
506e1051a39Sopenharmony_ci *      y^2 + x*y = x^3 + a*x^2 + b.
507e1051a39Sopenharmony_ci */
508e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
509e1051a39Sopenharmony_ci                                    BN_CTX *ctx)
510e1051a39Sopenharmony_ci{
511e1051a39Sopenharmony_ci    int ret = -1;
512e1051a39Sopenharmony_ci    BIGNUM *lh, *y2;
513e1051a39Sopenharmony_ci    int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
514e1051a39Sopenharmony_ci                      const BIGNUM *, BN_CTX *);
515e1051a39Sopenharmony_ci    int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
516e1051a39Sopenharmony_ci#ifndef FIPS_MODULE
517e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
518e1051a39Sopenharmony_ci#endif
519e1051a39Sopenharmony_ci
520e1051a39Sopenharmony_ci    if (EC_POINT_is_at_infinity(group, point))
521e1051a39Sopenharmony_ci        return 1;
522e1051a39Sopenharmony_ci
523e1051a39Sopenharmony_ci    field_mul = group->meth->field_mul;
524e1051a39Sopenharmony_ci    field_sqr = group->meth->field_sqr;
525e1051a39Sopenharmony_ci
526e1051a39Sopenharmony_ci    /* only support affine coordinates */
527e1051a39Sopenharmony_ci    if (!point->Z_is_one)
528e1051a39Sopenharmony_ci        return -1;
529e1051a39Sopenharmony_ci
530e1051a39Sopenharmony_ci#ifndef FIPS_MODULE
531e1051a39Sopenharmony_ci    if (ctx == NULL) {
532e1051a39Sopenharmony_ci        ctx = new_ctx = BN_CTX_new();
533e1051a39Sopenharmony_ci        if (ctx == NULL)
534e1051a39Sopenharmony_ci            return -1;
535e1051a39Sopenharmony_ci    }
536e1051a39Sopenharmony_ci#endif
537e1051a39Sopenharmony_ci
538e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
539e1051a39Sopenharmony_ci    y2 = BN_CTX_get(ctx);
540e1051a39Sopenharmony_ci    lh = BN_CTX_get(ctx);
541e1051a39Sopenharmony_ci    if (lh == NULL)
542e1051a39Sopenharmony_ci        goto err;
543e1051a39Sopenharmony_ci
544e1051a39Sopenharmony_ci    /*-
545e1051a39Sopenharmony_ci     * We have a curve defined by a Weierstrass equation
546e1051a39Sopenharmony_ci     *      y^2 + x*y = x^3 + a*x^2 + b.
547e1051a39Sopenharmony_ci     *  <=> x^3 + a*x^2 + x*y + b + y^2 = 0
548e1051a39Sopenharmony_ci     *  <=> ((x + a) * x + y ) * x + b + y^2 = 0
549e1051a39Sopenharmony_ci     */
550e1051a39Sopenharmony_ci    if (!BN_GF2m_add(lh, point->X, group->a))
551e1051a39Sopenharmony_ci        goto err;
552e1051a39Sopenharmony_ci    if (!field_mul(group, lh, lh, point->X, ctx))
553e1051a39Sopenharmony_ci        goto err;
554e1051a39Sopenharmony_ci    if (!BN_GF2m_add(lh, lh, point->Y))
555e1051a39Sopenharmony_ci        goto err;
556e1051a39Sopenharmony_ci    if (!field_mul(group, lh, lh, point->X, ctx))
557e1051a39Sopenharmony_ci        goto err;
558e1051a39Sopenharmony_ci    if (!BN_GF2m_add(lh, lh, group->b))
559e1051a39Sopenharmony_ci        goto err;
560e1051a39Sopenharmony_ci    if (!field_sqr(group, y2, point->Y, ctx))
561e1051a39Sopenharmony_ci        goto err;
562e1051a39Sopenharmony_ci    if (!BN_GF2m_add(lh, lh, y2))
563e1051a39Sopenharmony_ci        goto err;
564e1051a39Sopenharmony_ci    ret = BN_is_zero(lh);
565e1051a39Sopenharmony_ci
566e1051a39Sopenharmony_ci err:
567e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
568e1051a39Sopenharmony_ci#ifndef FIPS_MODULE
569e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
570e1051a39Sopenharmony_ci#endif
571e1051a39Sopenharmony_ci    return ret;
572e1051a39Sopenharmony_ci}
573e1051a39Sopenharmony_ci
574e1051a39Sopenharmony_ci/*-
575e1051a39Sopenharmony_ci * Indicates whether two points are equal.
576e1051a39Sopenharmony_ci * Return values:
577e1051a39Sopenharmony_ci *  -1   error
578e1051a39Sopenharmony_ci *   0   equal (in affine coordinates)
579e1051a39Sopenharmony_ci *   1   not equal
580e1051a39Sopenharmony_ci */
581e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
582e1051a39Sopenharmony_ci                            const EC_POINT *b, BN_CTX *ctx)
583e1051a39Sopenharmony_ci{
584e1051a39Sopenharmony_ci    BIGNUM *aX, *aY, *bX, *bY;
585e1051a39Sopenharmony_ci    int ret = -1;
586e1051a39Sopenharmony_ci#ifndef FIPS_MODULE
587e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
588e1051a39Sopenharmony_ci#endif
589e1051a39Sopenharmony_ci
590e1051a39Sopenharmony_ci    if (EC_POINT_is_at_infinity(group, a)) {
591e1051a39Sopenharmony_ci        return EC_POINT_is_at_infinity(group, b) ? 0 : 1;
592e1051a39Sopenharmony_ci    }
593e1051a39Sopenharmony_ci
594e1051a39Sopenharmony_ci    if (EC_POINT_is_at_infinity(group, b))
595e1051a39Sopenharmony_ci        return 1;
596e1051a39Sopenharmony_ci
597e1051a39Sopenharmony_ci    if (a->Z_is_one && b->Z_is_one) {
598e1051a39Sopenharmony_ci        return ((BN_cmp(a->X, b->X) == 0) && BN_cmp(a->Y, b->Y) == 0) ? 0 : 1;
599e1051a39Sopenharmony_ci    }
600e1051a39Sopenharmony_ci
601e1051a39Sopenharmony_ci#ifndef FIPS_MODULE
602e1051a39Sopenharmony_ci    if (ctx == NULL) {
603e1051a39Sopenharmony_ci        ctx = new_ctx = BN_CTX_new();
604e1051a39Sopenharmony_ci        if (ctx == NULL)
605e1051a39Sopenharmony_ci            return -1;
606e1051a39Sopenharmony_ci    }
607e1051a39Sopenharmony_ci#endif
608e1051a39Sopenharmony_ci
609e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
610e1051a39Sopenharmony_ci    aX = BN_CTX_get(ctx);
611e1051a39Sopenharmony_ci    aY = BN_CTX_get(ctx);
612e1051a39Sopenharmony_ci    bX = BN_CTX_get(ctx);
613e1051a39Sopenharmony_ci    bY = BN_CTX_get(ctx);
614e1051a39Sopenharmony_ci    if (bY == NULL)
615e1051a39Sopenharmony_ci        goto err;
616e1051a39Sopenharmony_ci
617e1051a39Sopenharmony_ci    if (!EC_POINT_get_affine_coordinates(group, a, aX, aY, ctx))
618e1051a39Sopenharmony_ci        goto err;
619e1051a39Sopenharmony_ci    if (!EC_POINT_get_affine_coordinates(group, b, bX, bY, ctx))
620e1051a39Sopenharmony_ci        goto err;
621e1051a39Sopenharmony_ci    ret = ((BN_cmp(aX, bX) == 0) && BN_cmp(aY, bY) == 0) ? 0 : 1;
622e1051a39Sopenharmony_ci
623e1051a39Sopenharmony_ci err:
624e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
625e1051a39Sopenharmony_ci#ifndef FIPS_MODULE
626e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
627e1051a39Sopenharmony_ci#endif
628e1051a39Sopenharmony_ci    return ret;
629e1051a39Sopenharmony_ci}
630e1051a39Sopenharmony_ci
631e1051a39Sopenharmony_ci/* Forces the given EC_POINT to internally use affine coordinates. */
632e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_make_affine(const EC_GROUP *group, EC_POINT *point,
633e1051a39Sopenharmony_ci                                    BN_CTX *ctx)
634e1051a39Sopenharmony_ci{
635e1051a39Sopenharmony_ci    BIGNUM *x, *y;
636e1051a39Sopenharmony_ci    int ret = 0;
637e1051a39Sopenharmony_ci#ifndef FIPS_MODULE
638e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
639e1051a39Sopenharmony_ci#endif
640e1051a39Sopenharmony_ci
641e1051a39Sopenharmony_ci    if (point->Z_is_one || EC_POINT_is_at_infinity(group, point))
642e1051a39Sopenharmony_ci        return 1;
643e1051a39Sopenharmony_ci
644e1051a39Sopenharmony_ci#ifndef FIPS_MODULE
645e1051a39Sopenharmony_ci    if (ctx == NULL) {
646e1051a39Sopenharmony_ci        ctx = new_ctx = BN_CTX_new();
647e1051a39Sopenharmony_ci        if (ctx == NULL)
648e1051a39Sopenharmony_ci            return 0;
649e1051a39Sopenharmony_ci    }
650e1051a39Sopenharmony_ci#endif
651e1051a39Sopenharmony_ci
652e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
653e1051a39Sopenharmony_ci    x = BN_CTX_get(ctx);
654e1051a39Sopenharmony_ci    y = BN_CTX_get(ctx);
655e1051a39Sopenharmony_ci    if (y == NULL)
656e1051a39Sopenharmony_ci        goto err;
657e1051a39Sopenharmony_ci
658e1051a39Sopenharmony_ci    if (!EC_POINT_get_affine_coordinates(group, point, x, y, ctx))
659e1051a39Sopenharmony_ci        goto err;
660e1051a39Sopenharmony_ci    if (!BN_copy(point->X, x))
661e1051a39Sopenharmony_ci        goto err;
662e1051a39Sopenharmony_ci    if (!BN_copy(point->Y, y))
663e1051a39Sopenharmony_ci        goto err;
664e1051a39Sopenharmony_ci    if (!BN_one(point->Z))
665e1051a39Sopenharmony_ci        goto err;
666e1051a39Sopenharmony_ci    point->Z_is_one = 1;
667e1051a39Sopenharmony_ci
668e1051a39Sopenharmony_ci    ret = 1;
669e1051a39Sopenharmony_ci
670e1051a39Sopenharmony_ci err:
671e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
672e1051a39Sopenharmony_ci#ifndef FIPS_MODULE
673e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
674e1051a39Sopenharmony_ci#endif
675e1051a39Sopenharmony_ci    return ret;
676e1051a39Sopenharmony_ci}
677e1051a39Sopenharmony_ci
678e1051a39Sopenharmony_ci/*
679e1051a39Sopenharmony_ci * Forces each of the EC_POINTs in the given array to use affine coordinates.
680e1051a39Sopenharmony_ci */
681e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_points_make_affine(const EC_GROUP *group, size_t num,
682e1051a39Sopenharmony_ci                                           EC_POINT *points[], BN_CTX *ctx)
683e1051a39Sopenharmony_ci{
684e1051a39Sopenharmony_ci    size_t i;
685e1051a39Sopenharmony_ci
686e1051a39Sopenharmony_ci    for (i = 0; i < num; i++) {
687e1051a39Sopenharmony_ci        if (!group->meth->make_affine(group, points[i], ctx))
688e1051a39Sopenharmony_ci            return 0;
689e1051a39Sopenharmony_ci    }
690e1051a39Sopenharmony_ci
691e1051a39Sopenharmony_ci    return 1;
692e1051a39Sopenharmony_ci}
693e1051a39Sopenharmony_ci
694e1051a39Sopenharmony_ci/* Wrapper to simple binary polynomial field multiplication implementation. */
695e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_field_mul(const EC_GROUP *group, BIGNUM *r,
696e1051a39Sopenharmony_ci                                  const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
697e1051a39Sopenharmony_ci{
698e1051a39Sopenharmony_ci    return BN_GF2m_mod_mul_arr(r, a, b, group->poly, ctx);
699e1051a39Sopenharmony_ci}
700e1051a39Sopenharmony_ci
701e1051a39Sopenharmony_ci/* Wrapper to simple binary polynomial field squaring implementation. */
702e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_field_sqr(const EC_GROUP *group, BIGNUM *r,
703e1051a39Sopenharmony_ci                                  const BIGNUM *a, BN_CTX *ctx)
704e1051a39Sopenharmony_ci{
705e1051a39Sopenharmony_ci    return BN_GF2m_mod_sqr_arr(r, a, group->poly, ctx);
706e1051a39Sopenharmony_ci}
707e1051a39Sopenharmony_ci
708e1051a39Sopenharmony_ci/* Wrapper to simple binary polynomial field division implementation. */
709e1051a39Sopenharmony_ciint ossl_ec_GF2m_simple_field_div(const EC_GROUP *group, BIGNUM *r,
710e1051a39Sopenharmony_ci                                  const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
711e1051a39Sopenharmony_ci{
712e1051a39Sopenharmony_ci    return BN_GF2m_mod_div(r, a, b, group->field, ctx);
713e1051a39Sopenharmony_ci}
714e1051a39Sopenharmony_ci
715e1051a39Sopenharmony_ci/*-
716e1051a39Sopenharmony_ci * Lopez-Dahab ladder, pre step.
717e1051a39Sopenharmony_ci * See e.g. "Guide to ECC" Alg 3.40.
718e1051a39Sopenharmony_ci * Modified to blind s and r independently.
719e1051a39Sopenharmony_ci * s:= p, r := 2p
720e1051a39Sopenharmony_ci */
721e1051a39Sopenharmony_cistatic
722e1051a39Sopenharmony_ciint ec_GF2m_simple_ladder_pre(const EC_GROUP *group,
723e1051a39Sopenharmony_ci                              EC_POINT *r, EC_POINT *s,
724e1051a39Sopenharmony_ci                              EC_POINT *p, BN_CTX *ctx)
725e1051a39Sopenharmony_ci{
726e1051a39Sopenharmony_ci    /* if p is not affine, something is wrong */
727e1051a39Sopenharmony_ci    if (p->Z_is_one == 0)
728e1051a39Sopenharmony_ci        return 0;
729e1051a39Sopenharmony_ci
730e1051a39Sopenharmony_ci    /* s blinding: make sure lambda (s->Z here) is not zero */
731e1051a39Sopenharmony_ci    do {
732e1051a39Sopenharmony_ci        if (!BN_priv_rand_ex(s->Z, BN_num_bits(group->field) - 1,
733e1051a39Sopenharmony_ci                             BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY, 0, ctx)) {
734e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB);
735e1051a39Sopenharmony_ci            return 0;
736e1051a39Sopenharmony_ci        }
737e1051a39Sopenharmony_ci    } while (BN_is_zero(s->Z));
738e1051a39Sopenharmony_ci
739e1051a39Sopenharmony_ci    /* if field_encode defined convert between representations */
740e1051a39Sopenharmony_ci    if ((group->meth->field_encode != NULL
741e1051a39Sopenharmony_ci         && !group->meth->field_encode(group, s->Z, s->Z, ctx))
742e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, s->X, p->X, s->Z, ctx))
743e1051a39Sopenharmony_ci        return 0;
744e1051a39Sopenharmony_ci
745e1051a39Sopenharmony_ci    /* r blinding: make sure lambda (r->Y here for storage) is not zero */
746e1051a39Sopenharmony_ci    do {
747e1051a39Sopenharmony_ci        if (!BN_priv_rand_ex(r->Y, BN_num_bits(group->field) - 1,
748e1051a39Sopenharmony_ci                             BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY, 0, ctx)) {
749e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB);
750e1051a39Sopenharmony_ci            return 0;
751e1051a39Sopenharmony_ci        }
752e1051a39Sopenharmony_ci    } while (BN_is_zero(r->Y));
753e1051a39Sopenharmony_ci
754e1051a39Sopenharmony_ci    if ((group->meth->field_encode != NULL
755e1051a39Sopenharmony_ci         && !group->meth->field_encode(group, r->Y, r->Y, ctx))
756e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, r->Z, p->X, ctx)
757e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, r->X, r->Z, ctx)
758e1051a39Sopenharmony_ci        || !BN_GF2m_add(r->X, r->X, group->b)
759e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, r->Z, r->Z, r->Y, ctx)
760e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, r->X, r->X, r->Y, ctx))
761e1051a39Sopenharmony_ci        return 0;
762e1051a39Sopenharmony_ci
763e1051a39Sopenharmony_ci    s->Z_is_one = 0;
764e1051a39Sopenharmony_ci    r->Z_is_one = 0;
765e1051a39Sopenharmony_ci
766e1051a39Sopenharmony_ci    return 1;
767e1051a39Sopenharmony_ci}
768e1051a39Sopenharmony_ci
769e1051a39Sopenharmony_ci/*-
770e1051a39Sopenharmony_ci * Ladder step: differential addition-and-doubling, mixed Lopez-Dahab coords.
771e1051a39Sopenharmony_ci * http://www.hyperelliptic.org/EFD/g12o/auto-code/shortw/xz/ladder/mladd-2003-s.op3
772e1051a39Sopenharmony_ci * s := r + s, r := 2r
773e1051a39Sopenharmony_ci */
774e1051a39Sopenharmony_cistatic
775e1051a39Sopenharmony_ciint ec_GF2m_simple_ladder_step(const EC_GROUP *group,
776e1051a39Sopenharmony_ci                               EC_POINT *r, EC_POINT *s,
777e1051a39Sopenharmony_ci                               EC_POINT *p, BN_CTX *ctx)
778e1051a39Sopenharmony_ci{
779e1051a39Sopenharmony_ci    if (!group->meth->field_mul(group, r->Y, r->Z, s->X, ctx)
780e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, s->X, r->X, s->Z, ctx)
781e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, s->Y, r->Z, ctx)
782e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, r->Z, r->X, ctx)
783e1051a39Sopenharmony_ci        || !BN_GF2m_add(s->Z, r->Y, s->X)
784e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, s->Z, s->Z, ctx)
785e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, s->X, r->Y, s->X, ctx)
786e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, r->Y, s->Z, p->X, ctx)
787e1051a39Sopenharmony_ci        || !BN_GF2m_add(s->X, s->X, r->Y)
788e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, r->Y, r->Z, ctx)
789e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, r->Z, r->Z, s->Y, ctx)
790e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, s->Y, s->Y, ctx)
791e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, s->Y, s->Y, group->b, ctx)
792e1051a39Sopenharmony_ci        || !BN_GF2m_add(r->X, r->Y, s->Y))
793e1051a39Sopenharmony_ci        return 0;
794e1051a39Sopenharmony_ci
795e1051a39Sopenharmony_ci    return 1;
796e1051a39Sopenharmony_ci}
797e1051a39Sopenharmony_ci
798e1051a39Sopenharmony_ci/*-
799e1051a39Sopenharmony_ci * Recover affine (x,y) result from Lopez-Dahab r and s, affine p.
800e1051a39Sopenharmony_ci * See e.g. "Fast Multiplication on Elliptic Curves over GF(2**m)
801e1051a39Sopenharmony_ci * without Precomputation" (Lopez and Dahab, CHES 1999),
802e1051a39Sopenharmony_ci * Appendix Alg Mxy.
803e1051a39Sopenharmony_ci */
804e1051a39Sopenharmony_cistatic
805e1051a39Sopenharmony_ciint ec_GF2m_simple_ladder_post(const EC_GROUP *group,
806e1051a39Sopenharmony_ci                               EC_POINT *r, EC_POINT *s,
807e1051a39Sopenharmony_ci                               EC_POINT *p, BN_CTX *ctx)
808e1051a39Sopenharmony_ci{
809e1051a39Sopenharmony_ci    int ret = 0;
810e1051a39Sopenharmony_ci    BIGNUM *t0, *t1, *t2 = NULL;
811e1051a39Sopenharmony_ci
812e1051a39Sopenharmony_ci    if (BN_is_zero(r->Z))
813e1051a39Sopenharmony_ci        return EC_POINT_set_to_infinity(group, r);
814e1051a39Sopenharmony_ci
815e1051a39Sopenharmony_ci    if (BN_is_zero(s->Z)) {
816e1051a39Sopenharmony_ci        if (!EC_POINT_copy(r, p)
817e1051a39Sopenharmony_ci            || !EC_POINT_invert(group, r, ctx)) {
818e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_EC, ERR_R_EC_LIB);
819e1051a39Sopenharmony_ci            return 0;
820e1051a39Sopenharmony_ci        }
821e1051a39Sopenharmony_ci        return 1;
822e1051a39Sopenharmony_ci    }
823e1051a39Sopenharmony_ci
824e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
825e1051a39Sopenharmony_ci    t0 = BN_CTX_get(ctx);
826e1051a39Sopenharmony_ci    t1 = BN_CTX_get(ctx);
827e1051a39Sopenharmony_ci    t2 = BN_CTX_get(ctx);
828e1051a39Sopenharmony_ci    if (t2 == NULL) {
829e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE);
830e1051a39Sopenharmony_ci        goto err;
831e1051a39Sopenharmony_ci    }
832e1051a39Sopenharmony_ci
833e1051a39Sopenharmony_ci    if (!group->meth->field_mul(group, t0, r->Z, s->Z, ctx)
834e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t1, p->X, r->Z, ctx)
835e1051a39Sopenharmony_ci        || !BN_GF2m_add(t1, r->X, t1)
836e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t2, p->X, s->Z, ctx)
837e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, r->Z, r->X, t2, ctx)
838e1051a39Sopenharmony_ci        || !BN_GF2m_add(t2, t2, s->X)
839e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t1, t1, t2, ctx)
840e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, t2, p->X, ctx)
841e1051a39Sopenharmony_ci        || !BN_GF2m_add(t2, p->Y, t2)
842e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t2, t2, t0, ctx)
843e1051a39Sopenharmony_ci        || !BN_GF2m_add(t1, t2, t1)
844e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t2, p->X, t0, ctx)
845e1051a39Sopenharmony_ci        || !group->meth->field_inv(group, t2, t2, ctx)
846e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t1, t1, t2, ctx)
847e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, r->X, r->Z, t2, ctx)
848e1051a39Sopenharmony_ci        || !BN_GF2m_add(t2, p->X, r->X)
849e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t2, t2, t1, ctx)
850e1051a39Sopenharmony_ci        || !BN_GF2m_add(r->Y, p->Y, t2)
851e1051a39Sopenharmony_ci        || !BN_one(r->Z))
852e1051a39Sopenharmony_ci        goto err;
853e1051a39Sopenharmony_ci
854e1051a39Sopenharmony_ci    r->Z_is_one = 1;
855e1051a39Sopenharmony_ci
856e1051a39Sopenharmony_ci    /* GF(2^m) field elements should always have BIGNUM::neg = 0 */
857e1051a39Sopenharmony_ci    BN_set_negative(r->X, 0);
858e1051a39Sopenharmony_ci    BN_set_negative(r->Y, 0);
859e1051a39Sopenharmony_ci
860e1051a39Sopenharmony_ci    ret = 1;
861e1051a39Sopenharmony_ci
862e1051a39Sopenharmony_ci err:
863e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
864e1051a39Sopenharmony_ci    return ret;
865e1051a39Sopenharmony_ci}
866e1051a39Sopenharmony_ci
867e1051a39Sopenharmony_cistatic
868e1051a39Sopenharmony_ciint ec_GF2m_simple_points_mul(const EC_GROUP *group, EC_POINT *r,
869e1051a39Sopenharmony_ci                              const BIGNUM *scalar, size_t num,
870e1051a39Sopenharmony_ci                              const EC_POINT *points[],
871e1051a39Sopenharmony_ci                              const BIGNUM *scalars[],
872e1051a39Sopenharmony_ci                              BN_CTX *ctx)
873e1051a39Sopenharmony_ci{
874e1051a39Sopenharmony_ci    int ret = 0;
875e1051a39Sopenharmony_ci    EC_POINT *t = NULL;
876e1051a39Sopenharmony_ci
877e1051a39Sopenharmony_ci    /*-
878e1051a39Sopenharmony_ci     * We limit use of the ladder only to the following cases:
879e1051a39Sopenharmony_ci     * - r := scalar * G
880e1051a39Sopenharmony_ci     *   Fixed point mul: scalar != NULL && num == 0;
881e1051a39Sopenharmony_ci     * - r := scalars[0] * points[0]
882e1051a39Sopenharmony_ci     *   Variable point mul: scalar == NULL && num == 1;
883e1051a39Sopenharmony_ci     * - r := scalar * G + scalars[0] * points[0]
884e1051a39Sopenharmony_ci     *   used, e.g., in ECDSA verification: scalar != NULL && num == 1
885e1051a39Sopenharmony_ci     *
886e1051a39Sopenharmony_ci     * In any other case (num > 1) we use the default wNAF implementation.
887e1051a39Sopenharmony_ci     *
888e1051a39Sopenharmony_ci     * We also let the default implementation handle degenerate cases like group
889e1051a39Sopenharmony_ci     * order or cofactor set to 0.
890e1051a39Sopenharmony_ci     */
891e1051a39Sopenharmony_ci    if (num > 1 || BN_is_zero(group->order) || BN_is_zero(group->cofactor))
892e1051a39Sopenharmony_ci        return ossl_ec_wNAF_mul(group, r, scalar, num, points, scalars, ctx);
893e1051a39Sopenharmony_ci
894e1051a39Sopenharmony_ci    if (scalar != NULL && num == 0)
895e1051a39Sopenharmony_ci        /* Fixed point multiplication */
896e1051a39Sopenharmony_ci        return ossl_ec_scalar_mul_ladder(group, r, scalar, NULL, ctx);
897e1051a39Sopenharmony_ci
898e1051a39Sopenharmony_ci    if (scalar == NULL && num == 1)
899e1051a39Sopenharmony_ci        /* Variable point multiplication */
900e1051a39Sopenharmony_ci        return ossl_ec_scalar_mul_ladder(group, r, scalars[0], points[0], ctx);
901e1051a39Sopenharmony_ci
902e1051a39Sopenharmony_ci    /*-
903e1051a39Sopenharmony_ci     * Double point multiplication:
904e1051a39Sopenharmony_ci     *  r := scalar * G + scalars[0] * points[0]
905e1051a39Sopenharmony_ci     */
906e1051a39Sopenharmony_ci
907e1051a39Sopenharmony_ci    if ((t = EC_POINT_new(group)) == NULL) {
908e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE);
909e1051a39Sopenharmony_ci        return 0;
910e1051a39Sopenharmony_ci    }
911e1051a39Sopenharmony_ci
912e1051a39Sopenharmony_ci    if (!ossl_ec_scalar_mul_ladder(group, t, scalar, NULL, ctx)
913e1051a39Sopenharmony_ci        || !ossl_ec_scalar_mul_ladder(group, r, scalars[0], points[0], ctx)
914e1051a39Sopenharmony_ci        || !EC_POINT_add(group, r, t, r, ctx))
915e1051a39Sopenharmony_ci        goto err;
916e1051a39Sopenharmony_ci
917e1051a39Sopenharmony_ci    ret = 1;
918e1051a39Sopenharmony_ci
919e1051a39Sopenharmony_ci err:
920e1051a39Sopenharmony_ci    EC_POINT_free(t);
921e1051a39Sopenharmony_ci    return ret;
922e1051a39Sopenharmony_ci}
923e1051a39Sopenharmony_ci
924e1051a39Sopenharmony_ci/*-
925e1051a39Sopenharmony_ci * Computes the multiplicative inverse of a in GF(2^m), storing the result in r.
926e1051a39Sopenharmony_ci * If a is zero (or equivalent), you'll get a EC_R_CANNOT_INVERT error.
927e1051a39Sopenharmony_ci * SCA hardening is with blinding: BN_GF2m_mod_inv does that.
928e1051a39Sopenharmony_ci */
929e1051a39Sopenharmony_cistatic int ec_GF2m_simple_field_inv(const EC_GROUP *group, BIGNUM *r,
930e1051a39Sopenharmony_ci                                    const BIGNUM *a, BN_CTX *ctx)
931e1051a39Sopenharmony_ci{
932e1051a39Sopenharmony_ci    int ret;
933e1051a39Sopenharmony_ci
934e1051a39Sopenharmony_ci    if (!(ret = BN_GF2m_mod_inv(r, a, group->field, ctx)))
935e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, EC_R_CANNOT_INVERT);
936e1051a39Sopenharmony_ci    return ret;
937e1051a39Sopenharmony_ci}
938e1051a39Sopenharmony_ci
939e1051a39Sopenharmony_ciconst EC_METHOD *EC_GF2m_simple_method(void)
940e1051a39Sopenharmony_ci{
941e1051a39Sopenharmony_ci    static const EC_METHOD ret = {
942e1051a39Sopenharmony_ci        EC_FLAGS_DEFAULT_OCT,
943e1051a39Sopenharmony_ci        NID_X9_62_characteristic_two_field,
944e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_group_init,
945e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_group_finish,
946e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_group_clear_finish,
947e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_group_copy,
948e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_group_set_curve,
949e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_group_get_curve,
950e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_group_get_degree,
951e1051a39Sopenharmony_ci        ossl_ec_group_simple_order_bits,
952e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_group_check_discriminant,
953e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_point_init,
954e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_point_finish,
955e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_point_clear_finish,
956e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_point_copy,
957e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_point_set_to_infinity,
958e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_point_set_affine_coordinates,
959e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_point_get_affine_coordinates,
960e1051a39Sopenharmony_ci        0, /* point_set_compressed_coordinates */
961e1051a39Sopenharmony_ci        0, /* point2oct */
962e1051a39Sopenharmony_ci        0, /* oct2point */
963e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_add,
964e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_dbl,
965e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_invert,
966e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_is_at_infinity,
967e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_is_on_curve,
968e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_cmp,
969e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_make_affine,
970e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_points_make_affine,
971e1051a39Sopenharmony_ci        ec_GF2m_simple_points_mul,
972e1051a39Sopenharmony_ci        0, /* precompute_mult */
973e1051a39Sopenharmony_ci        0, /* have_precompute_mult */
974e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_field_mul,
975e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_field_sqr,
976e1051a39Sopenharmony_ci        ossl_ec_GF2m_simple_field_div,
977e1051a39Sopenharmony_ci        ec_GF2m_simple_field_inv,
978e1051a39Sopenharmony_ci        0, /* field_encode */
979e1051a39Sopenharmony_ci        0, /* field_decode */
980e1051a39Sopenharmony_ci        0, /* field_set_to_one */
981e1051a39Sopenharmony_ci        ossl_ec_key_simple_priv2oct,
982e1051a39Sopenharmony_ci        ossl_ec_key_simple_oct2priv,
983e1051a39Sopenharmony_ci        0, /* set private */
984e1051a39Sopenharmony_ci        ossl_ec_key_simple_generate_key,
985e1051a39Sopenharmony_ci        ossl_ec_key_simple_check_key,
986e1051a39Sopenharmony_ci        ossl_ec_key_simple_generate_public_key,
987e1051a39Sopenharmony_ci        0, /* keycopy */
988e1051a39Sopenharmony_ci        0, /* keyfinish */
989e1051a39Sopenharmony_ci        ossl_ecdh_simple_compute_key,
990e1051a39Sopenharmony_ci        ossl_ecdsa_simple_sign_setup,
991e1051a39Sopenharmony_ci        ossl_ecdsa_simple_sign_sig,
992e1051a39Sopenharmony_ci        ossl_ecdsa_simple_verify_sig,
993e1051a39Sopenharmony_ci        0, /* field_inverse_mod_ord */
994e1051a39Sopenharmony_ci        0, /* blind_coordinates */
995e1051a39Sopenharmony_ci        ec_GF2m_simple_ladder_pre,
996e1051a39Sopenharmony_ci        ec_GF2m_simple_ladder_step,
997e1051a39Sopenharmony_ci        ec_GF2m_simple_ladder_post
998e1051a39Sopenharmony_ci    };
999e1051a39Sopenharmony_ci
1000e1051a39Sopenharmony_ci    return &ret;
1001e1051a39Sopenharmony_ci}
1002e1051a39Sopenharmony_ci
1003e1051a39Sopenharmony_ci#endif
1004