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