Palisade: EvalMult between plaintext and ciphertext resulting in tower size mismatch

125 views Asked by At

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?

1

There are 1 answers

5
Yuriy Polyakov On

It would be helpful to see a more complete code example, including the cryptocontext generation. I will assume you are using BGVrns, rather than BGV in PALISADE before 1.11. If not, I certainly suggest using BGVrns for efficiency.

BGVrns has two modulus switching modes: MANUAL and AUTO. In the MANUAL mode, the user has to call ModReduce() after each multiplication, while in the AUTO mode the modulus switching is done automatically. Based on the error you are describing, you are probably using the MANUAL mode and not calling ModReduce() 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.