/***************************************************************************
*
Copyright 2013 CertiVox UK Ltd. *
*
This file is part of CertiVox MIRACL Crypto SDK. *
*
The CertiVox MIRACL Crypto SDK provides developers with an *
extensive and efficient set of cryptographic functions. *
For further information about its features and functionalities please *
refer to http://www.certivox.com *
*
* The CertiVox MIRACL Crypto SDK is free software: you can *
redistribute it and/or modify it under the terms of the *
GNU Affero General Public License as published by the *
Free Software Foundation, either version 3 of the License, *
or (at your option) any later version. *
*
* The CertiVox MIRACL Crypto SDK is distributed in the hope *
that it will be useful, but WITHOUT ANY WARRANTY; without even the *
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
See the GNU Affero General Public License for more details. *
*
* You should have received a copy of the GNU Affero General Public *
License along with CertiVox MIRACL Crypto SDK. *
If not, see . *
*
You can be released from the requirements of the license by purchasing *
a commercial license. Buying such a license is mandatory as soon as you *
develop commercial activities involving the CertiVox MIRACL Crypto SDK *
without disclosing the source code of your own applications, or shipping *
the CertiVox MIRACL Crypto SDK with a closed source product. *
*
***************************************************************************/
/*
* MIRACL arithmetic routines 0 - Add and subtract routines
* mrarth0.c
*
*/
#include "miracl.h"
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
}