[CKKS] Extreme precision drop of 62-bits during original/initial encryption of plaintext (original data)

Hi all,

I am new to FHE and want to use it for one of my deep-learning projects. CKKS is currently the dominant scheme for deep-learning so I went ahead with that. I am facing severe precision drop in the data during the first encryption stage itself.

I have handled the bootstrap precision drop using NATIVE_SIZE=128 and Iterative Bootstrapping. Also, I will ensure that my input to bootstrap is within (-1, 1). But, what can I do to mitigate this large precision drop in the encryption of original data?

I am sharing the basic code below (used to get the above present screenshot).

#include <openfhe.h>
#include <vector>

using namespace lbcrypto;

int main() {

    // Creating dummy input
    std::vector<double> x{-8, -13, -2, -12, -11, -11};
    size_t encodedLength = x.size();

    CCParams<CryptoContextCKKSRNS> parameters;    
    
    parameters.SetSecurityLevel(HEStd_128_classic);
    parameters.SetSecretKeyDist(UNIFORM_TERNARY);  
    parameters.SetScalingModSize(120);
    parameters.SetScalingTechnique(FIXEDAUTO);
    parameters.SetFirstModSize(121);
    parameters.SetMultiplicativeDepth(26);
    auto cc = GenCryptoContext(parameters);
    cc->Enable(PKE);
    cc->Enable(KEYSWITCH);
    cc->Enable(LEVELEDSHE);

    // We need to enable Advanced SHE to use the Chebyshev approximation.
    cc->Enable(ADVANCEDSHE);

    // Enable features that you wish to use. Note, we must enable FHE to use bootstrapping.
    cc->Enable(FHE); 

    auto ringDim = cc->GetRingDimension();
    auto numSlots = ringDim/2;
    
    // Creating keys
    auto keyPair = cc->KeyGen();
    
    // Encoding
    Plaintext plaintext = cc->MakeCKKSPackedPlaintext(x, 1, 0, nullptr, numSlots);
    plaintext->SetLength(encodedLength);
    std::cout << "Initial PlainText: " << plaintext << std::endl;
    
    // Encrypting
    auto ciphertext = cc->Encrypt(keyPair.publicKey, plaintext);

    // Decrypting
    Plaintext plaintextDec;
    cc->Decrypt(keyPair.secretKey, ciphertext, &plaintextDec);
    plaintextDec->SetLength(encodedLength);

    std::cout << "Checking original cipher: " << plaintextDec << std::endl;

    return 0;
}

I have set both FirstModSize and ScalingModSize to maximum possible values to ensure high noise budget and high precision threshold. Also, I tried both the SecretKeyDist modes - UNIFORM_TERNARY & SPARSE_TERNARY but, there was no difference.

Is this expected? If not what can be done to overcome this? Precision drop of ~68 bit is huge. I was expecting somewhere between 5-10 bits.

Thanks!

Internally, we use double-precising floating numbers when encoding/decoding CKKS plaintexts. Hence, the precision is limited by 52 bits because of this. The high-level idea of large-precision CKKS (for NATIVE_SIZE=128) is to support double-precision floating-point arithmetic using CKKS + also provide support for IND-CPA^D security. We do not currently support larger floating-point precision (this is a limitation of encoding/decoding rather than the underlying CKKS implementation).

1 Like