long PAlgebra::addCoord(long i, long k, long offset) const { if (isDryRun()) return 0; assert(k >= 0 && k < (long) nSlots); assert(i >= 0 && i < (long) gens.size()); offset = offset % ((long) OrderOf(i)); if (offset < 0) offset += OrderOf(i); long k_i = coordinate(i, k); long k_i1 = (k_i + offset) % OrderOf(i); long k1 = k + (k_i1 - k_i) * prods[i+1]; return k1; }
void Reorder(void) { intish i; intish j; int min; struct entry* e; int o1, o2; for (i = 0; i < nidents-1; i++) { min = i; for (j = i+1; j < nidents; j++) { o1 = OrderOf(identtable[ j ]->name); o2 = OrderOf(identtable[ min ]->name); if (o1 < o2 ) min = j; } e = identtable[ min ]; identtable[ min ] = identtable[ i ]; identtable[ i ] = e; } }
bool PAlgebra::nextExpVector(vector<unsigned long>& buffer) const { // increment the vector in lexicographic order if (!isDryRun()) for (long i=gens.size()-1; i>=0; i--) { if (i>=(long)buffer.size()) continue; // sanity check // increment current index, set all the ones after it to zero if (buffer[i] < OrderOf(i)-1) { buffer[i]++; for (unsigned long j=i+1; j<buffer.size(); j++) buffer[j] = 0; return true; // succeeded in incrementing the vector } // if buffer[i] >= OrderOf(i)-1, mover to previous index i } return false; // cannot increment the vector anymore }
void PAlgebra::printout() const { unsigned long i; cout << "m = " << m << ", p = " << p << ", phi(m) = " << phiM << endl; cout << " ord(p)=" << ordP << endl; for (i=0; i<gens.size(); i++) if (gens[i]) { cout << " generator " << gens[i] << " has order (" << (SameOrd(i)? "=":"!") << "= Z_m^*) of " << OrderOf(i) << endl; } if (qGrpOrd()<100) { cout << " T = ["; for (i=0; i<T.size(); i++) cout << T[i] << " "; cout << "]\n"; } }
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 }
// 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]; } }