Преглед на файлове

Merge pull request #142 from openfheorg/dev

Updates to v0.8.7
yspolyakov преди 2 години
родител
ревизия
2ca3ce6d78

+ 7 - 6
.github/workflows/manual.yml

@@ -28,8 +28,8 @@ on:
     
   workflow_dispatch:
     inputs:
-      # # Selects the compiler to use, this choice will be used in the COMPILERS_MAP as the key to
-      # # retrieve the corresponding cmake compiler options to pass to the action
+      # Selects the compiler to use, this choice will be used in the COMPILERS_MAP as the key to
+      # retrieve the corresponding cmake compiler options to pass to the action
       compiler:
         description: 'Compiler type'
         type: choice
@@ -54,6 +54,9 @@ on:
         required: true
         default: 'main'
 
+# cmake_args_map_openfhe_lib holds job specific additional cmake options. As we are testing openfhe-python here
+# and not openfhe-development, we do not link unittest, benchmarks, etc. for openfhe-development.
+# compiler flags, native_backend flag and OpenMP flag are set in generic_workflow.yml
 jobs:
   call:
     uses: openfheorg/openfhe-python/.github/workflows/generic_workflow.yml@github-ci
@@ -62,10 +65,8 @@ jobs:
       compiler: "${{ inputs.compiler }}"
       native_backend: "${{ inputs.native_backend }}"
       openfhe_development_branch: "${{ inputs.openfhe_development_branch }}"
-      # cmake_args_map holds job specific additional cmake options. compiler flags, native_backend flag and
-      # OpenMP flag are set in generic_workflow.yml
-      cmake_args_map: '{
-                  "default"           : "-DBUILD_EXTRAS=ON",
+      cmake_args_map_openfhe_lib: '{
+                  "default"           : "-DBUILD_BENCHMARKS=OFF -DBUILD_UNITTESTS=OFF -DBUILD_EXAMPLES=OFF",
                 }'
       
 

+ 22 - 0
.readthedocs.yaml

@@ -0,0 +1,22 @@
+# .readthedocs.yaml
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+# Set the version of Python and other tools you might need
+build:
+  os: ubuntu-22.04
+  tools:
+    python: "3.11"
+
+# Build documentation in the docs/ directory with Sphinx
+sphinx:
+  configuration: docs/conf.py
+
+# We recommend specifying your dependencies to enable reproducible builds:
+# https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
+python:
+  install:
+  - requirements: docs/requirements.txt

+ 17 - 2
CMakeLists.txt

@@ -4,7 +4,7 @@ project (OpenFHE-Python)
 
 set(OPENFHE_PYTHON_VERSION_MAJOR 0)
 set(OPENFHE_PYTHON_VERSION_MINOR 8)
-set(OPENFHE_PYTHON_VERSION_PATCH 6)
+set(OPENFHE_PYTHON_VERSION_PATCH 7)
 set(OPENFHE_PYTHON_VERSION ${OPENFHE_PYTHON_VERSION_MAJOR}.${OPENFHE_PYTHON_VERSION_MINOR}.${OPENFHE_PYTHON_VERSION_PATCH})
 
 set(CMAKE_CXX_STANDARD 17)
@@ -69,11 +69,26 @@ else()
     # Set Python_EXECUTABLE to the specified path
     set(Python_EXECUTABLE "${PYTHON_EXECUTABLE_PATH}")
 endif()
+
+# Find Python interpreter
+find_package(PythonInterp REQUIRED)
+
+# Check Python version
+if(${PYTHON_VERSION_MAJOR} EQUAL 3 AND ${PYTHON_VERSION_MINOR} GREATER_EQUAL 10)
+execute_process(
+    COMMAND "${Python_EXECUTABLE}" -c "from sys import exec_prefix; print(exec_prefix)"
+    OUTPUT_VARIABLE PYTHON_SITE_PACKAGES
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+ )       
+else()
 execute_process(
     COMMAND "${Python_EXECUTABLE}" -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"
     OUTPUT_VARIABLE PYTHON_SITE_PACKAGES
     OUTPUT_STRIP_TRAILING_WHITESPACE
-)
+ )    
+endif()
+
+
 
 message(STATUS "Python site packages directory: ${PYTHON_SITE_PACKAGES}")
 install(TARGETS openfhe LIBRARY DESTINATION ${PYTHON_SITE_PACKAGES})

+ 8 - 0
README.md

@@ -91,6 +91,14 @@ which creates a lib folder, moves the built `.so` file into that lib folder, and
 
 **Note** You may wish to copy the `.so` file to any projects of your own, or add it to your system path to source from.
 
+## Running Tests
+
+Run tests with [pytest](https://docs.pytest.org), which may be called `pytest-3` on your system. See the [testing readme](tests/README.md) for more information.
+
+```bash
+pytest [--run-long]
+```
+
 ## Code Examples
 
 To get familiar with the OpenFHE Python API, check out the examples:

+ 24 - 0
docs/cryptoparams.rst

@@ -0,0 +1,24 @@
+CryptoParams
+============
+
+The following crypto parameter objects are available per scheme **BFV**, **BGV** and **CKKS** respectively.
+
+CyrptoParamsBFVRNS
+##################
+.. autoclass:: openfhe.CCParamsBFVRNS
+    :members:
+    :show-inheritance:
+
+CryptoParamsBGVRNS
+##################
+.. autoclass:: openfhe.CCParamsBGVRNS
+    :members:
+    :show-inheritance:
+
+	       
+CryptoParamsCKKSRNS
+###################
+.. autoclass:: openfhe.CCParamsCKKSRNS
+    :members:
+    :show-inheritance:
+

+ 2 - 1
docs/index.rst

@@ -14,10 +14,11 @@ Fully Homomorphic Encryption (FHE) is a powerful cryptographic primitive that en
 while keeping the efficiency of C++ FHE operations.
 
 .. toctree::
-   :maxdepth: 1
+   :maxdepth: 3
    :caption: API Reference:
    
    cryptocontext
+   cryptoparams
    ciphertext
    plaintext
    keys

+ 77 - 67
examples/pke/simple-integers-bgvrns.py

@@ -1,94 +1,104 @@
 # Initial Settings
 from openfhe import *
+import os
+
 # import openfhe.PKESchemeFeature as Feature
 
 
-# Sample Program: Step 1: Set CryptoContext
-parameters = CCParamsBGVRNS()
-parameters.SetPlaintextModulus(65537)
-parameters.SetMultiplicativeDepth(2)
+def main():
+    # Sample Program: Step 1: Set CryptoContext
+    parameters = CCParamsBGVRNS()
+    parameters.SetPlaintextModulus(65537)
+    parameters.SetMultiplicativeDepth(2)
+
+    crypto_context = GenCryptoContext(parameters)
+    # Enable features that you wish to use
+    crypto_context.Enable(PKESchemeFeature.PKE)
+    crypto_context.Enable(PKESchemeFeature.KEYSWITCH)
+    crypto_context.Enable(PKESchemeFeature.LEVELEDSHE)
 
-crypto_context = GenCryptoContext(parameters)
-# Enable features that you wish to use
-crypto_context.Enable(PKESchemeFeature.PKE)
-crypto_context.Enable(PKESchemeFeature.KEYSWITCH)
-crypto_context.Enable(PKESchemeFeature.LEVELEDSHE)
+    # Sample Program: Step 2: Key Generation
 
-# Sample Program: Step 2: Key Generation
+    # Generate a public/private key pair
+    key_pair = crypto_context.KeyGen()
 
-# Generate a public/private key pair
-key_pair = crypto_context.KeyGen()
+    # Generate the relinearization key
+    crypto_context.EvalMultKeyGen(key_pair.secretKey)
 
-# Generate the relinearization key
-crypto_context.EvalMultKeyGen(key_pair.secretKey)
+    # Generate the rotation evaluation keys
+    crypto_context.EvalRotateKeyGen(key_pair.secretKey, [1, 2, -1, -2])
 
-# Generate the rotation evaluation keys
-crypto_context.EvalRotateKeyGen(key_pair.secretKey, [1, 2, -1, -2])
+    # Sample Program: Step 3: Encryption
 
-# Sample Program: Step 3: Encryption
+    # First plaintext vector is encoded
+    vector_of_ints1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+    plaintext1 = crypto_context.MakePackedPlaintext(vector_of_ints1)
 
-# First plaintext vector is encoded
-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
+    vector_of_ints2 = [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+    plaintext2 = crypto_context.MakePackedPlaintext(vector_of_ints2)
 
-# Second plaintext vector is encoded
-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
+    vector_of_ints3 = [1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12]
+    plaintext3 = crypto_context.MakePackedPlaintext(vector_of_ints3)
 
-# Third plaintext vector is encoded
-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 = crypto_context.Encrypt(key_pair.publicKey, plaintext1)
+    ciphertext2 = crypto_context.Encrypt(key_pair.publicKey, plaintext2)
+    ciphertext3 = crypto_context.Encrypt(key_pair.publicKey, plaintext3)
 
-# The encoded vectors are encrypted
-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
 
-#  Sample Program: Step 4: Evaluation
+    # Homomorphic additions
+    ciphertext_add12 = crypto_context.EvalAdd(ciphertext1, ciphertext2)
+    ciphertext_add_result = crypto_context.EvalAdd(ciphertext_add12, ciphertext3)
 
-# Homomorphic additions
-ciphertext_add12 = crypto_context.EvalAdd(ciphertext1, ciphertext2)
-ciphertext_add_result = crypto_context.EvalAdd(ciphertext_add12, ciphertext3)
+    # Homomorphic Multiplication
+    ciphertext_mult12 = crypto_context.EvalMult(ciphertext1, ciphertext2)
+    ciphertext_mult_result = crypto_context.EvalMult(ciphertext_mult12, ciphertext3)
 
-# Homomorphic Multiplication
-ciphertext_mult12 = crypto_context.EvalMult(ciphertext1, ciphertext2)
-ciphertext_mult_result = crypto_context.EvalMult(ciphertext_mult12, ciphertext3)
+    # Homomorphic Rotations
+    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)
 
-# Homomorphic Rotations
-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
 
-# Sample Program: Step 5: Decryption
+    # Decrypt the result of additions
+    plaintext_add_result = crypto_context.Decrypt(
+        ciphertext_add_result, key_pair.secretKey
+    )
 
-# Decrypt the result of additions
-plaintext_add_result = crypto_context.Decrypt(ciphertext_add_result,key_pair.secretKey)
+    # Decrypt the result of multiplications
+    plaintext_mult_result = crypto_context.Decrypt(
+        ciphertext_mult_result, key_pair.secretKey
+    )
 
-# Decrypt the result of multiplications
-plaintext_mult_result = crypto_context.Decrypt(ciphertext_mult_result,key_pair.secretKey)
+    # Decrypt the result of rotations
+    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)
 
-# Decrypt the result of rotations
-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(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))
+    print("Plaintext #3: " + str(plaintext3))
 
-plaintextRot1.SetLength(len(vector_of_ints1))
-plaintextRot2.SetLength(len(vector_of_ints1))
-plaintextRot3.SetLength(len(vector_of_ints1))
-plaintextRot4.SetLength(len(vector_of_ints1))
+    # Output Results
+    print("\nResults of homomorphic computations")
+    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))
+    print("Right rotation of #1 by 2 = " + str(plaintextRot4))
 
-print("Plaintext #1: " + str(plaintext1))
-print("Plaintext #2: " + str(plaintext2))
-print("Plaintext #3: " + str(plaintext3))
 
-# Output Results
-print("\nResults of homomorphic computations")
-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))
-print("Right rotation of #1 by 2 = " + str(plaintextRot4))
+if __name__ == "__main__":
+    main()

+ 221 - 180
examples/pke/simple-integers-serial-bgvrns.py

@@ -1,193 +1,234 @@
 # Initial Settings
 from openfhe import *
