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 for prime field curves.
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"
55 #define ECP192_DIGITS ECL_CURVE_DIGITS(192)
57 /* Fast modular reduction for p192 = 2^192 - 2^64 - 1. a can be r. Uses
58 * algorithm 7 from Brown, Hankerson, Lopez, Menezes. Software
59 * Implementation of the NIST Elliptic Curves over Prime Fields. */
61 ec_GFp_nistp192_mod(const mp_int
*a
, mp_int
*r
, const GFMethod
*meth
)
64 mp_size a_used
= MP_USED(a
);
69 #ifdef ECL_THIRTY_TWO_BIT
70 mp_digit a5a
= 0, a5b
= 0, a4a
= 0, a4b
= 0, a3a
= 0, a3b
= 0;
71 mp_digit r0a
, r0b
, r1a
, r1b
, r2a
, r2b
;
73 mp_digit a5
= 0, a4
= 0, a3
= 0;
77 /* reduction not needed if a is not larger than field size */
78 if (a_used
< ECP192_DIGITS
) {
85 /* for polynomials larger than twice the field size, use regular
87 if (a_used
> ECP192_DIGITS
*2) {
88 MP_CHECKOK(mp_mod(a
, &meth
->irr
, r
));
90 /* copy out upper words of a */
92 #ifdef ECL_THIRTY_TWO_BIT
94 /* in all the math below,
95 * nXb is most signifiant, nXa is least significant */
98 a5b
= MP_DIGIT(a
, 11);
100 a5a
= MP_DIGIT(a
, 10);
102 a4b
= MP_DIGIT(a
, 9);
104 a4a
= MP_DIGIT(a
, 8);
106 a3b
= MP_DIGIT(a
, 7);
108 a3a
= MP_DIGIT(a
, 6);
114 r1b
= MP_DIGIT(a
, 3);
115 r1a
= MP_DIGIT(a
, 2);
116 r0b
= MP_DIGIT(a
, 1);
117 r0a
= MP_DIGIT(a
, 0);
119 /* implement r = (a2,a1,a0)+(a5,a5,a5)+(a4,a4,0)+(0,a3,a3) */
120 MP_ADD_CARRY(r0a
, a3a
, r0a
, 0, carry
);
121 MP_ADD_CARRY(r0b
, a3b
, r0b
, carry
, carry
);
122 MP_ADD_CARRY(r1a
, a3a
, r1a
, carry
, carry
);
123 MP_ADD_CARRY(r1b
, a3b
, r1b
, carry
, carry
);
124 MP_ADD_CARRY(r2a
, a4a
, r2a
, carry
, carry
);
125 MP_ADD_CARRY(r2b
, a4b
, r2b
, carry
, carry
);
126 r3
= carry
; carry
= 0;
127 MP_ADD_CARRY(r0a
, a5a
, r0a
, 0, carry
);
128 MP_ADD_CARRY(r0b
, a5b
, r0b
, carry
, carry
);
129 MP_ADD_CARRY(r1a
, a5a
, r1a
, carry
, carry
);
130 MP_ADD_CARRY(r1b
, a5b
, r1b
, carry
, carry
);
131 MP_ADD_CARRY(r2a
, a5a
, r2a
, carry
, carry
);
132 MP_ADD_CARRY(r2b
, a5b
, r2b
, carry
, carry
);
134 MP_ADD_CARRY(r1a
, a4a
, r1a
, 0, carry
);
135 MP_ADD_CARRY(r1b
, a4b
, r1b
, carry
, carry
);
136 MP_ADD_CARRY(r2a
, 0, r2a
, carry
, carry
);
137 MP_ADD_CARRY(r2b
, 0, r2b
, carry
, carry
);
140 /* reduce out the carry */
142 MP_ADD_CARRY(r0a
, r3
, r0a
, 0, carry
);
143 MP_ADD_CARRY(r0b
, 0, r0b
, carry
, carry
);
144 MP_ADD_CARRY(r1a
, r3
, r1a
, carry
, carry
);
145 MP_ADD_CARRY(r1b
, 0, r1b
, carry
, carry
);
146 MP_ADD_CARRY(r2a
, 0, r2a
, carry
, carry
);
147 MP_ADD_CARRY(r2b
, 0, r2b
, carry
, carry
);
151 /* check for final reduction */
153 * our field is 0xffffffffffffffff, 0xfffffffffffffffe,
154 * 0xffffffffffffffff. That means we can only be over and need
156 * if r2 == 0xffffffffffffffffff (same as r2+1 == 0)
158 * r1 == 0xffffffffffffffffff or
159 * r1 == 0xfffffffffffffffffe and r0 = 0xfffffffffffffffff
160 * In all cases, we subtract the field (or add the 2's
161 * complement value (1,1,0)). (r0, r1, r2)
163 if (((r2b
== 0xffffffff) && (r2a
== 0xffffffff)
164 && (r1b
== 0xffffffff) ) &&
165 ((r1a
== 0xffffffff) ||
166 (r1a
== 0xfffffffe) && (r0a
== 0xffffffff) &&
167 (r0b
== 0xffffffff)) ) {
168 /* do a quick subtract */
169 MP_ADD_CARRY(r0a
, 1, r0a
, 0, carry
);
171 r1a
= r1b
= r2a
= r2b
= 0;
174 /* set the lower words of r */
176 MP_CHECKOK(s_mp_pad(r
, 6));
178 MP_DIGIT(r
, 5) = r2b
;
179 MP_DIGIT(r
, 4) = r2a
;
180 MP_DIGIT(r
, 3) = r1b
;
181 MP_DIGIT(r
, 2) = r1a
;
182 MP_DIGIT(r
, 1) = r0b
;
183 MP_DIGIT(r
, 0) = r0a
;
199 /* implement r = (a2,a1,a0)+(a5,a5,a5)+(a4,a4,0)+(0,a3,a3) */
200 #ifndef MPI_AMD64_ADD
201 MP_ADD_CARRY(r0
, a3
, r0
, 0, carry
);
202 MP_ADD_CARRY(r1
, a3
, r1
, carry
, carry
);
203 MP_ADD_CARRY(r2
, a4
, r2
, carry
, carry
);
205 MP_ADD_CARRY(r0
, a5
, r0
, 0, carry
);
206 MP_ADD_CARRY(r1
, a5
, r1
, carry
, carry
);
207 MP_ADD_CARRY(r2
, a5
, r2
, carry
, carry
);
209 MP_ADD_CARRY(r1
, a4
, r1
, 0, carry
);
210 MP_ADD_CARRY(r2
, 0, r2
, carry
, carry
);
218 /* set the lower words of r */
232 : "=r"(r0
), "=r"(r1
), "=r"(r2
), "=r"(r3
), "=r"(a3
),
234 : "0" (r0
), "1" (r1
), "2" (r2
), "3" (r3
),
235 "4" (a3
), "5" (a4
), "6"(a5
)
239 /* reduce out the carry */
241 #ifndef MPI_AMD64_ADD
242 MP_ADD_CARRY(r0
, r3
, r0
, 0, carry
);
243 MP_ADD_CARRY(r1
, r3
, r1
, carry
, carry
);
244 MP_ADD_CARRY(r2
, 0, r2
, carry
, carry
);
254 : "=r"(r0
), "=r"(r1
), "=r"(r2
), "=r"(r3
), "=r"(a3
)
255 : "0" (r0
), "1" (r1
), "2" (r2
), "3" (r3
), "4"(a3
)
260 /* check for final reduction */
262 * our field is 0xffffffffffffffff, 0xfffffffffffffffe,
263 * 0xffffffffffffffff. That means we can only be over and need
265 * if r2 == 0xffffffffffffffffff (same as r2+1 == 0)
267 * r1 == 0xffffffffffffffffff or
268 * r1 == 0xfffffffffffffffffe and r0 = 0xfffffffffffffffff
269 * In all cases, we subtract the field (or add the 2's
270 * complement value (1,1,0)). (r0, r1, r2)
272 if (r3
|| ((r2
== MP_DIGIT_MAX
) &&
273 ((r1
== MP_DIGIT_MAX
) ||
274 ((r1
== (MP_DIGIT_MAX
-1)) && (r0
== MP_DIGIT_MAX
))))) {
275 /* do a quick subtract */
279 /* set the lower words of r */
281 MP_CHECKOK(s_mp_pad(r
, 3));
294 #ifndef ECL_THIRTY_TWO_BIT
295 /* Compute the sum of 192 bit curves. Do the work in-line since the
296 * number of words are so small, we don't want to overhead of mp function
297 * calls. Uses optimized modular reduction for p192.
300 ec_GFp_nistp192_add(const mp_int
*a
, const mp_int
*b
, mp_int
*r
,
301 const GFMethod
*meth
)
303 mp_err res
= MP_OKAY
;
304 mp_digit a0
= 0, a1
= 0, a2
= 0;
305 mp_digit r0
= 0, r1
= 0, r2
= 0;
325 #ifndef MPI_AMD64_ADD
326 MP_ADD_CARRY(a0
, r0
, r0
, 0, carry
);
327 MP_ADD_CARRY(a1
, r1
, r1
, carry
, carry
);
328 MP_ADD_CARRY(a2
, r2
, r2
, carry
, carry
);
336 : "=r"(r0
), "=r"(r1
), "=r"(r2
), "=r"(carry
)
337 : "r" (a0
), "r" (a1
), "r" (a2
), "0" (r0
),
342 /* Do quick 'subract' if we've gone over
343 * (add the 2's complement of the curve field) */
344 if (carry
|| ((r2
== MP_DIGIT_MAX
) &&
345 ((r1
== MP_DIGIT_MAX
) ||
346 ((r1
== (MP_DIGIT_MAX
-1)) && (r0
== MP_DIGIT_MAX
))))) {
347 #ifndef MPI_AMD64_ADD
348 MP_ADD_CARRY(r0
, 1, r0
, 0, carry
);
349 MP_ADD_CARRY(r1
, 1, r1
, carry
, carry
);
350 MP_ADD_CARRY(r2
, 0, r2
, carry
, carry
);
356 : "=r"(r0
), "=r"(r1
), "=r"(r2
)
357 : "0" (r0
), "1" (r1
), "2" (r2
)
363 MP_CHECKOK(s_mp_pad(r
, 3));
367 MP_SIGN(r
) = MP_ZPOS
;
376 /* Compute the diff of 192 bit curves. Do the work in-line since the
377 * number of words are so small, we don't want to overhead of mp function
378 * calls. Uses optimized modular reduction for p192.
381 ec_GFp_nistp192_sub(const mp_int
*a
, const mp_int
*b
, mp_int
*r
,
382 const GFMethod
*meth
)
384 mp_err res
= MP_OKAY
;
385 mp_digit b0
= 0, b1
= 0, b2
= 0;
386 mp_digit r0
= 0, r1
= 0, r2
= 0;
407 #ifndef MPI_AMD64_ADD
408 MP_SUB_BORROW(r0
, b0
, r0
, 0, borrow
);
409 MP_SUB_BORROW(r1
, b1
, r1
, borrow
, borrow
);
410 MP_SUB_BORROW(r2
, b2
, r2
, borrow
, borrow
);
418 : "=r"(r0
), "=r"(r1
), "=r"(r2
), "=r"(borrow
)
419 : "r" (b0
), "r" (b1
), "r" (b2
), "0" (r0
),
424 /* Do quick 'add' if we've gone under 0
425 * (subtract the 2's complement of the curve field) */
427 #ifndef MPI_AMD64_ADD
428 MP_SUB_BORROW(r0
, 1, r0
, 0, borrow
);
429 MP_SUB_BORROW(r1
, 1, r1
, borrow
, borrow
);
430 MP_SUB_BORROW(r2
, 0, r2
, borrow
, borrow
);
436 : "=r"(r0
), "=r"(r1
), "=r"(r2
)
437 : "0" (r0
), "1" (r1
), "2" (r2
)
442 MP_CHECKOK(s_mp_pad(r
, 3));
446 MP_SIGN(r
) = MP_ZPOS
;
456 /* Compute the square of polynomial a, reduce modulo p192. Store the
457 * result in r. r could be a. Uses optimized modular reduction for p192.
460 ec_GFp_nistp192_sqr(const mp_int
*a
, mp_int
*r
, const GFMethod
*meth
)
462 mp_err res
= MP_OKAY
;
464 MP_CHECKOK(mp_sqr(a
, r
));
465 MP_CHECKOK(ec_GFp_nistp192_mod(r
, r
, meth
));
470 /* Compute the product of two polynomials a and b, reduce modulo p192.
471 * Store the result in r. r could be a or b; a could be b. Uses
472 * optimized modular reduction for p192. */
474 ec_GFp_nistp192_mul(const mp_int
*a
, const mp_int
*b
, mp_int
*r
,
475 const GFMethod
*meth
)
477 mp_err res
= MP_OKAY
;
479 MP_CHECKOK(mp_mul(a
, b
, r
));
480 MP_CHECKOK(ec_GFp_nistp192_mod(r
, r
, meth
));
485 /* Divides two field elements. If a is NULL, then returns the inverse of
488 ec_GFp_nistp192_div(const mp_int
*a
, const mp_int
*b
, mp_int
*r
,
489 const GFMethod
*meth
)
491 mp_err res
= MP_OKAY
;
494 /* If a is NULL, then return the inverse of b, otherwise return a/b. */
496 return mp_invmod(b
, &meth
->irr
, r
);
498 /* MPI doesn't support divmod, so we implement it using invmod and
500 MP_CHECKOK(mp_init(&t
, FLAG(b
)));
501 MP_CHECKOK(mp_invmod(b
, &meth
->irr
, &t
));
502 MP_CHECKOK(mp_mul(a
, &t
, r
));
503 MP_CHECKOK(ec_GFp_nistp192_mod(r
, r
, meth
));
510 /* Wire in fast field arithmetic and precomputation of base point for
513 ec_group_set_gfp192(ECGroup
*group
, ECCurveName name
)
515 if (name
== ECCurve_NIST_P192
) {
516 group
->meth
->field_mod
= &ec_GFp_nistp192_mod
;
517 group
->meth
->field_mul
= &ec_GFp_nistp192_mul
;
518 group
->meth
->field_sqr
= &ec_GFp_nistp192_sqr
;
519 group
->meth
->field_div
= &ec_GFp_nistp192_div
;
520 #ifndef ECL_THIRTY_TWO_BIT
521 group
->meth
->field_add
= &ec_GFp_nistp192_add
;
522 group
->meth
->field_sub
= &ec_GFp_nistp192_sub
;