Browse Source

Merge pull request #22 from openfheorg/Oliveira_functions

Functions + BinFHE + 128bit support + code optimization
Rener Oliveira 1 year ago
parent
commit
871fe9db52

+ 9 - 1
CMakeLists.txt

@@ -16,8 +16,10 @@ include_directories( ${OpenFHE_INCLUDE} )
 include_directories( ${OpenFHE_INCLUDE}/third-party/include )
 include_directories( ${OpenFHE_INCLUDE}/core )
 include_directories( ${OpenFHE_INCLUDE}/pke )
+include_directories( ${OpenFHE_INCLUDE}/binfhe )
 # include_directories( ${OpenFHE_Py_SOURCES} )
 include_directories( ${OpenFHE_Py_INCLUDES}/pke )
+include_directories( ${OpenFHE_Py_INCLUDES}/binfhe )
 include_directories( ${OpenFHE_Py_INCLUDES} )
 ### add directories for other OpenFHE modules as needed for your project
 
@@ -38,7 +40,13 @@ endif()
 ### add_executable( test demo-simple-example.cpp )
 
 ### Pybind Modules
-pybind11_add_module(openfhe src/bindings.cpp src/pke/decryption.cpp src/pke/serialization.cpp src/pke/cryptocontext_wrapper.cpp)
+pybind11_add_module(openfhe 
+                    src/bindings.cpp 
+                    src/binfhe_bindings.cpp
+                    src/binfhe/binfhecontext_wrapper.cpp
+                    src/pke/serialization.cpp 
+                    src/pke/cryptocontext_wrapper.cpp
+                    )
 ### Python installation 
 find_package(Python REQUIRED COMPONENTS Interpreter Development)
 

+ 0 - 1
include/bindings.h

@@ -9,7 +9,6 @@ void bind_enums_and_constants(pybind11::module &m);
 void bind_keys(pybind11::module &m);
 void bind_encodings(pybind11::module &m);
 void bind_ciphertext(pybind11::module &m);
-void bind_decryption(pybind11::module &m);
 void bind_serialization(pybind11::module &m);
 void bind_schemes(pybind11::module &m);
 #endif // OPENFHE_BINDINGS_H

+ 22 - 0
include/binfhe/binfhecontext_wrapper.h

@@ -0,0 +1,22 @@
+#ifndef BINFHE_CRYPTOCONTEXT_BINDINGS_H
+#define BINFHE_CRYPTOCONTEXT_BINDINGS_H
+
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+#include "openfhe.h"
+#include "binfhecontext.h"
+
+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);
+
+#endif // BINFHE_CRYPTOCONTEXT_BINDINGS_H

+ 10 - 0
include/binfhe_bindings.h

@@ -0,0 +1,10 @@
+#ifndef BINFHE_BINDINGS_H
+#define BINFHE_BINDINGS_H
+
+#include <pybind11/pybind11.h>
+
+void bind_binfhe_enums(pybind11::module &m);
+void bind_binfhe_context(pybind11::module &m);
+void bind_binfhe_keys(pybind11::module &m);
+void bind_binfhe_ciphertext(pybind11::module &m);
+#endif // BINFHE_BINDINGS_H

+ 5 - 6
include/pke/cryptocontext_wrapper.h

@@ -13,12 +13,6 @@ namespace py = pybind11;
 using namespace lbcrypto;
 using ParmType = typename DCRTPoly::Params;
 
-Plaintext MakeCKKSPackedPlaintextWrapper(std::shared_ptr<CryptoContextImpl<DCRTPoly>> &self, 
-            const std::vector<float> &value, 
-            size_t depth, uint32_t level, 
-            const std::shared_ptr<ParmType> params,
-            usint slots);
-
 Ciphertext<DCRTPoly> EvalFastRotationPrecomputeWrapper(CryptoContext<DCRTPoly>& self,
                                                         ConstCiphertext<DCRTPoly> ciphertext);
 
@@ -28,4 +22,9 @@ Ciphertext<DCRTPoly> EvalFastRotationWrapper(CryptoContext<DCRTPoly>& self,
                                               const usint m,
                                               ConstCiphertext<DCRTPoly> digits);
 
+Plaintext DecryptWrapper(CryptoContext<DCRTPoly>& self,
+ConstCiphertext<DCRTPoly> ciphertext,const PrivateKey<DCRTPoly> privateKey);
+Plaintext DecryptWrapper(CryptoContext<DCRTPoly>& self,
+const PrivateKey<DCRTPoly> privateKey,ConstCiphertext<DCRTPoly> ciphertext);
+
 #endif // OPENFHE_CRYPTOCONTEXT_BINDINGS_H

+ 48 - 3
src/bindings.cpp

@@ -1,5 +1,7 @@
 #include <pybind11/pybind11.h>
 #include <pybind11/stl.h>
+#include <pybind11/complex.h>
+#include <pybind11/functional.h>
 #include <pybind11/operators.h>
 #include <pybind11/iostream.h>
 #include <iostream>
@@ -7,6 +9,7 @@
 #include "key/key-ser.h"
 #include "bindings.h"
 #include "cryptocontext_wrapper.h"
+#include "binfhe_bindings.h"
 
 using namespace lbcrypto;
 namespace py = pybind11;
@@ -72,7 +75,13 @@ void bind_crypto_context(py::module &m)
              py::arg("privateKey"), py::arg("indexList"), py::arg("publicKey") = nullptr)
         .def("MakePackedPlaintext", &CryptoContextImpl<DCRTPoly>::MakePackedPlaintext, "Make a plaintext from a vector of integers",
              py::arg("value"), py::arg("depth") = 1, py::arg("level") = 0)
-        .def("MakeCKKSPackedPlaintext",&MakeCKKSPackedPlaintextWrapper, "Make a CKKS plaintext from a vector of floats",
+        .def("MakeCKKSPackedPlaintext",static_cast<Plaintext (CryptoContextImpl<DCRTPoly>::*)(const std::vector<std::complex<double>>&,size_t, uint32_t,const std::shared_ptr<ParmType>, usint) const>(&CryptoContextImpl<DCRTPoly>::MakeCKKSPackedPlaintext), "Make a CKKS plaintext from a vector of complex doubles",
+            py::arg("value"),
+            py::arg("depth") = 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>, usint) const>(&CryptoContextImpl<DCRTPoly>::MakeCKKSPackedPlaintext), "Make a CKKS plaintext from a vector of doubles",
             py::arg("value"),
             py::arg("depth") = static_cast<size_t>(1),
             py::arg("level") = static_cast<uint32_t>(0),
@@ -83,11 +92,31 @@ void bind_crypto_context(py::module &m)
         .def("EvalFastRotation", &EvalFastRotationWrapper)
         .def("Encrypt", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(const PublicKey<DCRTPoly>, Plaintext) const>(&CryptoContextImpl<DCRTPoly>::Encrypt),
              "Encrypt a plaintext using public key")
+        .def("Decrypt", static_cast<Plaintext (*)(CryptoContext<DCRTPoly>&, const PrivateKey<DCRTPoly>, ConstCiphertext<DCRTPoly>)>(&DecryptWrapper),
+             "Decrypt a ciphertext using private key")
+        .def("Decrypt", static_cast<Plaintext (*)(CryptoContext<DCRTPoly>&, ConstCiphertext<DCRTPoly>,const PrivateKey<DCRTPoly>)>(&DecryptWrapper),
+             "Decrypt a ciphertext using private key")
         .def("EvalAdd", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>, ConstCiphertext<DCRTPoly>) const>(&CryptoContextImpl<DCRTPoly>::EvalAdd), "Add two ciphertexts")
         .def("EvalAdd", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>, double) const>(&CryptoContextImpl<DCRTPoly>::EvalAdd), "Add a ciphertext with a scalar")
         .def("EvalSub", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>, ConstCiphertext<DCRTPoly>) const>(&CryptoContextImpl<DCRTPoly>::EvalSub), "Subtract two ciphertexts")
+        .def("EvalSub", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>, double) const>(&CryptoContextImpl<DCRTPoly>::EvalSub), "Subtract double from ciphertext")
+        .def("EvalSub", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(double, ConstCiphertext<DCRTPoly>) const>(&CryptoContextImpl<DCRTPoly>::EvalSub), "Subtract ciphertext from double")
         .def("EvalMult", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>, ConstCiphertext<DCRTPoly>) const>(&CryptoContextImpl<DCRTPoly>::EvalMult), "Multiply two ciphertexts")
         .def("EvalMult", static_cast<Ciphertext<DCRTPoly> (CryptoContextImpl<DCRTPoly>::*)(ConstCiphertext<DCRTPoly>, double) const>(&CryptoContextImpl<DCRTPoly>::EvalMult), "Multiply a ciphertext with a scalar")
+        .def("EvalLogistic", &CryptoContextImpl<DCRTPoly>::EvalLogistic,
+            py::arg("ciphertext"),
+            py::arg("a"),
+            py::arg("b"),
+            py::arg("degree"))
+        .def("EvalChebyshevFunction", &CryptoContextImpl<DCRTPoly>::EvalChebyshevFunction,
+            py::arg("func"),
+            py::arg("ciphertext"),
+            py::arg("a"),
+            py::arg("b"),
+            py::arg("degree"))
+        .def("EvalPoly", &CryptoContextImpl<DCRTPoly>::EvalPoly,
+            py::arg("ciphertext"),
+            py::arg("coefficients"))
         .def("Rescale", &CryptoContextImpl<DCRTPoly>::Rescale, "Rescale a ciphertext")
         .def("EvalBootstrapSetup", &CryptoContextImpl<DCRTPoly>::EvalBootstrapSetup,
             py::arg("levelBudget") = std::vector<uint32_t>({5,4}),
@@ -154,6 +183,13 @@ void bind_crypto_context(py::module &m)
     m.def("ReleaseAllContexts", &CryptoContextFactory<DCRTPoly>::ReleaseAllContexts);
 }
 
+int get_native_int(){
+    #if NATIVEINT == 128 && !defined(__EMSCRIPTEN__)
+        return 128;
+    #else
+        return 64;    
+    #endif
+}
 void bind_enums_and_constants(py::module &m)
 {
     /* ---- PKE enums ---- */ 
@@ -210,6 +246,9 @@ void bind_enums_and_constants(py::module &m)
     /*TODO (Oliveira): If we expose Poly's and ParmType, this block will go somewhere else */
     using ParmType = typename DCRTPoly::Params;
     py::class_<ParmType, std::shared_ptr<ParmType>>(m, "ParmType");
+
+    //NATIVEINT function
+    m.def("get_native_int", &get_native_int);
 }
 
 void bind_keys(py::module &m)
@@ -235,6 +274,7 @@ void bind_encodings(py::module &m)
         //.def("GetEncondingParams", &PlaintextImpl::GetEncondingParams)
         .def("Encode", &PlaintextImpl::Encode)
         .def("Decode", &PlaintextImpl::Decode)
