// Returns a list of prime factors and their multiplicity, // N = \prod_i factors[i].first^{factors[i].second} void factorize(Vec< Pair<long, long> > &factors, long N) { factors.SetLength(0); if (N < 2) return; PrimeSeq s; long n = N; while (n > 1) { if (ProbPrime(n)) { // n itself is a prime, add (n,1) to the list append(factors, cons(n, 1L)); return; } long p = s.next(); if ((n % p) == 0) { // p divides n, find its multiplicity long e = 1; n = n/p; while ((n % p) == 0) { n = n/p; e++; } append(factors, cons(p, e)); // add (p,e) to the list } } }
// Find the next prime and add it to the chain long FHEcontext::AddPrime(long initialP, long delta, bool special, bool findRoot) { // long twoM = 2 * zMStar.getM(); // assert((initialP % twoM == 1) && (delta % twoM == 0)); // NOTE: this assertion will fail for the half-prime in ALT_CRT long p = initialP; do { p += delta; // delta could be positive or negative } while (p>initialP/16 && p<NTL_SP_BOUND && !(ProbPrime(p) && !inChain(p))); if (p<=initialP/16 || p>=NTL_SP_BOUND) return 0; // no prime found long i = moduli.size(); // The index of the new prime in the list moduli.push_back( Cmodulus(zMStar, p, findRoot ? 0 : 1) ); if (special) specialPrimes.insert(i); else ctxtPrimes.insert(i); return p; }
// Генерация параметров ЭК 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; }
bool ProvePrime(const ZZ& _n) { ZZ n(_n); if (n<0) abs(n,n); if (n<=1) return 0; if (n<=1000000) { // n is small so use trial division to check primality long ln = to_long(n); long end = to_long(SqrRoot(n)); PrimeSeq s; for (long p=s.next(); p<=end; p=s.next()) if ((ln%p)==0) return 0; return 1; } // check small primes PrimeSeq s; for (long p=s.next(); p<1000; p=s.next()) if (divide(n,p)) return 0; // obviously, something is missing here! return ProbPrime(n); }
// return a degree-d irreducible polynomial mod p ZZX makeIrredPoly(long p, long d) { assert(d >= 1); assert(ProbPrime(p)); if (d == 1) return ZZX(1, 1); // the monomial X zz_pBak bak; bak.save(); zz_p::init(p); return to_ZZX(BuildIrred_zz_pX(d)); }
// Find the next prime and add it to the chain long FHEcontext::AddPrime(long initialP, long delta, bool special) { long p = initialP; do { p += delta; } // delta could be positive or negative while (p>initialP/16 && p<NTL_SP_BOUND && !(ProbPrime(p) && !inChain(p))); if (p<=initialP/16 || p>=NTL_SP_BOUND) return 0; // no prime found long i = moduli.size(); // The index of the new prime in the list moduli.push_back( Cmodulus(zMStar, p, 0) ); if (special) specialPrimes.insert(i); else ctxtPrimes.insert(i); return p; }
void genparams( ZZ &p, ZZ &q, ZZ &a) { long err = 80; GenPrime(q, N, err); ZZ m; RandomLen(m, L-N); cout << "\nGenerating p, q and a...\n"; long NumTrials = 20; for (long i = 0; i < 10000; i++, m++) { p = q * m + 1; if (ProbPrime(p, NumTrials)) { // cout << "\ni = " << i << endl; // cout << "OK" << endl; break; } } ZZ d, f; // ZZ f1 = ((p-1) * InvMod(q, p)) % p; ZZ f1 = m; // = (p-1)/q for( d = 2; a == 0; d++ ) { f = PowerMod(d%p, f1%p, p); if ( f > 1 ) { a = f; // cout << a << " "; break; } } cout << "\np = \n"; show_dec_in_hex (p, L); cout << endl; cout << "\nq = \n"; show_dec_in_hex (q, N); cout << endl; cout << "\na = \n"; show_dec_in_hex (a, L); cout << endl; }
// Factoring by trial division, only works for N<2^{60}. // Only the primes are recorded, not their multiplicity template<class zz> static void factorT(vector<zz> &factors, const zz &N) { factors.resize(0); // reset the factors if (N<2) return; // sanity check PrimeSeq s; zz n = N; while (true) { if (ProbPrime(n)) { // we are left with just a single prime factors.push_back(n); return; } // if n is a composite, check if the next prime divides it long p = s.next(); if ((n%p)==0) { zz pp; conv(pp,p); factors.push_back(pp); do { n /= p; } while ((n%p)==0); } if (n==1) return; } }
// Генерация параметров ЭК // Порядок ЭК 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; }
PAlgebra::PAlgebra(unsigned long mm, unsigned long pp, const vector<long>& _gens, const vector<long>& _ords ) { assert( ProbPrime(pp) ); assert( (mm % pp) != 0 ); assert( mm < NTL_SP_BOUND ); assert( mm > 1 ); cM = 1.0; // default value for the ring constant m = mm; p = pp; long k = NextPowerOfTwo(m); if (mm == (1UL << k)) pow2 = k; else pow2 = 0; // For dry-run, use a tiny m value for the PAlgebra tables if (isDryRun()) mm = (p==3)? 4 : 3; // Compute the generators for (Z/mZ)^* (defined in NumbTh.cpp) if (_gens.size() == 0 || isDryRun()) ordP = findGenerators(this->gens, this->ords, mm, pp); else { assert(_gens.size() == _ords.size()); gens = _gens; ords = _ords; ordP = multOrd(pp, mm); } nSlots = qGrpOrd(); phiM = ordP * nSlots; // Allocate space for the various arrays T.resize(nSlots); dLogT.resize(nSlots*gens.size()); Tidx.assign(mm,-1); // allocate m slots, initialize them to -1 zmsIdx.assign(mm,-1); // allocate m slots, initialize them to -1 long i, idx; for (i=idx=0; i<(long)mm; i++) if (GCD(i,mm)==1) zmsIdx[i] = idx++; // Now fill the Tidx and dLogT translation tables. We identify an element // t\in T with its representation t = \prod_{i=0}^n gi^{ei} mod m (where // the gi's are the generators in gens[]) , represent t by the vector of // exponents *in reverse order* (en,...,e1,e0), and order these vectors // in lexicographic order. // FIXME: is the comment above about reverse order true? It doesn't // seem like it to me. VJS. // buffer is initialized to all-zero, which represents 1=\prod_i gi^0 vector<unsigned long> buffer(gens.size()); // temporaty holds exponents i = idx = 0; long ctr = 0; do { ctr++; unsigned long t = exponentiate(buffer); for (unsigned long j=0; j<buffer.size(); j++) dLogT[idx++] = buffer[j]; assert(GCD(t,mm) == 1); // sanity check for user-supplied gens assert(Tidx[t] == -1); T[i] = t; // The i'th element in T it t Tidx[t] = i++; // the index of t in T is i // increment buffer by one (in lexigoraphic order) } while (nextExpVector(buffer)); // until we cover all the group assert(ctr == long(nSlots)); // sanity check for user-supplied gens PhimX = Cyclotomic(mm); // compute and store Phi_m(X) // initialize prods array long ndims = gens.size(); prods.resize(ndims+1); prods[ndims] = 1; for (long j = ndims-1; j >= 0; j--) { prods[j] = OrderOf(j) * prods[j+1]; } // pp_factorize(mFactors,mm); // prime-power factorization from NumbTh.cpp }
long IsFFTPrime(long n, long& w) { long m, x, y, z; long j, k; if (n <= 1 || n >= NTL_SP_BOUND) return 0; if (n % 2 == 0) return 0; if (n % 3 == 0) return 0; if (n % 5 == 0) return 0; if (n % 7 == 0) return 0; m = n - 1; k = 0; while ((m & 1) == 0) { m = m >> 1; k++; } for (;;) { x = RandomBnd(n); if (x == 0) continue; z = PowerMod(x, m, n); if (z == 1) continue; x = z; j = 0; do { y = z; z = MulMod(y, y, n); j++; } while (j != k && z != 1); if (z != 1 || y != n-1) return 0; if (j == k) break; } /* x^{2^k} = 1 mod n, x^{2^{k-1}} = -1 mod n */ long TrialBound; TrialBound = m >> k; if (TrialBound > 0) { if (!ProbPrime(n, 5)) return 0; /* we have to do trial division by special numbers */ TrialBound = SqrRoot(TrialBound); long a, b; for (a = 1; a <= TrialBound; a++) { b = (a << k) + 1; if (n % b == 0) return 0; } } /* n is an FFT prime */ for (j = NTL_FFTMaxRoot; j < k; j++) x = MulMod(x, x, n); w = x; return 1; }
// Generate the representation of Z_m^* for a given odd integer m // and plaintext base p PAlgebra::PAlgebra(unsigned long mm, unsigned long pp) { m = mm; p = pp; assert( (m&1) == 1 ); assert( ProbPrime(p) ); // replaced by Mahdi after a conversation with Shai // assert( m > p && (m % p) != 0 ); // original line assert( (m % p) != 0 ); // end of replace by Mahdi assert( m < NTL_SP_BOUND ); // Compute the generators for (Z/mZ)^* vector<unsigned long> classes(m); vector<long> orders(m); unsigned long i; for (i=0; i<m; i++) { // initially each element in its own class if (GCD(i,m)!=1) classes[i] = 0; // i is not in (Z/mZ)^* else classes[i] = i; } // Start building a representation of (Z/mZ)^*, first use the generator p conjClasses(classes,p,m); // merge classes that have a factor of 2 // The order of p is the size of the equivalence class of 1 ordP = (unsigned long) count (classes.begin(), classes.end(), 1); // Compute orders in (Z/mZ)^*/<p> while comparing to (Z/mZ)^* long idx, largest; while (true) { compOrder(orders,classes,true,m); idx = argmax(orders); // find the element with largest order largest = orders[idx]; if (largest <= 0) break; // stop comparing to order in (Z/mZ)^* // store generator with same order as in (Z/mZ)^* gens.push_back(idx); ords.push_back(largest); conjClasses(classes,idx,m); // merge classes that have a factor of idx } // Compute orders in (Z/mZ)^*/<p> without comparing to (Z/mZ)^* while (true) { compOrder(orders,classes,false,m); idx = argmax(orders); // find the element with largest order largest = orders[idx]; if (largest <= 0) break; // we have the trivial group, we are done // store generator with different order than (Z/mZ)^* gens.push_back(idx); ords.push_back(-largest); // store with negative sign conjClasses(classes,idx,m); // merge classes that have a factor of idx } nSlots = qGrpOrd(); phiM = ordP * nSlots; // Allocate space for the various arrays T.resize(nSlots); dLogT.resize(nSlots*gens.size()); Tidx.assign(m,-1); // allocate m slots, initialize them to -1 zmsIdx.assign(m,-1); // allocate m slots, initialize them to -1 for (i=idx=0; i<m; i++) if (GCD(i,m)==1) zmsIdx[i] = idx++; // Now fill the Tidx and dLogT translation tables. We identify an element // t\in T with its representation t = \prod_{i=0}^n gi^{ei} mod m (where // the gi's are the generators in gens[]) , represent t by the vector of // exponents *in reverse order* (en,...,e1,e0), and order these vectors // in lexicographic order. // buffer is initialized to all-zero, which represents 1=\prod_i gi^0 vector<unsigned long> buffer(gens.size()); // temporaty holds exponents i = idx = 0; do { unsigned long t = exponentiate(buffer); for (unsigned long j=0; j<buffer.size(); j++) dLogT[idx++] = buffer[j]; T[i] = t; // The i'th element in T it t Tidx[t] = i++; // the index of t in T is i // increment buffer by one (in lexigoraphic order) } while (nextExpVector(buffer)); // until we cover all the group PhimX = Cyclotomic(m); // compute and store Phi_m(X) // initialize prods array long ndims = gens.size(); prods.resize(ndims+1); prods[ndims] = 1; for (long j = ndims-1; j >= 0; j--) { prods[j] = OrderOf(j) * prods[j+1]; } }
void main() { R = SqrRoot(m); int cnt = 0; for (long i = 1; m / i > R; ++i) basis[++cnt] = m / i; for (int i = R; i; --i) basis[++cnt] = i; // for (int i = 1; i <= cnt; ++i) { // if (get_index(basis[i]) != i) // print("!!! {} {}\n", get_index(basis[i]), i); // } for (int i = 1; i <= cnt; ++i) { num_primes[i] = basis[i] - 1; } // for (int i = 1; i < cnt; ++i) { // for (int v = basis[i + 1] + 1; v <= basis[i]; ++v) // if (v > R && ProbPrime(v)) // f[basis[i]] += 2; // } // f[1] = 1; // for (int i = cnt - 1; i; --i) { // f[basis[i]] += f[basis[i + 1]]; // // print("init {} = {}\n", basis[i], f[basis[i]]); // } // long ans = 0; // for (int i = 1; i <= m; ++i) { // ans += m / i; // } // print("bf = {}\n", ans); for (long x = 2; x <= R; ++x) { if (ProbPrime(x)) { print("current = {}\n", x); for (int i = 1; i <= cnt; ++i) { long y = basis[i]; if (x * x > y) break; auto a = num_primes[get_index(y / x)]; auto b = num_primes[get_index(x - 1)]; num_primes[i] -= a - b; } } } for (int i = 1; i <= cnt; ++i) { num_primes[i] %= MOD; // print("{} {}\n", basis[i], num_primes[i]); } for (int i = 1; i <= cnt; ++i) { f[i] = 1; // if (basis[i] >= R) { // f[i] += 2 * (num_primes[get_index(basis[i])] - num_primes[R]); // } // print("init {} {}\n", basis[i], f[i]); } for (long p = R; p; --p) { if (ProbPrime(p)) { print("current = {}\n", p); int t = p > n ? 0 : get_power(p, n); for (int e = 0; e <= 60; ++e) g[e] = (e + 1) * (t + 1) + t * (t + 1) / 2; for (int i = 1; i <= cnt; ++i) { long y = basis[i]; if (t == 0 && p * p > y) break; long v = 0; // 2 * (num_primes[get_index(y)] - num_primes[p]); for (int e = 0; y; ++e) { v += real_f(y, p) * g[e] % MOD; y /= p; } if (basis[i] >= p) v -= 2 * (num_primes[i] - num_primes[get_index(p)] + 1) % MOD; f[i] = (v + MOD) % MOD; // print("update {} = {}\n", basis[i], v); } } } print("ans = {}\n", real_f(m, 1)); }