From 1ce9348a617fa32005b3efb386dad901bbfc6f83 Mon Sep 17 00:00:00 2001 From: dsuponitskiy <28961198+dsuponitskiy@users.noreply.github.com> Date: Fri, 25 Jul 2025 19:54:52 -0400 Subject: [PATCH 1/6] Updated the cmake version (#236) Co-authored-by: Dmitriy Suponitskiy --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 899966c..a8dd70a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 3.5.1) +cmake_minimum_required (VERSION 3.16.3) project (OpenFHE-Python) From 052b700b88a61a3320975e06a852d3ab0f83493c Mon Sep 17 00:00:00 2001 From: dsuponitskiy <28961198+dsuponitskiy@users.noreply.github.com> Date: Thu, 31 Jul 2025 09:53:35 -0400 Subject: [PATCH 2/6] 216 standardize binding (#240) * Multiple changes to bindings, removed some wrappers * Removed cryptocontext_wrapper.cpp * binfhe_bindings cleanup * binfhe_bindings cleanup (2) --------- Co-authored-by: Dmitriy Suponitskiy --- CMakeLists.txt | 1 - src/include/binfhe/binfhecontext_wrapper.h | 33 +- src/include/pke/cryptocontext_wrapper.h | 67 - src/lib/bindings.cpp | 1420 +++++++++++--------- src/lib/binfhe/binfhecontext_wrapper.cpp | 80 +- src/lib/binfhe_bindings.cpp | 407 +++--- src/lib/pke/cryptocontext_wrapper.cpp | 148 -- 7 files changed, 1008 insertions(+), 1148 deletions(-) delete mode 100644 src/include/pke/cryptocontext_wrapper.h delete mode 100644 src/lib/pke/cryptocontext_wrapper.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a8dd70a..374462a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,7 +71,6 @@ pybind11_add_module(openfhe src/lib/binfhe_bindings.cpp src/lib/binfhe/binfhecontext_wrapper.cpp src/lib/pke/serialization.cpp - src/lib/pke/cryptocontext_wrapper.cpp ) ### Python installation # Allow the user to specify the path to Python executable (if not provided, find it) diff --git a/src/include/binfhe/binfhecontext_wrapper.h b/src/include/binfhe/binfhecontext_wrapper.h index a9603de..84d4aba 100644 --- a/src/include/binfhe/binfhecontext_wrapper.h +++ b/src/include/binfhe/binfhecontext_wrapper.h @@ -31,43 +31,14 @@ #ifndef __BINFHECONTEXT_WRAPPER_H__ #define __BINFHECONTEXT_WRAPPER_H__ -#include -#include -#include "openfhe.h" #include "binfhecontext.h" -#include + +#include #include namespace py = pybind11; using namespace lbcrypto; -LWECiphertext binfhe_EncryptWrapper(BinFHEContext &self, - ConstLWEPrivateKey sk, - const LWEPlaintext &m, - BINFHE_OUTPUT output, - LWEPlaintextModulus p, - uint64_t mod); -LWEPlaintext binfhe_DecryptWrapper(BinFHEContext &self, - ConstLWEPrivateKey sk, - ConstLWECiphertext ct, - LWEPlaintextModulus p); - -uint32_t GetnWrapper(BinFHEContext &self); - -const uint64_t GetqWrapper(BinFHEContext &self) ; - -const uint64_t GetMaxPlaintextSpaceWrapper(BinFHEContext &self); - -const uint64_t GetBetaWrapper(BinFHEContext &self); - -const uint64_t GetLWECiphertextModulusWrapper(LWECiphertext &self); std::vector GenerateLUTviaFunctionWrapper(BinFHEContext &self, py::function f, uint64_t p); -NativeInteger StaticFunction(NativeInteger m, NativeInteger p); - -// Define static variables to hold the state -// extern py::function static_f; - -LWECiphertext EvalFuncWrapper(BinFHEContext &self, ConstLWECiphertext &ct, const std::vector &LUT); - #endif // __BINFHECONTEXT_WRAPPER_H__ \ No newline at end of file diff --git a/src/include/pke/cryptocontext_wrapper.h b/src/include/pke/cryptocontext_wrapper.h deleted file mode 100644 index 8981991..0000000 --- a/src/include/pke/cryptocontext_wrapper.h +++ /dev/null @@ -1,67 +0,0 @@ -//================================================================================== -// BSD 2-Clause License -// -// Copyright (c) 2023-2025, 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. -//================================================================================== -#ifndef __CRYPTOCONTEXT_WRAPPER_H__ -#define __CRYPTOCONTEXT_WRAPPER_H__ - -#include "openfhe.h" - -using namespace lbcrypto; - - -Ciphertext EvalFastRotationPrecomputeWrapper(CryptoContext &self, - ConstCiphertext ciphertext); - -Ciphertext EvalFastRotationWrapper(CryptoContext &self, - ConstCiphertext ciphertext, - uint32_t index, - uint32_t m, - ConstCiphertext digits); -Ciphertext EvalFastRotationExtWrapper(CryptoContext &self, ConstCiphertext ciphertext, uint32_t index, ConstCiphertext digits, bool addFirst); - -Plaintext DecryptWrapper(CryptoContext &self, - ConstCiphertext ciphertext, const PrivateKey privateKey); -Plaintext DecryptWrapper(CryptoContext &self, - const PrivateKey privateKey, ConstCiphertext ciphertext); -Plaintext MultipartyDecryptFusionWrapper(CryptoContext& self,const std::vector>& partialCiphertextVec); - -const std::shared_ptr>> GetEvalSumKeyMapWrapper(CryptoContext& self, const std::string &id); -PlaintextModulus GetPlaintextModulusWrapper(CryptoContext& self); -uint32_t GetBatchSizeWrapper(CryptoContext& self); -double GetModulusWrapper(CryptoContext& self); -void RemoveElementWrapper(Ciphertext& self, uint32_t index); -double GetScalingFactorRealWrapper(CryptoContext& self, uint32_t l); -uint64_t GetModulusCKKSWrapper(CryptoContext& self); -ScalingTechnique GetScalingTechniqueWrapper(CryptoContext& self); -uint32_t GetDigitSizeWrapper(CryptoContext& self); - -void ClearEvalMultKeysWrapper(); - -#endif // __CRYPTOCONTEXT_WRAPPER_H__ diff --git a/src/lib/bindings.cpp b/src/lib/bindings.cpp index ac31112..f8c1c5d 100644 --- a/src/lib/bindings.cpp +++ b/src/lib/bindings.cpp @@ -30,19 +30,18 @@ //================================================================================== #include "bindings.h" +#include "openfhe.h" + +#include "key/key-ser.h" +#include "binfhe_bindings.h" + #include #include #include #include -#include #include -#include "openfhe.h" -#include "key/key-ser.h" -#include "binfhe_bindings.h" - -#include "cryptocontext_wrapper.h" #include "cryptocontext_docs.h" #include "cryptoparameters_docs.h" #include "plaintext_docs.h" @@ -66,7 +65,7 @@ void bind_DCRTPoly(py::module &m) { } template -void bind_parameters(py::module &m,const std::string name) +void bind_parameters(py::module &m, const std::string name) { py::class_>(m, name.c_str()) .def(py::init<>()) @@ -142,36 +141,151 @@ void bind_parameters(py::module &m,const std::string name) stream << params; return stream.str(); }); +} - // - +template +void bind_crypto_context_templates(py::class_, std::shared_ptr>>& cls) { + cls.def("EvalChebyshevSeries", + static_cast (CryptoContextImpl::*)( + ConstCiphertext&, + const std::vector&, + double, + double + ) const>(&CryptoContextImpl::EvalChebyshevSeries), + py::arg("ciphertext"), + py::arg("coefficients"), + py::arg("a"), + py::arg("b"), + py::doc(cc_EvalChebyshevSeries_docs)) + .def("EvalChebyshevSeriesLinear", + static_cast (CryptoContextImpl::*)( + ConstCiphertext&, + const std::vector&, + double, + double + ) const>(&CryptoContextImpl::EvalChebyshevSeriesLinear), + py::arg("ciphertext"), + py::arg("coefficients"), + py::arg("a"), + py::arg("b"), + py::doc(cc_EvalChebyshevSeriesLinear_docs)) + .def("EvalChebyshevSeriesPS", + static_cast (CryptoContextImpl::*)( + ConstCiphertext&, + const std::vector&, + double, + double + ) const>(&CryptoContextImpl::EvalChebyshevSeriesPS), + py::arg("ciphertext"), + py::arg("coefficients"), + py::arg("a"), + py::arg("b"), + py::doc(cc_EvalChebyshevSeriesPS_docs)) + .def("EvalLinearWSum", + static_cast (CryptoContextImpl::*)( + std::vector>&, + const std::vector& + ) const>(&CryptoContextImpl::EvalLinearWSum), + py::arg("ciphertextVec"), + py::arg("constantVec"), + py::doc("Evaluate a weighted sum of ciphertexts using scalar coefficients")) + .def("EvalLinearWSumMutable", + static_cast (CryptoContextImpl::*)( + const std::vector&, + std::vector>& + ) const>(&CryptoContextImpl::EvalLinearWSumMutable), + py::arg("constantsVec"), + py::arg("ciphertextVec"), + py::doc("Evaluate a weighted sum (mutable version) with given coefficients")) + .def("EvalPoly", + static_cast (CryptoContextImpl::*)( + ConstCiphertext&, + const std::vector& + ) const>(&CryptoContextImpl::EvalPoly), + py::arg("ciphertext"), + py::arg("coefficients"), + py::doc(cc_EvalPoly_docs)) + .def("EvalPolyLinear", + static_cast (CryptoContextImpl::*)( + ConstCiphertext&, + const std::vector& + ) const>(&CryptoContextImpl::EvalPolyLinear), + py::arg("ciphertext"), + py::arg("coefficients"), + py::doc(cc_EvalPolyLinear_docs)) + .def("EvalPolyPS", + static_cast (CryptoContextImpl::*)( + ConstCiphertext&, + const std::vector& + ) const>(&CryptoContextImpl::EvalPolyPS), + py::arg("ciphertext"), + py::arg("coefficients"), + py::doc(cc_EvalPolyPS_docs)) + ; } void bind_crypto_context(py::module &m) { //Parameters Type - /*TODO (Oliveira): If we expose Poly's and ParmType, this block will go somewhere else */ + // TODO (Oliveira): If we expose Poly's and ParmType, this block will go somewhere else using ParmType = typename DCRTPoly::Params; using ParmTypePtr = std::shared_ptr; py::class_(m, "ParmType"); - py::class_, std::shared_ptr>>(m, "CryptoContext") - .def(py::init<>()) + auto cc_class = py::class_, std::shared_ptr>>(m, "CryptoContext"); + + cc_class.def(py::init<>()) .def("GetKeyGenLevel", &CryptoContextImpl::GetKeyGenLevel, cc_GetKeyGenLevel_docs) - .def("SetKeyGenLevel", &CryptoContextImpl::SetKeyGenLevel, cc_SetKeyGenLevel_docs, - py::arg("level")) - .def("get_ptr", [](const CryptoContext &self) - { std::cout << "CC shared ptr (python cc)" << self << std::endl; }) - //.def("GetScheme",&CryptoContextImpl::GetScheme) - //.def("GetCryptoParameters", &CryptoContextImpl::GetCryptoParameters) + .def("SetKeyGenLevel", &CryptoContextImpl::SetKeyGenLevel, + py::arg("level"), + py::doc(cc_SetKeyGenLevel_docs)) + .def("get_ptr",[](const CryptoContext &self) { + std::cout << "CC shared ptr (python cc)" << self << std::endl; }) .def("GetRingDimension", &CryptoContextImpl::GetRingDimension, cc_GetRingDimension_docs) - .def("GetPlaintextModulus", &GetPlaintextModulusWrapper, cc_GetPlaintextModulus_docs) - .def("GetBatchSize", &GetBatchSizeWrapper) - .def("GetModulus", &GetModulusWrapper, cc_GetModulus_docs) - .def("GetModulusCKKS", &GetModulusCKKSWrapper) - .def("GetScalingFactorReal", &GetScalingFactorRealWrapper, cc_GetScalingFactorReal_docs) - .def("GetScalingTechnique",&GetScalingTechniqueWrapper) - .def("GetDigitSize", &GetDigitSizeWrapper) + .def("GetPlaintextModulus", + [](CryptoContext& self) { + return self->GetCryptoParameters()->GetPlaintextModulus(); + }, + py::doc(cc_GetPlaintextModulus_docs)) + .def("GetBatchSize", + [](CryptoContext& self) { + return self->GetCryptoParameters()->GetBatchSize(); + }) + .def("GetModulus", + [](CryptoContext& self) { + return self->GetCryptoParameters() + ->GetElementParams() + ->GetModulus() + .ConvertToDouble(); + }, + py::doc(cc_GetModulus_docs)) + .def("GetModulusCKKS", + [](CryptoContext& self) { + auto cryptoParams = std::dynamic_pointer_cast(self->GetCryptoParameters()); + if (!cryptoParams) + OPENFHE_THROW("std::dynamic_pointer_cast() failed"); + return cryptoParams->GetElementParams()->GetParams()[0]->GetModulus().ConvertToInt(); + }) + .def("GetScalingFactorReal", + [](CryptoContext& self, uint32_t level) { + auto cryptoParams = std::dynamic_pointer_cast(self->GetCryptoParameters()); + if (!cryptoParams) + OPENFHE_THROW("std::dynamic_pointer_cast() failed"); + return cryptoParams->GetScalingFactorReal(level); + }, + py::arg("level"), + py::doc(cc_GetScalingFactorReal_docs)) + .def("GetScalingTechnique", + [](CryptoContext& self) { + const auto cryptoParams = std::dynamic_pointer_cast(self->GetCryptoParameters()); + if (!cryptoParams) + OPENFHE_THROW("std::dynamic_pointer_cast() failed"); + return cryptoParams->GetScalingTechnique(); + }) + .def("GetDigitSize", + [](CryptoContext& self) { + return self->GetCryptoParameters()->GetDigitSize(); + }) .def("GetCyclotomicOrder", &CryptoContextImpl::GetCyclotomicOrder, cc_GetCyclotomicOrder_docs) .def("GetCKKSDataType", &CryptoContextImpl::GetCKKSDataType) .def("GetNoiseEstimate", [](CryptoContext& self) { @@ -179,664 +293,688 @@ void bind_crypto_context(py::module &m) }) .def("SetNoiseEstimate", [](CryptoContext& self, double noiseEstimate) { GetParamsRNSChecked(self, "SetNoiseEstimate")->SetNoiseEstimate(noiseEstimate); - }, py::arg("noiseEstimate")) + }, + py::arg("noiseEstimate")) .def("GetMultiplicativeDepth", [](CryptoContext& self) { return GetParamsRNSChecked(self, "GetMultiplicativeDepth")->GetMultiplicativeDepth(); }) .def("SetMultiplicativeDepth", [](CryptoContext& self, uint32_t multiplicativeDepth) { GetParamsRNSChecked(self, "SetMultiplicativeDepth")->SetMultiplicativeDepth(multiplicativeDepth); - }, py::arg("multiplicativeDepth")) + }, + py::arg("multiplicativeDepth")) .def("GetEvalAddCount", [](CryptoContext& self) { return GetParamsRNSChecked(self, "GetEvalAddCount")->GetEvalAddCount(); }) .def("SetEvalAddCount", [](CryptoContext& self, uint32_t evalAddCount) { GetParamsRNSChecked(self, "SetEvalAddCount")->SetEvalAddCount(evalAddCount); - }, py::arg("evalAddCount")) + }, + py::arg("evalAddCount")) .def("GetKeySwitchCount", [](CryptoContext& self) { - return GetParamsRNSChecked(self, "GetKeySwitchCount")->GetKeySwitchCount(); - }) + return GetParamsRNSChecked(self, "GetKeySwitchCount")->GetKeySwitchCount(); + }) .def("SetKeySwitchCount", [](CryptoContext& self, uint32_t keySwitchCount) { - GetParamsRNSChecked(self, "SetKeySwitchCount")->SetKeySwitchCount(keySwitchCount); - }, py::arg("keySwitchCount")) + GetParamsRNSChecked(self, "SetKeySwitchCount")->SetKeySwitchCount(keySwitchCount); + }, + py::arg("keySwitchCount")) .def("GetPRENumHops", [](CryptoContext& self) { - return GetParamsRNSChecked(self, "GetPRENumHops")->GetPRENumHops(); - }) + return GetParamsRNSChecked(self, "GetPRENumHops")->GetPRENumHops(); + }) .def("SetPRENumHops", [](CryptoContext& self, uint32_t PRENumHops) { - GetParamsRNSChecked(self, "SetPRENumHops")->SetPRENumHops(PRENumHops); - }, py::arg("PRENumHops")) + GetParamsRNSChecked(self, "SetPRENumHops")->SetPRENumHops(PRENumHops); + }, + py::arg("PRENumHops")) .def("GetRegisterWordSize", [](CryptoContext& self) { - return GetParamsRNSChecked(self, "GetRegisterWordSize")->GetRegisterWordSize(); - }) + return GetParamsRNSChecked(self, "GetRegisterWordSize")->GetRegisterWordSize(); + }) .def("GetCompositeDegree", [](CryptoContext& self) { - return GetParamsRNSChecked(self, "GetCompositeDegree")->GetCompositeDegree(); - }) - .def("Enable", static_cast::*)(PKESchemeFeature)>(&CryptoContextImpl::Enable), cc_Enable_docs, - py::arg("feature")) + return GetParamsRNSChecked(self, "GetCompositeDegree")->GetCompositeDegree(); + }) + .def("Enable", py::overload_cast(&CryptoContextImpl::Enable), + py::arg("feature"), + py::doc(cc_Enable_docs)) .def("KeyGen", &CryptoContextImpl::KeyGen, cc_KeyGen_docs) .def("EvalMultKeyGen", &CryptoContextImpl::EvalMultKeyGen, - cc_EvalMultKeyGen_docs, - py::arg("privateKey")) + py::arg("privateKey"), + py::doc(cc_EvalMultKeyGen_docs)) .def("EvalMultKeysGen", &CryptoContextImpl::EvalMultKeysGen, - cc_EvalMultKeysGen_docs, - py::arg("privateKey")) + py::arg("privateKey"), + py::doc(cc_EvalMultKeysGen_docs)) .def("EvalRotateKeyGen", &CryptoContextImpl::EvalRotateKeyGen, - cc_EvalRotateKeyGen_docs, - py::arg("privateKey"), - py::arg("indexList"), - py::arg("publicKey") = nullptr) + py::arg("privateKey"), + py::arg("indexList"), + py::arg("publicKey") = py::none(), + py::doc(cc_EvalRotateKeyGen_docs)) .def("MakeStringPlaintext", &CryptoContextImpl::MakeStringPlaintext, - cc_MakeStringPlaintext_docs, - py::arg("str")) + py::arg("str"), + py::doc(cc_MakeStringPlaintext_docs)) .def("MakePackedPlaintext", &CryptoContextImpl::MakePackedPlaintext, - cc_MakePackedPlaintext_docs, - py::arg("value"), - py::arg("noiseScaleDeg") = 1, - py::arg("level") = 0) + py::arg("value"), + py::arg("noiseScaleDeg") = 1, + py::arg("level") = 0, + py::doc(cc_MakePackedPlaintext_docs)) .def("MakeCoefPackedPlaintext", &CryptoContextImpl::MakeCoefPackedPlaintext, - cc_MakeCoefPackedPlaintext_docs, py::arg("value"), py::arg("noiseScaleDeg ") = 1, - py::arg("level") = 0) + py::arg("level") = 0, + py::doc(cc_MakeCoefPackedPlaintext_docs)) // TODO (Oliveira): allow user to specify different params values - .def("MakeCKKSPackedPlaintext", static_cast::*)(const std::vector<std::complex<double>> &, size_t, uint32_t, const std::shared_ptr<ParmType>, uint32_t) const>(&CryptoContextImpl<DCRTPoly>::MakeCKKSPackedPlaintext), cc_MakeCKKSPackedPlaintextComplex_docs, - py::arg("value"), - py::arg("scaleDeg") = static_cast<size_t>(1), - py::arg("level") = static_cast<uint32_t>(0), - py::arg("params") = py::none(), - py::arg("slots") = 0) - .def("MakeCKKSPackedPlaintext", static_cast<Plaintext (CryptoContextImpl<DCRTPoly>::*)(const std::vector<double> &, size_t, uint32_t, const std::shared_ptr<ParmType>, uint32_t) const>(&CryptoContextImpl<DCRTPoly>::MakeCKKSPackedPlaintext), cc_MakeCKKSPlaintextReal_docs, - py::arg("value"), - py::arg("scaleDeg") = static_cast<size_t>(1), - py::arg("level") = static_cast<uint32_t>(0), - py::arg("params") = py::none(), - py::arg("slots") = 0) + .def("MakeCKKSPackedPlaintext", + py::overload_cast< + const std::vector<std::complex<double>>&, size_t, uint32_t, + const std::shared_ptr<ParmType>, uint32_t + >(&CryptoContextImpl<DCRTPoly>::MakeCKKSPackedPlaintext, py::const_), + py::arg("value"), + py::arg("noiseScaleDeg") = 1, + py::arg("level") = 0, + py::arg("params") = py::none(), + py::arg("slots") = 0, + py::doc(cc_MakeCKKSPackedPlaintextComplex_docs)) + .def("MakeCKKSPackedPlaintext", + py::overload_cast< + const std::vector<double>&, size_t, uint32_t, + const std::shared_ptr<ParmType>, uint32_t + >(&CryptoContextImpl<DCRTPoly>::MakeCKKSPackedPlaintext, py::const_), + py::arg("value"), + py::arg("noiseScaleDeg") = 1, + py::arg("level") = 0, + py::arg("params") = py::none(), + py::arg("slots") = 0, + py::doc(cc_MakeCKKSPlaintextReal_docs)) .def("EvalRotate", &CryptoContextImpl<DCRTPoly>::EvalRotate, - cc_EvalRotate_docs, py::arg("ciphertext"), - py::arg("index")) - .def("EvalFastRotationPrecompute", &EvalFastRotationPrecomputeWrapper, - cc_EvalFastRotationPreCompute_docs, - py::arg("ciphertext")) - .def("EvalFastRotation", &EvalFastRotationWrapper, - cc_EvalFastRotation_docs, + py::arg("index"), + py::doc(cc_EvalRotate_docs)) + .def("EvalFastRotationPrecompute", + [](CryptoContext<DCRTPoly>& self, ConstCiphertext<DCRTPoly> ciphertext) { + auto precomp = self->EvalFastRotationPrecompute(ciphertext); + auto cipherdigits = std::make_shared<CiphertextImpl<DCRTPoly>>(self); + cipherdigits->SetElements(*precomp); + return cipherdigits; + }, + py::arg("ciphertext"), + py::doc(cc_EvalFastRotationPreCompute_docs)) + .def("EvalFastRotation", + [](CryptoContext<DCRTPoly>& self, + ConstCiphertext<DCRTPoly> ciphertext, + uint32_t index, + uint32_t m, + ConstCiphertext<DCRTPoly> digits) { + return self->EvalFastRotation(ciphertext, index, m, std::make_shared<std::vector<DCRTPoly>>(digits->GetElements())); + }, py::arg("ciphertext"), py::arg("index"), py::arg("m"), - py::arg("digits")) - .def("EvalFastRotationExt", &EvalFastRotationExtWrapper, - cc_EvalFastRotationExt_docs, + py::arg("digits"), + py::doc(cc_EvalFastRotation_docs)) + .def("EvalFastRotationExt", + [](CryptoContext<DCRTPoly>& self, + ConstCiphertext<DCRTPoly> ciphertext, + uint32_t index, + ConstCiphertext<DCRTPoly> digits, + bool addFirst) { + return self->EvalFastRotationExt(ciphertext, index, std::make_shared<std::vector<DCRTPoly>>(digits->GetElements()), addFirst); + }, py::arg("ciphertext"), py::arg("index"), py::arg("digits"), - py::arg("addFirst")) + py::arg("addFirst"), + py::doc(cc_EvalFastRotationExt_docs)) .def("EvalAtIndexKeyGen", &CryptoContextImpl<DCRTPoly>::EvalAtIndexKeyGen, - cc_EvalAtIndexKeyGen_docs, py::arg("privateKey"), py::arg("indexList"), - py::arg("publicKey") = nullptr) + py::arg("publicKey") = py::none(), + py::doc(cc_EvalAtIndexKeyGen_docs)) .def("EvalAtIndex", &CryptoContextImpl<DCRTPoly>::EvalAtIndex, - cc_EvalAtIndex_docs, py::arg("ciphertext"), - py::arg("index")) - .def("Encrypt", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(const PublicKey<DCRTPoly>&, ConstPlaintext&) const> - (&CryptoContextImpl<DCRTPoly>::Encrypt), - cc_Encrypt_docs, + py::arg("index"), + py::doc(cc_EvalAtIndex_docs)) + .def("Encrypt", + py::overload_cast<const PublicKey<DCRTPoly>&, ConstPlaintext&>(&CryptoContextImpl<DCRTPoly>::Encrypt, py::const_), py::arg("publicKey"), - py::arg("plaintext")) - .def("Decrypt", static_cast<Plaintext (*)(CryptoContext<DCRTPoly> &, const PrivateKey<DCRTPoly>, ConstCiphertext<DCRTPoly>)> - (&DecryptWrapper), cc_Decrypt_docs, + py::arg("plaintext"), + py::doc(cc_Encrypt_docs)) + .def("Decrypt", + [](CryptoContext<DCRTPoly>& self, const PrivateKey<DCRTPoly> privKey, ConstCiphertext<DCRTPoly> ct) { + Plaintext result; + self->Decrypt(privKey, ct, &result); + return result; + }, py::arg("privateKey"), - py::arg("ciphertext")) - .def("Decrypt", static_cast<Plaintext (*)(CryptoContext<DCRTPoly> &, ConstCiphertext<DCRTPoly>, const PrivateKey<DCRTPoly>)> - (&DecryptWrapper), cc_Decrypt_docs, py::arg("ciphertext"), - py::arg("privateKey")) + py::doc(cc_Decrypt_docs)) + .def("Decrypt", + [](CryptoContext<DCRTPoly>& self, ConstCiphertext<DCRTPoly> ct, const PrivateKey<DCRTPoly> privKey) { + Plaintext result; + self->Decrypt(privKey, ct, &result); + return result; + }, + py::arg("ciphertext"), + py::arg("privateKey"), + py::doc(cc_Decrypt_docs)) .def("KeySwitchGen", &CryptoContextImpl<DCRTPoly>::KeySwitchGen, - cc_KeySwitchGen_docs, py::arg("oldPrivateKey"), - py::arg("newPrivateKey")) - .def("EvalAdd", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>&, ConstCiphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalAdd), - cc_EvalAdd_docs, + py::arg("newPrivateKey"), + py::doc(cc_KeySwitchGen_docs)) + .def("EvalAdd", + py::overload_cast<ConstCiphertext<DCRTPoly>&, ConstCiphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalAdd, py::const_), py::arg("ciphertext1"), - py::arg("ciphertext2")) - .def("EvalAdd", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>&, double) const> - (&CryptoContextImpl<DCRTPoly>::EvalAdd), - cc_EvalAddfloat_docs, - py::arg("ciphertext"), - py::arg("scalar")) - .def("EvalAdd", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>&, Plaintext&) const> - (&CryptoContextImpl<DCRTPoly>::EvalAdd), - cc_EvalAddPlaintext_docs, - py::arg("ciphertext"), - py::arg("plaintext")) - .def("EvalAddInPlace", static_cast<void (CryptoContextImpl<DCRTPoly>::*)(Ciphertext<DCRTPoly>&, ConstCiphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalAddInPlace), - cc_EvalAddInPlace_docs, + py::arg("ciphertext2"), + py::doc(cc_EvalAdd_docs)) + .def("EvalAdd", + py::overload_cast<ConstCiphertext<DCRTPoly>&, double>(&CryptoContextImpl<DCRTPoly>::EvalAdd, py::const_), + py::arg("ciphertext"), + py::arg("scalar"), + py::doc(cc_EvalAddfloat_docs)) + .def("EvalAdd", + py::overload_cast<ConstCiphertext<DCRTPoly>&, Plaintext&>(&CryptoContextImpl<DCRTPoly>::EvalAdd, py::const_), + py::arg("ciphertext"), + py::arg("plaintext"), + py::doc(cc_EvalAddPlaintext_docs)) + .def("EvalAddInPlace", + py::overload_cast<Ciphertext<DCRTPoly>&, ConstCiphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalAddInPlace, py::const_), py::arg("ciphertext1"), - py::arg("ciphertext2")) - .def("EvalAddInPlace", static_cast<void (CryptoContextImpl<DCRTPoly>::*)(Ciphertext<DCRTPoly>&, Plaintext&) const> - (&CryptoContextImpl<DCRTPoly>::EvalAddInPlace), - cc_EvalAddInPlacePlaintext_docs, - py::arg("ciphertext"), - py::arg("plaintext")) - .def("EvalAddInPlace", static_cast<void (CryptoContextImpl<DCRTPoly>::*)(Plaintext&, Ciphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalAddInPlace), - "", + py::arg("ciphertext2"), + py::doc(cc_EvalAddInPlace_docs)) + .def("EvalAddInPlace", + py::overload_cast<Ciphertext<DCRTPoly>&, Plaintext&>(&CryptoContextImpl<DCRTPoly>::EvalAddInPlace, py::const_), + py::arg("ciphertext"), py::arg("plaintext"), - py::arg("ciphertext")) - .def("EvalAddMutable", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(Ciphertext<DCRTPoly>&, Ciphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalAddMutable), - cc_EvalAddMutable_docs, + py::doc(cc_EvalAddInPlacePlaintext_docs)) + .def("EvalAddInPlace", + py::overload_cast<Plaintext&, Ciphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalAddInPlace, py::const_), + py::arg("plaintext"), + py::arg("ciphertext"), + py::doc("")) // TODO (dsuponit): replace this with an actual docstring + .def("EvalAddMutable", + py::overload_cast<Ciphertext<DCRTPoly>&, Ciphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalAddMutable, py::const_), py::arg("ciphertext1"), - py::arg("ciphertext2")) - .def("EvalAddMutable", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(Ciphertext<DCRTPoly>&, Plaintext&) const> - (&CryptoContextImpl<DCRTPoly>::EvalAddMutable), - cc_EvalAddMutablePlaintext_docs, - py::arg("ciphertext"), - py::arg("plaintext")) - .def("EvalAddMutable", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(Plaintext&, Ciphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalAddMutable), - "", + py::arg("ciphertext2"), + py::doc(cc_EvalAddMutable_docs)) + .def("EvalAddMutable", + py::overload_cast<Ciphertext<DCRTPoly>&, Plaintext&>(&CryptoContextImpl<DCRTPoly>::EvalAddMutable, py::const_), + py::arg("ciphertext"), py::arg("plaintext"), - py::arg("ciphertext")) + py::doc(cc_EvalAddMutablePlaintext_docs)) + .def("EvalAddMutable", py::overload_cast<Plaintext&, Ciphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalAddMutable, py::const_), + py::arg("plaintext"), + py::arg("ciphertext"), + py::doc("")) // TODO (dsuponit): replace this with an actual docstring .def("EvalAddMutableInPlace", &CryptoContextImpl<DCRTPoly>::EvalAddMutableInPlace, - cc_EvalAddMutableInPlace_docs, py::arg("ciphertext1"), - py::arg("ciphertext2")) - .def("EvalSub", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>&, ConstCiphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalSub), - cc_EvalSub_docs, + py::arg("ciphertext2"), + py::doc(cc_EvalAddMutableInPlace_docs)) + .def("EvalSub", + py::overload_cast<ConstCiphertext<DCRTPoly>&, ConstCiphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalSub, py::const_), py::arg("ciphertext1"), - py::arg("ciphertext2")) - .def("EvalSub", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>&, double) const> - (&CryptoContextImpl<DCRTPoly>::EvalSub), - cc_EvalSubfloat_docs, - py::arg("ciphertext"), - py::arg("scalar")) - .def("EvalSub", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(double, ConstCiphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalSub), - "", + py::arg("ciphertext2"), + py::doc(cc_EvalSub_docs)) + .def("EvalSub", + py::overload_cast<ConstCiphertext<DCRTPoly>&, double>(&CryptoContextImpl<DCRTPoly>::EvalSub, py::const_), + py::arg("ciphertext"), py::arg("scalar"), - py::arg("ciphertext")) - .def("EvalSub", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>&, Plaintext&) const> - (&CryptoContextImpl<DCRTPoly>::EvalSub), - cc_EvalSubPlaintext_docs, - py::arg("ciphertext"), - py::arg("plaintext")) - .def("EvalSub", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(Plaintext&, ConstCiphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalSub), - "", + py::doc(cc_EvalSubfloat_docs)) + .def("EvalSub", + py::overload_cast<double, ConstCiphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalSub, py::const_), + py::arg("scalar"), + py::arg("ciphertext"), + py::doc("")) // TODO (dsuponit): replace this with an actual docstring + .def("EvalSub", + py::overload_cast<ConstCiphertext<DCRTPoly>&, Plaintext&>(&CryptoContextImpl<DCRTPoly>::EvalSub, py::const_), + py::arg("ciphertext"), py::arg("plaintext"), - py::arg("ciphertext")) - .def("EvalSubInPlace", static_cast<void (CryptoContextImpl<DCRTPoly>::*)(Ciphertext<DCRTPoly> &, ConstCiphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalSubInPlace), - cc_EvalSubInPlace_docs, + py::doc(cc_EvalSubPlaintext_docs)) + .def("EvalSub", + py::overload_cast<Plaintext&, ConstCiphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalSub, py::const_), + py::arg("plaintext"), + py::arg("ciphertext"), + py::doc("")) // TODO (dsuponit): replace this with an actual docstring + .def("EvalSubInPlace", + py::overload_cast<Ciphertext<DCRTPoly>&, ConstCiphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalSubInPlace, py::const_), py::arg("ciphertext1"), - py::arg("ciphertext2")) - .def("EvalSubInPlace", static_cast<void (CryptoContextImpl<DCRTPoly>::*)(Ciphertext<DCRTPoly> &, double) const> - (&CryptoContextImpl<DCRTPoly>::EvalSubInPlace), - cc_EvalSubInPlacefloat_docs, - py::arg("ciphertext"), - py::arg("scalar")) - .def("EvalSubInPlace", static_cast<void (CryptoContextImpl<DCRTPoly>::*)(double, Ciphertext<DCRTPoly> &) const> - (&CryptoContextImpl<DCRTPoly>::EvalSubInPlace), - "", + py::arg("ciphertext2"), + py::doc(cc_EvalSubInPlace_docs)) + .def("EvalSubInPlace", + py::overload_cast<Ciphertext<DCRTPoly>&, double>(&CryptoContextImpl<DCRTPoly>::EvalSubInPlace, py::const_), + py::arg("ciphertext"), py::arg("scalar"), - py::arg("ciphertext")) - .def("EvalSubMutable", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(Ciphertext<DCRTPoly>&, Ciphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalSubMutable), - cc_EvalSubMutable_docs, + py::doc(cc_EvalSubInPlacefloat_docs)) + .def("EvalSubInPlace", + py::overload_cast<double, Ciphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalSubInPlace, py::const_), + py::arg("scalar"), + py::arg("ciphertext"), + py::doc("")) // TODO (dsuponit): replace this with an actual docstring + .def("EvalSubMutable", + py::overload_cast<Ciphertext<DCRTPoly>&, Ciphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalSubMutable, py::const_), py::arg("ciphertext1"), - py::arg("ciphertext2")) - .def("EvalSubMutable", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(Ciphertext<DCRTPoly>&, Plaintext&) const> - (&CryptoContextImpl<DCRTPoly>::EvalSubMutable), - cc_EvalSubMutablePlaintext_docs, - py::arg("ciphertext"), - py::arg("plaintext")) - .def("EvalSubMutable", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(Plaintext&, Ciphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalSubMutable), - "", + py::arg("ciphertext2"), + py::doc(cc_EvalSubMutable_docs)) + .def("EvalSubMutable", + py::overload_cast<Ciphertext<DCRTPoly>&,Plaintext&>(&CryptoContextImpl<DCRTPoly>::EvalSubMutable, py::const_), + py::arg("ciphertext"), py::arg("plaintext"), - py::arg("ciphertext")) + py::doc(cc_EvalSubMutablePlaintext_docs)) + .def("EvalSubMutable", + py::overload_cast<Plaintext&, Ciphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalSubMutable, py::const_), + py::arg("plaintext"), + py::arg("ciphertext"), + py::doc("")) // TODO (dsuponit): replace this with an actual docstring .def("EvalSubMutableInPlace", &CryptoContextImpl<DCRTPoly>::EvalSubMutableInPlace, - cc_EvalSubMutableInPlace_docs, py::arg("ciphertext1"), - py::arg("ciphertext2")) - .def("EvalMult", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>&, ConstCiphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalMult), - cc_EvalMult_docs, + py::arg("ciphertext2"), + py::doc(cc_EvalSubMutableInPlace_docs)) + .def("EvalMult", + py::overload_cast<ConstCiphertext<DCRTPoly>&, ConstCiphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalMult, py::const_), py::arg("ciphertext1"), - py::arg("ciphertext2")) - .def("EvalMult", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>&, double) const> - (&CryptoContextImpl<DCRTPoly>::EvalMult), - cc_EvalMultfloat_docs, - py::arg("ciphertext"), - py::arg("scalar")) - .def("EvalMult", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>&, ConstPlaintext&) const> - (&CryptoContextImpl<DCRTPoly>::EvalMult), - cc_EvalMultPlaintext_docs, - py::arg("ciphertext"), - py::arg("plaintext")) - .def("EvalMult", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstPlaintext&, ConstCiphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalMult), - "", + py::arg("ciphertext2"), + py::doc(cc_EvalMult_docs)) + .def("EvalMult", + py::overload_cast<ConstCiphertext<DCRTPoly>&, double>(&CryptoContextImpl<DCRTPoly>::EvalMult, py::const_), + py::arg("ciphertext"), + py::arg("scalar"), + py::doc(cc_EvalMultfloat_docs)) + .def("EvalMult", + py::overload_cast<ConstCiphertext<DCRTPoly>&, ConstPlaintext&>(&CryptoContextImpl<DCRTPoly>::EvalMult, py::const_), + py::arg("ciphertext"), + py::arg("plaintext"), + py::doc(cc_EvalMultPlaintext_docs)) + .def("EvalMult", + py::overload_cast<ConstPlaintext&, ConstCiphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalMult, py::const_), py::arg("plaintext"), - py::arg("ciphertext")) - .def("EvalMult", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(double, ConstCiphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalMult), - "", + py::arg("ciphertext"), + py::doc("")) // TODO (dsuponit): replace this with an actual docstring + .def("EvalMult", + py::overload_cast<double, ConstCiphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalMult, py::const_), py::arg("scalar"), - py::arg("ciphertext")) - .def("EvalMultMutable", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(Ciphertext<DCRTPoly>&, Ciphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalMultMutable), - cc_EvalMultMutable_docs, + py::arg("ciphertext"), + py::doc("")) // TODO (dsuponit): replace this with an actual docstring + .def("EvalMultMutable", + py::overload_cast<Ciphertext<DCRTPoly>&, Ciphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalMultMutable, py::const_), py::arg("ciphertext1"), - py::arg("ciphertext2")) - .def("EvalMultMutable", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(Ciphertext<DCRTPoly>&, Plaintext&) const> - (&CryptoContextImpl<DCRTPoly>::EvalMultMutable), - cc_EvalMultMutablePlaintext_docs, - py::arg("ciphertext"), - py::arg("plaintext")) - .def("EvalMultMutable", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(Plaintext&, Ciphertext<DCRTPoly>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalMultMutable), - "", + py::arg("ciphertext2"), + py::doc(cc_EvalMultMutable_docs)) + .def("EvalMultMutable", + py::overload_cast<Ciphertext<DCRTPoly>&, Plaintext&>(&CryptoContextImpl<DCRTPoly>::EvalMultMutable, py::const_), + py::arg("ciphertext"), + py::arg("plaintext"), + py::doc(cc_EvalMultMutablePlaintext_docs)) + .def("EvalMultMutable", + py::overload_cast<Plaintext&, Ciphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalMultMutable, py::const_), py::arg("plaintext"), - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc("")) // TODO (dsuponit): replace this with an actual docstring .def("EvalMultMutableInPlace", &CryptoContextImpl<DCRTPoly>::EvalMultMutableInPlace, - cc_EvalMultMutableInPlace_docs, py::arg("ciphertext1"), - py::arg("ciphertext2")) + py::arg("ciphertext2"), + py::doc(cc_EvalMultMutableInPlace_docs)) .def("EvalSquare", &CryptoContextImpl<DCRTPoly>::EvalSquare, - cc_EvalSquare_docs, - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc(cc_EvalSquare_docs)) .def("EvalSquareMutable", &CryptoContextImpl<DCRTPoly>::EvalSquareMutable, - cc_EvalSquareMutable_docs, - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc(cc_EvalSquareMutable_docs)) .def("EvalSquareInPlace", &CryptoContextImpl<DCRTPoly>::EvalSquareInPlace, - cc_EvalSquareInPlace_docs, - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc(cc_EvalSquareInPlace_docs)) .def("EvalMultNoRelin", &CryptoContextImpl<DCRTPoly>::EvalMultNoRelin, - cc_EvalMultNoRelin_docs, py::arg("ciphertext1"), - py::arg("ciphertext2")) + py::arg("ciphertext2"), + py::doc(cc_EvalMultNoRelin_docs)) .def("Relinearize", &CryptoContextImpl<DCRTPoly>::Relinearize, - cc_Relinearize_docs, - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc(cc_Relinearize_docs)) .def("RelinearizeInPlace", &CryptoContextImpl<DCRTPoly>::RelinearizeInPlace, - cc_RelinearizeInPlace_docs, - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc(cc_RelinearizeInPlace_docs)) .def("EvalMultAndRelinearize", &CryptoContextImpl<DCRTPoly>::EvalMultAndRelinearize, - cc_EvalMultAndRelinearize_docs, py::arg("ciphertext1"), - py::arg("ciphertext2")) + py::arg("ciphertext2"), + py::doc(cc_EvalMultAndRelinearize_docs)) .def("EvalNegate", &CryptoContextImpl<DCRTPoly>::EvalNegate, - cc_EvalNegate_docs, - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc(cc_EvalNegate_docs)) .def("EvalNegateInPlace", &CryptoContextImpl<DCRTPoly>::EvalNegateInPlace, - cc_EvalNegateInPlace_docs, - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc(cc_EvalNegateInPlace_docs)) .def("EvalLogistic", &CryptoContextImpl<DCRTPoly>::EvalLogistic, - cc_EvalLogistic_docs, py::arg("ciphertext"), py::arg("a"), py::arg("b"), - py::arg("degree")) - .def("EvalChebyshevSeries", &CryptoContextImpl<DCRTPoly>::EvalChebyshevSeries, - cc_EvalChebyshevSeries_docs, + py::arg("degree"), + py::doc(cc_EvalLogistic_docs)) + .def("EvalChebyshevFunction", &CryptoContextImpl<DCRTPoly>::EvalChebyshevFunction, + py::arg("func"), py::arg("ciphertext"), - py::arg("coefficients"), py::arg("a"), - py::arg("b")) - .def("EvalChebyshevSeriesLinear", &CryptoContextImpl<DCRTPoly>::EvalChebyshevSeriesLinear, - cc_EvalChebyshevSeriesLinear_docs, + py::arg("b"), + py::arg("degree"), + py::doc(cc_EvalChebyshevFunction_docs)) + .def("EvalSin", &CryptoContextImpl<DCRTPoly>::EvalSin, py::arg("ciphertext"), - py::arg("coefficients"), py::arg("a"), - py::arg("b")) - .def("EvalChebyshevSeriesPS", &CryptoContextImpl<DCRTPoly>::EvalChebyshevSeriesPS, - cc_EvalChebyshevSeriesPS_docs, + py::arg("b"), + py::arg("degree"), + py::doc(cc_EvalSin_docs)) + .def("EvalCos", &CryptoContextImpl<DCRTPoly>::EvalCos, py::arg("ciphertext"), - py::arg("coefficients"), py::arg("a"), - py::arg("b")) - .def("EvalChebyshevFunction", &CryptoContextImpl<DCRTPoly>::EvalChebyshevFunction, - cc_EvalChebyshevFunction_docs, - py::arg("func"), - py::arg("ciphertext"), - py::arg("a"), - py::arg("b"), - py::arg("degree")) - .def("EvalSin", &CryptoContextImpl<DCRTPoly>::EvalSin, - cc_EvalSin_docs, - py::arg("ciphertext"), - py::arg("a"), - py::arg("b"), - py::arg("degree")) - .def("EvalCos", &CryptoContextImpl<DCRTPoly>::EvalCos, - cc_EvalCos_docs, - py::arg("ciphertext"), - py::arg("a"), - py::arg("b"), - py::arg("degree")) + py::arg("b"), + py::arg("degree"), + py::doc(cc_EvalCos_docs)) .def("EvalDivide", &CryptoContextImpl<DCRTPoly>::EvalDivide, - cc_EvalDivide_docs, - py::arg("ciphertext"), - py::arg("a"), - py::arg("b"), - py::arg("degree")) + py::arg("ciphertext"), + py::arg("a"), + py::arg("b"), + py::arg("degree"), + py::doc(cc_EvalDivide_docs)) .def("EvalSumKeyGen", &CryptoContextImpl<DCRTPoly>::EvalSumKeyGen, - cc_EvalSumKeyGen_docs, - py::arg("privateKey"), - py::arg("publicKey") = py::none()) + py::arg("privateKey"), + py::arg("publicKey") = py::none(), + py::doc(cc_EvalSumKeyGen_docs)) //TODO (Oliveira, R.): Solve pointer handling bug when dealing with EvalKeyMap object for the next functions .def("EvalSumRowsKeyGen", &CryptoContextImpl<DCRTPoly>::EvalSumRowsKeyGen, - cc_EvalSumRowsKeyGen_docs, - py::arg("privateKey"), - py::arg("publicKey") = py::none(), - py::arg("rowSize") = 0, - py::arg("subringDim") = 0) + py::arg("privateKey"), + py::arg("publicKey") = py::none(), + py::arg("rowSize") = 0, + py::arg("subringDim") = 0, + py::doc(cc_EvalSumRowsKeyGen_docs)) .def("EvalSumColsKeyGen", &CryptoContextImpl<DCRTPoly>::EvalSumColsKeyGen, - cc_EvalSumColsKeyGen_docs, - py::arg("privateKey"), - py::arg("publicKey") = py::none()) + py::arg("privateKey"), + py::arg("publicKey") = py::none(), + py::doc(cc_EvalSumColsKeyGen_docs)) .def("EvalSum", &CryptoContextImpl<DCRTPoly>::EvalSum, - cc_EvalSum_docs, - py::arg("ciphertext"), - py::arg("batchSize")) + py::arg("ciphertext"), + py::arg("batchSize"), + py::doc(cc_EvalSum_docs)) .def("EvalSumRows", &CryptoContextImpl<DCRTPoly>::EvalSumRows, - cc_EvalSumRows_docs, - py::arg("ciphertext"), - py::arg("numRows"), - py::arg("evalSumKeyMap"), - py::arg("subringDim") = 0) + py::arg("ciphertext"), + py::arg("numRows"), + py::arg("evalSumKeyMap"), + py::arg("subringDim") = 0, + py::doc(cc_EvalSumRows_docs)) .def("EvalSumCols", &CryptoContextImpl<DCRTPoly>::EvalSumCols, - cc_EvalSumCols_docs, - py::arg("ciphertext"), - py::arg("numCols"), - py::arg("evalSumKeyMap")) - .def("EvalInnerProduct", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>&, ConstCiphertext<DCRTPoly>&, uint32_t) const>(&CryptoContextImpl<DCRTPoly>::EvalInnerProduct), - cc_EvalInnerProduct_docs, - py::arg("ciphertext1"), - py::arg("ciphertext2"), - py::arg("batchSize")) - .def("EvalInnerProduct", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>&, ConstPlaintext&, uint32_t) const>(&CryptoContextImpl<DCRTPoly>::EvalInnerProduct), - cc_EvalInnerProductPlaintext_docs, - py::arg("ciphertext"), - py::arg("plaintext"), - py::arg("batchSize")) - .def("MultipartyKeyGen", static_cast<KeyPair<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(PublicKey<DCRTPoly>, bool, bool)>(&CryptoContextImpl<DCRTPoly>::MultipartyKeyGen), - cc_MultipartyKeyGen_docs, - py::arg("publicKey"), - py::arg("makeSparse") = false, - py::arg("fresh") = false) - .def("MultipartyKeyGen", static_cast<KeyPair<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(const std::vector<PrivateKey<DCRTPoly>> &)>(&CryptoContextImpl<DCRTPoly>::MultipartyKeyGen), - cc_MultipartyKeyGen_vector_docs, - py::arg("privateKeyVec")) + py::arg("ciphertext"), + py::arg("numCols"), + py::arg("evalSumKeyMap"), + py::doc(cc_EvalSumCols_docs)) + .def("EvalInnerProduct", + py::overload_cast<ConstCiphertext<DCRTPoly>&, ConstCiphertext<DCRTPoly>&, uint32_t>(&CryptoContextImpl<DCRTPoly>::EvalInnerProduct, py::const_), + py::arg("ciphertext1"), + py::arg("ciphertext2"), + py::arg("batchSize"), + py::doc(cc_EvalInnerProduct_docs)) + .def("EvalInnerProduct", + py::overload_cast<ConstCiphertext<DCRTPoly>&, ConstPlaintext&, uint32_t>(&CryptoContextImpl<DCRTPoly>::EvalInnerProduct, py::const_), + py::arg("ciphertext"), + py::arg("plaintext"), + py::arg("batchSize"), + py::doc(cc_EvalInnerProductPlaintext_docs)) + .def("MultipartyKeyGen", + py::overload_cast<PublicKey<DCRTPoly>, bool, bool>(&CryptoContextImpl<DCRTPoly>::MultipartyKeyGen), + py::arg("publicKey"), + py::arg("makeSparse") = false, + py::arg("fresh") = false, + py::doc(cc_MultipartyKeyGen_docs)) + .def("MultipartyKeyGen", + py::overload_cast<const std::vector<PrivateKey<DCRTPoly>>&>(&CryptoContextImpl<DCRTPoly>::MultipartyKeyGen), + py::arg("privateKeyVec"), + py::doc(cc_MultipartyKeyGen_vector_docs)) .def("MultipartyDecryptLead", &CryptoContextImpl<DCRTPoly>::MultipartyDecryptLead, - cc_MultipartyDecryptLead_docs, - py::arg("ciphertextVec"), - py::arg("privateKey")) + py::arg("ciphertextVec"), + py::arg("privateKey"), + py::doc(cc_MultipartyDecryptLead_docs)) .def("MultipartyDecryptMain", &CryptoContextImpl<DCRTPoly>::MultipartyDecryptMain, - cc_MultipartyDecryptMain_docs, py::arg("ciphertextVec"), - py::arg("privateKey")) - .def("MultipartyDecryptFusion", &MultipartyDecryptFusionWrapper, - cc_MultipartyDecryptFusion_docs, - py::arg("ciphertextVec")) + py::arg("privateKey"), + py::doc(cc_MultipartyDecryptMain_docs)) + .def("MultipartyDecryptFusion", + [](CryptoContext<DCRTPoly>& self, const std::vector<Ciphertext<DCRTPoly>>& partialCiphertextVec) { + Plaintext result; + self->MultipartyDecryptFusion(partialCiphertextVec, &result); + return result; + }, + py::arg("partialCiphertextVec"), + py::doc(cc_MultipartyDecryptFusion_docs)) .def("MultiKeySwitchGen", &CryptoContextImpl<DCRTPoly>::MultiKeySwitchGen, - cc_MultiKeySwitchGen_docs, - py::arg("originalPrivateKey"), - py::arg("newPrivateKey"), - py::arg("evalKey")) + py::arg("originalPrivateKey"), + py::arg("newPrivateKey"), + py::arg("evalKey"), + py::doc(cc_MultiKeySwitchGen_docs)) .def("MultiEvalAtIndexKeyGen", [](CryptoContextImpl<DCRTPoly>* self, const PrivateKey<DCRTPoly>& privateKey, std::shared_ptr<std::map<unsigned int, EvalKey<DCRTPoly>>> evalKeyMap, const std::vector<int32_t>& indexList, const std::string& keyTag = "") { - return self->MultiEvalAtIndexKeyGen(privateKey, evalKeyMap, indexList, keyTag); - }, - cc_MultiEvalAtIndexKeyGen_docs, - py::arg("privateKey"), - py::arg("evalKeyMap"), - py::arg("indexList"), - py::arg("keyTag") = "") + return self->MultiEvalAtIndexKeyGen(privateKey, evalKeyMap, indexList, keyTag); + }, + py::arg("privateKey"), + py::arg("evalKeyMap"), + py::arg("indexList"), + py::arg("keyTag") = "", + py::doc(cc_MultiEvalAtIndexKeyGen_docs)) .def("MultiEvalSumKeyGen", &CryptoContextImpl<DCRTPoly>::MultiEvalSumKeyGen, - cc_MultiEvalSumKeyGen_docs, - py::arg("privateKey"), - py::arg("evalKeyMap"), - py::arg("keyTag") = "") + py::arg("privateKey"), + py::arg("evalKeyMap"), + py::arg("keyTag") = "", + py::doc(cc_MultiEvalSumKeyGen_docs)) .def("MultiAddEvalAutomorphismKeys", &CryptoContextImpl<DCRTPoly>::MultiAddEvalAutomorphismKeys, - cc_MultiAddEvalAutomorphismKeys_docs, py::arg("evalKeyMap1"), py::arg("evalKeyMap1"), - py::arg("keyTag") = "") + py::arg("keyTag") = "", + py::doc(cc_MultiAddEvalAutomorphismKeys_docs)) .def("MultiAddPubKeys", &CryptoContextImpl<DCRTPoly>::MultiAddPubKeys, - cc_MultiAddPubKeys_docs, py::arg("publicKey1"), py::arg("publicKey2"), - py::arg("keyTag") = "") + py::arg("keyTag") = "", + py::doc(cc_MultiAddPubKeys_docs)) .def("MultiAddEvalKeys", &CryptoContextImpl<DCRTPoly>::MultiAddEvalKeys, - cc_MultiAddEvalKeys_docs, - py::arg("evalKey1"), - py::arg("evalKey2"), - py::arg("keyTag") = "") + py::arg("evalKey1"), + py::arg("evalKey2"), + py::arg("keyTag") = "", + py::doc(cc_MultiAddEvalKeys_docs)) .def("MultiAddEvalMultKeys", &CryptoContextImpl<DCRTPoly>::MultiAddEvalMultKeys, - cc_MultiAddEvalMultKeys_docs, - py::arg("evalKey1"), - py::arg("evalKey2"), - py::arg("keyTag") = "") + py::arg("evalKey1"), + py::arg("evalKey2"), + py::arg("keyTag") = "", + py::doc(cc_MultiAddEvalMultKeys_docs)) .def("IntBootDecrypt",&CryptoContextImpl<DCRTPoly>::IntBootDecrypt, - cc_IntBootDecrypt_docs, py::arg("privateKey"), - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc(cc_IntBootDecrypt_docs)) .def("IntBootEncrypt",&CryptoContextImpl<DCRTPoly>::IntBootEncrypt, - cc_IntBootEncrypt_docs, py::arg("publicKey"), - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc(cc_IntBootEncrypt_docs)) .def("IntBootAdd",&CryptoContextImpl<DCRTPoly>::IntBootAdd, - cc_IntBootAdd_docs, py::arg("ciphertext1"), - py::arg("ciphertext2")) + py::arg("ciphertext2"), + py::doc(cc_IntBootAdd_docs)) .def("IntBootAdjustScale",&CryptoContextImpl<DCRTPoly>::IntBootAdjustScale, - cc_IntBootAdjustScale_docs, - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc(cc_IntBootAdjustScale_docs)) .def("IntMPBootAdjustScale",&CryptoContextImpl<DCRTPoly>::IntMPBootAdjustScale, - cc_IntMPBootAdjustScale_docs, - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc(cc_IntMPBootAdjustScale_docs)) .def("IntMPBootRandomElementGen", &CryptoContextImpl<DCRTPoly>::IntMPBootRandomElementGen, - cc_IntMPBootRandomElementGen_docs, - py::arg("publicKey")) + py::arg("publicKey"), + py::doc(cc_IntMPBootRandomElementGen_docs)) .def("IntMPBootDecrypt", &CryptoContextImpl<DCRTPoly>::IntMPBootDecrypt, - cc_IntMPBootDecrypt_docs, - py::arg("privateKey"), - py::arg("ciphertext"), - py::arg("a")) + py::arg("privateKey"), + py::arg("ciphertext"), + py::arg("a"), + py::doc(cc_IntMPBootDecrypt_docs)) .def("IntMPBootAdd", &CryptoContextImpl<DCRTPoly>::IntMPBootAdd, - cc_IntMPBootAdd_docs, - py::arg("sharePairVec")) + py::arg("sharePairVec"), + py::doc(cc_IntMPBootAdd_docs)) .def("IntMPBootEncrypt", &CryptoContextImpl<DCRTPoly>::IntMPBootEncrypt, - cc_IntMPBootEncrypt_docs, - py::arg("publicKey"), - py::arg("sharePair"), - py::arg("a"), - py::arg("ciphertext")) + py::arg("publicKey"), + py::arg("sharePair"), + py::arg("a"), + py::arg("ciphertext"), + py::doc(cc_IntMPBootEncrypt_docs)) .def("MultiMultEvalKey", &CryptoContextImpl<DCRTPoly>::MultiMultEvalKey, - cc_MultiMultEvalKey_docs, - py::arg("privateKey"), - py::arg("evalKey"), - py::arg("keyTag") = "") + py::arg("privateKey"), + py::arg("evalKey"), + py::arg("keyTag") = "", + py::doc(cc_MultiMultEvalKey_docs)) .def("MultiAddEvalSumKeys", &CryptoContextImpl<DCRTPoly>::MultiAddEvalSumKeys, - cc_MultiAddEvalSumKeys_docs, - py::arg("evalKeyMap1"), - py::arg("evalKeyMap2"), - py::arg("keyTag") = "") + py::arg("evalKeyMap1"), + py::arg("evalKeyMap2"), + py::arg("keyTag") = "", + py::doc(cc_MultiAddEvalSumKeys_docs)) .def("EvalMerge", &CryptoContextImpl<DCRTPoly>::EvalMerge, - cc_EvalMerge_docs, - py::arg("ciphertextVec")) - // use static_cast: inline EvalKey<Element> ReKeyGen(const PrivateKey<Element> oldPrivateKey, const PublicKey<Element> newPublicKey) const; - .def("ReKeyGen", static_cast<EvalKey<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(const PrivateKey<DCRTPoly>, const PublicKey<DCRTPoly>) const>(&CryptoContextImpl<DCRTPoly>::ReKeyGen), - cc_ReKeyGen_docs, - py::arg("oldPrivateKey"), - py::arg("newPublicKey")) + py::arg("ciphertextVec"), + py::doc(cc_EvalMerge_docs)) + .def("ReKeyGen", + py::overload_cast<const PrivateKey<DCRTPoly>, const PublicKey<DCRTPoly>>(&CryptoContextImpl<DCRTPoly>::ReKeyGen, py::const_), + py::arg("oldPrivateKey"), + py::arg("newPublicKey"), + py::doc(cc_ReKeyGen_docs)) .def("ReEncrypt", &CryptoContextImpl<DCRTPoly>::ReEncrypt, - cc_ReEncrypt_docs, - py::arg("ciphertext"), - py::arg("evalKey"), - py::arg("publicKey") = nullptr) - .def("EvalPoly", &CryptoContextImpl<DCRTPoly>::EvalPoly, - cc_EvalPoly_docs, - py::arg("ciphertext"), - py::arg("coefficients")) - .def("EvalPolyLinear", &CryptoContextImpl<DCRTPoly>::EvalPolyLinear, - cc_EvalPolyLinear_docs, - py::arg("ciphertext"), - py::arg("coefficients")) - .def("EvalPolyPS", &CryptoContextImpl<DCRTPoly>::EvalPolyPS, - cc_EvalPolyPS_docs, - py::arg("ciphertext"), - py::arg("coefficients")) + py::arg("ciphertext"), + py::arg("evalKey"), + py::arg("publicKey") = py::none(), + py::doc(cc_ReEncrypt_docs)) .def("Rescale", &CryptoContextImpl<DCRTPoly>::Rescale, - cc_Rescale_docs, - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc(cc_Rescale_docs)) .def("RescaleInPlace", &CryptoContextImpl<DCRTPoly>::RescaleInPlace, - cc_RescaleInPlace_docs, - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc(cc_RescaleInPlace_docs)) .def("ModReduce", &CryptoContextImpl<DCRTPoly>::ModReduce, - cc_ModReduce_docs, - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc(cc_ModReduce_docs)) .def("ModReduceInPlace", &CryptoContextImpl<DCRTPoly>::ModReduceInPlace, - cc_ModReduceInPlace_docs, - py::arg("ciphertext")) + py::arg("ciphertext"), + py::doc(cc_ModReduceInPlace_docs)) .def("EvalBootstrapSetup", &CryptoContextImpl<DCRTPoly>::EvalBootstrapSetup, - cc_EvalBootstrapSetup_docs, - py::arg("levelBudget") = std::vector<uint32_t>({5, 4}), - py::arg("dim1") = std::vector<uint32_t>({0, 0}), - py::arg("slots") = 0, - py::arg("correctionFactor") = 0, - py::arg("precompute")= true) + py::arg("levelBudget") = std::vector<uint32_t>({5, 4}), + py::arg("dim1") = std::vector<uint32_t>({0, 0}), + py::arg("slots") = 0, + py::arg("correctionFactor") = 0, + py::arg("precompute")= true, + py::doc(cc_EvalBootstrapSetup_docs)) .def("EvalBootstrapKeyGen", &CryptoContextImpl<DCRTPoly>::EvalBootstrapKeyGen, - cc_EvalBootstrapKeyGen_docs, - py::arg("privateKey"), - py::arg("slots")) + py::arg("privateKey"), + py::arg("slots"), + py::doc(cc_EvalBootstrapKeyGen_docs)) .def("EvalBootstrap", &CryptoContextImpl<DCRTPoly>::EvalBootstrap, - cc_EvalBootstrap_docs, - py::arg("ciphertext"), - py::arg("numIterations") = 1, - py::arg("precision") = 0) + py::arg("ciphertext"), + py::arg("numIterations") = 1, + py::arg("precision") = 0, + py::doc(cc_EvalBootstrap_docs)) .def("EvalCKKStoFHEWSetup", &CryptoContextImpl<DCRTPoly>::EvalCKKStoFHEWSetup, - cc_EvalCKKStoFHEWSetup_docs, - py::arg("schswchparams")) + py::arg("schswchparams"), + py::doc(cc_EvalCKKStoFHEWSetup_docs)) .def("EvalCKKStoFHEWKeyGen", &CryptoContextImpl<DCRTPoly>::EvalCKKStoFHEWKeyGen, - cc_EvalCKKStoFHEWKeyGen_docs, - py::arg("keyPair"), - py::arg("lwesk")) + py::arg("keyPair"), + py::arg("lwesk"), + py::doc(cc_EvalCKKStoFHEWKeyGen_docs)) .def("EvalCKKStoFHEWPrecompute", &CryptoContextImpl<DCRTPoly>::EvalCKKStoFHEWPrecompute, - cc_EvalCKKStoFHEWPrecompute_docs, - py::arg("scale") = 1.0) + py::arg("scale") = 1.0, + py::doc(cc_EvalCKKStoFHEWPrecompute_docs)) .def("EvalCKKStoFHEW", &CryptoContextImpl<DCRTPoly>::EvalCKKStoFHEW, - cc_EvalCKKStoFHEW_docs, - py::arg("ciphertext"), - py::arg("numCtxts") = 0) + py::arg("ciphertext"), + py::arg("numCtxts") = 0, + py::doc(cc_EvalCKKStoFHEW_docs)) .def("EvalFHEWtoCKKSSetup", &CryptoContextImpl<DCRTPoly>::EvalFHEWtoCKKSSetup, - cc_EvalFHEWtoCKKSSetup_docs, - py::arg("ccLWE"), - py::arg("numSlotsCKKS") = 0, - py::arg("logQ") = 25) + py::arg("ccLWE"), + py::arg("numSlotsCKKS") = 0, + py::arg("logQ") = 25, + py::doc(cc_EvalFHEWtoCKKSSetup_docs)) .def("EvalFHEWtoCKKSKeyGen", &CryptoContextImpl<DCRTPoly>::EvalFHEWtoCKKSKeyGen, - cc_EvalFHEWtoCKKSKeyGen_docs, - py::arg("keyPair"), - py::arg("lwesk"), - py::arg("numSlots") = 0, - py::arg("numCtxts") = 0, - py::arg("dim1") = 0, - py::arg("L") = 0) + py::arg("keyPair"), + py::arg("lwesk"), + py::arg("numSlots") = 0, + py::arg("numCtxts") = 0, + py::arg("dim1") = 0, + py::arg("L") = 0, + py::doc(cc_EvalFHEWtoCKKSKeyGen_docs)) .def("EvalFHEWtoCKKS", &CryptoContextImpl<DCRTPoly>::EvalFHEWtoCKKS, - cc_EvalFHEWtoCKKS_docs, - py::arg("LWECiphertexts"), - py::arg("numCtxts") = 0, - py::arg("numSlots") = 0, - py::arg("p") = 4, - py::arg("pmin") = 0.0, - py::arg("pmax") = 2.0, - py::arg("dim1") = 0) + py::arg("LWECiphertexts"), + py::arg("numCtxts") = 0, + py::arg("numSlots") = 0, + py::arg("p") = 4, + py::arg("pmin") = 0.0, + py::arg("pmax") = 2.0, + py::arg("dim1") = 0, + py::doc(cc_EvalFHEWtoCKKS_docs)) .def("EvalSchemeSwitchingSetup", &CryptoContextImpl<DCRTPoly>::EvalSchemeSwitchingSetup, - cc_EvalSchemeSwitchingSetup_docs, - py::arg("schswchparams")) - //void EvalSchemeSwitchingKeyGen(const KeyPair<Element> &keyPair, ConstLWEPrivateKey &lwesk, uint32_t numValues = 0, bool oneHot = true, bool alt = false, uint32_t dim1CF = 0, uint32_t dim1FC = 0, uint32_t LCF = 1, uint32_t LFC = 0) + py::arg("schswchparams"), + py::doc(cc_EvalSchemeSwitchingSetup_docs)) + //void EvalSchemeSwitchingKeyGen(const KeyPair<DCRTPoly> &keyPair, ConstLWEPrivateKey &lwesk, uint32_t numValues = 0, bool oneHot = true, bool alt = false, uint32_t dim1CF = 0, uint32_t dim1FC = 0, uint32_t LCF = 1, uint32_t LFC = 0) .def("EvalSchemeSwitchingKeyGen", &CryptoContextImpl<DCRTPoly>::EvalSchemeSwitchingKeyGen, - cc_EvalSchemeSwitchingKeyGen_docs, - py::arg("keyPair"), - py::arg("lwesk")) + py::arg("keyPair"), + py::arg("lwesk"), + py::doc(cc_EvalSchemeSwitchingKeyGen_docs)) .def("EvalCompareSwitchPrecompute", &CryptoContextImpl<DCRTPoly>::EvalCompareSwitchPrecompute, - cc_EvalCompareSwitchPrecompute_docs, - py::arg("pLWE") = 0, - py::arg("scaleSign") = 1.0, - py::arg("unit") = false) + py::arg("pLWE") = 0, + py::arg("scaleSign") = 1.0, + py::arg("unit") = false, + py::doc(cc_EvalCompareSwitchPrecompute_docs)) .def("EvalCompareSchemeSwitching", &CryptoContextImpl<DCRTPoly>::EvalCompareSchemeSwitching, - cc_EvalCompareSchemeSwitching_docs, - py::arg("ciphertext1"), - py::arg("ciphertext2"), - py::arg("numCtxts") = 0, - py::arg("numSlots") = 0, - py::arg("pLWE") = 0, - py::arg("scaleSign") = 1.0, - py::arg("unit") = false) + py::arg("ciphertext1"), + py::arg("ciphertext2"), + py::arg("numCtxts") = 0, + py::arg("numSlots") = 0, + py::arg("pLWE") = 0, + py::arg("scaleSign") = 1.0, + py::arg("unit") = false, + py::doc(cc_EvalCompareSchemeSwitching_docs)) .def("EvalMinSchemeSwitching", &CryptoContextImpl<DCRTPoly>::EvalMinSchemeSwitching, - cc_EvalMinSchemeSwitching_docs, - py::arg("ciphertext"), - py::arg("publicKey"), - py::arg("numValues") = 0, - py::arg("numSlots") = 0, - py::arg("pLWE") = 0, - py::arg("scaleSign") = 1.0) + py::arg("ciphertext"), + py::arg("publicKey"), + py::arg("numValues") = 0, + py::arg("numSlots") = 0, + py::arg("pLWE") = 0, + py::arg("scaleSign") = 1.0, + py::doc(cc_EvalMinSchemeSwitching_docs)) .def("EvalMinSchemeSwitchingAlt", &CryptoContextImpl<DCRTPoly>::EvalMinSchemeSwitchingAlt, - cc_EvalMinSchemeSwitchingAlt_docs, - py::arg("ciphertext"), - py::arg("publicKey"), - py::arg("numValues") = 0, - py::arg("numSlots") = 0, - py::arg("pLWE") = 0, - py::arg("scaleSign") = 1.0) + py::arg("ciphertext"), + py::arg("publicKey"), + py::arg("numValues") = 0, + py::arg("numSlots") = 0, + py::arg("pLWE") = 0, + py::arg("scaleSign") = 1.0, + py::doc(cc_EvalMinSchemeSwitchingAlt_docs)) .def("EvalMaxSchemeSwitching", &CryptoContextImpl<DCRTPoly>::EvalMaxSchemeSwitching, - cc_EvalMaxSchemeSwitching_docs, - py::arg("ciphertext"), - py::arg("publicKey"), - py::arg("numValues") = 0, - py::arg("numSlots") = 0, - py::arg("pLWE") = 0, - py::arg("scaleSign") = 1.0) + py::arg("ciphertext"), + py::arg("publicKey"), + py::arg("numValues") = 0, + py::arg("numSlots") = 0, + py::arg("pLWE") = 0, + py::arg("scaleSign") = 1.0, + py::doc(cc_EvalMaxSchemeSwitching_docs)) .def("EvalMaxSchemeSwitchingAlt", &CryptoContextImpl<DCRTPoly>::EvalMaxSchemeSwitchingAlt, - cc_EvalMaxSchemeSwitchingAlt_docs, - py::arg("ciphertext"), - py::arg("publicKey"), - py::arg("numValues") = 0, - py::arg("numSlots") = 0, - py::arg("pLWE") = 0, - py::arg("scaleSign") = 1.0) + py::arg("ciphertext"), + py::arg("publicKey"), + py::arg("numValues") = 0, + py::arg("numSlots") = 0, + py::arg("pLWE") = 0, + py::arg("scaleSign") = 1.0, + py::doc(cc_EvalMaxSchemeSwitchingAlt_docs)) //TODO (Oliveira, R.): Solve pointer handling bug when returning EvalKeyMap objects for the next functions + // TODO (dsuponit): I'd suggest this version of EvalAutomorphismKeyGen instead: + // .def("EvalAutomorphismKeyGen", + // [](const CryptoContextImpl<DCRTPoly>& cc, + // const PrivateKey<DCRTPoly>& privateKey, + // const std::vector<uint32_t>& indexList) -> py::dict { + // auto keyMapPtr = cc.EvalAutomorphismKeyGen(privateKey, indexList); + // py::dict result; + // for (const auto& kv : *keyMapPtr) { + // result[py::int_(kv.first)] = kv.second; + // } + // return result; + // }, + // py::doc(cc_EvalAutomorphismKeyGen_docs)) + // py::arg("privateKey"), + // py::arg("indexList")) .def("EvalAutomorphismKeyGen", - static_cast<std::shared_ptr<std::map<uint32_t, EvalKey<DCRTPoly>>> (CryptoContextImpl<DCRTPoly>::*)(const PrivateKey<DCRTPoly>, const std::vector<uint32_t>&) const> - (&CryptoContextImpl<DCRTPoly>::EvalAutomorphismKeyGen), - cc_EvalAutomorphismKeyGen_docs, + py::overload_cast<const PrivateKey<DCRTPoly>, const std::vector<uint32_t>&>(&CryptoContextImpl<DCRTPoly>::EvalAutomorphismKeyGen, py::const_), py::arg("privateKey"), - py::arg("indexList")) - .def("EvalLinearWSumMutable", - static_cast<lbcrypto::Ciphertext<DCRTPoly> (lbcrypto::CryptoContextImpl<DCRTPoly>::*)( - const std::vector<double>&, - std::vector<std::shared_ptr<lbcrypto::CiphertextImpl<DCRTPoly> > >& - ) const>( - &CryptoContextImpl<DCRTPoly>::EvalLinearWSumMutable), - py::arg("ciphertext"), - py::arg("coefficients")) - .def("EvalLinearWSum", - static_cast<lbcrypto::Ciphertext<DCRTPoly> (lbcrypto::CryptoContextImpl<DCRTPoly>::*)( - std::vector<std::shared_ptr<const lbcrypto::CiphertextImpl<DCRTPoly> > >&,const std::vector<double>&) const>( - &CryptoContextImpl<DCRTPoly>::EvalLinearWSum), - py::arg("ciphertext"), - py::arg("coefficients")) - .def("Compress", &CryptoContextImpl<DCRTPoly>::Compress, + py::arg("indexList"), + py::doc(cc_EvalAutomorphismKeyGen_docs)) + .def("Compress", &CryptoContextImpl<DCRTPoly>::Compress, py::arg("ciphertext"), py::arg("towersLeft")) .def("EvalMultMany", &CryptoContextImpl<DCRTPoly>::EvalMultMany, @@ -846,74 +984,83 @@ void bind_crypto_context(py::module &m) .def("EvalAddManyInPlace", &CryptoContextImpl<DCRTPoly>::EvalAddManyInPlace, py::arg("ciphertextVec")) .def("FindAutomorphismIndex", &CryptoContextImpl<DCRTPoly>::FindAutomorphismIndex, - cc_FindAutomorphismIndex_docs, - py::arg("idx")) + py::arg("idx"), + py::doc(cc_FindAutomorphismIndex_docs)) .def("FindAutomorphismIndices", &CryptoContextImpl<DCRTPoly>::FindAutomorphismIndices, - cc_FindAutomorphismIndices_docs, - py::arg("idxList")) - .def("GetEvalSumKeyMap", &GetEvalSumKeyMapWrapper, - cc_GetEvalSumKeyMap_docs) + py::arg("idxList"), + py::doc(cc_FindAutomorphismIndices_docs)) + .def("GetEvalSumKeyMap", + [](CryptoContext<DCRTPoly>& self, const std::string& keyTag) { + return std::make_shared<std::map<uint32_t, EvalKey<DCRTPoly>>>(CryptoContextImpl<DCRTPoly>::GetEvalSumKeyMap(keyTag)); + }, + py::arg("keyTag"), + py::doc(cc_GetEvalSumKeyMap_docs)) .def("GetBinCCForSchemeSwitch", &CryptoContextImpl<DCRTPoly>::GetBinCCForSchemeSwitch) - .def_static( - "InsertEvalSumKey", &CryptoContextImpl<DCRTPoly>::InsertEvalSumKey, - cc_InsertEvalSumKey_docs, + .def_static("InsertEvalSumKey", &CryptoContextImpl<DCRTPoly>::InsertEvalSumKey, py::arg("evalKeyMap"), - py::arg("keyTag") = "") - .def_static( - "InsertEvalMultKey", &CryptoContextImpl<DCRTPoly>::InsertEvalMultKey, - cc_InsertEvalMultKey_docs, + py::arg("keyTag") = "", + py::doc(cc_InsertEvalSumKey_docs)) + .def_static("InsertEvalMultKey", &CryptoContextImpl<DCRTPoly>::InsertEvalMultKey, py::arg("evalKeyVec"), - py::arg("keyTag") = "") - .def_static( - "InsertEvalAutomorphismKey", &CryptoContextImpl<DCRTPoly>::InsertEvalAutomorphismKey, - cc_InsertEvalAutomorphismKey_docs, + py::arg("keyTag") = "", + py::doc(cc_InsertEvalMultKey_docs)) + .def_static("InsertEvalAutomorphismKey", &CryptoContextImpl<DCRTPoly>::InsertEvalAutomorphismKey, py::arg("evalKeyMap"), - py::arg("keyTag") = "") - .def_static("ClearEvalAutomorphismKeys", []() { - CryptoContextImpl<DCRTPoly>::ClearEvalAutomorphismKeys(); - }, - cc_ClearEvalAutomorphismKeys_docs) + py::arg("keyTag") = "", + py::doc(cc_InsertEvalAutomorphismKey_docs)) + .def_static("ClearEvalAutomorphismKeys", + static_cast<void (*)()>(&CryptoContextImpl<DCRTPoly>::ClearEvalAutomorphismKeys), + cc_ClearEvalAutomorphismKeys_docs + ) // it is safer to return by value instead of by reference (GetEvalMultKeyVector returns a const reference to std::vector) .def_static("GetEvalMultKeyVector", [](const std::string& keyTag) { return CryptoContextImpl<DCRTPoly>::GetEvalMultKeyVector(keyTag); }, - cc_GetEvalMultKeyVector_docs, - py::arg("keyTag") = "") + py::arg("keyTag") = "", + py::doc(cc_GetEvalMultKeyVector_docs)) .def_static("GetEvalAutomorphismKeyMap", &CryptoContextImpl<DCRTPoly>::GetEvalAutomorphismKeyMapPtr, - cc_GetEvalAutomorphismKeyMap_docs, - py::arg("keyTag") = "") + py::arg("keyTag") = "", + py::doc(cc_GetEvalAutomorphismKeyMap_docs)) .def_static("SerializeEvalMultKey", [](const std::string &filename, const SerType::SERBINARY &sertype, std::string keyTag = "") { std::ofstream outfile(filename, std::ios::out | std::ios::binary); bool res = CryptoContextImpl<DCRTPoly>::SerializeEvalMultKey<SerType::SERBINARY>(outfile, sertype, keyTag); outfile.close(); return res; }, - cc_SerializeEvalMultKey_docs, - py::arg("filename"), py::arg("sertype"), py::arg("keyTag") = "") + py::arg("filename"), + py::arg("sertype"), + py::arg("keyTag") = "", + py::doc(cc_SerializeEvalMultKey_docs)) .def_static("SerializeEvalMultKey", [](const std::string &filename, const SerType::SERJSON &sertype, std::string keyTag = "") { std::ofstream outfile(filename, std::ios::out | std::ios::binary); bool res = CryptoContextImpl<DCRTPoly>::SerializeEvalMultKey<SerType::SERJSON>(outfile, sertype, keyTag); outfile.close(); return res; }, - cc_SerializeEvalMultKey_docs, - py::arg("filename"), py::arg("sertype"), py::arg("keyTag") = "") + py::arg("filename"), + py::arg("sertype"), + py::arg("keyTag") = "", + py::doc(cc_SerializeEvalMultKey_docs)) .def_static("SerializeEvalAutomorphismKey", [](const std::string &filename, const SerType::SERBINARY &sertype, std::string keyTag = "") { std::ofstream outfile(filename, std::ios::out | std::ios::binary); bool res = CryptoContextImpl<DCRTPoly>::SerializeEvalAutomorphismKey<SerType::SERBINARY>(outfile, sertype, keyTag); outfile.close(); return res; }, - cc_SerializeEvalAutomorphismKey_docs, - py::arg("filename"), py::arg("sertype"), py::arg("keyTag") = "") + py::arg("filename"), + py::arg("sertype"), + py::arg("keyTag") = "", + py::doc(cc_SerializeEvalAutomorphismKey_docs)) .def_static("SerializeEvalAutomorphismKey", [](const std::string &filename, const SerType::SERJSON &sertype, std::string keyTag = "") { std::ofstream outfile(filename, std::ios::out | std::ios::binary); bool res = CryptoContextImpl<DCRTPoly>::SerializeEvalAutomorphismKey<SerType::SERJSON>(outfile, sertype, keyTag); outfile.close(); return res; }, - cc_SerializeEvalAutomorphismKey_docs, - py::arg("filename"), py::arg("sertype"), py::arg("keyTag") = "") + py::arg("filename"), + py::arg("sertype"), + py::arg("keyTag") = "", + py::doc(cc_SerializeEvalAutomorphismKey_docs)) .def_static("DeserializeEvalMultKey", [](const std::string &filename, const SerType::SERBINARY &sertype) { std::ifstream emkeys(filename, std::ios::in | std::ios::binary); if (!emkeys.is_open()) { @@ -922,8 +1069,9 @@ void bind_crypto_context(py::module &m) bool res = CryptoContextImpl<DCRTPoly>::DeserializeEvalMultKey<SerType::SERBINARY>(emkeys, sertype); return res; }, - cc_DeserializeEvalMultKey_docs, - py::arg("filename"), py::arg("sertype")) + py::arg("filename"), + py::arg("sertype"), + py::doc(cc_DeserializeEvalMultKey_docs)) .def_static("DeserializeEvalMultKey", [](const std::string &filename, const SerType::SERJSON &sertype) { std::ifstream emkeys(filename, std::ios::in | std::ios::binary); if (!emkeys.is_open()) { @@ -932,8 +1080,9 @@ void bind_crypto_context(py::module &m) bool res = CryptoContextImpl<DCRTPoly>::DeserializeEvalMultKey<SerType::SERJSON>(emkeys, sertype); return res; }, - cc_DeserializeEvalMultKey_docs, - py::arg("filename"), py::arg("sertype")) + py::arg("filename"), + py::arg("sertype"), + py::doc(cc_DeserializeEvalMultKey_docs)) .def_static("DeserializeEvalAutomorphismKey", [](const std::string &filename, const SerType::SERBINARY &sertype) { std::ifstream erkeys(filename, std::ios::in | std::ios::binary); if (!erkeys.is_open()) { @@ -942,8 +1091,9 @@ void bind_crypto_context(py::module &m) bool res = CryptoContextImpl<DCRTPoly>::DeserializeEvalAutomorphismKey<SerType::SERBINARY>(erkeys, sertype); return res; }, - cc_DeserializeEvalAutomorphismKey_docs, - py::arg("filename"), py::arg("sertype")) + py::arg("filename"), + py::arg("sertype"), + py::doc(cc_DeserializeEvalAutomorphismKey_docs)) .def_static("DeserializeEvalAutomorphismKey", [](const std::string &filename, const SerType::SERJSON &sertype) { std::ifstream erkeys(filename, std::ios::in | std::ios::binary); if (!erkeys.is_open()) { @@ -952,8 +1102,13 @@ void bind_crypto_context(py::module &m) bool res = CryptoContextImpl<DCRTPoly>::DeserializeEvalAutomorphismKey<SerType::SERJSON>(erkeys, sertype); return res; }, - cc_DeserializeEvalAutomorphismKey_docs, - py::arg("filename"), py::arg("sertype")); + py::arg("filename"), + py::arg("sertype"), + py::doc(cc_DeserializeEvalAutomorphismKey_docs)); + + bind_crypto_context_templates<int64_t>(cc_class); + bind_crypto_context_templates<double>(cc_class); + bind_crypto_context_templates<std::complex<double>>(cc_class); // Generator Functions m.def("GenCryptoContext", &GenCryptoContext<CryptoContextBFVRNS>, @@ -966,7 +1121,8 @@ void bind_crypto_context(py::module &m) m.def("GetAllContexts", &CryptoContextFactory<DCRTPoly>::GetAllContexts); m.def("ReleaseAllContexts", &CryptoContextFactory<DCRTPoly>::ReleaseAllContexts); - m.def("ClearEvalMultKeys", &ClearEvalMultKeysWrapper); + + m.def("ClearEvalMultKeys", static_cast<void (*)()>(&CryptoContextImpl<DCRTPoly>::ClearEvalMultKeys)); } int get_native_int(){ @@ -1247,41 +1403,29 @@ class PlaintextImpl_helper : public PlaintextImpl void bind_encodings(py::module &m) { py::class_<PlaintextImpl, std::shared_ptr<PlaintextImpl>, PlaintextImpl_helper>(m, "Plaintext") - .def("GetScalingFactor", &PlaintextImpl::GetScalingFactor, - ptx_GetScalingFactor_docs) + .def("GetScalingFactor", &PlaintextImpl::GetScalingFactor, ptx_GetScalingFactor_docs) .def("SetScalingFactor", &PlaintextImpl::SetScalingFactor, - ptx_SetScalingFactor_docs, - py::arg("sf")) - .def("GetSchemeID", &PlaintextImpl::GetSchemeID, - ptx_GetSchemeID_docs) - .def("GetLength", &PlaintextImpl::GetLength, - ptx_GetLength_docs) + py::arg("sf"), + py::doc(ptx_SetScalingFactor_docs)) + .def("GetSchemeID", &PlaintextImpl::GetSchemeID, ptx_GetSchemeID_docs) + .def("GetLength", &PlaintextImpl::GetLength, ptx_GetLength_docs) .def("SetLength", &PlaintextImpl::SetLength, - ptx_SetLength_docs, - py::arg("newSize")) - .def("IsEncoded", &PlaintextImpl::IsEncoded, - ptx_IsEncoded_docs) - .def("GetLogPrecision", &PlaintextImpl::GetLogPrecision, - ptx_GetLogPrecision_docs) - .def("Encode", &PlaintextImpl::Encode, - ptx_Encode_docs) - .def("Decode", py::overload_cast<>(&PlaintextImpl::Decode), - ptx_Decode_docs) - .def("Decode", py::overload_cast<size_t, double, ScalingTechnique, ExecutionMode>(&PlaintextImpl::Decode), - ptx_Decode_docs) - .def("LowBound", &PlaintextImpl::LowBound, - ptx_LowBound_docs) - .def("HighBound", &PlaintextImpl::HighBound, - ptx_HighBound_docs) + py::arg("newSize"), + py::doc(ptx_SetLength_docs)) + .def("IsEncoded", &PlaintextImpl::IsEncoded, ptx_IsEncoded_docs) + .def("GetLogPrecision", &PlaintextImpl::GetLogPrecision, ptx_GetLogPrecision_docs) + .def("Encode", &PlaintextImpl::Encode, ptx_Encode_docs) + .def("Decode", py::overload_cast<>(&PlaintextImpl::Decode), ptx_Decode_docs) + .def("Decode", py::overload_cast<size_t, double, ScalingTechnique, ExecutionMode>(&PlaintextImpl::Decode), ptx_Decode_docs) + .def("LowBound", &PlaintextImpl::LowBound, ptx_LowBound_docs) + .def("HighBound", &PlaintextImpl::HighBound, ptx_HighBound_docs) .def("SetFormat", &PlaintextImpl::SetFormat, - ptx_SetFormat_docs, - py::arg("fmt")) + py::arg("fmt"), + py::doc(ptx_SetFormat_docs)) .def("GetCoefPackedValue", &PlaintextImpl::GetCoefPackedValue) .def("GetPackedValue", &PlaintextImpl::GetPackedValue) - .def("GetCKKSPackedValue", &PlaintextImpl::GetCKKSPackedValue, - ptx_GetCKKSPackedValue_docs) - .def("GetRealPackedValue", &PlaintextImpl::GetRealPackedValue, - ptx_GetRealPackedValue_docs) + .def("GetCKKSPackedValue", &PlaintextImpl::GetCKKSPackedValue, ptx_GetCKKSPackedValue_docs) + .def("GetRealPackedValue", &PlaintextImpl::GetRealPackedValue, ptx_GetRealPackedValue_docs) .def("GetLevel", &PlaintextImpl::GetLevel) .def("SetLevel", &PlaintextImpl::SetLevel) .def("GetNoiseScaleDeg", &PlaintextImpl::GetNoiseScaleDeg) @@ -1317,10 +1461,16 @@ void bind_ciphertext(py::module &m) { // .def("GetDepth", &CiphertextImpl<DCRTPoly>::GetDepth) // .def("SetDepth", &CiphertextImpl<DCRTPoly>::SetDepth) .def("GetLevel", &CiphertextImpl<DCRTPoly>::GetLevel, ctx_GetLevel_docs) - .def("SetLevel", &CiphertextImpl<DCRTPoly>::SetLevel, ctx_SetLevel_docs, - py::arg("level")) + .def("SetLevel", &CiphertextImpl<DCRTPoly>::SetLevel, + py::arg("level"), + py::doc(ctx_SetLevel_docs)) .def("Clone", &CiphertextImpl<DCRTPoly>::Clone) - .def("RemoveElement", &RemoveElementWrapper, cc_RemoveElement_docs) + .def("RemoveElement", + [](Ciphertext<DCRTPoly>& self, uint32_t index) { + self->GetElements().erase(self->GetElements().begin() + index); + }, + py::arg("index"), + py::doc(cc_RemoveElement_docs)) // .def("GetHopLevel", &CiphertextImpl<DCRTPoly>::GetHopLevel) // .def("SetHopLevel", &CiphertextImpl<DCRTPoly>::SetHopLevel) // .def("GetScalingFactor", &CiphertextImpl<DCRTPoly>::GetScalingFactor) @@ -1347,52 +1497,20 @@ void bind_ciphertext(py::module &m) { }); } -// void bind_ciphertext(py::module &m) { -// using CiphertextImplDCRT = CiphertextImpl<DCRTPoly>; -// using CiphertextDCRT = Ciphertext<DCRTPoly>; // shared_ptr<CiphertextImpl<DCRTPoly>> - -// // Bind CiphertextImpl<DCRTPoly> and expose it to Python as "Ciphertext" -// py::class_<CiphertextImplDCRT, std::shared_ptr<CiphertextImplDCRT>>(m, "Ciphertext") -// .def(py::init<>()) -// .def("__add__", [](const CiphertextDCRT &a, const CiphertextDCRT &b) { -// return a + b; -// }, -// py::is_operator(), pybind11::keep_alive<0, 1>()) -// .def("GetLevel", &CiphertextImplDCRT::GetLevel, ctx_GetLevel_docs) -// .def("SetLevel", &CiphertextImplDCRT::SetLevel, ctx_SetLevel_docs, py::arg("level")) -// .def("Clone", &CiphertextImplDCRT::Clone) -// .def("RemoveElement", &RemoveElementWrapper, cc_RemoveElement_docs) -// .def("GetSlots", &CiphertextImplDCRT::GetSlots) -// .def("SetSlots", &CiphertextImplDCRT::SetSlots) -// .def("GetNoiseScaleDeg", &CiphertextImplDCRT::GetNoiseScaleDeg) -// .def("SetNoiseScaleDeg", &CiphertextImplDCRT::SetNoiseScaleDeg) -// .def("GetCryptoContext", &CiphertextImplDCRT::GetCryptoContext) -// .def("GetEncodingType", &CiphertextImplDCRT::GetEncodingType) -// .def("GetElements", [](const CiphertextImplDCRT& self) -> const std::vector<DCRTPoly>& { -// return self.GetElements(); -// }, py::return_value_policy::reference_internal) -// .def("GetElementsMutable", [](CiphertextImplDCRT& self) -> std::vector<DCRTPoly>& { -// return self.GetElements(); -// }, py::return_value_policy::reference_internal) -// .def("SetElements", [](CiphertextImplDCRT& self, const std::vector<DCRTPoly>& elems) { -// self.SetElements(elems); -// }) -// .def("SetElementsMove", [](CiphertextImplDCRT& self, std::vector<DCRTPoly>&& elems) { -// self.SetElements(std::move(elems)); -// }); - -// // Bind the shared_ptr alias (Ciphertext<DCRTPoly>) so it picks up the methods above -// py::class_<CiphertextDCRT>(m, "_CiphertextAlias"); // hidden helper; not necessary for users -// } - void bind_schemes(py::module &m){ - /*Bind schemes specific functionalities like bootstrapping functions and multiparty*/ + // Bind schemes specific functionalities like bootstrapping functions and multiparty py::class_<FHECKKSRNS>(m, "FHECKKSRNS") .def(py::init<>()) - //.def_static("GetBootstrapDepth", &FHECKKSRNS::GetBootstrapDepth) - .def_static("GetBootstrapDepth", static_cast<uint32_t (*)(uint32_t, const std::vector<uint32_t>&, SecretKeyDist)>(&FHECKKSRNS::GetBootstrapDepth)) - .def_static("GetBootstrapDepth", static_cast<uint32_t (*)(const std::vector<uint32_t>&, SecretKeyDist)>(&FHECKKSRNS::GetBootstrapDepth)); - + .def_static("GetBootstrapDepth", + py::overload_cast<uint32_t, const std::vector<uint32_t>&, SecretKeyDist>(&FHECKKSRNS::GetBootstrapDepth), + py::arg("depth"), + py::arg("levelBudget"), + py::arg("keyDist")) + .def_static("GetBootstrapDepth", + py::overload_cast<const std::vector<uint32_t>&, SecretKeyDist>(&FHECKKSRNS::GetBootstrapDepth), + py::arg("levelBudget"), + py::arg("keyDist")) + ; } void bind_sch_swch_params(py::module &m) @@ -1444,15 +1562,15 @@ void bind_sch_swch_params(py::module &m) }); } -PYBIND11_MODULE(openfhe, m) -{ +PYBIND11_MODULE(openfhe, m) { + // sequence of function calls matters m.doc() = "Open-Source Fully Homomorphic Encryption Library"; - // binfhe library bind_DCRTPoly(m); + // binfhe library bind_binfhe_enums(m); - bind_binfhe_context(m); - bind_binfhe_keys(m); bind_binfhe_ciphertext(m); + bind_binfhe_keys(m); + bind_binfhe_context(m); // pke library bind_enums_and_constants(m); bind_parameters<CryptoContextBFVRNS>(m,"CCParamsBFVRNS"); diff --git a/src/lib/binfhe/binfhecontext_wrapper.cpp b/src/lib/binfhe/binfhecontext_wrapper.cpp index 37338f1..6273531 100644 --- a/src/lib/binfhe/binfhecontext_wrapper.cpp +++ b/src/lib/binfhe/binfhecontext_wrapper.cpp @@ -28,97 +28,37 @@ // 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. //================================================================================== -#include <pybind11/pybind11.h> -#include <pybind11/stl.h> #include <openfhe.h> #include "binfhecontext_wrapper.h" +#include <pybind11/pybind11.h> +#include <pybind11/stl.h> + using namespace lbcrypto; namespace py = pybind11; -LWECiphertext binfhe_EncryptWrapper(BinFHEContext &self, ConstLWEPrivateKey sk, const LWEPlaintext &m, BINFHE_OUTPUT output, - LWEPlaintextModulus p, uint64_t mod) -{ - NativeInteger mod_native_int = NativeInteger(mod); - return self.Encrypt(sk, m, output, p, mod_native_int); -} - -LWEPlaintext binfhe_DecryptWrapper(BinFHEContext &self, - ConstLWEPrivateKey sk, - ConstLWECiphertext ct, - LWEPlaintextModulus p) -{ - - LWEPlaintext result; - self.Decrypt(sk, ct, &result, p); - return result; -} - -uint32_t GetnWrapper(BinFHEContext &self) -{ - return self.GetParams()->GetLWEParams()->Getn(); -} - -const uint64_t GetqWrapper(BinFHEContext &self) -{ - return self.GetParams()->GetLWEParams()->Getq().ConvertToInt<uint64_t>(); -} - -const uint64_t GetMaxPlaintextSpaceWrapper(BinFHEContext &self) -{ - return self.GetMaxPlaintextSpace().ConvertToInt<uint64_t>(); -} - -const uint64_t GetBetaWrapper(BinFHEContext &self) -{ - return self.GetBeta().ConvertToInt<uint64_t>(); -} - -const uint64_t GetLWECiphertextModulusWrapper(LWECiphertext &self) -{ - return self->GetModulus().ConvertToInt<uint64_t>(); -} // Define static variables to hold the state py::function* static_f = nullptr; // Define a static function that uses the static variables NativeInteger StaticFunction(NativeInteger m, NativeInteger p) { - // Convert the arguments to int - uint64_t m_int = m.ConvertToInt<uint64_t>(); - uint64_t p_int = p.ConvertToInt<uint64_t>(); // Call the Python function - py::object result_py = (*static_f)(m_int, p_int); + py::object result_py = (*static_f)(m.ConvertToInt<uint64_t>(), p.ConvertToInt<uint64_t>()); // Convert the result to a NativeInteger return NativeInteger(py::cast<uint64_t>(result_py)); } -std::vector<uint64_t> GenerateLUTviaFunctionWrapper(BinFHEContext &self, py::function f, uint64_t p) -{ - NativeInteger p_native_int = NativeInteger(p); +std::vector<uint64_t> GenerateLUTviaFunctionWrapper(BinFHEContext &self, py::function f, uint64_t p) { static_f = &f; - std::vector<NativeInteger> result = self.GenerateLUTviaFunction(StaticFunction, p_native_int); + std::vector<NativeInteger> result = self.GenerateLUTviaFunction(StaticFunction, NativeInteger(p)); static_f = nullptr; + std::vector<uint64_t> result_uint64_t; - // int size_int = static_cast<int>(result.size()); + result.reserve(result.size()); for (const auto& value : result) - { - result_uint64_t.push_back(value.ConvertToInt<uint64_t>()); - } - return result_uint64_t; -} + result_uint64_t.emplace_back(value.ConvertToInt<uint64_t>()); -// LWECiphertext EvalFunc(ConstLWECiphertext &ct, const std::vector<NativeInteger> &LUT) const -LWECiphertext EvalFuncWrapper(BinFHEContext &self, ConstLWECiphertext &ct, const std::vector<uint64_t> &LUT) -{ - std::vector<NativeInteger> LUT_native_int; - LUT_native_int.reserve(LUT.size()); // Reserve space for the elements - for (const auto& value : LUT) - { - LUT_native_int.push_back(NativeInteger(value)); - } - return self.EvalFunc(ct, LUT_native_int); + return result_uint64_t; } - - diff --git a/src/lib/binfhe_bindings.cpp b/src/lib/binfhe_bindings.cpp index d85c56f..3b85085 100644 --- a/src/lib/binfhe_bindings.cpp +++ b/src/lib/binfhe_bindings.cpp @@ -30,207 +30,254 @@ //================================================================================== #include "binfhe_bindings.h" -#include <pybind11/operators.h> - #include "openfhe.h" #include "binfhecontext.h" #include "binfhecontext_docs.h" #include "binfhecontext_wrapper.h" +#include <pybind11/stl.h> +#include <pybind11/operators.h> + #include "cereal/archives/binary.hpp" -// #include "cereal/archives/portable_binary.hpp" -// #include "core/utils/serial.h" using namespace lbcrypto; namespace py = pybind11; void bind_binfhe_enums(py::module &m) { - py::enum_<BINFHE_PARAMSET>(m, "BINFHE_PARAMSET") - .value("TOY", BINFHE_PARAMSET::TOY) - .value("MEDIUM", BINFHE_PARAMSET::MEDIUM) - .value("STD128_LMKCDEY", BINFHE_PARAMSET::STD128_LMKCDEY) - .value("STD128_AP", BINFHE_PARAMSET::STD128_AP) - .value("STD128", BINFHE_PARAMSET::STD128) - .value("STD192", BINFHE_PARAMSET::STD192) - .value("STD256", BINFHE_PARAMSET::STD256) - .value("STD128Q", BINFHE_PARAMSET::STD128Q) - .value("STD128Q_LMKCDEY", BINFHE_PARAMSET::STD128Q_LMKCDEY) - .value("STD192Q", BINFHE_PARAMSET::STD192Q) - .value("STD256Q", BINFHE_PARAMSET::STD256Q) - .value("STD128_3", BINFHE_PARAMSET::STD128_3) - .value("STD128_3_LMKCDEY", BINFHE_PARAMSET::STD128_3_LMKCDEY) - .value("STD128Q_3", BINFHE_PARAMSET::STD128Q_3) - .value("STD128Q_3_LMKCDEY", BINFHE_PARAMSET::STD128Q_3_LMKCDEY) - .value("STD192Q_3", BINFHE_PARAMSET::STD192Q_3) - .value("STD256Q_3", BINFHE_PARAMSET::STD256Q_3) - .value("STD128_4", BINFHE_PARAMSET::STD128_4) - .value("STD128_4_LMKCDEY", BINFHE_PARAMSET::STD128_4_LMKCDEY) - .value("STD128Q_4", BINFHE_PARAMSET::STD128Q_4) - .value("STD128Q_4_LMKCDEY", BINFHE_PARAMSET::STD128Q_4_LMKCDEY) - .value("STD192Q_4", BINFHE_PARAMSET::STD192Q_4) - .value("STD256Q_4", BINFHE_PARAMSET::STD256Q_4) - .value("SIGNED_MOD_TEST", BINFHE_PARAMSET::SIGNED_MOD_TEST); - m.attr("TOY") = py::cast(BINFHE_PARAMSET::TOY); - m.attr("MEDIUM") = py::cast(BINFHE_PARAMSET::MEDIUM); - m.attr("STD128_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128_LMKCDEY); - m.attr("STD128_AP") = py::cast(BINFHE_PARAMSET::STD128_AP); - m.attr("STD128") = py::cast(BINFHE_PARAMSET::STD128); - m.attr("STD192") = py::cast(BINFHE_PARAMSET::STD192); - m.attr("STD256") = py::cast(BINFHE_PARAMSET::STD256); - m.attr("STD128Q") = py::cast(BINFHE_PARAMSET::STD128Q); - m.attr("STD128Q_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128Q_LMKCDEY); - m.attr("STD192Q") = py::cast(BINFHE_PARAMSET::STD192Q); - m.attr("STD256Q") = py::cast(BINFHE_PARAMSET::STD256Q); - m.attr("STD128_3") = py::cast(BINFHE_PARAMSET::STD128_3); - m.attr("STD128_3_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128_3_LMKCDEY); - m.attr("STD128Q_3") = py::cast(BINFHE_PARAMSET::STD128Q_3); - m.attr("STD128Q_3_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128Q_3_LMKCDEY); - m.attr("STD192Q_3") = py::cast(BINFHE_PARAMSET::STD192Q_3); - m.attr("STD256Q_3") = py::cast(BINFHE_PARAMSET::STD256Q_3); - m.attr("STD128_4") = py::cast(BINFHE_PARAMSET::STD128_4); - m.attr("STD128_4_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128_4_LMKCDEY); - m.attr("STD128Q_4") = py::cast(BINFHE_PARAMSET::STD128Q_4); - m.attr("STD128Q_4_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128Q_4_LMKCDEY); - m.attr("STD192Q_4") = py::cast(BINFHE_PARAMSET::STD192Q_4); - m.attr("STD256Q_4") = py::cast(BINFHE_PARAMSET::STD256Q_4); - m.attr("SIGNED_MOD_TEST") = py::cast(BINFHE_PARAMSET::SIGNED_MOD_TEST); + py::enum_<BINFHE_PARAMSET>(m, "BINFHE_PARAMSET") + .value("TOY", BINFHE_PARAMSET::TOY) + .value("MEDIUM", BINFHE_PARAMSET::MEDIUM) + .value("STD128_LMKCDEY", BINFHE_PARAMSET::STD128_LMKCDEY) + .value("STD128_AP", BINFHE_PARAMSET::STD128_AP) + .value("STD128", BINFHE_PARAMSET::STD128) + .value("STD192", BINFHE_PARAMSET::STD192) + .value("STD256", BINFHE_PARAMSET::STD256) + .value("STD128Q", BINFHE_PARAMSET::STD128Q) + .value("STD128Q_LMKCDEY", BINFHE_PARAMSET::STD128Q_LMKCDEY) + .value("STD192Q", BINFHE_PARAMSET::STD192Q) + .value("STD256Q", BINFHE_PARAMSET::STD256Q) + .value("STD128_3", BINFHE_PARAMSET::STD128_3) + .value("STD128_3_LMKCDEY", BINFHE_PARAMSET::STD128_3_LMKCDEY) + .value("STD128Q_3", BINFHE_PARAMSET::STD128Q_3) + .value("STD128Q_3_LMKCDEY", BINFHE_PARAMSET::STD128Q_3_LMKCDEY) + .value("STD192Q_3", BINFHE_PARAMSET::STD192Q_3) + .value("STD256Q_3", BINFHE_PARAMSET::STD256Q_3) + .value("STD128_4", BINFHE_PARAMSET::STD128_4) + .value("STD128_4_LMKCDEY", BINFHE_PARAMSET::STD128_4_LMKCDEY) + .value("STD128Q_4", BINFHE_PARAMSET::STD128Q_4) + .value("STD128Q_4_LMKCDEY", BINFHE_PARAMSET::STD128Q_4_LMKCDEY) + .value("STD192Q_4", BINFHE_PARAMSET::STD192Q_4) + .value("STD256Q_4", BINFHE_PARAMSET::STD256Q_4) + .value("SIGNED_MOD_TEST", BINFHE_PARAMSET::SIGNED_MOD_TEST); + m.attr("TOY") = py::cast(BINFHE_PARAMSET::TOY); + m.attr("MEDIUM") = py::cast(BINFHE_PARAMSET::MEDIUM); + m.attr("STD128_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128_LMKCDEY); + m.attr("STD128_AP") = py::cast(BINFHE_PARAMSET::STD128_AP); + m.attr("STD128") = py::cast(BINFHE_PARAMSET::STD128); + m.attr("STD192") = py::cast(BINFHE_PARAMSET::STD192); + m.attr("STD256") = py::cast(BINFHE_PARAMSET::STD256); + m.attr("STD128Q") = py::cast(BINFHE_PARAMSET::STD128Q); + m.attr("STD128Q_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128Q_LMKCDEY); + m.attr("STD192Q") = py::cast(BINFHE_PARAMSET::STD192Q); + m.attr("STD256Q") = py::cast(BINFHE_PARAMSET::STD256Q); + m.attr("STD128_3") = py::cast(BINFHE_PARAMSET::STD128_3); + m.attr("STD128_3_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128_3_LMKCDEY); + m.attr("STD128Q_3") = py::cast(BINFHE_PARAMSET::STD128Q_3); + m.attr("STD128Q_3_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128Q_3_LMKCDEY); + m.attr("STD192Q_3") = py::cast(BINFHE_PARAMSET::STD192Q_3); + m.attr("STD256Q_3") = py::cast(BINFHE_PARAMSET::STD256Q_3); + m.attr("STD128_4") = py::cast(BINFHE_PARAMSET::STD128_4); + m.attr("STD128_4_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128_4_LMKCDEY); + m.attr("STD128Q_4") = py::cast(BINFHE_PARAMSET::STD128Q_4); + m.attr("STD128Q_4_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128Q_4_LMKCDEY); + m.attr("STD192Q_4") = py::cast(BINFHE_PARAMSET::STD192Q_4); + m.attr("STD256Q_4") = py::cast(BINFHE_PARAMSET::STD256Q_4); + m.attr("SIGNED_MOD_TEST") = py::cast(BINFHE_PARAMSET::SIGNED_MOD_TEST); - py::enum_<BINFHE_METHOD>(m, "BINFHE_METHOD") - .value("INVALID_METHOD", BINFHE_METHOD::INVALID_METHOD) - .value("AP", BINFHE_METHOD::AP) - .value("GINX", BINFHE_METHOD::GINX) - .value("LMKCDEY", BINFHE_METHOD::LMKCDEY); - m.attr("INVALID_METHOD") = py::cast(BINFHE_METHOD::INVALID_METHOD); - m.attr("GINX") = py::cast(BINFHE_METHOD::GINX); - m.attr("AP") = py::cast(BINFHE_METHOD::AP); - m.attr("LMKCDEY") = py::cast(BINFHE_METHOD::LMKCDEY); + py::enum_<BINFHE_METHOD>(m, "BINFHE_METHOD") + .value("INVALID_METHOD", BINFHE_METHOD::INVALID_METHOD) + .value("AP", BINFHE_METHOD::AP) + .value("GINX", BINFHE_METHOD::GINX) + .value("LMKCDEY", BINFHE_METHOD::LMKCDEY); + m.attr("INVALID_METHOD") = py::cast(BINFHE_METHOD::INVALID_METHOD); + m.attr("GINX") = py::cast(BINFHE_METHOD::GINX); + m.attr("AP") = py::cast(BINFHE_METHOD::AP); + m.attr("LMKCDEY") = py::cast(BINFHE_METHOD::LMKCDEY); - py::enum_<KEYGEN_MODE>(m, "KEYGEN_MODE") - .value("SYM_ENCRYPT", KEYGEN_MODE::SYM_ENCRYPT) - .value("PUB_ENCRYPT", KEYGEN_MODE::PUB_ENCRYPT); - m.attr("SYM_ENCRYPT") = py::cast(KEYGEN_MODE::SYM_ENCRYPT); - m.attr("PUB_ENCRYPT") = py::cast(KEYGEN_MODE::PUB_ENCRYPT); + py::enum_<KEYGEN_MODE>(m, "KEYGEN_MODE") + .value("SYM_ENCRYPT", KEYGEN_MODE::SYM_ENCRYPT) + .value("PUB_ENCRYPT", KEYGEN_MODE::PUB_ENCRYPT); + m.attr("SYM_ENCRYPT") = py::cast(KEYGEN_MODE::SYM_ENCRYPT); + m.attr("PUB_ENCRYPT") = py::cast(KEYGEN_MODE::PUB_ENCRYPT); - py::enum_<BINFHE_OUTPUT>(m, "BINFHE_OUTPUT") - .value("INVALID_OUTPUT", BINFHE_OUTPUT::INVALID_OUTPUT) - .value("FRESH", BINFHE_OUTPUT::FRESH) - .value("BOOTSTRAPPED", BINFHE_OUTPUT::BOOTSTRAPPED); - m.attr("INVALID_OUTPUT") = py::cast(BINFHE_OUTPUT::INVALID_OUTPUT); - m.attr("FRESH") = py::cast(BINFHE_OUTPUT::FRESH); - m.attr("BOOTSTRAPPED") = py::cast(BINFHE_OUTPUT::BOOTSTRAPPED); + py::enum_<BINFHE_OUTPUT>(m, "BINFHE_OUTPUT") + .value("INVALID_OUTPUT", BINFHE_OUTPUT::INVALID_OUTPUT) + .value("FRESH", BINFHE_OUTPUT::FRESH) + .value("BOOTSTRAPPED", BINFHE_OUTPUT::BOOTSTRAPPED); + m.attr("INVALID_OUTPUT") = py::cast(BINFHE_OUTPUT::INVALID_OUTPUT); + m.attr("FRESH") = py::cast(BINFHE_OUTPUT::FRESH); + m.attr("BOOTSTRAPPED") = py::cast(BINFHE_OUTPUT::BOOTSTRAPPED); - py::enum_<BINGATE>(m, "BINGATE") - .value("OR", BINGATE::OR) - .value("AND", BINGATE::AND) - .value("NOR", BINGATE::NOR) - .value("NAND", BINGATE::NAND) - .value("XOR_FAST", BINGATE::XOR_FAST) - .value("XNOR_FAST", BINGATE::XNOR_FAST) - .value("XOR", BINGATE::XOR) - .value("XNOR", BINGATE::XNOR); - m.attr("OR") = py::cast(BINGATE::OR); - m.attr("AND") = py::cast(BINGATE::AND); - m.attr("NOR") = py::cast(BINGATE::NOR); - m.attr("NAND") = py::cast(BINGATE::NAND); - m.attr("XOR_FAST") = py::cast(BINGATE::XOR_FAST); - m.attr("XNOR_FAST") = py::cast(BINGATE::XNOR_FAST); - m.attr("XOR") = py::cast(BINGATE::XOR); - m.attr("XNOR") = py::cast(BINGATE::XNOR); + py::enum_<BINGATE>(m, "BINGATE") + .value("OR", BINGATE::OR) + .value("AND", BINGATE::AND) + .value("NOR", BINGATE::NOR) + .value("NAND", BINGATE::NAND) + .value("XOR_FAST", BINGATE::XOR_FAST) + .value("XNOR_FAST", BINGATE::XNOR_FAST) + .value("XOR", BINGATE::XOR) + .value("XNOR", BINGATE::XNOR); + m.attr("OR") = py::cast(BINGATE::OR); + m.attr("AND") = py::cast(BINGATE::AND); + m.attr("NOR") = py::cast(BINGATE::NOR); + m.attr("NAND") = py::cast(BINGATE::NAND); + m.attr("XOR_FAST") = py::cast(BINGATE::XOR_FAST); + m.attr("XNOR_FAST") = py::cast(BINGATE::XNOR_FAST); + m.attr("XOR") = py::cast(BINGATE::XOR); + m.attr("XNOR") = py::cast(BINGATE::XNOR); } void bind_binfhe_keys(py::module &m) { - py::class_<LWEPrivateKeyImpl, std::shared_ptr<LWEPrivateKeyImpl>>( - m, "LWEPrivateKey") - .def(py::init<>()) - .def("GetLength", &LWEPrivateKeyImpl::GetLength) - .def(py::self == py::self) - .def(py::self != py::self); + py::class_<LWEPrivateKeyImpl, std::shared_ptr<LWEPrivateKeyImpl>>(m, "LWEPrivateKey") + .def(py::init<>()) + .def("GetLength", &LWEPrivateKeyImpl::GetLength) + .def(py::self == py::self) + .def(py::self != py::self); } void bind_binfhe_ciphertext(py::module &m) { - py::class_<LWECiphertextImpl, std::shared_ptr<LWECiphertextImpl>>( - m, "LWECiphertext") - .def(py::init<>()) - .def("GetLength", &LWECiphertextImpl::GetLength) - .def("GetModulus", &GetLWECiphertextModulusWrapper) - .def(py::self == py::self) - .def(py::self != py::self); + py::class_<LWECiphertextImpl, std::shared_ptr<LWECiphertextImpl>>(m, "LWECiphertext") + .def(py::init<>()) + .def("GetLength", &LWECiphertextImpl::GetLength) + .def("GetModulus", + [](LWECiphertext& self) { + return self->GetModulus().ConvertToInt<uint64_t>(); + }) + .def(py::self == py::self) + .def(py::self != py::self); } void bind_binfhe_context(py::module &m) { - py::class_<BinFHEContext, std::shared_ptr<BinFHEContext>>(m, "BinFHEContext") - .def(py::init<>()) - .def("GenerateBinFHEContext", - static_cast<void (BinFHEContext::*)(BINFHE_PARAMSET, BINFHE_METHOD)>( - &BinFHEContext::GenerateBinFHEContext), - binfhe_GenerateBinFHEContext_parset_docs, py::arg("set"), - py::arg("method") = GINX) - // void GenerateBinFHEContext(BINFHE_PARAMSET set, bool arbFunc, uint32_t - // logQ = 11, int64_t N = 0, BINFHE_METHOD method = GINX, bool - // timeOptimization = false) - .def("GenerateBinFHEContext", - static_cast<void (BinFHEContext::*)(BINFHE_PARAMSET, bool, uint32_t, - uint32_t, BINFHE_METHOD, bool)>( - &BinFHEContext::GenerateBinFHEContext), - binfhe_GenerateBinFHEContext_docs, py::arg("set"), - py::arg("arbFunc"), py::arg("logQ") = 11, py::arg("N") = 0, - py::arg("method") = GINX, py::arg("timeOptimization") = false) - .def("KeyGen", &BinFHEContext::KeyGen, binfhe_KeyGen_docs) - .def("KeyGenN", &BinFHEContext::KeyGenN) - .def("KeyGenPair", &BinFHEContext::KeyGenPair) - .def("BTKeyGen", &BinFHEContext::BTKeyGen, binfhe_BTKeyGen_docs, - py::arg("sk"), py::arg("keygenMode") = SYM_ENCRYPT) - .def("Encrypt", &binfhe_EncryptWrapper, binfhe_Encrypt_docs, - py::arg("sk"), py::arg("m"), py::arg("output") = BOOTSTRAPPED, - py::arg("p") = 4, py::arg("mod") = 0) - .def("Decrypt", &binfhe_DecryptWrapper, binfhe_Decrypt_docs, - py::arg("sk"), py::arg("ct"), py::arg("p") = 4) - .def("EvalBinGate", - static_cast<LWECiphertext (BinFHEContext::*)( - BINGATE, ConstLWECiphertext &, ConstLWECiphertext &, bool) const>( - &BinFHEContext::EvalBinGate), - binfhe_EvalBinGate_docs, py::arg("gate"), py::arg("ct1"), - py::arg("ct2"), py::arg("extended") = false) - .def("EvalBinGate", - static_cast<LWECiphertext (BinFHEContext::*)( - BINGATE, const std::vector<LWECiphertext> &, bool) const>( - &BinFHEContext::EvalBinGate), - py::arg("gate"), py::arg("ctvector"), py::arg("extended") = false) - .def("EvalNOT", &BinFHEContext::EvalNOT, binfhe_EvalNOT_docs, - py::arg("ct")) - .def("Getn", &GetnWrapper) - .def("Getq", &GetqWrapper) - .def("GetMaxPlaintextSpace", &GetMaxPlaintextSpaceWrapper) - .def("GetBeta", &GetBetaWrapper) - .def("EvalDecomp", &BinFHEContext::EvalDecomp, binfhe_EvalDecomp_docs, - py::arg("ct")) - .def("EvalFloor", &BinFHEContext::EvalFloor, binfhe_EvalFloor_docs, - py::arg("ct"), py::arg("roundbits") = 0) - .def("GenerateLUTviaFunction", &GenerateLUTviaFunctionWrapper, - binfhe_GenerateLUTviaFunction_docs, py::arg("f"), py::arg("p")) - .def("EvalFunc", &EvalFuncWrapper, binfhe_EvalFunc_docs, py::arg("ct"), - py::arg("LUT")) - .def("EvalSign", &BinFHEContext::EvalSign, binfhe_EvalSign_docs, - py::arg("ct"), py::arg("schemeSwitch") = false) - .def("EvalNOT", &BinFHEContext::EvalNOT) - .def("EvalConstant", &BinFHEContext::EvalConstant) - .def("ClearBTKeys", &BinFHEContext::ClearBTKeys) - .def("Bootstrap", &BinFHEContext::Bootstrap, py::arg("ct"), py::arg("extended") = false) - .def("SerializedVersion", &BinFHEContext::SerializedVersion, - binfhe_SerializedVersion_docs) - .def("SerializedObjectName", &BinFHEContext::SerializedObjectName, - binfhe_SerializedObjectName_docs) - .def("SaveJSON", &BinFHEContext::save<cereal::JSONOutputArchive>) - .def("LoadJSON", &BinFHEContext::load<cereal::JSONInputArchive>) - .def("SaveBinary", &BinFHEContext::save<cereal::BinaryOutputArchive>) - .def("LoadBinary", &BinFHEContext::load<cereal::BinaryInputArchive>) - .def("SavePortableBinary", - &BinFHEContext::save<cereal::PortableBinaryOutputArchive>) - .def("LoadPortableBinary", - &BinFHEContext::load<cereal::PortableBinaryInputArchive>) - .def("GetPublicKey", &BinFHEContext::GetPublicKey) - .def("GetSwitchKey", &BinFHEContext::GetSwitchKey) - .def("GetRefreshKey", &BinFHEContext::GetRefreshKey) - .def("GetBinFHEScheme", &BinFHEContext::GetBinFHEScheme) - .def("GetLWEScheme", &BinFHEContext::GetLWEScheme) - .def("GetParams", &BinFHEContext::GetParams); + py::class_<BinFHEContext, std::shared_ptr<BinFHEContext>>(m, "BinFHEContext") + .def(py::init<>()) + .def("GenerateBinFHEContext", + py::overload_cast<BINFHE_PARAMSET, BINFHE_METHOD>(&BinFHEContext::GenerateBinFHEContext), + binfhe_GenerateBinFHEContext_parset_docs, + py::arg("set"), + py::arg("method") = GINX) + // void GenerateBinFHEContext(BINFHE_PARAMSET set, bool arbFunc, uint32_t + // logQ = 11, int64_t N = 0, BINFHE_METHOD method = GINX, bool + // timeOptimization = false) + .def("GenerateBinFHEContext", + py::overload_cast<BINFHE_PARAMSET, bool, uint32_t, uint32_t, BINFHE_METHOD, bool>(&BinFHEContext::GenerateBinFHEContext), + binfhe_GenerateBinFHEContext_docs, + py::arg("set"), + py::arg("arbFunc"), + py::arg("logQ") = 11, + py::arg("N") = 0, + py::arg("method") = GINX, + py::arg("timeOptimization") = false) + .def("KeyGen", &BinFHEContext::KeyGen, binfhe_KeyGen_docs) + .def("KeyGenN", &BinFHEContext::KeyGenN) + .def("KeyGenPair", &BinFHEContext::KeyGenPair) + .def("BTKeyGen", &BinFHEContext::BTKeyGen, + binfhe_BTKeyGen_docs, + py::arg("sk"), + py::arg("keygenMode") = SYM_ENCRYPT) + .def("Encrypt", + [](BinFHEContext& self, ConstLWEPrivateKey sk, const LWEPlaintext& m, BINFHE_OUTPUT output, LWEPlaintextModulus p, uint64_t mod) { + return self.Encrypt(sk, m, output, p, NativeInteger(mod)); + }, + py::arg("sk"), + py::arg("m"), + py::arg("output") = BOOTSTRAPPED, + py::arg("p") = 4, + py::arg("mod") = 0, + py::doc(binfhe_Encrypt_docs)) + .def("Decrypt", + [](BinFHEContext& self, ConstLWEPrivateKey sk, ConstLWECiphertext ct, LWEPlaintextModulus p) { + LWEPlaintext result; + self.Decrypt(sk, ct, &result, p); + return result; + }, + py::arg("sk"), + py::arg("ct"), + py::arg("p") = 4, + py::doc(binfhe_Decrypt_docs)) + .def("EvalBinGate", + py::overload_cast<BINGATE, ConstLWECiphertext&, ConstLWECiphertext&, bool>(&BinFHEContext::EvalBinGate, py::const_), + binfhe_EvalBinGate_docs, + py::arg("gate"), + py::arg("ct1"), + py::arg("ct2"), + py::arg("extended") = false) + .def("EvalBinGate", + py::overload_cast<BINGATE, const std::vector<LWECiphertext>&, bool>(&BinFHEContext::EvalBinGate, py::const_), + py::arg("gate"), + py::arg("ctvector"), + py::arg("extended") = false) + .def("EvalNOT", &BinFHEContext::EvalNOT, + binfhe_EvalNOT_docs, + py::arg("ct")) + .def("Getn", + [](BinFHEContext& self) { + return self.GetParams()->GetLWEParams()->Getn(); + }) + .def("Getq", + [](BinFHEContext& self) { + return self.GetParams()->GetLWEParams()->Getq().ConvertToInt<uint64_t>(); + }) + .def("GetMaxPlaintextSpace", + [](BinFHEContext& self) { + return self.GetMaxPlaintextSpace().ConvertToInt<uint64_t>(); + }) + .def("GetBeta", + [](BinFHEContext& self) { + return self.GetBeta().ConvertToInt<uint64_t>(); + }) + .def("EvalDecomp", &BinFHEContext::EvalDecomp, + binfhe_EvalDecomp_docs, + py::arg("ct")) + .def("EvalFloor", &BinFHEContext::EvalFloor, + binfhe_EvalFloor_docs, + py::arg("ct"), + py::arg("roundbits") = 0) + .def("GenerateLUTviaFunction", &GenerateLUTviaFunctionWrapper, + binfhe_GenerateLUTviaFunction_docs, + py::arg("f"), + py::arg("p")) + .def("EvalFunc", + [](BinFHEContext& self, ConstLWECiphertext& ct, const std::vector<uint64_t>& LUT) { + std::vector<NativeInteger> nativeLUT; + nativeLUT.reserve(LUT.size()); + for (auto value : LUT) { + nativeLUT.emplace_back(value); + } + return self.EvalFunc(ct, nativeLUT); + }, + py::arg("ct"), + py::arg("LUT"), + py::doc(binfhe_EvalFunc_docs)) + .def("EvalSign", &BinFHEContext::EvalSign, + binfhe_EvalSign_docs, + py::arg("ct"), + py::arg("schemeSwitch") = false) + .def("EvalConstant", &BinFHEContext::EvalConstant) + .def("ClearBTKeys", &BinFHEContext::ClearBTKeys) + .def("Bootstrap", &BinFHEContext::Bootstrap, py::arg("ct"), py::arg("extended") = false) + .def("SerializedVersion", &BinFHEContext::SerializedVersion, + binfhe_SerializedVersion_docs) + .def("SerializedObjectName", &BinFHEContext::SerializedObjectName, + binfhe_SerializedObjectName_docs) + .def("SaveJSON", &BinFHEContext::save<cereal::JSONOutputArchive>) + .def("LoadJSON", &BinFHEContext::load<cereal::JSONInputArchive>) + .def("SaveBinary", &BinFHEContext::save<cereal::BinaryOutputArchive>) + .def("LoadBinary", &BinFHEContext::load<cereal::BinaryInputArchive>) + .def("SavePortableBinary", &BinFHEContext::save<cereal::PortableBinaryOutputArchive>) + .def("LoadPortableBinary", &BinFHEContext::load<cereal::PortableBinaryInputArchive>) + .def("GetPublicKey", &BinFHEContext::GetPublicKey) + .def("GetSwitchKey", &BinFHEContext::GetSwitchKey) + .def("GetRefreshKey", &BinFHEContext::GetRefreshKey) + .def("GetBinFHEScheme", &BinFHEContext::GetBinFHEScheme) + .def("GetLWEScheme", &BinFHEContext::GetLWEScheme) + .def("GetParams", &BinFHEContext::GetParams); } diff --git a/src/lib/pke/cryptocontext_wrapper.cpp b/src/lib/pke/cryptocontext_wrapper.cpp deleted file mode 100644 index 68bf965..0000000 --- a/src/lib/pke/cryptocontext_wrapper.cpp +++ /dev/null @@ -1,148 +0,0 @@ -//================================================================================== -// BSD 2-Clause License -// -// Copyright (c) 2023-2025, 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. -//================================================================================== -#include "cryptocontext_wrapper.h" - - -Ciphertext<DCRTPoly> EvalFastRotationPrecomputeWrapper(CryptoContext<DCRTPoly> &self,ConstCiphertext<DCRTPoly> ciphertext) { - std::shared_ptr<std::vector<DCRTPoly>> precomp = self->EvalFastRotationPrecompute(ciphertext); - std::vector<DCRTPoly> elements = *(precomp.get()); - std::shared_ptr<CiphertextImpl<DCRTPoly>> cipherdigits = std::make_shared<CiphertextImpl<DCRTPoly>>(self); - cipherdigits->SetElements(std::move(elements)); - return cipherdigits; -} -Ciphertext<DCRTPoly> EvalFastRotationWrapper(CryptoContext<DCRTPoly>& self,ConstCiphertext<DCRTPoly> ciphertext, uint32_t index, uint32_t m,ConstCiphertext<DCRTPoly> digits) { - - std::vector<DCRTPoly> digitsElements = digits->GetElements(); - std::shared_ptr<std::vector<DCRTPoly>> digitsElementsPtr = std::make_shared<std::vector<DCRTPoly>>(digitsElements); - return self->EvalFastRotation(ciphertext, index, m, digitsElementsPtr); - } - -Ciphertext<DCRTPoly> EvalFastRotationExtWrapper(CryptoContext<DCRTPoly>& self,ConstCiphertext<DCRTPoly> ciphertext, uint32_t index, ConstCiphertext<DCRTPoly> digits, bool addFirst) { - std::vector<DCRTPoly> digitsElements = digits->GetElements(); - std::shared_ptr<std::vector<DCRTPoly>> digitsElementsPtr = std::make_shared<std::vector<DCRTPoly>>(digitsElements); - return self->EvalFastRotationExt(ciphertext, index, digitsElementsPtr, addFirst); -} - - -Plaintext DecryptWrapper(CryptoContext<DCRTPoly>& self,ConstCiphertext<DCRTPoly> ciphertext,const PrivateKey<DCRTPoly> privateKey){ - Plaintext plaintextDecResult; - self->Decrypt(privateKey, ciphertext,&plaintextDecResult); - return plaintextDecResult; -} -Plaintext DecryptWrapper(CryptoContext<DCRTPoly>& self,const PrivateKey<DCRTPoly> privateKey,ConstCiphertext<DCRTPoly> ciphertext){ - Plaintext plaintextDecResult; - self->Decrypt(privateKey, ciphertext,&plaintextDecResult); - return plaintextDecResult; -} - -Plaintext MultipartyDecryptFusionWrapper(CryptoContext<DCRTPoly>& self,const std::vector<Ciphertext<DCRTPoly>>& partialCiphertextVec){ - Plaintext plaintextDecResult; - self->MultipartyDecryptFusion(partialCiphertextVec,&plaintextDecResult); - return plaintextDecResult; -} - -const std::shared_ptr<std::map<uint32_t, EvalKey<DCRTPoly>>> GetEvalSumKeyMapWrapper(CryptoContext<DCRTPoly>& self,const std::string &keyTag){ - return std::make_shared<std::map<uint32_t, EvalKey<DCRTPoly>>>(CryptoContextImpl<DCRTPoly>::GetEvalSumKeyMap(keyTag));; -} - -PlaintextModulus GetPlaintextModulusWrapper(CryptoContext<DCRTPoly>& self){ - return self->GetCryptoParameters()->GetPlaintextModulus(); -} - -uint32_t GetBatchSizeWrapper(CryptoContext<DCRTPoly>& self){ - return self->GetCryptoParameters()->GetBatchSize(); -} - -double GetModulusWrapper(CryptoContext<DCRTPoly>& self){ - return self->GetCryptoParameters()->GetElementParams()->GetModulus().ConvertToDouble(); -} - -void RemoveElementWrapper(Ciphertext<DCRTPoly> &self, uint32_t index){ - self->GetElements().erase(self->GetElements().begin()+index); -} -uint32_t GetDigitSizeWrapper(CryptoContext<DCRTPoly>& self){ - return self->GetCryptoParameters()->GetDigitSize(); -} - -double GetScalingFactorRealWrapper(CryptoContext<DCRTPoly>& self, uint32_t l){ - if(self->getSchemeId()==SCHEME::CKKSRNS_SCHEME){ - const auto cryptoParams = std::dynamic_pointer_cast<CryptoParametersCKKSRNS>(self->GetCryptoParameters()); - double scFactor = cryptoParams->GetScalingFactorReal(l); - return scFactor; - } - else if(self->getSchemeId()==SCHEME::BFVRNS_SCHEME){ - const auto cryptoParams = std::dynamic_pointer_cast<CryptoParametersBFVRNS>(self->GetCryptoParameters()); - double scFactor = cryptoParams->GetScalingFactorReal(l); - return scFactor; - } - else if(self->getSchemeId()==SCHEME::BGVRNS_SCHEME){ - const auto cryptoParams = std::dynamic_pointer_cast<CryptoParametersBGVRNS>(self->GetCryptoParameters()); - double scFactor = cryptoParams->GetScalingFactorReal(l); - return scFactor; - } - else{ - OPENFHE_THROW("Invalid scheme"); - return 0; - } -} - -uint64_t GetModulusCKKSWrapper(CryptoContext<DCRTPoly> &self) -{ - - const auto cryptoParams = std::dynamic_pointer_cast<CryptoParametersCKKSRNS>(self->GetCryptoParameters()); - ILDCRTParams<DCRTPoly::Integer> elementParams = *(cryptoParams->GetElementParams()); - auto paramsQ = elementParams.GetParams(); - uint64_t modulus_CKKS_from = paramsQ[0]->GetModulus().ConvertToInt<uint64_t>(); - return modulus_CKKS_from; -} - -ScalingTechnique GetScalingTechniqueWrapper(CryptoContext<DCRTPoly> & self){ - if(self->getSchemeId()==SCHEME::CKKSRNS_SCHEME){ - const auto cryptoParams = std::dynamic_pointer_cast<CryptoParametersCKKSRNS>(self->GetCryptoParameters()); - return cryptoParams->GetScalingTechnique(); - } - else if(self->getSchemeId()==SCHEME::BFVRNS_SCHEME){ - const auto cryptoParams = std::dynamic_pointer_cast<CryptoParametersBFVRNS>(self->GetCryptoParameters()); - return cryptoParams->GetScalingTechnique(); - } - else if(self->getSchemeId()==SCHEME::BGVRNS_SCHEME){ - const auto cryptoParams = std::dynamic_pointer_cast<CryptoParametersBGVRNS>(self->GetCryptoParameters()); - return cryptoParams->GetScalingTechnique(); - } - else{ - OPENFHE_THROW("Invalid scheme"); - } - -} - -void ClearEvalMultKeysWrapper() { - CryptoContextImpl<DCRTPoly>::ClearEvalMultKeys(); -} \ No newline at end of file From 25f3454019f9694d4e17796171c8dbe8fe039452 Mon Sep 17 00:00:00 2001 From: dsuponitskiy <28961198+dsuponitskiy@users.noreply.github.com> Date: Thu, 31 Jul 2025 12:13:07 -0400 Subject: [PATCH 3/6] Additional bindings for python (#241) Co-authored-by: Dmitriy Suponitskiy <dsuponitskiy@dualitytech.com> --- src/lib/bindings.cpp | 55 +++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/src/lib/bindings.cpp b/src/lib/bindings.cpp index f8c1c5d..bb94678 100644 --- a/src/lib/bindings.cpp +++ b/src/lib/bindings.cpp @@ -65,8 +65,7 @@ void bind_DCRTPoly(py::module &m) { } template <typename T> -void bind_parameters(py::module &m, const std::string name) -{ +void bind_parameters(py::module &m, const std::string name) { py::class_<CCParams<T>>(m, name.c_str()) .def(py::init<>()) // getters @@ -224,8 +223,7 @@ void bind_crypto_context_templates(py::class_<CryptoContextImpl<DCRTPoly>, std:: ; } -void bind_crypto_context(py::module &m) -{ +void bind_crypto_context(py::module &m) { //Parameters Type // TODO (Oliveira): If we expose Poly's and ParmType, this block will go somewhere else using ParmType = typename DCRTPoly::Params; @@ -485,6 +483,16 @@ void bind_crypto_context(py::module &m) py::arg("plaintext"), py::arg("ciphertext"), py::doc("")) // TODO (dsuponit): replace this with an actual docstring + .def("EvalAddInPlace", + py::overload_cast<Ciphertext<DCRTPoly>&, double>(&CryptoContextImpl<DCRTPoly>::EvalAddInPlace, py::const_), + py::arg("ciphertext"), + py::arg("scalar"), + py::doc("")) // TODO (dsuponit): replace this with an actual docstring + .def("EvalAddInPlace", + py::overload_cast<double, Ciphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalAddInPlace, py::const_), + py::arg("scalar"), + py::arg("ciphertext"), + py::doc("")) // TODO (dsuponit): replace this with an actual docstring .def("EvalAddMutable", py::overload_cast<Ciphertext<DCRTPoly>&, Ciphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalAddMutable, py::const_), py::arg("ciphertext1"), @@ -543,6 +551,18 @@ void bind_crypto_context(py::module &m) py::arg("scalar"), py::arg("ciphertext"), py::doc("")) // TODO (dsuponit): replace this with an actual docstring + .def("EvalSubInPlace", + py::overload_cast<Ciphertext<DCRTPoly>&, ConstPlaintext&>( + &CryptoContextImpl<DCRTPoly>::EvalSubInPlace, py::const_), + py::arg("ciphertext"), + py::arg("plaintext"), + py::doc("")) // TODO (dsuponit): replace this with an actual docstring + .def("EvalSubInPlace", + py::overload_cast<Plaintext&, Ciphertext<DCRTPoly>&>( + &CryptoContextImpl<DCRTPoly>::EvalSubInPlace, py::const_), + py::arg("plaintext"), + py::arg("ciphertext"), + py::doc("")) // TODO (dsuponit): replace this with an actual docstring .def("EvalSubMutable", py::overload_cast<Ciphertext<DCRTPoly>&, Ciphertext<DCRTPoly>&>(&CryptoContextImpl<DCRTPoly>::EvalSubMutable, py::const_), py::arg("ciphertext1"), @@ -1125,7 +1145,7 @@ void bind_crypto_context(py::module &m) m.def("ClearEvalMultKeys", static_cast<void (*)()>(&CryptoContextImpl<DCRTPoly>::ClearEvalMultKeys)); } -int get_native_int(){ +int get_native_int() { #if NATIVEINT == 128 && !defined(__EMSCRIPTEN__) return 128; #elif NATIVEINT == 32 @@ -1135,8 +1155,7 @@ int get_native_int(){ #endif } -void bind_enums_and_constants(py::module &m) -{ +void bind_enums_and_constants(py::module &m) { /* ---- PKE enums ---- */ // Scheme Types py::enum_<SCHEME>(m, "SCHEME") @@ -1298,8 +1317,7 @@ void bind_enums_and_constants(py::module &m) m.def("get_native_int", &get_native_int); } -void bind_keys(py::module &m) -{ +void bind_keys(py::module &m) { py::class_<PublicKeyImpl<DCRTPoly>, std::shared_ptr<PublicKeyImpl<DCRTPoly>>>(m, "PublicKey") .def(py::init<>()) .def("GetKeyTag", &PublicKeyImpl<DCRTPoly>::GetKeyTag) @@ -1322,8 +1340,7 @@ void bind_keys(py::module &m) } // PlaintextImpl is an abstract class, so we should use a helper (trampoline) class -class PlaintextImpl_helper : public PlaintextImpl -{ +class PlaintextImpl_helper : public PlaintextImpl { public: using PlaintextImpl::PlaintextImpl; // inherited constructors @@ -1400,8 +1417,7 @@ class PlaintextImpl_helper : public PlaintextImpl } }; -void bind_encodings(py::module &m) -{ +void bind_encodings(py::module &m) { py::class_<PlaintextImpl, std::shared_ptr<PlaintextImpl>, PlaintextImpl_helper>(m, "Plaintext") .def("GetScalingFactor", &PlaintextImpl::GetScalingFactor, ptx_GetScalingFactor_docs) .def("SetScalingFactor", &PlaintextImpl::SetScalingFactor, @@ -1497,7 +1513,7 @@ void bind_ciphertext(py::module &m) { }); } -void bind_schemes(py::module &m){ +void bind_schemes(py::module &m) { // Bind schemes specific functionalities like bootstrapping functions and multiparty py::class_<FHECKKSRNS>(m, "FHECKKSRNS") .def(py::init<>()) @@ -1513,8 +1529,7 @@ void bind_schemes(py::module &m){ ; } -void bind_sch_swch_params(py::module &m) -{ +void bind_sch_swch_params(py::module &m) { py::class_<SchSwchParams>(m, "SchSwchParams") .def(py::init<>()) .def("GetSecurityLevelCKKS", &SchSwchParams::GetSecurityLevelCKKS) @@ -1562,6 +1577,13 @@ void bind_sch_swch_params(py::module &m) }); } +void bind_utils(py::module& m) { + m.def("EnablePrecomputeCRTTablesAfterDeserializaton", &lbcrypto::EnablePrecomputeCRTTablesAfterDeserializaton, + py::doc("Enable CRT precomputation after deserialization")); + m.def("DisablePrecomputeCRTTablesAfterDeserializaton", &lbcrypto::DisablePrecomputeCRTTablesAfterDeserializaton, + py::doc("Disable CRT precomputation after deserialization")); +} + PYBIND11_MODULE(openfhe, m) { // sequence of function calls matters m.doc() = "Open-Source Fully Homomorphic Encryption Library"; @@ -1583,4 +1605,5 @@ PYBIND11_MODULE(openfhe, m) { bind_serialization(m); bind_schemes(m); bind_sch_swch_params(m); + bind_utils(m); } From 6d121a93a545d06a0dc6bd34f1c631c20ec85c9a Mon Sep 17 00:00:00 2001 From: dsuponitskiy <28961198+dsuponitskiy@users.noreply.github.com> Date: Thu, 31 Jul 2025 12:14:48 -0400 Subject: [PATCH 4/6] Set rpath, so the installed openfhe module can find its shared library dependencies (#239) * Added RPATH to CMakeLists.txt * Cleaned __init__.py * Moved __init__.py to src/ and amended CMakeLists.txt --------- Co-authored-by: Dmitriy Suponitskiy <dsuponitskiy@dualitytech.com> --- CMakeLists.txt | 6 +++++- __init__.py | 48 ------------------------------------------------ src/__init__.py | 1 + 3 files changed, 6 insertions(+), 49 deletions(-) delete mode 100644 __init__.py create mode 100644 src/__init__.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 374462a..e3a7bd4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,10 @@ pybind11_add_module(openfhe src/lib/binfhe/binfhecontext_wrapper.cpp src/lib/pke/serialization.cpp ) +# The next line ensures that the installed openfhe module can find its shared library dependencies +# in the 'lib/' subdirectory relative to itself without requiring LD_LIBRARY_PATH. +target_link_options(openfhe PRIVATE "-Wl,-rpath=$ORIGIN/lib" "-Wl,--disable-new-dtags") + ### Python installation # Allow the user to specify the path to Python executable (if not provided, find it) option(PYTHON_EXECUTABLE_PATH "Path to Python executable" "") @@ -103,5 +107,5 @@ else() endif() message("***** INSTALL IS AT ${Python_Install_Location}; to change, run cmake with -DCMAKE_INSTALL_PREFIX=/your/path") install(TARGETS openfhe LIBRARY DESTINATION ${Python_Install_Location}) -install(FILES ${CMAKE_SOURCE_DIR}/__init__.py DESTINATION ${Python_Install_Location}) +install(FILES ${CMAKE_SOURCE_DIR}/src/__init__.py DESTINATION ${Python_Install_Location}) diff --git a/__init__.py b/__init__.py deleted file mode 100644 index db9b485..0000000 --- a/__init__.py +++ /dev/null @@ -1,48 +0,0 @@ -import os -import ctypes - - -def load_shared_library(libname, paths): - for path in paths: - lib_path = os.path.join(path, libname) - if os.path.exists(lib_path): - return ctypes.CDLL(lib_path, mode=ctypes.RTLD_GLOBAL) - - raise FileNotFoundError( - f"Shared library {libname} not found in {paths}" - ) - -# Search LD_LIBRARY_PATH -ld_paths = os.environ.get("LD_LIBRARY_PATH", "").split(":") - -if not any(ld_paths): - # Path to the bundled `lib/` directory inside site-packages - package_dir = os.path.abspath(os.path.dirname(__file__)) - internal_lib_dir = [os.path.join(package_dir, 'lib')] - - # Shared libraries required - shared_libs = [ - 'libgomp.so', - 'libOPENFHEcore.so.1', - 'libOPENFHEbinfhe.so.1', - 'libOPENFHEpke.so.1', - ] - - for libname in shared_libs: - load_shared_library(libname, internal_lib_dir) - - from .openfhe import * - -else: - # Shared libraries required - # skip 'libgomp.so' if LD_LIBRARY_PATH is set as we should get it from the libgomp.so location - shared_libs = [ - 'libOPENFHEcore.so.1', - 'libOPENFHEbinfhe.so.1', - 'libOPENFHEpke.so.1', - ] - - for libname in shared_libs: - load_shared_library(libname, ld_paths) - - # from .openfhe import * diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..8d1bfc6 --- /dev/null +++ b/src/__init__.py @@ -0,0 +1 @@ +from .openfhe import * From 9e185b8f842c1baef3461a1163eff0f8390e309d Mon Sep 17 00:00:00 2001 From: dsuponitskiy <28961198+dsuponitskiy@users.noreply.github.com> Date: Wed, 6 Aug 2025 14:45:15 -0400 Subject: [PATCH 5/6] Some code corrections (#242) Co-authored-by: Dmitriy Suponitskiy <dsuponitskiy@dualitytech.com> --- docs/conf.py | 2 +- src/include/docstrings/cryptocontext_docs.h | 13 ++++++++----- src/lib/bindings.cpp | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index f10e41e..4a713de 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,7 +26,7 @@ # The short X.Y version version = '' # The full version, including alpha/beta/rc tags -release = '0.8.0' +release = 'v1.3.1.0' # -- General configuration --------------------------------------------------- diff --git a/src/include/docstrings/cryptocontext_docs.h b/src/include/docstrings/cryptocontext_docs.h index a4da327..a7571a0 100644 --- a/src/include/docstrings/cryptocontext_docs.h +++ b/src/include/docstrings/cryptocontext_docs.h @@ -153,12 +153,13 @@ const char* cc_MakeCoefPackedPlaintext_docs = R"pbdoc( :param value: vector of signed integers mod t :type value: List[int] - :param noiseScaleDeg : is degree of the scaling factor to encode the plaintext at - :type noiseScaleDeg : int + :param noiseScaleDeg: is degree of the scaling factor to encode the plaintext at + :type noiseScaleDeg: int :param level: is the level to encode the plaintext at :type level: int :return: plaintext :rtype: Plaintext + )pbdoc"; const char* cc_MakeCKKSPackedPlaintextComplex_docs = R"pbdoc( @@ -1179,9 +1180,10 @@ const char* cc_InsertEvalAutomorphismKey_docs = R"pbdoc( Add the given map of keys to the map, replacing the existing map if there is one :param evalKeyMap: map of keys to be inserted - :type EvalKeyMap + :type evalKeyMap: EvalKeyMap :param keyTag: key identifier for the given key map :type keyTag: str + )pbdoc"; const char* cc_EvalSum_docs = R"pbdoc( @@ -1376,10 +1378,11 @@ const char* cc_EvalFHEWtoCKKSSetup_docs = R"pbdoc( :param ccLWE: Source FHEW crypto context. :type ccLWE: BinFHEContext - :param numSlotsCKKS Number of slots in resulting CKKS ciphertext. + :param numSlotsCKKS: Number of slots in resulting CKKS ciphertext. :type numSlotsCKKS: int - :param logQ: Ciphertext modulus size in FHEW (for high precision). + :param logQ: Ciphertext modulus size in FHEW (for high precision). :type logQ: int + )pbdoc"; const char* cc_EvalFHEWtoCKKSKeyGen_docs = R"pbdoc( diff --git a/src/lib/bindings.cpp b/src/lib/bindings.cpp index bb94678..116292c 100644 --- a/src/lib/bindings.cpp +++ b/src/lib/bindings.cpp @@ -779,7 +779,7 @@ void bind_crypto_context(py::module &m) { py::doc(cc_MultiEvalSumKeyGen_docs)) .def("MultiAddEvalAutomorphismKeys", &CryptoContextImpl<DCRTPoly>::MultiAddEvalAutomorphismKeys, py::arg("evalKeyMap1"), - py::arg("evalKeyMap1"), + py::arg("evalKeyMap2"), py::arg("keyTag") = "", py::doc(cc_MultiAddEvalAutomorphismKeys_docs)) .def("MultiAddPubKeys", &CryptoContextImpl<DCRTPoly>::MultiAddPubKeys, From f88a631726c6620e02b67702b4555b3b04037299 Mon Sep 17 00:00:00 2001 From: yspolyakov <89226542+yspolyakov@users.noreply.github.com> Date: Sun, 17 Aug 2025 01:26:12 -0400 Subject: [PATCH 6/6] Update to v1.4.0.0 (#244) * Updated the version to v1.4.0.0 * Updated the version to v1.4.0.0 part 2 --------- Co-authored-by: Yuriy Polyakov <ypolyakod@dualitytech.com> --- CMakeLists.txt | 8 ++++---- README.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e3a7bd4..76cdbdb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,14 +3,14 @@ cmake_minimum_required (VERSION 3.16.3) project (OpenFHE-Python) set(OPENFHE_PYTHON_VERSION_MAJOR 1) -set(OPENFHE_PYTHON_VERSION_MINOR 3) -set(OPENFHE_PYTHON_VERSION_PATCH 1) +set(OPENFHE_PYTHON_VERSION_MINOR 4) +set(OPENFHE_PYTHON_VERSION_PATCH 0) set(OPENFHE_PYTHON_VERSION_TWEAK 0) set(OPENFHE_PYTHON_VERSION ${OPENFHE_PYTHON_VERSION_MAJOR}.${OPENFHE_PYTHON_VERSION_MINOR}.${OPENFHE_PYTHON_VERSION_PATCH}.${OPENFHE_PYTHON_VERSION_TWEAK}) -# OpenFHE version can be specified externally (-DOPENFHE_REQUIRED_VERSION=1.3.1) +# OpenFHE version can be specified externally (-DOPENFHE_REQUIRED_VERSION=1.4.0) if(NOT DEFINED OPENFHE_REQUIRED_VERSION) - set(OPENFHE_REQUIRED_VERSION "1.3.1" CACHE STRING "Required OpenFHE version") + set(OPENFHE_REQUIRED_VERSION "1.4.0" CACHE STRING "Required OpenFHE version") else() # User provided OPENFHE_REQUIRED_VERSION via -D message(STATUS "Using user-specified OpenFHE version: ${OPENFHE_REQUIRED_VERSION}") diff --git a/README.md b/README.md index 3376000..4b6a70d 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Please see [Instructions for the Docker setup](docker/README.md) Before building, make sure you have the following dependencies installed: -- [OpenFHE 1.3.1+](https://github.com/openfheorg/openfhe-development) by following the instructions in [OpenFHE Documentation](https://openfhe-development.readthedocs.io/en/latest/sphinx_rsts/intro/installation/installation.html) +- [OpenFHE 1.4.0+](https://github.com/openfheorg/openfhe-development) by following the instructions in [OpenFHE Documentation](https://openfhe-development.readthedocs.io/en/latest/sphinx_rsts/intro/installation/installation.html) - [Python 3.6+](https://www.python.org/) - [pybind11](https://pybind11.readthedocs.io/en/stable/installing.html)