+        .def("GetCKKSPackedValue", &PlaintextImpl::GetCKKSPackedValue)
         .def("__repr__", [](const PlaintextImpl &p)
              {
         std::stringstream ss;
@@ -280,13 +320,18 @@ void bind_schemes(py::module &m){
 PYBIND11_MODULE(openfhe, m)
 {
     m.doc() = "Open-Source Fully Homomorphic Encryption Library";
+    // pke library
     bind_parameters(m);
-    bind_crypto_context(m);
     bind_enums_and_constants(m);
+    bind_crypto_context(m);
     bind_keys(m);
     bind_encodings(m);
     bind_ciphertext(m);
-    bind_decryption(m);
     bind_serialization(m);
     bind_schemes(m);
+    // binfhe library
+    bind_binfhe_enums(m);
+    bind_binfhe_context(m);
+    bind_binfhe_keys(m);
+    bind_binfhe_ciphertext(m);
 }

+ 25 - 0
src/binfhe/binfhecontext_wrapper.cpp

@@ -0,0 +1,25 @@
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+#include <openfhe.h>
+#include "binfhecontext_wrapper.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;
+}

+ 58 - 0
src/binfhe/examples/boolean-ap.py

@@ -0,0 +1,58 @@
+from openfhe import *
+
+## Sample Program: Step 1: Set CryptoContext
+
+cc = BinFHEContext()
+
+"""
+STD128 is the security level of 128 bits of security based on LWE Estimator
+and HE standard. Other common options are TOY, MEDIUM, STD192, and STD256.
+MEDIUM corresponds to the level of more than 100 bits for both quantum and
+classical computer attacks. The second argument is the bootstrapping method
+(AP or GINX). The default method is GINX. Here we explicitly set AP. GINX
+typically provides better performance: the bootstrapping key is much
+smaller in GINX (by 20x) while the runtime is roughly the same.
+"""
+cc.GenerateBinFHEContext(STD128,AP)
+
+## Sample Program: Step 2: Key Generation
+
+# Generate the secret key
+sk = cc.KeyGen()
+
+print("Generating the bootstrapping keys...\n")
+
+# Generate the bootstrapping keys (refresh and switching keys)
+cc.BTKeyGen(sk)
+
+print("Completed the key generation.\n")
+# Sample Program: Step 3: Encryption
+"""
+Encrypt two ciphertexts representing Boolean True (1).
+By default, freshly encrypted ciphertexts are bootstrapped.
+If you wish to get a fresh encryption without bootstrapping, write
+ct1 = cc.Encrypt(sk, 1, FRESH)
+"""
+ct1 = cc.Encrypt(sk, 1)
+ct2 = cc.Encrypt(sk, 1)
+
+# Sample Program: Step 4: Evaluation
+
+# Compute (1 AND 1) = 1; Other binary gate options are OR, NAND, and NOR
+ctAND1 = cc.EvalBinGate(AND, ct1, ct2)
+
+# Compute (NOT 1) = 0
+ct2Not = cc.EvalNOT(ct2)
+
+# Compute (1 AND (NOT 1)) = 0
+ctAND2 = cc.EvalBinGate(AND, ct2Not, ct1)
+
+# Compute OR of the result in ctAND1 and ctAND2
+ctResult = cc.EvalBinGate(OR, ctAND1, ctAND2)
+
+# Sample Program: Step 5: Decryption
+
+result = cc.Decrypt(sk, ctResult)
+
+print(f"Result of encrypted computation of (1 AND 1) OR (1 AND (NOT 1)) = {result}")
+

+ 197 - 0
src/binfhe/examples/boolean-truth-tables.py

@@ -0,0 +1,197 @@
+from openfhe import *
+
+# Sample Program: Step 1: Set CryptoContext
+cc = BinFHEContext()
+
+print("Generate cryptocontext\n")
+
+"""
+STD128 is the security level of 128 bits of security based on LWE Estimator
+and HE standard. Other common options are TOY, MEDIUM, STD192, and STD256. MEDIUM 
+corresponds to the level of more than 100 bits for both quantum and
+classical computer attacks
+"""
+
+cc.GenerateBinFHEContext(STD128)
+print("Finished generating cryptocontext\n")
+
+# Sample Program: Step 2: Key Generation
+
+# Generate the secret key
+sk = cc.KeyGen()
+
+print("Generating the bootstrapping keys...\n")
+
+# Generate the bootstrapping keys (refresh and switching keys)
+cc.BTKeyGen(sk)
+
+print("Completed the key generation.\n\n")
+
+# Sample Program: Step 3: Encryption
+
+# Encrypt two ciphertexts representing Boolean True (1).
+ct10 = cc.Encrypt(sk, 1)
+ct11 = cc.Encrypt(sk, 1)
+# Encrypt two ciphertexts representing Boolean False (0).
+ct00 = cc.Encrypt(sk, 0)
+ct01 = cc.Encrypt(sk, 0)
+
+# Sample Program: Step 4: Evaluation of NAND gates
+
+ctNAND1 = cc.EvalBinGate(NAND, ct10, ct11)
+ctNAND2 = cc.EvalBinGate(NAND, ct10, ct01)
+ctNAND3 = cc.EvalBinGate(NAND, ct00, ct01)
+ctNAND4 = cc.EvalBinGate(NAND, ct00, ct11)
+
+result = cc.Decrypt(sk, ctNAND1)
+print(f"1 NAND 1 = {result}")
+
+result = cc.Decrypt(sk, ctNAND2)
+print(f"1 NAND 0 = {result}")
+
+result = cc.Decrypt(sk, ctNAND3)
+print(f"0 NAND 0 = {result}")
+
+result = cc.Decrypt(sk, ctNAND4)
+print(f"0 NAND 1 = {result}")
+
+# Sample Program: Step 5: Evaluation of AND gates
+
+ctAND1 = cc.EvalBinGate(AND, ct10, ct11)
+ctAND2 = cc.EvalBinGate(AND, ct10, ct01)
+ctAND3 = cc.EvalBinGate(AND, ct00, ct01)
+ctAND4 = cc.EvalBinGate(AND, ct00, ct11)
+
+result = cc.Decrypt(sk, ctAND1)
+print(f"1 AND 1 = {result}")
+
+result = cc.Decrypt(sk, ctAND2)
+print(f"1 AND 0 = {result}")
+
+result = cc.Decrypt(sk, ctAND3)
+print(f"0 AND 0 = {result}")
+
+result = cc.Decrypt(sk, ctAND4)
+print(f"0 AND 1 = {result}")
+
+# Sample Program: Step 6: Evaluation of OR gates
+
+ctOR1 = cc.EvalBinGate(OR, ct10, ct11)
+ctOR2 = cc.EvalBinGate(OR, ct10, ct01)
+ctOR3 = cc.EvalBinGate(OR, ct00, ct01)
+ctOR4 = cc.EvalBinGate(OR, ct00, ct11)
+
+result = cc.Decrypt(sk, ctOR1)
+print(f"1 OR 1 = {result}")
+
+result = cc.Decrypt(sk, ctOR2)
+print(f"1 OR 0 = {result}")
+
+result = cc.Decrypt(sk, ctOR3)
+print(f"0 OR 0 = {result}")
+
+result = cc.Decrypt(sk, ctOR4)
+print(f"0 OR 1 = {result}")
+
+# Sample Program: Step 7: Evaluation of NOR gates
+
+ctNOR1 = cc.EvalBinGate(NOR, ct10, ct11)
+ctNOR2 = cc.EvalBinGate(NOR, ct10, ct01)
+ctNOR3 = cc.EvalBinGate(NOR, ct00, ct01)
+ctNOR4 = cc.EvalBinGate(NOR, ct00, ct11)
+
+result = cc.Decrypt(sk, ctNOR1)
+print(f"1 NOR 1 = {result}")
+
+result = cc.Decrypt(sk, ctNOR2)
+print(f"1 NOR 0 = {result}")
+
+result = cc.Decrypt(sk, ctNOR3)
+print(f"0 NOR 0 = {result}")
+
+result = cc.Decrypt(sk, ctNOR4)
+print(f"0 NOR 1 = {result}")
+
+# Sample Program: Step 8: Evaluation of XOR gates
+
+ctXOR1 = cc.EvalBinGate(XOR, ct10, ct11)
+ctXOR2 = cc.EvalBinGate(XOR, ct10, ct01)
+ctXOR3 = cc.EvalBinGate(XOR, ct00, ct01)
+ctXOR4 = cc.EvalBinGate(XOR, ct00, ct11)
+
+result = cc.Decrypt(sk, ctXOR1)
+print(f"1 XOR 1 = {result}")
+
+result = cc.Decrypt(sk, ctXOR2)
+print(f"1 XOR 0 = {result}")
+
+result = cc.Decrypt(sk, ctXOR3)
+print(f"0 XOR 0 = {result}")
+
+result = cc.Decrypt(sk, ctXOR4)
+print(f"0 XOR 1 = {result}")
+
+# Sample Program: Step 9: Evaluation of XNOR gates
+
+ctXNOR1 = cc.EvalBinGate(XNOR, ct10, ct11)
+ctXNOR2 = cc.EvalBinGate(XNOR, ct10, ct01)
+ctXNOR3 = cc.EvalBinGate(XNOR, ct00, ct01)
+ctXNOR4 = cc.EvalBinGate(XNOR, ct00, ct11)
+
+result = cc.Decrypt(sk, ctXNOR1)
+print(f"1 XNOR 1 = {result}")
+
+result = cc.Decrypt(sk, ctXNOR2)
+print(f"1 XNOR 0 = {result}")
+
+result = cc.Decrypt(sk, ctXNOR3)
+print(f"0 XNOR 0 = {result}")
+
+result = cc.Decrypt(sk, ctXNOR4)
+print(f"0 XNOR 1 = {result}")
+
+# Sample Program: Step 90: Evaluation of NOR gates
+# using XOR_FAT (1 boostrap but the probability of failure is higher)
+
+ctNOR1_FAST = cc.EvalBinGate(XOR_FAST, ct10, ct11)
+ctNOR2_FAST = cc.EvalBinGate(XOR_FAST, ct10, ct01)
+ctNOR3_FAST = cc.EvalBinGate(XOR_FAST, ct00, ct01)
+ctNOR4_FAST = cc.EvalBinGate(XOR_FAST, ct00, ct11)
+
+result = cc.Decrypt(sk, ctNOR1_FAST)
+print(f"1 XOR_FAST 1 = {result}")
+
+result = cc.Decrypt(sk, ctNOR2_FAST)
+print(f"1 XOR_FAST 0 = {result}")
+
+result = cc.Decrypt(sk, ctNOR3_FAST)
+print(f"0 XOR_FAST 0 = {result}")
+
+result = cc.Decrypt(sk, ctNOR4_FAST)
+print(f"0 XOR_FAST 1 = {result}")
+
+# Sample Program: Step 10: Evaluation of XNOR gates
+# using XNOR_FAT (1 boostrap but the probability of failure is higher)
+
+ctXNOR1_FAST = cc.EvalBinGate(XNOR_FAST, ct10, ct11)
+ctXNOR2_FAST = cc.EvalBinGate(XNOR_FAST, ct10, ct01)
+ctXNOR3_FAST = cc.EvalBinGate(XNOR_FAST, ct00, ct01)
+ctXNOR4_FAST = cc.EvalBinGate(XNOR_FAST, ct00, ct11)
+
+result = cc.Decrypt(sk, ctXNOR1_FAST)
+print(f"1 XNOR_FAST 1 = {result}")
+
+result = cc.Decrypt(sk, ctXNOR2_FAST)
+print(f"1 XNOR_FAST 0 = {result}")
+
+result = cc.Decrypt(sk, ctXNOR3_FAST)
+print(f"0 XNOR_FAST 0 = {result}")
+
+result = cc.Decrypt(sk, ctXNOR4_FAST)
+print(f"0 XNOR_FAST 1 = {result}")
+
+
+
+
+
+

+ 54 - 0
src/binfhe/examples/boolean.py

@@ -0,0 +1,54 @@
+from openfhe import *
+
+## Sample Program: Step 1: Set CryptoContext
+
+cc = BinFHEContext()
+
+"""
+STD128 is the security level of 128 bits of security based on LWE Estimator
+and HE standard. Other common options are TOY, MEDIUM, STD192, and STD256.
+MEDIUM corresponds to the level of more than 100 bits for both quantum and
+classical computer attacks
+"""
+cc.GenerateBinFHEContext(STD128,GINX)
+
+## Sample Program: Step 2: Key Generation
+
+# Generate the secret key
+sk = cc.KeyGen()
+
+print("Generating the bootstrapping keys...\n")
+
+# Generate the bootstrapping keys (refresh and switching keys)
+cc.BTKeyGen(sk)
+
+# Sample Program: Step 3: Encryption
+"""
+Encrypt two ciphertexts representing Boolean True (1).
+By default, freshly encrypted ciphertexts are bootstrapped.
+If you wish to get a fresh encryption without bootstrapping, write
+ct1 = cc.Encrypt(sk, 1, FRESH)
+"""
+ct1 = cc.Encrypt(sk, 1)
+ct2 = cc.Encrypt(sk, 1)
+
+# Sample Program: Step 4: Evaluation
+
+# Compute (1 AND 1) = 1; Other binary gate options are OR, NAND, and NOR
+ctAND1 = cc.EvalBinGate(AND, ct1, ct2)
+
+# Compute (NOT 1) = 0
+ct2Not = cc.EvalNOT(ct2)
+
+# Compute (1 AND (NOT 1)) = 0
+ctAND2 = cc.EvalBinGate(AND, ct2Not, ct1)
+
+# Compute OR of the result in ctAND1 and ctAND2
+ctResult = cc.EvalBinGate(OR, ctAND1, ctAND2)
+
+# Sample Program: Step 5: Decryption
+
+result = cc.Decrypt(sk, ctResult)
+
+print(f"Result of encrypted computation of (1 AND 1) OR (1 AND (NOT 1)) = {result}")
+

+ 129 - 0
src/binfhe_bindings.cpp

@@ -0,0 +1,129 @@
+#include <pybind11/pybind11.h>
+#include <pybind11/operators.h>
+#include <iostream>
+#include "openfhe.h"
+#include "binfhe_bindings.h"
+#include "binfhecontext.h"
+#include "binfhecontext_wrapper.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_AP", BINFHE_PARAMSET::STD128_AP)
+        .value("STD128_APOPT", BINFHE_PARAMSET::STD128_APOPT)
+        .value("STD128", BINFHE_PARAMSET::STD128)
+        .value("STD128_OPT", BINFHE_PARAMSET::STD128_OPT)
+        .value("STD192", BINFHE_PARAMSET::STD192)
+        .value("STD192_OPT", BINFHE_PARAMSET::STD192_OPT)
+        .value("STD256", BINFHE_PARAMSET::STD256)
+        .value("STD256_OPT", BINFHE_PARAMSET::STD256_OPT)
+        .value("STD128Q", BINFHE_PARAMSET::STD128Q)
+        .value("STD128Q_OPT", BINFHE_PARAMSET::STD128Q_OPT)
+        .value("STD192Q", BINFHE_PARAMSET::STD192Q)
+        .value("STD192Q_OPT", BINFHE_PARAMSET::STD192Q_OPT)
+        .value("STD256Q", BINFHE_PARAMSET::STD256Q)
+        .value("STD256Q_OPT", BINFHE_PARAMSET::STD256Q_OPT)
+        .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_AP") = py::cast(BINFHE_PARAMSET::STD128_AP);
+    m.attr("STD128_APOPT") = py::cast(BINFHE_PARAMSET::STD128_APOPT);
+    m.attr("STD128") = py::cast(BINFHE_PARAMSET::STD128);
+    m.attr("STD128_OPT") = py::cast(BINFHE_PARAMSET::STD128_OPT);
+    m.attr("STD192") = py::cast(BINFHE_PARAMSET::STD192);
+    m.attr("STD192_OPT") = py::cast(BINFHE_PARAMSET::STD192_OPT);
+    m.attr("STD256") = py::cast(BINFHE_PARAMSET::STD256);
+    m.attr("STD256_OPT") = py::cast(BINFHE_PARAMSET::STD256_OPT);
+    m.attr("STD128Q") = py::cast(BINFHE_PARAMSET::STD128Q);
+    m.attr("STD128Q_OPT") = py::cast(BINFHE_PARAMSET::STD128Q_OPT);
+    m.attr("STD192Q") = py::cast(BINFHE_PARAMSET::STD192Q);
+    m.attr("STD192Q_OPT") = py::cast(BINFHE_PARAMSET::STD192Q_OPT);
+    m.attr("STD256Q") = py::cast(BINFHE_PARAMSET::STD256Q);
+    m.attr("STD256Q_OPT") = py::cast(BINFHE_PARAMSET::STD256Q_OPT);
+    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);
+    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);
+
+    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);
+
+}
+
+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);
+}
+void bind_binfhe_ciphertext(py::module &m)
+{
+    py::class_<LWECiphertextImpl, std::shared_ptr<LWECiphertextImpl>>(m, "LWECiphertext")
+        .def(py::init<>())
+        .def("GetLength", &LWECiphertextImpl::GetLength)
+        .def(py::self == py::self)
+        .def(py::self != py::self);
+}
+
+void bind_binfhe_context(py::module &m)
+{
+    py::class_<BinFHEContext>(m, "BinFHEContext")
+        .def(py::init<>())
+        .def("GenerateBinFHEContext", static_cast<void (BinFHEContext::*)(BINFHE_PARAMSET, BINFHE_METHOD)>(&BinFHEContext::GenerateBinFHEContext),
+             py::arg("set"), 
+             py::arg("method") = GINX)
+        .def("KeyGen", &BinFHEContext::KeyGen)
+        .def("BTKeyGen", &BinFHEContext::BTKeyGen)
+        .def("Encrypt", &binfhe_EncryptWrapper,
+             py::arg("sk"),
+             py::arg("m"),
+             py::arg("output") = BOOTSTRAPPED,
+             py::arg("p") = 4, 
+             py::arg("mod") = 0)
+        .def("Decrypt",&binfhe_DecryptWrapper,
+             py::arg("sk"),
+             py::arg("ct"),
+             py::arg("p") = 4)
+        .def("EvalBinGate",&BinFHEContext::EvalBinGate,
+             py::arg("gate"),
+             py::arg("ct1"),
+             py::arg("ct2"))
+        .def("EvalNOT",&BinFHEContext::EvalNOT,
+             py::arg("ct"));
+            
+}