-# import openfhe.PKESchemeFeature as Feature
-
-datafolder = 'demoData'
-serType = BINARY # BINARY or JSON 
-print("This program requres the subdirectory `" + datafolder + "' to exist, otherwise you will get an error writing serializations.")
-
-# Sample Program: Step 1: Set CryptoContext
-parameters = CCParamsBGVRNS()
-parameters.SetPlaintextModulus(65537)
-parameters.SetMultiplicativeDepth(2)
-
-cryptoContext = GenCryptoContext(parameters)
-# Enable features that you wish to use
-cryptoContext.Enable(PKESchemeFeature.PKE)
-cryptoContext.Enable(PKESchemeFeature.KEYSWITCH)
-cryptoContext.Enable(PKESchemeFeature.LEVELEDSHE)
-
-# Serialize cryptocontext
-if not SerializeToFile(datafolder + "/cryptocontext.txt", cryptoContext, serType):
-   raise Exception("Error writing serialization of the crypto context to cryptocontext.txt")
-print("The cryptocontext has been serialized.")
-
-# Sample Program: Step 2: Key Generation
-
-# Generate a public/private key pair
-keypair = cryptoContext.KeyGen()
-print("The keypair has been generated.")
-
-# Serialize the public key
-if not SerializeToFile(datafolder + "/key-public.txt", keypair.publicKey, serType):
-   raise Exception("Error writing serialization of the public key to key-public.txt")
-print("The public key has been serialized.")
-
-# Serialize the secret key
-if not SerializeToFile(datafolder + "/key-private.txt", keypair.secretKey, serType):
-   raise Exception("Error writing serialization of the secret key to key-private.txt")
-print("The secret key has been serialized.")
-
-# Generate the relinearization key
-cryptoContext.EvalMultKeyGen(keypair.secretKey)
-print("The relinearization key has been generated.")
-
-# Serialize the relinearization key
-if not cryptoContext.SerializeEvalMultKey(datafolder + "/key-eval-mult.txt",serType):
-   raise Exception("Error writing serialization of the eval mult keys to \"key-eval-mult.txt\"")
-print("The relinearization key has been serialized.")
-
-# Generate the rotation evaluation keys
-cryptoContext.EvalRotateKeyGen(keypair.secretKey, [1, 2, -1, -2])
-print("The rotation evaluation keys have been generated.")
-
-# Serialize the rotation evaluation keys
-if not cryptoContext.SerializeEvalAutomorphismKey(datafolder + "/key-eval-rot.txt",serType):
-   raise Exception("Error writing serialization of the eval rotate keys to \"key-eval-rot.txt\"")
-print("The rotation evaluation keys have been serialized.")
-
-# 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)
-
-# Second plaintext vector is encoded
-vectorOfInts2 = [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12]
-plaintext2 = cryptoContext.MakePackedPlaintext(vectorOfInts2)
-
-# Third plaintext vector is encoded
-vectorOfInts3 = [1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12]
-plaintext3 = cryptoContext.MakePackedPlaintext(vectorOfInts3)
-
-
-# The encoded vectors are encrypted
-ciphertext1 = cryptoContext.Encrypt(keypair.publicKey, plaintext1)
-ciphertext2 = cryptoContext.Encrypt(keypair.publicKey, plaintext2)
-ciphertext3 = cryptoContext.Encrypt(keypair.publicKey, plaintext3)
-print("The plaintexts have been encrypted.")
+import tempfile
+import os
 
-if not SerializeToFile(datafolder + "/ciphertext1.txt", ciphertext1, serType):
-   raise Exception("Error writing serialization of ciphertext 1 to ciphertext1.txt")
-print("The first ciphertext has been serialized.")
-
-if not SerializeToFile(datafolder + "/ciphertext2.txt", ciphertext2, serType):
-   raise Exception("Error writing serialization of ciphertext2 to ciphertext2.txt")
-print("The second ciphertext has been serialized.")
-
-if not SerializeToFile(datafolder + "/ciphertext3.txt", ciphertext3, serType):   
-   raise Exception("Error writing serialization of ciphertext3 to ciphertext3.txt")
-print("The third ciphertext has been serialized.")
-
-# Sample Program: Step 4: Evaluation
-
-# OpenFHE maintains an internal map of CryptoContext objects which are
-# indexed by a tag and the tag is applied to both the CryptoContext and some
-# of the keys. When deserializing a context, OpenFHE checks for the tag and
-# if it finds it in the CryptoContext map, it will return the stored version.
-# Hence, we need to clear the context and clear the keys.
-cryptoContext.ClearEvalMultKeys()
-cryptoContext.ClearEvalAutomorphismKeys()
-ReleaseAllContexts()
-
-# Deserialize the crypto context
-
-cc, res = DeserializeCryptoContext(datafolder + "/cryptocontext.txt", serType)
-if not res:
-   raise Exception("Error reading serialization of the crypto context from cryptocontext.txt")
-print("The cryptocontext has been deserialized.")
-
-# Deserialize the public key
-pk, res = DeserializePublicKey(datafolder + "/key-public.txt", serType)
-
-if not res:
-   raise Exception("Error reading serialization of the public key from key-public.txt")
-print("The public key has been deserialized.")
-
-if not cc.DeserializeEvalMultKey(datafolder + "/key-eval-mult.txt",serType):
-   raise Exception("Could not deserialize the eval mult key file")
-
-print("The relinearization key has been deserialized.")
-
-if not cc.DeserializeEvalAutomorphismKey(datafolder + "/key-eval-rot.txt",serType):
-   raise Exception("Could not deserialize the eval rotation key file")
-
-print("Deserialized the eval rotation keys.")
-
-# Deserialize the ciphertexts
-ct1, res =  DeserializeCiphertext(datafolder + "/ciphertext1.txt", serType)
-
-if not res:
-    raise Exception("Could not read the ciphertext")
-print("The first ciphertext has been deserialized.")
-
-ct2, res = DeserializeCiphertext(datafolder + "/ciphertext2.txt", serType)
-
-if not res:
-    raise Exception("Could not read the ciphertext")
-print("The second ciphertext has been deserialized.")
-
-ct3, res = DeserializeCiphertext(datafolder + "/ciphertext3.txt", serType)
-if not res:   
-    raise Exception("Could not read the ciphertext")
-print("The third ciphertext has been deserialized.")
-
-# Homomorphic addition
+# import openfhe.PKESchemeFeature as Feature
 
-ciphertextAdd12 = cc.EvalAdd(ct1, ct2)
-ciphertextAddResult = cc.EvalAdd(ciphertextAdd12, ct3)
+datafolder = "demoData"
+
+
+def main_action():
+    serType = BINARY  # BINARY or JSON
+    print(
+        "This program requres the subdirectory `"
+        + datafolder
+        + "' to exist, otherwise you will get an error writing serializations."
+    )
+
+    # Sample Program: Step 1: Set CryptoContext
+    parameters = CCParamsBGVRNS()
+    parameters.SetPlaintextModulus(65537)
+    parameters.SetMultiplicativeDepth(2)
+
+    cryptoContext = GenCryptoContext(parameters)
+    # Enable features that you wish to use
+    cryptoContext.Enable(PKESchemeFeature.PKE)
+    cryptoContext.Enable(PKESchemeFeature.KEYSWITCH)
+    cryptoContext.Enable(PKESchemeFeature.LEVELEDSHE)
+
+    # Serialize cryptocontext
+    if not SerializeToFile(datafolder + "/cryptocontext.txt", cryptoContext, serType):
+        raise Exception(
+            "Error writing serialization of the crypto context to cryptocontext.txt"
+        )
+    print("The cryptocontext has been serialized.")
+
+    # Sample Program: Step 2: Key Generation
+
+    # Generate a public/private key pair
+    keypair = cryptoContext.KeyGen()
+    print("The keypair has been generated.")
+
+    # Serialize the public key
+    if not SerializeToFile(datafolder + "/key-public.txt", keypair.publicKey, serType):
+        raise Exception(
+            "Error writing serialization of the public key to key-public.txt"
+        )
+    print("The public key has been serialized.")
+
+    # Serialize the secret key
+    if not SerializeToFile(datafolder + "/key-private.txt", keypair.secretKey, serType):
+        raise Exception(
+            "Error writing serialization of the secret key to key-private.txt"
+        )
+    print("The secret key has been serialized.")
+
+    # Generate the relinearization key
+    cryptoContext.EvalMultKeyGen(keypair.secretKey)
+    print("The relinearization key has been generated.")
+
+    # Serialize the relinearization key
+    if not cryptoContext.SerializeEvalMultKey(
+        datafolder + "/key-eval-mult.txt", serType
+    ):
+        raise Exception(
+            'Error writing serialization of the eval mult keys to "key-eval-mult.txt"'
+        )
+    print("The relinearization key has been serialized.")
+
+    # Generate the rotation evaluation keys
+    cryptoContext.EvalRotateKeyGen(keypair.secretKey, [1, 2, -1, -2])
+    print("The rotation evaluation keys have been generated.")
+
+    # Serialize the rotation evaluation keys
+    if not cryptoContext.SerializeEvalAutomorphismKey(
+        datafolder + "/key-eval-rot.txt", serType
+    ):
+        raise Exception(
+            'Error writing serialization of the eval rotate keys to "key-eval-rot.txt"'
+        )
+    print("The rotation evaluation keys have been serialized.")
+
+    # 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)
+
+    # Second plaintext vector is encoded
+    vectorOfInts2 = [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+    plaintext2 = cryptoContext.MakePackedPlaintext(vectorOfInts2)
+
+    # Third plaintext vector is encoded
+    vectorOfInts3 = [1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12]
+    plaintext3 = cryptoContext.MakePackedPlaintext(vectorOfInts3)
+
+    # The encoded vectors are encrypted
+    ciphertext1 = cryptoContext.Encrypt(keypair.publicKey, plaintext1)
+    ciphertext2 = cryptoContext.Encrypt(keypair.publicKey, plaintext2)
+    ciphertext3 = cryptoContext.Encrypt(keypair.publicKey, plaintext3)
+    print("The plaintexts have been encrypted.")
+
+    if not SerializeToFile(datafolder + "/ciphertext1.txt", ciphertext1, serType):
+        raise Exception(
+            "Error writing serialization of ciphertext 1 to ciphertext1.txt"
+        )
+    print("The first ciphertext has been serialized.")
+
+    if not SerializeToFile(datafolder + "/ciphertext2.txt", ciphertext2, serType):
+        raise Exception("Error writing serialization of ciphertext2 to ciphertext2.txt")
+    print("The second ciphertext has been serialized.")
+
+    if not SerializeToFile(datafolder + "/ciphertext3.txt", ciphertext3, serType):
+        raise Exception("Error writing serialization of ciphertext3 to ciphertext3.txt")
+    print("The third ciphertext has been serialized.")
+
+    # Sample Program: Step 4: Evaluation
+
+    # OpenFHE maintains an internal map of CryptoContext objects which are
+    # indexed by a tag and the tag is applied to both the CryptoContext and some
+    # of the keys. When deserializing a context, OpenFHE checks for the tag and
+    # if it finds it in the CryptoContext map, it will return the stored version.
+    # Hence, we need to clear the context and clear the keys.
+    cryptoContext.ClearEvalMultKeys()
+    cryptoContext.ClearEvalAutomorphismKeys()
+    ReleaseAllContexts()
+
+    # Deserialize the crypto context
+
+    cc, res = DeserializeCryptoContext(datafolder + "/cryptocontext.txt", serType)
+    if not res:
+        raise Exception(
+            "Error reading serialization of the crypto context from cryptocontext.txt"
+        )
+    print("The cryptocontext has been deserialized.")
+
+    # Deserialize the public key
+    pk, res = DeserializePublicKey(datafolder + "/key-public.txt", serType)
+
+    if not res:
+        raise Exception(
+            "Error reading serialization of the public key from key-public.txt"
+        )
+    print("The public key has been deserialized.")
+
+    if not cc.DeserializeEvalMultKey(datafolder + "/key-eval-mult.txt", serType):
+        raise Exception("Could not deserialize the eval mult key file")
+
+    print("The relinearization key has been deserialized.")
+
+    if not cc.DeserializeEvalAutomorphismKey(datafolder + "/key-eval-rot.txt", serType):
+        raise Exception("Could not deserialize the eval rotation key file")
+
+    print("Deserialized the eval rotation keys.")
+
+    # Deserialize the ciphertexts
+    ct1, res = DeserializeCiphertext(datafolder + "/ciphertext1.txt", serType)
+
+    if not res:
+        raise Exception("Could not read the ciphertext")
+    print("The first ciphertext has been deserialized.")
+
+    ct2, res = DeserializeCiphertext(datafolder + "/ciphertext2.txt", serType)
+
+    if not res:
+        raise Exception("Could not read the ciphertext")
+    print("The second ciphertext has been deserialized.")
+
+    ct3, res = DeserializeCiphertext(datafolder + "/ciphertext3.txt", serType)
+    if not res:
+        raise Exception("Could not read the ciphertext")
+    print("The third ciphertext has been deserialized.")
+
+    # Homomorphic addition
+
+    ciphertextAdd12 = cc.EvalAdd(ct1, ct2)
+    ciphertextAddResult = cc.EvalAdd(ciphertextAdd12, ct3)
+
+    # Homomorphic multiplication
+    ciphertextMult12 = cc.EvalMult(ct1, ct2)
+    ciphertextMultResult = cc.EvalMult(ciphertextMult12, ct3)
 
-# Homomorphic multiplication
-ciphertextMult12 = cc.EvalMult(ct1, ct2)
-ciphertextMultResult = cc.EvalMult(ciphertextMult12, ct3)
+    # Homomorphic rotation
+    ciphertextRot1 = cc.EvalRotate(ct1, 1)
+    ciphertextRot2 = cc.EvalRotate(ct2, 2)
+    ciphertextRot3 = cc.EvalRotate(ct3, -1)
+    ciphertextRot4 = cc.EvalRotate(ct3, -2)
 
-# Homomorphic rotation
-ciphertextRot1 = cc.EvalRotate(ct1, 1)
-ciphertextRot2 = cc.EvalRotate(ct2, 2)
-ciphertextRot3 = cc.EvalRotate(ct3, -1)
-ciphertextRot4 = cc.EvalRotate(ct3, -2)
+    # Sample Program: Step 5: Decryption
+
+    sk, res = DeserializePrivateKey(datafolder + "/key-private.txt", serType)
+    if not res:
+        raise Exception("Could not read secret key")
+    print("The secret key has been deserialized.")
+
+    # Decrypt the result of additions
+    plaintextAddResult = cc.Decrypt(sk, ciphertextAddResult)
+
+    # Decrypt the result of multiplications
+    plaintextMultResult = cc.Decrypt(sk, ciphertextMultResult)
 
-# Sample Program: Step 5: Decryption
+    # Decrypt the result of rotations
+    plaintextRot1 = cc.Decrypt(sk, ciphertextRot1)
+    plaintextRot2 = cc.Decrypt(sk, ciphertextRot2)
+    plaintextRot3 = cc.Decrypt(sk, ciphertextRot3)
+    plaintextRot4 = cc.Decrypt(sk, ciphertextRot4)
 
-sk, res = DeserializePrivateKey(datafolder + "/key-private.txt", serType)
-if not res:
-      raise Exception("Could not read secret key")
-print("The secret key has been deserialized.")
+    # Shows only the same number of elements as in the original plaintext vector
+    # By default it will show all coefficients in the BFV-encoded polynomial
+    plaintextRot1.SetLength(len(vectorOfInts1))
+    plaintextRot2.SetLength(len(vectorOfInts1))
+    plaintextRot3.SetLength(len(vectorOfInts1))
+    plaintextRot4.SetLength(len(vectorOfInts1))
 
-# Decrypt the result of additions
-plaintextAddResult = cc.Decrypt(sk, ciphertextAddResult)
+    # Output results
+    print("\nResults of homomorphic computations")
+    print("#1 + #2 + #3: " + str(plaintextAddResult))
+    print("#1 * #2 * #3: " + str(plaintextMultResult))
+    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))
+    print("Right rotation of #1 by 2: " + str(plaintextRot4))
 
