/*************************************************************************** * Copyright 2013 CertiVox UK Ltd. * * This file is part of CertiVox MIRACL Crypto SDK. * * The CertiVox MIRACL Crypto SDK provides developers with an * extensive and efficient set of cryptographic functions. * For further information about its features and functionalities please * refer to http://www.certivox.com * * * The CertiVox MIRACL Crypto SDK is free software: you can * redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the * Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * * The CertiVox MIRACL Crypto SDK is distributed in the hope * that it will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * * * You should have received a copy of the GNU Affero General Public * License along with CertiVox MIRACL Crypto SDK. * If not, see . * * You can be released from the requirements of the license by purchasing * a commercial license. Buying such a license is mandatory as soon as you * develop commercial activities involving the CertiVox MIRACL Crypto SDK * without disclosing the source code of your own applications, or shipping * the CertiVox MIRACL Crypto SDK with a closed source product. * * ***************************************************************************/ /* * MIRACL Montgomery's method for modular arithmetic without division. * mrmonty.c * * Programs to implement Montgomery's method * See "Modular Multiplication Without Trial Division", Math. Comp. * Vol 44, Number 170, April 1985, Pages 519-521 * NOTE - there is an important correction to this paper mentioned as a * footnote in "Speeding the Pollard and Elliptic Curve Methods", * Math. Comput., Vol. 48, January 1987, 243-264 * * The advantage of this approach is that no division required in order * to compute a modular reduction - useful if division is slow * e.g. on a SPARC processor, or a DSP. * * The disadvantage is that numbers must first be converted to an internal * "n-residue" form. * */ #include #include "miracl.h" #ifdef MR_FP #include #endif #ifdef MR_WIN64 #include #endif #ifdef MR_COUNT_OPS extern int fpc,fpa; #endif #ifdef MR_CELL extern void mod256(_MIPD_ big,big); #endif void kill_monty(_MIPDO_ ) { #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif zero(mr_mip->modulus); #ifdef MR_KCM zero(mr_mip->big_ndash); #endif } mr_small prepare_monty(_MIPD_ big n) { /* prepare Montgomery modulus */ #ifdef MR_KCM int nl; #endif #ifdef MR_PENTIUM mr_small ndash; mr_small base; mr_small magic=13835058055282163712.0; int control=0x1FFF; #endif #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif if (mr_mip->ERNUM) return (mr_small)0; /* Is it set-up already? */ if (size(mr_mip->modulus)!=0) if (mr_compare(n,mr_mip->modulus)==0) return mr_mip->ndash; MR_IN(80) if (size(n)<=2) { mr_berror(_MIPP_ MR_ERR_BAD_MODULUS); MR_OUT return (mr_small)0; } zero(mr_mip->w6); zero(mr_mip->w15); /* set a small negative QNR (on the assumption that n is prime!) */ /* These defaults can be over-ridden */ /* Did you know that for p=2 mod 3, -3 is a QNR? */ mr_mip->pmod8=remain(_MIPP_ n,8); switch (mr_mip->pmod8) { case 0: case 1: case 2: case 4: case 6: mr_mip->qnr=0; /* none defined */ break; case 3: mr_mip->qnr=-1; break; case 5: mr_mip->qnr=-2; break; case 7: mr_mip->qnr=-1; break; } mr_mip->pmod9=remain(_MIPP_ n,9); mr_mip->NO_CARRY=FALSE; if (n->w[n->len-1]>>M4 < 5) mr_mip->NO_CARRY=TRUE; #ifdef MR_PENTIUM mr_mip->ACTIVE=FALSE; if (mr_mip->base!=0) if (MR_PENTIUM==n->len) mr_mip->ACTIVE=TRUE; if (MR_PENTIUM<0) { if (n->len<=(-MR_PENTIUM)) mr_mip->ACTIVE=TRUE; if (logb2(_MIPP_ n)%mr_mip->lg2b==0) mr_mip->ACTIVE=FALSE; } #endif #ifdef MR_DISABLE_MONTGOMERY mr_mip->MONTY=OFF; #else mr_mip->MONTY=ON; #endif #ifdef MR_COMBA mr_mip->ACTIVE=FALSE; if (MR_COMBA==n->len && mr_mip->base==mr_mip->base2) { mr_mip->ACTIVE=TRUE; #ifdef MR_SPECIAL mr_mip->MONTY=OFF; /* "special" modulus reduction */ #endif /* implemented in mrcomba.c */ } #endif convert(_MIPP_ 1,mr_mip->one); if (!mr_mip->MONTY) { /* Montgomery arithmetic is turned off */ copy(n,mr_mip->modulus); mr_mip->ndash=0; MR_OUT return (mr_small)0; } #ifdef MR_KCM /* test for base==0 & n->len=MR_KCM.2^x */ mr_mip->ACTIVE=FALSE; if (mr_mip->base==0) { nl=(int)n->len; while (nl>=MR_KCM) { if (nl==MR_KCM) { mr_mip->ACTIVE=TRUE; break; } if (nl%2!=0) break; nl/=2; } } if (mr_mip->ACTIVE) { mr_mip->w6->len=n->len+1; mr_mip->w6->w[n->len]=1; if (invmodp(_MIPP_ n,mr_mip->w6,mr_mip->w14)!=1) { /* problems */ mr_berror(_MIPP_ MR_ERR_BAD_MODULUS); MR_OUT return (mr_small)0; } } else { #endif mr_mip->w6->len=2; mr_mip->w6->w[0]=0; mr_mip->w6->w[1]=1; /* w6 = base */ mr_mip->w15->len=1; mr_mip->w15->w[0]=n->w[0]; /* w15 = n mod base */ if (invmodp(_MIPP_ mr_mip->w15,mr_mip->w6,mr_mip->w14)!=1) { /* problems */ mr_berror(_MIPP_ MR_ERR_BAD_MODULUS); MR_OUT return (mr_small)0; } #ifdef MR_KCM } copy(mr_mip->w14,mr_mip->big_ndash); #endif mr_mip->ndash=mr_mip->base-mr_mip->w14->w[0]; /* = N' mod b */ copy(n,mr_mip->modulus); mr_mip->check=OFF; mr_shift(_MIPP_ mr_mip->modulus,(int)mr_mip->modulus->len,mr_mip->pR); mr_mip->check=ON; #ifdef MR_PENTIUM /* prime the FP stack */ if (mr_mip->ACTIVE) { ndash=mr_mip->ndash; base=mr_mip->base; magic *=base; ASM { finit fldcw WORD PTR control fld QWORD PTR ndash fld1 fld QWORD PTR base fdiv fld QWORD PTR magic } } #endif nres(_MIPP_ mr_mip->one,mr_mip->one); MR_OUT return mr_mip->ndash; } void nres(_MIPD_ big x,big y) { /* convert x to n-residue format */ #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif if (mr_mip->ERNUM) return; MR_IN(81) if (size(mr_mip->modulus)==0) { mr_berror(_MIPP_ MR_ERR_NO_MODULUS); MR_OUT return; } copy(x,y); divide(_MIPP_ y,mr_mip->modulus,mr_mip->modulus); if (size(y)<0) add(_MIPP_ y,mr_mip->modulus,y); if (!mr_mip->MONTY) { MR_OUT return; } mr_mip->check=OFF; mr_shift(_MIPP_ y,(int)mr_mip->modulus->len,mr_mip->w0); divide(_MIPP_ mr_mip->w0,mr_mip->modulus,mr_mip->modulus); mr_mip->check=ON; copy(mr_mip->w0,y); MR_OUT } void redc(_MIPD_ big x,big y) { /* Montgomery's REDC function p. 520 */ /* also used to convert n-residues back to normal form */ mr_small carry,delay_carry,m,ndash,*w0g,*mg; #ifdef MR_ITANIUM mr_small tm; #endif #ifdef MR_WIN64 mr_small tm,tr; #endif int i,j,rn,rn2; big w0,modulus; #ifdef MR_NOASM union doubleword dble; mr_large dbled,ldres; #endif #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif if (mr_mip->ERNUM) return; MR_IN(82) w0=mr_mip->w0; /* get these into local variables (for inline assembly) */ modulus=mr_mip->modulus; ndash=mr_mip->ndash; copy(x,w0); if (!mr_mip->MONTY) { /*#ifdef MR_CELL mod256(_MIPP_ w0,w0); #else */ divide(_MIPP_ w0,modulus,modulus); /* #endif */ copy(w0,y); MR_OUT return; } delay_carry=0; rn=(int)modulus->len; rn2=rn+rn; #ifndef MR_SIMPLE_BASE if (mr_mip->base==0) { #endif #ifndef MR_NOFULLWIDTH mg=modulus->w; w0g=w0->w; for (i=0;iw[i],ndash,0,&m); Note that after this time */ m=ndash*w0->w[i]; carry=0; /* around the loop, w0[i]=0 */ for (j=0;jw[j]+carry+w0->w[i+j]; w0->w[i+j]=dble.h[MR_BOT]; carry=dble.h[MR_TOP]; #else muldvd2(m,modulus->w[j],&carry,&w0->w[i+j]); #endif } w0->w[rn+i]+=delay_carry; if (w0->w[rn+i]w[rn+i]+=carry; if (w0->w[rn+i]w[i],ndash,0,mr_mip->base,mr_mip->inverse_base,&m); #else muldiv(w0->w[i],ndash,0,mr_mip->base,&m); #endif carry=0; for (j=0;jw[j]+carry+w0->w[i+j]; #ifdef MR_FP_ROUNDING carry=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); #else #ifndef MR_FP if (mr_mip->base==mr_mip->base2) carry=(mr_small)(dbled>>mr_mip->lg2b); else #endif carry=(mr_small)MR_LROUND(dbled/mr_mip->base); #endif w0->w[i+j]=(mr_small)(dbled-(mr_large)carry*mr_mip->base); #else #ifdef MR_FP_ROUNDING carry=imuldiv(modulus->w[j],m,w0->w[i+j]+carry,mr_mip->base,mr_mip->inverse_base,&w0->w[i+j]); #else carry=muldiv(modulus->w[j],m,w0->w[i+j]+carry,mr_mip->base,&w0->w[i+j]); #endif #endif } w0->w[rn+i]+=(delay_carry+carry); delay_carry=0; if (w0->w[rn+i]>=mr_mip->base) { w0->w[rn+i]-=mr_mip->base; delay_carry=1; } } #endif w0->w[rn2]=delay_carry; w0->len=rn2+1; mr_shift(_MIPP_ w0,(-rn),w0); mr_lzero(w0); if (mr_compare(w0,modulus)>=0) mr_psub(_MIPP_ w0,modulus,w0); copy(w0,y); MR_OUT } /* "Complex" method for ZZn2 squaring */ void nres_complex(_MIPD_ big a,big b,big r,big i) { #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif if (mr_mip->ERNUM) return; MR_IN(225) if (mr_mip->NO_CARRY && mr_mip->qnr==-1) { /* if modulus is small enough we can ignore carries, and use simple addition and subtraction */ /* recall that Montgomery reduction can cope as long as product is less than pR */ #ifdef MR_COMBA #ifdef MR_COUNT_OPS fpa+=3; #endif if (mr_mip->ACTIVE) { comba_add(a,b,mr_mip->w1); comba_add(a,mr_mip->modulus,mr_mip->w2); /* a-b is p+a-b */ comba_sub(mr_mip->w2,b,mr_mip->w2); comba_add(a,a,r); } else { #endif mr_padd(_MIPP_ a,b,mr_mip->w1); mr_padd(_MIPP_ a,mr_mip->modulus,mr_mip->w2); mr_psub(_MIPP_ mr_mip->w2,b,mr_mip->w2); mr_padd(_MIPP_ a,a,r); #ifdef MR_COMBA } #endif nres_modmult(_MIPP_ r,b,i); nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w2,r); } else { nres_modadd(_MIPP_ a,b,mr_mip->w1); nres_modsub(_MIPP_ a,b,mr_mip->w2); if (mr_mip->qnr==-2) nres_modsub(_MIPP_ mr_mip->w2,b,mr_mip->w2); nres_modmult(_MIPP_ a,b,i); nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w2,r); if (mr_mip->qnr==-2) nres_modadd(_MIPP_ r,i,r); nres_modadd(_MIPP_ i,i,i); } MR_OUT } #ifndef MR_NO_LAZY_REDUCTION /* Lazy reduction technique for zzn2 multiplication - competitive if Reduction is more expensive that Multiplication. This is true for pairing-based crypto. Note that Lazy reduction can also be used with Karatsuba! Uses w1, w2, w5, and w6. Reduction poly is X^2-D=0 (a0+a1.X).(b0+b1.X) = (a0.b0 + D.a1.b1) + (a1.b0+a0.b1).X Karatsuba (a0.b0+D.a1.b1) + ((a0+a1)(b0+b1) - a0.b0 - a1.b1).X */ void nres_lazy(_MIPD_ big a0,big a1,big b0,big b1,big r,big i) { #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif if (mr_mip->ERNUM) return; mr_mip->check=OFF; #ifdef MR_COUNT_OPS fpc+=3; fpa+=5; if (mr_mip->qnr==-2) fpa++; #endif #ifdef MR_COMBA if (mr_mip->ACTIVE) { comba_mult(a0,b0,mr_mip->w0); comba_mult(a1,b1,mr_mip->w5); } else { #endif #ifdef MR_KCM if (mr_mip->ACTIVE) { kcm_mul(_MIPP_ a1,b1,mr_mip->w5); /* this destroys w0! */ kcm_mul(_MIPP_ a0,b0,mr_mip->w0); } else { #endif MR_IN(151) multiply(_MIPP_ a0,b0,mr_mip->w0); multiply(_MIPP_ a1,b1,mr_mip->w5); #ifdef MR_COMBA } #endif #ifdef MR_KCM } #endif if (mr_mip->NO_CARRY && mr_mip->qnr==-1) { /* if modulus is small enough we can ignore carries, and use simple addition and subtraction */ #ifdef MR_COMBA #ifdef MR_COUNT_OPS fpa+=2; #endif if (mr_mip->ACTIVE) { comba_double_add(mr_mip->w0,mr_mip->w5,mr_mip->w6); comba_add(a0,a1,mr_mip->w1); comba_add(b0,b1,mr_mip->w2); } else { #endif mr_padd(_MIPP_ mr_mip->w0,mr_mip->w5,mr_mip->w6); mr_padd(_MIPP_ a0,a1,mr_mip->w1); mr_padd(_MIPP_ b0,b1,mr_mip->w2); #ifdef MR_COMBA } #endif } else { nres_double_modadd(_MIPP_ mr_mip->w0,mr_mip->w5,mr_mip->w6); /* w6 = a0.b0+a1.b1 */ if (mr_mip->qnr==-2) nres_double_modadd(_MIPP_ mr_mip->w5,mr_mip->w5,mr_mip->w5); nres_modadd(_MIPP_ a0,a1,mr_mip->w1); nres_modadd(_MIPP_ b0,b1,mr_mip->w2); } nres_double_modsub(_MIPP_ mr_mip->w0,mr_mip->w5,mr_mip->w0); /* r = a0.b0+D.a1.b1 */ #ifdef MR_COMBA if (mr_mip->ACTIVE) { comba_redc(_MIPP_ mr_mip->w0,r); comba_mult(mr_mip->w1,mr_mip->w2,mr_mip->w0); } else { #endif #ifdef MR_KCM if (mr_mip->ACTIVE) { kcm_redc(_MIPP_ mr_mip->w0,r); kcm_mul(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w0); } else { #endif redc(_MIPP_ mr_mip->w0,r); multiply(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w0); /* w0=(a0+a1)*(b0+b1) */ #ifdef MR_COMBA } #endif #ifdef MR_KCM } #endif if (mr_mip->NO_CARRY && mr_mip->qnr==-1) { #ifdef MR_COMBA if (mr_mip->ACTIVE) comba_double_sub(mr_mip->w0,mr_mip->w6,mr_mip->w0); else #endif mr_psub(_MIPP_ mr_mip->w0,mr_mip->w6,mr_mip->w0); } else nres_double_modsub(_MIPP_ mr_mip->w0,mr_mip->w6,mr_mip->w0); /* (a0+a1)*(b0+b1) - w6 */ #ifdef MR_COMBA if (mr_mip->ACTIVE) { comba_redc(_MIPP_ mr_mip->w0,i); } else { #endif #ifdef MR_KCM if (mr_mip->ACTIVE) { kcm_redc(_MIPP_ mr_mip->w0,i); } else { #endif redc(_MIPP_ mr_mip->w0,i); MR_OUT #ifdef MR_COMBA } #endif #ifdef MR_KCM } #endif mr_mip->check=ON; } #endif #ifndef MR_STATIC void nres_dotprod(_MIPD_ int n,big *x,big *y,big w) { int i; #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif if (mr_mip->ERNUM) return; MR_IN(120) mr_mip->check=OFF; zero(mr_mip->w7); for (i=0;iw0); mr_padd(_MIPP_ mr_mip->w7,mr_mip->w0,mr_mip->w7); } copy(mr_mip->pR,mr_mip->w6); /* w6 = p.R */ divide(_MIPP_ mr_mip->w7,mr_mip->w6,mr_mip->w6); redc(_MIPP_ mr_mip->w7,w); mr_mip->check=ON; MR_OUT } #endif void nres_negate(_MIPD_ big x, big w) { #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif if (size(x)==0) { zero(w); return; } #ifdef MR_COMBA if (mr_mip->ACTIVE) { comba_negate(_MIPP_ x,w); return; } else { #endif if (mr_mip->ERNUM) return; MR_IN(92) mr_psub(_MIPP_ mr_mip->modulus,x,w); MR_OUT #ifdef MR_COMBA } #endif } void nres_div2(_MIPD_ big x,big w) { #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif MR_IN(198) copy(x,mr_mip->w1); if (remain(_MIPP_ mr_mip->w1,2)!=0) add(_MIPP_ mr_mip->w1,mr_mip->modulus,mr_mip->w1); subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1); copy(mr_mip->w1,w); MR_OUT } void nres_div3(_MIPD_ big x,big w) { #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif MR_IN(199) copy(x,mr_mip->w1); while (remain(_MIPP_ mr_mip->w1,3)!=0) add(_MIPP_ mr_mip->w1,mr_mip->modulus,mr_mip->w1); subdiv(_MIPP_ mr_mip->w1,3,mr_mip->w1); copy(mr_mip->w1,w); MR_OUT } void nres_div5(_MIPD_ big x,big w) { #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif MR_IN(208) copy(x,mr_mip->w1); while (remain(_MIPP_ mr_mip->w1,5)!=0) add(_MIPP_ mr_mip->w1,mr_mip->modulus,mr_mip->w1); subdiv(_MIPP_ mr_mip->w1,5,mr_mip->w1); copy(mr_mip->w1,w); MR_OUT } /* mod pR addition and subtraction */ #ifndef MR_NO_LAZY_REDUCTION void nres_double_modadd(_MIPD_ big x,big y,big w) { #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif #ifdef MR_COMBA if (mr_mip->ACTIVE) { comba_double_modadd(_MIPP_ x,y,w); return; } else { #endif if (mr_mip->ERNUM) return; MR_IN(153) mr_padd(_MIPP_ x,y,w); if (mr_compare(w,mr_mip->pR)>=0) mr_psub(_MIPP_ w,mr_mip->pR,w); MR_OUT #ifdef MR_COMBA } #endif } void nres_double_modsub(_MIPD_ big x,big y,big w) { #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif #ifdef MR_COMBA if (mr_mip->ACTIVE) { comba_double_modsub(_MIPP_ x,y,w); return; } else { #endif if (mr_mip->ERNUM) return; MR_IN(154) if (mr_compare(x,y)>=0) mr_psub(_MIPP_ x,y,w); else { mr_psub(_MIPP_ y,x,w); mr_psub(_MIPP_ mr_mip->pR,w,w); } MR_OUT #ifdef MR_COMBA } #endif } #endif void nres_modadd(_MIPD_ big x,big y,big w) { /* modular addition */ #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif #ifdef MR_COUNT_OPS fpa++; #endif #ifdef MR_COMBA if (mr_mip->ACTIVE) { comba_modadd(_MIPP_ x,y,w); return; } else { #endif if (mr_mip->ERNUM) return; MR_IN(90) mr_padd(_MIPP_ x,y,w); if (mr_compare(w,mr_mip->modulus)>=0) mr_psub(_MIPP_ w,mr_mip->modulus,w); MR_OUT #ifdef MR_COMBA } #endif } void nres_modsub(_MIPD_ big x,big y,big w) { /* modular subtraction */ #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif #ifdef MR_COUNT_OPS fpa++; #endif #ifdef MR_COMBA if (mr_mip->ACTIVE) { comba_modsub(_MIPP_ x,y,w); return; } else { #endif if (mr_mip->ERNUM) return; MR_IN(91) if (mr_compare(x,y)>=0) mr_psub(_MIPP_ x,y,w); else { mr_psub(_MIPP_ y,x,w); mr_psub(_MIPP_ mr_mip->modulus,w,w); } MR_OUT #ifdef MR_COMBA } #endif } int nres_moddiv(_MIPD_ big x,big y,big w) { /* Modular division using n-residues w=x/y mod n */ int gcd; #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif if (mr_mip->ERNUM) return 0; MR_IN(85) if (x==y) { /* Illegal parameter usage */ mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); MR_OUT return 0; } redc(_MIPP_ y,mr_mip->w6); gcd=invmodp(_MIPP_ mr_mip->w6,mr_mip->modulus,mr_mip->w6); if (gcd!=1) zero(w); /* fails silently and returns 0 */ else { nres(_MIPP_ mr_mip->w6,mr_mip->w6); nres_modmult(_MIPP_ x,mr_mip->w6,w); /* mad(_MIPP_ x,mr_mip->w6,x,mr_mip->modulus,mr_mip->modulus,w); */ } MR_OUT return gcd; } void nres_premult(_MIPD_ big x,int k,big w) { /* multiply n-residue by small ordinary integer */ #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif int sign=0; if (k==0) { zero(w); return; } if (k<0) { k=-k; sign=1; } if (mr_mip->ERNUM) return; MR_IN(102) if (k<=6) { switch (k) { case 1: copy(x,w); break; case 2: nres_modadd(_MIPP_ x,x,w); break; case 3: nres_modadd(_MIPP_ x,x,mr_mip->w0); nres_modadd(_MIPP_ x,mr_mip->w0,w); break; case 4: nres_modadd(_MIPP_ x,x,w); nres_modadd(_MIPP_ w,w,w); break; case 5: nres_modadd(_MIPP_ x,x,mr_mip->w0); nres_modadd(_MIPP_ mr_mip->w0,mr_mip->w0,mr_mip->w0); nres_modadd(_MIPP_ x,mr_mip->w0,w); break; case 6: nres_modadd(_MIPP_ x,x,w); nres_modadd(_MIPP_ w,w,mr_mip->w0); nres_modadd(_MIPP_ w,mr_mip->w0,w); break; } if (sign==1) nres_negate(_MIPP_ w,w); MR_OUT return; } mr_pmul(_MIPP_ x,(mr_small)k,mr_mip->w0); #ifdef MR_COMBA #ifdef MR_SPECIAL comba_redc(_MIPP_ mr_mip->w0,w); #else divide(_MIPP_ mr_mip->w0,mr_mip->modulus,mr_mip->modulus); copy(mr_mip->w0,w); #endif #else divide(_MIPP_ mr_mip->w0,mr_mip->modulus,mr_mip->modulus); copy(mr_mip->w0,w); #endif if (sign==1) nres_negate(_MIPP_ w,w); MR_OUT } void nres_modmult(_MIPD_ big x,big y,big w) { /* Modular multiplication using n-residues w=x*y mod n */ #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif if ((x==NULL || x->len==0) && x==w) return; if ((y==NULL || y->len==0) && y==w) return; if (y==NULL || x==NULL || x->len==0 || y->len==0) { zero(w); return; } #ifdef MR_COUNT_OPS fpc++; #endif #ifdef MR_COMBA if (mr_mip->ACTIVE) { if (x==y) comba_square(x,mr_mip->w0); else comba_mult(x,y,mr_mip->w0); comba_redc(_MIPP_ mr_mip->w0,w); } else { #endif #ifdef MR_KCM if (mr_mip->ACTIVE) { if (x==y) kcm_sqr(_MIPP_ x,mr_mip->w0); else kcm_mul(_MIPP_ x,y,mr_mip->w0); kcm_redc(_MIPP_ mr_mip->w0,w); } else { #endif #ifdef MR_PENTIUM if (mr_mip->ACTIVE) { if (x==y) fastmodsquare(_MIPP_ x,w); else fastmodmult(_MIPP_ x,y,w); } else { #endif if (mr_mip->ERNUM) return; MR_IN(83) mr_mip->check=OFF; multiply(_MIPP_ x,y,mr_mip->w0); redc(_MIPP_ mr_mip->w0,w); mr_mip->check=ON; MR_OUT #ifdef MR_COMBA } #endif #ifdef MR_KCM } #endif #ifdef MR_PENTIUM } #endif } /* Montgomery's trick for finding multiple * * simultaneous modular inverses * * Based on the observation that * * 1/x = yz*(1/xyz) * * 1/y = xz*(1/xyz) * * 1/z = xy*(1/xyz) * * Why are all of Peter Montgomery's clever * * algorithms always described as "tricks" ??*/ BOOL nres_double_inverse(_MIPD_ big x,big y,big w,big z) { /* find y=1/x mod n and z=1/w mod n */ /* 1/x = w/xw, and 1/w = x/xw */ #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif MR_IN(145) nres_modmult(_MIPP_ x,w,mr_mip->w6); /* xw */ if (size(mr_mip->w6)==0) { mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); MR_OUT return FALSE; } redc(_MIPP_ mr_mip->w6,mr_mip->w6); redc(_MIPP_ mr_mip->w6,mr_mip->w6); invmodp(_MIPP_ mr_mip->w6,mr_mip->modulus,mr_mip->w6); nres_modmult(_MIPP_ w,mr_mip->w6,mr_mip->w5); nres_modmult(_MIPP_ x,mr_mip->w6,z); copy(mr_mip->w5,y); MR_OUT return TRUE; } BOOL nres_multi_inverse(_MIPD_ int m,big *x,big *w) { /* find w[i]=1/x[i] mod n, for i=0 to m-1 * * x and w MUST be distinct */ int i; #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif if (m==0) return TRUE; if (m<0) return FALSE; MR_IN(118) if (x==w) { mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); MR_OUT return FALSE; } if (m==1) { copy(mr_mip->one,w[0]); nres_moddiv(_MIPP_ w[0],x[0],w[0]); MR_OUT return TRUE; } convert(_MIPP_ 1,w[0]); copy(x[0],w[1]); for (i=2;iw6); /* y=x[0]*x[1]*x[2]....x[m-1] */ if (size(mr_mip->w6)==0) { mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); MR_OUT return FALSE; } redc(_MIPP_ mr_mip->w6,mr_mip->w6); redc(_MIPP_ mr_mip->w6,mr_mip->w6); invmodp(_MIPP_ mr_mip->w6,mr_mip->modulus,mr_mip->w6); /* Now y=1/y */ copy(x[m-1],mr_mip->w5); nres_modmult(_MIPP_ w[m-1],mr_mip->w6,w[m-1]); for (i=m-2;;i--) { if (i==0) { nres_modmult(_MIPP_ mr_mip->w5,mr_mip->w6,w[0]); break; } nres_modmult(_MIPP_ w[i],mr_mip->w5,w[i]); nres_modmult(_MIPP_ w[i],mr_mip->w6,w[i]); nres_modmult(_MIPP_ mr_mip->w5,x[i],mr_mip->w5); } MR_OUT return TRUE; } /* initialise elliptic curve */ void ecurve_init(_MIPD_ big a,big b,big p,int type) { /* Initialize the active ecurve * * Asize indicate size of A * * Bsize indicate size of B */ int as; #ifdef MR_OS_THREADS miracl *mr_mip=get_mip(); #endif if (mr_mip->ERNUM) return; MR_IN(93) #ifndef MR_NO_SS mr_mip->SS=FALSE; /* no special support for super-singular curves */ #endif prepare_monty(_MIPP_ p); mr_mip->Asize=size(a); if (mr_abs(mr_mip->Asize)==MR_TOOBIG) { if (mr_mip->Asize>=0) { /* big positive number - check it isn't minus something small */ copy(a,mr_mip->w1); divide(_MIPP_ mr_mip->w1,p,p); subtract(_MIPP_ p,mr_mip->w1,mr_mip->w1); as=size(mr_mip->w1); if (asAsize=-as; } } nres(_MIPP_ a,mr_mip->A); mr_mip->Bsize=size(b); if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) { if (mr_mip->Bsize>=0) { /* big positive number - check it isn't minus something small */ copy(b,mr_mip->w1); divide(_MIPP_ mr_mip->w1,p,p); subtract(_MIPP_ p,mr_mip->w1,mr_mip->w1); as=size(mr_mip->w1); if (asBsize=-as; } } nres(_MIPP_ b,mr_mip->B); #ifdef MR_EDWARDS mr_mip->coord=MR_PROJECTIVE; /* only type supported for Edwards curves */ #else #ifndef MR_AFFINE_ONLY if (type==MR_BEST) mr_mip->coord=MR_PROJECTIVE; else mr_mip->coord=type; #else if (type==MR_PROJECTIVE) mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); #endif #endif MR_OUT return; }