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.
53 #define ECP192_DIGITS ECL_CURVE_DIGITS(192)
55 /* Fast modular reduction for p192 = 2^192 - 2^64 - 1. a can be r. Uses
56 * algorithm 7 from Brown, Hankerson, Lopez, Menezes. Software
57 * Implementation of the NIST Elliptic Curves over Prime Fields. */
59 ec_GFp_nistp192_mod(const mp_int
*a
, mp_int
*r
, const GFMethod
*meth
)
62 mp_size a_used
= MP_USED(a
);
67 #ifdef ECL_THIRTY_TWO_BIT
68 mp_digit a5a
= 0, a5b
= 0, a4a
= 0, a4b
= 0, a3a
= 0, a3b
= 0;
69 mp_digit r0a
, r0b
, r1a
, r1b
, r2a
, r2b
;
71 mp_digit a5
= 0, a4
= 0, a3
= 0;
75 /* reduction not needed if a is not larger than field size */
76 if (a_used
< ECP192_DIGITS
) {
83 /* for polynomials larger than twice the field size, use regular
85 if (a_used
> ECP192_DIGITS
*2) {
86 MP_CHECKOK(mp_mod(a
, &meth
->irr
, r
));
88 /* copy out upper words of a */
90 #ifdef ECL_THIRTY_TWO_BIT
92 /* in all the math below,
93 * nXb is most signifiant, nXa is least significant */
96 a5b
= MP_DIGIT(a
, 11);
99 a5a
= MP_DIGIT(a
, 10);
102 a4b
= MP_DIGIT(a
, 9);
105 a4a
= MP_DIGIT(a
, 8);
108 a3b
= MP_DIGIT(a
, 7);
111 a3a
= MP_DIGIT(a
, 6);
117 r1b
= MP_DIGIT(a
, 3);
118 r1a
= MP_DIGIT(a
, 2);
119 r0b
= MP_DIGIT(a
, 1);
120 r0a
= MP_DIGIT(a
, 0);
122 /* implement r = (a2,a1,a0)+(a5,a5,a5)+(a4,a4,0)+(0,a3,a3) */
123 MP_ADD_CARRY(r0a
, a3a
, r0a
, 0, carry
);
124 MP_ADD_CARRY(r0b
, a3b
, r0b
, carry
, carry
);
125 MP_ADD_CARRY(r1a
, a3a
, r1a
, carry
, carry
);
126 MP_ADD_CARRY(r1b
, a3b
, r1b
, carry
, carry
);
127 MP_ADD_CARRY(r2a
, a4a
, r2a
, carry
, carry
);
128 MP_ADD_CARRY(r2b
, a4b
, r2b
, carry
, carry
);
129 r3
= carry
; carry
= 0;
130 MP_ADD_CARRY(r0a
, a5a
, r0a
, 0, carry
);
131 MP_ADD_CARRY(r0b
, a5b
, r0b
, carry
, carry
);
132 MP_ADD_CARRY(r1a
, a5a
, r1a
, carry
, carry
);
133 MP_ADD_CARRY(r1b
, a5b
, r1b
, carry
, carry
);
134 MP_ADD_CARRY(r2a
, a5a
, r2a
, carry
, carry
);
135 MP_ADD_CARRY(r2b
, a5b
, r2b
, carry
, carry
);
137 MP_ADD_CARRY(r1a
, a4a
, r1a
, 0, carry
);
138 MP_ADD_CARRY(r1b
, a4b
, r1b
, carry
, carry
);
139 MP_ADD_CARRY(r2a
, 0, r2a
, carry
, carry
);
140 MP_ADD_CARRY(r2b
, 0, r2b
, carry
, carry
);
143 /* reduce out the carry */
145 MP_ADD_CARRY(r0a
, r3
, r0a
, 0, carry
);
146 MP_ADD_CARRY(r0b
, 0, r0b
, carry
, carry
);
147 MP_ADD_CARRY(r1a
, r3
, r1a
, carry
, carry
);
148 MP_ADD_CARRY(r1b
, 0, r1b
, carry
, carry
);
149 MP_ADD_CARRY(r2a
, 0, r2a
, carry
, carry
);
150 MP_ADD_CARRY(r2b
, 0, r2b
, carry
, carry
);
154 /* check for final reduction */
156 * our field is 0xffffffffffffffff, 0xfffffffffffffffe,
157 * 0xffffffffffffffff. That means we can only be over and need
159 * if r2 == 0xffffffffffffffffff (same as r2+1 == 0)
161 * r1 == 0xffffffffffffffffff or
162 * r1 == 0xfffffffffffffffffe and r0 = 0xfffffffffffffffff
163 * In all cases, we subtract the field (or add the 2's
164 * complement value (1,1,0)). (r0, r1, r2)
166 if (((r2b
== 0xffffffff) && (r2a
== 0xffffffff)
167 && (r1b
== 0xffffffff) ) &&
168 ((r1a
== 0xffffffff) ||
169 (r1a
== 0xfffffffe) && (r0a
== 0xffffffff) &&
170 (r0b
== 0xffffffff)) ) {
171 /* do a quick subtract */
172 MP_ADD_CARRY(r0a
, 1, r0a
, 0, carry
);
174 r1a
= r1b
= r2a
= r2b
= 0;
177 /* set the lower words of r */
179 MP_CHECKOK(s_mp_pad(r
, 6));
181 MP_DIGIT(r
, 5) = r2b
;
182 MP_DIGIT(r
, 4) = r2a
;
183 MP_DIGIT(r
, 3) = r1b
;
184 MP_DIGIT(r
, 2) = r1a
;
185 MP_DIGIT(r
, 1) = r0b
;
186 MP_DIGIT(r
, 0) = r0a
;
204 /* implement r = (a2,a1,a0)+(a5,a5,a5)+(a4,a4,0)+(0,a3,a3) */
205 #ifndef MPI_AMD64_ADD
206 MP_ADD_CARRY(r0
, a3
, r0
, 0, carry
);
207 MP_ADD_CARRY(r1
, a3
, r1
, carry
, carry
);
208 MP_ADD_CARRY(r2
, a4
, r2
, carry
, carry
);
210 MP_ADD_CARRY(r0
, a5
, r0
, 0, carry
);
211 MP_ADD_CARRY(r1
, a5
, r1
, carry
, carry
);
212 MP_ADD_CARRY(r2
, a5
, r2
, carry
, carry
);
214 MP_ADD_CARRY(r1
, a4
, r1
, 0, carry
);
215 MP_ADD_CARRY(r2
, 0, r2
, carry
, carry
);
223 /* set the lower words of r */
237 : "=r"(r0
), "=r"(r1
), "=r"(r2
), "=r"(r3
), "=r"(a3
),
239 : "0" (r0
), "1" (r1
), "2" (r2
), "3" (r3
),
240 "4" (a3
), "5" (a4
), "6"(a5
)
244 /* reduce out the carry */
246 #ifndef MPI_AMD64_ADD
247 MP_ADD_CARRY(r0
, r3
, r0
, 0, carry
);
248 MP_ADD_CARRY(r1
, r3
, r1
, carry
, carry
);
249 MP_ADD_CARRY(r2
, 0, r2
, carry
, carry
);
259 : "=r"(r0
), "=r"(r1
), "=r"(r2
), "=r"(r3
), "=r"(a3
)
260 : "0" (r0
), "1" (r1
), "2" (r2
), "3" (r3
), "4"(a3
)
265 /* check for final reduction */
267 * our field is 0xffffffffffffffff, 0xfffffffffffffffe,
268 * 0xffffffffffffffff. That means we can only be over and need
270 * if r2 == 0xffffffffffffffffff (same as r2+1 == 0)
272 * r1 == 0xffffffffffffffffff or
273 * r1 == 0xfffffffffffffffffe and r0 = 0xfffffffffffffffff
274 * In all cases, we subtract the field (or add the 2's
275 * complement value (1,1,0)). (r0, r1, r2)
277 if (r3
|| ((r2
== MP_DIGIT_MAX
) &&
278 ((r1
== MP_DIGIT_MAX
) ||
279 ((r1
== (MP_DIGIT_MAX
-1)) && (r0
== MP_DIGIT_MAX
))))) {
280 /* do a quick subtract */
284 /* set the lower words of r */
286 MP_CHECKOK(s_mp_pad(r
, 3));
299 #ifndef ECL_THIRTY_TWO_BIT
300 /* Compute the sum of 192 bit curves. Do the work in-line since the
301 * number of words are so small, we don't want to overhead of mp function
302 * calls. Uses optimized modular reduction for p192.
305 ec_GFp_nistp192_add(const mp_int
*a
, const mp_int
*b
, mp_int
*r
,
306 const GFMethod
*meth
)
308 mp_err res
= MP_OKAY
;
309 mp_digit a0
= 0, a1
= 0, a2
= 0;
310 mp_digit r0
= 0, r1
= 0, r2
= 0;
334 #ifndef MPI_AMD64_ADD
335 MP_ADD_CARRY(a0
, r0
, r0
, 0, carry
);
336 MP_ADD_CARRY(a1
, r1
, r1
, carry
, carry
);
337 MP_ADD_CARRY(a2
, r2
, r2
, carry
, carry
);
345 : "=r"(r0
), "=r"(r1
), "=r"(r2
), "=r"(carry
)
346 : "r" (a0
), "r" (a1
), "r" (a2
), "0" (r0
),
351 /* Do quick 'subract' if we've gone over
352 * (add the 2's complement of the curve field) */
353 if (carry
|| ((r2
== MP_DIGIT_MAX
) &&
354 ((r1
== MP_DIGIT_MAX
) ||
355 ((r1
== (MP_DIGIT_MAX
-1)) && (r0
== MP_DIGIT_MAX
))))) {
356 #ifndef MPI_AMD64_ADD
357 MP_ADD_CARRY(r0
, 1, r0
, 0, carry
);
358 MP_ADD_CARRY(r1
, 1, r1
, carry
, carry
);
359 MP_ADD_CARRY(r2
, 0, r2
, carry
, carry
);
365 : "=r"(r0
), "=r"(r1
), "=r"(r2
)
366 : "0" (r0
), "1" (r1
), "2" (r2
)
372 MP_CHECKOK(s_mp_pad(r
, 3));
376 MP_SIGN(r
) = MP_ZPOS
;
385 /* Compute the diff of 192 bit curves. Do the work in-line since the
386 * number of words are so small, we don't want to overhead of mp function
387 * calls. Uses optimized modular reduction for p192.
390 ec_GFp_nistp192_sub(const mp_int
*a
, const mp_int
*b
, mp_int
*r
,
391 const GFMethod
*meth
)
393 mp_err res
= MP_OKAY
;
394 mp_digit b0
= 0, b1
= 0, b2
= 0;
395 mp_digit r0
= 0, r1
= 0, r2
= 0;
420 #ifndef MPI_AMD64_ADD
421 MP_SUB_BORROW(r0
, b0
, r0
, 0, borrow
);
422 MP_SUB_BORROW(r1
, b1
, r1
, borrow
, borrow
);
423 MP_SUB_BORROW(r2
, b2
, r2
, borrow
, borrow
);
431 : "=r"(r0
), "=r"(r1
), "=r"(r2
), "=r"(borrow
)
432 : "r" (b0
), "r" (b1
), "r" (b2
), "0" (r0
),
437 /* Do quick 'add' if we've gone under 0
438 * (subtract the 2's complement of the curve field) */
440 #ifndef MPI_AMD64_ADD
441 MP_SUB_BORROW(r0
, 1, r0
, 0, borrow
);
442 MP_SUB_BORROW(r1
, 1, r1
, borrow
, borrow
);
443 MP_SUB_BORROW(r2
, 0, r2
, borrow
, borrow
);
449 : "=r"(r0
), "=r"(r1
), "=r"(r2
)
450 : "0" (r0
), "1" (r1
), "2" (r2
)
455 MP_CHECKOK(s_mp_pad(r
, 3));
459 MP_SIGN(r
) = MP_ZPOS
;
469 /* Compute the square of polynomial a, reduce modulo p192. Store the
470 * result in r. r could be a. Uses optimized modular reduction for p192.
473 ec_GFp_nistp192_sqr(const mp_int
*a
, mp_int
*r
, const GFMethod
*meth
)
475 mp_err res
= MP_OKAY
;
477 MP_CHECKOK(mp_sqr(a
, r
));
478 MP_CHECKOK(ec_GFp_nistp192_mod(r
, r
, meth
));
483 /* Compute the product of two polynomials a and b, reduce modulo p192.
484 * Store the result in r. r could be a or b; a could be b. Uses
485 * optimized modular reduction for p192. */
487 ec_GFp_nistp192_mul(const mp_int
*a
, const mp_int
*b
, mp_int
*r
,
488 const GFMethod
*meth
)
490 mp_err res
= MP_OKAY
;
492 MP_CHECKOK(mp_mul(a
, b
, r
));
493 MP_CHECKOK(ec_GFp_nistp192_mod(r
, r
, meth
));
498 /* Divides two field elements. If a is NULL, then returns the inverse of
501 ec_GFp_nistp192_div(const mp_int
*a
, const mp_int
*b
, mp_int
*r
,
502 const GFMethod
*meth
)
504 mp_err res
= MP_OKAY
;
507 /* If a is NULL, then return the inverse of b, otherwise return a/b. */
509 return mp_invmod(b
, &meth
->irr
, r
);
511 /* MPI doesn't support divmod, so we implement it using invmod and
513 MP_CHECKOK(mp_init(&t
, FLAG(b
)));
514 MP_CHECKOK(mp_invmod(b
, &meth
->irr
, &t
));
515 MP_CHECKOK(mp_mul(a
, &t
, r
));
516 MP_CHECKOK(ec_GFp_nistp192_mod(r
, r
, meth
));
523 /* Wire in fast field arithmetic and precomputation of base point for
526 ec_group_set_gfp192(ECGroup
*group
, ECCurveName name
)
528 if (name
== ECCurve_NIST_P192
) {
529 group
->meth
->field_mod
= &ec_GFp_nistp192_mod
;
530 group
->meth
->field_mul
= &ec_GFp_nistp192_mul
;
531 group
->meth
->field_sqr
= &ec_GFp_nistp192_sqr
;
532 group
->meth
->field_div
= &ec_GFp_nistp192_div
;
533 #ifndef ECL_THIRTY_TWO_BIT
534 group
->meth
->field_add
= &ec_GFp_nistp192_add
;
535 group
->meth
->field_sub
= &ec_GFp_nistp192_sub
;