+ 13 - 15
src/pke/cryptocontext_wrapper.cpp

@@ -9,20 +9,6 @@
 using namespace lbcrypto;
 namespace py = pybind11;
 
-Plaintext MakeCKKSPackedPlaintextWrapper(std::shared_ptr<CryptoContextImpl<DCRTPoly>> &self, 
-            const std::vector<float> &value, 
-            size_t depth, uint32_t level, 
-            const std::shared_ptr<ParmType> params,
-            usint slots)
-            {
-                if (!value.size())
-                    OPENFHE_THROW(config_error, "Cannot encode an empty value vector");
-
-                std::vector<std::complex<double>> complexValue(value.size());
-                std::transform(value.begin(), value.end(), complexValue.begin(),
-                       [](float da) { return std::complex<double>(da); });
-                return self->MakeCKKSPackedPlaintext(complexValue, depth, level, params, slots); }
-
 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());
@@ -36,4 +22,16 @@ Ciphertext<DCRTPoly> EvalFastRotationWrapper(CryptoContext<DCRTPoly>& self,Const
         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);
-    }
+    }
+
+
+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;
+}

+ 0 - 18
src/pke/decryption.cpp

@@ -1,18 +0,0 @@
-#include <pybind11/pybind11.h>
-#include <pybind11/stl.h>
-#include "openfhe.h"
-#include "bindings.h"
-
-using namespace lbcrypto;
-namespace py = pybind11;
-
-template<typename Element>
-Plaintext DecryptWrapper(Ciphertext<Element> ciphertext,const PrivateKey<Element> privateKey){
-    Plaintext plaintextDecResult;
-    auto cc = ciphertext->GetCryptoContext();
-    cc->Decrypt(privateKey, ciphertext,&plaintextDecResult);
-    return plaintextDecResult;
-}
-void bind_decryption(py::module &m){
-    m.def("Decrypt",&DecryptWrapper<DCRTPoly>,"Decrypt a ciphertext using private key");
-}

+ 390 - 0
src/pke/examples/advanced-real-numbers-128.py