-# Decrypt the result of multiplications
-plaintextMultResult = cc.Decrypt(sk, ciphertextMultResult)
 
-# Decrypt the result of rotations
-plaintextRot1 = cc.Decrypt(sk, ciphertextRot1)
-plaintextRot2 = cc.Decrypt(sk, ciphertextRot2)
-plaintextRot3 = cc.Decrypt(sk, ciphertextRot3)
-plaintextRot4 = cc.Decrypt(sk, ciphertextRot4)
+def main():
+    global datafolder
+    with tempfile.TemporaryDirectory() as td:
+        datafolder = td + "/" + datafolder
+        os.mkdir(datafolder)
+        main_action()
 
-# Shows only the same number of elements as in the original plaintext vector
-# By default it will show all coefficients in the BFV-encoded polynomial
-plaintextRot1.SetLength(len(vectorOfInts1))
-plaintextRot2.SetLength(len(vectorOfInts1))
-plaintextRot3.SetLength(len(vectorOfInts1))
-plaintextRot4.SetLength(len(vectorOfInts1))
 
-# Output results
-print("\nResults of homomorphic computations")
-print("#1 + #2 + #3: " + str(plaintextAddResult))
-print("#1 * #2 * #3: " + str(plaintextMultResult))
-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))
-print("Right rotation of #1 by 2: " + str(plaintextRot4))
+if __name__ == "__main__":
+    main()

+ 222 - 181
examples/pke/simple-integers-serial.py

@@ -1,193 +1,234 @@
 # Initial Settings
 from openfhe import *
-# import openfhe.PKESchemeFeature as Feature
-
-datafolder = 'demoData'
-serType = BINARY # BINARY or JSON 
-print("This program requres the subdirectory `" + datafolder + "' to exist, otherwise you will get an error writing serializations.")
-
-# Sample Program: Step 1: Set CryptoContext
-parameters = CCParamsBFVRNS()
-parameters.SetPlaintextModulus(65537)
-parameters.SetMultiplicativeDepth(2)
-
-cryptoContext = GenCryptoContext(parameters)
-# Enable features that you wish to use
-cryptoContext.Enable(PKESchemeFeature.PKE)
-cryptoContext.Enable(PKESchemeFeature.KEYSWITCH)
-cryptoContext.Enable(PKESchemeFeature.LEVELEDSHE)
-
-# Serialize cryptocontext
-if not SerializeToFile(datafolder + "/cryptocontext.txt", cryptoContext, serType):
-   raise Exception("Error writing serialization of the crypto context to cryptocontext.txt")
-print("The cryptocontext has been serialized.")
-
-# Sample Program: Step 2: Key Generation
-
-# Generate a public/private key pair
-keypair = cryptoContext.KeyGen()
-print("The keypair has been generated.")
-
-# Serialize the public key
-if not SerializeToFile(datafolder + "/key-public.txt", keypair.publicKey, serType):
-   raise Exception("Error writing serialization of the public key to key-public.txt")
-print("The public key has been serialized.")
-
-# Serialize the secret key
-if not SerializeToFile(datafolder + "/key-private.txt", keypair.secretKey, serType):
-   raise Exception("Error writing serialization of the secret key to key-private.txt")
-print("The secret key has been serialized.")
-
-# Generate the relinearization key
-cryptoContext.EvalMultKeyGen(keypair.secretKey)
-print("The relinearization key has been generated.")
-
-# Serialize the relinearization key
-if not cryptoContext.SerializeEvalMultKey(datafolder + "/key-eval-mult.txt",serType):
-   raise Exception("Error writing serialization of the eval mult keys to \"key-eval-mult.txt\"")
-print("The relinearization key has been serialized.")
-
-# Generate the rotation evaluation keys
-cryptoContext.EvalRotateKeyGen(keypair.secretKey, [1, 2, -1, -2])
-print("The rotation evaluation keys have been generated.")
-
-# Serialize the rotation evaluation keys
-if not cryptoContext.SerializeEvalAutomorphismKey(datafolder + "/key-eval-rot.txt",serType):
-   raise Exception("Error writing serialization of the eval rotate keys to \"key-eval-rot.txt\"")
-print("The rotation evaluation keys have been serialized.")
-
-# 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)
-
-# Second plaintext vector is encoded
-vectorOfInts2 = [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12]
-plaintext2 = cryptoContext.MakePackedPlaintext(vectorOfInts2)
-
-# Third plaintext vector is encoded
-vectorOfInts3 = [1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12]
-plaintext3 = cryptoContext.MakePackedPlaintext(vectorOfInts3)
-
-
-# The encoded vectors are encrypted
-ciphertext1 = cryptoContext.Encrypt(keypair.publicKey, plaintext1)
-ciphertext2 = cryptoContext.Encrypt(keypair.publicKey, plaintext2)
-ciphertext3 = cryptoContext.Encrypt(keypair.publicKey, plaintext3)
-print("The plaintexts have been encrypted.")
-
-if not SerializeToFile(datafolder + "/ciphertext1.txt", ciphertext1, serType):
-   raise Exception("Error writing serialization of ciphertext 1 to ciphertext1.txt")
-print("The first ciphertext has been serialized.")
 
