xref: /titanic_51/usr/src/common/crypto/ecc/ecl_gf.c (revision f9fbec18f5b458b560ecf45d3db8e8bd56bf6942)
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 *
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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