// Генерация параметров ЭК void genparams ( Qxy &P, ZZ &q, ZZ &bpn ) { ZZ i; ZZ x, y; ZZ f1, f2; for ( x = 0, i = 0; x < p; x++) for ( y = 0; y < p; y++) { f1 = PowerMod(y, 2, p); f2 = (PowerMod(x, 3, p) + a * x + b)%p; if ( f1 == f2 ) { if ( i == bpn ) P.getQxy(x,y); i++; } } q = i+1; long NumTrials = 10; if ( !ProbPrime( q, NumTrials) ) cout << "\nq is not prime! Please, change params (p,a,b)." << endl; cout << "\nDomain parameters\n" << endl; cout << "\np = " << p; cout << "\na = " << a; cout << "\nb = " << b; cout << "\nbpn = " << bpn << endl; cout << "\nq = " << q << endl; cout << "\nP = "; P.putQxy(); cout << endl; }
// p is prime and p = 1 mod 4 vector<ZZ> CommonFunctions::decomposePrime(const ZZ &p, int stat) { ZZ b; if((p % 8) == to_ZZ(5)) { b = to_ZZ(2); } else { b = to_ZZ(3); while(PowerMod(b, (p-1)/2, p) == 1) { // next prime(b) returns the smallest prime larger than b b = NextPrime(b, stat); } } b = PowerMod(b, (p-1)/4, p); // b is now an imaginary unit, i.e. b^2 = -1 mod p ZZ a; a = p; while(power(b, 2) > p) { ZZ temp = a; a = b; b = temp % b; } // cout << "a : " << a << " b : " << b << endl; vector<ZZ> twoSquares; twoSquares.push_back(b); twoSquares.push_back(a % b); return twoSquares; }
// generate only matrices of the form s(X^{g^i})->s(X), but not all of them. // For a generator g whose order is larger than bound, generate only enough // matrices for the giant-step/baby-step procedures (2*sqrt(ord(g))of them). void addSome1DMatrices(FHESecKey& sKey, long bound, long keyID) { const FHEcontext &context = sKey.getContext(); long m = context.zMStar.getM(); // key-switching matrices for the automorphisms for (long i = 0; i < (long)context.zMStar.numOfGens(); i++) { // For generators of small order, add all the powers if (bound >= (long)context.zMStar.OrderOf(i)) for (long j = 1; j < (long)context.zMStar.OrderOf(i); j++) { long val = PowerMod(context.zMStar.ZmStarGen(i), j, m); // val = g^j // From s(X^val) to s(X) sKey.GenKeySWmatrix(1, val, keyID, keyID); if (!context.zMStar.SameOrd(i)) // also from s(X^{1/val}) to s(X) sKey.GenKeySWmatrix(1, InvMod(val,m), keyID, keyID); } else { // For generators of large order, add only some of the powers long num = SqrRoot(context.zMStar.OrderOf(i)); // floor(ord^{1/2}) if (num*num < (long) context.zMStar.OrderOf(i)) num++; // ceil(ord^{1/2}) // VJS: the above two lines replaces the following inexact calculation // with an exact calculation // long num = ceil(sqrt((double)context.zMStar.OrderOf(i))); for (long j=1; j <= num; j++) { // Add matrices for g^j and g^{j*num} long val1 = PowerMod(context.zMStar.ZmStarGen(i), j, m); // g^j long val2 = PowerMod(context.zMStar.ZmStarGen(i),num*j,m);// g^{j*num} if (j < num) { sKey.GenKeySWmatrix(1, val1, keyID, keyID); sKey.GenKeySWmatrix(1, val2, keyID, keyID); } if (!context.zMStar.SameOrd(i)) { // sKey.GenKeySWmatrix(1, InvMod(val1,m), keyID, keyID); sKey.GenKeySWmatrix(1, InvMod(val2,m), keyID, keyID); } } // VJS: experimantal feature...because the replication code // uses rotations by -1, -2, -4, -8, we add a few // of these as well...only the small ones are important, // and we only need them if SameOrd(i)... // Note: we do indeed get a nontrivial speed-up if (context.zMStar.SameOrd(i)) { for (long k = 1; k <= num; k = 2*k) { long j = context.zMStar.OrderOf(i) - k; long val = PowerMod(context.zMStar.ZmStarGen(i), j, m); // val = g^j sKey.GenKeySWmatrix(1, val, keyID, keyID); } } } } sKey.setKeySwitchMap(); // re-compute the key-switching map }
NTL_CLIENT int main() { ZZ a=to_ZZ(30),b=to_ZZ(10),p=to_ZZ(83); ZZ x1=to_ZZ("125566390161800"),x2=to_ZZ("674318834107560"),r=to_ZZ(41); ifstream ftask("task.txt"); ftask >> a >> b >> p >> r; cout << (PowerMod(a,x1,p)*PowerMod(b,x2,p))%p << endl; ftask.close(); return 0; }
void EncryptedArrayDerived<type>::rotate1D(Ctxt& ctxt, long i, long amt, bool dc) const { FHE_TIMER_START; const PAlgebra& al = context.zMStar; const vector< vector< RX > >& maskTable = tab.getMaskTable(); RBak bak; bak.save(); tab.restoreContext(); assert(&context == &ctxt.getContext()); assert(i >= 0 && i < (long)al.numOfGens()); // Make sure amt is in the range [1,ord-1] long ord = al.OrderOf(i); amt %= ord; if (amt == 0) return; long signed_amt = amt; if (amt < 0) amt += ord; // DIRT: the above assumes division with remainder // follows C++11 and C99 rules if (al.SameOrd(i)) { // a "native" rotation long val = PowerMod(al.ZmStarGen(i), amt, al.getM()); ctxt.smartAutomorph(val); } else if (dc) { // the "don't care" case...it is presumed that any shifts // "off the end" are zero. For this, we have to use // the "signed" version of amt. long val = PowerMod(al.ZmStarGen(i), signed_amt, al.getM()); ctxt.smartAutomorph(val); } else { // more expensive "non-native" rotation assert(maskTable[i].size() > 0); long val = PowerMod(al.ZmStarGen(i), amt, al.getM()); long ival = PowerMod(al.ZmStarGen(i), amt-ord, al.getM()); const RX& mask = maskTable[i][ord-amt]; DoubleCRT m1(conv<ZZX>(mask), context, ctxt.getPrimeSet()); Ctxt tmp(ctxt); // a copy of the ciphertext tmp.multByConstant(m1); // only the slots in which m1=1 ctxt -= tmp; // only the slots in which m1=0 ctxt.smartAutomorph(val); // shift left by val tmp.smartAutomorph(ival); // shift right by ord-val ctxt += tmp; // combine the two parts } FHE_TIMER_STOP; }
void dfs(int depth, long exp, long coef) { if (depth == 0) { ans += coef * PowerMod(2, exp, MOD) % MOD; return; } int t = cnt[depth]; if (t == 0) return dfs(depth - 1, exp, coef); for (int i = 0; i <= t; ++i) { dfs(depth - 1, exp * PowerMod(depth - 1, i, PHI) % PHI * PowerMod(depth, t - i, PHI) % PHI, coef * cb[t][i] % MOD * PowerMod(MOD - 1, i, MOD) % MOD); } }
long witness(const ZZ& n, const ZZ& x) { ZZ m, y, z; long j, k; if (x == 0) return 0; k = 1; m = n/2; while (m % 2 == 0) { k++; m /= 2; } z = PowerMod(x, m, n); if (z == 1) return 0; j = 0; do { y = z; z = (y*y) % n; j++; } while (j < k && z != 1); return z != 1 || y != n-1; }
UserTool::UserTool(int st, int l, const BankParameters *bp, const VEPublicKey &vPK, const VEPublicKey &rPK, const hashalg_t &ha) : stat(st), lx(l), bankParameters(new BankParameters(*bp)), vepk(vPK), pk(rPK), hashAlg(ha) { const GroupPrime* cashGroup = bankParameters->getCashGroup(); userSecretKey = cashGroup->randomExponent(); // now compute user public key = g^sk_u ZZ g = cashGroup->getGenerator(1); userPublicKey = PowerMod(g, userSecretKey, cashGroup->getModulus()); // also compute PoK of sk_u (useful later) // set up environment group_map groups; groups["G"] = cashGroup; variable_map v; v["pk_u"] = userPublicKey; v["sk_u"] = userSecretKey; // now compute proof and save it InterpreterProver p; p.check("ZKP/examples/userid.txt", groups); p.compute(v); idProof = p.computeProof(hashAlg); }
int main(int argc,char** argv) { long index=256; ZZ seed; clear(seed); PARSE_MAIN_ARGS { MATCH_MAIN_ARGID("--index",index); MATCH_MAIN_ARGID("--seed",seed); SYNTAX(); } ZZX phi=find_cyclotomic(index); long n=deg(phi); ZZ det=find_determinant(index,10*n,seed); ZZ alpha=find_unity_root(index,det,phi); mat_ZZ B; B.SetDims(n,n); clear(B); B(1,1) = det; for (long i=2; i<=n; i++) { B(i,1)=det-PowerMod(alpha,i-1,det); B(i,i)=1; } cout << B << endl; cout << n << " " << index << " " << seed<< endl; cout << phi << endl; }
/** \brief 有限域Fp上多项式在Fp中的根(不含重数) \param f Fp[x]中多项式 \param p 阶数 \return 根的集合 \note 利用因子分解算法求解 */ void UniZpRootZp(std::vector<mpz_ptr> & rootlist,const poly_z & f,mpz_ptr p) { resize_z_list(rootlist,0); poly_z h0,h; h0.resize(2); mpz_set_ui(h0[0],0); mpz_set_ui(h0[1],1); copy_poly_z(h,h0); PowerMod(h,p,f,p); mpz_sub_ui(h[1],h[1],1); UniGcdZp(h0,h,f,p); if(h0.size()==1) { h0.resize(0); h.resize(0); return ; } std::vector<poly_z> faclist; UniEqlDegFacZp(faclist,h0,p,1); for(uint i=0; i<faclist.size(); i++) { resize_z_list(rootlist,i+1); mpz_neg(rootlist[i],faclist[i][0]); } clear_poly_z_list(faclist); h0.resize(0); h.resize(0); std::sort(rootlist.begin(),rootlist.end(),mpz_ptr_less); return ; }
int main() { long long a, b, k; while (scanf("%lld%lld%lld", &a, &b, &k) == 3) printf("%lld\n", PowerMod(a, b, k)); return 0; }
NTL_CLIENT // Compute a degree-p polynomial poly(x) s.t. for any t<e and integr z of the // form z = z0 + p^t*z1 (with 0<=z0<p), we have poly(z) = z0 (mod p^{t+1}). // // We get poly(x) by interpolating a degree-(p-1) polynomial poly'(x) // s.t. poly'(z0)=z0 - z0^p (mod p^e) for all 0<=z0<p, and then setting // poly(x) = x^p + poly'(x). static void buildDigitPolynomial(ZZX& result, long p, long e) { if (p<2 || e<=1) return; // nothing to do FHE_TIMER_START; long p2e = power_long(p,e); // the integer p^e // Compute x - x^p (mod p^e), for x=0,1,...,p-1 vec_long x(INIT_SIZE, p); vec_long y(INIT_SIZE, p); long bottom = -(p/2); for (long j=0; j<p; j++) { long z = bottom+j; x[j] = z; y[j] = z-PowerMod((z < 0 ? z + p2e : z), p, p2e); // x - x^p (mod p^e) while (y[j] > p2e/2) y[j] -= p2e; while (y[j] < -(p2e/2)) y[j] += p2e; } interpolateMod(result, x, y, p, e); assert(deg(result)<p); // interpolating p points, should get deg<=p-1 SetCoeff(result, p); // return result = x^p + poly'(x) // cerr << "# digitExt mod "<<p<<"^"<<e<<"="<<result<<endl; FHE_TIMER_STOP; }
// Генерация ключей void genkeys ( ZZ &x, ZZ &y, ZZ &p, ZZ &q, ZZ &a) { RandomBnd(x, q-1); // Секретный ключ PowerMod(y, a%p, x%p, p); // Открытый ключ cout << "\nSecret key x = \n"; show_dec_in_hex (x, N); cout << endl; cout << "\nPublic key y = \n"; show_dec_in_hex (y, L); cout << endl; }
void rotate1D(DoubleCRT& d, long i, long amt, const vector< vector< DoubleCRT > > & maskTable) // rotate d in dimension i by amt { const FHEcontext& context = d.getContext(); const PAlgebra& al = context.zMstar; // const PAlgebraModTwo& al2 = context.modTwo; long ngens = al.numOfGens(); // long nslots = al.NSlots(); assert(i >= 0 && i < ngens); long ord = al.OrderOf(i); amt = amt % ord; if (amt < 0) amt += ord; if (amt == 0) return; if (al.SameOrd(i)) { // "native" rotation long val = PowerMod(al.ZmStarGen(i), amt, al.M()); d.automorph(val); } else { // more expensive "non-native" rotation assert(maskTable[i].size() > 0); long val = PowerMod(al.ZmStarGen(i), amt, al.M()); // long ival = InvMod(val, al.M()); long ival = PowerMod(al.ZmStarGen(i), amt-ord, al.M()); const DoubleCRT& m1 = maskTable[i].at(ord-amt); DoubleCRT d1(d); d1.Mul(m1, false); d -= d1; d.automorph(val); d1.automorph(ival); d += d1; } }
// Apply a permutation network to a ciphertext // FIXME: Do we need to also give an EncryptedArray object as paramter? void PermNetwork::applyToCtxt(Ctxt& c) const { const PAlgebra& al = c.getContext().zMStar; EncryptedArray ea(c.getContext()); // Use G(X)=X for this ea object, this works since we only have 0/1 entries // Apply the layers, one at a time for (long i=0; i<layers.length(); i++) { const PermNetLayer& lyr = layers[i]; if (lyr.isID) continue; // this layer is the identity permutation // This layer is shifted via powers of g^e mod m long g2e = PowerMod(al.ZmStarGen(lyr.genIdx), lyr.e, al.getM()); Vec<long> unused = lyr.shifts; // copy to a new vector vector<long> mask(lyr.shifts.length()); // buffer to hold masks Ctxt sum(c.getPubKey(), c.getPtxtSpace()); // an empty ciphertext long shamt = 0; bool frst = true; while (true) { pair<long,bool> ret=makeMask(mask, unused, shamt); // compute mask if (ret.second) { // non-empty mask Ctxt tmp = c; ZZX maskPoly; ea.encode(maskPoly, mask); // encode mask as polynomial tmp.multByConstant(maskPoly); // multiply by mask if (shamt!=0) // rotate if the shift amount is nonzero tmp.smartAutomorph(PowerMod(g2e, shamt, al.getM())); if (frst) { sum = tmp; frst = false; } else sum += tmp; } if (ret.first >= 0) shamt = unused[ret.first]; // next shift amount to use else break; // unused is all-zero, done with this layer } c = sum; // update the cipehrtext c before the next layer } }
// Generate all key-switching matrices for a given permutation network void addMatrices4Network(FHESecKey& sKey, const PermNetwork& net, long keyID) { const FHEcontext &context = sKey.getContext(); long m = context.zMStar.getM(); for (long i=0; i<net.depth(); i++) { long e = net.getLayer(i).getE(); long gIdx = net.getLayer(i).getGenIdx(); long g = context.zMStar.ZmStarGen(gIdx); long g2e = PowerMod(g, e, m); // g^e mod m const Vec<long>&shamts = net.getLayer(i).getShifts(); for (long j=0; j<shamts.length(); j++) { if (shamts[j]==0) continue; long val = PowerMod(g2e, shamts[j], m); sKey.GenKeySWmatrix(1, val, keyID, keyID); } } sKey.setKeySwitchMap(); // re-compute the key-switching map }
// Generate all Frobenius matrices of the form s(X^{2^i})->s(X) void addFrbMatrices(FHESecKey& sKey, long keyID) { const FHEcontext &context = sKey.getContext(); long m = context.zMStar.getM(); for (long j = 1; j < (long)context.zMStar.getOrdP(); j++) { long val = PowerMod(context.zMStar.getP(), j, m); // val = p^j mod m sKey.GenKeySWmatrix(1, val, keyID, keyID); } sKey.setKeySwitchMap(); // re-compute the key-switching map }
// Проверка ЭЦП void verifysign ( ZZ &u, ZZ &r, ZZ &s, ZZ &H, ZZ &y, ZZ &p, ZZ &q, ZZ &a) { ZZ v, z1, z2; v = PowerMod(H, (q-2), q); z1 = (s * v) % q; z2 = (SubMod(q, r%q, q) * v) % q; u = ((PowerMod(a, z1, p) * PowerMod(y, z2, p)) % p) % q; cout << "\nCheck sign\n"; cout << "\nv = \n"; show_dec_in_hex (v, N); cout << endl; cout << "\nz1 = \n"; show_dec_in_hex (z1, N); cout << endl; cout << "\nz2 = \n"; show_dec_in_hex (z2, N); cout << endl; cout << "\nu = \n"; show_dec_in_hex (u, N); cout << endl; cout << endl; if ( u == r ) cout << "u = r Sign is OK" << endl; else cout << "Sign is FAILED" << endl; }
unsigned long PAlgebra::exponentiate(const vector<unsigned long>& exps, bool onlySameOrd) const { unsigned long t = 1; unsigned long n = min(exps.size(),gens.size()); for (unsigned long i=0; i<n; i++) { if (onlySameOrd && !SameOrd(i)) continue; unsigned long g = PowerMod(gens[i] ,exps[i], m); t = MulMod(t, g, m); } return t; }
NTL_CLIENT // Программа для генерации задачи дискретного логарифмирования заданной размерности // Образующая и модуль - D1 гладкие int main() { ZZ a,b,p,r; //основание, степень, модуль, порядок циклической группы, образованной основанием ZZ x; //Показатель long len; //Длина модуля //Спросим длину модуля //Фактически, модуль будет иметь длину len+1 двоичных разрядов cin >> len; //Простое число Жермен - p - простое и 2*p+1 - тоже простое //Генерируем число заданной размерности (в двоичных разрядах) p=GenGermainPrime_ZZ(len); //Порядок циклической группы будет p-1. Мы будем искать образующую :) //Всё так, как учил нас Великий Шнайер в Красной Книге r=2*p; //Модуль p=2*p+1; a=2; //Найдём образующую while ((PowerMod(a,2,p)==1) || (PowerMod(a,(p-1)/2,p)==1)) { a=NextPrime(a+1); } //Получим степень b b=2; if (b==a) b=NextPrime(b+1); //Выдадим задачу на стандартный вывод cout << a << endl << b << endl << p << endl << r << endl; //Вот программе и конец, а кто - кодил - молодец! return 0; }
// applies the Frobenius automorphism p^j void Ctxt::frobeniusAutomorph(long j) { // Special case: if *this is empty then do nothing if (this->isEmpty()) return; long m = context.zMStar.getM(); long p = context.zMStar.getP(); long d = context.zMStar.getOrdP(); j = mcMod(j, d); long val = PowerMod(p, j, m); smartAutomorph(val); }
void EncryptedArrayDerived<type>::shift1D(Ctxt& ctxt, long i, long k) const { FHE_TIMER_START; const PAlgebra& al = context.zMStar; const vector< vector< RX > >& maskTable = tab.getMaskTable(); RBak bak; bak.save(); tab.restoreContext(); assert(&context == &ctxt.getContext()); assert(i >= 0 && i < (long)al.numOfGens()); long ord = al.OrderOf(i); if (k <= -ord || k >= ord) { ctxt.multByConstant(to_ZZX(0)); return; } // Make sure amt is in the range [1,ord-1] long amt = k % ord; if (amt == 0) return; if (amt < 0) amt += ord; RX mask = maskTable[i][ord-amt]; long val; if (k < 0) val = PowerMod(al.ZmStarGen(i), amt-ord, al.getM()); else { mask = 1 - mask; val = PowerMod(al.ZmStarGen(i), amt, al.getM()); } DoubleCRT m1(conv<ZZX>(mask), context, ctxt.getPrimeSet()); ctxt.multByConstant(m1); // zero out slots where mask=0 ctxt.smartAutomorph(val); // shift left by val FHE_TIMER_STOP; }
ZZ BankTool::identifyDoubleSpender(const Coin& coin1, const ZZ &tPrime2, const ZZ& rValue2) const { // Should probably check that the R values are different ZZ mod = coin1.getCashGroup()->getModulus(); ZZ order = coin1.getCashGroup()->getOrder(); ZZ t1 = coin1.getTPrime(); ZZ t2 = tPrime2; ZZ r1 = coin1.getR(); ZZ r2 = rValue2; if (r2 > r1) { NTL::swap(r2, r1); NTL::swap(t2, t1); } ZZ exp = InvMod(r1 - r2, order); ZZ num = PowerMod(t2, r1, mod); ZZ denom = InvMod(PowerMod(t1, r2, mod), mod); ZZ base = MulMod(num, denom, mod); ZZ publicKeyUser = PowerMod(base, exp, mod); return publicKeyUser; }
// Генерация параметров ЭК // Базовая точка P void genparam_P ( Qxy &P, ZZ &q, ZZ &bpn ) { ZZ i; ZZ x, y; ZZ f1, f2; for ( x = 0, i = 0; x < p; x++) for ( y = 0; y < p; y++) { f1 = PowerMod(y, 2, p); f2 = (PowerMod(x, 3, p) + a * x + b)%p; if ( f1 == f2) { if (i == bpn) { P.getQxy(x,y); goto out; } i++; } } out: {} }
// Генерация параметров ЭК // Порядок ЭК q void genparam_q ( Qxy &P, ZZ &q ) { ZZ i; ZZ x, y; ZZ f1, f2; for ( x = 0, i = 0; x < p; x++) for ( y = 0; y < p; y++) { f1 = PowerMod(y, 2, p); f2 = (PowerMod(x, 3, p) + a * x + b)%p; if ( f1 == f2 ) i++; } q = i+1; long NumTrials = 10; if ( !ProbPrime( q, NumTrials) ) cout << "\nq is not prime! Please, change params (p,a,b)." << endl; cout << "\np = " << p; cout << "\na = " << a; cout << "\nb = " << b; cout << "\nq = " << q << endl; }
// Генерация ЭЦП void gensign ( ZZ &r, ZZ &s, ZZ &H, ZZ &x, ZZ &p, ZZ &q, ZZ &a) { ZZ k; while ( s == 0 ) { RandomBnd(k, q); // Случайное число k r = PowerMod(a%p, k%p, p) % q; if ( r == 0 ) continue; s = (x * r + k * H ) % q; if ( s == 0 ) continue; } cout << "\nGenerate sign\n"; cout << "\nSession key k = \n"; show_dec_in_hex (H, N); cout << endl; cout << "\nr = \n"; show_dec_in_hex (r, N); cout << endl; cout << "\ns = \n"; show_dec_in_hex (s, N); cout << endl; }
//Ideal lattice challenge problem generator //modified from generate_ideal.cpp in Ideal lattice Challenge web page void gen_idealsvpchallenge(mat_ZZ& B,int index,ZZ seed,vec_ZZ& phivec) { ZZX phi=find_cyclotomic(index); long n=deg(phi); ZZ det=find_determinant(index,10*n,seed); ZZ alpha=find_unity_root(index,det,phi); B.SetDims(n,n); clear(B); B(1,1) = det; for (long i=2; i<=n; i++) { B(i,1)=det-PowerMod(alpha,i-1,det); B(i,i)=1; } phivec.SetLength(n+1); for (int i=0;i<=n;i++) phivec[i] = coeff(phi,i); }
// generate all matrices of the form s(X^{g^i})->s(X) for generators g of // Zm* /<2> and i<ord(g). If g has different orders in Zm* and Zm* /<2> // then generate also matrices of the form s(X^{g^{-i}})->s(X) void add1DMatrices(FHESecKey& sKey, long keyID) { const FHEcontext &context = sKey.getContext(); long m = context.zMStar.getM(); // key-switching matrices for the automorphisms for (long i = 0; i < (long)context.zMStar.numOfGens(); i++) { for (long j = 1; j < (long)context.zMStar.OrderOf(i); j++) { long val = PowerMod(context.zMStar.ZmStarGen(i), j, m); // val = g^j // From s(X^val) to s(X) sKey.GenKeySWmatrix(1, val, keyID, keyID); if (!context.zMStar.SameOrd(i)) // also from s(X^{1/val}) to s(X) sKey.GenKeySWmatrix(1, InvMod(val,m), keyID, keyID); } } sKey.setKeySwitchMap(); // re-compute the key-switching map }
NTL_CLIENT int main() { //основание, степень, модуль, порядок группы ZZ a,b,p,r; ifstream ftask("task.txt"); //Вводим исходные данные ftask >> a >> b >> p >> r; ftask.close(); ZZ i; for (i=to_ZZ(0);i<r;i++) if (PowerMod(a,i,p)==b) { cout << "x=" << i << endl; return 0; } cout << "NO ANSWER" << endl; return 0; }
void power_specially_for_eqldegfactorization(poly_z & a,const poly_z & f,mpz_ptr p,uint d) { poly_z poly_temp1,poly_temp2; static mpz_t exp; mpz_init(exp); copy_poly_z(poly_temp1,a); for(uint i=1;i<d;i++) { PowerMod_Pth_Power(poly_temp1,f,p); UniMulZ(poly_temp2,poly_temp1,a); UniModZp(a,poly_temp2,f,p); } mpz_sub_ui(exp,p,1); mpz_fdiv_q_2exp(exp,exp,1); PowerMod(a,exp,f,p); poly_temp1.resize(0); poly_temp2.resize(0); mpz_clear(exp); return ; }