-if not SerializeToFile(datafolder + "/ciphertext2.txt", ciphertext2, serType):
-   raise Exception("Error writing serialization of ciphertext2 to ciphertext2.txt")
-print("The second ciphertext has been serialized.")
-
-if not SerializeToFile(datafolder + "/ciphertext3.txt", ciphertext3, serType):   
-   raise Exception("Error writing serialization of ciphertext3 to ciphertext3.txt")
-print("The third ciphertext has been serialized.")
-
-# Sample Program: Step 4: Evaluation
-
-# OpenFHE maintains an internal map of CryptoContext objects which are
-# indexed by a tag and the tag is applied to both the CryptoContext and some
-# of the keys. When deserializing a context, OpenFHE checks for the tag and
-# if it finds it in the CryptoContext map, it will return the stored version.
-# Hence, we need to clear the context and clear the keys.
-cryptoContext.ClearEvalMultKeys()
-cryptoContext.ClearEvalAutomorphismKeys()
-ReleaseAllContexts()
-
-# Deserialize the crypto context
-
-cc, res = DeserializeCryptoContext(datafolder + "/cryptocontext.txt", serType)
-if not res:
-   raise Exception("Error reading serialization of the crypto context from cryptocontext.txt")
-print("The cryptocontext has been deserialized.")
-
-# Deserialize the public key
-pk, res = DeserializePublicKey(datafolder + "/key-public.txt", serType)
-
-if not res:
-   raise Exception("Error reading serialization of the public key from key-public.txt")
-print("The public key has been deserialized.")
-
-if not cc.DeserializeEvalMultKey(datafolder + "/key-eval-mult.txt",serType):
-   raise Exception("Could not deserialize the eval mult key file")
-
-print("The relinearization key has been deserialized.")
-
-if not cc.DeserializeEvalAutomorphismKey(datafolder + "/key-eval-rot.txt",serType):
-   raise Exception("Could not deserialize the eval rotation key file")
-
-print("Deserialized the eval rotation keys.")
-
-# Deserialize the ciphertexts
-ct1, res =  DeserializeCiphertext(datafolder + "/ciphertext1.txt", serType)
-
-if not res:
-    raise Exception("Could not read the ciphertext")
-print("The first ciphertext has been deserialized.")
-
-ct2, res = DeserializeCiphertext(datafolder + "/ciphertext2.txt", serType)
-
-if not res:
-    raise Exception("Could not read the ciphertext")
-print("The second ciphertext has been deserialized.")
-
-ct3, res = DeserializeCiphertext(datafolder + "/ciphertext3.txt", serType)
-if not res:   
-    raise Exception("Could not read the ciphertext")
-print("The third ciphertext has been deserialized.")
-
-# Homomorphic addition
-
-ciphertextAdd12 = cc.EvalAdd(ct1, ct2)
-ciphertextAddResult = cc.EvalAdd(ciphertextAdd12, ct3)
+# import openfhe.PKESchemeFeature as Feature
+import tempfile
+import os
+
+datafolder = "demoData"
+
+
+def main_action():
+    serType = BINARY  # BINARY or JSON
+    print(
+        "This program requres the subdirectory `"
+        + datafolder
+        + "' to exist, otherwise you will get an error writing serializations."
+    )
+
+    # Sample Program: Step 1: Set CryptoContext
+    parameters = CCParamsBFVRNS()
+    parameters.SetPlaintextModulus(65537)
+    parameters.SetMultiplicativeDepth(2)
+
+    cryptoContext = GenCryptoContext(parameters)
+    # Enable features that you wish to use
+    cryptoContext.Enable(PKESchemeFeature.PKE)
+    cryptoContext.Enable(PKESchemeFeature.KEYSWITCH)
+    cryptoContext.Enable(PKESchemeFeature.LEVELEDSHE)
+
+    # Serialize cryptocontext
+    if not SerializeToFile(datafolder + "/cryptocontext.txt", cryptoContext, serType):
+        raise Exception(
+            "Error writing serialization of the crypto context to cryptocontext.txt"
+        )
+    print("The cryptocontext has been serialized.")
+
+    # Sample Program: Step 2: Key Generation
+
+    # Generate a public/private key pair
+    keypair = cryptoContext.KeyGen()
+    print("The keypair has been generated.")
+
+    # Serialize the public key
+    if not SerializeToFile(datafolder + "/key-public.txt", keypair.publicKey, serType):
+        raise Exception(
+            "Error writing serialization of the public key to key-public.txt"
+        )
+    print("The public key has been serialized.")
+
+    # Serialize the secret key
+    if not SerializeToFile(datafolder + "/key-private.txt", keypair.secretKey, serType):
+        raise Exception(
+            "Error writing serialization of the secret key to key-private.txt"
+        )
+    print("The secret key has been serialized.")
+
+    # Generate the relinearization key
+    cryptoContext.EvalMultKeyGen(keypair.secretKey)
+    print("The relinearization key has been generated.")
+
+    # Serialize the relinearization key
+    if not cryptoContext.SerializeEvalMultKey(
+        datafolder + "/key-eval-mult.txt", serType
+    ):
+        raise Exception(
+            'Error writing serialization of the eval mult keys to "key-eval-mult.txt"'
+        )
+    print("The relinearization key has been serialized.")
+
+    # Generate the rotation evaluation keys
+    cryptoContext.EvalRotateKeyGen(keypair.secretKey, [1, 2, -1, -2])
+    print("The rotation evaluation keys have been generated.")
+
+    # Serialize the rotation evaluation keys
+    if not cryptoContext.SerializeEvalAutomorphismKey(
+        datafolder + "/key-eval-rot.txt", serType
+    ):
+        raise Exception(
+            'Error writing serialization of the eval rotate keys to "key-eval-rot.txt"'
+        )
+    print("The rotation evaluation keys have been serialized.")
+
+    # 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)
+
+    # Second plaintext vector is encoded
+    vectorOfInts2 = [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+    plaintext2 = cryptoContext.MakePackedPlaintext(vectorOfInts2)
+
+    # Third plaintext vector is encoded
+    vectorOfInts3 = [1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12]
+    plaintext3 = cryptoContext.MakePackedPlaintext(vectorOfInts3)
+
+    # The encoded vectors are encrypted
+    ciphertext1 = cryptoContext.Encrypt(keypair.publicKey, plaintext1)
+    ciphertext2 = cryptoContext.Encrypt(keypair.publicKey, plaintext2)
+    ciphertext3 = cryptoContext.Encrypt(keypair.publicKey, plaintext3)
+    print("The plaintexts have been encrypted.")
+
+    if not SerializeToFile(datafolder + "/ciphertext1.txt", ciphertext1, serType):
+        raise Exception(
+            "Error writing serialization of ciphertext 1 to ciphertext1.txt"
+        )
+    print("The first ciphertext has been serialized.")
+
+    if not SerializeToFile(datafolder + "/ciphertext2.txt", ciphertext2, serType):
+        raise Exception("Error writing serialization of ciphertext2 to ciphertext2.txt")
+    print("The second ciphertext has been serialized.")
+
+    if not SerializeToFile(datafolder + "/ciphertext3.txt", ciphertext3, serType):
+        raise Exception("Error writing serialization of ciphertext3 to ciphertext3.txt")
+    print("The third ciphertext has been serialized.")
+
+    # Sample Program: Step 4: Evaluation
+
+    # OpenFHE maintains an internal map of CryptoContext objects which are
+    # indexed by a tag and the tag is applied to both the CryptoContext and some
+    # of the keys. When deserializing a context, OpenFHE checks for the tag and
+    # if it finds it in the CryptoContext map, it will return the stored version.
+    # Hence, we need to clear the context and clear the keys.
+    cryptoContext.ClearEvalMultKeys()
+    cryptoContext.ClearEvalAutomorphismKeys()
+    ReleaseAllContexts()
+
+    # Deserialize the crypto context
+
+    cc, res = DeserializeCryptoContext(datafolder + "/cryptocontext.txt", serType)
+    if not res:
+        raise Exception(
+            "Error reading serialization of the crypto context from cryptocontext.txt"
+        )
+    print("The cryptocontext has been deserialized.")
+
+    # Deserialize the public key
+    pk, res = DeserializePublicKey(datafolder + "/key-public.txt", serType)
+
+    if not res:
+        raise Exception(
+            "Error reading serialization of the public key from key-public.txt"
+        )
+    print("The public key has been deserialized.")
+
+    if not cc.DeserializeEvalMultKey(datafolder + "/key-eval-mult.txt", serType):
+        raise Exception("Could not deserialize the eval mult key file")
+
+    print("The relinearization key has been deserialized.")
+
+    if not cc.DeserializeEvalAutomorphismKey(datafolder + "/key-eval-rot.txt", serType):
+        raise Exception("Could not deserialize the eval rotation key file")
+
+    print("Deserialized the eval rotation keys.")
+
+    # Deserialize the ciphertexts
+    ct1, res = DeserializeCiphertext(datafolder + "/ciphertext1.txt", serType)
+
+    if not res:
+        raise Exception("Could not read the ciphertext")
+    print("The first ciphertext has been deserialized.")
+
+    ct2, res = DeserializeCiphertext(datafolder + "/ciphertext2.txt", serType)
+
+    if not res:
+        raise Exception("Could not read the ciphertext")
+    print("The second ciphertext has been deserialized.")
+
+    ct3, res = DeserializeCiphertext(datafolder + "/ciphertext3.txt", serType)
+    if not res:
+        raise Exception("Could not read the ciphertext")
+    print("The third ciphertext has been deserialized.")
+
+    # Homomorphic addition
+
+    ciphertextAdd12 = cc.EvalAdd(ct1, ct2)
+    ciphertextAddResult = cc.EvalAdd(ciphertextAdd12, ct3)
+
+    # Homomorphic multiplication
+    ciphertextMult12 = cc.EvalMult(ct1, ct2)
+    ciphertextMultResult = cc.EvalMult(ciphertextMult12, ct3)
 
-# Homomorphic multiplication
-ciphertextMult12 = cc.EvalMult(ct1, ct2)
-ciphertextMultResult = cc.EvalMult(ciphertextMult12, ct3)
+    # Homomorphic rotation
+    ciphertextRot1 = cc.EvalRotate(ct1, 1)
+    ciphertextRot2 = cc.EvalRotate(ct2, 2)
+    ciphertextRot3 = cc.EvalRotate(ct3, -1)
+    ciphertextRot4 = cc.EvalRotate(ct3, -2)
 
-# Homomorphic rotation
-ciphertextRot1 = cc.EvalRotate(ct1, 1)
-ciphertextRot2 = cc.EvalRotate(ct2, 2)
-ciphertextRot3 = cc.EvalRotate(ct3, -1)
-ciphertextRot4 = cc.EvalRotate(ct3, -2)
+    # Sample Program: Step 5: Decryption
+
+    sk, res = DeserializePrivateKey(datafolder + "/key-private.txt", serType)
+    if not res:
+        raise Exception("Could not read secret key")
+    print("The secret key has been deserialized.")
+
+    # Decrypt the result of additions
+    plaintextAddResult = cc.Decrypt(sk, ciphertextAddResult)
+
+    # Decrypt the result of multiplications
+    plaintextMultResult = cc.Decrypt(sk, ciphertextMultResult)
 
-# Sample Program: Step 5: Decryption
+    # Decrypt the result of rotations
+    plaintextRot1 = cc.Decrypt(sk, ciphertextRot1)
+    plaintextRot2 = cc.Decrypt(sk, ciphertextRot2)
+    plaintextRot3 = cc.Decrypt(sk, ciphertextRot3)
+    plaintextRot4 = cc.Decrypt(sk, ciphertextRot4)
 
-sk, res = DeserializePrivateKey(datafolder + "/key-private.txt", serType)
-if not res:
-      raise Exception("Could not read secret key")
-print("The secret key has been deserialized.")
+    # Shows only the same number of elements as in the original plaintext vector
+    # By default it will show all coefficients in the BFV-encoded polynomial
+    plaintextRot1.SetLength(len(vectorOfInts1))
+    plaintextRot2.SetLength(len(vectorOfInts1))
+    plaintextRot3.SetLength(len(vectorOfInts1))
+    plaintextRot4.SetLength(len(vectorOfInts1))
 
-# Decrypt the result of additions
-plaintextAddResult = cc.Decrypt(sk, ciphertextAddResult)
+    # Output results
+    print("\nResults of homomorphic computations")
+    print("#1 + #2 + #3: " + str(plaintextAddResult))
+    print("#1 * #2 * #3: " + str(plaintextMultResult))
+    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))
+    print("Right rotation of #1 by 2: " + str(plaintextRot4))
 
-# Decrypt the result of multiplications
-plaintextMultResult = cc.Decrypt(sk, ciphertextMultResult)
 
-# Decrypt the result of rotations
-plaintextRot1 = cc.Decrypt(sk, ciphertextRot1)
-plaintextRot2 = cc.Decrypt(sk, ciphertextRot2)
-plaintextRot3 = cc.Decrypt(sk, ciphertextRot3)
-plaintextRot4 = cc.Decrypt(sk, ciphertextRot4)
+def main():
+    global datafolder
+    with tempfile.TemporaryDirectory() as td:
+        datafolder = td + "/" + datafolder
+        os.mkdir(datafolder)
+        main_action()
 
-# Shows only the same number of elements as in the original plaintext vector
-# By default it will show all coefficients in the BFV-encoded polynomial
-plaintextRot1.SetLength(len(vectorOfInts1))
-plaintextRot2.SetLength(len(vectorOfInts1))
-plaintextRot3.SetLength(len(vectorOfInts1))
-plaintextRot4.SetLength(len(vectorOfInts1))
 
-# Output results
-print("\nResults of homomorphic computations")
-print("#1 + #2 + #3: " + str(plaintextAddResult))
-print("#1 * #2 * #3: " + str(plaintextMultResult))
-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))
-print("Right rotation of #1 by 2: " + str(plaintextRot4))
+if __name__ == "__main__":
+    main()

+ 76 - 67
examples/pke/simple-integers.py

@@ -1,94 +1,103 @@
 # Initial Settings
 from openfhe import *
+
 # import openfhe.PKESchemeFeature as Feature
 
 
-# Sample Program: Step 1: Set CryptoContext
-parameters = CCParamsBFVRNS()
-parameters.SetPlaintextModulus(65537)
-parameters.SetMultiplicativeDepth(2)
+def main():
+    # Sample Program: Step 1: Set CryptoContext
+    parameters = CCParamsBFVRNS()
+    parameters.SetPlaintextModulus(65537)
+    parameters.SetMultiplicativeDepth(2)
+
+    crypto_context = GenCryptoContext(parameters)
+    # Enable features that you wish to use
+    crypto_context.Enable(PKESchemeFeature.PKE)
+    crypto_context.Enable(PKESchemeFeature.KEYSWITCH)
+    crypto_context.Enable(PKESchemeFeature.LEVELEDSHE)
 
