// Apply F(X)->F(X^k) followed by re-liearization. The automorphism is possibly // evaluated via a sequence of steps, to ensure that we can re-linearize the // result of every step. void Ctxt::smartAutomorph(long k) { FHE_TIMER_START; // Special case: if *this is empty then do nothing if (this->isEmpty()) return; long m = context.zMStar.getM(); k = mcMod(k, m); // Sanity check: verify that k \in Zm* assert (context.zMStar.inZmStar(k)); long keyID=getKeyID(); if (!inCanonicalForm(keyID)) { // Re-linearize the input, if needed reLinearize(keyID); assert (inCanonicalForm(keyID)); // ensure that re-linearization succeeded } assert (pubKey.isReachable(k,keyID)); // reachable from 1 while (k != 1) { const KeySwitch& matrix = pubKey.getNextKSWmatrix(k,keyID); long amt = matrix.fromKey.getPowerOfX(); automorph(amt); reLinearize(keyID); k = MulMod(k, InvMod(amt,m), m); } FHE_TIMER_STOP; }
void Ctxt::multiplyBy2(const Ctxt& other1, const Ctxt& other2) { // Special case: if *this is empty then do nothing if (this->isEmpty()) return; long lvl = findBaseLevel(); long lvl1 = other1.findBaseLevel(); long lvl2 = other2.findBaseLevel(); if (lvl<lvl1 && lvl<lvl2){ // if both others at higher levels than this, Ctxt tmp = other1; // multiply others by each other, then by this if (&other1 == &other2) tmp *= tmp; // squaring rather than multiplication else tmp *= other2; *this *= tmp; } else if (lvl<lvl2) { // lvl1<=lvl<lvl2, multiply by other2, then by other1 *this *= other2; *this *= other1; } else { // multiply first by other1, then by other2 *this *= other1; *this *= other2; } reLinearize(); // re-linearize after all the multiplications }
void Ctxt::multiplyBy(const Ctxt& other) { // Special case: if *this is empty then do nothing if (this->isEmpty()) return; *this *= other; // perform the multiplication reLinearize(); // re-linearize }
void Ctxt::cleanUp() { reLinearize(); reduce(); if (!primeSet.disjointFrom(context.specialPrimes)) { modDownToSet(primeSet / context.specialPrimes); } }
// Apply F(X)->F(X^k) followed by re-liearization. The automorphism is possibly // evaluated via a sequence of steps, to ensure that we can re-linearize the // result of every step. void Ctxt::smartAutomorph(long k) { FHE_TIMER_START; // A hack: record this automorphism rather than actually performing it if (isSetAutomorphVals()) { // defined in NumbTh.h recordAutomorphVal(k); return; } // Special case: if *this is empty then do nothing if (this->isEmpty()) return; // Sanity check: verify that k \in Zm* long m = context.zMStar.getM(); k = mcMod(k, m); assert (context.zMStar.inZmStar(k)); long keyID=getKeyID(); if (!pubKey.isReachable(k,keyID)) {// must have key-switching matrices for it throw std::logic_error("no key-switching matrices for k="+std::to_string(k) + ", keyID="+std::to_string(keyID)); } if (!inCanonicalForm(keyID)) { // Re-linearize the input, if needed reLinearize(keyID); assert (inCanonicalForm(keyID)); // ensure that re-linearization succeeded } while (k != 1) { const KeySwitch& matrix = pubKey.getNextKSWmatrix(k,keyID); long amt = matrix.fromKey.getPowerOfX(); // A hack: record this automorphism rather than actually performing it if (isSetAutomorphVals2()) { // defined in NumbTh.h recordAutomorphVal2(amt); return; } //cerr << "********* automorph " << amt << "\n"; automorph(amt); reLinearize(keyID); k = MulMod(k, InvMod(amt,m), m); } FHE_TIMER_STOP; }
void Ctxt::multiplyBy2(const Ctxt& other1, const Ctxt& other2) { FHE_TIMER_START; // Special case: if *this is empty then do nothing if (this->isEmpty()) return; long lvl = findBaseLevel(); long lvl1 = other1.findBaseLevel(); long lvl2 = other2.findBaseLevel(); if (lvl<lvl1 && lvl<lvl2){ // if both others at higher levels than this, Ctxt tmp = other1; // multiply others by each other, then by this if (&other1 == &other2) tmp *= tmp; // squaring rather than multiplication else tmp *= other2; *this *= tmp; reLinearize(); // re-linearize after all the multiplications return; } const Ctxt *first, *second; if (lvl<lvl2) { // lvl1<=lvl<lvl2, multiply by other2, then by other1 first = &other2; second = &other1; } else { // multiply first by other1, then by other2 first = &other1; second = &other2; } if (this == second) { // handle pointer collision Ctxt tmp = *second; *this *= *first; *this *= tmp; if (this == first) // cubing operation noiseVar *= 3; // a correction factor due to dependency else noiseVar *= 2; // a correction factor due to dependency } else { *this *= *first; *this *= *second; } reLinearize(); // re-linearize after all the multiplications }