@@ -0,0 +1,390 @@
+from openfhe import *
+import time # to enable TIC-TOC timing measurements
+
+def automatic_rescale_demo(scal_tech):
+    if(scal_tech == ScalingTechnique.FLEXIBLEAUTO):
+        print("\n\n\n ===== FlexibleAutoDemo =============\n") 
+    else:
+         print("\n\n\n ===== FixedAutoDemo =============\n")
+
+    batch_size = 8
+    parameters = CCParamsCKKSRNS()
+    parameters.SetMultiplicativeDepth(6)
+    parameters.SetScalingModSize(90)
+    parameters.SetScalingTechnique(scal_tech)
+    parameters.SetBatchSize(batch_size)
+
+    cc = GenCryptoContext(parameters)
+
+    print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()}\n")
+
+    cc.Enable(PKESchemeFeature.PKE)
+    cc.Enable(PKESchemeFeature.KEYSWITCH)
+    cc.Enable(PKESchemeFeature.LEVELEDSHE)
+
+    keys = cc.KeyGen()
+    cc.EvalMultKeyGen(keys.secretKey)
+
+    # Input
+    x = [1.0, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07]
+    ptxt = cc.MakeCKKSPackedPlaintext(x)
+
+    print(f"Input x: {ptxt}")
+
+    c = cc.Encrypt(keys.publicKey,ptxt)
+
+    # Computing f(x) = x^18 + x^9 + d
+    #
+    # In the following we compute f(x) with a computation
+    # that has a multiplicative depth of 5.
+    #
+    # The result is correct, even though there is no call to
+    # the Rescale() operation.
+
+    c2 = cc.EvalMult(c, c)                        # x^2
+    c4 = cc.EvalMult(c2, c2)                      # x^4
+    c8 = cc.EvalMult(c4, c4)                      # x^8
+    c16 = cc.EvalMult(c8, c8)                     # x^16
+    c9 = cc.EvalMult(c8, c)                       # x^9
+    c18 = cc.EvalMult(c16, c2)                    # x^18
+    c_res1 = cc.EvalAdd(cc.EvalAdd(c18, c9), 1.0)  # Final result 1
+    c_res2 = cc.EvalSub(cc.EvalAdd(c18,c9), 1.0)   # Final result 2
+    c_res3 = cc.EvalMult(cc.EvalAdd(c18,c9), 0.5)  # Final result 3
+
+    result1 = cc.Decrypt(c_res1,keys.secretKey)
+    result.SetLength(batch_size)
+    print("x^18 + x^9 + 1 = ", result1)
+    
+    result2 = cc.Decrypt(c_res2,keys.secretKey)
+    result.SetLength(batch_size)
+    print("x^18 + x^9 - 1 = ", result2)
+
+    result3 = cc.Decrypt(c_res3,keys.secretKey)
+    result.SetLength(batch_size)
+    print("0.5 * (x^18 + x^9) = ", result3)
+
+
+def manual_rescale_demo(scal_tech):
+    print("\n\n\n ===== FixedManualDemo =============\n")
+    
+    batch_size = 8
+    parameters = CCParamsCKKSRNS()
+    parameters.SetMultiplicativeDepth(5)
+    parameters.SetScalingModSize(90)
+    parameters.SetBatchSize(batch_size)
+
+    cc = GenCryptoContext(parameters)
+
+    print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()}\n")
+    
+    cc.Enable(PKESchemeFeature.PKE)
+    cc.Enable(PKESchemeFeature.KEYSWITCH)
+    cc.Enable(PKESchemeFeature.LEVELEDSHE)
+
+    keys = cc.KeyGen()
+    cc.EvalMultKeyGen(keys.secretKey)
+
+    # Input
+    x = [1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7]
+    ptxt = cc.MakeCKKSPackedPlaintext(x)
+
+    print(f"Input x: {ptxt}")
+
+    c = cc.Encrypt(keys.publicKey,ptxt)
+
+    # Computing f(x) = x^18 + x^9 + 1
+    #
+    # Compare the following with the corresponding code
+    # for FIXEDAUTO. Here we need to track the depth of ciphertexts
+    # and call Rescale whenever needed. In this instance it's still
+    # not hard to do so, but this can be quite tedious in other
+    # complicated computations. (e.g. in bootstrapping)
+    #
+    #
+
+    # x^2
+    c2_depth2 = cc.EvalMult(c, c)
+    c2_depth1 = cc.Rescale(c2_depth2)
+    # x^4
+    c4_depth2 = cc.EvalMult(c2_depth1, c2_depth1)
+    c4_depth1 = cc.Rescale(c4_depth2)
+    # x^8
+    c8_depth2 = cc.EvalMult(c4_depth1, c4_depth1)
+    c8_depth1 = cc.Rescale(c8_depth2)
+    # x^16
+    c16_depth2 = cc.EvalMult(c8_depth1, c8_depth1)
+    c16_depth1 = cc.Rescale(c16_depth2)
+    # x^9
+    c9_depth2 = cc.EvalMult(c8_depth1, c)
+    # x^18
+    c18_depth2 = cc.EvalMult(c16_depth1, c2_depth1)
+    # Final result
+    c_res_depth2 = cc.EvalAdd(cc.EvalAdd(c18_depth2, c9_depth2), 1.0)
+    c_res_depth1 = cc.Rescale(c_res_depth2)
+
+    result = cc.Decrypt(c_res_depth1,keys.secretKey)
+    result.SetLength(batch_size)
+    print("x^18 + x^9 + 1 = ", result)
+
+def hybrid_key_switching_demo1():
+    
+    print("\n\n\n ===== hybrid_key_switching_demo1 ============= \n")
+    dnum = 2
+    batch_size = 8
+    parameters = CCParamsCKKSRNS()
+    parameters.SetMultiplicativeDepth(5)
+    parameters.SetScalingModSize(90)
+    parameters.SetBatchSize(batch_size)
+    parameters.SetScalingTechnique(ScalingTechnique.FIXEDAUTO)
+    parameters.SetNumLargeDigits(dnum)
+
+    cc = GenCryptoContext(parameters)
+
+    print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()}\n")
+
+    print(f"- Using HYBRID key switching with {dnum} digits\n")
+
+    cc.Enable(PKESchemeFeature.PKE)
+    cc.Enable(PKESchemeFeature.KEYSWITCH)
+    cc.Enable(PKESchemeFeature.LEVELEDSHE)
+
+    keys = cc.KeyGen()
+    cc.EvalRotateKeyGen(keys.secretKey,[1,-2])
+
+    # Input
+    x = [1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7]
+    ptxt = cc.MakeCKKSPackedPlaintext(x)
+
+    print(f"Input x: {ptxt}")
+
+    c = cc.Encrypt(keys.publicKey,ptxt)
+
+    t = time.time()
+    c_rot1 = cc.EvalRotate(c,1)
+    c_rot2 = cc.EvalRotate(c_rot1,-2)
+    time2digits = time.time() - t
+
+    result = cc.Decrypt(c_rot2,keys.secretKey)
+    result.SetLength(batch_size)
+    print(f"x rotate by -1 = {result}")
+    print(f" - 2 rotations with HYBRID (2 digits) took {time2digits*1000} ms")
+
+
+def hybrid_key_switching_demo2():
+    print("\n\n\n ===== hybrid_key_switching_demo2 =============\n")
+    dnum = 3
+    batch_size = 8
+    parameters = CCParamsCKKSRNS()
+    parameters.SetMultiplicativeDepth(5)
+    parameters.SetScalingModSize(90)
+    parameters.SetBatchSize(batch_size)
+    parameters.SetScalingTechnique(ScalingTechnique.FIXEDAUTO)
+    parameters.SetNumLargeDigits(dnum)
+
+    cc = GenCryptoContext(parameters)
+
+    # Compare the ring dimension in this demo to the one in the previous
+    print(f"CKKS scheme is using ring dimension {cc.GetRingDimension()}\n")
+
+    print(f"- Using HYBRID key switching with {dnum} digits\n")
+
+    cc.Enable(PKESchemeFeature.PKE)
+    cc.Enable(PKESchemeFeature.KEYSWITCH)
+    cc.Enable(PKESchemeFeature.LEVELEDSHE)
+
+    keys = cc.KeyGen()
+    cc.EvalRotateKeyGen(keys.secretKey,[1,-2])
+
+    # Input
+    x = [1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7]
+    ptxt = cc.MakeCKKSPackedPlaintext(x)
+
+    print(f"Input x: {ptxt}")
+
+    c = cc.Encrypt(keys.publicKey,ptxt)
+
+    t = time.time()
+    c_rot1 = cc.EvalRotate(c,1)
+    c_rot2 = cc.EvalRotate(c_rot1,-2)
+    time3digits = time.time() - t
+    # The runtime here is smaller than the previous demo
+
+    result = cc.Decrypt(c_rot2,keys.secretKey)
+    result.SetLength(batch_size)
+    print(f"x rotate by -1 = {result}")
+    print(f" - 2 rotations with HYBRID (3 digits) took {time3digits*1000} ms")
+
+def fast_rotation_demo1():
+    print("\n\n\n ===== fast_rotation_demo1 =============\n")
+    batch_size = 8
+    parameters = CCParamsCKKSRNS()
+    parameters.SetMultiplicativeDepth(1)
+    parameters.SetScalingModSize(90)
+    parameters.SetBatchSize(batch_size)
+
+    cc = GenCryptoContext(parameters)
+
+    N = cc.GetRingDimension()
+    print(f"CKKS scheme is using ring dimension {N}\n")
+
+    cc.Enable(PKESchemeFeature.PKE)
+    cc.Enable(PKESchemeFeature.KEYSWITCH)
+    cc.Enable(PKESchemeFeature.LEVELEDSHE)
+
+    keys = cc.KeyGen()
+    cc.EvalRotateKeyGen(keys.secretKey,[1,2,3,4,5,6,7])
+
+    # Input
+    x = [0, 0, 0, 0, 0, 0, 0, 1]
+    ptxt = cc.MakeCKKSPackedPlaintext(x)
+
+    print(f"Input x: {ptxt}")
+
+    c = cc.Encrypt(keys.publicKey,ptxt)
+
+    # First, we perform 7 regular (non-hoisted) rotations
+    # and measure the runtime
+    t = time.time()
+    c_rot1 = cc.EvalRotate(c,1)
+    c_rot2 = cc.EvalRotate(c,2)
+    c_rot3 = cc.EvalRotate(c,3)
+    c_rot4 = cc.EvalRotate(c,4)
+    c_rot5 = cc.EvalRotate(c,5)
+    c_rot6 = cc.EvalRotate(c,6)
+    c_rot7 = cc.EvalRotate(c,7)
+    time_no_hoisting = time.time() - t
+
+    c_res_no_hoist = c + c_rot1 + c_rot2 + c_rot3 + c_rot4 + c_rot5 + c_rot6 + c_rot7
+
+    # M is the cyclotomic order and we need it to call EvalFastRotation
+    M = 2*N
+
+    # Then, we perform 7 rotations with hoisting.
+    t = time.time()
+    c_precomp = cc.EvalFastRotationPrecompute(c)
+    c_rot1 = cc.EvalFastRotation(c, 1, M, c_precomp)
+    c_rot2 = cc.EvalFastRotation(c, 2, M, c_precomp)
+    c_rot3 = cc.EvalFastRotation(c, 3, M, c_precomp)
+    c_rot4 = cc.EvalFastRotation(c, 4, M, c_precomp)
+    c_rot5 = cc.EvalFastRotation(c, 5, M, c_precomp)
+    c_rot6 = cc.EvalFastRotation(c, 6, M, c_precomp)
+    c_rot7 = cc.EvalFastRotation(c, 7, M, c_precomp)
+    time_hoisting = time.time() - t
+    # The time with hoisting should be faster than without hoisting.
+
+    c_res_hoist = c + c_rot1 + c_rot2 + c_rot3 + c_rot4 + c_rot5 + c_rot6 + c_rot7
+    
+    result = cc.Decrypt(c_res_no_hoist,keys.secretKey)
+    result.SetLength(batch_size)
+    print(f"Result without hoisting: {result}")
+    print(f" - 7 rotations without hoisting took {time_no_hoisting*1000} ms")
+
+    
+    result = cc.Decrypt(c_res_hoist,keys.secretKey)
+    result.SetLength(batch_size)
+    print(f"Result with hoisting: {result}")
+    print(f" - 7 rotations with hoisting took {time_hoisting*1000} ms")
+
+
+
+
+def fast_rotation_demo2():
+    print("\n\n\n ===== fast_rotation_demo2 =============\n")
+
+    batch_size = 8
+
+    parameters = CCParamsCKKSRNS()
+    parameters.SetMultiplicativeDepth(1)
+    parameters.SetScalingModSize(90)
+    parameters.SetBatchSize(batch_size)
+    parameters.SetScalingTechnique(ScalingTechnique.FIXEDAUTO)
+    parameters.SetKeySwitchTechnique(KeySwitchTechnique.BV)
+
+    digit_size = 10
+    first_mod_size = 100
+    parameters.SetFirstModSize(first_mod_size)
+    parameters.SetDigitSize(digit_size)
+
+    cc = GenCryptoContext(parameters)
+
+    N = cc.GetRingDimension()
+    print(f"CKKS scheme is using ring dimension {N}\n")
+
+    cc.Enable(PKESchemeFeature.PKE)
+    cc.Enable(PKESchemeFeature.KEYSWITCH)
+    cc.Enable(PKESchemeFeature.LEVELEDSHE)
+
+    keys = cc.KeyGen()
+    cc.EvalRotateKeyGen(keys.secretKey,[1,2,3,4,5,6,7])
+
+    # Input
+    x = [0, 0, 0, 0, 0, 0, 0, 1]
+    ptxt = cc.MakeCKKSPackedPlaintext(x)
+
+    print(f"Input x: {ptxt}")
+
+    c = cc.Encrypt(keys.publicKey,ptxt)
+
+    # First, we perform 7 regular (non-hoisted) rotations
+    # and measure the runtime
+    t = time.time()
+    c_rot1 = cc.EvalRotate(c,1)
+    c_rot2 = cc.EvalRotate(c,2)
+    c_rot3 = cc.EvalRotate(c,3)
+    c_rot4 = cc.EvalRotate(c,4)
+    c_rot5 = cc.EvalRotate(c,5)
+    c_rot6 = cc.EvalRotate(c,6)
+    c_rot7 = cc.EvalRotate(c,7)
+    time_no_hoisting = time.time() - t
+
+    c_res_no_hoist = c + c_rot1 + c_rot2 + c_rot3 + c_rot4 + c_rot5 + c_rot6 + c_rot7
+
+    # M is the cyclotomic order and we need it to call EvalFastRotation
+    M = 2*N
+
+    # Then, we perform 7 rotations with hoisting.
+    t = time.time()
+    c_precomp = cc.EvalFastRotationPrecompute(c)
+    c_rot1 = cc.EvalFastRotation(c, 1, M, c_precomp)
+    c_rot2 = cc.EvalFastRotation(c, 2, M, c_precomp)
+    c_rot3 = cc.EvalFastRotation(c, 3, M, c_precomp)
+    c_rot4 = cc.EvalFastRotation(c, 4, M, c_precomp)
+    c_rot5 = cc.EvalFastRotation(c, 5, M, c_precomp)
+    c_rot6 = cc.EvalFastRotation(c, 6, M, c_precomp)
+    c_rot7 = cc.EvalFastRotation(c, 7, M, c_precomp)
+    time_hoisting = time.time() - t
+    # The time with hoisting should be faster than without hoisting.
+    # Also, the benefits from hoisting should be more pronounced in this
+    # case because we're using BV. Of course, we also observe less
+    # accurate results than when using HYBRID, because of using
+    # digitSize = 10 (Users can decrease digitSize to see the accuracy
+    # increase, and performance decrease).
+
+    c_res_hoist = c + c_rot1 + c_rot2 + c_rot3 + c_rot4 + c_rot5 + c_rot6 + c_rot7
+
+    result = cc.Decrypt(c_res_no_hoist,keys.secretKey)
+    result.SetLength(batch_size)
+    print(f"Result without hoisting: {result}")
+    print(f" - 7 rotations without hoisting took {time_no_hoisting*1000} ms")
+
+    result = cc.Decrypt(c_res_hoist,keys.secretKey)
+    result.SetLength(batch_size)
+    print(f"Result with hoisting: {result}")
+    print(f" - 7 rotations with hoisting took {time_hoisting*1000} ms")
+
+
+def main():
+    if get_native_int() == 128:
+        automatic_rescale_demo(ScalingTechnique.FIXEDAUTO)
+        # Note that FLEXIBLEAUTO is not supported for 128-bit CKKS
+        manual_rescale_demo(ScalingTechnique.FIXEDMANUAL)
+        hybrid_key_switching_demo1()
+        hybrid_key_switching_demo2()
+        fast_rotation_demo1()
+        fast_rotation_demo2()
+    else:
+        print("This demo only runs for 128-bit CKKS.\n")
+
+if __name__ == "__main__":
+    main()
+

+ 98 - 98
src/pke/examples/advanced-real-numbers.py

@@ -1,18 +1,18 @@
 from openfhe import *
 import time # to enable TIC-TOC timing measurements
 
-def AutomaticRescaleDemo(scalTech):
-    if(scalTech == ScalingTechnique.FLEXIBLEAUTO):
+def automatic_rescale_demo(scal_tech):
+    if(scal_tech == ScalingTechnique.FLEXIBLEAUTO):
         print("\n\n\n ===== FlexibleAutoDemo =============\n") 
     else:
          print("\n\n\n ===== FixedAutoDemo =============\n")
 
-    batchSize = 8
+    batch_size = 8
     parameters = CCParamsCKKSRNS()
     parameters.SetMultiplicativeDepth(5)
     parameters.SetScalingModSize(50)
-    parameters.SetScalingTechnique(scalTech)
-    parameters.SetBatchSize(batchSize)
+    parameters.SetScalingTechnique(scal_tech)
+    parameters.SetBatchSize(batch_size)
 
     cc = GenCryptoContext(parameters)
 
@@ -49,19 +49,19 @@ def AutomaticRescaleDemo(scalTech):
     c18 = cc.EvalMult(c16, c2)                   # x^18
     cRes = cc.EvalAdd(cc.EvalAdd(c18, c9), 1.0)  # Final result
 
-    result = Decrypt(cRes,keys.secretKey)
+    result = cc.Decrypt(cRes,keys.secretKey)
     print("x^18 + x^9 + 1 = ", result)
-    result.SetLength(batchSize)
+    result.SetLength(batch_size)
     print(f"Result: {result}")
 
-def ManualRescaleDemo(ScalingTechnique):
+def manual_rescale_demo(scal_tech):
     print("\n\n\n ===== FixedManualDemo =============\n")
     
-    batchSize = 8
+    batch_size = 8
     parameters = CCParamsCKKSRNS()
     parameters.SetMultiplicativeDepth(5)
     parameters.SetScalingModSize(50)
-    parameters.SetBatchSize(batchSize)
+    parameters.SetBatchSize(batch_size)
 
     cc = GenCryptoContext(parameters)
 
@@ -93,10 +93,10 @@ def ManualRescaleDemo(ScalingTechnique):
     #
 
     # x^2
-    c2_depth_2 = cc.EvalMult(c, c)
-    c2_depth_1 = cc.Rescale(c2_depth_2)
+    c2_depth2 = cc.EvalMult(c, c)
+    c2_depth1 = cc.Rescale(c2_depth2)
     # x^4
