Cannot using HEStd_128_classic crashes my terminal

Hello,

I’m trying to run the following simple program in CKKS, it’s similar to the code in advanced-ckks-bootstrapping.cpp. I’m using WSL on Windows and the program compiles. But when I run it, it prints “CKKS scheme is using ring dimension 131072”, then the program crashes, printing “killed”. I tried to change the values of levelsBudget and levelsAvailableAfterBootstrap, but the program causes the terminal to crash and terminates!

Thanks in advance



#include "openfhe.h"

#include <assert.h>

using namespace lbcrypto;
using namespace std;

void test_additions(int num_additions) {
    CCParams<CryptoContextCKKSRNS> parameters;
    SecretKeyDist secretKeyDist = UNIFORM_TERNARY;
    parameters.SetSecretKeyDist(secretKeyDist);

    parameters.SetSecurityLevel(HEStd_128_classic);

#if NATIVEINT == 128
    ScalingTechnique rescaleTech = FIXEDAUTO;
    usint dcrtBits               = 78;
    usint firstMod               = 89;
#else
    ScalingTechnique rescaleTech = FLEXIBLEAUTO;
    usint dcrtBits               = 59;
    usint firstMod               = 60;
#endif

    parameters.SetScalingModSize(dcrtBits);
    parameters.SetScalingTechnique(rescaleTech);
    parameters.SetFirstModSize(firstMod);

    std::vector<uint32_t> levelBudget = {4, 4};

    uint32_t levelsAvailableAfterBootstrap = 10;
    usint depth = levelsAvailableAfterBootstrap + FHECKKSRNS::GetBootstrapDepth(levelBudget, secretKeyDist);
    parameters.SetMultiplicativeDepth(depth);
    cout << depth << endl;

    CryptoContext<DCRTPoly> cryptoContext = GenCryptoContext(parameters);

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

    usint ringDim = cryptoContext->GetRingDimension();
    // This is the maximum number of slots that can be used for full packing.
    usint numSlots = ringDim / 2;
    cout << "CKKS scheme is using ring dimension " << ringDim << endl << endl;

    cryptoContext->EvalBootstrapSetup(levelBudget);

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

    vector<double> x1 = {0.25, 0.5, 0.75, 1.0, 2.0, 3.0, 4.0, 5.0};
    vector<double> y1 = {0.25, 0.5, 0.75, 1.0, 2.0, 3.0, 4.0, 5.0};
    vector<double> x2 = {0.25, 0.5, 0.75, 1.0, 2.0, 3.0, 4.0, 5.0};
    vector<double> y2 = {0.25, 0.5, 0.75, 1.0, 2.0, 3.0, 4.0, 5.0};

    size_t encodedLength = x1.size();

    cout << "1" << endl;
    // We start with a depleted ciphertext that has used up all of its levels.
    Plaintext ptxt1 = cryptoContext->MakeCKKSPackedPlaintext(x1,1, 0, nullptr, numSlots);
    Plaintext ptxt2 = cryptoContext->MakeCKKSPackedPlaintext(y1,1, 0, nullptr, numSlots);

    Plaintext ptxt3 = cryptoContext->MakeCKKSPackedPlaintext(x2,1, 0, nullptr, numSlots);
    Plaintext ptxt4 = cryptoContext->MakeCKKSPackedPlaintext(y2,1, 0, nullptr, numSlots);


    ptxt1->SetLength(encodedLength);
    ptxt2->SetLength(encodedLength);
    cout << "Input 1: " << ptxt1 << endl;
    cout << "Input 2: " << ptxt2 << endl;

    ptxt3->SetLength(encodedLength);
    ptxt4->SetLength(encodedLength);
    cout << "Input 3: " << ptxt3 << endl;
    cout << "Input 4: " << ptxt4 << endl;

    Ciphertext<DCRTPoly> ciph1 = cryptoContext->Encrypt(keyPair.publicKey, ptxt1);
    Ciphertext<DCRTPoly> ciph2 = cryptoContext->Encrypt(keyPair.publicKey, ptxt2);

    Ciphertext<DCRTPoly> ciph3 = cryptoContext->Encrypt(keyPair.publicKey, ptxt3);
    Ciphertext<DCRTPoly> ciph4 = cryptoContext->Encrypt(keyPair.publicKey, ptxt4);

    cout << "Initial number of levels remaining 1: " << depth - ciph1->GetLevel() << endl;
    cout << "Initial number of levels remaining 2: " << depth - ciph2->GetLevel() << endl;

    cout << "Initial number of levels remaining 3: " << depth - ciph3->GetLevel() << endl;
    cout << "Initial number of levels remaining 4: " << depth - ciph4->GetLevel() << endl;



    auto start = chrono::high_resolution_clock::now();
    auto res1  = cryptoContext->EvalAdd(ciph1, ciph2);
    auto res2  = cryptoContext->EvalAdd(ciph3, ciph4);
    // auto res3  = cryptoContext->EvalAdd(res1, res2);
    //
    // for (int i = 1; i < num_additions; i++) {
    //     res3 = cryptoContext->EvalAdd(res3, res3);
    // }
    auto end = chrono::high_resolution_clock::now();

    // Perform the bootstrapping operation. The goal is to increase the number of levels remaining
    // for HE computation.
    // auto ciphertextAfter = cryptoContext->EvalBootstrap(res3);
    //
    // res3 = cryptoContext->EvalAdd(ciphertextAfter, ciphertextAfter);
    // res3 = cryptoContext->EvalAdd(res3, res3);

    cout << "Number of levels remaining after bootstrapping: "
         << depth - res1->GetLevel() - (res1->GetNoiseScaleDeg() - 1) << endl
         << endl;

    cout << "Level: " << res1->GetLevel() << endl << endl;
    cout << "Noise Scale log: " << res1->GetNoiseScaleDeg() << endl << endl;
    cout << "Hop Level: " << res1->GetHopLevel() << endl << endl;
    cout << "Scaling factor: " << res1->GetScalingFactor() << endl << endl;
    cout << "Scaling factor int: " << res1->GetScalingFactorInt() << endl << endl;
    cout << "last number of levels remaining: " << depth - res1->GetLevel() << std::endl;



    Plaintext result;
    cryptoContext->Decrypt(keyPair.secretKey, res1, &result);
    result->SetLength(encodedLength);

    cout << "Duration: " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms" << endl;
    vector<double> true_res;

    for (long unsigned int j = 0; j < x1.size(); j++) {
        auto tmp1 = x1[j] + y1[j];
        auto tmp2 = x2[j] + y2[j];
        auto tmp3 = tmp1 + tmp2;
        for (int i = 1; i < num_additions; i++) {
            tmp3 = tmp3 + tmp3;
        }
        true_res.push_back(tmp3);
    }
    cout << "Output after bootstrapping \n\t" << result << endl;
    cout << "true result: " << true_res << endl;
}
int main(int argc, char* argv[]) {
    test_additions(1);
}

This is probably caused by a lack of RAM, as N = 131072 is a large ring dimension. I can run your example on a setup with 64 GB of RAM. The estimated peak memory consumption is 30.81 GB, so you’d need at least 32 GB of RAM, but probably a bit more.
You can check your available memory with the free -h command.