X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_cryptkit/lib/giantFFT.c diff --git a/Security/libsecurity_cryptkit/lib/giantFFT.c b/Security/libsecurity_cryptkit/lib/giantFFT.c new file mode 100644 index 00000000..21e91983 --- /dev/null +++ b/Security/libsecurity_cryptkit/lib/giantFFT.c @@ -0,0 +1,519 @@ +/* Copyright (c) 1998,2011,2014 Apple Inc. All Rights Reserved. + * + * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT + * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE + * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE, INC. AND THE + * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE, + * INC. ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL + * EXPOSE YOU TO LIABILITY. + *************************************************************************** + + giantFFT.c + Library for large-integer arithmetic via FFT. Currently unused + in CryptKit. + + + Revision History + ---------------- + 19 Jan 1998 at Apple + Split off from NSGiantIntegers.c. + +*/ + +/* + * FIXME - make sure platform-specific math lib has floor(), fmod(), + * sin(), pow() + */ +#include +#include "NSGiantIntegers.h" + +#define AUTO_MUL 0 +#define GRAMMAR_MUL 1 +#define FFT_MUL 2 + +#define TWOPI (double)(2*3.1415926535897932384626433) +#define SQRT2 (double)(1.414213562373095048801688724209) +#define SQRTHALF (double)(0.707106781186547524400844362104) +#define TWO16 (double)(65536.0) +#define TWOM16 (double)(0.0000152587890625) +#define BREAK_SHORTS 400 // Number of shorts at which FFT breaks over. + +static int lpt(int n, int *lambda); +static void mul_hermitian(double *a, double *b, int n) ; +static void square_hermitian(double *b, int n); +static void addsignal(giant x, double *zs, int n); +static void scramble_real(double *x, int n); +static void fft_real_to_hermitian(double *zs, int n); +static void fftinv_hermitian_to_real(double *zs, int n); +static void GiantFFTSquare(giant gx); +static void GiantFFTMul(giant,giant); +static void giant_to_double(giant x, int sizex, double *zs, int L); + +static int mulmode = AUTO_MUL; + +void mulg(giant a, giant b) { /* b becomes a*b. */ + PROF_START; + INCR_MULGS; + GiantAuxMul(a,b); + #if FEE_DEBUG + (void)bitlen(b); // XXX + #endif FEE_DEBUG + PROF_END(mulgTime); + PROF_INCR(numMulg); +} + +static void GiantAuxMul(giant a, giant b) { +/* Optimized general multiply, b becomes a*b. Modes are: + AUTO_MUL: switch according to empirical speed criteria. + GRAMMAR_MUL: force grammar-school algorithm. + FFT_MUL: force floating point FFT method. +*/ + int square = (a==b); + + if (isZero(b)) return; + if (isZero(a)) { + gtog(a, b); + return; + } + switch(mulmode) { + case GRAMMAR_MUL: + GiantGrammarMul(a,b); + break; + case FFT_MUL: + if (square) { + GiantFFTSquare(b); + } + else { + GiantFFTMul(a,b); + } + break; + case AUTO_MUL: { + int sizea, sizeb; + float grammartime; + sizea = abs(a->sign); + sizeb = abs(b->sign); + grammartime = sizea; grammartime *= sizeb; + if(grammartime < BREAK_SHORTS*BREAK_SHORTS) { + GiantGrammarMul(a,b); + } + else { + if (square) GiantFFTSquare(b); + else GiantFFTMul(a,b); + } + break; + } + } +} + +/***************** Commence FFT multiply routines ****************/ + +static int CurrentRun = 0; +double *sincos = NULL; +static void init_sincos(int n) { + int j; + double e = TWOPI/n; + + if (n <= CurrentRun) return; + CurrentRun = n; + if (sincos) free(sincos); + sincos = (double *)malloc(sizeof(double)*(1+(n>>2))); + for(j=0;j<=(n>>2);j++) { + sincos[j] = sin(e*j); + } +} + +static double s_sin(int n) { + int seg = n/(CurrentRun>>2); + + switch(seg) { + case 0: return(sincos[n]); + case 1: return(sincos[(CurrentRun>>1)-n]); + case 2: return(-sincos[n-(CurrentRun>>1)]); + case 3: + default: return(-sincos[CurrentRun-n]); + } +} + +static double s_cos(int n) { + int quart = (CurrentRun>>2); + + if (n < quart) return(s_sin(n+quart)); + return(-s_sin(n-quart)); +} + + +static int lpt(int n, int *lambda) { +/* returns least power of two greater than n */ + register int i = 1; + + *lambda = 0; + while(imaxerr) maxerr = err; + */ + + zs[j] =0; + k = 0; + do{ + g = floor(f*TWOM16); + zs[j+k] += f-g*TWO16; + ++k; + f=g; + } while(f != 0.0); + } + car = 0; + for(j=0;jn[j] = m & 0xffff; + car = (m>>16); + } + if(car) x->n[j] = car; + else --j; + while(!(x->n[j])) --j; + x->sign = j+1; + if (abs(x->sign) > x->capacity) NSGiantRaise("addsignal overflow"); +} + +static void GiantFFTSquare(giant gx) { + int j,size = abs(gx->sign); + register int L; + + if(size<4) { GiantGrammarMul(gx,gx); return; } + L = lpt(size+size, &j); + { + //was...double doubles[L]; + //is... + double *doubles = malloc(sizeof(double) * L); + // end + giant_to_double(gx, size, doubles, L); + fft_real_to_hermitian(doubles, L); + square_hermitian(doubles, L); + fftinv_hermitian_to_real(doubles, L); + addsignal(gx, doubles, L); + // new + free(doubles); + } + gx->sign = abs(gx->sign); + bitlen(gx); // XXX + if (abs(gx->sign) > gx->capacity) NSGiantRaise("GiantFFTSquare overflow"); +} + +static void GiantFFTMul(giant y, giant x) { /* x becomes y*x. */ + int lambda, size, sizex = abs(x->sign), sizey = abs(y->sign); + int finalsign = gsign(x)*gsign(y); + register int L; + + if((sizex<=4)||(sizey<=4)) { GiantGrammarMul(y,x); return; } + size = sizex; if(sizesign = finalsign*abs(x->sign); + bitlen(x); // XXX + if (abs(x->sign) > x->capacity) NSGiantRaise("GiantFFTMul overflow"); +} + +static void scramble_real(double *x, int n) { + register int i,j,k; + register double tmp; + + for(i=0,j=0;i>=1; + } + j += k; + } +} + +static void fft_real_to_hermitian(double *zs, int n) { +/* Output is {Re(z^[0]),...,Re(z^[n/2),Im(z^[n/2-1]),...,Im(z^[1]). + This is a decimation-in-time, split-radix algorithm. + */ + register double cc1, ss1, cc3, ss3; + register int is, iD, i0, i1, i2, i3, i4, i5, i6, i7, i8, + a, a3, b, b3, nminus = n-1, dil, expand; + register double *x, e; + int nn = n>>1; + double t1, t2, t3, t4, t5, t6; + register int n2, n4, n8, i, j; + + init_sincos(n); + expand = CurrentRun/n; + scramble_real(zs, n); + x = zs-1; /* FORTRAN compatibility. */ + is = 1; + iD = 4; + do{ + for(i0=is;i0<=n;i0+=iD) { + i1 = i0+1; + e = x[i0]; + x[i0] = e + x[i1]; + x[i1] = e - x[i1]; + } + is = (iD<<1)-1; + iD <<= 2; + } while(is>=1) { + n2 <<= 1; + n4 = n2>>2; + n8 = n2>>3; + is = 0; + iD = n2<<1; + do { + for(i=is;i>1; + double t1, t2, t3, t4, t5; + int n2, n4, n8, i, j; + + init_sincos(n); + expand = CurrentRun/n; + x = zs-1; + n2 = n<<1; + while(nn >>= 1) { + is = 0; + iD = n2; + n2 >>= 1; + n4 = n2>>2; + n8 = n4>>1; + do { + for(i=is;i>1; + register double aa, bb, am, bm; + + b[0] *= a[0]; + b[half] *= a[half]; + for(k=1;k>1; + register double c, d; + + b[0] *= b[0]; + b[half] *= b[half]; + for(k=1;kn[j]; + } +}