KGC_TEST/KGC/miracl/source/mrmonty.c

1415 lines
32 KiB
C

/***************************************************************************
*
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 <http://www.gnu.org/licenses/>. *
*
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 <stdlib.h>
#include "miracl.h"
#ifdef MR_FP
#include <math.h>
#endif
#ifdef MR_WIN64
#include <intrin.h>
#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;i<rn;i++)
{
/* inline - substitutes for loop below */
#if INLINE_ASM == 1
ASM cld
ASM mov cx,rn
ASM mov si,i
ASM shl si,1
#ifdef MR_LMM
ASM push ds
ASM push es
ASM les bx,DWORD PTR w0g
ASM add bx,si
ASM mov ax,es:[bx]
ASM mul WORD PTR ndash
ASM mov di,ax
ASM lds si,DWORD PTR mg
#else
ASM mov bx,w0g
ASM add bx,si
ASM mov ax,[bx]
ASM mul WORD PTR ndash
ASM mov di,ax
ASM mov si,mg
#endif
ASM push bp
ASM xor bp,bp
m1:
ASM lodsw
ASM mul di
ASM add ax,bp
ASM adc dx,0
#ifdef MR_LMM
ASM add es:[bx],ax
#else
ASM add [bx],ax
#endif
ASM adc dx,0
ASM inc bx
ASM inc bx
ASM mov bp,dx
ASM loop m1
ASM pop bp
ASM mov ax,delay_carry
#ifdef MR_LMM
ASM add es:[bx],ax
ASM mov ax,0
ASM adc ax,0
ASM add es:[bx],dx
ASM pop es
ASM pop ds
#else
ASM add [bx],ax
ASM mov ax,0
ASM adc ax,0
ASM add [bx],dx
#endif
ASM adc ax,0
ASM mov delay_carry,ax
#endif
#if INLINE_ASM == 2
ASM cld
ASM mov cx,rn
ASM mov si,i
ASM shl si,2
#ifdef MR_LMM
ASM push ds
ASM push es
ASM les bx,DWORD PTR w0g
ASM add bx,si
ASM mov eax,es:[bx]
ASM mul DWORD PTR ndash
ASM mov edi,eax
ASM lds si,DWORD PTR mg
#else
ASM mov bx,w0g
ASM add bx,si
ASM mov eax,[bx]
ASM mul DWORD PTR ndash
ASM mov edi,eax
ASM mov si,mg
#endif
ASM push ebp
ASM xor ebp,ebp
m1:
ASM lodsd
ASM mul edi
ASM add eax,ebp
ASM adc edx,0
#ifdef MR_LMM
ASM add es:[bx],eax
#else
ASM add [bx],eax
#endif
ASM adc edx,0
ASM add bx,4
ASM mov ebp,edx
ASM loop m1
ASM pop ebp
ASM mov eax,delay_carry
#ifdef MR_LMM
ASM add es:[bx],eax
ASM mov eax,0
ASM adc eax,0
ASM add es:[bx],edx
ASM pop es
ASM pop ds
#else
ASM add [bx],eax
ASM mov eax,0
ASM adc eax,0
ASM add [bx],edx
#endif
ASM adc eax,0
ASM mov delay_carry,eax
#endif
#if INLINE_ASM == 3
ASM mov ecx,rn
ASM mov esi,i
ASM shl esi,2
ASM mov ebx,w0g
ASM add ebx,esi
ASM mov eax,[ebx]
ASM mul DWORD PTR ndash
ASM mov edi,eax
ASM mov esi,mg
ASM sub ebx,esi
ASM sub ebx,4
ASM push ebp
ASM xor ebp,ebp
m1:
ASM mov eax,[esi]
ASM add esi,4
ASM mul edi
ASM add eax,ebp
ASM mov ebp,[esi+ebx]
ASM adc edx,0
ASM add ebp,eax
ASM adc edx,0
ASM mov [esi+ebx],ebp
ASM dec ecx
ASM mov ebp,edx
ASM jnz m1
ASM pop ebp
ASM mov eax,delay_carry
ASM add [esi+ebx+4],eax
ASM mov eax,0
ASM adc eax,0
ASM add [esi+ebx+4],edx
ASM adc eax,0
ASM mov delay_carry,eax
#endif
#if INLINE_ASM == 4
ASM (
"movl %0,%%ecx\n"
"movl %1,%%esi\n"
"shll $2,%%esi\n"
"movl %2,%%ebx\n"
"addl %%esi,%%ebx\n"
"movl (%%ebx),%%eax\n"
"mull %3\n"
"movl %%eax,%%edi\n"
"movl %4,%%esi\n"
"subl %%esi,%%ebx\n"
"subl $4,%%ebx\n"
"pushl %%ebp\n"
"xorl %%ebp,%%ebp\n"
"m1:\n"
"movl (%%esi),%%eax\n"
"addl $4,%%esi\n"
"mull %%edi\n"
"addl %%ebp,%%eax\n"
"movl (%%esi,%%ebx),%%ebp\n"
"adcl $0,%%edx\n"
"addl %%eax,%%ebp\n"
"adcl $0,%%edx\n"
"movl %%ebp,(%%esi,%%ebx)\n"
"decl %%ecx\n"
"movl %%edx,%%ebp\n"
"jnz m1\n"
"popl %%ebp\n"
"movl %5,%%eax\n"
"addl %%eax,4(%%esi,%%ebx)\n"
"movl $0,%%eax\n"
"adcl $0,%%eax\n"
"addl %%edx,4(%%esi,%%ebx)\n"
"adcl $0,%%eax\n"
"movl %%eax,%5\n"
:
:"m"(rn),"m"(i),"m"(w0g),"m"(ndash),"m"(mg),"m"(delay_carry)
:"eax","edi","esi","ebx","ecx","edx","memory"
);
#endif
#ifndef INLINE_ASM
/* muldvd(w0->w[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;j<rn;j++)
{
#ifdef MR_NOASM
dble.d=(mr_large)m*modulus->w[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]<delay_carry) delay_carry=1;
else delay_carry=0;
w0->w[rn+i]+=carry;
if (w0->w[rn+i]<carry) delay_carry=1;
#endif
}
#endif
#ifndef MR_SIMPLE_BASE
}
else for (i=0;i<rn;i++)
{
#ifdef MR_FP_ROUNDING
imuldiv(w0->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;j<rn;j++)
{
#ifdef MR_NOASM
dbled=(mr_large)m*modulus->w[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;i<n;i++)
{
multiply(_MIPP_ x[i],y[i],mr_mip->w0);
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;i<m;i++)
nres_modmult(_MIPP_ w[i-1],x[i-1],w[i]);
nres_modmult(_MIPP_ w[m-1],x[m-1],mr_mip->w6); /* 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 (as<MR_TOOBIG) mr_mip->Asize=-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 (as<MR_TOOBIG) mr_mip->Bsize=-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;
}