I hope someone can help me understand an error I get when using Palisades. I want to only use the first 329 slots of a BGV ciphertext, and zero out the rest (which at some point contains some 'rubbish' I don't want to re-enter the first 329 slots when doing rotations). So I have created a Plaintext called mask that I fill with 1's in the first 329 slots, which I multiply on a ciphertext to zero out everything outside these slots. The complete code generating the error is here:
#include <fstream>
#include <iostream>
#include <iterator>
#include <random>
#include "palisade.h"
using namespace std;
using namespace lbcrypto;
Plaintext mask;
CryptoContext<DCRTPoly> cryptoContext;
Ciphertext<DCRTPoly> RotateLeft(Ciphertext<DCRTPoly> ct, int r, int ll){
/* Rotates the ciphertext ct of length ll with r positions to the right. */
Ciphertext<DCRTPoly> res, shiftR, shiftL;
shiftL=cryptoContext->EvalAtIndex(ct, r);
shiftR=cryptoContext->EvalAtIndex(ct, r-ll);
res=cryptoContext->EvalAdd(shiftR, shiftL);
res=cryptoContext->EvalMult(res,mask);
return res;
}
int main(){
usint plaintextModulus = 65537;
float sigma = 3.2;
SecurityLevel securityLevel = HEStd_128_classic;
uint32_t depth = 6;
////////////////////////////////////////////////////////////
// Parameter generation
////////////////////////////////////////////////////////////
cryptoContext = CryptoContextFactory<DCRTPoly>::genCryptoContextBGVrns(
depth,
plaintextModulus,
securityLevel,
sigma,
2,
OPTIMIZED,
BV,
0,
0,
0,
0,
0,
0,
AUTO);
// enable features that you wish to use
cryptoContext->Enable(ENCRYPTION);
cryptoContext->Enable(SHE);
cryptoContext->Enable(LEVELEDSHE);
LPKeyPair<DCRTPoly> keyPair;
// Perform Key Generation Operation
keyPair = cryptoContext->KeyGen();
if (!keyPair.good()) {
std::cout << "Key generation failed!" << std::endl;
exit(1);
}
//Keys for multiplication
cryptoContext->EvalMultKeysGen(keyPair.secretKey);
//Keys for rotations
cryptoContext->EvalAtIndexKeyGen(keyPair.secretKey,{1,2,3,-326,-327,-328});
vector<int64_t> vecMask;
for(int i=0; i<329; ++i)
vecMask.push_back(1);
mask = cryptoContext->MakePackedPlaintext(vecMask);
std::vector<int64_t> vectorOfBits1;
for(int64_t i=0; i<329; ++i)
vectorOfBits1.push_back((i/2)%2);
Plaintext p1 = cryptoContext->MakePackedPlaintext(vectorOfBits1);
Ciphertext<DCRTPoly> c1=cryptoContext->Encrypt(keyPair.publicKey, p1);
Ciphertext<DCRTPoly> r1=RotateLeft(c1,1,329);
Ciphertext<DCRTPoly> r2=RotateLeft(c1,2,329);
Ciphertext<DCRTPoly> chi_res=cryptoContext->EvalMult(r1,r2);
chi_res=cryptoContext->EvalAdd(chi_res,c1);
}
This results in the error
tower size mismatch; cannot add
If the masking is commented out, everything works fine except c1 will contain the rubbish I want removed. How should I do the masking correctly?
It would be helpful to see a more complete code example, including the cryptocontext generation. I will assume you are using
BGVrns
, rather thanBGV
in PALISADE before 1.11. If not, I certainly suggest usingBGVrns
for efficiency.BGVrns
has two modulus switching modes:MANUAL
andAUTO
. In theMANUAL
mode, the user has to callModReduce()
after each multiplication, while in theAUTO
mode the modulus switching is done automatically. Based on the error you are describing, you are probably using theMANUAL
mode and not callingModReduce()
after that.To answer your question more definitively, I would like to see the cryptocontext generation and all prior operations for both C1 and the other ciphertext you are trying to add. Thank you.