Program Listing for File cryptocontext.h
↰ Return to documentation for file (pke/include/cryptocontext.h)
//==================================================================================
// BSD 2-Clause License
//
// Copyright (c) 2014-2025, NJIT, Duality Technologies Inc. and other contributors
//
// All rights reserved.
//
// Author TPOC: contact@openfhe.org
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//==================================================================================
/*
Control for encryption operations
*/
#ifndef __CRYPTOCONTEXT_H__
#define __CRYPTOCONTEXT_H__
#include "binfhecontext.h"
#include "ciphertext.h"
#include "cryptocontextfactory.h"
#include "cryptocontext-fwd.h"
#include "encoding/plaintextfactory.h"
#include "key/evalkey.h"
#include "key/keypair.h"
#include "scheme/scheme-swch-params.h"
#include "schemebase/base-pke.h"
#include "schemebase/base-scheme.h"
#include "schemerns/rns-cryptoparameters.h"
#include "utils/caller_info.h"
#include "utils/type_name.h"
#include <algorithm>
#include <complex>
#include <functional>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <vector>
#ifdef DEBUG_KEY
#include <iostream>
#endif
namespace lbcrypto {
template <typename Element>
class CryptoContextImpl : public Serializable {
using IntType = typename Element::Integer;
using ParmType = typename Element::Params;
inline void VerifyCKKSScheme(const std::string& functionName) const {
if (!isCKKS(m_schemeId)) {
std::string errMsg = std::string(functionName) +
"() is available for the CKKS scheme only."
" The current scheme is " +
convertToString(m_schemeId);
OPENFHE_THROW(errMsg);
}
}
inline void VerifyCKKSRealDataType(const std::string& functionName) const {
if (GetCKKSDataType() != REAL) {
std::string errMsg =
"Function " + std::string(functionName) + " is available for the real CKKS data types only.";
OPENFHE_THROW(errMsg);
}
}
void SetKSTechniqueInScheme();
const CryptoContext<Element> GetContextForPointer(const CryptoContextImpl<Element>* cc) const {
const auto& contexts = CryptoContextFactory<Element>::GetAllContexts();
for (const auto& ctx : contexts) {
if (cc == ctx.get())
return ctx;
}
OPENFHE_THROW("Cannot find context for the given pointer to CryptoContextImpl");
}
Plaintext MakePlaintext(const PlaintextEncodings encoding, const std::vector<int64_t>& value, size_t depth,
uint32_t level) const {
const auto cryptoParams = std::dynamic_pointer_cast<CryptoParametersRNS>(GetCryptoParameters());
if (level > 0) {
size_t numModuli = cryptoParams->GetElementParams()->GetParams().size();
if (!isBFVRNS(m_schemeId)) {
// we throw an exception if level >= numModuli. However, we use multiplicativeDepth in the error message,
// so the user can understand the error more easily.
if (level >= numModuli) {
uint32_t multiplicativeDepth =
(cryptoParams->GetScalingTechnique() == FLEXIBLEAUTOEXT) ? (numModuli - 2) : (numModuli - 1);
std::string errorMsg{"The level value should be less than or equal to "};
errorMsg +=
((cryptoParams->GetScalingTechnique() == FLEXIBLEAUTOEXT) ? "(multiplicativeDepth + 1)." :
"multiplicativeDepth.");
errorMsg += " Currently: level is [" + std::to_string(level) + "] and multiplicativeDepth is [" +
std::to_string(multiplicativeDepth) + "]";
OPENFHE_THROW(errorMsg);
}
}
else {
if ((cryptoParams->GetMultiplicationTechnique() == BEHZ) ||
(cryptoParams->GetMultiplicationTechnique() == HPS)) {
OPENFHE_THROW(
"BFV: Encoding at level > 0 is not currently supported for BEHZ or HPS. Use one of the HPSPOVERQ* methods instead.");
}
if ((cryptoParams->GetEncryptionTechnique() == EXTENDED)) {
OPENFHE_THROW(
"BFV: Encoding at level > 0 is not currently supported for the EXTENDED encryption method. Use the STANDARD encryption method instead.");
}
if (level >= numModuli) {
std::string errorMsg =
"The level value should be less the current number of RNS limbs in the cryptocontext.";
errorMsg += " Currently: level is [" + std::to_string(level) + "] and number of RNS limbs is [" +
std::to_string(numModuli) + "]";
OPENFHE_THROW(errorMsg);
}
}
}
// uses a parameter set with a reduced number of RNS limbs corresponding to the level
std::shared_ptr<ILDCRTParams<DCRTPoly::Integer>> elemParamsPtr;
if (level != 0) {
ILDCRTParams<DCRTPoly::Integer> elemParams = *(cryptoParams->GetElementParams());
for (uint32_t i = 0; i < level; i++) {
elemParams.PopLastParam();
}
elemParamsPtr = std::make_shared<ILDCRTParams<DCRTPoly::Integer>>(elemParams);
}
else {
elemParamsPtr = cryptoParams->GetElementParams();
}
NativeInteger scf{1};
bool setNoiseScaleDeg = false;
auto scaleTech = cryptoParams->GetScalingTechnique();
if (isBGVRNS(m_schemeId) && (scaleTech == FLEXIBLEAUTO || scaleTech == FLEXIBLEAUTOEXT)) {
if (scaleTech == FLEXIBLEAUTOEXT && level == 0) {
scf = cryptoParams->GetScalingFactorIntBig(level);
depth = 1;
setNoiseScaleDeg = true;
}
else
scf = cryptoParams->GetScalingFactorInt(level);
}
Plaintext p = PlaintextFactory::MakePlaintext(value, encoding, elemParamsPtr, this->GetEncodingParams(),
getSchemeId(), depth, level, scf);
if (setNoiseScaleDeg)
p->SetNoiseScaleDeg(2);
return p;
}
template <typename Value1>
static Plaintext MakePlaintext(PlaintextEncodings encoding, CryptoContext<Element> cc, const Value1& value) {
return PlaintextFactory::MakePlaintext(value, encoding, cc->GetElementParams(), cc->GetEncodingParams());
}
template <typename Value1, typename Value2>
static Plaintext MakePlaintext(PlaintextEncodings encoding, CryptoContext<Element> cc, const Value1& value,
const Value2& value2) {
return PlaintextFactory::MakePlaintext(encoding, cc->GetElementParams(), cc->GetEncodingParams(), value,
value2);
}
static std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> GetPartialEvalAutomorphismKeyMapPtr(
const std::string& keyTag, const std::vector<uint32_t>& indexList);
// cached evalmult keys, by secret key UID
static std::map<std::string, std::vector<EvalKey<Element>>> s_evalMultKeyMap;
// cached evalautomorphism keys, by secret key UID
static std::map<std::string, std::shared_ptr<std::map<uint32_t, EvalKey<Element>>>> s_evalAutomorphismKeyMap;
protected:
// crypto parameters
std::shared_ptr<CryptoParametersBase<Element>> m_params{nullptr};
// algorithm used; accesses all crypto methods
std::shared_ptr<SchemeBase<Element>> m_scheme{nullptr};
SCHEME m_schemeId{SCHEME::INVALID_SCHEME};
uint32_t m_keyGenLevel{0};
void TypeCheck(ConstCiphertext<Element>& a, ConstCiphertext<Element>& b, CALLER_INFO_ARGS_HDR) const {
if (a == nullptr || b == nullptr) {
std::string errorMsg(std::string("Null Ciphertext") + CALLER_INFO);
OPENFHE_THROW(errorMsg);
}
if (a->GetCryptoContext().get() != this) {
std::string errorMsg(std::string("Ciphertext was not created in this CryptoContext") + CALLER_INFO);
OPENFHE_THROW(errorMsg);
}
if (a->GetCryptoContext() != b->GetCryptoContext()) {
std::string errorMsg(std::string("Ciphertexts were not created in the same CryptoContext") + CALLER_INFO);
OPENFHE_THROW(errorMsg);
}
if (a->GetKeyTag() != b->GetKeyTag()) {
std::string errorMsg(std::string("Ciphertexts were not encrypted with same keys") + CALLER_INFO);
OPENFHE_THROW(errorMsg);
}
if (a->GetEncodingType() != b->GetEncodingType()) {
std::stringstream ss;
ss << "Ciphertext encoding types " << a->GetEncodingType();
ss << " and " << b->GetEncodingType();
ss << " do not match";
ss << CALLER_INFO;
OPENFHE_THROW(ss.str());
}
}
void TypeCheck(ConstCiphertext<Element>& a, ConstPlaintext& b, CALLER_INFO_ARGS_HDR) const {
if (a == nullptr) {
std::string errorMsg(std::string("Null Ciphertext") + CALLER_INFO);
OPENFHE_THROW(errorMsg);
}
if (b == nullptr) {
std::string errorMsg(std::string("Null Plaintext") + CALLER_INFO);
OPENFHE_THROW(errorMsg);
}
if (a->GetCryptoContext().get() != this) {
std::string errorMsg(std::string("Ciphertext was not created in this CryptoContext") + CALLER_INFO);
OPENFHE_THROW(errorMsg);
}
if (a->GetEncodingType() != b->GetEncodingType()) {
std::stringstream ss;
ss << "Ciphertext encoding type " << a->GetEncodingType();
ss << " and Plaintext encoding type " << b->GetEncodingType();
ss << " do not match";
ss << CALLER_INFO;
OPENFHE_THROW(ss.str());
}
}
bool Mismatched(const CryptoContext<Element> a) const {
return a.get() != this;
}
template <typename T>
void ValidateKey(const T& key, CALLER_INFO_ARGS_HDR) const {
if (key == nullptr) {
std::string errorMsg(std::string("Key is nullptr") + CALLER_INFO);
OPENFHE_THROW(errorMsg);
}
if (Mismatched(key->GetCryptoContext())) {
std::string errorMsg(std::string("Key was not generated with the same crypto context") + CALLER_INFO);
OPENFHE_THROW(errorMsg);
}
}
void ValidateCiphertext(ConstCiphertext<Element>& ciphertext, CALLER_INFO_ARGS_HDR) const {
if (ciphertext == nullptr) {
std::string errorMsg(std::string("Ciphertext is nullptr") + CALLER_INFO);
OPENFHE_THROW(errorMsg);
}
if (Mismatched(ciphertext->GetCryptoContext())) {
std::string errorMsg(std::string("Ciphertext was not generated with the same crypto context") +
CALLER_INFO);
OPENFHE_THROW(errorMsg);
}
}
void ValidateSeriesPowers(std::shared_ptr<seriesPowers<Element>> powers, CALLER_INFO_ARGS_HDR) const {
if (powers == nullptr) {
std::string errorMsg(std::string("The object for powers is nullptr") + CALLER_INFO);
OPENFHE_THROW(errorMsg);
}
if (powers->powersRe.size() == 0) {
std::string errorMsg(std::string("The powersRe member is empty") + CALLER_INFO);
OPENFHE_THROW(errorMsg);
}
if (Mismatched(powers->powersRe[0]->GetCryptoContext())) {
std::string errorMsg(std::string("Power ciphertext was not generated with the same crypto context") +
CALLER_INFO);
OPENFHE_THROW(errorMsg);
}
}
virtual Plaintext MakeCKKSPackedPlaintextInternal(const std::vector<std::complex<double>>& value,
size_t noiseScaleDeg, uint32_t level,
const std::shared_ptr<ParmType> params, uint32_t slots) const {
VerifyCKKSScheme(__func__);
const auto cryptoParams = std::dynamic_pointer_cast<CryptoParametersRNS>(GetCryptoParameters());
if (level > 0) {
// validation of level: We need to compare it to multiplicativeDepth, but multiplicativeDepth is not
// readily available. so, what we get is numModuli and use it for calculations
size_t numModuli = cryptoParams->GetElementParams()->GetParams().size();
uint32_t multiplicativeDepth =
(cryptoParams->GetScalingTechnique() == FLEXIBLEAUTOEXT) ? (numModuli - 2) : (numModuli - 1);
// we throw an exception if level >= numModuli. however, we use multiplicativeDepth in the error message,
// so the user can understand the error more easily.
if (level >= numModuli) {
std::string errorMsg;
if (cryptoParams->GetScalingTechnique() == FLEXIBLEAUTOEXT)
errorMsg = "The level value should be less than or equal to (multiplicativeDepth + 1).";
else
errorMsg = "The level value should be less than or equal to multiplicativeDepth.";
errorMsg += " Currently: level is [" + std::to_string(level) + "] and multiplicativeDepth is [" +
std::to_string(multiplicativeDepth) + "]";
OPENFHE_THROW(errorMsg);
}
}
double scFact = 0;
if (cryptoParams->GetScalingTechnique() == FLEXIBLEAUTOEXT && level == 0) {
scFact = cryptoParams->GetScalingFactorRealBig(level);
// In FLEXIBLEAUTOEXT mode at level 0, we don't use the noiseScaleDeg in our encoding function,
// so we set it to 1 to make sure it has no effect on the encoding.
noiseScaleDeg = 1;
}
else {
scFact = cryptoParams->GetScalingFactorReal(level);
}
Plaintext p;
if (params == nullptr) {
std::shared_ptr<ILDCRTParams<DCRTPoly::Integer>> elemParamsPtr;
if (level != 0) {
ILDCRTParams<DCRTPoly::Integer> elemParams = *(cryptoParams->GetElementParams());
for (uint32_t i = 0; i < level; i++) {
elemParams.PopLastParam();
}
elemParamsPtr = std::make_shared<ILDCRTParams<DCRTPoly::Integer>>(elemParams);
}
else {
elemParamsPtr = cryptoParams->GetElementParams();
}
// Check if plaintext has got enough slots for data (value)
uint32_t ringDim = elemParamsPtr->GetRingDimension();
size_t valueSize = value.size();
if (valueSize > ringDim / 2) {
OPENFHE_THROW("The size [" + std::to_string(valueSize) +
"] of the vector with values should not be greater than ringDim/2 [" +
std::to_string(ringDim / 2) + "] if the scheme is CKKS");
}
// TODO (dsuponit): we should call a version of MakePlaintext instead of calling Plaintext() directly here
p = Plaintext(std::make_shared<CKKSPackedEncoding>(elemParamsPtr, this->GetEncodingParams(), value,
noiseScaleDeg, level, scFact, slots,
this->GetCKKSDataType()));
}
else {
// Check if plaintext has got enough slots for data (value)
uint32_t ringDim = params->GetRingDimension();
size_t valueSize = value.size();
if (valueSize > ringDim / 2) {
OPENFHE_THROW("The size [" + std::to_string(valueSize) +
"] of the vector with values should not be greater than ringDim/2 [" +
std::to_string(ringDim / 2) + "] if the scheme is CKKS");
}
// TODO (dsuponit): we should call a version of MakePlaintext instead of calling Plaintext() directly here
p = Plaintext(std::make_shared<CKKSPackedEncoding>(params, this->GetEncodingParams(), value, noiseScaleDeg,
level, scFact, slots, this->GetCKKSDataType()));
}
p->Encode();
// In FLEXIBLEAUTOEXT mode, a fresh plaintext at level 0 always has noiseScaleDeg 2.
if (cryptoParams->GetScalingTechnique() == FLEXIBLEAUTOEXT && level == 0) {
p->SetNoiseScaleDeg(2);
}
return p;
}
uint32_t GetCompositeDegreeFromCtxt() const {
const auto cryptoParams = std::dynamic_pointer_cast<CryptoParametersRNS>(m_params);
if (!cryptoParams) {
std::string errorMsg(std::string("std::dynamic_pointer_cast<CryptoParametersRNS>() failed"));
OPENFHE_THROW(errorMsg);
}
return cryptoParams->GetCompositeDegree();
}
#ifdef DEBUG_KEY
PrivateKey<Element> privateKey;
#endif
public:
#ifdef DEBUG_KEY
void SetPrivateKey(const PrivateKey<Element> privateKey) {
std::cerr << "Warning - SetPrivateKey is only intended to be used for debugging "
"purposes - not for production systems."
<< std::endl;
this->privateKey = privateKey;
}
const PrivateKey<Element>& GetPrivateKey() const {
return this->privateKey;
}
#endif
void setSchemeId(SCHEME schemeTag) {
this->m_schemeId = schemeTag;
}
SCHEME getSchemeId() const {
return this->m_schemeId;
}
// TODO (dsuponit): investigate if we really need 2 constructors for CryptoContextImpl as one of them take regular pointer
// and the other one takes shared_ptr
CryptoContextImpl(CryptoParametersBase<Element>* params = nullptr, SchemeBase<Element>* scheme = nullptr,
SCHEME schemeId = SCHEME::INVALID_SCHEME) {
this->m_params.reset(params);
this->m_scheme.reset(scheme);
this->m_keyGenLevel = 0;
this->m_schemeId = schemeId;
}
CryptoContextImpl(std::shared_ptr<CryptoParametersBase<Element>> params,
std::shared_ptr<SchemeBase<Element>> scheme, SCHEME schemeId = SCHEME::INVALID_SCHEME) {
this->m_params = params;
this->m_scheme = scheme;
this->m_keyGenLevel = 0;
this->m_schemeId = schemeId;
}
CryptoContextImpl(const CryptoContextImpl<Element>& other) {
m_params = other.m_params;
m_scheme = other.m_scheme;
m_keyGenLevel = 0;
m_schemeId = other.m_schemeId;
}
CryptoContextImpl<Element>& operator=(const CryptoContextImpl<Element>& rhs) {
m_params = rhs.m_params;
m_scheme = rhs.m_scheme;
m_keyGenLevel = rhs.m_keyGenLevel;
m_schemeId = rhs.m_schemeId;
return *this;
}
operator bool() const {
return m_params && m_scheme;
}
friend bool operator==(const CryptoContextImpl<Element>& a, const CryptoContextImpl<Element>& b) {
// Identical if the parameters and the schemes are identical... the exact
// same object, OR the same type and the same values
if (a.m_params.get() == b.m_params.get()) {
return true;
}
else {
if (typeid(*a.m_params.get()) != typeid(*b.m_params.get())) {
return false;
}
if (*a.m_params.get() != *b.m_params.get())
return false;
}
if (a.m_scheme.get() == b.m_scheme.get()) {
return true;
}
else {
if (typeid(*a.m_scheme.get()) != typeid(*b.m_scheme.get())) {
return false;
}
if (*a.m_scheme.get() != *b.m_scheme.get())
return false;
}
return true;
}
friend bool operator!=(const CryptoContextImpl<Element>& a, const CryptoContextImpl<Element>& b) {
return !(a == b);
}
static void ClearStaticMapsAndVectors();
template <typename ST>
static bool SerializeEvalMultKey(std::ostream& ser, const ST& sertype, const std::string& keyTag = "") {
const auto& evalMultKeys = CryptoContextImpl<Element>::GetAllEvalMultKeys();
if (keyTag.length() == 0) {
Serial::Serialize(evalMultKeys, ser, sertype);
}
else {
const auto it = evalMultKeys.find(keyTag);
if (it == evalMultKeys.end())
return false; // no such keyTag
std::map<std::string, std::vector<EvalKey<Element>>> omap{{it->first, it->second}};
Serial::Serialize(omap, ser, sertype);
}
return true;
}
template <typename ST>
static bool SerializeEvalMultKey(std::ostream& ser, const ST& sertype, const CryptoContext<Element> cc) {
std::map<std::string, std::vector<EvalKey<Element>>> omap;
for (const auto& [key, vec] : CryptoContextImpl<Element>::GetAllEvalMultKeys()) {
if (vec[0]->GetCryptoContext() == cc) {
omap[key] = vec;
}
}
if (omap.empty())
return false;
Serial::Serialize(omap, ser, sertype);
return true;
}
template <typename ST>
static bool DeserializeEvalMultKey(std::istream& ser, const ST& sertype) {
std::map<std::string, std::vector<EvalKey<Element>>> omap;
Serial::Deserialize(omap, ser, sertype);
// The deserialize call creates all contexts that need to be created...
// so, all we need to do is to insert the keys into the maps for their context(s)
for (auto& [tag, vec] : omap) {
CryptoContextImpl<Element>::InsertEvalMultKey(vec, tag);
}
return true;
}
static void ClearEvalMultKeys();
static void ClearEvalMultKeys(const std::string& keyTag);
static void ClearEvalMultKeys(const CryptoContext<Element>& cc);
static void InsertEvalMultKey(const std::vector<EvalKey<Element>>& evalKeyVec, const std::string& keyTag = "");
template <typename ST>
static bool SerializeEvalSumKey(std::ostream& ser, const ST& sertype, const std::string& keyTag = "") {
return CryptoContextImpl<Element>::SerializeEvalAutomorphismKey(ser, sertype, keyTag);
}
template <typename ST>
static bool SerializeEvalSumKey(std::ostream& ser, const ST& sertype, const CryptoContext<Element> cc) {
return CryptoContextImpl<Element>::SerializeEvalAutomorphismKey(ser, sertype, cc);
}
template <typename ST>
static bool DeserializeEvalSumKey(std::istream& ser, const ST& sertype) {
return CryptoContextImpl<Element>::DeserializeEvalAutomorphismKey(ser, sertype);
}
static void ClearEvalSumKeys();
static void ClearEvalSumKeys(const std::string& keyTag);
static void ClearEvalSumKeys(const CryptoContext<Element> cc);
static void InsertEvalSumKey(const std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> mapToInsert,
std::string keyTag = "") {
CryptoContextImpl<Element>::InsertEvalAutomorphismKey(mapToInsert, keyTag);
}
template <typename ST>
static bool SerializeEvalAutomorphismKey(std::ostream& ser, const ST& sertype, const std::string& keyTag = "") {
// TODO (dsuponit): do we need Serailize/Deserialized to return bool?
std::map<std::string, std::shared_ptr<std::map<uint32_t, EvalKey<Element>>>>* smap;
std::map<std::string, std::shared_ptr<std::map<uint32_t, EvalKey<Element>>>> omap;
if (keyTag.length() == 0) {
smap = &CryptoContextImpl<Element>::GetAllEvalAutomorphismKeys();
}
else {
const auto keys = CryptoContextImpl<Element>::GetEvalAutomorphismKeyMapPtr(keyTag);
omap[keyTag] = keys;
smap = &omap;
}
Serial::Serialize(*smap, ser, sertype);
return true;
}
template <typename ST>
static bool SerializeEvalAutomorphismKey(std::ostream& ser, const ST& sertype, const CryptoContext<Element> cc) {
std::map<std::string, std::shared_ptr<std::map<uint32_t, EvalKey<Element>>>> omap;
for (const auto& k : CryptoContextImpl<Element>::GetAllEvalAutomorphismKeys()) {
if (k.second->begin()->second->GetCryptoContext() == cc) {
omap[k.first] = k.second;
}
}
if (omap.empty())
return false;
Serial::Serialize(omap, ser, sertype);
return true;
}
template <typename ST>
static bool SerializeEvalAutomorphismKey(std::ostream& ser, const ST& sertype, const std::string& keyTag,
const std::vector<uint32_t>& indexList) {
std::map<std::string, std::shared_ptr<std::map<uint32_t, EvalKey<Element>>>> keyMap = {
{keyTag, CryptoContextImpl<Element>::GetPartialEvalAutomorphismKeyMapPtr(keyTag, indexList)}};
Serial::Serialize(keyMap, ser, sertype);
return true;
}
template <typename ST>
static bool DeserializeEvalAutomorphismKey(std::ostream& ser, const ST& sertype, const std::string& keyTag,
const std::vector<uint32_t>& indexList) {
if (indexList.empty())
OPENFHE_THROW("indexList may not be empty");
if (keyTag.empty())
OPENFHE_THROW("keyTag may not be empty");
std::map<std::string, std::shared_ptr<std::map<uint32_t, EvalKey<Element>>>> allDeserKeys;
Serial::Deserialize(allDeserKeys, ser, sertype);
const auto& keyMapIt = allDeserKeys.find(keyTag);
if (keyMapIt == allDeserKeys.end()) {
OPENFHE_THROW("Deserialized automorphism keys are not generated for ID [" + keyTag + "].");
}
// create a new map with evalkeys for the specified indices
std::map<uint32_t, EvalKey<Element>> newMap;
for (const uint32_t indx : indexList) {
const auto& key = keyMapIt->find(indx);
if (key == keyMapIt->end()) {
OPENFHE_THROW("No automorphism key generated for index [" + std::to_string(indx) + "] within keyTag [" +
keyTag + "].");
}
newMap[indx] = key->second;
}
CryptoContextImpl<Element>::InsertEvalAutomorphismKey(
std::make_shared<std::map<uint32_t, EvalKey<Element>>>(newMap), keyTag);
return true;
}
template <typename ST>
static bool DeserializeEvalAutomorphismKey(std::istream& ser, const ST& sertype) {
std::map<std::string, std::shared_ptr<std::map<uint32_t, EvalKey<Element>>>> keyMap;
Serial::Deserialize(keyMap, ser, sertype);
// The deserialize call created any contexts that needed to be created....
// so all we need to do is put the keys into the maps for their context
for (auto& k : keyMap) {
CryptoContextImpl<Element>::InsertEvalAutomorphismKey(k.second, k.first);
}
return true;
}
static void ClearEvalAutomorphismKeys();
static void ClearEvalAutomorphismKeys(const std::string& keyTag);
static void ClearEvalAutomorphismKeys(const CryptoContext<Element> cc);
// TODO (dsuponit): move InsertEvalAutomorphismKey() to the private section of the class
static void InsertEvalAutomorphismKey(const std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> mapToInsert,
const std::string& keyTag = "");
//------------------------------------------------------------------------------
// TURN FEATURES ON
//------------------------------------------------------------------------------
void Enable(PKESchemeFeature feature) {
m_scheme->Enable(feature);
}
void Enable(uint32_t featureMask) {
m_scheme->Enable(featureMask);
}
// GETTERS
const std::shared_ptr<SchemeBase<Element>> GetScheme() const {
return m_scheme;
}
const std::shared_ptr<CryptoParametersBase<Element>> GetCryptoParameters() const {
return m_params;
}
size_t GetKeyGenLevel() const {
return m_keyGenLevel;
}
void SetKeyGenLevel(size_t level) {
m_keyGenLevel = level;
}
const std::shared_ptr<ParmType> GetElementParams() const {
return m_params->GetElementParams();
}
const EncodingParams GetEncodingParams() const {
return m_params->GetEncodingParams();
}
uint32_t GetCyclotomicOrder() const {
return m_params->GetElementParams()->GetCyclotomicOrder();
}
uint32_t GetRingDimension() const {
return m_params->GetElementParams()->GetRingDimension();
}
const IntType& GetModulus() const {
return m_params->GetElementParams()->GetModulus();
}
const IntType& GetRootOfUnity() const {
return m_params->GetElementParams()->GetRootOfUnity();
}
CKKSDataType GetCKKSDataType() const {
const auto cryptoParams = std::dynamic_pointer_cast<CryptoParametersRNS>(m_params);
if (!cryptoParams) {
std::string errorMsg(std::string("std::dynamic_pointer_cast<CryptoParametersRNS>() failed"));
OPENFHE_THROW(errorMsg);
}
return cryptoParams->GetCKKSDataType();
}
//------------------------------------------------------------------------------
// KEYS GETTERS
//------------------------------------------------------------------------------
static std::map<std::string, std::vector<EvalKey<Element>>>& GetAllEvalMultKeys();
static const std::vector<EvalKey<Element>>& GetEvalMultKeyVector(const std::string& keyTag);
static std::map<std::string, std::shared_ptr<std::map<uint32_t, EvalKey<Element>>>>& GetAllEvalAutomorphismKeys();
static std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> GetEvalAutomorphismKeyMapPtr(
const std::string& keyTag);
static std::map<uint32_t, EvalKey<Element>>& GetEvalAutomorphismKeyMap(const std::string& keyTag) {
return *(CryptoContextImpl<Element>::GetEvalAutomorphismKeyMapPtr(keyTag));
}
static std::map<std::string, std::shared_ptr<std::map<uint32_t, EvalKey<Element>>>>& GetAllEvalSumKeys();
static const std::map<uint32_t, EvalKey<Element>>& GetEvalSumKeyMap(const std::string& keyTag);
//------------------------------------------------------------------------------
// PLAINTEXT FACTORY METHODS
//------------------------------------------------------------------------------
// TODO to be deprecated in 2.0
Plaintext MakeStringPlaintext(const std::string& str) const {
return PlaintextFactory::MakePlaintext(str, STRING_ENCODING, this->GetElementParams(),
this->GetEncodingParams());
}
Plaintext MakeCoefPackedPlaintext(const std::vector<int64_t>& value, size_t noiseScaleDeg = 1,
uint32_t level = 0) const {
if (value.empty())
OPENFHE_THROW("Cannot encode an empty value vector");
return MakePlaintext(COEF_PACKED_ENCODING, value, noiseScaleDeg, level);
}
Plaintext MakePackedPlaintext(const std::vector<int64_t>& value, size_t noiseScaleDeg = 1,
uint32_t level = 0) const {
if (value.empty())
OPENFHE_THROW("Cannot encode an empty value vector");
return MakePlaintext(PACKED_ENCODING, value, noiseScaleDeg, level);
}
Plaintext MakeCKKSPackedPlaintext(const std::vector<std::complex<double>>& value, size_t noiseScaleDeg = 1,
uint32_t level = 0, const std::shared_ptr<ParmType> params = nullptr,
uint32_t slots = 0) const {
VerifyCKKSScheme(__func__);
if (value.empty())
OPENFHE_THROW("Cannot encode an empty value vector");
return MakeCKKSPackedPlaintextInternal(value, noiseScaleDeg, level, params, slots);
}
Plaintext MakeCKKSPackedPlaintext(const std::vector<double>& value, size_t noiseScaleDeg = 1, uint32_t level = 0,
const std::shared_ptr<ParmType> params = nullptr, uint32_t slots = 0) const {
VerifyCKKSScheme(__func__);
if (value.empty())
OPENFHE_THROW("Cannot encode an empty value vector");
std::vector<std::complex<double>> complexValue(value.size());
std::transform(value.begin(), value.end(), complexValue.begin(),
[](double da) { return std::complex<double>(da); });
return MakeCKKSPackedPlaintextInternal(complexValue, noiseScaleDeg, level, params, slots);
}
static Plaintext GetPlaintextForDecrypt(PlaintextEncodings pte, std::shared_ptr<ParmType> evp, EncodingParams ep,
CKKSDataType cdt = REAL);
//------------------------------------------------------------------------------
// PKE Wrapper
//------------------------------------------------------------------------------
KeyPair<Element> KeyGen() const {
return GetScheme()->KeyGen(GetContextForPointer(this), false);
}
KeyPair<Element> SparseKeyGen() const {
return GetScheme()->KeyGen(GetContextForPointer(this), true);
}
Ciphertext<Element> Encrypt(ConstPlaintext& plaintext, const PublicKey<Element>& publicKey) const {
if (plaintext == nullptr)
OPENFHE_THROW("Input plaintext is nullptr");
ValidateKey(publicKey);
Ciphertext<Element> ciphertext = GetScheme()->Encrypt(plaintext->GetElement<Element>(), publicKey);
if (ciphertext) {
ciphertext->SetSlots(plaintext->GetSlots());
ciphertext->SetLevel(plaintext->GetLevel());
ciphertext->SetNoiseScaleDeg(plaintext->GetNoiseScaleDeg());
ciphertext->SetScalingFactor(plaintext->GetScalingFactor());
ciphertext->SetScalingFactorInt(plaintext->GetScalingFactorInt());
ciphertext->SetEncodingType(plaintext->GetEncodingType());
}
return ciphertext;
}
Ciphertext<Element> Encrypt(const PublicKey<Element>& publicKey, ConstPlaintext& plaintext) const {
return Encrypt(plaintext, publicKey);
}
Ciphertext<Element> Encrypt(ConstPlaintext& plaintext, const PrivateKey<Element>& privateKey) const {
// if (plaintext == nullptr)
// OPENFHE_THROW( "Input plaintext is nullptr");
ValidateKey(privateKey);
Ciphertext<Element> ciphertext = GetScheme()->Encrypt(plaintext->GetElement<Element>(), privateKey);
if (ciphertext) {
ciphertext->SetSlots(plaintext->GetSlots());
ciphertext->SetLevel(plaintext->GetLevel());
ciphertext->SetNoiseScaleDeg(plaintext->GetNoiseScaleDeg());
ciphertext->SetScalingFactor(plaintext->GetScalingFactor());
ciphertext->SetScalingFactorInt(plaintext->GetScalingFactorInt());
ciphertext->SetEncodingType(plaintext->GetEncodingType());
}
return ciphertext;
}
Ciphertext<Element> Encrypt(const PrivateKey<Element>& privateKey, ConstPlaintext& plaintext) const {
return Encrypt(plaintext, privateKey);
}
DecryptResult Decrypt(ConstCiphertext<Element>& ciphertext, const PrivateKey<Element>& privateKey,
Plaintext* plaintext);
inline DecryptResult Decrypt(const PrivateKey<Element>& privateKey, ConstCiphertext<Element>& ciphertext,
Plaintext* plaintext) {
return Decrypt(ciphertext, privateKey, plaintext);
}
//------------------------------------------------------------------------------
// KeySwitch Wrapper
//------------------------------------------------------------------------------
EvalKey<Element> KeySwitchGen(const PrivateKey<Element>& oldPrivateKey,
const PrivateKey<Element>& newPrivateKey) const {
ValidateKey(oldPrivateKey);
ValidateKey(newPrivateKey);
return GetScheme()->KeySwitchGen(oldPrivateKey, newPrivateKey);
}
Ciphertext<Element> KeySwitch(ConstCiphertext<Element>& ciphertext, const EvalKey<Element>& evalKey) const {
ValidateCiphertext(ciphertext);
ValidateKey(evalKey);
return GetScheme()->KeySwitch(ciphertext, evalKey);
}
void KeySwitchInPlace(Ciphertext<Element>& ciphertext, const EvalKey<Element>& evalKey) const {
ValidateCiphertext(ciphertext);
ValidateKey(evalKey);
GetScheme()->KeySwitchInPlace(ciphertext, evalKey);
}
//------------------------------------------------------------------------------
// SHE NEGATION Wrapper
//------------------------------------------------------------------------------
Ciphertext<Element> EvalNegate(ConstCiphertext<Element>& ciphertext) const {
ValidateCiphertext(ciphertext);
return GetScheme()->EvalNegate(ciphertext);
}
void EvalNegateInPlace(Ciphertext<Element>& ciphertext) const {
ValidateCiphertext(ciphertext);
GetScheme()->EvalNegateInPlace(ciphertext);
}
//------------------------------------------------------------------------------
// SHE ADDITION Wrapper
//------------------------------------------------------------------------------
Ciphertext<Element> EvalAdd(ConstCiphertext<Element>& ciphertext1, ConstCiphertext<Element>& ciphertext2) const {
TypeCheck(ciphertext1, ciphertext2);
return GetScheme()->EvalAdd(ciphertext1, ciphertext2);
}
void EvalAddInPlace(Ciphertext<Element>& ciphertext1, ConstCiphertext<Element>& ciphertext2) const {
TypeCheck(ciphertext1, ciphertext2);
GetScheme()->EvalAddInPlace(ciphertext1, ciphertext2);
}
void EvalAddInPlaceNoCheck(Ciphertext<Element>& ctxt1, ConstCiphertext<Element>& ctxt2) const {
auto& cv1 = ctxt1->GetElements();
auto& cv2 = ctxt2->GetElements();
uint32_t n = cv1.size();
for (uint32_t i = 0; i < n; ++i)
cv1[i] += cv2[i];
}
Ciphertext<Element> EvalAddMutable(Ciphertext<Element>& ciphertext1, Ciphertext<Element>& ciphertext2) const {
TypeCheck(ciphertext1, ciphertext2);
return GetScheme()->EvalAddMutable(ciphertext1, ciphertext2);
}
void EvalAddMutableInPlace(Ciphertext<Element>& ciphertext1, Ciphertext<Element>& ciphertext2) const {
TypeCheck(ciphertext1, ciphertext2);
GetScheme()->EvalAddMutableInPlace(ciphertext1, ciphertext2);
}
Ciphertext<Element> EvalAdd(ConstCiphertext<Element>& ciphertext, Plaintext& plaintext) const {
TypeCheck(ciphertext, plaintext);
plaintext->SetFormat(EVALUATION);
return GetScheme()->EvalAdd(ciphertext, plaintext);
}
inline Ciphertext<Element> EvalAdd(Plaintext& plaintext, ConstCiphertext<Element>& ciphertext) const {
return EvalAdd(ciphertext, plaintext);
}
void EvalAddInPlace(Ciphertext<Element>& ciphertext, Plaintext& plaintext) const {
TypeCheck(ciphertext, plaintext);
plaintext->SetFormat(EVALUATION);
GetScheme()->EvalAddInPlace(ciphertext, plaintext);
}
void EvalAddInPlace(Plaintext& plaintext, Ciphertext<Element>& ciphertext) const {
EvalAddInPlace(ciphertext, plaintext);
}
Ciphertext<Element> EvalAddMutable(Ciphertext<Element>& ciphertext, Plaintext& plaintext) const {
TypeCheck(ciphertext, plaintext);
plaintext->SetFormat(EVALUATION);
return GetScheme()->EvalAddMutable(ciphertext, plaintext);
}
Ciphertext<Element> EvalAddMutable(Plaintext& plaintext, Ciphertext<Element>& ciphertext) const {
return EvalAddMutable(ciphertext, plaintext);
}
Ciphertext<Element> EvalAdd(ConstCiphertext<Element>& ciphertext, double scalar) const {
return scalar >= 0. ? GetScheme()->EvalAdd(ciphertext, scalar) : GetScheme()->EvalSub(ciphertext, -scalar);
}
Ciphertext<Element> EvalAdd(double scalar, ConstCiphertext<Element>& ciphertext) const {
return EvalAdd(ciphertext, scalar);
}
void EvalAddInPlace(Ciphertext<Element>& ciphertext, double scalar) const {
if (scalar == 0.)
return;
if (scalar > 0.)
GetScheme()->EvalAddInPlace(ciphertext, scalar);
else
GetScheme()->EvalSubInPlace(ciphertext, -scalar);
}
void EvalAddInPlace(double scalar, Ciphertext<Element>& ciphertext) const {
EvalAddInPlace(ciphertext, scalar);
}
Ciphertext<Element> EvalAdd(ConstCiphertext<Element>& ciphertext, std::complex<double> scalar) const {
return GetScheme()->EvalAdd(ciphertext, scalar);
}
Ciphertext<Element> EvalAdd(std::complex<double> scalar, ConstCiphertext<Element>& ciphertext) const {
return EvalAdd(ciphertext, scalar);
}
void EvalAddInPlace(Ciphertext<Element>& ciphertext, std::complex<double> scalar) const {
if (scalar == std::complex<double>(0.0, 0.0))
return;
GetScheme()->EvalAddInPlace(ciphertext, scalar);
}
void EvalAddInPlace(std::complex<double> scalar, Ciphertext<Element>& ciphertext) const {
EvalAddInPlace(ciphertext, scalar);
}
//------------------------------------------------------------------------------
// SHE SUBTRACTION Wrapper
//------------------------------------------------------------------------------
Ciphertext<Element> EvalSub(ConstCiphertext<Element>& ciphertext1, ConstCiphertext<Element>& ciphertext2) const {
TypeCheck(ciphertext1, ciphertext2);
return GetScheme()->EvalSub(ciphertext1, ciphertext2);
}
void EvalSubInPlace(Ciphertext<Element>& ciphertext1, ConstCiphertext<Element>& ciphertext2) const {
TypeCheck(ciphertext1, ciphertext2);
GetScheme()->EvalSubInPlace(ciphertext1, ciphertext2);
}
Ciphertext<Element> EvalSubMutable(Ciphertext<Element>& ciphertext1, Ciphertext<Element>& ciphertext2) const {
TypeCheck(ciphertext1, ciphertext2);
return GetScheme()->EvalSubMutable(ciphertext1, ciphertext2);
}
void EvalSubMutableInPlace(Ciphertext<Element>& ciphertext1, Ciphertext<Element>& ciphertext2) const {
TypeCheck(ciphertext1, ciphertext2);
GetScheme()->EvalSubMutableInPlace(ciphertext1, ciphertext2);
}
Ciphertext<Element> EvalSub(ConstCiphertext<Element>& ciphertext, Plaintext& plaintext) const {
TypeCheck(ciphertext, plaintext);
return GetScheme()->EvalSub(ciphertext, plaintext);
}
Ciphertext<Element> EvalSub(Plaintext& plaintext, ConstCiphertext<Element>& ciphertext) const {
return EvalAdd(EvalNegate(ciphertext), plaintext);
}
Ciphertext<Element> EvalSubMutable(Ciphertext<Element>& ciphertext, Plaintext& plaintext) const {
TypeCheck(ciphertext, plaintext);
return GetScheme()->EvalSubMutable(ciphertext, plaintext);
}
Ciphertext<Element> EvalSubMutable(Plaintext& plaintext, Ciphertext<Element>& ciphertext) const {
Ciphertext<Element> negated = EvalNegate(ciphertext);
Ciphertext<Element> result = EvalAddMutable(negated, plaintext);
ciphertext = EvalNegate(negated);
return result;
}
void EvalSubInPlace(Ciphertext<Element>& ciphertext, ConstPlaintext& plaintext) const {
TypeCheck(ciphertext, plaintext);
GetScheme()->EvalSubInPlace(ciphertext, plaintext);
}
void EvalSubInPlace(Plaintext& plaintext, Ciphertext<Element>& ciphertext) const {
EvalNegateInPlace(ciphertext);
EvalAddInPlace(ciphertext, plaintext);
}
Ciphertext<Element> EvalSub(ConstCiphertext<Element>& ciphertext, double scalar) const {
return scalar >= 0 ? GetScheme()->EvalSub(ciphertext, scalar) : GetScheme()->EvalAdd(ciphertext, -scalar);
}
Ciphertext<Element> EvalSub(double scalar, ConstCiphertext<Element>& ciphertext) const {
return EvalAdd(EvalNegate(ciphertext), scalar);
}
void EvalSubInPlace(Ciphertext<Element>& ciphertext, double scalar) const {
if (scalar == 0.)
return;
if (scalar > 0.)
GetScheme()->EvalSubInPlace(ciphertext, scalar);
else
GetScheme()->EvalAddInPlace(ciphertext, -scalar);
}
void EvalSubInPlace(double scalar, Ciphertext<Element>& ciphertext) const {
EvalNegateInPlace(ciphertext);
EvalAddInPlace(ciphertext, scalar);
}
Ciphertext<Element> EvalSub(ConstCiphertext<Element>& ciphertext, std::complex<double> scalar) const {
return GetScheme()->EvalAdd(ciphertext, -scalar);
}
Ciphertext<Element> EvalSub(std::complex<double> scalar, ConstCiphertext<Element>& ciphertext) const {
return EvalAdd(EvalNegate(ciphertext), scalar);
}
void EvalSubInPlace(Ciphertext<Element>& ciphertext, std::complex<double> scalar) const {
if (scalar == std::complex<double>(0.0, 0.0))
return;
GetScheme()->EvalAddInPlace(ciphertext, -scalar);
}
void EvalSubInPlace(std::complex<double> scalar, Ciphertext<Element>& ciphertext) const {
EvalNegateInPlace(ciphertext);
EvalAddInPlace(ciphertext, scalar);
}
//------------------------------------------------------------------------------
// SHE MULTIPLICATION Wrapper
//------------------------------------------------------------------------------
void EvalMultKeyGen(const PrivateKey<Element>& key);
void EvalMultKeysGen(const PrivateKey<Element>& key);
Ciphertext<Element> EvalMult(ConstCiphertext<Element>& ciphertext1, ConstCiphertext<Element>& ciphertext2) const {
TypeCheck(ciphertext1, ciphertext2);
const auto& evalKeyVec = CryptoContextImpl<Element>::GetEvalMultKeyVector(ciphertext1->GetKeyTag());
if (evalKeyVec.empty())
OPENFHE_THROW("Evaluation key has not been generated for EvalMult");
return GetScheme()->EvalMult(ciphertext1, ciphertext2, evalKeyVec[0]);
}
Ciphertext<Element> EvalMultMutable(Ciphertext<Element>& ciphertext1, Ciphertext<Element>& ciphertext2) const {
TypeCheck(ciphertext1, ciphertext2);
const auto& evalKeyVec = CryptoContextImpl<Element>::GetEvalMultKeyVector(ciphertext1->GetKeyTag());
if (evalKeyVec.empty())
OPENFHE_THROW("Evaluation key has not been generated for EvalMultMutable");
return GetScheme()->EvalMultMutable(ciphertext1, ciphertext2, evalKeyVec[0]);
}
void EvalMultMutableInPlace(Ciphertext<Element>& ciphertext1, Ciphertext<Element>& ciphertext2) const {
TypeCheck(ciphertext1, ciphertext2);
const auto& evalKeyVec = CryptoContextImpl<Element>::GetEvalMultKeyVector(ciphertext1->GetKeyTag());
if (evalKeyVec.empty())
OPENFHE_THROW("Evaluation key has not been generated for EvalMultMutableInPlace");
GetScheme()->EvalMultMutableInPlace(ciphertext1, ciphertext2, evalKeyVec[0]);
}
Ciphertext<Element> EvalSquare(ConstCiphertext<Element>& ciphertext) const {
ValidateCiphertext(ciphertext);
const auto& evalKeyVec = CryptoContextImpl<Element>::GetEvalMultKeyVector(ciphertext->GetKeyTag());
if (evalKeyVec.empty())
OPENFHE_THROW("Evaluation key has not been generated for EvalSquare");
return GetScheme()->EvalSquare(ciphertext, evalKeyVec[0]);
}
Ciphertext<Element> EvalSquareMutable(Ciphertext<Element>& ciphertext) const {
ValidateCiphertext(ciphertext);
const auto& evalKeyVec = CryptoContextImpl<Element>::GetEvalMultKeyVector(ciphertext->GetKeyTag());
if (evalKeyVec.empty())
OPENFHE_THROW("Evaluation key has not been generated for EvalSquareMutable");
return GetScheme()->EvalSquareMutable(ciphertext, evalKeyVec[0]);
}
void EvalSquareInPlace(Ciphertext<Element>& ciphertext) const {
ValidateCiphertext(ciphertext);
const auto& evalKeyVec = CryptoContextImpl<Element>::GetEvalMultKeyVector(ciphertext->GetKeyTag());
if (evalKeyVec.empty())
OPENFHE_THROW("Evaluation key has not been generated for EvalSquareInPlace");
GetScheme()->EvalSquareInPlace(ciphertext, evalKeyVec[0]);
}
Ciphertext<Element> EvalMultNoRelin(ConstCiphertext<Element>& ciphertext1,
ConstCiphertext<Element>& ciphertext2) const {
TypeCheck(ciphertext1, ciphertext2);
return GetScheme()->EvalMult(ciphertext1, ciphertext2);
}
Ciphertext<Element> EvalMultNoRelinNoCheck(ConstCiphertext<Element>& ctxt1, ConstCiphertext<Element>& ctxt2) const {
auto& cv1 = ctxt1->GetElements();
auto& cv2 = ctxt2->GetElements();
uint32_t n1 = cv1.size();
uint32_t n2 = cv2.size();
uint32_t nr = n1 + n2 - 1;
std::vector<DCRTPoly> cvr;
cvr.reserve(nr);
if (n1 == 2 && n2 == 2) {
cvr.emplace_back(cv1[0] * cv2[0]);
cvr.emplace_back((cv1[0] * cv2[1]) += (cv1[1] * cv2[0]));
cvr.emplace_back(cv1[1] * cv2[1]);
}
else {
uint32_t m = 0;
for (uint32_t i = 0; i < n1; ++i) {
auto& cv1i = cv1[i];
for (uint32_t j = 0, k = i; j < n2; ++j, ++k) {
if (k == m) {
cvr.emplace_back(cv1i * cv2[j]);
++m;
}
else {
cvr[k] += (cv1i * cv2[j]);
}
}
}
}
auto result = ctxt1->CloneEmpty();
result->SetElements(std::move(cvr));
result->SetNoiseScaleDeg(ctxt1->GetNoiseScaleDeg() + ctxt2->GetNoiseScaleDeg());
result->SetScalingFactor(ctxt1->GetScalingFactor() * ctxt2->GetScalingFactor());
result->SetScalingFactorInt(ctxt1->GetScalingFactorInt().ModMul(
ctxt2->GetScalingFactorInt(), ctxt1->GetCryptoParameters()->GetPlaintextModulus()));
return result;
}
Ciphertext<Element> Relinearize(ConstCiphertext<Element>& ciphertext) const {
// input parameter check
if (!ciphertext)
OPENFHE_THROW("Input ciphertext is nullptr");
const auto& evalKeyVec = CryptoContextImpl<Element>::GetEvalMultKeyVector(ciphertext->GetKeyTag());
if (evalKeyVec.size() < (ciphertext->NumberCiphertextElements() - 2))
OPENFHE_THROW("Insufficient value was used for maxRelinSkDeg to generate keys for Relinearize");
return GetScheme()->Relinearize(ciphertext, evalKeyVec);
}
void RelinearizeInPlace(Ciphertext<Element>& ciphertext) const {
// input parameter check
if (!ciphertext)
OPENFHE_THROW("Input ciphertext is nullptr");
const auto& evalKeyVec = CryptoContextImpl<Element>::GetEvalMultKeyVector(ciphertext->GetKeyTag());
if (evalKeyVec.size() < (ciphertext->NumberCiphertextElements() - 2))
OPENFHE_THROW("Insufficient value was used for maxRelinSkDeg to generate keys for RelinearizeInPlace");
GetScheme()->RelinearizeInPlace(ciphertext, evalKeyVec);
}
Ciphertext<Element> EvalMultAndRelinearize(ConstCiphertext<Element>& ciphertext1,
ConstCiphertext<Element>& ciphertext2) const {
if (!ciphertext1 || !ciphertext2)
OPENFHE_THROW("Input ciphertext is nullptr");
const auto& evalKeyVec = CryptoContextImpl<Element>::GetEvalMultKeyVector(ciphertext1->GetKeyTag());
if (evalKeyVec.size() <
(ciphertext1->NumberCiphertextElements() + ciphertext2->NumberCiphertextElements() - 3)) {
OPENFHE_THROW("Insufficient value was used for maxRelinSkDeg to generate keys for EvalMultAndRelinearize");
}
return GetScheme()->EvalMultAndRelinearize(ciphertext1, ciphertext2, evalKeyVec);
}
Ciphertext<Element> EvalMultNoCheck(ConstCiphertext<Element>& ctxt, NativeInteger k) const {
auto result = ctxt->Clone();
auto& cv = result->GetElements();
uint32_t n = cv.size();
for (uint32_t i = 0; i < n; ++i)
cv[i] *= k;
return result;
}
Ciphertext<Element> EvalMult(ConstCiphertext<Element>& ciphertext, ConstPlaintext& plaintext) const {
TypeCheck(ciphertext, plaintext);
return GetScheme()->EvalMult(ciphertext, plaintext);
}
Ciphertext<Element> EvalMult(ConstPlaintext& plaintext, ConstCiphertext<Element>& ciphertext) const {
return EvalMult(ciphertext, plaintext);
}
Ciphertext<Element> EvalMultMutable(Ciphertext<Element>& ciphertext, Plaintext& plaintext) const {
TypeCheck(ciphertext, plaintext);
return GetScheme()->EvalMultMutable(ciphertext, plaintext);
}
Ciphertext<Element> EvalMultMutable(Plaintext& plaintext, Ciphertext<Element>& ciphertext) const {
return EvalMultMutable(ciphertext, plaintext);
}
Ciphertext<Element> EvalMult(ConstCiphertext<Element>& ciphertext, double scalar) const {
if (!ciphertext)
OPENFHE_THROW("Input ciphertext is nullptr");
return GetScheme()->EvalMult(ciphertext, scalar);
}
inline Ciphertext<Element> EvalMult(double scalar, ConstCiphertext<Element>& ciphertext) const {
return EvalMult(ciphertext, scalar);
}
void EvalMultInPlace(Ciphertext<Element>& ciphertext, double scalar) const {
if (!ciphertext)
OPENFHE_THROW("Input ciphertext is nullptr");
GetScheme()->EvalMultInPlace(ciphertext, scalar);
}
inline void EvalMultInPlace(double scalar, Ciphertext<Element>& ciphertext) const {
EvalMultInPlace(ciphertext, scalar);
}
Ciphertext<Element> EvalMult(ConstCiphertext<Element>& ciphertext, std::complex<double> scalar) const {
if (!ciphertext)
OPENFHE_THROW("Input ciphertext is nullptr");
return GetScheme()->EvalMult(ciphertext, scalar);
}
inline Ciphertext<Element> EvalMult(std::complex<double> scalar, ConstCiphertext<Element>& ciphertext) const {
return EvalMult(ciphertext, scalar);
}
void EvalMultInPlace(Ciphertext<Element>& ciphertext, std::complex<double> scalar) const {
if (!ciphertext)
OPENFHE_THROW("Input ciphertext is nullptr");
GetScheme()->EvalMultInPlace(ciphertext, scalar);
}
inline void EvalMultInPlace(std::complex<double> scalar, Ciphertext<Element>& ciphertext) const {
EvalMultInPlace(ciphertext, scalar);
}
//------------------------------------------------------------------------------
// SHE AUTOMORPHISM Wrapper
//------------------------------------------------------------------------------
std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> EvalAutomorphismKeyGen(
const PrivateKey<Element> privateKey, const std::vector<uint32_t>& indexList) const {
ValidateKey(privateKey);
if (indexList.empty())
OPENFHE_THROW("Input index vector is empty");
auto evalKeys = GetScheme()->EvalAutomorphismKeyGen(privateKey, indexList);
CryptoContextImpl<Element>::InsertEvalAutomorphismKey(evalKeys, privateKey->GetKeyTag());
return evalKeys;
}
Ciphertext<Element> EvalAutomorphism(ConstCiphertext<Element>& ciphertext, uint32_t i,
const std::map<uint32_t, EvalKey<Element>>& evalKeyMap,
CALLER_INFO_ARGS_HDR) const {
ValidateCiphertext(ciphertext);
if (evalKeyMap.empty())
OPENFHE_THROW(std::string("Empty input key map") + CALLER_INFO);
auto key = evalKeyMap.find(i);
if (key == evalKeyMap.end())
OPENFHE_THROW(std::string("Could not find an EvalKey for index ") + std::to_string(i) + CALLER_INFO);
auto evalKey = key->second;
ValidateKey(evalKey);
return GetScheme()->EvalAutomorphism(ciphertext, i, evalKeyMap);
}
uint32_t FindAutomorphismIndex(const uint32_t idx) const {
const auto cryptoParams = GetCryptoParameters();
const auto elementParams = cryptoParams->GetElementParams();
uint32_t m = elementParams->GetCyclotomicOrder();
return GetScheme()->FindAutomorphismIndex(idx, m);
}
std::vector<uint32_t> FindAutomorphismIndices(const std::vector<uint32_t>& idxList) const {
std::vector<uint32_t> newIndices;
newIndices.reserve(idxList.size());
for (const auto idx : idxList) {
newIndices.emplace_back(FindAutomorphismIndex(idx));
}
return newIndices;
}
Ciphertext<Element> EvalRotate(ConstCiphertext<Element>& ciphertext, int32_t index) const {
ValidateCiphertext(ciphertext);
auto evalKeyMap = CryptoContextImpl<Element>::GetEvalAutomorphismKeyMap(ciphertext->GetKeyTag());
return GetScheme()->EvalAtIndex(ciphertext, index, evalKeyMap);
}
std::shared_ptr<std::vector<Element>> EvalFastRotationPrecompute(ConstCiphertext<Element>& ciphertext) const {
return GetScheme()->EvalFastRotationPrecompute(ciphertext);
}
Ciphertext<Element> EvalFastRotation(ConstCiphertext<Element>& ciphertext, const uint32_t index, const uint32_t m,
const std::shared_ptr<std::vector<Element>> digits) const {
return GetScheme()->EvalFastRotation(ciphertext, index, m, digits);
}
Ciphertext<Element> EvalFastRotation(ConstCiphertext<Element>& ciphertext, const uint32_t index,
const std::shared_ptr<std::vector<Element>> digits) const {
return EvalFastRotation(ciphertext, index, GetRingDimension() * 2, digits);
}
Ciphertext<Element> EvalFastRotationExt(ConstCiphertext<Element>& ciphertext, uint32_t index,
const std::shared_ptr<std::vector<Element>> digits, bool addFirst) const {
auto evalKeyMap = CryptoContextImpl<Element>::GetEvalAutomorphismKeyMap(ciphertext->GetKeyTag());
return GetScheme()->EvalFastRotationExt(ciphertext, index, digits, addFirst, evalKeyMap);
}
Ciphertext<Element> KeySwitchDown(ConstCiphertext<Element>& ciphertext) const {
ValidateCiphertext(ciphertext);
return GetScheme()->KeySwitchDown(ciphertext);
}
Element KeySwitchDownFirstElement(ConstCiphertext<Element>& ciphertext) const {
ValidateCiphertext(ciphertext);
return GetScheme()->KeySwitchDownFirstElement(ciphertext);
}
Ciphertext<Element> KeySwitchExt(ConstCiphertext<Element>& ciphertext, bool addFirst) const {
ValidateCiphertext(ciphertext);
return GetScheme()->KeySwitchExt(ciphertext, addFirst);
}
void EvalAtIndexKeyGen(const PrivateKey<Element> privateKey, const std::vector<int32_t>& indexList);
void EvalRotateKeyGen(const PrivateKey<Element> privateKey, const std::vector<int32_t>& indexList) {
EvalAtIndexKeyGen(privateKey, indexList);
};
Ciphertext<Element> EvalAtIndex(ConstCiphertext<Element>& ciphertext, int32_t index) const;
//------------------------------------------------------------------------------
// SHE Leveled Methods Wrapper
//------------------------------------------------------------------------------
Ciphertext<Element> ComposedEvalMult(ConstCiphertext<Element>& ciphertext1,
ConstCiphertext<Element>& ciphertext2) const {
ValidateCiphertext(ciphertext1);
ValidateCiphertext(ciphertext2);
auto evalKeyVec = CryptoContextImpl<Element>::GetEvalMultKeyVector(ciphertext1->GetKeyTag());
if (evalKeyVec.empty())
OPENFHE_THROW("Evaluation key has not been generated for EvalMult");
return GetScheme()->ComposedEvalMult(ciphertext1, ciphertext2, evalKeyVec[0]);
}
Ciphertext<Element> Rescale(ConstCiphertext<Element>& ciphertext) const {
ValidateCiphertext(ciphertext);
return GetScheme()->ModReduce(ciphertext, GetCompositeDegreeFromCtxt());
}
void RescaleInPlace(Ciphertext<Element>& ciphertext) const {
ValidateCiphertext(ciphertext);
GetScheme()->ModReduceInPlace(ciphertext, GetCompositeDegreeFromCtxt());
}
Ciphertext<Element> ModReduce(ConstCiphertext<Element>& ciphertext) const {
ValidateCiphertext(ciphertext);
return GetScheme()->ModReduce(ciphertext, GetCompositeDegreeFromCtxt());
}
void ModReduceInPlace(Ciphertext<Element>& ciphertext) const {
ValidateCiphertext(ciphertext);
GetScheme()->ModReduceInPlace(ciphertext, GetCompositeDegreeFromCtxt());
}
Ciphertext<Element> LevelReduce(ConstCiphertext<Element>& ciphertext, const EvalKey<Element> evalKey,
size_t levels = 1) const {
ValidateCiphertext(ciphertext);
return GetScheme()->LevelReduce(ciphertext, evalKey, levels * GetCompositeDegreeFromCtxt());
}
void LevelReduceInPlace(Ciphertext<Element>& ciphertext, const EvalKey<Element> evalKey, size_t levels = 1) const {
ValidateCiphertext(ciphertext);
if (levels > 0)
GetScheme()->LevelReduceInPlace(ciphertext, evalKey, levels * GetCompositeDegreeFromCtxt());
}
Ciphertext<Element> Compress(ConstCiphertext<Element>& ciphertext, uint32_t towersLeft = 1,
size_t noiseScaleDeg = 1) const {
if (ciphertext == nullptr)
OPENFHE_THROW("input ciphertext is invalid (has no data)");
if (towersLeft < noiseScaleDeg) {
std::string errorMsg{"Input towersLeft["};
errorMsg += std::to_string(towersLeft) + "] may not be less than noiseScaleDeg[";
errorMsg += std::to_string(noiseScaleDeg) + "]";
OPENFHE_THROW(errorMsg);
}
return GetScheme()->Compress(ciphertext, towersLeft, noiseScaleDeg);
}
//------------------------------------------------------------------------------
// Advanced SHE Wrapper
//------------------------------------------------------------------------------
Ciphertext<Element> EvalAddMany(const std::vector<Ciphertext<Element>>& ciphertextVec) const {
if (ciphertextVec.empty())
OPENFHE_THROW("Empty input ciphertext vector");
if (ciphertextVec.size() == 1)
return ciphertextVec[0];
return GetScheme()->EvalAddMany(ciphertextVec);
}
Ciphertext<Element> EvalAddManyInPlace(std::vector<Ciphertext<Element>>& ciphertextVec) const {
if (ciphertextVec.empty())
OPENFHE_THROW("Empty input ciphertext vector");
return GetScheme()->EvalAddManyInPlace(ciphertextVec);
}
Ciphertext<Element> EvalMultMany(const std::vector<Ciphertext<Element>>& ciphertextVec) const {
if (ciphertextVec.empty())
OPENFHE_THROW("Empty input ciphertext vector");
if (ciphertextVec.size() == 1)
return ciphertextVec[0];
const auto evalKeyVec = CryptoContextImpl<Element>::GetEvalMultKeyVector(ciphertextVec[0]->GetKeyTag());
if (evalKeyVec.size() < (ciphertextVec[0]->NumberCiphertextElements() - 2))
OPENFHE_THROW("Insufficient value was used for maxRelinSkDeg to generate keys");
return GetScheme()->EvalMultMany(ciphertextVec, evalKeyVec);
}
//------------------------------------------------------------------------------
// Advanced SHE LINEAR WEIGHTED SUM
//------------------------------------------------------------------------------
template <typename VectorDataType = double>
Ciphertext<Element> EvalLinearWSum(std::vector<ReadOnlyCiphertext<Element>>& ciphertextVec,
const std::vector<VectorDataType>& constantVec) const {
return GetScheme()->EvalLinearWSum(ciphertextVec, constantVec);
}
template <typename VectorDataType = double>
Ciphertext<Element> EvalLinearWSum(const std::vector<VectorDataType>& constantsVec,
std::vector<ReadOnlyCiphertext<Element>>& ciphertextVec) const {
return EvalLinearWSum(ciphertextVec, constantsVec);
}
template <typename VectorDataType = double>
Ciphertext<Element> EvalLinearWSumMutable(std::vector<Ciphertext<Element>>& ciphertextVec,
const std::vector<VectorDataType>& constantsVec) const {
return GetScheme()->EvalLinearWSumMutable(ciphertextVec, constantsVec);
}
template <typename VectorDataType = double>
Ciphertext<Element> EvalLinearWSumMutable(const std::vector<VectorDataType>& constantsVec,
std::vector<Ciphertext<Element>>& ciphertextVec) const {
return EvalLinearWSumMutable(ciphertextVec, constantsVec);
}
//------------------------------------------------------------------------------
// Advanced SHE EVAL POLYNOMIAL
//------------------------------------------------------------------------------
template <typename VectorDataType = double>
std::shared_ptr<seriesPowers<Element>> EvalPowers(ConstCiphertext<Element>& ciphertext,
const std::vector<VectorDataType>& coefficients) const {
ValidateCiphertext(ciphertext);
return GetScheme()->EvalPowers(ciphertext, coefficients);
}
template <typename VectorDataType = double>
Ciphertext<Element> EvalPoly(ConstCiphertext<Element>& ciphertext,
const std::vector<VectorDataType>& coefficients) const {
ValidateCiphertext(ciphertext);
return GetScheme()->EvalPoly(ciphertext, coefficients);
}
template <typename VectorDataType = double>
Ciphertext<Element> EvalPolyWithPrecomp(std::shared_ptr<seriesPowers<Element>> powers,
const std::vector<VectorDataType>& coefficients) const {
ValidateSeriesPowers(powers);
return GetScheme()->EvalPolyWithPrecomp(powers, coefficients);
}
template <typename VectorDataType = double>
Ciphertext<Element> EvalPolyLinear(ConstCiphertext<Element>& ciphertext,
const std::vector<VectorDataType>& coefficients) const {
ValidateCiphertext(ciphertext);
return GetScheme()->EvalPolyLinear(ciphertext, coefficients);
}
template <typename VectorDataType = double>
Ciphertext<Element> EvalPolyPS(ConstCiphertext<Element>& ciphertext,
const std::vector<VectorDataType>& coefficients) const {
ValidateCiphertext(ciphertext);
return GetScheme()->EvalPolyPS(ciphertext, coefficients);
}
//------------------------------------------------------------------------------
// Advanced SHE EVAL CHEBYSHEV SERIES
//------------------------------------------------------------------------------
template <typename VectorDataType = double>
std::shared_ptr<seriesPowers<Element>> EvalChebyPolys(ConstCiphertext<Element>& ciphertext,
const std::vector<VectorDataType>& coefficients, double a,
double b) const {
ValidateCiphertext(ciphertext);
return GetScheme()->EvalChebyPolys(ciphertext, coefficients, a, b);
}
template <typename VectorDataType = double>
Ciphertext<Element> EvalChebyshevSeries(ConstCiphertext<Element>& ciphertext,
const std::vector<VectorDataType>& coefficients, double a, double b) const {
ValidateCiphertext(ciphertext);
return GetScheme()->EvalChebyshevSeries(ciphertext, coefficients, a, b);
}
template <typename VectorDataType = double>
Ciphertext<Element> EvalChebyshevSeriesWithPrecomp(std::shared_ptr<seriesPowers<Element>> polys,
const std::vector<VectorDataType>& coefficients) const {
ValidateSeriesPowers(polys);
return GetScheme()->EvalChebyshevSeriesWithPrecomp(polys, coefficients);
}
template <typename VectorDataType = double>
Ciphertext<Element> EvalChebyshevSeriesLinear(ConstCiphertext<Element>& ciphertext,
const std::vector<VectorDataType>& coefficients, double a,
double b) const {
ValidateCiphertext(ciphertext);
return GetScheme()->EvalChebyshevSeriesLinear(ciphertext, coefficients, a, b);
}
template <typename VectorDataType = double>
Ciphertext<Element> EvalChebyshevSeriesPS(ConstCiphertext<Element>& ciphertext,
const std::vector<VectorDataType>& coefficients, double a,
double b) const {
ValidateCiphertext(ciphertext);
return GetScheme()->EvalChebyshevSeriesPS(ciphertext, coefficients, a, b);
}
Ciphertext<Element> EvalChebyshevFunction(std::function<double(double)> func, ConstCiphertext<Element>& ciphertext,
double a, double b, uint32_t degree) const;
Ciphertext<Element> EvalSin(ConstCiphertext<Element>& ciphertext, double a, double b, uint32_t degree) const;
Ciphertext<Element> EvalCos(ConstCiphertext<Element>& ciphertext, double a, double b, uint32_t degree) const;
Ciphertext<Element> EvalLogistic(ConstCiphertext<Element>& ciphertext, double a, double b, uint32_t degree) const;
Ciphertext<Element> EvalDivide(ConstCiphertext<Element>& ciphertext, double a, double b, uint32_t degree) const;
//------------------------------------------------------------------------------
// Advanced SHE EVAL SUM
//------------------------------------------------------------------------------
void EvalSumKeyGen(const PrivateKey<Element> privateKey);
std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> EvalSumRowsKeyGen(const PrivateKey<Element> privateKey,
uint32_t rowSize = 0,
uint32_t subringDim = 0);
// TODO: this is here for backwards compatibility; should remove in v2.0
std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> EvalSumRowsKeyGen(const PrivateKey<Element> privateKey,
const PublicKey<Element> publicKey,
uint32_t rowSize = 0,
uint32_t subringDim = 0);
std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> EvalSumColsKeyGen(const PrivateKey<Element> privateKey);
Ciphertext<Element> EvalSum(ConstCiphertext<Element>& ciphertext, uint32_t batchSize) const;
Ciphertext<Element> EvalSumRows(ConstCiphertext<Element>& ciphertext, uint32_t numRows,
const std::map<uint32_t, EvalKey<Element>>& evalSumKeyMap,
uint32_t subringDim = 0) const;
Ciphertext<Element> EvalSumCols(ConstCiphertext<Element>& ciphertext, uint32_t numCols,
const std::map<uint32_t, EvalKey<Element>>& evalSumKeyMap) const;
//------------------------------------------------------------------------------
// Advanced SHE EVAL INNER PRODUCT
//------------------------------------------------------------------------------
Ciphertext<Element> EvalInnerProduct(ConstCiphertext<Element>& ciphertext1, ConstCiphertext<Element>& ciphertext2,
uint32_t batchSize) const;
Ciphertext<Element> EvalInnerProduct(ConstCiphertext<Element>& ciphertext, ConstPlaintext& plaintext,
uint32_t batchSize) const;
Ciphertext<Element> EvalMerge(const std::vector<Ciphertext<Element>>& ciphertextVec) const;
//------------------------------------------------------------------------------
// PRE Wrapper
//------------------------------------------------------------------------------
EvalKey<Element> ReKeyGen(const PrivateKey<Element> oldPrivateKey, const PublicKey<Element> newPublicKey) const {
ValidateKey(oldPrivateKey);
ValidateKey(newPublicKey);
return GetScheme()->ReKeyGen(oldPrivateKey, newPublicKey);
}
EvalKey<Element> ReKeyGen(const PrivateKey<Element> originalPrivateKey,
const PrivateKey<Element> newPrivateKey) const
__attribute__((deprecated("functionality removed from OpenFHE")));
Ciphertext<Element> ReEncrypt(ConstCiphertext<Element>& ciphertext, EvalKey<Element> evalKey,
const PublicKey<Element> publicKey = nullptr) const {
ValidateCiphertext(ciphertext);
ValidateKey(evalKey);
return GetScheme()->ReEncrypt(ciphertext, evalKey, publicKey);
}
//------------------------------------------------------------------------------
// Multiparty Wrapper
//------------------------------------------------------------------------------
KeyPair<Element> MultipartyKeyGen(const std::vector<PrivateKey<Element>>& privateKeyVec) {
if (privateKeyVec.empty())
OPENFHE_THROW("Input private key vector is empty");
return GetScheme()->MultipartyKeyGen(GetContextForPointer(this), privateKeyVec, false);
}
KeyPair<Element> MultipartyKeyGen(const PublicKey<Element> publicKey, bool makeSparse = false, bool fresh = false) {
if (!publicKey)
OPENFHE_THROW("Input public key is empty");
return GetScheme()->MultipartyKeyGen(GetContextForPointer(this), publicKey, makeSparse, fresh);
}
std::vector<Ciphertext<Element>> MultipartyDecryptLead(const std::vector<Ciphertext<Element>>& ciphertextVec,
const PrivateKey<Element> privateKey) const {
ValidateKey(privateKey);
std::vector<Ciphertext<Element>> newCiphertextVec;
for (const auto& ciphertext : ciphertextVec) {
ValidateCiphertext(ciphertext);
newCiphertextVec.push_back(GetScheme()->MultipartyDecryptLead(ciphertext, privateKey));
}
return newCiphertextVec;
}
std::vector<Ciphertext<Element>> MultipartyDecryptMain(const std::vector<Ciphertext<Element>>& ciphertextVec,
const PrivateKey<Element> privateKey) const {
ValidateKey(privateKey);
std::vector<Ciphertext<Element>> newCiphertextVec;
for (const auto& ciphertext : ciphertextVec) {
ValidateCiphertext(ciphertext);
newCiphertextVec.push_back(GetScheme()->MultipartyDecryptMain(ciphertext, privateKey));
}
return newCiphertextVec;
}
DecryptResult MultipartyDecryptFusion(const std::vector<Ciphertext<Element>>& partialCiphertextVec,
Plaintext* plaintext) const {
std::string datatype = demangle(typeid(Element).name());
OPENFHE_THROW("Not implemented for " + datatype);
}
EvalKey<Element> MultiKeySwitchGen(const PrivateKey<Element> originalPrivateKey,
const PrivateKey<Element> newPrivateKey, const EvalKey<Element> evalKey) const {
if (!originalPrivateKey)
OPENFHE_THROW("Input first private key is nullptr");
if (!newPrivateKey)
OPENFHE_THROW("Input second private key is nullptr");
if (!evalKey)
OPENFHE_THROW("Input evaluation key is nullptr");
return GetScheme()->MultiKeySwitchGen(originalPrivateKey, newPrivateKey, evalKey);
}
std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> MultiEvalAutomorphismKeyGen(
const PrivateKey<Element> privateKey, const std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> evalKeyMap,
const std::vector<uint32_t>& indexList, const std::string& keyTag = "") {
if (!privateKey)
OPENFHE_THROW("Input private key is nullptr");
if (!evalKeyMap)
OPENFHE_THROW("Input evaluation key map is nullptr");
if (indexList.empty())
OPENFHE_THROW("Input index vector is empty");
return GetScheme()->MultiEvalAutomorphismKeyGen(privateKey, evalKeyMap, indexList, keyTag);
}
std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> MultiEvalAtIndexKeyGen(
const PrivateKey<Element> privateKey, const std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> evalKeyMap,
const std::vector<int32_t>& indexList, const std::string& keyTag = "") {
if (!privateKey)
OPENFHE_THROW("Input private key is nullptr");
if (!evalKeyMap)
OPENFHE_THROW("Input evaluation key map is nullptr");
if (indexList.empty())
OPENFHE_THROW("Input index vector is empty");
return GetScheme()->MultiEvalAtIndexKeyGen(privateKey, evalKeyMap, indexList, keyTag);
}
std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> MultiEvalSumKeyGen(
const PrivateKey<Element> privateKey, const std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> evalKeyMap,
const std::string& keyTag = "") {
if (!privateKey)
OPENFHE_THROW("Input private key is nullptr");
if (!evalKeyMap)
OPENFHE_THROW("Input evaluation key map is nullptr");
return GetScheme()->MultiEvalSumKeyGen(privateKey, evalKeyMap, keyTag);
}
EvalKey<Element> MultiAddEvalKeys(EvalKey<Element> evalKey1, EvalKey<Element> evalKey2,
const std::string& keyTag = "") {
if (!evalKey1)
OPENFHE_THROW("Input first evaluation key is nullptr");
if (!evalKey2)
OPENFHE_THROW("Input second evaluation key is nullptr");
return GetScheme()->MultiAddEvalKeys(evalKey1, evalKey2, keyTag);
}
EvalKey<Element> MultiMultEvalKey(PrivateKey<Element> privateKey, EvalKey<Element> evalKey,
const std::string& keyTag = "") {
if (!privateKey)
OPENFHE_THROW("Input private key is nullptr");
if (!evalKey)
OPENFHE_THROW("Input evaluation key is nullptr");
return GetScheme()->MultiMultEvalKey(privateKey, evalKey, keyTag);
}
std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> MultiAddEvalSumKeys(
const std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> evalKeyMap1,
const std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> evalKeyMap2, const std::string& keyTag = "") {
if (!evalKeyMap1)
OPENFHE_THROW("Input first evaluation key map is nullptr");
if (!evalKeyMap2)
OPENFHE_THROW("Input second evaluation key map is nullptr");
return GetScheme()->MultiAddEvalSumKeys(evalKeyMap1, evalKeyMap2, keyTag);
}
std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> MultiAddEvalAutomorphismKeys(
const std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> evalKeyMap1,
const std::shared_ptr<std::map<uint32_t, EvalKey<Element>>> evalKeyMap2, const std::string& keyTag = "") {
if (!evalKeyMap1)
OPENFHE_THROW("Input first evaluation key map is nullptr");
if (!evalKeyMap2)
OPENFHE_THROW("Input second evaluation key map is nullptr");
return GetScheme()->MultiAddEvalAutomorphismKeys(evalKeyMap1, evalKeyMap2, keyTag);
}
PublicKey<Element> MultiAddPubKeys(PublicKey<Element> publicKey1, PublicKey<Element> publicKey2,
const std::string& keyTag = "") {
if (!publicKey1)
OPENFHE_THROW("Input first public key is nullptr");
if (!publicKey2)
OPENFHE_THROW("Input second public key is nullptr");
return GetScheme()->MultiAddPubKeys(publicKey1, publicKey2, keyTag);
}
EvalKey<Element> MultiAddEvalMultKeys(EvalKey<Element> evalKey1, EvalKey<Element> evalKey2,
const std::string& keyTag = "") {
if (!evalKey1)
OPENFHE_THROW("Input first evaluation key is nullptr");
if (!evalKey2)
OPENFHE_THROW("Input second evaluation key is nullptr");
return GetScheme()->MultiAddEvalMultKeys(evalKey1, evalKey2, keyTag);
}
Ciphertext<Element> IntBootDecrypt(const PrivateKey<Element> privateKey,
ConstCiphertext<Element>& ciphertext) const {
ValidateCiphertext(ciphertext);
ValidateKey(privateKey);
return GetScheme()->IntBootDecrypt(privateKey, ciphertext);
}
Ciphertext<Element> IntBootEncrypt(const PublicKey<Element> publicKey, ConstCiphertext<Element>& ciphertext) const {
ValidateCiphertext(ciphertext);
ValidateKey(publicKey);
return GetScheme()->IntBootEncrypt(publicKey, ciphertext);
}
Ciphertext<Element> IntBootAdd(ConstCiphertext<Element>& ciphertext1, ConstCiphertext<Element>& ciphertext2) const {
ValidateCiphertext(ciphertext1);
ValidateCiphertext(ciphertext2);
return GetScheme()->IntBootAdd(ciphertext1, ciphertext2);
}
Ciphertext<Element> IntBootAdjustScale(ConstCiphertext<Element>& ciphertext) const {
ValidateCiphertext(ciphertext);
return GetScheme()->IntBootAdjustScale(ciphertext);
}
Ciphertext<Element> IntMPBootAdjustScale(ConstCiphertext<Element>& ciphertext) const;
Ciphertext<Element> IntMPBootRandomElementGen(const PublicKey<Element> publicKey) const;
Ciphertext<Element> IntMPBootRandomElementGen(ConstCiphertext<Element>& ciphertext) const;
std::vector<Ciphertext<Element>> IntMPBootDecrypt(const PrivateKey<Element> privateKey,
ConstCiphertext<Element>& ciphertext,
ConstCiphertext<Element>& a) const;
std::vector<Ciphertext<Element>> IntMPBootAdd(std::vector<std::vector<Ciphertext<Element>>>& sharesPairVec) const;
Ciphertext<Element> IntMPBootEncrypt(const PublicKey<Element> publicKey,
const std::vector<Ciphertext<Element>>& sharesPair,
ConstCiphertext<Element>& a, ConstCiphertext<Element>& ciphertext) const;
std::unordered_map<uint32_t, Element> ShareKeys(const PrivateKey<Element>& sk, uint32_t N, uint32_t threshold,
uint32_t index, const std::string& shareType) const {
std::string datatype = demangle(typeid(Element).name());
OPENFHE_THROW("Not implemented for " + datatype);
}
void RecoverSharedKey(PrivateKey<Element>& sk, std::unordered_map<uint32_t, Element>& sk_shares, uint32_t N,
uint32_t threshold, const std::string& shareType) const;
//------------------------------------------------------------------------------
// FHE Bootstrap Methods
//------------------------------------------------------------------------------
void EvalBootstrapSetup(std::vector<uint32_t> levelBudget = {5, 4}, std::vector<uint32_t> dim1 = {0, 0},
uint32_t slots = 0, uint32_t correctionFactor = 0, bool precompute = true,
bool BTSlotsEncoding = false) {
GetScheme()->EvalBootstrapSetup(*this, levelBudget, dim1, slots, correctionFactor, precompute, BTSlotsEncoding);
}
void EvalBootstrapKeyGen(const PrivateKey<Element> privateKey, uint32_t slots) {
ValidateKey(privateKey);
auto evalKeys = GetScheme()->EvalBootstrapKeyGen(privateKey, slots);
CryptoContextImpl<Element>::InsertEvalAutomorphismKey(evalKeys, privateKey->GetKeyTag());
}
void EvalBootstrapPrecompute(uint32_t slots = 0) {
GetScheme()->EvalBootstrapPrecompute(*this, slots);
}
Ciphertext<Element> EvalBootstrap(ConstCiphertext<Element>& ciphertext, uint32_t numIterations = 1,
uint32_t precision = 0) const {
return GetScheme()->EvalBootstrap(ciphertext, numIterations, precision);
}
Ciphertext<Element> EvalBootstrapStCFirst(ConstCiphertext<Element>& ciphertext, uint32_t numIterations = 1,
uint32_t precision = 0) const {
return GetScheme()->EvalBootstrapStCFirst(ciphertext, numIterations, precision);
}
template <typename VectorDataType>
void EvalFBTSetup(const std::vector<VectorDataType>& coeffs, uint32_t numSlots, const BigInteger& PIn,
const BigInteger& POut, const BigInteger& Bigq, const PublicKey<DCRTPoly>& pubKey,
const std::vector<uint32_t>& dim1, const std::vector<uint32_t>& levelBudget,
uint32_t lvlsAfterBoot = 0, uint32_t depthLeveledComputation = 0, size_t order = 1) {
GetScheme()->EvalFBTSetup(*this, coeffs, numSlots, PIn, POut, Bigq, pubKey, dim1, levelBudget, lvlsAfterBoot,
depthLeveledComputation, order);
}
template <typename VectorDataType>
Ciphertext<Element> EvalFBT(ConstCiphertext<Element>& ciphertext, const std::vector<VectorDataType>& coeffs,
uint32_t digitBitSize, const BigInteger& initialScaling, uint64_t postScaling,
uint32_t levelToReduce = 0, size_t order = 1) {
return GetScheme()->EvalFBT(ciphertext, coeffs, digitBitSize, initialScaling, postScaling, levelToReduce,
order);
}
template <typename VectorDataType>
Ciphertext<Element> EvalFBTNoDecoding(ConstCiphertext<Element>& ciphertext,
const std::vector<VectorDataType>& coeffs, uint32_t digitBitSize,
const BigInteger& initialScaling, size_t order = 1) {
return GetScheme()->EvalFBTNoDecoding(ciphertext, coeffs, digitBitSize, initialScaling, order);
}
Ciphertext<Element> EvalHomDecoding(ConstCiphertext<Element>& ciphertext, uint64_t postScaling,
uint32_t levelToReduce = 0) {
return GetScheme()->EvalHomDecoding(ciphertext, postScaling, levelToReduce);
}
template <typename VectorDataType>
std::shared_ptr<seriesPowers<Element>> EvalMVBPrecompute(ConstCiphertext<Element>& ciphertext,
const std::vector<VectorDataType>& coeffs,
uint32_t digitBitSize, const BigInteger& initialScaling,
size_t order = 1) {
return GetScheme()->EvalMVBPrecompute(ciphertext, coeffs, digitBitSize, initialScaling, order);
}
template <typename VectorDataType>
Ciphertext<Element> EvalMVB(const std::shared_ptr<seriesPowers<Element>> ciphertexts,
const std::vector<VectorDataType>& coeffs, uint32_t digitBitSize,
const uint64_t postScaling, uint32_t levelToReduce = 0, size_t order = 1) {
return GetScheme()->EvalMVB(ciphertexts, coeffs, digitBitSize, postScaling, levelToReduce, order);
}
template <typename VectorDataType>
Ciphertext<Element> EvalMVBNoDecoding(const std::shared_ptr<seriesPowers<Element>> ciphertexts,
const std::vector<VectorDataType>& coeffs, uint32_t digitBitSize,
size_t order = 1) {
return GetScheme()->EvalMVBNoDecoding(ciphertexts, coeffs, digitBitSize, order);
}
template <typename VectorDataType>
Ciphertext<Element> EvalHermiteTrigSeries(ConstCiphertext<Element>& ciphertext,
const std::vector<std::complex<double>>& coefficientsCheb, double a,
double b, const std::vector<VectorDataType>& coefficientsHerm,
size_t precomp = 0) {
return GetScheme()->EvalHermiteTrigSeries(ciphertext, coefficientsCheb, a, b, coefficientsHerm, precomp);
}
uint32_t GetCKKSBootCorrectionFactor() {
return GetScheme()->GetCKKSBootCorrectionFactor();
}
void SetCKKSBootCorrectionFactor(uint32_t cf) {
return GetScheme()->SetCKKSBootCorrectionFactor(cf);
}
//------------------------------------------------------------------------------
// Scheme switching Methods
//------------------------------------------------------------------------------
LWEPrivateKey EvalCKKStoFHEWSetup(SchSwchParams params) {
VerifyCKKSScheme(__func__);
VerifyCKKSRealDataType(__func__);
SetParamsFromCKKSCryptocontext(params);
return GetScheme()->EvalCKKStoFHEWSetup(params);
}
void EvalCKKStoFHEWKeyGen(const KeyPair<Element>& keyPair, ConstLWEPrivateKey& lwesk) {
VerifyCKKSScheme(__func__);
VerifyCKKSRealDataType(__func__);
ValidateKey(keyPair.secretKey);
if (!lwesk)
OPENFHE_THROW("FHEW private key passed to EvalCKKStoFHEWKeyGen is null");
auto evalKeys = GetScheme()->EvalCKKStoFHEWKeyGen(keyPair, lwesk);
CryptoContextImpl<Element>::InsertEvalAutomorphismKey(evalKeys, keyPair.secretKey->GetKeyTag());
}
void EvalCKKStoFHEWPrecompute(double scale = 1.0) {
VerifyCKKSScheme(__func__);
VerifyCKKSRealDataType(__func__);
GetScheme()->EvalCKKStoFHEWPrecompute(*this, scale);
}
std::vector<std::shared_ptr<LWECiphertextImpl>> EvalCKKStoFHEW(ConstCiphertext<Element>& ciphertext,
uint32_t numCtxts = 0) {
VerifyCKKSScheme(__func__);
VerifyCKKSRealDataType(__func__);
if (ciphertext == nullptr)
OPENFHE_THROW("ciphertext passed to EvalCKKStoFHEW is empty");
return GetScheme()->EvalCKKStoFHEW(ciphertext, numCtxts);
}
void EvalFHEWtoCKKSSetup(const std::shared_ptr<BinFHEContext>& ccLWE, uint32_t numSlotsCKKS = 0,
uint32_t logQ = 25) {
VerifyCKKSScheme(__func__);
VerifyCKKSRealDataType(__func__);
GetScheme()->EvalFHEWtoCKKSSetup(*this, ccLWE, numSlotsCKKS, logQ);
}
void EvalFHEWtoCKKSKeyGen(const KeyPair<Element>& keyPair, ConstLWEPrivateKey& lwesk, uint32_t numSlots = 0,
uint32_t numCtxts = 0, uint32_t dim1 = 0, uint32_t L = 0) {
VerifyCKKSScheme(__func__);
VerifyCKKSRealDataType(__func__);
ValidateKey(keyPair.secretKey);
auto evalKeys = GetScheme()->EvalFHEWtoCKKSKeyGen(keyPair, lwesk, numSlots, numCtxts, dim1, L);
CryptoContextImpl<Element>::InsertEvalAutomorphismKey(evalKeys, keyPair.secretKey->GetKeyTag());
}
Ciphertext<Element> EvalFHEWtoCKKS(std::vector<std::shared_ptr<LWECiphertextImpl>>& LWECiphertexts,
uint32_t numCtxts = 0, uint32_t numSlots = 0, uint32_t p = 4, double pmin = 0.0,
double pmax = 2.0, uint32_t dim1 = 0) const {
VerifyCKKSScheme(__func__);
VerifyCKKSRealDataType(__func__);
return GetScheme()->EvalFHEWtoCKKS(LWECiphertexts, numCtxts, numSlots, p, pmin, pmax, dim1);
}
void SetParamsFromCKKSCryptocontext(SchSwchParams& params) {
const auto cryptoParams = std::dynamic_pointer_cast<CryptoParametersCKKSRNS>(GetCryptoParameters());
if (!cryptoParams)
OPENFHE_THROW("std::dynamic_pointer_cast<CryptoParametersCKKSRNS>() failed");
params.SetInitialCKKSModulus(cryptoParams->GetElementParams()->GetParams()[0]->GetModulus());
params.SetRingDimension(GetRingDimension());
// TODO (dsuponit): is this correct - PlaintextModulus used as scalingModSize?
params.SetScalingModSize(GetEncodingParams()->GetPlaintextModulus());
params.SetBatchSize(GetEncodingParams()->GetBatchSize());
params.SetParamsFromCKKSCryptocontextCalled();
}
LWEPrivateKey EvalSchemeSwitchingSetup(SchSwchParams& params) {
VerifyCKKSScheme(__func__);
VerifyCKKSRealDataType(__func__);
SetParamsFromCKKSCryptocontext(params);
return GetScheme()->EvalSchemeSwitchingSetup(params);
}
void EvalSchemeSwitchingKeyGen(const KeyPair<Element>& keyPair, ConstLWEPrivateKey& lwesk) {
VerifyCKKSScheme(__func__);
VerifyCKKSRealDataType(__func__);
ValidateKey(keyPair.secretKey);
auto evalKeys = GetScheme()->EvalSchemeSwitchingKeyGen(keyPair, lwesk);
CryptoContextImpl<Element>::InsertEvalAutomorphismKey(evalKeys, keyPair.secretKey->GetKeyTag());
}
void EvalCompareSwitchPrecompute(uint32_t pLWE = 0, double scaleSign = 1.0, bool unit = false) {
VerifyCKKSScheme(__func__);
VerifyCKKSRealDataType(__func__);
GetScheme()->EvalCompareSwitchPrecompute(*this, pLWE, scaleSign, unit);
}
Ciphertext<Element> EvalCompareSchemeSwitching(ConstCiphertext<Element>& ciphertext1,
ConstCiphertext<Element>& ciphertext2, uint32_t numCtxts = 0,
uint32_t numSlots = 0, uint32_t pLWE = 0, double scaleSign = 1.0,
bool unit = false) {
VerifyCKKSScheme(__func__);
VerifyCKKSRealDataType(__func__);
ValidateCiphertext(ciphertext1);
ValidateCiphertext(ciphertext2);
return GetScheme()->EvalCompareSchemeSwitching(ciphertext1, ciphertext2, numCtxts, numSlots, pLWE, scaleSign,
unit);
}
std::vector<Ciphertext<Element>> EvalMinSchemeSwitching(ConstCiphertext<Element>& ciphertext,
PublicKey<Element>& publicKey, uint32_t numValues = 0,
uint32_t numSlots = 0, uint32_t pLWE = 0,
double scaleSign = 1.0) {
VerifyCKKSScheme(__func__);
VerifyCKKSRealDataType(__func__);
ValidateCiphertext(ciphertext);
return GetScheme()->EvalMinSchemeSwitching(ciphertext, publicKey, numValues, numSlots, pLWE, scaleSign);
}
std::vector<Ciphertext<Element>> EvalMinSchemeSwitchingAlt(ConstCiphertext<Element>& ciphertext,
PublicKey<Element>& publicKey, uint32_t numValues = 0,
uint32_t numSlots = 0, uint32_t pLWE = 0,
double scaleSign = 1.0) {
VerifyCKKSScheme(__func__);
VerifyCKKSRealDataType(__func__);
ValidateCiphertext(ciphertext);
return GetScheme()->EvalMinSchemeSwitchingAlt(ciphertext, publicKey, numValues, numSlots, pLWE, scaleSign);
}
std::vector<Ciphertext<Element>> EvalMaxSchemeSwitching(ConstCiphertext<Element>& ciphertext,
PublicKey<Element>& publicKey, uint32_t numValues = 0,
uint32_t numSlots = 0, uint32_t pLWE = 0,
double scaleSign = 1.0) {
VerifyCKKSScheme(__func__);
VerifyCKKSRealDataType(__func__);
ValidateCiphertext(ciphertext);
return GetScheme()->EvalMaxSchemeSwitching(ciphertext, publicKey, numValues, numSlots, pLWE, scaleSign);
}
std::vector<Ciphertext<Element>> EvalMaxSchemeSwitchingAlt(ConstCiphertext<Element>& ciphertext,
PublicKey<Element>& publicKey, uint32_t numValues = 0,
uint32_t numSlots = 0, uint32_t pLWE = 0,
double scaleSign = 1.0) {
VerifyCKKSScheme(__func__);
VerifyCKKSRealDataType(__func__);
ValidateCiphertext(ciphertext);
return GetScheme()->EvalMaxSchemeSwitchingAlt(ciphertext, publicKey, numValues, numSlots, pLWE, scaleSign);
}
std::shared_ptr<lbcrypto::BinFHEContext> GetBinCCForSchemeSwitch() const {
return GetScheme()->GetBinCCForSchemeSwitch();
}
void SetBinCCForSchemeSwitch(std::shared_ptr<lbcrypto::BinFHEContext> ccLWE) {
GetScheme()->SetBinCCForSchemeSwitch(ccLWE);
}
Ciphertext<Element> GetSwkFC() const {
return GetScheme()->GetSwkFC();
}
void SetSwkFC(Ciphertext<Element> FHEWtoCKKSswk) {
GetScheme()->SetSwkFC(FHEWtoCKKSswk);
}
static std::set<uint32_t> GetEvalAutomorphismNoKeyIndices(const std::string& keyTag,
const std::set<uint32_t>& indices) {
std::set<uint32_t> existingIndices{CryptoContextImpl<Element>::GetExistingEvalAutomorphismKeyIndices(keyTag)};
// if no index found for the given keyTag, then the entire set "indices" is returned
return (existingIndices.empty()) ? indices :
CryptoContextImpl<Element>::GetUniqueValues(existingIndices, indices);
}
static std::set<uint32_t> GetExistingEvalAutomorphismKeyIndices(const std::string& keyTag);
static std::set<uint32_t> GetUniqueValues(const std::set<uint32_t>& oldValues, const std::set<uint32_t>& newValues);
template <class Archive>
void save(Archive& ar, std::uint32_t const version) const {
ar(cereal::make_nvp("cc", m_params));
ar(cereal::make_nvp("kt", m_scheme));
ar(cereal::make_nvp("si", m_schemeId));
}
template <class Archive>
void load(Archive& ar, std::uint32_t const version) {
if (version > CryptoContextImpl<Element>::SerializedVersion()) {
OPENFHE_THROW("serialized object version " + std::to_string(version) +
" is from a later version of the library");
}
ar(cereal::make_nvp("cc", m_params));
ar(cereal::make_nvp("kt", m_scheme));
ar(cereal::make_nvp("si", m_schemeId));
SetKSTechniqueInScheme();
// NOTE: a pointer to this object will be wrapped in a shared_ptr, and is a
// "CryptoContext". OpenFHE relies on the notion that identical
// CryptoContextImpls are not duplicated in memory Once we deserialize this
// object, we must check to see if there is a matching object for this
// object that's already existing in memory if it DOES exist, use it. If it
// does NOT exist, add this to the cache of all contexts
}
std::string SerializedObjectName() const override {
return "CryptoContext";
}
static uint32_t SerializedVersion() {
return 1;
}
};
// Member function specializations. Their implementations are in cryptocontext.cpp
template <>
DecryptResult CryptoContextImpl<DCRTPoly>::MultipartyDecryptFusion(
const std::vector<Ciphertext<DCRTPoly>>& partialCiphertextVec, Plaintext* plaintext) const;
template <>
std::unordered_map<uint32_t, DCRTPoly> CryptoContextImpl<DCRTPoly>::ShareKeys(const PrivateKey<DCRTPoly>& sk,
uint32_t N, uint32_t threshold,
uint32_t index,
const std::string& shareType) const;
} // namespace lbcrypto
#endif // __CRYPTOCONTEXT_H__