From 6a598cbdb8b6a4c51123d1f0ca992fbfebfeccc9 Mon Sep 17 00:00:00 2001 From: "[GGSuchao]" <[1500062807@pku.edu.cn]> Date: Thu, 6 Jul 2017 11:41:39 +0800 Subject: [PATCH] add sm2_standard --- crypto/sm2/build.info | 10 +- crypto/sm2/miracl/mralloc.c | 85 ++ crypto/sm2/miracl/mrarth0.c | 320 +++++ crypto/sm2/miracl/mrarth1.c | 1068 +++++++++++++++ crypto/sm2/miracl/mrarth2.c | 1584 ++++++++++++++++++++++ crypto/sm2/miracl/mrarth3.c | 231 ++++ crypto/sm2/miracl/mrbits.c | 245 ++++ crypto/sm2/miracl/mrcore.c | 2290 ++++++++++++++++++++++++++++++++ crypto/sm2/miracl/mrcurve.c | 2507 +++++++++++++++++++++++++++++++++++ crypto/sm2/miracl/mrjack.c | 342 +++++ crypto/sm2/miracl/mrlucas.c | 157 +++ crypto/sm2/miracl/mrmonty.c | 1414 ++++++++++++++++++++ crypto/sm2/miracl/mrmuldv.c | 57 + crypto/sm2/miracl/mrsroot.c | 188 +++ crypto/sm2/miracl/mrxgcd.c | 495 +++++++ 15 files changed, 10990 insertions(+), 3 deletions(-) create mode 100644 crypto/sm2/miracl/mralloc.c create mode 100644 crypto/sm2/miracl/mrarth0.c create mode 100644 crypto/sm2/miracl/mrarth1.c create mode 100644 crypto/sm2/miracl/mrarth2.c create mode 100644 crypto/sm2/miracl/mrarth3.c create mode 100644 crypto/sm2/miracl/mrbits.c create mode 100644 crypto/sm2/miracl/mrcore.c create mode 100644 crypto/sm2/miracl/mrcurve.c create mode 100644 crypto/sm2/miracl/mrjack.c create mode 100644 crypto/sm2/miracl/mrlucas.c create mode 100644 crypto/sm2/miracl/mrmonty.c create mode 100644 crypto/sm2/miracl/mrmuldv.c create mode 100644 crypto/sm2/miracl/mrsroot.c create mode 100644 crypto/sm2/miracl/mrxgcd.c diff --git a/crypto/sm2/build.info b/crypto/sm2/build.info index 6b650d73..d87944c2 100644 --- a/crypto/sm2/build.info +++ b/crypto/sm2/build.info @@ -1,3 +1,7 @@ -LIBS=../../libcrypto -SOURCE[../../libcrypto]=sm2_err.c sm2_asn1.c sm2_id.c sm2_sign.c sm2_enc.c \ - sm2_oct.c sm2_exch.c sm2_kmeth.c +LIBS=../../libcrypto +SOURCE[../../libcrypto]=sm2_err.c sm2_asn1.c sm2_id.c sm2_sign.c sm2_enc.c \ + sm2_oct.c sm2_exch.c sm2_kmeth.c sm2_standard_enc.c sm2_standard_exch.c \ + sm2_standard_sign.c ./miracl/mralloc.c ./miracl/mrarth0.c \ + ./miracl/mrarth1.c ./miracl/mrarth2.c ./miracl/mrarth3.c ./miracl/mrbits.c \ + ./miracl/mrcore.c ./miracl/mrcurve.c ./miracl/mrjack.c ./miracl/mrlucas.c\ + ./miracl/mrmonty.c ./miracl/mrmuldv.c ./miracl/mrsroot.c ./miracl/mrxgcd.c diff --git a/crypto/sm2/miracl/mralloc.c b/crypto/sm2/miracl/mralloc.c new file mode 100644 index 00000000..f3855ad5 --- /dev/null +++ b/crypto/sm2/miracl/mralloc.c @@ -0,0 +1,85 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox IOM 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 memory allocation routines + * mralloc.c + * + * MIRACL C Memory allocation/deallocation + * Can be replaced with special user-defined routines + * Default is to standard system routines + * + * NOTE: uses calloc() which initialises memory to Zero, so make sure + * any substituted routine does the same! + */ + +#include +#include + +#ifndef MR_STATIC + +miracl *mr_first_alloc() +{ + return (miracl *)calloc(1,sizeof(miracl)); +} + +void *mr_alloc(_MIPD_ int num,int size) +{ + char *p; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip==NULL) + { + p=(char *)calloc(num,size); + return (void *)p; + } + + if (mr_mip->ERNUM) return NULL; + + p=(char *)calloc(num,size); + if (p==NULL) mr_berror(_MIPP_ MR_ERR_OUT_OF_MEMORY); + return (void *)p; + +} + +void mr_free(void *addr) +{ + if (addr==NULL) return; + free(addr); + return; +} + +#endif diff --git a/crypto/sm2/miracl/mrarth0.c b/crypto/sm2/miracl/mrarth0.c new file mode 100644 index 00000000..2016a1d4 --- /dev/null +++ b/crypto/sm2/miracl/mrarth0.c @@ -0,0 +1,320 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox IOM 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 arithmetic routines 0 - Add and subtract routines + * mrarth0.c + * + */ +#include + +void mr_padd(_MIPD_ big x,big y,big z) +{ /* add two big numbers, z=x+y where * + * x and y are positive */ + int i,lx,ly,lz,la; + mr_small carry,psum; + mr_small *gx,*gy,*gz; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + lx = (int)x->len; + ly = (int)y->len; + + if (ly>lx) + { + lz=ly; + la=lx; + if (x!=z) copy(y,z); + else la=ly; + } + else + { + lz=lx; + la=ly; + if (y!=z) copy(x,z); + else la=lx; + } + carry=0; + z->len=lz; + gx=x->w; gy=y->w; gz=z->w; + if (lznib || !mr_mip->check) z->len++; +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif + for (i=0;igx[i]) carry=0; + else if (psum0;i++ ) + { /* add by columns to the length of larger number (if there is a carry) */ + psum=gx[i]+gy[i]+carry; + if (psum>gx[i]) carry=0; + else if (psumcheck && i>=mr_mip->nib) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + return; + } + gz[i]=carry; + } +#ifndef MR_SIMPLE_BASE + } + else + { + for (i=0;i=mr_mip->base) + { /* set carry */ + carry=1; + psum-=mr_mip->base; + } + gz[i]=psum; + } + for (;i0;i++) + { + psum=gx[i]+gy[i]+carry; + carry=0; + if (psum>=mr_mip->base) + { /* set carry */ + carry=1; + psum-=mr_mip->base; + } + gz[i]=psum; + } + if (carry) + { /* carry left over - possible overflow */ + if (mr_mip->check && i>=mr_mip->nib) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + return; + } + gz[i]=carry; + } + } +#endif + if (gz[z->len-1]==0) z->len--; + +} + +void mr_psub(_MIPD_ big x,big y,big z) +{ /* subtract two big numbers z=x-y * + * where x and y are positive and x>y */ + int i,lx,ly; + mr_small borrow,pdiff; + mr_small *gx,*gy,*gz; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + lx = (int)x->len; + ly = (int)y->len; + if (ly>lx) + { + mr_berror(_MIPP_ MR_ERR_NEG_RESULT); + return; + } + if (y!=z) copy(x,z); + else ly=lx; + z->len=lx; + gx=x->w; gy=y->w; gz=z->w; + borrow=0; +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif + for (i=0;i0;i++) + { /* subtract by columns */ + if (i>lx) + { + mr_berror(_MIPP_ MR_ERR_NEG_RESULT); + return; + } + pdiff=gx[i]-gy[i]-borrow; + if (pdiffgx[i]) borrow=1; + gz[i]=pdiff; + } +#ifndef MR_SIMPLE_BASE + } + else for (i=0;i0;i++) + { /* subtract by columns */ + if (i>lx) + { + mr_berror(_MIPP_ MR_ERR_NEG_RESULT); + return; + } + pdiff=gy[i]+borrow; + borrow=0; + if (gx[i]>=pdiff) pdiff=gx[i]-pdiff; + else + { /* set borrow */ + pdiff=mr_mip->base+gx[i]-pdiff; + borrow=1; + } + gz[i]=pdiff; + } +#endif + mr_lzero(z); +} + +static void mr_select(_MIPD_ big x,int d,big y,big z) +{ /* perform required add or subtract operation */ + int sx,sy,sz,jf,xgty; +#ifdef MR_FLASH + if (mr_notint(x) || mr_notint(y)) + { + mr_berror(_MIPP_ MR_ERR_INT_OP); + return; + } +#endif + sx=exsign(x); + sy=exsign(y); + sz=0; + x->len&=MR_OBITS; /* force operands to be positive */ + y->len&=MR_OBITS; + xgty=mr_compare(x,y); + jf=(1+sx)+(1+d*sy)/2; + switch (jf) + { /* branch according to signs of operands */ + case 0: + if (xgty>=0) + mr_padd(_MIPP_ x,y,z); + else + mr_padd(_MIPP_ y,x,z); + sz=MINUS; + break; + case 1: + if (xgty<=0) + { + mr_psub(_MIPP_ y,x,z); + sz=PLUS; + } + else + { + mr_psub(_MIPP_ x,y,z); + sz=MINUS; + } + break; + case 2: + if (xgty>=0) + { + mr_psub(_MIPP_ x,y,z); + sz=PLUS; + } + else + { + mr_psub(_MIPP_ y,x,z); + sz=MINUS; + } + break; + case 3: + if (xgty>=0) + mr_padd(_MIPP_ x,y,z); + else + mr_padd(_MIPP_ y,x,z); + sz=PLUS; + break; + } + if (sz<0) z->len^=MR_MSBIT; /* set sign of result */ + if (x!=z && sx<0) x->len^=MR_MSBIT; /* restore signs to operands */ + if (y!=z && y!=x && sy<0) y->len^=MR_MSBIT; +} + +void add(_MIPD_ big x,big y,big z) +{ /* add two signed big numbers together z=x+y */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(27) + + mr_select(_MIPP_ x,PLUS,y,z); + + MR_OUT +} + +void subtract(_MIPD_ big x,big y,big z) +{ /* subtract two big signed numbers z=x-y */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(28) + + mr_select(_MIPP_ x,MINUS,y,z); + + MR_OUT +} + +void incr(_MIPD_ big x,int n,big z) +{ /* add int to big number: z=x+n */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(7) + + convert(_MIPP_ n,mr_mip->w0); + mr_select(_MIPP_ x,PLUS,mr_mip->w0,z); + + MR_OUT +} + +void decr(_MIPD_ big x,int n,big z) +{ /* subtract int from big number: z=x-n */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(8) + + convert(_MIPP_ n,mr_mip->w0); + mr_select(_MIPP_ x,MINUS,mr_mip->w0,z); + + MR_OUT +} + diff --git a/crypto/sm2/miracl/mrarth1.c b/crypto/sm2/miracl/mrarth1.c new file mode 100644 index 00000000..f43b798a --- /dev/null +++ b/crypto/sm2/miracl/mrarth1.c @@ -0,0 +1,1068 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox IOM 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 arithmetic routines 1 - multiplying and dividing BIG NUMBERS by + * integer numbers. + * mrarth1.c + * + */ + +#include + +#ifdef MR_FP +#include +#endif + +#ifdef MR_WIN64 +#include +#endif + +#ifdef MR_FP_ROUNDING +#ifdef __GNUC__ +#include +#endif + +/* Invert n and set FP rounding. + * Set to round up + * Calculate 1/n + * set to round down (towards zero) + * If rounding cannot be controlled, this function returns 0.0 */ + +mr_large mr_invert(mr_small n) +{ + mr_large inn; + int up= 0x1BFF; + +#ifdef _MSC_VER + #ifdef MR_NOASM +#define NO_EXTENDED + #endif +#endif + +#ifdef NO_EXTENDED + int down=0x1EFF; +#else + int down=0x1FFF; +#endif + +#ifdef __TURBOC__ + asm + { + fldcw WORD PTR up + fld1 + fld QWORD PTR n; + fdiv + fstp TBYTE PTR inn; + fldcw WORD PTR down; + } + return inn; +#endif +#ifdef _MSC_VER + _asm + { + fldcw WORD PTR up + fld1 + fld QWORD PTR n; + fdiv + fstp QWORD PTR inn; + fldcw WORD PTR down; + } + return inn; +#endif +#ifdef __GNUC__ +#ifdef i386 + __asm__ __volatile__ ( + "fldcw %2\n" + "fld1\n" + "fldl %1\n" + "fdivrp\n" + "fstpt %0\n" + "fldcw %3\n" + : "=m"(inn) + : "m"(n),"m"(up),"m"(down) + : "memory" + ); + return inn; +#else + fpsetround(FP_RP); + inn=(mr_large)1.0/n; + fpsetround(FP_RZ); + return inn; +#endif +#endif + return 0.0L; +} + +#endif + +void mr_pmul(_MIPD_ big x,mr_small sn,big z) +{ + int m,xl; + mr_lentype sx; + mr_small carry,*xg,*zg; + +#ifdef MR_ITANIUM + mr_small tm; +#endif +#ifdef MR_WIN64 + mr_small tm; +#endif +#ifdef MR_NOASM + union doubleword dble; + mr_large dbled; + mr_large ldres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (x!=z) + { + zero(z); + if (sn==0) return; + } + else if (sn==0) + { + zero(z); + return; + } + m=0; + carry=0; + sx=x->len&MR_MSBIT; + xl=(int)(x->len&MR_OBITS); + +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH + xg=x->w; zg=z->w; +/* inline 8086 assembly - substitutes for loop below */ +#ifdef INLINE_ASM +#if INLINE_ASM == 1 + ASM cld + ASM mov cx,xl + ASM or cx,cx + ASM je out1 +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les di,DWORD PTR zg + ASM lds si,DWORD PTR xg +#else + ASM mov ax,ds + ASM mov es,ax + ASM mov di,zg + ASM mov si,xg +#endif + ASM mov bx,sn + ASM push bp + ASM xor bp,bp + tcl1: + ASM lodsw + ASM mul bx + ASM add ax,bp + ASM adc dx,0 + ASM stosw + ASM mov bp,dx + ASM loop tcl1 + + ASM mov ax,bp + ASM pop bp +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif + ASM mov carry,ax + out1: +#endif +#if INLINE_ASM == 2 + ASM cld + ASM mov cx,xl + ASM or cx,cx + ASM je out1 +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les di,DWORD PTR zg + ASM lds si,DWORD PTR xg +#else + ASM mov ax,ds + ASM mov es,ax + ASM mov di,zg + ASM mov si,xg +#endif + ASM mov ebx,sn + ASM push ebp + ASM xor ebp,ebp + tcl1: + ASM lodsd + ASM mul ebx + ASM add eax,ebp + ASM adc edx,0 + ASM stosd + ASM mov ebp,edx + ASM loop tcl1 + + ASM mov eax,ebp + ASM pop ebp +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif + ASM mov carry,eax + out1: +#endif +#if INLINE_ASM == 3 + ASM mov ecx,xl + ASM or ecx,ecx + ASM je out1 + ASM mov ebx,sn + ASM mov edi,zg + ASM mov esi,xg + ASM push ebp + ASM xor ebp,ebp + tcl1: + ASM mov eax,[esi] + ASM add esi,4 + ASM mul ebx + ASM add eax,ebp + ASM adc edx,0 + ASM mov [edi],eax + ASM add edi,4 + ASM mov ebp,edx + ASM dec ecx + ASM jnz tcl1 + + ASM mov eax,ebp + ASM pop ebp + ASM mov carry,eax + out1: +#endif +#if INLINE_ASM == 4 + + ASM ( + "movl %4,%%ecx\n" + "orl %%ecx,%%ecx\n" + "je 1f\n" + "movl %3,%%ebx\n" + "movl %1,%%edi\n" + "movl %2,%%esi\n" + "pushl %%ebp\n" + "xorl %%ebp,%%ebp\n" + "0:\n" + "movl (%%esi),%%eax\n" + "addl $4,%%esi\n" + "mull %%ebx\n" + "addl %%ebp,%%eax\n" + "adcl $0,%%edx\n" + "movl %%eax,(%%edi)\n" + "addl $4,%%edi\n" + "movl %%edx,%%ebp\n" + "decl %%ecx\n" + "jnz 0b\n" + + "movl %%ebp,%%eax\n" + "popl %%ebp\n" + "movl %%eax,%0\n" + "1:" + :"=m"(carry) + :"m"(zg),"m"(xg),"m"(sn),"m"(xl) + :"eax","edi","esi","ebx","ecx","edx","memory" + ); + +#endif +#endif +#ifndef INLINE_ASM + for (m=0;mw[m]*sn+carry; + carry=dble.h[MR_TOP]; + z->w[m]=dble.h[MR_BOT]; + } +#else + carry=muldvd(x->w[m],sn,carry,&z->w[m]); +#endif +#endif + if (carry>0) + { + m=xl; + if (m>=mr_mip->nib && mr_mip->check) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + return; + } + z->w[m]=carry; + z->len=m+1; + } + else z->len=xl; +#endif +#ifndef MR_SIMPLE_BASE + } + else while (m0) + { /* multiply each digit of x by n */ + + if (m>mr_mip->nib && mr_mip->check) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + return; + } +#ifdef MR_NOASM + dbled=(mr_large)x->w[m]*sn+carry; + #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 + z->w[m]=(mr_small)(dbled-(mr_large)carry*mr_mip->base); +#else + #ifdef MR_FP_ROUNDING + carry=imuldiv(x->w[m],sn,carry,mr_mip->base,mr_mip->inverse_base,&z->w[m]); + #else + carry=muldiv(x->w[m],sn,carry,mr_mip->base,&z->w[m]); + #endif +#endif + + m++; + z->len=m; + } +#endif + if (z->len!=0) z->len|=sx; +} + +void premult(_MIPD_ big x,int n,big z) +{ /* premultiply a big number by an int z=x.n */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(9) + + +#ifdef MR_FLASH + if (mr_notint(x)) + { + mr_berror(_MIPP_ MR_ERR_INT_OP); + MR_OUT + return; + } +#endif + if (n==0) /* test for some special cases */ + { + zero(z); + MR_OUT + return; + } + if (n==1) + { + copy(x,z); + MR_OUT + return; + } + if (n<0) + { + n=(-n); + mr_pmul(_MIPP_ x,(mr_small)n,z); + if (z->len!=0) z->len^=MR_MSBIT; + } + else mr_pmul(_MIPP_ x,(mr_small)n,z); + MR_OUT +} + +#ifdef MR_FP_ROUNDING +mr_small mr_sdiv(_MIPD_ big x,mr_small sn,mr_large isn,big z) +#else +mr_small mr_sdiv(_MIPD_ big x,mr_small sn,big z) +#endif +{ + int i,xl; + mr_small sr,*xg,*zg; +#ifdef MR_NOASM + union doubleword dble; + mr_large dbled; + mr_large ldres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + sr=0; + xl=(int)(x->len&MR_OBITS); + if (x!=z) zero(z); +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH + xg=x->w; zg=z->w; +/* inline - substitutes for loop below */ +#ifdef INLINE_ASM +#if INLINE_ASM == 1 + ASM std + ASM mov cx,xl + ASM or cx,cx + ASM je out2 + ASM mov bx,cx + ASM shl bx,1 + ASM sub bx,2 +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les di,DWORD PTR zg + ASM lds si,DWORD PTR xg +#else + ASM mov ax,ds + ASM mov es,ax + ASM mov di,zg + ASM mov si,xg +#endif + ASM add si,bx + ASM add di,bx + ASM mov bx,sn + ASM push bp + ASM xor bp,bp + tcl2: + ASM mov dx,bp + ASM lodsw + ASM div bx + ASM mov bp,dx + ASM stosw + ASM loop tcl2 + + ASM mov ax,bp + ASM pop bp +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif + ASM mov sr,ax + out2: + ASM cld +#endif +#if INLINE_ASM == 2 + ASM std + ASM mov cx,xl + ASM or cx,cx + ASM je out2 + ASM mov bx,cx + ASM shl bx,2 + ASM sub bx,4 +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les di,DWORD PTR zg + ASM lds si,DWORD PTR xg +#else + ASM mov ax,ds + ASM mov es,ax + ASM mov di, zg + ASM mov si, xg +#endif + ASM add si,bx + ASM add di,bx + ASM mov ebx,sn + ASM push ebp + ASM xor ebp,ebp + tcl2: + ASM mov edx,ebp + ASM lodsd + ASM div ebx + ASM mov ebp,edx + ASM stosd + ASM loop tcl2 + + ASM mov eax,ebp + ASM pop ebp +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif + ASM mov sr,eax + out2: + ASM cld +#endif +#if INLINE_ASM == 3 + ASM mov ecx,xl + ASM or ecx,ecx + ASM je out2 + ASM mov ebx,ecx + ASM shl ebx,2 + ASM mov esi, xg + ASM add esi,ebx + ASM mov edi, zg + ASM add edi,ebx + ASM mov ebx,sn + ASM push ebp + ASM xor ebp,ebp + tcl2: + ASM sub esi,4 + ASM mov edx,ebp + ASM mov eax,[esi] + ASM div ebx + ASM sub edi,4 + ASM mov ebp,edx + ASM mov [edi],eax + ASM dec ecx + ASM jnz tcl2 + + ASM mov eax,ebp + ASM pop ebp + ASM mov sr,eax + out2: + ASM nop +#endif +#if INLINE_ASM == 4 + + ASM ( + "movl %4,%%ecx\n" + "orl %%ecx,%%ecx\n" + "je 3f\n" + "movl %%ecx,%%ebx\n" + "shll $2,%%ebx\n" + "movl %2,%%esi\n" + "addl %%ebx,%%esi\n" + "movl %1,%%edi\n" + "addl %%ebx,%%edi\n" + "movl %3,%%ebx\n" + "pushl %%ebp\n" + "xorl %%ebp,%%ebp\n" + "2:\n" + "subl $4,%%esi\n" + "movl %%ebp,%%edx\n" + "movl (%%esi),%%eax\n" + "divl %%ebx\n" + "subl $4,%%edi\n" + "movl %%edx,%%ebp\n" + "movl %%eax,(%%edi)\n" + "decl %%ecx\n" + "jnz 2b\n" + + "movl %%ebp,%%eax\n" + "popl %%ebp\n" + "movl %%eax,%0\n" + "3:" + "nop" + :"=m"(sr) + :"m"(zg),"m"(xg),"m"(sn),"m"(xl) + :"eax","edi","esi","ebx","ecx","edx","memory" + ); +#endif +#endif +#ifndef INLINE_ASM + for (i=xl-1;i>=0;i--) + { +#ifdef MR_NOASM + dble.h[MR_BOT]=x->w[i]; + dble.h[MR_TOP]=sr; + z->w[i]=(mr_small)(dble.d/sn); + sr=(mr_small)(dble.d-(mr_large)z->w[i]*sn); +#else + z->w[i]=muldvm(sr,x->w[i],sn,&sr); +#endif + } +#endif +#endif +#ifndef MR_SIMPLE_BASE + } + else for (i=xl-1;i>=0;i--) + { /* divide each digit of x by n */ +#ifdef MR_NOASM + dbled=(mr_large)sr*mr_mip->base+x->w[i]; +#ifdef MR_FP_ROUNDING + z->w[i]=(mr_small)MR_LROUND(dbled*isn); +#else + z->w[i]=(mr_small)MR_LROUND(dbled/sn); +#endif + sr=(mr_small)(dbled-(mr_large)z->w[i]*sn); +#else +#ifdef MR_FP_ROUNDING + z->w[i]=imuldiv(sr,mr_mip->base,x->w[i],sn,isn,&sr); +#else + z->w[i]=muldiv(sr,mr_mip->base,x->w[i],sn,&sr); +#endif +#endif + } +#endif + z->len=x->len; + mr_lzero(z); + return sr; +} + +int subdiv(_MIPD_ big x,int n,big z) +{ /* subdivide a big number by an int z=x/n * + * returns int remainder */ + mr_lentype sx; +#ifdef MR_FP_ROUNDING + mr_large in; +#endif + int r,i,msb; + mr_small lsb; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(10) +#ifdef MR_FLASH + if (mr_notint(x)) mr_berror(_MIPP_ MR_ERR_INT_OP); +#endif + if (n==0) mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); + if (mr_mip->ERNUM) + { + MR_OUT + return 0; + } + + if (x->len==0) + { + zero(z); + MR_OUT + return 0; + } + if (n==1) /* special case */ + { + copy(x,z); + MR_OUT + return 0; + } + sx=(x->len&MR_MSBIT); + if (n==2 && mr_mip->base==0) + { /* fast division by 2 using shifting */ +#ifndef MR_NOFULLWIDTH + +/* I don't want this code upsetting the compiler ... */ +/* mr_mip->base==0 can't happen with MR_NOFULLWIDTH */ + + copy(x,z); + msb=(int)(z->len&MR_OBITS)-1; + r=(int)z->w[0]&1; + for (i=0;;i++) + { + z->w[i]>>=1; + if (i==msb) + { + if (z->w[i]==0) mr_lzero(z); + break; + } + lsb=z->w[i+1]&1; + z->w[i]|=(lsb<<(MIRACL-1)); + } + + MR_OUT + if (sx==0) return r; + else return (-r); +#endif + } + +#ifdef MR_FP_ROUNDING + in=mr_invert(n); +#endif + if (n<0) + { + n=(-n); +#ifdef MR_FP_ROUNDING + r=(int)mr_sdiv(_MIPP_ x,(mr_small)n,in,z); +#else + r=(int)mr_sdiv(_MIPP_ x,(mr_small)n,z); +#endif + if (z->len!=0) z->len^=MR_MSBIT; + } +#ifdef MR_FP_ROUNDING + else r=(int)mr_sdiv(_MIPP_ x,(mr_small)n,in,z); +#else + else r=(int)mr_sdiv(_MIPP_ x,(mr_small)n,z); +#endif + MR_OUT + if (sx==0) return r; + else return (-r); +} + +int remain(_MIPD_ big x,int n) +{ /* return integer remainder when x divided by n */ + int r; + mr_lentype sx; +#ifdef MR_FP + mr_small dres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(88); + + sx=(x->len&MR_MSBIT); + + if (n==2 && MR_REMAIN(mr_mip->base,2)==0) + { /* fast odd/even check if base is even */ + MR_OUT + if ((int)MR_REMAIN(x->w[0],2)==0) return 0; + else + { + if (sx==0) return 1; + else return (-1); + } + } + if (n==8 && MR_REMAIN(mr_mip->base,8)==0) + { /* fast check */ + MR_OUT + r=(int)MR_REMAIN(x->w[0],8); + if (sx!=0) r=-r; + return r; + } + + copy(x,mr_mip->w0); + r=subdiv(_MIPP_ mr_mip->w0,n,mr_mip->w0); + MR_OUT + return r; +} + +BOOL subdivisible(_MIPD_ big x,int n) +{ + if (remain(_MIPP_ x,n)==0) return TRUE; + else return FALSE; +} + +int hamming(_MIPD_ big x) +{ + int h; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + MR_IN(148); + h=0; + copy(x,mr_mip->w1); + absol(mr_mip->w1,mr_mip->w1); + while (size(mr_mip->w1)!=0) + h+=subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1); + + MR_OUT + return h; +} + +void bytes_to_big(_MIPD_ int len,const char *ptr,big x) +{ /* convert len bytes into a big * + * The first byte is the Most significant */ + int i,j,m,n,r; + unsigned int dig; + unsigned char ch; + mr_small wrd; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(140); + + zero(x); + + if (len<=0) + { + MR_OUT + return; + } +/* remove leading zeros.. */ + + while (*ptr==0) + { + ptr++; len--; + if (len==0) + { + MR_OUT + return; + } + } + +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { /* pack bytes directly into big */ +#endif +#ifndef MR_NOFULLWIDTH + m=MIRACL/8; + n=len/m; + + r=len%m; + wrd=(mr_small)0; + if (r!=0) + { + n++; + for (j=0;jlen=n; + if (n>mr_mip->nib && mr_mip->check) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + MR_OUT + return; + } + if (r!=0) + { + n--; + x->w[n]=wrd; + } + + for (i=n-1;i>=0;i--) + { + for (j=0;jw[i]=wrd; + } + mr_lzero(x); /* needed */ +#endif +#ifndef MR_SIMPLE_BASE + } + else + { + for (i=0;iERNUM) break; +#if MIRACL==8 + mr_shift(_MIPP_ x,1,x); +#else + premult(_MIPP_ x,256,x); +#endif + ch=MR_TOBYTE(ptr[i]); + dig=ch; + incr(_MIPP_ x,(int)dig,x); + } + } +#endif + MR_OUT +} + +int big_to_bytes(_MIPD_ int max,big x,char *ptr,BOOL justify) +{ /* convert positive big into octet string */ + int i,j,r,m,n,len,start; + unsigned int dig; + unsigned char ch; + mr_small wrd; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM || max<0) return 0; + + if (max==0 && justify) return 0; + if (size(x)==0) + { + if (justify) + { + for (i=0;ibase==0) + { +#endif +#ifndef MR_NOFULLWIDTH + m=MIRACL/8; + n=(int)(x->len&MR_OBITS); + n--; + len=n*m; + wrd=x->w[n]; /* most significant */ + r=0; + while (wrd!=(mr_small)0) { r++; wrd>>=8; len++;} + r%=m; + + if (max>0 && len>max) + { + mr_berror(_MIPP_ MR_ERR_TOO_BIG); + MR_OUT + return 0; + } + + if (justify) + { + start=max-len; + for (i=0;iw[n--]; + for (i=r-1;i>=0;i--) + { + ptr[start+i]=(char)(wrd&0xFF); + wrd>>=8; + } + } + + for (i=r;iw[n--]; + for (j=m-1;j>=0;j--) + { + ptr[start+i+j]=(char)(wrd&0xFF); + wrd>>=8; + } + } +#endif +#ifndef MR_SIMPLE_BASE + } + else + { + copy(x,mr_mip->w1); + for (len=0;;len++) + { + if (mr_mip->ERNUM) break; + + if (size(mr_mip->w1)==0) + { + if (justify) + { + if (len==max) break; + } + else break; + } + + if (max>0 && len>=max) + { + mr_berror(_MIPP_ MR_ERR_TOO_BIG); + MR_OUT + return 0; + } +#if MIRACL==8 + ch=mr_mip->w1->w[0]; + mr_shift(_MIPP_ mr_mip->w1,-1,mr_mip->w1); +#else + dig=(unsigned int)subdiv(_MIPP_ mr_mip->w1,256,mr_mip->w1); + ch=MR_TOBYTE(dig); +#endif + for (i=len;i>0;i--) ptr[i]=ptr[i-1]; + ptr[0]=MR_TOBYTE(ch); + } + } +#endif + MR_OUT + if (justify) return max; + else return len; +} + +#ifndef MR_NO_ECC_MULTIADD + +/* Solinas's Joint Sparse Form */ + +void mr_jsf(_MIPD_ big k0,big k1,big u0p,big u0m,big u1p,big u1m) +{ + int j,u0,u1,d0,d1,l0,l1; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(191) + + d0=d1=0; + + convert(_MIPP_ 1,mr_mip->w1); + copy(k0,mr_mip->w2); + copy(k1,mr_mip->w3); + zero(u0p); zero(u0m); zero(u1p); zero(u1m); + + j=0; + while (!mr_mip->ERNUM) + { + if (size(mr_mip->w2)==0 && d0==0 && size(mr_mip->w3)==0 && d1==0) break; + l0=remain(_MIPP_ mr_mip->w2,8); + l0=(l0+d0)&0x7; + l1=remain(_MIPP_ mr_mip->w3,8); + l1=(l1+d1)&0x7; + + if (l0%2==0) u0=0; + else + { + u0=2-(l0%4); + if ((l0==3 || l0==5) && l1%4==2) u0=-u0; + } + if (l1%2==0) u1=0; + else + { + u1=2-(l1%4); + if ((l1==3 || l1==5) && l0%4==2) u1=-u1; + } +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + if (u0>0) mr_addbit(_MIPP_ u0p,j); + if (u0<0) mr_addbit(_MIPP_ u0m,j); + if (u1>0) mr_addbit(_MIPP_ u1p,j); + if (u1<0) mr_addbit(_MIPP_ u1m,j); + +#ifndef MR_ALWAYS_BINARY + } + else + { + if (u0>0) add(_MIPP_ u0p,mr_mip->w1,u0p); + if (u0<0) add(_MIPP_ u0m,mr_mip->w1,u0m); + if (u1>0) add(_MIPP_ u1p,mr_mip->w1,u1p); + if (u1<0) add(_MIPP_ u1m,mr_mip->w1,u1m); + } +#endif + + if (d0+d0==1+u0) d0=1-d0; + if (d1+d1==1+u1) d1=1-d1; + + subdiv(_MIPP_ mr_mip->w2,2,mr_mip->w2); + subdiv(_MIPP_ mr_mip->w3,2,mr_mip->w3); + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) +#endif + j++; +#ifndef MR_ALWAYS_BINARY + else + premult(_MIPP_ mr_mip->w1,2,mr_mip->w1); +#endif + } + MR_OUT + return; +} + +#endif diff --git a/crypto/sm2/miracl/mrarth2.c b/crypto/sm2/miracl/mrarth2.c new file mode 100644 index 00000000..6daed161 --- /dev/null +++ b/crypto/sm2/miracl/mrarth2.c @@ -0,0 +1,1584 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox IOM 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 arithmetic routines 2 - multiplying and dividing BIG NUMBERS. + * mrarth2.c + * + */ + +#include + +#ifdef MR_FP +#include +#endif + +#ifdef MR_WIN64 +#include +#endif + + +/* If a number has more than this number of digits, then squaring is faster */ + +#define SQR_FASTER_THRESHOLD 5 + +mr_small normalise(_MIPD_ big x,big y) +{ /* normalise divisor */ + mr_small norm,r; +#ifdef MR_FP + mr_small dres; +#endif + int len; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + MR_IN(4) + + if (x!=y) copy(x,y); + len=(int)(y->len&MR_OBITS); +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH + if ((r=y->w[len-1]+1)==0) norm=1; +#ifdef MR_NOASM + else norm=(mr_small)(((mr_large)1 << MIRACL)/r); +#else + else norm=muldvm((mr_small)1,(mr_small)0,r,&r); +#endif + if (norm!=1) mr_pmul(_MIPP_ y,norm,y); +#endif +#ifndef MR_SIMPLE_BASE + } + else + { + norm=MR_DIV(mr_mip->base,(mr_small)(y->w[len-1]+1)); + if (norm!=1) mr_pmul(_MIPP_ y,norm,y); + } +#endif + MR_OUT + return norm; +} + +void multiply(_MIPD_ big x,big y,big z) +{ /* multiply two big numbers: z=x.y */ + int i,xl,yl,j,ti; + mr_small carry,*xg,*yg,*w0g; + +#ifdef MR_ITANIUM + mr_small tm; +#endif +#ifdef MR_WIN64 + mr_small tm,tr; +#endif + mr_lentype sz; + big w0; +#ifdef MR_NOASM + union doubleword dble; + mr_large dbled; + mr_large ldres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + if (y->len==0 || x->len==0) + { + zero(z); + return; + } + if (x!=mr_mip->w5 && y!=mr_mip->w5 && z==mr_mip->w5) w0=mr_mip->w5; + else w0=mr_mip->w0; /* local pointer */ + + MR_IN(5) + +#ifdef MR_FLASH + if (mr_notint(x) || mr_notint(y)) + { + mr_berror(_MIPP_ MR_ERR_INT_OP); + MR_OUT + return; + } +#endif + sz=((x->len&MR_MSBIT)^(y->len&MR_MSBIT)); + xl=(int)(x->len&MR_OBITS); + yl=(int)(y->len&MR_OBITS); + zero(w0); + if (mr_mip->check && xl+yl>mr_mip->nib) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + MR_OUT + return; + } +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH + xg=x->w; yg=y->w; w0g=w0->w; + if (x==y && xl>SQR_FASTER_THRESHOLD) + /* extra hassle make it not */ + /* worth it for small numbers */ + { /* fast squaring */ + for (i=0;iw[i]*x->w[j]+carry+w0->w[i+j]; + w0->w[i+j]=dble.h[MR_BOT]; + carry=dble.h[MR_TOP]; +#else + muldvd2(x->w[i],x->w[j],&carry,&w0->w[i+j]); +#endif + } + w0->w[xl+i]=carry; +#endif + } +#ifdef INLINE_ASM +#if INLINE_ASM == 1 + ASM mov cx,xl + ASM shl cx,1 +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les bx,DWORD PTR w0g +#else + ASM mov bx,w0g +#endif + tcl5: +#ifdef MR_LMM + ASM rcl WORD PTR es:[bx],1 +#else + ASM rcl WORD PTR [bx],1 +#endif + ASM inc bx + ASM inc bx + ASM loop tcl5 + + ASM cld + ASM mov cx,xl +#ifdef MR_LMM + ASM les di,DWORD PTR w0g + ASM lds si,DWORD PTR xg +#else + ASM mov di,w0g + ASM mov si,xg +#endif + + ASM xor bx,bx + tcl7: + ASM lodsw + ASM mul ax + ASM add ax,bx + ASM adc dx,0 +#ifdef MR_LMM + ASM add es:[di],ax +#else + ASM add [di],ax +#endif + ASM adc dx,0 + ASM xor bx,bx + ASM inc di + ASM inc di +#ifdef MR_LMM + ASM add es:[di],dx +#else + ASM add [di],dx +#endif + ASM adc bx,0 + ASM inc di + ASM inc di + ASM loop tcl7 +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif +#endif +#if INLINE_ASM == 2 + ASM mov cx,xl + ASM shl cx,1 +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les bx,DWORD PTR w0g +#else + ASM mov bx,w0g +#endif + tcl5: +#ifdef MR_LMM + ASM rcl DWORD PTR es:[bx],1 +#else + ASM rcl DWORD PTR [bx],1 +#endif + ASM inc bx + ASM inc bx + ASM inc bx + ASM inc bx + ASM loop tcl5 + + ASM cld + ASM mov cx,xl +#ifdef MR_LMM + ASM les di,DWORD PTR w0g + ASM lds si,DWORD PTR xg +#else + ASM mov di,w0g + ASM mov si,xg +#endif + ASM xor ebx,ebx + tcl7: + ASM lodsd + ASM mul eax + ASM add eax,ebx + ASM adc edx,0 +#ifdef MR_LMM + ASM add es:[di],eax +#else + ASM add [di],eax +#endif + ASM adc edx,0 + ASM xor ebx,ebx + ASM add di,4 +#ifdef MR_LMM + ASM add es:[di],edx +#else + ASM add [di],edx +#endif + ASM adc ebx,0 + ASM add di,4 + ASM loop tcl7 +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif +#endif +#if INLINE_ASM == 3 + ASM mov ecx,xl + ASM shl ecx,1 + ASM mov edi,w0g + tcl5: + ASM rcl DWORD PTR [edi],1 + ASM inc edi + ASM inc edi + ASM inc edi + ASM inc edi + ASM loop tcl5 + + ASM mov ecx,xl + ASM mov esi,xg + ASM mov edi,w0g + ASM xor ebx,ebx + tcl7: + ASM mov eax,[esi] + ASM add esi,4 + ASM mul eax + ASM add eax,ebx + ASM adc edx,0 + ASM add [edi],eax + ASM adc edx,0 + ASM xor ebx,ebx + ASM add edi,4 + ASM add [edi],edx + ASM adc ebx,0 + ASM add edi,4 + ASM dec ecx + ASM jnz tcl7 +#endif +#if INLINE_ASM == 4 + ASM ( + "movl %0,%%ecx\n" + "shll $1,%%ecx\n" + "movl %1,%%edi\n" + "tcl5:\n" + "rcll $1,(%%edi)\n" + "incl %%edi\n" + "incl %%edi\n" + "incl %%edi\n" + "incl %%edi\n" + "loop tcl5\n" + + "movl %0,%%ecx\n" + "movl %2,%%esi\n" + "movl %1,%%edi\n" + "xorl %%ebx,%%ebx\n" + "tcl7:\n" + "movl (%%esi),%%eax\n" + "addl $4,%%esi\n" + "mull %%eax\n" + "addl %%ebx,%%eax\n" + "adcl $0,%%edx\n" + "addl %%eax,(%%edi)\n" + "adcl $0,%%edx\n" + "xorl %%ebx,%%ebx\n" + "addl $4,%%edi\n" + "addl %%edx,(%%edi)\n" + "adcl $0,%%ebx\n" + "addl $4,%%edi\n" + "decl %%ecx\n" + "jnz tcl7\n" + : + :"m"(xl),"m"(w0g),"m"(xg) + :"eax","edi","esi","ebx","ecx","edx","memory" + ); +#endif +#endif +#ifndef INLINE_ASM + w0->len=xl+xl-1; + mr_padd(_MIPP_ w0,w0,w0); /* double it */ + carry=0; + for (i=0;iw[i]*x->w[i]+carry+w0->w[ti]; + w0->w[ti]=dble.h[MR_BOT]; + carry=dble.h[MR_TOP]; +#else + muldvd2(x->w[i],x->w[i],&carry,&w0->w[ti]); +#endif + w0->w[ti+1]+=carry; + if (w0->w[ti+1]w[i]*y->w[j]+carry+w0->w[i+j]; + w0->w[i+j]=dble.h[MR_BOT]; + carry=dble.h[MR_TOP]; +#else + muldvd2(x->w[i],y->w[j],&carry,&w0->w[i+j]); +#endif + } + w0->w[yl+i]=carry; +#endif + } +#endif +#ifndef MR_SIMPLE_BASE + } + else + { + if (x==y && xl>SQR_FASTER_THRESHOLD) + { /* squaring can be done nearly twice as fast */ + for (i=0;iw[i]*x->w[j]+w0->w[i+j]+carry; + #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(x->w[i],x->w[j],w0->w[i+j]+carry,mr_mip->base,mr_mip->inverse_base,&w0->w[i+j]); + #else + carry=muldiv(x->w[i],x->w[j],w0->w[i+j]+carry,mr_mip->base,&w0->w[i+j]); + #endif +#endif + } + w0->w[xl+i]=carry; + } + w0->len=xl+xl-1; + mr_padd(_MIPP_ w0,w0,w0); /* double it */ + carry=0; + for (i=0;iw[i]*x->w[i]+w0->w[ti]+carry; +#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[ti]=(mr_small)(dbled-(mr_large)carry*mr_mip->base); +#else + +#ifdef MR_FP_ROUNDING + carry=imuldiv(x->w[i],x->w[i],w0->w[ti]+carry,mr_mip->base,mr_mip->inverse_base,&w0->w[ti]); +#else + carry=muldiv(x->w[i],x->w[i],w0->w[ti]+carry,mr_mip->base,&w0->w[ti]); +#endif + +#endif + w0->w[ti+1]+=carry; + carry=0; + if (w0->w[ti+1]>=mr_mip->base) + { + carry=1; + w0->w[ti+1]-=mr_mip->base; + } + } + } + else for (i=0;iw[i]*y->w[j]+w0->w[i+j]+carry; + +#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(x->w[i],y->w[j],w0->w[i+j]+carry,mr_mip->base,mr_mip->inverse_base,&w0->w[i+j]); +#else + carry=muldiv(x->w[i],y->w[j],w0->w[i+j]+carry,mr_mip->base,&w0->w[i+j]); +#endif + +#endif + } + w0->w[yl+i]=carry; + } + } +#endif + w0->len=(sz|(xl+yl)); /* set length and sign of result */ + + mr_lzero(w0); + copy(w0,z); + MR_OUT +} + +void divide(_MIPD_ big x,big y,big z) +{ /* divide two big numbers z=x/y : x=x mod y * + * returns quotient only if divide(x,y,x) * + * returns remainder only if divide(x,y,y) */ + mr_small carry,attemp,ldy,sdy,ra,r,d,tst,psum; +#ifdef MR_FP + mr_small dres; +#endif + mr_lentype sx,sy,sz; + mr_small borrow,dig,*w0g,*yg; + int i,k,m,x0,y0,w00; + big w0; + +#ifdef MR_ITANIUM + mr_small tm; +#endif +#ifdef MR_WIN64 + mr_small tm; +#endif +#ifdef MR_NOASM + union doubleword dble; + mr_large dbled; + mr_large ldres; +#endif + BOOL check; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + w0=mr_mip->w0; + + MR_IN(6) + + if (x==y) mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); +#ifdef MR_FLASH + if (mr_notint(x) || mr_notint(y)) mr_berror(_MIPP_ MR_ERR_INT_OP); +#endif + if (y->len==0) mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); + if (mr_mip->ERNUM) + { + MR_OUT + return; + } + sx=(x->len&MR_MSBIT); /* extract signs ... */ + sy=(y->len&MR_MSBIT); + sz=(sx^sy); + x->len&=MR_OBITS; /* ... and force operands to positive */ + y->len&=MR_OBITS; + x0=(int)x->len; + y0=(int)y->len; + copy(x,w0); + w00=(int)w0->len; + if (mr_mip->check && (w00-y0+1>mr_mip->nib)) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + MR_OUT + return; + } + d=0; + if (x0==y0) + { + if (x0==1) /* special case - x and y are both mr_smalls */ + { + d=MR_DIV(w0->w[0],y->w[0]); + w0->w[0]=MR_REMAIN(w0->w[0],y->w[0]); + mr_lzero(w0); + } + else if (MR_DIV(w0->w[x0-1],4)w[x0-1]) + while (mr_compare(w0,y)>=0) + { /* mr_small quotient - so do up to four subtracts instead */ + mr_psub(_MIPP_ w0,y,w0); + d++; + } + } + if (mr_compare(w0,y)<0) + { /* x less than y - so x becomes remainder */ + if (x!=z) /* testing parameters */ + { + copy(w0,x); + if (x->len!=0) x->len|=sx; + } + if (y!=z) + { + zero(z); + z->w[0]=d; + if (d>0) z->len=(sz|1); + } + y->len|=sy; + MR_OUT + return; + } + + if (y0==1) + { /* y is int - so use subdiv instead */ +#ifdef MR_FP_ROUNDING + r=mr_sdiv(_MIPP_ w0,y->w[0],mr_invert(y->w[0]),w0); +#else + r=mr_sdiv(_MIPP_ w0,y->w[0],w0); +#endif + if (y!=z) + { + copy(w0,z); + z->len|=sz; + } + if (x!=z) + { + zero(x); + x->w[0]=r; + if (r>0) x->len=(sx|1); + } + y->len|=sy; + MR_OUT + return; + } + if (y!=z) zero(z); + d=normalise(_MIPP_ y,y); + check=mr_mip->check; + mr_mip->check=OFF; +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH + if (d!=1) mr_pmul(_MIPP_ w0,d,w0); + ldy=y->w[y0-1]; + sdy=y->w[y0-2]; + w0g=w0->w; yg=y->w; + for (k=w00-1;k>=y0-1;k--) + { /* long division */ +#ifdef INLINE_ASM +#if INLINE_ASM == 1 +#ifdef MR_LMM + ASM push ds + ASM lds bx,DWORD PTR w0g +#else + ASM mov bx,w0g +#endif + ASM mov si,k + ASM shl si,1 + ASM add bx,si + ASM mov dx,[bx+2] + ASM mov ax,[bx] + ASM cmp dx,ldy + ASM jne tcl8 + ASM mov di,0xffff + ASM mov si,ax + ASM add si,ldy + ASM jc tcl12 + ASM jmp tcl10 + tcl8: + ASM div WORD PTR ldy + ASM mov di,ax + ASM mov si,dx + tcl10: + ASM mov ax,sdy + ASM mul di + ASM cmp dx,si + ASM jb tcl12 + ASM jne tcl11 + ASM cmp ax,[bx-2] + ASM jbe tcl12 + tcl11: + ASM dec di + ASM add si,ldy + ASM jnc tcl10 + tcl12: + ASM mov attemp,di +#ifdef MR_LMM + ASM pop ds +#endif +#endif +/* NOTE push and pop of esi/edi should not be necessary - Borland C bug * + * These pushes are needed here even if register variables are disabled */ +#if INLINE_ASM == 2 + ASM push esi + ASM push edi +#ifdef MR_LMM + ASM push ds + ASM lds bx,DWORD PTR w0g +#else + ASM mov bx,w0g +#endif + ASM mov si,k + ASM shl si,2 + ASM add bx,si + ASM mov edx,[bx+4] + ASM mov eax,[bx] + ASM cmp edx,ldy + ASM jne tcl8 + ASM mov edi,0xffffffff + ASM mov esi,eax + ASM add esi,ldy + ASM jc tcl12 + ASM jmp tcl10 + tcl8: + ASM div DWORD PTR ldy + ASM mov edi,eax + ASM mov esi,edx + tcl10: + ASM mov eax,sdy + ASM mul edi + ASM cmp edx,esi + ASM jb tcl12 + ASM jne tcl11 + ASM cmp eax,[bx-4] + ASM jbe tcl12 + tcl11: + ASM dec edi + ASM add esi,ldy + ASM jnc tcl10 + tcl12: + ASM mov attemp,edi +#ifdef MR_LMM + ASM pop ds +#endif + ASM pop edi + ASM pop esi +#endif +#if INLINE_ASM == 3 + ASM push esi + ASM push edi + ASM mov ebx,w0g + ASM mov esi,k + ASM shl esi,2 + ASM add ebx,esi + ASM mov edx,[ebx+4] + ASM mov eax,[ebx] + ASM cmp edx,ldy + ASM jne tcl8 + ASM mov edi,0xffffffff + ASM mov esi,eax + ASM add esi,ldy + ASM jc tcl12 + ASM jmp tcl10 + tcl8: + ASM div DWORD PTR ldy + ASM mov edi,eax + ASM mov esi,edx + tcl10: + ASM mov eax,sdy + ASM mul edi + ASM cmp edx,esi + ASM jb tcl12 + ASM jne tcl11 + ASM cmp eax,[ebx-4] + ASM jbe tcl12 + tcl11: + ASM dec edi + ASM add esi,ldy + ASM jnc tcl10 + tcl12: + ASM mov attemp,edi + ASM pop edi + ASM pop esi +#endif +#if INLINE_ASM == 4 + ASM ( + "movl %1,%%ebx\n" + "movl %2,%%esi\n" + "shll $2,%%esi\n" + "addl %%esi,%%ebx\n" + "movl 4(%%ebx),%%edx\n" + "movl (%%ebx),%%eax\n" + "cmpl %3,%%edx\n" + "jne tcl8\n" + "movl $0xffffffff,%%edi\n" + "movl %%eax,%%esi\n" + "addl %3,%%esi\n" + "jc tcl12\n" + "jmp tcl10\n" + "tcl8:\n" + "divl %3\n" + "movl %%eax,%%edi\n" + "movl %%edx,%%esi\n" + "tcl10:\n" + "movl %4,%%eax\n" + "mull %%edi\n" + "cmpl %%esi,%%edx\n" + "jb tcl12\n" + "jne tcl11\n" + "cmpl -4(%%ebx),%%eax\n" + "jbe tcl12\n" + "tcl11:\n" + "decl %%edi\n" + "addl %3,%%esi\n" + "jnc tcl10\n" + "tcl12:\n" + "movl %%edi,%0\n" + :"=m"(attemp) + :"m"(w0g),"m"(k),"m"(ldy),"m"(sdy) + :"eax","edi","esi","ebx","ecx","edx","memory" + ); +#endif +#endif +#ifndef INLINE_ASM + carry=0; + if (w0->w[k+1]==ldy) /* guess next quotient digit */ + { + attemp=(mr_small)(-1); + ra=ldy+w0->w[k]; + if (raw[k]; + dble.h[MR_TOP]=w0->w[k+1]; + attemp=(mr_small)(dble.d/ldy); + ra=(mr_small)(dble.d-(mr_large)attemp*ldy); + } +#else + else attemp=muldvm(w0->w[k+1],w0->w[k],ldy,&ra); +#endif + while (carry==0) + { +#ifdef MR_NOASM + dble.d=(mr_large)attemp*sdy; + r=dble.h[MR_BOT]; + tst=dble.h[MR_TOP]; +#else + tst=muldvd(sdy,attemp,(mr_small)0,&r); +#endif + if (tst< ra || (tst==ra && r<=w0->w[k-1])) break; + attemp--; /* refine guess */ + ra+=ldy; + if (ra0) + { /* do partial subtraction */ + borrow=0; + /* inline - substitutes for loop below */ +#ifdef INLINE_ASM +#if INLINE_ASM == 1 + ASM cld + ASM mov cx,y0 + ASM mov si,m + ASM shl si,1 + ASM mov di,attemp +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les bx,DWORD PTR w0g + ASM add bx,si + ASM sub bx,2 + ASM lds si,DWORD PTR yg +#else + ASM mov bx,w0g + ASM add bx,si + ASM sub bx,2 + ASM mov si,yg +#endif + ASM push bp + ASM xor bp,bp + + tcl3: + ASM lodsw + ASM mul di + ASM add ax,bp + ASM adc dx,0 + ASM inc bx + ASM inc bx +#ifdef MR_LMM + ASM sub es:[bx],ax +#else + ASM sub [bx],ax +#endif + ASM adc dx,0 + ASM mov bp,dx + ASM loop tcl3 + + ASM mov ax,bp + ASM pop bp +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif + ASM mov borrow,ax +#endif +/* NOTE push and pop of esi/edi should not be necessary - Borland C bug * + * These pushes are needed here even if register variables are disabled */ +#if INLINE_ASM == 2 + ASM push esi + ASM push edi + ASM cld + ASM mov cx,y0 + ASM mov si,m + ASM shl si,2 + ASM mov edi,attemp +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les bx,DWORD PTR w0g + ASM add bx,si + ASM sub bx,4 + ASM lds si,DWORD PTR yg +#else + ASM mov bx,w0g + ASM add bx,si + ASM sub bx,4 + ASM mov si,yg +#endif + ASM push ebp + ASM xor ebp,ebp + + tcl3: + ASM lodsd + ASM mul edi + ASM add eax,ebp + ASM adc edx,0 + ASM add bx,4 +#ifdef MR_LMM + ASM sub es:[bx],eax +#else + ASM sub [bx],eax +#endif + ASM adc edx,0 + ASM mov ebp,edx + ASM loop tcl3 + + ASM mov eax,ebp + ASM pop ebp +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif + ASM mov borrow,eax + ASM pop edi + ASM pop esi +#endif +#if INLINE_ASM == 3 + ASM push esi + ASM push edi + ASM mov ecx,y0 + ASM mov esi,m + ASM shl esi,2 + ASM mov edi,attemp + ASM mov ebx,w0g + ASM add ebx,esi + ASM mov esi,yg + ASM sub ebx,esi + ASM sub ebx,4 + ASM push ebp + ASM xor ebp,ebp + + tcl3: + 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 sub ebp,eax + ASM adc edx,0 + ASM mov [esi+ebx],ebp + ASM dec ecx + ASM mov ebp,edx + ASM jnz tcl3 + + ASM mov eax,ebp + ASM pop ebp + ASM mov borrow,eax + ASM pop edi + ASM pop esi +#endif +#if INLINE_ASM == 4 + ASM ( + "movl %1,%%ecx\n" + "movl %2,%%esi\n" + "shll $2,%%esi\n" + "movl %3,%%edi\n" + "movl %4,%%ebx\n" + "addl %%esi,%%ebx\n" + "movl %5,%%esi\n" + "subl %%esi,%%ebx\n" + "subl $4,%%ebx\n" + "pushl %%ebp\n" + "xorl %%ebp,%%ebp\n" + "tcl3:\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" + "subl %%eax,%%ebp\n" + "adcl $0,%%edx\n" + "movl %%ebp,(%%esi,%%ebx)\n" + "decl %%ecx\n" + "movl %%edx,%%ebp\n" + "jnz tcl3\n" + + "movl %%ebp,%%eax\n" + "popl %%ebp\n" + "movl %%eax,%0\n" + + :"=m"(borrow) + :"m"(y0),"m"(m),"m"(attemp),"m"(w0g),"m"(yg) + :"eax","edi","esi","ebx","ecx","edx","memory" + ); +#endif +#endif +#ifndef INLINE_ASM + for (i=0;iw[i]+borrow; + dig=dble.h[MR_BOT]; + borrow=dble.h[MR_TOP]; +#else + borrow=muldvd(attemp,y->w[i],borrow,&dig); +#endif + if (w0->w[m+i]w[m+i]-=dig; + } +#endif + + if (w0->w[k+1]w[k+1]=0; + carry=0; + for (i=0;iw[m+i]+y->w[i]+carry; + if (psum>y->w[i]) carry=0; + if (psumw[i]) carry=1; + w0->w[m+i]=psum; + } + attemp--; /* ... and adjust guess */ + } + else w0->w[k+1]-=borrow; + } + if (k==w00-1 && attemp==0) w00--; + else if (y!=z) z->w[m]=attemp; + } +#endif +#ifndef MR_SIMPLE_BASE + } + else + { /* have to do it the hard way */ + if (d!=1) mr_pmul(_MIPP_ w0,d,w0); + ldy=y->w[y0-1]; + sdy=y->w[y0-2]; + + for (k=w00-1;k>=y0-1;k--) + { /* long division */ + + + if (w0->w[k+1]==ldy) /* guess next quotient digit */ + { + attemp=mr_mip->base-1; + ra=ldy+w0->w[k]; + } +#ifdef MR_NOASM + else + { + dbled=(mr_large)w0->w[k+1]*mr_mip->base+w0->w[k]; + attemp=(mr_small)MR_LROUND(dbled/ldy); + ra=(mr_small)(dbled-(mr_large)attemp*ldy); + } +#else + else attemp=muldiv(w0->w[k+1],mr_mip->base,w0->w[k],ldy,&ra); +#endif + while (rabase) + { +#ifdef MR_NOASM + dbled=(mr_large)sdy*attemp; +#ifdef MR_FP_ROUNDING + tst=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); +#else +#ifndef MR_FP + if (mr_mip->base==mr_mip->base2) + tst=(mr_small)(dbled>>mr_mip->lg2b); + else +#endif + tst=(mr_small)MR_LROUND(dbled/mr_mip->base); +#endif + r=(mr_small)(dbled-(mr_large)tst*mr_mip->base); +#else +#ifdef MR_FP_ROUNDING + tst=imuldiv(sdy,attemp,(mr_small)0,mr_mip->base,mr_mip->inverse_base,&r); +#else + tst=muldiv(sdy,attemp,(mr_small)0,mr_mip->base,&r); +#endif +#endif + if (tst< ra || (tst==ra && r<=w0->w[k-1])) break; + attemp--; /* refine guess */ + ra+=ldy; + } + m=k-y0+1; + if (attemp>0) + { /* do partial subtraction */ + borrow=0; + for (i=0;iw[i]+borrow; +#ifdef MR_FP_ROUNDING + borrow=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); +#else +#ifndef MR_FP + if (mr_mip->base==mr_mip->base2) + borrow=(mr_small)(dbled>>mr_mip->lg2b); + else +#endif + borrow=(mr_small)MR_LROUND(dbled/mr_mip->base); +#endif + dig=(mr_small)(dbled-(mr_large)borrow*mr_mip->base); +#else +#ifdef MR_FP_ROUNDING + borrow=imuldiv(attemp,y->w[i],borrow,mr_mip->base,mr_mip->inverse_base,&dig); +#else + borrow=muldiv(attemp,y->w[i],borrow,mr_mip->base,&dig); +#endif +#endif + if (w0->w[m+i]w[m+i]+=(mr_mip->base-dig); + } + else w0->w[m+i]-=dig; + } + if (w0->w[k+1]w[k+1]=0; + carry=0; + for (i=0;iw[m+i]+y->w[i]+carry; + carry=0; + if (psum>=mr_mip->base) + { + carry=1; + psum-=mr_mip->base; + } + w0->w[m+i]=psum; + } + attemp--; /* ... and adjust guess */ + } + else + w0->w[k+1]-=borrow; + } + if (k==w00-1 && attemp==0) w00--; + else if (y!=z) z->w[m]=attemp; + } + } +#endif + if (y!=z) z->len=((w00-y0+1)|sz); /* set sign and length of result */ + + w0->len=y0; + + mr_lzero(y); + mr_lzero(z); + + if (x!=z) + { + mr_lzero(w0); +#ifdef MR_FP_ROUNDING + if (d!=1) mr_sdiv(_MIPP_ w0,d,mr_invert(d),x); +#else + if (d!=1) mr_sdiv(_MIPP_ w0,d,x); +#endif + else copy(w0,x); + if (x->len!=0) x->len|=sx; + } +#ifdef MR_FP_ROUNDING + if (d!=1) mr_sdiv(_MIPP_ y,d,mr_invert(d),y); +#else + if (d!=1) mr_sdiv(_MIPP_ y,d,y); +#endif + y->len|=sy; + mr_mip->check=check; + + MR_OUT +} + +BOOL divisible(_MIPD_ big x,big y) +{ /* returns y|x, that is TRUE if y divides x exactly */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(87) + + copy (x,mr_mip->w0); + divide(_MIPP_ mr_mip->w0,y,y); + + MR_OUT + if (size(mr_mip->w0)==0) return TRUE; + else return FALSE; +} + +void mad(_MIPD_ big x,big y,big z,big w,big q,big r) +{ /* Multiply, Add and Divide; q=(x*y+z)/w remainder r * + * returns remainder only if w=q, quotient only if q=r * + * add done only if x, y and z are distinct. */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + BOOL check; + if (mr_mip->ERNUM) return; + + MR_IN(24) + if (w==r) + { + mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + MR_OUT + return; + } + check=mr_mip->check; + mr_mip->check=OFF; /* turn off some error checks */ + + multiply(_MIPP_ x,y,mr_mip->w0); + if (x!=z && y!=z) add(_MIPP_ mr_mip->w0,z,mr_mip->w0); + + divide(_MIPP_ mr_mip->w0,w,q); + if (q!=r) copy(mr_mip->w0,r); + mr_mip->check=check; + MR_OUT +} + diff --git a/crypto/sm2/miracl/mrarth3.c b/crypto/sm2/miracl/mrarth3.c new file mode 100644 index 00000000..5f4deb74 --- /dev/null +++ b/crypto/sm2/miracl/mrarth3.c @@ -0,0 +1,231 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox IOM 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 arithmetic routines 3 - simple powers and roots + * mrarth3.c + */ + +#include +#include + +void expint(_MIPD_ int b,int n,big x) +{ /* sets x=b^n */ + unsigned int bit,un; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + convert(_MIPP_ 1,x); + if (n==0) return; + + MR_IN(50) + + if (n<0) + { + mr_berror(_MIPP_ MR_ERR_NEG_POWER); + MR_OUT + return; + } + if (b==2) expb2(_MIPP_ n,x); + else + { + bit=1; + un=(unsigned int)n; + while (un>=bit) bit<<=1; + bit>>=1; + while (bit>0) + { /* ltr method */ + multiply(_MIPP_ x,x,x); + if ((bit&un)!=0) premult(_MIPP_ x,b,x); + bit>>=1; + } + } + MR_OUT +} + +void power(_MIPD_ big x,long n,big z,big w) +{ /* raise big number to int power w=x^n * + * (mod z if z and w distinct) */ + mr_small norm; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + copy(x,mr_mip->w5); + zero(w); + if(mr_mip->ERNUM || size(mr_mip->w5)==0) return; + convert(_MIPP_ 1,w); + if (n==0L) return; + + MR_IN(17) + + if (n<0L) + { + mr_berror(_MIPP_ MR_ERR_NEG_POWER); + MR_OUT + return; + } + + if (w==z) forever + { /* "Russian peasant" exponentiation */ + if (n%2!=0L) + multiply(_MIPP_ w,mr_mip->w5,w); + n/=2L; + if (mr_mip->ERNUM || n==0L) break; + multiply(_MIPP_ mr_mip->w5,mr_mip->w5,mr_mip->w5); + } + else + { + norm=normalise(_MIPP_ z,z); + divide(_MIPP_ mr_mip->w5,z,z); + forever + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + if (n%2!=0L) mad(_MIPP_ w,mr_mip->w5,mr_mip->w5,z,z,w); + n/=2L; + if (mr_mip->ERNUM || n==0L) break; + mad(_MIPP_ mr_mip->w5,mr_mip->w5,mr_mip->w5,z,z,mr_mip->w5); + } + if (norm!=1) + { +#ifdef MR_FP_ROUNDING + mr_sdiv(_MIPP_ z,norm,mr_invert(norm),z); +#else + mr_sdiv(_MIPP_ z,norm,z); +#endif + divide(_MIPP_ w,z,z); + } + } + + MR_OUT +} + +BOOL nroot(_MIPD_ big x,int n,big w) +{ /* extract lower approximation to nth root * + * w=x^(1/n) returns TRUE for exact root * + * uses Newtons method */ + int sx,dif,s,p,d,lg2,lgx,rem; + BOOL full; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + if (size(x)==0 || n==1) + { + copy(x,w); + return TRUE; + } + + MR_IN(16) + + if (n<1) mr_berror(_MIPP_ MR_ERR_BAD_ROOT); + sx=exsign(x); + if (n%2==0 && sx==MINUS) mr_berror(_MIPP_ MR_ERR_NEG_ROOT); + if (mr_mip->ERNUM) + { + MR_OUT + return FALSE; + } + insign(PLUS,x); + lgx=logb2(_MIPP_ x); + if (n>=lgx) + { /* root must be 1 */ + insign(sx,x); + convert(_MIPP_ sx,w); + MR_OUT + if (lgx==1) return TRUE; + else return FALSE; + } + expb2(_MIPP_ 1+(lgx-1)/n,mr_mip->w2); /* guess root as 2^(log2(x)/n) */ + s=(-(((int)x->len-1)/n)*n); + mr_shift(_MIPP_ mr_mip->w2,s/n,mr_mip->w2); + lg2=logb2(_MIPP_ mr_mip->w2)-1; + full=FALSE; + if (s==0) full=TRUE; + d=0; + p=1; + while (!mr_mip->ERNUM) + { /* Newtons method */ + copy(mr_mip->w2,mr_mip->w3); + mr_shift(_MIPP_ x,s,mr_mip->w4); + mr_mip->check=OFF; + power(_MIPP_ mr_mip->w2,n-1,mr_mip->w6,mr_mip->w6); + mr_mip->check=ON; + divide(_MIPP_ mr_mip->w4,mr_mip->w6,mr_mip->w2); + rem=size(mr_mip->w4); + subtract(_MIPP_ mr_mip->w2,mr_mip->w3,mr_mip->w2); + dif=size(mr_mip->w2); + subdiv(_MIPP_ mr_mip->w2,n,mr_mip->w2); + add(_MIPP_ mr_mip->w2,mr_mip->w3,mr_mip->w2); + p*=2; + if(plg2b) continue; + if (full && mr_abs(dif)w2,1,mr_mip->w2); + mr_mip->check=OFF; + power(_MIPP_ mr_mip->w2,n,mr_mip->w6,mr_mip->w6); + mr_mip->check=ON; + dif=mr_compare(x,mr_mip->w6); + } + copy(mr_mip->w2,w); + insign(sx,w); + insign(sx,x); + MR_OUT + if (rem==0 && dif==0) return TRUE; + else return FALSE; + } + else + { /* adjust precision */ + d*=2; + if (d==0) d=1; + s+=d*n; + if (s>=0) + { + d-=s/n; + s=0; + full=TRUE; + } + mr_shift(_MIPP_ mr_mip->w2,d,mr_mip->w2); + } + p/=2; + } + MR_OUT + return FALSE; +} + diff --git a/crypto/sm2/miracl/mrbits.c b/crypto/sm2/miracl/mrbits.c new file mode 100644 index 00000000..b14021f8 --- /dev/null +++ b/crypto/sm2/miracl/mrbits.c @@ -0,0 +1,245 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox IOM 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 bit manipulation routines + * mrbits.c + */ + +#include +#include + +#ifdef MR_FP +#include +#endif + +int logb2(_MIPD_ big x) +{ /* returns number of bits in x */ + int xl,lg2; + mr_small top; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM || size(x)==0) return 0; + + MR_IN(49) + + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + xl=(int)(x->len&MR_OBITS); + lg2=mr_mip->lg2b*(xl-1); + top=x->w[xl-1]; + while (top>=1) + { + lg2++; + top/=2; + } + +#ifndef MR_ALWAYS_BINARY + } + else + { + copy(x,mr_mip->w0); + insign(PLUS,mr_mip->w0); + lg2=0; + while (mr_mip->w0->len>1) + { +#ifdef MR_FP_ROUNDING + mr_sdiv(_MIPP_ mr_mip->w0,mr_mip->base2,mr_invert(mr_mip->base2),mr_mip->w0); +#else + mr_sdiv(_MIPP_ mr_mip->w0,mr_mip->base2,mr_mip->w0); +#endif + lg2+=mr_mip->lg2b; + } + + while (mr_mip->w0->w[0]>=1) + { + lg2++; + mr_mip->w0->w[0]/=2; + } + } +#endif + MR_OUT + return lg2; +} + +void sftbit(_MIPD_ big x,int n,big z) +{ /* shift x by n bits */ + int m; + mr_small sm; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + copy(x,z); + if (n==0) return; + + MR_IN(47) + + m=mr_abs(n); + sm=mr_shiftbits((mr_small)1,m%mr_mip->lg2b); + if (n>0) + { /* shift left */ + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + mr_shift(_MIPP_ z,n/mr_mip->lg2b,z); + mr_pmul(_MIPP_ z,sm,z); +#ifndef MR_ALWAYS_BINARY + } + else + { + expb2(_MIPP_ m,mr_mip->w1); + multiply(_MIPP_ z,mr_mip->w1,z); + } +#endif + } + else + { /* shift right */ + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + mr_shift(_MIPP_ z,n/mr_mip->lg2b,z); +#ifdef MR_FP_ROUNDING + mr_sdiv(_MIPP_ z,sm,mr_invert(sm),z); +#else + mr_sdiv(_MIPP_ z,sm,z); +#endif + +#ifndef MR_ALWAYS_BINARY + } + else + { + expb2(_MIPP_ m,mr_mip->w1); + divide(_MIPP_ z,mr_mip->w1,z); + } +#endif + } + MR_OUT +} + +void expb2(_MIPD_ int n,big x) +{ /* sets x=2^n */ + int r,p; +#ifndef MR_ALWAYS_BINARY + int i; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + convert(_MIPP_ 1,x); + if (n==0) return; + + MR_IN(149) + + if (n<0) + { + mr_berror(_MIPP_ MR_ERR_NEG_POWER); + MR_OUT + return; + } + r=n/mr_mip->lg2b; + p=n%mr_mip->lg2b; + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + mr_shift(_MIPP_ x,r,x); + x->w[x->len-1]=mr_shiftbits(x->w[x->len-1],p); +#ifndef MR_ALWAYS_BINARY + } + else + { + for (i=1;i<=r;i++) + mr_pmul(_MIPP_ x,mr_mip->base2,x); + mr_pmul(_MIPP_ x,mr_shiftbits((mr_small)1,p),x); + } +#endif + MR_OUT +} + +#ifndef MR_NO_RAND + +void bigbits(_MIPD_ int n,big x) +{ /* sets x as random < 2^n */ + mr_small r; + mr_lentype wlen; +#ifdef MR_FP + mr_small dres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zero(x); + if (mr_mip->ERNUM || n<=0) return; + + MR_IN(150) + + expb2(_MIPP_ n,mr_mip->w1); + wlen=mr_mip->w1->len; + do + { + r=brand(_MIPPO_ ); + if (mr_mip->base==0) x->w[x->len++]=r; + else x->w[x->len++]=MR_REMAIN(r,mr_mip->base); + } while (x->lenbase==mr_mip->base2) + { +#endif + + x->w[wlen-1]=MR_REMAIN(x->w[wlen-1],mr_mip->w1->w[wlen-1]); + mr_lzero(x); + +#ifndef MR_ALWAYS_BINARY + } + else + { + divide(_MIPP_ x,mr_mip->w1,mr_mip->w1); + } +#endif + + MR_OUT +} + +#endif diff --git a/crypto/sm2/miracl/mrcore.c b/crypto/sm2/miracl/mrcore.c new file mode 100644 index 00000000..855b063f --- /dev/null +++ b/crypto/sm2/miracl/mrcore.c @@ -0,0 +1,2290 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox IOM 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 Core module - contains initialisation code and general purpose + * utilities + * mrcore.c + * + * Space can be saved by removing unneeded functions (mr_and ?) + * + */ + +#include +#include +#include + + +#ifdef MR_FP +#include +#endif + + +/*** Multi-Threaded Support ***/ + +#ifndef MR_GENERIC_MT + + #ifdef MR_OPENMP_MT + #include + +#define MR_MIP_EXISTS + + miracl *mr_mip; + #pragma omp threadprivate(mr_mip) + + miracl *get_mip() + { + return mr_mip; + } + + void mr_init_threading() + { + } + + void mr_end_threading() + { + } + + #endif + + #ifdef MR_WINDOWS_MT + #include + DWORD mr_key; + + miracl *get_mip() + { + return (miracl *)TlsGetValue(mr_key); + } + + void mr_init_threading() + { + mr_key=TlsAlloc(); + } + + void mr_end_threading() + { + TlsFree(mr_key); + } + + #endif + + #ifdef MR_UNIX_MT + #include + pthread_key_t mr_key; + + miracl *get_mip() + { + return (miracl *)pthread_getspecific(mr_key); + } + + void mr_init_threading() + { + pthread_key_create(&mr_key,(void(*)(void *))NULL); + } + + void mr_end_threading() + { + pthread_key_delete(mr_key); + } + #endif + + #ifndef MR_WINDOWS_MT + #ifndef MR_UNIX_MT + #ifndef MR_OPENMP_MT + #ifdef MR_STATIC + miracl mip; + miracl *mr_mip=&mip; + #else + miracl *mr_mip=NULL; /* MIRACL's one and only global variable */ + #endif +#define MR_MIP_EXISTS + miracl *get_mip() + { + return (miracl *)mr_mip; + } + #endif + #endif + #endif + +#ifdef MR_MIP_EXISTS + void set_mip(miracl *mip) + { + mr_mip=mip; + } +#endif + +#endif + +/* See Advanced Windows by Jeffrey Richter, Chapter 12 for methods for + creating different instances of this global for each executing thread + when using Windows '95/NT +*/ + +#ifdef MR_STATIC + +#if MIRACL==8 + +static const int mr_small_primes[]= +{2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103, +107,109,113,127,0}; + +#else + +static const int mr_small_primes[]= +{2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103, +107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211, +223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331, +337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449, +457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587, +593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709, +719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853, +857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991, +997,0}; + +#endif + +#endif + +#ifndef MR_STRIPPED_DOWN +#ifndef MR_NO_STANDARD_IO + +static char *names[] = +{(char *)"your program",(char *)"innum",(char *)"otnum",(char *)"jack",(char *)"normalise", +(char *)"multiply",(char *)"divide",(char *)"incr",(char *)"decr",(char *)"premult", +(char *)"subdiv",(char *)"fdsize",(char *)"egcd",(char *)"cbase", +(char *)"cinnum",(char *)"cotnum",(char *)"nroot",(char *)"power", +(char *)"powmod",(char *)"bigdig",(char *)"bigrand",(char *)"nxprime",(char *)"isprime", +(char *)"mirvar",(char *)"mad",(char *)"multi_inverse",(char *)"putdig", +(char *)"add",(char *)"subtract",(char *)"mirsys",(char *)"xgcd", +(char *)"fpack",(char *)"dconv",(char *)"mr_shift",(char *)"mround",(char *)"fmul", +(char *)"fdiv",(char *)"fadd",(char *)"fsub",(char *)"fcomp",(char *)"fconv", +(char *)"frecip",(char *)"fpmul",(char *)"fincr",(char *)"",(char *)"ftrunc", +(char *)"frand",(char *)"sftbit",(char *)"build",(char *)"logb2",(char *)"expint", +(char *)"fpower",(char *)"froot",(char *)"fpi",(char *)"fexp",(char *)"flog",(char *)"fpowf", +(char *)"ftan",(char *)"fatan",(char *)"fsin",(char *)"fasin",(char *)"fcos",(char *)"facos", +(char *)"ftanh",(char *)"fatanh",(char *)"fsinh",(char *)"fasinh",(char *)"fcosh", +(char *)"facosh",(char *)"flop",(char *)"gprime",(char *)"powltr",(char *)"fft_mult", +(char *)"crt_init",(char *)"crt",(char *)"otstr",(char *)"instr",(char *)"cotstr",(char *)"cinstr",(char *)"powmod2", +(char *)"prepare_monty",(char *)"nres",(char *)"redc",(char *)"nres_modmult",(char *)"nres_powmod", +(char *)"nres_moddiv",(char *)"nres_powltr",(char *)"divisible",(char *)"remain", +(char *)"fmodulo",(char *)"nres_modadd",(char *)"nres_modsub",(char *)"nres_negate", +(char *)"ecurve_init",(char *)"ecurve_add",(char *)"ecurve_mult", +(char *)"epoint_init",(char *)"epoint_set",(char *)"epoint_get",(char *)"nres_powmod2", +(char *)"nres_sqroot",(char *)"sqroot",(char *)"nres_premult",(char *)"ecurve_mult2", +(char *)"ecurve_sub",(char *)"trial_division",(char *)"nxsafeprime",(char *)"nres_lucas",(char *)"lucas", +(char *)"brick_init",(char *)"pow_brick",(char *)"set_user_function", +(char *)"nres_powmodn",(char *)"powmodn",(char *)"ecurve_multn", +(char *)"ebrick_init",(char *)"mul_brick",(char *)"epoint_norm",(char *)"nres_multi_inverse",(char *)"", +(char *)"nres_dotprod",(char *)"epoint_negate",(char *)"ecurve_multi_add", +(char *)"ecurve2_init",(char *)"",(char *)"epoint2_set",(char *)"epoint2_norm",(char *)"epoint2_get", +(char *)"epoint2_comp",(char *)"ecurve2_add",(char *)"epoint2_negate",(char *)"ecurve2_sub", +(char *)"ecurve2_multi_add",(char *)"ecurve2_mult",(char *)"ecurve2_multn",(char *)"ecurve2_mult2", +(char *)"ebrick2_init",(char *)"mul2_brick",(char *)"prepare_basis",(char *)"strong_bigrand", +(char *)"bytes_to_big",(char *)"big_to_bytes",(char *)"set_io_buffer_size", +(char *)"epoint_getxyz",(char *)"epoint_double_add",(char *)"nres_double_inverse", +(char *)"double_inverse",(char *)"epoint_x",(char *)"hamming",(char *)"expb2",(char *)"bigbits", +(char *)"nres_lazy",(char *)"zzn2_imul",(char *)"nres_double_modadd",(char *)"nres_double_modsub", +/*155*/(char *)"",(char *)"zzn2_from_int",(char *)"zzn2_negate",(char *)"zzn2_conj",(char *)"zzn2_add", +(char *)"zzn2_sub",(char *)"zzn2_smul",(char *)"zzn2_mul",(char *)"zzn2_inv",(char *)"zzn2_timesi",(char *)"zzn2_powl", +(char *)"zzn2_from_bigs",(char *)"zzn2_from_big",(char *)"zzn2_from_ints", +(char *)"zzn2_sadd",(char *)"zzn2_ssub",(char *)"zzn2_times_irp",(char *)"zzn2_div2", +(char *)"zzn3_from_int",(char *)"zzn3_from_ints",(char *)"zzn3_from_bigs", +(char *)"zzn3_from_big",(char *)"zzn3_negate",(char *)"zzn3_powq",(char *)"zzn3_init", +(char *)"zzn3_add",(char *)"zzn3_sadd",(char *)"zzn3_sub",(char *)"zzn3_ssub",(char *)"zzn3_smul", +(char *)"zzn3_imul",(char *)"zzn3_mul",(char *)"zzn3_inv",(char *)"zzn3_div2",(char *)"zzn3_timesi", +(char *)"epoint_multi_norm",(char *)"mr_jsf",(char *)"epoint2_multi_norm", +(char *)"ecn2_compare",(char *)"ecn2_norm",(char *)"ecn2_set",(char *)"zzn2_txx", +(char *)"zzn2_txd",(char *)"nres_div2",(char *)"nres_div3",(char *)"zzn2_div3", +(char *)"ecn2_setx",(char *)"ecn2_rhs",(char *)"zzn2_qr",(char *)"zzn2_sqrt",(char *)"ecn2_add",(char *)"ecn2_mul2_jsf",(char *)"ecn2_mul", +(char *)"nres_div5",(char *)"zzn2_div5",(char *)"zzn2_sqr",(char *)"ecn2_add_sub",(char *)"ecn2_psi",(char *)"invmodp", +(char *)"zzn2_multi_inverse",(char *)"ecn2_multi_norm",(char *)"ecn2_precomp",(char *)"ecn2_mul4_gls_v", +(char *)"ecn2_mul2",(char *)"ecn2_precomp_gls",(char *)"ecn2_mul2_gls", +(char *)"ecn2_brick_init",(char *)"ecn2_mul_brick_gls",(char *)"ecn2_multn",(char *)"zzn3_timesi2", +(char *)"nres_complex",(char *)"zzn4_from_int",(char *)"zzn4_negate",(char *)"zzn4_conj",(char *)"zzn4_add",(char *)"zzn4_sadd",(char *)"zzn4_sub",(char *)"zzn4_ssub",(char *)"zzn4_smul",(char *)"zzn4_sqr", +(char *)"zzn4_mul",(char *)"zzn4_inv",(char *)"zzn4_div2",(char *)"zzn4_powq",(char *)"zzn4_tx",(char *)"zzn4_imul",(char *)"zzn4_lmul",(char *)"zzn4_from_big", +(char *)"ecn2_mult4"}; + +/* 0 - 243 (244 in all) */ + +#endif +#endif + +#ifdef MR_NOASM + +/* C only versions of muldiv/muldvd/muldvd2/muldvm */ +/* Note that mr_large should be twice the size of mr_small */ + +mr_small muldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_small *rp) +{ + mr_small q; + mr_large ldres,p=(mr_large)a*b+c; + q=(mr_small)(MR_LROUND(p/m)); + *rp=(mr_small)(p-(mr_large)q*m); + return q; +} + +#ifdef MR_FP_ROUNDING + +mr_small imuldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_large im,mr_small *rp) +{ + mr_small q; + mr_large ldres,p=(mr_large)a*b+c; + q=(mr_small)MR_LROUND(p*im); + *rp=(mr_small)(p-(mr_large)q*m); + return q; +} + +#endif + +#ifndef MR_NOFULLWIDTH + +mr_small muldvm(mr_small a,mr_small c,mr_small m,mr_small *rp) +{ + mr_small q; + union doubleword dble; + dble.h[MR_BOT]=c; + dble.h[MR_TOP]=a; + + q=(mr_small)(dble.d/m); + *rp=(mr_small)(dble.d-(mr_large)q*m); + return q; +} + +mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) +{ + union doubleword dble; + dble.d=(mr_large)a*b+c; + + *rp=dble.h[MR_BOT]; + return dble.h[MR_TOP]; +} + +void muldvd2(mr_small a,mr_small b,mr_small *c,mr_small *rp) +{ + union doubleword dble; + dble.d=(mr_large)a*b+*c+*rp; + *rp=dble.h[MR_BOT]; + *c=dble.h[MR_TOP]; +} + +#endif +#endif + +#ifdef MR_NOFULLWIDTH + +/* no FULLWIDTH working, so supply dummies */ + +/* + +mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) +{ + return (mr_small)0; +} + +mr_small muldvm(mr_small a,mr_small c,mr_small m,mr_small *rp) +{ + return (mr_small)0; +} + +void muldvd2(mr_small a,mr_small b,mr_small *c,mr_small *rp) +{ +} + +*/ + +#endif + +#ifndef MR_NO_STANDARD_IO + +static void mputs(char *s) +{ /* output a string */ + int i=0; + while (s[i]!=0) fputc((int)s[i++],stdout); +} +#endif + +void mr_berror(_MIPD_ int nerr) +{ /* Big number error routine */ +#ifndef MR_STRIPPED_DOWN +int i; +#endif + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + +if (mr_mip->ERCON) +{ + mr_mip->ERNUM=nerr; + return; +} +#ifndef MR_NO_STANDARD_IO + +#ifndef MR_STRIPPED_DOWN +mputs((char *)"\nMIRACL error from routine "); +if (mr_mip->depthtrace[mr_mip->depth]]); +else mputs((char *)"???"); +fputc('\n',stdout); + +for (i=mr_mip->depth-1;i>=0;i--) +{ + mputs((char *)" called from "); + if (itrace[i]]); + else mputs((char *)"???"); + fputc('\n',stdout); +} + +switch (nerr) +{ +case 1 : +mputs((char *)"Number base too big for representation\n"); +break; +case 2 : +mputs((char *)"Division by zero attempted\n"); +break; +case 3 : +mputs((char *)"Overflow - Number too big\n"); +break; +case 4 : +mputs((char *)"Internal result is negative\n"); +break; +case 5 : +mputs((char *)"Input format error\n"); +break; +case 6 : +mputs((char *)"Illegal number base\n"); +break; +case 7 : +mputs((char *)"Illegal parameter usage\n"); +break; +case 8 : +mputs((char *)"Out of space\n"); +break; +case 9 : +mputs((char *)"Even root of a negative number\n"); +break; +case 10: +mputs((char *)"Raising integer to negative power\n"); +break; +case 11: +mputs((char *)"Attempt to take illegal root\n"); +break; +case 12: +mputs((char *)"Integer operation attempted on Flash number\n"); +break; +case 13: +mputs((char *)"Flash overflow\n"); +break; +case 14: +mputs((char *)"Numbers too big\n"); +break; +case 15: +mputs((char *)"Log of a non-positive number\n"); +break; +case 16: +mputs((char *)"Flash to double conversion failure\n"); +break; +case 17: +mputs((char *)"I/O buffer overflow\n"); +break; +case 18: +mputs((char *)"MIRACL not initialised - no call to mirsys()\n"); +break; +case 19: +mputs((char *)"Illegal modulus \n"); +break; +case 20: +mputs((char *)"No modulus defined\n"); +break; +case 21: +mputs((char *)"Exponent too big\n"); +break; +case 22: +mputs((char *)"Unsupported Feature - check mirdef.h\n"); +break; +case 23: +mputs((char *)"Specified double length type isn't double length\n"); +break; +case 24: +mputs((char *)"Specified basis is NOT irreducible\n"); +break; +case 25: +mputs((char *)"Unable to control Floating-point rounding\n"); +break; +case 26: +mputs((char *)"Base must be binary (MR_ALWAYS_BINARY defined in mirdef.h ?)\n"); +break; +case 27: +mputs((char *)"No irreducible basis defined\n"); +break; +case 28: +mputs((char *)"Composite modulus\n"); +break; +case 29: +mputs((char *)"Input/output error when reading from RNG device node\n"); +break; +default: +mputs((char *)"Undefined error\n"); +break; +} +exit(0); +#else +mputs((char *)"MIRACL error\n"); +exit(0); +#endif + +#endif +} + +#ifndef MR_STRIPPED_DOWN + +void mr_track(_MIPDO_ ) +{ /* track course of program execution * + * through the MIRACL routines */ + +#ifndef MR_NO_STANDARD_IO + + int i; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + for (i=0;idepth;i++) fputc('-',stdout); + fputc('>',stdout); + mputs(names[mr_mip->trace[mr_mip->depth]]); + fputc('\n',stdout); +#endif +} + +#endif + +#ifndef MR_NO_RAND + +mr_small brand(_MIPDO_ ) +{ /* Marsaglia & Zaman random number generator */ + int i,k; + mr_unsign32 pdiff,t; + mr_small r; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->lg2b>32) + { /* underlying type is > 32 bits. Assume <= 64 bits */ + mr_mip->rndptr+=2; + if (mr_mip->rndptrira[mr_mip->rndptr]; + r=mr_shiftbits(r,mr_mip->lg2b-32); + r+=(mr_small)mr_mip->ira[mr_mip->rndptr+1]; + return r; + } + } + else + { + mr_mip->rndptr++; + if (mr_mip->rndptrira[mr_mip->rndptr]; + } + mr_mip->rndptr=0; + for (i=0,k=NK-NJ;iira[k]; + pdiff=t - mr_mip->ira[i] - mr_mip->borrow; + if (pdiffborrow=0; + if (pdiff>t) mr_mip->borrow=1; + mr_mip->ira[i]=pdiff; + } + if (mr_mip->lg2b>32) + { /* double up */ + r=(mr_small)mr_mip->ira[0]; + r=mr_shiftbits(r,mr_mip->lg2b-32); + r+=(mr_small)mr_mip->ira[1]; + return r; + } + else return (mr_small)(mr_mip->ira[0]); +} + +void irand(_MIPD_ mr_unsign32 seed) +{ /* initialise random number system */ + int i,in; + mr_unsign32 t,m=1L; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + mr_mip->borrow=0L; + mr_mip->rndptr=0; + mr_mip->ira[0]=seed; + for (i=1;iira[in]=m; + t=m; + m=seed-m; + seed=t; + } + for (i=0;i<1000;i++) brand(_MIPPO_ ); /* "warm-up" & stir the generator */ +} + +#endif + +mr_small mr_shiftbits(mr_small x,int n) +{ +#ifdef MR_FP + int i; + mr_small dres; + if (n==0) return x; + if (n>0) + { + for (i=0;i0) x<<=n; + else x>>=(-n); + return x; +#endif + +} + +mr_small mr_setbase(_MIPD_ mr_small nb) +{ /* set base. Pack as many digits as * + * possible into each computer word */ + mr_small temp; +#ifdef MR_FP + mr_small dres; +#endif +#ifndef MR_NOFULLWIDTH + BOOL fits; + int bits; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + fits=FALSE; + bits=MIRACL; + while (bits>1) + { + bits/=2; + temp=((mr_small)1<apbase=nb; + mr_mip->pack=MIRACL/bits; + mr_mip->base=0; + return 0; + } +#endif + mr_mip->apbase=nb; + mr_mip->pack=1; + mr_mip->base=nb; +#ifdef MR_SIMPLE_BASE + return 0; +#else + if (mr_mip->base==0) return 0; + temp=MR_DIV(MAXBASE,nb); + while (temp>=nb) + { + temp=MR_DIV(temp,nb); + mr_mip->base*=nb; + mr_mip->pack++; + } +#ifdef MR_FP_ROUNDING + mr_mip->inverse_base=mr_invert(mr_mip->base); + return mr_mip->inverse_base; +#else + return 0; +#endif +#endif +} + +#ifdef MR_FLASH + +BOOL fit(big x,big y,int f) +{ /* returns TRUE if x/y would fit flash format of length f */ + int n,d; + n=(int)(x->len&(MR_OBITS)); + d=(int)(y->len&(MR_OBITS)); + if (n==1 && x->w[0]==1) n=0; + if (d==1 && y->w[0]==1) d=0; + if (n+d<=f) return TRUE; + return FALSE; +} + +#endif + +int mr_lent(flash x) +{ /* return length of big or flash in words */ + mr_lentype lx; + lx=(x->len&(MR_OBITS)); +#ifdef MR_FLASH + return (int)((lx&(MR_MSK))+((lx>>(MR_BTS))&(MR_MSK))); +#else + return (int)lx; +#endif +} + +void zero(flash x) +{ /* set big/flash number to zero */ + int i,n; + mr_small *g; + if (x==NULL) return; +#ifdef MR_FLASH + n=mr_lent(x); +#else + n=(x->len&MR_OBITS); +#endif + g=x->w; + + for (i=0;ilen=0; +} + +void uconvert(_MIPD_ unsigned int n ,big x) +{ /* convert unsigned integer n to big number format */ + int m; +#ifdef MR_FP + mr_small dres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zero(x); + if (n==0) return; + + m=0; +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH +#if MR_IBITS > MIRACL + while (n>0) + { + x->w[m++]=(mr_small)(n%((mr_small)1<<(MIRACL))); + n/=((mr_small)1<<(MIRACL)); + } +#else + x->w[m++]=(mr_small)n; +#endif +#endif +#ifndef MR_SIMPLE_BASE + } + else while (n>0) + { + x->w[m++]=MR_REMAIN((mr_small)n,mr_mip->base); + n=(unsigned int)((mr_small)n/mr_mip->base); + } +#endif + x->len=m; +} + +void tconvert(_MIPD_ mr_utype n,big x) +{ + mr_lentype s; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (n==0) {zero(x); return;} + s=0; + if (n<0) + { + s=MR_MSBIT; + n=(-n); + } + x->w[0]=n; + x->len=1; + x->len|=s; +} + +void convert(_MIPD_ int n ,big x) +{ /* convert signed integer n to big number format */ + mr_lentype s; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (n==0) {zero(x); return;} + s=0; + if (n<0) + { + s=MR_MSBIT; + n=(-n); + } + uconvert(_MIPP_ (unsigned int)n,x); + x->len|=s; +} + +#ifndef MR_STATIC +#ifdef mr_dltype + +void dlconv(_MIPD_ mr_dltype n,big x) +{ /* convert double length integer to big number format - rarely needed */ + int m; + mr_lentype s; +#ifdef MR_FP + mr_small dres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zero(x); + if (n==0) return; + s=0; + if (n<0) + { + s=MR_MSBIT; + n=(-n); + } + m=0; +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH + while (n>0) + { + x->w[m++]=(mr_small)(n%((mr_dltype)1<<(MIRACL))); + n/=((mr_dltype)1<<(MIRACL)); + } +#endif +#ifndef MR_SIMPLE_BASE + } + else while (n>0) + { + x->w[m++]=(mr_small)MR_REMAIN(n,mr_mip->base); + n/=mr_mip->base; + } +#endif + x->len=(m|s); +} + +#endif + +void ulgconv(_MIPD_ unsigned long n,big x) +{ /* convert unsigned long integer to big number format - rarely needed */ + int m; +#ifdef MR_FP + mr_small dres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zero(x); + if (n==0) return; + + m=0; +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH +#if MR_LBITS > MIRACL + while (n>0) + { + x->w[m++]=(mr_small)(n%(1L<<(MIRACL))); + n/=(1L<<(MIRACL)); + } +#else + x->w[m++]=(mr_small)n; +#endif +#endif +#ifndef MR_SIMPLE_BASE + } + else while (n>0) + { + x->w[m++]=MR_REMAIN(n,mr_mip->base); + n=(unsigned long)((mr_small)n/mr_mip->base); + } +#endif + x->len=m; +} + +void lgconv(_MIPD_ long n,big x) +{ /* convert signed long integer to big number format - rarely needed */ + mr_lentype s; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (n==0) {zero(x); return;} + s=0; + if (n<0) + { + s=MR_MSBIT; + n=(-n); + } + ulgconv(_MIPP_ (unsigned long)n,x); + + x->len|=s; +} + +flash mirvar(_MIPD_ int iv) +{ /* initialize big/flash number */ + flash x; + int align; + char *ptr; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return NULL; + MR_IN(23); + + if (!(mr_mip->active)) + { + mr_berror(_MIPP_ MR_ERR_NO_MIRSYS); + MR_OUT + return NULL; + } + +/* OK, now I control alignment.... */ + +/* Allocate space for big, the length, the pointer, and the array */ +/* Do it all in one memory allocation - this is quicker */ +/* Ensure that the array has correct alignment */ + + x=(big)mr_alloc(_MIPP_ mr_size(mr_mip->nib-1),1); + if (x==NULL) + { + MR_OUT + return x; + } + + ptr=(char *)&x->w; + align=(unsigned long)(ptr+sizeof(mr_small *))%sizeof(mr_small); + + x->w=(mr_small *)(ptr+sizeof(mr_small *)+sizeof(mr_small)-align); + + if (iv!=0) convert(_MIPP_ iv,x); + MR_OUT + return x; +} + +#endif + +flash mirvar_mem_variable(char *mem,int index,int sz) +{ + flash x; + int align; + char *ptr; + int offset,r; + +/* alignment */ + offset=0; + r=(unsigned long)mem%MR_SL; + if (r>0) offset=MR_SL-r; + + x=(big)&mem[offset+mr_size(sz)*index]; + ptr=(char *)&x->w; + align=(unsigned long)(ptr+sizeof(mr_small *))%sizeof(mr_small); + x->w=(mr_small *)(ptr+sizeof(mr_small *)+sizeof(mr_small)-align); + + return x; +} + +flash mirvar_mem(_MIPD_ char *mem,int index) +{ /* initialize big/flash number from pre-allocated memory */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return NULL; + + return mirvar_mem_variable(mem,index,mr_mip->nib-1); + +} + +void set_user_function(_MIPD_ BOOL (*user)(void)) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(111) + + if (!(mr_mip->active)) + { + mr_berror(_MIPP_ MR_ERR_NO_MIRSYS); + MR_OUT + return; + } + + mr_mip->user=user; + + MR_OUT +} + +#ifndef MR_STATIC + +#ifndef MR_SIMPLE_IO + +void set_io_buffer_size(_MIPD_ int len) +{ + int i; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (len<0) return; + MR_IN(142) + for (i=0;iIOBSIZ;i++) mr_mip->IOBUFF[i]=0; + mr_free(mr_mip->IOBUFF); + if (len==0) + { + MR_OUT + return; + } + mr_mip->IOBSIZ=len; + mr_mip->IOBUFF=(char *)mr_alloc(_MIPP_ len+1,1); + mr_mip->IOBUFF[0]='\0'; + MR_OUT +} +#endif + +#endif + +/* Initialise a big from ROM given its fixed length */ + +BOOL init_big_from_rom(big x,int len,const mr_small *rom,int romsize,int *romptr) +{ + int i; + zero(x); + x->len=len; + for (i=0;i=romsize) return FALSE; +#ifdef MR_AVR + x->w[i]=pgm_read_byte_near(&rom[*romptr]); +#else + x->w[i]=rom[*romptr]; +#endif + (*romptr)++; + } + + mr_lzero(x); + return TRUE; +} + +/* Initialise an elliptic curve point from ROM */ + +BOOL init_point_from_rom(epoint *P,int len,const mr_small *rom,int romsize,int *romptr) +{ + if (!init_big_from_rom(P->X,len,rom,romsize,romptr)) return FALSE; + if (!init_big_from_rom(P->Y,len,rom,romsize,romptr)) return FALSE; + P->marker=MR_EPOINT_NORMALIZED; + return TRUE; +} + +#ifdef MR_GENERIC_AND_STATIC +miracl *mirsys(miracl *mr_mip,int nd,mr_small nb) +#else +miracl *mirsys(int nd,mr_small nb) +#endif +{ /* Initialize MIRACL system to * + * use numbers to base nb, and * + * nd digits or (-nd) bytes long */ + +/* In these cases mr_mip is passed as the first parameter */ + +#ifdef MR_GENERIC_AND_STATIC + return mirsys_basic(mr_mip,nd,nb); +#endif + +#ifdef MR_GENERIC_MT +#ifndef MR_STATIC + miracl *mr_mip=mr_first_alloc(); + return mirsys_basic(mr_mip,nd,nb); +#endif +#endif +/* In these cases mr_mip is a "global" pointer and the mip itself is allocated from the heap. + In fact mr_mip (and mip) may be thread specific if some multi-threading scheme is implemented */ +#ifndef MR_STATIC + #ifdef MR_WINDOWS_MT + miracl *mr_mip=mr_first_alloc(); + TlsSetValue(mr_key,mr_mip); + #endif + + #ifdef MR_UNIX_MT + miracl *mr_mip=mr_first_alloc(); + pthread_setspecific(mr_key,mr_mip); + #endif + + #ifdef MR_OPENMP_MT + mr_mip=mr_first_alloc(); + #endif + + #ifndef MR_WINDOWS_MT + #ifndef MR_UNIX_MT + #ifndef MR_OPENMP_MT + mr_mip=mr_first_alloc(); + #endif + #endif + #endif +#endif + +#ifndef MR_GENERIC_MT + mr_mip=get_mip(); +#endif + return mirsys_basic(mr_mip,nd,nb); +} + +miracl *mirsys_basic(miracl *mr_mip,int nd,mr_small nb) +{ +#ifndef MR_NO_RAND + int i; +#endif + + mr_small b,nw; +#ifdef MR_FP + mr_small dres; +#endif + + if (mr_mip==NULL) return NULL; + +#ifndef MR_STRIPPED_DOWN + mr_mip->depth=0; + mr_mip->trace[0]=0; + mr_mip->depth++; + mr_mip->trace[mr_mip->depth]=29; +#endif + /* digest hardware configuration */ + +#ifdef MR_NO_STANDARD_IO + mr_mip->ERCON=TRUE; +#else + mr_mip->ERCON=FALSE; +#endif +#ifndef MR_STATIC + mr_mip->logN=0; + mr_mip->degree=0; + mr_mip->chin.NP=0; +#endif + + + mr_mip->user=NULL; + mr_mip->same=FALSE; + mr_mip->first_one=FALSE; + mr_mip->debug=FALSE; + mr_mip->AA=0; +#ifndef MR_AFFINE_ONLY + mr_mip->coord=MR_NOTSET; +#endif + +#ifdef MR_NOFULLWIDTH + if (nb==0) + { + mr_berror(_MIPP_ MR_ERR_BAD_BASE); + MR_OUT + return mr_mip; + } +#endif + +#ifndef MR_FP +#ifdef mr_dltype +#ifndef MR_NOFULLWIDTH + if (sizeof(mr_dltype)<2*sizeof(mr_utype)) + { /* double length type, isn't */ + mr_berror(_MIPP_ MR_ERR_NOT_DOUBLE_LEN); + MR_OUT + return mr_mip; + } +#endif +#endif +#endif + + if (nb==1 || nb>MAXBASE) + { + mr_berror(_MIPP_ MR_ERR_BAD_BASE); + MR_OUT + return mr_mip; + } + +#ifdef MR_FP_ROUNDING + if (mr_setbase(_MIPP_ nb)==0) + { /* unable in fact to control FP rounding */ + mr_berror(_MIPP_ MR_ERR_NO_ROUNDING); + MR_OUT + return mr_mip; + } +#else + mr_setbase(_MIPP_ nb); +#endif + + b=mr_mip->base; + +#ifdef MR_SIMPLE_BASE + if (b!=0) + { + mr_berror(_MIPP_ MR_ERR_BAD_BASE); + MR_OUT + return mr_mip; + } +#endif + + mr_mip->lg2b=0; + mr_mip->base2=1; +#ifndef MR_SIMPLE_BASE + if (b==0) + { +#endif + mr_mip->lg2b=MIRACL; + mr_mip->base2=0; +#ifndef MR_SIMPLE_BASE + } + else while (b>1) + { + b=MR_DIV(b,2); + mr_mip->lg2b++; + mr_mip->base2*=2; + } +#endif + +#ifdef MR_ALWAYS_BINARY + if (mr_mip->base!=mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_BINARY); + MR_OUT + return mr_mip; + } +#endif + +/* calculate total space for bigs */ +/* + + big -> |int len|small *ptr| alignment space | size in words +1| alignment up to multiple of 4 | + + +*/ + if (nd>0) nw=MR_ROUNDUP(nd,mr_mip->pack); + else nw=MR_ROUNDUP(8*(-nd),mr_mip->lg2b); + + if (nw<1) nw=1; + mr_mip->nib=(int)(nw+1); /* add one extra word for small overflows */ + +#ifdef MR_STATIC + if (nw>MR_STATIC) + { + mr_berror(_MIPP_ MR_ERR_TOO_BIG); + MR_OUT + return mr_mip; + } +#endif + + /* mr_mip->nib=(int)(nw+1); add one extra word for small overflows */ + +#ifdef MR_FLASH + mr_mip->workprec=mr_mip->nib; + mr_mip->stprec=mr_mip->nib; + while (mr_mip->stprec>2 && mr_mip->stprec>MR_FLASH/mr_mip->lg2b) + mr_mip->stprec=(mr_mip->stprec+1)/2; + if (mr_mip->stprec<2) mr_mip->stprec=2; + +#endif + +#ifndef MR_DOUBLE_BIG + mr_mip->check=ON; +#else + mr_mip->check=OFF; +#endif + +#ifndef MR_SIMPLE_BASE +#ifndef MR_SIMPLE_IO + mr_mip->IOBASE=10; /* defaults */ +#endif +#endif + mr_mip->ERNUM=0; + + mr_mip->NTRY=6; + mr_mip->MONTY=ON; +#ifdef MR_FLASH + mr_mip->EXACT=TRUE; + mr_mip->RPOINT=OFF; +#endif +#ifndef MR_STRIPPED_DOWN + mr_mip->TRACER=OFF; +#endif + +#ifndef MR_SIMPLE_IO + mr_mip->INPLEN=0; + mr_mip->IOBSIZ=MR_DEFAULT_BUFFER_SIZE; +#endif + +#ifdef MR_STATIC + mr_mip->PRIMES=mr_small_primes; +#else + mr_mip->PRIMES=NULL; +#ifndef MR_SIMPLE_IO + mr_mip->IOBUFF=(char *)mr_alloc(_MIPP_ MR_DEFAULT_BUFFER_SIZE+1,1); +#endif +#endif +#ifndef MR_SIMPLE_IO + mr_mip->IOBUFF[0]='\0'; +#endif + mr_mip->qnr=0; + mr_mip->cnr=0; + mr_mip->TWIST=0; + mr_mip->pmod8=0; + mr_mip->pmod9=0; + +/* quick start for rng. irand(.) should be called first before serious use.. */ + +#ifndef MR_NO_RAND + mr_mip->ira[0]=0x55555555; + mr_mip->ira[1]=0x12345678; + + for (i=2;iira[i]=mr_mip->ira[i-1]+mr_mip->ira[i-2]+0x1379BDF1; + mr_mip->rndptr=NK; + mr_mip->borrow=0; +#endif + + mr_mip->nib=2*mr_mip->nib+1; +#ifdef MR_FLASH + if (mr_mip->nib!=(mr_mip->nib&(MR_MSK))) +#else + if (mr_mip->nib!=(int)(mr_mip->nib&(MR_OBITS))) +#endif + { + mr_berror(_MIPP_ MR_ERR_TOO_BIG); + mr_mip->nib=(mr_mip->nib-1)/2; + MR_OUT + return mr_mip; + } +#ifndef MR_STATIC + mr_mip->workspace=(char *)memalloc(_MIPP_ MR_SPACES); /* grab workspace */ +#else + memset(mr_mip->workspace,0,MR_BIG_RESERVE(MR_SPACES)); +#endif + + mr_mip->M=0; + mr_mip->fin=FALSE; + mr_mip->fout=FALSE; + mr_mip->active=ON; + + mr_mip->nib=(mr_mip->nib-1)/2; + +/* allocate memory for workspace variables */ + +#ifndef MR_DOUBLE_BIG + + mr_mip->w0=mirvar_mem(_MIPP_ mr_mip->workspace,0); /* double length */ + mr_mip->w1=mirvar_mem(_MIPP_ mr_mip->workspace,2); + mr_mip->w2=mirvar_mem(_MIPP_ mr_mip->workspace,3); + mr_mip->w3=mirvar_mem(_MIPP_ mr_mip->workspace,4); + mr_mip->w4=mirvar_mem(_MIPP_ mr_mip->workspace,5); + mr_mip->w5=mirvar_mem(_MIPP_ mr_mip->workspace,6); /* double length */ + mr_mip->w6=mirvar_mem(_MIPP_ mr_mip->workspace,8); /* double length */ + mr_mip->w7=mirvar_mem(_MIPP_ mr_mip->workspace,10); /* double length */ + mr_mip->w8=mirvar_mem(_MIPP_ mr_mip->workspace,12); + mr_mip->w9=mirvar_mem(_MIPP_ mr_mip->workspace,13); + mr_mip->w10=mirvar_mem(_MIPP_ mr_mip->workspace,14); + mr_mip->w11=mirvar_mem(_MIPP_ mr_mip->workspace,15); + mr_mip->w12=mirvar_mem(_MIPP_ mr_mip->workspace,16); + mr_mip->w13=mirvar_mem(_MIPP_ mr_mip->workspace,17); + mr_mip->w14=mirvar_mem(_MIPP_ mr_mip->workspace,18); + mr_mip->w15=mirvar_mem(_MIPP_ mr_mip->workspace,19); + mr_mip->sru=mirvar_mem(_MIPP_ mr_mip->workspace,20); + mr_mip->modulus=mirvar_mem(_MIPP_ mr_mip->workspace,21); + mr_mip->pR=mirvar_mem(_MIPP_ mr_mip->workspace,22); /* double length */ + mr_mip->A=mirvar_mem(_MIPP_ mr_mip->workspace,24); + mr_mip->B=mirvar_mem(_MIPP_ mr_mip->workspace,25); + mr_mip->one=mirvar_mem(_MIPP_ mr_mip->workspace,26); +#ifdef MR_KCM + mr_mip->big_ndash=mirvar_mem(_MIPP_ mr_mip->workspace,27); + mr_mip->ws=mirvar_mem(_MIPP_ mr_mip->workspace,28); + mr_mip->wt=mirvar_mem(_MIPP_ mr_mip->workspace,29); /* double length */ +#endif +#ifdef MR_FLASH +#ifdef MR_KCM + mr_mip->pi=mirvar_mem(_MIPP_ mr_mip->workspace,31); +#else + mr_mip->pi=mirvar_mem(_MIPP_ mr_mip->workspace,27); +#endif +#endif + +#else +/* w0-w7 are double normal length */ + mr_mip->w0=mirvar_mem(_MIPP_ mr_mip->workspace,0); /* quad length */ + mr_mip->w1=mirvar_mem(_MIPP_ mr_mip->workspace,4); /* double length */ + mr_mip->w2=mirvar_mem(_MIPP_ mr_mip->workspace,6); + mr_mip->w3=mirvar_mem(_MIPP_ mr_mip->workspace,8); + mr_mip->w4=mirvar_mem(_MIPP_ mr_mip->workspace,10); + mr_mip->w5=mirvar_mem(_MIPP_ mr_mip->workspace,12); /* quad length */ + mr_mip->w6=mirvar_mem(_MIPP_ mr_mip->workspace,16); /* quad length */ + mr_mip->w7=mirvar_mem(_MIPP_ mr_mip->workspace,20); /* quad length */ + mr_mip->w8=mirvar_mem(_MIPP_ mr_mip->workspace,24); + + mr_mip->w9=mirvar_mem(_MIPP_ mr_mip->workspace,25); + mr_mip->w10=mirvar_mem(_MIPP_ mr_mip->workspace,26); + mr_mip->w11=mirvar_mem(_MIPP_ mr_mip->workspace,27); + mr_mip->w12=mirvar_mem(_MIPP_ mr_mip->workspace,28); + mr_mip->w13=mirvar_mem(_MIPP_ mr_mip->workspace,29); + mr_mip->w14=mirvar_mem(_MIPP_ mr_mip->workspace,30); + mr_mip->w15=mirvar_mem(_MIPP_ mr_mip->workspace,31); + mr_mip->sru=mirvar_mem(_MIPP_ mr_mip->workspace,32); + mr_mip->modulus=mirvar_mem(_MIPP_ mr_mip->workspace,33); + mr_mip->pR=mirvar_mem(_MIPP_ mr_mip->workspace,34); /* double length */ + mr_mip->A=mirvar_mem(_MIPP_ mr_mip->workspace,36); + mr_mip->B=mirvar_mem(_MIPP_ mr_mip->workspace,37); + mr_mip->one=mirvar_mem(_MIPP_ mr_mip->workspace,38); +#ifdef MR_KCM + mr_mip->big_ndash=mirvar_mem(_MIPP_ mr_mip->workspace,39); + mr_mip->ws=mirvar_mem(_MIPP_ mr_mip->workspace,40); + mr_mip->wt=mirvar_mem(_MIPP_ mr_mip->workspace,41); /* double length */ +#endif +#ifdef MR_FLASH +#ifdef MR_KCM + mr_mip->pi=mirvar_mem(_MIPP_ mr_mip->workspace,43); +#else + mr_mip->pi=mirvar_mem(_MIPP_ mr_mip->workspace,39); +#endif +#endif + +#endif + MR_OUT + return mr_mip; +} + +#ifndef MR_STATIC + +/* allocate space for a number of bigs from the heap */ + +void *memalloc(_MIPD_ int num) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + return mr_alloc(_MIPP_ mr_big_reserve(num,mr_mip->nib-1),1); +} + +#endif + +void memkill(_MIPD_ char *mem,int len) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mem==NULL) return; + memset(mem,0,mr_big_reserve(len,mr_mip->nib-1)); +#ifndef MR_STATIC + mr_free(mem); +#endif +} + +#ifndef MR_STATIC + +void mirkill(big x) +{ /* kill a big/flash variable, that is set it to zero + and free its memory */ + if (x==NULL) return; + zero(x); + mr_free(x); +} + +#endif + +void mirexit(_MIPDO_ ) +{ /* clean up after miracl */ + + int i; +#ifdef MR_WINDOWS_MT + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_UNIX_MT + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_OPENMP_MT + miracl *mr_mip=get_mip(); +#endif + mr_mip->ERCON=FALSE; + mr_mip->active=OFF; + memkill(_MIPP_ mr_mip->workspace,MR_SPACES); +#ifndef MR_NO_RAND + for (i=0;iira[i]=0L; +#endif +#ifndef MR_STATIC +#ifndef MR_SIMPLE_IO + set_io_buffer_size(_MIPP_ 0); +#endif + if (mr_mip->PRIMES!=NULL) mr_free(mr_mip->PRIMES); +#else +#ifndef MR_SIMPLE_IO + for (i=0;i<=MR_DEFAULT_BUFFER_SIZE;i++) + mr_mip->IOBUFF[i]=0; +#endif +#endif + +#ifndef MR_STATIC + mr_free(mr_mip); +#ifdef MR_WINDOWS_MT + TlsSetValue(mr_key, NULL); /* Thank you Thales */ +#endif +#endif + +#ifndef MR_GENERIC_MT +#ifndef MR_WINDOWS_MT +#ifndef MR_UNIX_MT +#ifndef MR_STATIC + mr_mip=NULL; +#endif +#endif +#endif +#endif + +#ifdef MR_OPENMP_MT + mr_mip=NULL; +#endif + +} + +int exsign(flash x) +{ /* extract sign of big/flash number */ + if ((x->len&(MR_MSBIT))==0) return PLUS; + else return MINUS; +} + +void insign(int s,flash x) +{ /* assert sign of big/flash number */ + if (x->len==0) return; + if (s<0) x->len|=MR_MSBIT; + else x->len&=MR_OBITS; +} + +void mr_lzero(big x) +{ /* strip leading zeros from big number */ + mr_lentype s; + int m; + s=(x->len&(MR_MSBIT)); + m=(int)(x->len&(MR_OBITS)); + while (m>0 && x->w[m-1]==0) + m--; + x->len=m; + if (m>0) x->len|=s; +} + +#ifndef MR_SIMPLE_IO + +int getdig(_MIPD_ big x,int i) +{ /* extract a packed digit */ + int k; + mr_small n; +#ifdef MR_FP + mr_small dres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + i--; + n=x->w[i/mr_mip->pack]; + + if (mr_mip->pack==1) return (int)n; + k=i%mr_mip->pack; + for (i=1;i<=k;i++) + n=MR_DIV(n,mr_mip->apbase); + return (int)MR_REMAIN(n,mr_mip->apbase); +} + +int numdig(_MIPD_ big x) +{ /* returns number of digits in x */ + int nd; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (x->len==0) return 0; + + nd=(int)(x->len&(MR_OBITS))*mr_mip->pack; + while (getdig(_MIPP_ x,nd)==0) + nd--; + return nd; +} + +void putdig(_MIPD_ int n,big x,int i) +{ /* insert a digit into a packed word */ + int j,k,lx; + mr_small m,p; + mr_lentype s; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(26) + + s=(x->len&(MR_MSBIT)); + lx=(int)(x->len&(MR_OBITS)); + m=getdig(_MIPP_ x,i); + p=n; + i--; + j=i/mr_mip->pack; + k=i%mr_mip->pack; + for (i=1;i<=k;i++) + { + m*=mr_mip->apbase; + p*=mr_mip->apbase; + } + if (j>=mr_mip->nib && (mr_mip->check || j>=2*mr_mip->nib)) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + MR_OUT + return; + } + + x->w[j]=(x->w[j]-m)+p; + if (j>=lx) x->len=((j+1)|s); + mr_lzero(x); + MR_OUT +} + +#endif + +#ifndef MR_FP + +void mr_and(big x,big y,big z) +{ /* z= bitwise logical AND of x and y */ + int i,nx,ny,nz,nr; + if (x==y) + { + copy(x,z); + return; + } + +#ifdef MR_FLASH + nx=mr_lent(x); + ny=mr_lent(y); + nz=mr_lent(z); +#else + ny=(y->len&(MR_OBITS)); + nx=(x->len&(MR_OBITS)); + nz=(z->len&(MR_OBITS)); +#endif + if (nyw[i]=x->w[i]&y->w[i]; + for (i=nr;iw[i]=0; + z->len=nr; +} + +void mr_xor(big x,big y,big z) +{ + int i,nx,ny,nz,nr; + if (x==y) + { + copy(x,z); + return; + } + +#ifdef MR_FLASH + nx=mr_lent(x); + ny=mr_lent(y); + nz=mr_lent(z); +#else + ny=(y->len&(MR_OBITS)); + nx=(x->len&(MR_OBITS)); + nz=(z->len&(MR_OBITS)); +#endif + if (nyw[i]=x->w[i]^y->w[i]; + for (i=nr;iw[i]=0; + z->len=nr; +} + +#endif + +void copy(flash x,flash y) +{ /* copy x to y: y=x */ + int i,nx,ny; + mr_small *gx,*gy; + if (x==y || y==NULL) return; + + if (x==NULL) + { + zero(y); + return; + } + +#ifdef MR_FLASH + ny=mr_lent(y); + nx=mr_lent(x); +#else + ny=(y->len&(MR_OBITS)); + nx=(x->len&(MR_OBITS)); +#endif + + gx=x->w; + gy=y->w; + + for (i=nx;ilen=x->len; + +} + +void negify(flash x,flash y) +{ /* negate a big/flash variable: y=-x */ + copy(x,y); + if (y->len!=0) y->len^=MR_MSBIT; +} + +void absol(flash x,flash y) +{ /* y=abs(x) */ + copy(x,y); + y->len&=MR_OBITS; +} + +BOOL mr_notint(flash x) +{ /* returns TRUE if x is Flash */ +#ifdef MR_FLASH + if ((((x->len&(MR_OBITS))>>(MR_BTS))&(MR_MSK))!=0) return TRUE; +#endif + return FALSE; +} + +void mr_shift(_MIPD_ big x,int n,big w) +{ /* set w=x.(mr_base^n) by shifting */ + mr_lentype s; + int i,bl; + mr_small *gw=w->w; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + copy(x,w); + if (w->len==0 || n==0) return; + MR_IN(33) + + if (mr_notint(w)) mr_berror(_MIPP_ MR_ERR_INT_OP); + s=(w->len&(MR_MSBIT)); + bl=(int)(w->len&(MR_OBITS))+n; + if (bl<=0) + { + zero(w); + MR_OUT + return; + } + if (bl>mr_mip->nib && mr_mip->check) mr_berror(_MIPP_ MR_ERR_OVERFLOW); + if (mr_mip->ERNUM) + { + MR_OUT + return; + } + if (n>0) + { + for (i=bl-1;i>=n;i--) + gw[i]=gw[i-n]; + for (i=0;ilen=(bl|s); + MR_OUT +} + +int size(big x) +{ /* get size of big number; convert to * + * integer - if possible */ + int n,m; + mr_lentype s; + if (x==NULL) return 0; + s=(x->len&MR_MSBIT); + m=(int)(x->len&MR_OBITS); + if (m==0) return 0; + if (m==1 && x->w[0]<(mr_small)MR_TOOBIG) n=(int)x->w[0]; + else n=MR_TOOBIG; + if (s==MR_MSBIT) return (-n); + return n; +} + +int mr_compare(big x,big y) +{ /* compare x and y: =1 if x>y =-1 if xlen&MR_MSBIT); + sy=(y->len&MR_MSBIT); + if (sx==0) sig=PLUS; + else sig=MINUS; + if (sx!=sy) return sig; + m=(int)(x->len&MR_OBITS); + n=(int)(y->len&MR_OBITS); + if (m>n) return sig; + if (m0) + { /* check digit by digit */ + m--; + if (x->w[m]>y->w[m]) return sig; + if (x->w[m]w[m]) return -sig; + } + return 0; +} + +#ifdef MR_FLASH + +void fpack(_MIPD_ big n,big d,flash x) +{ /* create floating-slash number x=n/d from * + * big integer numerator and denominator */ + mr_lentype s; + int i,ld,ln; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(31) + + ld=(int)(d->len&MR_OBITS); + if (ld==0) mr_berror(_MIPP_ MR_ERR_FLASH_OVERFLOW); + if (ld==1 && d->w[0]==1) ld=0; + if (x==d) mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + if (mr_notint(n) || mr_notint(d)) mr_berror(_MIPP_ MR_ERR_INT_OP); + s=(n->len&MR_MSBIT); + ln=(int)(n->len&MR_OBITS); + if (ln==1 && n->w[0]==1) ln=0; + if ((ld+ln>mr_mip->nib) && (mr_mip->check || ld+ln>2*mr_mip->nib)) + mr_berror(_MIPP_ MR_ERR_FLASH_OVERFLOW); + if (mr_mip->ERNUM) + { + MR_OUT + return; + } + copy(n,x); + if (n->len==0) + { + MR_OUT + return; + } + s^=(d->len&MR_MSBIT); + if (ld==0) + { + if (x->len!=0) x->len|=s; + MR_OUT + return; + } + for (i=0;iw[ln+i]=d->w[i]; + x->len=(s|(ln+((mr_lentype)ld<ERNUM) return; + if (mr_notint(x)) + { + s=(x->len&MR_MSBIT); + ly=(x->len&MR_OBITS); + ln=(int)(ly&MR_MSK); + if (ln==0) + { + if(s==MR_MSBIT) convert(_MIPP_ (-1),y); + else convert(_MIPP_ 1,y); + return; + } + ld=(int)((ly>>MR_BTS)&MR_MSK); + if (x!=y) + { + for (i=0;iw[i]=x->w[i]; + for (i=ln;iw[i]=0; + } + else for (i=0;iw[ln+i]=0; + y->len=(ln|s); + } + else copy(x,y); +} + +void denom(_MIPD_ flash x,big y) +{ /* extract denominator of x */ + int i,ln,ld; + mr_lentype ly; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + if (!mr_notint(x)) + { + convert(_MIPP_ 1,y); + return; + } + ly=(x->len&MR_OBITS); + ln=(int)(ly&MR_MSK); + ld=(int)((ly>>MR_BTS)&MR_MSK); + for (i=0;iw[i]=x->w[ln+i]; + if (x==y) for (i=0;iw[ld+i]=0; + else for (i=ld;iw[i]=0; + y->len=ld; +} + +#endif + +unsigned int igcd(unsigned int x,unsigned int y) +{ /* integer GCD, returns GCD of x and y */ + unsigned int r; + if (y==0) return x; + while ((r=x%y)!=0) + x=y,y=r; + return y; +} + +unsigned long lgcd(unsigned long x,unsigned long y) +{ /* long GCD, returns GCD of x and y */ + unsigned long r; + if (y==0) return x; + while ((r=x%y)!=0) + x=y,y=r; + return y; +} + +unsigned int isqrt(unsigned int num,unsigned int guess) +{ /* square root of an integer */ + unsigned int sqr; + unsigned int oldguess=guess; + if (num==0) return 0; + if (num<4) return 1; + + for (;;) + { /* Newtons iteration */ + /* sqr=guess+(((num/guess)-guess)/2); */ + sqr=((num/guess)+guess)/2; + if (sqr==guess || sqr==oldguess) + { + if (sqr*sqr>num) sqr--; + return sqr; + } + oldguess=guess; + guess=sqr; + } +} + +unsigned long mr_lsqrt(unsigned long num,unsigned long guess) +{ /* square root of a long */ + unsigned long sqr; + unsigned long oldguess=guess; + if (num==0) return 0; + if (num<4) return 1; + + for (;;) + { /* Newtons iteration */ + /* sqr=guess+(((num/guess)-guess)/2); */ + sqr=((num/guess)+guess)/2; + if (sqr==guess || sqr==oldguess) + { + if (sqr*sqr>num) sqr--; + return sqr; + } + oldguess=guess; + guess=sqr; + } +} + +mr_small sgcd(mr_small x,mr_small y) +{ /* integer GCD, returns GCD of x and y */ + mr_small r; +#ifdef MR_FP + mr_small dres; +#endif + if (y==(mr_small)0) return x; + while ((r=MR_REMAIN(x,y))!=(mr_small)0) + x=y,y=r; + return y; +} + +/* routines to support sliding-windows exponentiation * + * in various contexts */ + +int mr_testbit(_MIPD_ big x,int n) +{ /* return value of n-th bit of big */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_FP + mr_small m,a,dres; + m=mr_shiftbits((mr_small)1,n%mr_mip->lg2b); + + a=x->w[n/mr_mip->lg2b]; + + a=MR_DIV(a,m); + + if ((MR_DIV(a,2.0)*2.0) != a) return 1; +#else + if ((x->w[n/mr_mip->lg2b] & ((mr_small)1<<(n%mr_mip->lg2b))) >0) return 1; +#endif + return 0; +} + +void mr_addbit(_MIPD_ big x,int n) +{ /* add 2^n to positive x - where you know that bit is zero. Use with care! */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + mr_lentype m=n/mr_mip->lg2b; + x->w[m]+=mr_shiftbits((mr_small)1,n%mr_mip->lg2b); + if (x->lenlen=m+1; +} + +int recode(_MIPD_ big e,int t,int w,int i) +{ /* recode exponent for Comb method */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + int j,r; + r=0; + for (j=w-1;j>=0;j--) + { + r<<=1; + r|=mr_testbit(_MIPP_ e,i+j*t); + } + return r; +} + +int mr_window(_MIPD_ big x,int i,int *nbs,int * nzs,int window_size) +{ /* returns sliding window value, max. of 5 bits, * + * (Note from version 5.23 this can be changed by * + * setting parameter window_size. This can be * + * a useful space-saver) starting at i-th bit of big x. * + * nbs is number of bits processed, nzs is the number of * + * additional trailing zeros detected. Returns valid bit * + * pattern 1x..x1 with no two adjacent 0's. So 10101 * + * will return 21 with nbs=5, nzs=0. 11001 will return 3,* + * with nbs=2, nzs=2, having stopped after the first 11..*/ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + int j,r,w; + w=window_size; + +/* check for leading 0 bit */ + + *nbs=1; + *nzs=0; + if (!mr_testbit(_MIPP_ x,i)) return 0; + +/* adjust window size if not enough bits left */ + + if (i-w+1<0) w=i+1; + + r=1; + for (j=i-1;j>i-w;j--) + { /* accumulate bits. Abort if two 0's in a row */ + (*nbs)++; + r*=2; + if (mr_testbit(_MIPP_ x,j)) r+=1; + if (r%4==0) + { /* oops - too many zeros - shorten window */ + r/=4; + *nbs-=2; + *nzs=2; + break; + } + } + if (r%2==0) + { /* remove trailing 0 */ + r/=2; + *nzs=1; + (*nbs)--; + } + return r; +} + +int mr_window2(_MIPD_ big x,big y,int i,int *nbs,int *nzs) +{ /* two bit window for double exponentiation */ + int r,w; + BOOL a,b,c,d; + w=2; + *nbs=1; + *nzs=0; + +/* check for two leading 0's */ + a=mr_testbit(_MIPP_ x,i); b=mr_testbit(_MIPP_ y,i); + + if (!a && !b) return 0; + if (i<1) w=1; + + if (a) + { + if (b) r=3; + else r=2; + } + else r=1; + if (w==1) return r; + + c=mr_testbit(_MIPP_ x,i-1); d=mr_testbit(_MIPP_ y,i-1); + + if (!c && !d) + { + *nzs=1; + return r; + } + + *nbs=2; + r*=4; + if (c) + { + if (d) r+=3; + else r+=2; + } + else r+=1; + return r; +} + +int mr_naf_window(_MIPD_ big x,big x3,int i,int *nbs,int *nzs,int store) +{ /* returns sliding window value, using fractional windows * + * where "store" precomputed values are precalulated and * + * stored. Scanning starts at the i-th bit of x. nbs is * + * the number of bits processed. nzs is number of * + * additional trailing zeros detected. x and x3 (which is * + * 3*x) are combined to produce the NAF (non-adjacent * + * form). So if x=11011(27) and x3 is 1010001, the LSB is * + * ignored and the value 100T0T (32-4-1=27) processed, * + * where T is -1. Note x.P = (3x-x)/2.P. This value will * + * return +7, with nbs=4 and nzs=1, having stopped after * + * the first 4 bits. If it goes too far, it must backtrack * + * Note in an NAF non-zero elements are never side by side, * + * so 10T10T won't happen. NOTE: return value n zero or * + * odd, -21 <= n <= +21 */ + + int nb,j,r,biggest; + + /* get first bit */ + nb=mr_testbit(_MIPP_ x3,i)-mr_testbit(_MIPP_ x,i); + + *nbs=1; + *nzs=0; + if (nb==0) return 0; + if (i==0) return nb; + + biggest=2*store-1; + + if (nb>0) r=1; + else r=(-1); + + for (j=i-1;j>0;j--) + { + (*nbs)++; + r*=2; + nb=mr_testbit(_MIPP_ x3,j)-mr_testbit(_MIPP_ x,j); + if (nb>0) r+=1; + if (nb<0) r-=1; + if (abs(r)>biggest) break; + } + + if (r%2!=0 && j!=0) + { /* backtrack */ + if (nb>0) r=(r-1)/2; + if (nb<0) r=(r+1)/2; + (*nbs)--; + } + + while (r%2==0) + { /* remove trailing zeros */ + r/=2; + (*nzs)++; + (*nbs)--; + } + return r; +} + +/* Some general purpose elliptic curve stuff */ + +BOOL point_at_infinity(epoint *p) +{ + if (p==NULL) return FALSE; + if (p->marker==MR_EPOINT_INFINITY) return TRUE; + return FALSE; +} + +#ifndef MR_STATIC + +epoint* epoint_init(_MIPDO_ ) +{ /* initialise epoint to general point at infinity. */ + epoint *p; + char *ptr; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return NULL; + + MR_IN(96) + +/* Create space for whole structure in one heap access */ + + p=(epoint *)mr_alloc(_MIPP_ mr_esize(mr_mip->nib-1),1); + + ptr=(char *)p+sizeof(epoint); + p->X=mirvar_mem(_MIPP_ ptr,0); + p->Y=mirvar_mem(_MIPP_ ptr,1); +#ifndef MR_AFFINE_ONLY + p->Z=mirvar_mem(_MIPP_ ptr,2); +#endif + p->marker=MR_EPOINT_INFINITY; + + MR_OUT + + return p; +} + +#endif + +epoint* epoint_init_mem_variable(_MIPD_ char *mem,int index,int sz) +{ + epoint *p; + char *ptr; + int offset,r; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + offset=0; + r=(unsigned long)mem%MR_SL; + if (r>0) offset=MR_SL-r; + +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + p=(epoint *)&mem[offset+index*mr_esize_a(sz)]; + else +#endif + p=(epoint *)&mem[offset+index*mr_esize(sz)]; + + ptr=(char *)p+sizeof(epoint); + p->X=mirvar_mem_variable(ptr,0,sz); + p->Y=mirvar_mem_variable(ptr,1,sz); +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord!=MR_AFFINE) p->Z=mirvar_mem_variable(ptr,2,sz); +#endif + p->marker=MR_EPOINT_INFINITY; + return p; +} + +epoint* epoint_init_mem(_MIPD_ char *mem,int index) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return NULL; + + return epoint_init_mem_variable(_MIPP_ mem,index,mr_mip->nib-1); +} + +#ifndef MR_STATIC + +/* allocate space for a number of epoints from the heap */ + +void *ecp_memalloc(_MIPD_ int num) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + return mr_alloc(_MIPP_ mr_ecp_reserve_a(num,mr_mip->nib-1),1); + else +#endif + return mr_alloc(_MIPP_ mr_ecp_reserve(num,mr_mip->nib-1),1); +} + +#endif + +void ecp_memkill(_MIPD_ char *mem,int num) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mem==NULL) return; + +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + memset(mem,0,mr_ecp_reserve_a(num,mr_mip->nib-1)); + else +#endif + memset(mem,0,mr_ecp_reserve(num,mr_mip->nib-1)); + + +#ifndef MR_STATIC + mr_free(mem); +#endif +} + +#ifndef MR_STATIC + +void epoint_free(epoint *p) +{ /* clean up point */ + + if (p==NULL) return; + zero(p->X); + zero(p->Y); +#ifndef MR_AFFINE_ONLY + if (p->marker==MR_EPOINT_GENERAL) zero(p->Z); +#endif + mr_free(p); +} + +#endif diff --git a/crypto/sm2/miracl/mrcurve.c b/crypto/sm2/miracl/mrcurve.c new file mode 100644 index 00000000..8cfdeb4f --- /dev/null +++ b/crypto/sm2/miracl/mrcurve.c @@ -0,0 +1,2507 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox IOM 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 elliptic curve routines + * mrcurve.c + * + * Assumes Weierstrass equation y^2 = x^3 + Ax + B + * See IEEE P1363 Draft Standard + * + * (See below for Edwards coordinates implementation) + * + * Uses Montgomery's representation internally + * + * Works particularly well with fixed length Comba multiplier + * e.g. #define MR_COMBA 5 for 5x32 = 160 bit modulus + * on 32-bit computer + * + */ + +#include +#include +#ifdef MR_STATIC +#include +#endif + +#ifndef MR_EDWARDS + +static void epoint_getrhs(_MIPD_ big x,big y) +{ /* x and y must be different */ + + /* find x^3+Ax+B */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + nres_modmult(_MIPP_ x,x,y); + + nres_modmult(_MIPP_ y,x,y); + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) + nres_modmult(_MIPP_ x,mr_mip->A,mr_mip->w1); + else + nres_premult(_MIPP_ x,mr_mip->Asize,mr_mip->w1); + nres_modadd(_MIPP_ y,mr_mip->w1,y); + if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) + nres_modadd(_MIPP_ y,mr_mip->B,y); + else + { + convert(_MIPP_ mr_mip->Bsize,mr_mip->w1); + nres(_MIPP_ mr_mip->w1,mr_mip->w1); + nres_modadd(_MIPP_ y,mr_mip->w1,y); + } +} + +#ifndef MR_NOSUPPORT_COMPRESSION + +BOOL epoint_x(_MIPD_ big x) +{ /* test if x is associated with a point on the * + * currently active curve */ + int j; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(147) + + if (x==NULL) return FALSE; + + nres(_MIPP_ x,mr_mip->w2); + epoint_getrhs(_MIPP_ mr_mip->w2,mr_mip->w3); + + if (size(mr_mip->w3)==0) + { + MR_OUT + return TRUE; + } + + redc(_MIPP_ mr_mip->w3,mr_mip->w4); + j=jack(_MIPP_ mr_mip->w4,mr_mip->modulus); + + MR_OUT + if (j==1) return TRUE; + return FALSE; +} + +#endif + +BOOL epoint_set(_MIPD_ big x,big y,int cb,epoint *p) +{ /* initialise a point on active ecurve * + * if x or y == NULL, set to point at infinity * + * if x==y, a y co-ordinate is calculated - if * + * possible - and cb suggests LSB 0/1 of y * + * (which "decompresses" y). Otherwise, check * + * validity of given (x,y) point, ignoring cb. * + * Returns TRUE for valid point, otherwise FALSE. */ + + BOOL valid; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(97) + + if (x==NULL || y==NULL) + { + copy(mr_mip->one,p->X); + copy(mr_mip->one,p->Y); + p->marker=MR_EPOINT_INFINITY; + MR_OUT + return TRUE; + } + +/* find x^3+Ax+B */ + + nres(_MIPP_ x,p->X); + + epoint_getrhs(_MIPP_ p->X,mr_mip->w3); + + valid=FALSE; + + if (x!=y) + { /* compare with y^2 */ + nres(_MIPP_ y,p->Y); + nres_modmult(_MIPP_ p->Y,p->Y,mr_mip->w1); + + if (mr_compare(mr_mip->w1,mr_mip->w3)==0) valid=TRUE; + } + else + { /* no y supplied - calculate one. Find square root */ +#ifndef MR_NOSUPPORT_COMPRESSION + + valid=nres_sqroot(_MIPP_ mr_mip->w3,p->Y); + /* check LSB - have we got the right root? */ + redc(_MIPP_ p->Y,mr_mip->w1); + if (remain(_MIPP_ mr_mip->w1,2)!=cb) + mr_psub(_MIPP_ mr_mip->modulus,p->Y,p->Y); + +#else + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return FALSE; +#endif + } + if (valid) + { + p->marker=MR_EPOINT_NORMALIZED; + MR_OUT + return TRUE; + } + + MR_OUT + return FALSE; +} + +#ifndef MR_STATIC + +void epoint_getxyz(_MIPD_ epoint *p,big x,big y,big z) +{ /* get (x,y,z) coordinates */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + MR_IN(143) + convert(_MIPP_ 1,mr_mip->w1); + if (p->marker==MR_EPOINT_INFINITY) + { +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { /* (0,1) or (0,0) = O */ +#endif + if (x!=NULL) zero(x); + if (mr_mip->Bsize==0) + { + if (y!=NULL) copy(mr_mip->w1,y); + } + else + { + if (y!=NULL) zero(y); + } +#ifndef MR_AFFINE_ONLY + } + if (mr_mip->coord==MR_PROJECTIVE) + { /* (1,1,0) = O */ + if (x!=NULL) copy(mr_mip->w1,x); + if (y!=NULL) copy(mr_mip->w1,y); + } +#endif + if (z!=NULL) zero(z); + MR_OUT + return; + } + if (x!=NULL) redc(_MIPP_ p->X,x); + if (y!=NULL) redc(_MIPP_ p->Y,y); +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { +#endif + if (z!=NULL) zero(z); +#ifndef MR_AFFINE_ONLY + } + + if (mr_mip->coord==MR_PROJECTIVE) + { + if (z!=NULL) + { + if (p->marker!=MR_EPOINT_GENERAL) copy(mr_mip->w1,z); + else redc(_MIPP_ p->Z,z); + } + } +#endif + MR_OUT + return; +} + +#endif + +int epoint_get(_MIPD_ epoint* p,big x,big y) +{ /* Get point co-ordinates in affine, normal form * + * (converted from projective, Montgomery form) * + * if x==y, supplies x only. Return value is Least * + * Significant Bit of y (useful for point compression) */ + + int lsb; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (p->marker==MR_EPOINT_INFINITY) + { + zero(x); + zero(y); + return 0; + } + if (mr_mip->ERNUM) return 0; + + MR_IN(98) + + if (!epoint_norm(_MIPP_ p)) + { /* not possible ! */ + MR_OUT + return (-1); + } + + redc(_MIPP_ p->X,x); + redc(_MIPP_ p->Y,mr_mip->w1); + + if (x!=y) copy(mr_mip->w1,y); + lsb=remain(_MIPP_ mr_mip->w1,2); + MR_OUT + return lsb; +} + +BOOL epoint_norm(_MIPD_ epoint *p) +{ /* normalise a point */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + +#ifndef MR_AFFINE_ONLY + + if (mr_mip->coord==MR_AFFINE) return TRUE; + if (p->marker!=MR_EPOINT_GENERAL) return TRUE; + + if (mr_mip->ERNUM) return FALSE; + + MR_IN(117) + + copy(mr_mip->one,mr_mip->w8); + + if (nres_moddiv(_MIPP_ mr_mip->w8,p->Z,mr_mip->w8)>1) /* 1/Z */ + { + epoint_set(_MIPP_ NULL,NULL,0,p); + mr_berror(_MIPP_ MR_ERR_COMPOSITE_MODULUS); + MR_OUT + return FALSE; + } + + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w1);/* 1/ZZ */ + nres_modmult(_MIPP_ p->X,mr_mip->w1,p->X); /* X/ZZ */ + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w8,mr_mip->w1);/* 1/ZZZ */ + nres_modmult(_MIPP_ p->Y,mr_mip->w1,p->Y); /* Y/ZZZ */ + + copy(mr_mip->one,p->Z); + + p->marker=MR_EPOINT_NORMALIZED; + MR_OUT + +#endif + + return TRUE; +} + +BOOL epoint_multi_norm(_MIPD_ int m,big *work,epoint **p) +{ /* Normalise an array of points of length mcoord==MR_AFFINE) return TRUE; + if (mr_mip->ERNUM) return FALSE; + if (m>MR_MAX_M_T_S) return FALSE; + + MR_IN(190) + + for (i=0;imarker==MR_EPOINT_NORMALIZED) w[i]=mr_mip->one; + else w[i]=p[i]->Z; + if (p[i]->marker==MR_EPOINT_INFINITY) {inf=TRUE; break;} /* whoops, one of them is point at infinity */ + } + + if (inf) + { + for (i=0;ione,p[i]->Z); + p[i]->marker=MR_EPOINT_NORMALIZED; + nres_modmult(_MIPP_ work[i],work[i],mr_mip->w1); + nres_modmult(_MIPP_ p[i]->X,mr_mip->w1,p[i]->X); /* X/ZZ */ + nres_modmult(_MIPP_ mr_mip->w1,work[i],mr_mip->w1); + nres_modmult(_MIPP_ p[i]->Y,mr_mip->w1,p[i]->Y); /* Y/ZZZ */ + } + MR_OUT +#endif + return TRUE; +} + +/* adds b+=a, d+=c, and slopes in s1 and s2 */ + +#ifndef MR_NO_ECC_MULTIADD +#ifndef MR_STATIC + +void ecurve_double_add(_MIPD_ epoint *a,epoint*b,epoint *c,epoint *d,big *s1,big *s2) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(144); + +#ifndef MR_AFFINE_ONLY + + if (mr_mip->coord==MR_AFFINE) + { +#endif + if (a->marker==MR_EPOINT_INFINITY || size(a->Y)==0) + { + *s1=NULL; + ecurve_add(_MIPP_ c,d); + *s2=mr_mip->w8; + MR_OUT + return; + } + if (b->marker==MR_EPOINT_INFINITY || size(b->Y)==0) + { + *s1=NULL; + epoint_copy(a,b); + ecurve_add(_MIPP_ c,d); + *s2=mr_mip->w8; + MR_OUT + return; + } + if (c->marker==MR_EPOINT_INFINITY || size(c->Y)==0) + { + ecurve_add(_MIPP_ a,b); + *s1=mr_mip->w8; + *s2=NULL; + MR_OUT + return; + } + if (d->marker==MR_EPOINT_INFINITY || size(d->Y)==0) + { + epoint_copy(c,d); + ecurve_add(_MIPP_ a,b); + *s1=mr_mip->w8; + *s2=NULL; + MR_OUT + return; + } + + if (a==b || (mr_compare(a->X,b->X)==0 && mr_compare(a->Y,b->Y)==0)) + { + nres_modmult(_MIPP_ a->X,a->X,mr_mip->w8); + nres_premult(_MIPP_ mr_mip->w8,3,mr_mip->w8); /* 3x^2 */ + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->A,mr_mip->w8); + else + { + convert(_MIPP_ mr_mip->Asize,mr_mip->w2); + nres(_MIPP_ mr_mip->w2,mr_mip->w2); + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w2,mr_mip->w8); + } + nres_premult(_MIPP_ a->Y,2,mr_mip->w10); + } + else + { + if (mr_compare(a->X,b->X)==0) + { + epoint_set(_MIPP_ NULL,NULL,0,b); + *s1=NULL; + ecurve_add(_MIPP_ c,d); + *s2=mr_mip->w8; + MR_OUT + return; + } + nres_modsub(_MIPP_ a->Y,b->Y,mr_mip->w8); + nres_modsub(_MIPP_ a->X,b->X,mr_mip->w10); + } + + if (c==d || (mr_compare(c->X,d->X)==0 && mr_compare(c->Y,d->Y)==0)) + { + nres_modmult(_MIPP_ c->X,c->X,mr_mip->w9); + nres_premult(_MIPP_ mr_mip->w9,3,mr_mip->w9); /* 3x^2 */ + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) + nres_modadd(_MIPP_ mr_mip->w9,mr_mip->A,mr_mip->w9); + else + { + convert(_MIPP_ mr_mip->Asize,mr_mip->w2); + nres(_MIPP_ mr_mip->w2,mr_mip->w2); + nres_modadd(_MIPP_ mr_mip->w9,mr_mip->w2,mr_mip->w9); + } + nres_premult(_MIPP_ c->Y,2,mr_mip->w11); + } + else + { + if (mr_compare(c->X,d->X)==0) + { + epoint_set(_MIPP_ NULL,NULL,0,d); + *s2=NULL; + ecurve_add(_MIPP_ a,b); + *s1=mr_mip->w8; + MR_OUT + return; + } + nres_modsub(_MIPP_ c->Y,d->Y,mr_mip->w9); + nres_modsub(_MIPP_ c->X,d->X,mr_mip->w11); + } + + nres_double_inverse(_MIPP_ mr_mip->w10,mr_mip->w10,mr_mip->w11,mr_mip->w11); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w10,mr_mip->w8); + nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); + + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w2); /* m^2 */ + nres_modsub(_MIPP_ mr_mip->w2,a->X,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w1,b->X,mr_mip->w1); + + nres_modsub(_MIPP_ b->X,mr_mip->w1,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w8,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w2,b->Y,b->Y); + copy(mr_mip->w1,b->X); + b->marker=MR_EPOINT_GENERAL; + + nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w9,mr_mip->w2); /* m^2 */ + nres_modsub(_MIPP_ mr_mip->w2,c->X,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w1,d->X,mr_mip->w1); + + nres_modsub(_MIPP_ d->X,mr_mip->w1,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w9,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w2,d->Y,d->Y); + copy(mr_mip->w1,d->X); + d->marker=MR_EPOINT_GENERAL; + + *s1=mr_mip->w8; + *s2=mr_mip->w9; +#ifndef MR_AFFINE_ONLY + } + else + { /* no speed-up */ + ecurve_add(_MIPP_ a,b); + copy(mr_mip->w8,mr_mip->w9); + *s1=mr_mip->w9; + ecurve_add(_MIPP_ c,d); + *s2=mr_mip->w8; + } +#endif + MR_OUT +} + +void ecurve_multi_add(_MIPD_ int m,epoint **x,epoint**w) +{ /* adds m points together simultaneously, w[i]+=x[i] */ + int i,*flag; + big *A,*B,*C; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(122) +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { /* this can be done faster */ +#endif + A=(big *)mr_alloc(_MIPP_ m,sizeof(big)); + B=(big *)mr_alloc(_MIPP_ m,sizeof(big)); + C=(big *)mr_alloc(_MIPP_ m,sizeof(big)); + flag=(int *)mr_alloc(_MIPP_ m,sizeof(int)); + + copy(mr_mip->one,mr_mip->w3); + + for (i=0;iX,w[i]->X)==0 && mr_compare(x[i]->Y,w[i]->Y)==0) + { /* doubling */ + if (x[i]->marker==MR_EPOINT_INFINITY || size(x[i]->Y)==0) + { + flag[i]=1; /* result is infinity */ + copy(mr_mip->w3,B[i]); + continue; + } + nres_modmult(_MIPP_ x[i]->X,x[i]->X,A[i]); + nres_premult(_MIPP_ A[i],3,A[i]); /* 3*x^2 */ + if (mr_abs(mr_mip->Asize) == MR_TOOBIG) + nres_modadd(_MIPP_ A[i],mr_mip->A,A[i]); + else + { + convert(_MIPP_ mr_mip->Asize,mr_mip->w2); + nres(_MIPP_ mr_mip->w2,mr_mip->w2); + nres_modadd(_MIPP_ A[i],mr_mip->w2,A[i]); + } /* 3*x^2+A */ + nres_premult(_MIPP_ x[i]->Y,2,B[i]); + } + else + { + if (x[i]->marker==MR_EPOINT_INFINITY) + { + flag[i]=2; /* w[i] unchanged */ + copy(mr_mip->w3,B[i]); + continue; + } + if (w[i]->marker==MR_EPOINT_INFINITY) + { + flag[i]=3; /* w[i] = x[i] */ + copy(mr_mip->w3,B[i]); + continue; + } + nres_modsub(_MIPP_ x[i]->X,w[i]->X,B[i]); + if (size(B[i])==0) + { /* point at infinity */ + flag[i]=1; /* result is infinity */ + copy(mr_mip->w3,B[i]); + continue; + } + nres_modsub(_MIPP_ x[i]->Y,w[i]->Y,A[i]); + } + } + nres_multi_inverse(_MIPP_ m,B,C); /* only one inversion needed */ + for (i=0;iw8); + + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w2); /* m^2 */ + nres_modsub(_MIPP_ mr_mip->w2,x[i]->X,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w1,w[i]->X,mr_mip->w1); + + nres_modsub(_MIPP_ w[i]->X,mr_mip->w1,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w8,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w2,w[i]->Y,w[i]->Y); + copy(mr_mip->w1,w[i]->X); + w[i]->marker=MR_EPOINT_NORMALIZED; + + mr_free(C[i]); + mr_free(B[i]); + mr_free(A[i]); + } + mr_free(flag); + mr_free(C); mr_free(B); mr_free(A); +#ifndef MR_AFFINE_ONLY + } + else + { /* no speed-up */ + for (i=0;iERNUM) return; + + if (p->marker==MR_EPOINT_INFINITY) + { /* 2 times infinity == infinity ! */ + return; + } + +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { /* 2 sqrs, 1 mul, 1 div */ +#endif + if (size(p->Y)==0) + { /* set to point at infinity */ + epoint_set(_MIPP_ NULL,NULL,0,p); + return; + } + + nres_modmult(_MIPP_ p->X,p->X,mr_mip->w8); /* w8=x^2 */ + nres_premult(_MIPP_ mr_mip->w8,3,mr_mip->w8); /* w8=3*x^2 */ + if (mr_abs(mr_mip->Asize) == MR_TOOBIG) + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->A,mr_mip->w8); + else + { + convert(_MIPP_ mr_mip->Asize,mr_mip->w2); + nres(_MIPP_ mr_mip->w2,mr_mip->w2); + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w2,mr_mip->w8); + } /* w8=3*x^2+A */ + nres_premult(_MIPP_ p->Y,2,mr_mip->w6); /* w6=2y */ + if (nres_moddiv(_MIPP_ mr_mip->w8,mr_mip->w6,mr_mip->w8)>1) + { + epoint_set(_MIPP_ NULL,NULL,0,p); + mr_berror(_MIPP_ MR_ERR_COMPOSITE_MODULUS); + return; + } + +/* w8 is slope m on exit */ + + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w2); /* w2=m^2 */ + nres_premult(_MIPP_ p->X,2,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w2,mr_mip->w1,mr_mip->w1); /* w1=m^2-2x */ + + nres_modsub(_MIPP_ p->X,mr_mip->w1,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w8,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w2,p->Y,p->Y); + copy(mr_mip->w1,p->X); + + return; +#ifndef MR_AFFINE_ONLY + } + + if (size(p->Y)==0) + { /* set to point at infinity */ + epoint_set(_MIPP_ NULL,NULL,0,p); + return; + } + + convert(_MIPP_ 1,mr_mip->w1); + if (mr_abs(mr_mip->Asize) < MR_TOOBIG) + { + if (mr_mip->Asize!=0) + { + if (p->marker==MR_EPOINT_NORMALIZED) + nres(_MIPP_ mr_mip->w1,mr_mip->w6); + else nres_modmult(_MIPP_ p->Z,p->Z,mr_mip->w6); + } + + if (mr_mip->Asize==(-3)) + { /* a is -3. Goody. 4 sqrs, 4 muls */ + nres_modsub(_MIPP_ p->X,mr_mip->w6,mr_mip->w3); + nres_modadd(_MIPP_ p->X,mr_mip->w6,mr_mip->w8); + nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w8,mr_mip->w3); + nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w3,mr_mip->w8); + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w8); + } + else + { /* a is small */ + if (mr_mip->Asize!=0) + { /* a is non zero! */ + nres_modmult(_MIPP_ mr_mip->w6,mr_mip->w6,mr_mip->w3); + nres_premult(_MIPP_ mr_mip->w3,mr_mip->Asize,mr_mip->w3); + } + nres_modmult(_MIPP_ p->X,p->X,mr_mip->w1); + nres_modadd(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w8); + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w1,mr_mip->w8); + if (mr_mip->Asize!=0) nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w8); + } + } + else + { /* a is not special */ + if (p->marker==MR_EPOINT_NORMALIZED) nres(_MIPP_ mr_mip->w1,mr_mip->w6); + else nres_modmult(_MIPP_ p->Z,p->Z,mr_mip->w6); + + nres_modmult(_MIPP_ mr_mip->w6,mr_mip->w6,mr_mip->w3); + nres_modmult(_MIPP_ mr_mip->w3,mr_mip->A,mr_mip->w3); + nres_modmult(_MIPP_ p->X,p->X,mr_mip->w1); + nres_modadd(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w8); + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w1,mr_mip->w8); + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w8); + } + +/* w8 contains numerator of slope 3x^2+A.z^4 * + * denominator is now placed in Z */ + + nres_modmult(_MIPP_ p->Y,p->Y,mr_mip->w2); + nres_modmult(_MIPP_ p->X,mr_mip->w2,mr_mip->w3); + nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w3,mr_mip->w3); + nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w3,mr_mip->w3); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,p->X); + nres_modsub(_MIPP_ p->X,mr_mip->w3,p->X); + nres_modsub(_MIPP_ p->X,mr_mip->w3,p->X); + + if (p->marker==MR_EPOINT_NORMALIZED) + copy(p->Y,p->Z); + else nres_modmult(_MIPP_ p->Z,p->Y,p->Z); + nres_modadd(_MIPP_ p->Z,p->Z,p->Z); + + nres_modadd(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w7); + nres_modmult(_MIPP_ mr_mip->w7,mr_mip->w7,mr_mip->w2); + nres_modadd(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w3,p->X,mr_mip->w3); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w3,p->Y); + nres_modsub(_MIPP_ p->Y,mr_mip->w2,p->Y); + +/* alternative method + nres_modadd(_MIPP_ p->Y,p->Y,mr_mip->w2); + + if (p->marker==MR_EPOINT_NORMALIZED) + copy(mr_mip->w2,p->Z); + + else nres_modmult(_MIPP_ mr_mip->w2,p->Z,p->Z); + + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w2); + nres_modmult(_MIPP_ p->X,mr_mip->w2,mr_mip->w3); + nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w3,p->X); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w1,p->X,p->X); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w2); + + if (remain(_MIPP_ mr_mip->w2,2)!=0) + mr_padd(_MIPP_ mr_mip->w2,mr_mip->modulus,mr_mip->w2); + subdiv(_MIPP_ mr_mip->w2,2,mr_mip->w2); + + nres_modsub(_MIPP_ mr_mip->w3,p->X,mr_mip->w3); + nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w8,mr_mip->w3); + nres_modsub(_MIPP_ mr_mip->w3,mr_mip->w2,p->Y); +*/ + +/* + +Observe that when finished w8 contains the line slope, w7 has 2y^2 and w6 has z^2 +This is useful for calculating line functions in pairings + +*/ + + p->marker=MR_EPOINT_GENERAL; + return; +#endif +} + +static BOOL ecurve_padd(_MIPD_ epoint *p,epoint *pa) +{ /* primitive add two epoints on the active ecurve - pa+=p; * + * note that if p is normalized, its Z coordinate isn't used */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { /* 1 sqr, 1 mul, 1 div */ +#endif + nres_modsub(_MIPP_ p->Y,pa->Y,mr_mip->w8); + nres_modsub(_MIPP_ p->X,pa->X,mr_mip->w6); + if (size(mr_mip->w6)==0) + { /* divide by 0 */ + if (size(mr_mip->w8)==0) + { /* should have doubled ! */ + return FALSE; + } + else + { /* point at infinity */ + epoint_set(_MIPP_ NULL,NULL,0,pa); + return TRUE; + } + } + if (nres_moddiv(_MIPP_ mr_mip->w8,mr_mip->w6,mr_mip->w8)>1) + { + epoint_set(_MIPP_ NULL,NULL,0,pa); + mr_berror(_MIPP_ MR_ERR_COMPOSITE_MODULUS); + return TRUE; + } + + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w2); /* w2=m^2 */ + nres_modsub(_MIPP_ mr_mip->w2,p->X,mr_mip->w1); /* w1=m^2-x1-x2 */ + nres_modsub(_MIPP_ mr_mip->w1,pa->X,mr_mip->w1); + + + nres_modsub(_MIPP_ pa->X,mr_mip->w1,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w8,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w2,pa->Y,pa->Y); + copy(mr_mip->w1,pa->X); + + pa->marker=MR_EPOINT_NORMALIZED; + return TRUE; +#ifndef MR_AFFINE_ONLY + } + + if (p->marker!=MR_EPOINT_NORMALIZED) + { + nres_modmult(_MIPP_ p->Z,p->Z,mr_mip->w6); + nres_modmult(_MIPP_ pa->X,mr_mip->w6,mr_mip->w1); + nres_modmult(_MIPP_ mr_mip->w6,p->Z,mr_mip->w6); + nres_modmult(_MIPP_ pa->Y,mr_mip->w6,mr_mip->w8); + } + else + { + copy(pa->X,mr_mip->w1); + copy(pa->Y,mr_mip->w8); + } + if (pa->marker==MR_EPOINT_NORMALIZED) + copy(mr_mip->one,mr_mip->w6); + + else nres_modmult(_MIPP_ pa->Z,pa->Z,mr_mip->w6); + nres_modmult(_MIPP_ p->X,mr_mip->w6,mr_mip->w4); + if (pa->marker!=MR_EPOINT_NORMALIZED) + nres_modmult(_MIPP_ mr_mip->w6,pa->Z,mr_mip->w6); + nres_modmult(_MIPP_ p->Y,mr_mip->w6,mr_mip->w5); + nres_modsub(_MIPP_ mr_mip->w1,mr_mip->w4,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w5,mr_mip->w8); + +/* w8 contains the numerator of the slope */ + + if (size(mr_mip->w1)==0) + { + if (size(mr_mip->w8)==0) + { /* should have doubled ! */ + return FALSE; + } + else + { /* point at infinity */ + epoint_set(_MIPP_ NULL,NULL,0,pa); + return TRUE; + } + } + nres_modadd(_MIPP_ mr_mip->w4,mr_mip->w4,mr_mip->w6); + nres_modadd(_MIPP_ mr_mip->w1,mr_mip->w6,mr_mip->w4); + nres_modadd(_MIPP_ mr_mip->w5,mr_mip->w5,mr_mip->w6); + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w6,mr_mip->w5); + + if (p->marker!=MR_EPOINT_NORMALIZED) + { + if (pa->marker!=MR_EPOINT_NORMALIZED) + nres_modmult(_MIPP_ pa->Z,p->Z,mr_mip->w3); + else + copy(p->Z,mr_mip->w3); + nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w1,pa->Z); + } + else + { + if (pa->marker!=MR_EPOINT_NORMALIZED) + nres_modmult(_MIPP_ pa->Z,mr_mip->w1,pa->Z); + else + copy(mr_mip->w1,pa->Z); + } + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w6); + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w6,mr_mip->w1); + nres_modmult(_MIPP_ mr_mip->w6,mr_mip->w4,mr_mip->w6); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w4); + + nres_modsub(_MIPP_ mr_mip->w4,mr_mip->w6,pa->X); + nres_modsub(_MIPP_ mr_mip->w6,pa->X,mr_mip->w6); + nres_modsub(_MIPP_ mr_mip->w6,pa->X,mr_mip->w6); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w6,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w5,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w2,mr_mip->w1,mr_mip->w5); + +/* divide by 2 */ + + nres_div2(_MIPP_ mr_mip->w5,pa->Y); + + pa->marker=MR_EPOINT_GENERAL; + return TRUE; +#endif +} + +void epoint_copy(epoint *a,epoint *b) +{ + if (a==b || b==NULL) return; + + copy(a->X,b->X); + copy(a->Y,b->Y); +#ifndef MR_AFFINE_ONLY + if (a->marker==MR_EPOINT_GENERAL) copy(a->Z,b->Z); +#endif + b->marker=a->marker; + return; +} + +BOOL epoint_comp(_MIPD_ epoint *a,epoint *b) +{ + BOOL result; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + if (a==b) return TRUE; + if (a->marker==MR_EPOINT_INFINITY) + { + if (b->marker==MR_EPOINT_INFINITY) return TRUE; + else return FALSE; + } + if (b->marker==MR_EPOINT_INFINITY) + return FALSE; + +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { +#endif + if (mr_compare(a->X,b->X)==0 && mr_compare(a->Y,b->Y)==0) result=TRUE; + else result=FALSE; + return result; +#ifndef MR_AFFINE_ONLY + } + + if (mr_mip->coord==MR_PROJECTIVE) + { + MR_IN(105) + if (a->marker!=MR_EPOINT_GENERAL) + copy(mr_mip->one,mr_mip->w1); + else copy(a->Z,mr_mip->w1); + + if (b->marker!=MR_EPOINT_GENERAL) + copy(mr_mip->one,mr_mip->w2); + else copy(b->Z,mr_mip->w2); + + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w3); /* Za*Za */ + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w4); /* Zb*Zb */ + + nres_modmult(_MIPP_ a->X,mr_mip->w4,mr_mip->w5); /* Xa*Zb*Zb */ + nres_modmult(_MIPP_ b->X,mr_mip->w3,mr_mip->w6); /* Xb*Za*Za */ + + if (mr_compare(mr_mip->w5,mr_mip->w6)!=0) result=FALSE; + else + { + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w3,mr_mip->w3); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w4,mr_mip->w4); + + nres_modmult(_MIPP_ a->Y,mr_mip->w4,mr_mip->w5); + nres_modmult(_MIPP_ b->Y,mr_mip->w3,mr_mip->w6); + + if (mr_compare(mr_mip->w5,mr_mip->w6)!=0) result=FALSE; + else result=TRUE; + } + MR_OUT + return result; + } + return FALSE; +#endif +} + +int ecurve_add(_MIPD_ epoint *p,epoint *pa) +{ /* pa=pa+p; */ + /* An ephemeral pointer to the line slope is returned */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return MR_OVER; + + MR_IN(94) + + if (p==pa) + { + ecurve_double(_MIPP_ pa); + MR_OUT + if (pa->marker==MR_EPOINT_INFINITY) return MR_OVER; + return MR_DOUBLE; + } + if (pa->marker==MR_EPOINT_INFINITY) + { + epoint_copy(p,pa); + MR_OUT + return MR_ADD; + } + if (p->marker==MR_EPOINT_INFINITY) + { + MR_OUT + return MR_ADD; + } + + if (!ecurve_padd(_MIPP_ p,pa)) + { + ecurve_double(_MIPP_ pa); + MR_OUT + return MR_DOUBLE; + } + MR_OUT + if (pa->marker==MR_EPOINT_INFINITY) return MR_OVER; + return MR_ADD; +} + +void epoint_negate(_MIPD_ epoint *p) +{ /* negate a point */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + if (p->marker==MR_EPOINT_INFINITY) return; + + MR_IN(121) + if (size(p->Y)!=0) mr_psub(_MIPP_ mr_mip->modulus,p->Y,p->Y); + MR_OUT +} + +int ecurve_sub(_MIPD_ epoint *p,epoint *pa) +{ + int r; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return MR_OVER; + + MR_IN(104) + + if (p==pa) + { + epoint_set(_MIPP_ NULL,NULL,0,pa); + MR_OUT + return MR_OVER; + } + if (p->marker==MR_EPOINT_INFINITY) + { + MR_OUT + return MR_ADD; + } + + epoint_negate(_MIPP_ p); + r=ecurve_add(_MIPP_ p,pa); + epoint_negate(_MIPP_ p); + + MR_OUT + return r; +} + +int ecurve_mult(_MIPD_ big e,epoint *pa,epoint *pt) +{ /* pt=e*pa; */ + int i,j,n,nb,nbs,nzs,nadds; + epoint *table[MR_ECC_STORE_N]; +#ifndef MR_AFFINE_ONLY + big work[MR_ECC_STORE_N]; +#endif + +#ifdef MR_STATIC + char mem[MR_ECP_RESERVE(MR_ECC_STORE_N)]; +#ifndef MR_AFFINE_ONLY + char mem1[MR_BIG_RESERVE(MR_ECC_STORE_N)]; +#endif +#else + char *mem; +#ifndef MR_AFFINE_ONLY + char *mem1; +#endif +#endif + +#ifndef MR_ALWAYS_BINARY + epoint *p; + int ce,ch; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(95) + if (size(e)==0) + { /* multiplied by 0 */ + epoint_set(_MIPP_ NULL,NULL,0,pt); + MR_OUT + return 0; + } + copy(e,mr_mip->w9); +/* epoint_norm(_MIPP_ pa); */ + epoint_copy(pa,pt); + + if (size(mr_mip->w9)<0) + { /* pt = -pt */ + negify(mr_mip->w9,mr_mip->w9); + epoint_negate(_MIPP_ pt); + } + + if (size(mr_mip->w9)==1) + { + MR_OUT + return 0; + } + + premult(_MIPP_ mr_mip->w9,3,mr_mip->w10); /* h=3*e */ + +#ifndef MR_STATIC +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif +#endif + +#ifdef MR_STATIC + memset(mem,0,MR_ECP_RESERVE(MR_ECC_STORE_N)); +#ifndef MR_AFFINE_ONLY + memset(mem1,0,MR_BIG_RESERVE(MR_ECC_STORE_N)); +#endif +#else + mem=(char *)ecp_memalloc(_MIPP_ MR_ECC_STORE_N); +#ifndef MR_AFFINE_ONLY + mem1=(char *)memalloc(_MIPP_ MR_ECC_STORE_N); +#endif +#endif + + for (i=0;i<=MR_ECC_STORE_N-1;i++) + { + table[i]=epoint_init_mem(_MIPP_ mem,i); +#ifndef MR_AFFINE_ONLY + work[i]=mirvar_mem(_MIPP_ mem1,i); +#endif + } + + epoint_copy(pt,table[0]); + epoint_copy(table[0],table[MR_ECC_STORE_N-1]); + ecurve_double(_MIPP_ table[MR_ECC_STORE_N-1]); + /* epoint_norm(_MIPP_ table[MR_ECC_STORE_N-1]); */ + + for (i=1;iw10); + nadds=0; + epoint_set(_MIPP_ NULL,NULL,0,pt); + for (i=nb-1;i>=1;) + { /* add/subtract */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + n=mr_naf_window(_MIPP_ mr_mip->w9,mr_mip->w10,i,&nbs,&nzs,MR_ECC_STORE_N); + for (j=0;j0) {ecurve_add(_MIPP_ table[n/2],pt); nadds++;} + if (n<0) {ecurve_sub(_MIPP_ table[(-n)/2],pt); nadds++;} + i-=nbs; + if (nzs) + { + for (j=0;jw10)-1,mr_mip->w11); + mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); + subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); + while (size(mr_mip->w11) > 1) + { /* add/subtract method */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + ecurve_double(_MIPP_ pt); + ce=mr_compare(mr_mip->w9,mr_mip->w11); /* e(i)=1? */ + ch=mr_compare(mr_mip->w10,mr_mip->w11); /* h(i)=1? */ + if (ch>=0) + { /* h(i)=1 */ + if (ce<0) {ecurve_add(_MIPP_ p,pt); nadds++;} + mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); + } + if (ce>=0) + { /* e(i)=1 */ + if (ch<0) {ecurve_sub(_MIPP_ p,pt); nadds++;} + mr_psub(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); + } + subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); + } + ecp_memkill(_MIPP_ mem,1); + } +#endif +#endif + MR_OUT + return nadds; +} + +#ifndef MR_NO_ECC_MULTIADD +#ifndef MR_STATIC + +void ecurve_multn(_MIPD_ int n,big *y,epoint **x,epoint *w) +{ /* pt=e[o]*p[0]+e[1]*p[1]+ .... e[n-1]*p[n-1] */ + int i,j,k,m,nb,ea; + epoint **G; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(114) + + m=1< nb) nb=k; + + epoint_set(_MIPP_ NULL,NULL,0,w); /* w=0 */ + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + for (i=nb-1;i>=0;i--) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + ea=0; + k=1; + for (j=0;jERNUM) return FALSE; + + if (P->marker==MR_EPOINT_GENERAL || Q->marker==MR_EPOINT_GENERAL) + { + mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + MR_OUT + return FALSE; + } + + if (mr_compare(P->X,Q->X)==0) + { /* P=Q or P=-Q - shouldn't happen */ + epoint_copy(P,PP); + ecurve_add(_MIPP_ Q,PP); + epoint_copy(P,PM); + ecurve_sub(_MIPP_ Q,PM); + + MR_OUT + return TRUE; + } + + t1= mr_mip->w10; + t2= mr_mip->w11; + lam = mr_mip->w13; + + copy(P->X,t2); + nres_modsub(_MIPP_ t2,Q->X,t2); + + redc(_MIPP_ t2,t2); + invmodp(_MIPP_ t2,mr_mip->modulus,t2); + nres(_MIPP_ t2,t2); + + nres_modadd(_MIPP_ P->X,Q->X,PP->X); + copy(PP->X,PM->X); + + copy(P->Y,t1); + nres_modsub(_MIPP_ t1,Q->Y,t1); + copy(t1,lam); + nres_modmult(_MIPP_ lam,t2,lam); + copy(lam,t1); + nres_modmult(_MIPP_ t1,t1,t1); + nres_modsub(_MIPP_ t1,PP->X,PP->X); + copy(Q->X,PP->Y); + nres_modsub(_MIPP_ PP->Y,PP->X,PP->Y); + nres_modmult(_MIPP_ PP->Y,lam,PP->Y); + nres_modsub(_MIPP_ PP->Y,Q->Y,PP->Y); + + copy(P->Y,t1); + nres_modadd(_MIPP_ t1,Q->Y,t1); + copy(t1,lam); + nres_modmult(_MIPP_ lam,t2,lam); + copy(lam,t1); + nres_modmult(_MIPP_ t1,t1,t1); + nres_modsub(_MIPP_ t1,PM->X,PM->X); + copy(Q->X,PM->Y); + nres_modsub(_MIPP_ PM->Y,PM->X,PM->Y); + nres_modmult(_MIPP_ PM->Y,lam,PM->Y); + nres_modadd(_MIPP_ PM->Y,Q->Y,PM->Y); + + PP->marker=MR_EPOINT_NORMALIZED; + PM->marker=MR_EPOINT_NORMALIZED; + + return TRUE; +} + +void ecurve_mult2(_MIPD_ big e,epoint *p,big ea,epoint *pa,epoint *pt) +{ /* pt=e*p+ea*pa; */ + int e1,h1,e2,h2,bb; + epoint *p1,*p2,*ps[2]; +#ifdef MR_STATIC + char mem[MR_ECP_RESERVE(4)]; +#else + char *mem; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return; + + MR_IN(103) + + if (size(e)==0) + { + ecurve_mult(_MIPP_ ea,pa,pt); + MR_OUT + return; + } +#ifdef MR_STATIC + memset(mem,0,MR_ECP_RESERVE(4)); +#else + mem=(char *)ecp_memalloc(_MIPP_ 4); +#endif + p2=epoint_init_mem(_MIPP_ mem,0); + p1=epoint_init_mem(_MIPP_ mem,1); + ps[0]=epoint_init_mem(_MIPP_ mem,2); + ps[1]=epoint_init_mem(_MIPP_ mem,3); + + epoint_norm(_MIPP_ pa); + epoint_copy(pa,p2); + copy(ea,mr_mip->w9); + if (size(mr_mip->w9)<0) + { /* p2 = -p2 */ + negify(mr_mip->w9,mr_mip->w9); + epoint_negate(_MIPP_ p2); + } + + epoint_norm(_MIPP_ p); + epoint_copy(p,p1); + copy(e,mr_mip->w12); + if (size(mr_mip->w12)<0) + { /* p1= -p1 */ + negify(mr_mip->w12,mr_mip->w12); + epoint_negate(_MIPP_ p1); + } + + + epoint_set(_MIPP_ NULL,NULL,0,pt); /* pt=0 */ + ecurve_add_sub(_MIPP_ p1,p2,ps[0],ps[1]); /* only one inversion! ps[0]=p1+p2, ps[1]=p1-p2 */ + + mr_jsf(_MIPP_ mr_mip->w9,mr_mip->w12,mr_mip->w10,mr_mip->w9,mr_mip->w13,mr_mip->w12); + +/* To use a simple NAF instead, substitute this for the JSF + premult(_MIPP_ mr_mip->w9,3,mr_mip->w10); 3*ea + premult(_MIPP_ mr_mip->w12,3,mr_mip->w13); 3*e +*/ + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + if (mr_compare(mr_mip->w10,mr_mip->w13)>=0) bb=logb2(_MIPP_ mr_mip->w10)-1; + else bb=logb2(_MIPP_ mr_mip->w13)-1; + + while (bb>=0) /* for the simple NAF, this should be 1 */ + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + ecurve_double(_MIPP_ pt); + + e1=h1=e2=h2=0; + if (mr_testbit(_MIPP_ mr_mip->w9,bb)) e2=1; + if (mr_testbit(_MIPP_ mr_mip->w10,bb)) h2=1; + if (mr_testbit(_MIPP_ mr_mip->w12,bb)) e1=1; + if (mr_testbit(_MIPP_ mr_mip->w13,bb)) h1=1; + + if (e1!=h1) + { + if (e2==h2) + { + if (h1==1) ecurve_add(_MIPP_ p1,pt); + else ecurve_sub(_MIPP_ p1,pt); + } + else + { + if (h1==1) + { + if (h2==1) ecurve_add(_MIPP_ ps[0],pt); + else ecurve_add(_MIPP_ ps[1],pt); + } + else + { + if (h2==1) ecurve_sub(_MIPP_ ps[1],pt); + else ecurve_sub(_MIPP_ ps[0],pt); + } + } + } + else if (e2!=h2) + { + if (h2==1) ecurve_add(_MIPP_ p2,pt); + else ecurve_sub(_MIPP_ p2,pt); + } + bb-=1; + } +#ifndef MR_ALWAYS_BINARY + } + else + { + if (mr_compare(mr_mip->w10,mr_mip->w13)>=0) + expb2(_MIPP_ logb2(_MIPP_ mr_mip->w10)-1,mr_mip->w11); + else expb2(_MIPP_ logb2(_MIPP_ mr_mip->w13)-1,mr_mip->w11); + + while (size(mr_mip->w11) > 0) /* for the NAF, this should be 1 */ + { /* add/subtract method */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + ecurve_double(_MIPP_ pt); + + e1=h1=e2=h2=0; + if (mr_compare(mr_mip->w9,mr_mip->w11)>=0) + { /* e1(i)=1? */ + e2=1; + mr_psub(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); + } + if (mr_compare(mr_mip->w10,mr_mip->w11)>=0) + { /* h1(i)=1? */ + h2=1; + mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); + } + if (mr_compare(mr_mip->w12,mr_mip->w11)>=0) + { /* e2(i)=1? */ + e1=1; + mr_psub(_MIPP_ mr_mip->w12,mr_mip->w11,mr_mip->w12); + } + if (mr_compare(mr_mip->w13,mr_mip->w11)>=0) + { /* h2(i)=1? */ + h1=1; + mr_psub(_MIPP_ mr_mip->w13,mr_mip->w11,mr_mip->w13); + } + + if (e1!=h1) + { + if (e2==h2) + { + if (h1==1) ecurve_add(_MIPP_ p1,pt); + else ecurve_sub(_MIPP_ p1,pt); + } + else + { + if (h1==1) + { + if (h2==1) ecurve_add(_MIPP_ ps[0],pt); + else ecurve_add(_MIPP_ ps[1],pt); + } + else + { + if (h2==1) ecurve_sub(_MIPP_ ps[1],pt); + else ecurve_sub(_MIPP_ ps[0],pt); + } + } + } + else if (e2!=h2) + { + if (h2==1) ecurve_add(_MIPP_ p2,pt); + else ecurve_sub(_MIPP_ p2,pt); + } + + subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); + } + } +#endif + ecp_memkill(_MIPP_ mem,4); + MR_OUT +} + +#endif + +#else + +/* Twisted Inverted Edwards curves + + * Assumes Twisted Inverted Edward's equation x^2+Ay^2 = x^2.y^2 + B + * Assumes points are not of order 2 or 4 +*/ + +static void epoint_getrhs(_MIPD_ big x,big y) +{ + /* find RHS=(x^2-B)/(x^2-A) */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + nres_modmult(_MIPP_ x,x,mr_mip->w6); + nres_modsub(_MIPP_ mr_mip->w6,mr_mip->B,y); + nres_modsub(_MIPP_ mr_mip->w6,mr_mip->A,mr_mip->w6); + + nres_moddiv(_MIPP_ y,mr_mip->w6,y); +} + +#ifndef MR_NOSUPPORT_COMPRESSION + +BOOL epoint_x(_MIPD_ big x) +{ /* test if x is associated with a point on the * + * currently active curve */ + int j; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(147) + + if (x==NULL) return FALSE; + + nres(_MIPP_ x,mr_mip->w2); + epoint_getrhs(_MIPP_ mr_mip->w2,mr_mip->w7); + + if (size(mr_mip->w7)==0) + { + MR_OUT + return TRUE; + } + + redc(_MIPP_ mr_mip->w7,mr_mip->w4); + j=jack(_MIPP_ mr_mip->w4,mr_mip->modulus); + + MR_OUT + if (j==1) return TRUE; + return FALSE; +} + +#endif + +BOOL epoint_set(_MIPD_ big x,big y,int cb,epoint *p) +{ /* initialise a point on active ecurve * + * if x or y == NULL, set to point at infinity * + * if x==y, a y co-ordinate is calculated - if * + * possible - and cb suggests LSB 0/1 of y * + * (which "decompresses" y). Otherwise, check * + * validity of given (x,y) point, ignoring cb. * + * Returns TRUE for valid point, otherwise FALSE. */ + + BOOL valid; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(97) + + if (x==NULL || y==NULL) + { + copy(mr_mip->one,p->X); + zero(p->Y); + p->marker=MR_EPOINT_INFINITY; + MR_OUT + return TRUE; + } + + valid=FALSE; + nres(_MIPP_ x,p->X); + if (x!=y) + { /* Check directly that x^2+Ay^2 == x^2.y^2+B */ + nres(_MIPP_ y,p->Y); + nres_modmult(_MIPP_ p->X,p->X,mr_mip->w1); + nres_modmult(_MIPP_ p->Y,p->Y,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w3); + nres_modadd(_MIPP_ mr_mip->w3,mr_mip->B,mr_mip->w3); + + + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->A,mr_mip->w2); + else + nres_premult(_MIPP_ mr_mip->w2,mr_mip->Asize,mr_mip->w2); + nres_modadd(_MIPP_ mr_mip->w2,mr_mip->w1,mr_mip->w2); + if (mr_compare(mr_mip->w2,mr_mip->w3)==0) valid=TRUE; + } + else + { /* find RHS */ + epoint_getrhs(_MIPP_ p->X,mr_mip->w7); + /* no y supplied - calculate one. Find square root */ +#ifndef MR_NOSUPPORT_COMPRESSION + valid=nres_sqroot(_MIPP_ mr_mip->w7,p->Y); + /* check LSB - have we got the right root? */ + redc(_MIPP_ p->Y,mr_mip->w1); + if (remain(_MIPP_ mr_mip->w1,2)!=cb) + mr_psub(_MIPP_ mr_mip->modulus,p->Y,p->Y); + +#else + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return FALSE; +#endif + } + if (valid) + { + p->marker=MR_EPOINT_NORMALIZED; + MR_OUT + return TRUE; + } + + MR_OUT + return FALSE; +} + +#ifndef MR_STATIC + +void epoint_getxyz(_MIPD_ epoint *p,big x,big y,big z) +{ /* get (x,y,z) coordinates */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + MR_IN(143) + convert(_MIPP_ 1,mr_mip->w1); + if (p->marker==MR_EPOINT_INFINITY) + { + if (x!=NULL) copy(mr_mip->w1,x); + if (y!=NULL) zero(y); + if (z!=NULL) zero(z); + MR_OUT + return; + } + if (x!=NULL) redc(_MIPP_ p->X,x); + if (y!=NULL) redc(_MIPP_ p->Y,y); + if (z!=NULL) redc(_MIPP_ p->Z,z); + + MR_OUT + return; +} + +#endif + +int epoint_get(_MIPD_ epoint* p,big x,big y) +{ /* Get point co-ordinates in affine, normal form * + * (converted from projective, Montgomery form) * + * if x==y, supplies x only. Return value is Least * + * Significant Bit of y (useful for point compression) */ + + int lsb; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (p->marker==MR_EPOINT_INFINITY) + { + zero(y); + convert(_MIPP_ 1,x); + return 0; + } + if (mr_mip->ERNUM) return 0; + + MR_IN(98) + + if (!epoint_norm(_MIPP_ p)) + { /* not possible ! */ + MR_OUT + return (-1); + } + + redc(_MIPP_ p->X,x); + redc(_MIPP_ p->Y,mr_mip->w1); + + if (x!=y) copy(mr_mip->w1,y); + lsb=remain(_MIPP_ mr_mip->w1,2); + MR_OUT + return lsb; +} + +BOOL epoint_norm(_MIPD_ epoint *p) +{ /* normalise a point */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (p->marker!=MR_EPOINT_GENERAL) return TRUE; + + if (mr_mip->ERNUM) return FALSE; + + MR_IN(117) + + copy(mr_mip->one,mr_mip->w8); + + if (nres_moddiv(_MIPP_ mr_mip->w8,p->Z,mr_mip->w8)>1) /* 1/Z */ + { + epoint_set(_MIPP_ NULL,NULL,0,p); + mr_berror(_MIPP_ MR_ERR_COMPOSITE_MODULUS); + MR_OUT + return FALSE; + } + + nres_modmult(_MIPP_ p->X,mr_mip->w8,p->X); /* X/Z */ + nres_modmult(_MIPP_ p->Y,mr_mip->w8,p->Y); /* Y/Z */ + + copy(mr_mip->one,p->Z); + + p->marker=MR_EPOINT_NORMALIZED; + MR_OUT + + return TRUE; +} + +void ecurve_double(_MIPD_ epoint *p) +{ /* double epoint on active ecurve */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + if (p->marker==MR_EPOINT_INFINITY) + { /* 2 times infinity == infinity ! */ + return; + } + nres_modadd(_MIPP_ p->X,p->Y,mr_mip->w1); + + nres_modmult(_MIPP_ p->X,p->X,p->X); /* A=X1^2 */ + nres_modmult(_MIPP_ p->Y,p->Y,p->Y); /* B=Y1^2 */ + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w1); /* (X+Y)^2 */ + nres_modsub(_MIPP_ mr_mip->w1,p->X,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w1,p->Y,mr_mip->w1); /* E=(X+Y)^2-A-B */ + + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) /* U = aB */ + nres_modmult(_MIPP_ p->Y,mr_mip->A,p->Y); + else + nres_premult(_MIPP_ p->Y,mr_mip->Asize,p->Y); + + if (p->marker!=MR_EPOINT_NORMALIZED) + nres_modmult(_MIPP_ p->Z,p->Z,p->Z); + else + copy(mr_mip->one,p->Z); + + nres_modadd(_MIPP_ p->Z,p->Z,p->Z); + if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) /* 2dZ^2 */ + nres_modmult(_MIPP_ p->Z,mr_mip->B,p->Z); + else + nres_premult(_MIPP_ p->Z,mr_mip->Bsize,p->Z); + + nres_modadd(_MIPP_ p->X,p->Y,mr_mip->w2); /* C=A+U */ + nres_modsub(_MIPP_ p->X,p->Y,mr_mip->w3); /* D=A-U */ + + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w3,p->X); /* X=C.D */ + + nres_modsub(_MIPP_ mr_mip->w2,p->Z,mr_mip->w2); /* C-2dZ^2 */ + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w1,p->Y); /* Y=E.(C-2dZ^2) */ + nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w1,p->Z); /* Z=D.E */ + + p->marker=MR_EPOINT_GENERAL; + return; +} + +static BOOL ecurve_padd(_MIPD_ epoint *p,epoint *pa) +{ /* primitive add two epoints on the active ecurve - pa+=p; * + * note that if p is normalized, its Z coordinate isn't used */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (p->marker==MR_EPOINT_INFINITY) return TRUE; + if (pa->marker==MR_EPOINT_INFINITY) + { + epoint_copy(p,pa); + return TRUE; + } + + nres_modadd(_MIPP_ p->X,p->Y,mr_mip->w1); + nres_modadd(_MIPP_ pa->X,pa->Y,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); /* I=(X1+Y1)(X2+Y2) */ + if (p->marker!=MR_EPOINT_NORMALIZED) + { + if (pa->marker==MR_EPOINT_NORMALIZED) + copy(p->Z,pa->Z); + else nres_modmult(_MIPP_ p->Z,pa->Z,pa->Z); /* z = A = Z1*Z2 */ + } + else + { + if (pa->marker==MR_EPOINT_NORMALIZED) copy(mr_mip->one,pa->Z); + } + + nres_modmult(_MIPP_ pa->Z,pa->Z,mr_mip->w2); /* w2 = B = dA^2 */ + if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->B,mr_mip->w2); + else + nres_premult(_MIPP_ mr_mip->w2,mr_mip->Bsize,mr_mip->w2); + nres_modmult(_MIPP_ p->X,pa->X,pa->X); /* x = C = X1*X2 */ + nres_modmult(_MIPP_ p->Y,pa->Y,pa->Y); /* y = D = Y1*Y2 */ + nres_modmult(_MIPP_ pa->X,pa->Y,mr_mip->w3); /* w3 = E = C*D */ + + nres_modsub(_MIPP_ mr_mip->w1,pa->X,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w1,pa->Y,mr_mip->w1); /* I=(X1+Y1)(X2+Y2)-C-D =X1*Y2+Y1*X2 */ + + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) /* */ + nres_modmult(_MIPP_ pa->Y,mr_mip->A,pa->Y); + else + nres_premult(_MIPP_ pa->Y,mr_mip->Asize,pa->Y); + nres_modsub(_MIPP_ pa->X,pa->Y,pa->X); /* X = H = C-aD */ + + nres_modmult(_MIPP_ pa->Z,pa->X,pa->Z); + nres_modmult(_MIPP_ pa->Z,mr_mip->w1,pa->Z); + + nres_modsub(_MIPP_ mr_mip->w3,mr_mip->w2,pa->Y); + nres_modmult(_MIPP_ pa->Y,mr_mip->w1,pa->Y); + + nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w2,mr_mip->w3); + nres_modmult(_MIPP_ pa->X,mr_mip->w3,pa->X); + + if (size(pa->Z)==0) + { + copy(mr_mip->one,pa->X); + zero(pa->Y); + pa->marker=MR_EPOINT_INFINITY; + } + else pa->marker=MR_EPOINT_GENERAL; + + return TRUE; +} + +void epoint_copy(epoint *a,epoint *b) +{ + if (a==b || b==NULL) return; + + copy(a->X,b->X); + copy(a->Y,b->Y); + copy(a->Z,b->Z); + + b->marker=a->marker; + return; +} + +BOOL epoint_comp(_MIPD_ epoint *a,epoint *b) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + if (a==b) return TRUE; + if (a->marker==MR_EPOINT_INFINITY) + { + if (b->marker==MR_EPOINT_INFINITY) return TRUE; + else return FALSE; + } + if (b->marker==MR_EPOINT_INFINITY) + return FALSE; + + MR_IN(105) + copy(a->Z,mr_mip->w1); + copy(b->Z,mr_mip->w2); + + nres_modmult(_MIPP_ a->X,b->Z,mr_mip->w1); + nres_modmult(_MIPP_ b->X,a->Z,mr_mip->w2); + + if (mr_compare(mr_mip->w1,mr_mip->w2)!=0) + { + MR_OUT + return FALSE; + } + + nres_modmult(_MIPP_ a->Y,b->Z,mr_mip->w1); + nres_modmult(_MIPP_ b->Y,a->Z,mr_mip->w2); + + if (mr_compare(mr_mip->w1,mr_mip->w2)!=0) + { + MR_OUT + return FALSE; + } + MR_OUT + return TRUE; + +} + +int ecurve_add(_MIPD_ epoint *p,epoint *pa) +{ /* pa=pa+p; */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return MR_OVER; + + MR_IN(94) + + if (p==pa) + { + ecurve_double(_MIPP_ pa); + MR_OUT + if (pa->marker==MR_EPOINT_INFINITY) return MR_OVER; + return MR_DOUBLE; + } + if (pa->marker==MR_EPOINT_INFINITY) + { + epoint_copy(p,pa); + MR_OUT + return MR_ADD; + } + if (p->marker==MR_EPOINT_INFINITY) + { + MR_OUT + return MR_ADD; + } + + if (!ecurve_padd(_MIPP_ p,pa)) + { + ecurve_double(_MIPP_ pa); + MR_OUT + return MR_DOUBLE; + } + MR_OUT + if (pa->marker==MR_EPOINT_INFINITY) return MR_OVER; + return MR_ADD; +} + +void epoint_negate(_MIPD_ epoint *p) +{ /* negate a point */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + if (p->marker==MR_EPOINT_INFINITY) return; + + MR_IN(121) + if (size(p->X)!=0) mr_psub(_MIPP_ mr_mip->modulus,p->X,p->X); + MR_OUT +} + +int ecurve_sub(_MIPD_ epoint *p,epoint *pa) +{ + int r; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return MR_OVER; + + MR_IN(104) + + if (p==pa) + { + epoint_set(_MIPP_ NULL,NULL,0,pa); + MR_OUT + return MR_OVER; + } + if (p->marker==MR_EPOINT_INFINITY) + { + MR_OUT + return MR_ADD; + } + + epoint_negate(_MIPP_ p); + r=ecurve_add(_MIPP_ p,pa); + epoint_negate(_MIPP_ p); + + MR_OUT + return r; +} + +int ecurve_mult(_MIPD_ big e,epoint *pa,epoint *pt) +{ /* pt=e*pa; */ + int i,j,n,nb,nbs,nzs,nadds; + epoint *table[MR_ECC_STORE_N]; + +#ifdef MR_STATIC + char mem[MR_ECP_RESERVE(MR_ECC_STORE_N)]; +#else + char *mem; +#endif + +#ifndef MR_ALWAYS_BINARY + epoint *p; + int ce,ch; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(95) + if (size(e)==0) + { /* multiplied by 0 */ + epoint_set(_MIPP_ NULL,NULL,0,pt); + MR_OUT + return 0; + } + copy(e,mr_mip->w9); + epoint_copy(pa,pt); + + if (size(mr_mip->w9)<0) + { /* pt = -pt */ + negify(mr_mip->w9,mr_mip->w9); + epoint_negate(_MIPP_ pt); + } + + if (size(mr_mip->w9)==1) + { + MR_OUT + return 0; + } + + premult(_MIPP_ mr_mip->w9,3,mr_mip->w10); /* h=3*e */ + +#ifndef MR_STATIC +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif +#endif + +#ifdef MR_STATIC + memset(mem,0,MR_ECP_RESERVE(MR_ECC_STORE_N)); +#else + mem=(char *)ecp_memalloc(_MIPP_ MR_ECC_STORE_N); +#endif + + for (i=0;i<=MR_ECC_STORE_N-1;i++) + table[i]=epoint_init_mem(_MIPP_ mem,i); + + epoint_copy(pt,table[0]); + epoint_copy(table[0],table[MR_ECC_STORE_N-1]); + ecurve_double(_MIPP_ table[MR_ECC_STORE_N-1]); + + for (i=1;iw10); + nadds=0; + epoint_set(_MIPP_ NULL,NULL,0,pt); + for (i=nb-1;i>=1;) + { /* add/subtract */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + n=mr_naf_window(_MIPP_ mr_mip->w9,mr_mip->w10,i,&nbs,&nzs,MR_ECC_STORE_N); + for (j=0;j0) {ecurve_add(_MIPP_ table[n/2],pt); nadds++;} + if (n<0) {ecurve_sub(_MIPP_ table[(-n)/2],pt); nadds++;} + i-=nbs; + if (nzs) + { + for (j=0;jw10)-1,mr_mip->w11); + mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); + subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); + while (size(mr_mip->w11) > 1) + { /* add/subtract method */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + ecurve_double(_MIPP_ pt); + ce=mr_compare(mr_mip->w9,mr_mip->w11); /* e(i)=1? */ + ch=mr_compare(mr_mip->w10,mr_mip->w11); /* h(i)=1? */ + if (ch>=0) + { /* h(i)=1 */ + if (ce<0) {ecurve_add(_MIPP_ p,pt); nadds++;} + mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); + } + if (ce>=0) + { /* e(i)=1 */ + if (ch<0) {ecurve_sub(_MIPP_ p,pt); nadds++;} + mr_psub(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); + } + subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); + } + ecp_memkill(_MIPP_ mem,1); + } +#endif +#endif + MR_OUT + return nadds; +} + +#ifndef MR_NO_ECC_MULTIADD +#ifndef MR_STATIC + +void ecurve_multn(_MIPD_ int n,big *y,epoint **x,epoint *w) +{ /* pt=e[0]*p[0]+e[1]*p[1]+ .... e[n-1]*p[n-1] */ + int i,j,k,m,nb,ea; + epoint **G; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(114) + + m=1< nb) nb=k; + + epoint_set(_MIPP_ NULL,NULL,0,w); /* w=0 */ + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + for (i=nb-1;i>=0;i--) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + ea=0; + k=1; + for (j=0;jmarker==MR_EPOINT_NORMALIZED) + { + if (Q->marker==MR_EPOINT_NORMALIZED) + copy(mr_mip->one,mr_mip->w1); + else copy(Q->Z,mr_mip->w1); + } + else + { + if (Q->marker==MR_EPOINT_NORMALIZED) + copy(P->Z,mr_mip->w1); + else nres_modmult(_MIPP_ P->Z,Q->Z,mr_mip->w1); /* w1 = A = Z1*Z2 */ + } + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w2); /* w2 = B = dA^2 */ + if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->B,mr_mip->w2); + else + nres_premult(_MIPP_ mr_mip->w2,mr_mip->Bsize,mr_mip->w2); + nres_modmult(_MIPP_ P->X,Q->X,mr_mip->w3); /* w3 = C = X1*X2 */ + nres_modmult(_MIPP_ P->Y,Q->Y,mr_mip->w4); /* w4 = D = Y1*Y2 */ + nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w4,mr_mip->w5); /* w5 = E = C*D */ + nres_modmult(_MIPP_ P->X,Q->Y,mr_mip->w7); /* w7 = F = X1.Y2 */ + nres_modmult(_MIPP_ Q->X,P->Y,mr_mip->w8); /* w8 = G = X2.Y1 */ + + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) /* w4 = aD */ + nres_modmult(_MIPP_ mr_mip->w4,mr_mip->A,mr_mip->w4); + else + nres_premult(_MIPP_ mr_mip->w4,mr_mip->Asize,mr_mip->w4); + +/* P+Q */ + + nres_modsub(_MIPP_ mr_mip->w3,mr_mip->w4,mr_mip->w6); /* w6 = H = C-aD */ + nres_modadd(_MIPP_ mr_mip->w7,mr_mip->w8,PP->Z); /* X1*Y2+X2*Y1 */ + nres_modadd(_MIPP_ mr_mip->w5,mr_mip->w2,PP->X); + nres_modmult(_MIPP_ PP->X,mr_mip->w6,PP->X); + nres_modsub(_MIPP_ mr_mip->w5,mr_mip->w2,PP->Y); + nres_modmult(_MIPP_ PP->Y,PP->Z,PP->Y); + nres_modmult(_MIPP_ PP->Z,mr_mip->w6,PP->Z); + nres_modmult(_MIPP_ PP->Z,mr_mip->w1,PP->Z); + + if (size(PP->Z)==0) + { + copy(mr_mip->one,PP->X); + zero(PP->Y); + PP->marker=MR_EPOINT_INFINITY; + } + else PP->marker=MR_EPOINT_GENERAL; + +/* P-Q */ + + nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w4,mr_mip->w6); /* w6 = C+aD */ + nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w7,PM->Z); /* X2*Y1-X1*Y2 */ + nres_modsub(_MIPP_ mr_mip->w5,mr_mip->w2,PM->X); + nres_modmult(_MIPP_ PM->X,mr_mip->w6,PM->X); + nres_modadd(_MIPP_ mr_mip->w5,mr_mip->w2,PM->Y); + nres_modmult(_MIPP_ PM->Y,PM->Z,PM->Y); + nres_modmult(_MIPP_ PM->Z,mr_mip->w6,PM->Z); + nres_modmult(_MIPP_ PM->Z,mr_mip->w1,PM->Z); + + if (size(PM->Z)==0) + { + copy(mr_mip->one,PM->X); + zero(PM->Y); + PM->marker=MR_EPOINT_INFINITY; + } + else PM->marker=MR_EPOINT_GENERAL; + + return TRUE; +} + +void ecurve_mult2(_MIPD_ big e,epoint *p,big ea,epoint *pa,epoint *pt) +{ /* pt=e*p+ea*pa; */ + int e1,h1,e2,h2,bb; + epoint *p1,*p2,*ps[2]; +#ifdef MR_STATIC + char mem[MR_ECP_RESERVE(4)]; +#else + char *mem; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return; + + MR_IN(103) + + if (size(e)==0) + { + ecurve_mult(_MIPP_ ea,pa,pt); + MR_OUT + return; + } +#ifdef MR_STATIC + memset(mem,0,MR_ECP_RESERVE(4)); +#else + mem=ecp_memalloc(_MIPP_ 4); +#endif + p2=epoint_init_mem(_MIPP_ mem,0); + p1=epoint_init_mem(_MIPP_ mem,1); + ps[0]=epoint_init_mem(_MIPP_ mem,2); + ps[1]=epoint_init_mem(_MIPP_ mem,3); + + epoint_copy(pa,p2); + copy(ea,mr_mip->w9); + if (size(mr_mip->w9)<0) + { /* p2 = -p2 */ + negify(mr_mip->w9,mr_mip->w9); + epoint_negate(_MIPP_ p2); + } + + epoint_copy(p,p1); + copy(e,mr_mip->w12); + if (size(mr_mip->w12)<0) + { /* p1= -p1 */ + negify(mr_mip->w12,mr_mip->w12); + epoint_negate(_MIPP_ p1); + } + + epoint_set(_MIPP_ NULL,NULL,0,pt); /* pt=0 */ + ecurve_add_sub(_MIPP_ p1,p2,ps[0],ps[1]); /* ps[0]=p1+p2, ps[1]=p1-p2 */ + + mr_jsf(_MIPP_ mr_mip->w9,mr_mip->w12,mr_mip->w10,mr_mip->w9,mr_mip->w13,mr_mip->w12); + +/* To use a simple NAF instead, substitute this for the JSF + premult(_MIPP_ mr_mip->w9,3,mr_mip->w10); 3*ea + premult(_MIPP_ mr_mip->w12,3,mr_mip->w13); 3*e +*/ + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + if (mr_compare(mr_mip->w10,mr_mip->w13)>=0) bb=logb2(_MIPP_ mr_mip->w10)-1; + else bb=logb2(_MIPP_ mr_mip->w13)-1; + + while (bb>=0) /* for the simple NAF, this should be 1 */ + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + ecurve_double(_MIPP_ pt); + + e1=h1=e2=h2=0; + if (mr_testbit(_MIPP_ mr_mip->w9,bb)) e2=1; + if (mr_testbit(_MIPP_ mr_mip->w10,bb)) h2=1; + if (mr_testbit(_MIPP_ mr_mip->w12,bb)) e1=1; + if (mr_testbit(_MIPP_ mr_mip->w13,bb)) h1=1; + + if (e1!=h1) + { + if (e2==h2) + { + if (h1==1) ecurve_add(_MIPP_ p1,pt); + else ecurve_sub(_MIPP_ p1,pt); + } + else + { + if (h1==1) + { + if (h2==1) ecurve_add(_MIPP_ ps[0],pt); + else ecurve_add(_MIPP_ ps[1],pt); + } + else + { + if (h2==1) ecurve_sub(_MIPP_ ps[1],pt); + else ecurve_sub(_MIPP_ ps[0],pt); + } + } + } + else if (e2!=h2) + { + if (h2==1) ecurve_add(_MIPP_ p2,pt); + else ecurve_sub(_MIPP_ p2,pt); + } + bb-=1; + } +#ifndef MR_ALWAYS_BINARY + } + else + { + if (mr_compare(mr_mip->w10,mr_mip->w13)>=0) + expb2(_MIPP_ logb2(_MIPP_ mr_mip->w10)-1,mr_mip->w11); + else expb2(_MIPP_ logb2(_MIPP_ mr_mip->w13)-1,mr_mip->w11); + + while (size(mr_mip->w11) > 0) /* for the NAF, this should be 1 */ + { /* add/subtract method */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + ecurve_double(_MIPP_ pt); + + e1=h1=e2=h2=0; + if (mr_compare(mr_mip->w9,mr_mip->w11)>=0) + { /* e1(i)=1? */ + e2=1; + mr_psub(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); + } + if (mr_compare(mr_mip->w10,mr_mip->w11)>=0) + { /* h1(i)=1? */ + h2=1; + mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); + } + if (mr_compare(mr_mip->w12,mr_mip->w11)>=0) + { /* e2(i)=1? */ + e1=1; + mr_psub(_MIPP_ mr_mip->w12,mr_mip->w11,mr_mip->w12); + } + if (mr_compare(mr_mip->w13,mr_mip->w11)>=0) + { /* h2(i)=1? */ + h1=1; + mr_psub(_MIPP_ mr_mip->w13,mr_mip->w11,mr_mip->w13); + } + + if (e1!=h1) + { + if (e2==h2) + { + if (h1==1) ecurve_add(_MIPP_ p1,pt); + else ecurve_sub(_MIPP_ p1,pt); + } + else + { + if (h1==1) + { + if (h2==1) ecurve_add(_MIPP_ ps[0],pt); + else ecurve_add(_MIPP_ ps[1],pt); + } + else + { + if (h2==1) ecurve_sub(_MIPP_ ps[1],pt); + else ecurve_sub(_MIPP_ ps[0],pt); + } + } + } + else if (e2!=h2) + { + if (h2==1) ecurve_add(_MIPP_ p2,pt); + else ecurve_sub(_MIPP_ p2,pt); + } + + subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); + } + } +#endif + ecp_memkill(_MIPP_ mem,4); + MR_OUT +} + +#endif + +#endif diff --git a/crypto/sm2/miracl/mrjack.c b/crypto/sm2/miracl/mrjack.c new file mode 100644 index 00000000..1b77a984 --- /dev/null +++ b/crypto/sm2/miracl/mrjack.c @@ -0,0 +1,342 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox IOM 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 Jacobi symbol routine + * mrjack.c + * + * See "A binary algorithm for the Jacobi symbol" + * Shallit and Sorenson + */ +#include +#include + +int jack(_MIPD_ big a,big n) +{ /* find jacobi symbol (a/n), for positive odd n */ + big w; + int nm8,onm8,t; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM || size(a)==0 || size(n) <1) return 0; + MR_IN(3) + + t=1; + copy(n,mr_mip->w2); + nm8=remain(_MIPP_ mr_mip->w2,8); + if (nm8%2==0) + { + MR_OUT + return 0; + } + + if (size(a)<0) + { + if (nm8%4==3) t=-1; + negify(a,mr_mip->w1); + } + else copy(a,mr_mip->w1); + + while (size(mr_mip->w1)!=0) + { + while (remain(_MIPP_ mr_mip->w1,2)==0) + { + subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1); + if (nm8==3 || nm8==5) t=-t; + } + if (mr_compare(mr_mip->w1,mr_mip->w2)<0) + { + onm8=nm8; + w=mr_mip->w1; mr_mip->w1=mr_mip->w2; mr_mip->w2=w; + nm8=remain(_MIPP_ mr_mip->w2,8); + if (onm8%4==3 && nm8%4==3) t=-t; + } + mr_psub(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); + subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1); + + if (nm8==3 || nm8==5) t=-t; + } + + MR_OUT + if (size(mr_mip->w2)==1) return t; + return 0; +} + +/* + * See "Efficient Algorithms for Computing the Jacobi Symbol" + * Eikenberry & Sorenson + * + * Its turns out this is slower than the binary method above for reasonable sizes + * of parameters (and takes up a lot more space!) + + +#ifdef MR_FP +#include +#endif + + +static void rfind(mr_small u,mr_small v,mr_small k,mr_small sk,mr_utype *a,mr_utype *b) +{ + mr_utype x2,y2,r; + mr_small w,q,x1,y1,sr; +#ifdef MR_FP + mr_small dres; +#endif + + w=invers(v,k); + w=smul(u,w,k); + + x1=k; x2=0; + y1=w; y2=1; + +// NOTE: x1 and y1 are always +ve. x2 and y2 are always small + + while (y1>=sk) + { +#ifndef MR_NOFULLWIDTH + if (x1==0) q=muldvm((mr_small)1,(mr_small)0,y1,&sr); + else +#endif + q=MR_DIV(x1,y1); + r= x1-q*y1; x1=y1; y1=r; + sr=x2-q*y2; x2=y2; y2=sr; + } + if (y2>=0) { *a=y2; *b=0-y1; } + else { *a=-y2; *b=y1; } +} + +int jack(_MIPD_ big U,big V) +{ // find jacobi symbol for U wrt V. Only defined for + // positive V, V odd. Otherwise returns 0 + int i,e,r,m,t,v8,u4; + mr_utype a,b; + mr_small u,v,d,g,k,sk,s; +#ifdef MR_FP + mr_small dres; +#endif + big w; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_FP_ROUNDING + mr_large ik,id; +#endif + if (mr_mip->ERNUM || size(U)==0 || size(V) <1) return 0; + copy(U,mr_mip->w1); + copy(V,mr_mip->w2); + a=0; + MR_IN(3) + + if (remain(_MIPP_ mr_mip->w2,2)==0) + { // V is even + MR_OUT + return 0; + } + + if (mr_mip->base!=0) + { + k=1; + for (m=1;;m++) + { + k*=2; + if (k==MAXBASE) break; + } + if (m%2==1) {m--; k=MR_DIV(k,2);} +#ifdef MR_FP_ROUNDING + ik=mr_invert(k); +#endif + } + else + { + m=MIRACL; + k=0; + } + r=m/2; + sk=1; + for (i=0;iw2,8); + + while (!mr_mip->ERNUM && size(mr_mip->w1)!=0) + { + if (size(mr_mip->w1)<0) + { + negify(mr_mip->w1,mr_mip->w1); + if (v8%4==3) t=-t; + } + + do { // oddify + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + if (mr_mip->base==k) u=mr_mip->w1->w[0]; + else u=MR_REMAIN(mr_mip->w1->w[0],k); +#ifndef MR_ALWAYS_BINARY + } + +#ifdef MR_FP_ROUNDING + else u=mr_sdiv(_MIPP_ mr_mip->w1,k,ik,mr_mip->w3); +#else + else u=mr_sdiv(_MIPP_ mr_mip->w1,k,mr_mip->w3); +#endif + +#endif + if (u==0) {s=k; e=0;} + else + { + s=1; e=0; + while (MR_REMAIN(u,2)==0) {s*=2; e++; u=MR_DIV(u,2);} + } + if (s==mr_mip->base) mr_shift(_MIPP_ mr_mip->w1,-1,mr_mip->w1); +#ifdef MR_FP_ROUNDING + else if (s>1) + { + mr_sdiv(_MIPP_ mr_mip->w1,s,mr_invert(s),mr_mip->w1); + } +#else + else if (s>1) mr_sdiv(_MIPP_ mr_mip->w1,s,mr_mip->w1); +#endif + } while (u==0); + if (e%2!=0 && (v8==3 || v8==5)) t=-t; + if (mr_compare(mr_mip->w1,mr_mip->w2)<0) + { + if (mr_mip->base==mr_mip->base2) u4=(int)MR_REMAIN(mr_mip->w1->w[0],4); + else u4=remain(_MIPP_ mr_mip->w1,4); + if (v8%4==3 && u4==3) t=-t; + w=mr_mip->w1; mr_mip->w1=mr_mip->w2; mr_mip->w2=w; + } + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + if (k==mr_mip->base) + { + u=mr_mip->w1->w[0]; + v=mr_mip->w2->w[0]; + } + else + { + u=MR_REMAIN(mr_mip->w1->w[0],k); + v=MR_REMAIN(mr_mip->w2->w[0],k); + } +#ifndef MR_ALWAYS_BINARY + } + else + { +#ifdef MR_FP_ROUNDING + u=mr_sdiv(_MIPP_ mr_mip->w1,k,ik,mr_mip->w3); + v=mr_sdiv(_MIPP_ mr_mip->w2,k,ik,mr_mip->w3); +#else + u=mr_sdiv(_MIPP_ mr_mip->w1,k,mr_mip->w3); + v=mr_sdiv(_MIPP_ mr_mip->w2,k,mr_mip->w3); +#endif + } +#endif + rfind(u,v,k,sk,&a,&b); + if (a>1) + { +#ifdef MR_FP_ROUNDING + d=mr_sdiv(_MIPP_ mr_mip->w2,a,mr_invert(a),mr_mip->w3); +#else + d=mr_sdiv(_MIPP_ mr_mip->w2,a,mr_mip->w3); +#endif + d=sgcd(d,a); + a=MR_DIV(a,d); + } + else d=1; + + if (d>1) + { +#ifdef MR_FP_ROUNDING + id=mr_invert(d); + mr_sdiv(_MIPP_ mr_mip->w2,d,id,mr_mip->w2); + u=mr_sdiv(_MIPP_ mr_mip->w1,d,id,mr_mip->w3); +#else + mr_sdiv(_MIPP_ mr_mip->w2,d,mr_mip->w2); + u=mr_sdiv(_MIPP_ mr_mip->w1,d,mr_mip->w3); +#endif + } + else u=0; + + g=a; + if (mr_mip->base==mr_mip->base2) v8=(int)MR_REMAIN(mr_mip->w2->w[0],8); + else v8=remain(_MIPP_ mr_mip->w2,8); + while (MR_REMAIN(g,2)==0) + { + g=MR_DIV(g,2); + if (v8==3 || v8==5) t=-t; + } + if (MR_REMAIN(g,4)==3 && v8%4==3) t=-t; +#ifdef MR_FP_ROUNDING + v=mr_sdiv(_MIPP_ mr_mip->w2,g,mr_invert(g),mr_mip->w3); +#else + v=mr_sdiv(_MIPP_ mr_mip->w2,g,mr_mip->w3); +#endif + t*=jac(v,g)*jac(u,d); + if (t==0) + { + MR_OUT + return 0; + } + +// printf("a= %I64d b=%I64d %d\n",a,b,(int)b); + + if (a>1) mr_pmul(_MIPP_ mr_mip->w1,a,mr_mip->w1); + if (b>=0) + mr_pmul(_MIPP_ mr_mip->w2,b,mr_mip->w3); + else + { + b=-b; + mr_pmul(_MIPP_ mr_mip->w2,b,mr_mip->w3); + negify(mr_mip->w3,mr_mip->w3); + } + // premult(_MIPP_ mr_mip->w2,(int)b,mr_mip->w3); <- nasty bug - potential loss of precision in b + add(_MIPP_ mr_mip->w1,mr_mip->w3,mr_mip->w1); + if (k==mr_mip->base) mr_shift(_MIPP_ mr_mip->w1,-1,mr_mip->w1); +#ifdef MR_FP_ROUNDING + else mr_sdiv(_MIPP_ mr_mip->w1,k,ik,mr_mip->w1); +#else + else mr_sdiv(_MIPP_ mr_mip->w1,k,mr_mip->w1); +#endif + } + MR_OUT + if (size(mr_mip->w2)==1) return t; + return 0; +} + +*/ diff --git a/crypto/sm2/miracl/mrlucas.c b/crypto/sm2/miracl/mrlucas.c new file mode 100644 index 00000000..2a19b49f --- /dev/null +++ b/crypto/sm2/miracl/mrlucas.c @@ -0,0 +1,157 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox IOM 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 methods for evaluating lucas V function + * mrlucas.c (Postl's algorithm) + */ + +#include +#include + +void nres_lucas(_MIPD_ big p,big r,big vp,big v) +{ + int i,nb; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(107) + + if (size(r)==0) + { + zero(vp); + convert(_MIPP_ 2,v); + nres(_MIPP_ v,v); + MR_OUT + return; + } + if (size(r)==1 || size(r)==(-1)) + { /* note - sign of r doesn't matter */ + convert(_MIPP_ 2,vp); + nres(_MIPP_ vp,vp); + copy(p,v); + MR_OUT + return; + } + + copy(p,mr_mip->w3); + + convert(_MIPP_ 2,mr_mip->w4); + nres(_MIPP_ mr_mip->w4,mr_mip->w4); /* w4=2 */ + + copy(mr_mip->w4,mr_mip->w8); + copy(mr_mip->w3,mr_mip->w9); + + copy(r,mr_mip->w1); + insign(PLUS,mr_mip->w1); + decr(_MIPP_ mr_mip->w1,1,mr_mip->w1); + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + nb=logb2(_MIPP_ mr_mip->w1); + for (i=nb-1;i>=0;i--) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + if (mr_testbit(_MIPP_ mr_mip->w1,i)) + { + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w9,mr_mip->w8); + nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w8); + nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w9,mr_mip->w9); + nres_modsub(_MIPP_ mr_mip->w9,mr_mip->w4,mr_mip->w9); + + } + else + { + nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w8,mr_mip->w9); + nres_modsub(_MIPP_ mr_mip->w9,mr_mip->w3,mr_mip->w9); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w8); + nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w4,mr_mip->w8); + } + } + +#ifndef MR_ALWAYS_BINARY + } + else + { + expb2(_MIPP_ logb2(_MIPP_ mr_mip->w1)-1,mr_mip->w2); + + while (!mr_mip->ERNUM && size(mr_mip->w2)!=0) + { /* use binary method */ + if (mr_compare(mr_mip->w1,mr_mip->w2)>=0) + { /* vp=v*vp-p, v=v*v-2 */ + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w9,mr_mip->w8); + nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w8); + nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w9,mr_mip->w9); + nres_modsub(_MIPP_ mr_mip->w9,mr_mip->w4,mr_mip->w9); + subtract(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); + } + else + { /* v=v*vp-p, vp=vp*vp-2 */ + nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w8,mr_mip->w9); + nres_modsub(_MIPP_ mr_mip->w9,mr_mip->w3,mr_mip->w9); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w8); + nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w4,mr_mip->w8); + } + subdiv(_MIPP_ mr_mip->w2,2,mr_mip->w2); + } + } +#endif + + copy(mr_mip->w9,v); + if (v!=vp) copy(mr_mip->w8,vp); + MR_OUT + +} + +void lucas(_MIPD_ big p,big r,big n,big vp,big v) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(108) + prepare_monty(_MIPP_ n); + nres(_MIPP_ p,mr_mip->w3); + nres_lucas(_MIPP_ mr_mip->w3,r,mr_mip->w8,mr_mip->w9); + redc(_MIPP_ mr_mip->w9,v); + if (v!=vp) redc(_MIPP_ mr_mip->w8,vp); + MR_OUT +} + diff --git a/crypto/sm2/miracl/mrmonty.c b/crypto/sm2/miracl/mrmonty.c new file mode 100644 index 00000000..102b4d34 --- /dev/null +++ b/crypto/sm2/miracl/mrmonty.c @@ -0,0 +1,1414 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox IOM 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 + +#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; +} diff --git a/crypto/sm2/miracl/mrmuldv.c b/crypto/sm2/miracl/mrmuldv.c new file mode 100644 index 00000000..b485cc59 --- /dev/null +++ b/crypto/sm2/miracl/mrmuldv.c @@ -0,0 +1,57 @@ +/* + * Borland C++ 32-bit compiler (BCC32). Use with mirdef.h32 + * Uses inline assembly feature. Suitable for Win32 Apps + * Also compatible with Microsoft Visual C++ 32-bit compiler + */ + +#define ASM __asm__ + +int muldiv(a,b,c,m,rp) +int a,b,c,m,*rp; +{ + ASM ("mov eax,DWORD PTR a"); + ASM ("mul DWORD PTR b"); + ASM ("add eax,DWORD PTR c"); + ASM ("adc edx,0h"); + ASM ("div DWORD PTR m"); + ASM ("mov ebx,DWORD PTR rp"); + ASM ("mov [ebx],edx"); +} + +int muldvm(a,c,m,rp) +int a,c,m,*rp; +{ + ASM ("mov edx,DWORD PTR a"); + ASM ("mov eax,DWORD PTR c"); + ASM ("div DWORD PTR m"); + ASM ("mov ebx,DWORD PTR rp"); + ASM ("mov [ebx],edx"); +} + +int muldvd(a,b,c,rp) +int a,b,c,*rp; +{ + ASM ("mov eax,DWORD PTR a"); + ASM ("mul DWORD PTR b"); + ASM ("add eax,DWORD PTR c"); + ASM ("adc edx,0h"); + ASM ("mov ebx,DWORD PTR rp"); + ASM ("mov [ebx],eax"); + ASM ("mov eax,edx"); +} + +void muldvd2(a,b,c,rp) +int a,b,*c,*rp; +{ + ASM ("mov eax,DWORD PTR a"); + ASM ("mul DWORD PTR b"); + ASM ("mov ebx,DWORD PTR c"); + ASM ("add eax,[ebx]"); + ASM ("adc edx,0h"); + ASM ("mov esi,DWORD PTR rp"); + ASM ("add eax,[esi]"); + ASM ("adc edx,0h"); + ASM ("mov [esi],eax"); + ASM ("mov [ebx],edx"); +} + diff --git a/crypto/sm2/miracl/mrsroot.c b/crypto/sm2/miracl/mrsroot.c new file mode 100644 index 00000000..ccf6d56b --- /dev/null +++ b/crypto/sm2/miracl/mrsroot.c @@ -0,0 +1,188 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox IOM 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 method for modular square root + * mrsroot.c + * + * Siguna Mueller's O(lg(p)^3) algorithm, Designs Codes and Cryptography, 2004 + * + * This is a little slower for p=1 mod 4 primes, but its not time critical, and + * more importantly it doesn't pull in the large powmod code into elliptic curve programs + * It does require code from mrjack.c and mrlucas.c + * + * If p=3 mod 4, then sqrt(a)=a^[(p+1)/4] mod p. Note that for many elliptic curves + * (p+1)/4 has very low hamming weight. + * + * (was sqrt(a) = V_{(p+1)/4}(a+1/a,1)/(1+1/a)) + * + * Mueller's method is also very simple, uses very little memory, and it works just fine for p=1 mod 8 primes + * (for example the "annoying" NIST modulus 2^224-2^96+1) + * Also doesn't waste time on non-squares, as a jacobi test is done first + * + * If you know that the prime is 3 mod 4, and you know that x is almost certainly a QR + * then the jacobi-dependent code can be deleted with some space savings. + * + * NOTE - IF p IS NOT PRIME, THIS CODE WILL FAIL SILENTLY! + * + */ + +#include +#include + +BOOL nres_sqroot(_MIPD_ big x,big w) +{ /* w=sqrt(x) mod p. This depends on p being prime! */ + int t,js; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + copy(x,w); + if (size(w)==0) return TRUE; + + MR_IN(100) + + redc(_MIPP_ w,w); /* get it back into normal form */ + + if (size(w)==1) /* square root of 1 is 1 */ + { + nres(_MIPP_ w,w); + MR_OUT + return TRUE; + } + + if (size(w)==4) /* square root of 4 is 2 */ + { + convert(_MIPP_ 2,w); + nres(_MIPP_ w,w); + MR_OUT + return TRUE; + } + + if (jack(_MIPP_ w,mr_mip->modulus)!=1) + { /* Jacobi test */ + zero(w); + MR_OUT + return FALSE; + } + + js=mr_mip->pmod8%4-2; /* 1 mod 4 or 3 mod 4 prime? */ + + incr(_MIPP_ mr_mip->modulus,js,mr_mip->w10); + subdiv(_MIPP_ mr_mip->w10,4,mr_mip->w10); /* (p+/-1)/4 */ + + if (js==1) + { /* 3 mod 4 primes - do a quick and dirty sqrt(x)=x^(p+1)/4 mod p */ + nres(_MIPP_ w,mr_mip->w2); + copy(mr_mip->one,w); + forever + { /* Simple Right-to-Left exponentiation */ + + if (mr_mip->user!=NULL) (*mr_mip->user)(); + if (subdiv(_MIPP_ mr_mip->w10,2,mr_mip->w10)!=0) + nres_modmult(_MIPP_ w,mr_mip->w2,w); + if (mr_mip->ERNUM || size(mr_mip->w10)==0) break; + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w2); + } + + /* nres_moddiv(_MIPP_ mr_mip->one,w,mr_mip->w11); + nres_modadd(_MIPP_ mr_mip->w11,w,mr_mip->w3); + nres_lucas(_MIPP_ mr_mip->w3,mr_mip->w10,w,w); + nres_modadd(_MIPP_ mr_mip->w11,mr_mip->one,mr_mip->w11); + nres_moddiv(_MIPP_ w,mr_mip->w11,w); */ + } + else + { /* 1 mod 4 primes */ + for (t=1; ;t++) + { /* t=1.5 on average */ + if (t==1) copy(w,mr_mip->w4); + else + { + premult(_MIPP_ w,t,mr_mip->w4); + divide(_MIPP_ mr_mip->w4,mr_mip->modulus,mr_mip->modulus); + premult(_MIPP_ mr_mip->w4,t,mr_mip->w4); + divide(_MIPP_ mr_mip->w4,mr_mip->modulus,mr_mip->modulus); + } + + decr(_MIPP_ mr_mip->w4,4,mr_mip->w1); + if (jack(_MIPP_ mr_mip->w1,mr_mip->modulus)==js) break; + if (mr_mip->ERNUM) break; + } + + decr(_MIPP_ mr_mip->w4,2,mr_mip->w3); + nres(_MIPP_ mr_mip->w3,mr_mip->w3); + nres_lucas(_MIPP_ mr_mip->w3,mr_mip->w10,w,w); /* heavy lifting done here */ + if (t!=1) + { + convert(_MIPP_ t,mr_mip->w11); + nres(_MIPP_ mr_mip->w11,mr_mip->w11); + nres_moddiv(_MIPP_ w,mr_mip->w11,w); + } + } + + MR_OUT + return TRUE; +} + +BOOL sqroot(_MIPD_ big x,big p,big w) +{ /* w = sqrt(x) mod p */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(101) + + if (subdivisible(_MIPP_ p,2)) + { /* p must be odd */ + zero(w); + MR_OUT + return FALSE; + } + + prepare_monty(_MIPP_ p); + nres(_MIPP_ x,w); + if (nres_sqroot(_MIPP_ w,w)) + { + redc(_MIPP_ w,w); + MR_OUT + return TRUE; + } + + zero(w); + MR_OUT + return FALSE; +} diff --git a/crypto/sm2/miracl/mrxgcd.c b/crypto/sm2/miracl/mrxgcd.c new file mode 100644 index 00000000..437f6e97 --- /dev/null +++ b/crypto/sm2/miracl/mrxgcd.c @@ -0,0 +1,495 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox IOM 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 Extended Greatest Common Divisor module. + * mrxgcd.c + */ + +#include + +#ifdef MR_FP +#include +#endif + +#ifdef MR_COUNT_OPS +extern int fpx; +#endif + +#ifndef MR_USE_BINARY_XGCD + +#ifdef mr_dltype + +static mr_small qdiv(mr_large u,mr_large v) +{ /* fast division - small quotient expected. */ + mr_large lq,x=u; +#ifdef MR_FP + mr_small dres; +#endif + x-=v; + if (x=MAXBASE) return 0; + return (mr_small)lq; +} + +#else + +static mr_small qdiv(mr_small u,mr_small v) +{ /* fast division - small quotient expected */ + mr_small x=u; + x-=v; + if (xERNUM) return 0; + + MR_IN(30) + +#ifdef MR_COUNT_OPS + fpx++; +#endif + + copy(x,mr_mip->w1); + copy(y,mr_mip->w2); + s=exsign(mr_mip->w1); + insign(PLUS,mr_mip->w1); + insign(PLUS,mr_mip->w2); + convert(_MIPP_ 1,mr_mip->w3); + zero(mr_mip->w4); + last=FALSE; + a=b=c=d=0; + iter=0; + + while (size(mr_mip->w2)!=0) + { + if (b==0) + { /* update mr_mip->w1 and mr_mip->w2 */ + + divide(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w5); + t=mr_mip->w1,mr_mip->w1=mr_mip->w2,mr_mip->w2=t; /* swap(mr_mip->w1,mr_mip->w2) */ + multiply(_MIPP_ mr_mip->w4,mr_mip->w5,mr_mip->w0); + add(_MIPP_ mr_mip->w3,mr_mip->w0,mr_mip->w3); + t=mr_mip->w3,mr_mip->w3=mr_mip->w4,mr_mip->w4=t; /* swap(xd,yd) */ + iter++; + + } + else + { + + /* printf("a= %I64u b= %I64u c= %I64u d= %I64u \n",a,b,c,d); */ + + mr_pmul(_MIPP_ mr_mip->w1,c,mr_mip->w5); /* c*w1 */ + mr_pmul(_MIPP_ mr_mip->w1,a,mr_mip->w1); /* a*w1 */ + mr_pmul(_MIPP_ mr_mip->w2,b,mr_mip->w0); /* b*w2 */ + mr_pmul(_MIPP_ mr_mip->w2,d,mr_mip->w2); /* d*w2 */ + + if (!dplus) + { + mr_psub(_MIPP_ mr_mip->w0,mr_mip->w1,mr_mip->w1); /* b*w2-a*w1 */ + mr_psub(_MIPP_ mr_mip->w5,mr_mip->w2,mr_mip->w2); /* c*w1-d*w2 */ + } + else + { + mr_psub(_MIPP_ mr_mip->w1,mr_mip->w0,mr_mip->w1); /* a*w1-b*w2 */ + mr_psub(_MIPP_ mr_mip->w2,mr_mip->w5,mr_mip->w2); /* d*w2-c*w1 */ + } + mr_pmul(_MIPP_ mr_mip->w3,c,mr_mip->w5); + mr_pmul(_MIPP_ mr_mip->w3,a,mr_mip->w3); + mr_pmul(_MIPP_ mr_mip->w4,b,mr_mip->w0); + mr_pmul(_MIPP_ mr_mip->w4,d,mr_mip->w4); + + if (a==0) copy(mr_mip->w0,mr_mip->w3); + else mr_padd(_MIPP_ mr_mip->w3,mr_mip->w0,mr_mip->w3); + mr_padd(_MIPP_ mr_mip->w4,mr_mip->w5,mr_mip->w4); + } + if (mr_mip->ERNUM || size(mr_mip->w2)==0) break; + + + n=(int)mr_mip->w1->len; + if (n==1) + { + last=TRUE; + u=mr_mip->w1->w[0]; + v=mr_mip->w2->w[0]; + } + else + { + m=mr_mip->w1->w[n-1]+1; +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH +#ifdef mr_dltype + /* use double length type if available */ + if (n>2 && m!=0) + { /* squeeze out as much significance as possible */ + uu.h[MR_TOP]=muldvm(mr_mip->w1->w[n-1],mr_mip->w1->w[n-2],m,&sr); + uu.h[MR_BOT]=muldvm(sr,mr_mip->w1->w[n-3],m,&sr); + vv.h[MR_TOP]=muldvm(mr_mip->w2->w[n-1],mr_mip->w2->w[n-2],m,&sr); + vv.h[MR_BOT]=muldvm(sr,mr_mip->w2->w[n-3],m,&sr); + } + else + { + uu.h[MR_TOP]=mr_mip->w1->w[n-1]; + uu.h[MR_BOT]=mr_mip->w1->w[n-2]; + vv.h[MR_TOP]=mr_mip->w2->w[n-1]; + vv.h[MR_BOT]=mr_mip->w2->w[n-2]; + if (n==2) last=TRUE; + } + + u=uu.d; + v=vv.d; +#else + if (m==0) + { + u=mr_mip->w1->w[n-1]; + v=mr_mip->w2->w[n-1]; + } + else + { + u=muldvm(mr_mip->w1->w[n-1],mr_mip->w1->w[n-2],m,&sr); + v=muldvm(mr_mip->w2->w[n-1],mr_mip->w2->w[n-2],m,&sr); + } +#endif +#endif +#ifndef MR_SIMPLE_BASE + } + else + { +#ifdef mr_dltype + if (n>2) + { /* squeeze out as much significance as possible */ + u=muldiv(mr_mip->w1->w[n-1],mr_mip->base,mr_mip->w1->w[n-2],m,&sr); + u=u*mr_mip->base+muldiv(sr,mr_mip->base,mr_mip->w1->w[n-3],m,&sr); + v=muldiv(mr_mip->w2->w[n-1],mr_mip->base,mr_mip->w2->w[n-2],m,&sr); + v=v*mr_mip->base+muldiv(sr,mr_mip->base,mr_mip->w2->w[n-3],m,&sr); + } + else + { + u=(mr_large)mr_mip->base*mr_mip->w1->w[n-1]+mr_mip->w1->w[n-2]; + v=(mr_large)mr_mip->base*mr_mip->w2->w[n-1]+mr_mip->w2->w[n-2]; + last=TRUE; + } +#else + u=muldiv(mr_mip->w1->w[n-1],mr_mip->base,mr_mip->w1->w[n-2],m,&sr); + v=muldiv(mr_mip->w2->w[n-1],mr_mip->base,mr_mip->w2->w[n-2],m,&sr); +#endif + } +#endif + } + + dplus=TRUE; + a=1; b=0; c=0; d=1; + + forever + { /* work only with most significant piece */ + if (last) + { + if (v==0) break; + q=qdiv(u,v); + if (q==0) break; + } + else + { + if (dplus) + { + if ((mr_small)(v-c)==0 || (mr_small)(v+d)==0) break; + + q=qdiv(u+a,v-c); + + if (q==0) break; + + if (q!=qdiv(u-b,v+d)) break; + } + else + { + if ((mr_small)(v+c)==0 || (mr_small)(v-d)==0) break; + q=qdiv(u-a,v+c); + if (q==0) break; + if (q!=qdiv(u+b,v-d)) break; + } + } + + if (q==1) + { + if ((mr_small)(b+d) >= MAXBASE) break; + r=a+c; a=c; c=r; + r=b+d; b=d; d=r; + lr=u-v; u=v; v=lr; + } + else + { + if (q>=MR_DIV(MAXBASE-b,d)) break; + r=a+q*c; a=c; c=r; + r=b+q*d; b=d; d=r; + lr=u-q*v; u=v; v=lr; + } + iter++; + dplus=!dplus; + } + iter%=2; + + } + + if (s==MINUS) iter++; + if (iter%2==1) subtract(_MIPP_ y,mr_mip->w3,mr_mip->w3); + + if (xd!=yd) + { + negify(x,mr_mip->w2); + mad(_MIPP_ mr_mip->w2,mr_mip->w3,mr_mip->w1,y,mr_mip->w4,mr_mip->w4); + copy(mr_mip->w4,yd); + } + copy(mr_mip->w3,xd); + if (z!=xd && z!=yd) copy(mr_mip->w1,z); + + MR_OUT + return (size(mr_mip->w1)); +} + +int invmodp(_MIPD_ big x,big y,big z) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + int gcd; + + MR_IN(213); + gcd=xgcd(_MIPP_ x,y,z,z,z); + MR_OUT + return gcd; +} + +#else + +/* much smaller, much slower binary inversion algorithm */ +/* fails silently if a is not co-prime to p */ + +/* experimental! At least 3 times slower than standard method.. */ + +int invmodp(_MIPD_ big a,big p,big z) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + big u,v,x1,x2; + + MR_IN(213); + + u=mr_mip->w1; v=mr_mip->w2; x1=mr_mip->w3; x2=mr_mip->w4; + copy(a,u); + copy(p,v); + convert(_MIPP_ 1,x1); + zero(x2); + + while (size(u)!=1 && size(v)!=1) + { + while (remain(_MIPP_ u,2)==0) + { + subdiv(_MIPP_ u,2,u); + if (remain(_MIPP_ x1,2)!=0) add(_MIPP_ x1,p,x1); + subdiv(_MIPP_ x1,2,x1); + } + while (remain(_MIPP_ v,2)==0) + { + subdiv(_MIPP_ v,2,v); + if (remain(_MIPP_ x2,2)!=0) add(_MIPP_ x2,p,x2); + subdiv(_MIPP_ x2,2,x2); + } + if (compare(u,v)>=0) + { + mr_psub(_MIPP_ u,v,u); + subtract(_MIPP_ x1,x2,x1); + } + else + { + mr_psub(_MIPP_ v,u,v); + subtract(_MIPP_ x2,x1,x2); + } + } + if (size(u)==1) copy(x1,z); + else copy(x2,z); + + if (size(z)<0) add(_MIPP_ z,p,z); + + MR_OUT + return 1; /* note - no checking that gcd=1 */ +} + +#endif + +#ifndef MR_STATIC + +/* Montgomery's method for multiple + simultaneous modular inversions */ + +BOOL double_inverse(_MIPD_ big n,big x,big y,big w,big z) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + MR_IN(146) + + mad(_MIPP_ x,w,w,n,n,mr_mip->w6); + if (size(mr_mip->w6)==0) + { + mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); + MR_OUT + return FALSE; + } + invmodp(_MIPP_ mr_mip->w6,n,mr_mip->w6); + + mad(_MIPP_ w,mr_mip->w6,w,n,n,y); + mad(_MIPP_ x,mr_mip->w6,x,n,n,z); + + MR_OUT + return TRUE; +} + +BOOL multi_inverse(_MIPD_ int m,big *x,big n,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(25) + + if (x==w) + { + mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + MR_OUT + return FALSE; + } + if (m==1) + { + invmodp(_MIPP_ x[0],n,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; + } + + invmodp(_MIPP_ mr_mip->w6,n,mr_mip->w6); + +/* Now y=1/y */ + + copy(x[m-1],mr_mip->w5); + mad(_MIPP_ w[m-1],mr_mip->w6,mr_mip->w6,n,n,w[m-1]); + + for (i=m-2;;i--) + { + if (i==0) + { + mad(_MIPP_ mr_mip->w5,mr_mip->w6,mr_mip->w6,n,n,w[0]); + break; + } + mad(_MIPP_ w[i],mr_mip->w5,w[i],n,n,w[i]); + mad(_MIPP_ w[i],mr_mip->w6,w[i],n,n,w[i]); + mad(_MIPP_ mr_mip->w5,x[i],x[i],n,n,mr_mip->w5); + } + + MR_OUT + return TRUE; +} + +#endif