1109998Smarkm/* crypto/ec/ecp_smpl.c */
2296341Sdelphij/*
3296341Sdelphij * Includes code written by Lenka Fibikova <fibikova@exp-math.uni-essen.de>
4296341Sdelphij * for the OpenSSL project. Includes code written by Bodo Moeller for the
5296341Sdelphij * OpenSSL project.
6296341Sdelphij */
7109998Smarkm/* ====================================================================
8160814Ssimon * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
9109998Smarkm *
10109998Smarkm * Redistribution and use in source and binary forms, with or without
11109998Smarkm * modification, are permitted provided that the following conditions
12109998Smarkm * are met:
13109998Smarkm *
14109998Smarkm * 1. Redistributions of source code must retain the above copyright
15296341Sdelphij *    notice, this list of conditions and the following disclaimer.
16109998Smarkm *
17109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright
18109998Smarkm *    notice, this list of conditions and the following disclaimer in
19109998Smarkm *    the documentation and/or other materials provided with the
20109998Smarkm *    distribution.
21109998Smarkm *
22109998Smarkm * 3. All advertising materials mentioning features or use of this
23109998Smarkm *    software must display the following acknowledgment:
24109998Smarkm *    "This product includes software developed by the OpenSSL Project
25109998Smarkm *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
26109998Smarkm *
27109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
28109998Smarkm *    endorse or promote products derived from this software without
29109998Smarkm *    prior written permission. For written permission, please contact
30109998Smarkm *    openssl-core@openssl.org.
31109998Smarkm *
32109998Smarkm * 5. Products derived from this software may not be called "OpenSSL"
33109998Smarkm *    nor may "OpenSSL" appear in their names without prior written
34109998Smarkm *    permission of the OpenSSL Project.
35109998Smarkm *
36109998Smarkm * 6. Redistributions of any form whatsoever must retain the following
37109998Smarkm *    acknowledgment:
38109998Smarkm *    "This product includes software developed by the OpenSSL Project
39109998Smarkm *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
40109998Smarkm *
41109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
42109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
44109998Smarkm * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
45109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
48109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
50109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
52109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE.
53109998Smarkm * ====================================================================
54109998Smarkm *
55109998Smarkm * This product includes cryptographic software written by Eric Young
56109998Smarkm * (eay@cryptsoft.com).  This product includes software written by Tim
57109998Smarkm * Hudson (tjh@cryptsoft.com).
58109998Smarkm *
59109998Smarkm */
60160814Ssimon/* ====================================================================
61160814Ssimon * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
62160814Ssimon * Portions of this software developed by SUN MICROSYSTEMS, INC.,
63160814Ssimon * and contributed to the OpenSSL project.
64160814Ssimon */
65109998Smarkm
66109998Smarkm#include <openssl/err.h>
67160814Ssimon#include <openssl/symhacks.h>
68109998Smarkm
69238405Sjkim#ifdef OPENSSL_FIPS
70296341Sdelphij# include <openssl/fips.h>
71238405Sjkim#endif
72238405Sjkim
73109998Smarkm#include "ec_lcl.h"
74109998Smarkm
75109998Smarkmconst EC_METHOD *EC_GFp_simple_method(void)
76296341Sdelphij{
77296341Sdelphij    static const EC_METHOD ret = {
78296341Sdelphij        EC_FLAGS_DEFAULT_OCT,
79296341Sdelphij        NID_X9_62_prime_field,
80296341Sdelphij        ec_GFp_simple_group_init,
81296341Sdelphij        ec_GFp_simple_group_finish,
82296341Sdelphij        ec_GFp_simple_group_clear_finish,
83296341Sdelphij        ec_GFp_simple_group_copy,
84296341Sdelphij        ec_GFp_simple_group_set_curve,
85296341Sdelphij        ec_GFp_simple_group_get_curve,
86296341Sdelphij        ec_GFp_simple_group_get_degree,
87296341Sdelphij        ec_GFp_simple_group_check_discriminant,
88296341Sdelphij        ec_GFp_simple_point_init,
89296341Sdelphij        ec_GFp_simple_point_finish,
90296341Sdelphij        ec_GFp_simple_point_clear_finish,
91296341Sdelphij        ec_GFp_simple_point_copy,
92296341Sdelphij        ec_GFp_simple_point_set_to_infinity,
93296341Sdelphij        ec_GFp_simple_set_Jprojective_coordinates_GFp,
94296341Sdelphij        ec_GFp_simple_get_Jprojective_coordinates_GFp,
95296341Sdelphij        ec_GFp_simple_point_set_affine_coordinates,
96296341Sdelphij        ec_GFp_simple_point_get_affine_coordinates,
97296341Sdelphij        0, 0, 0,
98296341Sdelphij        ec_GFp_simple_add,
99296341Sdelphij        ec_GFp_simple_dbl,
100296341Sdelphij        ec_GFp_simple_invert,
101296341Sdelphij        ec_GFp_simple_is_at_infinity,
102296341Sdelphij        ec_GFp_simple_is_on_curve,
103296341Sdelphij        ec_GFp_simple_cmp,
104296341Sdelphij        ec_GFp_simple_make_affine,
105296341Sdelphij        ec_GFp_simple_points_make_affine,
106296341Sdelphij        0 /* mul */ ,
107296341Sdelphij        0 /* precompute_mult */ ,
108296341Sdelphij        0 /* have_precompute_mult */ ,
109296341Sdelphij        ec_GFp_simple_field_mul,
110296341Sdelphij        ec_GFp_simple_field_sqr,
111296341Sdelphij        0 /* field_div */ ,
112296341Sdelphij        0 /* field_encode */ ,
113296341Sdelphij        0 /* field_decode */ ,
114296341Sdelphij        0                       /* field_set_to_one */
115296341Sdelphij    };
116109998Smarkm
117273399Sdelphij#ifdef OPENSSL_FIPS
118296341Sdelphij    if (FIPS_mode())
119296341Sdelphij        return fips_ec_gfp_simple_method();
120273399Sdelphij#endif
121273399Sdelphij
122296341Sdelphij    return &ret;
123296341Sdelphij}
124109998Smarkm
125296341Sdelphij/*
126296341Sdelphij * Most method functions in this file are designed to work with
127160814Ssimon * non-trivial representations of field elements if necessary
128160814Ssimon * (see ecp_mont.c): while standard modular addition and subtraction
129160814Ssimon * are used, the field_mul and field_sqr methods will be used for
130160814Ssimon * multiplication, and field_encode and field_decode (if defined)
131160814Ssimon * will be used for converting between representations.
132296341Sdelphij *
133160814Ssimon * Functions ec_GFp_simple_points_make_affine() and
134160814Ssimon * ec_GFp_simple_point_get_affine_coordinates() specifically assume
135160814Ssimon * that if a non-trivial representation is used, it is a Montgomery
136160814Ssimon * representation (i.e. 'encoding' means multiplying by some factor R).
137160814Ssimon */
138160814Ssimon
139109998Smarkmint ec_GFp_simple_group_init(EC_GROUP *group)
140296341Sdelphij{
141296341Sdelphij    BN_init(&group->field);
142296341Sdelphij    BN_init(&group->a);
143296341Sdelphij    BN_init(&group->b);
144296341Sdelphij    group->a_is_minus3 = 0;
145296341Sdelphij    return 1;
146296341Sdelphij}
147109998Smarkm
148109998Smarkmvoid ec_GFp_simple_group_finish(EC_GROUP *group)
149296341Sdelphij{
150296341Sdelphij    BN_free(&group->field);
151296341Sdelphij    BN_free(&group->a);
152296341Sdelphij    BN_free(&group->b);
153296341Sdelphij}
154109998Smarkm
155109998Smarkmvoid ec_GFp_simple_group_clear_finish(EC_GROUP *group)
156296341Sdelphij{
157296341Sdelphij    BN_clear_free(&group->field);
158296341Sdelphij    BN_clear_free(&group->a);
159296341Sdelphij    BN_clear_free(&group->b);
160296341Sdelphij}
161109998Smarkm
162109998Smarkmint ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src)
163296341Sdelphij{
164296341Sdelphij    if (!BN_copy(&dest->field, &src->field))
165296341Sdelphij        return 0;
166296341Sdelphij    if (!BN_copy(&dest->a, &src->a))
167296341Sdelphij        return 0;
168296341Sdelphij    if (!BN_copy(&dest->b, &src->b))
169296341Sdelphij        return 0;
170109998Smarkm
171296341Sdelphij    dest->a_is_minus3 = src->a_is_minus3;
172109998Smarkm
173296341Sdelphij    return 1;
174296341Sdelphij}
175109998Smarkm
176160814Ssimonint ec_GFp_simple_group_set_curve(EC_GROUP *group,
177296341Sdelphij                                  const BIGNUM *p, const BIGNUM *a,
178296341Sdelphij                                  const BIGNUM *b, BN_CTX *ctx)
179296341Sdelphij{
180296341Sdelphij    int ret = 0;
181296341Sdelphij    BN_CTX *new_ctx = NULL;
182296341Sdelphij    BIGNUM *tmp_a;
183109998Smarkm
184296341Sdelphij    /* p must be a prime > 3 */
185296341Sdelphij    if (BN_num_bits(p) <= 2 || !BN_is_odd(p)) {
186296341Sdelphij        ECerr(EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE, EC_R_INVALID_FIELD);
187296341Sdelphij        return 0;
188296341Sdelphij    }
189109998Smarkm
190296341Sdelphij    if (ctx == NULL) {
191296341Sdelphij        ctx = new_ctx = BN_CTX_new();
192296341Sdelphij        if (ctx == NULL)
193296341Sdelphij            return 0;
194296341Sdelphij    }
195109998Smarkm
196296341Sdelphij    BN_CTX_start(ctx);
197296341Sdelphij    tmp_a = BN_CTX_get(ctx);
198296341Sdelphij    if (tmp_a == NULL)
199296341Sdelphij        goto err;
200109998Smarkm
201296341Sdelphij    /* group->field */
202296341Sdelphij    if (!BN_copy(&group->field, p))
203296341Sdelphij        goto err;
204296341Sdelphij    BN_set_negative(&group->field, 0);
205109998Smarkm
206296341Sdelphij    /* group->a */
207296341Sdelphij    if (!BN_nnmod(tmp_a, a, p, ctx))
208296341Sdelphij        goto err;
209296341Sdelphij    if (group->meth->field_encode) {
210296341Sdelphij        if (!group->meth->field_encode(group, &group->a, tmp_a, ctx))
211296341Sdelphij            goto err;
212296341Sdelphij    } else if (!BN_copy(&group->a, tmp_a))
213296341Sdelphij        goto err;
214109998Smarkm
215296341Sdelphij    /* group->b */
216296341Sdelphij    if (!BN_nnmod(&group->b, b, p, ctx))
217296341Sdelphij        goto err;
218296341Sdelphij    if (group->meth->field_encode)
219296341Sdelphij        if (!group->meth->field_encode(group, &group->b, &group->b, ctx))
220296341Sdelphij            goto err;
221296341Sdelphij
222296341Sdelphij    /* group->a_is_minus3 */
223296341Sdelphij    if (!BN_add_word(tmp_a, 3))
224296341Sdelphij        goto err;
225296341Sdelphij    group->a_is_minus3 = (0 == BN_cmp(tmp_a, &group->field));
226296341Sdelphij
227296341Sdelphij    ret = 1;
228296341Sdelphij
229109998Smarkm err:
230296341Sdelphij    BN_CTX_end(ctx);
231296341Sdelphij    if (new_ctx != NULL)
232296341Sdelphij        BN_CTX_free(new_ctx);
233296341Sdelphij    return ret;
234296341Sdelphij}
235109998Smarkm
236296341Sdelphijint ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a,
237296341Sdelphij                                  BIGNUM *b, BN_CTX *ctx)
238296341Sdelphij{
239296341Sdelphij    int ret = 0;
240296341Sdelphij    BN_CTX *new_ctx = NULL;
241109998Smarkm
242296341Sdelphij    if (p != NULL) {
243296341Sdelphij        if (!BN_copy(p, &group->field))
244296341Sdelphij            return 0;
245296341Sdelphij    }
246109998Smarkm
247296341Sdelphij    if (a != NULL || b != NULL) {
248296341Sdelphij        if (group->meth->field_decode) {
249296341Sdelphij            if (ctx == NULL) {
250296341Sdelphij                ctx = new_ctx = BN_CTX_new();
251296341Sdelphij                if (ctx == NULL)
252296341Sdelphij                    return 0;
253296341Sdelphij            }
254296341Sdelphij            if (a != NULL) {
255296341Sdelphij                if (!group->meth->field_decode(group, a, &group->a, ctx))
256296341Sdelphij                    goto err;
257296341Sdelphij            }
258296341Sdelphij            if (b != NULL) {
259296341Sdelphij                if (!group->meth->field_decode(group, b, &group->b, ctx))
260296341Sdelphij                    goto err;
261296341Sdelphij            }
262296341Sdelphij        } else {
263296341Sdelphij            if (a != NULL) {
264296341Sdelphij                if (!BN_copy(a, &group->a))
265296341Sdelphij                    goto err;
266296341Sdelphij            }
267296341Sdelphij            if (b != NULL) {
268296341Sdelphij                if (!BN_copy(b, &group->b))
269296341Sdelphij                    goto err;
270296341Sdelphij            }
271296341Sdelphij        }
272296341Sdelphij    }
273296341Sdelphij
274296341Sdelphij    ret = 1;
275296341Sdelphij
276109998Smarkm err:
277296341Sdelphij    if (new_ctx)
278296341Sdelphij        BN_CTX_free(new_ctx);
279296341Sdelphij    return ret;
280296341Sdelphij}
281109998Smarkm
282160814Ssimonint ec_GFp_simple_group_get_degree(const EC_GROUP *group)
283296341Sdelphij{
284296341Sdelphij    return BN_num_bits(&group->field);
285296341Sdelphij}
286109998Smarkm
287160814Ssimonint ec_GFp_simple_group_check_discriminant(const EC_GROUP *group, BN_CTX *ctx)
288296341Sdelphij{
289296341Sdelphij    int ret = 0;
290296341Sdelphij    BIGNUM *a, *b, *order, *tmp_1, *tmp_2;
291296341Sdelphij    const BIGNUM *p = &group->field;
292296341Sdelphij    BN_CTX *new_ctx = NULL;
293160814Ssimon
294296341Sdelphij    if (ctx == NULL) {
295296341Sdelphij        ctx = new_ctx = BN_CTX_new();
296296341Sdelphij        if (ctx == NULL) {
297296341Sdelphij            ECerr(EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT,
298296341Sdelphij                  ERR_R_MALLOC_FAILURE);
299296341Sdelphij            goto err;
300296341Sdelphij        }
301296341Sdelphij    }
302296341Sdelphij    BN_CTX_start(ctx);
303296341Sdelphij    a = BN_CTX_get(ctx);
304296341Sdelphij    b = BN_CTX_get(ctx);
305296341Sdelphij    tmp_1 = BN_CTX_get(ctx);
306296341Sdelphij    tmp_2 = BN_CTX_get(ctx);
307296341Sdelphij    order = BN_CTX_get(ctx);
308296341Sdelphij    if (order == NULL)
309296341Sdelphij        goto err;
310109998Smarkm
311296341Sdelphij    if (group->meth->field_decode) {
312296341Sdelphij        if (!group->meth->field_decode(group, a, &group->a, ctx))
313296341Sdelphij            goto err;
314296341Sdelphij        if (!group->meth->field_decode(group, b, &group->b, ctx))
315296341Sdelphij            goto err;
316296341Sdelphij    } else {
317296341Sdelphij        if (!BN_copy(a, &group->a))
318296341Sdelphij            goto err;
319296341Sdelphij        if (!BN_copy(b, &group->b))
320296341Sdelphij            goto err;
321296341Sdelphij    }
322109998Smarkm
323296341Sdelphij    /*-
324296341Sdelphij     * check the discriminant:
325296341Sdelphij     * y^2 = x^3 + a*x + b is an elliptic curve <=> 4*a^3 + 27*b^2 != 0 (mod p)
326296341Sdelphij     * 0 =< a, b < p
327296341Sdelphij     */
328296341Sdelphij    if (BN_is_zero(a)) {
329296341Sdelphij        if (BN_is_zero(b))
330296341Sdelphij            goto err;
331296341Sdelphij    } else if (!BN_is_zero(b)) {
332296341Sdelphij        if (!BN_mod_sqr(tmp_1, a, p, ctx))
333296341Sdelphij            goto err;
334296341Sdelphij        if (!BN_mod_mul(tmp_2, tmp_1, a, p, ctx))
335296341Sdelphij            goto err;
336296341Sdelphij        if (!BN_lshift(tmp_1, tmp_2, 2))
337296341Sdelphij            goto err;
338296341Sdelphij        /* tmp_1 = 4*a^3 */
339109998Smarkm
340296341Sdelphij        if (!BN_mod_sqr(tmp_2, b, p, ctx))
341296341Sdelphij            goto err;
342296341Sdelphij        if (!BN_mul_word(tmp_2, 27))
343296341Sdelphij            goto err;
344296341Sdelphij        /* tmp_2 = 27*b^2 */
345109998Smarkm
346296341Sdelphij        if (!BN_mod_add(a, tmp_1, tmp_2, p, ctx))
347296341Sdelphij            goto err;
348296341Sdelphij        if (BN_is_zero(a))
349296341Sdelphij            goto err;
350296341Sdelphij    }
351296341Sdelphij    ret = 1;
352109998Smarkm
353296341Sdelphij err:
354296341Sdelphij    if (ctx != NULL)
355296341Sdelphij        BN_CTX_end(ctx);
356296341Sdelphij    if (new_ctx != NULL)
357296341Sdelphij        BN_CTX_free(new_ctx);
358296341Sdelphij    return ret;
359296341Sdelphij}
360109998Smarkm
361109998Smarkmint ec_GFp_simple_point_init(EC_POINT *point)
362296341Sdelphij{
363296341Sdelphij    BN_init(&point->X);
364296341Sdelphij    BN_init(&point->Y);
365296341Sdelphij    BN_init(&point->Z);
366296341Sdelphij    point->Z_is_one = 0;
367109998Smarkm
368296341Sdelphij    return 1;
369296341Sdelphij}
370109998Smarkm
371109998Smarkmvoid ec_GFp_simple_point_finish(EC_POINT *point)
372296341Sdelphij{
373296341Sdelphij    BN_free(&point->X);
374296341Sdelphij    BN_free(&point->Y);
375296341Sdelphij    BN_free(&point->Z);
376296341Sdelphij}
377109998Smarkm
378109998Smarkmvoid ec_GFp_simple_point_clear_finish(EC_POINT *point)
379296341Sdelphij{
380296341Sdelphij    BN_clear_free(&point->X);
381296341Sdelphij    BN_clear_free(&point->Y);
382296341Sdelphij    BN_clear_free(&point->Z);
383296341Sdelphij    point->Z_is_one = 0;
384296341Sdelphij}
385109998Smarkm
386109998Smarkmint ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src)
387296341Sdelphij{
388296341Sdelphij    if (!BN_copy(&dest->X, &src->X))
389296341Sdelphij        return 0;
390296341Sdelphij    if (!BN_copy(&dest->Y, &src->Y))
391296341Sdelphij        return 0;
392296341Sdelphij    if (!BN_copy(&dest->Z, &src->Z))
393296341Sdelphij        return 0;
394296341Sdelphij    dest->Z_is_one = src->Z_is_one;
395109998Smarkm
396296341Sdelphij    return 1;
397296341Sdelphij}
398109998Smarkm
399296341Sdelphijint ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group,
400296341Sdelphij                                        EC_POINT *point)
401296341Sdelphij{
402296341Sdelphij    point->Z_is_one = 0;
403296341Sdelphij    BN_zero(&point->Z);
404296341Sdelphij    return 1;
405296341Sdelphij}
406109998Smarkm
407296341Sdelphijint ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *group,
408296341Sdelphij                                                  EC_POINT *point,
409296341Sdelphij                                                  const BIGNUM *x,
410296341Sdelphij                                                  const BIGNUM *y,
411296341Sdelphij                                                  const BIGNUM *z,
412296341Sdelphij                                                  BN_CTX *ctx)
413296341Sdelphij{
414296341Sdelphij    BN_CTX *new_ctx = NULL;
415296341Sdelphij    int ret = 0;
416109998Smarkm
417296341Sdelphij    if (ctx == NULL) {
418296341Sdelphij        ctx = new_ctx = BN_CTX_new();
419296341Sdelphij        if (ctx == NULL)
420296341Sdelphij            return 0;
421296341Sdelphij    }
422109998Smarkm
423296341Sdelphij    if (x != NULL) {
424296341Sdelphij        if (!BN_nnmod(&point->X, x, &group->field, ctx))
425296341Sdelphij            goto err;
426296341Sdelphij        if (group->meth->field_encode) {
427296341Sdelphij            if (!group->meth->field_encode(group, &point->X, &point->X, ctx))
428296341Sdelphij                goto err;
429296341Sdelphij        }
430296341Sdelphij    }
431109998Smarkm
432296341Sdelphij    if (y != NULL) {
433296341Sdelphij        if (!BN_nnmod(&point->Y, y, &group->field, ctx))
434296341Sdelphij            goto err;
435296341Sdelphij        if (group->meth->field_encode) {
436296341Sdelphij            if (!group->meth->field_encode(group, &point->Y, &point->Y, ctx))
437296341Sdelphij                goto err;
438296341Sdelphij        }
439296341Sdelphij    }
440109998Smarkm
441296341Sdelphij    if (z != NULL) {
442296341Sdelphij        int Z_is_one;
443296341Sdelphij
444296341Sdelphij        if (!BN_nnmod(&point->Z, z, &group->field, ctx))
445296341Sdelphij            goto err;
446296341Sdelphij        Z_is_one = BN_is_one(&point->Z);
447296341Sdelphij        if (group->meth->field_encode) {
448296341Sdelphij            if (Z_is_one && (group->meth->field_set_to_one != 0)) {
449296341Sdelphij                if (!group->meth->field_set_to_one(group, &point->Z, ctx))
450296341Sdelphij                    goto err;
451296341Sdelphij            } else {
452296341Sdelphij                if (!group->
453296341Sdelphij                    meth->field_encode(group, &point->Z, &point->Z, ctx))
454296341Sdelphij                    goto err;
455296341Sdelphij            }
456296341Sdelphij        }
457296341Sdelphij        point->Z_is_one = Z_is_one;
458296341Sdelphij    }
459296341Sdelphij
460296341Sdelphij    ret = 1;
461296341Sdelphij
462109998Smarkm err:
463296341Sdelphij    if (new_ctx != NULL)
464296341Sdelphij        BN_CTX_free(new_ctx);
465296341Sdelphij    return ret;
466296341Sdelphij}
467109998Smarkm
468296341Sdelphijint ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group,
469296341Sdelphij                                                  const EC_POINT *point,
470296341Sdelphij                                                  BIGNUM *x, BIGNUM *y,
471296341Sdelphij                                                  BIGNUM *z, BN_CTX *ctx)
472296341Sdelphij{
473296341Sdelphij    BN_CTX *new_ctx = NULL;
474296341Sdelphij    int ret = 0;
475109998Smarkm
476296341Sdelphij    if (group->meth->field_decode != 0) {
477296341Sdelphij        if (ctx == NULL) {
478296341Sdelphij            ctx = new_ctx = BN_CTX_new();
479296341Sdelphij            if (ctx == NULL)
480296341Sdelphij                return 0;
481296341Sdelphij        }
482109998Smarkm
483296341Sdelphij        if (x != NULL) {
484296341Sdelphij            if (!group->meth->field_decode(group, x, &point->X, ctx))
485296341Sdelphij                goto err;
486296341Sdelphij        }
487296341Sdelphij        if (y != NULL) {
488296341Sdelphij            if (!group->meth->field_decode(group, y, &point->Y, ctx))
489296341Sdelphij                goto err;
490296341Sdelphij        }
491296341Sdelphij        if (z != NULL) {
492296341Sdelphij            if (!group->meth->field_decode(group, z, &point->Z, ctx))
493296341Sdelphij                goto err;
494296341Sdelphij        }
495296341Sdelphij    } else {
496296341Sdelphij        if (x != NULL) {
497296341Sdelphij            if (!BN_copy(x, &point->X))
498296341Sdelphij                goto err;
499296341Sdelphij        }
500296341Sdelphij        if (y != NULL) {
501296341Sdelphij            if (!BN_copy(y, &point->Y))
502296341Sdelphij                goto err;
503296341Sdelphij        }
504296341Sdelphij        if (z != NULL) {
505296341Sdelphij            if (!BN_copy(z, &point->Z))
506296341Sdelphij                goto err;
507296341Sdelphij        }
508296341Sdelphij    }
509109998Smarkm
510296341Sdelphij    ret = 1;
511296341Sdelphij
512109998Smarkm err:
513296341Sdelphij    if (new_ctx != NULL)
514296341Sdelphij        BN_CTX_free(new_ctx);
515296341Sdelphij    return ret;
516296341Sdelphij}
517109998Smarkm
518296341Sdelphijint ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group,
519296341Sdelphij                                               EC_POINT *point,
520296341Sdelphij                                               const BIGNUM *x,
521296341Sdelphij                                               const BIGNUM *y, BN_CTX *ctx)
522296341Sdelphij{
523296341Sdelphij    if (x == NULL || y == NULL) {
524296341Sdelphij        /*
525296341Sdelphij         * unlike for projective coordinates, we do not tolerate this
526296341Sdelphij         */
527296341Sdelphij        ECerr(EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES,
528296341Sdelphij              ERR_R_PASSED_NULL_PARAMETER);
529296341Sdelphij        return 0;
530296341Sdelphij    }
531109998Smarkm
532296341Sdelphij    return EC_POINT_set_Jprojective_coordinates_GFp(group, point, x, y,
533296341Sdelphij                                                    BN_value_one(), ctx);
534296341Sdelphij}
535109998Smarkm
536296341Sdelphijint ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group,
537296341Sdelphij                                               const EC_POINT *point,
538296341Sdelphij                                               BIGNUM *x, BIGNUM *y,
539296341Sdelphij                                               BN_CTX *ctx)
540296341Sdelphij{
541296341Sdelphij    BN_CTX *new_ctx = NULL;
542296341Sdelphij    BIGNUM *Z, *Z_1, *Z_2, *Z_3;
543296341Sdelphij    const BIGNUM *Z_;
544296341Sdelphij    int ret = 0;
545109998Smarkm
546296341Sdelphij    if (EC_POINT_is_at_infinity(group, point)) {
547296341Sdelphij        ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES,
548296341Sdelphij              EC_R_POINT_AT_INFINITY);
549296341Sdelphij        return 0;
550296341Sdelphij    }
551109998Smarkm
552296341Sdelphij    if (ctx == NULL) {
553296341Sdelphij        ctx = new_ctx = BN_CTX_new();
554296341Sdelphij        if (ctx == NULL)
555296341Sdelphij            return 0;
556296341Sdelphij    }
557109998Smarkm
558296341Sdelphij    BN_CTX_start(ctx);
559296341Sdelphij    Z = BN_CTX_get(ctx);
560296341Sdelphij    Z_1 = BN_CTX_get(ctx);
561296341Sdelphij    Z_2 = BN_CTX_get(ctx);
562296341Sdelphij    Z_3 = BN_CTX_get(ctx);
563296341Sdelphij    if (Z_3 == NULL)
564296341Sdelphij        goto err;
565109998Smarkm
566296341Sdelphij    /* transform  (X, Y, Z)  into  (x, y) := (X/Z^2, Y/Z^3) */
567109998Smarkm
568296341Sdelphij    if (group->meth->field_decode) {
569296341Sdelphij        if (!group->meth->field_decode(group, Z, &point->Z, ctx))
570296341Sdelphij            goto err;
571296341Sdelphij        Z_ = Z;
572296341Sdelphij    } else {
573296341Sdelphij        Z_ = &point->Z;
574296341Sdelphij    }
575109998Smarkm
576296341Sdelphij    if (BN_is_one(Z_)) {
577296341Sdelphij        if (group->meth->field_decode) {
578296341Sdelphij            if (x != NULL) {
579296341Sdelphij                if (!group->meth->field_decode(group, x, &point->X, ctx))
580296341Sdelphij                    goto err;
581296341Sdelphij            }
582296341Sdelphij            if (y != NULL) {
583296341Sdelphij                if (!group->meth->field_decode(group, y, &point->Y, ctx))
584296341Sdelphij                    goto err;
585296341Sdelphij            }
586296341Sdelphij        } else {
587296341Sdelphij            if (x != NULL) {
588296341Sdelphij                if (!BN_copy(x, &point->X))
589296341Sdelphij                    goto err;
590296341Sdelphij            }
591296341Sdelphij            if (y != NULL) {
592296341Sdelphij                if (!BN_copy(y, &point->Y))
593296341Sdelphij                    goto err;
594296341Sdelphij            }
595296341Sdelphij        }
596296341Sdelphij    } else {
597296341Sdelphij        if (!BN_mod_inverse(Z_1, Z_, &group->field, ctx)) {
598296341Sdelphij            ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES,
599296341Sdelphij                  ERR_R_BN_LIB);
600296341Sdelphij            goto err;
601296341Sdelphij        }
602109998Smarkm
603296341Sdelphij        if (group->meth->field_encode == 0) {
604296341Sdelphij            /* field_sqr works on standard representation */
605296341Sdelphij            if (!group->meth->field_sqr(group, Z_2, Z_1, ctx))
606296341Sdelphij                goto err;
607296341Sdelphij        } else {
608296341Sdelphij            if (!BN_mod_sqr(Z_2, Z_1, &group->field, ctx))
609296341Sdelphij                goto err;
610296341Sdelphij        }
611160814Ssimon
612296341Sdelphij        if (x != NULL) {
613296341Sdelphij            /*
614296341Sdelphij             * in the Montgomery case, field_mul will cancel out Montgomery
615296341Sdelphij             * factor in X:
616296341Sdelphij             */
617296341Sdelphij            if (!group->meth->field_mul(group, x, &point->X, Z_2, ctx))
618296341Sdelphij                goto err;
619296341Sdelphij        }
620109998Smarkm
621296341Sdelphij        if (y != NULL) {
622296341Sdelphij            if (group->meth->field_encode == 0) {
623296341Sdelphij                /*
624296341Sdelphij                 * field_mul works on standard representation
625296341Sdelphij                 */
626296341Sdelphij                if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx))
627296341Sdelphij                    goto err;
628296341Sdelphij            } else {
629296341Sdelphij                if (!BN_mod_mul(Z_3, Z_2, Z_1, &group->field, ctx))
630296341Sdelphij                    goto err;
631296341Sdelphij            }
632109998Smarkm
633296341Sdelphij            /*
634296341Sdelphij             * in the Montgomery case, field_mul will cancel out Montgomery
635296341Sdelphij             * factor in Y:
636296341Sdelphij             */
637296341Sdelphij            if (!group->meth->field_mul(group, y, &point->Y, Z_3, ctx))
638296341Sdelphij                goto err;
639296341Sdelphij        }
640296341Sdelphij    }
641296341Sdelphij
642296341Sdelphij    ret = 1;
643296341Sdelphij
644109998Smarkm err:
645296341Sdelphij    BN_CTX_end(ctx);
646296341Sdelphij    if (new_ctx != NULL)
647296341Sdelphij        BN_CTX_free(new_ctx);
648296341Sdelphij    return ret;
649296341Sdelphij}
650109998Smarkm
651296341Sdelphijint ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
652296341Sdelphij                      const EC_POINT *b, BN_CTX *ctx)
653296341Sdelphij{
654296341Sdelphij    int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
655296341Sdelphij                      const BIGNUM *, BN_CTX *);
656296341Sdelphij    int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
657296341Sdelphij    const BIGNUM *p;
658296341Sdelphij    BN_CTX *new_ctx = NULL;
659296341Sdelphij    BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6;
660296341Sdelphij    int ret = 0;
661109998Smarkm
662296341Sdelphij    if (a == b)
663296341Sdelphij        return EC_POINT_dbl(group, r, a, ctx);
664296341Sdelphij    if (EC_POINT_is_at_infinity(group, a))
665296341Sdelphij        return EC_POINT_copy(r, b);
666296341Sdelphij    if (EC_POINT_is_at_infinity(group, b))
667296341Sdelphij        return EC_POINT_copy(r, a);
668109998Smarkm
669296341Sdelphij    field_mul = group->meth->field_mul;
670296341Sdelphij    field_sqr = group->meth->field_sqr;
671296341Sdelphij    p = &group->field;
672109998Smarkm
673296341Sdelphij    if (ctx == NULL) {
674296341Sdelphij        ctx = new_ctx = BN_CTX_new();
675296341Sdelphij        if (ctx == NULL)
676296341Sdelphij            return 0;
677296341Sdelphij    }
678109998Smarkm
679296341Sdelphij    BN_CTX_start(ctx);
680296341Sdelphij    n0 = BN_CTX_get(ctx);
681296341Sdelphij    n1 = BN_CTX_get(ctx);
682296341Sdelphij    n2 = BN_CTX_get(ctx);
683296341Sdelphij    n3 = BN_CTX_get(ctx);
684296341Sdelphij    n4 = BN_CTX_get(ctx);
685296341Sdelphij    n5 = BN_CTX_get(ctx);
686296341Sdelphij    n6 = BN_CTX_get(ctx);
687296341Sdelphij    if (n6 == NULL)
688296341Sdelphij        goto end;
689109998Smarkm
690296341Sdelphij    /*
691296341Sdelphij     * Note that in this function we must not read components of 'a' or 'b'
692296341Sdelphij     * once we have written the corresponding components of 'r'. ('r' might
693296341Sdelphij     * be one of 'a' or 'b'.)
694296341Sdelphij     */
695109998Smarkm
696296341Sdelphij    /* n1, n2 */
697296341Sdelphij    if (b->Z_is_one) {
698296341Sdelphij        if (!BN_copy(n1, &a->X))
699296341Sdelphij            goto end;
700296341Sdelphij        if (!BN_copy(n2, &a->Y))
701296341Sdelphij            goto end;
702296341Sdelphij        /* n1 = X_a */
703296341Sdelphij        /* n2 = Y_a */
704296341Sdelphij    } else {
705296341Sdelphij        if (!field_sqr(group, n0, &b->Z, ctx))
706296341Sdelphij            goto end;
707296341Sdelphij        if (!field_mul(group, n1, &a->X, n0, ctx))
708296341Sdelphij            goto end;
709296341Sdelphij        /* n1 = X_a * Z_b^2 */
710109998Smarkm
711296341Sdelphij        if (!field_mul(group, n0, n0, &b->Z, ctx))
712296341Sdelphij            goto end;
713296341Sdelphij        if (!field_mul(group, n2, &a->Y, n0, ctx))
714296341Sdelphij            goto end;
715296341Sdelphij        /* n2 = Y_a * Z_b^3 */
716296341Sdelphij    }
717109998Smarkm
718296341Sdelphij    /* n3, n4 */
719296341Sdelphij    if (a->Z_is_one) {
720296341Sdelphij        if (!BN_copy(n3, &b->X))
721296341Sdelphij            goto end;
722296341Sdelphij        if (!BN_copy(n4, &b->Y))
723296341Sdelphij            goto end;
724296341Sdelphij        /* n3 = X_b */
725296341Sdelphij        /* n4 = Y_b */
726296341Sdelphij    } else {
727296341Sdelphij        if (!field_sqr(group, n0, &a->Z, ctx))
728296341Sdelphij            goto end;
729296341Sdelphij        if (!field_mul(group, n3, &b->X, n0, ctx))
730296341Sdelphij            goto end;
731296341Sdelphij        /* n3 = X_b * Z_a^2 */
732109998Smarkm
733296341Sdelphij        if (!field_mul(group, n0, n0, &a->Z, ctx))
734296341Sdelphij            goto end;
735296341Sdelphij        if (!field_mul(group, n4, &b->Y, n0, ctx))
736296341Sdelphij            goto end;
737296341Sdelphij        /* n4 = Y_b * Z_a^3 */
738296341Sdelphij    }
739109998Smarkm
740296341Sdelphij    /* n5, n6 */
741296341Sdelphij    if (!BN_mod_sub_quick(n5, n1, n3, p))
742296341Sdelphij        goto end;
743296341Sdelphij    if (!BN_mod_sub_quick(n6, n2, n4, p))
744296341Sdelphij        goto end;
745296341Sdelphij    /* n5 = n1 - n3 */
746296341Sdelphij    /* n6 = n2 - n4 */
747109998Smarkm
748296341Sdelphij    if (BN_is_zero(n5)) {
749296341Sdelphij        if (BN_is_zero(n6)) {
750296341Sdelphij            /* a is the same point as b */
751296341Sdelphij            BN_CTX_end(ctx);
752296341Sdelphij            ret = EC_POINT_dbl(group, r, a, ctx);
753296341Sdelphij            ctx = NULL;
754296341Sdelphij            goto end;
755296341Sdelphij        } else {
756296341Sdelphij            /* a is the inverse of b */
757296341Sdelphij            BN_zero(&r->Z);
758296341Sdelphij            r->Z_is_one = 0;
759296341Sdelphij            ret = 1;
760296341Sdelphij            goto end;
761296341Sdelphij        }
762296341Sdelphij    }
763109998Smarkm
764296341Sdelphij    /* 'n7', 'n8' */
765296341Sdelphij    if (!BN_mod_add_quick(n1, n1, n3, p))
766296341Sdelphij        goto end;
767296341Sdelphij    if (!BN_mod_add_quick(n2, n2, n4, p))
768296341Sdelphij        goto end;
769296341Sdelphij    /* 'n7' = n1 + n3 */
770296341Sdelphij    /* 'n8' = n2 + n4 */
771109998Smarkm
772296341Sdelphij    /* Z_r */
773296341Sdelphij    if (a->Z_is_one && b->Z_is_one) {
774296341Sdelphij        if (!BN_copy(&r->Z, n5))
775296341Sdelphij            goto end;
776296341Sdelphij    } else {
777296341Sdelphij        if (a->Z_is_one) {
778296341Sdelphij            if (!BN_copy(n0, &b->Z))
779296341Sdelphij                goto end;
780296341Sdelphij        } else if (b->Z_is_one) {
781296341Sdelphij            if (!BN_copy(n0, &a->Z))
782296341Sdelphij                goto end;
783296341Sdelphij        } else {
784296341Sdelphij            if (!field_mul(group, n0, &a->Z, &b->Z, ctx))
785296341Sdelphij                goto end;
786296341Sdelphij        }
787296341Sdelphij        if (!field_mul(group, &r->Z, n0, n5, ctx))
788296341Sdelphij            goto end;
789296341Sdelphij    }
790296341Sdelphij    r->Z_is_one = 0;
791296341Sdelphij    /* Z_r = Z_a * Z_b * n5 */
792109998Smarkm
793296341Sdelphij    /* X_r */
794296341Sdelphij    if (!field_sqr(group, n0, n6, ctx))
795296341Sdelphij        goto end;
796296341Sdelphij    if (!field_sqr(group, n4, n5, ctx))
797296341Sdelphij        goto end;
798296341Sdelphij    if (!field_mul(group, n3, n1, n4, ctx))
799296341Sdelphij        goto end;
800296341Sdelphij    if (!BN_mod_sub_quick(&r->X, n0, n3, p))
801296341Sdelphij        goto end;
802296341Sdelphij    /* X_r = n6^2 - n5^2 * 'n7' */
803109998Smarkm
804296341Sdelphij    /* 'n9' */
805296341Sdelphij    if (!BN_mod_lshift1_quick(n0, &r->X, p))
806296341Sdelphij        goto end;
807296341Sdelphij    if (!BN_mod_sub_quick(n0, n3, n0, p))
808296341Sdelphij        goto end;
809296341Sdelphij    /* n9 = n5^2 * 'n7' - 2 * X_r */
810296341Sdelphij
811296341Sdelphij    /* Y_r */
812296341Sdelphij    if (!field_mul(group, n0, n0, n6, ctx))
813296341Sdelphij        goto end;
814296341Sdelphij    if (!field_mul(group, n5, n4, n5, ctx))
815296341Sdelphij        goto end;               /* now n5 is n5^3 */
816296341Sdelphij    if (!field_mul(group, n1, n2, n5, ctx))
817296341Sdelphij        goto end;
818296341Sdelphij    if (!BN_mod_sub_quick(n0, n0, n1, p))
819296341Sdelphij        goto end;
820296341Sdelphij    if (BN_is_odd(n0))
821296341Sdelphij        if (!BN_add(n0, n0, p))
822296341Sdelphij            goto end;
823296341Sdelphij    /* now  0 <= n0 < 2*p,  and n0 is even */
824296341Sdelphij    if (!BN_rshift1(&r->Y, n0))
825296341Sdelphij        goto end;
826296341Sdelphij    /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */
827296341Sdelphij
828296341Sdelphij    ret = 1;
829296341Sdelphij
830109998Smarkm end:
831296341Sdelphij    if (ctx)                    /* otherwise we already called BN_CTX_end */
832296341Sdelphij        BN_CTX_end(ctx);
833296341Sdelphij    if (new_ctx != NULL)
834296341Sdelphij        BN_CTX_free(new_ctx);
835296341Sdelphij    return ret;
836296341Sdelphij}
837109998Smarkm
838296341Sdelphijint ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
839296341Sdelphij                      BN_CTX *ctx)
840296341Sdelphij{
841296341Sdelphij    int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
842296341Sdelphij                      const BIGNUM *, BN_CTX *);
843296341Sdelphij    int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
844296341Sdelphij    const BIGNUM *p;
845296341Sdelphij    BN_CTX *new_ctx = NULL;
846296341Sdelphij    BIGNUM *n0, *n1, *n2, *n3;
847296341Sdelphij    int ret = 0;
848109998Smarkm
849296341Sdelphij    if (EC_POINT_is_at_infinity(group, a)) {
850296341Sdelphij        BN_zero(&r->Z);
851296341Sdelphij        r->Z_is_one = 0;
852296341Sdelphij        return 1;
853296341Sdelphij    }
854109998Smarkm
855296341Sdelphij    field_mul = group->meth->field_mul;
856296341Sdelphij    field_sqr = group->meth->field_sqr;
857296341Sdelphij    p = &group->field;
858109998Smarkm
859296341Sdelphij    if (ctx == NULL) {
860296341Sdelphij        ctx = new_ctx = BN_CTX_new();
861296341Sdelphij        if (ctx == NULL)
862296341Sdelphij            return 0;
863296341Sdelphij    }
864109998Smarkm
865296341Sdelphij    BN_CTX_start(ctx);
866296341Sdelphij    n0 = BN_CTX_get(ctx);
867296341Sdelphij    n1 = BN_CTX_get(ctx);
868296341Sdelphij    n2 = BN_CTX_get(ctx);
869296341Sdelphij    n3 = BN_CTX_get(ctx);
870296341Sdelphij    if (n3 == NULL)
871296341Sdelphij        goto err;
872109998Smarkm
873296341Sdelphij    /*
874296341Sdelphij     * Note that in this function we must not read components of 'a' once we
875296341Sdelphij     * have written the corresponding components of 'r'. ('r' might the same
876296341Sdelphij     * as 'a'.)
877296341Sdelphij     */
878109998Smarkm
879296341Sdelphij    /* n1 */
880296341Sdelphij    if (a->Z_is_one) {
881296341Sdelphij        if (!field_sqr(group, n0, &a->X, ctx))
882296341Sdelphij            goto err;
883296341Sdelphij        if (!BN_mod_lshift1_quick(n1, n0, p))
884296341Sdelphij            goto err;
885296341Sdelphij        if (!BN_mod_add_quick(n0, n0, n1, p))
886296341Sdelphij            goto err;
887296341Sdelphij        if (!BN_mod_add_quick(n1, n0, &group->a, p))
888296341Sdelphij            goto err;
889296341Sdelphij        /* n1 = 3 * X_a^2 + a_curve */
890296341Sdelphij    } else if (group->a_is_minus3) {
891296341Sdelphij        if (!field_sqr(group, n1, &a->Z, ctx))
892296341Sdelphij            goto err;
893296341Sdelphij        if (!BN_mod_add_quick(n0, &a->X, n1, p))
894296341Sdelphij            goto err;
895296341Sdelphij        if (!BN_mod_sub_quick(n2, &a->X, n1, p))
896296341Sdelphij            goto err;
897296341Sdelphij        if (!field_mul(group, n1, n0, n2, ctx))
898296341Sdelphij            goto err;
899296341Sdelphij        if (!BN_mod_lshift1_quick(n0, n1, p))
900296341Sdelphij            goto err;
901296341Sdelphij        if (!BN_mod_add_quick(n1, n0, n1, p))
902296341Sdelphij            goto err;
903296341Sdelphij        /*-
904296341Sdelphij         * n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2)
905296341Sdelphij         *    = 3 * X_a^2 - 3 * Z_a^4
906296341Sdelphij         */
907296341Sdelphij    } else {
908296341Sdelphij        if (!field_sqr(group, n0, &a->X, ctx))
909296341Sdelphij            goto err;
910296341Sdelphij        if (!BN_mod_lshift1_quick(n1, n0, p))
911296341Sdelphij            goto err;
912296341Sdelphij        if (!BN_mod_add_quick(n0, n0, n1, p))
913296341Sdelphij            goto err;
914296341Sdelphij        if (!field_sqr(group, n1, &a->Z, ctx))
915296341Sdelphij            goto err;
916296341Sdelphij        if (!field_sqr(group, n1, n1, ctx))
917296341Sdelphij            goto err;
918296341Sdelphij        if (!field_mul(group, n1, n1, &group->a, ctx))
919296341Sdelphij            goto err;
920296341Sdelphij        if (!BN_mod_add_quick(n1, n1, n0, p))
921296341Sdelphij            goto err;
922296341Sdelphij        /* n1 = 3 * X_a^2 + a_curve * Z_a^4 */
923296341Sdelphij    }
924109998Smarkm
925296341Sdelphij    /* Z_r */
926296341Sdelphij    if (a->Z_is_one) {
927296341Sdelphij        if (!BN_copy(n0, &a->Y))
928296341Sdelphij            goto err;
929296341Sdelphij    } else {
930296341Sdelphij        if (!field_mul(group, n0, &a->Y, &a->Z, ctx))
931296341Sdelphij            goto err;
932296341Sdelphij    }
933296341Sdelphij    if (!BN_mod_lshift1_quick(&r->Z, n0, p))
934296341Sdelphij        goto err;
935296341Sdelphij    r->Z_is_one = 0;
936296341Sdelphij    /* Z_r = 2 * Y_a * Z_a */
937109998Smarkm
938296341Sdelphij    /* n2 */
939296341Sdelphij    if (!field_sqr(group, n3, &a->Y, ctx))
940296341Sdelphij        goto err;
941296341Sdelphij    if (!field_mul(group, n2, &a->X, n3, ctx))
942296341Sdelphij        goto err;
943296341Sdelphij    if (!BN_mod_lshift_quick(n2, n2, 2, p))
944296341Sdelphij        goto err;
945296341Sdelphij    /* n2 = 4 * X_a * Y_a^2 */
946109998Smarkm
947296341Sdelphij    /* X_r */
948296341Sdelphij    if (!BN_mod_lshift1_quick(n0, n2, p))
949296341Sdelphij        goto err;
950296341Sdelphij    if (!field_sqr(group, &r->X, n1, ctx))
951296341Sdelphij        goto err;
952296341Sdelphij    if (!BN_mod_sub_quick(&r->X, &r->X, n0, p))
953296341Sdelphij        goto err;
954296341Sdelphij    /* X_r = n1^2 - 2 * n2 */
955109998Smarkm
956296341Sdelphij    /* n3 */
957296341Sdelphij    if (!field_sqr(group, n0, n3, ctx))
958296341Sdelphij        goto err;
959296341Sdelphij    if (!BN_mod_lshift_quick(n3, n0, 3, p))
960296341Sdelphij        goto err;
961296341Sdelphij    /* n3 = 8 * Y_a^4 */
962109998Smarkm
963296341Sdelphij    /* Y_r */
964296341Sdelphij    if (!BN_mod_sub_quick(n0, n2, &r->X, p))
965296341Sdelphij        goto err;
966296341Sdelphij    if (!field_mul(group, n0, n1, n0, ctx))
967296341Sdelphij        goto err;
968296341Sdelphij    if (!BN_mod_sub_quick(&r->Y, n0, n3, p))
969296341Sdelphij        goto err;
970296341Sdelphij    /* Y_r = n1 * (n2 - X_r) - n3 */
971296341Sdelphij
972296341Sdelphij    ret = 1;
973296341Sdelphij
974109998Smarkm err:
975296341Sdelphij    BN_CTX_end(ctx);
976296341Sdelphij    if (new_ctx != NULL)
977296341Sdelphij        BN_CTX_free(new_ctx);
978296341Sdelphij    return ret;
979296341Sdelphij}
980109998Smarkm
981109998Smarkmint ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx)
982296341Sdelphij{
983296341Sdelphij    if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(&point->Y))
984296341Sdelphij        /* point is its own inverse */
985296341Sdelphij        return 1;
986109998Smarkm
987296341Sdelphij    return BN_usub(&point->Y, &group->field, &point->Y);
988296341Sdelphij}
989109998Smarkm
990109998Smarkmint ec_GFp_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point)
991296341Sdelphij{
992296341Sdelphij    return BN_is_zero(&point->Z);
993296341Sdelphij}
994109998Smarkm
995296341Sdelphijint ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
996296341Sdelphij                              BN_CTX *ctx)
997296341Sdelphij{
998296341Sdelphij    int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
999296341Sdelphij                      const BIGNUM *, BN_CTX *);
1000296341Sdelphij    int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
1001296341Sdelphij    const BIGNUM *p;
1002296341Sdelphij    BN_CTX *new_ctx = NULL;
1003296341Sdelphij    BIGNUM *rh, *tmp, *Z4, *Z6;
1004296341Sdelphij    int ret = -1;
1005109998Smarkm
1006296341Sdelphij    if (EC_POINT_is_at_infinity(group, point))
1007296341Sdelphij        return 1;
1008109998Smarkm
1009296341Sdelphij    field_mul = group->meth->field_mul;
1010296341Sdelphij    field_sqr = group->meth->field_sqr;
1011296341Sdelphij    p = &group->field;
1012109998Smarkm
1013296341Sdelphij    if (ctx == NULL) {
1014296341Sdelphij        ctx = new_ctx = BN_CTX_new();
1015296341Sdelphij        if (ctx == NULL)
1016296341Sdelphij            return -1;
1017296341Sdelphij    }
1018109998Smarkm
1019296341Sdelphij    BN_CTX_start(ctx);
1020296341Sdelphij    rh = BN_CTX_get(ctx);
1021296341Sdelphij    tmp = BN_CTX_get(ctx);
1022296341Sdelphij    Z4 = BN_CTX_get(ctx);
1023296341Sdelphij    Z6 = BN_CTX_get(ctx);
1024296341Sdelphij    if (Z6 == NULL)
1025296341Sdelphij        goto err;
1026109998Smarkm
1027296341Sdelphij    /*-
1028296341Sdelphij     * We have a curve defined by a Weierstrass equation
1029296341Sdelphij     *      y^2 = x^3 + a*x + b.
1030296341Sdelphij     * The point to consider is given in Jacobian projective coordinates
1031296341Sdelphij     * where  (X, Y, Z)  represents  (x, y) = (X/Z^2, Y/Z^3).
1032296341Sdelphij     * Substituting this and multiplying by  Z^6  transforms the above equation into
1033296341Sdelphij     *      Y^2 = X^3 + a*X*Z^4 + b*Z^6.
1034296341Sdelphij     * To test this, we add up the right-hand side in 'rh'.
1035296341Sdelphij     */
1036109998Smarkm
1037296341Sdelphij    /* rh := X^2 */
1038296341Sdelphij    if (!field_sqr(group, rh, &point->X, ctx))
1039296341Sdelphij        goto err;
1040109998Smarkm
1041296341Sdelphij    if (!point->Z_is_one) {
1042296341Sdelphij        if (!field_sqr(group, tmp, &point->Z, ctx))
1043296341Sdelphij            goto err;
1044296341Sdelphij        if (!field_sqr(group, Z4, tmp, ctx))
1045296341Sdelphij            goto err;
1046296341Sdelphij        if (!field_mul(group, Z6, Z4, tmp, ctx))
1047296341Sdelphij            goto err;
1048109998Smarkm
1049296341Sdelphij        /* rh := (rh + a*Z^4)*X */
1050296341Sdelphij        if (group->a_is_minus3) {
1051296341Sdelphij            if (!BN_mod_lshift1_quick(tmp, Z4, p))
1052296341Sdelphij                goto err;
1053296341Sdelphij            if (!BN_mod_add_quick(tmp, tmp, Z4, p))
1054296341Sdelphij                goto err;
1055296341Sdelphij            if (!BN_mod_sub_quick(rh, rh, tmp, p))
1056296341Sdelphij                goto err;
1057296341Sdelphij            if (!field_mul(group, rh, rh, &point->X, ctx))
1058296341Sdelphij                goto err;
1059296341Sdelphij        } else {
1060296341Sdelphij            if (!field_mul(group, tmp, Z4, &group->a, ctx))
1061296341Sdelphij                goto err;
1062296341Sdelphij            if (!BN_mod_add_quick(rh, rh, tmp, p))
1063296341Sdelphij                goto err;
1064296341Sdelphij            if (!field_mul(group, rh, rh, &point->X, ctx))
1065296341Sdelphij                goto err;
1066296341Sdelphij        }
1067109998Smarkm
1068296341Sdelphij        /* rh := rh + b*Z^6 */
1069296341Sdelphij        if (!field_mul(group, tmp, &group->b, Z6, ctx))
1070296341Sdelphij            goto err;
1071296341Sdelphij        if (!BN_mod_add_quick(rh, rh, tmp, p))
1072296341Sdelphij            goto err;
1073296341Sdelphij    } else {
1074296341Sdelphij        /* point->Z_is_one */
1075109998Smarkm
1076296341Sdelphij        /* rh := (rh + a)*X */
1077296341Sdelphij        if (!BN_mod_add_quick(rh, rh, &group->a, p))
1078296341Sdelphij            goto err;
1079296341Sdelphij        if (!field_mul(group, rh, rh, &point->X, ctx))
1080296341Sdelphij            goto err;
1081296341Sdelphij        /* rh := rh + b */
1082296341Sdelphij        if (!BN_mod_add_quick(rh, rh, &group->b, p))
1083296341Sdelphij            goto err;
1084296341Sdelphij    }
1085109998Smarkm
1086296341Sdelphij    /* 'lh' := Y^2 */
1087296341Sdelphij    if (!field_sqr(group, tmp, &point->Y, ctx))
1088296341Sdelphij        goto err;
1089109998Smarkm
1090296341Sdelphij    ret = (0 == BN_ucmp(tmp, rh));
1091109998Smarkm
1092109998Smarkm err:
1093296341Sdelphij    BN_CTX_end(ctx);
1094296341Sdelphij    if (new_ctx != NULL)
1095296341Sdelphij        BN_CTX_free(new_ctx);
1096296341Sdelphij    return ret;
1097296341Sdelphij}
1098109998Smarkm
1099296341Sdelphijint ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
1100296341Sdelphij                      const EC_POINT *b, BN_CTX *ctx)
1101296341Sdelphij{
1102296341Sdelphij    /*-
1103296341Sdelphij     * return values:
1104296341Sdelphij     *  -1   error
1105296341Sdelphij     *   0   equal (in affine coordinates)
1106296341Sdelphij     *   1   not equal
1107296341Sdelphij     */
1108109998Smarkm
1109296341Sdelphij    int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
1110296341Sdelphij                      const BIGNUM *, BN_CTX *);
1111296341Sdelphij    int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
1112296341Sdelphij    BN_CTX *new_ctx = NULL;
1113296341Sdelphij    BIGNUM *tmp1, *tmp2, *Za23, *Zb23;
1114296341Sdelphij    const BIGNUM *tmp1_, *tmp2_;
1115296341Sdelphij    int ret = -1;
1116109998Smarkm
1117296341Sdelphij    if (EC_POINT_is_at_infinity(group, a)) {
1118296341Sdelphij        return EC_POINT_is_at_infinity(group, b) ? 0 : 1;
1119296341Sdelphij    }
1120237657Sjkim
1121296341Sdelphij    if (EC_POINT_is_at_infinity(group, b))
1122296341Sdelphij        return 1;
1123109998Smarkm
1124296341Sdelphij    if (a->Z_is_one && b->Z_is_one) {
1125296341Sdelphij        return ((BN_cmp(&a->X, &b->X) == 0)
1126296341Sdelphij                && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1;
1127296341Sdelphij    }
1128109998Smarkm
1129296341Sdelphij    field_mul = group->meth->field_mul;
1130296341Sdelphij    field_sqr = group->meth->field_sqr;
1131109998Smarkm
1132296341Sdelphij    if (ctx == NULL) {
1133296341Sdelphij        ctx = new_ctx = BN_CTX_new();
1134296341Sdelphij        if (ctx == NULL)
1135296341Sdelphij            return -1;
1136296341Sdelphij    }
1137109998Smarkm
1138296341Sdelphij    BN_CTX_start(ctx);
1139296341Sdelphij    tmp1 = BN_CTX_get(ctx);
1140296341Sdelphij    tmp2 = BN_CTX_get(ctx);
1141296341Sdelphij    Za23 = BN_CTX_get(ctx);
1142296341Sdelphij    Zb23 = BN_CTX_get(ctx);
1143296341Sdelphij    if (Zb23 == NULL)
1144296341Sdelphij        goto end;
1145109998Smarkm
1146296341Sdelphij    /*-
1147296341Sdelphij     * We have to decide whether
1148296341Sdelphij     *     (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3),
1149296341Sdelphij     * or equivalently, whether
1150296341Sdelphij     *     (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3).
1151296341Sdelphij     */
1152109998Smarkm
1153296341Sdelphij    if (!b->Z_is_one) {
1154296341Sdelphij        if (!field_sqr(group, Zb23, &b->Z, ctx))
1155296341Sdelphij            goto end;
1156296341Sdelphij        if (!field_mul(group, tmp1, &a->X, Zb23, ctx))
1157296341Sdelphij            goto end;
1158296341Sdelphij        tmp1_ = tmp1;
1159296341Sdelphij    } else
1160296341Sdelphij        tmp1_ = &a->X;
1161296341Sdelphij    if (!a->Z_is_one) {
1162296341Sdelphij        if (!field_sqr(group, Za23, &a->Z, ctx))
1163296341Sdelphij            goto end;
1164296341Sdelphij        if (!field_mul(group, tmp2, &b->X, Za23, ctx))
1165296341Sdelphij            goto end;
1166296341Sdelphij        tmp2_ = tmp2;
1167296341Sdelphij    } else
1168296341Sdelphij        tmp2_ = &b->X;
1169109998Smarkm
1170296341Sdelphij    /* compare  X_a*Z_b^2  with  X_b*Z_a^2 */
1171296341Sdelphij    if (BN_cmp(tmp1_, tmp2_) != 0) {
1172296341Sdelphij        ret = 1;                /* points differ */
1173296341Sdelphij        goto end;
1174296341Sdelphij    }
1175109998Smarkm
1176296341Sdelphij    if (!b->Z_is_one) {
1177296341Sdelphij        if (!field_mul(group, Zb23, Zb23, &b->Z, ctx))
1178296341Sdelphij            goto end;
1179296341Sdelphij        if (!field_mul(group, tmp1, &a->Y, Zb23, ctx))
1180296341Sdelphij            goto end;
1181296341Sdelphij        /* tmp1_ = tmp1 */
1182296341Sdelphij    } else
1183296341Sdelphij        tmp1_ = &a->Y;
1184296341Sdelphij    if (!a->Z_is_one) {
1185296341Sdelphij        if (!field_mul(group, Za23, Za23, &a->Z, ctx))
1186296341Sdelphij            goto end;
1187296341Sdelphij        if (!field_mul(group, tmp2, &b->Y, Za23, ctx))
1188296341Sdelphij            goto end;
1189296341Sdelphij        /* tmp2_ = tmp2 */
1190296341Sdelphij    } else
1191296341Sdelphij        tmp2_ = &b->Y;
1192109998Smarkm
1193296341Sdelphij    /* compare  Y_a*Z_b^3  with  Y_b*Z_a^3 */
1194296341Sdelphij    if (BN_cmp(tmp1_, tmp2_) != 0) {
1195296341Sdelphij        ret = 1;                /* points differ */
1196296341Sdelphij        goto end;
1197296341Sdelphij    }
1198109998Smarkm
1199296341Sdelphij    /* points are equal */
1200296341Sdelphij    ret = 0;
1201296341Sdelphij
1202109998Smarkm end:
1203296341Sdelphij    BN_CTX_end(ctx);
1204296341Sdelphij    if (new_ctx != NULL)
1205296341Sdelphij        BN_CTX_free(new_ctx);
1206296341Sdelphij    return ret;
1207296341Sdelphij}
1208109998Smarkm
1209296341Sdelphijint ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point,
1210296341Sdelphij                              BN_CTX *ctx)
1211296341Sdelphij{
1212296341Sdelphij    BN_CTX *new_ctx = NULL;
1213296341Sdelphij    BIGNUM *x, *y;
1214296341Sdelphij    int ret = 0;
1215109998Smarkm
1216296341Sdelphij    if (point->Z_is_one || EC_POINT_is_at_infinity(group, point))
1217296341Sdelphij        return 1;
1218109998Smarkm
1219296341Sdelphij    if (ctx == NULL) {
1220296341Sdelphij        ctx = new_ctx = BN_CTX_new();
1221296341Sdelphij        if (ctx == NULL)
1222296341Sdelphij            return 0;
1223296341Sdelphij    }
1224109998Smarkm
1225296341Sdelphij    BN_CTX_start(ctx);
1226296341Sdelphij    x = BN_CTX_get(ctx);
1227296341Sdelphij    y = BN_CTX_get(ctx);
1228296341Sdelphij    if (y == NULL)
1229296341Sdelphij        goto err;
1230109998Smarkm
1231296341Sdelphij    if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx))
1232296341Sdelphij        goto err;
1233296341Sdelphij    if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx))
1234296341Sdelphij        goto err;
1235296341Sdelphij    if (!point->Z_is_one) {
1236296341Sdelphij        ECerr(EC_F_EC_GFP_SIMPLE_MAKE_AFFINE, ERR_R_INTERNAL_ERROR);
1237296341Sdelphij        goto err;
1238296341Sdelphij    }
1239109998Smarkm
1240296341Sdelphij    ret = 1;
1241109998Smarkm
1242109998Smarkm err:
1243296341Sdelphij    BN_CTX_end(ctx);
1244296341Sdelphij    if (new_ctx != NULL)
1245296341Sdelphij        BN_CTX_free(new_ctx);
1246296341Sdelphij    return ret;
1247296341Sdelphij}
1248109998Smarkm
1249296341Sdelphijint ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num,
1250296341Sdelphij                                     EC_POINT *points[], BN_CTX *ctx)
1251296341Sdelphij{
1252296341Sdelphij    BN_CTX *new_ctx = NULL;
1253296341Sdelphij    BIGNUM *tmp, *tmp_Z;
1254296341Sdelphij    BIGNUM **prod_Z = NULL;
1255296341Sdelphij    size_t i;
1256296341Sdelphij    int ret = 0;
1257109998Smarkm
1258296341Sdelphij    if (num == 0)
1259296341Sdelphij        return 1;
1260109998Smarkm
1261296341Sdelphij    if (ctx == NULL) {
1262296341Sdelphij        ctx = new_ctx = BN_CTX_new();
1263296341Sdelphij        if (ctx == NULL)
1264296341Sdelphij            return 0;
1265296341Sdelphij    }
1266109998Smarkm
1267296341Sdelphij    BN_CTX_start(ctx);
1268296341Sdelphij    tmp = BN_CTX_get(ctx);
1269296341Sdelphij    tmp_Z = BN_CTX_get(ctx);
1270296341Sdelphij    if (tmp == NULL || tmp_Z == NULL)
1271296341Sdelphij        goto err;
1272109998Smarkm
1273296341Sdelphij    prod_Z = OPENSSL_malloc(num * sizeof prod_Z[0]);
1274296341Sdelphij    if (prod_Z == NULL)
1275296341Sdelphij        goto err;
1276296341Sdelphij    for (i = 0; i < num; i++) {
1277296341Sdelphij        prod_Z[i] = BN_new();
1278296341Sdelphij        if (prod_Z[i] == NULL)
1279296341Sdelphij            goto err;
1280296341Sdelphij    }
1281109998Smarkm
1282296341Sdelphij    /*
1283296341Sdelphij     * Set each prod_Z[i] to the product of points[0]->Z .. points[i]->Z,
1284296341Sdelphij     * skipping any zero-valued inputs (pretend that they're 1).
1285296341Sdelphij     */
1286109998Smarkm
1287296341Sdelphij    if (!BN_is_zero(&points[0]->Z)) {
1288296341Sdelphij        if (!BN_copy(prod_Z[0], &points[0]->Z))
1289296341Sdelphij            goto err;
1290296341Sdelphij    } else {
1291296341Sdelphij        if (group->meth->field_set_to_one != 0) {
1292296341Sdelphij            if (!group->meth->field_set_to_one(group, prod_Z[0], ctx))
1293296341Sdelphij                goto err;
1294296341Sdelphij        } else {
1295296341Sdelphij            if (!BN_one(prod_Z[0]))
1296296341Sdelphij                goto err;
1297296341Sdelphij        }
1298296341Sdelphij    }
1299109998Smarkm
1300296341Sdelphij    for (i = 1; i < num; i++) {
1301296341Sdelphij        if (!BN_is_zero(&points[i]->Z)) {
1302296341Sdelphij            if (!group->meth->field_mul(group, prod_Z[i], prod_Z[i - 1],
1303296341Sdelphij                                        &points[i]->Z, ctx))
1304296341Sdelphij                goto err;
1305296341Sdelphij        } else {
1306296341Sdelphij            if (!BN_copy(prod_Z[i], prod_Z[i - 1]))
1307296341Sdelphij                goto err;
1308296341Sdelphij        }
1309296341Sdelphij    }
1310109998Smarkm
1311296341Sdelphij    /*
1312296341Sdelphij     * Now use a single explicit inversion to replace every non-zero
1313296341Sdelphij     * points[i]->Z by its inverse.
1314296341Sdelphij     */
1315269686Sjkim
1316296341Sdelphij    if (!BN_mod_inverse(tmp, prod_Z[num - 1], &group->field, ctx)) {
1317296341Sdelphij        ECerr(EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE, ERR_R_BN_LIB);
1318296341Sdelphij        goto err;
1319296341Sdelphij    }
1320296341Sdelphij    if (group->meth->field_encode != 0) {
1321296341Sdelphij        /*
1322296341Sdelphij         * In the Montgomery case, we just turned R*H (representing H) into
1323296341Sdelphij         * 1/(R*H), but we need R*(1/H) (representing 1/H); i.e. we need to
1324296341Sdelphij         * multiply by the Montgomery factor twice.
1325296341Sdelphij         */
1326296341Sdelphij        if (!group->meth->field_encode(group, tmp, tmp, ctx))
1327296341Sdelphij            goto err;
1328296341Sdelphij        if (!group->meth->field_encode(group, tmp, tmp, ctx))
1329296341Sdelphij            goto err;
1330296341Sdelphij    }
1331269686Sjkim
1332296341Sdelphij    for (i = num - 1; i > 0; --i) {
1333296341Sdelphij        /*
1334296341Sdelphij         * Loop invariant: tmp is the product of the inverses of points[0]->Z
1335296341Sdelphij         * .. points[i]->Z (zero-valued inputs skipped).
1336296341Sdelphij         */
1337296341Sdelphij        if (!BN_is_zero(&points[i]->Z)) {
1338296341Sdelphij            /*
1339296341Sdelphij             * Set tmp_Z to the inverse of points[i]->Z (as product of Z
1340296341Sdelphij             * inverses 0 .. i, Z values 0 .. i - 1).
1341296341Sdelphij             */
1342296341Sdelphij            if (!group->
1343296341Sdelphij                meth->field_mul(group, tmp_Z, prod_Z[i - 1], tmp, ctx))
1344296341Sdelphij                goto err;
1345296341Sdelphij            /*
1346296341Sdelphij             * Update tmp to satisfy the loop invariant for i - 1.
1347296341Sdelphij             */
1348296341Sdelphij            if (!group->meth->field_mul(group, tmp, tmp, &points[i]->Z, ctx))
1349296341Sdelphij                goto err;
1350296341Sdelphij            /* Replace points[i]->Z by its inverse. */
1351296341Sdelphij            if (!BN_copy(&points[i]->Z, tmp_Z))
1352296341Sdelphij                goto err;
1353296341Sdelphij        }
1354296341Sdelphij    }
1355109998Smarkm
1356296341Sdelphij    if (!BN_is_zero(&points[0]->Z)) {
1357296341Sdelphij        /* Replace points[0]->Z by its inverse. */
1358296341Sdelphij        if (!BN_copy(&points[0]->Z, tmp))
1359296341Sdelphij            goto err;
1360296341Sdelphij    }
1361109998Smarkm
1362296341Sdelphij    /* Finally, fix up the X and Y coordinates for all points. */
1363269686Sjkim
1364296341Sdelphij    for (i = 0; i < num; i++) {
1365296341Sdelphij        EC_POINT *p = points[i];
1366269686Sjkim
1367296341Sdelphij        if (!BN_is_zero(&p->Z)) {
1368296341Sdelphij            /* turn  (X, Y, 1/Z)  into  (X/Z^2, Y/Z^3, 1) */
1369269686Sjkim
1370296341Sdelphij            if (!group->meth->field_sqr(group, tmp, &p->Z, ctx))
1371296341Sdelphij                goto err;
1372296341Sdelphij            if (!group->meth->field_mul(group, &p->X, &p->X, tmp, ctx))
1373296341Sdelphij                goto err;
1374109998Smarkm
1375296341Sdelphij            if (!group->meth->field_mul(group, tmp, tmp, &p->Z, ctx))
1376296341Sdelphij                goto err;
1377296341Sdelphij            if (!group->meth->field_mul(group, &p->Y, &p->Y, tmp, ctx))
1378296341Sdelphij                goto err;
1379109998Smarkm
1380296341Sdelphij            if (group->meth->field_set_to_one != 0) {
1381296341Sdelphij                if (!group->meth->field_set_to_one(group, &p->Z, ctx))
1382296341Sdelphij                    goto err;
1383296341Sdelphij            } else {
1384296341Sdelphij                if (!BN_one(&p->Z))
1385296341Sdelphij                    goto err;
1386296341Sdelphij            }
1387296341Sdelphij            p->Z_is_one = 1;
1388296341Sdelphij        }
1389296341Sdelphij    }
1390269686Sjkim
1391296341Sdelphij    ret = 1;
1392109998Smarkm
1393109998Smarkm err:
1394296341Sdelphij    BN_CTX_end(ctx);
1395296341Sdelphij    if (new_ctx != NULL)
1396296341Sdelphij        BN_CTX_free(new_ctx);
1397296341Sdelphij    if (prod_Z != NULL) {
1398296341Sdelphij        for (i = 0; i < num; i++) {
1399296341Sdelphij            if (prod_Z[i] == NULL)
1400296341Sdelphij                break;
1401296341Sdelphij            BN_clear_free(prod_Z[i]);
1402296341Sdelphij        }
1403296341Sdelphij        OPENSSL_free(prod_Z);
1404296341Sdelphij    }
1405296341Sdelphij    return ret;
1406296341Sdelphij}
1407109998Smarkm
1408296341Sdelphijint ec_GFp_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
1409296341Sdelphij                            const BIGNUM *b, BN_CTX *ctx)
1410296341Sdelphij{
1411296341Sdelphij    return BN_mod_mul(r, a, b, &group->field, ctx);
1412296341Sdelphij}
1413109998Smarkm
1414296341Sdelphijint ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
1415296341Sdelphij                            BN_CTX *ctx)
1416296341Sdelphij{
1417296341Sdelphij    return BN_mod_sqr(r, a, &group->field, ctx);
1418296341Sdelphij}
1419