// break *this into n digits,according to the primeSets in context.digits void DoubleCRT::breakIntoDigits(vector<DoubleCRT>& digits, long n) const { FHE_TIMER_START; IndexSet allPrimes = getIndexSet() | context.specialPrimes; assert(n <= (long)context.digits.size()); digits.resize(n, DoubleCRT(context, IndexSet::emptySet())); if (dryRun) return; for (long i=0; i<(long)digits.size(); i++) { digits[i]=*this; IndexSet notInDigit = digits[i].getIndexSet()/context.digits[i]; digits[i].removePrimes(notInDigit); // reduce modulo the digit primes } for (long i=0; i<(long)digits.size(); i++) { IndexSet notInDigit = allPrimes / digits[i].getIndexSet(); digits[i].addPrimes(notInDigit); // add back all the primes // subtract this digits from all the others, then divide by pi ZZ pi = context.productOfPrimes(context.digits[i]); for (long j=i+1; j<(long)digits.size(); j++) { digits[j].Sub(digits[i], /*matchIndexSets=*/false); digits[j] /= pi; } } #if 0 dgts.resize(n, DoubleCRT(context, IndexSet::emptySet())); for (long i=0; i<n; i++) // copy only the primes for this digit dgts[i].partialCopy(*this, context.digits[i]); IndexSet allPrimes = getIndexSet() | context.specialPrimes; for (long i=0; i<n; i++) { IndexSet notInDigit = allPrimes / dgts[i].getIndexSet(); dgts[i].addPrimes(notInDigit); // add back all the primes // subtract this digits from all the others, then divide by pi ZZ pi = context.productOfPrimes(context.digits[i]); for (long j=i+1; j<n; j++) { dgts[j].Sub(dgts[i], /*matchIndexSets=*/false); dgts[j] /= pi; } } #endif FHE_TIMER_STOP; }
// Used in lieu of istream& operator>>(istream& str, KeySwitch& matrix) void KeySwitch::readMatrix(istream& str, const FHEcontext& context) { // cerr << "KeySwitch["; seekPastChar(str,'['); // defined in NumbTh.cpp str >> fromKey; str >> toKeyID; str >> ptxtSpace; long nDigits; str >> nDigits; b.resize(nDigits, DoubleCRT(context, IndexSet::emptySet())); for (long i=0; i<nDigits; i++) str >> b[i]; str >> prgSeed; seekPastChar(str,']'); // cerr << "]"; }
void KeySwitch::verify(FHESecKey& sk) { long fromSPower = fromKey.getPowerOfS(); long fromXPower = fromKey.getPowerOfX(); long fromIdx = fromKey.getSecretKeyID(); long toIdx = toKeyID; long p = ptxtSpace; long n = b.size(); cout << "KeySwitch::verify\n"; cout << "fromS = " << fromSPower << " fromX = " << fromXPower << " fromIdx = " << fromIdx << " toIdx = " << toIdx << " p = " << p << " n = " << n << "\n"; if (fromSPower != 1 || fromXPower != 1 || (fromIdx == toIdx) || n == 0) { cout << "KeySwitch::verify: these parameters not checkable\n"; return; } const FHEcontext& context = b[0].getContext(); // we don't store the context in the ks matrix, so let's // check that they are consistent for (long i = 0; i < n; i++) { if (&context != &(b[i].getContext())) cout << "KeySwitch::verify: bad context " << i << "\n"; } cout << "context.ctxtPrimes = " << context.ctxtPrimes << "\n"; cout << "context.specialPrimes = " << context.specialPrimes << "\n"; IndexSet allPrimes = context.ctxtPrimes | context.specialPrimes; cout << "digits: "; for (long i = 0; i < n; i++) cout << context.digits[i] << " "; cout << "\n"; cout << "IndexSets of b: "; for (long i = 0; i < n; i++) cout << b[i].getMap().getIndexSet() << " "; cout << "\n"; // VJS: suspicious shadowing of fromKey, toKey const DoubleCRT& _fromKey = sk.sKeys.at(fromIdx); const DoubleCRT& _toKey = sk.sKeys.at(toIdx); cout << "IndexSet of fromKey: " << _fromKey.getMap().getIndexSet() << "\n"; cout << "IndexSet of toKey: " << _toKey.getMap().getIndexSet() << "\n"; vector<DoubleCRT> a; a.resize(n, DoubleCRT(context, allPrimes)); // defined modulo all primes { RandomState state; SetSeed(prgSeed); for (long i = 0; i < n; i++) a[i].randomize(); } // the RandomState destructor "restores the state" (see NumbTh.h) vector<ZZX> A, B; A.resize(n); B.resize(n); for (long i = 0; i < n; i++) { a[i].toPoly(A[i]); b[i].toPoly(B[i]); } ZZX FromKey, ToKey; _fromKey.toPoly(FromKey, allPrimes); _toKey.toPoly(ToKey, allPrimes); ZZ Q = context.productOfPrimes(allPrimes); ZZ prod = context.productOfPrimes(context.specialPrimes); ZZX C, D; ZZX PhimX = context.zMStar.getPhimX(); long nb = 0; for (long i = 0; i < n; i++) { C = (B[i] - FromKey*prod + ToKey*A[i]) % PhimX; PolyRed(C, Q); if (!divide(D, C, p)) { cout << "*** not divisible by p at " << i << "\n"; } else { for (long j = 0; j <= deg(D); j++) if (NumBits(coeff(D, j)) > nb) nb = NumBits(coeff(D, j)); } prod *= context.productOfPrimes(context.digits[i]); } cout << "error ratio: " << ((double) nb)/((double) NumBits(Q)) << "\n"; }