-    c4_depth2 = cc.EvalMult(c2_depth_1, c2_depth_1)
+    c4_depth2 = cc.EvalMult(c2_depth1, c2_depth1)
     c4_depth1 = cc.Rescale(c4_depth2)
     # x^8
     c8_depth2 = cc.EvalMult(c4_depth1, c4_depth1)
@@ -107,23 +107,23 @@ def ManualRescaleDemo(ScalingTechnique):
     # x^9
     c9_depth2 = cc.EvalMult(c8_depth1, c)
     # x^18
-    c18_depth2 = cc.EvalMult(c16_depth1, c2_depth_1)
+    c18_depth2 = cc.EvalMult(c16_depth1, c2_depth1)
     # Final result
     cRes_depth2 = cc.EvalAdd(cc.EvalAdd(c18_depth2, c9_depth2), 1.0)
     cRes_depth1 = cc.Rescale(cRes_depth2)
 
-    result = Decrypt(cRes_depth1,keys.secretKey)
-    result.SetLength(batchSize)
+    result = cc.Decrypt(cRes_depth1,keys.secretKey)
+    result.SetLength(batch_size)
     print("x^18 + x^9 + 1 = ", result)
 
-def HybridKeySwitchingDemo1():
-    
+def hybrid_key_switching_demo1():
+    print("\n\n\n ===== hybrid_key_switching_demo1 =============\n")
     dnum = 2
-    batchSize = 8
+    batch_size = 8
     parameters = CCParamsCKKSRNS()
     parameters.SetMultiplicativeDepth(5)
     parameters.SetScalingModSize(50)
-    parameters.SetBatchSize(batchSize)
+    parameters.SetBatchSize(batch_size)
     parameters.SetScalingTechnique(ScalingTechnique.FLEXIBLEAUTO)
     parameters.SetNumLargeDigits(dnum)
 
@@ -149,24 +149,24 @@ def HybridKeySwitchingDemo1():
     c = cc.Encrypt(keys.publicKey,ptxt)
 
     t = time.time()
-    cRot1 = cc.EvalRotate(c,1)
-    cRot2 = cc.EvalRotate(cRot1,-2)
+    c_rot1 = cc.EvalRotate(c,1)
+    c_rot2 = cc.EvalRotate(c_rot1,-2)
     time2digits = time.time() - t
 
-    result = Decrypt(cRot2,keys.secretKey)
-    result.SetLength(batchSize)
+    result = cc.Decrypt(c_rot2,keys.secretKey)
+    result.SetLength(batch_size)
     print(f"x rotate by -1 = {result}")
     print(f" - 2 rotations with HYBRID (2 digits) took {time2digits*1000} ms")
 
 
-def HybridKeySwitchingDemo2():
-    print("\n\n\n ===== HybridKeySwitchingDemo2 =============\n")
+def hybrid_key_switching_demo2():
+    print("\n\n\n ===== hybrid_key_switching_demo2 =============\n")
     dnum = 3
-    batchSize = 8
+    batch_size = 8
     parameters = CCParamsCKKSRNS()
     parameters.SetMultiplicativeDepth(5)
     parameters.SetScalingModSize(50)
-    parameters.SetBatchSize(batchSize)
+    parameters.SetBatchSize(batch_size)
     parameters.SetScalingTechnique(ScalingTechnique.FLEXIBLEAUTO)
     parameters.SetNumLargeDigits(dnum)
 
@@ -193,19 +193,19 @@ def HybridKeySwitchingDemo2():
     c = cc.Encrypt(keys.publicKey,ptxt)
 
     t = time.time()
-    cRot1 = cc.EvalRotate(c,1)
-    cRot2 = cc.EvalRotate(cRot1,-2)
+    c_rot1 = cc.EvalRotate(c,1)
+    c_rot2 = cc.EvalRotate(c_rot1,-2)
     time3digits = time.time() - t
     # The runtime here is smaller than the previous demo
 
-    result = Decrypt(cRot2,keys.secretKey)
-    result.SetLength(batchSize)
+    result = cc.Decrypt(c_rot2,keys.secretKey)
+    result.SetLength(batch_size)
     print(f"x rotate by -1 = {result}")
     print(f" - 2 rotations with HYBRID (3 digits) took {time3digits*1000} ms")
 
-def FastRotationDemo1():
-    print("\n\n\n ===== FastRotationDemo1 =============\n")
-    batchSize = 8
+def fast_rotation_demo1():
+    print("\n\n\n ===== fast_rotation_demo1 =============\n")
+    batch_size = 8
     parameters = CCParamsCKKSRNS()
     parameters.SetMultiplicativeDepth(5)
     parameters.SetScalingModSize(50)
@@ -234,63 +234,63 @@ def FastRotationDemo1():
     # First, we perform 7 regular (non-hoisted) rotations
     # and measure the runtime
     t = time.time()
-    cRot1 = cc.EvalRotate(c,1)
-    cRot2 = cc.EvalRotate(c,2)
-    cRot3 = cc.EvalRotate(c,3)
-    cRot4 = cc.EvalRotate(c,4)
-    cRot5 = cc.EvalRotate(c,5)
-    cRot6 = cc.EvalRotate(c,6)
-    cRot7 = cc.EvalRotate(c,7)
-    timeNoHoisting = time.time() - t
+    c_rot1 = cc.EvalRotate(c,1)
+    c_rot2 = cc.EvalRotate(c,2)
+    c_rot3 = cc.EvalRotate(c,3)
+    c_rot4 = cc.EvalRotate(c,4)
+    c_rot5 = cc.EvalRotate(c,5)
+    c_rot6 = cc.EvalRotate(c,6)
+    c_rot7 = cc.EvalRotate(c,7)
+    time_no_hoisting = time.time() - t
 
-    cResNoHoist = c + cRot1 + cRot2 + cRot3 + cRot4 + cRot5 + cRot6 + cRot7
+    c_res_no_hoist = c + c_rot1 + c_rot2 + c_rot3 + c_rot4 + c_rot5 + c_rot6 + c_rot7
 
     # M is the cyclotomic order and we need it to call EvalFastRotation
     M = 2*N
 
     # Then, we perform 7 rotations with hoisting.
     t = time.time()
-    cPrecomp = cc.EvalFastRotationPrecompute(c)
-    cRot1 = cc.EvalFastRotation(c, 1, M, cPrecomp)
-    cRot2 = cc.EvalFastRotation(c, 2, M, cPrecomp)
-    cRot3 = cc.EvalFastRotation(c, 3, M, cPrecomp)
-    cRot4 = cc.EvalFastRotation(c, 4, M, cPrecomp)
-    cRot5 = cc.EvalFastRotation(c, 5, M, cPrecomp)
-    cRot6 = cc.EvalFastRotation(c, 6, M, cPrecomp)
-    cRot7 = cc.EvalFastRotation(c, 7, M, cPrecomp)
-    timeHoisting = time.time() - t
+    c_precomp = cc.EvalFastRotationPrecompute(c)
+    c_rot1 = cc.EvalFastRotation(c,1,M,c_precomp)
+    c_rot2 = cc.EvalFastRotation(c,2,M,c_precomp)
+    c_rot3 = cc.EvalFastRotation(c,3,M,c_precomp)
+    c_rot4 = cc.EvalFastRotation(c,4,M,c_precomp)
+    c_rot5 = cc.EvalFastRotation(c,5,M,c_precomp)
+    c_rot6 = cc.EvalFastRotation(c,6,M,c_precomp)
+    c_rot7 = cc.EvalFastRotation(c,7,M,c_precomp)
+    time_hoisting = time.time() - t
     # The time with hoisting should be faster than without hoisting.
 
-    cResHoist = c + cRot1 + cRot2 + cRot3 + cRot4 + cRot5 + cRot6 + cRot7
+    c_res_hoist = c + c_rot1 + c_rot2 + c_rot3 + c_rot4 + c_rot5 + c_rot6 + c_rot7
     
-    result = Decrypt(cResNoHoist,keys.secretKey)
-    result.SetLength(batchSize)
+    result = cc.Decrypt(c_res_no_hoist,keys.secretKey)
+    result.SetLength(batch_size)
     print(f"Result without hoisting: {result}")
-    print(f" - 7 rotations without hoisting took {timeNoHoisting*1000} ms")
+    print(f" - 7 rotations without hoisting took {time_no_hoisting*1000} ms")
 
     
-    result = Decrypt(cResHoist,keys.secretKey)
-    result.SetLength(batchSize)
+    result = cc.Decrypt(c_res_hoist,keys.secretKey)
+    result.SetLength(batch_size)
     print(f"Result with hoisting: {result}")
-    print(f" - 7 rotations with hoisting took {timeHoisting*1000} ms")
+    print(f" - 7 rotations with hoisting took {time_hoisting*1000} ms")
 
 
 
 
-def FastRotationDemo2():
-    print("\n\n\n ===== FastRotationDemo2 =============\n")
+def fast_rotation_demo2():
+    print("\n\n\n ===== fast_rotation_demo2 =============\n")
 
-    digitSize = 3
-    batchSize = 8
+    digit_size = 3
+    batch_size = 8
 
     parameters = CCParamsCKKSRNS()
     parameters.SetMultiplicativeDepth(1)
     parameters.SetScalingModSize(50)
-    parameters.SetBatchSize(batchSize)
+    parameters.SetBatchSize(batch_size)
     parameters.SetScalingTechnique(ScalingTechnique.FLEXIBLEAUTO)
     parameters.SetKeySwitchTechnique(KeySwitchTechnique.BV)
     parameters.SetFirstModSize(60)
-    parameters.SetDigitSize(digitSize)
+    parameters.SetDigitSize(digit_size)
 
     cc = GenCryptoContext(parameters)
 
@@ -315,31 +315,31 @@ def FastRotationDemo2():
     # First, we perform 7 regular (non-hoisted) rotations
     # and measure the runtime
     t = time.time()
-    cRot1 = cc.EvalRotate(c,1)
-    cRot2 = cc.EvalRotate(c,2)
-    cRot3 = cc.EvalRotate(c,3)
-    cRot4 = cc.EvalRotate(c,4)
-    cRot5 = cc.EvalRotate(c,5)
-    cRot6 = cc.EvalRotate(c,6)
-    cRot7 = cc.EvalRotate(c,7)
-    timeNoHoisting = time.time() - t
+    c_rot1 = cc.EvalRotate(c,1)
+    c_rot2 = cc.EvalRotate(c,2)
+    c_rot3 = cc.EvalRotate(c,3)
+    c_rot4 = cc.EvalRotate(c,4)
+    c_rot5 = cc.EvalRotate(c,5)
+    c_rot6 = cc.EvalRotate(c,6)
+    c_rot7 = cc.EvalRotate(c,7)
+    time_no_hoisting = time.time() - t
 
-    cResNoHoist = c + cRot1 + cRot2 + cRot3 + cRot4 + cRot5 + cRot6 + cRot7
+    c_res_no_hoist = c + c_rot1 + c_rot2 + c_rot3 + c_rot4 + c_rot5 + c_rot6 + c_rot7
 
     # M is the cyclotomic order and we need it to call EvalFastRotation
     M = 2*N
 
     # Then, we perform 7 rotations with hoisting.
     t = time.time()
-    cPrecomp = cc.EvalFastRotationPrecompute(c)
-    cRot1 = cc.EvalFastRotation(c, 1, M, cPrecomp)
-    cRot2 = cc.EvalFastRotation(c, 2, M, cPrecomp)
-    cRot3 = cc.EvalFastRotation(c, 3, M, cPrecomp)
-    cRot4 = cc.EvalFastRotation(c, 4, M, cPrecomp)
-    cRot5 = cc.EvalFastRotation(c, 5, M, cPrecomp)
-    cRot6 = cc.EvalFastRotation(c, 6, M, cPrecomp)
-    cRot7 = cc.EvalFastRotation(c, 7, M, cPrecomp)
-    timeHoisting = time.time() - t
+    c_precomp = cc.EvalFastRotationPrecompute(c)
+    c_rot1 = cc.EvalFastRotation(c,1,M,c_precomp)
+    c_rot2 = cc.EvalFastRotation(c,2,M,c_precomp)
+    c_rot3 = cc.EvalFastRotation(c,3,M,c_precomp)
+    c_rot4 = cc.EvalFastRotation(c,4,M,c_precomp)
+    c_rot5 = cc.EvalFastRotation(c,5,M,c_precomp)
+    c_rot6 = cc.EvalFastRotation(c,6,M,c_precomp)
+    c_rot7 = cc.EvalFastRotation(c,7,M,c_precomp)
+    time_hoisting = time.time() - t
     # The time with hoisting should be faster than without hoisting.
     # Also, the benefits from hoisting should be more pronounced in this
     # case because we're using BV. Of course, we also observe less
