EvalSign Error "No key found in map"

Hi all,

I’m trying to test the EvalSign() function after performing scheme switching from CKKS to FHEW.
However, I get the following error message:

terminate called after throwing an instance of 'lbcrypto::openfhe_error'
  what():  /home/clemens/Documents/openfhe-development/src/binfhe/lib/binfhe-base-scheme.cpp:373 ERROR: No key [262144] found in the map
Aborted (core dumped)

I noticed that ccLWE.GetBTKeyMap()->size() is 0, so it appears to me that there are actually no bootstrapping keys after the scheme switching. Is this to be expected?

Could you please help me troubleshoot this further?
Also, is there a working example for executing EvalSign after scheme switching? I can only find either scheme switching examples where different functions are evaluated, or EvalSign examples that do not use scheme switching.

Thank you very much!


I used the code below. The code was originally taken from the ArgminViaSchemeSwitching() function that is part of the scheme-switching.cpp example and then adjusted.

#include "openfhe.h"

#include "binfhecontext.h"

using namespace lbcrypto;


int main() {
  std::cout << "\n-----Sign Evaluation through Scheme Switching Test-----\n" << std::endl;

  // Step 1: Setup CryptoContext for CKKS
  uint32_t scaleModSize = 50;
  uint32_t firstModSize = 60;
  uint32_t ringDim = 8192;
  SecurityLevel sl = HEStd_NotSet;
  BINFHE_PARAMSET slBin = TOY;
  uint32_t logQ_ccLWE = 25;
  bool arbFunc = false;
  bool oneHot = true; // Change to false if the output should not be one-hot encoded

  uint32_t slots = 16; // sparsely-packed
  uint32_t batchSize = slots;
  uint32_t numValues = 16;
  ScalingTechnique scTech = FIXEDMANUAL;
  uint32_t multDepth =
    9 + 3 + 1 + static_cast < int > (std::log2(numValues)); // 13 for FHEW to CKKS, log2(numValues) for argmin
  if (scTech == FLEXIBLEAUTOEXT)
    multDepth += 1;

  CCParams < CryptoContextCKKSRNS > parameters;
  parameters.SetMultiplicativeDepth(multDepth);
  parameters.SetScalingModSize(scaleModSize);
  parameters.SetFirstModSize(firstModSize);
  parameters.SetScalingTechnique(scTech);
  parameters.SetSecurityLevel(sl);
  parameters.SetRingDim(ringDim);
  parameters.SetBatchSize(batchSize);

  CryptoContext < DCRTPoly > cc = GenCryptoContext(parameters);

  // Enable the features that you wish to use
  cc -> Enable(PKE);
  cc -> Enable(KEYSWITCH);
  cc -> Enable(LEVELEDSHE);
  cc -> Enable(ADVANCEDSHE);
  cc -> Enable(SCHEMESWITCH);

  std::cout << "CKKS scheme is using ring dimension " << cc -> GetRingDimension();
  std::cout << ", and number of slots " << slots << ", and supports a depth of " << multDepth << std::endl <<
    std::endl;

  // Generate encryption keys
  auto keys = cc -> KeyGen();

  // Step 2: Prepare the FHEW cryptocontext and keys for FHEW and scheme switching
  auto FHEWparams = cc -> EvalSchemeSwitchingSetup(sl, slBin, arbFunc, logQ_ccLWE, false, slots);
  auto ccLWE = FHEWparams.first;
  auto privateKeyFHEW = FHEWparams.second;


  const auto cryptoParams = std::dynamic_pointer_cast < CryptoParametersCKKSRNS > (cc -> GetCryptoParameters());


  cc -> EvalSchemeSwitchingKeyGen(keys, privateKeyFHEW, numValues, oneHot);

  std::cout << "FHEW scheme is using lattice parameter " << ccLWE.GetParams() -> GetLWEParams() -> Getn();
  std::cout << ", logQ " << logQ_ccLWE;
  std::cout << ", and modulus q " << ccLWE.GetParams() -> GetLWEParams() -> Getq() << std::endl << std::endl;

  // Scale the inputs to ensure their difference is correctly represented after switching to FHEW
  double scaleSign = 512.0;
  auto modulus_LWE = 1 << logQ_ccLWE;
  auto beta = ccLWE.GetBeta().ConvertToInt();
  auto pLWE = modulus_LWE / (2 * beta); // Large precision

  uint32_t init_level = 0;
  //const auto cryptoParams = std::dynamic_pointer_cast<CryptoParametersCKKSRNS>(cc->GetCryptoParameters());
  if (cryptoParams -> GetScalingTechnique() == FLEXIBLEAUTOEXT)
    init_level = 1;

  // This formulation is for clarity
  cc -> EvalCompareSwitchPrecompute(pLWE, init_level, scaleSign);


  // Step 3: Encoding and encryption of inputs
  // Inputs
  std::vector<double> x1 = {-1.125, -1.12, 5.0,  6.0,  -1.0, 2.0,  8.0,   -1.0,
                              9.0,    10.0,  11.0, 12.0, 13.0, 14.0, 15.25, 15.30};

  
  // Encoding as plaintexts
  Plaintext ptxt1 = cc -> MakeCKKSPackedPlaintext(x1);
  
  // Encrypt the encoded vectors
  auto c1 = cc -> Encrypt(keys.publicKey, ptxt1);

  

  // Transform the ciphertext from CKKS to FHEW
  auto cTemp = cc -> EvalCKKStoFHEW(c1, numValues);


  std::cout << "BT Keymap Size: " << ccLWE.GetBTKeyMap()->size();


  std::vector < LWECiphertext > LWESign(numValues);
  for (uint32_t j = 0; j < numValues; j++) {
    LWESign[j] = ccLWE.EvalSign(cTemp[j], true);
    std::cout << "--> " << LWESign[j] << std::endl;
  }
  

  return 0;
}

Hi, the BTkey is not attached to the ccLWE outside. This is a known issue, but it hasn’t been ported yet to the main branch; this will happen soon in the stable release 1.1.2.

Until then, if you want to make modifications locally for this to work, you need to change ccLWE to be a shared pointer in ckksrns-schemeswitching.h. You can check the dtt-ss branch for these details.

It’s working now, thanks a lot!
I’m looking forward to the upcoming stable release.