My application of CKKS → FHEW scheme switching has a significant amount of randomness, at least with the settings I am using. For instance, a CKKS computation that decrypts to (approximately) -0.525 will mostly decrypt to -1 (technically, it will decrypt to N-1 where N is the plaintext modulus I specify for FHEW decrypt) but about 20% (!!) of the time it decrypts to 0. Is this to be expected or is it some artifact of how I am doing scheme switching?
Here is a code I was using that appears to demonstrate this:
uint32_t multDepth = 26;
uint32_t scaleModSize = 50;
SecurityLevel sl = HEStd_128_classic;
BINFHE_PARAMSET slBin = STD128;
uint32_t logQ_ccLWE = 25;
uint32_t slots = 16; // sparsely-packed
uint32_t batchSize = slots;
CCParams<CryptoContextCKKSRNS> parameters;
parameters.SetMultiplicativeDepth(multDepth);
parameters.SetScalingModSize(scaleModSize);
parameters.SetScalingTechnique(FLEXIBLEAUTOEXT);
parameters.SetSecurityLevel(sl);
parameters.SetBatchSize(batchSize);
CryptoContext<DCRTPoly> cc = GenCryptoContext(parameters);
// Enable the features that you wish to use
cc->Enable(PKE);
cc->Enable(KEYSWITCH);
cc->Enable(LEVELEDSHE);
cc->Enable(SCHEMESWITCH);
auto keys = cc->KeyGen();
SchSwchParams params;
params.SetSecurityLevelCKKS(sl);
params.SetSecurityLevelFHEW(slBin);
params.SetCtxtModSizeFHEWLargePrec(logQ_ccLWE);
params.SetNumSlotsCKKS(slots);
auto privateKeyFHEW = cc->EvalCKKStoFHEWSetup(params);
auto ccLWE = cc->GetBinCCForSchemeSwitch();
cc->EvalCKKStoFHEWKeyGen(keys, privateKeyFHEW);
auto pLWE1 = 131072;
double scale1 = 1.0 / pLWE1;
std::cout <<"pLWE1 is " << pLWE1 << std::endl;
cc->EvalCKKStoFHEWPrecompute(scale1);
std::vector<double> x1 = {0, 0.1, 0.2, 0.3, 0.4, -0.525914, 0.6, 0.7, 0.8, 0.9, 1, 2, 3, 4, 5, 6};
uint32_t encodedLength1 = x1.size();
Plaintext ptxt1 = cc->MakeCKKSPackedPlaintext(x1, 1, 0, nullptr);
auto c1 = cc->Encrypt(keys.publicKey, ptxt1);
auto cTemp = cc->EvalCKKStoFHEW(c1, encodedLength1);
std::cout << "FHEW decryption: ";
LWEPlaintext result;
for (uint32_t i = 0; i < cTemp.size(); ++i) {
ccLWE->Decrypt(privateKeyFHEW, cTemp[i], &result, pLWE1);
std::cout << result << " ";
}
std::cout << "\n" << std::endl;
Output is:
for run in {1..10}; do ./scheme-switching-simple; done
pLWE1 is 131072
FHEW decryption: 0 0 0 0 0 131071 1 1 1 1 1 2 3 4 5 6
pLWE1 is 131072
FHEW decryption: 0 0 0 0 0 131071 1 1 1 1 1 2 3 4 5 6
pLWE1 is 131072
FHEW decryption: 0 0 0 0 0 131071 1 1 1 1 1 2 3 4 5 6
pLWE1 is 131072
FHEW decryption: 0 0 0 0 0 0 1 1 1 1 1 2 3 4 5 6
pLWE1 is 131072
FHEW decryption: 0 0 0 0 0 131071 1 1 1 1 1 2 3 4 5 6
pLWE1 is 131072
FHEW decryption: 0 0 0 0 0 131071 1 1 1 1 1 2 3 4 5 6
pLWE1 is 131072
FHEW decryption: 0 0 0 0 0 0 1 1 1 1 1 2 3 4 5 6
pLWE1 is 131072
FHEW decryption: 0 0 0 0 0 0 1 1 1 1 1 2 3 4 5 6
pLWE1 is 131072
FHEW decryption: 0 0 0 0 0 131071 1 1 1 1 1 2 3 4 5 6
pLWE1 is 131072
FHEW decryption: 0 0 0 0 1 131071 1 1 1 1 1 2 3 4 5 6