@@ -347,27 +347,27 @@ def FastRotationDemo2():
     # digitSize = 10 (Users can decrease digitSize to see the accuracy
     # increase, and performance decrease).
 
-    cResHoist = c + cRot1 + cRot2 + cRot3 + cRot4 + cRot5 + cRot6 + cRot7
+    c_res_hoist = c + c_rot1 + c_rot2 + c_rot3 + c_rot4 + c_rot5 + c_rot6 + c_rot7
 
-    result = Decrypt(cResNoHoist,keys.secretKey)
-    result.SetLength(batchSize)
+    result = cc.Decrypt(c_res_no_hoist,keys.secretKey)
+    result.SetLength(batch_size)
     print(f"Result without hoisting: {result}")
-    print(f" - 7 rotations without hoisting took {timeNoHoisting*1000} ms")
+    print(f" - 7 rotations without hoisting took {time_no_hoisting*1000} ms")
 
-    result = Decrypt(cResHoist,keys.secretKey)
-    result.SetLength(batchSize)
+    result = cc.Decrypt(c_res_no_hoist,keys.secretKey)
+    result.SetLength(batch_size)
     print(f"Result with hoisting: {result}")
-    print(f" - 7 rotations with hoisting took {timeHoisting*1000} ms")
+    print(f" - 7 rotations with hoisting took {time_hoisting*1000} ms")
 
 
 def main():
-    AutomaticRescaleDemo(ScalingTechnique.FLEXIBLEAUTO)
-    AutomaticRescaleDemo(ScalingTechnique.FIXEDAUTO)
-    ManualRescaleDemo(ScalingTechnique.FIXEDMANUAL)
-    HybridKeySwitchingDemo1()
-    HybridKeySwitchingDemo2()
-    FastRotationDemo1()
-    FastRotationDemo2()
+    automatic_rescale_demo(ScalingTechnique.FLEXIBLEAUTO)
+    automatic_rescale_demo(ScalingTechnique.FIXEDAUTO)
+    manual_rescale_demo(ScalingTechnique.FIXEDMANUAL)
+    hybrid_key_switching_demo1()
+    hybrid_key_switching_demo2()
+    fast_rotation_demo1()
+    fast_rotation_demo2()
 
 if __name__ == "__main__":
     main()

+ 94 - 0
src/pke/examples/function-evaluation.py

@@ -0,0 +1,94 @@
+from openfhe import *
+import math
+
+def main():
+    eval_logistic_example()
+    eval_function_example()
+
+def eval_logistic_example():
+    print("--------------------------------- EVAL LOGISTIC FUNCTION ---------------------------------\n")
+    parameters = CCParamsCKKSRNS()
+    parameters.SetSecurityLevel(SecurityLevel.HEStd_NotSet)
+    parameters.SetRingDim(1 << 10)
+
+    scaling_mod_size = 59
+    first_mod_size = 60
+
+    parameters.SetScalingModSize(scaling_mod_size)
+    parameters.SetFirstModSize(first_mod_size)
+
+    poly_degree = 16
+    mult_depth = 6
+
+    parameters.SetMultiplicativeDepth(mult_depth)
+    cc = GenCryptoContext(parameters)
+    cc.Enable(PKESchemeFeature.PKE)
+    cc.Enable(PKESchemeFeature.KEYSWITCH)
+    cc.Enable(PKESchemeFeature.LEVELEDSHE)
+    cc.Enable(PKESchemeFeature.ADVANCEDSHE)
+
+    key_pair = cc.KeyGen()
+    cc.EvalMultKeyGen(key_pair.secretKey)
+
+    input = [-4, -3, -2, -1, 0, 1, 2, 3, 4]
+    encoded_length = len(input)
+    plaintext = cc.MakeCKKSPackedPlaintext(input)
+    ciphertext = cc.Encrypt(key_pair.publicKey, plaintext)
+
+    lower_bound = -4
+    upper_bound = 4
+    result = cc.EvalLogistic(ciphertext, lower_bound, upper_bound, poly_degree)
+
+    plaintext_dec = cc.Decrypt(result, key_pair.secretKey)
+    plaintext_dec.SetLength(encoded_length)
+
+    expected_output = [0.0179885, 0.0474289, 0.119205, 0.268936, 0.5, 0.731064, 0.880795, 0.952571, 0.982011]
+    print(f"Expected output\n\t {expected_output}\n")
+
+    final_result = plaintext_dec.GetCKKSPackedValue()
+    print(f"Actual output\n\t {final_result}\n")
+
+def eval_function_example():
+    print("--------------------------------- EVAL SQUARE ROOT FUNCTION ---------------------------------\n")
+    parameters = CCParamsCKKSRNS()
+    parameters.SetSecurityLevel(SecurityLevel.HEStd_NotSet)
+    parameters.SetRingDim(1 << 10)
+
+    scaling_mod_size = 59
+    first_mod_size = 60
+
+    parameters.SetScalingModSize(scaling_mod_size)
+    parameters.SetFirstModSize(first_mod_size)
+
+    poly_degree = 50
+    mult_depth = 7
+
+    parameters.SetMultiplicativeDepth(mult_depth)
+    cc = GenCryptoContext(parameters)
+    cc.Enable(PKESchemeFeature.PKE)
+    cc.Enable(PKESchemeFeature.KEYSWITCH)
+    cc.Enable(PKESchemeFeature.LEVELEDSHE)
+    cc.Enable(PKESchemeFeature.ADVANCEDSHE)
+
+    key_pair = cc.KeyGen()
+    cc.EvalMultKeyGen(key_pair.secretKey)
+
+    input = [1, 2, 3, 4, 5, 6, 7, 8, 9]
+    encoded_length = len(input)
+    plaintext = cc.MakeCKKSPackedPlaintext(input)
+    ciphertext = cc.Encrypt(key_pair.publicKey, plaintext)
+
+    lower_bound = 1
+    upper_bound = 9
+    result = cc.EvalChebyshevFunction(math.sqrt,ciphertext, lower_bound, upper_bound, poly_degree)
+
+    plaintext_dec = cc.Decrypt(result, key_pair.secretKey)
+    plaintext_dec.SetLength(encoded_length)
+
+    expected_output = [1, 1.414213, 1.732050, 2, 2.236067, 2.449489, 2.645751, 2.828427, 3]
+    print(f"Expected output\n\t {expected_output}\n")
+
+    final_result = plaintext_dec.GetCKKSPackedValue()
+    print(f"Actual output\n\t {final_result}\n")
+if __name__ == "__main__":
+    main()

+ 113 - 0
src/pke/examples/iterative-ckks-bootstrapping.py

@@ -0,0 +1,113 @@
+from openfhe import *
+import math
+import random
+
+def main():
+    iterative_bootstrap_example()
+
+def calculate_approximation_error(result,expected_result):
+    if len(result) != len(expected_result):
+        raise Exception("Cannot compare vectors with different numbers of elements")
+    # using the infinity norm
+    # error is abs of the difference of real parts
+    max_error = max([abs(el1.real - el2.real) for (el1, el2) in zip(result, expected_result)])
+    # return absolute value of log base2 of the error
+    return abs(math.log(max_error,2))
+def iterative_bootstrap_example():
+    # Step 1: Set CryptoContext
+    parameters = CCParamsCKKSRNS()
+    secret_key_dist = SecretKeyDist.UNIFORM_TERNARY
+    parameters.SetSecretKeyDist(secret_key_dist)
+    parameters.SetSecurityLevel(SecurityLevel.HEStd_NotSet)
+    parameters.SetRingDim(1 << 12)
+
+    rescale_tech = ScalingTechnique.FLEXIBLEAUTO
+    dcrt_bits = 59
+    first_mod = 60
+
+    parameters.SetScalingModSize(dcrt_bits)
+    parameters.SetScalingTechnique(rescale_tech)
+    parameters.SetFirstModSize(first_mod)
+
+    # Here, we specify the number of iterations to run bootstrapping. 
+    # Note that we currently only support 1 or 2 iterations.
+    # Two iterations should give us approximately double the precision of one iteration.
+    num_iterations = 2
+
+    level_budget = [3, 3]
+    # Each extra iteration on top of 1 requires an extra level to be consumed.
+    approx_bootstrapp_depth = 8 + (num_iterations - 1)
+    bsgs_dim = [0,0]
+
+    levels_used_before_bootstrap = 10
+    depth = levels_used_before_bootstrap + FHECKKSRNS.GetBootstrapDepth(approx_bootstrapp_depth, level_budget, secret_key_dist)
+    parameters.SetMultiplicativeDepth(depth)
+
+    # Generate crypto context
+    cryptocontext = GenCryptoContext(parameters)
+
+    # Enable features that you wish to use. Note, we must enable FHE to use bootstrapping.
+
+    cryptocontext.Enable(PKESchemeFeature.PKE)
+    cryptocontext.Enable(PKESchemeFeature.KEYSWITCH)
+    cryptocontext.Enable(PKESchemeFeature.LEVELEDSHE)
+    cryptocontext.Enable(PKESchemeFeature.ADVANCEDSHE)
+    cryptocontext.Enable(PKESchemeFeature.FHE)
+
+    ring_dim = cryptocontext.GetRingDimension()
+    print(f"CKKS is using ring dimension {ring_dim}\n\n")
+
+    # Step 2: Precomputations for bootstrapping
+    # We use a sparse packing
+    num_slots = 8
+    cryptocontext.EvalBootstrapSetup(levelBudget, bsgs_dim, num_slots)
+
+    # Step 3: Key generation
+    key_pair = cryptocontext.KeyGen()
+    cryptocontext.EvalMultKeyGen(key_pair.secretKey)
+    # Generate bootstrapping keys.
+    cryptocontext.EvalBootstrapKeyGen(key_pair.secretKey, num_slots)
+
+    # Step 4: Encoding and encryption of inputs
+    # Generate random input
+    x = [random.uniform(0, 1) for i in range(num_slots)]
+
+    """ Encoding as plaintexts
+        We specify the number of slots as num_slots to achieve a performance improvement.
+        We use the other default values of depth 1, levels 0, and no params.
+        Alternatively, you can also set batch size as a parameter in the CryptoContext as follows:
+        parameters.SetBatchSize(num_slots);
+        Here, we assume all ciphertexts in the cryptoContext will have num_slots slots.
+        We start with a depleted ciphertext that has used up all of its levels."""
+    ptxt = cryptocontext.MakeCKKSPackedPlaintext(x, 1, depth -1,None,num_slots)
+
+    # Encrypt the encoded vectors
+    ciph = cryptocontext.Encrypt(key_pair.publicKey, ptxt)
+
+    # Step 5: Measure the precision of a single bootstrapping operation.
+    ciphertext_after = cryptocontext.EvalBootstrap(ciph)
+
+    result = cryptocontext.Decrypt(ciphertext_after,key_pair.secretKey)
+    result.SetLength(num_slots)
+    precision = calculate_approximation_error(result.GetCKKSPackedValue(),ptxt.GetCKKSPackedValue())
+    print(f"Bootstrapping precision after 1 iteration: {precision} bits\n")
+
+    # Set the precision equal to empirically measured value after many test runs.
+    precision = 17
+    print(f"Precision input to algorithm: {precision}\n")
+
+    # Step 6: Run bootstrapping with multiple iterations
+    ciphertext_two_iterations = cryptocontext.EvalBootstrap(ciph,num_iterations,precision)
+
+    result_two_iterations = cryptocontext.Decrypt(ciphertext_two_iterations,key_pair.secretKey)
+    result_two_iterations.SetLength(num_slots)
+    actual_result = result_two_iterations.GetCKKSPackedValue()
+
+    print(f"Output after two interations of bootstrapping: {actual_result}\n")
+    precision_multiple_iterations = calculate_approximation_error(actual_result,ptxt.GetCKKSPackedValue())
+
+    print(f"Bootstrapping precision after 2 iterations: {precision_multiple_iterations} bits\n")
+    print(f"Number of levels remaining after 2 bootstrappings: {depth - ciphertext_two_iterations.GetLevel()}\n")
+
+if __name__ == "__main__":
+    main()

+ 70 - 0
src/pke/examples/polynomial-evaluation.py

