1f9fbec1mcpowers/*
2f9fbec1mcpowers * ***** BEGIN LICENSE BLOCK *****
3f9fbec1mcpowers * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4f9fbec1mcpowers *
5f9fbec1mcpowers * The contents of this file are subject to the Mozilla Public License Version
6f9fbec1mcpowers * 1.1 (the "License"); you may not use this file except in compliance with
7f9fbec1mcpowers * the License. You may obtain a copy of the License at
8f9fbec1mcpowers * http://www.mozilla.org/MPL/
9f9fbec1mcpowers *
10f9fbec1mcpowers * Software distributed under the License is distributed on an "AS IS" basis,
11f9fbec1mcpowers * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12f9fbec1mcpowers * for the specific language governing rights and limitations under the
13f9fbec1mcpowers * License.
14f9fbec1mcpowers *
15f9fbec1mcpowers * The Original Code is the elliptic curve math library.
16f9fbec1mcpowers *
17f9fbec1mcpowers * The Initial Developer of the Original Code is
18f9fbec1mcpowers * Sun Microsystems, Inc.
19f9fbec1mcpowers * Portions created by the Initial Developer are Copyright (C) 2003
20f9fbec1mcpowers * the Initial Developer. All Rights Reserved.
21f9fbec1mcpowers *
22f9fbec1mcpowers * Contributor(s):
23f9fbec1mcpowers *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
24f9fbec1mcpowers *
25f9fbec1mcpowers * Alternatively, the contents of this file may be used under the terms of
26f9fbec1mcpowers * either the GNU General Public License Version 2 or later (the "GPL"), or
27f9fbec1mcpowers * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28f9fbec1mcpowers * in which case the provisions of the GPL or the LGPL are applicable instead
29f9fbec1mcpowers * of those above. If you wish to allow use of your version of this file only
30f9fbec1mcpowers * under the terms of either the GPL or the LGPL, and not to allow others to
31f9fbec1mcpowers * use your version of this file under the terms of the MPL, indicate your
32f9fbec1mcpowers * decision by deleting the provisions above and replace them with the notice
33f9fbec1mcpowers * and other provisions required by the GPL or the LGPL. If you do not delete
34f9fbec1mcpowers * the provisions above, a recipient may use your version of this file under
35f9fbec1mcpowers * the terms of any one of the MPL, the GPL or the LGPL.
36f9fbec1mcpowers *
37f9fbec1mcpowers * ***** END LICENSE BLOCK ***** */
38f9fbec1mcpowers/*
39f9fbec1mcpowers * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
40f9fbec1mcpowers * Use is subject to license terms.
41f9fbec1mcpowers *
42f9fbec1mcpowers * Sun elects to use this software under the MPL license.
43f9fbec1mcpowers */
44f9fbec1mcpowers
45f9fbec1mcpowers#pragma ident	"%Z%%M%	%I%	%E% SMI"
46f9fbec1mcpowers
47f9fbec1mcpowers#include "mpi.h"
48f9fbec1mcpowers#include "mplogic.h"
49f9fbec1mcpowers#include "ecl.h"
50f9fbec1mcpowers#include "ecl-priv.h"
51f9fbec1mcpowers#include "ec2.h"
52f9fbec1mcpowers#include "ecp.h"
53f9fbec1mcpowers#ifndef _KERNEL
54f9fbec1mcpowers#include <stdlib.h>
55f9fbec1mcpowers#include <string.h>
56f9fbec1mcpowers#endif
57f9fbec1mcpowers
58f9fbec1mcpowers/* Allocate memory for a new ECGroup object. */
59f9fbec1mcpowersECGroup *
60f9fbec1mcpowersECGroup_new(int kmflag)
61f9fbec1mcpowers{
62f9fbec1mcpowers	mp_err res = MP_OKAY;
63f9fbec1mcpowers	ECGroup *group;
64f9fbec1mcpowers#ifdef _KERNEL
65f9fbec1mcpowers	group = (ECGroup *) kmem_alloc(sizeof(ECGroup), kmflag);
66f9fbec1mcpowers#else
67f9fbec1mcpowers	group = (ECGroup *) malloc(sizeof(ECGroup));
68f9fbec1mcpowers#endif
69f9fbec1mcpowers	if (group == NULL)
70f9fbec1mcpowers		return NULL;
71f9fbec1mcpowers	group->constructed = MP_YES;
72f9fbec1mcpowers        group->meth = NULL;
73f9fbec1mcpowers	group->text = NULL;
74f9fbec1mcpowers	MP_DIGITS(&group->curvea) = 0;
75f9fbec1mcpowers	MP_DIGITS(&group->curveb) = 0;
76f9fbec1mcpowers	MP_DIGITS(&group->genx) = 0;
77f9fbec1mcpowers	MP_DIGITS(&group->geny) = 0;
78f9fbec1mcpowers	MP_DIGITS(&group->order) = 0;
79f9fbec1mcpowers	group->base_point_mul = NULL;
80f9fbec1mcpowers	group->points_mul = NULL;
81f9fbec1mcpowers	group->validate_point = NULL;
82f9fbec1mcpowers	group->extra1 = NULL;
83f9fbec1mcpowers	group->extra2 = NULL;
84f9fbec1mcpowers	group->extra_free = NULL;
85f9fbec1mcpowers	MP_CHECKOK(mp_init(&group->curvea, kmflag));
86f9fbec1mcpowers	MP_CHECKOK(mp_init(&group->curveb, kmflag));
87f9fbec1mcpowers	MP_CHECKOK(mp_init(&group->genx, kmflag));
88f9fbec1mcpowers	MP_CHECKOK(mp_init(&group->geny, kmflag));
89f9fbec1mcpowers	MP_CHECKOK(mp_init(&group->order, kmflag));
90f9fbec1mcpowers
91f9fbec1mcpowers  CLEANUP:
92f9fbec1mcpowers	if (res != MP_OKAY) {
93f9fbec1mcpowers		ECGroup_free(group);
94f9fbec1mcpowers		return NULL;
95f9fbec1mcpowers	}
96f9fbec1mcpowers	return group;
97f9fbec1mcpowers}
98f9fbec1mcpowers
99f9fbec1mcpowers/* Construct a generic ECGroup for elliptic curves over prime fields. */
100f9fbec1mcpowersECGroup *
101f9fbec1mcpowersECGroup_consGFp(const mp_int *irr, const mp_int *curvea,
102f9fbec1mcpowers				const mp_int *curveb, const mp_int *genx,
103f9fbec1mcpowers				const mp_int *geny, const mp_int *order, int cofactor)
104f9fbec1mcpowers{
105f9fbec1mcpowers	mp_err res = MP_OKAY;
106f9fbec1mcpowers	ECGroup *group = NULL;
107f9fbec1mcpowers
108f9fbec1mcpowers	group = ECGroup_new(FLAG(irr));
109f9fbec1mcpowers	if (group == NULL)
110f9fbec1mcpowers		return NULL;
111f9fbec1mcpowers
112f9fbec1mcpowers	group->meth = GFMethod_consGFp(irr);
113f9fbec1mcpowers	if (group->meth == NULL) {
114f9fbec1mcpowers		res = MP_MEM;
115f9fbec1mcpowers		goto CLEANUP;
116f9fbec1mcpowers	}
117f9fbec1mcpowers	MP_CHECKOK(mp_copy(curvea, &group->curvea));
118f9fbec1mcpowers	MP_CHECKOK(mp_copy(curveb, &group->curveb));
119f9fbec1mcpowers	MP_CHECKOK(mp_copy(genx, &group->genx));
120f9fbec1mcpowers	MP_CHECKOK(mp_copy(geny, &group->geny));
121f9fbec1mcpowers	MP_CHECKOK(mp_copy(order, &group->order));
122f9fbec1mcpowers	group->cofactor = cofactor;
123f9fbec1mcpowers	group->point_add = &ec_GFp_pt_add_aff;
124f9fbec1mcpowers	group->point_sub = &ec_GFp_pt_sub_aff;
125f9fbec1mcpowers	group->point_dbl = &ec_GFp_pt_dbl_aff;
126f9fbec1mcpowers	group->point_mul = &ec_GFp_pt_mul_jm_wNAF;
127f9fbec1mcpowers	group->base_point_mul = NULL;
128f9fbec1mcpowers	group->points_mul = &ec_GFp_pts_mul_jac;
129f9fbec1mcpowers	group->validate_point = &ec_GFp_validate_point;
130f9fbec1mcpowers
131f9fbec1mcpowers  CLEANUP:
132f9fbec1mcpowers	if (res != MP_OKAY) {
133f9fbec1mcpowers		ECGroup_free(group);
134f9fbec1mcpowers		return NULL;
135f9fbec1mcpowers	}
136f9fbec1mcpowers	return group;
137f9fbec1mcpowers}
138f9fbec1mcpowers
139f9fbec1mcpowers/* Construct a generic ECGroup for elliptic curves over prime fields with
140f9fbec1mcpowers * field arithmetic implemented in Montgomery coordinates. */
141f9fbec1mcpowersECGroup *
142f9fbec1mcpowersECGroup_consGFp_mont(const mp_int *irr, const mp_int *curvea,
143f9fbec1mcpowers					 const mp_int *curveb, const mp_int *genx,
144f9fbec1mcpowers					 const mp_int *geny, const mp_int *order, int cofactor)
145f9fbec1mcpowers{
146f9fbec1mcpowers	mp_err res = MP_OKAY;
147f9fbec1mcpowers	ECGroup *group = NULL;
148f9fbec1mcpowers
149f9fbec1mcpowers	group = ECGroup_new(FLAG(irr));
150f9fbec1mcpowers	if (group == NULL)
151f9fbec1mcpowers		return NULL;
152f9fbec1mcpowers
153f9fbec1mcpowers	group->meth = GFMethod_consGFp_mont(irr);
154f9fbec1mcpowers	if (group->meth == NULL) {
155f9fbec1mcpowers		res = MP_MEM;
156f9fbec1mcpowers		goto CLEANUP;
157f9fbec1mcpowers	}
158f9fbec1mcpowers	MP_CHECKOK(group->meth->
159f9fbec1mcpowers			   field_enc(curvea, &group->curvea, group->meth));
160f9fbec1mcpowers	MP_CHECKOK(group->meth->
161f9fbec1mcpowers			   field_enc(curveb, &group->curveb, group->meth));
162f9fbec1mcpowers	MP_CHECKOK(group->meth->field_enc(genx, &group->genx, group->meth));
163f9fbec1mcpowers	MP_CHECKOK(group->meth->field_enc(geny, &group->geny, group->meth));
164f9fbec1mcpowers	MP_CHECKOK(mp_copy(order, &group->order));
165f9fbec1mcpowers	group->cofactor = cofactor;
166f9fbec1mcpowers	group->point_add = &ec_GFp_pt_add_aff;
167f9fbec1mcpowers	group->point_sub = &ec_GFp_pt_sub_aff;
168f9fbec1mcpowers	group->point_dbl = &ec_GFp_pt_dbl_aff;
169f9fbec1mcpowers	group->point_mul = &ec_GFp_pt_mul_jm_wNAF;
170f9fbec1mcpowers	group->base_point_mul = NULL;
171f9fbec1mcpowers	group->points_mul = &ec_GFp_pts_mul_jac;
172f9fbec1mcpowers	group->validate_point = &ec_GFp_validate_point;
173f9fbec1mcpowers
174f9fbec1mcpowers  CLEANUP:
175f9fbec1mcpowers	if (res != MP_OKAY) {
176f9fbec1mcpowers		ECGroup_free(group);
177f9fbec1mcpowers		return NULL;
178f9fbec1mcpowers	}
179f9fbec1mcpowers	return group;
180f9fbec1mcpowers}
181f9fbec1mcpowers
182f9fbec1mcpowers#ifdef NSS_ECC_MORE_THAN_SUITE_B
183f9fbec1mcpowers/* Construct a generic ECGroup for elliptic curves over binary polynomial
184f9fbec1mcpowers * fields. */
185f9fbec1mcpowersECGroup *
186f9fbec1mcpowersECGroup_consGF2m(const mp_int *irr, const unsigned int irr_arr[5],
187f9fbec1mcpowers				 const mp_int *curvea, const mp_int *curveb,
188f9fbec1mcpowers				 const mp_int *genx, const mp_int *geny,
189f9fbec1mcpowers				 const mp_int *order, int cofactor)
190f9fbec1mcpowers{
191f9fbec1mcpowers	mp_err res = MP_OKAY;
192f9fbec1mcpowers	ECGroup *group = NULL;
193f9fbec1mcpowers
194f9fbec1mcpowers	group = ECGroup_new(FLAG(irr));
195f9fbec1mcpowers	if (group == NULL)
196f9fbec1mcpowers		return NULL;
197f9fbec1mcpowers
198f9fbec1mcpowers	group->meth = GFMethod_consGF2m(irr, irr_arr);
199f9fbec1mcpowers	if (group->meth == NULL) {
200f9fbec1mcpowers		res = MP_MEM;
201f9fbec1mcpowers		goto CLEANUP;
202f9fbec1mcpowers	}
203f9fbec1mcpowers	MP_CHECKOK(mp_copy(curvea, &group->curvea));
204f9fbec1mcpowers	MP_CHECKOK(mp_copy(curveb, &group->curveb));
205f9fbec1mcpowers	MP_CHECKOK(mp_copy(genx, &group->genx));
206f9fbec1mcpowers	MP_CHECKOK(mp_copy(geny, &group->geny));
207f9fbec1mcpowers	MP_CHECKOK(mp_copy(order, &group->order));
208f9fbec1mcpowers	group->cofactor = cofactor;
209f9fbec1mcpowers	group->point_add = &ec_GF2m_pt_add_aff;
210f9fbec1mcpowers	group->point_sub = &ec_GF2m_pt_sub_aff;
211f9fbec1mcpowers	group->point_dbl = &ec_GF2m_pt_dbl_aff;
212f9fbec1mcpowers	group->point_mul = &ec_GF2m_pt_mul_mont;
213f9fbec1mcpowers	group->base_point_mul = NULL;
214f9fbec1mcpowers	group->points_mul = &ec_pts_mul_basic;
215f9fbec1mcpowers	group->validate_point = &ec_GF2m_validate_point;
216f9fbec1mcpowers
217f9fbec1mcpowers  CLEANUP:
218f9fbec1mcpowers	if (res != MP_OKAY) {
219f9fbec1mcpowers		ECGroup_free(group);
220f9fbec1mcpowers		return NULL;
221f9fbec1mcpowers	}
222f9fbec1mcpowers	return group;
223f9fbec1mcpowers}
224f9fbec1mcpowers#endif
225f9fbec1mcpowers
226f9fbec1mcpowers/* Construct ECGroup from hex parameters and name, if any. Called by
227f9fbec1mcpowers * ECGroup_fromHex and ECGroup_fromName. */
228f9fbec1mcpowersECGroup *
229f9fbec1mcpowersecgroup_fromNameAndHex(const ECCurveName name,
230f9fbec1mcpowers				   const ECCurveParams * params, int kmflag)
231f9fbec1mcpowers{
232f9fbec1mcpowers	mp_int irr, curvea, curveb, genx, geny, order;
233f9fbec1mcpowers	int bits;
234f9fbec1mcpowers	ECGroup *group = NULL;
235f9fbec1mcpowers	mp_err res = MP_OKAY;
236f9fbec1mcpowers
237f9fbec1mcpowers	/* initialize values */
238f9fbec1mcpowers	MP_DIGITS(&irr) = 0;
239f9fbec1mcpowers	MP_DIGITS(&curvea) = 0;
240f9fbec1mcpowers	MP_DIGITS(&curveb) = 0;
241f9fbec1mcpowers	MP_DIGITS(&genx) = 0;
242f9fbec1mcpowers	MP_DIGITS(&geny) = 0;
243f9fbec1mcpowers	MP_DIGITS(&order) = 0;
244f9fbec1mcpowers	MP_CHECKOK(mp_init(&irr, kmflag));
245f9fbec1mcpowers	MP_CHECKOK(mp_init(&curvea, kmflag));
246f9fbec1mcpowers	MP_CHECKOK(mp_init(&curveb, kmflag));
247f9fbec1mcpowers	MP_CHECKOK(mp_init(&genx, kmflag));
248f9fbec1mcpowers	MP_CHECKOK(mp_init(&geny, kmflag));
249f9fbec1mcpowers	MP_CHECKOK(mp_init(&order, kmflag));
250f9fbec1mcpowers	MP_CHECKOK(mp_read_radix(&irr, params->irr, 16));
251f9fbec1mcpowers	MP_CHECKOK(mp_read_radix(&curvea, params->curvea, 16));
252f9fbec1mcpowers	MP_CHECKOK(mp_read_radix(&curveb, params->curveb, 16));
253f9fbec1mcpowers	MP_CHECKOK(mp_read_radix(&genx, params->genx, 16));
254f9fbec1mcpowers	MP_CHECKOK(mp_read_radix(&geny, params->geny, 16));
255f9fbec1mcpowers	MP_CHECKOK(mp_read_radix(&order, params->order, 16));
256f9fbec1mcpowers
257f9fbec1mcpowers	/* determine number of bits */
258f9fbec1mcpowers	bits = mpl_significant_bits(&irr) - 1;
259f9fbec1mcpowers	if (bits < MP_OKAY) {
260f9fbec1mcpowers		res = bits;
261f9fbec1mcpowers		goto CLEANUP;
262f9fbec1mcpowers	}
263f9fbec1mcpowers
264f9fbec1mcpowers	/* determine which optimizations (if any) to use */
265f9fbec1mcpowers	if (params->field == ECField_GFp) {
266f9fbec1mcpowers#ifdef NSS_ECC_MORE_THAN_SUITE_B
267f9fbec1mcpowers	    switch (name) {
268f9fbec1mcpowers#ifdef ECL_USE_FP
269f9fbec1mcpowers		case ECCurve_SECG_PRIME_160R1:
270f9fbec1mcpowers			group =
271f9fbec1mcpowers				ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
272f9fbec1mcpowers								&order, params->cofactor);
273f9fbec1mcpowers			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
274f9fbec1mcpowers			MP_CHECKOK(ec_group_set_secp160r1_fp(group));
275f9fbec1mcpowers			break;
276f9fbec1mcpowers#endif
277f9fbec1mcpowers		case ECCurve_SECG_PRIME_192R1:
278f9fbec1mcpowers#ifdef ECL_USE_FP
279f9fbec1mcpowers			group =
280f9fbec1mcpowers				ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
281f9fbec1mcpowers								&order, params->cofactor);
282f9fbec1mcpowers			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
283f9fbec1mcpowers			MP_CHECKOK(ec_group_set_nistp192_fp(group));
284f9fbec1mcpowers#else
285f9fbec1mcpowers			group =
286f9fbec1mcpowers				ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
287f9fbec1mcpowers								&order, params->cofactor);
288f9fbec1mcpowers			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
289f9fbec1mcpowers			MP_CHECKOK(ec_group_set_gfp192(group, name));
290f9fbec1mcpowers#endif
291f9fbec1mcpowers			break;
292f9fbec1mcpowers		case ECCurve_SECG_PRIME_224R1:
293f9fbec1mcpowers#ifdef ECL_USE_FP
294f9fbec1mcpowers			group =
295f9fbec1mcpowers				ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
296f9fbec1mcpowers								&order, params->cofactor);
297f9fbec1mcpowers			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
298f9fbec1mcpowers			MP_CHECKOK(ec_group_set_nistp224_fp(group));
299f9fbec1mcpowers#else
300f9fbec1mcpowers			group =
301f9fbec1mcpowers				ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
302f9fbec1mcpowers								&order, params->cofactor);
303f9fbec1mcpowers			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
304f9fbec1mcpowers			MP_CHECKOK(ec_group_set_gfp224(group, name));
305f9fbec1mcpowers#endif
306f9fbec1mcpowers			break;
307f9fbec1mcpowers		case ECCurve_SECG_PRIME_256R1:
308f9fbec1mcpowers			group =
309f9fbec1mcpowers				ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
310f9fbec1mcpowers								&order, params->cofactor);
311f9fbec1mcpowers			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
312f9fbec1mcpowers			MP_CHECKOK(ec_group_set_gfp256(group, name));
313f9fbec1mcpowers			break;
314f9fbec1mcpowers		case ECCurve_SECG_PRIME_521R1:
315f9fbec1mcpowers			group =
316f9fbec1mcpowers				ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny,
317f9fbec1mcpowers								&order, params->cofactor);
318f9fbec1mcpowers			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
319f9fbec1mcpowers			MP_CHECKOK(ec_group_set_gfp521(group, name));
320f9fbec1mcpowers			break;
321f9fbec1mcpowers		default:
322f9fbec1mcpowers			/* use generic arithmetic */
323f9fbec1mcpowers#endif
324f9fbec1mcpowers			group =
325f9fbec1mcpowers				ECGroup_consGFp_mont(&irr, &curvea, &curveb, &genx, &geny,
326f9fbec1mcpowers									 &order, params->cofactor);
327f9fbec1mcpowers			if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
328f9fbec1mcpowers#ifdef NSS_ECC_MORE_THAN_SUITE_B
329f9fbec1mcpowers		}
330f9fbec1mcpowers	} else if (params->field == ECField_GF2m) {
331f9fbec1mcpowers		group = ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx, &geny, &order, params->cofactor);
332f9fbec1mcpowers		if (group == NULL) { res = MP_UNDEF; goto CLEANUP; }
333f9fbec1mcpowers		if ((name == ECCurve_NIST_K163) ||
334f9fbec1mcpowers		    (name == ECCurve_NIST_B163) ||
335f9fbec1mcpowers		    (name == ECCurve_SECG_CHAR2_163R1)) {
336f9fbec1mcpowers			MP_CHECKOK(ec_group_set_gf2m163(group, name));
337f9fbec1mcpowers		} else if ((name == ECCurve_SECG_CHAR2_193R1) ||
338f9fbec1mcpowers		           (name == ECCurve_SECG_CHAR2_193R2)) {
339f9fbec1mcpowers			MP_CHECKOK(ec_group_set_gf2m193(group, name));
340f9fbec1mcpowers		} else if ((name == ECCurve_NIST_K233) ||
341f9fbec1mcpowers		           (name == ECCurve_NIST_B233)) {
342f9fbec1mcpowers			MP_CHECKOK(ec_group_set_gf2m233(group, name));
343f9fbec1mcpowers		}
344f9fbec1mcpowers#endif
345f9fbec1mcpowers	} else {
346f9fbec1mcpowers		res = MP_UNDEF;
347f9fbec1mcpowers		goto CLEANUP;
348f9fbec1mcpowers	}
349f9fbec1mcpowers
350f9fbec1mcpowers	/* set name, if any */
351f9fbec1mcpowers	if ((group != NULL) && (params->text != NULL)) {
352f9fbec1mcpowers#ifdef _KERNEL
353f9fbec1mcpowers		int n = strlen(params->text) + 1;
354f9fbec1mcpowers
355f9fbec1mcpowers		group->text = kmem_alloc(n, kmflag);
356f9fbec1mcpowers		if (group->text == NULL) {
357f9fbec1mcpowers			res = MP_MEM;
358f9fbec1mcpowers			goto CLEANUP;
359f9fbec1mcpowers		}
360f9fbec1mcpowers		bcopy(params->text, group->text, n);
361f9fbec1mcpowers		group->text_len = n;
362f9fbec1mcpowers#else
363f9fbec1mcpowers		group->text = strdup(params->text);
364f9fbec1mcpowers		if (group->text == NULL) {
365f9fbec1mcpowers			res = MP_MEM;
366f9fbec1mcpowers		}
367f9fbec1mcpowers#endif
368f9fbec1mcpowers	}
369f9fbec1mcpowers
370f9fbec1mcpowers  CLEANUP:
371f9fbec1mcpowers	mp_clear(&irr);
372f9fbec1mcpowers	mp_clear(&curvea);
373f9fbec1mcpowers	mp_clear(&curveb);
374f9fbec1mcpowers	mp_clear(&genx);
375f9fbec1mcpowers	mp_clear(&geny);
376f9fbec1mcpowers	mp_clear(&order);
377f9fbec1mcpowers	if (res != MP_OKAY) {
378f9fbec1mcpowers		ECGroup_free(group);
379f9fbec1mcpowers		return NULL;
380f9fbec1mcpowers	}
381f9fbec1mcpowers	return group;
382f9fbec1mcpowers}
383f9fbec1mcpowers
384f9fbec1mcpowers/* Construct ECGroup from hexadecimal representations of parameters. */
385f9fbec1mcpowersECGroup *
386f9fbec1mcpowersECGroup_fromHex(const ECCurveParams * params, int kmflag)
387f9fbec1mcpowers{
388f9fbec1mcpowers	return ecgroup_fromNameAndHex(ECCurve_noName, params, kmflag);
389f9fbec1mcpowers}
390f9fbec1mcpowers
391f9fbec1mcpowers/* Construct ECGroup from named parameters. */
392f9fbec1mcpowersECGroup *
393f9fbec1mcpowersECGroup_fromName(const ECCurveName name, int kmflag)
394f9fbec1mcpowers{
395f9fbec1mcpowers	ECGroup *group = NULL;
396f9fbec1mcpowers	ECCurveParams *params = NULL;
397f9fbec1mcpowers	mp_err res = MP_OKAY;
398f9fbec1mcpowers
399f9fbec1mcpowers	params = EC_GetNamedCurveParams(name, kmflag);
400f9fbec1mcpowers	if (params == NULL) {
401f9fbec1mcpowers		res = MP_UNDEF;
402f9fbec1mcpowers		goto CLEANUP;
403f9fbec1mcpowers	}
404f9fbec1mcpowers
405f9fbec1mcpowers	/* construct actual group */
406f9fbec1mcpowers	group = ecgroup_fromNameAndHex(name, params, kmflag);
407f9fbec1mcpowers	if (group == NULL) {
408f9fbec1mcpowers		res = MP_UNDEF;
409f9fbec1mcpowers		goto CLEANUP;
410f9fbec1mcpowers	}
411f9fbec1mcpowers
412f9fbec1mcpowers  CLEANUP:
413f9fbec1mcpowers	EC_FreeCurveParams(params);
414f9fbec1mcpowers	if (res != MP_OKAY) {
415f9fbec1mcpowers		ECGroup_free(group);
416f9fbec1mcpowers		return NULL;
417f9fbec1mcpowers	}
418f9fbec1mcpowers	return group;
419f9fbec1mcpowers}
420f9fbec1mcpowers
421f9fbec1mcpowers/* Validates an EC public key as described in Section 5.2.2 of X9.62. */
422f9fbec1mcpowersmp_err ECPoint_validate(const ECGroup *group, const mp_int *px, const
423f9fbec1mcpowers					mp_int *py)
424f9fbec1mcpowers{
425f9fbec1mcpowers    /* 1: Verify that publicValue is not the point at infinity */
426f9fbec1mcpowers    /* 2: Verify that the coordinates of publicValue are elements
427f9fbec1mcpowers     *    of the field.
428f9fbec1mcpowers     */
429f9fbec1mcpowers    /* 3: Verify that publicValue is on the curve. */
430f9fbec1mcpowers    /* 4: Verify that the order of the curve times the publicValue
431f9fbec1mcpowers     *    is the point at infinity.
432f9fbec1mcpowers     */
433f9fbec1mcpowers	return group->validate_point(px, py, group);
434f9fbec1mcpowers}
435f9fbec1mcpowers
436f9fbec1mcpowers/* Free the memory allocated (if any) to an ECGroup object. */
437f9fbec1mcpowersvoid
438f9fbec1mcpowersECGroup_free(ECGroup *group)
439f9fbec1mcpowers{
440f9fbec1mcpowers	if (group == NULL)
441f9fbec1mcpowers		return;
442f9fbec1mcpowers	GFMethod_free(group->meth);
443f9fbec1mcpowers	if (group->constructed == MP_NO)
444f9fbec1mcpowers		return;
445f9fbec1mcpowers	mp_clear(&group->curvea);
446f9fbec1mcpowers	mp_clear(&group->curveb);
447f9fbec1mcpowers	mp_clear(&group->genx);
448f9fbec1mcpowers	mp_clear(&group->geny);
449f9fbec1mcpowers	mp_clear(&group->order);
450f9fbec1mcpowers	if (group->text != NULL)
451f9fbec1mcpowers#ifdef _KERNEL
452f9fbec1mcpowers		kmem_free(group->text, group->text_len);
453f9fbec1mcpowers#else
454f9fbec1mcpowers		free(group->text);
455f9fbec1mcpowers#endif
456f9fbec1mcpowers	if (group->extra_free != NULL)
457f9fbec1mcpowers		group->extra_free(group);
458f9fbec1mcpowers#ifdef _KERNEL
459f9fbec1mcpowers	kmem_free(group, sizeof (ECGroup));
460f9fbec1mcpowers#else
461f9fbec1mcpowers	free(group);
462f9fbec1mcpowers#endif
463f9fbec1mcpowers}
464