|
1 /* ********************************************************************* |
|
2 * |
|
3 * Sun elects to have this file available under and governed by the |
|
4 * Mozilla Public License Version 1.1 ("MPL") (see |
|
5 * http://www.mozilla.org/MPL/ for full license text). For the avoidance |
|
6 * of doubt and subject to the following, Sun also elects to allow |
|
7 * licensees to use this file under the MPL, the GNU General Public |
|
8 * License version 2 only or the Lesser General Public License version |
|
9 * 2.1 only. Any references to the "GNU General Public License version 2 |
|
10 * or later" or "GPL" in the following shall be construed to mean the |
|
11 * GNU General Public License version 2 only. Any references to the "GNU |
|
12 * Lesser General Public License version 2.1 or later" or "LGPL" in the |
|
13 * following shall be construed to mean the GNU Lesser General Public |
|
14 * License version 2.1 only. However, the following notice accompanied |
|
15 * the original version of this file: |
|
16 * |
|
17 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
|
18 * |
|
19 * The contents of this file are subject to the Mozilla Public License Version |
|
20 * 1.1 (the "License"); you may not use this file except in compliance with |
|
21 * the License. You may obtain a copy of the License at |
|
22 * http://www.mozilla.org/MPL/ |
|
23 * |
|
24 * Software distributed under the License is distributed on an "AS IS" basis, |
|
25 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
|
26 * for the specific language governing rights and limitations under the |
|
27 * License. |
|
28 * |
|
29 * The Original Code is the elliptic curve math library. |
|
30 * |
|
31 * The Initial Developer of the Original Code is |
|
32 * Sun Microsystems, Inc. |
|
33 * Portions created by the Initial Developer are Copyright (C) 2003 |
|
34 * the Initial Developer. All Rights Reserved. |
|
35 * |
|
36 * Contributor(s): |
|
37 * Stephen Fung <fungstep@hotmail.com> and |
|
38 * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories |
|
39 * |
|
40 * Alternatively, the contents of this file may be used under the terms of |
|
41 * either the GNU General Public License Version 2 or later (the "GPL"), or |
|
42 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
|
43 * in which case the provisions of the GPL or the LGPL are applicable instead |
|
44 * of those above. If you wish to allow use of your version of this file only |
|
45 * under the terms of either the GPL or the LGPL, and not to allow others to |
|
46 * use your version of this file under the terms of the MPL, indicate your |
|
47 * decision by deleting the provisions above and replace them with the notice |
|
48 * and other provisions required by the GPL or the LGPL. If you do not delete |
|
49 * the provisions above, a recipient may use your version of this file under |
|
50 * the terms of any one of the MPL, the GPL or the LGPL. |
|
51 * |
|
52 *********************************************************************** */ |
|
53 /* |
|
54 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. |
|
55 * Use is subject to license terms. |
|
56 */ |
|
57 |
|
58 #pragma ident "%Z%%M% %I% %E% SMI" |
|
59 |
|
60 #include "mpi.h" |
|
61 #include "mp_gf2m.h" |
|
62 #include "ecl-priv.h" |
|
63 #include "mpi-priv.h" |
|
64 #ifndef _KERNEL |
|
65 #include <stdlib.h> |
|
66 #endif |
|
67 |
|
68 /* Allocate memory for a new GFMethod object. */ |
|
69 GFMethod * |
|
70 GFMethod_new(int kmflag) |
|
71 { |
|
72 mp_err res = MP_OKAY; |
|
73 GFMethod *meth; |
|
74 #ifdef _KERNEL |
|
75 meth = (GFMethod *) kmem_alloc(sizeof(GFMethod), kmflag); |
|
76 #else |
|
77 meth = (GFMethod *) malloc(sizeof(GFMethod)); |
|
78 if (meth == NULL) |
|
79 return NULL; |
|
80 #endif |
|
81 meth->constructed = MP_YES; |
|
82 MP_DIGITS(&meth->irr) = 0; |
|
83 meth->extra_free = NULL; |
|
84 MP_CHECKOK(mp_init(&meth->irr, kmflag)); |
|
85 |
|
86 CLEANUP: |
|
87 if (res != MP_OKAY) { |
|
88 GFMethod_free(meth); |
|
89 return NULL; |
|
90 } |
|
91 return meth; |
|
92 } |
|
93 |
|
94 /* Construct a generic GFMethod for arithmetic over prime fields with |
|
95 * irreducible irr. */ |
|
96 GFMethod * |
|
97 GFMethod_consGFp(const mp_int *irr) |
|
98 { |
|
99 mp_err res = MP_OKAY; |
|
100 GFMethod *meth = NULL; |
|
101 |
|
102 meth = GFMethod_new(FLAG(irr)); |
|
103 if (meth == NULL) |
|
104 return NULL; |
|
105 |
|
106 MP_CHECKOK(mp_copy(irr, &meth->irr)); |
|
107 meth->irr_arr[0] = mpl_significant_bits(irr); |
|
108 meth->irr_arr[1] = meth->irr_arr[2] = meth->irr_arr[3] = |
|
109 meth->irr_arr[4] = 0; |
|
110 switch(MP_USED(&meth->irr)) { |
|
111 /* maybe we need 1 and 2 words here as well?*/ |
|
112 case 3: |
|
113 meth->field_add = &ec_GFp_add_3; |
|
114 meth->field_sub = &ec_GFp_sub_3; |
|
115 break; |
|
116 case 4: |
|
117 meth->field_add = &ec_GFp_add_4; |
|
118 meth->field_sub = &ec_GFp_sub_4; |
|
119 break; |
|
120 case 5: |
|
121 meth->field_add = &ec_GFp_add_5; |
|
122 meth->field_sub = &ec_GFp_sub_5; |
|
123 break; |
|
124 case 6: |
|
125 meth->field_add = &ec_GFp_add_6; |
|
126 meth->field_sub = &ec_GFp_sub_6; |
|
127 break; |
|
128 default: |
|
129 meth->field_add = &ec_GFp_add; |
|
130 meth->field_sub = &ec_GFp_sub; |
|
131 } |
|
132 meth->field_neg = &ec_GFp_neg; |
|
133 meth->field_mod = &ec_GFp_mod; |
|
134 meth->field_mul = &ec_GFp_mul; |
|
135 meth->field_sqr = &ec_GFp_sqr; |
|
136 meth->field_div = &ec_GFp_div; |
|
137 meth->field_enc = NULL; |
|
138 meth->field_dec = NULL; |
|
139 meth->extra1 = NULL; |
|
140 meth->extra2 = NULL; |
|
141 meth->extra_free = NULL; |
|
142 |
|
143 CLEANUP: |
|
144 if (res != MP_OKAY) { |
|
145 GFMethod_free(meth); |
|
146 return NULL; |
|
147 } |
|
148 return meth; |
|
149 } |
|
150 |
|
151 /* Construct a generic GFMethod for arithmetic over binary polynomial |
|
152 * fields with irreducible irr that has array representation irr_arr (see |
|
153 * ecl-priv.h for description of the representation). If irr_arr is NULL, |
|
154 * then it is constructed from the bitstring representation. */ |
|
155 GFMethod * |
|
156 GFMethod_consGF2m(const mp_int *irr, const unsigned int irr_arr[5]) |
|
157 { |
|
158 mp_err res = MP_OKAY; |
|
159 int ret; |
|
160 GFMethod *meth = NULL; |
|
161 |
|
162 meth = GFMethod_new(FLAG(irr)); |
|
163 if (meth == NULL) |
|
164 return NULL; |
|
165 |
|
166 MP_CHECKOK(mp_copy(irr, &meth->irr)); |
|
167 if (irr_arr != NULL) { |
|
168 /* Irreducible polynomials are either trinomials or pentanomials. */ |
|
169 meth->irr_arr[0] = irr_arr[0]; |
|
170 meth->irr_arr[1] = irr_arr[1]; |
|
171 meth->irr_arr[2] = irr_arr[2]; |
|
172 if (irr_arr[2] > 0) { |
|
173 meth->irr_arr[3] = irr_arr[3]; |
|
174 meth->irr_arr[4] = irr_arr[4]; |
|
175 } else { |
|
176 meth->irr_arr[3] = meth->irr_arr[4] = 0; |
|
177 } |
|
178 } else { |
|
179 ret = mp_bpoly2arr(irr, meth->irr_arr, 5); |
|
180 /* Irreducible polynomials are either trinomials or pentanomials. */ |
|
181 if ((ret != 5) && (ret != 3)) { |
|
182 res = MP_UNDEF; |
|
183 goto CLEANUP; |
|
184 } |
|
185 } |
|
186 meth->field_add = &ec_GF2m_add; |
|
187 meth->field_neg = &ec_GF2m_neg; |
|
188 meth->field_sub = &ec_GF2m_add; |
|
189 meth->field_mod = &ec_GF2m_mod; |
|
190 meth->field_mul = &ec_GF2m_mul; |
|
191 meth->field_sqr = &ec_GF2m_sqr; |
|
192 meth->field_div = &ec_GF2m_div; |
|
193 meth->field_enc = NULL; |
|
194 meth->field_dec = NULL; |
|
195 meth->extra1 = NULL; |
|
196 meth->extra2 = NULL; |
|
197 meth->extra_free = NULL; |
|
198 |
|
199 CLEANUP: |
|
200 if (res != MP_OKAY) { |
|
201 GFMethod_free(meth); |
|
202 return NULL; |
|
203 } |
|
204 return meth; |
|
205 } |
|
206 |
|
207 /* Free the memory allocated (if any) to a GFMethod object. */ |
|
208 void |
|
209 GFMethod_free(GFMethod *meth) |
|
210 { |
|
211 if (meth == NULL) |
|
212 return; |
|
213 if (meth->constructed == MP_NO) |
|
214 return; |
|
215 mp_clear(&meth->irr); |
|
216 if (meth->extra_free != NULL) |
|
217 meth->extra_free(meth); |
|
218 #ifdef _KERNEL |
|
219 kmem_free(meth, sizeof(GFMethod)); |
|
220 #else |
|
221 free(meth); |
|
222 #endif |
|
223 } |
|
224 |
|
225 /* Wrapper functions for generic prime field arithmetic. */ |
|
226 |
|
227 /* Add two field elements. Assumes that 0 <= a, b < meth->irr */ |
|
228 mp_err |
|
229 ec_GFp_add(const mp_int *a, const mp_int *b, mp_int *r, |
|
230 const GFMethod *meth) |
|
231 { |
|
232 /* PRE: 0 <= a, b < p = meth->irr POST: 0 <= r < p, r = a + b (mod p) */ |
|
233 mp_err res; |
|
234 |
|
235 if ((res = mp_add(a, b, r)) != MP_OKAY) { |
|
236 return res; |
|
237 } |
|
238 if (mp_cmp(r, &meth->irr) >= 0) { |
|
239 return mp_sub(r, &meth->irr, r); |
|
240 } |
|
241 return res; |
|
242 } |
|
243 |
|
244 /* Negates a field element. Assumes that 0 <= a < meth->irr */ |
|
245 mp_err |
|
246 ec_GFp_neg(const mp_int *a, mp_int *r, const GFMethod *meth) |
|
247 { |
|
248 /* PRE: 0 <= a < p = meth->irr POST: 0 <= r < p, r = -a (mod p) */ |
|
249 |
|
250 if (mp_cmp_z(a) == 0) { |
|
251 mp_zero(r); |
|
252 return MP_OKAY; |
|
253 } |
|
254 return mp_sub(&meth->irr, a, r); |
|
255 } |
|
256 |
|
257 /* Subtracts two field elements. Assumes that 0 <= a, b < meth->irr */ |
|
258 mp_err |
|
259 ec_GFp_sub(const mp_int *a, const mp_int *b, mp_int *r, |
|
260 const GFMethod *meth) |
|
261 { |
|
262 mp_err res = MP_OKAY; |
|
263 |
|
264 /* PRE: 0 <= a, b < p = meth->irr POST: 0 <= r < p, r = a - b (mod p) */ |
|
265 res = mp_sub(a, b, r); |
|
266 if (res == MP_RANGE) { |
|
267 MP_CHECKOK(mp_sub(b, a, r)); |
|
268 if (mp_cmp_z(r) < 0) { |
|
269 MP_CHECKOK(mp_add(r, &meth->irr, r)); |
|
270 } |
|
271 MP_CHECKOK(ec_GFp_neg(r, r, meth)); |
|
272 } |
|
273 if (mp_cmp_z(r) < 0) { |
|
274 MP_CHECKOK(mp_add(r, &meth->irr, r)); |
|
275 } |
|
276 CLEANUP: |
|
277 return res; |
|
278 } |
|
279 /* |
|
280 * Inline adds for small curve lengths. |
|
281 */ |
|
282 /* 3 words */ |
|
283 mp_err |
|
284 ec_GFp_add_3(const mp_int *a, const mp_int *b, mp_int *r, |
|
285 const GFMethod *meth) |
|
286 { |
|
287 mp_err res = MP_OKAY; |
|
288 mp_digit a0 = 0, a1 = 0, a2 = 0; |
|
289 mp_digit r0 = 0, r1 = 0, r2 = 0; |
|
290 mp_digit carry; |
|
291 |
|
292 switch(MP_USED(a)) { |
|
293 case 3: |
|
294 a2 = MP_DIGIT(a,2); |
|
295 case 2: |
|
296 a1 = MP_DIGIT(a,1); |
|
297 case 1: |
|
298 a0 = MP_DIGIT(a,0); |
|
299 } |
|
300 switch(MP_USED(b)) { |
|
301 case 3: |
|
302 r2 = MP_DIGIT(b,2); |
|
303 case 2: |
|
304 r1 = MP_DIGIT(b,1); |
|
305 case 1: |
|
306 r0 = MP_DIGIT(b,0); |
|
307 } |
|
308 |
|
309 #ifndef MPI_AMD64_ADD |
|
310 MP_ADD_CARRY(a0, r0, r0, 0, carry); |
|
311 MP_ADD_CARRY(a1, r1, r1, carry, carry); |
|
312 MP_ADD_CARRY(a2, r2, r2, carry, carry); |
|
313 #else |
|
314 __asm__ ( |
|
315 "xorq %3,%3 \n\t" |
|
316 "addq %4,%0 \n\t" |
|
317 "adcq %5,%1 \n\t" |
|
318 "adcq %6,%2 \n\t" |
|
319 "adcq $0,%3 \n\t" |
|
320 : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(carry) |
|
321 : "r" (a0), "r" (a1), "r" (a2), |
|
322 "0" (r0), "1" (r1), "2" (r2) |
|
323 : "%cc" ); |
|
324 #endif |
|
325 |
|
326 MP_CHECKOK(s_mp_pad(r, 3)); |
|
327 MP_DIGIT(r, 2) = r2; |
|
328 MP_DIGIT(r, 1) = r1; |
|
329 MP_DIGIT(r, 0) = r0; |
|
330 MP_SIGN(r) = MP_ZPOS; |
|
331 MP_USED(r) = 3; |
|
332 |
|
333 /* Do quick 'subract' if we've gone over |
|
334 * (add the 2's complement of the curve field) */ |
|
335 a2 = MP_DIGIT(&meth->irr,2); |
|
336 if (carry || r2 > a2 || |
|
337 ((r2 == a2) && mp_cmp(r,&meth->irr) != MP_LT)) { |
|
338 a1 = MP_DIGIT(&meth->irr,1); |
|
339 a0 = MP_DIGIT(&meth->irr,0); |
|
340 #ifndef MPI_AMD64_ADD |
|
341 MP_SUB_BORROW(r0, a0, r0, 0, carry); |
|
342 MP_SUB_BORROW(r1, a1, r1, carry, carry); |
|
343 MP_SUB_BORROW(r2, a2, r2, carry, carry); |
|
344 #else |
|
345 __asm__ ( |
|
346 "subq %3,%0 \n\t" |
|
347 "sbbq %4,%1 \n\t" |
|
348 "sbbq %5,%2 \n\t" |
|
349 : "=r"(r0), "=r"(r1), "=r"(r2) |
|
350 : "r" (a0), "r" (a1), "r" (a2), |
|
351 "0" (r0), "1" (r1), "2" (r2) |
|
352 : "%cc" ); |
|
353 #endif |
|
354 MP_DIGIT(r, 2) = r2; |
|
355 MP_DIGIT(r, 1) = r1; |
|
356 MP_DIGIT(r, 0) = r0; |
|
357 } |
|
358 |
|
359 s_mp_clamp(r); |
|
360 |
|
361 CLEANUP: |
|
362 return res; |
|
363 } |
|
364 |
|
365 /* 4 words */ |
|
366 mp_err |
|
367 ec_GFp_add_4(const mp_int *a, const mp_int *b, mp_int *r, |
|
368 const GFMethod *meth) |
|
369 { |
|
370 mp_err res = MP_OKAY; |
|
371 mp_digit a0 = 0, a1 = 0, a2 = 0, a3 = 0; |
|
372 mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0; |
|
373 mp_digit carry; |
|
374 |
|
375 switch(MP_USED(a)) { |
|
376 case 4: |
|
377 a3 = MP_DIGIT(a,3); |
|
378 case 3: |
|
379 a2 = MP_DIGIT(a,2); |
|
380 case 2: |
|
381 a1 = MP_DIGIT(a,1); |
|
382 case 1: |
|
383 a0 = MP_DIGIT(a,0); |
|
384 } |
|
385 switch(MP_USED(b)) { |
|
386 case 4: |
|
387 r3 = MP_DIGIT(b,3); |
|
388 case 3: |
|
389 r2 = MP_DIGIT(b,2); |
|
390 case 2: |
|
391 r1 = MP_DIGIT(b,1); |
|
392 case 1: |
|
393 r0 = MP_DIGIT(b,0); |
|
394 } |
|
395 |
|
396 #ifndef MPI_AMD64_ADD |
|
397 MP_ADD_CARRY(a0, r0, r0, 0, carry); |
|
398 MP_ADD_CARRY(a1, r1, r1, carry, carry); |
|
399 MP_ADD_CARRY(a2, r2, r2, carry, carry); |
|
400 MP_ADD_CARRY(a3, r3, r3, carry, carry); |
|
401 #else |
|
402 __asm__ ( |
|
403 "xorq %4,%4 \n\t" |
|
404 "addq %5,%0 \n\t" |
|
405 "adcq %6,%1 \n\t" |
|
406 "adcq %7,%2 \n\t" |
|
407 "adcq %8,%3 \n\t" |
|
408 "adcq $0,%4 \n\t" |
|
409 : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r"(carry) |
|
410 : "r" (a0), "r" (a1), "r" (a2), "r" (a3), |
|
411 "0" (r0), "1" (r1), "2" (r2), "3" (r3) |
|
412 : "%cc" ); |
|
413 #endif |
|
414 |
|
415 MP_CHECKOK(s_mp_pad(r, 4)); |
|
416 MP_DIGIT(r, 3) = r3; |
|
417 MP_DIGIT(r, 2) = r2; |
|
418 MP_DIGIT(r, 1) = r1; |
|
419 MP_DIGIT(r, 0) = r0; |
|
420 MP_SIGN(r) = MP_ZPOS; |
|
421 MP_USED(r) = 4; |
|
422 |
|
423 /* Do quick 'subract' if we've gone over |
|
424 * (add the 2's complement of the curve field) */ |
|
425 a3 = MP_DIGIT(&meth->irr,3); |
|
426 if (carry || r3 > a3 || |
|
427 ((r3 == a3) && mp_cmp(r,&meth->irr) != MP_LT)) { |
|
428 a2 = MP_DIGIT(&meth->irr,2); |
|
429 a1 = MP_DIGIT(&meth->irr,1); |
|
430 a0 = MP_DIGIT(&meth->irr,0); |
|
431 #ifndef MPI_AMD64_ADD |
|
432 MP_SUB_BORROW(r0, a0, r0, 0, carry); |
|
433 MP_SUB_BORROW(r1, a1, r1, carry, carry); |
|
434 MP_SUB_BORROW(r2, a2, r2, carry, carry); |
|
435 MP_SUB_BORROW(r3, a3, r3, carry, carry); |
|
436 #else |
|
437 __asm__ ( |
|
438 "subq %4,%0 \n\t" |
|
439 "sbbq %5,%1 \n\t" |
|
440 "sbbq %6,%2 \n\t" |
|
441 "sbbq %7,%3 \n\t" |
|
442 : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3) |
|
443 : "r" (a0), "r" (a1), "r" (a2), "r" (a3), |
|
444 "0" (r0), "1" (r1), "2" (r2), "3" (r3) |
|
445 : "%cc" ); |
|
446 #endif |
|
447 MP_DIGIT(r, 3) = r3; |
|
448 MP_DIGIT(r, 2) = r2; |
|
449 MP_DIGIT(r, 1) = r1; |
|
450 MP_DIGIT(r, 0) = r0; |
|
451 } |
|
452 |
|
453 s_mp_clamp(r); |
|
454 |
|
455 CLEANUP: |
|
456 return res; |
|
457 } |
|
458 |
|
459 /* 5 words */ |
|
460 mp_err |
|
461 ec_GFp_add_5(const mp_int *a, const mp_int *b, mp_int *r, |
|
462 const GFMethod *meth) |
|
463 { |
|
464 mp_err res = MP_OKAY; |
|
465 mp_digit a0 = 0, a1 = 0, a2 = 0, a3 = 0, a4 = 0; |
|
466 mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0; |
|
467 mp_digit carry; |
|
468 |
|
469 switch(MP_USED(a)) { |
|
470 case 5: |
|
471 a4 = MP_DIGIT(a,4); |
|
472 case 4: |
|
473 a3 = MP_DIGIT(a,3); |
|
474 case 3: |
|
475 a2 = MP_DIGIT(a,2); |
|
476 case 2: |
|
477 a1 = MP_DIGIT(a,1); |
|
478 case 1: |
|
479 a0 = MP_DIGIT(a,0); |
|
480 } |
|
481 switch(MP_USED(b)) { |
|
482 case 5: |
|
483 r4 = MP_DIGIT(b,4); |
|
484 case 4: |
|
485 r3 = MP_DIGIT(b,3); |
|
486 case 3: |
|
487 r2 = MP_DIGIT(b,2); |
|
488 case 2: |
|
489 r1 = MP_DIGIT(b,1); |
|
490 case 1: |
|
491 r0 = MP_DIGIT(b,0); |
|
492 } |
|
493 |
|
494 MP_ADD_CARRY(a0, r0, r0, 0, carry); |
|
495 MP_ADD_CARRY(a1, r1, r1, carry, carry); |
|
496 MP_ADD_CARRY(a2, r2, r2, carry, carry); |
|
497 MP_ADD_CARRY(a3, r3, r3, carry, carry); |
|
498 MP_ADD_CARRY(a4, r4, r4, carry, carry); |
|
499 |
|
500 MP_CHECKOK(s_mp_pad(r, 5)); |
|
501 MP_DIGIT(r, 4) = r4; |
|
502 MP_DIGIT(r, 3) = r3; |
|
503 MP_DIGIT(r, 2) = r2; |
|
504 MP_DIGIT(r, 1) = r1; |
|
505 MP_DIGIT(r, 0) = r0; |
|
506 MP_SIGN(r) = MP_ZPOS; |
|
507 MP_USED(r) = 5; |
|
508 |
|
509 /* Do quick 'subract' if we've gone over |
|
510 * (add the 2's complement of the curve field) */ |
|
511 a4 = MP_DIGIT(&meth->irr,4); |
|
512 if (carry || r4 > a4 || |
|
513 ((r4 == a4) && mp_cmp(r,&meth->irr) != MP_LT)) { |
|
514 a3 = MP_DIGIT(&meth->irr,3); |
|
515 a2 = MP_DIGIT(&meth->irr,2); |
|
516 a1 = MP_DIGIT(&meth->irr,1); |
|
517 a0 = MP_DIGIT(&meth->irr,0); |
|
518 MP_SUB_BORROW(r0, a0, r0, 0, carry); |
|
519 MP_SUB_BORROW(r1, a1, r1, carry, carry); |
|
520 MP_SUB_BORROW(r2, a2, r2, carry, carry); |
|
521 MP_SUB_BORROW(r3, a3, r3, carry, carry); |
|
522 MP_SUB_BORROW(r4, a4, r4, carry, carry); |
|
523 MP_DIGIT(r, 4) = r4; |
|
524 MP_DIGIT(r, 3) = r3; |
|
525 MP_DIGIT(r, 2) = r2; |
|
526 MP_DIGIT(r, 1) = r1; |
|
527 MP_DIGIT(r, 0) = r0; |
|
528 } |
|
529 |
|
530 s_mp_clamp(r); |
|
531 |
|
532 CLEANUP: |
|
533 return res; |
|
534 } |
|
535 |
|
536 /* 6 words */ |
|
537 mp_err |
|
538 ec_GFp_add_6(const mp_int *a, const mp_int *b, mp_int *r, |
|
539 const GFMethod *meth) |
|
540 { |
|
541 mp_err res = MP_OKAY; |
|
542 mp_digit a0 = 0, a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0; |
|
543 mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0; |
|
544 mp_digit carry; |
|
545 |
|
546 switch(MP_USED(a)) { |
|
547 case 6: |
|
548 a5 = MP_DIGIT(a,5); |
|
549 case 5: |
|
550 a4 = MP_DIGIT(a,4); |
|
551 case 4: |
|
552 a3 = MP_DIGIT(a,3); |
|
553 case 3: |
|
554 a2 = MP_DIGIT(a,2); |
|
555 case 2: |
|
556 a1 = MP_DIGIT(a,1); |
|
557 case 1: |
|
558 a0 = MP_DIGIT(a,0); |
|
559 } |
|
560 switch(MP_USED(b)) { |
|
561 case 6: |
|
562 r5 = MP_DIGIT(b,5); |
|
563 case 5: |
|
564 r4 = MP_DIGIT(b,4); |
|
565 case 4: |
|
566 r3 = MP_DIGIT(b,3); |
|
567 case 3: |
|
568 r2 = MP_DIGIT(b,2); |
|
569 case 2: |
|
570 r1 = MP_DIGIT(b,1); |
|
571 case 1: |
|
572 r0 = MP_DIGIT(b,0); |
|
573 } |
|
574 |
|
575 MP_ADD_CARRY(a0, r0, r0, 0, carry); |
|
576 MP_ADD_CARRY(a1, r1, r1, carry, carry); |
|
577 MP_ADD_CARRY(a2, r2, r2, carry, carry); |
|
578 MP_ADD_CARRY(a3, r3, r3, carry, carry); |
|
579 MP_ADD_CARRY(a4, r4, r4, carry, carry); |
|
580 MP_ADD_CARRY(a5, r5, r5, carry, carry); |
|
581 |
|
582 MP_CHECKOK(s_mp_pad(r, 6)); |
|
583 MP_DIGIT(r, 5) = r5; |
|
584 MP_DIGIT(r, 4) = r4; |
|
585 MP_DIGIT(r, 3) = r3; |
|
586 MP_DIGIT(r, 2) = r2; |
|
587 MP_DIGIT(r, 1) = r1; |
|
588 MP_DIGIT(r, 0) = r0; |
|
589 MP_SIGN(r) = MP_ZPOS; |
|
590 MP_USED(r) = 6; |
|
591 |
|
592 /* Do quick 'subract' if we've gone over |
|
593 * (add the 2's complement of the curve field) */ |
|
594 a5 = MP_DIGIT(&meth->irr,5); |
|
595 if (carry || r5 > a5 || |
|
596 ((r5 == a5) && mp_cmp(r,&meth->irr) != MP_LT)) { |
|
597 a4 = MP_DIGIT(&meth->irr,4); |
|
598 a3 = MP_DIGIT(&meth->irr,3); |
|
599 a2 = MP_DIGIT(&meth->irr,2); |
|
600 a1 = MP_DIGIT(&meth->irr,1); |
|
601 a0 = MP_DIGIT(&meth->irr,0); |
|
602 MP_SUB_BORROW(r0, a0, r0, 0, carry); |
|
603 MP_SUB_BORROW(r1, a1, r1, carry, carry); |
|
604 MP_SUB_BORROW(r2, a2, r2, carry, carry); |
|
605 MP_SUB_BORROW(r3, a3, r3, carry, carry); |
|
606 MP_SUB_BORROW(r4, a4, r4, carry, carry); |
|
607 MP_SUB_BORROW(r5, a5, r5, carry, carry); |
|
608 MP_DIGIT(r, 5) = r5; |
|
609 MP_DIGIT(r, 4) = r4; |
|
610 MP_DIGIT(r, 3) = r3; |
|
611 MP_DIGIT(r, 2) = r2; |
|
612 MP_DIGIT(r, 1) = r1; |
|
613 MP_DIGIT(r, 0) = r0; |
|
614 } |
|
615 |
|
616 s_mp_clamp(r); |
|
617 |
|
618 CLEANUP: |
|
619 return res; |
|
620 } |
|
621 |
|
622 /* |
|
623 * The following subraction functions do in-line subractions based |
|
624 * on our curve size. |
|
625 * |
|
626 * ... 3 words |
|
627 */ |
|
628 mp_err |
|
629 ec_GFp_sub_3(const mp_int *a, const mp_int *b, mp_int *r, |
|
630 const GFMethod *meth) |
|
631 { |
|
632 mp_err res = MP_OKAY; |
|
633 mp_digit b0 = 0, b1 = 0, b2 = 0; |
|
634 mp_digit r0 = 0, r1 = 0, r2 = 0; |
|
635 mp_digit borrow; |
|
636 |
|
637 switch(MP_USED(a)) { |
|
638 case 3: |
|
639 r2 = MP_DIGIT(a,2); |
|
640 case 2: |
|
641 r1 = MP_DIGIT(a,1); |
|
642 case 1: |
|
643 r0 = MP_DIGIT(a,0); |
|
644 } |
|
645 switch(MP_USED(b)) { |
|
646 case 3: |
|
647 b2 = MP_DIGIT(b,2); |
|
648 case 2: |
|
649 b1 = MP_DIGIT(b,1); |
|
650 case 1: |
|
651 b0 = MP_DIGIT(b,0); |
|
652 } |
|
653 |
|
654 #ifndef MPI_AMD64_ADD |
|
655 MP_SUB_BORROW(r0, b0, r0, 0, borrow); |
|
656 MP_SUB_BORROW(r1, b1, r1, borrow, borrow); |
|
657 MP_SUB_BORROW(r2, b2, r2, borrow, borrow); |
|
658 #else |
|
659 __asm__ ( |
|
660 "xorq %3,%3 \n\t" |
|
661 "subq %4,%0 \n\t" |
|
662 "sbbq %5,%1 \n\t" |
|
663 "sbbq %6,%2 \n\t" |
|
664 "adcq $0,%3 \n\t" |
|
665 : "=r"(r0), "=r"(r1), "=r"(r2), "=r" (borrow) |
|
666 : "r" (b0), "r" (b1), "r" (b2), |
|
667 "0" (r0), "1" (r1), "2" (r2) |
|
668 : "%cc" ); |
|
669 #endif |
|
670 |
|
671 /* Do quick 'add' if we've gone under 0 |
|
672 * (subtract the 2's complement of the curve field) */ |
|
673 if (borrow) { |
|
674 b2 = MP_DIGIT(&meth->irr,2); |
|
675 b1 = MP_DIGIT(&meth->irr,1); |
|
676 b0 = MP_DIGIT(&meth->irr,0); |
|
677 #ifndef MPI_AMD64_ADD |
|
678 MP_ADD_CARRY(b0, r0, r0, 0, borrow); |
|
679 MP_ADD_CARRY(b1, r1, r1, borrow, borrow); |
|
680 MP_ADD_CARRY(b2, r2, r2, borrow, borrow); |
|
681 #else |
|
682 __asm__ ( |
|
683 "addq %3,%0 \n\t" |
|
684 "adcq %4,%1 \n\t" |
|
685 "adcq %5,%2 \n\t" |
|
686 : "=r"(r0), "=r"(r1), "=r"(r2) |
|
687 : "r" (b0), "r" (b1), "r" (b2), |
|
688 "0" (r0), "1" (r1), "2" (r2) |
|
689 : "%cc" ); |
|
690 #endif |
|
691 } |
|
692 |
|
693 #ifdef MPI_AMD64_ADD |
|
694 /* compiler fakeout? */ |
|
695 if ((r2 == b0) && (r1 == b0) && (r0 == b0)) { |
|
696 MP_CHECKOK(s_mp_pad(r, 4)); |
|
697 } |
|
698 #endif |
|
699 MP_CHECKOK(s_mp_pad(r, 3)); |
|
700 MP_DIGIT(r, 2) = r2; |
|
701 MP_DIGIT(r, 1) = r1; |
|
702 MP_DIGIT(r, 0) = r0; |
|
703 MP_SIGN(r) = MP_ZPOS; |
|
704 MP_USED(r) = 3; |
|
705 s_mp_clamp(r); |
|
706 |
|
707 CLEANUP: |
|
708 return res; |
|
709 } |
|
710 |
|
711 /* 4 words */ |
|
712 mp_err |
|
713 ec_GFp_sub_4(const mp_int *a, const mp_int *b, mp_int *r, |
|
714 const GFMethod *meth) |
|
715 { |
|
716 mp_err res = MP_OKAY; |
|
717 mp_digit b0 = 0, b1 = 0, b2 = 0, b3 = 0; |
|
718 mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0; |
|
719 mp_digit borrow; |
|
720 |
|
721 switch(MP_USED(a)) { |
|
722 case 4: |
|
723 r3 = MP_DIGIT(a,3); |
|
724 case 3: |
|
725 r2 = MP_DIGIT(a,2); |
|
726 case 2: |
|
727 r1 = MP_DIGIT(a,1); |
|
728 case 1: |
|
729 r0 = MP_DIGIT(a,0); |
|
730 } |
|
731 switch(MP_USED(b)) { |
|
732 case 4: |
|
733 b3 = MP_DIGIT(b,3); |
|
734 case 3: |
|
735 b2 = MP_DIGIT(b,2); |
|
736 case 2: |
|
737 b1 = MP_DIGIT(b,1); |
|
738 case 1: |
|
739 b0 = MP_DIGIT(b,0); |
|
740 } |
|
741 |
|
742 #ifndef MPI_AMD64_ADD |
|
743 MP_SUB_BORROW(r0, b0, r0, 0, borrow); |
|
744 MP_SUB_BORROW(r1, b1, r1, borrow, borrow); |
|
745 MP_SUB_BORROW(r2, b2, r2, borrow, borrow); |
|
746 MP_SUB_BORROW(r3, b3, r3, borrow, borrow); |
|
747 #else |
|
748 __asm__ ( |
|
749 "xorq %4,%4 \n\t" |
|
750 "subq %5,%0 \n\t" |
|
751 "sbbq %6,%1 \n\t" |
|
752 "sbbq %7,%2 \n\t" |
|
753 "sbbq %8,%3 \n\t" |
|
754 "adcq $0,%4 \n\t" |
|
755 : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r" (borrow) |
|
756 : "r" (b0), "r" (b1), "r" (b2), "r" (b3), |
|
757 "0" (r0), "1" (r1), "2" (r2), "3" (r3) |
|
758 : "%cc" ); |
|
759 #endif |
|
760 |
|
761 /* Do quick 'add' if we've gone under 0 |
|
762 * (subtract the 2's complement of the curve field) */ |
|
763 if (borrow) { |
|
764 b3 = MP_DIGIT(&meth->irr,3); |
|
765 b2 = MP_DIGIT(&meth->irr,2); |
|
766 b1 = MP_DIGIT(&meth->irr,1); |
|
767 b0 = MP_DIGIT(&meth->irr,0); |
|
768 #ifndef MPI_AMD64_ADD |
|
769 MP_ADD_CARRY(b0, r0, r0, 0, borrow); |
|
770 MP_ADD_CARRY(b1, r1, r1, borrow, borrow); |
|
771 MP_ADD_CARRY(b2, r2, r2, borrow, borrow); |
|
772 MP_ADD_CARRY(b3, r3, r3, borrow, borrow); |
|
773 #else |
|
774 __asm__ ( |
|
775 "addq %4,%0 \n\t" |
|
776 "adcq %5,%1 \n\t" |
|
777 "adcq %6,%2 \n\t" |
|
778 "adcq %7,%3 \n\t" |
|
779 : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3) |
|
780 : "r" (b0), "r" (b1), "r" (b2), "r" (b3), |
|
781 "0" (r0), "1" (r1), "2" (r2), "3" (r3) |
|
782 : "%cc" ); |
|
783 #endif |
|
784 } |
|
785 #ifdef MPI_AMD64_ADD |
|
786 /* compiler fakeout? */ |
|
787 if ((r3 == b0) && (r1 == b0) && (r0 == b0)) { |
|
788 MP_CHECKOK(s_mp_pad(r, 4)); |
|
789 } |
|
790 #endif |
|
791 MP_CHECKOK(s_mp_pad(r, 4)); |
|
792 MP_DIGIT(r, 3) = r3; |
|
793 MP_DIGIT(r, 2) = r2; |
|
794 MP_DIGIT(r, 1) = r1; |
|
795 MP_DIGIT(r, 0) = r0; |
|
796 MP_SIGN(r) = MP_ZPOS; |
|
797 MP_USED(r) = 4; |
|
798 s_mp_clamp(r); |
|
799 |
|
800 CLEANUP: |
|
801 return res; |
|
802 } |
|
803 |
|
804 /* 5 words */ |
|
805 mp_err |
|
806 ec_GFp_sub_5(const mp_int *a, const mp_int *b, mp_int *r, |
|
807 const GFMethod *meth) |
|
808 { |
|
809 mp_err res = MP_OKAY; |
|
810 mp_digit b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0; |
|
811 mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0; |
|
812 mp_digit borrow; |
|
813 |
|
814 switch(MP_USED(a)) { |
|
815 case 5: |
|
816 r4 = MP_DIGIT(a,4); |
|
817 case 4: |
|
818 r3 = MP_DIGIT(a,3); |
|
819 case 3: |
|
820 r2 = MP_DIGIT(a,2); |
|
821 case 2: |
|
822 r1 = MP_DIGIT(a,1); |
|
823 case 1: |
|
824 r0 = MP_DIGIT(a,0); |
|
825 } |
|
826 switch(MP_USED(b)) { |
|
827 case 5: |
|
828 b4 = MP_DIGIT(b,4); |
|
829 case 4: |
|
830 b3 = MP_DIGIT(b,3); |
|
831 case 3: |
|
832 b2 = MP_DIGIT(b,2); |
|
833 case 2: |
|
834 b1 = MP_DIGIT(b,1); |
|
835 case 1: |
|
836 b0 = MP_DIGIT(b,0); |
|
837 } |
|
838 |
|
839 MP_SUB_BORROW(r0, b0, r0, 0, borrow); |
|
840 MP_SUB_BORROW(r1, b1, r1, borrow, borrow); |
|
841 MP_SUB_BORROW(r2, b2, r2, borrow, borrow); |
|
842 MP_SUB_BORROW(r3, b3, r3, borrow, borrow); |
|
843 MP_SUB_BORROW(r4, b4, r4, borrow, borrow); |
|
844 |
|
845 /* Do quick 'add' if we've gone under 0 |
|
846 * (subtract the 2's complement of the curve field) */ |
|
847 if (borrow) { |
|
848 b4 = MP_DIGIT(&meth->irr,4); |
|
849 b3 = MP_DIGIT(&meth->irr,3); |
|
850 b2 = MP_DIGIT(&meth->irr,2); |
|
851 b1 = MP_DIGIT(&meth->irr,1); |
|
852 b0 = MP_DIGIT(&meth->irr,0); |
|
853 MP_ADD_CARRY(b0, r0, r0, 0, borrow); |
|
854 MP_ADD_CARRY(b1, r1, r1, borrow, borrow); |
|
855 MP_ADD_CARRY(b2, r2, r2, borrow, borrow); |
|
856 MP_ADD_CARRY(b3, r3, r3, borrow, borrow); |
|
857 } |
|
858 MP_CHECKOK(s_mp_pad(r, 5)); |
|
859 MP_DIGIT(r, 4) = r4; |
|
860 MP_DIGIT(r, 3) = r3; |
|
861 MP_DIGIT(r, 2) = r2; |
|
862 MP_DIGIT(r, 1) = r1; |
|
863 MP_DIGIT(r, 0) = r0; |
|
864 MP_SIGN(r) = MP_ZPOS; |
|
865 MP_USED(r) = 5; |
|
866 s_mp_clamp(r); |
|
867 |
|
868 CLEANUP: |
|
869 return res; |
|
870 } |
|
871 |
|
872 /* 6 words */ |
|
873 mp_err |
|
874 ec_GFp_sub_6(const mp_int *a, const mp_int *b, mp_int *r, |
|
875 const GFMethod *meth) |
|
876 { |
|
877 mp_err res = MP_OKAY; |
|
878 mp_digit b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0; |
|
879 mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0; |
|
880 mp_digit borrow; |
|
881 |
|
882 switch(MP_USED(a)) { |
|
883 case 6: |
|
884 r5 = MP_DIGIT(a,5); |
|
885 case 5: |
|
886 r4 = MP_DIGIT(a,4); |
|
887 case 4: |
|
888 r3 = MP_DIGIT(a,3); |
|
889 case 3: |
|
890 r2 = MP_DIGIT(a,2); |
|
891 case 2: |
|
892 r1 = MP_DIGIT(a,1); |
|
893 case 1: |
|
894 r0 = MP_DIGIT(a,0); |
|
895 } |
|
896 switch(MP_USED(b)) { |
|
897 case 6: |
|
898 b5 = MP_DIGIT(b,5); |
|
899 case 5: |
|
900 b4 = MP_DIGIT(b,4); |
|
901 case 4: |
|
902 b3 = MP_DIGIT(b,3); |
|
903 case 3: |
|
904 b2 = MP_DIGIT(b,2); |
|
905 case 2: |
|
906 b1 = MP_DIGIT(b,1); |
|
907 case 1: |
|
908 b0 = MP_DIGIT(b,0); |
|
909 } |
|
910 |
|
911 MP_SUB_BORROW(r0, b0, r0, 0, borrow); |
|
912 MP_SUB_BORROW(r1, b1, r1, borrow, borrow); |
|
913 MP_SUB_BORROW(r2, b2, r2, borrow, borrow); |
|
914 MP_SUB_BORROW(r3, b3, r3, borrow, borrow); |
|
915 MP_SUB_BORROW(r4, b4, r4, borrow, borrow); |
|
916 MP_SUB_BORROW(r5, b5, r5, borrow, borrow); |
|
917 |
|
918 /* Do quick 'add' if we've gone under 0 |
|
919 * (subtract the 2's complement of the curve field) */ |
|
920 if (borrow) { |
|
921 b5 = MP_DIGIT(&meth->irr,5); |
|
922 b4 = MP_DIGIT(&meth->irr,4); |
|
923 b3 = MP_DIGIT(&meth->irr,3); |
|
924 b2 = MP_DIGIT(&meth->irr,2); |
|
925 b1 = MP_DIGIT(&meth->irr,1); |
|
926 b0 = MP_DIGIT(&meth->irr,0); |
|
927 MP_ADD_CARRY(b0, r0, r0, 0, borrow); |
|
928 MP_ADD_CARRY(b1, r1, r1, borrow, borrow); |
|
929 MP_ADD_CARRY(b2, r2, r2, borrow, borrow); |
|
930 MP_ADD_CARRY(b3, r3, r3, borrow, borrow); |
|
931 MP_ADD_CARRY(b4, r4, r4, borrow, borrow); |
|
932 } |
|
933 |
|
934 MP_CHECKOK(s_mp_pad(r, 6)); |
|
935 MP_DIGIT(r, 5) = r5; |
|
936 MP_DIGIT(r, 4) = r4; |
|
937 MP_DIGIT(r, 3) = r3; |
|
938 MP_DIGIT(r, 2) = r2; |
|
939 MP_DIGIT(r, 1) = r1; |
|
940 MP_DIGIT(r, 0) = r0; |
|
941 MP_SIGN(r) = MP_ZPOS; |
|
942 MP_USED(r) = 6; |
|
943 s_mp_clamp(r); |
|
944 |
|
945 CLEANUP: |
|
946 return res; |
|
947 } |
|
948 |
|
949 |
|
950 /* Reduces an integer to a field element. */ |
|
951 mp_err |
|
952 ec_GFp_mod(const mp_int *a, mp_int *r, const GFMethod *meth) |
|
953 { |
|
954 return mp_mod(a, &meth->irr, r); |
|
955 } |
|
956 |
|
957 /* Multiplies two field elements. */ |
|
958 mp_err |
|
959 ec_GFp_mul(const mp_int *a, const mp_int *b, mp_int *r, |
|
960 const GFMethod *meth) |
|
961 { |
|
962 return mp_mulmod(a, b, &meth->irr, r); |
|
963 } |
|
964 |
|
965 /* Squares a field element. */ |
|
966 mp_err |
|
967 ec_GFp_sqr(const mp_int *a, mp_int *r, const GFMethod *meth) |
|
968 { |
|
969 return mp_sqrmod(a, &meth->irr, r); |
|
970 } |
|
971 |
|
972 /* Divides two field elements. If a is NULL, then returns the inverse of |
|
973 * b. */ |
|
974 mp_err |
|
975 ec_GFp_div(const mp_int *a, const mp_int *b, mp_int *r, |
|
976 const GFMethod *meth) |
|
977 { |
|
978 mp_err res = MP_OKAY; |
|
979 mp_int t; |
|
980 |
|
981 /* If a is NULL, then return the inverse of b, otherwise return a/b. */ |
|
982 if (a == NULL) { |
|
983 return mp_invmod(b, &meth->irr, r); |
|
984 } else { |
|
985 /* MPI doesn't support divmod, so we implement it using invmod and |
|
986 * mulmod. */ |
|
987 MP_CHECKOK(mp_init(&t, FLAG(b))); |
|
988 MP_CHECKOK(mp_invmod(b, &meth->irr, &t)); |
|
989 MP_CHECKOK(mp_mulmod(a, &t, &meth->irr, r)); |
|
990 CLEANUP: |
|
991 mp_clear(&t); |
|
992 return res; |
|
993 } |
|
994 } |
|
995 |
|
996 /* Wrapper functions for generic binary polynomial field arithmetic. */ |
|
997 |
|
998 /* Adds two field elements. */ |
|
999 mp_err |
|
1000 ec_GF2m_add(const mp_int *a, const mp_int *b, mp_int *r, |
|
1001 const GFMethod *meth) |
|
1002 { |
|
1003 return mp_badd(a, b, r); |
|
1004 } |
|
1005 |
|
1006 /* Negates a field element. Note that for binary polynomial fields, the |
|
1007 * negation of a field element is the field element itself. */ |
|
1008 mp_err |
|
1009 ec_GF2m_neg(const mp_int *a, mp_int *r, const GFMethod *meth) |
|
1010 { |
|
1011 if (a == r) { |
|
1012 return MP_OKAY; |
|
1013 } else { |
|
1014 return mp_copy(a, r); |
|
1015 } |
|
1016 } |
|
1017 |
|
1018 /* Reduces a binary polynomial to a field element. */ |
|
1019 mp_err |
|
1020 ec_GF2m_mod(const mp_int *a, mp_int *r, const GFMethod *meth) |
|
1021 { |
|
1022 return mp_bmod(a, meth->irr_arr, r); |
|
1023 } |
|
1024 |
|
1025 /* Multiplies two field elements. */ |
|
1026 mp_err |
|
1027 ec_GF2m_mul(const mp_int *a, const mp_int *b, mp_int *r, |
|
1028 const GFMethod *meth) |
|
1029 { |
|
1030 return mp_bmulmod(a, b, meth->irr_arr, r); |
|
1031 } |
|
1032 |
|
1033 /* Squares a field element. */ |
|
1034 mp_err |
|
1035 ec_GF2m_sqr(const mp_int *a, mp_int *r, const GFMethod *meth) |
|
1036 { |
|
1037 return mp_bsqrmod(a, meth->irr_arr, r); |
|
1038 } |
|
1039 |
|
1040 /* Divides two field elements. If a is NULL, then returns the inverse of |
|
1041 * b. */ |
|
1042 mp_err |
|
1043 ec_GF2m_div(const mp_int *a, const mp_int *b, mp_int *r, |
|
1044 const GFMethod *meth) |
|
1045 { |
|
1046 mp_err res = MP_OKAY; |
|
1047 mp_int t; |
|
1048 |
|
1049 /* If a is NULL, then return the inverse of b, otherwise return a/b. */ |
|
1050 if (a == NULL) { |
|
1051 /* The GF(2^m) portion of MPI doesn't support invmod, so we |
|
1052 * compute 1/b. */ |
|
1053 MP_CHECKOK(mp_init(&t, FLAG(b))); |
|
1054 MP_CHECKOK(mp_set_int(&t, 1)); |
|
1055 MP_CHECKOK(mp_bdivmod(&t, b, &meth->irr, meth->irr_arr, r)); |
|
1056 CLEANUP: |
|
1057 mp_clear(&t); |
|
1058 return res; |
|
1059 } else { |
|
1060 return mp_bdivmod(a, b, &meth->irr, meth->irr_arr, r); |
|
1061 } |
|
1062 } |