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