Coverage Report

Created: 2024-05-20 06:23

/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
}