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