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