xref: /third_party/openssl/crypto/ec/ecp_smpl.c (revision e1051a39)
1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2001-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#include <openssl/symhacks.h>
19e1051a39Sopenharmony_ci
20e1051a39Sopenharmony_ci#include "ec_local.h"
21e1051a39Sopenharmony_ci
22e1051a39Sopenharmony_ciconst EC_METHOD *EC_GFp_simple_method(void)
23e1051a39Sopenharmony_ci{
24e1051a39Sopenharmony_ci    static const EC_METHOD ret = {
25e1051a39Sopenharmony_ci        EC_FLAGS_DEFAULT_OCT,
26e1051a39Sopenharmony_ci        NID_X9_62_prime_field,
27e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_group_init,
28e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_group_finish,
29e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_group_clear_finish,
30e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_group_copy,
31e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_group_set_curve,
32e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_group_get_curve,
33e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_group_get_degree,
34e1051a39Sopenharmony_ci        ossl_ec_group_simple_order_bits,
35e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_group_check_discriminant,
36e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_point_init,
37e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_point_finish,
38e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_point_clear_finish,
39e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_point_copy,
40e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_point_set_to_infinity,
41e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_point_set_affine_coordinates,
42e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_point_get_affine_coordinates,
43e1051a39Sopenharmony_ci        0, 0, 0,
44e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_add,
45e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_dbl,
46e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_invert,
47e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_is_at_infinity,
48e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_is_on_curve,
49e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_cmp,
50e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_make_affine,
51e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_points_make_affine,
52e1051a39Sopenharmony_ci        0 /* mul */ ,
53e1051a39Sopenharmony_ci        0 /* precompute_mult */ ,
54e1051a39Sopenharmony_ci        0 /* have_precompute_mult */ ,
55e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_field_mul,
56e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_field_sqr,
57e1051a39Sopenharmony_ci        0 /* field_div */ ,
58e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_field_inv,
59e1051a39Sopenharmony_ci        0 /* field_encode */ ,
60e1051a39Sopenharmony_ci        0 /* field_decode */ ,
61e1051a39Sopenharmony_ci        0,                      /* field_set_to_one */
62e1051a39Sopenharmony_ci        ossl_ec_key_simple_priv2oct,
63e1051a39Sopenharmony_ci        ossl_ec_key_simple_oct2priv,
64e1051a39Sopenharmony_ci        0, /* set private */
65e1051a39Sopenharmony_ci        ossl_ec_key_simple_generate_key,
66e1051a39Sopenharmony_ci        ossl_ec_key_simple_check_key,
67e1051a39Sopenharmony_ci        ossl_ec_key_simple_generate_public_key,
68e1051a39Sopenharmony_ci        0, /* keycopy */
69e1051a39Sopenharmony_ci        0, /* keyfinish */
70e1051a39Sopenharmony_ci        ossl_ecdh_simple_compute_key,
71e1051a39Sopenharmony_ci        ossl_ecdsa_simple_sign_setup,
72e1051a39Sopenharmony_ci        ossl_ecdsa_simple_sign_sig,
73e1051a39Sopenharmony_ci        ossl_ecdsa_simple_verify_sig,
74e1051a39Sopenharmony_ci        0, /* field_inverse_mod_ord */
75e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_blind_coordinates,
76e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_ladder_pre,
77e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_ladder_step,
78e1051a39Sopenharmony_ci        ossl_ec_GFp_simple_ladder_post
79e1051a39Sopenharmony_ci    };
80e1051a39Sopenharmony_ci
81e1051a39Sopenharmony_ci    return &ret;
82e1051a39Sopenharmony_ci}
83e1051a39Sopenharmony_ci
84e1051a39Sopenharmony_ci/*
85e1051a39Sopenharmony_ci * Most method functions in this file are designed to work with
86e1051a39Sopenharmony_ci * non-trivial representations of field elements if necessary
87e1051a39Sopenharmony_ci * (see ecp_mont.c): while standard modular addition and subtraction
88e1051a39Sopenharmony_ci * are used, the field_mul and field_sqr methods will be used for
89e1051a39Sopenharmony_ci * multiplication, and field_encode and field_decode (if defined)
90e1051a39Sopenharmony_ci * will be used for converting between representations.
91e1051a39Sopenharmony_ci *
92e1051a39Sopenharmony_ci * Functions ec_GFp_simple_points_make_affine() and
93e1051a39Sopenharmony_ci * ec_GFp_simple_point_get_affine_coordinates() specifically assume
94e1051a39Sopenharmony_ci * that if a non-trivial representation is used, it is a Montgomery
95e1051a39Sopenharmony_ci * representation (i.e. 'encoding' means multiplying by some factor R).
96e1051a39Sopenharmony_ci */
97e1051a39Sopenharmony_ci
98e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_group_init(EC_GROUP *group)
99e1051a39Sopenharmony_ci{
100e1051a39Sopenharmony_ci    group->field = BN_new();
101e1051a39Sopenharmony_ci    group->a = BN_new();
102e1051a39Sopenharmony_ci    group->b = BN_new();
103e1051a39Sopenharmony_ci    if (group->field == NULL || group->a == NULL || group->b == NULL) {
104e1051a39Sopenharmony_ci        BN_free(group->field);
105e1051a39Sopenharmony_ci        BN_free(group->a);
106e1051a39Sopenharmony_ci        BN_free(group->b);
107e1051a39Sopenharmony_ci        return 0;
108e1051a39Sopenharmony_ci    }
109e1051a39Sopenharmony_ci    group->a_is_minus3 = 0;
110e1051a39Sopenharmony_ci    return 1;
111e1051a39Sopenharmony_ci}
112e1051a39Sopenharmony_ci
113e1051a39Sopenharmony_civoid ossl_ec_GFp_simple_group_finish(EC_GROUP *group)
114e1051a39Sopenharmony_ci{
115e1051a39Sopenharmony_ci    BN_free(group->field);
116e1051a39Sopenharmony_ci    BN_free(group->a);
117e1051a39Sopenharmony_ci    BN_free(group->b);
118e1051a39Sopenharmony_ci}
119e1051a39Sopenharmony_ci
120e1051a39Sopenharmony_civoid ossl_ec_GFp_simple_group_clear_finish(EC_GROUP *group)
121e1051a39Sopenharmony_ci{
122e1051a39Sopenharmony_ci    BN_clear_free(group->field);
123e1051a39Sopenharmony_ci    BN_clear_free(group->a);
124e1051a39Sopenharmony_ci    BN_clear_free(group->b);
125e1051a39Sopenharmony_ci}
126e1051a39Sopenharmony_ci
127e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src)
128e1051a39Sopenharmony_ci{
129e1051a39Sopenharmony_ci    if (!BN_copy(dest->field, src->field))
130e1051a39Sopenharmony_ci        return 0;
131e1051a39Sopenharmony_ci    if (!BN_copy(dest->a, src->a))
132e1051a39Sopenharmony_ci        return 0;
133e1051a39Sopenharmony_ci    if (!BN_copy(dest->b, src->b))
134e1051a39Sopenharmony_ci        return 0;
135e1051a39Sopenharmony_ci
136e1051a39Sopenharmony_ci    dest->a_is_minus3 = src->a_is_minus3;
137e1051a39Sopenharmony_ci
138e1051a39Sopenharmony_ci    return 1;
139e1051a39Sopenharmony_ci}
140e1051a39Sopenharmony_ci
141e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_group_set_curve(EC_GROUP *group,
142e1051a39Sopenharmony_ci                                       const BIGNUM *p, const BIGNUM *a,
143e1051a39Sopenharmony_ci                                       const BIGNUM *b, BN_CTX *ctx)
144e1051a39Sopenharmony_ci{
145e1051a39Sopenharmony_ci    int ret = 0;
146e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
147e1051a39Sopenharmony_ci    BIGNUM *tmp_a;
148e1051a39Sopenharmony_ci
149e1051a39Sopenharmony_ci    /* p must be a prime > 3 */
150e1051a39Sopenharmony_ci    if (BN_num_bits(p) <= 2 || !BN_is_odd(p)) {
151e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, EC_R_INVALID_FIELD);
152e1051a39Sopenharmony_ci        return 0;
153e1051a39Sopenharmony_ci    }
154e1051a39Sopenharmony_ci
155e1051a39Sopenharmony_ci    if (ctx == NULL) {
156e1051a39Sopenharmony_ci        ctx = new_ctx = BN_CTX_new_ex(group->libctx);
157e1051a39Sopenharmony_ci        if (ctx == NULL)
158e1051a39Sopenharmony_ci            return 0;
159e1051a39Sopenharmony_ci    }
160e1051a39Sopenharmony_ci
161e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
162e1051a39Sopenharmony_ci    tmp_a = BN_CTX_get(ctx);
163e1051a39Sopenharmony_ci    if (tmp_a == NULL)
164e1051a39Sopenharmony_ci        goto err;
165e1051a39Sopenharmony_ci
166e1051a39Sopenharmony_ci    /* group->field */
167e1051a39Sopenharmony_ci    if (!BN_copy(group->field, p))
168e1051a39Sopenharmony_ci        goto err;
169e1051a39Sopenharmony_ci    BN_set_negative(group->field, 0);
170e1051a39Sopenharmony_ci
171e1051a39Sopenharmony_ci    /* group->a */
172e1051a39Sopenharmony_ci    if (!BN_nnmod(tmp_a, a, p, ctx))
173e1051a39Sopenharmony_ci        goto err;
174e1051a39Sopenharmony_ci    if (group->meth->field_encode) {
175e1051a39Sopenharmony_ci        if (!group->meth->field_encode(group, group->a, tmp_a, ctx))
176e1051a39Sopenharmony_ci            goto err;
177e1051a39Sopenharmony_ci    } else if (!BN_copy(group->a, tmp_a))
178e1051a39Sopenharmony_ci        goto err;
179e1051a39Sopenharmony_ci
180e1051a39Sopenharmony_ci    /* group->b */
181e1051a39Sopenharmony_ci    if (!BN_nnmod(group->b, b, p, ctx))
182e1051a39Sopenharmony_ci        goto err;
183e1051a39Sopenharmony_ci    if (group->meth->field_encode)
184e1051a39Sopenharmony_ci        if (!group->meth->field_encode(group, group->b, group->b, ctx))
185e1051a39Sopenharmony_ci            goto err;
186e1051a39Sopenharmony_ci
187e1051a39Sopenharmony_ci    /* group->a_is_minus3 */
188e1051a39Sopenharmony_ci    if (!BN_add_word(tmp_a, 3))
189e1051a39Sopenharmony_ci        goto err;
190e1051a39Sopenharmony_ci    group->a_is_minus3 = (0 == BN_cmp(tmp_a, group->field));
191e1051a39Sopenharmony_ci
192e1051a39Sopenharmony_ci    ret = 1;
193e1051a39Sopenharmony_ci
194e1051a39Sopenharmony_ci err:
195e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
196e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
197e1051a39Sopenharmony_ci    return ret;
198e1051a39Sopenharmony_ci}
199e1051a39Sopenharmony_ci
200e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p,
201e1051a39Sopenharmony_ci                                       BIGNUM *a, BIGNUM *b, BN_CTX *ctx)
202e1051a39Sopenharmony_ci{
203e1051a39Sopenharmony_ci    int ret = 0;
204e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
205e1051a39Sopenharmony_ci
206e1051a39Sopenharmony_ci    if (p != NULL) {
207e1051a39Sopenharmony_ci        if (!BN_copy(p, group->field))
208e1051a39Sopenharmony_ci            return 0;
209e1051a39Sopenharmony_ci    }
210e1051a39Sopenharmony_ci
211e1051a39Sopenharmony_ci    if (a != NULL || b != NULL) {
212e1051a39Sopenharmony_ci        if (group->meth->field_decode) {
213e1051a39Sopenharmony_ci            if (ctx == NULL) {
214e1051a39Sopenharmony_ci                ctx = new_ctx = BN_CTX_new_ex(group->libctx);
215e1051a39Sopenharmony_ci                if (ctx == NULL)
216e1051a39Sopenharmony_ci                    return 0;
217e1051a39Sopenharmony_ci            }
218e1051a39Sopenharmony_ci            if (a != NULL) {
219e1051a39Sopenharmony_ci                if (!group->meth->field_decode(group, a, group->a, ctx))
220e1051a39Sopenharmony_ci                    goto err;
221e1051a39Sopenharmony_ci            }
222e1051a39Sopenharmony_ci            if (b != NULL) {
223e1051a39Sopenharmony_ci                if (!group->meth->field_decode(group, b, group->b, ctx))
224e1051a39Sopenharmony_ci                    goto err;
225e1051a39Sopenharmony_ci            }
226e1051a39Sopenharmony_ci        } else {
227e1051a39Sopenharmony_ci            if (a != NULL) {
228e1051a39Sopenharmony_ci                if (!BN_copy(a, group->a))
229e1051a39Sopenharmony_ci                    goto err;
230e1051a39Sopenharmony_ci            }
231e1051a39Sopenharmony_ci            if (b != NULL) {
232e1051a39Sopenharmony_ci                if (!BN_copy(b, group->b))
233e1051a39Sopenharmony_ci                    goto err;
234e1051a39Sopenharmony_ci            }
235e1051a39Sopenharmony_ci        }
236e1051a39Sopenharmony_ci    }
237e1051a39Sopenharmony_ci
238e1051a39Sopenharmony_ci    ret = 1;
239e1051a39Sopenharmony_ci
240e1051a39Sopenharmony_ci err:
241e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
242e1051a39Sopenharmony_ci    return ret;
243e1051a39Sopenharmony_ci}
244e1051a39Sopenharmony_ci
245e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_group_get_degree(const EC_GROUP *group)
246e1051a39Sopenharmony_ci{
247e1051a39Sopenharmony_ci    return BN_num_bits(group->field);
248e1051a39Sopenharmony_ci}
249e1051a39Sopenharmony_ci
250e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_group_check_discriminant(const EC_GROUP *group,
251e1051a39Sopenharmony_ci                                                BN_CTX *ctx)
252e1051a39Sopenharmony_ci{
253e1051a39Sopenharmony_ci    int ret = 0;
254e1051a39Sopenharmony_ci    BIGNUM *a, *b, *order, *tmp_1, *tmp_2;
255e1051a39Sopenharmony_ci    const BIGNUM *p = group->field;
256e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
257e1051a39Sopenharmony_ci
258e1051a39Sopenharmony_ci    if (ctx == NULL) {
259e1051a39Sopenharmony_ci        ctx = new_ctx = BN_CTX_new_ex(group->libctx);
260e1051a39Sopenharmony_ci        if (ctx == NULL) {
261e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE);
262e1051a39Sopenharmony_ci            goto err;
263e1051a39Sopenharmony_ci        }
264e1051a39Sopenharmony_ci    }
265e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
266e1051a39Sopenharmony_ci    a = BN_CTX_get(ctx);
267e1051a39Sopenharmony_ci    b = BN_CTX_get(ctx);
268e1051a39Sopenharmony_ci    tmp_1 = BN_CTX_get(ctx);
269e1051a39Sopenharmony_ci    tmp_2 = BN_CTX_get(ctx);
270e1051a39Sopenharmony_ci    order = BN_CTX_get(ctx);
271e1051a39Sopenharmony_ci    if (order == NULL)
272e1051a39Sopenharmony_ci        goto err;
273e1051a39Sopenharmony_ci
274e1051a39Sopenharmony_ci    if (group->meth->field_decode) {
275e1051a39Sopenharmony_ci        if (!group->meth->field_decode(group, a, group->a, ctx))
276e1051a39Sopenharmony_ci            goto err;
277e1051a39Sopenharmony_ci        if (!group->meth->field_decode(group, b, group->b, ctx))
278e1051a39Sopenharmony_ci            goto err;
279e1051a39Sopenharmony_ci    } else {
280e1051a39Sopenharmony_ci        if (!BN_copy(a, group->a))
281e1051a39Sopenharmony_ci            goto err;
282e1051a39Sopenharmony_ci        if (!BN_copy(b, group->b))
283e1051a39Sopenharmony_ci            goto err;
284e1051a39Sopenharmony_ci    }
285e1051a39Sopenharmony_ci
286e1051a39Sopenharmony_ci    /*-
287e1051a39Sopenharmony_ci     * check the discriminant:
288e1051a39Sopenharmony_ci     * y^2 = x^3 + a*x + b is an elliptic curve <=> 4*a^3 + 27*b^2 != 0 (mod p)
289e1051a39Sopenharmony_ci     * 0 =< a, b < p
290e1051a39Sopenharmony_ci     */
291e1051a39Sopenharmony_ci    if (BN_is_zero(a)) {
292e1051a39Sopenharmony_ci        if (BN_is_zero(b))
293e1051a39Sopenharmony_ci            goto err;
294e1051a39Sopenharmony_ci    } else if (!BN_is_zero(b)) {
295e1051a39Sopenharmony_ci        if (!BN_mod_sqr(tmp_1, a, p, ctx))
296e1051a39Sopenharmony_ci            goto err;
297e1051a39Sopenharmony_ci        if (!BN_mod_mul(tmp_2, tmp_1, a, p, ctx))
298e1051a39Sopenharmony_ci            goto err;
299e1051a39Sopenharmony_ci        if (!BN_lshift(tmp_1, tmp_2, 2))
300e1051a39Sopenharmony_ci            goto err;
301e1051a39Sopenharmony_ci        /* tmp_1 = 4*a^3 */
302e1051a39Sopenharmony_ci
303e1051a39Sopenharmony_ci        if (!BN_mod_sqr(tmp_2, b, p, ctx))
304e1051a39Sopenharmony_ci            goto err;
305e1051a39Sopenharmony_ci        if (!BN_mul_word(tmp_2, 27))
306e1051a39Sopenharmony_ci            goto err;
307e1051a39Sopenharmony_ci        /* tmp_2 = 27*b^2 */
308e1051a39Sopenharmony_ci
309e1051a39Sopenharmony_ci        if (!BN_mod_add(a, tmp_1, tmp_2, p, ctx))
310e1051a39Sopenharmony_ci            goto err;
311e1051a39Sopenharmony_ci        if (BN_is_zero(a))
312e1051a39Sopenharmony_ci            goto err;
313e1051a39Sopenharmony_ci    }
314e1051a39Sopenharmony_ci    ret = 1;
315e1051a39Sopenharmony_ci
316e1051a39Sopenharmony_ci err:
317e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
318e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
319e1051a39Sopenharmony_ci    return ret;
320e1051a39Sopenharmony_ci}
321e1051a39Sopenharmony_ci
322e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_point_init(EC_POINT *point)
323e1051a39Sopenharmony_ci{
324e1051a39Sopenharmony_ci    point->X = BN_new();
325e1051a39Sopenharmony_ci    point->Y = BN_new();
326e1051a39Sopenharmony_ci    point->Z = BN_new();
327e1051a39Sopenharmony_ci    point->Z_is_one = 0;
328e1051a39Sopenharmony_ci
329e1051a39Sopenharmony_ci    if (point->X == NULL || point->Y == NULL || point->Z == NULL) {
330e1051a39Sopenharmony_ci        BN_free(point->X);
331e1051a39Sopenharmony_ci        BN_free(point->Y);
332e1051a39Sopenharmony_ci        BN_free(point->Z);
333e1051a39Sopenharmony_ci        return 0;
334e1051a39Sopenharmony_ci    }
335e1051a39Sopenharmony_ci    return 1;
336e1051a39Sopenharmony_ci}
337e1051a39Sopenharmony_ci
338e1051a39Sopenharmony_civoid ossl_ec_GFp_simple_point_finish(EC_POINT *point)
339e1051a39Sopenharmony_ci{
340e1051a39Sopenharmony_ci    BN_free(point->X);
341e1051a39Sopenharmony_ci    BN_free(point->Y);
342e1051a39Sopenharmony_ci    BN_free(point->Z);
343e1051a39Sopenharmony_ci}
344e1051a39Sopenharmony_ci
345e1051a39Sopenharmony_civoid ossl_ec_GFp_simple_point_clear_finish(EC_POINT *point)
346e1051a39Sopenharmony_ci{
347e1051a39Sopenharmony_ci    BN_clear_free(point->X);
348e1051a39Sopenharmony_ci    BN_clear_free(point->Y);
349e1051a39Sopenharmony_ci    BN_clear_free(point->Z);
350e1051a39Sopenharmony_ci    point->Z_is_one = 0;
351e1051a39Sopenharmony_ci}
352e1051a39Sopenharmony_ci
353e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src)
354e1051a39Sopenharmony_ci{
355e1051a39Sopenharmony_ci    if (!BN_copy(dest->X, src->X))
356e1051a39Sopenharmony_ci        return 0;
357e1051a39Sopenharmony_ci    if (!BN_copy(dest->Y, src->Y))
358e1051a39Sopenharmony_ci        return 0;
359e1051a39Sopenharmony_ci    if (!BN_copy(dest->Z, src->Z))
360e1051a39Sopenharmony_ci        return 0;
361e1051a39Sopenharmony_ci    dest->Z_is_one = src->Z_is_one;
362e1051a39Sopenharmony_ci    dest->curve_name = src->curve_name;
363e1051a39Sopenharmony_ci
364e1051a39Sopenharmony_ci    return 1;
365e1051a39Sopenharmony_ci}
366e1051a39Sopenharmony_ci
367e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group,
368e1051a39Sopenharmony_ci                                             EC_POINT *point)
369e1051a39Sopenharmony_ci{
370e1051a39Sopenharmony_ci    point->Z_is_one = 0;
371e1051a39Sopenharmony_ci    BN_zero(point->Z);
372e1051a39Sopenharmony_ci    return 1;
373e1051a39Sopenharmony_ci}
374e1051a39Sopenharmony_ci
375e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *group,
376e1051a39Sopenharmony_ci                                                       EC_POINT *point,
377e1051a39Sopenharmony_ci                                                       const BIGNUM *x,
378e1051a39Sopenharmony_ci                                                       const BIGNUM *y,
379e1051a39Sopenharmony_ci                                                       const BIGNUM *z,
380e1051a39Sopenharmony_ci                                                       BN_CTX *ctx)
381e1051a39Sopenharmony_ci{
382e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
383e1051a39Sopenharmony_ci    int ret = 0;
384e1051a39Sopenharmony_ci
385e1051a39Sopenharmony_ci    if (ctx == NULL) {
386e1051a39Sopenharmony_ci        ctx = new_ctx = BN_CTX_new_ex(group->libctx);
387e1051a39Sopenharmony_ci        if (ctx == NULL)
388e1051a39Sopenharmony_ci            return 0;
389e1051a39Sopenharmony_ci    }
390e1051a39Sopenharmony_ci
391e1051a39Sopenharmony_ci    if (x != NULL) {
392e1051a39Sopenharmony_ci        if (!BN_nnmod(point->X, x, group->field, ctx))
393e1051a39Sopenharmony_ci            goto err;
394e1051a39Sopenharmony_ci        if (group->meth->field_encode) {
395e1051a39Sopenharmony_ci            if (!group->meth->field_encode(group, point->X, point->X, ctx))
396e1051a39Sopenharmony_ci                goto err;
397e1051a39Sopenharmony_ci        }
398e1051a39Sopenharmony_ci    }
399e1051a39Sopenharmony_ci
400e1051a39Sopenharmony_ci    if (y != NULL) {
401e1051a39Sopenharmony_ci        if (!BN_nnmod(point->Y, y, group->field, ctx))
402e1051a39Sopenharmony_ci            goto err;
403e1051a39Sopenharmony_ci        if (group->meth->field_encode) {
404e1051a39Sopenharmony_ci            if (!group->meth->field_encode(group, point->Y, point->Y, ctx))
405e1051a39Sopenharmony_ci                goto err;
406e1051a39Sopenharmony_ci        }
407e1051a39Sopenharmony_ci    }
408e1051a39Sopenharmony_ci
409e1051a39Sopenharmony_ci    if (z != NULL) {
410e1051a39Sopenharmony_ci        int Z_is_one;
411e1051a39Sopenharmony_ci
412e1051a39Sopenharmony_ci        if (!BN_nnmod(point->Z, z, group->field, ctx))
413e1051a39Sopenharmony_ci            goto err;
414e1051a39Sopenharmony_ci        Z_is_one = BN_is_one(point->Z);
415e1051a39Sopenharmony_ci        if (group->meth->field_encode) {
416e1051a39Sopenharmony_ci            if (Z_is_one && (group->meth->field_set_to_one != 0)) {
417e1051a39Sopenharmony_ci                if (!group->meth->field_set_to_one(group, point->Z, ctx))
418e1051a39Sopenharmony_ci                    goto err;
419e1051a39Sopenharmony_ci            } else {
420e1051a39Sopenharmony_ci                if (!group->
421e1051a39Sopenharmony_ci                    meth->field_encode(group, point->Z, point->Z, ctx))
422e1051a39Sopenharmony_ci                    goto err;
423e1051a39Sopenharmony_ci            }
424e1051a39Sopenharmony_ci        }
425e1051a39Sopenharmony_ci        point->Z_is_one = Z_is_one;
426e1051a39Sopenharmony_ci    }
427e1051a39Sopenharmony_ci
428e1051a39Sopenharmony_ci    ret = 1;
429e1051a39Sopenharmony_ci
430e1051a39Sopenharmony_ci err:
431e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
432e1051a39Sopenharmony_ci    return ret;
433e1051a39Sopenharmony_ci}
434e1051a39Sopenharmony_ci
435e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group,
436e1051a39Sopenharmony_ci                                                       const EC_POINT *point,
437e1051a39Sopenharmony_ci                                                       BIGNUM *x, BIGNUM *y,
438e1051a39Sopenharmony_ci                                                       BIGNUM *z, BN_CTX *ctx)
439e1051a39Sopenharmony_ci{
440e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
441e1051a39Sopenharmony_ci    int ret = 0;
442e1051a39Sopenharmony_ci
443e1051a39Sopenharmony_ci    if (group->meth->field_decode != 0) {
444e1051a39Sopenharmony_ci        if (ctx == NULL) {
445e1051a39Sopenharmony_ci            ctx = new_ctx = BN_CTX_new_ex(group->libctx);
446e1051a39Sopenharmony_ci            if (ctx == NULL)
447e1051a39Sopenharmony_ci                return 0;
448e1051a39Sopenharmony_ci        }
449e1051a39Sopenharmony_ci
450e1051a39Sopenharmony_ci        if (x != NULL) {
451e1051a39Sopenharmony_ci            if (!group->meth->field_decode(group, x, point->X, ctx))
452e1051a39Sopenharmony_ci                goto err;
453e1051a39Sopenharmony_ci        }
454e1051a39Sopenharmony_ci        if (y != NULL) {
455e1051a39Sopenharmony_ci            if (!group->meth->field_decode(group, y, point->Y, ctx))
456e1051a39Sopenharmony_ci                goto err;
457e1051a39Sopenharmony_ci        }
458e1051a39Sopenharmony_ci        if (z != NULL) {
459e1051a39Sopenharmony_ci            if (!group->meth->field_decode(group, z, point->Z, ctx))
460e1051a39Sopenharmony_ci                goto err;
461e1051a39Sopenharmony_ci        }
462e1051a39Sopenharmony_ci    } else {
463e1051a39Sopenharmony_ci        if (x != NULL) {
464e1051a39Sopenharmony_ci            if (!BN_copy(x, point->X))
465e1051a39Sopenharmony_ci                goto err;
466e1051a39Sopenharmony_ci        }
467e1051a39Sopenharmony_ci        if (y != NULL) {
468e1051a39Sopenharmony_ci            if (!BN_copy(y, point->Y))
469e1051a39Sopenharmony_ci                goto err;
470e1051a39Sopenharmony_ci        }
471e1051a39Sopenharmony_ci        if (z != NULL) {
472e1051a39Sopenharmony_ci            if (!BN_copy(z, point->Z))
473e1051a39Sopenharmony_ci                goto err;
474e1051a39Sopenharmony_ci        }
475e1051a39Sopenharmony_ci    }
476e1051a39Sopenharmony_ci
477e1051a39Sopenharmony_ci    ret = 1;
478e1051a39Sopenharmony_ci
479e1051a39Sopenharmony_ci err:
480e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
481e1051a39Sopenharmony_ci    return ret;
482e1051a39Sopenharmony_ci}
483e1051a39Sopenharmony_ci
484e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group,
485e1051a39Sopenharmony_ci                                                    EC_POINT *point,
486e1051a39Sopenharmony_ci                                                    const BIGNUM *x,
487e1051a39Sopenharmony_ci                                                    const BIGNUM *y, BN_CTX *ctx)
488e1051a39Sopenharmony_ci{
489e1051a39Sopenharmony_ci    if (x == NULL || y == NULL) {
490e1051a39Sopenharmony_ci        /*
491e1051a39Sopenharmony_ci         * unlike for projective coordinates, we do not tolerate this
492e1051a39Sopenharmony_ci         */
493e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, ERR_R_PASSED_NULL_PARAMETER);
494e1051a39Sopenharmony_ci        return 0;
495e1051a39Sopenharmony_ci    }
496e1051a39Sopenharmony_ci
497e1051a39Sopenharmony_ci    return EC_POINT_set_Jprojective_coordinates_GFp(group, point, x, y,
498e1051a39Sopenharmony_ci                                                    BN_value_one(), ctx);
499e1051a39Sopenharmony_ci}
500e1051a39Sopenharmony_ci
501e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group,
502e1051a39Sopenharmony_ci                                                    const EC_POINT *point,
503e1051a39Sopenharmony_ci                                                    BIGNUM *x, BIGNUM *y,
504e1051a39Sopenharmony_ci                                                    BN_CTX *ctx)
505e1051a39Sopenharmony_ci{
506e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
507e1051a39Sopenharmony_ci    BIGNUM *Z, *Z_1, *Z_2, *Z_3;
508e1051a39Sopenharmony_ci    const BIGNUM *Z_;
509e1051a39Sopenharmony_ci    int ret = 0;
510e1051a39Sopenharmony_ci
511e1051a39Sopenharmony_ci    if (EC_POINT_is_at_infinity(group, point)) {
512e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, EC_R_POINT_AT_INFINITY);
513e1051a39Sopenharmony_ci        return 0;
514e1051a39Sopenharmony_ci    }
515e1051a39Sopenharmony_ci
516e1051a39Sopenharmony_ci    if (ctx == NULL) {
517e1051a39Sopenharmony_ci        ctx = new_ctx = BN_CTX_new_ex(group->libctx);
518e1051a39Sopenharmony_ci        if (ctx == NULL)
519e1051a39Sopenharmony_ci            return 0;
520e1051a39Sopenharmony_ci    }
521e1051a39Sopenharmony_ci
522e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
523e1051a39Sopenharmony_ci    Z = BN_CTX_get(ctx);
524e1051a39Sopenharmony_ci    Z_1 = BN_CTX_get(ctx);
525e1051a39Sopenharmony_ci    Z_2 = BN_CTX_get(ctx);
526e1051a39Sopenharmony_ci    Z_3 = BN_CTX_get(ctx);
527e1051a39Sopenharmony_ci    if (Z_3 == NULL)
528e1051a39Sopenharmony_ci        goto err;
529e1051a39Sopenharmony_ci
530e1051a39Sopenharmony_ci    /* transform  (X, Y, Z)  into  (x, y) := (X/Z^2, Y/Z^3) */
531e1051a39Sopenharmony_ci
532e1051a39Sopenharmony_ci    if (group->meth->field_decode) {
533e1051a39Sopenharmony_ci        if (!group->meth->field_decode(group, Z, point->Z, ctx))
534e1051a39Sopenharmony_ci            goto err;
535e1051a39Sopenharmony_ci        Z_ = Z;
536e1051a39Sopenharmony_ci    } else {
537e1051a39Sopenharmony_ci        Z_ = point->Z;
538e1051a39Sopenharmony_ci    }
539e1051a39Sopenharmony_ci
540e1051a39Sopenharmony_ci    if (BN_is_one(Z_)) {
541e1051a39Sopenharmony_ci        if (group->meth->field_decode) {
542e1051a39Sopenharmony_ci            if (x != NULL) {
543e1051a39Sopenharmony_ci                if (!group->meth->field_decode(group, x, point->X, ctx))
544e1051a39Sopenharmony_ci                    goto err;
545e1051a39Sopenharmony_ci            }
546e1051a39Sopenharmony_ci            if (y != NULL) {
547e1051a39Sopenharmony_ci                if (!group->meth->field_decode(group, y, point->Y, ctx))
548e1051a39Sopenharmony_ci                    goto err;
549e1051a39Sopenharmony_ci            }
550e1051a39Sopenharmony_ci        } else {
551e1051a39Sopenharmony_ci            if (x != NULL) {
552e1051a39Sopenharmony_ci                if (!BN_copy(x, point->X))
553e1051a39Sopenharmony_ci                    goto err;
554e1051a39Sopenharmony_ci            }
555e1051a39Sopenharmony_ci            if (y != NULL) {
556e1051a39Sopenharmony_ci                if (!BN_copy(y, point->Y))
557e1051a39Sopenharmony_ci                    goto err;
558e1051a39Sopenharmony_ci            }
559e1051a39Sopenharmony_ci        }
560e1051a39Sopenharmony_ci    } else {
561e1051a39Sopenharmony_ci        if (!group->meth->field_inv(group, Z_1, Z_, ctx)) {
562e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB);
563e1051a39Sopenharmony_ci            goto err;
564e1051a39Sopenharmony_ci        }
565e1051a39Sopenharmony_ci
566e1051a39Sopenharmony_ci        if (group->meth->field_encode == 0) {
567e1051a39Sopenharmony_ci            /* field_sqr works on standard representation */
568e1051a39Sopenharmony_ci            if (!group->meth->field_sqr(group, Z_2, Z_1, ctx))
569e1051a39Sopenharmony_ci                goto err;
570e1051a39Sopenharmony_ci        } else {
571e1051a39Sopenharmony_ci            if (!BN_mod_sqr(Z_2, Z_1, group->field, ctx))
572e1051a39Sopenharmony_ci                goto err;
573e1051a39Sopenharmony_ci        }
574e1051a39Sopenharmony_ci
575e1051a39Sopenharmony_ci        if (x != NULL) {
576e1051a39Sopenharmony_ci            /*
577e1051a39Sopenharmony_ci             * in the Montgomery case, field_mul will cancel out Montgomery
578e1051a39Sopenharmony_ci             * factor in X:
579e1051a39Sopenharmony_ci             */
580e1051a39Sopenharmony_ci            if (!group->meth->field_mul(group, x, point->X, Z_2, ctx))
581e1051a39Sopenharmony_ci                goto err;
582e1051a39Sopenharmony_ci        }
583e1051a39Sopenharmony_ci
584e1051a39Sopenharmony_ci        if (y != NULL) {
585e1051a39Sopenharmony_ci            if (group->meth->field_encode == 0) {
586e1051a39Sopenharmony_ci                /*
587e1051a39Sopenharmony_ci                 * field_mul works on standard representation
588e1051a39Sopenharmony_ci                 */
589e1051a39Sopenharmony_ci                if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx))
590e1051a39Sopenharmony_ci                    goto err;
591e1051a39Sopenharmony_ci            } else {
592e1051a39Sopenharmony_ci                if (!BN_mod_mul(Z_3, Z_2, Z_1, group->field, ctx))
593e1051a39Sopenharmony_ci                    goto err;
594e1051a39Sopenharmony_ci            }
595e1051a39Sopenharmony_ci
596e1051a39Sopenharmony_ci            /*
597e1051a39Sopenharmony_ci             * in the Montgomery case, field_mul will cancel out Montgomery
598e1051a39Sopenharmony_ci             * factor in Y:
599e1051a39Sopenharmony_ci             */
600e1051a39Sopenharmony_ci            if (!group->meth->field_mul(group, y, point->Y, Z_3, ctx))
601e1051a39Sopenharmony_ci                goto err;
602e1051a39Sopenharmony_ci        }
603e1051a39Sopenharmony_ci    }
604e1051a39Sopenharmony_ci
605e1051a39Sopenharmony_ci    ret = 1;
606e1051a39Sopenharmony_ci
607e1051a39Sopenharmony_ci err:
608e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
609e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
610e1051a39Sopenharmony_ci    return ret;
611e1051a39Sopenharmony_ci}
612e1051a39Sopenharmony_ci
613e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
614e1051a39Sopenharmony_ci                           const EC_POINT *b, BN_CTX *ctx)
615e1051a39Sopenharmony_ci{
616e1051a39Sopenharmony_ci    int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
617e1051a39Sopenharmony_ci                      const BIGNUM *, BN_CTX *);
618e1051a39Sopenharmony_ci    int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
619e1051a39Sopenharmony_ci    const BIGNUM *p;
620e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
621e1051a39Sopenharmony_ci    BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6;
622e1051a39Sopenharmony_ci    int ret = 0;
623e1051a39Sopenharmony_ci
624e1051a39Sopenharmony_ci    if (a == b)
625e1051a39Sopenharmony_ci        return EC_POINT_dbl(group, r, a, ctx);
626e1051a39Sopenharmony_ci    if (EC_POINT_is_at_infinity(group, a))
627e1051a39Sopenharmony_ci        return EC_POINT_copy(r, b);
628e1051a39Sopenharmony_ci    if (EC_POINT_is_at_infinity(group, b))
629e1051a39Sopenharmony_ci        return EC_POINT_copy(r, a);
630e1051a39Sopenharmony_ci
631e1051a39Sopenharmony_ci    field_mul = group->meth->field_mul;
632e1051a39Sopenharmony_ci    field_sqr = group->meth->field_sqr;
633e1051a39Sopenharmony_ci    p = group->field;
634e1051a39Sopenharmony_ci
635e1051a39Sopenharmony_ci    if (ctx == NULL) {
636e1051a39Sopenharmony_ci        ctx = new_ctx = BN_CTX_new_ex(group->libctx);
637e1051a39Sopenharmony_ci        if (ctx == NULL)
638e1051a39Sopenharmony_ci            return 0;
639e1051a39Sopenharmony_ci    }
640e1051a39Sopenharmony_ci
641e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
642e1051a39Sopenharmony_ci    n0 = BN_CTX_get(ctx);
643e1051a39Sopenharmony_ci    n1 = BN_CTX_get(ctx);
644e1051a39Sopenharmony_ci    n2 = BN_CTX_get(ctx);
645e1051a39Sopenharmony_ci    n3 = BN_CTX_get(ctx);
646e1051a39Sopenharmony_ci    n4 = BN_CTX_get(ctx);
647e1051a39Sopenharmony_ci    n5 = BN_CTX_get(ctx);
648e1051a39Sopenharmony_ci    n6 = BN_CTX_get(ctx);
649e1051a39Sopenharmony_ci    if (n6 == NULL)
650e1051a39Sopenharmony_ci        goto end;
651e1051a39Sopenharmony_ci
652e1051a39Sopenharmony_ci    /*
653e1051a39Sopenharmony_ci     * Note that in this function we must not read components of 'a' or 'b'
654e1051a39Sopenharmony_ci     * once we have written the corresponding components of 'r'. ('r' might
655e1051a39Sopenharmony_ci     * be one of 'a' or 'b'.)
656e1051a39Sopenharmony_ci     */
657e1051a39Sopenharmony_ci
658e1051a39Sopenharmony_ci    /* n1, n2 */
659e1051a39Sopenharmony_ci    if (b->Z_is_one) {
660e1051a39Sopenharmony_ci        if (!BN_copy(n1, a->X))
661e1051a39Sopenharmony_ci            goto end;
662e1051a39Sopenharmony_ci        if (!BN_copy(n2, a->Y))
663e1051a39Sopenharmony_ci            goto end;
664e1051a39Sopenharmony_ci        /* n1 = X_a */
665e1051a39Sopenharmony_ci        /* n2 = Y_a */
666e1051a39Sopenharmony_ci    } else {
667e1051a39Sopenharmony_ci        if (!field_sqr(group, n0, b->Z, ctx))
668e1051a39Sopenharmony_ci            goto end;
669e1051a39Sopenharmony_ci        if (!field_mul(group, n1, a->X, n0, ctx))
670e1051a39Sopenharmony_ci            goto end;
671e1051a39Sopenharmony_ci        /* n1 = X_a * Z_b^2 */
672e1051a39Sopenharmony_ci
673e1051a39Sopenharmony_ci        if (!field_mul(group, n0, n0, b->Z, ctx))
674e1051a39Sopenharmony_ci            goto end;
675e1051a39Sopenharmony_ci        if (!field_mul(group, n2, a->Y, n0, ctx))
676e1051a39Sopenharmony_ci            goto end;
677e1051a39Sopenharmony_ci        /* n2 = Y_a * Z_b^3 */
678e1051a39Sopenharmony_ci    }
679e1051a39Sopenharmony_ci
680e1051a39Sopenharmony_ci    /* n3, n4 */
681e1051a39Sopenharmony_ci    if (a->Z_is_one) {
682e1051a39Sopenharmony_ci        if (!BN_copy(n3, b->X))
683e1051a39Sopenharmony_ci            goto end;
684e1051a39Sopenharmony_ci        if (!BN_copy(n4, b->Y))
685e1051a39Sopenharmony_ci            goto end;
686e1051a39Sopenharmony_ci        /* n3 = X_b */
687e1051a39Sopenharmony_ci        /* n4 = Y_b */
688e1051a39Sopenharmony_ci    } else {
689e1051a39Sopenharmony_ci        if (!field_sqr(group, n0, a->Z, ctx))
690e1051a39Sopenharmony_ci            goto end;
691e1051a39Sopenharmony_ci        if (!field_mul(group, n3, b->X, n0, ctx))
692e1051a39Sopenharmony_ci            goto end;
693e1051a39Sopenharmony_ci        /* n3 = X_b * Z_a^2 */
694e1051a39Sopenharmony_ci
695e1051a39Sopenharmony_ci        if (!field_mul(group, n0, n0, a->Z, ctx))
696e1051a39Sopenharmony_ci            goto end;
697e1051a39Sopenharmony_ci        if (!field_mul(group, n4, b->Y, n0, ctx))
698e1051a39Sopenharmony_ci            goto end;
699e1051a39Sopenharmony_ci        /* n4 = Y_b * Z_a^3 */
700e1051a39Sopenharmony_ci    }
701e1051a39Sopenharmony_ci
702e1051a39Sopenharmony_ci    /* n5, n6 */
703e1051a39Sopenharmony_ci    if (!BN_mod_sub_quick(n5, n1, n3, p))
704e1051a39Sopenharmony_ci        goto end;
705e1051a39Sopenharmony_ci    if (!BN_mod_sub_quick(n6, n2, n4, p))
706e1051a39Sopenharmony_ci        goto end;
707e1051a39Sopenharmony_ci    /* n5 = n1 - n3 */
708e1051a39Sopenharmony_ci    /* n6 = n2 - n4 */
709e1051a39Sopenharmony_ci
710e1051a39Sopenharmony_ci    if (BN_is_zero(n5)) {
711e1051a39Sopenharmony_ci        if (BN_is_zero(n6)) {
712e1051a39Sopenharmony_ci            /* a is the same point as b */
713e1051a39Sopenharmony_ci            BN_CTX_end(ctx);
714e1051a39Sopenharmony_ci            ret = EC_POINT_dbl(group, r, a, ctx);
715e1051a39Sopenharmony_ci            ctx = NULL;
716e1051a39Sopenharmony_ci            goto end;
717e1051a39Sopenharmony_ci        } else {
718e1051a39Sopenharmony_ci            /* a is the inverse of b */
719e1051a39Sopenharmony_ci            BN_zero(r->Z);
720e1051a39Sopenharmony_ci            r->Z_is_one = 0;
721e1051a39Sopenharmony_ci            ret = 1;
722e1051a39Sopenharmony_ci            goto end;
723e1051a39Sopenharmony_ci        }
724e1051a39Sopenharmony_ci    }
725e1051a39Sopenharmony_ci
726e1051a39Sopenharmony_ci    /* 'n7', 'n8' */
727e1051a39Sopenharmony_ci    if (!BN_mod_add_quick(n1, n1, n3, p))
728e1051a39Sopenharmony_ci        goto end;
729e1051a39Sopenharmony_ci    if (!BN_mod_add_quick(n2, n2, n4, p))
730e1051a39Sopenharmony_ci        goto end;
731e1051a39Sopenharmony_ci    /* 'n7' = n1 + n3 */
732e1051a39Sopenharmony_ci    /* 'n8' = n2 + n4 */
733e1051a39Sopenharmony_ci
734e1051a39Sopenharmony_ci    /* Z_r */
735e1051a39Sopenharmony_ci    if (a->Z_is_one && b->Z_is_one) {
736e1051a39Sopenharmony_ci        if (!BN_copy(r->Z, n5))
737e1051a39Sopenharmony_ci            goto end;
738e1051a39Sopenharmony_ci    } else {
739e1051a39Sopenharmony_ci        if (a->Z_is_one) {
740e1051a39Sopenharmony_ci            if (!BN_copy(n0, b->Z))
741e1051a39Sopenharmony_ci                goto end;
742e1051a39Sopenharmony_ci        } else if (b->Z_is_one) {
743e1051a39Sopenharmony_ci            if (!BN_copy(n0, a->Z))
744e1051a39Sopenharmony_ci                goto end;
745e1051a39Sopenharmony_ci        } else {
746e1051a39Sopenharmony_ci            if (!field_mul(group, n0, a->Z, b->Z, ctx))
747e1051a39Sopenharmony_ci                goto end;
748e1051a39Sopenharmony_ci        }
749e1051a39Sopenharmony_ci        if (!field_mul(group, r->Z, n0, n5, ctx))
750e1051a39Sopenharmony_ci            goto end;
751e1051a39Sopenharmony_ci    }
752e1051a39Sopenharmony_ci    r->Z_is_one = 0;
753e1051a39Sopenharmony_ci    /* Z_r = Z_a * Z_b * n5 */
754e1051a39Sopenharmony_ci
755e1051a39Sopenharmony_ci    /* X_r */
756e1051a39Sopenharmony_ci    if (!field_sqr(group, n0, n6, ctx))
757e1051a39Sopenharmony_ci        goto end;
758e1051a39Sopenharmony_ci    if (!field_sqr(group, n4, n5, ctx))
759e1051a39Sopenharmony_ci        goto end;
760e1051a39Sopenharmony_ci    if (!field_mul(group, n3, n1, n4, ctx))
761e1051a39Sopenharmony_ci        goto end;
762e1051a39Sopenharmony_ci    if (!BN_mod_sub_quick(r->X, n0, n3, p))
763e1051a39Sopenharmony_ci        goto end;
764e1051a39Sopenharmony_ci    /* X_r = n6^2 - n5^2 * 'n7' */
765e1051a39Sopenharmony_ci
766e1051a39Sopenharmony_ci    /* 'n9' */
767e1051a39Sopenharmony_ci    if (!BN_mod_lshift1_quick(n0, r->X, p))
768e1051a39Sopenharmony_ci        goto end;
769e1051a39Sopenharmony_ci    if (!BN_mod_sub_quick(n0, n3, n0, p))
770e1051a39Sopenharmony_ci        goto end;
771e1051a39Sopenharmony_ci    /* n9 = n5^2 * 'n7' - 2 * X_r */
772e1051a39Sopenharmony_ci
773e1051a39Sopenharmony_ci    /* Y_r */
774e1051a39Sopenharmony_ci    if (!field_mul(group, n0, n0, n6, ctx))
775e1051a39Sopenharmony_ci        goto end;
776e1051a39Sopenharmony_ci    if (!field_mul(group, n5, n4, n5, ctx))
777e1051a39Sopenharmony_ci        goto end;               /* now n5 is n5^3 */
778e1051a39Sopenharmony_ci    if (!field_mul(group, n1, n2, n5, ctx))
779e1051a39Sopenharmony_ci        goto end;
780e1051a39Sopenharmony_ci    if (!BN_mod_sub_quick(n0, n0, n1, p))
781e1051a39Sopenharmony_ci        goto end;
782e1051a39Sopenharmony_ci    if (BN_is_odd(n0))
783e1051a39Sopenharmony_ci        if (!BN_add(n0, n0, p))
784e1051a39Sopenharmony_ci            goto end;
785e1051a39Sopenharmony_ci    /* now  0 <= n0 < 2*p,  and n0 is even */
786e1051a39Sopenharmony_ci    if (!BN_rshift1(r->Y, n0))
787e1051a39Sopenharmony_ci        goto end;
788e1051a39Sopenharmony_ci    /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */
789e1051a39Sopenharmony_ci
790e1051a39Sopenharmony_ci    ret = 1;
791e1051a39Sopenharmony_ci
792e1051a39Sopenharmony_ci end:
793e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
794e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
795e1051a39Sopenharmony_ci    return ret;
796e1051a39Sopenharmony_ci}
797e1051a39Sopenharmony_ci
798e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
799e1051a39Sopenharmony_ci                           BN_CTX *ctx)
800e1051a39Sopenharmony_ci{
801e1051a39Sopenharmony_ci    int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
802e1051a39Sopenharmony_ci                      const BIGNUM *, BN_CTX *);
803e1051a39Sopenharmony_ci    int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
804e1051a39Sopenharmony_ci    const BIGNUM *p;
805e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
806e1051a39Sopenharmony_ci    BIGNUM *n0, *n1, *n2, *n3;
807e1051a39Sopenharmony_ci    int ret = 0;
808e1051a39Sopenharmony_ci
809e1051a39Sopenharmony_ci    if (EC_POINT_is_at_infinity(group, a)) {
810e1051a39Sopenharmony_ci        BN_zero(r->Z);
811e1051a39Sopenharmony_ci        r->Z_is_one = 0;
812e1051a39Sopenharmony_ci        return 1;
813e1051a39Sopenharmony_ci    }
814e1051a39Sopenharmony_ci
815e1051a39Sopenharmony_ci    field_mul = group->meth->field_mul;
816e1051a39Sopenharmony_ci    field_sqr = group->meth->field_sqr;
817e1051a39Sopenharmony_ci    p = group->field;
818e1051a39Sopenharmony_ci
819e1051a39Sopenharmony_ci    if (ctx == NULL) {
820e1051a39Sopenharmony_ci        ctx = new_ctx = BN_CTX_new_ex(group->libctx);
821e1051a39Sopenharmony_ci        if (ctx == NULL)
822e1051a39Sopenharmony_ci            return 0;
823e1051a39Sopenharmony_ci    }
824e1051a39Sopenharmony_ci
825e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
826e1051a39Sopenharmony_ci    n0 = BN_CTX_get(ctx);
827e1051a39Sopenharmony_ci    n1 = BN_CTX_get(ctx);
828e1051a39Sopenharmony_ci    n2 = BN_CTX_get(ctx);
829e1051a39Sopenharmony_ci    n3 = BN_CTX_get(ctx);
830e1051a39Sopenharmony_ci    if (n3 == NULL)
831e1051a39Sopenharmony_ci        goto err;
832e1051a39Sopenharmony_ci
833e1051a39Sopenharmony_ci    /*
834e1051a39Sopenharmony_ci     * Note that in this function we must not read components of 'a' once we
835e1051a39Sopenharmony_ci     * have written the corresponding components of 'r'. ('r' might the same
836e1051a39Sopenharmony_ci     * as 'a'.)
837e1051a39Sopenharmony_ci     */
838e1051a39Sopenharmony_ci
839e1051a39Sopenharmony_ci    /* n1 */
840e1051a39Sopenharmony_ci    if (a->Z_is_one) {
841e1051a39Sopenharmony_ci        if (!field_sqr(group, n0, a->X, ctx))
842e1051a39Sopenharmony_ci            goto err;
843e1051a39Sopenharmony_ci        if (!BN_mod_lshift1_quick(n1, n0, p))
844e1051a39Sopenharmony_ci            goto err;
845e1051a39Sopenharmony_ci        if (!BN_mod_add_quick(n0, n0, n1, p))
846e1051a39Sopenharmony_ci            goto err;
847e1051a39Sopenharmony_ci        if (!BN_mod_add_quick(n1, n0, group->a, p))
848e1051a39Sopenharmony_ci            goto err;
849e1051a39Sopenharmony_ci        /* n1 = 3 * X_a^2 + a_curve */
850e1051a39Sopenharmony_ci    } else if (group->a_is_minus3) {
851e1051a39Sopenharmony_ci        if (!field_sqr(group, n1, a->Z, ctx))
852e1051a39Sopenharmony_ci            goto err;
853e1051a39Sopenharmony_ci        if (!BN_mod_add_quick(n0, a->X, n1, p))
854e1051a39Sopenharmony_ci            goto err;
855e1051a39Sopenharmony_ci        if (!BN_mod_sub_quick(n2, a->X, n1, p))
856e1051a39Sopenharmony_ci            goto err;
857e1051a39Sopenharmony_ci        if (!field_mul(group, n1, n0, n2, ctx))
858e1051a39Sopenharmony_ci            goto err;
859e1051a39Sopenharmony_ci        if (!BN_mod_lshift1_quick(n0, n1, p))
860e1051a39Sopenharmony_ci            goto err;
861e1051a39Sopenharmony_ci        if (!BN_mod_add_quick(n1, n0, n1, p))
862e1051a39Sopenharmony_ci            goto err;
863e1051a39Sopenharmony_ci        /*-
864e1051a39Sopenharmony_ci         * n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2)
865e1051a39Sopenharmony_ci         *    = 3 * X_a^2 - 3 * Z_a^4
866e1051a39Sopenharmony_ci         */
867e1051a39Sopenharmony_ci    } else {
868e1051a39Sopenharmony_ci        if (!field_sqr(group, n0, a->X, ctx))
869e1051a39Sopenharmony_ci            goto err;
870e1051a39Sopenharmony_ci        if (!BN_mod_lshift1_quick(n1, n0, p))
871e1051a39Sopenharmony_ci            goto err;
872e1051a39Sopenharmony_ci        if (!BN_mod_add_quick(n0, n0, n1, p))
873e1051a39Sopenharmony_ci            goto err;
874e1051a39Sopenharmony_ci        if (!field_sqr(group, n1, a->Z, ctx))
875e1051a39Sopenharmony_ci            goto err;
876e1051a39Sopenharmony_ci        if (!field_sqr(group, n1, n1, ctx))
877e1051a39Sopenharmony_ci            goto err;
878e1051a39Sopenharmony_ci        if (!field_mul(group, n1, n1, group->a, ctx))
879e1051a39Sopenharmony_ci            goto err;
880e1051a39Sopenharmony_ci        if (!BN_mod_add_quick(n1, n1, n0, p))
881e1051a39Sopenharmony_ci            goto err;
882e1051a39Sopenharmony_ci        /* n1 = 3 * X_a^2 + a_curve * Z_a^4 */
883e1051a39Sopenharmony_ci    }
884e1051a39Sopenharmony_ci
885e1051a39Sopenharmony_ci    /* Z_r */
886e1051a39Sopenharmony_ci    if (a->Z_is_one) {
887e1051a39Sopenharmony_ci        if (!BN_copy(n0, a->Y))
888e1051a39Sopenharmony_ci            goto err;
889e1051a39Sopenharmony_ci    } else {
890e1051a39Sopenharmony_ci        if (!field_mul(group, n0, a->Y, a->Z, ctx))
891e1051a39Sopenharmony_ci            goto err;
892e1051a39Sopenharmony_ci    }
893e1051a39Sopenharmony_ci    if (!BN_mod_lshift1_quick(r->Z, n0, p))
894e1051a39Sopenharmony_ci        goto err;
895e1051a39Sopenharmony_ci    r->Z_is_one = 0;
896e1051a39Sopenharmony_ci    /* Z_r = 2 * Y_a * Z_a */
897e1051a39Sopenharmony_ci
898e1051a39Sopenharmony_ci    /* n2 */
899e1051a39Sopenharmony_ci    if (!field_sqr(group, n3, a->Y, ctx))
900e1051a39Sopenharmony_ci        goto err;
901e1051a39Sopenharmony_ci    if (!field_mul(group, n2, a->X, n3, ctx))
902e1051a39Sopenharmony_ci        goto err;
903e1051a39Sopenharmony_ci    if (!BN_mod_lshift_quick(n2, n2, 2, p))
904e1051a39Sopenharmony_ci        goto err;
905e1051a39Sopenharmony_ci    /* n2 = 4 * X_a * Y_a^2 */
906e1051a39Sopenharmony_ci
907e1051a39Sopenharmony_ci    /* X_r */
908e1051a39Sopenharmony_ci    if (!BN_mod_lshift1_quick(n0, n2, p))
909e1051a39Sopenharmony_ci        goto err;
910e1051a39Sopenharmony_ci    if (!field_sqr(group, r->X, n1, ctx))
911e1051a39Sopenharmony_ci        goto err;
912e1051a39Sopenharmony_ci    if (!BN_mod_sub_quick(r->X, r->X, n0, p))
913e1051a39Sopenharmony_ci        goto err;
914e1051a39Sopenharmony_ci    /* X_r = n1^2 - 2 * n2 */
915e1051a39Sopenharmony_ci
916e1051a39Sopenharmony_ci    /* n3 */
917e1051a39Sopenharmony_ci    if (!field_sqr(group, n0, n3, ctx))
918e1051a39Sopenharmony_ci        goto err;
919e1051a39Sopenharmony_ci    if (!BN_mod_lshift_quick(n3, n0, 3, p))
920e1051a39Sopenharmony_ci        goto err;
921e1051a39Sopenharmony_ci    /* n3 = 8 * Y_a^4 */
922e1051a39Sopenharmony_ci
923e1051a39Sopenharmony_ci    /* Y_r */
924e1051a39Sopenharmony_ci    if (!BN_mod_sub_quick(n0, n2, r->X, p))
925e1051a39Sopenharmony_ci        goto err;
926e1051a39Sopenharmony_ci    if (!field_mul(group, n0, n1, n0, ctx))
927e1051a39Sopenharmony_ci        goto err;
928e1051a39Sopenharmony_ci    if (!BN_mod_sub_quick(r->Y, n0, n3, p))
929e1051a39Sopenharmony_ci        goto err;
930e1051a39Sopenharmony_ci    /* Y_r = n1 * (n2 - X_r) - n3 */
931e1051a39Sopenharmony_ci
932e1051a39Sopenharmony_ci    ret = 1;
933e1051a39Sopenharmony_ci
934e1051a39Sopenharmony_ci err:
935e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
936e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
937e1051a39Sopenharmony_ci    return ret;
938e1051a39Sopenharmony_ci}
939e1051a39Sopenharmony_ci
940e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point,
941e1051a39Sopenharmony_ci                              BN_CTX *ctx)
942e1051a39Sopenharmony_ci{
943e1051a39Sopenharmony_ci    if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(point->Y))
944e1051a39Sopenharmony_ci        /* point is its own inverse */
945e1051a39Sopenharmony_ci        return 1;
946e1051a39Sopenharmony_ci
947e1051a39Sopenharmony_ci    return BN_usub(point->Y, group->field, point->Y);
948e1051a39Sopenharmony_ci}
949e1051a39Sopenharmony_ci
950e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_is_at_infinity(const EC_GROUP *group,
951e1051a39Sopenharmony_ci                                      const EC_POINT *point)
952e1051a39Sopenharmony_ci{
953e1051a39Sopenharmony_ci    return BN_is_zero(point->Z);
954e1051a39Sopenharmony_ci}
955e1051a39Sopenharmony_ci
956e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
957e1051a39Sopenharmony_ci                                   BN_CTX *ctx)
958e1051a39Sopenharmony_ci{
959e1051a39Sopenharmony_ci    int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
960e1051a39Sopenharmony_ci                      const BIGNUM *, BN_CTX *);
961e1051a39Sopenharmony_ci    int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
962e1051a39Sopenharmony_ci    const BIGNUM *p;
963e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
964e1051a39Sopenharmony_ci    BIGNUM *rh, *tmp, *Z4, *Z6;
965e1051a39Sopenharmony_ci    int ret = -1;
966e1051a39Sopenharmony_ci
967e1051a39Sopenharmony_ci    if (EC_POINT_is_at_infinity(group, point))
968e1051a39Sopenharmony_ci        return 1;
969e1051a39Sopenharmony_ci
970e1051a39Sopenharmony_ci    field_mul = group->meth->field_mul;
971e1051a39Sopenharmony_ci    field_sqr = group->meth->field_sqr;
972e1051a39Sopenharmony_ci    p = group->field;
973e1051a39Sopenharmony_ci
974e1051a39Sopenharmony_ci    if (ctx == NULL) {
975e1051a39Sopenharmony_ci        ctx = new_ctx = BN_CTX_new_ex(group->libctx);
976e1051a39Sopenharmony_ci        if (ctx == NULL)
977e1051a39Sopenharmony_ci            return -1;
978e1051a39Sopenharmony_ci    }
979e1051a39Sopenharmony_ci
980e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
981e1051a39Sopenharmony_ci    rh = BN_CTX_get(ctx);
982e1051a39Sopenharmony_ci    tmp = BN_CTX_get(ctx);
983e1051a39Sopenharmony_ci    Z4 = BN_CTX_get(ctx);
984e1051a39Sopenharmony_ci    Z6 = BN_CTX_get(ctx);
985e1051a39Sopenharmony_ci    if (Z6 == NULL)
986e1051a39Sopenharmony_ci        goto err;
987e1051a39Sopenharmony_ci
988e1051a39Sopenharmony_ci    /*-
989e1051a39Sopenharmony_ci     * We have a curve defined by a Weierstrass equation
990e1051a39Sopenharmony_ci     *      y^2 = x^3 + a*x + b.
991e1051a39Sopenharmony_ci     * The point to consider is given in Jacobian projective coordinates
992e1051a39Sopenharmony_ci     * where  (X, Y, Z)  represents  (x, y) = (X/Z^2, Y/Z^3).
993e1051a39Sopenharmony_ci     * Substituting this and multiplying by  Z^6  transforms the above equation into
994e1051a39Sopenharmony_ci     *      Y^2 = X^3 + a*X*Z^4 + b*Z^6.
995e1051a39Sopenharmony_ci     * To test this, we add up the right-hand side in 'rh'.
996e1051a39Sopenharmony_ci     */
997e1051a39Sopenharmony_ci
998e1051a39Sopenharmony_ci    /* rh := X^2 */
999e1051a39Sopenharmony_ci    if (!field_sqr(group, rh, point->X, ctx))
1000e1051a39Sopenharmony_ci        goto err;
1001e1051a39Sopenharmony_ci
1002e1051a39Sopenharmony_ci    if (!point->Z_is_one) {
1003e1051a39Sopenharmony_ci        if (!field_sqr(group, tmp, point->Z, ctx))
1004e1051a39Sopenharmony_ci            goto err;
1005e1051a39Sopenharmony_ci        if (!field_sqr(group, Z4, tmp, ctx))
1006e1051a39Sopenharmony_ci            goto err;
1007e1051a39Sopenharmony_ci        if (!field_mul(group, Z6, Z4, tmp, ctx))
1008e1051a39Sopenharmony_ci            goto err;
1009e1051a39Sopenharmony_ci
1010e1051a39Sopenharmony_ci        /* rh := (rh + a*Z^4)*X */
1011e1051a39Sopenharmony_ci        if (group->a_is_minus3) {
1012e1051a39Sopenharmony_ci            if (!BN_mod_lshift1_quick(tmp, Z4, p))
1013e1051a39Sopenharmony_ci                goto err;
1014e1051a39Sopenharmony_ci            if (!BN_mod_add_quick(tmp, tmp, Z4, p))
1015e1051a39Sopenharmony_ci                goto err;
1016e1051a39Sopenharmony_ci            if (!BN_mod_sub_quick(rh, rh, tmp, p))
1017e1051a39Sopenharmony_ci                goto err;
1018e1051a39Sopenharmony_ci            if (!field_mul(group, rh, rh, point->X, ctx))
1019e1051a39Sopenharmony_ci                goto err;
1020e1051a39Sopenharmony_ci        } else {
1021e1051a39Sopenharmony_ci            if (!field_mul(group, tmp, Z4, group->a, ctx))
1022e1051a39Sopenharmony_ci                goto err;
1023e1051a39Sopenharmony_ci            if (!BN_mod_add_quick(rh, rh, tmp, p))
1024e1051a39Sopenharmony_ci                goto err;
1025e1051a39Sopenharmony_ci            if (!field_mul(group, rh, rh, point->X, ctx))
1026e1051a39Sopenharmony_ci                goto err;
1027e1051a39Sopenharmony_ci        }
1028e1051a39Sopenharmony_ci
1029e1051a39Sopenharmony_ci        /* rh := rh + b*Z^6 */
1030e1051a39Sopenharmony_ci        if (!field_mul(group, tmp, group->b, Z6, ctx))
1031e1051a39Sopenharmony_ci            goto err;
1032e1051a39Sopenharmony_ci        if (!BN_mod_add_quick(rh, rh, tmp, p))
1033e1051a39Sopenharmony_ci            goto err;
1034e1051a39Sopenharmony_ci    } else {
1035e1051a39Sopenharmony_ci        /* point->Z_is_one */
1036e1051a39Sopenharmony_ci
1037e1051a39Sopenharmony_ci        /* rh := (rh + a)*X */
1038e1051a39Sopenharmony_ci        if (!BN_mod_add_quick(rh, rh, group->a, p))
1039e1051a39Sopenharmony_ci            goto err;
1040e1051a39Sopenharmony_ci        if (!field_mul(group, rh, rh, point->X, ctx))
1041e1051a39Sopenharmony_ci            goto err;
1042e1051a39Sopenharmony_ci        /* rh := rh + b */
1043e1051a39Sopenharmony_ci        if (!BN_mod_add_quick(rh, rh, group->b, p))
1044e1051a39Sopenharmony_ci            goto err;
1045e1051a39Sopenharmony_ci    }
1046e1051a39Sopenharmony_ci
1047e1051a39Sopenharmony_ci    /* 'lh' := Y^2 */
1048e1051a39Sopenharmony_ci    if (!field_sqr(group, tmp, point->Y, ctx))
1049e1051a39Sopenharmony_ci        goto err;
1050e1051a39Sopenharmony_ci
1051e1051a39Sopenharmony_ci    ret = (0 == BN_ucmp(tmp, rh));
1052e1051a39Sopenharmony_ci
1053e1051a39Sopenharmony_ci err:
1054e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
1055e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
1056e1051a39Sopenharmony_ci    return ret;
1057e1051a39Sopenharmony_ci}
1058e1051a39Sopenharmony_ci
1059e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
1060e1051a39Sopenharmony_ci                           const EC_POINT *b, BN_CTX *ctx)
1061e1051a39Sopenharmony_ci{
1062e1051a39Sopenharmony_ci    /*-
1063e1051a39Sopenharmony_ci     * return values:
1064e1051a39Sopenharmony_ci     *  -1   error
1065e1051a39Sopenharmony_ci     *   0   equal (in affine coordinates)
1066e1051a39Sopenharmony_ci     *   1   not equal
1067e1051a39Sopenharmony_ci     */
1068e1051a39Sopenharmony_ci
1069e1051a39Sopenharmony_ci    int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
1070e1051a39Sopenharmony_ci                      const BIGNUM *, BN_CTX *);
1071e1051a39Sopenharmony_ci    int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
1072e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
1073e1051a39Sopenharmony_ci    BIGNUM *tmp1, *tmp2, *Za23, *Zb23;
1074e1051a39Sopenharmony_ci    const BIGNUM *tmp1_, *tmp2_;
1075e1051a39Sopenharmony_ci    int ret = -1;
1076e1051a39Sopenharmony_ci
1077e1051a39Sopenharmony_ci    if (EC_POINT_is_at_infinity(group, a)) {
1078e1051a39Sopenharmony_ci        return EC_POINT_is_at_infinity(group, b) ? 0 : 1;
1079e1051a39Sopenharmony_ci    }
1080e1051a39Sopenharmony_ci
1081e1051a39Sopenharmony_ci    if (EC_POINT_is_at_infinity(group, b))
1082e1051a39Sopenharmony_ci        return 1;
1083e1051a39Sopenharmony_ci
1084e1051a39Sopenharmony_ci    if (a->Z_is_one && b->Z_is_one) {
1085e1051a39Sopenharmony_ci        return ((BN_cmp(a->X, b->X) == 0) && BN_cmp(a->Y, b->Y) == 0) ? 0 : 1;
1086e1051a39Sopenharmony_ci    }
1087e1051a39Sopenharmony_ci
1088e1051a39Sopenharmony_ci    field_mul = group->meth->field_mul;
1089e1051a39Sopenharmony_ci    field_sqr = group->meth->field_sqr;
1090e1051a39Sopenharmony_ci
1091e1051a39Sopenharmony_ci    if (ctx == NULL) {
1092e1051a39Sopenharmony_ci        ctx = new_ctx = BN_CTX_new_ex(group->libctx);
1093e1051a39Sopenharmony_ci        if (ctx == NULL)
1094e1051a39Sopenharmony_ci            return -1;
1095e1051a39Sopenharmony_ci    }
1096e1051a39Sopenharmony_ci
1097e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
1098e1051a39Sopenharmony_ci    tmp1 = BN_CTX_get(ctx);
1099e1051a39Sopenharmony_ci    tmp2 = BN_CTX_get(ctx);
1100e1051a39Sopenharmony_ci    Za23 = BN_CTX_get(ctx);
1101e1051a39Sopenharmony_ci    Zb23 = BN_CTX_get(ctx);
1102e1051a39Sopenharmony_ci    if (Zb23 == NULL)
1103e1051a39Sopenharmony_ci        goto end;
1104e1051a39Sopenharmony_ci
1105e1051a39Sopenharmony_ci    /*-
1106e1051a39Sopenharmony_ci     * We have to decide whether
1107e1051a39Sopenharmony_ci     *     (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3),
1108e1051a39Sopenharmony_ci     * or equivalently, whether
1109e1051a39Sopenharmony_ci     *     (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3).
1110e1051a39Sopenharmony_ci     */
1111e1051a39Sopenharmony_ci
1112e1051a39Sopenharmony_ci    if (!b->Z_is_one) {
1113e1051a39Sopenharmony_ci        if (!field_sqr(group, Zb23, b->Z, ctx))
1114e1051a39Sopenharmony_ci            goto end;
1115e1051a39Sopenharmony_ci        if (!field_mul(group, tmp1, a->X, Zb23, ctx))
1116e1051a39Sopenharmony_ci            goto end;
1117e1051a39Sopenharmony_ci        tmp1_ = tmp1;
1118e1051a39Sopenharmony_ci    } else
1119e1051a39Sopenharmony_ci        tmp1_ = a->X;
1120e1051a39Sopenharmony_ci    if (!a->Z_is_one) {
1121e1051a39Sopenharmony_ci        if (!field_sqr(group, Za23, a->Z, ctx))
1122e1051a39Sopenharmony_ci            goto end;
1123e1051a39Sopenharmony_ci        if (!field_mul(group, tmp2, b->X, Za23, ctx))
1124e1051a39Sopenharmony_ci            goto end;
1125e1051a39Sopenharmony_ci        tmp2_ = tmp2;
1126e1051a39Sopenharmony_ci    } else
1127e1051a39Sopenharmony_ci        tmp2_ = b->X;
1128e1051a39Sopenharmony_ci
1129e1051a39Sopenharmony_ci    /* compare  X_a*Z_b^2  with  X_b*Z_a^2 */
1130e1051a39Sopenharmony_ci    if (BN_cmp(tmp1_, tmp2_) != 0) {
1131e1051a39Sopenharmony_ci        ret = 1;                /* points differ */
1132e1051a39Sopenharmony_ci        goto end;
1133e1051a39Sopenharmony_ci    }
1134e1051a39Sopenharmony_ci
1135e1051a39Sopenharmony_ci    if (!b->Z_is_one) {
1136e1051a39Sopenharmony_ci        if (!field_mul(group, Zb23, Zb23, b->Z, ctx))
1137e1051a39Sopenharmony_ci            goto end;
1138e1051a39Sopenharmony_ci        if (!field_mul(group, tmp1, a->Y, Zb23, ctx))
1139e1051a39Sopenharmony_ci            goto end;
1140e1051a39Sopenharmony_ci        /* tmp1_ = tmp1 */
1141e1051a39Sopenharmony_ci    } else
1142e1051a39Sopenharmony_ci        tmp1_ = a->Y;
1143e1051a39Sopenharmony_ci    if (!a->Z_is_one) {
1144e1051a39Sopenharmony_ci        if (!field_mul(group, Za23, Za23, a->Z, ctx))
1145e1051a39Sopenharmony_ci            goto end;
1146e1051a39Sopenharmony_ci        if (!field_mul(group, tmp2, b->Y, Za23, ctx))
1147e1051a39Sopenharmony_ci            goto end;
1148e1051a39Sopenharmony_ci        /* tmp2_ = tmp2 */
1149e1051a39Sopenharmony_ci    } else
1150e1051a39Sopenharmony_ci        tmp2_ = b->Y;
1151e1051a39Sopenharmony_ci
1152e1051a39Sopenharmony_ci    /* compare  Y_a*Z_b^3  with  Y_b*Z_a^3 */
1153e1051a39Sopenharmony_ci    if (BN_cmp(tmp1_, tmp2_) != 0) {
1154e1051a39Sopenharmony_ci        ret = 1;                /* points differ */
1155e1051a39Sopenharmony_ci        goto end;
1156e1051a39Sopenharmony_ci    }
1157e1051a39Sopenharmony_ci
1158e1051a39Sopenharmony_ci    /* points are equal */
1159e1051a39Sopenharmony_ci    ret = 0;
1160e1051a39Sopenharmony_ci
1161e1051a39Sopenharmony_ci end:
1162e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
1163e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
1164e1051a39Sopenharmony_ci    return ret;
1165e1051a39Sopenharmony_ci}
1166e1051a39Sopenharmony_ci
1167e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point,
1168e1051a39Sopenharmony_ci                                   BN_CTX *ctx)
1169e1051a39Sopenharmony_ci{
1170e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
1171e1051a39Sopenharmony_ci    BIGNUM *x, *y;
1172e1051a39Sopenharmony_ci    int ret = 0;
1173e1051a39Sopenharmony_ci
1174e1051a39Sopenharmony_ci    if (point->Z_is_one || EC_POINT_is_at_infinity(group, point))
1175e1051a39Sopenharmony_ci        return 1;
1176e1051a39Sopenharmony_ci
1177e1051a39Sopenharmony_ci    if (ctx == NULL) {
1178e1051a39Sopenharmony_ci        ctx = new_ctx = BN_CTX_new_ex(group->libctx);
1179e1051a39Sopenharmony_ci        if (ctx == NULL)
1180e1051a39Sopenharmony_ci            return 0;
1181e1051a39Sopenharmony_ci    }
1182e1051a39Sopenharmony_ci
1183e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
1184e1051a39Sopenharmony_ci    x = BN_CTX_get(ctx);
1185e1051a39Sopenharmony_ci    y = BN_CTX_get(ctx);
1186e1051a39Sopenharmony_ci    if (y == NULL)
1187e1051a39Sopenharmony_ci        goto err;
1188e1051a39Sopenharmony_ci
1189e1051a39Sopenharmony_ci    if (!EC_POINT_get_affine_coordinates(group, point, x, y, ctx))
1190e1051a39Sopenharmony_ci        goto err;
1191e1051a39Sopenharmony_ci    if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx))
1192e1051a39Sopenharmony_ci        goto err;
1193e1051a39Sopenharmony_ci    if (!point->Z_is_one) {
1194e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, ERR_R_INTERNAL_ERROR);
1195e1051a39Sopenharmony_ci        goto err;
1196e1051a39Sopenharmony_ci    }
1197e1051a39Sopenharmony_ci
1198e1051a39Sopenharmony_ci    ret = 1;
1199e1051a39Sopenharmony_ci
1200e1051a39Sopenharmony_ci err:
1201e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
1202e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
1203e1051a39Sopenharmony_ci    return ret;
1204e1051a39Sopenharmony_ci}
1205e1051a39Sopenharmony_ci
1206e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num,
1207e1051a39Sopenharmony_ci                                          EC_POINT *points[], BN_CTX *ctx)
1208e1051a39Sopenharmony_ci{
1209e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
1210e1051a39Sopenharmony_ci    BIGNUM *tmp, *tmp_Z;
1211e1051a39Sopenharmony_ci    BIGNUM **prod_Z = NULL;
1212e1051a39Sopenharmony_ci    size_t i;
1213e1051a39Sopenharmony_ci    int ret = 0;
1214e1051a39Sopenharmony_ci
1215e1051a39Sopenharmony_ci    if (num == 0)
1216e1051a39Sopenharmony_ci        return 1;
1217e1051a39Sopenharmony_ci
1218e1051a39Sopenharmony_ci    if (ctx == NULL) {
1219e1051a39Sopenharmony_ci        ctx = new_ctx = BN_CTX_new_ex(group->libctx);
1220e1051a39Sopenharmony_ci        if (ctx == NULL)
1221e1051a39Sopenharmony_ci            return 0;
1222e1051a39Sopenharmony_ci    }
1223e1051a39Sopenharmony_ci
1224e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
1225e1051a39Sopenharmony_ci    tmp = BN_CTX_get(ctx);
1226e1051a39Sopenharmony_ci    tmp_Z = BN_CTX_get(ctx);
1227e1051a39Sopenharmony_ci    if (tmp_Z == NULL)
1228e1051a39Sopenharmony_ci        goto err;
1229e1051a39Sopenharmony_ci
1230e1051a39Sopenharmony_ci    prod_Z = OPENSSL_malloc(num * sizeof(prod_Z[0]));
1231e1051a39Sopenharmony_ci    if (prod_Z == NULL)
1232e1051a39Sopenharmony_ci        goto err;
1233e1051a39Sopenharmony_ci    for (i = 0; i < num; i++) {
1234e1051a39Sopenharmony_ci        prod_Z[i] = BN_new();
1235e1051a39Sopenharmony_ci        if (prod_Z[i] == NULL)
1236e1051a39Sopenharmony_ci            goto err;
1237e1051a39Sopenharmony_ci    }
1238e1051a39Sopenharmony_ci
1239e1051a39Sopenharmony_ci    /*
1240e1051a39Sopenharmony_ci     * Set each prod_Z[i] to the product of points[0]->Z .. points[i]->Z,
1241e1051a39Sopenharmony_ci     * skipping any zero-valued inputs (pretend that they're 1).
1242e1051a39Sopenharmony_ci     */
1243e1051a39Sopenharmony_ci
1244e1051a39Sopenharmony_ci    if (!BN_is_zero(points[0]->Z)) {
1245e1051a39Sopenharmony_ci        if (!BN_copy(prod_Z[0], points[0]->Z))
1246e1051a39Sopenharmony_ci            goto err;
1247e1051a39Sopenharmony_ci    } else {
1248e1051a39Sopenharmony_ci        if (group->meth->field_set_to_one != 0) {
1249e1051a39Sopenharmony_ci            if (!group->meth->field_set_to_one(group, prod_Z[0], ctx))
1250e1051a39Sopenharmony_ci                goto err;
1251e1051a39Sopenharmony_ci        } else {
1252e1051a39Sopenharmony_ci            if (!BN_one(prod_Z[0]))
1253e1051a39Sopenharmony_ci                goto err;
1254e1051a39Sopenharmony_ci        }
1255e1051a39Sopenharmony_ci    }
1256e1051a39Sopenharmony_ci
1257e1051a39Sopenharmony_ci    for (i = 1; i < num; i++) {
1258e1051a39Sopenharmony_ci        if (!BN_is_zero(points[i]->Z)) {
1259e1051a39Sopenharmony_ci            if (!group->
1260e1051a39Sopenharmony_ci                meth->field_mul(group, prod_Z[i], prod_Z[i - 1], points[i]->Z,
1261e1051a39Sopenharmony_ci                                ctx))
1262e1051a39Sopenharmony_ci                goto err;
1263e1051a39Sopenharmony_ci        } else {
1264e1051a39Sopenharmony_ci            if (!BN_copy(prod_Z[i], prod_Z[i - 1]))
1265e1051a39Sopenharmony_ci                goto err;
1266e1051a39Sopenharmony_ci        }
1267e1051a39Sopenharmony_ci    }
1268e1051a39Sopenharmony_ci
1269e1051a39Sopenharmony_ci    /*
1270e1051a39Sopenharmony_ci     * Now use a single explicit inversion to replace every non-zero
1271e1051a39Sopenharmony_ci     * points[i]->Z by its inverse.
1272e1051a39Sopenharmony_ci     */
1273e1051a39Sopenharmony_ci
1274e1051a39Sopenharmony_ci    if (!group->meth->field_inv(group, tmp, prod_Z[num - 1], ctx)) {
1275e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, ERR_R_BN_LIB);
1276e1051a39Sopenharmony_ci        goto err;
1277e1051a39Sopenharmony_ci    }
1278e1051a39Sopenharmony_ci    if (group->meth->field_encode != 0) {
1279e1051a39Sopenharmony_ci        /*
1280e1051a39Sopenharmony_ci         * In the Montgomery case, we just turned R*H (representing H) into
1281e1051a39Sopenharmony_ci         * 1/(R*H), but we need R*(1/H) (representing 1/H); i.e. we need to
1282e1051a39Sopenharmony_ci         * multiply by the Montgomery factor twice.
1283e1051a39Sopenharmony_ci         */
1284e1051a39Sopenharmony_ci        if (!group->meth->field_encode(group, tmp, tmp, ctx))
1285e1051a39Sopenharmony_ci            goto err;
1286e1051a39Sopenharmony_ci        if (!group->meth->field_encode(group, tmp, tmp, ctx))
1287e1051a39Sopenharmony_ci            goto err;
1288e1051a39Sopenharmony_ci    }
1289e1051a39Sopenharmony_ci
1290e1051a39Sopenharmony_ci    for (i = num - 1; i > 0; --i) {
1291e1051a39Sopenharmony_ci        /*
1292e1051a39Sopenharmony_ci         * Loop invariant: tmp is the product of the inverses of points[0]->Z
1293e1051a39Sopenharmony_ci         * .. points[i]->Z (zero-valued inputs skipped).
1294e1051a39Sopenharmony_ci         */
1295e1051a39Sopenharmony_ci        if (!BN_is_zero(points[i]->Z)) {
1296e1051a39Sopenharmony_ci            /*
1297e1051a39Sopenharmony_ci             * Set tmp_Z to the inverse of points[i]->Z (as product of Z
1298e1051a39Sopenharmony_ci             * inverses 0 .. i, Z values 0 .. i - 1).
1299e1051a39Sopenharmony_ci             */
1300e1051a39Sopenharmony_ci            if (!group->
1301e1051a39Sopenharmony_ci                meth->field_mul(group, tmp_Z, prod_Z[i - 1], tmp, ctx))
1302e1051a39Sopenharmony_ci                goto err;
1303e1051a39Sopenharmony_ci            /*
1304e1051a39Sopenharmony_ci             * Update tmp to satisfy the loop invariant for i - 1.
1305e1051a39Sopenharmony_ci             */
1306e1051a39Sopenharmony_ci            if (!group->meth->field_mul(group, tmp, tmp, points[i]->Z, ctx))
1307e1051a39Sopenharmony_ci                goto err;
1308e1051a39Sopenharmony_ci            /* Replace points[i]->Z by its inverse. */
1309e1051a39Sopenharmony_ci            if (!BN_copy(points[i]->Z, tmp_Z))
1310e1051a39Sopenharmony_ci                goto err;
1311e1051a39Sopenharmony_ci        }
1312e1051a39Sopenharmony_ci    }
1313e1051a39Sopenharmony_ci
1314e1051a39Sopenharmony_ci    if (!BN_is_zero(points[0]->Z)) {
1315e1051a39Sopenharmony_ci        /* Replace points[0]->Z by its inverse. */
1316e1051a39Sopenharmony_ci        if (!BN_copy(points[0]->Z, tmp))
1317e1051a39Sopenharmony_ci            goto err;
1318e1051a39Sopenharmony_ci    }
1319e1051a39Sopenharmony_ci
1320e1051a39Sopenharmony_ci    /* Finally, fix up the X and Y coordinates for all points. */
1321e1051a39Sopenharmony_ci
1322e1051a39Sopenharmony_ci    for (i = 0; i < num; i++) {
1323e1051a39Sopenharmony_ci        EC_POINT *p = points[i];
1324e1051a39Sopenharmony_ci
1325e1051a39Sopenharmony_ci        if (!BN_is_zero(p->Z)) {
1326e1051a39Sopenharmony_ci            /* turn  (X, Y, 1/Z)  into  (X/Z^2, Y/Z^3, 1) */
1327e1051a39Sopenharmony_ci
1328e1051a39Sopenharmony_ci            if (!group->meth->field_sqr(group, tmp, p->Z, ctx))
1329e1051a39Sopenharmony_ci                goto err;
1330e1051a39Sopenharmony_ci            if (!group->meth->field_mul(group, p->X, p->X, tmp, ctx))
1331e1051a39Sopenharmony_ci                goto err;
1332e1051a39Sopenharmony_ci
1333e1051a39Sopenharmony_ci            if (!group->meth->field_mul(group, tmp, tmp, p->Z, ctx))
1334e1051a39Sopenharmony_ci                goto err;
1335e1051a39Sopenharmony_ci            if (!group->meth->field_mul(group, p->Y, p->Y, tmp, ctx))
1336e1051a39Sopenharmony_ci                goto err;
1337e1051a39Sopenharmony_ci
1338e1051a39Sopenharmony_ci            if (group->meth->field_set_to_one != 0) {
1339e1051a39Sopenharmony_ci                if (!group->meth->field_set_to_one(group, p->Z, ctx))
1340e1051a39Sopenharmony_ci                    goto err;
1341e1051a39Sopenharmony_ci            } else {
1342e1051a39Sopenharmony_ci                if (!BN_one(p->Z))
1343e1051a39Sopenharmony_ci                    goto err;
1344e1051a39Sopenharmony_ci            }
1345e1051a39Sopenharmony_ci            p->Z_is_one = 1;
1346e1051a39Sopenharmony_ci        }
1347e1051a39Sopenharmony_ci    }
1348e1051a39Sopenharmony_ci
1349e1051a39Sopenharmony_ci    ret = 1;
1350e1051a39Sopenharmony_ci
1351e1051a39Sopenharmony_ci err:
1352e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
1353e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
1354e1051a39Sopenharmony_ci    if (prod_Z != NULL) {
1355e1051a39Sopenharmony_ci        for (i = 0; i < num; i++) {
1356e1051a39Sopenharmony_ci            if (prod_Z[i] == NULL)
1357e1051a39Sopenharmony_ci                break;
1358e1051a39Sopenharmony_ci            BN_clear_free(prod_Z[i]);
1359e1051a39Sopenharmony_ci        }
1360e1051a39Sopenharmony_ci        OPENSSL_free(prod_Z);
1361e1051a39Sopenharmony_ci    }
1362e1051a39Sopenharmony_ci    return ret;
1363e1051a39Sopenharmony_ci}
1364e1051a39Sopenharmony_ci
1365e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
1366e1051a39Sopenharmony_ci                                 const BIGNUM *b, BN_CTX *ctx)
1367e1051a39Sopenharmony_ci{
1368e1051a39Sopenharmony_ci    return BN_mod_mul(r, a, b, group->field, ctx);
1369e1051a39Sopenharmony_ci}
1370e1051a39Sopenharmony_ci
1371e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
1372e1051a39Sopenharmony_ci                                 BN_CTX *ctx)
1373e1051a39Sopenharmony_ci{
1374e1051a39Sopenharmony_ci    return BN_mod_sqr(r, a, group->field, ctx);
1375e1051a39Sopenharmony_ci}
1376e1051a39Sopenharmony_ci
1377e1051a39Sopenharmony_ci/*-
1378e1051a39Sopenharmony_ci * Computes the multiplicative inverse of a in GF(p), storing the result in r.
1379e1051a39Sopenharmony_ci * If a is zero (or equivalent), you'll get a EC_R_CANNOT_INVERT error.
1380e1051a39Sopenharmony_ci * Since we don't have a Mont structure here, SCA hardening is with blinding.
1381e1051a39Sopenharmony_ci * NB: "a" must be in _decoded_ form. (i.e. field_decode must precede.)
1382e1051a39Sopenharmony_ci */
1383e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_field_inv(const EC_GROUP *group, BIGNUM *r,
1384e1051a39Sopenharmony_ci                                 const BIGNUM *a, BN_CTX *ctx)
1385e1051a39Sopenharmony_ci{
1386e1051a39Sopenharmony_ci    BIGNUM *e = NULL;
1387e1051a39Sopenharmony_ci    BN_CTX *new_ctx = NULL;
1388e1051a39Sopenharmony_ci    int ret = 0;
1389e1051a39Sopenharmony_ci
1390e1051a39Sopenharmony_ci    if (ctx == NULL
1391e1051a39Sopenharmony_ci            && (ctx = new_ctx = BN_CTX_secure_new_ex(group->libctx)) == NULL)
1392e1051a39Sopenharmony_ci        return 0;
1393e1051a39Sopenharmony_ci
1394e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
1395e1051a39Sopenharmony_ci    if ((e = BN_CTX_get(ctx)) == NULL)
1396e1051a39Sopenharmony_ci        goto err;
1397e1051a39Sopenharmony_ci
1398e1051a39Sopenharmony_ci    do {
1399e1051a39Sopenharmony_ci        if (!BN_priv_rand_range_ex(e, group->field, 0, ctx))
1400e1051a39Sopenharmony_ci        goto err;
1401e1051a39Sopenharmony_ci    } while (BN_is_zero(e));
1402e1051a39Sopenharmony_ci
1403e1051a39Sopenharmony_ci    /* r := a * e */
1404e1051a39Sopenharmony_ci    if (!group->meth->field_mul(group, r, a, e, ctx))
1405e1051a39Sopenharmony_ci        goto err;
1406e1051a39Sopenharmony_ci    /* r := 1/(a * e) */
1407e1051a39Sopenharmony_ci    if (!BN_mod_inverse(r, r, group->field, ctx)) {
1408e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, EC_R_CANNOT_INVERT);
1409e1051a39Sopenharmony_ci        goto err;
1410e1051a39Sopenharmony_ci    }
1411e1051a39Sopenharmony_ci    /* r := e/(a * e) = 1/a */
1412e1051a39Sopenharmony_ci    if (!group->meth->field_mul(group, r, r, e, ctx))
1413e1051a39Sopenharmony_ci        goto err;
1414e1051a39Sopenharmony_ci
1415e1051a39Sopenharmony_ci    ret = 1;
1416e1051a39Sopenharmony_ci
1417e1051a39Sopenharmony_ci err:
1418e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
1419e1051a39Sopenharmony_ci    BN_CTX_free(new_ctx);
1420e1051a39Sopenharmony_ci    return ret;
1421e1051a39Sopenharmony_ci}
1422e1051a39Sopenharmony_ci
1423e1051a39Sopenharmony_ci/*-
1424e1051a39Sopenharmony_ci * Apply randomization of EC point projective coordinates:
1425e1051a39Sopenharmony_ci *
1426e1051a39Sopenharmony_ci *   (X, Y ,Z ) = (lambda^2*X, lambda^3*Y, lambda*Z)
1427e1051a39Sopenharmony_ci *   lambda = [1,group->field)
1428e1051a39Sopenharmony_ci *
1429e1051a39Sopenharmony_ci */
1430e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_blind_coordinates(const EC_GROUP *group, EC_POINT *p,
1431e1051a39Sopenharmony_ci                                         BN_CTX *ctx)
1432e1051a39Sopenharmony_ci{
1433e1051a39Sopenharmony_ci    int ret = 0;
1434e1051a39Sopenharmony_ci    BIGNUM *lambda = NULL;
1435e1051a39Sopenharmony_ci    BIGNUM *temp = NULL;
1436e1051a39Sopenharmony_ci
1437e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
1438e1051a39Sopenharmony_ci    lambda = BN_CTX_get(ctx);
1439e1051a39Sopenharmony_ci    temp = BN_CTX_get(ctx);
1440e1051a39Sopenharmony_ci    if (temp == NULL) {
1441e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE);
1442e1051a39Sopenharmony_ci        goto end;
1443e1051a39Sopenharmony_ci    }
1444e1051a39Sopenharmony_ci
1445e1051a39Sopenharmony_ci    /*-
1446e1051a39Sopenharmony_ci     * Make sure lambda is not zero.
1447e1051a39Sopenharmony_ci     * If the RNG fails, we cannot blind but nevertheless want
1448e1051a39Sopenharmony_ci     * code to continue smoothly and not clobber the error stack.
1449e1051a39Sopenharmony_ci     */
1450e1051a39Sopenharmony_ci    do {
1451e1051a39Sopenharmony_ci        ERR_set_mark();
1452e1051a39Sopenharmony_ci        ret = BN_priv_rand_range_ex(lambda, group->field, 0, ctx);
1453e1051a39Sopenharmony_ci        ERR_pop_to_mark();
1454e1051a39Sopenharmony_ci        if (ret == 0) {
1455e1051a39Sopenharmony_ci            ret = 1;
1456e1051a39Sopenharmony_ci            goto end;
1457e1051a39Sopenharmony_ci        }
1458e1051a39Sopenharmony_ci    } while (BN_is_zero(lambda));
1459e1051a39Sopenharmony_ci
1460e1051a39Sopenharmony_ci    /* if field_encode defined convert between representations */
1461e1051a39Sopenharmony_ci    if ((group->meth->field_encode != NULL
1462e1051a39Sopenharmony_ci         && !group->meth->field_encode(group, lambda, lambda, ctx))
1463e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, p->Z, p->Z, lambda, ctx)
1464e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, temp, lambda, ctx)
1465e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, p->X, p->X, temp, ctx)
1466e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, temp, temp, lambda, ctx)
1467e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, p->Y, p->Y, temp, ctx))
1468e1051a39Sopenharmony_ci        goto end;
1469e1051a39Sopenharmony_ci
1470e1051a39Sopenharmony_ci    p->Z_is_one = 0;
1471e1051a39Sopenharmony_ci    ret = 1;
1472e1051a39Sopenharmony_ci
1473e1051a39Sopenharmony_ci end:
1474e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
1475e1051a39Sopenharmony_ci    return ret;
1476e1051a39Sopenharmony_ci}
1477e1051a39Sopenharmony_ci
1478e1051a39Sopenharmony_ci/*-
1479e1051a39Sopenharmony_ci * Input:
1480e1051a39Sopenharmony_ci * - p: affine coordinates
1481e1051a39Sopenharmony_ci *
1482e1051a39Sopenharmony_ci * Output:
1483e1051a39Sopenharmony_ci * - s := p, r := 2p: blinded projective (homogeneous) coordinates
1484e1051a39Sopenharmony_ci *
1485e1051a39Sopenharmony_ci * For doubling we use Formula 3 from Izu-Takagi "A fast parallel elliptic curve
1486e1051a39Sopenharmony_ci * multiplication resistant against side channel attacks" appendix, described at
1487e1051a39Sopenharmony_ci * https://hyperelliptic.org/EFD/g1p/auto-shortw-xz.html#doubling-dbl-2002-it-2
1488e1051a39Sopenharmony_ci * simplified for Z1=1.
1489e1051a39Sopenharmony_ci *
1490e1051a39Sopenharmony_ci * Blinding uses the equivalence relation (\lambda X, \lambda Y, \lambda Z)
1491e1051a39Sopenharmony_ci * for any non-zero \lambda that holds for projective (homogeneous) coords.
1492e1051a39Sopenharmony_ci */
1493e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_ladder_pre(const EC_GROUP *group,
1494e1051a39Sopenharmony_ci                                  EC_POINT *r, EC_POINT *s,
1495e1051a39Sopenharmony_ci                                  EC_POINT *p, BN_CTX *ctx)
1496e1051a39Sopenharmony_ci{
1497e1051a39Sopenharmony_ci    BIGNUM *t1, *t2, *t3, *t4, *t5 = NULL;
1498e1051a39Sopenharmony_ci
1499e1051a39Sopenharmony_ci    t1 = s->Z;
1500e1051a39Sopenharmony_ci    t2 = r->Z;
1501e1051a39Sopenharmony_ci    t3 = s->X;
1502e1051a39Sopenharmony_ci    t4 = r->X;
1503e1051a39Sopenharmony_ci    t5 = s->Y;
1504e1051a39Sopenharmony_ci
1505e1051a39Sopenharmony_ci    if (!p->Z_is_one /* r := 2p */
1506e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, t3, p->X, ctx)
1507e1051a39Sopenharmony_ci        || !BN_mod_sub_quick(t4, t3, group->a, group->field)
1508e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, t4, t4, ctx)
1509e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t5, p->X, group->b, ctx)
1510e1051a39Sopenharmony_ci        || !BN_mod_lshift_quick(t5, t5, 3, group->field)
1511e1051a39Sopenharmony_ci        /* r->X coord output */
1512e1051a39Sopenharmony_ci        || !BN_mod_sub_quick(r->X, t4, t5, group->field)
1513e1051a39Sopenharmony_ci        || !BN_mod_add_quick(t1, t3, group->a, group->field)
1514e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t2, p->X, t1, ctx)
1515e1051a39Sopenharmony_ci        || !BN_mod_add_quick(t2, group->b, t2, group->field)
1516e1051a39Sopenharmony_ci        /* r->Z coord output */
1517e1051a39Sopenharmony_ci        || !BN_mod_lshift_quick(r->Z, t2, 2, group->field))
1518e1051a39Sopenharmony_ci        return 0;
1519e1051a39Sopenharmony_ci
1520e1051a39Sopenharmony_ci    /* make sure lambda (r->Y here for storage) is not zero */
1521e1051a39Sopenharmony_ci    do {
1522e1051a39Sopenharmony_ci        if (!BN_priv_rand_range_ex(r->Y, group->field, 0, ctx))
1523e1051a39Sopenharmony_ci            return 0;
1524e1051a39Sopenharmony_ci    } while (BN_is_zero(r->Y));
1525e1051a39Sopenharmony_ci
1526e1051a39Sopenharmony_ci    /* make sure lambda (s->Z here for storage) is not zero */
1527e1051a39Sopenharmony_ci    do {
1528e1051a39Sopenharmony_ci        if (!BN_priv_rand_range_ex(s->Z, group->field, 0, ctx))
1529e1051a39Sopenharmony_ci            return 0;
1530e1051a39Sopenharmony_ci    } while (BN_is_zero(s->Z));
1531e1051a39Sopenharmony_ci
1532e1051a39Sopenharmony_ci    /* if field_encode defined convert between representations */
1533e1051a39Sopenharmony_ci    if (group->meth->field_encode != NULL
1534e1051a39Sopenharmony_ci        && (!group->meth->field_encode(group, r->Y, r->Y, ctx)
1535e1051a39Sopenharmony_ci            || !group->meth->field_encode(group, s->Z, s->Z, ctx)))
1536e1051a39Sopenharmony_ci        return 0;
1537e1051a39Sopenharmony_ci
1538e1051a39Sopenharmony_ci    /* blind r and s independently */
1539e1051a39Sopenharmony_ci    if (!group->meth->field_mul(group, r->Z, r->Z, r->Y, ctx)
1540e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, r->X, r->X, r->Y, ctx)
1541e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, s->X, p->X, s->Z, ctx)) /* s := p */
1542e1051a39Sopenharmony_ci        return 0;
1543e1051a39Sopenharmony_ci
1544e1051a39Sopenharmony_ci    r->Z_is_one = 0;
1545e1051a39Sopenharmony_ci    s->Z_is_one = 0;
1546e1051a39Sopenharmony_ci
1547e1051a39Sopenharmony_ci    return 1;
1548e1051a39Sopenharmony_ci}
1549e1051a39Sopenharmony_ci
1550e1051a39Sopenharmony_ci/*-
1551e1051a39Sopenharmony_ci * Input:
1552e1051a39Sopenharmony_ci * - s, r: projective (homogeneous) coordinates
1553e1051a39Sopenharmony_ci * - p: affine coordinates
1554e1051a39Sopenharmony_ci *
1555e1051a39Sopenharmony_ci * Output:
1556e1051a39Sopenharmony_ci * - s := r + s, r := 2r: projective (homogeneous) coordinates
1557e1051a39Sopenharmony_ci *
1558e1051a39Sopenharmony_ci * Differential addition-and-doubling using Eq. (9) and (10) from Izu-Takagi
1559e1051a39Sopenharmony_ci * "A fast parallel elliptic curve multiplication resistant against side channel
1560e1051a39Sopenharmony_ci * attacks", as described at
1561e1051a39Sopenharmony_ci * https://hyperelliptic.org/EFD/g1p/auto-shortw-xz.html#ladder-mladd-2002-it-4
1562e1051a39Sopenharmony_ci */
1563e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_ladder_step(const EC_GROUP *group,
1564e1051a39Sopenharmony_ci                                   EC_POINT *r, EC_POINT *s,
1565e1051a39Sopenharmony_ci                                   EC_POINT *p, BN_CTX *ctx)
1566e1051a39Sopenharmony_ci{
1567e1051a39Sopenharmony_ci    int ret = 0;
1568e1051a39Sopenharmony_ci    BIGNUM *t0, *t1, *t2, *t3, *t4, *t5, *t6 = NULL;
1569e1051a39Sopenharmony_ci
1570e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
1571e1051a39Sopenharmony_ci    t0 = BN_CTX_get(ctx);
1572e1051a39Sopenharmony_ci    t1 = BN_CTX_get(ctx);
1573e1051a39Sopenharmony_ci    t2 = BN_CTX_get(ctx);
1574e1051a39Sopenharmony_ci    t3 = BN_CTX_get(ctx);
1575e1051a39Sopenharmony_ci    t4 = BN_CTX_get(ctx);
1576e1051a39Sopenharmony_ci    t5 = BN_CTX_get(ctx);
1577e1051a39Sopenharmony_ci    t6 = BN_CTX_get(ctx);
1578e1051a39Sopenharmony_ci
1579e1051a39Sopenharmony_ci    if (t6 == NULL
1580e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t6, r->X, s->X, ctx)
1581e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t0, r->Z, s->Z, ctx)
1582e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t4, r->X, s->Z, ctx)
1583e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t3, r->Z, s->X, ctx)
1584e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t5, group->a, t0, ctx)
1585e1051a39Sopenharmony_ci        || !BN_mod_add_quick(t5, t6, t5, group->field)
1586e1051a39Sopenharmony_ci        || !BN_mod_add_quick(t6, t3, t4, group->field)
1587e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t5, t6, t5, ctx)
1588e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, t0, t0, ctx)
1589e1051a39Sopenharmony_ci        || !BN_mod_lshift_quick(t2, group->b, 2, group->field)
1590e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t0, t2, t0, ctx)
1591e1051a39Sopenharmony_ci        || !BN_mod_lshift1_quick(t5, t5, group->field)
1592e1051a39Sopenharmony_ci        || !BN_mod_sub_quick(t3, t4, t3, group->field)
1593e1051a39Sopenharmony_ci        /* s->Z coord output */
1594e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, s->Z, t3, ctx)
1595e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t4, s->Z, p->X, ctx)
1596e1051a39Sopenharmony_ci        || !BN_mod_add_quick(t0, t0, t5, group->field)
1597e1051a39Sopenharmony_ci        /* s->X coord output */
1598e1051a39Sopenharmony_ci        || !BN_mod_sub_quick(s->X, t0, t4, group->field)
1599e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, t4, r->X, ctx)
1600e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, t5, r->Z, ctx)
1601e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t6, t5, group->a, ctx)
1602e1051a39Sopenharmony_ci        || !BN_mod_add_quick(t1, r->X, r->Z, group->field)
1603e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, t1, t1, ctx)
1604e1051a39Sopenharmony_ci        || !BN_mod_sub_quick(t1, t1, t4, group->field)
1605e1051a39Sopenharmony_ci        || !BN_mod_sub_quick(t1, t1, t5, group->field)
1606e1051a39Sopenharmony_ci        || !BN_mod_sub_quick(t3, t4, t6, group->field)
1607e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, t3, t3, ctx)
1608e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t0, t5, t1, ctx)
1609e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t0, t2, t0, ctx)
1610e1051a39Sopenharmony_ci        /* r->X coord output */
1611e1051a39Sopenharmony_ci        || !BN_mod_sub_quick(r->X, t3, t0, group->field)
1612e1051a39Sopenharmony_ci        || !BN_mod_add_quick(t3, t4, t6, group->field)
1613e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, t4, t5, ctx)
1614e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t4, t4, t2, ctx)
1615e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t1, t1, t3, ctx)
1616e1051a39Sopenharmony_ci        || !BN_mod_lshift1_quick(t1, t1, group->field)
1617e1051a39Sopenharmony_ci        /* r->Z coord output */
1618e1051a39Sopenharmony_ci        || !BN_mod_add_quick(r->Z, t4, t1, group->field))
1619e1051a39Sopenharmony_ci        goto err;
1620e1051a39Sopenharmony_ci
1621e1051a39Sopenharmony_ci    ret = 1;
1622e1051a39Sopenharmony_ci
1623e1051a39Sopenharmony_ci err:
1624e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
1625e1051a39Sopenharmony_ci    return ret;
1626e1051a39Sopenharmony_ci}
1627e1051a39Sopenharmony_ci
1628e1051a39Sopenharmony_ci/*-
1629e1051a39Sopenharmony_ci * Input:
1630e1051a39Sopenharmony_ci * - s, r: projective (homogeneous) coordinates
1631e1051a39Sopenharmony_ci * - p: affine coordinates
1632e1051a39Sopenharmony_ci *
1633e1051a39Sopenharmony_ci * Output:
1634e1051a39Sopenharmony_ci * - r := (x,y): affine coordinates
1635e1051a39Sopenharmony_ci *
1636e1051a39Sopenharmony_ci * Recovers the y-coordinate of r using Eq. (8) from Brier-Joye, "Weierstrass
1637e1051a39Sopenharmony_ci * Elliptic Curves and Side-Channel Attacks", modified to work in mixed
1638e1051a39Sopenharmony_ci * projective coords, i.e. p is affine and (r,s) in projective (homogeneous)
1639e1051a39Sopenharmony_ci * coords, and return r in affine coordinates.
1640e1051a39Sopenharmony_ci *
1641e1051a39Sopenharmony_ci * X4 = two*Y1*X2*Z3*Z2;
1642e1051a39Sopenharmony_ci * Y4 = two*b*Z3*SQR(Z2) + Z3*(a*Z2+X1*X2)*(X1*Z2+X2) - X3*SQR(X1*Z2-X2);
1643e1051a39Sopenharmony_ci * Z4 = two*Y1*Z3*SQR(Z2);
1644e1051a39Sopenharmony_ci *
1645e1051a39Sopenharmony_ci * Z4 != 0 because:
1646e1051a39Sopenharmony_ci *  - Z2==0 implies r is at infinity (handled by the BN_is_zero(r->Z) branch);
1647e1051a39Sopenharmony_ci *  - Z3==0 implies s is at infinity (handled by the BN_is_zero(s->Z) branch);
1648e1051a39Sopenharmony_ci *  - Y1==0 implies p has order 2, so either r or s are infinity and handled by
1649e1051a39Sopenharmony_ci *    one of the BN_is_zero(...) branches.
1650e1051a39Sopenharmony_ci */
1651e1051a39Sopenharmony_ciint ossl_ec_GFp_simple_ladder_post(const EC_GROUP *group,
1652e1051a39Sopenharmony_ci                                   EC_POINT *r, EC_POINT *s,
1653e1051a39Sopenharmony_ci                                   EC_POINT *p, BN_CTX *ctx)
1654e1051a39Sopenharmony_ci{
1655e1051a39Sopenharmony_ci    int ret = 0;
1656e1051a39Sopenharmony_ci    BIGNUM *t0, *t1, *t2, *t3, *t4, *t5, *t6 = NULL;
1657e1051a39Sopenharmony_ci
1658e1051a39Sopenharmony_ci    if (BN_is_zero(r->Z))
1659e1051a39Sopenharmony_ci        return EC_POINT_set_to_infinity(group, r);
1660e1051a39Sopenharmony_ci
1661e1051a39Sopenharmony_ci    if (BN_is_zero(s->Z)) {
1662e1051a39Sopenharmony_ci        if (!EC_POINT_copy(r, p)
1663e1051a39Sopenharmony_ci            || !EC_POINT_invert(group, r, ctx))
1664e1051a39Sopenharmony_ci            return 0;
1665e1051a39Sopenharmony_ci        return 1;
1666e1051a39Sopenharmony_ci    }
1667e1051a39Sopenharmony_ci
1668e1051a39Sopenharmony_ci    BN_CTX_start(ctx);
1669e1051a39Sopenharmony_ci    t0 = BN_CTX_get(ctx);
1670e1051a39Sopenharmony_ci    t1 = BN_CTX_get(ctx);
1671e1051a39Sopenharmony_ci    t2 = BN_CTX_get(ctx);
1672e1051a39Sopenharmony_ci    t3 = BN_CTX_get(ctx);
1673e1051a39Sopenharmony_ci    t4 = BN_CTX_get(ctx);
1674e1051a39Sopenharmony_ci    t5 = BN_CTX_get(ctx);
1675e1051a39Sopenharmony_ci    t6 = BN_CTX_get(ctx);
1676e1051a39Sopenharmony_ci
1677e1051a39Sopenharmony_ci    if (t6 == NULL
1678e1051a39Sopenharmony_ci        || !BN_mod_lshift1_quick(t4, p->Y, group->field)
1679e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t6, r->X, t4, ctx)
1680e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t6, s->Z, t6, ctx)
1681e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t5, r->Z, t6, ctx)
1682e1051a39Sopenharmony_ci        || !BN_mod_lshift1_quick(t1, group->b, group->field)
1683e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t1, s->Z, t1, ctx)
1684e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, t3, r->Z, ctx)
1685e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t2, t3, t1, ctx)
1686e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t6, r->Z, group->a, ctx)
1687e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t1, p->X, r->X, ctx)
1688e1051a39Sopenharmony_ci        || !BN_mod_add_quick(t1, t1, t6, group->field)
1689e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t1, s->Z, t1, ctx)
1690e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t0, p->X, r->Z, ctx)
1691e1051a39Sopenharmony_ci        || !BN_mod_add_quick(t6, r->X, t0, group->field)
1692e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t6, t6, t1, ctx)
1693e1051a39Sopenharmony_ci        || !BN_mod_add_quick(t6, t6, t2, group->field)
1694e1051a39Sopenharmony_ci        || !BN_mod_sub_quick(t0, t0, r->X, group->field)
1695e1051a39Sopenharmony_ci        || !group->meth->field_sqr(group, t0, t0, ctx)
1696e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t0, t0, s->X, ctx)
1697e1051a39Sopenharmony_ci        || !BN_mod_sub_quick(t0, t6, t0, group->field)
1698e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t1, s->Z, t4, ctx)
1699e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, t1, t3, t1, ctx)
1700e1051a39Sopenharmony_ci        || (group->meth->field_decode != NULL
1701e1051a39Sopenharmony_ci            && !group->meth->field_decode(group, t1, t1, ctx))
1702e1051a39Sopenharmony_ci        || !group->meth->field_inv(group, t1, t1, ctx)
1703e1051a39Sopenharmony_ci        || (group->meth->field_encode != NULL
1704e1051a39Sopenharmony_ci            && !group->meth->field_encode(group, t1, t1, ctx))
1705e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, r->X, t5, t1, ctx)
1706e1051a39Sopenharmony_ci        || !group->meth->field_mul(group, r->Y, t0, t1, ctx))
1707e1051a39Sopenharmony_ci        goto err;
1708e1051a39Sopenharmony_ci
1709e1051a39Sopenharmony_ci    if (group->meth->field_set_to_one != NULL) {
1710e1051a39Sopenharmony_ci        if (!group->meth->field_set_to_one(group, r->Z, ctx))
1711e1051a39Sopenharmony_ci            goto err;
1712e1051a39Sopenharmony_ci    } else {
1713e1051a39Sopenharmony_ci        if (!BN_one(r->Z))
1714e1051a39Sopenharmony_ci            goto err;
1715e1051a39Sopenharmony_ci    }
1716e1051a39Sopenharmony_ci
1717e1051a39Sopenharmony_ci    r->Z_is_one = 1;
1718e1051a39Sopenharmony_ci    ret = 1;
1719e1051a39Sopenharmony_ci
1720e1051a39Sopenharmony_ci err:
1721e1051a39Sopenharmony_ci    BN_CTX_end(ctx);
1722e1051a39Sopenharmony_ci    return ret;
1723e1051a39Sopenharmony_ci}
1724