-crypto_context = GenCryptoContext(parameters)
-# Enable features that you wish to use
-crypto_context.Enable(PKESchemeFeature.PKE)
-crypto_context.Enable(PKESchemeFeature.KEYSWITCH)
-crypto_context.Enable(PKESchemeFeature.LEVELEDSHE)
+    # Sample Program: Step 2: Key Generation
 
-# Sample Program: Step 2: Key Generation
+    # Generate a public/private key pair
+    key_pair = crypto_context.KeyGen()
 
-# Generate a public/private key pair
-key_pair = crypto_context.KeyGen()
+    # Generate the relinearization key
+    crypto_context.EvalMultKeyGen(key_pair.secretKey)
 
-# Generate the relinearization key
-crypto_context.EvalMultKeyGen(key_pair.secretKey)
+    # Generate the rotation evaluation keys
+    crypto_context.EvalRotateKeyGen(key_pair.secretKey, [1, 2, -1, -2])
 
-# Generate the rotation evaluation keys
-crypto_context.EvalRotateKeyGen(key_pair.secretKey, [1, 2, -1, -2])
+    # Sample Program: Step 3: Encryption
 
-# Sample Program: Step 3: Encryption
+    # First plaintext vector is encoded
+    vector_of_ints1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+    plaintext1 = crypto_context.MakePackedPlaintext(vector_of_ints1)
 
-# First plaintext vector is encoded
-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
+    vector_of_ints2 = [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+    plaintext2 = crypto_context.MakePackedPlaintext(vector_of_ints2)
 
-# Second plaintext vector is encoded
-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
+    vector_of_ints3 = [1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12]
+    plaintext3 = crypto_context.MakePackedPlaintext(vector_of_ints3)
 
-# Third plaintext vector is encoded
-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 = crypto_context.Encrypt(key_pair.publicKey, plaintext1)
+    ciphertext2 = crypto_context.Encrypt(key_pair.publicKey, plaintext2)
+    ciphertext3 = crypto_context.Encrypt(key_pair.publicKey, plaintext3)
 
-# The encoded vectors are encrypted
-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
 
-#  Sample Program: Step 4: Evaluation
+    # Homomorphic additions
+    ciphertext_add12 = crypto_context.EvalAdd(ciphertext1, ciphertext2)
+    ciphertext_add_result = crypto_context.EvalAdd(ciphertext_add12, ciphertext3)
 
-# Homomorphic additions
-ciphertext_add12 = crypto_context.EvalAdd(ciphertext1, ciphertext2)
-ciphertext_add_result = crypto_context.EvalAdd(ciphertext_add12, ciphertext3)
+    # Homomorphic Multiplication
+    ciphertext_mult12 = crypto_context.EvalMult(ciphertext1, ciphertext2)
+    ciphertext_mult_result = crypto_context.EvalMult(ciphertext_mult12, ciphertext3)
 
-# Homomorphic Multiplication
-ciphertext_mult12 = crypto_context.EvalMult(ciphertext1, ciphertext2)
-ciphertext_mult_result = crypto_context.EvalMult(ciphertext_mult12, ciphertext3)
+    # Homomorphic Rotations
+    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)
 
-# Homomorphic Rotations
-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
 
-# Sample Program: Step 5: Decryption
+    # Decrypt the result of additions
+    plaintext_add_result = crypto_context.Decrypt(
+        ciphertext_add_result, key_pair.secretKey
+    )
 
-# Decrypt the result of additions
-plaintext_add_result = crypto_context.Decrypt(ciphertext_add_result,key_pair.secretKey)
+    # Decrypt the result of multiplications
+    plaintext_mult_result = crypto_context.Decrypt(
+        ciphertext_mult_result, key_pair.secretKey
+    )
 
-# Decrypt the result of multiplications
-plaintext_mult_result = crypto_context.Decrypt(ciphertext_mult_result,key_pair.secretKey)
+    # Decrypt the result of rotations
+    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)
 
-# Decrypt the result of rotations
-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(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))
+    print("Plaintext #3: " + str(plaintext3))
 
-plaintextRot1.SetLength(len(vector_of_ints1))
-plaintextRot2.SetLength(len(vector_of_ints1))
-plaintextRot3.SetLength(len(vector_of_ints1))
-plaintextRot4.SetLength(len(vector_of_ints1))
+    # Output Results
+    print("\nResults of homomorphic computations")
+    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))
+    print("Right rotation of #1 by 2 = " + str(plaintextRot4))
 
-print("Plaintext #1: " + str(plaintext1))
-print("Plaintext #2: " + str(plaintext2))
-print("Plaintext #3: " + str(plaintext3))
 
-# Output Results
-print("\nResults of homomorphic computations")
-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))
-print("Right rotation of #1 by 2 = " + str(plaintextRot4))
+if __name__ == "__main__":
+    main()

+ 114 - 62
examples/pke/simple-real-numbers-serial.py

@@ -1,27 +1,30 @@
 from openfhe import *
-
+import os
+from pathlib import Path
+import tempfile
 
 # NOTE:
 # If running locally, you may want to replace the "hardcoded" datafolder with
 # the datafolder location below which gets the current working directory
 
 # Save-Load locations for keys
-datafolder = 'demoData'
-ccLocation = '/cryptocontext.txt'
-pubKeyLocation = '/key_pub.txt' # Pub key
-multKeyLocation = '/key_mult.txt' # relinearization key
-rotKeyLocation = '/key_rot.txt' # automorphism / rotation key
+datafolder = "demoData"
+ccLocation = "/cryptocontext.txt"
+pubKeyLocation = "/key_pub.txt"  # Pub key
+multKeyLocation = "/key_mult.txt"  # relinearization key
+rotKeyLocation = "/key_rot.txt"  # automorphism / rotation key
 
 # Save-load locations for RAW ciphertexts
-cipherOneLocation = '/ciphertext1.txt'
-cipherTwoLocation = '/ciphertext2.txt'
+cipherOneLocation = "/ciphertext1.txt"
+cipherTwoLocation = "/ciphertext2.txt"
 
 # Save-load locations for evaluated ciphertexts
-cipherMultLocation = '/ciphertextMult.txt'
-cipherAddLocation = '/ciphertextAdd.txt'
-cipherRotLocation = '/ciphertextRot.txt'
-cipherRotNegLocation = '/ciphertextRotNegLocation.txt'
-clientVectorLocation = '/clientVectorFromClient.txt'
+cipherMultLocation = "/ciphertextMult.txt"
+cipherAddLocation = "/ciphertextAdd.txt"
+cipherRotLocation = "/ciphertextRot.txt"
+cipherRotNegLocation = "/ciphertextRotNegLocation.txt"
+clientVectorLocation = "/clientVectorFromClient.txt"
+
 
 # Demarcate - Visual separator between the sections of code
 def demarcate(msg):
@@ -29,6 +32,7 @@ def demarcate(msg):
     print(msg)
     print("**************************************************\n")
 
+
 """
 serverSetupAndWrite(multDepth, scaleModSize, batchSize)
     simulates a server at startup where we generate a cryptocontext and keys.
@@ -40,6 +44,8 @@ serverSetupAndWrite(multDepth, scaleModSize, batchSize)
     :param batchSize: batch size to use
     :return Tuple<cryptoContext, keyPair>
 """
+
+
 def serverSetupAndWrite(multDepth, scaleModSize, batchSize):
 
     parameters = CCParamsCKKSRNS()
@@ -75,7 +81,7 @@ def serverSetupAndWrite(multDepth, scaleModSize, batchSize):
     serverP2 = serverCC.MakeCKKSPackedPlaintext(vec2)
     serverP3 = serverCC.MakeCKKSPackedPlaintext(vec3)
 
-    print("Plaintext version of first vector: "+ str(serverP1))
+    print("Plaintext version of first vector: " + str(serverP1))
 
     print("Plaintexts have been generated from complex-double vectors")
 
@@ -93,7 +99,7 @@ def serverSetupAndWrite(multDepth, scaleModSize, batchSize):
     #      relinearization (eval mult keys)
     #      rotation keys
     #      Some of the ciphertext
-    #    
+    #
     #      We serialize all of them to files
     ###
     demarcate("Part 2: Data Serialization (server)")
@@ -116,22 +122,24 @@ def serverSetupAndWrite(multDepth, scaleModSize, batchSize):
 
     if not SerializeToFile(datafolder + cipherOneLocation, serverC1, BINARY):
         raise Exception("Error writing ciphertext 1")
-    
+
     if not SerializeToFile(datafolder + cipherTwoLocation, serverC2, BINARY):
         raise Exception("Error writing ciphertext 2")
-    
+
     return (serverCC, serverKP, len(vec1))
 
+
 ###
- # clientProcess
- #  - deserialize data from a file which simulates receiving data from a server
- # after making a request
- #  - we then process the data by doing operations (multiplication, addition,
- # rotation, etc)
- #  - !! We also create an object and encrypt it in this function before sending
- # it off to the server to be decrypted
+# clientProcess
+#  - deserialize data from a file which simulates receiving data from a server
+# after making a request
+#  - we then process the data by doing operations (multiplication, addition,
+# rotation, etc)
+#  - !! We also create an object and encrypt it in this function before sending
+# it off to the server to be decrypted
 ###
 
+
 def clientProcess():
     # clientCC = CryptoContext()
     # clientCC.ClearEvalMultKeys()
@@ -140,33 +148,45 @@ def clientProcess():
 
     clientCC, res = DeserializeCryptoContext(datafolder + ccLocation, BINARY)
     if not res:
-        raise Exception(f"I cannot deserialize the cryptocontext from {datafolder+ccLocation}")
+        raise Exception(
+            f"I cannot deserialize the cryptocontext from {datafolder+ccLocation}"
+        )
 
     print("Client CC deserialized")
 
-    #clientKP = KeyPair()
+    # clientKP = KeyPair()
     # We do NOT have a secret key. The client
     # should not have access to this
     clientPuclicKey, res = DeserializePublicKey(datafolder + pubKeyLocation, BINARY)
     if not res:
-        raise Exception(f"I cannot deserialize the public key from {datafolder+pubKeyLocation}")
+        raise Exception(
+            f"I cannot deserialize the public key from {datafolder+pubKeyLocation}"
+        )
     print("Client KP deserialized\n")
 
     if not clientCC.DeserializeEvalMultKey(datafolder + multKeyLocation, BINARY):
-        raise Exception(f"Cannot deserialize eval mult keys from {datafolder+multKeyLocation}")
+        raise Exception(
+            f"Cannot deserialize eval mult keys from {datafolder+multKeyLocation}"
+        )
     print("Deserialized eval mult keys\n")
 
     if not clientCC.DeserializeEvalAutomorphismKey(datafolder + rotKeyLocation, BINARY):
-        raise Exception(f"Cannot deserialize eval automorphism keys from {datafolder+rotKeyLocation}")
-    
+        raise Exception(
+            f"Cannot deserialize eval automorphism keys from {datafolder+rotKeyLocation}"
+        )
+
     clientC1, res = DeserializeCiphertext(datafolder + cipherOneLocation, BINARY)
     if not res:
-        raise Exception(f"Cannot deserialize the ciphertext from {datafolder+cipherOneLocation}")
+        raise Exception(
+            f"Cannot deserialize the ciphertext from {datafolder+cipherOneLocation}"
+        )
     print("Deserialized ciphertext 1\n")
 
     clientC2, res = DeserializeCiphertext(datafolder + cipherTwoLocation, BINARY)
     if not res:
-        raise Exception(f"Cannot deserialize the ciphertext from {datafolder+cipherTwoLocation}")
+        raise Exception(
+            f"Cannot deserialize the ciphertext from {datafolder+cipherTwoLocation}"
+        )
     print("Deserialized ciphertext 2\n")
 
     clientCiphertextMult = clientCC.EvalMult(clientC1, clientC2)
