byte smallest_nth_primitive_root_of_unity(uint n){ byte res = 0; byte b = 2; uint j = 0; while(j < 257) { uint i = 0; // is it a nth root? if ( (res = pol_pow(b,n)) == 1) { bool ok = 1; for( i = 2; i < n;++i) { if (pol_pow(b,i) == 1) { ok = 0; } } if (ok) { return b; } } ++b; ++j; } return 0; }
/*! * */ static void _efft(uint P, uint Q, byte qroot, byte nroot, byte * f, byte * res) { uint qhat = 0, rho = 0, q = 0, rhohat = 0; uint N = P*Q, i =0; byte oN = nroot; byte oq = qroot; byte z = 1, y = 1; byte Y[256][256] = {{0}}; if (oN == 0) { printf("Failed to find %u root of unity\n", N); } if (oq == 0) { printf("Failed to find %u root of unity\n",q); } for(qhat = 0; qhat <= Q;++qhat) { for(rho = 0; rho <= P; ++rho) { for(q = 0; q < Q;++q) { uint fidx = q*P+rho; Y[rho][qhat] = add(Y[rho][qhat],multiply(f[fidx],pol_pow(y,q))); if (qhat == 15) { printf("Y[%u][%u]=%u\n", rho, qhat, Y[rho][qhat]); } if (qhat == Q-1) printf("fidx=%u ",fidx); } } y = multiply(y,oq); } printf("\n"); for(rhohat = 0 ; rhohat <= P;++rhohat ) { for(qhat = 0; qhat <= Q; ++qhat ) {// qhat loop for(rho = 0;rho < P;++rho) { // SUM uint residx = rhohat*Q + qhat; res[rhohat*Q + qhat] = add(res[rhohat*Q+qhat], multiply(Y[rho][qhat], pol_pow(z,rho))); if (residx == 255) { printf("Y[%u][%u]=%u, pow(%u,%u)\n",rho,qhat,Y[rho][qhat],z,rho); } if (rho == P-1) { printf("residx = %u ",residx); } } z = multiply(z,oN); } } printf("\n"); }
static inline gf8 do_op(char op, gf8 l, gf8 r) { if (op == '+' || op == '-') return add(l,r); if (op == '*') return multiply(l,r); if (op == '/') return multiply(l,inverse(r)); if (op == '^') return pol_pow(l,r); if (op == 'o') return smallest_nth_primitive_root_of_unity(l); if (op == 's') { uint i = 0; for (i = 0;i < r;++i) { printf("%u ",pol_pow(l,i)); } return pol_pow(l,i); } printf("unknown operator %c\n",op); exit(-1); }
/*! * DFT_w^{-1}(f) = DFT_{w^{-1}}(f) */ void efftinv2(uint P, uint Q, byte * y, byte * res) { uint N = P*Q,i=0; byte nroot = omega; byte qroot = pol_pow(nroot,P); byte nrootinv = inverse(nroot); byte qrootinv = inverse(qroot); composite_fft2(P,Q,qrootinv, nrootinv, y, res); }
/*! * Evaluates the polynomial f[0]+f[1]x+...+f[lf-1]x^{lf-1} in the * point x. */ uint order_of(byte e) { uint ord = 0; for(ord = 1;ord < 255;++ord) { if (pol_pow(e,ord) == 1) return ord; } return 0; }
uint nth_root_of_unity(byte * r, uint n) { int b = 0; uint count = 0; for(b = 2;b<256;++b) { if (pol_pow( (byte)b, n) == 1) { r[count++] = b; } } return count; }
void efftinv(uint P, uint Q, byte * f, byte *res ) { byte oN = smallest_nth_primitive_root_of_unity(P*Q); byte oQ = pol_pow(oN,P); uint pc = 0, qc = 0, k = 0; byte Qroot = 1; byte Nroot = 1; byte rowFFT[256][256] = {{0}}; // P x Q byte rootK = 0; oN = inverse(oN); oQ = inverse(oQ); for(qc = 0;qc < Q;++qc) { for(pc = 0;pc < P;++pc) { rootK = 1; for(k = 0;k < Q;++k) { // rowFFT[pc,qc] = SUM_{k=0}^{Q-1} byte term = 0; // A[k,pc] each term: f_{pc*Q+k} term = multiply(f[k*P+pc],rootK); rowFFT[pc][qc] = add(rowFFT[pc][qc],term); rootK = multiply(rootK, Qroot); } } Qroot = multiply(Qroot,oQ); } for(pc = 0;pc < P;++pc) { for(qc = 0;qc < Q;++qc) { rootK = 1; for(k = 0;k < P;++k) { byte term = 0; uint res_idx = pc*Q+qc; term = multiply(rowFFT[k][qc],rootK); res[res_idx] = add(res[res_idx],term); rootK = multiply(rootK, Nroot); } Nroot = multiply(Nroot,oN); } } }
/*! * * */ void efft(uint P, uint Q, byte * f, byte * res) { uint N = P*Q; byte nroot = omega; byte qroot = pol_pow(nroot,P); composite_fft2(P,Q,qroot,nroot,f,res); }