xref: /onnv-gate/usr/src/common/openssl/crypto/ec/ecp_smpl.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /* crypto/ec/ecp_smpl.c */
2*0Sstevel@tonic-gate /* Includes code written by Lenka Fibikova <fibikova@exp-math.uni-essen.de>
3*0Sstevel@tonic-gate  * for the OpenSSL project. */
4*0Sstevel@tonic-gate /* ====================================================================
5*0Sstevel@tonic-gate  * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
6*0Sstevel@tonic-gate  *
7*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
8*0Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
9*0Sstevel@tonic-gate  * are met:
10*0Sstevel@tonic-gate  *
11*0Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
12*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
15*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in
16*0Sstevel@tonic-gate  *    the documentation and/or other materials provided with the
17*0Sstevel@tonic-gate  *    distribution.
18*0Sstevel@tonic-gate  *
19*0Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this
20*0Sstevel@tonic-gate  *    software must display the following acknowledgment:
21*0Sstevel@tonic-gate  *    "This product includes software developed by the OpenSSL Project
22*0Sstevel@tonic-gate  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
23*0Sstevel@tonic-gate  *
24*0Sstevel@tonic-gate  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25*0Sstevel@tonic-gate  *    endorse or promote products derived from this software without
26*0Sstevel@tonic-gate  *    prior written permission. For written permission, please contact
27*0Sstevel@tonic-gate  *    openssl-core@openssl.org.
28*0Sstevel@tonic-gate  *
29*0Sstevel@tonic-gate  * 5. Products derived from this software may not be called "OpenSSL"
30*0Sstevel@tonic-gate  *    nor may "OpenSSL" appear in their names without prior written
31*0Sstevel@tonic-gate  *    permission of the OpenSSL Project.
32*0Sstevel@tonic-gate  *
33*0Sstevel@tonic-gate  * 6. Redistributions of any form whatsoever must retain the following
34*0Sstevel@tonic-gate  *    acknowledgment:
35*0Sstevel@tonic-gate  *    "This product includes software developed by the OpenSSL Project
36*0Sstevel@tonic-gate  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
37*0Sstevel@tonic-gate  *
38*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39*0Sstevel@tonic-gate  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40*0Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41*0Sstevel@tonic-gate  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
42*0Sstevel@tonic-gate  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43*0Sstevel@tonic-gate  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44*0Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45*0Sstevel@tonic-gate  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46*0Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47*0Sstevel@tonic-gate  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48*0Sstevel@tonic-gate  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49*0Sstevel@tonic-gate  * OF THE POSSIBILITY OF SUCH DAMAGE.
50*0Sstevel@tonic-gate  * ====================================================================
51*0Sstevel@tonic-gate  *
52*0Sstevel@tonic-gate  * This product includes cryptographic software written by Eric Young
53*0Sstevel@tonic-gate  * (eay@cryptsoft.com).  This product includes software written by Tim
54*0Sstevel@tonic-gate  * Hudson (tjh@cryptsoft.com).
55*0Sstevel@tonic-gate  *
56*0Sstevel@tonic-gate  */
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate #include <openssl/err.h>
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate #include "ec_lcl.h"
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate const EC_METHOD *EC_GFp_simple_method(void)
64*0Sstevel@tonic-gate 	{
65*0Sstevel@tonic-gate 	static const EC_METHOD ret = {
66*0Sstevel@tonic-gate 		ec_GFp_simple_group_init,
67*0Sstevel@tonic-gate 		ec_GFp_simple_group_finish,
68*0Sstevel@tonic-gate 		ec_GFp_simple_group_clear_finish,
69*0Sstevel@tonic-gate 		ec_GFp_simple_group_copy,
70*0Sstevel@tonic-gate 		ec_GFp_simple_group_set_curve_GFp,
71*0Sstevel@tonic-gate 		ec_GFp_simple_group_get_curve_GFp,
72*0Sstevel@tonic-gate 		ec_GFp_simple_group_set_generator,
73*0Sstevel@tonic-gate 		ec_GFp_simple_group_get0_generator,
74*0Sstevel@tonic-gate 		ec_GFp_simple_group_get_order,
75*0Sstevel@tonic-gate 		ec_GFp_simple_group_get_cofactor,
76*0Sstevel@tonic-gate 		ec_GFp_simple_point_init,
77*0Sstevel@tonic-gate 		ec_GFp_simple_point_finish,
78*0Sstevel@tonic-gate 		ec_GFp_simple_point_clear_finish,
79*0Sstevel@tonic-gate 		ec_GFp_simple_point_copy,
80*0Sstevel@tonic-gate 		ec_GFp_simple_point_set_to_infinity,
81*0Sstevel@tonic-gate 		ec_GFp_simple_set_Jprojective_coordinates_GFp,
82*0Sstevel@tonic-gate 		ec_GFp_simple_get_Jprojective_coordinates_GFp,
83*0Sstevel@tonic-gate 		ec_GFp_simple_point_set_affine_coordinates_GFp,
84*0Sstevel@tonic-gate 		ec_GFp_simple_point_get_affine_coordinates_GFp,
85*0Sstevel@tonic-gate 		ec_GFp_simple_set_compressed_coordinates_GFp,
86*0Sstevel@tonic-gate 		ec_GFp_simple_point2oct,
87*0Sstevel@tonic-gate 		ec_GFp_simple_oct2point,
88*0Sstevel@tonic-gate 		ec_GFp_simple_add,
89*0Sstevel@tonic-gate 		ec_GFp_simple_dbl,
90*0Sstevel@tonic-gate 		ec_GFp_simple_invert,
91*0Sstevel@tonic-gate 		ec_GFp_simple_is_at_infinity,
92*0Sstevel@tonic-gate 		ec_GFp_simple_is_on_curve,
93*0Sstevel@tonic-gate 		ec_GFp_simple_cmp,
94*0Sstevel@tonic-gate 		ec_GFp_simple_make_affine,
95*0Sstevel@tonic-gate 		ec_GFp_simple_points_make_affine,
96*0Sstevel@tonic-gate 		ec_GFp_simple_field_mul,
97*0Sstevel@tonic-gate 		ec_GFp_simple_field_sqr,
98*0Sstevel@tonic-gate 		0 /* field_encode */,
99*0Sstevel@tonic-gate 		0 /* field_decode */,
100*0Sstevel@tonic-gate 		0 /* field_set_to_one */ };
101*0Sstevel@tonic-gate 
102*0Sstevel@tonic-gate 	return &ret;
103*0Sstevel@tonic-gate 	}
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate int ec_GFp_simple_group_init(EC_GROUP *group)
107*0Sstevel@tonic-gate 	{
108*0Sstevel@tonic-gate 	BN_init(&group->field);
109*0Sstevel@tonic-gate 	BN_init(&group->a);
110*0Sstevel@tonic-gate 	BN_init(&group->b);
111*0Sstevel@tonic-gate 	group->a_is_minus3 = 0;
112*0Sstevel@tonic-gate 	group->generator = NULL;
113*0Sstevel@tonic-gate 	BN_init(&group->order);
114*0Sstevel@tonic-gate 	BN_init(&group->cofactor);
115*0Sstevel@tonic-gate 	return 1;
116*0Sstevel@tonic-gate 	}
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate void ec_GFp_simple_group_finish(EC_GROUP *group)
120*0Sstevel@tonic-gate 	{
121*0Sstevel@tonic-gate 	BN_free(&group->field);
122*0Sstevel@tonic-gate 	BN_free(&group->a);
123*0Sstevel@tonic-gate 	BN_free(&group->b);
124*0Sstevel@tonic-gate 	if (group->generator != NULL)
125*0Sstevel@tonic-gate 		EC_POINT_free(group->generator);
126*0Sstevel@tonic-gate 	BN_free(&group->order);
127*0Sstevel@tonic-gate 	BN_free(&group->cofactor);
128*0Sstevel@tonic-gate 	}
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate void ec_GFp_simple_group_clear_finish(EC_GROUP *group)
132*0Sstevel@tonic-gate 	{
133*0Sstevel@tonic-gate 	BN_clear_free(&group->field);
134*0Sstevel@tonic-gate 	BN_clear_free(&group->a);
135*0Sstevel@tonic-gate 	BN_clear_free(&group->b);
136*0Sstevel@tonic-gate 	if (group->generator != NULL)
137*0Sstevel@tonic-gate 		{
138*0Sstevel@tonic-gate 		EC_POINT_clear_free(group->generator);
139*0Sstevel@tonic-gate 		group->generator = NULL;
140*0Sstevel@tonic-gate 		}
141*0Sstevel@tonic-gate 	BN_clear_free(&group->order);
142*0Sstevel@tonic-gate 	BN_clear_free(&group->cofactor);
143*0Sstevel@tonic-gate 	}
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate int ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src)
147*0Sstevel@tonic-gate 	{
148*0Sstevel@tonic-gate 	if (!BN_copy(&dest->field, &src->field)) return 0;
149*0Sstevel@tonic-gate 	if (!BN_copy(&dest->a, &src->a)) return 0;
150*0Sstevel@tonic-gate 	if (!BN_copy(&dest->b, &src->b)) return 0;
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	dest->a_is_minus3 = src->a_is_minus3;
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 	if (src->generator != NULL)
155*0Sstevel@tonic-gate 		{
156*0Sstevel@tonic-gate 		if (dest->generator == NULL)
157*0Sstevel@tonic-gate 			{
158*0Sstevel@tonic-gate 			dest->generator = EC_POINT_new(dest);
159*0Sstevel@tonic-gate 			if (dest->generator == NULL) return 0;
160*0Sstevel@tonic-gate 			}
161*0Sstevel@tonic-gate 		if (!EC_POINT_copy(dest->generator, src->generator)) return 0;
162*0Sstevel@tonic-gate 		}
163*0Sstevel@tonic-gate 	else
164*0Sstevel@tonic-gate 		{
165*0Sstevel@tonic-gate 		/* src->generator == NULL */
166*0Sstevel@tonic-gate 		if (dest->generator != NULL)
167*0Sstevel@tonic-gate 			{
168*0Sstevel@tonic-gate 			EC_POINT_clear_free(dest->generator);
169*0Sstevel@tonic-gate 			dest->generator = NULL;
170*0Sstevel@tonic-gate 			}
171*0Sstevel@tonic-gate 		}
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate 	if (!BN_copy(&dest->order, &src->order)) return 0;
174*0Sstevel@tonic-gate 	if (!BN_copy(&dest->cofactor, &src->cofactor)) return 0;
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 	return 1;
177*0Sstevel@tonic-gate 	}
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate int ec_GFp_simple_group_set_curve_GFp(EC_GROUP *group,
181*0Sstevel@tonic-gate 	const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
182*0Sstevel@tonic-gate 	{
183*0Sstevel@tonic-gate 	int ret = 0;
184*0Sstevel@tonic-gate 	BN_CTX *new_ctx = NULL;
185*0Sstevel@tonic-gate 	BIGNUM *tmp_a;
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	/* p must be a prime > 3 */
188*0Sstevel@tonic-gate 	if (BN_num_bits(p) <= 2 || !BN_is_odd(p))
189*0Sstevel@tonic-gate 		{
190*0Sstevel@tonic-gate 		ECerr(EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE_GFP, EC_R_INVALID_FIELD);
191*0Sstevel@tonic-gate 		return 0;
192*0Sstevel@tonic-gate 		}
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	if (ctx == NULL)
195*0Sstevel@tonic-gate 		{
196*0Sstevel@tonic-gate 		ctx = new_ctx = BN_CTX_new();
197*0Sstevel@tonic-gate 		if (ctx == NULL)
198*0Sstevel@tonic-gate 			return 0;
199*0Sstevel@tonic-gate 		}
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 	BN_CTX_start(ctx);
202*0Sstevel@tonic-gate 	tmp_a = BN_CTX_get(ctx);
203*0Sstevel@tonic-gate 	if (tmp_a == NULL) goto err;
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	/* group->field */
206*0Sstevel@tonic-gate 	if (!BN_copy(&group->field, p)) goto err;
207*0Sstevel@tonic-gate 	group->field.neg = 0;
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	/* group->a */
210*0Sstevel@tonic-gate 	if (!BN_nnmod(tmp_a, a, p, ctx)) goto err;
211*0Sstevel@tonic-gate 	if (group->meth->field_encode)
212*0Sstevel@tonic-gate 		{ if (!group->meth->field_encode(group, &group->a, tmp_a, ctx)) goto err; }
213*0Sstevel@tonic-gate 	else
214*0Sstevel@tonic-gate 		if (!BN_copy(&group->a, tmp_a)) goto err;
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 	/* group->b */
217*0Sstevel@tonic-gate 	if (!BN_nnmod(&group->b, b, p, ctx)) goto err;
218*0Sstevel@tonic-gate 	if (group->meth->field_encode)
219*0Sstevel@tonic-gate 		if (!group->meth->field_encode(group, &group->b, &group->b, ctx)) goto err;
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	/* group->a_is_minus3 */
222*0Sstevel@tonic-gate 	if (!BN_add_word(tmp_a, 3)) goto err;
223*0Sstevel@tonic-gate 	group->a_is_minus3 = (0 == BN_cmp(tmp_a, &group->field));
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 	ret = 1;
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate  err:
228*0Sstevel@tonic-gate 	BN_CTX_end(ctx);
229*0Sstevel@tonic-gate 	if (new_ctx != NULL)
230*0Sstevel@tonic-gate 		BN_CTX_free(new_ctx);
231*0Sstevel@tonic-gate 	return ret;
232*0Sstevel@tonic-gate 	}
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate int ec_GFp_simple_group_get_curve_GFp(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *ctx)
236*0Sstevel@tonic-gate 	{
237*0Sstevel@tonic-gate 	int ret = 0;
238*0Sstevel@tonic-gate 	BN_CTX *new_ctx = NULL;
239*0Sstevel@tonic-gate 
240*0Sstevel@tonic-gate 	if (p != NULL)
241*0Sstevel@tonic-gate 		{
242*0Sstevel@tonic-gate 		if (!BN_copy(p, &group->field)) return 0;
243*0Sstevel@tonic-gate 		}
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	if (a != NULL || b != NULL)
246*0Sstevel@tonic-gate 		{
247*0Sstevel@tonic-gate 		if (group->meth->field_decode)
248*0Sstevel@tonic-gate 			{
249*0Sstevel@tonic-gate 			if (ctx == NULL)
250*0Sstevel@tonic-gate 				{
251*0Sstevel@tonic-gate 				ctx = new_ctx = BN_CTX_new();
252*0Sstevel@tonic-gate 				if (ctx == NULL)
253*0Sstevel@tonic-gate 					return 0;
254*0Sstevel@tonic-gate 				}
255*0Sstevel@tonic-gate 			if (a != NULL)
256*0Sstevel@tonic-gate 				{
257*0Sstevel@tonic-gate 				if (!group->meth->field_decode(group, a, &group->a, ctx)) goto err;
258*0Sstevel@tonic-gate 				}
259*0Sstevel@tonic-gate 			if (b != NULL)
260*0Sstevel@tonic-gate 				{
261*0Sstevel@tonic-gate 				if (!group->meth->field_decode(group, b, &group->b, ctx)) goto err;
262*0Sstevel@tonic-gate 				}
263*0Sstevel@tonic-gate 			}
264*0Sstevel@tonic-gate 		else
265*0Sstevel@tonic-gate 			{
266*0Sstevel@tonic-gate 			if (a != NULL)
267*0Sstevel@tonic-gate 				{
268*0Sstevel@tonic-gate 				if (!BN_copy(a, &group->a)) goto err;
269*0Sstevel@tonic-gate 				}
270*0Sstevel@tonic-gate 			if (b != NULL)
271*0Sstevel@tonic-gate 				{
272*0Sstevel@tonic-gate 				if (!BN_copy(b, &group->b)) goto err;
273*0Sstevel@tonic-gate 				}
274*0Sstevel@tonic-gate 			}
275*0Sstevel@tonic-gate 		}
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	ret = 1;
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate  err:
280*0Sstevel@tonic-gate 	if (new_ctx)
281*0Sstevel@tonic-gate 		BN_CTX_free(new_ctx);
282*0Sstevel@tonic-gate 	return ret;
283*0Sstevel@tonic-gate 	}
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate int ec_GFp_simple_group_set_generator(EC_GROUP *group, const EC_POINT *generator,
288*0Sstevel@tonic-gate 	const BIGNUM *order, const BIGNUM *cofactor)
289*0Sstevel@tonic-gate 	{
290*0Sstevel@tonic-gate 	if (generator == NULL)
291*0Sstevel@tonic-gate 		{
292*0Sstevel@tonic-gate 		ECerr(EC_F_EC_GFP_SIMPLE_GROUP_SET_GENERATOR, ERR_R_PASSED_NULL_PARAMETER);
293*0Sstevel@tonic-gate 		return 0   ;
294*0Sstevel@tonic-gate 		}
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	if (group->generator == NULL)
297*0Sstevel@tonic-gate 		{
298*0Sstevel@tonic-gate 		group->generator = EC_POINT_new(group);
299*0Sstevel@tonic-gate 		if (group->generator == NULL) return 0;
300*0Sstevel@tonic-gate 		}
301*0Sstevel@tonic-gate 	if (!EC_POINT_copy(group->generator, generator)) return 0;
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 	if (order != NULL)
304*0Sstevel@tonic-gate 		{ if (!BN_copy(&group->order, order)) return 0; }
305*0Sstevel@tonic-gate 	else
306*0Sstevel@tonic-gate 		{ if (!BN_zero(&group->order)) return 0; }
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	if (cofactor != NULL)
309*0Sstevel@tonic-gate 		{ if (!BN_copy(&group->cofactor, cofactor)) return 0; }
310*0Sstevel@tonic-gate 	else
311*0Sstevel@tonic-gate 		{ if (!BN_zero(&group->cofactor)) return 0; }
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate 	return 1;
314*0Sstevel@tonic-gate 	}
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate EC_POINT *ec_GFp_simple_group_get0_generator(const EC_GROUP *group)
318*0Sstevel@tonic-gate 	{
319*0Sstevel@tonic-gate 	return group->generator;
320*0Sstevel@tonic-gate 	}
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate int ec_GFp_simple_group_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx)
324*0Sstevel@tonic-gate 	{
325*0Sstevel@tonic-gate 	if (!BN_copy(order, &group->order))
326*0Sstevel@tonic-gate 		return 0;
327*0Sstevel@tonic-gate 
328*0Sstevel@tonic-gate 	return !BN_is_zero(&group->order);
329*0Sstevel@tonic-gate 	}
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate int ec_GFp_simple_group_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, BN_CTX *ctx)
333*0Sstevel@tonic-gate 	{
334*0Sstevel@tonic-gate 	if (!BN_copy(cofactor, &group->cofactor))
335*0Sstevel@tonic-gate 		return 0;
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate 	return !BN_is_zero(&group->cofactor);
338*0Sstevel@tonic-gate 	}
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate int ec_GFp_simple_point_init(EC_POINT *point)
342*0Sstevel@tonic-gate 	{
343*0Sstevel@tonic-gate 	BN_init(&point->X);
344*0Sstevel@tonic-gate 	BN_init(&point->Y);
345*0Sstevel@tonic-gate 	BN_init(&point->Z);
346*0Sstevel@tonic-gate 	point->Z_is_one = 0;
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate 	return 1;
349*0Sstevel@tonic-gate 	}
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate void ec_GFp_simple_point_finish(EC_POINT *point)
353*0Sstevel@tonic-gate 	{
354*0Sstevel@tonic-gate 	BN_free(&point->X);
355*0Sstevel@tonic-gate 	BN_free(&point->Y);
356*0Sstevel@tonic-gate 	BN_free(&point->Z);
357*0Sstevel@tonic-gate 	}
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate void ec_GFp_simple_point_clear_finish(EC_POINT *point)
361*0Sstevel@tonic-gate 	{
362*0Sstevel@tonic-gate 	BN_clear_free(&point->X);
363*0Sstevel@tonic-gate 	BN_clear_free(&point->Y);
364*0Sstevel@tonic-gate 	BN_clear_free(&point->Z);
365*0Sstevel@tonic-gate 	point->Z_is_one = 0;
366*0Sstevel@tonic-gate 	}
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src)
370*0Sstevel@tonic-gate 	{
371*0Sstevel@tonic-gate 	if (!BN_copy(&dest->X, &src->X)) return 0;
372*0Sstevel@tonic-gate 	if (!BN_copy(&dest->Y, &src->Y)) return 0;
373*0Sstevel@tonic-gate 	if (!BN_copy(&dest->Z, &src->Z)) return 0;
374*0Sstevel@tonic-gate 	dest->Z_is_one = src->Z_is_one;
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 	return 1;
377*0Sstevel@tonic-gate 	}
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group, EC_POINT *point)
381*0Sstevel@tonic-gate 	{
382*0Sstevel@tonic-gate 	point->Z_is_one = 0;
383*0Sstevel@tonic-gate 	return (BN_zero(&point->Z));
384*0Sstevel@tonic-gate 	}
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
388*0Sstevel@tonic-gate 	const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *ctx)
389*0Sstevel@tonic-gate 	{
390*0Sstevel@tonic-gate 	BN_CTX *new_ctx = NULL;
391*0Sstevel@tonic-gate 	int ret = 0;
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 	if (ctx == NULL)
394*0Sstevel@tonic-gate 		{
395*0Sstevel@tonic-gate 		ctx = new_ctx = BN_CTX_new();
396*0Sstevel@tonic-gate 		if (ctx == NULL)
397*0Sstevel@tonic-gate 			return 0;
398*0Sstevel@tonic-gate 		}
399*0Sstevel@tonic-gate 
400*0Sstevel@tonic-gate 	if (x != NULL)
401*0Sstevel@tonic-gate 		{
402*0Sstevel@tonic-gate 		if (!BN_nnmod(&point->X, x, &group->field, ctx)) goto err;
403*0Sstevel@tonic-gate 		if (group->meth->field_encode)
404*0Sstevel@tonic-gate 			{
405*0Sstevel@tonic-gate 			if (!group->meth->field_encode(group, &point->X, &point->X, ctx)) goto err;
406*0Sstevel@tonic-gate 			}
407*0Sstevel@tonic-gate 		}
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 	if (y != NULL)
410*0Sstevel@tonic-gate 		{
411*0Sstevel@tonic-gate 		if (!BN_nnmod(&point->Y, y, &group->field, ctx)) goto err;
412*0Sstevel@tonic-gate 		if (group->meth->field_encode)
413*0Sstevel@tonic-gate 			{
414*0Sstevel@tonic-gate 			if (!group->meth->field_encode(group, &point->Y, &point->Y, ctx)) goto err;
415*0Sstevel@tonic-gate 			}
416*0Sstevel@tonic-gate 		}
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 	if (z != NULL)
419*0Sstevel@tonic-gate 		{
420*0Sstevel@tonic-gate 		int Z_is_one;
421*0Sstevel@tonic-gate 
422*0Sstevel@tonic-gate 		if (!BN_nnmod(&point->Z, z, &group->field, ctx)) goto err;
423*0Sstevel@tonic-gate 		Z_is_one = BN_is_one(&point->Z);
424*0Sstevel@tonic-gate 		if (group->meth->field_encode)
425*0Sstevel@tonic-gate 			{
426*0Sstevel@tonic-gate 			if (Z_is_one && (group->meth->field_set_to_one != 0))
427*0Sstevel@tonic-gate 				{
428*0Sstevel@tonic-gate 				if (!group->meth->field_set_to_one(group, &point->Z, ctx)) goto err;
429*0Sstevel@tonic-gate 				}
430*0Sstevel@tonic-gate 			else
431*0Sstevel@tonic-gate 				{
432*0Sstevel@tonic-gate 				if (!group->meth->field_encode(group, &point->Z, &point->Z, ctx)) goto err;
433*0Sstevel@tonic-gate 				}
434*0Sstevel@tonic-gate 			}
435*0Sstevel@tonic-gate 		point->Z_is_one = Z_is_one;
436*0Sstevel@tonic-gate 		}
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate 	ret = 1;
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate  err:
441*0Sstevel@tonic-gate 	if (new_ctx != NULL)
442*0Sstevel@tonic-gate 		BN_CTX_free(new_ctx);
443*0Sstevel@tonic-gate 	return ret;
444*0Sstevel@tonic-gate 	}
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group, const EC_POINT *point,
448*0Sstevel@tonic-gate 	BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *ctx)
449*0Sstevel@tonic-gate 	{
450*0Sstevel@tonic-gate 	BN_CTX *new_ctx = NULL;
451*0Sstevel@tonic-gate 	int ret = 0;
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 	if (group->meth->field_decode != 0)
454*0Sstevel@tonic-gate 		{
455*0Sstevel@tonic-gate 		if (ctx == NULL)
456*0Sstevel@tonic-gate 			{
457*0Sstevel@tonic-gate 			ctx = new_ctx = BN_CTX_new();
458*0Sstevel@tonic-gate 			if (ctx == NULL)
459*0Sstevel@tonic-gate 				return 0;
460*0Sstevel@tonic-gate 			}
461*0Sstevel@tonic-gate 
462*0Sstevel@tonic-gate 		if (x != NULL)
463*0Sstevel@tonic-gate 			{
464*0Sstevel@tonic-gate 			if (!group->meth->field_decode(group, x, &point->X, ctx)) goto err;
465*0Sstevel@tonic-gate 			}
466*0Sstevel@tonic-gate 		if (y != NULL)
467*0Sstevel@tonic-gate 			{
468*0Sstevel@tonic-gate 			if (!group->meth->field_decode(group, y, &point->Y, ctx)) goto err;
469*0Sstevel@tonic-gate 			}
470*0Sstevel@tonic-gate 		if (z != NULL)
471*0Sstevel@tonic-gate 			{
472*0Sstevel@tonic-gate 			if (!group->meth->field_decode(group, z, &point->Z, ctx)) goto err;
473*0Sstevel@tonic-gate 			}
474*0Sstevel@tonic-gate 		}
475*0Sstevel@tonic-gate 	else
476*0Sstevel@tonic-gate 		{
477*0Sstevel@tonic-gate 		if (x != NULL)
478*0Sstevel@tonic-gate 			{
479*0Sstevel@tonic-gate 			if (!BN_copy(x, &point->X)) goto err;
480*0Sstevel@tonic-gate 			}
481*0Sstevel@tonic-gate 		if (y != NULL)
482*0Sstevel@tonic-gate 			{
483*0Sstevel@tonic-gate 			if (!BN_copy(y, &point->Y)) goto err;
484*0Sstevel@tonic-gate 			}
485*0Sstevel@tonic-gate 		if (z != NULL)
486*0Sstevel@tonic-gate 			{
487*0Sstevel@tonic-gate 			if (!BN_copy(z, &point->Z)) goto err;
488*0Sstevel@tonic-gate 			}
489*0Sstevel@tonic-gate 		}
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 	ret = 1;
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate  err:
494*0Sstevel@tonic-gate 	if (new_ctx != NULL)
495*0Sstevel@tonic-gate 		BN_CTX_free(new_ctx);
496*0Sstevel@tonic-gate 	return ret;
497*0Sstevel@tonic-gate 	}
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate int ec_GFp_simple_point_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
501*0Sstevel@tonic-gate 	const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx)
502*0Sstevel@tonic-gate 	{
503*0Sstevel@tonic-gate 	if (x == NULL || y == NULL)
504*0Sstevel@tonic-gate 		{
505*0Sstevel@tonic-gate 		/* unlike for projective coordinates, we do not tolerate this */
506*0Sstevel@tonic-gate 		ECerr(EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES_GFP, ERR_R_PASSED_NULL_PARAMETER);
507*0Sstevel@tonic-gate 		return 0;
508*0Sstevel@tonic-gate 		}
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 	return EC_POINT_set_Jprojective_coordinates_GFp(group, point, x, y, BN_value_one(), ctx);
511*0Sstevel@tonic-gate 	}
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate int ec_GFp_simple_point_get_affine_coordinates_GFp(const EC_GROUP *group, const EC_POINT *point,
515*0Sstevel@tonic-gate 	BIGNUM *x, BIGNUM *y, BN_CTX *ctx)
516*0Sstevel@tonic-gate 	{
517*0Sstevel@tonic-gate 	BN_CTX *new_ctx = NULL;
518*0Sstevel@tonic-gate 	BIGNUM *X, *Y, *Z, *Z_1, *Z_2, *Z_3;
519*0Sstevel@tonic-gate 	const BIGNUM *X_, *Y_, *Z_;
520*0Sstevel@tonic-gate 	int ret = 0;
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 	if (EC_POINT_is_at_infinity(group, point))
523*0Sstevel@tonic-gate 		{
524*0Sstevel@tonic-gate 		ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES_GFP, EC_R_POINT_AT_INFINITY);
525*0Sstevel@tonic-gate 		return 0;
526*0Sstevel@tonic-gate 		}
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	if (ctx == NULL)
529*0Sstevel@tonic-gate 		{
530*0Sstevel@tonic-gate 		ctx = new_ctx = BN_CTX_new();
531*0Sstevel@tonic-gate 		if (ctx == NULL)
532*0Sstevel@tonic-gate 			return 0;
533*0Sstevel@tonic-gate 		}
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 	BN_CTX_start(ctx);
536*0Sstevel@tonic-gate 	X = BN_CTX_get(ctx);
537*0Sstevel@tonic-gate 	Y = BN_CTX_get(ctx);
538*0Sstevel@tonic-gate 	Z = BN_CTX_get(ctx);
539*0Sstevel@tonic-gate 	Z_1 = BN_CTX_get(ctx);
540*0Sstevel@tonic-gate 	Z_2 = BN_CTX_get(ctx);
541*0Sstevel@tonic-gate 	Z_3 = BN_CTX_get(ctx);
542*0Sstevel@tonic-gate 	if (Z_3 == NULL) goto err;
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 	/* transform  (X, Y, Z)  into  (x, y) := (X/Z^2, Y/Z^3) */
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 	if (group->meth->field_decode)
547*0Sstevel@tonic-gate 		{
548*0Sstevel@tonic-gate 		if (!group->meth->field_decode(group, X, &point->X, ctx)) goto err;
549*0Sstevel@tonic-gate 		if (!group->meth->field_decode(group, Y, &point->Y, ctx)) goto err;
550*0Sstevel@tonic-gate 		if (!group->meth->field_decode(group, Z, &point->Z, ctx)) goto err;
551*0Sstevel@tonic-gate 		X_ = X; Y_ = Y;	Z_ = Z;
552*0Sstevel@tonic-gate 		}
553*0Sstevel@tonic-gate 	else
554*0Sstevel@tonic-gate 		{
555*0Sstevel@tonic-gate 		X_ = &point->X;
556*0Sstevel@tonic-gate 		Y_ = &point->Y;
557*0Sstevel@tonic-gate 		Z_ = &point->Z;
558*0Sstevel@tonic-gate 		}
559*0Sstevel@tonic-gate 
560*0Sstevel@tonic-gate 	if (BN_is_one(Z_))
561*0Sstevel@tonic-gate 		{
562*0Sstevel@tonic-gate 		if (x != NULL)
563*0Sstevel@tonic-gate 			{
564*0Sstevel@tonic-gate 			if (!BN_copy(x, X_)) goto err;
565*0Sstevel@tonic-gate 			}
566*0Sstevel@tonic-gate 		if (y != NULL)
567*0Sstevel@tonic-gate 			{
568*0Sstevel@tonic-gate 			if (!BN_copy(y, Y_)) goto err;
569*0Sstevel@tonic-gate 			}
570*0Sstevel@tonic-gate 		}
571*0Sstevel@tonic-gate 	else
572*0Sstevel@tonic-gate 		{
573*0Sstevel@tonic-gate 		if (!BN_mod_inverse(Z_1, Z_, &group->field, ctx))
574*0Sstevel@tonic-gate 			{
575*0Sstevel@tonic-gate 			ECerr(EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES_GFP, ERR_R_BN_LIB);
576*0Sstevel@tonic-gate 			goto err;
577*0Sstevel@tonic-gate 			}
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate 		if (group->meth->field_encode == 0)
580*0Sstevel@tonic-gate 			{
581*0Sstevel@tonic-gate 			/* field_sqr works on standard representation */
582*0Sstevel@tonic-gate 			if (!group->meth->field_sqr(group, Z_2, Z_1, ctx)) goto err;
583*0Sstevel@tonic-gate 			}
584*0Sstevel@tonic-gate 		else
585*0Sstevel@tonic-gate 			{
586*0Sstevel@tonic-gate 			if (!BN_mod_sqr(Z_2, Z_1, &group->field, ctx)) goto err;
587*0Sstevel@tonic-gate 			}
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 		if (x != NULL)
590*0Sstevel@tonic-gate 			{
591*0Sstevel@tonic-gate 			if (group->meth->field_encode == 0)
592*0Sstevel@tonic-gate 				{
593*0Sstevel@tonic-gate 				/* field_mul works on standard representation */
594*0Sstevel@tonic-gate 				if (!group->meth->field_mul(group, x, X_, Z_2, ctx)) goto err;
595*0Sstevel@tonic-gate 				}
596*0Sstevel@tonic-gate 			else
597*0Sstevel@tonic-gate 				{
598*0Sstevel@tonic-gate 				if (!BN_mod_mul(x, X_, Z_2, &group->field, ctx)) goto err;
599*0Sstevel@tonic-gate 				}
600*0Sstevel@tonic-gate 			}
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate 		if (y != NULL)
603*0Sstevel@tonic-gate 			{
604*0Sstevel@tonic-gate 			if (group->meth->field_encode == 0)
605*0Sstevel@tonic-gate 				{
606*0Sstevel@tonic-gate 				/* field_mul works on standard representation */
607*0Sstevel@tonic-gate 				if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx)) goto err;
608*0Sstevel@tonic-gate 				if (!group->meth->field_mul(group, y, Y_, Z_3, ctx)) goto err;
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 				}
611*0Sstevel@tonic-gate 			else
612*0Sstevel@tonic-gate 				{
613*0Sstevel@tonic-gate 				if (!BN_mod_mul(Z_3, Z_2, Z_1, &group->field, ctx)) goto err;
614*0Sstevel@tonic-gate 				if (!BN_mod_mul(y, Y_, Z_3, &group->field, ctx)) goto err;
615*0Sstevel@tonic-gate 				}
616*0Sstevel@tonic-gate 			}
617*0Sstevel@tonic-gate 		}
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	ret = 1;
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate  err:
622*0Sstevel@tonic-gate 	BN_CTX_end(ctx);
623*0Sstevel@tonic-gate 	if (new_ctx != NULL)
624*0Sstevel@tonic-gate 		BN_CTX_free(new_ctx);
625*0Sstevel@tonic-gate 	return ret;
626*0Sstevel@tonic-gate 	}
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate int ec_GFp_simple_set_compressed_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
630*0Sstevel@tonic-gate 	const BIGNUM *x_, int y_bit, BN_CTX *ctx)
631*0Sstevel@tonic-gate 	{
632*0Sstevel@tonic-gate 	BN_CTX *new_ctx = NULL;
633*0Sstevel@tonic-gate 	BIGNUM *tmp1, *tmp2, *x, *y;
634*0Sstevel@tonic-gate 	int ret = 0;
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate 	if (ctx == NULL)
637*0Sstevel@tonic-gate 		{
638*0Sstevel@tonic-gate 		ctx = new_ctx = BN_CTX_new();
639*0Sstevel@tonic-gate 		if (ctx == NULL)
640*0Sstevel@tonic-gate 			return 0;
641*0Sstevel@tonic-gate 		}
642*0Sstevel@tonic-gate 
643*0Sstevel@tonic-gate 	y_bit = (y_bit != 0);
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate 	BN_CTX_start(ctx);
646*0Sstevel@tonic-gate 	tmp1 = BN_CTX_get(ctx);
647*0Sstevel@tonic-gate 	tmp2 = BN_CTX_get(ctx);
648*0Sstevel@tonic-gate 	x = BN_CTX_get(ctx);
649*0Sstevel@tonic-gate 	y = BN_CTX_get(ctx);
650*0Sstevel@tonic-gate 	if (y == NULL) goto err;
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate 	/* Recover y.  We have a Weierstrass equation
653*0Sstevel@tonic-gate 	 *     y^2 = x^3 + a*x + b,
654*0Sstevel@tonic-gate 	 * so  y  is one of the square roots of  x^3 + a*x + b.
655*0Sstevel@tonic-gate 	 */
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 	/* tmp1 := x^3 */
658*0Sstevel@tonic-gate 	if (!BN_nnmod(x, x_, &group->field,ctx)) goto err;
659*0Sstevel@tonic-gate 	if (group->meth->field_decode == 0)
660*0Sstevel@tonic-gate 		{
661*0Sstevel@tonic-gate 		/* field_{sqr,mul} work on standard representation */
662*0Sstevel@tonic-gate 		if (!group->meth->field_sqr(group, tmp2, x_, ctx)) goto err;
663*0Sstevel@tonic-gate 		if (!group->meth->field_mul(group, tmp1, tmp2, x_, ctx)) goto err;
664*0Sstevel@tonic-gate 		}
665*0Sstevel@tonic-gate 	else
666*0Sstevel@tonic-gate 		{
667*0Sstevel@tonic-gate 		if (!BN_mod_sqr(tmp2, x_, &group->field, ctx)) goto err;
668*0Sstevel@tonic-gate 		if (!BN_mod_mul(tmp1, tmp2, x_, &group->field, ctx)) goto err;
669*0Sstevel@tonic-gate 		}
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate 	/* tmp1 := tmp1 + a*x */
672*0Sstevel@tonic-gate 	if (group->a_is_minus3)
673*0Sstevel@tonic-gate 		{
674*0Sstevel@tonic-gate 		if (!BN_mod_lshift1_quick(tmp2, x, &group->field)) goto err;
675*0Sstevel@tonic-gate 		if (!BN_mod_add_quick(tmp2, tmp2, x, &group->field)) goto err;
676*0Sstevel@tonic-gate 		if (!BN_mod_sub_quick(tmp1, tmp1, tmp2, &group->field)) goto err;
677*0Sstevel@tonic-gate 		}
678*0Sstevel@tonic-gate 	else
679*0Sstevel@tonic-gate 		{
680*0Sstevel@tonic-gate 		if (group->meth->field_decode)
681*0Sstevel@tonic-gate 			{
682*0Sstevel@tonic-gate 			if (!group->meth->field_decode(group, tmp2, &group->a, ctx)) goto err;
683*0Sstevel@tonic-gate 			if (!BN_mod_mul(tmp2, tmp2, x, &group->field, ctx)) goto err;
684*0Sstevel@tonic-gate 			}
685*0Sstevel@tonic-gate 		else
686*0Sstevel@tonic-gate 			{
687*0Sstevel@tonic-gate 			/* field_mul works on standard representation */
688*0Sstevel@tonic-gate 			if (!group->meth->field_mul(group, tmp2, &group->a, x, ctx)) goto err;
689*0Sstevel@tonic-gate 			}
690*0Sstevel@tonic-gate 
691*0Sstevel@tonic-gate 		if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) goto err;
692*0Sstevel@tonic-gate 		}
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 	/* tmp1 := tmp1 + b */
695*0Sstevel@tonic-gate 	if (group->meth->field_decode)
696*0Sstevel@tonic-gate 		{
697*0Sstevel@tonic-gate 		if (!group->meth->field_decode(group, tmp2, &group->b, ctx)) goto err;
698*0Sstevel@tonic-gate 		if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) goto err;
699*0Sstevel@tonic-gate 		}
700*0Sstevel@tonic-gate 	else
701*0Sstevel@tonic-gate 		{
702*0Sstevel@tonic-gate 		if (!BN_mod_add_quick(tmp1, tmp1, &group->b, &group->field)) goto err;
703*0Sstevel@tonic-gate 		}
704*0Sstevel@tonic-gate 
705*0Sstevel@tonic-gate 	if (!BN_mod_sqrt(y, tmp1, &group->field, ctx))
706*0Sstevel@tonic-gate 		{
707*0Sstevel@tonic-gate 		unsigned long err = ERR_peek_error();
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate 		if (ERR_GET_LIB(err) == ERR_LIB_BN && ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE)
710*0Sstevel@tonic-gate 			{
711*0Sstevel@tonic-gate 			(void)ERR_get_error();
712*0Sstevel@tonic-gate 			ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP, EC_R_INVALID_COMPRESSED_POINT);
713*0Sstevel@tonic-gate 			}
714*0Sstevel@tonic-gate 		else
715*0Sstevel@tonic-gate 			ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP, ERR_R_BN_LIB);
716*0Sstevel@tonic-gate 		goto err;
717*0Sstevel@tonic-gate 		}
718*0Sstevel@tonic-gate 	/* If tmp1 is not a square (i.e. there is no point on the curve with
719*0Sstevel@tonic-gate 	 * our x), then y now is a nonsense value too */
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate 	if (y_bit != BN_is_odd(y))
722*0Sstevel@tonic-gate 		{
723*0Sstevel@tonic-gate 		if (BN_is_zero(y))
724*0Sstevel@tonic-gate 			{
725*0Sstevel@tonic-gate 			int kron;
726*0Sstevel@tonic-gate 
727*0Sstevel@tonic-gate 			kron = BN_kronecker(x, &group->field, ctx);
728*0Sstevel@tonic-gate 			if (kron == -2) goto err;
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate 			if (kron == 1)
731*0Sstevel@tonic-gate 				ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP, EC_R_INVALID_COMPRESSION_BIT);
732*0Sstevel@tonic-gate 			else
733*0Sstevel@tonic-gate 				ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP, EC_R_INVALID_COMPRESSED_POINT);
734*0Sstevel@tonic-gate 			goto err;
735*0Sstevel@tonic-gate 			}
736*0Sstevel@tonic-gate 		if (!BN_usub(y, &group->field, y)) goto err;
737*0Sstevel@tonic-gate 		}
738*0Sstevel@tonic-gate 	if (y_bit != BN_is_odd(y))
739*0Sstevel@tonic-gate 		{
740*0Sstevel@tonic-gate 		ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP, ERR_R_INTERNAL_ERROR);
741*0Sstevel@tonic-gate 		goto err;
742*0Sstevel@tonic-gate 		}
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate 	if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
745*0Sstevel@tonic-gate 
746*0Sstevel@tonic-gate 	ret = 1;
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate  err:
749*0Sstevel@tonic-gate 	BN_CTX_end(ctx);
750*0Sstevel@tonic-gate 	if (new_ctx != NULL)
751*0Sstevel@tonic-gate 		BN_CTX_free(new_ctx);
752*0Sstevel@tonic-gate 	return ret;
753*0Sstevel@tonic-gate 	}
754*0Sstevel@tonic-gate 
755*0Sstevel@tonic-gate 
756*0Sstevel@tonic-gate size_t ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form,
757*0Sstevel@tonic-gate 	unsigned char *buf, size_t len, BN_CTX *ctx)
758*0Sstevel@tonic-gate 	{
759*0Sstevel@tonic-gate 	size_t ret;
760*0Sstevel@tonic-gate 	BN_CTX *new_ctx = NULL;
761*0Sstevel@tonic-gate 	int used_ctx = 0;
762*0Sstevel@tonic-gate 	BIGNUM *x, *y;
763*0Sstevel@tonic-gate 	size_t field_len, i, skip;
764*0Sstevel@tonic-gate 
765*0Sstevel@tonic-gate 	if ((form != POINT_CONVERSION_COMPRESSED)
766*0Sstevel@tonic-gate 		&& (form != POINT_CONVERSION_UNCOMPRESSED)
767*0Sstevel@tonic-gate 		&& (form != POINT_CONVERSION_HYBRID))
768*0Sstevel@tonic-gate 		{
769*0Sstevel@tonic-gate 		ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_INVALID_FORM);
770*0Sstevel@tonic-gate 		goto err;
771*0Sstevel@tonic-gate 		}
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 	if (EC_POINT_is_at_infinity(group, point))
774*0Sstevel@tonic-gate 		{
775*0Sstevel@tonic-gate 		/* encodes to a single 0 octet */
776*0Sstevel@tonic-gate 		if (buf != NULL)
777*0Sstevel@tonic-gate 			{
778*0Sstevel@tonic-gate 			if (len < 1)
779*0Sstevel@tonic-gate 				{
780*0Sstevel@tonic-gate 				ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
781*0Sstevel@tonic-gate 				return 0;
782*0Sstevel@tonic-gate 				}
783*0Sstevel@tonic-gate 			buf[0] = 0;
784*0Sstevel@tonic-gate 			}
785*0Sstevel@tonic-gate 		return 1;
786*0Sstevel@tonic-gate 		}
787*0Sstevel@tonic-gate 
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate 	/* ret := required output buffer length */
790*0Sstevel@tonic-gate 	field_len = BN_num_bytes(&group->field);
791*0Sstevel@tonic-gate 	ret = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len;
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 	/* if 'buf' is NULL, just return required length */
794*0Sstevel@tonic-gate 	if (buf != NULL)
795*0Sstevel@tonic-gate 		{
796*0Sstevel@tonic-gate 		if (len < ret)
797*0Sstevel@tonic-gate 			{
798*0Sstevel@tonic-gate 			ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
799*0Sstevel@tonic-gate 			goto err;
800*0Sstevel@tonic-gate 			}
801*0Sstevel@tonic-gate 
802*0Sstevel@tonic-gate 		if (ctx == NULL)
803*0Sstevel@tonic-gate 			{
804*0Sstevel@tonic-gate 			ctx = new_ctx = BN_CTX_new();
805*0Sstevel@tonic-gate 			if (ctx == NULL)
806*0Sstevel@tonic-gate 				return 0;
807*0Sstevel@tonic-gate 			}
808*0Sstevel@tonic-gate 
809*0Sstevel@tonic-gate 		BN_CTX_start(ctx);
810*0Sstevel@tonic-gate 		used_ctx = 1;
811*0Sstevel@tonic-gate 		x = BN_CTX_get(ctx);
812*0Sstevel@tonic-gate 		y = BN_CTX_get(ctx);
813*0Sstevel@tonic-gate 		if (y == NULL) goto err;
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate 		if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
816*0Sstevel@tonic-gate 
817*0Sstevel@tonic-gate 		if ((form == POINT_CONVERSION_COMPRESSED || form == POINT_CONVERSION_HYBRID) && BN_is_odd(y))
818*0Sstevel@tonic-gate 			buf[0] = form + 1;
819*0Sstevel@tonic-gate 		else
820*0Sstevel@tonic-gate 			buf[0] = form;
821*0Sstevel@tonic-gate 
822*0Sstevel@tonic-gate 		i = 1;
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate 		skip = field_len - BN_num_bytes(x);
825*0Sstevel@tonic-gate 		if (skip > field_len)
826*0Sstevel@tonic-gate 			{
827*0Sstevel@tonic-gate 			ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
828*0Sstevel@tonic-gate 			goto err;
829*0Sstevel@tonic-gate 			}
830*0Sstevel@tonic-gate 		while (skip > 0)
831*0Sstevel@tonic-gate 			{
832*0Sstevel@tonic-gate 			buf[i++] = 0;
833*0Sstevel@tonic-gate 			skip--;
834*0Sstevel@tonic-gate 			}
835*0Sstevel@tonic-gate 		skip = BN_bn2bin(x, buf + i);
836*0Sstevel@tonic-gate 		i += skip;
837*0Sstevel@tonic-gate 		if (i != 1 + field_len)
838*0Sstevel@tonic-gate 			{
839*0Sstevel@tonic-gate 			ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
840*0Sstevel@tonic-gate 			goto err;
841*0Sstevel@tonic-gate 			}
842*0Sstevel@tonic-gate 
843*0Sstevel@tonic-gate 		if (form == POINT_CONVERSION_UNCOMPRESSED || form == POINT_CONVERSION_HYBRID)
844*0Sstevel@tonic-gate 			{
845*0Sstevel@tonic-gate 			skip = field_len - BN_num_bytes(y);
846*0Sstevel@tonic-gate 			if (skip > field_len)
847*0Sstevel@tonic-gate 				{
848*0Sstevel@tonic-gate 				ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
849*0Sstevel@tonic-gate 				goto err;
850*0Sstevel@tonic-gate 				}
851*0Sstevel@tonic-gate 			while (skip > 0)
852*0Sstevel@tonic-gate 				{
853*0Sstevel@tonic-gate 				buf[i++] = 0;
854*0Sstevel@tonic-gate 				skip--;
855*0Sstevel@tonic-gate 				}
856*0Sstevel@tonic-gate 			skip = BN_bn2bin(y, buf + i);
857*0Sstevel@tonic-gate 			i += skip;
858*0Sstevel@tonic-gate 			}
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 		if (i != ret)
861*0Sstevel@tonic-gate 			{
862*0Sstevel@tonic-gate 			ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
863*0Sstevel@tonic-gate 			goto err;
864*0Sstevel@tonic-gate 			}
865*0Sstevel@tonic-gate 		}
866*0Sstevel@tonic-gate 
867*0Sstevel@tonic-gate 	if (used_ctx)
868*0Sstevel@tonic-gate 		BN_CTX_end(ctx);
869*0Sstevel@tonic-gate 	if (new_ctx != NULL)
870*0Sstevel@tonic-gate 		BN_CTX_free(new_ctx);
871*0Sstevel@tonic-gate 	return ret;
872*0Sstevel@tonic-gate 
873*0Sstevel@tonic-gate  err:
874*0Sstevel@tonic-gate 	if (used_ctx)
875*0Sstevel@tonic-gate 		BN_CTX_end(ctx);
876*0Sstevel@tonic-gate 	if (new_ctx != NULL)
877*0Sstevel@tonic-gate 		BN_CTX_free(new_ctx);
878*0Sstevel@tonic-gate 	return 0;
879*0Sstevel@tonic-gate 	}
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 
882*0Sstevel@tonic-gate int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
883*0Sstevel@tonic-gate 	const unsigned char *buf, size_t len, BN_CTX *ctx)
884*0Sstevel@tonic-gate 	{
885*0Sstevel@tonic-gate 	point_conversion_form_t form;
886*0Sstevel@tonic-gate 	int y_bit;
887*0Sstevel@tonic-gate 	BN_CTX *new_ctx = NULL;
888*0Sstevel@tonic-gate 	BIGNUM *x, *y;
889*0Sstevel@tonic-gate 	size_t field_len, enc_len;
890*0Sstevel@tonic-gate 	int ret = 0;
891*0Sstevel@tonic-gate 
892*0Sstevel@tonic-gate 	if (len == 0)
893*0Sstevel@tonic-gate 		{
894*0Sstevel@tonic-gate 		ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_BUFFER_TOO_SMALL);
895*0Sstevel@tonic-gate 		return 0;
896*0Sstevel@tonic-gate 		}
897*0Sstevel@tonic-gate 	form = buf[0];
898*0Sstevel@tonic-gate 	y_bit = form & 1;
899*0Sstevel@tonic-gate 	form = form & ~1U;
900*0Sstevel@tonic-gate 	if ((form != 0)	&& (form != POINT_CONVERSION_COMPRESSED)
901*0Sstevel@tonic-gate 		&& (form != POINT_CONVERSION_UNCOMPRESSED)
902*0Sstevel@tonic-gate 		&& (form != POINT_CONVERSION_HYBRID))
903*0Sstevel@tonic-gate 		{
904*0Sstevel@tonic-gate 		ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
905*0Sstevel@tonic-gate 		return 0;
906*0Sstevel@tonic-gate 		}
907*0Sstevel@tonic-gate 	if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit)
908*0Sstevel@tonic-gate 		{
909*0Sstevel@tonic-gate 		ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
910*0Sstevel@tonic-gate 		return 0;
911*0Sstevel@tonic-gate 		}
912*0Sstevel@tonic-gate 
913*0Sstevel@tonic-gate 	if (form == 0)
914*0Sstevel@tonic-gate 		{
915*0Sstevel@tonic-gate 		if (len != 1)
916*0Sstevel@tonic-gate 			{
917*0Sstevel@tonic-gate 			ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
918*0Sstevel@tonic-gate 			return 0;
919*0Sstevel@tonic-gate 			}
920*0Sstevel@tonic-gate 
921*0Sstevel@tonic-gate 		return EC_POINT_set_to_infinity(group, point);
922*0Sstevel@tonic-gate 		}
923*0Sstevel@tonic-gate 
924*0Sstevel@tonic-gate 	field_len = BN_num_bytes(&group->field);
925*0Sstevel@tonic-gate 	enc_len = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len;
926*0Sstevel@tonic-gate 
927*0Sstevel@tonic-gate 	if (len != enc_len)
928*0Sstevel@tonic-gate 		{
929*0Sstevel@tonic-gate 		ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
930*0Sstevel@tonic-gate 		return 0;
931*0Sstevel@tonic-gate 		}
932*0Sstevel@tonic-gate 
933*0Sstevel@tonic-gate 	if (ctx == NULL)
934*0Sstevel@tonic-gate 		{
935*0Sstevel@tonic-gate 		ctx = new_ctx = BN_CTX_new();
936*0Sstevel@tonic-gate 		if (ctx == NULL)
937*0Sstevel@tonic-gate 			return 0;
938*0Sstevel@tonic-gate 		}
939*0Sstevel@tonic-gate 
940*0Sstevel@tonic-gate 	BN_CTX_start(ctx);
941*0Sstevel@tonic-gate 	x = BN_CTX_get(ctx);
942*0Sstevel@tonic-gate 	y = BN_CTX_get(ctx);
943*0Sstevel@tonic-gate 	if (y == NULL) goto err;
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate 	if (!BN_bin2bn(buf + 1, field_len, x)) goto err;
946*0Sstevel@tonic-gate 	if (BN_ucmp(x, &group->field) >= 0)
947*0Sstevel@tonic-gate 		{
948*0Sstevel@tonic-gate 		ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
949*0Sstevel@tonic-gate 		goto err;
950*0Sstevel@tonic-gate 		}
951*0Sstevel@tonic-gate 
952*0Sstevel@tonic-gate 	if (form == POINT_CONVERSION_COMPRESSED)
953*0Sstevel@tonic-gate 		{
954*0Sstevel@tonic-gate 		if (!EC_POINT_set_compressed_coordinates_GFp(group, point, x, y_bit, ctx)) goto err;
955*0Sstevel@tonic-gate 		}
956*0Sstevel@tonic-gate 	else
957*0Sstevel@tonic-gate 		{
958*0Sstevel@tonic-gate 		if (!BN_bin2bn(buf + 1 + field_len, field_len, y)) goto err;
959*0Sstevel@tonic-gate 		if (BN_ucmp(y, &group->field) >= 0)
960*0Sstevel@tonic-gate 			{
961*0Sstevel@tonic-gate 			ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
962*0Sstevel@tonic-gate 			goto err;
963*0Sstevel@tonic-gate 			}
964*0Sstevel@tonic-gate 		if (form == POINT_CONVERSION_HYBRID)
965*0Sstevel@tonic-gate 			{
966*0Sstevel@tonic-gate 			if (y_bit != BN_is_odd(y))
967*0Sstevel@tonic-gate 				{
968*0Sstevel@tonic-gate 				ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
969*0Sstevel@tonic-gate 				goto err;
970*0Sstevel@tonic-gate 				}
971*0Sstevel@tonic-gate 			}
972*0Sstevel@tonic-gate 
973*0Sstevel@tonic-gate 		if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
974*0Sstevel@tonic-gate 		}
975*0Sstevel@tonic-gate 
976*0Sstevel@tonic-gate 	if (!EC_POINT_is_on_curve(group, point, ctx)) /* test required by X9.62 */
977*0Sstevel@tonic-gate 		{
978*0Sstevel@tonic-gate 		ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_POINT_IS_NOT_ON_CURVE);
979*0Sstevel@tonic-gate 		goto err;
980*0Sstevel@tonic-gate 		}
981*0Sstevel@tonic-gate 
982*0Sstevel@tonic-gate 	ret = 1;
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate  err:
985*0Sstevel@tonic-gate 	BN_CTX_end(ctx);
986*0Sstevel@tonic-gate 	if (new_ctx != NULL)
987*0Sstevel@tonic-gate 		BN_CTX_free(new_ctx);
988*0Sstevel@tonic-gate 	return ret;
989*0Sstevel@tonic-gate 	}
990*0Sstevel@tonic-gate 
991*0Sstevel@tonic-gate 
992*0Sstevel@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)
993*0Sstevel@tonic-gate 	{
994*0Sstevel@tonic-gate 	int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
995*0Sstevel@tonic-gate 	int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
996*0Sstevel@tonic-gate 	const BIGNUM *p;
997*0Sstevel@tonic-gate 	BN_CTX *new_ctx = NULL;
998*0Sstevel@tonic-gate 	BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6;
999*0Sstevel@tonic-gate 	int ret = 0;
1000*0Sstevel@tonic-gate 
1001*0Sstevel@tonic-gate 	if (a == b)
1002*0Sstevel@tonic-gate 		return EC_POINT_dbl(group, r, a, ctx);
1003*0Sstevel@tonic-gate 	if (EC_POINT_is_at_infinity(group, a))
1004*0Sstevel@tonic-gate 		return EC_POINT_copy(r, b);
1005*0Sstevel@tonic-gate 	if (EC_POINT_is_at_infinity(group, b))
1006*0Sstevel@tonic-gate 		return EC_POINT_copy(r, a);
1007*0Sstevel@tonic-gate 
1008*0Sstevel@tonic-gate 	field_mul = group->meth->field_mul;
1009*0Sstevel@tonic-gate 	field_sqr = group->meth->field_sqr;
1010*0Sstevel@tonic-gate 	p = &group->field;
1011*0Sstevel@tonic-gate 
1012*0Sstevel@tonic-gate 	if (ctx == NULL)
1013*0Sstevel@tonic-gate 		{
1014*0Sstevel@tonic-gate 		ctx = new_ctx = BN_CTX_new();
1015*0Sstevel@tonic-gate 		if (ctx == NULL)
1016*0Sstevel@tonic-gate 			return 0;
1017*0Sstevel@tonic-gate 		}
1018*0Sstevel@tonic-gate 
1019*0Sstevel@tonic-gate 	BN_CTX_start(ctx);
1020*0Sstevel@tonic-gate 	n0 = BN_CTX_get(ctx);
1021*0Sstevel@tonic-gate 	n1 = BN_CTX_get(ctx);
1022*0Sstevel@tonic-gate 	n2 = BN_CTX_get(ctx);
1023*0Sstevel@tonic-gate 	n3 = BN_CTX_get(ctx);
1024*0Sstevel@tonic-gate 	n4 = BN_CTX_get(ctx);
1025*0Sstevel@tonic-gate 	n5 = BN_CTX_get(ctx);
1026*0Sstevel@tonic-gate 	n6 = BN_CTX_get(ctx);
1027*0Sstevel@tonic-gate 	if (n6 == NULL) goto end;
1028*0Sstevel@tonic-gate 
1029*0Sstevel@tonic-gate 	/* Note that in this function we must not read components of 'a' or 'b'
1030*0Sstevel@tonic-gate 	 * once we have written the corresponding components of 'r'.
1031*0Sstevel@tonic-gate 	 * ('r' might be one of 'a' or 'b'.)
1032*0Sstevel@tonic-gate 	 */
1033*0Sstevel@tonic-gate 
1034*0Sstevel@tonic-gate 	/* n1, n2 */
1035*0Sstevel@tonic-gate 	if (b->Z_is_one)
1036*0Sstevel@tonic-gate 		{
1037*0Sstevel@tonic-gate 		if (!BN_copy(n1, &a->X)) goto end;
1038*0Sstevel@tonic-gate 		if (!BN_copy(n2, &a->Y)) goto end;
1039*0Sstevel@tonic-gate 		/* n1 = X_a */
1040*0Sstevel@tonic-gate 		/* n2 = Y_a */
1041*0Sstevel@tonic-gate 		}
1042*0Sstevel@tonic-gate 	else
1043*0Sstevel@tonic-gate 		{
1044*0Sstevel@tonic-gate 		if (!field_sqr(group, n0, &b->Z, ctx)) goto end;
1045*0Sstevel@tonic-gate 		if (!field_mul(group, n1, &a->X, n0, ctx)) goto end;
1046*0Sstevel@tonic-gate 		/* n1 = X_a * Z_b^2 */
1047*0Sstevel@tonic-gate 
1048*0Sstevel@tonic-gate 		if (!field_mul(group, n0, n0, &b->Z, ctx)) goto end;
1049*0Sstevel@tonic-gate 		if (!field_mul(group, n2, &a->Y, n0, ctx)) goto end;
1050*0Sstevel@tonic-gate 		/* n2 = Y_a * Z_b^3 */
1051*0Sstevel@tonic-gate 		}
1052*0Sstevel@tonic-gate 
1053*0Sstevel@tonic-gate 	/* n3, n4 */
1054*0Sstevel@tonic-gate 	if (a->Z_is_one)
1055*0Sstevel@tonic-gate 		{
1056*0Sstevel@tonic-gate 		if (!BN_copy(n3, &b->X)) goto end;
1057*0Sstevel@tonic-gate 		if (!BN_copy(n4, &b->Y)) goto end;
1058*0Sstevel@tonic-gate 		/* n3 = X_b */
1059*0Sstevel@tonic-gate 		/* n4 = Y_b */
1060*0Sstevel@tonic-gate 		}
1061*0Sstevel@tonic-gate 	else
1062*0Sstevel@tonic-gate 		{
1063*0Sstevel@tonic-gate 		if (!field_sqr(group, n0, &a->Z, ctx)) goto end;
1064*0Sstevel@tonic-gate 		if (!field_mul(group, n3, &b->X, n0, ctx)) goto end;
1065*0Sstevel@tonic-gate 		/* n3 = X_b * Z_a^2 */
1066*0Sstevel@tonic-gate 
1067*0Sstevel@tonic-gate 		if (!field_mul(group, n0, n0, &a->Z, ctx)) goto end;
1068*0Sstevel@tonic-gate 		if (!field_mul(group, n4, &b->Y, n0, ctx)) goto end;
1069*0Sstevel@tonic-gate 		/* n4 = Y_b * Z_a^3 */
1070*0Sstevel@tonic-gate 		}
1071*0Sstevel@tonic-gate 
1072*0Sstevel@tonic-gate 	/* n5, n6 */
1073*0Sstevel@tonic-gate 	if (!BN_mod_sub_quick(n5, n1, n3, p)) goto end;
1074*0Sstevel@tonic-gate 	if (!BN_mod_sub_quick(n6, n2, n4, p)) goto end;
1075*0Sstevel@tonic-gate 	/* n5 = n1 - n3 */
1076*0Sstevel@tonic-gate 	/* n6 = n2 - n4 */
1077*0Sstevel@tonic-gate 
1078*0Sstevel@tonic-gate 	if (BN_is_zero(n5))
1079*0Sstevel@tonic-gate 		{
1080*0Sstevel@tonic-gate 		if (BN_is_zero(n6))
1081*0Sstevel@tonic-gate 			{
1082*0Sstevel@tonic-gate 			/* a is the same point as b */
1083*0Sstevel@tonic-gate 			BN_CTX_end(ctx);
1084*0Sstevel@tonic-gate 			ret = EC_POINT_dbl(group, r, a, ctx);
1085*0Sstevel@tonic-gate 			ctx = NULL;
1086*0Sstevel@tonic-gate 			goto end;
1087*0Sstevel@tonic-gate 			}
1088*0Sstevel@tonic-gate 		else
1089*0Sstevel@tonic-gate 			{
1090*0Sstevel@tonic-gate 			/* a is the inverse of b */
1091*0Sstevel@tonic-gate 			if (!BN_zero(&r->Z)) goto end;
1092*0Sstevel@tonic-gate 			r->Z_is_one = 0;
1093*0Sstevel@tonic-gate 			ret = 1;
1094*0Sstevel@tonic-gate 			goto end;
1095*0Sstevel@tonic-gate 			}
1096*0Sstevel@tonic-gate 		}
1097*0Sstevel@tonic-gate 
1098*0Sstevel@tonic-gate 	/* 'n7', 'n8' */
1099*0Sstevel@tonic-gate 	if (!BN_mod_add_quick(n1, n1, n3, p)) goto end;
1100*0Sstevel@tonic-gate 	if (!BN_mod_add_quick(n2, n2, n4, p)) goto end;
1101*0Sstevel@tonic-gate 	/* 'n7' = n1 + n3 */
1102*0Sstevel@tonic-gate 	/* 'n8' = n2 + n4 */
1103*0Sstevel@tonic-gate 
1104*0Sstevel@tonic-gate 	/* Z_r */
1105*0Sstevel@tonic-gate 	if (a->Z_is_one && b->Z_is_one)
1106*0Sstevel@tonic-gate 		{
1107*0Sstevel@tonic-gate 		if (!BN_copy(&r->Z, n5)) goto end;
1108*0Sstevel@tonic-gate 		}
1109*0Sstevel@tonic-gate 	else
1110*0Sstevel@tonic-gate 		{
1111*0Sstevel@tonic-gate 		if (a->Z_is_one)
1112*0Sstevel@tonic-gate 			{ if (!BN_copy(n0, &b->Z)) goto end; }
1113*0Sstevel@tonic-gate 		else if (b->Z_is_one)
1114*0Sstevel@tonic-gate 			{ if (!BN_copy(n0, &a->Z)) goto end; }
1115*0Sstevel@tonic-gate 		else
1116*0Sstevel@tonic-gate 			{ if (!field_mul(group, n0, &a->Z, &b->Z, ctx)) goto end; }
1117*0Sstevel@tonic-gate 		if (!field_mul(group, &r->Z, n0, n5, ctx)) goto end;
1118*0Sstevel@tonic-gate 		}
1119*0Sstevel@tonic-gate 	r->Z_is_one = 0;
1120*0Sstevel@tonic-gate 	/* Z_r = Z_a * Z_b * n5 */
1121*0Sstevel@tonic-gate 
1122*0Sstevel@tonic-gate 	/* X_r */
1123*0Sstevel@tonic-gate 	if (!field_sqr(group, n0, n6, ctx)) goto end;
1124*0Sstevel@tonic-gate 	if (!field_sqr(group, n4, n5, ctx)) goto end;
1125*0Sstevel@tonic-gate 	if (!field_mul(group, n3, n1, n4, ctx)) goto end;
1126*0Sstevel@tonic-gate 	if (!BN_mod_sub_quick(&r->X, n0, n3, p)) goto end;
1127*0Sstevel@tonic-gate 	/* X_r = n6^2 - n5^2 * 'n7' */
1128*0Sstevel@tonic-gate 
1129*0Sstevel@tonic-gate 	/* 'n9' */
1130*0Sstevel@tonic-gate 	if (!BN_mod_lshift1_quick(n0, &r->X, p)) goto end;
1131*0Sstevel@tonic-gate 	if (!BN_mod_sub_quick(n0, n3, n0, p)) goto end;
1132*0Sstevel@tonic-gate 	/* n9 = n5^2 * 'n7' - 2 * X_r */
1133*0Sstevel@tonic-gate 
1134*0Sstevel@tonic-gate 	/* Y_r */
1135*0Sstevel@tonic-gate 	if (!field_mul(group, n0, n0, n6, ctx)) goto end;
1136*0Sstevel@tonic-gate 	if (!field_mul(group, n5, n4, n5, ctx)) goto end; /* now n5 is n5^3 */
1137*0Sstevel@tonic-gate 	if (!field_mul(group, n1, n2, n5, ctx)) goto end;
1138*0Sstevel@tonic-gate 	if (!BN_mod_sub_quick(n0, n0, n1, p)) goto end;
1139*0Sstevel@tonic-gate 	if (BN_is_odd(n0))
1140*0Sstevel@tonic-gate 		if (!BN_add(n0, n0, p)) goto end;
1141*0Sstevel@tonic-gate 	/* now  0 <= n0 < 2*p,  and n0 is even */
1142*0Sstevel@tonic-gate 	if (!BN_rshift1(&r->Y, n0)) goto end;
1143*0Sstevel@tonic-gate 	/* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */
1144*0Sstevel@tonic-gate 
1145*0Sstevel@tonic-gate 	ret = 1;
1146*0Sstevel@tonic-gate 
1147*0Sstevel@tonic-gate  end:
1148*0Sstevel@tonic-gate 	if (ctx) /* otherwise we already called BN_CTX_end */
1149*0Sstevel@tonic-gate 		BN_CTX_end(ctx);
1150*0Sstevel@tonic-gate 	if (new_ctx != NULL)
1151*0Sstevel@tonic-gate 		BN_CTX_free(new_ctx);
1152*0Sstevel@tonic-gate 	return ret;
1153*0Sstevel@tonic-gate 	}
1154*0Sstevel@tonic-gate 
1155*0Sstevel@tonic-gate 
1156*0Sstevel@tonic-gate int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx)
1157*0Sstevel@tonic-gate 	{
1158*0Sstevel@tonic-gate 	int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
1159*0Sstevel@tonic-gate 	int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
1160*0Sstevel@tonic-gate 	const BIGNUM *p;
1161*0Sstevel@tonic-gate 	BN_CTX *new_ctx = NULL;
1162*0Sstevel@tonic-gate 	BIGNUM *n0, *n1, *n2, *n3;
1163*0Sstevel@tonic-gate 	int ret = 0;
1164*0Sstevel@tonic-gate 
1165*0Sstevel@tonic-gate 	if (EC_POINT_is_at_infinity(group, a))
1166*0Sstevel@tonic-gate 		{
1167*0Sstevel@tonic-gate 		if (!BN_zero(&r->Z)) return 0;
1168*0Sstevel@tonic-gate 		r->Z_is_one = 0;
1169*0Sstevel@tonic-gate 		return 1;
1170*0Sstevel@tonic-gate 		}
1171*0Sstevel@tonic-gate 
1172*0Sstevel@tonic-gate 	field_mul = group->meth->field_mul;
1173*0Sstevel@tonic-gate 	field_sqr = group->meth->field_sqr;
1174*0Sstevel@tonic-gate 	p = &group->field;
1175*0Sstevel@tonic-gate 
1176*0Sstevel@tonic-gate 	if (ctx == NULL)
1177*0Sstevel@tonic-gate 		{
1178*0Sstevel@tonic-gate 		ctx = new_ctx = BN_CTX_new();
1179*0Sstevel@tonic-gate 		if (ctx == NULL)
1180*0Sstevel@tonic-gate 			return 0;
1181*0Sstevel@tonic-gate 		}
1182*0Sstevel@tonic-gate 
1183*0Sstevel@tonic-gate 	BN_CTX_start(ctx);
1184*0Sstevel@tonic-gate 	n0 = BN_CTX_get(ctx);
1185*0Sstevel@tonic-gate 	n1 = BN_CTX_get(ctx);
1186*0Sstevel@tonic-gate 	n2 = BN_CTX_get(ctx);
1187*0Sstevel@tonic-gate 	n3 = BN_CTX_get(ctx);
1188*0Sstevel@tonic-gate 	if (n3 == NULL) goto err;
1189*0Sstevel@tonic-gate 
1190*0Sstevel@tonic-gate 	/* Note that in this function we must not read components of 'a'
1191*0Sstevel@tonic-gate 	 * once we have written the corresponding components of 'r'.
1192*0Sstevel@tonic-gate 	 * ('r' might the same as 'a'.)
1193*0Sstevel@tonic-gate 	 */
1194*0Sstevel@tonic-gate 
1195*0Sstevel@tonic-gate 	/* n1 */
1196*0Sstevel@tonic-gate 	if (a->Z_is_one)
1197*0Sstevel@tonic-gate 		{
1198*0Sstevel@tonic-gate 		if (!field_sqr(group, n0, &a->X, ctx)) goto err;
1199*0Sstevel@tonic-gate 		if (!BN_mod_lshift1_quick(n1, n0, p)) goto err;
1200*0Sstevel@tonic-gate 		if (!BN_mod_add_quick(n0, n0, n1, p)) goto err;
1201*0Sstevel@tonic-gate 		if (!BN_mod_add_quick(n1, n0, &group->a, p)) goto err;
1202*0Sstevel@tonic-gate 		/* n1 = 3 * X_a^2 + a_curve */
1203*0Sstevel@tonic-gate 		}
1204*0Sstevel@tonic-gate 	else if (group->a_is_minus3)
1205*0Sstevel@tonic-gate 		{
1206*0Sstevel@tonic-gate 		if (!field_sqr(group, n1, &a->Z, ctx)) goto err;
1207*0Sstevel@tonic-gate 		if (!BN_mod_add_quick(n0, &a->X, n1, p)) goto err;
1208*0Sstevel@tonic-gate 		if (!BN_mod_sub_quick(n2, &a->X, n1, p)) goto err;
1209*0Sstevel@tonic-gate 		if (!field_mul(group, n1, n0, n2, ctx)) goto err;
1210*0Sstevel@tonic-gate 		if (!BN_mod_lshift1_quick(n0, n1, p)) goto err;
1211*0Sstevel@tonic-gate 		if (!BN_mod_add_quick(n1, n0, n1, p)) goto err;
1212*0Sstevel@tonic-gate 		/* n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2)
1213*0Sstevel@tonic-gate 		 *    = 3 * X_a^2 - 3 * Z_a^4 */
1214*0Sstevel@tonic-gate 		}
1215*0Sstevel@tonic-gate 	else
1216*0Sstevel@tonic-gate 		{
1217*0Sstevel@tonic-gate 		if (!field_sqr(group, n0, &a->X, ctx)) goto err;
1218*0Sstevel@tonic-gate 		if (!BN_mod_lshift1_quick(n1, n0, p)) goto err;
1219*0Sstevel@tonic-gate 		if (!BN_mod_add_quick(n0, n0, n1, p)) goto err;
1220*0Sstevel@tonic-gate 		if (!field_sqr(group, n1, &a->Z, ctx)) goto err;
1221*0Sstevel@tonic-gate 		if (!field_sqr(group, n1, n1, ctx)) goto err;
1222*0Sstevel@tonic-gate 		if (!field_mul(group, n1, n1, &group->a, ctx)) goto err;
1223*0Sstevel@tonic-gate 		if (!BN_mod_add_quick(n1, n1, n0, p)) goto err;
1224*0Sstevel@tonic-gate 		/* n1 = 3 * X_a^2 + a_curve * Z_a^4 */
1225*0Sstevel@tonic-gate 		}
1226*0Sstevel@tonic-gate 
1227*0Sstevel@tonic-gate 	/* Z_r */
1228*0Sstevel@tonic-gate 	if (a->Z_is_one)
1229*0Sstevel@tonic-gate 		{
1230*0Sstevel@tonic-gate 		if (!BN_copy(n0, &a->Y)) goto err;
1231*0Sstevel@tonic-gate 		}
1232*0Sstevel@tonic-gate 	else
1233*0Sstevel@tonic-gate 		{
1234*0Sstevel@tonic-gate 		if (!field_mul(group, n0, &a->Y, &a->Z, ctx)) goto err;
1235*0Sstevel@tonic-gate 		}
1236*0Sstevel@tonic-gate 	if (!BN_mod_lshift1_quick(&r->Z, n0, p)) goto err;
1237*0Sstevel@tonic-gate 	r->Z_is_one = 0;
1238*0Sstevel@tonic-gate 	/* Z_r = 2 * Y_a * Z_a */
1239*0Sstevel@tonic-gate 
1240*0Sstevel@tonic-gate 	/* n2 */
1241*0Sstevel@tonic-gate 	if (!field_sqr(group, n3, &a->Y, ctx)) goto err;
1242*0Sstevel@tonic-gate 	if (!field_mul(group, n2, &a->X, n3, ctx)) goto err;
1243*0Sstevel@tonic-gate 	if (!BN_mod_lshift_quick(n2, n2, 2, p)) goto err;
1244*0Sstevel@tonic-gate 	/* n2 = 4 * X_a * Y_a^2 */
1245*0Sstevel@tonic-gate 
1246*0Sstevel@tonic-gate 	/* X_r */
1247*0Sstevel@tonic-gate 	if (!BN_mod_lshift1_quick(n0, n2, p)) goto err;
1248*0Sstevel@tonic-gate 	if (!field_sqr(group, &r->X, n1, ctx)) goto err;
1249*0Sstevel@tonic-gate 	if (!BN_mod_sub_quick(&r->X, &r->X, n0, p)) goto err;
1250*0Sstevel@tonic-gate 	/* X_r = n1^2 - 2 * n2 */
1251*0Sstevel@tonic-gate 
1252*0Sstevel@tonic-gate 	/* n3 */
1253*0Sstevel@tonic-gate 	if (!field_sqr(group, n0, n3, ctx)) goto err;
1254*0Sstevel@tonic-gate 	if (!BN_mod_lshift_quick(n3, n0, 3, p)) goto err;
1255*0Sstevel@tonic-gate 	/* n3 = 8 * Y_a^4 */
1256*0Sstevel@tonic-gate 
1257*0Sstevel@tonic-gate 	/* Y_r */
1258*0Sstevel@tonic-gate 	if (!BN_mod_sub_quick(n0, n2, &r->X, p)) goto err;
1259*0Sstevel@tonic-gate 	if (!field_mul(group, n0, n1, n0, ctx)) goto err;
1260*0Sstevel@tonic-gate 	if (!BN_mod_sub_quick(&r->Y, n0, n3, p)) goto err;
1261*0Sstevel@tonic-gate 	/* Y_r = n1 * (n2 - X_r) - n3 */
1262*0Sstevel@tonic-gate 
1263*0Sstevel@tonic-gate 	ret = 1;
1264*0Sstevel@tonic-gate 
1265*0Sstevel@tonic-gate  err:
1266*0Sstevel@tonic-gate 	BN_CTX_end(ctx);
1267*0Sstevel@tonic-gate 	if (new_ctx != NULL)
1268*0Sstevel@tonic-gate 		BN_CTX_free(new_ctx);
1269*0Sstevel@tonic-gate 	return ret;
1270*0Sstevel@tonic-gate 	}
1271*0Sstevel@tonic-gate 
1272*0Sstevel@tonic-gate 
1273*0Sstevel@tonic-gate int ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx)
1274*0Sstevel@tonic-gate 	{
1275*0Sstevel@tonic-gate 	if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(&point->Y))
1276*0Sstevel@tonic-gate 		/* point is its own inverse */
1277*0Sstevel@tonic-gate 		return 1;
1278*0Sstevel@tonic-gate 
1279*0Sstevel@tonic-gate 	return BN_usub(&point->Y, &group->field, &point->Y);
1280*0Sstevel@tonic-gate 	}
1281*0Sstevel@tonic-gate 
1282*0Sstevel@tonic-gate 
1283*0Sstevel@tonic-gate int ec_GFp_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point)
1284*0Sstevel@tonic-gate 	{
1285*0Sstevel@tonic-gate 	return BN_is_zero(&point->Z);
1286*0Sstevel@tonic-gate 	}
1287*0Sstevel@tonic-gate 
1288*0Sstevel@tonic-gate 
1289*0Sstevel@tonic-gate int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx)
1290*0Sstevel@tonic-gate 	{
1291*0Sstevel@tonic-gate 	int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
1292*0Sstevel@tonic-gate 	int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
1293*0Sstevel@tonic-gate 	const BIGNUM *p;
1294*0Sstevel@tonic-gate 	BN_CTX *new_ctx = NULL;
1295*0Sstevel@tonic-gate 	BIGNUM *rh, *tmp1, *tmp2, *Z4, *Z6;
1296*0Sstevel@tonic-gate 	int ret = -1;
1297*0Sstevel@tonic-gate 
1298*0Sstevel@tonic-gate 	if (EC_POINT_is_at_infinity(group, point))
1299*0Sstevel@tonic-gate 		return 1;
1300*0Sstevel@tonic-gate 
1301*0Sstevel@tonic-gate 	field_mul = group->meth->field_mul;
1302*0Sstevel@tonic-gate 	field_sqr = group->meth->field_sqr;
1303*0Sstevel@tonic-gate 	p = &group->field;
1304*0Sstevel@tonic-gate 
1305*0Sstevel@tonic-gate 	if (ctx == NULL)
1306*0Sstevel@tonic-gate 		{
1307*0Sstevel@tonic-gate 		ctx = new_ctx = BN_CTX_new();
1308*0Sstevel@tonic-gate 		if (ctx == NULL)
1309*0Sstevel@tonic-gate 			return -1;
1310*0Sstevel@tonic-gate 		}
1311*0Sstevel@tonic-gate 
1312*0Sstevel@tonic-gate 	BN_CTX_start(ctx);
1313*0Sstevel@tonic-gate 	rh = BN_CTX_get(ctx);
1314*0Sstevel@tonic-gate 	tmp1 = BN_CTX_get(ctx);
1315*0Sstevel@tonic-gate 	tmp2 = BN_CTX_get(ctx);
1316*0Sstevel@tonic-gate 	Z4 = BN_CTX_get(ctx);
1317*0Sstevel@tonic-gate 	Z6 = BN_CTX_get(ctx);
1318*0Sstevel@tonic-gate 	if (Z6 == NULL) goto err;
1319*0Sstevel@tonic-gate 
1320*0Sstevel@tonic-gate 	/* We have a curve defined by a Weierstrass equation
1321*0Sstevel@tonic-gate 	 *      y^2 = x^3 + a*x + b.
1322*0Sstevel@tonic-gate 	 * The point to consider is given in Jacobian projective coordinates
1323*0Sstevel@tonic-gate 	 * where  (X, Y, Z)  represents  (x, y) = (X/Z^2, Y/Z^3).
1324*0Sstevel@tonic-gate 	 * Substituting this and multiplying by  Z^6  transforms the above equation into
1325*0Sstevel@tonic-gate 	 *      Y^2 = X^3 + a*X*Z^4 + b*Z^6.
1326*0Sstevel@tonic-gate 	 * To test this, we add up the right-hand side in 'rh'.
1327*0Sstevel@tonic-gate 	 */
1328*0Sstevel@tonic-gate 
1329*0Sstevel@tonic-gate 	/* rh := X^3 */
1330*0Sstevel@tonic-gate 	if (!field_sqr(group, rh, &point->X, ctx)) goto err;
1331*0Sstevel@tonic-gate 	if (!field_mul(group, rh, rh, &point->X, ctx)) goto err;
1332*0Sstevel@tonic-gate 
1333*0Sstevel@tonic-gate 	if (!point->Z_is_one)
1334*0Sstevel@tonic-gate 		{
1335*0Sstevel@tonic-gate 		if (!field_sqr(group, tmp1, &point->Z, ctx)) goto err;
1336*0Sstevel@tonic-gate 		if (!field_sqr(group, Z4, tmp1, ctx)) goto err;
1337*0Sstevel@tonic-gate 		if (!field_mul(group, Z6, Z4, tmp1, ctx)) goto err;
1338*0Sstevel@tonic-gate 
1339*0Sstevel@tonic-gate 		/* rh := rh + a*X*Z^4 */
1340*0Sstevel@tonic-gate 		if (!field_mul(group, tmp1, &point->X, Z4, ctx)) goto err;
1341*0Sstevel@tonic-gate 		if (group->a_is_minus3)
1342*0Sstevel@tonic-gate 			{
1343*0Sstevel@tonic-gate 			if (!BN_mod_lshift1_quick(tmp2, tmp1, p)) goto err;
1344*0Sstevel@tonic-gate 			if (!BN_mod_add_quick(tmp2, tmp2, tmp1, p)) goto err;
1345*0Sstevel@tonic-gate 			if (!BN_mod_sub_quick(rh, rh, tmp2, p)) goto err;
1346*0Sstevel@tonic-gate 			}
1347*0Sstevel@tonic-gate 		else
1348*0Sstevel@tonic-gate 			{
1349*0Sstevel@tonic-gate 			if (!field_mul(group, tmp2, tmp1, &group->a, ctx)) goto err;
1350*0Sstevel@tonic-gate 			if (!BN_mod_add_quick(rh, rh, tmp2, p)) goto err;
1351*0Sstevel@tonic-gate 			}
1352*0Sstevel@tonic-gate 
1353*0Sstevel@tonic-gate 		/* rh := rh + b*Z^6 */
1354*0Sstevel@tonic-gate 		if (!field_mul(group, tmp1, &group->b, Z6, ctx)) goto err;
1355*0Sstevel@tonic-gate 		if (!BN_mod_add_quick(rh, rh, tmp1, p)) goto err;
1356*0Sstevel@tonic-gate 		}
1357*0Sstevel@tonic-gate 	else
1358*0Sstevel@tonic-gate 		{
1359*0Sstevel@tonic-gate 		/* point->Z_is_one */
1360*0Sstevel@tonic-gate 
1361*0Sstevel@tonic-gate 		/* rh := rh + a*X */
1362*0Sstevel@tonic-gate 		if (group->a_is_minus3)
1363*0Sstevel@tonic-gate 			{
1364*0Sstevel@tonic-gate 			if (!BN_mod_lshift1_quick(tmp2, &point->X, p)) goto err;
1365*0Sstevel@tonic-gate 			if (!BN_mod_add_quick(tmp2, tmp2, &point->X, p)) goto err;
1366*0Sstevel@tonic-gate 			if (!BN_mod_sub_quick(rh, rh, tmp2, p)) goto err;
1367*0Sstevel@tonic-gate 			}
1368*0Sstevel@tonic-gate 		else
1369*0Sstevel@tonic-gate 			{
1370*0Sstevel@tonic-gate 			if (!field_mul(group, tmp2, &point->X, &group->a, ctx)) goto err;
1371*0Sstevel@tonic-gate 			if (!BN_mod_add_quick(rh, rh, tmp2, p)) goto err;
1372*0Sstevel@tonic-gate 			}
1373*0Sstevel@tonic-gate 
1374*0Sstevel@tonic-gate 		/* rh := rh + b */
1375*0Sstevel@tonic-gate 		if (!BN_mod_add_quick(rh, rh, &group->b, p)) goto err;
1376*0Sstevel@tonic-gate 		}
1377*0Sstevel@tonic-gate 
1378*0Sstevel@tonic-gate 	/* 'lh' := Y^2 */
1379*0Sstevel@tonic-gate 	if (!field_sqr(group, tmp1, &point->Y, ctx)) goto err;
1380*0Sstevel@tonic-gate 
1381*0Sstevel@tonic-gate 	ret = (0 == BN_cmp(tmp1, rh));
1382*0Sstevel@tonic-gate 
1383*0Sstevel@tonic-gate  err:
1384*0Sstevel@tonic-gate 	BN_CTX_end(ctx);
1385*0Sstevel@tonic-gate 	if (new_ctx != NULL)
1386*0Sstevel@tonic-gate 		BN_CTX_free(new_ctx);
1387*0Sstevel@tonic-gate 	return ret;
1388*0Sstevel@tonic-gate 	}
1389*0Sstevel@tonic-gate 
1390*0Sstevel@tonic-gate 
1391*0Sstevel@tonic-gate int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx)
1392*0Sstevel@tonic-gate 	{
1393*0Sstevel@tonic-gate 	/* return values:
1394*0Sstevel@tonic-gate 	 *  -1   error
1395*0Sstevel@tonic-gate 	 *   0   equal (in affine coordinates)
1396*0Sstevel@tonic-gate 	 *   1   not equal
1397*0Sstevel@tonic-gate 	 */
1398*0Sstevel@tonic-gate 
1399*0Sstevel@tonic-gate 	int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
1400*0Sstevel@tonic-gate 	int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
1401*0Sstevel@tonic-gate 	BN_CTX *new_ctx = NULL;
1402*0Sstevel@tonic-gate 	BIGNUM *tmp1, *tmp2, *Za23, *Zb23;
1403*0Sstevel@tonic-gate 	const BIGNUM *tmp1_, *tmp2_;
1404*0Sstevel@tonic-gate 	int ret = -1;
1405*0Sstevel@tonic-gate 
1406*0Sstevel@tonic-gate 	if (EC_POINT_is_at_infinity(group, a))
1407*0Sstevel@tonic-gate 		{
1408*0Sstevel@tonic-gate 		return EC_POINT_is_at_infinity(group, b) ? 0 : 1;
1409*0Sstevel@tonic-gate 		}
1410*0Sstevel@tonic-gate 
1411*0Sstevel@tonic-gate 	if (a->Z_is_one && b->Z_is_one)
1412*0Sstevel@tonic-gate 		{
1413*0Sstevel@tonic-gate 		return ((BN_cmp(&a->X, &b->X) == 0) && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1;
1414*0Sstevel@tonic-gate 		}
1415*0Sstevel@tonic-gate 
1416*0Sstevel@tonic-gate 	field_mul = group->meth->field_mul;
1417*0Sstevel@tonic-gate 	field_sqr = group->meth->field_sqr;
1418*0Sstevel@tonic-gate 
1419*0Sstevel@tonic-gate 	if (ctx == NULL)
1420*0Sstevel@tonic-gate 		{
1421*0Sstevel@tonic-gate 		ctx = new_ctx = BN_CTX_new();
1422*0Sstevel@tonic-gate 		if (ctx == NULL)
1423*0Sstevel@tonic-gate 			return -1;
1424*0Sstevel@tonic-gate 		}
1425*0Sstevel@tonic-gate 
1426*0Sstevel@tonic-gate 	BN_CTX_start(ctx);
1427*0Sstevel@tonic-gate 	tmp1 = BN_CTX_get(ctx);
1428*0Sstevel@tonic-gate 	tmp2 = BN_CTX_get(ctx);
1429*0Sstevel@tonic-gate 	Za23 = BN_CTX_get(ctx);
1430*0Sstevel@tonic-gate 	Zb23 = BN_CTX_get(ctx);
1431*0Sstevel@tonic-gate 	if (Zb23 == NULL) goto end;
1432*0Sstevel@tonic-gate 
1433*0Sstevel@tonic-gate 	/* We have to decide whether
1434*0Sstevel@tonic-gate 	 *     (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3),
1435*0Sstevel@tonic-gate 	 * or equivalently, whether
1436*0Sstevel@tonic-gate 	 *     (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3).
1437*0Sstevel@tonic-gate 	 */
1438*0Sstevel@tonic-gate 
1439*0Sstevel@tonic-gate 	if (!b->Z_is_one)
1440*0Sstevel@tonic-gate 		{
1441*0Sstevel@tonic-gate 		if (!field_sqr(group, Zb23, &b->Z, ctx)) goto end;
1442*0Sstevel@tonic-gate 		if (!field_mul(group, tmp1, &a->X, Zb23, ctx)) goto end;
1443*0Sstevel@tonic-gate 		tmp1_ = tmp1;
1444*0Sstevel@tonic-gate 		}
1445*0Sstevel@tonic-gate 	else
1446*0Sstevel@tonic-gate 		tmp1_ = &a->X;
1447*0Sstevel@tonic-gate 	if (!a->Z_is_one)
1448*0Sstevel@tonic-gate 		{
1449*0Sstevel@tonic-gate 		if (!field_sqr(group, Za23, &a->Z, ctx)) goto end;
1450*0Sstevel@tonic-gate 		if (!field_mul(group, tmp2, &b->X, Za23, ctx)) goto end;
1451*0Sstevel@tonic-gate 		tmp2_ = tmp2;
1452*0Sstevel@tonic-gate 		}
1453*0Sstevel@tonic-gate 	else
1454*0Sstevel@tonic-gate 		tmp2_ = &b->X;
1455*0Sstevel@tonic-gate 
1456*0Sstevel@tonic-gate 	/* compare  X_a*Z_b^2  with  X_b*Z_a^2 */
1457*0Sstevel@tonic-gate 	if (BN_cmp(tmp1_, tmp2_) != 0)
1458*0Sstevel@tonic-gate 		{
1459*0Sstevel@tonic-gate 		ret = 1; /* points differ */
1460*0Sstevel@tonic-gate 		goto end;
1461*0Sstevel@tonic-gate 		}
1462*0Sstevel@tonic-gate 
1463*0Sstevel@tonic-gate 
1464*0Sstevel@tonic-gate 	if (!b->Z_is_one)
1465*0Sstevel@tonic-gate 		{
1466*0Sstevel@tonic-gate 		if (!field_mul(group, Zb23, Zb23, &b->Z, ctx)) goto end;
1467*0Sstevel@tonic-gate 		if (!field_mul(group, tmp1, &a->Y, Zb23, ctx)) goto end;
1468*0Sstevel@tonic-gate 		/* tmp1_ = tmp1 */
1469*0Sstevel@tonic-gate 		}
1470*0Sstevel@tonic-gate 	else
1471*0Sstevel@tonic-gate 		tmp1_ = &a->Y;
1472*0Sstevel@tonic-gate 	if (!a->Z_is_one)
1473*0Sstevel@tonic-gate 		{
1474*0Sstevel@tonic-gate 		if (!field_mul(group, Za23, Za23, &a->Z, ctx)) goto end;
1475*0Sstevel@tonic-gate 		if (!field_mul(group, tmp2, &b->Y, Za23, ctx)) goto end;
1476*0Sstevel@tonic-gate 		/* tmp2_ = tmp2 */
1477*0Sstevel@tonic-gate 		}
1478*0Sstevel@tonic-gate 	else
1479*0Sstevel@tonic-gate 		tmp2_ = &b->Y;
1480*0Sstevel@tonic-gate 
1481*0Sstevel@tonic-gate 	/* compare  Y_a*Z_b^3  with  Y_b*Z_a^3 */
1482*0Sstevel@tonic-gate 	if (BN_cmp(tmp1_, tmp2_) != 0)
1483*0Sstevel@tonic-gate 		{
1484*0Sstevel@tonic-gate 		ret = 1; /* points differ */
1485*0Sstevel@tonic-gate 		goto end;
1486*0Sstevel@tonic-gate 		}
1487*0Sstevel@tonic-gate 
1488*0Sstevel@tonic-gate 	/* points are equal */
1489*0Sstevel@tonic-gate 	ret = 0;
1490*0Sstevel@tonic-gate 
1491*0Sstevel@tonic-gate  end:
1492*0Sstevel@tonic-gate 	BN_CTX_end(ctx);
1493*0Sstevel@tonic-gate 	if (new_ctx != NULL)
1494*0Sstevel@tonic-gate 		BN_CTX_free(new_ctx);
1495*0Sstevel@tonic-gate 	return ret;
1496*0Sstevel@tonic-gate 	}
1497*0Sstevel@tonic-gate 
1498*0Sstevel@tonic-gate 
1499*0Sstevel@tonic-gate int ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx)
1500*0Sstevel@tonic-gate 	{
1501*0Sstevel@tonic-gate 	BN_CTX *new_ctx = NULL;
1502*0Sstevel@tonic-gate 	BIGNUM *x, *y;
1503*0Sstevel@tonic-gate 	int ret = 0;
1504*0Sstevel@tonic-gate 
1505*0Sstevel@tonic-gate 	if (point->Z_is_one || EC_POINT_is_at_infinity(group, point))
1506*0Sstevel@tonic-gate 		return 1;
1507*0Sstevel@tonic-gate 
1508*0Sstevel@tonic-gate 	if (ctx == NULL)
1509*0Sstevel@tonic-gate 		{
1510*0Sstevel@tonic-gate 		ctx = new_ctx = BN_CTX_new();
1511*0Sstevel@tonic-gate 		if (ctx == NULL)
1512*0Sstevel@tonic-gate 			return 0;
1513*0Sstevel@tonic-gate 		}
1514*0Sstevel@tonic-gate 
1515*0Sstevel@tonic-gate 	BN_CTX_start(ctx);
1516*0Sstevel@tonic-gate 	x = BN_CTX_get(ctx);
1517*0Sstevel@tonic-gate 	y = BN_CTX_get(ctx);
1518*0Sstevel@tonic-gate 	if (y == NULL) goto err;
1519*0Sstevel@tonic-gate 
1520*0Sstevel@tonic-gate 	if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
1521*0Sstevel@tonic-gate 	if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err;
1522*0Sstevel@tonic-gate 	if (!point->Z_is_one)
1523*0Sstevel@tonic-gate 		{
1524*0Sstevel@tonic-gate 		ECerr(EC_F_EC_GFP_SIMPLE_MAKE_AFFINE, ERR_R_INTERNAL_ERROR);
1525*0Sstevel@tonic-gate 		goto err;
1526*0Sstevel@tonic-gate 		}
1527*0Sstevel@tonic-gate 
1528*0Sstevel@tonic-gate 	ret = 1;
1529*0Sstevel@tonic-gate 
1530*0Sstevel@tonic-gate  err:
1531*0Sstevel@tonic-gate 	BN_CTX_end(ctx);
1532*0Sstevel@tonic-gate 	if (new_ctx != NULL)
1533*0Sstevel@tonic-gate 		BN_CTX_free(new_ctx);
1534*0Sstevel@tonic-gate 	return ret;
1535*0Sstevel@tonic-gate 	}
1536*0Sstevel@tonic-gate 
1537*0Sstevel@tonic-gate 
1538*0Sstevel@tonic-gate int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], BN_CTX *ctx)
1539*0Sstevel@tonic-gate 	{
1540*0Sstevel@tonic-gate 	BN_CTX *new_ctx = NULL;
1541*0Sstevel@tonic-gate 	BIGNUM *tmp0, *tmp1;
1542*0Sstevel@tonic-gate 	size_t pow2 = 0;
1543*0Sstevel@tonic-gate 	BIGNUM **heap = NULL;
1544*0Sstevel@tonic-gate 	size_t i;
1545*0Sstevel@tonic-gate 	int ret = 0;
1546*0Sstevel@tonic-gate 
1547*0Sstevel@tonic-gate 	if (num == 0)
1548*0Sstevel@tonic-gate 		return 1;
1549*0Sstevel@tonic-gate 
1550*0Sstevel@tonic-gate 	if (ctx == NULL)
1551*0Sstevel@tonic-gate 		{
1552*0Sstevel@tonic-gate 		ctx = new_ctx = BN_CTX_new();
1553*0Sstevel@tonic-gate 		if (ctx == NULL)
1554*0Sstevel@tonic-gate 			return 0;
1555*0Sstevel@tonic-gate 		}
1556*0Sstevel@tonic-gate 
1557*0Sstevel@tonic-gate 	BN_CTX_start(ctx);
1558*0Sstevel@tonic-gate 	tmp0 = BN_CTX_get(ctx);
1559*0Sstevel@tonic-gate 	tmp1 = BN_CTX_get(ctx);
1560*0Sstevel@tonic-gate 	if (tmp0  == NULL || tmp1 == NULL) goto err;
1561*0Sstevel@tonic-gate 
1562*0Sstevel@tonic-gate 	/* Before converting the individual points, compute inverses of all Z values.
1563*0Sstevel@tonic-gate 	 * Modular inversion is rather slow, but luckily we can do with a single
1564*0Sstevel@tonic-gate 	 * explicit inversion, plus about 3 multiplications per input value.
1565*0Sstevel@tonic-gate 	 */
1566*0Sstevel@tonic-gate 
1567*0Sstevel@tonic-gate 	pow2 = 1;
1568*0Sstevel@tonic-gate 	while (num > pow2)
1569*0Sstevel@tonic-gate 		pow2 <<= 1;
1570*0Sstevel@tonic-gate 	/* Now pow2 is the smallest power of 2 satifsying pow2 >= num.
1571*0Sstevel@tonic-gate 	 * We need twice that. */
1572*0Sstevel@tonic-gate 	pow2 <<= 1;
1573*0Sstevel@tonic-gate 
1574*0Sstevel@tonic-gate 	heap = OPENSSL_malloc(pow2 * sizeof heap[0]);
1575*0Sstevel@tonic-gate 	if (heap == NULL) goto err;
1576*0Sstevel@tonic-gate 
1577*0Sstevel@tonic-gate 	/* The array is used as a binary tree, exactly as in heapsort:
1578*0Sstevel@tonic-gate 	 *
1579*0Sstevel@tonic-gate 	 *                               heap[1]
1580*0Sstevel@tonic-gate 	 *                 heap[2]                     heap[3]
1581*0Sstevel@tonic-gate 	 *          heap[4]       heap[5]       heap[6]       heap[7]
1582*0Sstevel@tonic-gate 	 *   heap[8]heap[9] heap[10]heap[11] heap[12]heap[13] heap[14] heap[15]
1583*0Sstevel@tonic-gate 	 *
1584*0Sstevel@tonic-gate 	 * We put the Z's in the last line;
1585*0Sstevel@tonic-gate 	 * then we set each other node to the product of its two child-nodes (where
1586*0Sstevel@tonic-gate 	 * empty or 0 entries are treated as ones);
1587*0Sstevel@tonic-gate 	 * then we invert heap[1];
1588*0Sstevel@tonic-gate 	 * then we invert each other node by replacing it by the product of its
1589*0Sstevel@tonic-gate 	 * parent (after inversion) and its sibling (before inversion).
1590*0Sstevel@tonic-gate 	 */
1591*0Sstevel@tonic-gate 	heap[0] = NULL;
1592*0Sstevel@tonic-gate 	for (i = pow2/2 - 1; i > 0; i--)
1593*0Sstevel@tonic-gate 		heap[i] = NULL;
1594*0Sstevel@tonic-gate 	for (i = 0; i < num; i++)
1595*0Sstevel@tonic-gate 		heap[pow2/2 + i] = &points[i]->Z;
1596*0Sstevel@tonic-gate 	for (i = pow2/2 + num; i < pow2; i++)
1597*0Sstevel@tonic-gate 		heap[i] = NULL;
1598*0Sstevel@tonic-gate 
1599*0Sstevel@tonic-gate 	/* set each node to the product of its children */
1600*0Sstevel@tonic-gate 	for (i = pow2/2 - 1; i > 0; i--)
1601*0Sstevel@tonic-gate 		{
1602*0Sstevel@tonic-gate 		heap[i] = BN_new();
1603*0Sstevel@tonic-gate 		if (heap[i] == NULL) goto err;
1604*0Sstevel@tonic-gate 
1605*0Sstevel@tonic-gate 		if (heap[2*i] != NULL)
1606*0Sstevel@tonic-gate 			{
1607*0Sstevel@tonic-gate 			if ((heap[2*i + 1] == NULL) || BN_is_zero(heap[2*i + 1]))
1608*0Sstevel@tonic-gate 				{
1609*0Sstevel@tonic-gate 				if (!BN_copy(heap[i], heap[2*i])) goto err;
1610*0Sstevel@tonic-gate 				}
1611*0Sstevel@tonic-gate 			else
1612*0Sstevel@tonic-gate 				{
1613*0Sstevel@tonic-gate 				if (BN_is_zero(heap[2*i]))
1614*0Sstevel@tonic-gate 					{
1615*0Sstevel@tonic-gate 					if (!BN_copy(heap[i], heap[2*i + 1])) goto err;
1616*0Sstevel@tonic-gate 					}
1617*0Sstevel@tonic-gate 				else
1618*0Sstevel@tonic-gate 					{
1619*0Sstevel@tonic-gate 					if (!group->meth->field_mul(group, heap[i],
1620*0Sstevel@tonic-gate 						heap[2*i], heap[2*i + 1], ctx)) goto err;
1621*0Sstevel@tonic-gate 					}
1622*0Sstevel@tonic-gate 				}
1623*0Sstevel@tonic-gate 			}
1624*0Sstevel@tonic-gate 		}
1625*0Sstevel@tonic-gate 
1626*0Sstevel@tonic-gate 	/* invert heap[1] */
1627*0Sstevel@tonic-gate 	if (!BN_is_zero(heap[1]))
1628*0Sstevel@tonic-gate 		{
1629*0Sstevel@tonic-gate 		if (!BN_mod_inverse(heap[1], heap[1], &group->field, ctx))
1630*0Sstevel@tonic-gate 			{
1631*0Sstevel@tonic-gate 			ECerr(EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE, ERR_R_BN_LIB);
1632*0Sstevel@tonic-gate 			goto err;
1633*0Sstevel@tonic-gate 			}
1634*0Sstevel@tonic-gate 		}
1635*0Sstevel@tonic-gate 	if (group->meth->field_encode != 0)
1636*0Sstevel@tonic-gate 		{
1637*0Sstevel@tonic-gate 		/* in the Montgomery case, we just turned  R*H  (representing H)
1638*0Sstevel@tonic-gate 		 * into  1/(R*H),  but we need  R*(1/H)  (representing 1/H);
1639*0Sstevel@tonic-gate 		 * i.e. we have need to multiply by the Montgomery factor twice */
1640*0Sstevel@tonic-gate 		if (!group->meth->field_encode(group, heap[1], heap[1], ctx)) goto err;
1641*0Sstevel@tonic-gate 		if (!group->meth->field_encode(group, heap[1], heap[1], ctx)) goto err;
1642*0Sstevel@tonic-gate 		}
1643*0Sstevel@tonic-gate 
1644*0Sstevel@tonic-gate 	/* set other heap[i]'s to their inverses */
1645*0Sstevel@tonic-gate 	for (i = 2; i < pow2/2 + num; i += 2)
1646*0Sstevel@tonic-gate 		{
1647*0Sstevel@tonic-gate 		/* i is even */
1648*0Sstevel@tonic-gate 		if ((heap[i + 1] != NULL) && !BN_is_zero(heap[i + 1]))
1649*0Sstevel@tonic-gate 			{
1650*0Sstevel@tonic-gate 			if (!group->meth->field_mul(group, tmp0, heap[i/2], heap[i + 1], ctx)) goto err;
1651*0Sstevel@tonic-gate 			if (!group->meth->field_mul(group, tmp1, heap[i/2], heap[i], ctx)) goto err;
1652*0Sstevel@tonic-gate 			if (!BN_copy(heap[i], tmp0)) goto err;
1653*0Sstevel@tonic-gate 			if (!BN_copy(heap[i + 1], tmp1)) goto err;
1654*0Sstevel@tonic-gate 			}
1655*0Sstevel@tonic-gate 		else
1656*0Sstevel@tonic-gate 			{
1657*0Sstevel@tonic-gate 			if (!BN_copy(heap[i], heap[i/2])) goto err;
1658*0Sstevel@tonic-gate 			}
1659*0Sstevel@tonic-gate 		}
1660*0Sstevel@tonic-gate 
1661*0Sstevel@tonic-gate 	/* we have replaced all non-zero Z's by their inverses, now fix up all the points */
1662*0Sstevel@tonic-gate 	for (i = 0; i < num; i++)
1663*0Sstevel@tonic-gate 		{
1664*0Sstevel@tonic-gate 		EC_POINT *p = points[i];
1665*0Sstevel@tonic-gate 
1666*0Sstevel@tonic-gate 		if (!BN_is_zero(&p->Z))
1667*0Sstevel@tonic-gate 			{
1668*0Sstevel@tonic-gate 			/* turn  (X, Y, 1/Z)  into  (X/Z^2, Y/Z^3, 1) */
1669*0Sstevel@tonic-gate 
1670*0Sstevel@tonic-gate 			if (!group->meth->field_sqr(group, tmp1, &p->Z, ctx)) goto err;
1671*0Sstevel@tonic-gate 			if (!group->meth->field_mul(group, &p->X, &p->X, tmp1, ctx)) goto err;
1672*0Sstevel@tonic-gate 
1673*0Sstevel@tonic-gate 			if (!group->meth->field_mul(group, tmp1, tmp1, &p->Z, ctx)) goto err;
1674*0Sstevel@tonic-gate 			if (!group->meth->field_mul(group, &p->Y, &p->Y, tmp1, ctx)) goto err;
1675*0Sstevel@tonic-gate 
1676*0Sstevel@tonic-gate 			if (group->meth->field_set_to_one != 0)
1677*0Sstevel@tonic-gate 				{
1678*0Sstevel@tonic-gate 				if (!group->meth->field_set_to_one(group, &p->Z, ctx)) goto err;
1679*0Sstevel@tonic-gate 				}
1680*0Sstevel@tonic-gate 			else
1681*0Sstevel@tonic-gate 				{
1682*0Sstevel@tonic-gate 				if (!BN_one(&p->Z)) goto err;
1683*0Sstevel@tonic-gate 				}
1684*0Sstevel@tonic-gate 			p->Z_is_one = 1;
1685*0Sstevel@tonic-gate 			}
1686*0Sstevel@tonic-gate 		}
1687*0Sstevel@tonic-gate 
1688*0Sstevel@tonic-gate 	ret = 1;
1689*0Sstevel@tonic-gate 
1690*0Sstevel@tonic-gate  err:
1691*0Sstevel@tonic-gate 	BN_CTX_end(ctx);
1692*0Sstevel@tonic-gate 	if (new_ctx != NULL)
1693*0Sstevel@tonic-gate 		BN_CTX_free(new_ctx);
1694*0Sstevel@tonic-gate 	if (heap != NULL)
1695*0Sstevel@tonic-gate 		{
1696*0Sstevel@tonic-gate 		/* heap[pow2/2] .. heap[pow2-1] have not been allocated locally! */
1697*0Sstevel@tonic-gate 		for (i = pow2/2 - 1; i > 0; i--)
1698*0Sstevel@tonic-gate 			{
1699*0Sstevel@tonic-gate 			if (heap[i] != NULL)
1700*0Sstevel@tonic-gate 				BN_clear_free(heap[i]);
1701*0Sstevel@tonic-gate 			}
1702*0Sstevel@tonic-gate 		OPENSSL_free(heap);
1703*0Sstevel@tonic-gate 		}
1704*0Sstevel@tonic-gate 	return ret;
1705*0Sstevel@tonic-gate 	}
1706*0Sstevel@tonic-gate 
1707*0Sstevel@tonic-gate 
1708*0Sstevel@tonic-gate int ec_GFp_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
1709*0Sstevel@tonic-gate 	{
1710*0Sstevel@tonic-gate 	return BN_mod_mul(r, a, b, &group->field, ctx);
1711*0Sstevel@tonic-gate 	}
1712*0Sstevel@tonic-gate 
1713*0Sstevel@tonic-gate 
1714*0Sstevel@tonic-gate int ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
1715*0Sstevel@tonic-gate 	{
1716*0Sstevel@tonic-gate 	return BN_mod_sqr(r, a, &group->field, ctx);
1717*0Sstevel@tonic-gate 	}
1718