BGV correctness guarantees

Hi,

Why the output of my program is different from the expected output?

    parameters.SetMultiplicativeDepth(3);
    parameters.SetEvalAddCount(45);
    parameters.SetPlaintextModulus(536903681);
    parameters.SetMaxRelinSkDeg(4);

    std::vector<int64_t> vectorOfInts1 = {0};
    Plaintext plaintext1               = cryptoContext->MakePackedPlaintext(vectorOfInts1);

    std::vector<int64_t> vectorOfInts2 = {0};
    Plaintext plaintext2               = cryptoContext->MakePackedPlaintext(vectorOfInts2);

Ciphertext<DCRTPoly> ciphertext1;
    Ciphertext<DCRTPoly> ciphertext2;
    ciphertext1 = cryptoContext->Encrypt(keyPair.publicKey, plaintext1);
      ciphertext2 = cryptoContext->Encrypt(keyPair.publicKey, plaintext2);
    Plaintext plaintextDecMult;
    ciphertext1 = cryptoContext->EvalMult(ciphertext1, ciphertext2);
    cryptoContext->ModReduceInPlace(ciphertext1);
    ciphertext1 = cryptoContext->EvalMult(ciphertext1, ciphertext2);
    cryptoContext->ModReduceInPlace(ciphertext1);
    ciphertext1 = cryptoContext->EvalMult(ciphertext1, ciphertext2);

    //cryptoContext->ModReduceInPlace(ciphertext1);                                                                                                                                                   
    cryptoContext->RelinearizeInPlace(ciphertext1);
    cryptoContext->Decrypt(keyPair.secretKey, ciphertext1, &plaintextDecMult);
    plaintextDecMult->SetLength(plaintext1->GetLength());
    std::cout << "\nResult of 3 homomorphic multiplications: \n";
    std::cout << plaintextDecMult << std::endl;

    for(int i=0; i<=20; i++){
    ciphertext1 = cryptoContext->EvalAdd(ciphertext1,ciphertext1);
    }

    cryptoContext->Decrypt(keyPair.secretKey, ciphertext1, &plaintextDecMult);
    plaintextDecMult->SetLength(plaintext1->GetLength());
    std::cout << "\n After adding 0 vector 20 times to the result of multiplication: " << std::endl;
    std::cout << plaintextDecMult << std::endl;

Output is:

Result of 3 homomorphic multiplications: 
( 0 ... )

 After adding 0 vector 20 times to the result of multiplication: 
( -94411888 ... )

Expected output was ( 0 ... )

Do I need to set EvalAddCount to 2^20?

Briefly, the circuit specification currently done in OpenFHE only allows circuits with independent inputs. So if you set SetEvalAddCount(45) this generates parameters for adding encryptions x + x + ... + x for 45 times. If you want to add the same ciphertext over again, like you do, you either need to increase the SetEvalAddCount to 2^{20} (this corresponds to the true number of additions that happen in the recursive addition you are doing) or you need to increase the SetMultiplicativeDepth by 1 which would generate sufficiently large parameters to allow for 2^{20}\cdot Enc(x).

We are investigating ways to provide in OpenFHE a more granular description of the circuits to be evaluated. But please see https://eprint.iacr.org/2024/203.pdf for a detailed discussion, targeting the example you are running.