2 * ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is the elliptic curve math library.
17 * The Initial Developer of the Original Code is
18 * Sun Microsystems, Inc.
19 * Portions created by the Initial Developer are Copyright (C) 2003
20 * the Initial Developer. All Rights Reserved.
23 * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
40 * Use is subject to license terms.
42 * Sun elects to use this software under the MPL license.
45 #pragma ident "%Z%%M% %I% %E% SMI"
58 /* Allocate memory for a new ECGroup object. */
60 ECGroup_new(int kmflag
)
65 group
= (ECGroup
*) kmem_alloc(sizeof(ECGroup
), kmflag
);
67 group
= (ECGroup
*) malloc(sizeof(ECGroup
));
71 group
->constructed
= MP_YES
;
74 MP_DIGITS(&group
->curvea
) = 0;
75 MP_DIGITS(&group
->curveb
) = 0;
76 MP_DIGITS(&group
->genx
) = 0;
77 MP_DIGITS(&group
->geny
) = 0;
78 MP_DIGITS(&group
->order
) = 0;
79 group
->base_point_mul
= NULL
;
80 group
->points_mul
= NULL
;
81 group
->validate_point
= NULL
;
84 group
->extra_free
= NULL
;
85 MP_CHECKOK(mp_init(&group
->curvea
, kmflag
));
86 MP_CHECKOK(mp_init(&group
->curveb
, kmflag
));
87 MP_CHECKOK(mp_init(&group
->genx
, kmflag
));
88 MP_CHECKOK(mp_init(&group
->geny
, kmflag
));
89 MP_CHECKOK(mp_init(&group
->order
, kmflag
));
99 /* Construct a generic ECGroup for elliptic curves over prime fields. */
101 ECGroup_consGFp(const mp_int
*irr
, const mp_int
*curvea
,
102 const mp_int
*curveb
, const mp_int
*genx
,
103 const mp_int
*geny
, const mp_int
*order
, int cofactor
)
105 mp_err res
= MP_OKAY
;
106 ECGroup
*group
= NULL
;
108 group
= ECGroup_new(FLAG(irr
));
112 group
->meth
= GFMethod_consGFp(irr
);
113 if (group
->meth
== NULL
) {
117 MP_CHECKOK(mp_copy(curvea
, &group
->curvea
));
118 MP_CHECKOK(mp_copy(curveb
, &group
->curveb
));
119 MP_CHECKOK(mp_copy(genx
, &group
->genx
));
120 MP_CHECKOK(mp_copy(geny
, &group
->geny
));
121 MP_CHECKOK(mp_copy(order
, &group
->order
));
122 group
->cofactor
= cofactor
;
123 group
->point_add
= &ec_GFp_pt_add_aff
;
124 group
->point_sub
= &ec_GFp_pt_sub_aff
;
125 group
->point_dbl
= &ec_GFp_pt_dbl_aff
;
126 group
->point_mul
= &ec_GFp_pt_mul_jm_wNAF
;
127 group
->base_point_mul
= NULL
;
128 group
->points_mul
= &ec_GFp_pts_mul_jac
;
129 group
->validate_point
= &ec_GFp_validate_point
;
132 if (res
!= MP_OKAY
) {
139 /* Construct a generic ECGroup for elliptic curves over prime fields with
140 * field arithmetic implemented in Montgomery coordinates. */
142 ECGroup_consGFp_mont(const mp_int
*irr
, const mp_int
*curvea
,
143 const mp_int
*curveb
, const mp_int
*genx
,
144 const mp_int
*geny
, const mp_int
*order
, int cofactor
)
146 mp_err res
= MP_OKAY
;
147 ECGroup
*group
= NULL
;
149 group
= ECGroup_new(FLAG(irr
));
153 group
->meth
= GFMethod_consGFp_mont(irr
);
154 if (group
->meth
== NULL
) {
158 MP_CHECKOK(group
->meth
->
159 field_enc(curvea
, &group
->curvea
, group
->meth
));
160 MP_CHECKOK(group
->meth
->
161 field_enc(curveb
, &group
->curveb
, group
->meth
));
162 MP_CHECKOK(group
->meth
->field_enc(genx
, &group
->genx
, group
->meth
));
163 MP_CHECKOK(group
->meth
->field_enc(geny
, &group
->geny
, group
->meth
));
164 MP_CHECKOK(mp_copy(order
, &group
->order
));
165 group
->cofactor
= cofactor
;
166 group
->point_add
= &ec_GFp_pt_add_aff
;
167 group
->point_sub
= &ec_GFp_pt_sub_aff
;
168 group
->point_dbl
= &ec_GFp_pt_dbl_aff
;
169 group
->point_mul
= &ec_GFp_pt_mul_jm_wNAF
;
170 group
->base_point_mul
= NULL
;
171 group
->points_mul
= &ec_GFp_pts_mul_jac
;
172 group
->validate_point
= &ec_GFp_validate_point
;
175 if (res
!= MP_OKAY
) {
182 #ifdef NSS_ECC_MORE_THAN_SUITE_B
183 /* Construct a generic ECGroup for elliptic curves over binary polynomial
186 ECGroup_consGF2m(const mp_int
*irr
, const unsigned int irr_arr
[5],
187 const mp_int
*curvea
, const mp_int
*curveb
,
188 const mp_int
*genx
, const mp_int
*geny
,
189 const mp_int
*order
, int cofactor
)
191 mp_err res
= MP_OKAY
;
192 ECGroup
*group
= NULL
;
194 group
= ECGroup_new(FLAG(irr
));
198 group
->meth
= GFMethod_consGF2m(irr
, irr_arr
);
199 if (group
->meth
== NULL
) {
203 MP_CHECKOK(mp_copy(curvea
, &group
->curvea
));
204 MP_CHECKOK(mp_copy(curveb
, &group
->curveb
));
205 MP_CHECKOK(mp_copy(genx
, &group
->genx
));
206 MP_CHECKOK(mp_copy(geny
, &group
->geny
));
207 MP_CHECKOK(mp_copy(order
, &group
->order
));
208 group
->cofactor
= cofactor
;
209 group
->point_add
= &ec_GF2m_pt_add_aff
;
210 group
->point_sub
= &ec_GF2m_pt_sub_aff
;
211 group
->point_dbl
= &ec_GF2m_pt_dbl_aff
;
212 group
->point_mul
= &ec_GF2m_pt_mul_mont
;
213 group
->base_point_mul
= NULL
;
214 group
->points_mul
= &ec_pts_mul_basic
;
215 group
->validate_point
= &ec_GF2m_validate_point
;
218 if (res
!= MP_OKAY
) {
226 /* Construct ECGroup from hex parameters and name, if any. Called by
227 * ECGroup_fromHex and ECGroup_fromName. */
229 ecgroup_fromNameAndHex(const ECCurveName name
,
230 const ECCurveParams
* params
, int kmflag
)
232 mp_int irr
, curvea
, curveb
, genx
, geny
, order
;
234 ECGroup
*group
= NULL
;
235 mp_err res
= MP_OKAY
;
237 /* initialize values */
239 MP_DIGITS(&curvea
) = 0;
240 MP_DIGITS(&curveb
) = 0;
241 MP_DIGITS(&genx
) = 0;
242 MP_DIGITS(&geny
) = 0;
243 MP_DIGITS(&order
) = 0;
244 MP_CHECKOK(mp_init(&irr
, kmflag
));
245 MP_CHECKOK(mp_init(&curvea
, kmflag
));
246 MP_CHECKOK(mp_init(&curveb
, kmflag
));
247 MP_CHECKOK(mp_init(&genx
, kmflag
));
248 MP_CHECKOK(mp_init(&geny
, kmflag
));
249 MP_CHECKOK(mp_init(&order
, kmflag
));
250 MP_CHECKOK(mp_read_radix(&irr
, params
->irr
, 16));
251 MP_CHECKOK(mp_read_radix(&curvea
, params
->curvea
, 16));
252 MP_CHECKOK(mp_read_radix(&curveb
, params
->curveb
, 16));
253 MP_CHECKOK(mp_read_radix(&genx
, params
->genx
, 16));
254 MP_CHECKOK(mp_read_radix(&geny
, params
->geny
, 16));
255 MP_CHECKOK(mp_read_radix(&order
, params
->order
, 16));
257 /* determine number of bits */
258 bits
= mpl_significant_bits(&irr
) - 1;
259 if (bits
< MP_OKAY
) {
264 /* determine which optimizations (if any) to use */
265 if (params
->field
== ECField_GFp
) {
266 #ifdef NSS_ECC_MORE_THAN_SUITE_B
269 case ECCurve_SECG_PRIME_160R1
:
271 ECGroup_consGFp(&irr
, &curvea
, &curveb
, &genx
, &geny
,
272 &order
, params
->cofactor
);
273 if (group
== NULL
) { res
= MP_UNDEF
; goto CLEANUP
; }
274 MP_CHECKOK(ec_group_set_secp160r1_fp(group
));
277 case ECCurve_SECG_PRIME_192R1
:
280 ECGroup_consGFp(&irr
, &curvea
, &curveb
, &genx
, &geny
,
281 &order
, params
->cofactor
);
282 if (group
== NULL
) { res
= MP_UNDEF
; goto CLEANUP
; }
283 MP_CHECKOK(ec_group_set_nistp192_fp(group
));
286 ECGroup_consGFp(&irr
, &curvea
, &curveb
, &genx
, &geny
,
287 &order
, params
->cofactor
);
288 if (group
== NULL
) { res
= MP_UNDEF
; goto CLEANUP
; }
289 MP_CHECKOK(ec_group_set_gfp192(group
, name
));
292 case ECCurve_SECG_PRIME_224R1
:
295 ECGroup_consGFp(&irr
, &curvea
, &curveb
, &genx
, &geny
,
296 &order
, params
->cofactor
);
297 if (group
== NULL
) { res
= MP_UNDEF
; goto CLEANUP
; }
298 MP_CHECKOK(ec_group_set_nistp224_fp(group
));
301 ECGroup_consGFp(&irr
, &curvea
, &curveb
, &genx
, &geny
,
302 &order
, params
->cofactor
);
303 if (group
== NULL
) { res
= MP_UNDEF
; goto CLEANUP
; }
304 MP_CHECKOK(ec_group_set_gfp224(group
, name
));
307 case ECCurve_SECG_PRIME_256R1
:
309 ECGroup_consGFp(&irr
, &curvea
, &curveb
, &genx
, &geny
,
310 &order
, params
->cofactor
);
311 if (group
== NULL
) { res
= MP_UNDEF
; goto CLEANUP
; }
312 MP_CHECKOK(ec_group_set_gfp256(group
, name
));
314 case ECCurve_SECG_PRIME_521R1
:
316 ECGroup_consGFp(&irr
, &curvea
, &curveb
, &genx
, &geny
,
317 &order
, params
->cofactor
);
318 if (group
== NULL
) { res
= MP_UNDEF
; goto CLEANUP
; }
319 MP_CHECKOK(ec_group_set_gfp521(group
, name
));
322 /* use generic arithmetic */
325 ECGroup_consGFp_mont(&irr
, &curvea
, &curveb
, &genx
, &geny
,
326 &order
, params
->cofactor
);
327 if (group
== NULL
) { res
= MP_UNDEF
; goto CLEANUP
; }
328 #ifdef NSS_ECC_MORE_THAN_SUITE_B
330 } else if (params
->field
== ECField_GF2m
) {
331 group
= ECGroup_consGF2m(&irr
, NULL
, &curvea
, &curveb
, &genx
, &geny
, &order
, params
->cofactor
);
332 if (group
== NULL
) { res
= MP_UNDEF
; goto CLEANUP
; }
333 if ((name
== ECCurve_NIST_K163
) ||
334 (name
== ECCurve_NIST_B163
) ||
335 (name
== ECCurve_SECG_CHAR2_163R1
)) {
336 MP_CHECKOK(ec_group_set_gf2m163(group
, name
));
337 } else if ((name
== ECCurve_SECG_CHAR2_193R1
) ||
338 (name
== ECCurve_SECG_CHAR2_193R2
)) {
339 MP_CHECKOK(ec_group_set_gf2m193(group
, name
));
340 } else if ((name
== ECCurve_NIST_K233
) ||
341 (name
== ECCurve_NIST_B233
)) {
342 MP_CHECKOK(ec_group_set_gf2m233(group
, name
));
350 /* set name, if any */
351 if ((group
!= NULL
) && (params
->text
!= NULL
)) {
353 int n
= strlen(params
->text
) + 1;
355 group
->text
= kmem_alloc(n
, kmflag
);
356 if (group
->text
== NULL
) {
360 bcopy(params
->text
, group
->text
, n
);
363 group
->text
= strdup(params
->text
);
364 if (group
->text
== NULL
) {
377 if (res
!= MP_OKAY
) {
384 /* Construct ECGroup from hexadecimal representations of parameters. */
386 ECGroup_fromHex(const ECCurveParams
* params
, int kmflag
)
388 return ecgroup_fromNameAndHex(ECCurve_noName
, params
, kmflag
);
391 /* Construct ECGroup from named parameters. */
393 ECGroup_fromName(const ECCurveName name
, int kmflag
)
395 ECGroup
*group
= NULL
;
396 ECCurveParams
*params
= NULL
;
397 mp_err res
= MP_OKAY
;
399 params
= EC_GetNamedCurveParams(name
, kmflag
);
400 if (params
== NULL
) {
405 /* construct actual group */
406 group
= ecgroup_fromNameAndHex(name
, params
, kmflag
);
413 EC_FreeCurveParams(params
);
414 if (res
!= MP_OKAY
) {
421 /* Validates an EC public key as described in Section 5.2.2 of X9.62. */
422 mp_err
ECPoint_validate(const ECGroup
*group
, const mp_int
*px
, const
425 /* 1: Verify that publicValue is not the point at infinity */
426 /* 2: Verify that the coordinates of publicValue are elements
429 /* 3: Verify that publicValue is on the curve. */
430 /* 4: Verify that the order of the curve times the publicValue
431 * is the point at infinity.
433 return group
->validate_point(px
, py
, group
);
436 /* Free the memory allocated (if any) to an ECGroup object. */
438 ECGroup_free(ECGroup
*group
)
442 GFMethod_free(group
->meth
);
443 if (group
->constructed
== MP_NO
)
445 mp_clear(&group
->curvea
);
446 mp_clear(&group
->curveb
);
447 mp_clear(&group
->genx
);
448 mp_clear(&group
->geny
);
449 mp_clear(&group
->order
);
450 if (group
->text
!= NULL
)
452 kmem_free(group
->text
, group
->text_len
);
456 if (group
->extra_free
!= NULL
)
457 group
->extra_free(group
);
459 kmem_free(group
, sizeof (ECGroup
));