@@ -185,10 +205,13 @@ def clientProcess():
     SerializeToFile(datafolder + cipherAddLocation, clientCiphertextAdd, BINARY)
     SerializeToFile(datafolder + cipherRotLocation, clientCiphertextRot, BINARY)
     SerializeToFile(datafolder + cipherRotNegLocation, clientCiphertextRotNeg, BINARY)
-    SerializeToFile(datafolder + clientVectorLocation, clientInitializedEncryption, BINARY)
+    SerializeToFile(
+        datafolder + clientVectorLocation, clientInitializedEncryption, BINARY
+    )
 
     print("Serialized all ciphertexts from client\n")
 
+
 ###
 #  serverVerification
 #  - deserialize data from the client.
@@ -199,22 +222,42 @@ def clientProcess():
 # @return
 #  5-tuple of the plaintexts of various operations
 ##
-def serverVerification(cc,kp,vectorSize):
-    
-    serverCiphertextFromClient_Mult, res = DeserializeCiphertext(datafolder + cipherMultLocation, BINARY)
-    serverCiphertextFromClient_Add, res = DeserializeCiphertext(datafolder + cipherAddLocation, BINARY)
-    serverCiphertextFromClient_Rot, res = DeserializeCiphertext(datafolder + cipherRotLocation, BINARY)
-    serverCiphertextFromClient_RotNeg, res = DeserializeCiphertext(datafolder + cipherRotNegLocation, BINARY)
-    serverCiphertextFromClient_Vec, res = DeserializeCiphertext(datafolder + clientVectorLocation, BINARY)
+def serverVerification(cc, kp, vectorSize):
+
+    serverCiphertextFromClient_Mult, res = DeserializeCiphertext(
+        datafolder + cipherMultLocation, BINARY
+    )
+    serverCiphertextFromClient_Add, res = DeserializeCiphertext(
+        datafolder + cipherAddLocation, BINARY
+    )
+    serverCiphertextFromClient_Rot, res = DeserializeCiphertext(
+        datafolder + cipherRotLocation, BINARY
+    )
+    serverCiphertextFromClient_RotNeg, res = DeserializeCiphertext(
+        datafolder + cipherRotNegLocation, BINARY
+    )
+    serverCiphertextFromClient_Vec, res = DeserializeCiphertext(
+        datafolder + clientVectorLocation, BINARY
+    )
     print("Deserialized all data from client on server\n")
 
     print("Part 5: Correctness Verification")
 
-    serverPlaintextFromClient_Mult = cc.Decrypt(kp.secretKey, serverCiphertextFromClient_Mult)
-    serverPlaintextFromClient_Add = cc.Decrypt(kp.secretKey, serverCiphertextFromClient_Add)
-    serverPlaintextFromClient_Rot = cc.Decrypt(kp.secretKey, serverCiphertextFromClient_Rot)
-    serverPlaintextFromClient_RotNeg = cc.Decrypt(kp.secretKey, serverCiphertextFromClient_RotNeg)
-    serverPlaintextFromClient_Vec = cc.Decrypt(kp.secretKey, serverCiphertextFromClient_Vec)
+    serverPlaintextFromClient_Mult = cc.Decrypt(
+        kp.secretKey, serverCiphertextFromClient_Mult
+    )
+    serverPlaintextFromClient_Add = cc.Decrypt(
+        kp.secretKey, serverCiphertextFromClient_Add
+    )
+    serverPlaintextFromClient_Rot = cc.Decrypt(
+        kp.secretKey, serverCiphertextFromClient_Rot
+    )
+    serverPlaintextFromClient_RotNeg = cc.Decrypt(
+        kp.secretKey, serverCiphertextFromClient_RotNeg
+    )
+    serverPlaintextFromClient_Vec = cc.Decrypt(
+        kp.secretKey, serverCiphertextFromClient_Vec
+    )
 
     serverPlaintextFromClient_Mult.SetLength(vectorSize)
     serverPlaintextFromClient_Add.SetLength(vectorSize)
@@ -222,14 +265,27 @@ def serverVerification(cc,kp,vectorSize):
     serverPlaintextFromClient_Rot.SetLength(vectorSize + 1)
     serverPlaintextFromClient_RotNeg.SetLength(vectorSize + 1)
 
-    return (serverPlaintextFromClient_Mult, 
-            serverPlaintextFromClient_Add, 
-            serverPlaintextFromClient_Vec, 
-            serverPlaintextFromClient_Rot, 
-            serverPlaintextFromClient_RotNeg)
+    return (
+        serverPlaintextFromClient_Mult,
+        serverPlaintextFromClient_Add,
+        serverPlaintextFromClient_Vec,
+        serverPlaintextFromClient_Rot,
+        serverPlaintextFromClient_RotNeg,
+    )
+
 
 def main():
-    print(f"This program requires the subdirectory `{datafolder}' to exist, otherwise you will get\n an error writing serializations.")
+    global datafolder
+    with tempfile.TemporaryDirectory() as td:
+        datafolder = td + "/" + datafolder
+        os.makedirs(datafolder)
+        main_action()
+
+
+def main_action():
+    print(
+        f"This program requires the subdirectory `{datafolder}' to exist, otherwise you will get\n an error writing serializations."
+    )
 
     # Set main params
     multDepth = 5
@@ -246,7 +302,9 @@ def main():
     cipherRotResIdx = 3
     cipherRotNegResIdx = 4
 
-    demarcate("Part 1: Cryptocontext generation, key generation, data encryption \n(server)")
+    demarcate(
+        "Part 1: Cryptocontext generation, key generation, data encryption \n(server)"
+    )
 
     tupleCryptoContext_KeyPair = serverSetupAndWrite(multDepth, scaleModSize, batchSize)
     cc = tupleCryptoContext_KeyPair[cryptoContextIdx]
@@ -269,19 +327,13 @@ def main():
     # vec2: [12.5, 13.5, 14.5, 15.5]
 
     print(multRes)  # EXPECT: 12.5, 27.0, 43.5, 62
-    print(addRes)   # EXPECT: 13.5, 15.5, 17.5, 19.5
-    print(vecRes)   # EXPECT:  [1,2,3,4]
+    print(addRes)  # EXPECT: 13.5, 15.5, 17.5, 19.5
+    print(vecRes)  # EXPECT:  [1,2,3,4]
 
     print("Displaying 5 elements of a 4-element vector to illustrate rotation")
-    print(rotRes)     # EXPECT: [2, 3, 4, noise, noise]
+    print(rotRes)  # EXPECT: [2, 3, 4, noise, noise]
     print(rotNegRes)  # EXPECT: [noise, 1, 2, 3, 4]
 
+
 if __name__ == "__main__":
     main()
-
-
-
-
-
-
-

+ 85 - 86
examples/pke/simple-real-numbers.py

@@ -1,89 +1,88 @@
 from openfhe import *
 
-mult_depth = 1
-scale_mod_size = 50
-batch_size = 8
-
-parameters = CCParamsCKKSRNS()
-parameters.SetMultiplicativeDepth(mult_depth)
-parameters.SetScalingModSize(scale_mod_size)
-parameters.SetBatchSize(batch_size)
-
-cc = GenCryptoContext(parameters)
-cc.Enable(PKESchemeFeature.PKE)
-cc.Enable(PKESchemeFeature.KEYSWITCH)
-cc.Enable(PKESchemeFeature.LEVELEDSHE)
-
-print("The CKKS scheme is using ring dimension: " + str(cc.GetRingDimension()))
-
-keys = cc.KeyGen()
-cc.EvalMultKeyGen(keys.secretKey)
-cc.EvalRotateKeyGen(keys.secretKey, [1, -2])
-
-x1 = [0.25, 0.5, 0.75, 1.0, 2.0, 3.0, 4.0, 5.0]
-x2 = [5.0, 4.0, 3.0, 2.0, 1.0, 0.75, 0.5, 0.25]
-
-ptx1 = cc.MakeCKKSPackedPlaintext(x1)
-ptx2 = cc.MakeCKKSPackedPlaintext(x2)
-
-print("Input x1: " + str(ptx1))
-print("Input x2: " + str(ptx2))
-
-# Encrypt the encoded vectors
-c1 = cc.Encrypt(keys.publicKey, ptx1)
-c2 = cc.Encrypt(keys.publicKey, ptx2)
-
-# Step 4: Evaluation
-# Homomorphic additions
-c_add = cc.EvalAdd(c1, c2)
-# Homomorphic subtraction
-c_sub = cc.EvalSub(c1, c2)
-# Homomorphic scalar multiplication
-c_scalar = cc.EvalMult(c1,4)
-# Homomorphic multiplication
-c_mult = cc.EvalMult(c1, c2)
-# Homomorphic rotations
-c_rot1 = cc.EvalRotate(c1, 1)
-c_rot2 = cc.EvalRotate(c1, -2)
-
-# Step 5: Decryption and output
-# Decrypt the result of additions
-ptAdd = cc.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
-# to 15 and it should become visible.
-
-precision = 8
-print("Results of homomorphic computations:")
-result = cc.Decrypt(c1, keys.secretKey)
-result.SetLength(batch_size)
-print("x1 = " + str(result))
-print("Estimated precision in bits: " + str(result.GetLogPrecision()))
-
-# Decrypt the result of scalar multiplication
-result = cc.Decrypt(c_scalar,keys.secretKey)
-result.SetLength(batch_size)
-print("4 * x1 = " + str(result))
-
-# Decrypt the result of multiplication
-result = cc.Decrypt(c_mult,keys.secretKey)
-result.SetLength(batch_size)
-print("x1 * x2 = " + str(result))
-
-# Decrypt the result of rotations
-result = cc.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 = cc.Decrypt(c_rot2,keys.secretKey)
-result.SetLength(batch_size)
-print("x1 rotated by -2 = " + str(result))
-
-
-
-
-
-
 
+def main():
+    mult_depth = 1
+    scale_mod_size = 50
+    batch_size = 8
+
+    parameters = CCParamsCKKSRNS()
+    parameters.SetMultiplicativeDepth(mult_depth)
+    parameters.SetScalingModSize(scale_mod_size)
+    parameters.SetBatchSize(batch_size)
+
+    cc = GenCryptoContext(parameters)
+    cc.Enable(PKESchemeFeature.PKE)
+    cc.Enable(PKESchemeFeature.KEYSWITCH)
+    cc.Enable(PKESchemeFeature.LEVELEDSHE)
+
+    print("The CKKS scheme is using ring dimension: " + str(cc.GetRingDimension()))
+
+    keys = cc.KeyGen()
+    cc.EvalMultKeyGen(keys.secretKey)
+    cc.EvalRotateKeyGen(keys.secretKey, [1, -2])
+
+    x1 = [0.25, 0.5, 0.75, 1.0, 2.0, 3.0, 4.0, 5.0]
+    x2 = [5.0, 4.0, 3.0, 2.0, 1.0, 0.75, 0.5, 0.25]
+
+    ptx1 = cc.MakeCKKSPackedPlaintext(x1)
+    ptx2 = cc.MakeCKKSPackedPlaintext(x2)
+
+    print("Input x1: " + str(ptx1))
+    print("Input x2: " + str(ptx2))
+
+    # Encrypt the encoded vectors
+    c1 = cc.Encrypt(keys.publicKey, ptx1)
+    c2 = cc.Encrypt(keys.publicKey, ptx2)
+
+    # Step 4: Evaluation
+    # Homomorphic additions
+    c_add = cc.EvalAdd(c1, c2)
+    # Homomorphic subtraction
+    c_sub = cc.EvalSub(c1, c2)
+    # Homomorphic scalar multiplication
+    c_scalar = cc.EvalMult(c1, 4)
+    # Homomorphic multiplication
+    c_mult = cc.EvalMult(c1, c2)
+    # Homomorphic rotations
+    c_rot1 = cc.EvalRotate(c1, 1)
+    c_rot2 = cc.EvalRotate(c1, -2)
+
+    # Step 5: Decryption and output
+    # Decrypt the result of additions
+    ptAdd = cc.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
+    # to 15 and it should become visible.
+
+    precision = 8
+    print("Results of homomorphic computations:")
+    result = cc.Decrypt(c1, keys.secretKey)
+    result.SetLength(batch_size)
+    print("x1 = " + str(result))
+    print("Estimated precision in bits: " + str(result.GetLogPrecision()))
+
+    # Decrypt the result of scalar multiplication
+    result = cc.Decrypt(c_scalar, keys.secretKey)
+    result.SetLength(batch_size)
+    print("4 * x1 = " + str(result))
+
+    # Decrypt the result of multiplication
+    result = cc.Decrypt(c_mult, keys.secretKey)
+    result.SetLength(batch_size)
+    print("x1 * x2 = " + str(result))
+
+    # Decrypt the result of rotations
+    result = cc.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 = cc.Decrypt(c_rot2, keys.secretKey)
+    result.SetLength(batch_size)
+    print("x1 rotated by -2 = " + str(result))
+
+
+if __name__ == "__main__":
+    main()

