// Add/subtract another ciphertxt (depending on the negative flag) void Ctxt::addCtxt(const Ctxt& other, bool negative) { FHE_TIMER_START; // Sanity check: same context and public key assert (&context==&other.context && &pubKey==&other.pubKey); // Special case: if *this is empty then just copy other if (this->isEmpty()) { *this = other; if (negative) negate(); return; } // Sanity check: verify that the plaintext spaces are compatible long g = GCD(this->ptxtSpace, other.ptxtSpace); assert (g>1); this->ptxtSpace = g; // Match the prime-sets, mod-UP the arguments if needed IndexSet s = other.primeSet / primeSet; // set-minus if (!empty(s)) modUpToSet(s); const Ctxt* other_pt = &other; Ctxt tmp(pubKey, other.ptxtSpace); // a temporaty empty ciphertext s = primeSet / other.primeSet; // set-minus if (!empty(s)) { // need to mod-UP the other, use a temporary copy tmp = other; tmp.modUpToSet(s); other_pt = &tmp; } // Go over the parts of other, for each one check if // there is a matching part in *this for (size_t i=0; i<other_pt->parts.size(); i++) { const CtxtPart& part = other_pt->parts[i]; long j = getPartIndexByHandle(part.skHandle); if (j>=0) { // found a matching part, add them up if (negative) parts[j] -= part; else parts[j] += part; } else { // no mathing part found, just append this part parts.push_back(part); if (negative) parts.back().Negate(); // not thread safe?? } } noiseVar += other_pt->noiseVar; FHE_TIMER_STOP; }
// Modulus-switching down void Ctxt::modDownToLevel(long lvl) { long currentLvl; IndexSet targetSet; IndexSet currentSet = primeSet & context.ctxtPrimes; if (context.containsSmallPrime()) { currentLvl = 2*card(currentSet); if (currentSet.contains(0)) currentLvl--; // first prime is half the size if (lvl & 1) { // odd level, includes the half-size prime targetSet = IndexSet(0,(lvl-1)/2); } else { targetSet = IndexSet(1,lvl/2); } } else { currentLvl = card(currentSet); targetSet = IndexSet(0,lvl-1); // one prime per level } // If target is not below the current level, nothing to do if (lvl >= currentLvl && currentSet==primeSet) return; if (lvl >= currentLvl) { // just remove the special primes targetSet = currentSet; } // sanity-check: interval does not contain special primes assert(targetSet.disjointFrom(context.specialPrimes)); // may need to mod-UP to include the smallest prime if (targetSet.contains(0) && !currentSet.contains(0)) modUpToSet(targetSet); // adds the primes in targetSet / primeSet modDownToSet(targetSet); // removes the primes in primeSet / targetSet }