10Sstevel@tonic-gate /* crypto/ec/ecp_smpl.c */
20Sstevel@tonic-gate /* Includes code written by Lenka Fibikova <fibikova@exp-math.uni-essen.de>
3*2139Sjp161948 * for the OpenSSL project.
4*2139Sjp161948 * Includes code written by Bodo Moeller for the OpenSSL project.
5*2139Sjp161948 */
60Sstevel@tonic-gate /* ====================================================================
7*2139Sjp161948 * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
100Sstevel@tonic-gate * modification, are permitted provided that the following conditions
110Sstevel@tonic-gate * are met:
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
140Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
150Sstevel@tonic-gate *
160Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
170Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in
180Sstevel@tonic-gate * the documentation and/or other materials provided with the
190Sstevel@tonic-gate * distribution.
200Sstevel@tonic-gate *
210Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this
220Sstevel@tonic-gate * software must display the following acknowledgment:
230Sstevel@tonic-gate * "This product includes software developed by the OpenSSL Project
240Sstevel@tonic-gate * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
250Sstevel@tonic-gate *
260Sstevel@tonic-gate * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
270Sstevel@tonic-gate * endorse or promote products derived from this software without
280Sstevel@tonic-gate * prior written permission. For written permission, please contact
290Sstevel@tonic-gate * openssl-core@openssl.org.
300Sstevel@tonic-gate *
310Sstevel@tonic-gate * 5. Products derived from this software may not be called "OpenSSL"
320Sstevel@tonic-gate * nor may "OpenSSL" appear in their names without prior written
330Sstevel@tonic-gate * permission of the OpenSSL Project.
340Sstevel@tonic-gate *
350Sstevel@tonic-gate * 6. Redistributions of any form whatsoever must retain the following
360Sstevel@tonic-gate * acknowledgment:
370Sstevel@tonic-gate * "This product includes software developed by the OpenSSL Project
380Sstevel@tonic-gate * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
390Sstevel@tonic-gate *
400Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
410Sstevel@tonic-gate * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
420Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
430Sstevel@tonic-gate * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
440Sstevel@tonic-gate * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
450Sstevel@tonic-gate * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
460Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
470Sstevel@tonic-gate * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
480Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
490Sstevel@tonic-gate * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
500Sstevel@tonic-gate * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
510Sstevel@tonic-gate * OF THE POSSIBILITY OF SUCH DAMAGE.
520Sstevel@tonic-gate * ====================================================================
530Sstevel@tonic-gate *
540Sstevel@tonic-gate * This product includes cryptographic software written by Eric Young
550Sstevel@tonic-gate * (eay@cryptsoft.com). This product includes software written by Tim
560Sstevel@tonic-gate * Hudson (tjh@cryptsoft.com).
570Sstevel@tonic-gate *
580Sstevel@tonic-gate */
59*2139Sjp161948 /* ====================================================================
60*2139Sjp161948 * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
61*2139Sjp161948 * Portions of this software developed by SUN MICROSYSTEMS, INC.,
62*2139Sjp161948 * and contributed to the OpenSSL project.
63*2139Sjp161948 */
640Sstevel@tonic-gate
650Sstevel@tonic-gate #include <openssl/err.h>
66*2139Sjp161948 #include <openssl/symhacks.h>
670Sstevel@tonic-gate
680Sstevel@tonic-gate #include "ec_lcl.h"
690Sstevel@tonic-gate
EC_GFp_simple_method(void)700Sstevel@tonic-gate const EC_METHOD *EC_GFp_simple_method(void)
710Sstevel@tonic-gate {
720Sstevel@tonic-gate static const EC_METHOD ret = {
73*2139Sjp161948 NID_X9_62_prime_field,
740Sstevel@tonic-gate ec_GFp_simple_group_init,
750Sstevel@tonic-gate ec_GFp_simple_group_finish,
760Sstevel@tonic-gate ec_GFp_simple_group_clear_finish,
770Sstevel@tonic-gate ec_GFp_simple_group_copy,
78*2139Sjp161948 ec_GFp_simple_group_set_curve,
79*2139Sjp161948 ec_GFp_simple_group_get_curve,
80*2139Sjp161948 ec_GFp_simple_group_get_degree,
81*2139Sjp161948 ec_GFp_simple_group_check_discriminant,
820Sstevel@tonic-gate ec_GFp_simple_point_init,
830Sstevel@tonic-gate ec_GFp_simple_point_finish,
840Sstevel@tonic-gate ec_GFp_simple_point_clear_finish,
850Sstevel@tonic-gate ec_GFp_simple_point_copy,
860Sstevel@tonic-gate ec_GFp_simple_point_set_to_infinity,
870Sstevel@tonic-gate ec_GFp_simple_set_Jprojective_coordinates_GFp,
880Sstevel@tonic-gate ec_GFp_simple_get_Jprojective_coordinates_GFp,
89*2139Sjp161948 ec_GFp_simple_point_set_affine_coordinates,
90*2139Sjp161948 ec_GFp_simple_point_get_affine_coordinates,
91*2139Sjp161948 ec_GFp_simple_set_compressed_coordinates,
920Sstevel@tonic-gate ec_GFp_simple_point2oct,
930Sstevel@tonic-gate ec_GFp_simple_oct2point,
940Sstevel@tonic-gate ec_GFp_simple_add,
950Sstevel@tonic-gate ec_GFp_simple_dbl,
960Sstevel@tonic-gate ec_GFp_simple_invert,
970Sstevel@tonic-gate ec_GFp_simple_is_at_infinity,
980Sstevel@tonic-gate ec_GFp_simple_is_on_curve,
990Sstevel@tonic-gate ec_GFp_simple_cmp,
1000Sstevel@tonic-gate ec_GFp_simple_make_affine,
1010Sstevel@tonic-gate ec_GFp_simple_points_make_affine,
102*2139Sjp161948 0 /* mul */,
103*2139Sjp161948 0 /* precompute_mult */,
104*2139Sjp161948 0 /* have_precompute_mult */,
1050Sstevel@tonic-gate ec_GFp_simple_field_mul,
1060Sstevel@tonic-gate ec_GFp_simple_field_sqr,
107*2139Sjp161948 0 /* field_div */,
1080Sstevel@tonic-gate 0 /* field_encode */,
1090Sstevel@tonic-gate 0 /* field_decode */,
1100Sstevel@tonic-gate 0 /* field_set_to_one */ };
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate return &ret;
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate
116*2139Sjp161948 /* Most method functions in this file are designed to work with
117*2139Sjp161948 * non-trivial representations of field elements if necessary
118*2139Sjp161948 * (see ecp_mont.c): while standard modular addition and subtraction
119*2139Sjp161948 * are used, the field_mul and field_sqr methods will be used for
120*2139Sjp161948 * multiplication, and field_encode and field_decode (if defined)
121*2139Sjp161948 * will be used for converting between representations.
122*2139Sjp161948
123*2139Sjp161948 * Functions ec_GFp_simple_points_make_affine() and
124*2139Sjp161948 * ec_GFp_simple_point_get_affine_coordinates() specifically assume
125*2139Sjp161948 * that if a non-trivial representation is used, it is a Montgomery
126*2139Sjp161948 * representation (i.e. 'encoding' means multiplying by some factor R).
127*2139Sjp161948 */
128*2139Sjp161948
129*2139Sjp161948
ec_GFp_simple_group_init(EC_GROUP * group)1300Sstevel@tonic-gate int ec_GFp_simple_group_init(EC_GROUP *group)
1310Sstevel@tonic-gate {
1320Sstevel@tonic-gate BN_init(&group->field);
1330Sstevel@tonic-gate BN_init(&group->a);
1340Sstevel@tonic-gate BN_init(&group->b);
1350Sstevel@tonic-gate group->a_is_minus3 = 0;
1360Sstevel@tonic-gate return 1;
1370Sstevel@tonic-gate }
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate
ec_GFp_simple_group_finish(EC_GROUP * group)1400Sstevel@tonic-gate void ec_GFp_simple_group_finish(EC_GROUP *group)
1410Sstevel@tonic-gate {
1420Sstevel@tonic-gate BN_free(&group->field);
1430Sstevel@tonic-gate BN_free(&group->a);
1440Sstevel@tonic-gate BN_free(&group->b);
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate
ec_GFp_simple_group_clear_finish(EC_GROUP * group)1480Sstevel@tonic-gate void ec_GFp_simple_group_clear_finish(EC_GROUP *group)
1490Sstevel@tonic-gate {
1500Sstevel@tonic-gate BN_clear_free(&group->field);
1510Sstevel@tonic-gate BN_clear_free(&group->a);
1520Sstevel@tonic-gate BN_clear_free(&group->b);
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate
ec_GFp_simple_group_copy(EC_GROUP * dest,const EC_GROUP * src)1560Sstevel@tonic-gate int ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate if (!BN_copy(&dest->field, &src->field)) return 0;
1590Sstevel@tonic-gate if (!BN_copy(&dest->a, &src->a)) return 0;
1600Sstevel@tonic-gate if (!BN_copy(&dest->b, &src->b)) return 0;
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate dest->a_is_minus3 = src->a_is_minus3;
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate return 1;
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate
ec_GFp_simple_group_set_curve(EC_GROUP * group,const BIGNUM * p,const BIGNUM * a,const BIGNUM * b,BN_CTX * ctx)168*2139Sjp161948 int ec_GFp_simple_group_set_curve(EC_GROUP *group,
1690Sstevel@tonic-gate const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
1700Sstevel@tonic-gate {
1710Sstevel@tonic-gate int ret = 0;
1720Sstevel@tonic-gate BN_CTX *new_ctx = NULL;
1730Sstevel@tonic-gate BIGNUM *tmp_a;
1740Sstevel@tonic-gate
1750Sstevel@tonic-gate /* p must be a prime > 3 */
1760Sstevel@tonic-gate if (BN_num_bits(p) <= 2 || !BN_is_odd(p))
1770Sstevel@tonic-gate {
178*2139Sjp161948 ECerr(EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE, EC_R_INVALID_FIELD);
1790Sstevel@tonic-gate return 0;
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate if (ctx == NULL)
1830Sstevel@tonic-gate {
1840Sstevel@tonic-gate ctx = new_ctx = BN_CTX_new();
1850Sstevel@tonic-gate if (ctx == NULL)
1860Sstevel@tonic-gate return 0;
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate
1890Sstevel@tonic-gate BN_CTX_start(ctx);
1900Sstevel@tonic-gate tmp_a = BN_CTX_get(ctx);
1910Sstevel@tonic-gate if (tmp_a == NULL) goto err;
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate /* group->field */
1940Sstevel@tonic-gate if (!BN_copy(&group->field, p)) goto err;
195*2139Sjp161948 BN_set_negative(&group->field, 0);
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate /* group->a */
1980Sstevel@tonic-gate if (!BN_nnmod(tmp_a, a, p, ctx)) goto err;
1990Sstevel@tonic-gate if (group->meth->field_encode)
2000Sstevel@tonic-gate { if (!group->meth->field_encode(group, &group->a, tmp_a, ctx)) goto err; }
2010Sstevel@tonic-gate else
2020Sstevel@tonic-gate if (!BN_copy(&group->a, tmp_a)) goto err;
2030Sstevel@tonic-gate
2040Sstevel@tonic-gate /* group->b */
2050Sstevel@tonic-gate if (!BN_nnmod(&group->b, b, p, ctx)) goto err;
2060Sstevel@tonic-gate if (group->meth->field_encode)
2070Sstevel@tonic-gate if (!group->meth->field_encode(group, &group->b, &group->b, ctx)) goto err;
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate /* group->a_is_minus3 */
2100Sstevel@tonic-gate if (!BN_add_word(tmp_a, 3)) goto err;
2110Sstevel@tonic-gate group->a_is_minus3 = (0 == BN_cmp(tmp_a, &group->field));
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate ret = 1;
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate err:
2160Sstevel@tonic-gate BN_CTX_end(ctx);
2170Sstevel@tonic-gate if (new_ctx != NULL)
2180Sstevel@tonic-gate BN_CTX_free(new_ctx);
2190Sstevel@tonic-gate return ret;
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate
ec_GFp_simple_group_get_curve(const EC_GROUP * group,BIGNUM * p,BIGNUM * a,BIGNUM * b,BN_CTX * ctx)223*2139Sjp161948 int ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *ctx)
2240Sstevel@tonic-gate {
2250Sstevel@tonic-gate int ret = 0;
2260Sstevel@tonic-gate BN_CTX *new_ctx = NULL;
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate if (p != NULL)
2290Sstevel@tonic-gate {
2300Sstevel@tonic-gate if (!BN_copy(p, &group->field)) return 0;
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate
2330Sstevel@tonic-gate if (a != NULL || b != NULL)
2340Sstevel@tonic-gate {
2350Sstevel@tonic-gate if (group->meth->field_decode)
2360Sstevel@tonic-gate {
2370Sstevel@tonic-gate if (ctx == NULL)
2380Sstevel@tonic-gate {
2390Sstevel@tonic-gate ctx = new_ctx = BN_CTX_new();
2400Sstevel@tonic-gate if (ctx == NULL)
2410Sstevel@tonic-gate return 0;
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate if (a != NULL)
2440Sstevel@tonic-gate {
2450Sstevel@tonic-gate if (!group->meth->field_decode(group, a, &group->a, ctx)) goto err;
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate if (b != NULL)
2480Sstevel@tonic-gate {
2490Sstevel@tonic-gate if (!group->meth->field_decode(group, b, &group->b, ctx)) goto err;
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate }
2520Sstevel@tonic-gate else
2530Sstevel@tonic-gate {
2540Sstevel@tonic-gate if (a != NULL)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate if (!BN_copy(a, &group->a)) goto err;
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate if (b != NULL)
2590Sstevel@tonic-gate {
2600Sstevel@tonic-gate if (!BN_copy(b, &group->b)) goto err;
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate }
2640Sstevel@tonic-gate
2650Sstevel@tonic-gate ret = 1;
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate err:
2680Sstevel@tonic-gate if (new_ctx)
2690Sstevel@tonic-gate BN_CTX_free(new_ctx);
2700Sstevel@tonic-gate return ret;
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate
2730Sstevel@tonic-gate
ec_GFp_simple_group_get_degree(const EC_GROUP * group)274*2139Sjp161948 int ec_GFp_simple_group_get_degree(const EC_GROUP *group)
2750Sstevel@tonic-gate {
276*2139Sjp161948 return BN_num_bits(&group->field);
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate
ec_GFp_simple_group_check_discriminant(const EC_GROUP * group,BN_CTX * ctx)280*2139Sjp161948 int ec_GFp_simple_group_check_discriminant(const EC_GROUP *group, BN_CTX *ctx)
2810Sstevel@tonic-gate {
282*2139Sjp161948 int ret = 0;
283*2139Sjp161948 BIGNUM *a,*b,*order,*tmp_1,*tmp_2;
284*2139Sjp161948 const BIGNUM *p = &group->field;
285*2139Sjp161948 BN_CTX *new_ctx = NULL;
2860Sstevel@tonic-gate
287*2139Sjp161948 if (ctx == NULL)
288*2139Sjp161948 {
289*2139Sjp161948 ctx = new_ctx = BN_CTX_new();
290*2139Sjp161948 if (ctx == NULL)
291*2139Sjp161948 {
292*2139Sjp161948 ECerr(EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT, ERR_R_MALLOC_FAILURE);
293*2139Sjp161948 goto err;
294*2139Sjp161948 }
295*2139Sjp161948 }
296*2139Sjp161948 BN_CTX_start(ctx);
297*2139Sjp161948 a = BN_CTX_get(ctx);
298*2139Sjp161948 b = BN_CTX_get(ctx);
299*2139Sjp161948 tmp_1 = BN_CTX_get(ctx);
300*2139Sjp161948 tmp_2 = BN_CTX_get(ctx);
301*2139Sjp161948 order = BN_CTX_get(ctx);
302*2139Sjp161948 if (order == NULL) goto err;
3030Sstevel@tonic-gate
304*2139Sjp161948 if (group->meth->field_decode)
305*2139Sjp161948 {
306*2139Sjp161948 if (!group->meth->field_decode(group, a, &group->a, ctx)) goto err;
307*2139Sjp161948 if (!group->meth->field_decode(group, b, &group->b, ctx)) goto err;
308*2139Sjp161948 }
309*2139Sjp161948 else
310*2139Sjp161948 {
311*2139Sjp161948 if (!BN_copy(a, &group->a)) goto err;
312*2139Sjp161948 if (!BN_copy(b, &group->b)) goto err;
313*2139Sjp161948 }
314*2139Sjp161948
315*2139Sjp161948 /* check the discriminant:
316*2139Sjp161948 * y^2 = x^3 + a*x + b is an elliptic curve <=> 4*a^3 + 27*b^2 != 0 (mod p)
317*2139Sjp161948 * 0 =< a, b < p */
318*2139Sjp161948 if (BN_is_zero(a))
319*2139Sjp161948 {
320*2139Sjp161948 if (BN_is_zero(b)) goto err;
321*2139Sjp161948 }
322*2139Sjp161948 else if (!BN_is_zero(b))
323*2139Sjp161948 {
324*2139Sjp161948 if (!BN_mod_sqr(tmp_1, a, p, ctx)) goto err;
325*2139Sjp161948 if (!BN_mod_mul(tmp_2, tmp_1, a, p, ctx)) goto err;
326*2139Sjp161948 if (!BN_lshift(tmp_1, tmp_2, 2)) goto err;
327*2139Sjp161948 /* tmp_1 = 4*a^3 */
3280Sstevel@tonic-gate
329*2139Sjp161948 if (!BN_mod_sqr(tmp_2, b, p, ctx)) goto err;
330*2139Sjp161948 if (!BN_mul_word(tmp_2, 27)) goto err;
331*2139Sjp161948 /* tmp_2 = 27*b^2 */
3320Sstevel@tonic-gate
333*2139Sjp161948 if (!BN_mod_add(a, tmp_1, tmp_2, p, ctx)) goto err;
334*2139Sjp161948 if (BN_is_zero(a)) goto err;
335*2139Sjp161948 }
336*2139Sjp161948 ret = 1;
337*2139Sjp161948
338*2139Sjp161948 err:
339*2139Sjp161948 BN_CTX_end(ctx);
340*2139Sjp161948 if (new_ctx != NULL)
341*2139Sjp161948 BN_CTX_free(new_ctx);
342*2139Sjp161948 return ret;
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate
ec_GFp_simple_point_init(EC_POINT * point)3460Sstevel@tonic-gate int ec_GFp_simple_point_init(EC_POINT *point)
3470Sstevel@tonic-gate {
3480Sstevel@tonic-gate BN_init(&point->X);
3490Sstevel@tonic-gate BN_init(&point->Y);
3500Sstevel@tonic-gate BN_init(&point->Z);
3510Sstevel@tonic-gate point->Z_is_one = 0;
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate return 1;
3540Sstevel@tonic-gate }
3550Sstevel@tonic-gate
3560Sstevel@tonic-gate
ec_GFp_simple_point_finish(EC_POINT * point)3570Sstevel@tonic-gate void ec_GFp_simple_point_finish(EC_POINT *point)
3580Sstevel@tonic-gate {
3590Sstevel@tonic-gate BN_free(&point->X);
3600Sstevel@tonic-gate BN_free(&point->Y);
3610Sstevel@tonic-gate BN_free(&point->Z);
3620Sstevel@tonic-gate }
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate
ec_GFp_simple_point_clear_finish(EC_POINT * point)3650Sstevel@tonic-gate void ec_GFp_simple_point_clear_finish(EC_POINT *point)
3660Sstevel@tonic-gate {
3670Sstevel@tonic-gate BN_clear_free(&point->X);
3680Sstevel@tonic-gate BN_clear_free(&point->Y);
3690Sstevel@tonic-gate BN_clear_free(&point->Z);
3700Sstevel@tonic-gate point->Z_is_one = 0;
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate
3730Sstevel@tonic-gate
ec_GFp_simple_point_copy(EC_POINT * dest,const EC_POINT * src)3740Sstevel@tonic-gate int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src)
3750Sstevel@tonic-gate {
3760Sstevel@tonic-gate if (!BN_copy(&dest->X, &src->X)) return 0;
3770Sstevel@tonic-gate if (!BN_copy(&dest->Y, &src->Y)) return 0;
3780Sstevel@tonic-gate if (!BN_copy(&dest->Z, &src->Z)) return 0;
3790Sstevel@tonic-gate dest->Z_is_one = src->Z_is_one;
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate return 1;
3820Sstevel@tonic-gate }
3830Sstevel@tonic-gate
3840Sstevel@tonic-gate
ec_GFp_simple_point_set_to_infinity(const EC_GROUP * group,EC_POINT * point)3850Sstevel@tonic-gate int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group, EC_POINT *point)
3860Sstevel@tonic-gate {
3870Sstevel@tonic-gate point->Z_is_one = 0;
388*2139Sjp161948 BN_zero(&point->Z);
389*2139Sjp161948 return 1;
3900Sstevel@tonic-gate }
3910Sstevel@tonic-gate
3920Sstevel@tonic-gate
ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP * group,EC_POINT * point,const BIGNUM * x,const BIGNUM * y,const BIGNUM * z,BN_CTX * ctx)3930Sstevel@tonic-gate int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
3940Sstevel@tonic-gate const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *ctx)
3950Sstevel@tonic-gate {
3960Sstevel@tonic-gate BN_CTX *new_ctx = NULL;
3970Sstevel@tonic-gate int ret = 0;
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate if (ctx == NULL)
4000Sstevel@tonic-gate {
4010Sstevel@tonic-gate ctx = new_ctx = BN_CTX_new();
4020Sstevel@tonic-gate if (ctx == NULL)
4030Sstevel@tonic-gate return 0;
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate if (x != NULL)
4070Sstevel@tonic-gate {
4080Sstevel@tonic-gate if (!BN_nnmod(&point->X, x, &group->field, ctx)) goto err;
4090Sstevel@tonic-gate if (group->meth->field_encode)
4100Sstevel@tonic-gate {
4110Sstevel@tonic-gate if (!group->meth->field_encode(group, &point->X, &point->X, ctx)) goto err;
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate
4150Sstevel@tonic-gate if (y != NULL)
4160Sstevel@tonic-gate {
4170Sstevel@tonic-gate if (!BN_nnmod(&point->Y, y, &group->field, ctx)) goto err;
4180Sstevel@tonic-gate if (group->meth->field_encode)
4190Sstevel@tonic-gate {
4200Sstevel@tonic-gate if (!group->meth->field_encode(group, &point->Y, &point->Y, ctx)) goto err;
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate if (z != NULL)
4250Sstevel@tonic-gate {
4260Sstevel@tonic-gate int Z_is_one;
4270Sstevel@tonic-gate
4280Sstevel@tonic-gate if (!BN_nnmod(&point->Z, z, &group->field, ctx)) goto err;
4290Sstevel@tonic-gate Z_is_one = BN_is_one(&point->Z);
4300Sstevel@tonic-gate if (group->meth->field_encode)
4310Sstevel@tonic-gate {
4320Sstevel@tonic-gate if (Z_is_one && (group->meth->field_set_to_one != 0))
4330Sstevel@tonic-gate {
4340Sstevel@tonic-gate if (!group->meth->field_set_to_one(group, &point->Z, ctx)) goto err;
4350Sstevel@tonic-gate }
4360Sstevel@tonic-gate else
4370Sstevel@tonic-gate {
4380Sstevel@tonic-gate if (!group->meth->field_encode(group, &point->Z, &point->Z, ctx)) goto err;
4390Sstevel@tonic-gate }
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate point->Z_is_one = Z_is_one;
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate
4440Sstevel@tonic-gate ret = 1;
4450Sstevel@tonic-gate
4460Sstevel@tonic-gate err:
4470Sstevel@tonic-gate if (new_ctx != NULL)
4480Sstevel@tonic-gate BN_CTX_free(new_ctx);
4490Sstevel@tonic-gate return ret;
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate
4520Sstevel@tonic-gate
ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP * group,const EC_POINT * point,BIGNUM * x,BIGNUM * y,BIGNUM * z,BN_CTX * ctx)4530Sstevel@tonic-gate int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group, const EC_POINT *point,
4540Sstevel@tonic-gate BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *ctx)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate BN_CTX *new_ctx = NULL;
4570Sstevel@tonic-gate int ret = 0;
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate if (group->meth->field_decode != 0)
4600Sstevel@tonic-gate {
4610Sstevel@tonic-gate if (ctx == NULL)
4620Sstevel@tonic-gate {
4630Sstevel@tonic-gate ctx = new_ctx = BN_CTX_new();
4640Sstevel@tonic-gate if (ctx == NULL)
4650Sstevel@tonic-gate return 0;
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate if (x != NULL)
4690Sstevel@tonic-gate {
4700Sstevel@tonic-gate if (!group->meth->field_decode(group, x, &point->X, ctx)) goto err;
4710Sstevel@tonic-gate }
4720Sstevel@tonic-gate if (y != NULL)
4730Sstevel@tonic-gate {
4740Sstevel@tonic-gate if (!group->meth->field_decode(group, y, &point->Y, ctx)) goto err;
4750Sstevel@tonic-gate }
4760Sstevel@tonic-gate if (z != NULL)
4770Sstevel@tonic-gate {
4780Sstevel@tonic-gate if (!group->meth->field_decode(group, z, &point->Z, ctx)) goto err;
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate else
4820Sstevel@tonic-gate {
4830Sstevel@tonic-gate if (x != NULL)
4840Sstevel@tonic-gate {
4850Sstevel@tonic-gate if (!BN_copy(x, &point->X)) goto err;
4860Sstevel@tonic-gate }
4870Sstevel@tonic-gate if (y != NULL)
4880Sstevel@tonic-gate {
4890Sstevel@tonic-gate if (!BN_copy(y, &point->Y)) goto err;
4900Sstevel@tonic-gate }
4910Sstevel@tonic-gate if (z != NULL)
4920Sstevel@tonic-gate {
4930Sstevel@tonic-gate if (!BN_copy(z, &point->Z)) goto err;
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate
4970Sstevel@tonic-gate ret = 1;
4980Sstevel@tonic-gate
4990Sstevel@tonic-gate err:
5000Sstevel@tonic-gate if (new_ctx != NULL)
5010Sstevel@tonic-gate BN_CTX_free(new_ctx);
5020Sstevel@tonic-gate return ret;
5030Sstevel@tonic-gate }
5040Sstevel@tonic-gate
5050Sstevel@tonic-gate
ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP * group,EC_POINT * point,const BIGNUM * x,const BIGNUM * y,BN_CTX * ctx)506*2139Sjp161948 int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group, EC_POINT *point,
5070Sstevel@tonic-gate const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx)
5080Sstevel@tonic-gate {
5090Sstevel@tonic-gate if (x == NULL || y == NULL)
5100Sstevel@tonic-gate {
5110Sstevel@tonic-gate /* unlike for projective coordinates, we do not tolerate this */
512*2139Sjp161948 ECerr(EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES, ERR_R_PASSED_NULL_PARAMETER);
5130Sstevel@tonic-gate return 0;
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate return EC_POINT_set_Jprojective_coordinates_GFp(group, point, x, y, BN_value_one(), ctx);
5170Sstevel@tonic-gate }
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate
ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP * group,const EC_POINT * point,BIGNUM * x,BIGNUM * y,BN_CTX * ctx)520*2139Sjp161948 int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point,
5210Sstevel@tonic-gate BIGNUM *x, BIGNUM *y, BN_CTX *ctx)
5220Sstevel@tonic-gate {
5230Sstevel@tonic-gate BN_CTX *new_ctx = NULL;
524*2139Sjp161948 BIGNUM *Z, *Z_1, *Z_2, *Z_3;
525*2139Sjp161948 const BIGNUM *Z_;
5260Sstevel@tonic-gate int ret = 0;
5270Sstevel@tonic-gate
5280Sstevel@tonic-gate if (EC_POINT_is_at_infinity(group, point))
5290Sstevel@tonic-gate {
530*2139Sjp161948 ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES, EC_R_POINT_AT_INFINITY);
5310Sstevel@tonic-gate return 0;
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate if (ctx == NULL)
5350Sstevel@tonic-gate {
5360Sstevel@tonic-gate ctx = new_ctx = BN_CTX_new();
5370Sstevel@tonic-gate if (ctx == NULL)
5380Sstevel@tonic-gate return 0;
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate BN_CTX_start(ctx);
5420Sstevel@tonic-gate Z = BN_CTX_get(ctx);
5430Sstevel@tonic-gate Z_1 = BN_CTX_get(ctx);
5440Sstevel@tonic-gate Z_2 = BN_CTX_get(ctx);
5450Sstevel@tonic-gate Z_3 = BN_CTX_get(ctx);
5460Sstevel@tonic-gate if (Z_3 == NULL) goto err;
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */
5490Sstevel@tonic-gate
5500Sstevel@tonic-gate if (group->meth->field_decode)
5510Sstevel@tonic-gate {
5520Sstevel@tonic-gate if (!group->meth->field_decode(group, Z, &point->Z, ctx)) goto err;
553*2139Sjp161948 Z_ = Z;
5540Sstevel@tonic-gate }
5550Sstevel@tonic-gate else
5560Sstevel@tonic-gate {
5570Sstevel@tonic-gate Z_ = &point->Z;
5580Sstevel@tonic-gate }
5590Sstevel@tonic-gate
5600Sstevel@tonic-gate if (BN_is_one(Z_))
5610Sstevel@tonic-gate {
562*2139Sjp161948 if (group->meth->field_decode)
5630Sstevel@tonic-gate {
564*2139Sjp161948 if (x != NULL)
565*2139Sjp161948 {
566*2139Sjp161948 if (!group->meth->field_decode(group, x, &point->X, ctx)) goto err;
567*2139Sjp161948 }
568*2139Sjp161948 if (y != NULL)
569*2139Sjp161948 {
570*2139Sjp161948 if (!group->meth->field_decode(group, y, &point->Y, ctx)) goto err;
571*2139Sjp161948 }
5720Sstevel@tonic-gate }
573*2139Sjp161948 else
5740Sstevel@tonic-gate {
575*2139Sjp161948 if (x != NULL)
576*2139Sjp161948 {
577*2139Sjp161948 if (!BN_copy(x, &point->X)) goto err;
578*2139Sjp161948 }
579*2139Sjp161948 if (y != NULL)
580*2139Sjp161948 {
581*2139Sjp161948 if (!BN_copy(y, &point->Y)) goto err;
582*2139Sjp161948 }
5830Sstevel@tonic-gate }
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate else
5860Sstevel@tonic-gate {
5870Sstevel@tonic-gate if (!BN_mod_inverse(Z_1, Z_, &group->field, ctx))
5880Sstevel@tonic-gate {
589*2139Sjp161948 ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES, ERR_R_BN_LIB);
5900Sstevel@tonic-gate goto err;
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate
5930Sstevel@tonic-gate if (group->meth->field_encode == 0)
5940Sstevel@tonic-gate {
5950Sstevel@tonic-gate /* field_sqr works on standard representation */
5960Sstevel@tonic-gate if (!group->meth->field_sqr(group, Z_2, Z_1, ctx)) goto err;
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate else
5990Sstevel@tonic-gate {
6000Sstevel@tonic-gate if (!BN_mod_sqr(Z_2, Z_1, &group->field, ctx)) goto err;
6010Sstevel@tonic-gate }
6020Sstevel@tonic-gate
6030Sstevel@tonic-gate if (x != NULL)
6040Sstevel@tonic-gate {
605*2139Sjp161948 /* in the Montgomery case, field_mul will cancel out Montgomery factor in X: */
606*2139Sjp161948 if (!group->meth->field_mul(group, x, &point->X, Z_2, ctx)) goto err;
6070Sstevel@tonic-gate }
6080Sstevel@tonic-gate
6090Sstevel@tonic-gate if (y != NULL)
6100Sstevel@tonic-gate {
6110Sstevel@tonic-gate if (group->meth->field_encode == 0)
6120Sstevel@tonic-gate {
6130Sstevel@tonic-gate /* field_mul works on standard representation */
6140Sstevel@tonic-gate if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx)) goto err;
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate else
6170Sstevel@tonic-gate {
6180Sstevel@tonic-gate if (!BN_mod_mul(Z_3, Z_2, Z_1, &group->field, ctx)) goto err;
6190Sstevel@tonic-gate }
620*2139Sjp161948
621*2139Sjp161948 /* in the Montgomery case, field_mul will cancel out Montgomery factor in Y: */
622*2139Sjp161948 if (!group->meth->field_mul(group, y, &point->Y, Z_3, ctx)) goto err;
6230Sstevel@tonic-gate }
6240Sstevel@tonic-gate }
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate ret = 1;
6270Sstevel@tonic-gate
6280Sstevel@tonic-gate err:
6290Sstevel@tonic-gate BN_CTX_end(ctx);
6300Sstevel@tonic-gate if (new_ctx != NULL)
6310Sstevel@tonic-gate BN_CTX_free(new_ctx);
6320Sstevel@tonic-gate return ret;
6330Sstevel@tonic-gate }
6340Sstevel@tonic-gate
6350Sstevel@tonic-gate
ec_GFp_simple_set_compressed_coordinates(const EC_GROUP * group,EC_POINT * point,const BIGNUM * x_,int y_bit,BN_CTX * ctx)636*2139Sjp161948 int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, EC_POINT *point,
6370Sstevel@tonic-gate const BIGNUM *x_, int y_bit, BN_CTX *ctx)
6380Sstevel@tonic-gate {
6390Sstevel@tonic-gate BN_CTX *new_ctx = NULL;
6400Sstevel@tonic-gate BIGNUM *tmp1, *tmp2, *x, *y;
6410Sstevel@tonic-gate int ret = 0;
6420Sstevel@tonic-gate
643*2139Sjp161948 /* clear error queue*/
644*2139Sjp161948 ERR_clear_error();
645*2139Sjp161948
6460Sstevel@tonic-gate if (ctx == NULL)
6470Sstevel@tonic-gate {
6480Sstevel@tonic-gate ctx = new_ctx = BN_CTX_new();
6490Sstevel@tonic-gate if (ctx == NULL)
6500Sstevel@tonic-gate return 0;
6510Sstevel@tonic-gate }
6520Sstevel@tonic-gate
6530Sstevel@tonic-gate y_bit = (y_bit != 0);
6540Sstevel@tonic-gate
6550Sstevel@tonic-gate BN_CTX_start(ctx);
6560Sstevel@tonic-gate tmp1 = BN_CTX_get(ctx);
6570Sstevel@tonic-gate tmp2 = BN_CTX_get(ctx);
6580Sstevel@tonic-gate x = BN_CTX_get(ctx);
6590Sstevel@tonic-gate y = BN_CTX_get(ctx);
6600Sstevel@tonic-gate if (y == NULL) goto err;
6610Sstevel@tonic-gate
6620Sstevel@tonic-gate /* Recover y. We have a Weierstrass equation
6630Sstevel@tonic-gate * y^2 = x^3 + a*x + b,
6640Sstevel@tonic-gate * so y is one of the square roots of x^3 + a*x + b.
6650Sstevel@tonic-gate */
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate /* tmp1 := x^3 */
6680Sstevel@tonic-gate if (!BN_nnmod(x, x_, &group->field,ctx)) goto err;
6690Sstevel@tonic-gate if (group->meth->field_decode == 0)
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate /* field_{sqr,mul} work on standard representation */
6720Sstevel@tonic-gate if (!group->meth->field_sqr(group, tmp2, x_, ctx)) goto err;
6730Sstevel@tonic-gate if (!group->meth->field_mul(group, tmp1, tmp2, x_, ctx)) goto err;
6740Sstevel@tonic-gate }
6750Sstevel@tonic-gate else
6760Sstevel@tonic-gate {
6770Sstevel@tonic-gate if (!BN_mod_sqr(tmp2, x_, &group->field, ctx)) goto err;
6780Sstevel@tonic-gate if (!BN_mod_mul(tmp1, tmp2, x_, &group->field, ctx)) goto err;
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate
6810Sstevel@tonic-gate /* tmp1 := tmp1 + a*x */
6820Sstevel@tonic-gate if (group->a_is_minus3)
6830Sstevel@tonic-gate {
6840Sstevel@tonic-gate if (!BN_mod_lshift1_quick(tmp2, x, &group->field)) goto err;
6850Sstevel@tonic-gate if (!BN_mod_add_quick(tmp2, tmp2, x, &group->field)) goto err;
6860Sstevel@tonic-gate if (!BN_mod_sub_quick(tmp1, tmp1, tmp2, &group->field)) goto err;
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate else
6890Sstevel@tonic-gate {
6900Sstevel@tonic-gate if (group->meth->field_decode)
6910Sstevel@tonic-gate {
6920Sstevel@tonic-gate if (!group->meth->field_decode(group, tmp2, &group->a, ctx)) goto err;
6930Sstevel@tonic-gate if (!BN_mod_mul(tmp2, tmp2, x, &group->field, ctx)) goto err;
6940Sstevel@tonic-gate }
6950Sstevel@tonic-gate else
6960Sstevel@tonic-gate {
6970Sstevel@tonic-gate /* field_mul works on standard representation */
6980Sstevel@tonic-gate if (!group->meth->field_mul(group, tmp2, &group->a, x, ctx)) goto err;
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate
7010Sstevel@tonic-gate if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) goto err;
7020Sstevel@tonic-gate }
7030Sstevel@tonic-gate
7040Sstevel@tonic-gate /* tmp1 := tmp1 + b */
7050Sstevel@tonic-gate if (group->meth->field_decode)
7060Sstevel@tonic-gate {
7070Sstevel@tonic-gate if (!group->meth->field_decode(group, tmp2, &group->b, ctx)) goto err;
7080Sstevel@tonic-gate if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) goto err;
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate else
7110Sstevel@tonic-gate {
7120Sstevel@tonic-gate if (!BN_mod_add_quick(tmp1, tmp1, &group->b, &group->field)) goto err;
7130Sstevel@tonic-gate }
7140Sstevel@tonic-gate
7150Sstevel@tonic-gate if (!BN_mod_sqrt(y, tmp1, &group->field, ctx))
7160Sstevel@tonic-gate {
717*2139Sjp161948 unsigned long err = ERR_peek_last_error();
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate if (ERR_GET_LIB(err) == ERR_LIB_BN && ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE)
7200Sstevel@tonic-gate {
721*2139Sjp161948 ERR_clear_error();
722*2139Sjp161948 ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSED_POINT);
7230Sstevel@tonic-gate }
7240Sstevel@tonic-gate else
725*2139Sjp161948 ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_BN_LIB);
7260Sstevel@tonic-gate goto err;
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate
7290Sstevel@tonic-gate if (y_bit != BN_is_odd(y))
7300Sstevel@tonic-gate {
7310Sstevel@tonic-gate if (BN_is_zero(y))
7320Sstevel@tonic-gate {
7330Sstevel@tonic-gate int kron;
7340Sstevel@tonic-gate
7350Sstevel@tonic-gate kron = BN_kronecker(x, &group->field, ctx);
7360Sstevel@tonic-gate if (kron == -2) goto err;
7370Sstevel@tonic-gate
7380Sstevel@tonic-gate if (kron == 1)
739*2139Sjp161948 ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSION_BIT);
7400Sstevel@tonic-gate else
741*2139Sjp161948 /* BN_mod_sqrt() should have cought this error (not a square) */
742*2139Sjp161948 ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSED_POINT);
7430Sstevel@tonic-gate goto err;
7440Sstevel@tonic-gate }
7450Sstevel@tonic-gate if (!BN_usub(y, &group->field, y)) goto err;
7460Sstevel@tonic-gate }
7470Sstevel@tonic-gate if (y_bit != BN_is_odd(y))
7480Sstevel@tonic-gate {
749*2139Sjp161948 ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_INTERNAL_ERROR);
7500Sstevel@tonic-gate goto err;
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate
7530Sstevel@tonic-gate if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
7540Sstevel@tonic-gate
7550Sstevel@tonic-gate ret = 1;
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate err:
7580Sstevel@tonic-gate BN_CTX_end(ctx);
7590Sstevel@tonic-gate if (new_ctx != NULL)
7600Sstevel@tonic-gate BN_CTX_free(new_ctx);
7610Sstevel@tonic-gate return ret;
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate
7640Sstevel@tonic-gate
ec_GFp_simple_point2oct(const EC_GROUP * group,const EC_POINT * point,point_conversion_form_t form,unsigned char * buf,size_t len,BN_CTX * ctx)7650Sstevel@tonic-gate size_t ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form,
7660Sstevel@tonic-gate unsigned char *buf, size_t len, BN_CTX *ctx)
7670Sstevel@tonic-gate {
7680Sstevel@tonic-gate size_t ret;
7690Sstevel@tonic-gate BN_CTX *new_ctx = NULL;
7700Sstevel@tonic-gate int used_ctx = 0;
7710Sstevel@tonic-gate BIGNUM *x, *y;
7720Sstevel@tonic-gate size_t field_len, i, skip;
7730Sstevel@tonic-gate
7740Sstevel@tonic-gate if ((form != POINT_CONVERSION_COMPRESSED)
7750Sstevel@tonic-gate && (form != POINT_CONVERSION_UNCOMPRESSED)
7760Sstevel@tonic-gate && (form != POINT_CONVERSION_HYBRID))
7770Sstevel@tonic-gate {
7780Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_INVALID_FORM);
7790Sstevel@tonic-gate goto err;
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate
7820Sstevel@tonic-gate if (EC_POINT_is_at_infinity(group, point))
7830Sstevel@tonic-gate {
7840Sstevel@tonic-gate /* encodes to a single 0 octet */
7850Sstevel@tonic-gate if (buf != NULL)
7860Sstevel@tonic-gate {
7870Sstevel@tonic-gate if (len < 1)
7880Sstevel@tonic-gate {
7890Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
7900Sstevel@tonic-gate return 0;
7910Sstevel@tonic-gate }
7920Sstevel@tonic-gate buf[0] = 0;
7930Sstevel@tonic-gate }
7940Sstevel@tonic-gate return 1;
7950Sstevel@tonic-gate }
7960Sstevel@tonic-gate
7970Sstevel@tonic-gate
7980Sstevel@tonic-gate /* ret := required output buffer length */
7990Sstevel@tonic-gate field_len = BN_num_bytes(&group->field);
8000Sstevel@tonic-gate ret = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len;
8010Sstevel@tonic-gate
8020Sstevel@tonic-gate /* if 'buf' is NULL, just return required length */
8030Sstevel@tonic-gate if (buf != NULL)
8040Sstevel@tonic-gate {
8050Sstevel@tonic-gate if (len < ret)
8060Sstevel@tonic-gate {
8070Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
8080Sstevel@tonic-gate goto err;
8090Sstevel@tonic-gate }
8100Sstevel@tonic-gate
8110Sstevel@tonic-gate if (ctx == NULL)
8120Sstevel@tonic-gate {
8130Sstevel@tonic-gate ctx = new_ctx = BN_CTX_new();
8140Sstevel@tonic-gate if (ctx == NULL)
8150Sstevel@tonic-gate return 0;
8160Sstevel@tonic-gate }
8170Sstevel@tonic-gate
8180Sstevel@tonic-gate BN_CTX_start(ctx);
8190Sstevel@tonic-gate used_ctx = 1;
8200Sstevel@tonic-gate x = BN_CTX_get(ctx);
8210Sstevel@tonic-gate y = BN_CTX_get(ctx);
8220Sstevel@tonic-gate if (y == NULL) goto err;
8230Sstevel@tonic-gate
8240Sstevel@tonic-gate if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
8250Sstevel@tonic-gate
8260Sstevel@tonic-gate if ((form == POINT_CONVERSION_COMPRESSED || form == POINT_CONVERSION_HYBRID) && BN_is_odd(y))
8270Sstevel@tonic-gate buf[0] = form + 1;
8280Sstevel@tonic-gate else
8290Sstevel@tonic-gate buf[0] = form;
8300Sstevel@tonic-gate
8310Sstevel@tonic-gate i = 1;
8320Sstevel@tonic-gate
8330Sstevel@tonic-gate skip = field_len - BN_num_bytes(x);
8340Sstevel@tonic-gate if (skip > field_len)
8350Sstevel@tonic-gate {
8360Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
8370Sstevel@tonic-gate goto err;
8380Sstevel@tonic-gate }
8390Sstevel@tonic-gate while (skip > 0)
8400Sstevel@tonic-gate {
8410Sstevel@tonic-gate buf[i++] = 0;
8420Sstevel@tonic-gate skip--;
8430Sstevel@tonic-gate }
8440Sstevel@tonic-gate skip = BN_bn2bin(x, buf + i);
8450Sstevel@tonic-gate i += skip;
8460Sstevel@tonic-gate if (i != 1 + field_len)
8470Sstevel@tonic-gate {
8480Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
8490Sstevel@tonic-gate goto err;
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate
8520Sstevel@tonic-gate if (form == POINT_CONVERSION_UNCOMPRESSED || form == POINT_CONVERSION_HYBRID)
8530Sstevel@tonic-gate {
8540Sstevel@tonic-gate skip = field_len - BN_num_bytes(y);
8550Sstevel@tonic-gate if (skip > field_len)
8560Sstevel@tonic-gate {
8570Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
8580Sstevel@tonic-gate goto err;
8590Sstevel@tonic-gate }
8600Sstevel@tonic-gate while (skip > 0)
8610Sstevel@tonic-gate {
8620Sstevel@tonic-gate buf[i++] = 0;
8630Sstevel@tonic-gate skip--;
8640Sstevel@tonic-gate }
8650Sstevel@tonic-gate skip = BN_bn2bin(y, buf + i);
8660Sstevel@tonic-gate i += skip;
8670Sstevel@tonic-gate }
8680Sstevel@tonic-gate
8690Sstevel@tonic-gate if (i != ret)
8700Sstevel@tonic-gate {
8710Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
8720Sstevel@tonic-gate goto err;
8730Sstevel@tonic-gate }
8740Sstevel@tonic-gate }
8750Sstevel@tonic-gate
8760Sstevel@tonic-gate if (used_ctx)
8770Sstevel@tonic-gate BN_CTX_end(ctx);
8780Sstevel@tonic-gate if (new_ctx != NULL)
8790Sstevel@tonic-gate BN_CTX_free(new_ctx);
8800Sstevel@tonic-gate return ret;
8810Sstevel@tonic-gate
8820Sstevel@tonic-gate err:
8830Sstevel@tonic-gate if (used_ctx)
8840Sstevel@tonic-gate BN_CTX_end(ctx);
8850Sstevel@tonic-gate if (new_ctx != NULL)
8860Sstevel@tonic-gate BN_CTX_free(new_ctx);
8870Sstevel@tonic-gate return 0;
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate
ec_GFp_simple_oct2point(const EC_GROUP * group,EC_POINT * point,const unsigned char * buf,size_t len,BN_CTX * ctx)8910Sstevel@tonic-gate int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
8920Sstevel@tonic-gate const unsigned char *buf, size_t len, BN_CTX *ctx)
8930Sstevel@tonic-gate {
8940Sstevel@tonic-gate point_conversion_form_t form;
8950Sstevel@tonic-gate int y_bit;
8960Sstevel@tonic-gate BN_CTX *new_ctx = NULL;
8970Sstevel@tonic-gate BIGNUM *x, *y;
8980Sstevel@tonic-gate size_t field_len, enc_len;
8990Sstevel@tonic-gate int ret = 0;
9000Sstevel@tonic-gate
9010Sstevel@tonic-gate if (len == 0)
9020Sstevel@tonic-gate {
9030Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_BUFFER_TOO_SMALL);
9040Sstevel@tonic-gate return 0;
9050Sstevel@tonic-gate }
9060Sstevel@tonic-gate form = buf[0];
9070Sstevel@tonic-gate y_bit = form & 1;
9080Sstevel@tonic-gate form = form & ~1U;
9090Sstevel@tonic-gate if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED)
9100Sstevel@tonic-gate && (form != POINT_CONVERSION_UNCOMPRESSED)
9110Sstevel@tonic-gate && (form != POINT_CONVERSION_HYBRID))
9120Sstevel@tonic-gate {
9130Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
9140Sstevel@tonic-gate return 0;
9150Sstevel@tonic-gate }
9160Sstevel@tonic-gate if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit)
9170Sstevel@tonic-gate {
9180Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
9190Sstevel@tonic-gate return 0;
9200Sstevel@tonic-gate }
9210Sstevel@tonic-gate
9220Sstevel@tonic-gate if (form == 0)
9230Sstevel@tonic-gate {
9240Sstevel@tonic-gate if (len != 1)
9250Sstevel@tonic-gate {
9260Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
9270Sstevel@tonic-gate return 0;
9280Sstevel@tonic-gate }
9290Sstevel@tonic-gate
9300Sstevel@tonic-gate return EC_POINT_set_to_infinity(group, point);
9310Sstevel@tonic-gate }
9320Sstevel@tonic-gate
9330Sstevel@tonic-gate field_len = BN_num_bytes(&group->field);
9340Sstevel@tonic-gate enc_len = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len;
9350Sstevel@tonic-gate
9360Sstevel@tonic-gate if (len != enc_len)
9370Sstevel@tonic-gate {
9380Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
9390Sstevel@tonic-gate return 0;
9400Sstevel@tonic-gate }
9410Sstevel@tonic-gate
9420Sstevel@tonic-gate if (ctx == NULL)
9430Sstevel@tonic-gate {
9440Sstevel@tonic-gate ctx = new_ctx = BN_CTX_new();
9450Sstevel@tonic-gate if (ctx == NULL)
9460Sstevel@tonic-gate return 0;
9470Sstevel@tonic-gate }
9480Sstevel@tonic-gate
9490Sstevel@tonic-gate BN_CTX_start(ctx);
9500Sstevel@tonic-gate x = BN_CTX_get(ctx);
9510Sstevel@tonic-gate y = BN_CTX_get(ctx);
9520Sstevel@tonic-gate if (y == NULL) goto err;
9530Sstevel@tonic-gate
9540Sstevel@tonic-gate if (!BN_bin2bn(buf + 1, field_len, x)) goto err;
9550Sstevel@tonic-gate if (BN_ucmp(x, &group->field) >= 0)
9560Sstevel@tonic-gate {
9570Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
9580Sstevel@tonic-gate goto err;
9590Sstevel@tonic-gate }
9600Sstevel@tonic-gate
9610Sstevel@tonic-gate if (form == POINT_CONVERSION_COMPRESSED)
9620Sstevel@tonic-gate {
9630Sstevel@tonic-gate if (!EC_POINT_set_compressed_coordinates_GFp(group, point, x, y_bit, ctx)) goto err;
9640Sstevel@tonic-gate }
9650Sstevel@tonic-gate else
9660Sstevel@tonic-gate {
9670Sstevel@tonic-gate if (!BN_bin2bn(buf + 1 + field_len, field_len, y)) goto err;
9680Sstevel@tonic-gate if (BN_ucmp(y, &group->field) >= 0)
9690Sstevel@tonic-gate {
9700Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
9710Sstevel@tonic-gate goto err;
9720Sstevel@tonic-gate }
9730Sstevel@tonic-gate if (form == POINT_CONVERSION_HYBRID)
9740Sstevel@tonic-gate {
9750Sstevel@tonic-gate if (y_bit != BN_is_odd(y))
9760Sstevel@tonic-gate {
9770Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
9780Sstevel@tonic-gate goto err;
9790Sstevel@tonic-gate }
9800Sstevel@tonic-gate }
9810Sstevel@tonic-gate
9820Sstevel@tonic-gate if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
9830Sstevel@tonic-gate }
9840Sstevel@tonic-gate
9850Sstevel@tonic-gate if (!EC_POINT_is_on_curve(group, point, ctx)) /* test required by X9.62 */
9860Sstevel@tonic-gate {
9870Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_POINT_IS_NOT_ON_CURVE);
9880Sstevel@tonic-gate goto err;
9890Sstevel@tonic-gate }
9900Sstevel@tonic-gate
9910Sstevel@tonic-gate ret = 1;
9920Sstevel@tonic-gate
9930Sstevel@tonic-gate err:
9940Sstevel@tonic-gate BN_CTX_end(ctx);
9950Sstevel@tonic-gate if (new_ctx != NULL)
9960Sstevel@tonic-gate BN_CTX_free(new_ctx);
9970Sstevel@tonic-gate return ret;
9980Sstevel@tonic-gate }
9990Sstevel@tonic-gate
10000Sstevel@tonic-gate
ec_GFp_simple_add(const EC_GROUP * group,EC_POINT * r,const EC_POINT * a,const EC_POINT * b,BN_CTX * ctx)10010Sstevel@tonic-gate int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx)
10020Sstevel@tonic-gate {
10030Sstevel@tonic-gate int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
10040Sstevel@tonic-gate int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
10050Sstevel@tonic-gate const BIGNUM *p;
10060Sstevel@tonic-gate BN_CTX *new_ctx = NULL;
10070Sstevel@tonic-gate BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6;
10080Sstevel@tonic-gate int ret = 0;
10090Sstevel@tonic-gate
10100Sstevel@tonic-gate if (a == b)
10110Sstevel@tonic-gate return EC_POINT_dbl(group, r, a, ctx);
10120Sstevel@tonic-gate if (EC_POINT_is_at_infinity(group, a))
10130Sstevel@tonic-gate return EC_POINT_copy(r, b);
10140Sstevel@tonic-gate if (EC_POINT_is_at_infinity(group, b))
10150Sstevel@tonic-gate return EC_POINT_copy(r, a);
10160Sstevel@tonic-gate
10170Sstevel@tonic-gate field_mul = group->meth->field_mul;
10180Sstevel@tonic-gate field_sqr = group->meth->field_sqr;
10190Sstevel@tonic-gate p = &group->field;
10200Sstevel@tonic-gate
10210Sstevel@tonic-gate if (ctx == NULL)
10220Sstevel@tonic-gate {
10230Sstevel@tonic-gate ctx = new_ctx = BN_CTX_new();
10240Sstevel@tonic-gate if (ctx == NULL)
10250Sstevel@tonic-gate return 0;
10260Sstevel@tonic-gate }
10270Sstevel@tonic-gate
10280Sstevel@tonic-gate BN_CTX_start(ctx);
10290Sstevel@tonic-gate n0 = BN_CTX_get(ctx);
10300Sstevel@tonic-gate n1 = BN_CTX_get(ctx);
10310Sstevel@tonic-gate n2 = BN_CTX_get(ctx);
10320Sstevel@tonic-gate n3 = BN_CTX_get(ctx);
10330Sstevel@tonic-gate n4 = BN_CTX_get(ctx);
10340Sstevel@tonic-gate n5 = BN_CTX_get(ctx);
10350Sstevel@tonic-gate n6 = BN_CTX_get(ctx);
10360Sstevel@tonic-gate if (n6 == NULL) goto end;
10370Sstevel@tonic-gate
10380Sstevel@tonic-gate /* Note that in this function we must not read components of 'a' or 'b'
10390Sstevel@tonic-gate * once we have written the corresponding components of 'r'.
10400Sstevel@tonic-gate * ('r' might be one of 'a' or 'b'.)
10410Sstevel@tonic-gate */
10420Sstevel@tonic-gate
10430Sstevel@tonic-gate /* n1, n2 */
10440Sstevel@tonic-gate if (b->Z_is_one)
10450Sstevel@tonic-gate {
10460Sstevel@tonic-gate if (!BN_copy(n1, &a->X)) goto end;
10470Sstevel@tonic-gate if (!BN_copy(n2, &a->Y)) goto end;
10480Sstevel@tonic-gate /* n1 = X_a */
10490Sstevel@tonic-gate /* n2 = Y_a */
10500Sstevel@tonic-gate }
10510Sstevel@tonic-gate else
10520Sstevel@tonic-gate {
10530Sstevel@tonic-gate if (!field_sqr(group, n0, &b->Z, ctx)) goto end;
10540Sstevel@tonic-gate if (!field_mul(group, n1, &a->X, n0, ctx)) goto end;
10550Sstevel@tonic-gate /* n1 = X_a * Z_b^2 */
10560Sstevel@tonic-gate
10570Sstevel@tonic-gate if (!field_mul(group, n0, n0, &b->Z, ctx)) goto end;
10580Sstevel@tonic-gate if (!field_mul(group, n2, &a->Y, n0, ctx)) goto end;
10590Sstevel@tonic-gate /* n2 = Y_a * Z_b^3 */
10600Sstevel@tonic-gate }
10610Sstevel@tonic-gate
10620Sstevel@tonic-gate /* n3, n4 */
10630Sstevel@tonic-gate if (a->Z_is_one)
10640Sstevel@tonic-gate {
10650Sstevel@tonic-gate if (!BN_copy(n3, &b->X)) goto end;
10660Sstevel@tonic-gate if (!BN_copy(n4, &b->Y)) goto end;
10670Sstevel@tonic-gate /* n3 = X_b */
10680Sstevel@tonic-gate /* n4 = Y_b */
10690Sstevel@tonic-gate }
10700Sstevel@tonic-gate else
10710Sstevel@tonic-gate {
10720Sstevel@tonic-gate if (!field_sqr(group, n0, &a->Z, ctx)) goto end;
10730Sstevel@tonic-gate if (!field_mul(group, n3, &b->X, n0, ctx)) goto end;
10740Sstevel@tonic-gate /* n3 = X_b * Z_a^2 */
10750Sstevel@tonic-gate
10760Sstevel@tonic-gate if (!field_mul(group, n0, n0, &a->Z, ctx)) goto end;
10770Sstevel@tonic-gate if (!field_mul(group, n4, &b->Y, n0, ctx)) goto end;
10780Sstevel@tonic-gate /* n4 = Y_b * Z_a^3 */
10790Sstevel@tonic-gate }
10800Sstevel@tonic-gate
10810Sstevel@tonic-gate /* n5, n6 */
10820Sstevel@tonic-gate if (!BN_mod_sub_quick(n5, n1, n3, p)) goto end;
10830Sstevel@tonic-gate if (!BN_mod_sub_quick(n6, n2, n4, p)) goto end;
10840Sstevel@tonic-gate /* n5 = n1 - n3 */
10850Sstevel@tonic-gate /* n6 = n2 - n4 */
10860Sstevel@tonic-gate
10870Sstevel@tonic-gate if (BN_is_zero(n5))
10880Sstevel@tonic-gate {
10890Sstevel@tonic-gate if (BN_is_zero(n6))
10900Sstevel@tonic-gate {
10910Sstevel@tonic-gate /* a is the same point as b */
10920Sstevel@tonic-gate BN_CTX_end(ctx);
10930Sstevel@tonic-gate ret = EC_POINT_dbl(group, r, a, ctx);
10940Sstevel@tonic-gate ctx = NULL;
10950Sstevel@tonic-gate goto end;
10960Sstevel@tonic-gate }
10970Sstevel@tonic-gate else
10980Sstevel@tonic-gate {
10990Sstevel@tonic-gate /* a is the inverse of b */
1100*2139Sjp161948 BN_zero(&r->Z);
11010Sstevel@tonic-gate r->Z_is_one = 0;
11020Sstevel@tonic-gate ret = 1;
11030Sstevel@tonic-gate goto end;
11040Sstevel@tonic-gate }
11050Sstevel@tonic-gate }
11060Sstevel@tonic-gate
11070Sstevel@tonic-gate /* 'n7', 'n8' */
11080Sstevel@tonic-gate if (!BN_mod_add_quick(n1, n1, n3, p)) goto end;
11090Sstevel@tonic-gate if (!BN_mod_add_quick(n2, n2, n4, p)) goto end;
11100Sstevel@tonic-gate /* 'n7' = n1 + n3 */
11110Sstevel@tonic-gate /* 'n8' = n2 + n4 */
11120Sstevel@tonic-gate
11130Sstevel@tonic-gate /* Z_r */
11140Sstevel@tonic-gate if (a->Z_is_one && b->Z_is_one)
11150Sstevel@tonic-gate {
11160Sstevel@tonic-gate if (!BN_copy(&r->Z, n5)) goto end;
11170Sstevel@tonic-gate }
11180Sstevel@tonic-gate else
11190Sstevel@tonic-gate {
11200Sstevel@tonic-gate if (a->Z_is_one)
11210Sstevel@tonic-gate { if (!BN_copy(n0, &b->Z)) goto end; }
11220Sstevel@tonic-gate else if (b->Z_is_one)
11230Sstevel@tonic-gate { if (!BN_copy(n0, &a->Z)) goto end; }
11240Sstevel@tonic-gate else
11250Sstevel@tonic-gate { if (!field_mul(group, n0, &a->Z, &b->Z, ctx)) goto end; }
11260Sstevel@tonic-gate if (!field_mul(group, &r->Z, n0, n5, ctx)) goto end;
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate r->Z_is_one = 0;
11290Sstevel@tonic-gate /* Z_r = Z_a * Z_b * n5 */
11300Sstevel@tonic-gate
11310Sstevel@tonic-gate /* X_r */
11320Sstevel@tonic-gate if (!field_sqr(group, n0, n6, ctx)) goto end;
11330Sstevel@tonic-gate if (!field_sqr(group, n4, n5, ctx)) goto end;
11340Sstevel@tonic-gate if (!field_mul(group, n3, n1, n4, ctx)) goto end;
11350Sstevel@tonic-gate if (!BN_mod_sub_quick(&r->X, n0, n3, p)) goto end;
11360Sstevel@tonic-gate /* X_r = n6^2 - n5^2 * 'n7' */
11370Sstevel@tonic-gate
11380Sstevel@tonic-gate /* 'n9' */
11390Sstevel@tonic-gate if (!BN_mod_lshift1_quick(n0, &r->X, p)) goto end;
11400Sstevel@tonic-gate if (!BN_mod_sub_quick(n0, n3, n0, p)) goto end;
11410Sstevel@tonic-gate /* n9 = n5^2 * 'n7' - 2 * X_r */
11420Sstevel@tonic-gate
11430Sstevel@tonic-gate /* Y_r */
11440Sstevel@tonic-gate if (!field_mul(group, n0, n0, n6, ctx)) goto end;
11450Sstevel@tonic-gate if (!field_mul(group, n5, n4, n5, ctx)) goto end; /* now n5 is n5^3 */
11460Sstevel@tonic-gate if (!field_mul(group, n1, n2, n5, ctx)) goto end;
11470Sstevel@tonic-gate if (!BN_mod_sub_quick(n0, n0, n1, p)) goto end;
11480Sstevel@tonic-gate if (BN_is_odd(n0))
11490Sstevel@tonic-gate if (!BN_add(n0, n0, p)) goto end;
11500Sstevel@tonic-gate /* now 0 <= n0 < 2*p, and n0 is even */
11510Sstevel@tonic-gate if (!BN_rshift1(&r->Y, n0)) goto end;
11520Sstevel@tonic-gate /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */
11530Sstevel@tonic-gate
11540Sstevel@tonic-gate ret = 1;
11550Sstevel@tonic-gate
11560Sstevel@tonic-gate end:
11570Sstevel@tonic-gate if (ctx) /* otherwise we already called BN_CTX_end */
11580Sstevel@tonic-gate BN_CTX_end(ctx);
11590Sstevel@tonic-gate if (new_ctx != NULL)
11600Sstevel@tonic-gate BN_CTX_free(new_ctx);
11610Sstevel@tonic-gate return ret;
11620Sstevel@tonic-gate }
11630Sstevel@tonic-gate
11640Sstevel@tonic-gate
ec_GFp_simple_dbl(const EC_GROUP * group,EC_POINT * r,const EC_POINT * a,BN_CTX * ctx)11650Sstevel@tonic-gate int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx)
11660Sstevel@tonic-gate {
11670Sstevel@tonic-gate int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
11680Sstevel@tonic-gate int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
11690Sstevel@tonic-gate const BIGNUM *p;
11700Sstevel@tonic-gate BN_CTX *new_ctx = NULL;
11710Sstevel@tonic-gate BIGNUM *n0, *n1, *n2, *n3;
11720Sstevel@tonic-gate int ret = 0;
11730Sstevel@tonic-gate
11740Sstevel@tonic-gate if (EC_POINT_is_at_infinity(group, a))
11750Sstevel@tonic-gate {
1176*2139Sjp161948 BN_zero(&r->Z);
11770Sstevel@tonic-gate r->Z_is_one = 0;
11780Sstevel@tonic-gate return 1;
11790Sstevel@tonic-gate }
11800Sstevel@tonic-gate
11810Sstevel@tonic-gate field_mul = group->meth->field_mul;
11820Sstevel@tonic-gate field_sqr = group->meth->field_sqr;
11830Sstevel@tonic-gate p = &group->field;
11840Sstevel@tonic-gate
11850Sstevel@tonic-gate if (ctx == NULL)
11860Sstevel@tonic-gate {
11870Sstevel@tonic-gate ctx = new_ctx = BN_CTX_new();
11880Sstevel@tonic-gate if (ctx == NULL)
11890Sstevel@tonic-gate return 0;
11900Sstevel@tonic-gate }
11910Sstevel@tonic-gate
11920Sstevel@tonic-gate BN_CTX_start(ctx);
11930Sstevel@tonic-gate n0 = BN_CTX_get(ctx);
11940Sstevel@tonic-gate n1 = BN_CTX_get(ctx);
11950Sstevel@tonic-gate n2 = BN_CTX_get(ctx);
11960Sstevel@tonic-gate n3 = BN_CTX_get(ctx);
11970Sstevel@tonic-gate if (n3 == NULL) goto err;
11980Sstevel@tonic-gate
11990Sstevel@tonic-gate /* Note that in this function we must not read components of 'a'
12000Sstevel@tonic-gate * once we have written the corresponding components of 'r'.
12010Sstevel@tonic-gate * ('r' might the same as 'a'.)
12020Sstevel@tonic-gate */
12030Sstevel@tonic-gate
12040Sstevel@tonic-gate /* n1 */
12050Sstevel@tonic-gate if (a->Z_is_one)
12060Sstevel@tonic-gate {
12070Sstevel@tonic-gate if (!field_sqr(group, n0, &a->X, ctx)) goto err;
12080Sstevel@tonic-gate if (!BN_mod_lshift1_quick(n1, n0, p)) goto err;
12090Sstevel@tonic-gate if (!BN_mod_add_quick(n0, n0, n1, p)) goto err;
12100Sstevel@tonic-gate if (!BN_mod_add_quick(n1, n0, &group->a, p)) goto err;
12110Sstevel@tonic-gate /* n1 = 3 * X_a^2 + a_curve */
12120Sstevel@tonic-gate }
12130Sstevel@tonic-gate else if (group->a_is_minus3)
12140Sstevel@tonic-gate {
12150Sstevel@tonic-gate if (!field_sqr(group, n1, &a->Z, ctx)) goto err;
12160Sstevel@tonic-gate if (!BN_mod_add_quick(n0, &a->X, n1, p)) goto err;
12170Sstevel@tonic-gate if (!BN_mod_sub_quick(n2, &a->X, n1, p)) goto err;
12180Sstevel@tonic-gate if (!field_mul(group, n1, n0, n2, ctx)) goto err;
12190Sstevel@tonic-gate if (!BN_mod_lshift1_quick(n0, n1, p)) goto err;
12200Sstevel@tonic-gate if (!BN_mod_add_quick(n1, n0, n1, p)) goto err;
12210Sstevel@tonic-gate /* n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2)
12220Sstevel@tonic-gate * = 3 * X_a^2 - 3 * Z_a^4 */
12230Sstevel@tonic-gate }
12240Sstevel@tonic-gate else
12250Sstevel@tonic-gate {
12260Sstevel@tonic-gate if (!field_sqr(group, n0, &a->X, ctx)) goto err;
12270Sstevel@tonic-gate if (!BN_mod_lshift1_quick(n1, n0, p)) goto err;
12280Sstevel@tonic-gate if (!BN_mod_add_quick(n0, n0, n1, p)) goto err;
12290Sstevel@tonic-gate if (!field_sqr(group, n1, &a->Z, ctx)) goto err;
12300Sstevel@tonic-gate if (!field_sqr(group, n1, n1, ctx)) goto err;
12310Sstevel@tonic-gate if (!field_mul(group, n1, n1, &group->a, ctx)) goto err;
12320Sstevel@tonic-gate if (!BN_mod_add_quick(n1, n1, n0, p)) goto err;
12330Sstevel@tonic-gate /* n1 = 3 * X_a^2 + a_curve * Z_a^4 */
12340Sstevel@tonic-gate }
12350Sstevel@tonic-gate
12360Sstevel@tonic-gate /* Z_r */
12370Sstevel@tonic-gate if (a->Z_is_one)
12380Sstevel@tonic-gate {
12390Sstevel@tonic-gate if (!BN_copy(n0, &a->Y)) goto err;
12400Sstevel@tonic-gate }
12410Sstevel@tonic-gate else
12420Sstevel@tonic-gate {
12430Sstevel@tonic-gate if (!field_mul(group, n0, &a->Y, &a->Z, ctx)) goto err;
12440Sstevel@tonic-gate }
12450Sstevel@tonic-gate if (!BN_mod_lshift1_quick(&r->Z, n0, p)) goto err;
12460Sstevel@tonic-gate r->Z_is_one = 0;
12470Sstevel@tonic-gate /* Z_r = 2 * Y_a * Z_a */
12480Sstevel@tonic-gate
12490Sstevel@tonic-gate /* n2 */
12500Sstevel@tonic-gate if (!field_sqr(group, n3, &a->Y, ctx)) goto err;
12510Sstevel@tonic-gate if (!field_mul(group, n2, &a->X, n3, ctx)) goto err;
12520Sstevel@tonic-gate if (!BN_mod_lshift_quick(n2, n2, 2, p)) goto err;
12530Sstevel@tonic-gate /* n2 = 4 * X_a * Y_a^2 */
12540Sstevel@tonic-gate
12550Sstevel@tonic-gate /* X_r */
12560Sstevel@tonic-gate if (!BN_mod_lshift1_quick(n0, n2, p)) goto err;
12570Sstevel@tonic-gate if (!field_sqr(group, &r->X, n1, ctx)) goto err;
12580Sstevel@tonic-gate if (!BN_mod_sub_quick(&r->X, &r->X, n0, p)) goto err;
12590Sstevel@tonic-gate /* X_r = n1^2 - 2 * n2 */
12600Sstevel@tonic-gate
12610Sstevel@tonic-gate /* n3 */
12620Sstevel@tonic-gate if (!field_sqr(group, n0, n3, ctx)) goto err;
12630Sstevel@tonic-gate if (!BN_mod_lshift_quick(n3, n0, 3, p)) goto err;
12640Sstevel@tonic-gate /* n3 = 8 * Y_a^4 */
12650Sstevel@tonic-gate
12660Sstevel@tonic-gate /* Y_r */
12670Sstevel@tonic-gate if (!BN_mod_sub_quick(n0, n2, &r->X, p)) goto err;
12680Sstevel@tonic-gate if (!field_mul(group, n0, n1, n0, ctx)) goto err;
12690Sstevel@tonic-gate if (!BN_mod_sub_quick(&r->Y, n0, n3, p)) goto err;
12700Sstevel@tonic-gate /* Y_r = n1 * (n2 - X_r) - n3 */
12710Sstevel@tonic-gate
12720Sstevel@tonic-gate ret = 1;
12730Sstevel@tonic-gate
12740Sstevel@tonic-gate err:
12750Sstevel@tonic-gate BN_CTX_end(ctx);
12760Sstevel@tonic-gate if (new_ctx != NULL)
12770Sstevel@tonic-gate BN_CTX_free(new_ctx);
12780Sstevel@tonic-gate return ret;
12790Sstevel@tonic-gate }
12800Sstevel@tonic-gate
12810Sstevel@tonic-gate
ec_GFp_simple_invert(const EC_GROUP * group,EC_POINT * point,BN_CTX * ctx)12820Sstevel@tonic-gate int ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx)
12830Sstevel@tonic-gate {
12840Sstevel@tonic-gate if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(&point->Y))
12850Sstevel@tonic-gate /* point is its own inverse */
12860Sstevel@tonic-gate return 1;
12870Sstevel@tonic-gate
12880Sstevel@tonic-gate return BN_usub(&point->Y, &group->field, &point->Y);
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate
12910Sstevel@tonic-gate
ec_GFp_simple_is_at_infinity(const EC_GROUP * group,const EC_POINT * point)12920Sstevel@tonic-gate int ec_GFp_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point)
12930Sstevel@tonic-gate {
12940Sstevel@tonic-gate return BN_is_zero(&point->Z);
12950Sstevel@tonic-gate }
12960Sstevel@tonic-gate
12970Sstevel@tonic-gate
ec_GFp_simple_is_on_curve(const EC_GROUP * group,const EC_POINT * point,BN_CTX * ctx)12980Sstevel@tonic-gate int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx)
12990Sstevel@tonic-gate {
13000Sstevel@tonic-gate int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
13010Sstevel@tonic-gate int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
13020Sstevel@tonic-gate const BIGNUM *p;
13030Sstevel@tonic-gate BN_CTX *new_ctx = NULL;
1304*2139Sjp161948 BIGNUM *rh, *tmp, *Z4, *Z6;
13050Sstevel@tonic-gate int ret = -1;
13060Sstevel@tonic-gate
13070Sstevel@tonic-gate if (EC_POINT_is_at_infinity(group, point))
13080Sstevel@tonic-gate return 1;
13090Sstevel@tonic-gate
13100Sstevel@tonic-gate field_mul = group->meth->field_mul;
13110Sstevel@tonic-gate field_sqr = group->meth->field_sqr;
13120Sstevel@tonic-gate p = &group->field;
13130Sstevel@tonic-gate
13140Sstevel@tonic-gate if (ctx == NULL)
13150Sstevel@tonic-gate {
13160Sstevel@tonic-gate ctx = new_ctx = BN_CTX_new();
13170Sstevel@tonic-gate if (ctx == NULL)
13180Sstevel@tonic-gate return -1;
13190Sstevel@tonic-gate }
13200Sstevel@tonic-gate
13210Sstevel@tonic-gate BN_CTX_start(ctx);
13220Sstevel@tonic-gate rh = BN_CTX_get(ctx);
1323*2139Sjp161948 tmp = BN_CTX_get(ctx);
13240Sstevel@tonic-gate Z4 = BN_CTX_get(ctx);
13250Sstevel@tonic-gate Z6 = BN_CTX_get(ctx);
13260Sstevel@tonic-gate if (Z6 == NULL) goto err;
13270Sstevel@tonic-gate
13280Sstevel@tonic-gate /* We have a curve defined by a Weierstrass equation
13290Sstevel@tonic-gate * y^2 = x^3 + a*x + b.
13300Sstevel@tonic-gate * The point to consider is given in Jacobian projective coordinates
13310Sstevel@tonic-gate * where (X, Y, Z) represents (x, y) = (X/Z^2, Y/Z^3).
13320Sstevel@tonic-gate * Substituting this and multiplying by Z^6 transforms the above equation into
13330Sstevel@tonic-gate * Y^2 = X^3 + a*X*Z^4 + b*Z^6.
13340Sstevel@tonic-gate * To test this, we add up the right-hand side in 'rh'.
13350Sstevel@tonic-gate */
13360Sstevel@tonic-gate
1337*2139Sjp161948 /* rh := X^2 */
13380Sstevel@tonic-gate if (!field_sqr(group, rh, &point->X, ctx)) goto err;
13390Sstevel@tonic-gate
13400Sstevel@tonic-gate if (!point->Z_is_one)
13410Sstevel@tonic-gate {
1342*2139Sjp161948 if (!field_sqr(group, tmp, &point->Z, ctx)) goto err;
1343*2139Sjp161948 if (!field_sqr(group, Z4, tmp, ctx)) goto err;
1344*2139Sjp161948 if (!field_mul(group, Z6, Z4, tmp, ctx)) goto err;
13450Sstevel@tonic-gate
1346*2139Sjp161948 /* rh := (rh + a*Z^4)*X */
13470Sstevel@tonic-gate if (group->a_is_minus3)
13480Sstevel@tonic-gate {
1349*2139Sjp161948 if (!BN_mod_lshift1_quick(tmp, Z4, p)) goto err;
1350*2139Sjp161948 if (!BN_mod_add_quick(tmp, tmp, Z4, p)) goto err;
1351*2139Sjp161948 if (!BN_mod_sub_quick(rh, rh, tmp, p)) goto err;
1352*2139Sjp161948 if (!field_mul(group, rh, rh, &point->X, ctx)) goto err;
13530Sstevel@tonic-gate }
13540Sstevel@tonic-gate else
13550Sstevel@tonic-gate {
1356*2139Sjp161948 if (!field_mul(group, tmp, Z4, &group->a, ctx)) goto err;
1357*2139Sjp161948 if (!BN_mod_add_quick(rh, rh, tmp, p)) goto err;
1358*2139Sjp161948 if (!field_mul(group, rh, rh, &point->X, ctx)) goto err;
13590Sstevel@tonic-gate }
13600Sstevel@tonic-gate
13610Sstevel@tonic-gate /* rh := rh + b*Z^6 */
1362*2139Sjp161948 if (!field_mul(group, tmp, &group->b, Z6, ctx)) goto err;
1363*2139Sjp161948 if (!BN_mod_add_quick(rh, rh, tmp, p)) goto err;
13640Sstevel@tonic-gate }
13650Sstevel@tonic-gate else
13660Sstevel@tonic-gate {
13670Sstevel@tonic-gate /* point->Z_is_one */
13680Sstevel@tonic-gate
1369*2139Sjp161948 /* rh := (rh + a)*X */
1370*2139Sjp161948 if (!BN_mod_add_quick(rh, rh, &group->a, p)) goto err;
1371*2139Sjp161948 if (!field_mul(group, rh, rh, &point->X, ctx)) goto err;
13720Sstevel@tonic-gate /* rh := rh + b */
13730Sstevel@tonic-gate if (!BN_mod_add_quick(rh, rh, &group->b, p)) goto err;
13740Sstevel@tonic-gate }
13750Sstevel@tonic-gate
13760Sstevel@tonic-gate /* 'lh' := Y^2 */
1377*2139Sjp161948 if (!field_sqr(group, tmp, &point->Y, ctx)) goto err;
13780Sstevel@tonic-gate
1379*2139Sjp161948 ret = (0 == BN_ucmp(tmp, rh));
13800Sstevel@tonic-gate
13810Sstevel@tonic-gate err:
13820Sstevel@tonic-gate BN_CTX_end(ctx);
13830Sstevel@tonic-gate if (new_ctx != NULL)
13840Sstevel@tonic-gate BN_CTX_free(new_ctx);
13850Sstevel@tonic-gate return ret;
13860Sstevel@tonic-gate }
13870Sstevel@tonic-gate
13880Sstevel@tonic-gate
ec_GFp_simple_cmp(const EC_GROUP * group,const EC_POINT * a,const EC_POINT * b,BN_CTX * ctx)13890Sstevel@tonic-gate int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx)
13900Sstevel@tonic-gate {
13910Sstevel@tonic-gate /* return values:
13920Sstevel@tonic-gate * -1 error
13930Sstevel@tonic-gate * 0 equal (in affine coordinates)
13940Sstevel@tonic-gate * 1 not equal
13950Sstevel@tonic-gate */
13960Sstevel@tonic-gate
13970Sstevel@tonic-gate int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
13980Sstevel@tonic-gate int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
13990Sstevel@tonic-gate BN_CTX *new_ctx = NULL;
14000Sstevel@tonic-gate BIGNUM *tmp1, *tmp2, *Za23, *Zb23;
14010Sstevel@tonic-gate const BIGNUM *tmp1_, *tmp2_;
14020Sstevel@tonic-gate int ret = -1;
14030Sstevel@tonic-gate
14040Sstevel@tonic-gate if (EC_POINT_is_at_infinity(group, a))
14050Sstevel@tonic-gate {
14060Sstevel@tonic-gate return EC_POINT_is_at_infinity(group, b) ? 0 : 1;
14070Sstevel@tonic-gate }
14080Sstevel@tonic-gate
14090Sstevel@tonic-gate if (a->Z_is_one && b->Z_is_one)
14100Sstevel@tonic-gate {
14110Sstevel@tonic-gate return ((BN_cmp(&a->X, &b->X) == 0) && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1;
14120Sstevel@tonic-gate }
14130Sstevel@tonic-gate
14140Sstevel@tonic-gate field_mul = group->meth->field_mul;
14150Sstevel@tonic-gate field_sqr = group->meth->field_sqr;
14160Sstevel@tonic-gate
14170Sstevel@tonic-gate if (ctx == NULL)
14180Sstevel@tonic-gate {
14190Sstevel@tonic-gate ctx = new_ctx = BN_CTX_new();
14200Sstevel@tonic-gate if (ctx == NULL)
14210Sstevel@tonic-gate return -1;
14220Sstevel@tonic-gate }
14230Sstevel@tonic-gate
14240Sstevel@tonic-gate BN_CTX_start(ctx);
14250Sstevel@tonic-gate tmp1 = BN_CTX_get(ctx);
14260Sstevel@tonic-gate tmp2 = BN_CTX_get(ctx);
14270Sstevel@tonic-gate Za23 = BN_CTX_get(ctx);
14280Sstevel@tonic-gate Zb23 = BN_CTX_get(ctx);
14290Sstevel@tonic-gate if (Zb23 == NULL) goto end;
14300Sstevel@tonic-gate
14310Sstevel@tonic-gate /* We have to decide whether
14320Sstevel@tonic-gate * (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3),
14330Sstevel@tonic-gate * or equivalently, whether
14340Sstevel@tonic-gate * (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3).
14350Sstevel@tonic-gate */
14360Sstevel@tonic-gate
14370Sstevel@tonic-gate if (!b->Z_is_one)
14380Sstevel@tonic-gate {
14390Sstevel@tonic-gate if (!field_sqr(group, Zb23, &b->Z, ctx)) goto end;
14400Sstevel@tonic-gate if (!field_mul(group, tmp1, &a->X, Zb23, ctx)) goto end;
14410Sstevel@tonic-gate tmp1_ = tmp1;
14420Sstevel@tonic-gate }
14430Sstevel@tonic-gate else
14440Sstevel@tonic-gate tmp1_ = &a->X;
14450Sstevel@tonic-gate if (!a->Z_is_one)
14460Sstevel@tonic-gate {
14470Sstevel@tonic-gate if (!field_sqr(group, Za23, &a->Z, ctx)) goto end;
14480Sstevel@tonic-gate if (!field_mul(group, tmp2, &b->X, Za23, ctx)) goto end;
14490Sstevel@tonic-gate tmp2_ = tmp2;
14500Sstevel@tonic-gate }
14510Sstevel@tonic-gate else
14520Sstevel@tonic-gate tmp2_ = &b->X;
14530Sstevel@tonic-gate
14540Sstevel@tonic-gate /* compare X_a*Z_b^2 with X_b*Z_a^2 */
14550Sstevel@tonic-gate if (BN_cmp(tmp1_, tmp2_) != 0)
14560Sstevel@tonic-gate {
14570Sstevel@tonic-gate ret = 1; /* points differ */
14580Sstevel@tonic-gate goto end;
14590Sstevel@tonic-gate }
14600Sstevel@tonic-gate
14610Sstevel@tonic-gate
14620Sstevel@tonic-gate if (!b->Z_is_one)
14630Sstevel@tonic-gate {
14640Sstevel@tonic-gate if (!field_mul(group, Zb23, Zb23, &b->Z, ctx)) goto end;
14650Sstevel@tonic-gate if (!field_mul(group, tmp1, &a->Y, Zb23, ctx)) goto end;
14660Sstevel@tonic-gate /* tmp1_ = tmp1 */
14670Sstevel@tonic-gate }
14680Sstevel@tonic-gate else
14690Sstevel@tonic-gate tmp1_ = &a->Y;
14700Sstevel@tonic-gate if (!a->Z_is_one)
14710Sstevel@tonic-gate {
14720Sstevel@tonic-gate if (!field_mul(group, Za23, Za23, &a->Z, ctx)) goto end;
14730Sstevel@tonic-gate if (!field_mul(group, tmp2, &b->Y, Za23, ctx)) goto end;
14740Sstevel@tonic-gate /* tmp2_ = tmp2 */
14750Sstevel@tonic-gate }
14760Sstevel@tonic-gate else
14770Sstevel@tonic-gate tmp2_ = &b->Y;
14780Sstevel@tonic-gate
14790Sstevel@tonic-gate /* compare Y_a*Z_b^3 with Y_b*Z_a^3 */
14800Sstevel@tonic-gate if (BN_cmp(tmp1_, tmp2_) != 0)
14810Sstevel@tonic-gate {
14820Sstevel@tonic-gate ret = 1; /* points differ */
14830Sstevel@tonic-gate goto end;
14840Sstevel@tonic-gate }
14850Sstevel@tonic-gate
14860Sstevel@tonic-gate /* points are equal */
14870Sstevel@tonic-gate ret = 0;
14880Sstevel@tonic-gate
14890Sstevel@tonic-gate end:
14900Sstevel@tonic-gate BN_CTX_end(ctx);
14910Sstevel@tonic-gate if (new_ctx != NULL)
14920Sstevel@tonic-gate BN_CTX_free(new_ctx);
14930Sstevel@tonic-gate return ret;
14940Sstevel@tonic-gate }
14950Sstevel@tonic-gate
14960Sstevel@tonic-gate
ec_GFp_simple_make_affine(const EC_GROUP * group,EC_POINT * point,BN_CTX * ctx)14970Sstevel@tonic-gate int ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx)
14980Sstevel@tonic-gate {
14990Sstevel@tonic-gate BN_CTX *new_ctx = NULL;
15000Sstevel@tonic-gate BIGNUM *x, *y;
15010Sstevel@tonic-gate int ret = 0;
15020Sstevel@tonic-gate
15030Sstevel@tonic-gate if (point->Z_is_one || EC_POINT_is_at_infinity(group, point))
15040Sstevel@tonic-gate return 1;
15050Sstevel@tonic-gate
15060Sstevel@tonic-gate if (ctx == NULL)
15070Sstevel@tonic-gate {
15080Sstevel@tonic-gate ctx = new_ctx = BN_CTX_new();
15090Sstevel@tonic-gate if (ctx == NULL)
15100Sstevel@tonic-gate return 0;
15110Sstevel@tonic-gate }
15120Sstevel@tonic-gate
15130Sstevel@tonic-gate BN_CTX_start(ctx);
15140Sstevel@tonic-gate x = BN_CTX_get(ctx);
15150Sstevel@tonic-gate y = BN_CTX_get(ctx);
15160Sstevel@tonic-gate if (y == NULL) goto err;
15170Sstevel@tonic-gate
15180Sstevel@tonic-gate if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
15190Sstevel@tonic-gate if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
15200Sstevel@tonic-gate if (!point->Z_is_one)
15210Sstevel@tonic-gate {
15220Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_MAKE_AFFINE, ERR_R_INTERNAL_ERROR);
15230Sstevel@tonic-gate goto err;
15240Sstevel@tonic-gate }
15250Sstevel@tonic-gate
15260Sstevel@tonic-gate ret = 1;
15270Sstevel@tonic-gate
15280Sstevel@tonic-gate err:
15290Sstevel@tonic-gate BN_CTX_end(ctx);
15300Sstevel@tonic-gate if (new_ctx != NULL)
15310Sstevel@tonic-gate BN_CTX_free(new_ctx);
15320Sstevel@tonic-gate return ret;
15330Sstevel@tonic-gate }
15340Sstevel@tonic-gate
15350Sstevel@tonic-gate
ec_GFp_simple_points_make_affine(const EC_GROUP * group,size_t num,EC_POINT * points[],BN_CTX * ctx)15360Sstevel@tonic-gate int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], BN_CTX *ctx)
15370Sstevel@tonic-gate {
15380Sstevel@tonic-gate BN_CTX *new_ctx = NULL;
15390Sstevel@tonic-gate BIGNUM *tmp0, *tmp1;
15400Sstevel@tonic-gate size_t pow2 = 0;
15410Sstevel@tonic-gate BIGNUM **heap = NULL;
15420Sstevel@tonic-gate size_t i;
15430Sstevel@tonic-gate int ret = 0;
15440Sstevel@tonic-gate
15450Sstevel@tonic-gate if (num == 0)
15460Sstevel@tonic-gate return 1;
15470Sstevel@tonic-gate
15480Sstevel@tonic-gate if (ctx == NULL)
15490Sstevel@tonic-gate {
15500Sstevel@tonic-gate ctx = new_ctx = BN_CTX_new();
15510Sstevel@tonic-gate if (ctx == NULL)
15520Sstevel@tonic-gate return 0;
15530Sstevel@tonic-gate }
15540Sstevel@tonic-gate
15550Sstevel@tonic-gate BN_CTX_start(ctx);
15560Sstevel@tonic-gate tmp0 = BN_CTX_get(ctx);
15570Sstevel@tonic-gate tmp1 = BN_CTX_get(ctx);
15580Sstevel@tonic-gate if (tmp0 == NULL || tmp1 == NULL) goto err;
15590Sstevel@tonic-gate
15600Sstevel@tonic-gate /* Before converting the individual points, compute inverses of all Z values.
15610Sstevel@tonic-gate * Modular inversion is rather slow, but luckily we can do with a single
15620Sstevel@tonic-gate * explicit inversion, plus about 3 multiplications per input value.
15630Sstevel@tonic-gate */
15640Sstevel@tonic-gate
15650Sstevel@tonic-gate pow2 = 1;
15660Sstevel@tonic-gate while (num > pow2)
15670Sstevel@tonic-gate pow2 <<= 1;
15680Sstevel@tonic-gate /* Now pow2 is the smallest power of 2 satifsying pow2 >= num.
15690Sstevel@tonic-gate * We need twice that. */
15700Sstevel@tonic-gate pow2 <<= 1;
15710Sstevel@tonic-gate
15720Sstevel@tonic-gate heap = OPENSSL_malloc(pow2 * sizeof heap[0]);
15730Sstevel@tonic-gate if (heap == NULL) goto err;
15740Sstevel@tonic-gate
15750Sstevel@tonic-gate /* The array is used as a binary tree, exactly as in heapsort:
15760Sstevel@tonic-gate *
15770Sstevel@tonic-gate * heap[1]
15780Sstevel@tonic-gate * heap[2] heap[3]
15790Sstevel@tonic-gate * heap[4] heap[5] heap[6] heap[7]
15800Sstevel@tonic-gate * heap[8]heap[9] heap[10]heap[11] heap[12]heap[13] heap[14] heap[15]
15810Sstevel@tonic-gate *
15820Sstevel@tonic-gate * We put the Z's in the last line;
15830Sstevel@tonic-gate * then we set each other node to the product of its two child-nodes (where
15840Sstevel@tonic-gate * empty or 0 entries are treated as ones);
15850Sstevel@tonic-gate * then we invert heap[1];
15860Sstevel@tonic-gate * then we invert each other node by replacing it by the product of its
15870Sstevel@tonic-gate * parent (after inversion) and its sibling (before inversion).
15880Sstevel@tonic-gate */
15890Sstevel@tonic-gate heap[0] = NULL;
15900Sstevel@tonic-gate for (i = pow2/2 - 1; i > 0; i--)
15910Sstevel@tonic-gate heap[i] = NULL;
15920Sstevel@tonic-gate for (i = 0; i < num; i++)
15930Sstevel@tonic-gate heap[pow2/2 + i] = &points[i]->Z;
15940Sstevel@tonic-gate for (i = pow2/2 + num; i < pow2; i++)
15950Sstevel@tonic-gate heap[i] = NULL;
15960Sstevel@tonic-gate
15970Sstevel@tonic-gate /* set each node to the product of its children */
15980Sstevel@tonic-gate for (i = pow2/2 - 1; i > 0; i--)
15990Sstevel@tonic-gate {
16000Sstevel@tonic-gate heap[i] = BN_new();
16010Sstevel@tonic-gate if (heap[i] == NULL) goto err;
16020Sstevel@tonic-gate
16030Sstevel@tonic-gate if (heap[2*i] != NULL)
16040Sstevel@tonic-gate {
16050Sstevel@tonic-gate if ((heap[2*i + 1] == NULL) || BN_is_zero(heap[2*i + 1]))
16060Sstevel@tonic-gate {
16070Sstevel@tonic-gate if (!BN_copy(heap[i], heap[2*i])) goto err;
16080Sstevel@tonic-gate }
16090Sstevel@tonic-gate else
16100Sstevel@tonic-gate {
16110Sstevel@tonic-gate if (BN_is_zero(heap[2*i]))
16120Sstevel@tonic-gate {
16130Sstevel@tonic-gate if (!BN_copy(heap[i], heap[2*i + 1])) goto err;
16140Sstevel@tonic-gate }
16150Sstevel@tonic-gate else
16160Sstevel@tonic-gate {
16170Sstevel@tonic-gate if (!group->meth->field_mul(group, heap[i],
16180Sstevel@tonic-gate heap[2*i], heap[2*i + 1], ctx)) goto err;
16190Sstevel@tonic-gate }
16200Sstevel@tonic-gate }
16210Sstevel@tonic-gate }
16220Sstevel@tonic-gate }
16230Sstevel@tonic-gate
16240Sstevel@tonic-gate /* invert heap[1] */
16250Sstevel@tonic-gate if (!BN_is_zero(heap[1]))
16260Sstevel@tonic-gate {
16270Sstevel@tonic-gate if (!BN_mod_inverse(heap[1], heap[1], &group->field, ctx))
16280Sstevel@tonic-gate {
16290Sstevel@tonic-gate ECerr(EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE, ERR_R_BN_LIB);
16300Sstevel@tonic-gate goto err;
16310Sstevel@tonic-gate }
16320Sstevel@tonic-gate }
16330Sstevel@tonic-gate if (group->meth->field_encode != 0)
16340Sstevel@tonic-gate {
16350Sstevel@tonic-gate /* in the Montgomery case, we just turned R*H (representing H)
16360Sstevel@tonic-gate * into 1/(R*H), but we need R*(1/H) (representing 1/H);
16370Sstevel@tonic-gate * i.e. we have need to multiply by the Montgomery factor twice */
16380Sstevel@tonic-gate if (!group->meth->field_encode(group, heap[1], heap[1], ctx)) goto err;
16390Sstevel@tonic-gate if (!group->meth->field_encode(group, heap[1], heap[1], ctx)) goto err;
16400Sstevel@tonic-gate }
16410Sstevel@tonic-gate
16420Sstevel@tonic-gate /* set other heap[i]'s to their inverses */
16430Sstevel@tonic-gate for (i = 2; i < pow2/2 + num; i += 2)
16440Sstevel@tonic-gate {
16450Sstevel@tonic-gate /* i is even */
16460Sstevel@tonic-gate if ((heap[i + 1] != NULL) && !BN_is_zero(heap[i + 1]))
16470Sstevel@tonic-gate {
16480Sstevel@tonic-gate if (!group->meth->field_mul(group, tmp0, heap[i/2], heap[i + 1], ctx)) goto err;
16490Sstevel@tonic-gate if (!group->meth->field_mul(group, tmp1, heap[i/2], heap[i], ctx)) goto err;
16500Sstevel@tonic-gate if (!BN_copy(heap[i], tmp0)) goto err;
16510Sstevel@tonic-gate if (!BN_copy(heap[i + 1], tmp1)) goto err;
16520Sstevel@tonic-gate }
16530Sstevel@tonic-gate else
16540Sstevel@tonic-gate {
16550Sstevel@tonic-gate if (!BN_copy(heap[i], heap[i/2])) goto err;
16560Sstevel@tonic-gate }
16570Sstevel@tonic-gate }
16580Sstevel@tonic-gate
16590Sstevel@tonic-gate /* we have replaced all non-zero Z's by their inverses, now fix up all the points */
16600Sstevel@tonic-gate for (i = 0; i < num; i++)
16610Sstevel@tonic-gate {
16620Sstevel@tonic-gate EC_POINT *p = points[i];
16630Sstevel@tonic-gate
16640Sstevel@tonic-gate if (!BN_is_zero(&p->Z))
16650Sstevel@tonic-gate {
16660Sstevel@tonic-gate /* turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1) */
16670Sstevel@tonic-gate
16680Sstevel@tonic-gate if (!group->meth->field_sqr(group, tmp1, &p->Z, ctx)) goto err;
16690Sstevel@tonic-gate if (!group->meth->field_mul(group, &p->X, &p->X, tmp1, ctx)) goto err;
16700Sstevel@tonic-gate
16710Sstevel@tonic-gate if (!group->meth->field_mul(group, tmp1, tmp1, &p->Z, ctx)) goto err;
16720Sstevel@tonic-gate if (!group->meth->field_mul(group, &p->Y, &p->Y, tmp1, ctx)) goto err;
16730Sstevel@tonic-gate
16740Sstevel@tonic-gate if (group->meth->field_set_to_one != 0)
16750Sstevel@tonic-gate {
16760Sstevel@tonic-gate if (!group->meth->field_set_to_one(group, &p->Z, ctx)) goto err;
16770Sstevel@tonic-gate }
16780Sstevel@tonic-gate else
16790Sstevel@tonic-gate {
16800Sstevel@tonic-gate if (!BN_one(&p->Z)) goto err;
16810Sstevel@tonic-gate }
16820Sstevel@tonic-gate p->Z_is_one = 1;
16830Sstevel@tonic-gate }
16840Sstevel@tonic-gate }
16850Sstevel@tonic-gate
16860Sstevel@tonic-gate ret = 1;
16870Sstevel@tonic-gate
16880Sstevel@tonic-gate err:
16890Sstevel@tonic-gate BN_CTX_end(ctx);
16900Sstevel@tonic-gate if (new_ctx != NULL)
16910Sstevel@tonic-gate BN_CTX_free(new_ctx);
16920Sstevel@tonic-gate if (heap != NULL)
16930Sstevel@tonic-gate {
16940Sstevel@tonic-gate /* heap[pow2/2] .. heap[pow2-1] have not been allocated locally! */
16950Sstevel@tonic-gate for (i = pow2/2 - 1; i > 0; i--)
16960Sstevel@tonic-gate {
16970Sstevel@tonic-gate if (heap[i] != NULL)
16980Sstevel@tonic-gate BN_clear_free(heap[i]);
16990Sstevel@tonic-gate }
17000Sstevel@tonic-gate OPENSSL_free(heap);
17010Sstevel@tonic-gate }
17020Sstevel@tonic-gate return ret;
17030Sstevel@tonic-gate }
17040Sstevel@tonic-gate
17050Sstevel@tonic-gate
ec_GFp_simple_field_mul(const EC_GROUP * group,BIGNUM * r,const BIGNUM * a,const BIGNUM * b,BN_CTX * ctx)17060Sstevel@tonic-gate int ec_GFp_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
17070Sstevel@tonic-gate {
17080Sstevel@tonic-gate return BN_mod_mul(r, a, b, &group->field, ctx);
17090Sstevel@tonic-gate }
17100Sstevel@tonic-gate
17110Sstevel@tonic-gate
ec_GFp_simple_field_sqr(const EC_GROUP * group,BIGNUM * r,const BIGNUM * a,BN_CTX * ctx)17120Sstevel@tonic-gate int ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
17130Sstevel@tonic-gate {
17140Sstevel@tonic-gate return BN_mod_sqr(r, a, &group->field, ctx);
17150Sstevel@tonic-gate }
1716