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