xref: /onnv-gate/usr/src/common/openssl/crypto/ec/ecp_smpl.c (revision 2139:6243c3338933)
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