1069 lines
23 KiB
C
1069 lines
23 KiB
C
|
|
/***************************************************************************
|
|
*
|
|
Copyright 2013 CertiVox UK Ltd. *
|
|
*
|
|
This file is part of CertiVox MIRACL Crypto SDK. *
|
|
*
|
|
The CertiVox MIRACL Crypto SDK provides developers with an *
|
|
extensive and efficient set of cryptographic functions. *
|
|
For further information about its features and functionalities please *
|
|
refer to http://www.certivox.com *
|
|
*
|
|
* The CertiVox MIRACL Crypto SDK is free software: you can *
|
|
redistribute it and/or modify it under the terms of the *
|
|
GNU Affero General Public License as published by the *
|
|
Free Software Foundation, either version 3 of the License, *
|
|
or (at your option) any later version. *
|
|
*
|
|
* The CertiVox MIRACL Crypto SDK is distributed in the hope *
|
|
that it will be useful, but WITHOUT ANY WARRANTY; without even the *
|
|
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
See the GNU Affero General Public License for more details. *
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public *
|
|
License along with CertiVox MIRACL Crypto SDK. *
|
|
If not, see <http://www.gnu.org/licenses/>. *
|
|
*
|
|
You can be released from the requirements of the license by purchasing *
|
|
a commercial license. Buying such a license is mandatory as soon as you *
|
|
develop commercial activities involving the CertiVox MIRACL Crypto SDK *
|
|
without disclosing the source code of your own applications, or shipping *
|
|
the CertiVox MIRACL Crypto SDK with a closed source product. *
|
|
*
|
|
***************************************************************************/
|
|
|
|
/*
|
|
*
|
|
* MIRACL arithmetic routines 1 - multiplying and dividing BIG NUMBERS by
|
|
* integer numbers.
|
|
* mrarth1.c
|
|
*
|
|
*/
|
|
|
|
#include "miracl.h"
|
|
|
|
#ifdef MR_FP
|
|
#include <math.h>
|
|
#endif
|
|
|
|
#ifdef MR_WIN64
|
|
#include <intrin.h>
|
|
#endif
|
|
|
|
#ifdef MR_FP_ROUNDING
|
|
#ifdef __GNUC__
|
|
#include <ieeefp.h>
|
|
#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;m<xl;m++)
|
|
#ifdef MR_NOASM
|
|
{
|
|
dble.d=(mr_large)x->w[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 (m<xl || carry>0)
|
|
{ /* 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;j<r;j++) {wrd<<=8; wrd|=MR_TOBYTE(*ptr++); }
|
|
}
|
|
x->len=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;j<m;j++) { wrd<<=8; wrd|=MR_TOBYTE(*ptr++); }
|
|
x->w[i]=wrd;
|
|
}
|
|
mr_lzero(x); /* needed */
|
|
#endif
|
|
#ifndef MR_SIMPLE_BASE
|
|
}
|
|
else
|
|
{
|
|
for (i=0;i<len;i++)
|
|
{
|
|
if (mr_mip->ERNUM) 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;i<max;i++) ptr[i]=0;
|
|
return max;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
MR_IN(141);
|
|
|
|
mr_lzero(x); /* should not be needed.... */
|
|
#ifndef MR_SIMPLE_BASE
|
|
if (mr_mip->base==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;i<start;i++) ptr[i]=0;
|
|
}
|
|
else start=0;
|
|
|
|
if (r!=0)
|
|
{
|
|
wrd=x->w[n--];
|
|
for (i=r-1;i>=0;i--)
|
|
{
|
|
ptr[start+i]=(char)(wrd&0xFF);
|
|
wrd>>=8;
|
|
}
|
|
}
|
|
|
|
for (i=r;i<len;i+=m)
|
|
{
|
|
wrd=x->w[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
|