Just for the record, this is the program that tries to decrypt with two and with one prime left.
#include "openfhe.h"
using namespace lbcrypto;
int get_number_primes(const Ciphertext<DCRTPoly>& ctxt1){
const DCRTPoly& poly = ctxt1->GetElements()[0];
return poly.GetNumOfElements();
}
int main(int argc, char* argv[]) {
int numSlots = 8;
// Step 1: Set CryptoContext
CCParams<CryptoContextCKKSRNS> parameters;
SecretKeyDist secretKeyDist = UNIFORM_TERNARY;
parameters.SetSecretKeyDist(secretKeyDist);
parameters.SetSecurityLevel(HEStd_NotSet);
parameters.SetRingDim(1 << 12);
parameters.SetNumLargeDigits(3);
parameters.SetKeySwitchTechnique(HYBRID);
ScalingTechnique rescaleTech = FLEXIBLEAUTO;
usint dcrtBits = 59;
usint firstMod = 60;
parameters.SetScalingModSize(dcrtBits);
parameters.SetScalingTechnique(rescaleTech);
parameters.SetFirstModSize(firstMod);
parameters.SetBatchSize(numSlots); // fix the number of slots for all plaintexts
std::cout << "Parameters " << parameters << std::endl << std::endl;
int depth = 5;
parameters.SetMultiplicativeDepth(depth);
// Generate crypto context.
CryptoContext<DCRTPoly> cryptoContext = GenCryptoContext(parameters);
// Enable features that you wish to use. Note, we must enable FHE to use bootstrapping.
cryptoContext->Enable(PKE);
cryptoContext->Enable(KEYSWITCH);
cryptoContext->Enable(LEVELEDSHE);
cryptoContext->Enable(ADVANCEDSHE);
usint ringDim = cryptoContext->GetRingDimension();
std::cout << "CKKS scheme is using ring dimension " << ringDim << std::endl << std::endl;
auto keyPair = cryptoContext->KeyGen();
cryptoContext->EvalMultKeyGen(keyPair.secretKey);
// Step 4: Encoding and encryption of inputs
// Generate random input
std::vector<double> x1;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(0.0, 1.0);
for (size_t i = 0; i < numSlots; i++)
x1.push_back(dis(gen));
Plaintext ptxt1 = cryptoContext->MakeCKKSPackedPlaintext(x1);
ptxt1->SetLength(numSlots);
std::cout << "Input 1: " << ptxt1 << std::endl;
// Encrypt the encoded vector
Ciphertext<DCRTPoly> ctxt1 = cryptoContext->Encrypt(keyPair.publicKey, ptxt1);
std::cout << "Initial level ctxt1: " << ctxt1->GetLevel() << std::endl;
std::cout << "depth: " << depth << std::endl;
std::cout << "Number of primes in the moduli chain of ctxt1: " << get_number_primes(ctxt1) << std::endl;
Ciphertext<DCRTPoly> cMul = cryptoContext->EvalMult(ctxt1, ctxt1);
std::cout << "Number of primes in the moduli chain of cMul: " << get_number_primes(ctxt1) << std::endl << std::endl;
while (get_number_primes(cMul) > 2)
cMul = cryptoContext->EvalMult(cMul, ctxt1);
std::cout << "Decrypting cMul while it has " << get_number_primes(cMul) << " primes in the moduli chain" << std::endl;
Plaintext result;
cryptoContext->Decrypt(keyPair.secretKey, cMul, &result);
result->SetLength(numSlots);
std::cout << "Decrypted result: " << result << std::endl << std::endl;
cMul = cryptoContext->EvalMult(cMul, ctxt1); // this should drop one of the two remaining primes
if (1 == get_number_primes(cMul)){
std::cout << "Decrypting cMul while it has only 1 prime in the moduli chain" << std::endl;
cryptoContext->Decrypt(keyPair.secretKey, cMul, &result);
result->SetLength(numSlots);
std::cout << "Decrypted result: " << result << std::endl;
}
return 0;
}
And this the ouput I get
Parameters scheme: CKKSRNS; ptModulus: 0; digitSize: 0; standardDeviation: 3.19; secretKeyDist: UNIFORM_TERNARY; maxRelinSkDeg: 2; ksTech: HYBRID; scalTech: FLEXIBLEAUTO; batchSize: 8; firstModSize: 60; numLargeDigits: 3; multiplicativeDepth:1; scalingModSize: 59; securityLevel: HEStd_NotSet; ringDim: 4096; evalAddCount: 0; keySwitchCount: 0; encryptionTechnique: STANDARD; multiplicationTechnique: HPS; PRENumHops: 0; PREMode: INDCPA; multipartyMode: FIXED_NOISE_MULTIPARTY; executionMode: EXEC_EVALUATION; decryptionNoiseMode: FIXED_NOISE_DECRYPT; noiseEstimate: 0; desiredPrecision: 25; statisticalSecurity: 30; numAdversarialQueries: 1; thresholdNumOfParties: 1; interactiveBootCompressionLevel: SLACK
CKKS scheme is using ring dimension 4096
Input 1: (0.937898, 0.798491, 0.889802, 0.0889563, 0.0410105, 0.435597, 0.0616124, 0.207677, … ); Estimated precision: 59 bits
Initial level ctxt1: 0
depth: 5
Number of primes in the moduli chain of ctxt1: 6
Number of primes in the moduli chain of cMul: 6Decrypting cMul while it has 2 primes in the moduli chain
Decrypted result: (0.680667, 0.259191, 0.496319, 4.95521e-07, 4.75742e-09, 0.0068314, 5.47028e-08, 8.02298e-05, … ); Estimated precision: 49 bitsDecrypting cMul while it has only 1 prime in the moduli chain
terminate called after throwing an instance of ‘lbcrypto::OpenFHEException’
what(): /home/hilder/Documents/gitRepos/openfhe-src/src/pke/lib/encoding/ckkspackedencoding.cpp:l.537:Decode(): The decryption failed because the approximation error is too high. Check the parameters.
Aborted (core dumped)