xref: /openbsd-src/lib/libcrypto/ec/ec_lib.c (revision a9bbc4f7ee50119ba947c454863c40a902ce9b30)
1*a9bbc4f7Stb /* $OpenBSD: ec_lib.c,v 1.116 2025/01/25 13:13:57 tb Exp $ */
24fcf65c5Sdjm /*
34fcf65c5Sdjm  * Originally written by Bodo Moeller for the OpenSSL project.
44fcf65c5Sdjm  */
5da347917Sbeck /* ====================================================================
64fcf65c5Sdjm  * Copyright (c) 1998-2003 The OpenSSL Project.  All rights reserved.
7da347917Sbeck  *
8da347917Sbeck  * Redistribution and use in source and binary forms, with or without
9da347917Sbeck  * modification, are permitted provided that the following conditions
10da347917Sbeck  * are met:
11da347917Sbeck  *
12da347917Sbeck  * 1. Redistributions of source code must retain the above copyright
13da347917Sbeck  *    notice, this list of conditions and the following disclaimer.
14da347917Sbeck  *
15da347917Sbeck  * 2. Redistributions in binary form must reproduce the above copyright
16da347917Sbeck  *    notice, this list of conditions and the following disclaimer in
17da347917Sbeck  *    the documentation and/or other materials provided with the
18da347917Sbeck  *    distribution.
19da347917Sbeck  *
20da347917Sbeck  * 3. All advertising materials mentioning features or use of this
21da347917Sbeck  *    software must display the following acknowledgment:
22da347917Sbeck  *    "This product includes software developed by the OpenSSL Project
23da347917Sbeck  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
24da347917Sbeck  *
25da347917Sbeck  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26da347917Sbeck  *    endorse or promote products derived from this software without
27da347917Sbeck  *    prior written permission. For written permission, please contact
28da347917Sbeck  *    openssl-core@openssl.org.
29da347917Sbeck  *
30da347917Sbeck  * 5. Products derived from this software may not be called "OpenSSL"
31da347917Sbeck  *    nor may "OpenSSL" appear in their names without prior written
32da347917Sbeck  *    permission of the OpenSSL Project.
33da347917Sbeck  *
34da347917Sbeck  * 6. Redistributions of any form whatsoever must retain the following
35da347917Sbeck  *    acknowledgment:
36da347917Sbeck  *    "This product includes software developed by the OpenSSL Project
37da347917Sbeck  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
38da347917Sbeck  *
39da347917Sbeck  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40da347917Sbeck  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41da347917Sbeck  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42da347917Sbeck  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43da347917Sbeck  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44da347917Sbeck  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45da347917Sbeck  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46da347917Sbeck  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47da347917Sbeck  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48da347917Sbeck  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49da347917Sbeck  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50da347917Sbeck  * OF THE POSSIBILITY OF SUCH DAMAGE.
51da347917Sbeck  * ====================================================================
52da347917Sbeck  *
53da347917Sbeck  * This product includes cryptographic software written by Eric Young
54da347917Sbeck  * (eay@cryptsoft.com).  This product includes software written by Tim
55da347917Sbeck  * Hudson (tjh@cryptsoft.com).
56da347917Sbeck  *
57da347917Sbeck  */
584fcf65c5Sdjm /* ====================================================================
594fcf65c5Sdjm  * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
604fcf65c5Sdjm  * Binary polynomial ECC support in OpenSSL originally developed by
614fcf65c5Sdjm  * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
624fcf65c5Sdjm  */
63da347917Sbeck 
64587ebde5Stb #include <stdlib.h>
65da347917Sbeck #include <string.h>
66da347917Sbeck 
678cf4d6a6Sjsing #include <openssl/opensslconf.h>
688cf4d6a6Sjsing 
69587ebde5Stb #include <openssl/bn.h>
70587ebde5Stb #include <openssl/ec.h>
71da347917Sbeck #include <openssl/err.h>
72587ebde5Stb #include <openssl/objects.h>
73da347917Sbeck #include <openssl/opensslv.h>
74da347917Sbeck 
75c9675a23Stb #include "bn_local.h"
76c9675a23Stb #include "ec_local.h"
77da347917Sbeck 
78f67ac449Stedu EC_GROUP *
79f67ac449Stedu EC_GROUP_new(const EC_METHOD *meth)
80da347917Sbeck {
8121332710Stb 	EC_GROUP *group = NULL;
82da347917Sbeck 
83f67ac449Stedu 	if (meth == NULL) {
845067ae9fSbeck 		ECerror(EC_R_SLOT_FULL);
8521332710Stb 		goto err;
86da347917Sbeck 	}
8721332710Stb 	if ((group = calloc(1, sizeof(*group))) == NULL) {
885067ae9fSbeck 		ECerror(ERR_R_MALLOC_FAILURE);
8921332710Stb 		goto err;
90da347917Sbeck 	}
91da347917Sbeck 
9221332710Stb 	group->meth = meth;
934fcf65c5Sdjm 
9421332710Stb 	group->asn1_flag = OPENSSL_EC_NAMED_CURVE;
9521332710Stb 	group->asn1_form = POINT_CONVERSION_UNCOMPRESSED;
96da347917Sbeck 
973c2cb882Stb 	if ((group->p = BN_new()) == NULL)
983c2cb882Stb 		goto err;
993c2cb882Stb 	if ((group->a = BN_new()) == NULL)
1003c2cb882Stb 		goto err;
1013c2cb882Stb 	if ((group->b = BN_new()) == NULL)
1023c2cb882Stb 		goto err;
1033c2cb882Stb 
1043c2cb882Stb 	if ((group->order = BN_new()) == NULL)
1053c2cb882Stb 		goto err;
1063c2cb882Stb 	if ((group->cofactor = BN_new()) == NULL)
1073c2cb882Stb 		goto err;
1083c2cb882Stb 
1093c2cb882Stb 	/*
1101c80ffcfStb 	 * generator, seed and mont_ctx are optional.
1113c2cb882Stb 	 */
1123c2cb882Stb 
11321332710Stb 	return group;
11421332710Stb 
11521332710Stb  err:
11621332710Stb 	EC_GROUP_free(group);
11721332710Stb 
118da347917Sbeck 	return NULL;
119da347917Sbeck }
120ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_new);
121da347917Sbeck 
122f67ac449Stedu void
123f67ac449Stedu EC_GROUP_free(EC_GROUP *group)
124da347917Sbeck {
125d7292987Sjsing 	if (group == NULL)
126f67ac449Stedu 		return;
127c58501deSbeck 
1283c2cb882Stb 	BN_free(group->p);
1293c2cb882Stb 	BN_free(group->a);
1303c2cb882Stb 	BN_free(group->b);
13121084e45Stb 
13221084e45Stb 	BN_MONT_CTX_free(group->mont_ctx);
133da347917Sbeck 
134a7854573Sjsing 	EC_POINT_free(group->generator);
1353c2cb882Stb 	BN_free(group->order);
1363c2cb882Stb 	BN_free(group->cofactor);
1374fcf65c5Sdjm 
1387de8a684Sderaadt 	freezero(group->seed, group->seed_len);
1397de8a684Sderaadt 	freezero(group, sizeof *group);
140da347917Sbeck }
141ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_free);
142da347917Sbeck 
143a7854573Sjsing void
144a7854573Sjsing EC_GROUP_clear_free(EC_GROUP *group)
145a7854573Sjsing {
146d7292987Sjsing 	EC_GROUP_free(group);
147a7854573Sjsing }
1488a552917Sbeck LCRYPTO_ALIAS(EC_GROUP_clear_free);
149da347917Sbeck 
150f67ac449Stedu int
151428f68d0Stb EC_GROUP_copy(EC_GROUP *dst, const EC_GROUP *src)
152da347917Sbeck {
153428f68d0Stb 	if (dst->meth != src->meth) {
1545067ae9fSbeck 		ECerror(EC_R_INCOMPATIBLE_OBJECTS);
155da347917Sbeck 		return 0;
156da347917Sbeck 	}
157428f68d0Stb 	if (dst == src)
158da347917Sbeck 		return 1;
159da347917Sbeck 
160428f68d0Stb 	if (!bn_copy(dst->p, src->p))
161f67ac449Stedu 		return 0;
162428f68d0Stb 	if (!bn_copy(dst->a, src->a))
1632ab5ac8dStb 		return 0;
164428f68d0Stb 	if (!bn_copy(dst->b, src->b))
1652ab5ac8dStb 		return 0;
1662ab5ac8dStb 
167428f68d0Stb 	dst->a_is_minus3 = src->a_is_minus3;
1682ab5ac8dStb 
169428f68d0Stb 	BN_MONT_CTX_free(dst->mont_ctx);
170428f68d0Stb 	dst->mont_ctx = NULL;
1712ab5ac8dStb 	if (src->mont_ctx != NULL) {
172428f68d0Stb 		if ((dst->mont_ctx = BN_MONT_CTX_new()) == NULL)
1732ab5ac8dStb 			return 0;
174428f68d0Stb 		if (!BN_MONT_CTX_copy(dst->mont_ctx, src->mont_ctx))
1752ab5ac8dStb 			return 0;
1762ab5ac8dStb 	}
177cf85019eStb 
178428f68d0Stb 	EC_POINT_free(dst->generator);
179428f68d0Stb 	dst->generator = NULL;
180cf85019eStb 	if (src->generator != NULL) {
181428f68d0Stb 		if (!EC_GROUP_set_generator(dst, src->generator, src->order,
1823c2cb882Stb 		    src->cofactor))
183cf85019eStb 			return 0;
184cf85019eStb 	} else {
185cf85019eStb 		/* XXX - should do the sanity checks as in set_generator() */
186428f68d0Stb 		if (!bn_copy(dst->order, src->order))
187f67ac449Stedu 			return 0;
188428f68d0Stb 		if (!bn_copy(dst->cofactor, src->cofactor))
189f67ac449Stedu 			return 0;
190cf85019eStb 	}
1914fcf65c5Sdjm 
192428f68d0Stb 	dst->nid = src->nid;
193428f68d0Stb 	dst->asn1_flag = src->asn1_flag;
194428f68d0Stb 	dst->asn1_form = src->asn1_form;
1954fcf65c5Sdjm 
196428f68d0Stb 	if (!EC_GROUP_set_seed(dst, src->seed, src->seed_len))
1974fcf65c5Sdjm 		return 0;
1984fcf65c5Sdjm 
1992ab5ac8dStb 	return 1;
200da347917Sbeck }
201ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_copy);
202da347917Sbeck 
203f67ac449Stedu EC_GROUP *
20426b186dbStb EC_GROUP_dup(const EC_GROUP *in_group)
2054fcf65c5Sdjm {
20626b186dbStb 	EC_GROUP *group = NULL;
2074fcf65c5Sdjm 
20826b186dbStb 	if (in_group == NULL)
20926b186dbStb 		goto err;
21026b186dbStb 
21126b186dbStb 	if ((group = EC_GROUP_new(in_group->meth)) == NULL)
21226b186dbStb 		goto err;
21326b186dbStb 	if (!EC_GROUP_copy(group, in_group))
21426b186dbStb 		goto err;
21526b186dbStb 
21626b186dbStb 	return group;
21726b186dbStb 
21826b186dbStb  err:
21926b186dbStb 	EC_GROUP_free(group);
22026b186dbStb 
2218b4d06edStb 	return NULL;
2224fcf65c5Sdjm }
223ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_dup);
2244fcf65c5Sdjm 
225baf7262aStb /*
22615f1f9a3Stb  * If there is a user-provided cofactor, sanity check and use it. Otherwise
227823dae7dStb  * try computing the cofactor from generator order n and field cardinality p.
228baf7262aStb  * This works for all curves of cryptographic interest.
229baf7262aStb  *
230823dae7dStb  * Hasse's theorem: | h * n - (p + 1) | <= 2 * sqrt(p)
231baf7262aStb  *
232823dae7dStb  * So: h_min = (p + 1 - 2*sqrt(p)) / n and h_max = (p + 1 + 2*sqrt(p)) / n and
233823dae7dStb  * therefore h_max - h_min = 4*sqrt(p) / n. So if n > 4*sqrt(p) holds, there is
234baf7262aStb  * only one possible value for h:
235baf7262aStb  *
236823dae7dStb  *	h = \lfloor (h_min + h_max)/2 \rceil = \lfloor (p + 1)/n \rceil
237baf7262aStb  *
238baf7262aStb  * Otherwise, zero cofactor and return success.
239baf7262aStb  */
240baf7262aStb static int
24115f1f9a3Stb ec_set_cofactor(EC_GROUP *group, const BIGNUM *in_cofactor)
242baf7262aStb {
243baf7262aStb 	BN_CTX *ctx = NULL;
24415f1f9a3Stb 	BIGNUM *cofactor;
245baf7262aStb 	int ret = 0;
246baf7262aStb 
2473c2cb882Stb 	BN_zero(group->cofactor);
24815f1f9a3Stb 
24915f1f9a3Stb 	if ((ctx = BN_CTX_new()) == NULL)
25015f1f9a3Stb 		goto err;
25115f1f9a3Stb 
25215f1f9a3Stb 	BN_CTX_start(ctx);
25315f1f9a3Stb 	if ((cofactor = BN_CTX_get(ctx)) == NULL)
25415f1f9a3Stb 		goto err;
25515f1f9a3Stb 
25615f1f9a3Stb 	/*
25715f1f9a3Stb 	 * Unfortunately, the cofactor is an optional field in many standards.
25815f1f9a3Stb 	 * Internally, the library uses a 0 cofactor as a marker for "unknown
25915f1f9a3Stb 	 * cofactor".  So accept in_cofactor == NULL or in_cofactor >= 0.
26015f1f9a3Stb 	 */
26115f1f9a3Stb 	if (in_cofactor != NULL && !BN_is_zero(in_cofactor)) {
26215f1f9a3Stb 		if (BN_is_negative(in_cofactor)) {
26315f1f9a3Stb 			ECerror(EC_R_UNKNOWN_COFACTOR);
26415f1f9a3Stb 			goto err;
26515f1f9a3Stb 		}
26615f1f9a3Stb 		if (!bn_copy(cofactor, in_cofactor))
26715f1f9a3Stb 			goto err;
26815f1f9a3Stb 		goto done;
26915f1f9a3Stb 	}
27015f1f9a3Stb 
271baf7262aStb 	/*
272baf7262aStb 	 * If the cofactor is too large, we cannot guess it and default to zero.
273823dae7dStb 	 * The RHS of below is a strict overestimate of log(4 * sqrt(p)).
274baf7262aStb 	 */
2753c2cb882Stb 	if (BN_num_bits(group->order) <= (BN_num_bits(group->p) + 1) / 2 + 3)
27615f1f9a3Stb 		goto done;
277baf7262aStb 
278baf7262aStb 	/*
279baf7262aStb 	 * Compute
280823dae7dStb 	 *     h = \lfloor (p + 1)/n \rceil = \lfloor (p + 1 + n/2) / n \rfloor.
281baf7262aStb 	 */
282baf7262aStb 
283baf7262aStb 	/* h = n/2 */
2843c2cb882Stb 	if (!BN_rshift1(cofactor, group->order))
285baf7262aStb 		goto err;
286baf7262aStb 	/* h = 1 + n/2 */
28715f1f9a3Stb 	if (!BN_add_word(cofactor, 1))
288baf7262aStb 		goto err;
289823dae7dStb 	/* h = p + 1 + n/2 */
2903c2cb882Stb 	if (!BN_add(cofactor, cofactor, group->p))
291baf7262aStb 		goto err;
292823dae7dStb 	/* h = (p + 1 + n/2) / n */
2933c2cb882Stb 	if (!BN_div_ct(cofactor, NULL, cofactor, group->order, ctx))
29415f1f9a3Stb 		goto err;
29515f1f9a3Stb 
29615f1f9a3Stb  done:
29715f1f9a3Stb 	/* Use Hasse's theorem to bound the cofactor. */
2983c2cb882Stb 	if (BN_num_bits(cofactor) > BN_num_bits(group->p) + 1) {
29915f1f9a3Stb 		ECerror(EC_R_INVALID_GROUP_ORDER);
30015f1f9a3Stb 		goto err;
30115f1f9a3Stb 	}
30215f1f9a3Stb 
3033c2cb882Stb 	if (!bn_copy(group->cofactor, cofactor))
304baf7262aStb 		goto err;
305baf7262aStb 
306baf7262aStb 	ret = 1;
307e2787e9fStb 
308baf7262aStb  err:
309baf7262aStb 	BN_CTX_end(ctx);
310baf7262aStb 	BN_CTX_free(ctx);
311e2787e9fStb 
312baf7262aStb 	return ret;
313baf7262aStb }
314da347917Sbeck 
315f67ac449Stedu int
316f67ac449Stedu EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator,
317f67ac449Stedu     const BIGNUM *order, const BIGNUM *cofactor)
318da347917Sbeck {
319f67ac449Stedu 	if (generator == NULL) {
3205067ae9fSbeck 		ECerror(ERR_R_PASSED_NULL_PARAMETER);
321da347917Sbeck 		return 0;
322da347917Sbeck 	}
323baf7262aStb 
3243fd2f05cStb 	/* Require p >= 1. */
3253c2cb882Stb 	if (BN_is_zero(group->p) || BN_is_negative(group->p)) {
326baf7262aStb 		ECerror(EC_R_INVALID_FIELD);
327baf7262aStb 		return 0;
328baf7262aStb 	}
329baf7262aStb 
330baf7262aStb 	/*
3313cc94d96Stb 	 * Require order > 1 and enforce an upper bound of at most one bit more
332baf7262aStb 	 * than the field cardinality due to Hasse's theorem.
333baf7262aStb 	 */
3343cc94d96Stb 	if (order == NULL || BN_cmp(order, BN_value_one()) <= 0 ||
3353c2cb882Stb 	    BN_num_bits(order) > BN_num_bits(group->p) + 1) {
336baf7262aStb 		ECerror(EC_R_INVALID_GROUP_ORDER);
337baf7262aStb 		return 0;
338baf7262aStb 	}
339baf7262aStb 
34026dd3e34Stb 	if (group->generator == NULL)
3414fcf65c5Sdjm 		group->generator = EC_POINT_new(group);
342f67ac449Stedu 	if (group->generator == NULL)
343f67ac449Stedu 		return 0;
34426dd3e34Stb 
345f67ac449Stedu 	if (!EC_POINT_copy(group->generator, generator))
346f67ac449Stedu 		return 0;
3474fcf65c5Sdjm 
3483c2cb882Stb 	if (!bn_copy(group->order, order))
349f67ac449Stedu 		return 0;
3504fcf65c5Sdjm 
35115f1f9a3Stb 	if (!ec_set_cofactor(group, cofactor))
352f67ac449Stedu 		return 0;
353206d4dd0Stb 
3544fcf65c5Sdjm 	return 1;
355da347917Sbeck }
356ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_set_generator);
357da347917Sbeck 
358f67ac449Stedu const EC_POINT *
359f67ac449Stedu EC_GROUP_get0_generator(const EC_GROUP *group)
360da347917Sbeck {
3614fcf65c5Sdjm 	return group->generator;
362da347917Sbeck }
363ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_get0_generator);
364da347917Sbeck 
365f67ac449Stedu int
366f67ac449Stedu EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx)
367da347917Sbeck {
3683c2cb882Stb 	if (!bn_copy(order, group->order))
369da347917Sbeck 		return 0;
3704fcf65c5Sdjm 
3714fcf65c5Sdjm 	return !BN_is_zero(order);
372da347917Sbeck }
373ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_get_order);
374da347917Sbeck 
3757fd74d8bStb const BIGNUM *
3767fd74d8bStb EC_GROUP_get0_order(const EC_GROUP *group)
3777fd74d8bStb {
3783c2cb882Stb 	return group->order;
3797fd74d8bStb }
3807fd74d8bStb 
38170b8897aStb int
38270b8897aStb EC_GROUP_order_bits(const EC_GROUP *group)
38370b8897aStb {
384be018b2cStb 	return BN_num_bits(group->order);
38570b8897aStb }
386ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_order_bits);
387da347917Sbeck 
388f67ac449Stedu int
389f67ac449Stedu EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, BN_CTX *ctx)
390da347917Sbeck {
3913c2cb882Stb 	if (!bn_copy(cofactor, group->cofactor))
3924fcf65c5Sdjm 		return 0;
3934fcf65c5Sdjm 
3943c2cb882Stb 	return !BN_is_zero(group->cofactor);
3954fcf65c5Sdjm }
396ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_get_cofactor);
3974fcf65c5Sdjm 
398b072588bStb const BIGNUM *
399b072588bStb EC_GROUP_get0_cofactor(const EC_GROUP *group)
400b072588bStb {
4013c2cb882Stb 	return group->cofactor;
402b072588bStb }
403b072588bStb 
404f67ac449Stedu void
405f67ac449Stedu EC_GROUP_set_curve_name(EC_GROUP *group, int nid)
406da347917Sbeck {
40749eaabcdStb 	group->nid = nid;
4084fcf65c5Sdjm }
409ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_set_curve_name);
4104fcf65c5Sdjm 
411f67ac449Stedu int
412f67ac449Stedu EC_GROUP_get_curve_name(const EC_GROUP *group)
4134fcf65c5Sdjm {
41449eaabcdStb 	return group->nid;
4154fcf65c5Sdjm }
416ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_get_curve_name);
4174fcf65c5Sdjm 
418f67ac449Stedu void
419f67ac449Stedu EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag)
4204fcf65c5Sdjm {
4214fcf65c5Sdjm 	group->asn1_flag = flag;
4224fcf65c5Sdjm }
423ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_set_asn1_flag);
4244fcf65c5Sdjm 
425f67ac449Stedu int
426f67ac449Stedu EC_GROUP_get_asn1_flag(const EC_GROUP *group)
4274fcf65c5Sdjm {
4284fcf65c5Sdjm 	return group->asn1_flag;
4294fcf65c5Sdjm }
430ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_get_asn1_flag);
4314fcf65c5Sdjm 
432f67ac449Stedu void
433f67ac449Stedu EC_GROUP_set_point_conversion_form(EC_GROUP *group,
4344fcf65c5Sdjm     point_conversion_form_t form)
4354fcf65c5Sdjm {
4364fcf65c5Sdjm 	group->asn1_form = form;
4374fcf65c5Sdjm }
438ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_set_point_conversion_form);
4394fcf65c5Sdjm 
440f67ac449Stedu point_conversion_form_t
441f67ac449Stedu EC_GROUP_get_point_conversion_form(const EC_GROUP *group)
4424fcf65c5Sdjm {
4434fcf65c5Sdjm 	return group->asn1_form;
4444fcf65c5Sdjm }
445ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_get_point_conversion_form);
4464fcf65c5Sdjm 
447f67ac449Stedu size_t
448b5448e3dStb EC_GROUP_set_seed(EC_GROUP *group, const unsigned char *seed, size_t len)
4494fcf65c5Sdjm {
4506f3a6cb1Sbeck 	free(group->seed);
4514fcf65c5Sdjm 	group->seed = NULL;
4524fcf65c5Sdjm 	group->seed_len = 0;
453b5448e3dStb 
454c715fd08Stb 	if (seed == NULL || len == 0)
4554fcf65c5Sdjm 		return 1;
4564fcf65c5Sdjm 
4576f3a6cb1Sbeck 	if ((group->seed = malloc(len)) == NULL)
4584fcf65c5Sdjm 		return 0;
459b5448e3dStb 	memcpy(group->seed, seed, len);
4604fcf65c5Sdjm 	group->seed_len = len;
4614fcf65c5Sdjm 
4624fcf65c5Sdjm 	return len;
4634fcf65c5Sdjm }
464ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_set_seed);
4654fcf65c5Sdjm 
466f67ac449Stedu unsigned char *
467f67ac449Stedu EC_GROUP_get0_seed(const EC_GROUP *group)
4684fcf65c5Sdjm {
4694fcf65c5Sdjm 	return group->seed;
4704fcf65c5Sdjm }
471ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_get0_seed);
4724fcf65c5Sdjm 
473f67ac449Stedu size_t
474f67ac449Stedu EC_GROUP_get_seed_len(const EC_GROUP *group)
4754fcf65c5Sdjm {
4764fcf65c5Sdjm 	return group->seed_len;
4774fcf65c5Sdjm }
478ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_get_seed_len);
4794fcf65c5Sdjm 
480f67ac449Stedu int
4810b15d7eeStb EC_GROUP_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a,
4821f65bd71Sjsing     const BIGNUM *b, BN_CTX *ctx_in)
4834fcf65c5Sdjm {
4841f65bd71Sjsing 	BN_CTX *ctx;
4851f65bd71Sjsing 	int ret = 0;
4861f65bd71Sjsing 
4871f65bd71Sjsing 	if ((ctx = ctx_in) == NULL)
4881f65bd71Sjsing 		ctx = BN_CTX_new();
4891f65bd71Sjsing 	if (ctx == NULL)
4901f65bd71Sjsing 		goto err;
4911f65bd71Sjsing 
49260ca3fa5Stb 	if (group->meth->group_set_curve == NULL) {
4935067ae9fSbeck 		ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
4941f65bd71Sjsing 		goto err;
495da347917Sbeck 	}
4961f65bd71Sjsing 	ret = group->meth->group_set_curve(group, p, a, b, ctx);
4971f65bd71Sjsing 
4981f65bd71Sjsing  err:
4991f65bd71Sjsing 	if (ctx != ctx_in)
5001f65bd71Sjsing 		BN_CTX_free(ctx);
5011f65bd71Sjsing 
5021f65bd71Sjsing 	return ret;
5034fcf65c5Sdjm }
504ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_set_curve);
5054fcf65c5Sdjm 
506f67ac449Stedu int
5070b15d7eeStb EC_GROUP_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b,
5081f65bd71Sjsing     BN_CTX *ctx_in)
5094fcf65c5Sdjm {
5101f65bd71Sjsing 	BN_CTX *ctx;
5111f65bd71Sjsing 	int ret = 0;
5121f65bd71Sjsing 
5131f65bd71Sjsing 	if ((ctx = ctx_in) == NULL)
5141f65bd71Sjsing 		ctx = BN_CTX_new();
5151f65bd71Sjsing 	if (ctx == NULL)
5161f65bd71Sjsing 		goto err;
5171f65bd71Sjsing 
51860ca3fa5Stb 	if (group->meth->group_get_curve == NULL) {
5195067ae9fSbeck 		ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
5207b871452Stb 		goto err;
5214fcf65c5Sdjm 	}
5221f65bd71Sjsing 	ret = group->meth->group_get_curve(group, p, a, b, ctx);
5231f65bd71Sjsing 
5241f65bd71Sjsing  err:
5251f65bd71Sjsing 	if (ctx != ctx_in)
5261f65bd71Sjsing 		BN_CTX_free(ctx);
5271f65bd71Sjsing 
5281f65bd71Sjsing 	return ret;
5294fcf65c5Sdjm }
530ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_get_curve);
5314fcf65c5Sdjm 
5320b15d7eeStb int
5330b15d7eeStb EC_GROUP_set_curve_GFp(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a,
5340b15d7eeStb     const BIGNUM *b, BN_CTX *ctx)
5350b15d7eeStb {
5360b15d7eeStb 	return EC_GROUP_set_curve(group, p, a, b, ctx);
5370b15d7eeStb }
5388a552917Sbeck LCRYPTO_ALIAS(EC_GROUP_set_curve_GFp);
5390b15d7eeStb 
5400b15d7eeStb int
5410b15d7eeStb EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b,
5420b15d7eeStb     BN_CTX *ctx)
5430b15d7eeStb {
5440b15d7eeStb 	return EC_GROUP_get_curve(group, p, a, b, ctx);
5450b15d7eeStb }
5468a552917Sbeck LCRYPTO_ALIAS(EC_GROUP_get_curve_GFp);
5470b15d7eeStb 
5482567856aStb EC_GROUP *
5492567856aStb EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b,
5502567856aStb     BN_CTX *ctx)
5512567856aStb {
5522567856aStb 	EC_GROUP *group;
5532567856aStb 
5542567856aStb 	if ((group = EC_GROUP_new(EC_GFp_mont_method())) == NULL)
5552567856aStb 		goto err;
5562567856aStb 
5572567856aStb 	if (!EC_GROUP_set_curve(group, p, a, b, ctx))
5582567856aStb 		goto err;
5592567856aStb 
5602567856aStb 	return group;
5612567856aStb 
5622567856aStb  err:
5632567856aStb 	EC_GROUP_free(group);
5642567856aStb 
5652567856aStb 	return NULL;
5662567856aStb }
5672567856aStb LCRYPTO_ALIAS(EC_GROUP_new_curve_GFp);
5682567856aStb 
569f67ac449Stedu int
570f67ac449Stedu EC_GROUP_get_degree(const EC_GROUP *group)
5714fcf65c5Sdjm {
572be018b2cStb 	return BN_num_bits(group->p);
5734fcf65c5Sdjm }
574ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_get_degree);
5754fcf65c5Sdjm 
576f67ac449Stedu int
5771f65bd71Sjsing EC_GROUP_check_discriminant(const EC_GROUP *group, BN_CTX *ctx_in)
5784fcf65c5Sdjm {
5791f65bd71Sjsing 	BN_CTX *ctx;
580a537a13eStb 	BIGNUM *p, *a, *b, *discriminant;
5811f65bd71Sjsing 	int ret = 0;
5821f65bd71Sjsing 
5831f65bd71Sjsing 	if ((ctx = ctx_in) == NULL)
5841f65bd71Sjsing 		ctx = BN_CTX_new();
5851f65bd71Sjsing 	if (ctx == NULL)
5861f65bd71Sjsing 		goto err;
5871f65bd71Sjsing 
588a537a13eStb 	BN_CTX_start(ctx);
589a537a13eStb 
590a537a13eStb 	if ((p = BN_CTX_get(ctx)) == NULL)
5917b871452Stb 		goto err;
592a537a13eStb 	if ((a = BN_CTX_get(ctx)) == NULL)
593a537a13eStb 		goto err;
594a537a13eStb 	if ((b = BN_CTX_get(ctx)) == NULL)
595a537a13eStb 		goto err;
596a537a13eStb 	if ((discriminant = BN_CTX_get(ctx)) == NULL)
597a537a13eStb 		goto err;
598a537a13eStb 
599a537a13eStb 	if (!EC_GROUP_get_curve(group, p, a, b, ctx))
600a537a13eStb 		goto err;
601a537a13eStb 
602a537a13eStb 	/*
603742574bfStb 	 * Check that the discriminant 4a^3 + 27b^2 is non-zero modulo p
604742574bfStb 	 * assuming that p > 3 is prime and that a and b are in [0, p).
605a537a13eStb 	 */
606a537a13eStb 
607a537a13eStb 	if (BN_is_zero(a) && BN_is_zero(b))
608a537a13eStb 		goto err;
609a537a13eStb 	if (BN_is_zero(a) || BN_is_zero(b))
610a537a13eStb 		goto done;
611a537a13eStb 
612a537a13eStb 	/* Compute the discriminant: first 4a^3, then 27b^2, then their sum. */
613a537a13eStb 	if (!BN_mod_sqr(discriminant, a, p, ctx))
614a537a13eStb 		goto err;
615a537a13eStb 	if (!BN_mod_mul(discriminant, discriminant, a, p, ctx))
616a537a13eStb 		goto err;
617a537a13eStb 	if (!BN_lshift(discriminant, discriminant, 2))
618a537a13eStb 		goto err;
619a537a13eStb 
620a537a13eStb 	if (!BN_mod_sqr(b, b, p, ctx))
621a537a13eStb 		goto err;
622a537a13eStb 	if (!BN_mul_word(b, 27))
623a537a13eStb 		goto err;
624a537a13eStb 
625a537a13eStb 	if (!BN_mod_add(discriminant, discriminant, b, p, ctx))
626a537a13eStb 		goto err;
627a537a13eStb 
628a537a13eStb 	if (BN_is_zero(discriminant))
629a537a13eStb 		goto err;
630a537a13eStb 
631a537a13eStb  done:
632a537a13eStb 	ret = 1;
6331f65bd71Sjsing 
6341f65bd71Sjsing  err:
6351f65bd71Sjsing 	if (ctx != ctx_in)
6361f65bd71Sjsing 		BN_CTX_free(ctx);
6371f65bd71Sjsing 
6381f65bd71Sjsing 	return ret;
6394fcf65c5Sdjm }
640ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_check_discriminant);
6414fcf65c5Sdjm 
642f67ac449Stedu int
643c827a8a4Stb EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx_in)
644c827a8a4Stb {
645c827a8a4Stb 	BN_CTX *ctx;
646c827a8a4Stb 	EC_POINT *point = NULL;
647ba47179bStb 	const EC_POINT *generator;
648c827a8a4Stb 	const BIGNUM *order;
649c827a8a4Stb 	int ret = 0;
650c827a8a4Stb 
651c827a8a4Stb 	if ((ctx = ctx_in) == NULL)
652c827a8a4Stb 		ctx = BN_CTX_new();
653c827a8a4Stb 	if (ctx == NULL)
654c827a8a4Stb 		goto err;
655c827a8a4Stb 
656c827a8a4Stb 	if (!EC_GROUP_check_discriminant(group, ctx)) {
657c827a8a4Stb 		ECerror(EC_R_DISCRIMINANT_IS_ZERO);
658c827a8a4Stb 		goto err;
659c827a8a4Stb 	}
660c6fb1b70Stb 
661ba47179bStb 	if ((generator = EC_GROUP_get0_generator(group)) == NULL) {
662c827a8a4Stb 		ECerror(EC_R_UNDEFINED_GENERATOR);
663c827a8a4Stb 		goto err;
664c827a8a4Stb 	}
665ba47179bStb 	if (EC_POINT_is_on_curve(group, generator, ctx) <= 0) {
666c827a8a4Stb 		ECerror(EC_R_POINT_IS_NOT_ON_CURVE);
667c827a8a4Stb 		goto err;
668c827a8a4Stb 	}
669c6fb1b70Stb 
670c827a8a4Stb 	if ((point = EC_POINT_new(group)) == NULL)
671c827a8a4Stb 		goto err;
672c827a8a4Stb 	if ((order = EC_GROUP_get0_order(group)) == NULL)
673c827a8a4Stb 		goto err;
674c827a8a4Stb 	if (BN_is_zero(order)) {
675c827a8a4Stb 		ECerror(EC_R_UNDEFINED_ORDER);
676c827a8a4Stb 		goto err;
677c827a8a4Stb 	}
678c827a8a4Stb 	if (!EC_POINT_mul(group, point, order, NULL, NULL, ctx))
679c827a8a4Stb 		goto err;
68009b27144Stb 	if (!EC_POINT_is_at_infinity(group, point)) {
681c827a8a4Stb 		ECerror(EC_R_INVALID_GROUP_ORDER);
682c827a8a4Stb 		goto err;
683c827a8a4Stb 	}
684c827a8a4Stb 
685c827a8a4Stb 	ret = 1;
686c827a8a4Stb 
687c827a8a4Stb  err:
688c827a8a4Stb 	if (ctx != ctx_in)
689c827a8a4Stb 		BN_CTX_free(ctx);
690c827a8a4Stb 
691c827a8a4Stb 	EC_POINT_free(point);
692c827a8a4Stb 
693c827a8a4Stb 	return ret;
694c827a8a4Stb }
695c827a8a4Stb LCRYPTO_ALIAS(EC_GROUP_check);
696c827a8a4Stb 
6977e8924c8Stb /*
6987e8924c8Stb  * Returns -1 on error, 0 if the groups are equal, 1 if they are distinct.
6997e8924c8Stb  */
700c827a8a4Stb int
7017e8924c8Stb EC_GROUP_cmp(const EC_GROUP *group1, const EC_GROUP *group2, BN_CTX *ctx_in)
7024fcf65c5Sdjm {
7037e8924c8Stb 	BN_CTX *ctx = NULL;
7047e8924c8Stb 	BIGNUM *p1, *a1, *b1, *p2, *a2, *b2;
7057e8924c8Stb 	const EC_POINT *generator1, *generator2;
7067e8924c8Stb 	const BIGNUM *order1, *order2, *cofactor1, *cofactor2;
7077e8924c8Stb 	int nid1, nid2;
7087e8924c8Stb 	int cmp = 1;
7097e8924c8Stb 	int ret = -1;
7104fcf65c5Sdjm 
7117e8924c8Stb 	if ((ctx = ctx_in) == NULL)
7127e8924c8Stb 		ctx = BN_CTX_new();
7137e8924c8Stb 	if (ctx == NULL)
7147e8924c8Stb 		goto err;
7154fcf65c5Sdjm 
7164fcf65c5Sdjm 	BN_CTX_start(ctx);
7177e8924c8Stb 
7187e8924c8Stb 	if ((nid1 = EC_GROUP_get_curve_name(group1)) != NID_undef &&
7197e8924c8Stb 	    (nid2 = EC_GROUP_get_curve_name(group2)) != NID_undef) {
7207e8924c8Stb 		if (nid1 != nid2)
7217e8924c8Stb 			goto distinct;
7227e8924c8Stb 	}
7237e8924c8Stb 
7247e8924c8Stb 	if ((p1 = BN_CTX_get(ctx)) == NULL)
7257e8924c8Stb 		goto err;
726aa389b8cSjsing 	if ((a1 = BN_CTX_get(ctx)) == NULL)
727aa389b8cSjsing 		goto err;
728aa389b8cSjsing 	if ((b1 = BN_CTX_get(ctx)) == NULL)
729aa389b8cSjsing 		goto err;
7307e8924c8Stb 	if ((p2 = BN_CTX_get(ctx)) == NULL)
731aa389b8cSjsing 		goto err;
7327e8924c8Stb 	if ((a2 = BN_CTX_get(ctx)) == NULL)
7337e8924c8Stb 		goto err;
7347e8924c8Stb 	if ((b2 = BN_CTX_get(ctx)) == NULL)
735aa389b8cSjsing 		goto err;
736aa389b8cSjsing 
737f67ac449Stedu 	/*
7387e8924c8Stb 	 * If we ever support curves in non-Weierstrass form, this check needs
7397e8924c8Stb 	 * to be adjusted. The comparison of the generators will fail anyway.
7404fcf65c5Sdjm 	 */
7417e8924c8Stb 	if (!EC_GROUP_get_curve(group1, p1, a1, b1, ctx))
7424c1eb2ebSdoug 		goto err;
7437e8924c8Stb 	if (!EC_GROUP_get_curve(group2, p2, a2, b2, ctx))
7447e8924c8Stb 		goto err;
7454fcf65c5Sdjm 
7467e8924c8Stb 	if (BN_cmp(p1, p2) != 0 || BN_cmp(a1, a2) != 0 || BN_cmp(b1, b2) != 0)
7477e8924c8Stb 		goto distinct;
7487e8924c8Stb 
7497e8924c8Stb 	if ((generator1 = EC_GROUP_get0_generator(group1)) == NULL)
7507e8924c8Stb 		goto err;
7517e8924c8Stb 	if ((generator2 = EC_GROUP_get0_generator(group2)) == NULL)
7527e8924c8Stb 		goto err;
7537e8924c8Stb 
7547e8924c8Stb 	/*
7557e8924c8Stb 	 * It does not matter whether group1 or group2 is used: both points must
7567e8924c8Stb 	 * have a matching method for this to succeed.
7577e8924c8Stb 	 */
7587e8924c8Stb 	if ((cmp = EC_POINT_cmp(group1, generator1, generator2, ctx)) < 0)
7597e8924c8Stb 		goto err;
7607e8924c8Stb 	if (cmp == 1)
7617e8924c8Stb 		goto distinct;
7627e8924c8Stb 	cmp = 1;
7637e8924c8Stb 
7647e8924c8Stb 	if ((order1 = EC_GROUP_get0_order(group1)) == NULL)
7657e8924c8Stb 		goto err;
7667e8924c8Stb 	if ((order2 = EC_GROUP_get0_order(group2)) == NULL)
7677e8924c8Stb 		goto err;
7687e8924c8Stb 
7697e8924c8Stb 	if ((cofactor1 = EC_GROUP_get0_cofactor(group1)) == NULL)
7707e8924c8Stb 		goto err;
7717e8924c8Stb 	if ((cofactor2 = EC_GROUP_get0_cofactor(group2)) == NULL)
7727e8924c8Stb 		goto err;
7737e8924c8Stb 
7747e8924c8Stb 	if (BN_cmp(order1, order2) != 0 || BN_cmp(cofactor1, cofactor2) != 0)
7757e8924c8Stb 		goto distinct;
7767e8924c8Stb 
7777e8924c8Stb 	/* All parameters match: the groups are equal. */
7787e8924c8Stb 	cmp = 0;
7797e8924c8Stb 
7807e8924c8Stb  distinct:
7817e8924c8Stb 	ret = cmp;
782aa389b8cSjsing 
783aa389b8cSjsing  err:
784aa389b8cSjsing 	BN_CTX_end(ctx);
7857e8924c8Stb 
7867e8924c8Stb 	if (ctx != ctx_in)
787aa389b8cSjsing 		BN_CTX_free(ctx);
7887e8924c8Stb 
7897e8924c8Stb 	return ret;
790da347917Sbeck }
791ea2baf45Sbeck LCRYPTO_ALIAS(EC_GROUP_cmp);
792da347917Sbeck 
793f67ac449Stedu EC_POINT *
794f67ac449Stedu EC_POINT_new(const EC_GROUP *group)
795da347917Sbeck {
79622896994Stb 	EC_POINT *point = NULL;
797da347917Sbeck 
798f67ac449Stedu 	if (group == NULL) {
7995067ae9fSbeck 		ECerror(ERR_R_PASSED_NULL_PARAMETER);
80022896994Stb 		goto err;
801da347917Sbeck 	}
802da347917Sbeck 
80322896994Stb 	if ((point = calloc(1, sizeof(*point))) == NULL) {
80422896994Stb 		ECerror(ERR_R_MALLOC_FAILURE);
80522896994Stb 		goto err;
806da347917Sbeck 	}
80722896994Stb 
8083c2cb882Stb 	if ((point->X = BN_new()) == NULL)
8093c2cb882Stb 		goto err;
8103c2cb882Stb 	if ((point->Y = BN_new()) == NULL)
8113c2cb882Stb 		goto err;
8123c2cb882Stb 	if ((point->Z = BN_new()) == NULL)
8133c2cb882Stb 		goto err;
8143c2cb882Stb 
81522896994Stb 	point->meth = group->meth;
81622896994Stb 
81722896994Stb 	return point;
81822896994Stb 
81922896994Stb  err:
82022896994Stb 	EC_POINT_free(point);
82122896994Stb 
82222896994Stb 	return NULL;
823da347917Sbeck }
824ea2baf45Sbeck LCRYPTO_ALIAS(EC_POINT_new);
825da347917Sbeck 
826f67ac449Stedu void
827f67ac449Stedu EC_POINT_free(EC_POINT *point)
828da347917Sbeck {
829d7292987Sjsing 	if (point == NULL)
830f67ac449Stedu 		return;
831c58501deSbeck 
8323c2cb882Stb 	BN_free(point->X);
8333c2cb882Stb 	BN_free(point->Y);
8343c2cb882Stb 	BN_free(point->Z);
835da347917Sbeck 
836a7854573Sjsing 	freezero(point, sizeof *point);
837a7854573Sjsing }
838ea2baf45Sbeck LCRYPTO_ALIAS(EC_POINT_free);
839da347917Sbeck 
840f67ac449Stedu void
841f67ac449Stedu EC_POINT_clear_free(EC_POINT *point)
842da347917Sbeck {
843d7292987Sjsing 	EC_POINT_free(point);
844da347917Sbeck }
8458a552917Sbeck LCRYPTO_ALIAS(EC_POINT_clear_free);
846da347917Sbeck 
847f67ac449Stedu int
848cb86d051Stb EC_POINT_copy(EC_POINT *dst, const EC_POINT *src)
849da347917Sbeck {
850cb86d051Stb 	if (dst->meth != src->meth) {
8515067ae9fSbeck 		ECerror(EC_R_INCOMPATIBLE_OBJECTS);
852da347917Sbeck 		return 0;
853da347917Sbeck 	}
854cb86d051Stb 	if (dst == src)
855da347917Sbeck 		return 1;
8569da94e6dStb 
857cb86d051Stb 	if (!bn_copy(dst->X, src->X))
8589da94e6dStb 		return 0;
859cb86d051Stb 	if (!bn_copy(dst->Y, src->Y))
8609da94e6dStb 		return 0;
861cb86d051Stb 	if (!bn_copy(dst->Z, src->Z))
8629da94e6dStb 		return 0;
863cb86d051Stb 	dst->Z_is_one = src->Z_is_one;
8649da94e6dStb 
8659da94e6dStb 	return 1;
866da347917Sbeck }
867ea2baf45Sbeck LCRYPTO_ALIAS(EC_POINT_copy);
868da347917Sbeck 
869f67ac449Stedu EC_POINT *
87022896994Stb EC_POINT_dup(const EC_POINT *in_point, const EC_GROUP *group)
8714fcf65c5Sdjm {
87222896994Stb 	EC_POINT *point = NULL;
8734fcf65c5Sdjm 
87422896994Stb 	if (in_point == NULL)
87522896994Stb 		goto err;
8764fcf65c5Sdjm 
87722896994Stb 	if ((point = EC_POINT_new(group)) == NULL)
87822896994Stb 		goto err;
87922896994Stb 
88022896994Stb 	if (!EC_POINT_copy(point, in_point))
88122896994Stb 		goto err;
88222896994Stb 
88322896994Stb 	return point;
88422896994Stb 
88522896994Stb  err:
88622896994Stb 	EC_POINT_free(point);
88722896994Stb 
8884fcf65c5Sdjm 	return NULL;
8894fcf65c5Sdjm }
890ea2baf45Sbeck LCRYPTO_ALIAS(EC_POINT_dup);
8914fcf65c5Sdjm 
892f67ac449Stedu int
893f67ac449Stedu EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point)
894da347917Sbeck {
895f67ac449Stedu 	if (group->meth != point->meth) {
8965067ae9fSbeck 		ECerror(EC_R_INCOMPATIBLE_OBJECTS);
897da347917Sbeck 		return 0;
898da347917Sbeck 	}
8999da94e6dStb 
9003c2cb882Stb 	BN_zero(point->Z);
9019da94e6dStb 	point->Z_is_one = 0;
9029da94e6dStb 
9039da94e6dStb 	return 1;
904da347917Sbeck }
905ea2baf45Sbeck LCRYPTO_ALIAS(EC_POINT_set_to_infinity);
906da347917Sbeck 
9074f21b6f2Stb int
90874a506e7Stb EC_POINT_set_affine_coordinates(const EC_GROUP *group, EC_POINT *point,
9091f65bd71Sjsing     const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx_in)
910da347917Sbeck {
9111f65bd71Sjsing 	BN_CTX *ctx;
9121f65bd71Sjsing 	int ret = 0;
9131f65bd71Sjsing 
9141f65bd71Sjsing 	if ((ctx = ctx_in) == NULL)
9151f65bd71Sjsing 		ctx = BN_CTX_new();
9161f65bd71Sjsing 	if (ctx == NULL)
9171f65bd71Sjsing 		goto err;
9181f65bd71Sjsing 
91914a674d4Stb 	if (group->meth->point_set_affine_coordinates == NULL) {
9205067ae9fSbeck 		ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
9211f65bd71Sjsing 		goto err;
922da347917Sbeck 	}
923f67ac449Stedu 	if (group->meth != point->meth) {
9245067ae9fSbeck 		ECerror(EC_R_INCOMPATIBLE_OBJECTS);
9251f65bd71Sjsing 		goto err;
926da347917Sbeck 	}
927ea076652Stb 	if (!group->meth->point_set_affine_coordinates(group, point, x, y, ctx))
9281f65bd71Sjsing 		goto err;
9291f65bd71Sjsing 
930ea076652Stb 	if (EC_POINT_is_on_curve(group, point, ctx) <= 0) {
931ea076652Stb 		ECerror(EC_R_POINT_IS_NOT_ON_CURVE);
9321f65bd71Sjsing 		goto err;
933ea076652Stb 	}
9341f65bd71Sjsing 
9351f65bd71Sjsing 	ret = 1;
9361f65bd71Sjsing 
9371f65bd71Sjsing  err:
9381f65bd71Sjsing 	if (ctx != ctx_in)
9391f65bd71Sjsing 		BN_CTX_free(ctx);
9401f65bd71Sjsing 
9411f65bd71Sjsing 	return ret;
9424fcf65c5Sdjm }
943ea2baf45Sbeck LCRYPTO_ALIAS(EC_POINT_set_affine_coordinates);
9444fcf65c5Sdjm 
94574a506e7Stb int
94674a506e7Stb EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
94774a506e7Stb     const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx)
94874a506e7Stb {
94974a506e7Stb 	return EC_POINT_set_affine_coordinates(group, point, x, y, ctx);
95074a506e7Stb }
9518a552917Sbeck LCRYPTO_ALIAS(EC_POINT_set_affine_coordinates_GFp);
95274a506e7Stb 
953f67ac449Stedu int
95474a506e7Stb EC_POINT_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *point,
9551f65bd71Sjsing     BIGNUM *x, BIGNUM *y, BN_CTX *ctx_in)
956da347917Sbeck {
9572d40ce70Stb 	BN_CTX *ctx = NULL;
9581f65bd71Sjsing 	int ret = 0;
9591f65bd71Sjsing 
9602d40ce70Stb 	if (EC_POINT_is_at_infinity(group, point) > 0) {
9612d40ce70Stb 		ECerror(EC_R_POINT_AT_INFINITY);
9622d40ce70Stb 		goto err;
9632d40ce70Stb 	}
9642d40ce70Stb 
9651f65bd71Sjsing 	if ((ctx = ctx_in) == NULL)
9661f65bd71Sjsing 		ctx = BN_CTX_new();
9671f65bd71Sjsing 	if (ctx == NULL)
9681f65bd71Sjsing 		goto err;
9691f65bd71Sjsing 
97014a674d4Stb 	if (group->meth->point_get_affine_coordinates == NULL) {
9715067ae9fSbeck 		ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
9727b871452Stb 		goto err;
973da347917Sbeck 	}
974f67ac449Stedu 	if (group->meth != point->meth) {
9755067ae9fSbeck 		ECerror(EC_R_INCOMPATIBLE_OBJECTS);
9767b871452Stb 		goto err;
977da347917Sbeck 	}
9781f65bd71Sjsing 	ret = group->meth->point_get_affine_coordinates(group, point, x, y, ctx);
9791f65bd71Sjsing 
9801f65bd71Sjsing  err:
9811f65bd71Sjsing 	if (ctx != ctx_in)
9821f65bd71Sjsing 		BN_CTX_free(ctx);
9831f65bd71Sjsing 
9841f65bd71Sjsing 	return ret;
9854fcf65c5Sdjm }
986ea2baf45Sbeck LCRYPTO_ALIAS(EC_POINT_get_affine_coordinates);
9874fcf65c5Sdjm 
98874a506e7Stb int
98974a506e7Stb EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, const EC_POINT *point,
99074a506e7Stb     BIGNUM *x, BIGNUM *y, BN_CTX *ctx)
99174a506e7Stb {
99274a506e7Stb 	return EC_POINT_get_affine_coordinates(group, point, x, y, ctx);
99374a506e7Stb }
9948a552917Sbeck LCRYPTO_ALIAS(EC_POINT_get_affine_coordinates_GFp);
99574a506e7Stb 
996f67ac449Stedu int
997c2bab48dStb EC_POINT_set_compressed_coordinates(const EC_GROUP *group, EC_POINT *point,
99869100aa7Stb     const BIGNUM *in_x, int y_bit, BN_CTX *ctx_in)
999c2bab48dStb {
100069100aa7Stb 	BIGNUM *p, *a, *b, *w, *x, *y;
1001c2bab48dStb 	BN_CTX *ctx;
1002c2bab48dStb 	int ret = 0;
1003c2bab48dStb 
1004c2bab48dStb 	if ((ctx = ctx_in) == NULL)
1005c2bab48dStb 		ctx = BN_CTX_new();
1006c2bab48dStb 	if (ctx == NULL)
1007c2bab48dStb 		goto err;
1008c2bab48dStb 
100969100aa7Stb 	y_bit = (y_bit != 0);
101069100aa7Stb 
101169100aa7Stb 	BN_CTX_start(ctx);
101269100aa7Stb 
101369100aa7Stb 	if ((p = BN_CTX_get(ctx)) == NULL)
101469100aa7Stb 		goto err;
101569100aa7Stb 	if ((a = BN_CTX_get(ctx)) == NULL)
101669100aa7Stb 		goto err;
101769100aa7Stb 	if ((b = BN_CTX_get(ctx)) == NULL)
101869100aa7Stb 		goto err;
101969100aa7Stb 	if ((w = BN_CTX_get(ctx)) == NULL)
102069100aa7Stb 		goto err;
102169100aa7Stb 	if ((x = BN_CTX_get(ctx)) == NULL)
102269100aa7Stb 		goto err;
102369100aa7Stb 	if ((y = BN_CTX_get(ctx)) == NULL)
102469100aa7Stb 		goto err;
102569100aa7Stb 
102669100aa7Stb 	/*
102769100aa7Stb 	 * Weierstrass equation: y^2 = x^3 + ax + b, so y is one of the
102869100aa7Stb 	 * square roots of x^3 + ax + b. The y-bit indicates which one.
102969100aa7Stb 	 */
103069100aa7Stb 
103169100aa7Stb 	if (!EC_GROUP_get_curve(group, p, a, b, ctx))
103269100aa7Stb 		goto err;
103369100aa7Stb 
103469100aa7Stb 	/* XXX - should we not insist on 0 <= x < p instead? */
103569100aa7Stb 	if (!BN_nnmod(x, in_x, p, ctx))
103669100aa7Stb 		goto err;
103769100aa7Stb 
103869100aa7Stb 	/* y = x^3 */
103969100aa7Stb 	if (!BN_mod_sqr(y, x, p, ctx))
104069100aa7Stb 		goto err;
104169100aa7Stb 	if (!BN_mod_mul(y, y, x, p, ctx))
104269100aa7Stb 		goto err;
104369100aa7Stb 
104469100aa7Stb 	/* y += ax */
104569100aa7Stb 	if (group->a_is_minus3) {
104669100aa7Stb 		if (!BN_mod_lshift1_quick(w, x, p))
104769100aa7Stb 			goto err;
104869100aa7Stb 		if (!BN_mod_add_quick(w, w, x, p))
104969100aa7Stb 			goto err;
105069100aa7Stb 		if (!BN_mod_sub_quick(y, y, w, p))
105169100aa7Stb 			goto err;
105269100aa7Stb 	} else {
105369100aa7Stb 		if (!BN_mod_mul(w, a, x, p, ctx))
105469100aa7Stb 			goto err;
105569100aa7Stb 		if (!BN_mod_add_quick(y, y, w, p))
1056c2bab48dStb 			goto err;
1057c2bab48dStb 	}
105869100aa7Stb 
105969100aa7Stb 	/* y += b */
106069100aa7Stb 	if (!BN_mod_add_quick(y, y, b, p))
106169100aa7Stb 		goto err;
106269100aa7Stb 
106369100aa7Stb 	if (!BN_mod_sqrt(y, y, p, ctx)) {
106469100aa7Stb 		ECerror(EC_R_INVALID_COMPRESSED_POINT);
1065c2bab48dStb 		goto err;
1066c2bab48dStb 	}
106769100aa7Stb 
106869100aa7Stb 	if (y_bit == BN_is_odd(y))
106969100aa7Stb 		goto done;
107069100aa7Stb 
107169100aa7Stb 	if (BN_is_zero(y)) {
107269100aa7Stb 		ECerror(EC_R_INVALID_COMPRESSION_BIT);
107369100aa7Stb 		goto err;
107469100aa7Stb 	}
107569100aa7Stb 	if (!BN_usub(y, p, y))
107669100aa7Stb 		goto err;
107769100aa7Stb 
107869100aa7Stb 	if (y_bit != BN_is_odd(y)) {
107969100aa7Stb 		/* Can only happen if p is even and should not be reachable. */
108069100aa7Stb 		ECerror(ERR_R_INTERNAL_ERROR);
108169100aa7Stb 		goto err;
108269100aa7Stb 	}
108369100aa7Stb 
108469100aa7Stb  done:
108569100aa7Stb 	if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx))
108669100aa7Stb 		goto err;
108769100aa7Stb 
108869100aa7Stb 	ret = 1;
1089c2bab48dStb 
1090c2bab48dStb  err:
109169100aa7Stb 	BN_CTX_end(ctx);
109269100aa7Stb 
1093c2bab48dStb 	if (ctx != ctx_in)
1094c2bab48dStb 		BN_CTX_free(ctx);
1095c2bab48dStb 
1096c2bab48dStb 	return ret;
1097c2bab48dStb }
1098c2bab48dStb LCRYPTO_ALIAS(EC_POINT_set_compressed_coordinates);
1099c2bab48dStb 
1100c2bab48dStb int
1101c2bab48dStb EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
1102c2bab48dStb     const BIGNUM *x, int y_bit, BN_CTX *ctx)
1103c2bab48dStb {
1104c2bab48dStb 	return EC_POINT_set_compressed_coordinates(group, point, x, y_bit, ctx);
1105c2bab48dStb }
1106c2bab48dStb LCRYPTO_ALIAS(EC_POINT_set_compressed_coordinates_GFp);
1107c2bab48dStb 
1108c2bab48dStb int
1109f67ac449Stedu EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
11101f65bd71Sjsing     const EC_POINT *b, BN_CTX *ctx_in)
1111da347917Sbeck {
11121f65bd71Sjsing 	BN_CTX *ctx;
11131f65bd71Sjsing 	int ret = 0;
11141f65bd71Sjsing 
11151f65bd71Sjsing 	if ((ctx = ctx_in) == NULL)
11161f65bd71Sjsing 		ctx = BN_CTX_new();
11171f65bd71Sjsing 	if (ctx == NULL)
11181f65bd71Sjsing 		goto err;
11191f65bd71Sjsing 
11201f65bd71Sjsing 	if (group->meth->add == NULL) {
11211f65bd71Sjsing 		ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
11221f65bd71Sjsing 		goto err;
11231f65bd71Sjsing 	}
11241f65bd71Sjsing 	if (group->meth != r->meth || group->meth != a->meth ||
11251f65bd71Sjsing 	    group->meth != b->meth) {
11261f65bd71Sjsing 		ECerror(EC_R_INCOMPATIBLE_OBJECTS);
11271f65bd71Sjsing 		goto err;
11281f65bd71Sjsing 	}
11291f65bd71Sjsing 	ret = group->meth->add(group, r, a, b, ctx);
11301f65bd71Sjsing 
11311f65bd71Sjsing  err:
11321f65bd71Sjsing 	if (ctx != ctx_in)
11331f65bd71Sjsing 		BN_CTX_free(ctx);
11341f65bd71Sjsing 
11351f65bd71Sjsing 	return ret;
11361f65bd71Sjsing }
1137ea2baf45Sbeck LCRYPTO_ALIAS(EC_POINT_add);
11381f65bd71Sjsing 
11391f65bd71Sjsing int
11401f65bd71Sjsing EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
11411f65bd71Sjsing     BN_CTX *ctx_in)
11421f65bd71Sjsing {
11431f65bd71Sjsing 	BN_CTX *ctx;
11441f65bd71Sjsing 	int ret = 0;
11451f65bd71Sjsing 
11461f65bd71Sjsing 	if ((ctx = ctx_in) == NULL)
11471f65bd71Sjsing 		ctx = BN_CTX_new();
11481f65bd71Sjsing 	if (ctx == NULL)
11491f65bd71Sjsing 		goto err;
11501f65bd71Sjsing 
11511f65bd71Sjsing 	if (group->meth->dbl == NULL) {
11525067ae9fSbeck 		ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
11537b871452Stb 		goto err;
1154da347917Sbeck 	}
11551f65bd71Sjsing 	if (group->meth != r->meth || r->meth != a->meth) {
11565067ae9fSbeck 		ECerror(EC_R_INCOMPATIBLE_OBJECTS);
11577b871452Stb 		goto err;
1158da347917Sbeck 	}
11591f65bd71Sjsing 	ret = group->meth->dbl(group, r, a, ctx);
1160da347917Sbeck 
11611f65bd71Sjsing  err:
11621f65bd71Sjsing 	if (ctx != ctx_in)
11631f65bd71Sjsing 		BN_CTX_free(ctx);
11641f65bd71Sjsing 
11651f65bd71Sjsing 	return ret;
11661f65bd71Sjsing }
1167ea2baf45Sbeck LCRYPTO_ALIAS(EC_POINT_dbl);
1168da347917Sbeck 
1169f67ac449Stedu int
11701f65bd71Sjsing EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx_in)
1171da347917Sbeck {
11721f65bd71Sjsing 	BN_CTX *ctx;
11731f65bd71Sjsing 	int ret = 0;
1174da347917Sbeck 
11751f65bd71Sjsing 	if ((ctx = ctx_in) == NULL)
11761f65bd71Sjsing 		ctx = BN_CTX_new();
11771f65bd71Sjsing 	if (ctx == NULL)
11781f65bd71Sjsing 		goto err;
1179da347917Sbeck 
11807b871452Stb 	if (group->meth->invert == NULL) {
11815067ae9fSbeck 		ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
11827b871452Stb 		goto err;
1183da347917Sbeck 	}
1184f67ac449Stedu 	if (group->meth != a->meth) {
11855067ae9fSbeck 		ECerror(EC_R_INCOMPATIBLE_OBJECTS);
11867b871452Stb 		goto err;
1187da347917Sbeck 	}
11887b871452Stb 	ret = group->meth->invert(group, a, ctx);
1189da347917Sbeck 
11901f65bd71Sjsing  err:
11911f65bd71Sjsing 	if (ctx != ctx_in)
11921f65bd71Sjsing 		BN_CTX_free(ctx);
11931f65bd71Sjsing 
11941f65bd71Sjsing 	return ret;
11951f65bd71Sjsing }
1196ea2baf45Sbeck LCRYPTO_ALIAS(EC_POINT_invert);
1197da347917Sbeck 
1198f67ac449Stedu int
1199f67ac449Stedu EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point)
1200da347917Sbeck {
1201f67ac449Stedu 	if (group->meth != point->meth) {
12025067ae9fSbeck 		ECerror(EC_R_INCOMPATIBLE_OBJECTS);
1203da347917Sbeck 		return 0;
1204da347917Sbeck 	}
12059da94e6dStb 
12063c2cb882Stb 	return BN_is_zero(point->Z);
1207da347917Sbeck }
1208ea2baf45Sbeck LCRYPTO_ALIAS(EC_POINT_is_at_infinity);
1209da347917Sbeck 
1210f67ac449Stedu int
12111f65bd71Sjsing EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
12121f65bd71Sjsing     BN_CTX *ctx_in)
1213da347917Sbeck {
12141f65bd71Sjsing 	BN_CTX *ctx;
12151540d532Stb 	int ret = -1;
12161f65bd71Sjsing 
12171f65bd71Sjsing 	if ((ctx = ctx_in) == NULL)
12181f65bd71Sjsing 		ctx = BN_CTX_new();
12191f65bd71Sjsing 	if (ctx == NULL)
12201f65bd71Sjsing 		goto err;
12211f65bd71Sjsing 
12224fb59ff9Stb 	if (group->meth->point_is_on_curve == NULL) {
12235067ae9fSbeck 		ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
12241f65bd71Sjsing 		goto err;
1225da347917Sbeck 	}
1226f67ac449Stedu 	if (group->meth != point->meth) {
12275067ae9fSbeck 		ECerror(EC_R_INCOMPATIBLE_OBJECTS);
12281f65bd71Sjsing 		goto err;
1229da347917Sbeck 	}
12304fb59ff9Stb 	ret = group->meth->point_is_on_curve(group, point, ctx);
1231da347917Sbeck 
12321f65bd71Sjsing  err:
12331f65bd71Sjsing 	if (ctx != ctx_in)
12341f65bd71Sjsing 		BN_CTX_free(ctx);
12351f65bd71Sjsing 
12361f65bd71Sjsing 	return ret;
12371f65bd71Sjsing }
1238ea2baf45Sbeck LCRYPTO_ALIAS(EC_POINT_is_on_curve);
1239da347917Sbeck 
1240f67ac449Stedu int
1241f67ac449Stedu EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b,
12421f65bd71Sjsing     BN_CTX *ctx_in)
1243da347917Sbeck {
12441f65bd71Sjsing 	BN_CTX *ctx;
12451f65bd71Sjsing 	int ret = -1;
1246da347917Sbeck 
12471f65bd71Sjsing 	if ((ctx = ctx_in) == NULL)
12481f65bd71Sjsing 		ctx = BN_CTX_new();
12491f65bd71Sjsing 	if (ctx == NULL)
12501f65bd71Sjsing 		goto err;
12511f65bd71Sjsing 
12521f65bd71Sjsing 	if (group->meth->point_cmp == NULL) {
12531f65bd71Sjsing 		ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
12541f65bd71Sjsing 		goto err;
12551f65bd71Sjsing 	}
12561f65bd71Sjsing 	if (group->meth != a->meth || a->meth != b->meth) {
12571f65bd71Sjsing 		ECerror(EC_R_INCOMPATIBLE_OBJECTS);
12581f65bd71Sjsing 		goto err;
12591f65bd71Sjsing 	}
12601f65bd71Sjsing 	ret = group->meth->point_cmp(group, a, b, ctx);
12611f65bd71Sjsing 
12621f65bd71Sjsing  err:
12631f65bd71Sjsing 	if (ctx != ctx_in)
12641f65bd71Sjsing 		BN_CTX_free(ctx);
12651f65bd71Sjsing 
12661f65bd71Sjsing 	return ret;
12671f65bd71Sjsing }
1268ea2baf45Sbeck LCRYPTO_ALIAS(EC_POINT_cmp);
1269da347917Sbeck 
1270f67ac449Stedu int
12711f65bd71Sjsing EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx_in)
1272da347917Sbeck {
12731f65bd71Sjsing 	BN_CTX *ctx;
127407ff836aStb 	BIGNUM *x, *y;
12751f65bd71Sjsing 	int ret = 0;
12761f65bd71Sjsing 
12771f65bd71Sjsing 	if ((ctx = ctx_in) == NULL)
12781f65bd71Sjsing 		ctx = BN_CTX_new();
12791f65bd71Sjsing 	if (ctx == NULL)
12801f65bd71Sjsing 		goto err;
12811f65bd71Sjsing 
128207ff836aStb 	BN_CTX_start(ctx);
128307ff836aStb 
128407ff836aStb 	if ((x = BN_CTX_get(ctx)) == NULL)
128507ff836aStb 		goto err;
128607ff836aStb 	if ((y = BN_CTX_get(ctx)) == NULL)
128707ff836aStb 		goto err;
128807ff836aStb 
128907ff836aStb 	if (!EC_POINT_get_affine_coordinates(group, point, x, y, ctx))
129007ff836aStb 		goto err;
129107ff836aStb 	if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx))
129207ff836aStb 		goto err;
129307ff836aStb 
129407ff836aStb 	ret = 1;
1295da347917Sbeck 
12961f65bd71Sjsing  err:
129707ff836aStb 	BN_CTX_end(ctx);
129807ff836aStb 
12991f65bd71Sjsing 	if (ctx != ctx_in)
13001f65bd71Sjsing 		BN_CTX_free(ctx);
13011f65bd71Sjsing 
13021f65bd71Sjsing 	return ret;
13031f65bd71Sjsing }
1304ea2baf45Sbeck LCRYPTO_ALIAS(EC_POINT_make_affine);
1305da347917Sbeck 
1306f67ac449Stedu int
1307f67ac449Stedu EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar,
13081f65bd71Sjsing     const EC_POINT *point, const BIGNUM *p_scalar, BN_CTX *ctx_in)
13094fcf65c5Sdjm {
13101f65bd71Sjsing 	BN_CTX *ctx;
13111f65bd71Sjsing 	int ret = 0;
13121f65bd71Sjsing 
13131f65bd71Sjsing 	if ((ctx = ctx_in) == NULL)
13141f65bd71Sjsing 		ctx = BN_CTX_new();
13151f65bd71Sjsing 	if (ctx == NULL)
13161f65bd71Sjsing 		goto err;
13171f65bd71Sjsing 
13181447fb01Sjsing 	if (group->meth->mul_single_ct == NULL ||
1319149fe518Stb 	    group->meth->mul_double_nonct == NULL) {
1320149fe518Stb 		ECerror(ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
13211f65bd71Sjsing 		goto err;
1322149fe518Stb 	}
13231f65bd71Sjsing 
1324149fe518Stb 	if (g_scalar != NULL && point == NULL && p_scalar == NULL) {
1325149fe518Stb 		/*
1326149fe518Stb 		 * In this case we want to compute g_scalar * GeneratorPoint:
1327149fe518Stb 		 * this codepath is reached most prominently by (ephemeral) key
1328149fe518Stb 		 * generation of EC cryptosystems (i.e. ECDSA keygen and sign
1329149fe518Stb 		 * setup, ECDH keygen/first half), where the scalar is always
1330149fe518Stb 		 * secret. This is why we ignore if BN_FLG_CONSTTIME is actually
1331149fe518Stb 		 * set and we always call the constant time version.
1332149fe518Stb 		 */
13331447fb01Sjsing 		ret = group->meth->mul_single_ct(group, r, g_scalar,
13341447fb01Sjsing 		    group->generator, ctx);
13351f65bd71Sjsing 	} else if (g_scalar == NULL && point != NULL && p_scalar != NULL) {
13361f65bd71Sjsing 		/*
13371f65bd71Sjsing 		 * In this case we want to compute p_scalar * GenericPoint:
1338149fe518Stb 		 * this codepath is reached most prominently by the second half
1339149fe518Stb 		 * of ECDH, where the secret scalar is multiplied by the peer's
1340149fe518Stb 		 * public point. To protect the secret scalar, we ignore if
1341149fe518Stb 		 * BN_FLG_CONSTTIME is actually set and we always call the
1342149fe518Stb 		 * constant time version.
1343149fe518Stb 		 */
13441f65bd71Sjsing 		ret = group->meth->mul_single_ct(group, r, p_scalar, point, ctx);
13451f65bd71Sjsing 	} else if (g_scalar != NULL && point != NULL && p_scalar != NULL) {
1346149fe518Stb 		/*
1347149fe518Stb 		 * In this case we want to compute
1348149fe518Stb 		 *   g_scalar * GeneratorPoint + p_scalar * GenericPoint:
1349149fe518Stb 		 * this codepath is reached most prominently by ECDSA signature
1350149fe518Stb 		 * verification. So we call the non-ct version.
1351149fe518Stb 		 */
13521f65bd71Sjsing 		ret = group->meth->mul_double_nonct(group, r, g_scalar,
1353149fe518Stb 		    p_scalar, point, ctx);
13541f65bd71Sjsing 	} else {
1355149fe518Stb 		/* Anything else is an error. */
1356149fe518Stb 		ECerror(ERR_R_EC_LIB);
13571f65bd71Sjsing 		goto err;
13581f65bd71Sjsing 	}
13591f65bd71Sjsing 
13601f65bd71Sjsing  err:
13611f65bd71Sjsing 	if (ctx != ctx_in)
13621f65bd71Sjsing 		BN_CTX_free(ctx);
13631f65bd71Sjsing 
13641f65bd71Sjsing 	return ret;
13654fcf65c5Sdjm }
1366ea2baf45Sbeck LCRYPTO_ALIAS(EC_POINT_mul);
13674fcf65c5Sdjm 
1368c9edc1b9Stb /*
1369c9edc1b9Stb  * XXX - remove everything below in the next bump
1370c9edc1b9Stb  */
1371c9edc1b9Stb 
1372c9edc1b9Stb int
1373c9edc1b9Stb EC_POINT_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
1374c9edc1b9Stb     const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *ctx)
1375c9edc1b9Stb {
1376c9edc1b9Stb 	ECerror(ERR_R_DISABLED);
1377c9edc1b9Stb 	return 0;
1378c9edc1b9Stb }
1379c9edc1b9Stb LCRYPTO_ALIAS(EC_POINT_set_Jprojective_coordinates_GFp);
1380c9edc1b9Stb 
1381c9edc1b9Stb int
1382c9edc1b9Stb EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *group,
1383c9edc1b9Stb     const EC_POINT *point, BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *ctx)
1384c9edc1b9Stb {
1385c9edc1b9Stb 	ECerror(ERR_R_DISABLED);
1386c9edc1b9Stb 	return 0;
1387c9edc1b9Stb }
1388c9edc1b9Stb LCRYPTO_ALIAS(EC_POINT_get_Jprojective_coordinates_GFp);
1389c21af703Stb 
1390c21af703Stb int
1391c21af703Stb EC_POINTs_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[],
1392c21af703Stb     BN_CTX *ctx_in)
1393c21af703Stb {
1394c21af703Stb 	ECerror(ERR_R_DISABLED);
1395c21af703Stb 	return 0;
1396c21af703Stb }
1397c21af703Stb LCRYPTO_ALIAS(EC_POINTs_make_affine);
1398c21af703Stb 
1399c21af703Stb int
1400c21af703Stb EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar,
1401c21af703Stb     size_t num, const EC_POINT *points[], const BIGNUM *scalars[],
1402c21af703Stb     BN_CTX *ctx_in)
1403c21af703Stb {
1404c21af703Stb 	ECerror(ERR_R_DISABLED);
1405c21af703Stb 	return 0;
1406c21af703Stb }
1407c21af703Stb LCRYPTO_ALIAS(EC_POINTs_mul);
1408*a9bbc4f7Stb 
1409*a9bbc4f7Stb const EC_METHOD *
1410*a9bbc4f7Stb EC_GROUP_method_of(const EC_GROUP *group)
1411*a9bbc4f7Stb {
1412*a9bbc4f7Stb 	ECerror(ERR_R_DISABLED);
1413*a9bbc4f7Stb 	return NULL;
1414*a9bbc4f7Stb }
1415*a9bbc4f7Stb LCRYPTO_ALIAS(EC_GROUP_method_of);
1416*a9bbc4f7Stb 
1417*a9bbc4f7Stb int
1418*a9bbc4f7Stb EC_METHOD_get_field_type(const EC_METHOD *meth)
1419*a9bbc4f7Stb {
1420*a9bbc4f7Stb 	ECerror(ERR_R_DISABLED);
1421*a9bbc4f7Stb 	return NID_undef;
1422*a9bbc4f7Stb }
1423*a9bbc4f7Stb LCRYPTO_ALIAS(EC_METHOD_get_field_type);
1424*a9bbc4f7Stb 
1425*a9bbc4f7Stb const EC_METHOD *
1426*a9bbc4f7Stb EC_POINT_method_of(const EC_POINT *point)
1427*a9bbc4f7Stb {
1428*a9bbc4f7Stb 	ECerror(ERR_R_DISABLED);
1429*a9bbc4f7Stb 	return NULL;
1430*a9bbc4f7Stb }
1431*a9bbc4f7Stb LCRYPTO_ALIAS(EC_POINT_method_of);
1432*a9bbc4f7Stb 
1433*a9bbc4f7Stb int
1434*a9bbc4f7Stb EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx_in)
1435*a9bbc4f7Stb {
1436*a9bbc4f7Stb 	ECerror(ERR_R_DISABLED);
1437*a9bbc4f7Stb 	return 0;
1438*a9bbc4f7Stb }
1439*a9bbc4f7Stb LCRYPTO_ALIAS(EC_GROUP_precompute_mult);
1440*a9bbc4f7Stb 
1441*a9bbc4f7Stb int
1442*a9bbc4f7Stb EC_GROUP_have_precompute_mult(const EC_GROUP *group)
1443*a9bbc4f7Stb {
1444*a9bbc4f7Stb 	ECerror(ERR_R_DISABLED);
1445*a9bbc4f7Stb 	return 0;
1446*a9bbc4f7Stb }
1447*a9bbc4f7Stb LCRYPTO_ALIAS(EC_GROUP_have_precompute_mult);
1448