+ 1 - 1
openfhe/__init__.py

@@ -1 +1 @@
-from .openfhe import *
+from openfhe.openfhe import *

+ 3 - 0
pytest.ini

@@ -0,0 +1,3 @@
+[pytest]
+testpaths =
+    tests

+ 2 - 1
setup.py

@@ -74,5 +74,6 @@ setup(
     },
     include_package_data=True,
     python_requires=">=3.6",
-    install_requires=['pybind11', 'pybind11-global', 'pybind11-stubgen']
+    install_requires=['pybind11', 'pybind11-global', 'pybind11-stubgen'],
+    tests_require = ['pytest'],
 )

+ 18 - 0
src/lib/bindings.cpp

@@ -691,6 +691,24 @@ void bind_crypto_context(py::module &m)
             py::arg("privateKey"),
             py::arg("indexList"),
             py::return_value_policy::reference_internal)
+        .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("EvalMultMany", &CryptoContextImpl<DCRTPoly>::EvalMultMany,
+            py::arg("ciphertextVec"))
+        .def("EvalAddManyInPlace", &CryptoContextImpl<DCRTPoly>::EvalAddManyInPlace,
+            py::arg("ciphertextVec"))
         .def("FindAutomorphismIndex", &CryptoContextImpl<DCRTPoly>::FindAutomorphismIndex,
             cc_FindAutomorphismIndex_docs,
             py::arg("idx"))

+ 0 - 59
src/pke/examples/test_serial_cc.py

@@ -1,59 +0,0 @@
-# Initial Settings
-from openfhe import *
-# import openfhe.PKESchemeFeature as Feature
-
-datafolder = 'demoData'
-
-print("This program requres the subdirectory `" + datafolder + "' to exist, otherwise you will get an error writing serializations.")
-
-# Sample Program: Step 1: Set CryptoContext
-parameters = CCParamsBFVRNS()
-parameters.SetPlaintextModulus(65537)
-parameters.SetMultiplicativeDepth(2)
-
-cryptoContext = GenCryptoContext(parameters)
-# Enable features that you wish to use
-cryptoContext.Enable(PKESchemeFeature.PKE)
-cryptoContext.Enable(PKESchemeFeature.KEYSWITCH)
-cryptoContext.Enable(PKESchemeFeature.LEVELEDSHE)
-
-keypair = cryptoContext.KeyGen()
-vectorOfInts1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
-plaintext1 = cryptoContext.MakePackedPlaintext(vectorOfInts1)
-ciphertext1 = cryptoContext.Encrypt(keypair.publicKey, plaintext1)
-
-# Serialize cryptocontext
-if not SerializeToFile(datafolder + "/cryptocontext.json", cryptoContext, JSON):
-   raise Exception("Error writing serialization of the crypto context to cryptocontext.json")
-print("The cryptocontext has been serialized.")
-# Serialize Ciphertext
-if not SerializeToFile(datafolder + "/ciphertext1.json", ciphertext1, JSON):
-   raise Exception("Error writing serialization of the ciphertext to ciphertext1.json")
-
-cryptoContext.ClearEvalMultKeys()
-cryptoContext.ClearEvalAutomorphismKeys()
-ReleaseAllContexts()
-# Deserialize the crypto context
-#cc = CryptoContext()
-
-res, cc = DeserializeFromFiletuple(datafolder + "/cryptocontext.json", JSON)
-if not res:
-   raise Exception("Error reading serialization of the crypto context from cryptocontext.txt")
-# cc = DeserializeFromFile2(datafolder + "/cryptocontext.json", JSON)
-# print("The cryptocontext has been deserialized.")
-# Serialize cryptocontext again
-if not SerializeToFile(datafolder + "/cryptocontext2.json", cc, JSON):
-   raise Exception("Error writing serialization of the crypto context to cryptocontext.json")
-print("The cryptocontext has been serialized.")
-
-ct1 = Ciphertext()
-# Deserialize the ciphertext
-if not DeserializeFromFile(datafolder + "/ciphertext1.json", ct1, JSON):
-   raise Exception("Error reading serialization of the ciphertext from ciphertext1.txt")
-
-# Serialize the ciphertext again
-if not SerializeToFile(datafolder + "/ciphertext12.json", ct1, JSON):
-   raise Exception("Error writing serialization of the ciphertext to ciphertext2.json")
-
-
-

+ 90 - 0
tests/README.md

@@ -0,0 +1,90 @@
+# Working with Tests
+
+These tests use [Pytest](https://docs.pytest.org/).
+
+## Running and Using Tests
+
+These tests assume that openfhe-python is installed in the current python environment, which you can check by importing openfhe.
+```bash
+python -c "__import__('openfhe')"
+```
+and that the `pytest` package is installed, either through pip or by installing `python3-pytest` in the operating system package manager.
+
+### Specific to the OpenFHE unit tests
+
+Some tests are marked with `@pytest.mark.long` if they are not meant to run
+on Github Actions. Run these locally with:
+
+```bash
+pytest --run-long
+pytest --run-all
+```
+
+### General Pytest usage
+
+This is a quick reminder of pytest's features. To test a particular file:
+
+```bash
+pytest test_particular_file.py
+```
+
+Test all functions matching a name. For instance, this would pick up
+`test_add_two_numbers`:
+
+```bash
+pytest -k add
+```
+
+As a reminder, pytest can be helpful for debugging. This command-line option
+shows debug output from logging statements.
+
+```bash
+pytest --log-cli-level=debug
+```
+
+If a test is failing, pytest can drop into the debugger when an exception
+happens.
+
+```bash
+pytest --pdb
+```
+
+## Guidelines for Writing Tests
+
+**Mark long-running tests with long** -- These tests run with default settings
+on Github Actions, which can be underpowered, so there is a way to mark tests
+that can be run by hand or on other automation servers.
+
+```python
+@pytest.mark.long
+def test_ckks_large_context():
+    assert true
+```
+
+The goal is for the Github Actions tests to reassure a committer that they have
+not broken the Python wrapper.
+
+**Import OpenFHE as fhe** -- Unit tests tend to use more imports than most
+code, for instance JSON, which conflicts with an OpenFHE name, so qualify
+imports in the tests.
+
+```python
+import openfhe as fhe
+
+def test_something():
+    parameters = fhe.CCParamsCKKSRNS()
+```
+
+**Use logging instead of print statements** -- Pytest has nice support for
+making logging statements visible, in the case that you are using tests
+for debugging.
+
+```python
+import logging
+
+LOGGER = logging.getLogger("test_file_name")
+
+def test_something():
+    arg = 3
+    LOGGER.debug("My message has an argument %s", arg)
+```

+ 105 - 0
tests/conftest.py

@@ -0,0 +1,105 @@
+"""
+This is a specially-named file that pytest finds in order to
+configure testing. Most of the logic comes from
+https://docs.pytest.org/en/7.1.x/example/simple.html#control-skipping-of-tests-according-to-command-line-option
+"""
+import pytest
+
+
+class CustomMarker:
+    """
+    Custom Markers are used to annotate tests.
+
+    Tests marked with a custom marker will be skipped by default. Pass either
+
+        --run-NAME_OF_MARKER or --run-NAME-OF-MARKER
+
+    to override this behavior.
+
+    --run-all may also be used to run all marked tests.
+    """
+    def __init__(self, name, desc, dest=None):
+        self.name = name
+        self.desc = desc
+        self.dest = name if dest is None else dest
+
+    def option_flags(self):
+        """
+        Return option flags for this marker.
+
+        >>> marker = CustomMarker('foo_bar', 'my desc')
+        >>> marker.option_flags()
+        ['--run-foo_bar', '--run-foo-bar']
+        >>> marker2 = CustomMarker('foo', 'my desc')
+        >>> marker2.option_flags()
+        ['--run-foo']
+        """
+        # NOTE: pytest is not testing the above doctest
+        # instead, run this file directly (see doctest.testmod at bottom)
+        result = ['--run-{}'.format(self.name)]
+        as_hyphen = '--run-{}'.format(self.name.replace('_', '-'))
+        if as_hyphen != result[0]:
+            result.append(as_hyphen)
+
+        return result
+
+
+CUSTOM_MARKERS = (
+    CustomMarker('long',
+                 'this test runs too long for Github Actions'),
+    CustomMarker('uses_card',
+                 'must have acceleration card installed to run test'),
+)
+
+
+def pytest_addoption(parser):
+    """
+    pytest hook - adds options to argument parser.
+    """
+
+    parser.addoption('--run-all',
+                     dest='run_all',
+                     action='store_true',
+                     help='Run all tests normally skipped by default')
+
+    for marker in CUSTOM_MARKERS:
+        parser.addoption(*marker.option_flags(),
+                         dest=marker.dest,
+                         action='store_true',
+                         help='Run tests marked with {}'.format(marker.name))
+
+
+def pytest_configure(config):
+    # Adds explicit marker definitions
+    # with these, pytest will error if `--strict` is applied and unregistered
+    # markers are present.
+    for marker in CUSTOM_MARKERS:
+        config.addinivalue_line("markers",
+                                "{}: {}".format(marker.name, marker.desc))
+
+
+def pytest_collection_modifyitems(config, items):
+    """
+    pytest hook which runs after tests have been collected.
+    """
+    skip_marked_tests(config, items)
+
+
+def skip_marked_tests(config, items):
+    """
+    Dynamically applies pytest.mark.skip to tests with custom markers.
+
+    Tests with explicit --run-FOO flags are not skipped.
+
+    This keeps `pytest` from footshooting with tests that should only be run
+    under particular conditions.
+    """
+    run_all = config.getoption('--run-all', default=False)
+    run_mark = {marker.name: config.getoption(marker.dest)
+                for marker in CUSTOM_MARKERS}
+
+    for item in items:
+        for marker_name, run_marker in run_mark.items():
+            if marker_name in item.keywords and not (run_all or run_marker):
+                item.add_marker(pytest.mark.skip)
+                break

+ 103 - 0
tests/test_bgv.py

@@ -0,0 +1,103 @@
+import logging
+import random
+
+import pytest
+import openfhe as fhe
+
+
+LOGGER = logging.getLogger("test_bgv")
+
+
+@pytest.fixture(scope="module")
+def bgv_context():
+    """
+    This fixture creates a small CKKS context, with its paramters and keys.
+    We make it because context creation can be slow.
+    """
+    parameters = fhe.CCParamsBGVRNS()
+    parameters.SetPlaintextModulus(65537)
+    parameters.SetMultiplicativeDepth(2)
+
+    crypto_context = fhe.GenCryptoContext(parameters)
+    crypto_context.Enable(fhe.PKESchemeFeature.PKE)
+    crypto_context.Enable(fhe.PKESchemeFeature.KEYSWITCH)
+    crypto_context.Enable(fhe.PKESchemeFeature.LEVELEDSHE)
+    key_pair = crypto_context.KeyGen()
+    # Generate the relinearization key
+    crypto_context.EvalMultKeyGen(key_pair.secretKey)
+    # Generate the rotation evaluation keys
+    crypto_context.EvalRotateKeyGen(key_pair.secretKey, [1, 2, -1, -2])
+    return parameters, crypto_context, key_pair
+
+
+def bgv_equal(raw, ciphertext, cc, keys):
+    """Compare an unencrypted list of values with encrypted values"""
+    pt = cc.Decrypt(ciphertext, keys.secretKey)
+    pt.SetLength(len(raw))
+    compare = pt.GetPackedValue()
+    success = all([a == b for (a, b) in zip(raw, compare)])
+    if not success:
+        LOGGER.info("Mismatch between %s %s", raw, compare)
+    return success
+
+
+def roll(a, n):
+    """Circularly rotate a list, like numpy.roll but without numpy."""
+    return [a[i % len(a)] for i in range(-n, len(a) - n)]
+
+
+@pytest.mark.parametrize("n,final", [
+    (0, [0, 1, 2, 3, 4, 5, 6, 7]),
+    (2, [6, 7, 0, 1, 2, 3, 4, 5]),
+    (3, [5, 6, 7, 0, 1, 2, 3, 4]),
+    (-1, [1, 2, 3, 4, 5, 6, 7, 0]),
+    ])
+def test_roll(n, final):
+    assert roll(list(range(8)), n) == final
+
+
+def shift(a, n):
+    """Rotate a list with infill of 0."""
+    return [(a[i] if 0 <= i < len(a) else 0) for i in range(-n, len(a) - n)]
+
+
+@pytest.mark.parametrize("n,final", [
+    (0, [1, 2, 3, 4, 5, 6, 7, 8]),
+    (2, [0, 0, 1, 2, 3, 4, 5, 6]),
+    (3, [0, 0, 0, 1, 2, 3, 4, 5]),
+    (-1, [2, 3, 4, 5, 6, 7, 8, 0]),
+    ])
+def test_shift(n, final):
+    assert shift(list(range(1, 9)), n) == final
+
+
+def test_simple_integers(bgv_context):
+    parameters, crypto_context, key_pair = bgv_context
+    rng = random.Random(342342)
+    cnt = 12
+    raw = [[rng.randint(1, 12) for _ in range(cnt)] for _ in range(3)]
+    plaintext = [crypto_context.MakePackedPlaintext(r) for r in raw]
+    ciphertext = [crypto_context.Encrypt(key_pair.publicKey, pt) for pt in plaintext]
+    assert bgv_equal(raw[0], ciphertext[0], crypto_context, key_pair)
+
+    # Homomorphic additions
+    ciphertext_add12 = crypto_context.EvalAdd(ciphertext[0], ciphertext[1])
+    ciphertext_add_result = crypto_context.EvalAdd(ciphertext_add12, ciphertext[2])
+    assert bgv_equal(
+        [a + b + c for (a, b, c) in zip(*raw)],
+        ciphertext_add_result, crypto_context, key_pair
+        )
+
+    # Homomorphic Multiplication
+    ciphertext_mult12 = crypto_context.EvalMult(ciphertext[0], ciphertext[1])
+    ciphertext_mult_result = crypto_context.EvalMult(ciphertext_mult12, ciphertext[2])
+    assert bgv_equal(
+        [a * b * c for (a, b, c) in zip(*raw)],
+        ciphertext_mult_result, crypto_context, key_pair
+        )
+
+    # Homomorphic Rotations. These values must be initialized with EvalRotateKeyGen.
+    for rotation in [1, 2, -1, -2]:
+        ciphertext_rot1 = crypto_context.EvalRotate(ciphertext[0], rotation)
+        # This is a rotation with infill of 0, NOT a circular rotation.
+        assert bgv_equal(shift(raw[0], -rotation), ciphertext_rot1, crypto_context, key_pair)

+ 64 - 0
tests/test_boolean.py

@@ -0,0 +1,64 @@
+from openfhe import *
+import pytest
+
+
+## Sample Program: Step 1: Set CryptoContext
+@pytest.mark.parametrize("a", [0, 1])
+@pytest.mark.parametrize("b", [0, 1])
+def test_boolean_AND(a, b):
+    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, a)
+    ct2 = cc.Encrypt(sk, b)
+
+    # 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 ({a} AND {b}) OR ({a} AND (NOT {b})) = {result}"
+    )
+    plaintext_result = (a and b) or (a and (not b))
+    assert (
+        result == plaintext_result
+    ), "Logical AND in plaintext and ciphertext should be same"