@@ -0,0 +1,70 @@
+from openfhe import *
+import time
+
+def main():
+
+    print("\n======EXAMPLE FOR EVALPOLY========\n")
+    parameters = CCParamsCKKSRNS()
+    parameters.SetMultiplicativeDepth(6)
+    parameters.SetScalingModSize(50)
+
+    cc = GenCryptoContext(parameters)
+    cc.Enable(PKESchemeFeature.PKE)
+    cc.Enable(PKESchemeFeature.KEYSWITCH)
+    cc.Enable(PKESchemeFeature.LEVELEDSHE)
+    cc.Enable(PKESchemeFeature.ADVANCEDSHE)
+
+    input = [complex(a,0) for a in [0.5, 0.7, 0.9, 0.95, 0.93]]
+    # input = [0.5, 0.7, 0.9, 0.95, 0.93]
+    encoded_length = len(input)
+    coefficients1 = [0.15, 0.75, 0, 1.25, 0, 0, 1, 0, 1, 2, 0, 1, 0, 0, 0, 0, 1]
+    coefficients2 = [1, 2, 3, 4, 5, -1, -2, -3, -4, -5,
+                    0.1, 0.2, 0.3, 0.4, 0.5, -0.1, -0.2, -0.3, -0.4, -0.5,
+                    0.1, 0.2, 0.3, 0.4, 0.5, -0.1, -0.2, -0.3, -0.4, -0.5]
+    plaintext1 = cc.MakeCKKSPackedPlaintext(input)
+
+    key_pair = cc.KeyGen()
+    
+    print("Generating evaluation key for homomorphic multiplication...")
+    cc.EvalMultKeyGen(key_pair.secretKey)
+    print("Completed.\n")
+
+    ciphertext1 = cc.Encrypt(key_pair.publicKey, plaintext1)
+
+    t = time.time()
+    result = cc.EvalPoly(ciphertext1, coefficients1)
+    time_eval_poly1 = time.time() - t
+
+    t = time.time()
+    result2 = cc.EvalPoly(ciphertext1, coefficients2)
+    time_eval_poly2 = time.time() - t
+
+    plaintext_dec = cc.Decrypt(result, key_pair.secretKey)
+
+    plaintext_dec.SetLength(encoded_length)
+
+    plaintext_dec2 = cc.Decrypt(result2, key_pair.secretKey)
+
+    plaintext_dec2.SetLength(encoded_length)
+
+    print("\n Original Plaintext #1: \n")
+    print(plaintext1)
+
+    print(f"\n Result of evaluating a polynomial with coefficients {coefficients1}: \n")
+    print(plaintext_dec)
+
+    print("\n Expected result: (0.70519107, 1.38285078, 3.97211180, "
+                 "5.60215665, 4.86357575) \n") 
+
+    print(f"\n Evaluation time: {time_eval_poly1*1000} ms \n")
+
+    print(f"\n Result of evaluating a polynomial with coefficients {coefficients2}: \n")
+    print(plaintext_dec2)  
+
+    print("\n Expected result: (3.4515092326, 5.3752765397, 4.8993108833, "
+                 "3.2495023573, 4.0485229982) \n")
+
+    print(f"\n Evaluation time: {time_eval_poly2*1000} ms \n")
+
+if __name__ == '__main__':
+    main() 

+ 28 - 28
src/pke/examples/simple-ckks-bootstrapping.py

@@ -1,31 +1,31 @@
 from openfhe import *
 
 def main():
-    SimpleBootstrapExample()
+    simple_bootstrap_example()
 
-def SimpleBootstrapExample():
+def simple_bootstrap_example():
     parameters = CCParamsCKKSRNS()
 
-    secretKeyDist = SecretKeyDist.UNIFORM_TERNARY
-    parameters.SetSecretKeyDist(secretKeyDist)
+    secret_key_dist = SecretKeyDist.UNIFORM_TERNARY
+    parameters.SetSecretKeyDist(secret_key_dist)
 
     parameters.SetSecurityLevel(SecurityLevel.HEStd_NotSet)
     parameters.SetRingDim(1<<12)
 
-    rescaleTech = ScalingTechnique.FLEXIBLEAUTO
-    dcrtBits = 59
-    firstMod = 60
+    rescale_tech = ScalingTechnique.FLEXIBLEAUTO
+    dcrt_bits = 59
+    first_mod = 60
     
-    parameters.SetScalingModSize(dcrtBits)
-    parameters.SetScalingTechnique(rescaleTech)
-    parameters.SetFirstModSize(firstMod)
+    parameters.SetScalingModSize(dcrt_bits)
+    parameters.SetScalingTechnique(rescale_tech)
+    parameters.SetFirstModSize(first_mod)
 
-    levelBudget = [4, 4]
-    approxBootstrappDepth = 8
+    level_budget = [4, 4]
+    approx_bootstrapp_depth = 8
 
-    levelsUsedBeforeBootstrap = 10
+    levels_used_before_bootstrap = 10
 
-    depth = levelsUsedBeforeBootstrap + FHECKKSRNS.GetBootstrapDepth(approxBootstrappDepth, levelBudget, secretKeyDist)
+    depth = levels_used_before_bootstrap + FHECKKSRNS.GetBootstrapDepth(approx_bootstrapp_depth, level_budget, secret_key_dist)
 
     parameters.SetMultiplicativeDepth(depth)
 
@@ -36,36 +36,36 @@ def SimpleBootstrapExample():
     cryptocontext.Enable(PKESchemeFeature.ADVANCEDSHE)
     cryptocontext.Enable(PKESchemeFeature.FHE)
 
-    ringDim = cryptocontext.GetRingDimension()
+    ring_dim = cryptocontext.GetRingDimension()
     # This is the mazimum number of slots that can be used full packing.
 
-    numSlots = int(ringDim / 2)
-    print(f"CKKS is using ring dimension {ringDim}")
+    num_slots = int(ring_dim / 2)
+    print(f"CKKS is using ring dimension {ring_dim}")
 
-    cryptocontext.EvalBootstrapSetup(levelBudget)
+    cryptocontext.EvalBootstrapSetup(level_budget)
 
-    keyPair = cryptocontext.KeyGen()
-    cryptocontext.EvalMultKeyGen(keyPair.secretKey)
-    cryptocontext.EvalBootstrapKeyGen(keyPair.secretKey, numSlots)
+    key_pair = cryptocontext.KeyGen()
+    cryptocontext.EvalMultKeyGen(key_pair.secretKey)
+    cryptocontext.EvalBootstrapKeyGen(key_pair.secretKey, num_slots)
 
     x = [0.25, 0.5, 0.75, 1.0, 2.0, 3.0, 4.0, 5.0]
-    encodedLength = len(x)
+    encoded_length = len(x)
 
     ptxt = cryptocontext.MakeCKKSPackedPlaintext(x)
-    ptxt.SetLength(encodedLength)
+    ptxt.SetLength(encoded_length)
 
     print(f"Input: {x}")
 
-    ciph = cryptocontext.Encrypt(keyPair.publicKey, ptxt)
+    ciph = cryptocontext.Encrypt(key_pair.publicKey, ptxt)
 
     print(f"Initial number of levels remaining: {ciph.GetLevel()}")
 
-    ciphertextAfter = cryptocontext.EvalBootstrap(ciph)
+    ciphertext_after = cryptocontext.EvalBootstrap(ciph)
 
-    print(f"Number of levels remaining after bootstrapping: {ciphertextAfter.GetLevel()}")
+    print(f"Number of levels remaining after bootstrapping: {ciphertext_after.GetLevel()}")
 
-    result = Decrypt(ciphertextAfter,keyPair.secretKey)
-    result.SetLength(encodedLength)
+    result = cryptocontext.Decrypt(ciphertext_after,key_pair.secretKey)
+    result.SetLength(encoded_length)
     print(f"Output after bootstrapping: {result}")
 
 if __name__ == '__main__':

+ 38 - 36
src/pke/examples/simple-integers-bgvrns.py

@@ -1,82 +1,84 @@
 # Initial Settings
 from openfhe import *
+# import openfhe.PKESchemeFeature as Feature
+
 
 # Sample Program: Step 1: Set CryptoContext
 parameters = CCParamsBGVRNS()
 parameters.SetPlaintextModulus(65537)
 parameters.SetMultiplicativeDepth(2)
 
-cryptoContext = GenCryptoContext(parameters)
+crypto_context = GenCryptoContext(parameters)
 # Enable features that you wish to use
-cryptoContext.Enable(PKESchemeFeature.PKE)
-cryptoContext.Enable(PKESchemeFeature.KEYSWITCH)
-cryptoContext.Enable(PKESchemeFeature.LEVELEDSHE)
+crypto_context.Enable(PKESchemeFeature.PKE)
+crypto_context.Enable(PKESchemeFeature.KEYSWITCH)
+crypto_context.Enable(PKESchemeFeature.LEVELEDSHE)
 
 # Sample Program: Step 2: Key Generation
 
 # Generate a public/private key pair
-keypair = cryptoContext.KeyGen()
+key_pair = crypto_context.KeyGen()
 
 # Generate the relinearization key
-cryptoContext.EvalMultKeyGen(keypair.secretKey)
+crypto_context.EvalMultKeyGen(key_pair.secretKey)
 
 # Generate the rotation evaluation keys
-cryptoContext.EvalRotateKeyGen(keypair.secretKey, [1, 2, -1, -2])
+crypto_context.EvalRotateKeyGen(key_pair.secretKey, [1, 2, -1, -2])
 
 # Sample Program: Step 3: Encryption
 
 # First plaintext vector is encoded
-vectorOfInts1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
-plaintext1 = cryptoContext.MakePackedPlaintext(vectorOfInts1)
+vector_of_ints1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+plaintext1 = crypto_context.MakePackedPlaintext(vector_of_ints1)
 
 # Second plaintext vector is encoded
