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 }
Ctxt& Ctxt::operator*=(const Ctxt& other) { FHE_TIMER_START; // Special case: if *this is empty then do nothing if (this->isEmpty()) return *this; // Sanity check: plaintext spaces are compatible long g = GCD(ptxtSpace, other.ptxtSpace); assert (g>1); this->ptxtSpace = g; Ctxt tmpCtxt(this->pubKey, this->ptxtSpace); // a scratch ciphertext if (this == &other) { // a squaring operation modDownToLevel(findBaseLevel()); // mod-down if needed tmpCtxt.tensorProduct(*this, other); // compute the actual product tmpCtxt.noiseVar *= 2; // a correction factor due to dependency } else { // standard multiplication between two ciphertexts // Sanity check: same context and public key assert (&context==&other.context && &pubKey==&other.pubKey); // Match the levels, mod-DOWN the arguments if needed long lvl = findBaseLevel(); long otherLvl = other.findBaseLevel(); if (lvl > otherLvl) lvl = otherLvl; // the smallest of the two // mod-DOWN *this, if needed (also removes special primes, if any) modDownToLevel(lvl); // mod-DOWN other, if needed if (primeSet!=other.primeSet){ // use temporary copy to mod-DOWN other Ctxt tmpCtxt1 = other; tmpCtxt1.modDownToLevel(lvl); tmpCtxt.tensorProduct(*this,tmpCtxt1); // compute the actual product } else tmpCtxt.tensorProduct(*this, other); // compute the actual product } *this = tmpCtxt; // copy the result into *this FHE_TIMER_STOP; return *this; }
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 }