+ 56 - 0
tests/test_ckks.py

@@ -0,0 +1,56 @@
+import random
+
+import pytest
+import openfhe as fhe
+
+
+@pytest.fixture(scope="module")
+def ckks_context():
+    """
+    This fixture creates a small CKKS context, with its paramters and keys.
+    We make it because context creation can be slow.
+    """
+    batch_size = 8
+    parameters = fhe.CCParamsCKKSRNS()
+    parameters.SetMultiplicativeDepth(5)
+    if fhe.get_native_int() > 90:
+        parameters.SetFirstModSize(89)
+        parameters.SetScalingModSize(78)
+        parameters.SetBatchSize(batch_size)
+        parameters.SetScalingTechnique(fhe.ScalingTechnique.FIXEDAUTO)
+        parameters.SetNumLargeDigits(2)
+
+    elif fhe.get_native_int() > 60:
+        parameters.SetFirstModSize(60)
+        parameters.SetScalingModSize(56)
+        parameters.SetBatchSize(batch_size)
+        parameters.SetScalingTechnique(fhe.ScalingTechnique.FLEXIBLEAUTO)
+        parameters.SetNumLargeDigits(2)
+
+    else:
+        raise ValueError("Expected a native int size greater than 60.")
+
+    cc = fhe.GenCryptoContext(parameters)
+    cc.Enable(fhe.PKESchemeFeature.PKE)
+    cc.Enable(fhe.PKESchemeFeature.KEYSWITCH)
+    cc.Enable(fhe.PKESchemeFeature.LEVELEDSHE)
+    keys = cc.KeyGen()
+    cc.EvalRotateKeyGen(keys.secretKey, [1, -2])
+    return parameters, cc, keys
+
+
+def test_add_two_numbers(ckks_context):
+    params, cc, keys = ckks_context
+    batch_size = params.GetBatchSize()
+    rng = random.Random(42429842)
+    raw = [[rng.uniform(-1, 1) for _ in range(batch_size)] for _ in range(2)]
+    ptxt = [cc.MakeCKKSPackedPlaintext(x) for x in raw]
+    ctxt = [cc.Encrypt(keys.publicKey, y) for y in ptxt]
+
+    ct_added = cc.EvalAdd(ctxt[0], ctxt[1])
+    pt_added = cc.Decrypt(ct_added, keys.secretKey)
+    pt_added.SetLength(batch_size)
+    final_added = pt_added.GetCKKSPackedValue()
+    raw_added = [a + b for (a, b) in zip(*raw)]
+    total = sum(abs(a - b) for (a, b) in zip(raw_added, final_added))
+    assert total < 1e-3

+ 17 - 0
tests/test_cryptocontext.py

@@ -0,0 +1,17 @@
+import pytest
+import openfhe as fhe
+
+
+@pytest.mark.long
+@pytest.mark.skipif(fhe.get_native_int() < 80, reason="Only for NATIVE_INT=128")
+@pytest.mark.parametrize("scaling", [fhe.FIXEDAUTO, fhe.FIXEDMANUAL])
+def test_ckks_context(scaling):
+    batch_size = 8
+    parameters = fhe.CCParamsCKKSRNS()
+    parameters.SetMultiplicativeDepth(5)
+    parameters.SetScalingModSize(78)
+    parameters.SetBatchSize(batch_size)
+    parameters.SetScalingTechnique(scaling)
+    parameters.SetNumLargeDigits(2)
+    cc = fhe.GenCryptoContext(parameters)
+    assert isinstance(cc, fhe.CryptoContext)

+ 57 - 0
tests/test_examples.py

@@ -0,0 +1,57 @@
+import os
+import sys
+from pathlib import Path
+import importlib.util
+import pytest
+import tempfile
+import shutil
+
+EXAMPLES_SCRIPTS_PATH = os.path.join(Path(__file__).parent.parent, "examples", "pke")
+
+
+def importhelper(path, modulename):
+    spec = importlib.util.spec_from_file_location(
+        modulename, os.path.join(path, modulename + ".py")
+    )
+    module = importlib.util.module_from_spec(spec)
+    sys.modules[modulename] = module
+    spec.loader.exec_module(module)
+    return module
+
+
+@pytest.mark.parametrize(
+    "raw_modulename",
+    [
+        "simple-ckks-bootstrapping.py",
+        "simple-integers-serial-bgvrns.py",
+        "function-evaluation.py",
+        "advanced-real-numbers-128.py",
+        "simple-integers-bgvrns.py",
+        "simple-integers-serial.py",
+        "polynomial-evaluation.py",
+        "scheme-switching.py",
+        "tckks-interactive-mp-bootstrapping.py",
+        "advanced-real-numbers.py",
+        "threshold-fhe-5p.py",
+        "simple-integers.py",
+        "simple-real-numbers-serial.py",
+        "iterative-ckks-bootstrapping.py",
+        "tckks-interactive-mp-bootstrapping-Chebyschev.py",
+        "simple-real-numbers.py",
+        "threshold-fhe.py",
+        "pre-buffer.py",
+    ],
+)
+def test_run_scripts(raw_modulename):
+    with tempfile.TemporaryDirectory() as td:
+        os.mkdir(td + "/demoData")
+        modulename_py = raw_modulename.replace("-", "_")
+        shutil.copyfile(
+            os.path.join(EXAMPLES_SCRIPTS_PATH, raw_modulename),
+            os.path.join(td, modulename_py),
+        )
+        sys.path.insert(0, td)
+        modulename = modulename_py.split(".")[0]
+        print(f"-*- running module {modulename} -*-")
+        module = importhelper(td, modulename)
+        module.main()

+ 39 - 0
tests/test_serial_cc.py

@@ -0,0 +1,39 @@
+import logging
+
+import openfhe as fhe
+
+LOGGER = logging.getLogger("test_serial_cc")
+
+
+def test_serial_cryptocontext(tmp_path):
+    parameters = fhe.CCParamsBFVRNS()
+    parameters.SetPlaintextModulus(65537)
+    parameters.SetMultiplicativeDepth(2)
+
+    cryptoContext = fhe.GenCryptoContext(parameters)
+    cryptoContext.Enable(fhe.PKESchemeFeature.PKE)
+
+    keypair = cryptoContext.KeyGen()
+    vectorOfInts1 = list(range(12))
+    plaintext1 = cryptoContext.MakePackedPlaintext(vectorOfInts1)
+    ciphertext1 = cryptoContext.Encrypt(keypair.publicKey, plaintext1)
+
+    assert fhe.SerializeToFile(str(tmp_path / "cryptocontext.json"), cryptoContext, fhe.JSON)
+    LOGGER.debug("The cryptocontext has been serialized.")
+    assert fhe.SerializeToFile(str(tmp_path / "ciphertext1.json"), ciphertext1, fhe.JSON)
+
+    cryptoContext.ClearEvalMultKeys()
+    cryptoContext.ClearEvalAutomorphismKeys()
+    fhe.ReleaseAllContexts()
+
+    cc, success = fhe.DeserializeCryptoContext(str(tmp_path / "cryptocontext.json"), fhe.JSON)
+    assert success
+    assert isinstance(cc, fhe.CryptoContext)
+    assert fhe.SerializeToFile(str(tmp_path / "cryptocontext2.json"), cc, fhe.JSON)
+    LOGGER.debug("The cryptocontext has been serialized.")
+
+    ct1, success = fhe.DeserializeCiphertext(str(tmp_path / "ciphertext1.json"), fhe.JSON)
+    assert success
+    assert isinstance(ct1, fhe.Ciphertext)
+    LOGGER.debug("Cryptocontext deserializes to %s %s", success, ct1)
+    assert fhe.SerializeToFile(str(tmp_path / "ciphertext12.json"), ct1, fhe.JSON)