Calculating Security Level and logq in OpenFHE

Hi all,

I’m working on a CKKS application in OpenFHE and trying to determine the appropriate security level, but I’m a bit unsure about how to calculate it properly. I’ve been referring to the Homomorphic Encryption Standard v1.1

From my understanding, logq is related to the multiplicative depth and the scaling factor. For example, in my current setup, I have the following crypto parameters:

parameters.SetRingDim(1 << 15);
parameters.SetBatchSize(1 << 14);
parameters.SetScalingModSize(50);
parameters.SetFirstModSize(54);
parameters.SetNumLargeDigits(4);
parameters.SetMultiplicativeDepth(27);

If I try to compute logq as 54 + (27 * 50), I get 1404 but the documentation says logq = 881 However, I’m unsure if this is the correct way to calculate it and how to estimate the security in this case.

I also want to achieve a security level of 128 bits. Based on the tables in the standard and my calculations, with a ring dimension of 1 << 15, the scaling modulus size should be around 32 to meet 128-bit security. But if I use 32 as my scaling modulus, my computations fail.

My main goal is to balance performance, accuracy, and security, but I’m not sure how to pick the right values or scaling modulus to achieve this.

What you refer to as \log q is related to the scaling factor, multiplicative depth (number of RNS limbs), and the number of large digits. So for security, you should consider \log(PQ), where P is the auxiliary modulus and Q is your main CKKS modulus (see https://eprint.iacr.org/2024/463.pdf). This can be displayed using the code below. With your parameters, I get a total modulus larger than 1800 bits, meaning that the minimum ring dimension for 128 bits of security is N = 2^{17}.

The recommended solution is to let the library choose the parameters (ring dimension) for you by using parameters.SetSecurityLevel(HEStd_128_classic);, once you have defined the requirements for your application in terms of precision (scaling) and multiplicative depth. You can also consider the use of bootstrapping.

To optimize runtime, you can use OpenMP for parallelization, carefully design your circuit and look at building OpenFHE for best performance.

#include "openfhe.h"

using namespace lbcrypto;

double getlogPQ(const DCRTPoly& poly) {
    int n = poly.GetNumOfElements();
    double logPQ = 0;
    for (int i = 0; i < n; i++) {
        auto qi = poly.GetParams()->GetParams()[i]->GetModulus(); std::cout << log(qi.ConvertToDouble()) / log(2) << std::endl;
        logPQ += log(qi.ConvertToDouble()) / log(2);
    }
    
    return logPQ;
}

int main() {
    CCParams<CryptoContextCKKSRNS> parameters;
    parameters.SetRingDim(1 << 15);
    parameters.SetBatchSize(1 << 14);
    parameters.SetScalingModSize(50);
    parameters.SetFirstModSize(54);
    parameters.SetNumLargeDigits(4);
    parameters.SetMultiplicativeDepth(27);
    parameters.SetSecurityLevel(HEStd_128_classic);

    CryptoContext<DCRTPoly> cryptoContext = GenCryptoContext(parameters);

    cryptoContext->Enable(PKE);
    cryptoContext->Enable(KEYSWITCH);
    cryptoContext->Enable(LEVELEDSHE);
    cryptoContext->Enable(ADVANCEDSHE);

    auto keyPair = cryptoContext->KeyGen();
    cryptoContext->EvalMultKeyGen(keyPair.secretKey);

    double logPQ = getlogPQ(keyPair.publicKey->GetPublicElements()[0]);

    std::cout << "log PQ = " << logPQ << std::endl << std::endl;
}

Thank you for your response. This was very helpful.

How can I determine the security level (bits) of my crypto context??? At the very least, just to know the security level of my application.

I do not want to drastically increase the ringDim of my application because that will increase the run time. OpenMP will help but it is independent of OpenFHE optimization.

Regarding the first part of your answer, one common way to estimate the hardness is to use the lattice estimator (see the associated paper). Note that LWE/RLWE hardness analysis is very complex, so it is best to use the recommended parameters, as I already mentioned.

For the second part, I understand that you do not want to increase the ring dimension, as it has a heavy effect on latency. Nevertheless, there is always a tradeoff between security, performance, and complexity.
As your application needs a lot of multiplicative depth and modulus (complex circuit), you have to increase the ring dimension for security, which negatively impacts performance. You could try to reduce your ciphertext modulus by either changing your circuit, using bootstrapping, or using other techniques (like composite scaling).