/* Demo of NTT code M.Scott 21/07/2017 gcc -O3 ntt_ref.c -o ntt_ref.exe */ #include #include #include // Uncomment to create transcript of excesses //#define RECORD_EXCESS // Set some constants //q= 12289 #define PRIME 0x3001 // q in Hex #define LGN 10 // Degree n=2^LGN #define ND 0xF7002FFF // 1/(R-q) mod R #define ONE 0x2AC8 // R mod q #define R2MODP 0x1620 // R^2 mod q #define L 1 // 2nq < 2^{31-L} #define XLIM 0x2AA9C // available excess 2^{31}/q //q= 8383489 /* #define PRIME 0x7FEC01 // q in Hex #define LGN 9 // Degree n=2^LGN #define ND 0xBEEFEBFF // 1/(R-q) mod R #define ONE 0x27FE00 // R mod q #define R2MODP 0x58F4C // R^2 mod q #define L 4 // 2nq < 2^{31-L} #define XLIM 0x100 // available excess 2^{31}/q */ // q=39960577 /* #define PRIME 0x261C001 #define LGN 9 #define ND 0xF261BFFF #define ONE 0x124BF95 #define R2MODP 0xAB9F67 #define L 32 #define XLIM 0x35 */ #define DEGREE (1<>WL; } inline int_t nres(uint_t x) { return redc((uint_dt)x*R2MODP); } inline int_t modmul(uint_t a,uint_t b) { return redc((uint_dt)a*b); } /* reverse bits */ uint_t reverse(uint_t v) { uint_t r = v; int s = sizeof(v) * 8 - 1; for (v >>= 1; v; v >>= 1) { r <<= 1; r |= v & 1; s--; } r <<= s; r>>=(WL-LGN); return r; } /* some number theory functions borrowed from MIRACL */ int spmd(int x,int n,int m) { /* returns x^n mod m */ int r,sx; x%=m; r=0; if (x==0) return r; r=1; if (n==0) return r; sx=x; for (;;) { if (n%2!=0) r=((int_dt)r*sx)%m; n/=2; if (n==0) return r; sx=((int_dt)sx*sx)%m; } } int invers(int x,int y) { /* returns inverse of x mod y */ int r,s,q,t,p,pos; if (y!=0) x%=y; r=1; s=0; p=y; pos=1; while (p!=0) { /* main euclidean loop */ q=x/p; t=r+s*q; r=s; s=t; t=x-p*q; x=p; p=t; pos=!pos; } if (!pos) r=y-r; return r; } int sqrmp(int x,int m) { /* square root mod a small prime =1 mod 8 by Shanks method * * returns 0 if root does not exist or m not prime */ int z,y,v,w,t,q,i,e,n,r,pp; x%=m; if (x==0) return 0; if (x==1) return 1; if (spmd(x,(m-1)/2,m)!=1) return 0; /* Legendre symbol not 1 */ q=m-1; e=0; while (q%2==0) { q/=2; e++; } if (e==0) return 0; /* even m */ for (r=2;;r++) { /* find suitable z */ z=spmd(r,q,m); if (z==1) continue; t=z; pp=0; for (i=1;i=r) return 0; y=spmd(y,(1<<(r-n-1)),m); v=((int_dt)v*y)%m; y=((int_dt)y*y)%m; w=((int_dt)w*y)%m; r=n; } return v; } /* NTT code */ /* precompute roots of unity and its powers */ void init_ntt2(int_t *roots,int_t *iroots) { int q=PRIME; int i,j,proot=q-1; for (j=0;jXLIM) {printf("******* Possible Overflow *******\n"); exit(0);} printf("NTT ADD XES= %d XLIM %d\n",xes[j],XLIM); if (xes[j]>XLIM) {printf("******* Possible Overflow *******\n"); exit(0);} #endif x[j+t]=U+2*q-V; } k+=2*t; } t/=2; m*=2; } } /* Gentleman-Sande INTT */ void intt(int_t inv,int_t invpr,int_t *iroots,int_t *x) { int m,i,j,k,n,lim,t=1; int_t S,U,V,W,q=PRIME; #ifdef RECORD_EXCESS int xes[DEGREE]; int eU,eV; for (j=0;j1) { //lim=L/(2*m); lim=L>>n; n--; k=0; for (i=0;iXLIM) {printf("******* Possible Overflow *******\n"); exit(0);} printf("INTT MUL XES= %d XLIM %d\n",eU+(DEGREE/L),XLIM); if (eU+(DEGREE/L)>XLIM) {printf("******* Possible Overflow *******\n"); exit(0);} if (eV>(DEGREE/L)) {printf("******* Possible Overflow *******\n"); exit(0);} xes[j]=eU+eV; xes[j+t]=2; #endif W=U+(DEGREE/L)*q-V; x[j+t]=modmul(W,S); } k+=2*t; } t*=2; m/=2; } /* Last iteration merged with n^-1 */ t=DEGREE/2; for (j=0;jXLIM) {printf("******* Possible Overflow *******\n"); /*exit(0);*/} printf("INTT MUL XES= %d XLIM %d\n",eU+(DEGREE/L),XLIM); if (eU+(DEGREE/L)>XLIM) {printf("******* Possible Overflow *******\n"); /* exit(0);*/} xes[j]=eU+eV; xes[j+t]=2; #endif W=U+(DEGREE/L)*q-V; x[j+t]=modmul(W,invpr); x[j]=modmul(U+V,inv); } /* convert back from Montgomery to "normal" form */ for (j=0;j>(WL-1))&q; } } int main() { int i,j,k,err,q=PRIME; int_t a[DEGREE],b[DEGREE],roots[DEGREE],iroots[DEGREE]; int_t inv,invpr; srand(3); /* initialise random number generator */ /* pre-calculate powers of roots of unity */ init_ntt2(roots,iroots); inv=nres(invers(DEGREE,q)); invpr=modmul(iroots[1],inv); inv-=q; inv+=(inv>>(WL-1))&q; invpr-=q; invpr+=(invpr>>(WL-1))&q; /* generate some random data */ for (i=0;i