-vectorOfInts2 = [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12]
-plaintext2 = cryptoContext.MakePackedPlaintext(vectorOfInts2)
+vector_of_ints2 = [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+plaintext2 = crypto_context.MakePackedPlaintext(vector_of_ints2)
 
 # Third plaintext vector is encoded
-vectorOfInts3 = [1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12]
-plaintext3 = cryptoContext.MakePackedPlaintext(vectorOfInts3)
+vector_of_ints3 = [1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12]
+plaintext3 = crypto_context.MakePackedPlaintext(vector_of_ints3)
 
 # The encoded vectors are encrypted
-ciphertext1 = cryptoContext.Encrypt(keypair.publicKey, plaintext1)
-ciphertext2 = cryptoContext.Encrypt(keypair.publicKey, plaintext2)
-ciphertext3 = cryptoContext.Encrypt(keypair.publicKey, plaintext3)
+ciphertext1 = crypto_context.Encrypt(key_pair.publicKey, plaintext1)
+ciphertext2 = crypto_context.Encrypt(key_pair.publicKey, plaintext2)
+ciphertext3 = crypto_context.Encrypt(key_pair.publicKey, plaintext3)
 
 #  Sample Program: Step 4: Evaluation
 
 # Homomorphic additions
-ciphertextAdd12 = cryptoContext.EvalAdd(ciphertext1, ciphertext2)
-ciphertextAddResult = cryptoContext.EvalAdd(ciphertextAdd12, ciphertext3)
+ciphertext_add12 = crypto_context.EvalAdd(ciphertext1, ciphertext2)
+ciphertext_add_result = crypto_context.EvalAdd(ciphertext_add12, ciphertext3)
 
 # Homomorphic Multiplication
-ciphertextMult12 = cryptoContext.EvalMult(ciphertext1, ciphertext2)
-ciphertextMultResult = cryptoContext.EvalMult(ciphertextMult12, ciphertext3)
+ciphertext_mult12 = crypto_context.EvalMult(ciphertext1, ciphertext2)
+ciphertext_mult_result = crypto_context.EvalMult(ciphertext_mult12, ciphertext3)
 
 # Homomorphic Rotations
-ciphertextRot1 = cryptoContext.EvalRotate(ciphertext1, 1)
-ciphertextRot2 = cryptoContext.EvalRotate(ciphertext1, 2)
-ciphertextRot3 = cryptoContext.EvalRotate(ciphertext1, -1)
-ciphertextRot4 = cryptoContext.EvalRotate(ciphertext1, -2)
+ciphertext_rot1 = crypto_context.EvalRotate(ciphertext1, 1)
+ciphertext_rot2 = crypto_context.EvalRotate(ciphertext1, 2)
+ciphertext_rot3 = crypto_context.EvalRotate(ciphertext1, -1)
+ciphertext_rot4 = crypto_context.EvalRotate(ciphertext1, -2)
 
 # Sample Program: Step 5: Decryption
 
 # Decrypt the result of additions
-plaintextAddResult = Decrypt(ciphertextAddResult,keypair.secretKey)
+plaintext_add_result = crypto_context.Decrypt(ciphertext_add_result,key_pair.secretKey)
 
 # Decrypt the result of multiplications
-plaintextMultResult = Decrypt(ciphertextMultResult,keypair.secretKey)
+plaintext_mult_result = crypto_context.Decrypt(ciphertext_mult_result,key_pair.secretKey)
 
 # Decrypt the result of rotations
-plaintextRot1 = Decrypt(ciphertextRot1,keypair.secretKey)
-plaintextRot2 = Decrypt(ciphertextRot2,keypair.secretKey)
-plaintextRot3 = Decrypt(ciphertextRot3,keypair.secretKey)
-plaintextRot4 = Decrypt(ciphertextRot4,keypair.secretKey)
+plaintextRot1 = crypto_context.Decrypt(ciphertext_rot1,key_pair.secretKey)
+plaintextRot2 = crypto_context.Decrypt(ciphertext_rot2,key_pair.secretKey)
+plaintextRot3 = crypto_context.Decrypt(ciphertext_rot3,key_pair.secretKey)
+plaintextRot4 = crypto_context.Decrypt(ciphertext_rot4,key_pair.secretKey)
 
 
-plaintextRot1.SetLength(len(vectorOfInts1))
-plaintextRot2.SetLength(len(vectorOfInts1))
-plaintextRot3.SetLength(len(vectorOfInts1))
-plaintextRot4.SetLength(len(vectorOfInts1))
+plaintextRot1.SetLength(len(vector_of_ints1))
+plaintextRot2.SetLength(len(vector_of_ints1))
+plaintextRot3.SetLength(len(vector_of_ints1))
+plaintextRot4.SetLength(len(vector_of_ints1))
 
 print("Plaintext #1: " + str(plaintext1))
 print("Plaintext #2: " + str(plaintext2))
@@ -84,8 +86,8 @@ print("Plaintext #3: " + str(plaintext3))
 
 # Output Results
 print("\nResults of homomorphic computations")
-print("#1 + #2 + #3 = " + str(plaintextAddResult))
-print("#1 * #2 * #3 = " + str(plaintextMultResult))
+print("#1 + #2 + #3 = " + str(plaintext_add_result))
+print("#1 * #2 * #3 = " + str(plaintext_mult_result))
 print("Left rotation of #1 by 1 = " + str(plaintextRot1))
 print("Left rotation of #1 by 2 = " + str(plaintextRot2))
 print("Right rotation of #1 by 1 = " + str(plaintextRot3))

+ 36 - 36
src/pke/examples/simple-integers.py

@@ -8,77 +8,77 @@ parameters = CCParamsBFVRNS()
 parameters.SetPlaintextModulus(65537)
 parameters.SetMultiplicativeDepth(2)
 
-cryptoContext = GenCryptoContext(parameters)
+crypto_context = GenCryptoContext(parameters)
 # Enable features that you wish to use
-cryptoContext.Enable(PKESchemeFeature.PKE)
-cryptoContext.Enable(PKESchemeFeature.KEYSWITCH)
-cryptoContext.Enable(PKESchemeFeature.LEVELEDSHE)
+crypto_context.Enable(PKESchemeFeature.PKE)
+crypto_context.Enable(PKESchemeFeature.KEYSWITCH)
+crypto_context.Enable(PKESchemeFeature.LEVELEDSHE)
 
 # Sample Program: Step 2: Key Generation
 
 # Generate a public/private key pair
-keypair = cryptoContext.KeyGen()
+key_pair = crypto_context.KeyGen()
 
 # Generate the relinearization key
-cryptoContext.EvalMultKeyGen(keypair.secretKey)
+crypto_context.EvalMultKeyGen(key_pair.secretKey)
 
 # Generate the rotation evaluation keys
-cryptoContext.EvalRotateKeyGen(keypair.secretKey, [1, 2, -1, -2])
+crypto_context.EvalRotateKeyGen(key_pair.secretKey, [1, 2, -1, -2])
 
 # Sample Program: Step 3: Encryption
 
 # First plaintext vector is encoded
-vectorOfInts1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
-plaintext1 = cryptoContext.MakePackedPlaintext(vectorOfInts1)
+vector_of_ints1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+plaintext1 = crypto_context.MakePackedPlaintext(vector_of_ints1)
 
 # Second plaintext vector is encoded
-vectorOfInts2 = [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12]
-plaintext2 = cryptoContext.MakePackedPlaintext(vectorOfInts2)
+vector_of_ints2 = [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+plaintext2 = crypto_context.MakePackedPlaintext(vector_of_ints2)
 
 # Third plaintext vector is encoded
-vectorOfInts3 = [1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12]
-plaintext3 = cryptoContext.MakePackedPlaintext(vectorOfInts3)
+vector_of_ints3 = [1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12]
+plaintext3 = crypto_context.MakePackedPlaintext(vector_of_ints3)
 
 # The encoded vectors are encrypted
-ciphertext1 = cryptoContext.Encrypt(keypair.publicKey, plaintext1)
-ciphertext2 = cryptoContext.Encrypt(keypair.publicKey, plaintext2)
-ciphertext3 = cryptoContext.Encrypt(keypair.publicKey, plaintext3)
+ciphertext1 = crypto_context.Encrypt(key_pair.publicKey, plaintext1)
+ciphertext2 = crypto_context.Encrypt(key_pair.publicKey, plaintext2)
+ciphertext3 = crypto_context.Encrypt(key_pair.publicKey, plaintext3)
 
 #  Sample Program: Step 4: Evaluation
 
 # Homomorphic additions
-ciphertextAdd12 = cryptoContext.EvalAdd(ciphertext1, ciphertext2)
-ciphertextAddResult = cryptoContext.EvalAdd(ciphertextAdd12, ciphertext3)
+ciphertext_add12 = crypto_context.EvalAdd(ciphertext1, ciphertext2)
+ciphertext_add_result = crypto_context.EvalAdd(ciphertext_add12, ciphertext3)
 
 # Homomorphic Multiplication
-ciphertextMult12 = cryptoContext.EvalMult(ciphertext1, ciphertext2)
-ciphertextMultResult = cryptoContext.EvalMult(ciphertextMult12, ciphertext3)
+ciphertext_mult12 = crypto_context.EvalMult(ciphertext1, ciphertext2)
+ciphertext_mult_result = crypto_context.EvalMult(ciphertext_mult12, ciphertext3)
 
 # Homomorphic Rotations
-ciphertextRot1 = cryptoContext.EvalRotate(ciphertext1, 1)
-ciphertextRot2 = cryptoContext.EvalRotate(ciphertext1, 2)
-ciphertextRot3 = cryptoContext.EvalRotate(ciphertext1, -1)
-ciphertextRot4 = cryptoContext.EvalRotate(ciphertext1, -2)
+ciphertext_rot1 = crypto_context.EvalRotate(ciphertext1, 1)
+ciphertext_rot2 = crypto_context.EvalRotate(ciphertext1, 2)
+ciphertext_rot3 = crypto_context.EvalRotate(ciphertext1, -1)
+ciphertext_rot4 = crypto_context.EvalRotate(ciphertext1, -2)
 
 # Sample Program: Step 5: Decryption
 
 # Decrypt the result of additions
-plaintextAddResult = Decrypt(ciphertextAddResult,keypair.secretKey)
+plaintext_add_result = crypto_context.Decrypt(ciphertext_add_result,key_pair.secretKey)
 
 # Decrypt the result of multiplications
-plaintextMultResult = Decrypt(ciphertextMultResult,keypair.secretKey)
+plaintext_mult_result = crypto_context.Decrypt(ciphertext_mult_result,key_pair.secretKey)
 
 # Decrypt the result of rotations
-plaintextRot1 = Decrypt(ciphertextRot1,keypair.secretKey)
-plaintextRot2 = Decrypt(ciphertextRot2,keypair.secretKey)
-plaintextRot3 = Decrypt(ciphertextRot3,keypair.secretKey)
-plaintextRot4 = Decrypt(ciphertextRot4,keypair.secretKey)
+plaintextRot1 = crypto_context.Decrypt(ciphertext_rot1,key_pair.secretKey)
+plaintextRot2 = crypto_context.Decrypt(ciphertext_rot2,key_pair.secretKey)
+plaintextRot3 = crypto_context.Decrypt(ciphertext_rot3,key_pair.secretKey)
+plaintextRot4 = crypto_context.Decrypt(ciphertext_rot4,key_pair.secretKey)
 
 
-plaintextRot1.SetLength(len(vectorOfInts1))
-plaintextRot2.SetLength(len(vectorOfInts1))
-plaintextRot3.SetLength(len(vectorOfInts1))
-plaintextRot4.SetLength(len(vectorOfInts1))
+plaintextRot1.SetLength(len(vector_of_ints1))
+plaintextRot2.SetLength(len(vector_of_ints1))
+plaintextRot3.SetLength(len(vector_of_ints1))
+plaintextRot4.SetLength(len(vector_of_ints1))
 
 print("Plaintext #1: " + str(plaintext1))
 print("Plaintext #2: " + str(plaintext2))
@@ -86,8 +86,8 @@ print("Plaintext #3: " + str(plaintext3))
 
 # Output Results
 print("\nResults of homomorphic computations")
-print("#1 + #2 + #3 = " + str(plaintextAddResult))
-print("#1 * #2 * #3 = " + str(plaintextMultResult))
+print("#1 + #2 + #3 = " + str(plaintext_add_result))
+print("#1 * #2 * #3 = " + str(plaintext_mult_result))
 print("Left rotation of #1 by 1 = " + str(plaintextRot1))
 print("Left rotation of #1 by 2 = " + str(plaintextRot2))
 print("Right rotation of #1 by 1 = " + str(plaintextRot3))

+ 22 - 22
src/pke/examples/simple-real-numbers.py

@@ -1,13 +1,13 @@
 from openfhe import *
 
-multDepth = 1
-scaleModSize = 50
-batchSize = 8
+mult_depth = 1
+scale_mod_size = 50
+batch_size = 8
 
 parameters = CCParamsCKKSRNS()
-parameters.SetMultiplicativeDepth(multDepth)
-parameters.SetScalingModSize(scaleModSize)
-parameters.SetBatchSize(batchSize)
+parameters.SetMultiplicativeDepth(mult_depth)
+parameters.SetScalingModSize(scale_mod_size)
+parameters.SetBatchSize(batch_size)
 
 cc = GenCryptoContext(parameters)
 cc.Enable(PKESchemeFeature.PKE)
@@ -35,20 +35,20 @@ c2 = cc.Encrypt(keys.publicKey, ptx2)
 
 # Step 4: Evaluation
 # Homomorphic additions
-cAdd = cc.EvalAdd(c1, c2)
+c_add = cc.EvalAdd(c1, c2)
 # Homomorphic subtraction
-cSub = cc.EvalSub(c1, c2)
+c_sub = cc.EvalSub(c1, c2)
 # Homomorphic scalar multiplication
-cScalar = cc.EvalMult(c1,4)
+c_scalar = cc.EvalMult(c1,4)
 # Homomorphic multiplication
-cMult = cc.EvalMult(c1, c2)
+c_mult = cc.EvalMult(c1, c2)
 # Homomorphic rotations
-cRot1 = cc.EvalRotate(c1, 1)
-cRot2 = cc.EvalRotate(c1, -2)
+c_rot1 = cc.EvalRotate(c1, 1)
+c_rot2 = cc.EvalRotate(c1, -2)
 
 # Step 5: Decryption and output
 # Decrypt the result of additions
-ptAdd = Decrypt(cAdd,keys.secretKey)
+ptAdd = Decrypt(c_add,keys.secretKey)
 
 # We set the precision to 8 decimal digits for a nicer output.
 # If you want to see the error/noise introduced by CKKS, bump it up
@@ -57,28 +57,28 @@ ptAdd = Decrypt(cAdd,keys.secretKey)
 precision = 8
 print("Results of homomorphic computations:")
 result = Decrypt(c1, keys.secretKey)
-result.SetLength(batchSize)
+result.SetLength(batch_size)
 print("x1 = " + str(result))
 print("Estimated precision in bits: " + str(result.GetLogPrecision()))
 
 # Decrypt the result of scalar multiplication
-result = Decrypt(cScalar,keys.secretKey)
-result.SetLength(batchSize)
+result = Decrypt(c_scalar,keys.secretKey)
+result.SetLength(batch_size)
 print("4 * x1 = " + str(result))
 
 # Decrypt the result of multiplication
-result = Decrypt(cMult,keys.secretKey)
-result.SetLength(batchSize)
+result = Decrypt(c_mult,keys.secretKey)
+result.SetLength(batch_size)
 print("x1 * x2 = " + str(result))
 
 # Decrypt the result of rotations
-result = Decrypt(cRot1,keys.secretKey)
-result.SetLength(batchSize)
+result = Decrypt(c_rot1,keys.secretKey)
+result.SetLength(batch_size)
 print("In rotations, very small outputs (~10^-10 here) correspond to 0's:")
 print("x1 rotated by 1 = " + str(result))
 
-result = Decrypt(cRot2,keys.secretKey)
-result.SetLength(batchSize)
+result = Decrypt(c_rot2,keys.secretKey)
+result.SetLength(batch_size)
 print("x1 rotated by -2 = " + str(result))