/*************************************************************************** * 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 3 - simple powers and roots * mrarth3.c */ #include #include "miracl.h" 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; }