├── .github └── workflows │ └── manual.yml ├── .gitignore ├── .readthedocs.yaml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── build_package.sh ├── docker ├── Dockerfile └── README.md ├── docs ├── Makefile ├── binfhe.rst ├── binfhe_enums.rst ├── ciphertext.rst ├── conf.py ├── cryptocontext.rst ├── cryptoparams.rst ├── index.rst ├── keys.rst ├── make.bat ├── pke_enums.rst ├── plaintext.rst └── requirements.txt ├── examples ├── binfhe │ ├── boolean-ap.py │ ├── boolean-lmkcdey.py │ ├── boolean-truth-tables.py │ └── boolean.py └── pke │ ├── advanced-real-numbers-128.py │ ├── advanced-real-numbers.py │ ├── function-evaluation.py │ ├── iterative-ckks-bootstrapping.py │ ├── polynomial-evaluation.py │ ├── pre-buffer.py │ ├── scheme-switching.py │ ├── simple-ckks-bootstrapping.py │ ├── simple-integers-bgvrns.py │ ├── simple-integers-serial-bgvrns.py │ ├── simple-integers-serial.py │ ├── simple-integers.py │ ├── simple-real-numbers-serial.py │ ├── simple-real-numbers.py │ ├── tckks-interactive-mp-bootstrapping-Chebyschev.py │ ├── tckks-interactive-mp-bootstrapping.py │ ├── threshold-fhe-5p.py │ └── threshold-fhe.py ├── openfhe └── __init__.py ├── pytest.ini ├── setup.py ├── src ├── include │ ├── bindings.h │ ├── binfhe │ │ └── binfhecontext_wrapper.h │ ├── binfhe_bindings.h │ ├── docstrings │ │ ├── binfhecontext_docs.h │ │ ├── ciphertext_docs.h │ │ ├── cryptocontext_docs.h │ │ ├── cryptoparameters_docs.h │ │ └── plaintext_docs.h │ └── pke │ │ ├── cryptocontext_wrapper.h │ │ └── serialization.h └── lib │ ├── bindings.cpp │ ├── binfhe │ └── binfhecontext_wrapper.cpp │ ├── binfhe_bindings.cpp │ └── pke │ ├── cryptocontext_wrapper.cpp │ └── serialization.cpp ├── tests ├── README.md ├── conftest.py ├── test_bgv.py ├── test_boolean.py ├── test_ckks.py ├── test_cryptocontext.py ├── test_examples.py └── test_serial_cc.py └── utils └── print-used-modules-and-libraries-linux.py /.github/workflows/manual.yml: -------------------------------------------------------------------------------- 1 | name: Manual 2 | 3 | # the workflow_call block was added to this manual workflow (on workflow_dispatch:) because 4 | # it has to be included if a reuseable workflow is called. 5 | # The changes from the workflow_dispatch inputs to the workflow_call inputs are: 6 | # - "type: choice" is replaced with "type: string" 7 | # - all "options:" are removed 8 | # The variable/tag for the runner (var.RUNNER) is defined on the "Actions secrets and variables" page, tab "Variables": 9 | # https://github.com/openfheorg/openfhe-development/settings/variables/actions 10 | on: 11 | workflow_call: 12 | inputs: 13 | compiler: 14 | description: 'Compiler type' 15 | type: string 16 | required: true 17 | default: 'GLANG-18' 18 | native_backend: 19 | description: 'Size of NativeInteger' 20 | type: string 21 | required: true 22 | default: '64' 23 | openfhe_development_branch: 24 | description: 'openfhe-development branch' 25 | type: string 26 | required: true 27 | default: 'main' 28 | 29 | workflow_dispatch: 30 | inputs: 31 | # Selects the compiler to use, this choice will be used in the COMPILERS_MAP as the key to 32 | # retrieve the corresponding cmake compiler options to pass to the action 33 | compiler: 34 | description: 'Compiler type' 35 | type: choice 36 | options: 37 | - 'GCC-14' 38 | - 'CLANG-18' 39 | required: true 40 | default: 'GLANG-18' 41 | native_backend: 42 | description: 'Size of NativeInteger' 43 | type: choice 44 | options: 45 | - '32' 46 | - '64' 47 | - '128' 48 | - 'all' 49 | required: true 50 | default: '64' 51 | openfhe_development_branch: 52 | description: 'openfhe-development branch' 53 | type: string 54 | required: true 55 | default: 'main' 56 | 57 | # cmake_args_map_openfhe_lib holds job specific additional cmake options. As we are testing openfhe-python here 58 | # and not openfhe-development, we do not link unittest, benchmarks, etc. for openfhe-development. 59 | # compiler flags, native_backend flag and OpenMP flag are set in generic_workflow.yml 60 | jobs: 61 | call: 62 | uses: openfheorg/openfhe-python/.github/workflows/generic_workflow.yml@github-ci 63 | with: 64 | runner: ${{ vars.RUNNER }} 65 | compiler: "${{ inputs.compiler }}" 66 | native_backend: "${{ inputs.native_backend }}" 67 | openfhe_development_branch: "${{ inputs.openfhe_development_branch }}" 68 | cmake_args_map_openfhe_lib: '{ 69 | "default" : "-DBUILD_BENCHMARKS=OFF -DBUILD_UNITTESTS=OFF -DBUILD_EXAMPLES=OFF", 70 | }' 71 | 72 | 73 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .vscode/ 3 | .idea 4 | .png 5 | *.json 6 | *.txt 7 | .cproject 8 | .project 9 | .html 10 | *.pyc 11 | .settings/ 12 | docs/ 13 | demoData/ 14 | dist/ 15 | openfhe/openfhe.so 16 | openfhe/*.pyi 17 | openfhe.egg-info/ 18 | stubs/ 19 | .venv/ 20 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.11" 13 | 14 | # Build documentation in the docs/ directory with Sphinx 15 | sphinx: 16 | configuration: docs/conf.py 17 | 18 | # We recommend specifying your dependencies to enable reproducible builds: 19 | # https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 20 | python: 21 | install: 22 | - requirements: docs/requirements.txt 23 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.5.1) 2 | 3 | project (OpenFHE-Python) 4 | 5 | set(OPENFHE_PYTHON_VERSION_MAJOR 1) 6 | set(OPENFHE_PYTHON_VERSION_MINOR 3) 7 | set(OPENFHE_PYTHON_VERSION_PATCH 0) 8 | set(OPENFHE_PYTHON_VERSION_TWEAK 0) 9 | set(OPENFHE_PYTHON_VERSION ${OPENFHE_PYTHON_VERSION_MAJOR}.${OPENFHE_PYTHON_VERSION_MINOR}.${OPENFHE_PYTHON_VERSION_PATCH}.${OPENFHE_PYTHON_VERSION_TWEAK}) 10 | 11 | set(CMAKE_CXX_STANDARD 17) 12 | option( BUILD_STATIC "Set to ON to include static versions of the library" OFF) 13 | 14 | if(APPLE) 15 | set(CMAKE_CXX_VISIBILITY_PRESET default) 16 | endif() 17 | 18 | find_package(OpenFHE 1.3.0 REQUIRED) 19 | find_package(pybind11 REQUIRED) 20 | 21 | # "CMAKE_INTERPROCEDURAL_OPTIMIZATION ON" (ON is the default value) causes link failure. see 22 | # https://github.com/openfheorg/openfhe-python/actions/runs/11492843373/job/31987579944 23 | set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF) 24 | 25 | set( OpenFHE_Py_SOURCES src/lib) 26 | set( OpenFHE_Py_INCLUDES src/include) 27 | 28 | include_directories( ${OPENMP_INCLUDES} ) 29 | include_directories( ${OpenFHE_INCLUDE} ) 30 | include_directories( ${OpenFHE_INCLUDE}/third-party/include ) 31 | include_directories( ${OpenFHE_INCLUDE}/core ) 32 | include_directories( ${OpenFHE_INCLUDE}/pke ) 33 | include_directories( ${OpenFHE_INCLUDE}/binfhe ) 34 | # include_directories( ${OpenFHE_Py_SOURCES} ) 35 | include_directories( ${OpenFHE_Py_INCLUDES}/pke ) 36 | include_directories( ${OpenFHE_Py_INCLUDES}/binfhe ) 37 | include_directories( ${OpenFHE_Py_INCLUDES}/docstrings ) 38 | include_directories( ${OpenFHE_Py_INCLUDES} ) 39 | ### add directories for other OpenFHE modules as needed for your project 40 | 41 | link_directories( ${OpenFHE_LIBDIR} ) 42 | link_directories( ${OPENMP_LIBRARIES} ) 43 | if(BUILD_STATIC) 44 | set( CMAKE_EXE_LINKER_FLAGS "${OpenFHE_EXE_LINKER_FLAGS} -static") 45 | link_libraries( ${OpenFHE_STATIC_LIBRARIES} ) 46 | else() 47 | set( CMAKE_EXE_LINKER_FLAGS ${OpenFHE_EXE_LINKER_FLAGS} ) 48 | link_libraries( ${OpenFHE_SHARED_LIBRARIES} ) 49 | endif() 50 | 51 | ### ADD YOUR EXECUTABLE(s) HERE 52 | ### add_executable( EXECUTABLE-NAME SOURCES ) 53 | ### 54 | ### EXAMPLE: 55 | ### add_executable( test demo-simple-example.cpp ) 56 | 57 | ### Pybind Modules 58 | pybind11_add_module(openfhe 59 | src/lib/bindings.cpp 60 | src/lib/binfhe_bindings.cpp 61 | src/lib/binfhe/binfhecontext_wrapper.cpp 62 | src/lib/pke/serialization.cpp 63 | src/lib/pke/cryptocontext_wrapper.cpp 64 | ) 65 | ### Python installation 66 | # Allow the user to specify the path to Python executable (if not provided, find it) 67 | option(PYTHON_EXECUTABLE_PATH "Path to Python executable" "") 68 | 69 | if(NOT PYTHON_EXECUTABLE_PATH) 70 | # Find Python and its development components 71 | find_package(Python REQUIRED COMPONENTS Interpreter Development) 72 | else() 73 | # Set Python_EXECUTABLE to the specified path 74 | set(Python_EXECUTABLE "${PYTHON_EXECUTABLE_PATH}") 75 | endif() 76 | 77 | # Find Python interpreter 78 | find_package(PythonInterp REQUIRED) 79 | 80 | # Check Python version 81 | if(${PYTHON_VERSION_MAJOR} EQUAL 3 AND ${PYTHON_VERSION_MINOR} GREATER_EQUAL 10) 82 | execute_process( 83 | COMMAND "${Python_EXECUTABLE}" -c "from sys import exec_prefix; print(exec_prefix)" 84 | OUTPUT_VARIABLE PYTHON_SITE_PACKAGES 85 | OUTPUT_STRIP_TRAILING_WHITESPACE 86 | ) 87 | else() 88 | execute_process( 89 | COMMAND "${Python_EXECUTABLE}" -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())" 90 | OUTPUT_VARIABLE PYTHON_SITE_PACKAGES 91 | OUTPUT_STRIP_TRAILING_WHITESPACE 92 | ) 93 | endif() 94 | 95 | message(STATUS "Python site packages directory: ${PYTHON_SITE_PACKAGES}") 96 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) 97 | set(Python_Install_Location "${PYTHON_SITE_PACKAGES}") 98 | else() 99 | set(Python_Install_Location "${CMAKE_INSTALL_PREFIX}") 100 | endif() 101 | message("***** INSTALL IS AT ${Python_Install_Location}; to change, run cmake with -DCMAKE_INSTALL_PREFIX=/your/path") 102 | install(TARGETS openfhe LIBRARY DESTINATION ${Python_Install_Location}) 103 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2022, OpenFHE 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Official Python wrapper for OpenFHE 2 | 3 | ## Table of Contents 4 | 5 | - [Installing using pip](#installing-using-pip) 6 | - [Running from Docker](#running-from-docker) 7 | - [Building from Source](#building-from-source) 8 | - [Prerequisites](#requirements) 9 | - [Linux Install](#linux) 10 | - [Installing directly on your system](#system-level-installation) 11 | - [Using Conda environments](#conda) 12 | - [Running Examples](#code-examples) 13 | - [OpenFHE Python Wrapper Documentation](#openfhe-python-wrapper-documentation) 14 | - [Contributing Guide](#contributing-guide) 15 | 16 | ## Installing using pip (for Ubuntu) 17 | 18 | On Ubuntu, openfhe-python can be installed using pip. All available releases are listed at [Python Package Index OpenFHE Release History](https://pypi.org/project/openfhe/#history). Find the release for your version of Ubuntu and run 19 | 20 | ``` 21 | pip install openfhe== 22 | ``` 23 | 24 | Once installed, any python example at https://github.com/openfheorg/openfhe-python/tree/main/examples can be executed. 25 | 26 | Note that Ubuntu LTS 20.04, 22.04, and 24.04 are currently supported. `pip uninstal` can be used to uninstall the openfhe package. 27 | 28 | ## Running from Docker 29 | 30 | Please see [Instructions for the Docker setup](docker/README.md) 31 | 32 | ## Building from Source 33 | 34 | ### Requirements 35 | 36 | Before building, make sure you have the following dependencies installed: 37 | 38 | - [OpenFHE 1.3.0+](https://github.com/openfheorg/openfhe-development) by following the instructions in [OpenFHE Documentation](https://openfhe-development.readthedocs.io/en/latest/sphinx_rsts/intro/installation/installation.html) 39 | - [Python 3.6+](https://www.python.org/) 40 | - [pybind11](https://pybind11.readthedocs.io/en/stable/installing.html) 41 | 42 | We recommend following OpenFHE C++ installation instructions first (which covers Linux, Windows and MacOS) and then getting back to this repo. See notes on installing `pybind11` below 43 | 44 | ### Linux 45 | 46 | #### System-level installation 47 | 48 | To install OpenFHE-python directly to your system, ensure the dependencies are set up. Then clone the repository, open a terminal in the repo folder and run the following commands: 49 | 50 | ```bash 51 | pip install "pybind11[global]" 52 | mkdir build 53 | cd build 54 | cmake .. # Alternatively, cmake .. -DCMAKE_PREFIX_PATH=/path/to/installed/openfhe if you installed OpenFHE elsewhere 55 | make 56 | make install # You may have to run sudo make install 57 | ``` 58 | 59 | At this point the `.so` file has been built. Your exact installation process will depend on your virtual environment. 60 | Cmake will automatically find the python installation path, if unwanted, you can specify the python path by adding `-DPYTHON_EXECUTABLE_PATH=/path/to/python` to the cmake command. 61 | 62 | If you see an error saying that one of OpenFHE .so files cannot be found when running a Python example (occurs only for some environments), 63 | add the path where the .so files reside to the `PYTHONPATH` environment variable: 64 | 65 | ``` 66 | export PYTHONPATH=(/path/to/installed/openfhe):$PYTHONPATH 67 | ``` 68 | 69 | In some environments (this happens rarely), it may also be necessary to add the OpenFHE libraries path to `LD_LIBRARY_PATH`. 70 | 71 | If OpenFHE is not installed in the default location, then both `PYTHONPATH and LD_LIBRARY_PATH` must be set before running any Python example. 72 | 73 | #### Conda 74 | 75 | Alternatively you can install the library and handle the linking via Conda. Clone the repository, open a terminal in the repo folder and run the following commands: 76 | 77 | ```bash 78 | conda create -n ${ENV_NAME} python=3.{X} anaconda 79 | ``` 80 | 81 | where `${ENV_NAME}` should be replaced with the name of your environment, and `{X}` should be replaced with your desired python version. For example you might have ` 82 | conda create -n openfhe_python python=3.9 anaconda`. Now, you would install `pybind11` either via: 83 | 84 | `pip install "pybind11[global]"` or via `conda install -c conda-forge pybind11`, but for now we recommend using the first method, with pip. Some users have reported issues when using the conda pybind11 85 | 86 | Now, you would clone the repository, and run the following commands to install : 87 | 88 | ```bash 89 | mkdir build 90 | cd build 91 | cmake .. # Add in -DCMAKE_PREFIX_PATH=/path/to/installed/openfhe if you installed OpenFHE elsewhere 92 | make 93 | make install # You may have to run sudo make install 94 | ``` 95 | 96 | Then, you can develop the library to link 97 | 98 | ``` 99 | cd .. 100 | mkdir lib 101 | mv *.so lib 102 | conda develop lib 103 | ``` 104 | 105 | which creates a lib folder, moves the built `.so` file into that lib folder, and tells conda where to look for external libraries. 106 | 107 | **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. 108 | 109 | ## Running Tests 110 | 111 | 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. 112 | 113 | ```bash 114 | pytest [--run-long] 115 | ``` 116 | 117 | ## Code Examples 118 | 119 | To get familiar with the OpenFHE Python API, check out the examples: 120 | 121 | - FHE for arithmetic over integers (BFV): 122 | - [Simple Code Example](examples/pke/simple-integers.py) 123 | 124 | - FHE for arithmetic over integers (BGV): 125 | - [Simple Code Example](examples/pke/simple-integers-bgvrns.py) 126 | 127 | - FHE for arithmetic over real numbers (CKKS): 128 | - [Simple Code Example](examples/pke/simple-real-numbers.py) 129 | - [Advanced Code Example](examples/pke/advanced-real-numbers.py) 130 | - [Advanced Code Example for High-Precision CKKS](examples/pke/advanced-real-numbers-128.py) 131 | - [Arbitrary Smooth Function Evaluation](examples/pke/function-evaluation.py) 132 | - [Simple CKKS Bootstrapping Example](examples/pke/simple-ckks-bootstrapping.py) 133 | - [Advanced CKKS Bootstrapping Example](examples/pke/advanced-ckks-bootstrapping.cpp) 134 | - [Double-Precision (Iterative) Bootstrapping Example](examples/pke/iterative-ckks-bootstrapping.py) 135 | - FHE for Boolean circuits and larger plaintext spaces (FHEW/TFHE): 136 | - [Simple Code Example with Symmetric Encryption](examples/binfhe/boolean.py) 137 | - [Truth Table Example](examples/binfhe/boolean-truth-table.py) 138 | - Scheme Switching: 139 | - [Examples with Scheme Switching between CKKS and FHEW/TFHE](examples/pke/scheme-switching.py) 140 | 141 | 142 | 143 | 144 | - Threshold FHE: 145 | - [Code Example for BGV, BFV, and CKKS](examples/pke/threshold-fhe.py) 146 | - [Simple Interactive Bootstrapping Example](examples/pke/tckks-interactive-mp-bootstrapping.py) 147 | - [Interactive Bootstrapping after Chebyshev Approximation](examples/pke/tckks-interactive-mp-bootstrapping-Chebyschev.py) 148 | - [Code Example for BFV with 5 parties](examples/pke/threshold-fhe-5p.py) 149 | 150 | ## OpenFHE Python Wrapper Documentation 151 | 152 | [OpenFHE Python Wrapper API Reference](https://openfheorg.github.io/openfhe-python/html/index.html) 153 | 154 | ## Contributing Guide 155 | 156 | [OpenFHE Development - Contributing Guide](https://openfhe-development.readthedocs.io/en/latest/sphinx_rsts/contributing/contributing_workflow.html) 157 | -------------------------------------------------------------------------------- /build_package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Exit on any error 3 | set -e 4 | 5 | # Find the venv directory 6 | if [ -d ".venv" ]; then 7 | VENV_DIR=".venv" 8 | elif [ -d "../.venv" ]; then 9 | VENV_DIR="../.venv" 10 | else 11 | echo "The virtual environment does not exist. Please run 'python -m venv .venv' to create it." >&2 12 | exit 1 13 | fi 14 | 15 | # Activate the virtual environment 16 | source $VENV_DIR/bin/activate 17 | 18 | # Install pybind11-stubgen 19 | if ! pip show pybind11-stubgen > /dev/null; then 20 | pip install pybind11-stubgen 21 | fi 22 | 23 | # Check if the virtual environment has the openfhe package installed 24 | if ! pip show openfhe > /dev/null; then 25 | echo "The openfhe package is not installed in the virtual environment. Please run 'pip install -e .' to install it." >&2 26 | exit 1 27 | fi 28 | 29 | # Generate stub files using pybind11-stubgen 30 | echo "Generating stub files..." 31 | pybind11-stubgen openfhe 32 | 33 | # Check if stub generation was successful 34 | if [ $? -eq 0 ]; then 35 | echo "Stub files generated successfully." 36 | else 37 | echo "Stub generation failed." >&2 38 | exit 1 39 | fi 40 | 41 | # Move the generated stub files to the openfhe package directory 42 | echo "Moving the generated stub files to the openfhe package directory..." 43 | mv stubs/openfhe/* openfhe/ 44 | rm -r -d stubs 45 | 46 | # Build the source distribution and wheel distribution 47 | echo "Building the sdist and bdist_wheel..." 48 | python setup.py sdist bdist_wheel 49 | 50 | # Indicate where the distributions were saved 51 | echo "The distributions have been built and are located in the 'dist' directory. You can install the package using 'pip install dist/'." 52 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the official Ubuntu base image 2 | FROM ubuntu:22.04 3 | 4 | # Set environment variables to non-interactive (this prevents some prompts) 5 | ENV DEBIAN_FRONTEND=noninteractive 6 | 7 | # Install necessary dependencies for OpenFHE and JupyterLab 8 | RUN apt-get update && apt-get install -y \ 9 | git \ 10 | cmake \ 11 | build-essential \ 12 | python3 \ 13 | python3-dev \ 14 | python3-pip \ 15 | python3-venv \ 16 | sudo \ 17 | && apt-get clean && rm -rf /var/lib/apt/lists/* 18 | 19 | # Install PyBind11 20 | RUN pip3 install "pybind11[global]" 21 | 22 | # Install JupyterLab 23 | RUN python3 -m pip install --no-cache-dir jupyterlab 24 | 25 | # Clone and build OpenFHE-development 26 | RUN git clone https://github.com/openfheorg/openfhe-development.git \ 27 | && cd openfhe-development \ 28 | && mkdir build \ 29 | && cd build \ 30 | && cmake -DBUILD_UNITTESTS=OFF -DBUILD_EXAMPLES=OFF -DBUILD_BENCHMARKS=OFF .. \ 31 | && make -j$(nproc) \ 32 | && make install 33 | 34 | # Assume that OpenFHE installs libraries into /usr/local/lib 35 | # Update LD_LIBRARY_PATH to include this directory 36 | ENV LD_LIBRARY_PATH=/usr/local/lib:${LD_LIBRARY_PATH} 37 | 38 | # Clone and build OpenFHE-Python 39 | RUN git clone https://github.com/openfheorg/openfhe-python.git \ 40 | && cd openfhe-python \ 41 | && mkdir build \ 42 | && cd build \ 43 | && cmake .. \ 44 | && make -j$(nproc) \ 45 | && make install 46 | 47 | # Install openfhe as a pip package 48 | WORKDIR /openfhe-python 49 | RUN python3 setup.py sdist bdist_wheel && pip install dist/openfhe-*.whl 50 | 51 | # Expose the port JupyterLab will listen on 52 | EXPOSE 8888 53 | 54 | # Set the working directory 55 | WORKDIR /workspace 56 | 57 | # Start JupyterLab without token authentication 58 | CMD ["jupyter-lab", "--ip=0.0.0.0", "--no-browser", "--allow-root", "--NotebookApp.token=''", "--NotebookApp.allow_origin='*'", "--NotebookApp.password=''", "--NotebookApp.password_required=False"] -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | # Readme 2 | 3 | ### Command to build the docker image: 4 | 5 | ```docker 6 | docker build -t openfhe-docker . 7 | ``` 8 | Make sure you run this command from the same folder where the Dockerfile is located (in the "docker" folder of the openfhe-python repository). 9 | 10 | ### Command to check if the image is built: 11 | 12 | ```docker 13 | docker images 14 | ``` 15 | 16 | You should see a "openfhe-docker" in the list 17 | 18 | ### Command to create the container from the image: 19 | 20 | ```docker 21 | docker run -d -p 8888:8888 openfhe-docker 22 | ``` 23 | 24 | ### Command to check if the container is running: 25 | 26 | ```docker 27 | docker ps 28 | ``` 29 | 30 | You should see openfhe-docker running 31 | 32 | ### This openfhe-docker has jupyterlab installed in it which has access to openfhe installation and is accessible via localhost. To run the jupyterlab use: 33 | 34 | ```docker 35 | [http://localhost:8888](http://localhost:8888/) 36 | ``` 37 | 38 | All the code can be executed through this jupyterlab now 39 | 40 | ## Alternate way to execute the code in this docker: 41 | 42 | ### Go inside the docker, use: 43 | 44 | ```docker 45 | docker exec -it /bin/bash 46 | ``` 47 | 48 | replace the with the name that you see when you use the command "docker run -d -p 8888:8888 openfhe-docker" 49 | 50 | This takes you to a terminal interface inside the container which has all the dependencies installed. 51 | 52 | You can now clone a github repo that depends on OpenFHE and run the code. 53 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = . 8 | BUILDDIR = . 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/binfhe.rst: -------------------------------------------------------------------------------- 1 | BinFHEContext 2 | ---------------- 3 | 4 | .. autoclass:: openfhe.BinFHEContext 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | LWECiphertext 10 | ---------------- 11 | .. autoclass:: openfhe.LWECiphertext 12 | :members: 13 | :undoc-members: 14 | :show-inheritance: 15 | 16 | LWEPrivateKey 17 | ---------------- 18 | .. autoclass:: openfhe.LWEPrivateKey 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: -------------------------------------------------------------------------------- /docs/binfhe_enums.rst: -------------------------------------------------------------------------------- 1 | BinFHE enums 2 | ============= 3 | 4 | Parameter Set 5 | ############# 6 | 7 | .. autoclass:: openfhe.BINFHE_PARAMSET 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | 12 | BINFHE_METHOD 13 | ############# 14 | .. autoclass:: openfhe.BINFHE_METHOD 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | BinFHE Output 20 | ############# 21 | .. autoclass:: openfhe.BINFHE_OUTPUT 22 | :members: 23 | :undoc-members: 24 | :show-inheritance: 25 | 26 | Binary Gates 27 | ############# 28 | .. autoclass:: openfhe.BINGATE 29 | :members: 30 | :undoc-members: 31 | :show-inheritance: 32 | -------------------------------------------------------------------------------- /docs/ciphertext.rst: -------------------------------------------------------------------------------- 1 | Ciphertext 2 | ========== 3 | 4 | .. autoclass:: openfhe.Ciphertext 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Configuration file for the Sphinx documentation builder. 4 | # 5 | # This file does only contain a selection of the most common options. For a 6 | # full list see the documentation: 7 | # http://www.sphinx-doc.org/en/master/config 8 | 9 | # -- Path setup -------------------------------------------------------------- 10 | 11 | # If extensions (or modules to document with autodoc) are in another directory, 12 | # add these directories to sys.path here. If the directory is relative to the 13 | # documentation root, use os.path.abspath to make it absolute, like shown here. 14 | # 15 | # import os 16 | # import sys 17 | # sys.path.insert(0, os.path.abspath('.')) 18 | 19 | 20 | # -- Project information ----------------------------------------------------- 21 | 22 | project = 'openfhe-python' 23 | copyright = '2023, Yuriy Polyakov, Ian Quah, Rener Oliveira, and Matthew Triplett.' 24 | author = 'Yuriy Polyakov, Ian Quah, Rener Oliveira, and Matthew Triplett.' 25 | 26 | # The short X.Y version 27 | version = '' 28 | # The full version, including alpha/beta/rc tags 29 | release = '0.8.0' 30 | 31 | 32 | # -- General configuration --------------------------------------------------- 33 | 34 | # If your documentation needs a minimal Sphinx version, state it here. 35 | # 36 | # needs_sphinx = '1.0' 37 | 38 | # Add any Sphinx extension module names here, as strings. They can be 39 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 40 | # ones. 41 | extensions = [ 42 | 'sphinx.ext.autodoc', 43 | 'sphinx.ext.autosummary', 44 | 'sphinx.ext.intersphinx', 45 | 'sphinx.ext.napoleon' 46 | ] 47 | 48 | # Add any paths that contain templates here, relative to this directory. 49 | templates_path = ['_templates'] 50 | 51 | # The suffix(es) of source filenames. 52 | # You can specify multiple suffix as a list of string: 53 | # 54 | # source_suffix = ['.rst', '.md'] 55 | source_suffix = '.rst' 56 | 57 | # The master toctree document. 58 | master_doc = 'index' 59 | 60 | # The language for content autogenerated by Sphinx. Refer to documentation 61 | # for a list of supported languages. 62 | # 63 | # This is also used if you do content translation via gettext catalogs. 64 | # Usually you set "language" from the command line for these cases. 65 | language = 'en' 66 | 67 | # List of patterns, relative to source directory, that match files and 68 | # directories to ignore when looking for source files. 69 | # This pattern also affects html_static_path and html_extra_path. 70 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 71 | 72 | # The name of the Pygments (syntax highlighting) style to use. 73 | pygments_style = None 74 | 75 | 76 | # -- Options for HTML output ------------------------------------------------- 77 | 78 | # The theme to use for HTML and HTML Help pages. See the documentation for 79 | # a list of builtin themes. 80 | # 81 | html_theme = 'sphinx_rtd_theme' 82 | 83 | # Theme options are theme-specific and customize the look and feel of a theme 84 | # further. For a list of options available for each theme, see the 85 | # documentation. 86 | # 87 | # html_theme_options = {} 88 | 89 | # Add any paths that contain custom static files (such as style sheets) here, 90 | # relative to this directory. They are copied after the builtin static files, 91 | # so a file named "default.css" will overwrite the builtin "default.css". 92 | html_static_path = ['_static'] 93 | 94 | # Custom sidebar templates, must be a dictionary that maps document names 95 | # to template names. 96 | # 97 | # The default sidebars (for documents that don't match any pattern) are 98 | # defined by theme itself. Builtin themes are using these templates by 99 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', 100 | # 'searchbox.html']``. 101 | # 102 | # html_sidebars = {} 103 | 104 | 105 | # -- Options for HTMLHelp output --------------------------------------------- 106 | 107 | # Output file base name for HTML help builder. 108 | htmlhelp_basename = 'openfhe-pythondoc' 109 | 110 | 111 | # -- Options for LaTeX output ------------------------------------------------ 112 | 113 | latex_elements = { 114 | # The paper size ('letterpaper' or 'a4paper'). 115 | # 116 | # 'papersize': 'letterpaper', 117 | 118 | # The font size ('10pt', '11pt' or '12pt'). 119 | # 120 | # 'pointsize': '10pt', 121 | 122 | # Additional stuff for the LaTeX preamble. 123 | # 124 | # 'preamble': '', 125 | 126 | # Latex figure (float) alignment 127 | # 128 | # 'figure_align': 'htbp', 129 | } 130 | 131 | # Grouping the document tree into LaTeX files. List of tuples 132 | # (source start file, target name, title, 133 | # author, documentclass [howto, manual, or own class]). 134 | latex_documents = [ 135 | (master_doc, 'openfhe-python.tex', 'openfhe-python Documentation', 136 | 'Yuriy Polyakov, Ian Quah, Rener Oliveira, and Matthew Triplett.', 'manual'), 137 | ] 138 | 139 | 140 | # -- Options for manual page output ------------------------------------------ 141 | 142 | # One entry per manual page. List of tuples 143 | # (source start file, name, description, authors, manual section). 144 | man_pages = [ 145 | (master_doc, 'openfhe-python', 'openfhe-python Documentation', 146 | [author], 1) 147 | ] 148 | 149 | 150 | # -- Options for Texinfo output ---------------------------------------------- 151 | 152 | # Grouping the document tree into Texinfo files. List of tuples 153 | # (source start file, target name, title, author, 154 | # dir menu entry, description, category) 155 | texinfo_documents = [ 156 | (master_doc, 'openfhe-python', 'openfhe-python Documentation', 157 | author, 'openfhe-python', 'One line description of project.', 158 | 'Miscellaneous'), 159 | ] 160 | 161 | 162 | # -- Options for Epub output ------------------------------------------------- 163 | 164 | # Bibliographic Dublin Core info. 165 | epub_title = project 166 | 167 | # The unique identifier of the text. This can be a ISBN number 168 | # or the project homepage. 169 | # 170 | # epub_identifier = '' 171 | 172 | # A unique identification for the text. 173 | # 174 | # epub_uid = '' 175 | 176 | # A list of files that should not be packed into the epub file. 177 | epub_exclude_files = ['search.html'] 178 | -------------------------------------------------------------------------------- /docs/cryptocontext.rst: -------------------------------------------------------------------------------- 1 | CryptoContext 2 | ============= 3 | 4 | .. autoclass:: openfhe.CryptoContext 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | :noindex: 9 | -------------------------------------------------------------------------------- /docs/cryptoparams.rst: -------------------------------------------------------------------------------- 1 | CryptoParams 2 | ============ 3 | 4 | The following crypto parameter objects are available per scheme **BFV**, **BGV** and **CKKS** respectively. 5 | 6 | CyrptoParamsBFVRNS 7 | ################## 8 | .. autoclass:: openfhe.CCParamsBFVRNS 9 | :members: 10 | :show-inheritance: 11 | 12 | CryptoParamsBGVRNS 13 | ################## 14 | .. autoclass:: openfhe.CCParamsBGVRNS 15 | :members: 16 | :show-inheritance: 17 | 18 | 19 | CryptoParamsCKKSRNS 20 | ################### 21 | .. autoclass:: openfhe.CCParamsCKKSRNS 22 | :members: 23 | :show-inheritance: 24 | 25 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. openfhe-python documentation master file, created by 2 | sphinx-quickstart on Tue Jul 25 18:24:19 2023. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to OpenFHE - Python's documentation! 7 | ============================================ 8 | 9 | OpenFHE - Python 10 | ---------------- 11 | Fully Homomorphic Encryption (FHE) is a powerful cryptographic primitive that enables performing computations over encrypted data without having access to the secret key. `OpenFHE `_ is an open-source FHE library that includes efficient implementations of all common FHE schemes: BFV, BGV, CKKS, DM and CGGI. 12 | 13 | ``openfhe-python`` is a Python library built as a wrapper for the main capabilities of OpenFHE C++ library. It provides a more user-friendly interface for Python developers, 14 | while keeping the efficiency of C++ FHE operations. 15 | 16 | .. toctree:: 17 | :maxdepth: 3 18 | :caption: API Reference: 19 | 20 | cryptocontext 21 | cryptoparams 22 | ciphertext 23 | plaintext 24 | keys 25 | pke_enums 26 | binfhe 27 | binfhe_enums 28 | 29 | -------------------------------------------------------------------------------- /docs/keys.rst: -------------------------------------------------------------------------------- 1 | Public Key 2 | =========== 3 | 4 | .. autoclass:: openfhe.PublicKey 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | 9 | Private Key 10 | =========== 11 | .. autoclass:: openfhe.PrivateKey 12 | :members: 13 | :undoc-members: 14 | :show-inheritance: 15 | 16 | KeyPair 17 | ======= 18 | .. autoclass:: openfhe.KeyPair 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=. 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/pke_enums.rst: -------------------------------------------------------------------------------- 1 | PKE enums 2 | ============= 3 | 4 | Scheme Types 5 | ############# 6 | 7 | .. autoclass:: openfhe.SCHEME 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | 12 | PKE Scheme Features 13 | #################### 14 | .. autoclass:: openfhe.PKESchemeFeature 15 | :members: 16 | :undoc-members: 17 | :show-inheritance: 18 | 19 | Scaling Techniques 20 | #################### 21 | .. autoclass:: openfhe.ScalingTechnique 22 | :members: 23 | :undoc-members: 24 | :show-inheritance: 25 | 26 | Key Switching Techniques 27 | ######################## 28 | .. autoclass:: openfhe.KeySwitchTechnique 29 | :members: 30 | :undoc-members: 31 | :show-inheritance: 32 | 33 | Secret Key Dist 34 | ################ 35 | .. autoclass:: openfhe.SecretKeyDist 36 | :members: 37 | :undoc-members: 38 | :show-inheritance: 39 | 40 | Proxy Reencryption Mode 41 | ####################### 42 | .. autoclass:: openfhe.ProxyReEncryptionMode 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | Multiparty Mode 48 | ############### 49 | .. autoclass:: openfhe.MultipartyMode 50 | :members: 51 | :undoc-members: 52 | :show-inheritance: 53 | 54 | Execution Mode 55 | ############### 56 | .. autoclass:: openfhe.ExecutionMode 57 | :members: 58 | :undoc-members: 59 | :show-inheritance: 60 | 61 | Decryption Noise Mode 62 | ###################### 63 | .. autoclass:: openfhe.DecryptionNoiseMode 64 | :members: 65 | :undoc-members: 66 | :show-inheritance: 67 | 68 | Encryption Technique 69 | ##################### 70 | .. autoclass:: openfhe.EncryptionTechnique 71 | :members: 72 | :undoc-members: 73 | :show-inheritance: 74 | 75 | Multiplication Technique 76 | ######################### 77 | .. autoclass:: openfhe.MultiplicationTechnique 78 | :members: 79 | :undoc-members: 80 | :show-inheritance: 81 | 82 | Security Level 83 | ############### 84 | .. autoclass:: openfhe.SecurityLevel 85 | :members: 86 | :undoc-members: 87 | :show-inheritance: 88 | 89 | """ 90 | -------------------------------------------------------------------------------- /docs/plaintext.rst: -------------------------------------------------------------------------------- 1 | Plaintext 2 | ============= 3 | 4 | .. autoclass:: openfhe.Plaintext 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | alabaster==0.7.12 2 | Babel==2.9.1 3 | breathe==4.33.1 4 | certifi==2021.10.8 5 | charset-normalizer==2.0.12 6 | docutils==0.17.1 7 | exhale>=0.3.0 8 | idna==3.3 9 | imagesize==1.3.0 10 | importlib-metadata>=4.0.0 11 | Jinja2==3.0.3 12 | MarkupSafe>=2.0.0 13 | packaging==21.3 14 | pybind11>=2.10.3 15 | pybind11-global>=2.10.3 16 | Pygments==2.11.2 17 | pyparsing==3.0.7 18 | pytz==2021.3 19 | requests==2.27.1 20 | setuptools==69.0.3 21 | snowballstemmer==2.2.0 22 | Sphinx==4.4.0 23 | sphinx-rtd-theme==1.0.0 24 | sphinxcontrib-applehelp==1.0.2 25 | sphinxcontrib-devhelp==1.0.2 26 | sphinxcontrib-htmlhelp==2.0.0 27 | sphinxcontrib-jsmath==1.0.1 28 | sphinxcontrib-mermaid==0.7.1 29 | sphinxcontrib-qthelp==1.0.3 30 | sphinxcontrib-serializinghtml==1.1.5 31 | tomli==1.2.2 32 | typing-extensions==4.7.1 33 | wheel==0.38.4 34 | zipp>=3.7.0 35 | -------------------------------------------------------------------------------- /examples/binfhe/boolean-ap.py: -------------------------------------------------------------------------------- 1 | from openfhe import * 2 | 3 | ## Sample Program: Step 1: Set CryptoContext 4 | 5 | cc = BinFHEContext() 6 | 7 | """ 8 | STD128 is the security level of 128 bits of security based on LWE Estimator 9 | and HE standard. Other common options are TOY, MEDIUM, STD192, and STD256. 10 | MEDIUM corresponds to the level of more than 100 bits for both quantum and 11 | classical computer attacks. The second argument is the bootstrapping method 12 | (AP or GINX). The default method is GINX. Here we explicitly set AP. GINX 13 | typically provides better performance: the bootstrapping key is much 14 | smaller in GINX (by 20x) while the runtime is roughly the same. 15 | """ 16 | cc.GenerateBinFHEContext(STD128,AP) 17 | 18 | ## Sample Program: Step 2: Key Generation 19 | 20 | # Generate the secret key 21 | sk = cc.KeyGen() 22 | 23 | print("Generating the bootstrapping keys...\n") 24 | 25 | # Generate the bootstrapping keys (refresh and switching keys) 26 | cc.BTKeyGen(sk) 27 | 28 | print("Completed the key generation.\n") 29 | # Sample Program: Step 3: Encryption 30 | """ 31 | Encrypt two ciphertexts representing Boolean True (1). 32 | By default, freshly encrypted ciphertexts are bootstrapped. 33 | If you wish to get a fresh encryption without bootstrapping, write 34 | ct1 = cc.Encrypt(sk, 1, FRESH) 35 | """ 36 | ct1 = cc.Encrypt(sk, 1) 37 | ct2 = cc.Encrypt(sk, 1) 38 | 39 | # Sample Program: Step 4: Evaluation 40 | 41 | # Compute (1 AND 1) = 1; Other binary gate options are OR, NAND, and NOR 42 | ctAND1 = cc.EvalBinGate(AND, ct1, ct2) 43 | 44 | # Compute (NOT 1) = 0 45 | ct2Not = cc.EvalNOT(ct2) 46 | 47 | # Compute (1 AND (NOT 1)) = 0 48 | ctAND2 = cc.EvalBinGate(AND, ct2Not, ct1) 49 | 50 | # Compute OR of the result in ctAND1 and ctAND2 51 | ctResult = cc.EvalBinGate(OR, ctAND1, ctAND2) 52 | 53 | # Sample Program: Step 5: Decryption 54 | 55 | result = cc.Decrypt(sk, ctResult) 56 | 57 | print(f"Result of encrypted computation of (1 AND 1) OR (1 AND (NOT 1)) = {result}") 58 | 59 | -------------------------------------------------------------------------------- /examples/binfhe/boolean-lmkcdey.py: -------------------------------------------------------------------------------- 1 | from openfhe import * 2 | 3 | ## Sample Program: Step 1: Set CryptoContext 4 | 5 | cc = BinFHEContext() 6 | 7 | # We use the STD128 setting optimized for the LMKCDEY mode. 8 | cc.GenerateBinFHEContext(STD128,LMKCDEY) 9 | 10 | ## Sample Program: Step 2: Key Generation 11 | 12 | # Generate the secret key 13 | sk = cc.KeyGen() 14 | 15 | print("Generating the bootstrapping keys...\n") 16 | 17 | # Generate the bootstrapping keys (refresh and switching keys) 18 | cc.BTKeyGen(sk) 19 | 20 | print("Completed the key generation.\n") 21 | 22 | # Sample Program: Step 3: Encryption 23 | """ 24 | Encrypt two ciphertexts representing Boolean True (1). 25 | By default, freshly encrypted ciphertexts are bootstrapped. 26 | If you wish to get a fresh encryption without bootstrapping, write 27 | ct1 = cc.Encrypt(sk, 1, FRESH) 28 | """ 29 | ct1 = cc.Encrypt(sk, 1) 30 | ct2 = cc.Encrypt(sk, 1) 31 | 32 | # Sample Program: Step 4: Evaluation 33 | 34 | # Compute (1 AND 1) = 1; Other binary gate options are OR, NAND, and NOR 35 | ctAND1 = cc.EvalBinGate(AND, ct1, ct2) 36 | 37 | # Compute (NOT 1) = 0 38 | ct2Not = cc.EvalNOT(ct2) 39 | 40 | # Compute (1 AND (NOT 1)) = 0 41 | ctAND2 = cc.EvalBinGate(AND, ct2Not, ct1) 42 | 43 | # Compute OR of the result in ctAND1 and ctAND2 44 | ctResult = cc.EvalBinGate(OR, ctAND1, ctAND2) 45 | 46 | # Sample Program: Step 5: Decryption 47 | 48 | result = cc.Decrypt(sk, ctResult) 49 | 50 | print(f"Result of encrypted computation of (1 AND 1) OR (1 AND (NOT 1)) = {result}") 51 | 52 | -------------------------------------------------------------------------------- /examples/binfhe/boolean-truth-tables.py: -------------------------------------------------------------------------------- 1 | from openfhe import * 2 | 3 | # Sample Program: Step 1: Set CryptoContext 4 | cc = BinFHEContext() 5 | 6 | print("Generate cryptocontext\n") 7 | 8 | """ 9 | STD128 is the security level of 128 bits of security based on LWE Estimator 10 | and HE standard. Other common options are TOY, MEDIUM, STD192, and STD256. MEDIUM 11 | corresponds to the level of more than 100 bits for both quantum and 12 | classical computer attacks 13 | """ 14 | 15 | cc.GenerateBinFHEContext(STD128) 16 | print("Finished generating cryptocontext\n") 17 | 18 | # Sample Program: Step 2: Key Generation 19 | 20 | # Generate the secret key 21 | sk = cc.KeyGen() 22 | 23 | print("Generating the bootstrapping keys...\n") 24 | 25 | # Generate the bootstrapping keys (refresh and switching keys) 26 | cc.BTKeyGen(sk) 27 | 28 | print("Completed the key generation.\n\n") 29 | 30 | # Sample Program: Step 3: Encryption 31 | 32 | # Encrypt two ciphertexts representing Boolean True (1). 33 | ct10 = cc.Encrypt(sk, 1) 34 | ct11 = cc.Encrypt(sk, 1) 35 | # Encrypt two ciphertexts representing Boolean False (0). 36 | ct00 = cc.Encrypt(sk, 0) 37 | ct01 = cc.Encrypt(sk, 0) 38 | 39 | # Sample Program: Step 4: Evaluation of NAND gates 40 | 41 | ctNAND1 = cc.EvalBinGate(NAND, ct10, ct11) 42 | ctNAND2 = cc.EvalBinGate(NAND, ct10, ct01) 43 | ctNAND3 = cc.EvalBinGate(NAND, ct00, ct01) 44 | ctNAND4 = cc.EvalBinGate(NAND, ct00, ct11) 45 | 46 | result = cc.Decrypt(sk, ctNAND1) 47 | print(f"1 NAND 1 = {result}") 48 | 49 | result = cc.Decrypt(sk, ctNAND2) 50 | print(f"1 NAND 0 = {result}") 51 | 52 | result = cc.Decrypt(sk, ctNAND3) 53 | print(f"0 NAND 0 = {result}") 54 | 55 | result = cc.Decrypt(sk, ctNAND4) 56 | print(f"0 NAND 1 = {result}") 57 | 58 | # Sample Program: Step 5: Evaluation of AND gates 59 | 60 | ctAND1 = cc.EvalBinGate(AND, ct10, ct11) 61 | ctAND2 = cc.EvalBinGate(AND, ct10, ct01) 62 | ctAND3 = cc.EvalBinGate(AND, ct00, ct01) 63 | ctAND4 = cc.EvalBinGate(AND, ct00, ct11) 64 | 65 | result = cc.Decrypt(sk, ctAND1) 66 | print(f"1 AND 1 = {result}") 67 | 68 | result = cc.Decrypt(sk, ctAND2) 69 | print(f"1 AND 0 = {result}") 70 | 71 | result = cc.Decrypt(sk, ctAND3) 72 | print(f"0 AND 0 = {result}") 73 | 74 | result = cc.Decrypt(sk, ctAND4) 75 | print(f"0 AND 1 = {result}") 76 | 77 | # Sample Program: Step 6: Evaluation of OR gates 78 | 79 | ctOR1 = cc.EvalBinGate(OR, ct10, ct11) 80 | ctOR2 = cc.EvalBinGate(OR, ct10, ct01) 81 | ctOR3 = cc.EvalBinGate(OR, ct00, ct01) 82 | ctOR4 = cc.EvalBinGate(OR, ct00, ct11) 83 | 84 | result = cc.Decrypt(sk, ctOR1) 85 | print(f"1 OR 1 = {result}") 86 | 87 | result = cc.Decrypt(sk, ctOR2) 88 | print(f"1 OR 0 = {result}") 89 | 90 | result = cc.Decrypt(sk, ctOR3) 91 | print(f"0 OR 0 = {result}") 92 | 93 | result = cc.Decrypt(sk, ctOR4) 94 | print(f"0 OR 1 = {result}") 95 | 96 | # Sample Program: Step 7: Evaluation of NOR gates 97 | 98 | ctNOR1 = cc.EvalBinGate(NOR, ct10, ct11) 99 | ctNOR2 = cc.EvalBinGate(NOR, ct10, ct01) 100 | ctNOR3 = cc.EvalBinGate(NOR, ct00, ct01) 101 | ctNOR4 = cc.EvalBinGate(NOR, ct00, ct11) 102 | 103 | result = cc.Decrypt(sk, ctNOR1) 104 | print(f"1 NOR 1 = {result}") 105 | 106 | result = cc.Decrypt(sk, ctNOR2) 107 | print(f"1 NOR 0 = {result}") 108 | 109 | result = cc.Decrypt(sk, ctNOR3) 110 | print(f"0 NOR 0 = {result}") 111 | 112 | result = cc.Decrypt(sk, ctNOR4) 113 | print(f"0 NOR 1 = {result}") 114 | 115 | # Sample Program: Step 8: Evaluation of XOR gates 116 | 117 | ctXOR1 = cc.EvalBinGate(XOR, ct10, ct11) 118 | ctXOR2 = cc.EvalBinGate(XOR, ct10, ct01) 119 | ctXOR3 = cc.EvalBinGate(XOR, ct00, ct01) 120 | ctXOR4 = cc.EvalBinGate(XOR, ct00, ct11) 121 | 122 | result = cc.Decrypt(sk, ctXOR1) 123 | print(f"1 XOR 1 = {result}") 124 | 125 | result = cc.Decrypt(sk, ctXOR2) 126 | print(f"1 XOR 0 = {result}") 127 | 128 | result = cc.Decrypt(sk, ctXOR3) 129 | print(f"0 XOR 0 = {result}") 130 | 131 | result = cc.Decrypt(sk, ctXOR4) 132 | print(f"0 XOR 1 = {result}") 133 | 134 | # Sample Program: Step 9: Evaluation of XNOR gates 135 | 136 | ctXNOR1 = cc.EvalBinGate(XNOR, ct10, ct11) 137 | ctXNOR2 = cc.EvalBinGate(XNOR, ct10, ct01) 138 | ctXNOR3 = cc.EvalBinGate(XNOR, ct00, ct01) 139 | ctXNOR4 = cc.EvalBinGate(XNOR, ct00, ct11) 140 | 141 | result = cc.Decrypt(sk, ctXNOR1) 142 | print(f"1 XNOR 1 = {result}") 143 | 144 | result = cc.Decrypt(sk, ctXNOR2) 145 | print(f"1 XNOR 0 = {result}") 146 | 147 | result = cc.Decrypt(sk, ctXNOR3) 148 | print(f"0 XNOR 0 = {result}") 149 | 150 | result = cc.Decrypt(sk, ctXNOR4) 151 | print(f"0 XNOR 1 = {result}") 152 | 153 | # Sample Program: Step 90: Evaluation of NOR gates 154 | # using XOR_FAT (1 boostrap but the probability of failure is higher) 155 | 156 | ctNOR1_FAST = cc.EvalBinGate(XOR_FAST, ct10, ct11) 157 | ctNOR2_FAST = cc.EvalBinGate(XOR_FAST, ct10, ct01) 158 | ctNOR3_FAST = cc.EvalBinGate(XOR_FAST, ct00, ct01) 159 | ctNOR4_FAST = cc.EvalBinGate(XOR_FAST, ct00, ct11) 160 | 161 | result = cc.Decrypt(sk, ctNOR1_FAST) 162 | print(f"1 XOR_FAST 1 = {result}") 163 | 164 | result = cc.Decrypt(sk, ctNOR2_FAST) 165 | print(f"1 XOR_FAST 0 = {result}") 166 | 167 | result = cc.Decrypt(sk, ctNOR3_FAST) 168 | print(f"0 XOR_FAST 0 = {result}") 169 | 170 | result = cc.Decrypt(sk, ctNOR4_FAST) 171 | print(f"0 XOR_FAST 1 = {result}") 172 | 173 | # Sample Program: Step 10: Evaluation of XNOR gates 174 | # using XNOR_FAT (1 boostrap but the probability of failure is higher) 175 | 176 | ctXNOR1_FAST = cc.EvalBinGate(XNOR_FAST, ct10, ct11) 177 | ctXNOR2_FAST = cc.EvalBinGate(XNOR_FAST, ct10, ct01) 178 | ctXNOR3_FAST = cc.EvalBinGate(XNOR_FAST, ct00, ct01) 179 | ctXNOR4_FAST = cc.EvalBinGate(XNOR_FAST, ct00, ct11) 180 | 181 | result = cc.Decrypt(sk, ctXNOR1_FAST) 182 | print(f"1 XNOR_FAST 1 = {result}") 183 | 184 | result = cc.Decrypt(sk, ctXNOR2_FAST) 185 | print(f"1 XNOR_FAST 0 = {result}") 186 | 187 | result = cc.Decrypt(sk, ctXNOR3_FAST) 188 | print(f"0 XNOR_FAST 0 = {result}") 189 | 190 | result = cc.Decrypt(sk, ctXNOR4_FAST) 191 | print(f"0 XNOR_FAST 1 = {result}") 192 | 193 | 194 | 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /examples/binfhe/boolean.py: -------------------------------------------------------------------------------- 1 | from openfhe import * 2 | 3 | ## Sample Program: Step 1: Set CryptoContext 4 | 5 | cc = BinFHEContext() 6 | 7 | """ 8 | STD128 is the security level of 128 bits of security based on LWE Estimator 9 | and HE standard. Other common options are TOY, MEDIUM, STD192, and STD256. 10 | MEDIUM corresponds to the level of more than 100 bits for both quantum and 11 | classical computer attacks 12 | """ 13 | cc.GenerateBinFHEContext(STD128,GINX) 14 | 15 | ## Sample Program: Step 2: Key Generation 16 | 17 | # Generate the secret key 18 | sk = cc.KeyGen() 19 | 20 | print("Generating the bootstrapping keys...\n") 21 | 22 | # Generate the bootstrapping keys (refresh and switching keys) 23 | cc.BTKeyGen(sk) 24 | 25 | # Sample Program: Step 3: Encryption 26 | """ 27 | Encrypt two ciphertexts representing Boolean True (1). 28 | By default, freshly encrypted ciphertexts are bootstrapped. 29 | If you wish to get a fresh encryption without bootstrapping, write 30 | ct1 = cc.Encrypt(sk, 1, FRESH) 31 | """ 32 | ct1 = cc.Encrypt(sk, 1) 33 | ct2 = cc.Encrypt(sk, 1) 34 | 35 | # Sample Program: Step 4: Evaluation 36 | 37 | # Compute (1 AND 1) = 1; Other binary gate options are OR, NAND, and NOR 38 | ctAND1 = cc.EvalBinGate(AND, ct1, ct2) 39 | 40 | # Compute (NOT 1) = 0 41 | ct2Not = cc.EvalNOT(ct2) 42 | 43 | # Compute (1 AND (NOT 1)) = 0 44 | ctAND2 = cc.EvalBinGate(AND, ct2Not, ct1) 45 | 46 | # Compute OR of the result in ctAND1 and ctAND2 47 | ctResult = cc.EvalBinGate(OR, ctAND1, ctAND2) 48 | 49 | # Sample Program: Step 5: Decryption 50 | 51 | result = cc.Decrypt(sk, ctResult) 52 | 53 | print(f"Result of encrypted computation of (1 AND 1) OR (1 AND (NOT 1)) = {result}") 54 | 55 | -------------------------------------------------------------------------------- /examples/pke/function-evaluation.py: -------------------------------------------------------------------------------- 1 | from openfhe import * 2 | import math 3 | 4 | def main(): 5 | eval_logistic_example() 6 | eval_function_example() 7 | 8 | def eval_logistic_example(): 9 | print("--------------------------------- EVAL LOGISTIC FUNCTION ---------------------------------\n") 10 | parameters = CCParamsCKKSRNS() 11 | parameters.SetSecurityLevel(SecurityLevel.HEStd_NotSet) 12 | parameters.SetRingDim(1 << 10) 13 | 14 | scaling_mod_size = 59 15 | first_mod_size = 60 16 | 17 | parameters.SetScalingModSize(scaling_mod_size) 18 | parameters.SetFirstModSize(first_mod_size) 19 | 20 | poly_degree = 16 21 | mult_depth = 6 22 | 23 | parameters.SetMultiplicativeDepth(mult_depth) 24 | cc = GenCryptoContext(parameters) 25 | cc.Enable(PKESchemeFeature.PKE) 26 | cc.Enable(PKESchemeFeature.KEYSWITCH) 27 | cc.Enable(PKESchemeFeature.LEVELEDSHE) 28 | cc.Enable(PKESchemeFeature.ADVANCEDSHE) 29 | 30 | key_pair = cc.KeyGen() 31 | cc.EvalMultKeyGen(key_pair.secretKey) 32 | 33 | input = [-4, -3, -2, -1, 0, 1, 2, 3, 4] 34 | encoded_length = len(input) 35 | plaintext = cc.MakeCKKSPackedPlaintext(input) 36 | ciphertext = cc.Encrypt(key_pair.publicKey, plaintext) 37 | 38 | lower_bound = -4 39 | upper_bound = 4 40 | result = cc.EvalLogistic(ciphertext, lower_bound, upper_bound, poly_degree) 41 | 42 | plaintext_dec = cc.Decrypt(result, key_pair.secretKey) 43 | plaintext_dec.SetLength(encoded_length) 44 | 45 | expected_output = [0.0179885, 0.0474289, 0.119205, 0.268936, 0.5, 0.731064, 0.880795, 0.952571, 0.982011] 46 | print(f"Expected output\n\t {expected_output}\n") 47 | 48 | final_result = plaintext_dec.GetCKKSPackedValue() 49 | print(f"Actual output\n\t {final_result}\n") 50 | 51 | def eval_function_example(): 52 | print("--------------------------------- EVAL SQUARE ROOT FUNCTION ---------------------------------\n") 53 | parameters = CCParamsCKKSRNS() 54 | parameters.SetSecurityLevel(SecurityLevel.HEStd_NotSet) 55 | parameters.SetRingDim(1 << 10) 56 | 57 | if get_native_int() == 128: 58 | scaling_mod_size = 78 59 | first_mod_size = 89 60 | else: 61 | scaling_mod_size = 50 62 | first_mod_size = 60 63 | 64 | parameters.SetScalingModSize(scaling_mod_size) 65 | parameters.SetFirstModSize(first_mod_size) 66 | 67 | poly_degree = 50 68 | mult_depth = 7 69 | 70 | parameters.SetMultiplicativeDepth(mult_depth) 71 | cc = GenCryptoContext(parameters) 72 | cc.Enable(PKESchemeFeature.PKE) 73 | cc.Enable(PKESchemeFeature.KEYSWITCH) 74 | cc.Enable(PKESchemeFeature.LEVELEDSHE) 75 | cc.Enable(PKESchemeFeature.ADVANCEDSHE) 76 | 77 | key_pair = cc.KeyGen() 78 | cc.EvalMultKeyGen(key_pair.secretKey) 79 | 80 | input = [1, 2, 3, 4, 5, 6, 7, 8, 9] 81 | encoded_length = len(input) 82 | plaintext = cc.MakeCKKSPackedPlaintext(input) 83 | ciphertext = cc.Encrypt(key_pair.publicKey, plaintext) 84 | 85 | lower_bound = 0 86 | upper_bound = 10 87 | result = cc.EvalChebyshevFunction(math.sqrt,ciphertext, lower_bound, upper_bound, poly_degree) 88 | 89 | plaintext_dec = cc.Decrypt(result, key_pair.secretKey) 90 | plaintext_dec.SetLength(encoded_length) 91 | 92 | expected_output = [1, 1.414213, 1.732050, 2, 2.236067, 2.449489, 2.645751, 2.828427, 3] 93 | print(f"Expected output\n\t {expected_output}\n") 94 | 95 | final_result = plaintext_dec.GetCKKSPackedValue() 96 | print(f"Actual output\n\t {final_result}\n") 97 | if __name__ == "__main__": 98 | main() -------------------------------------------------------------------------------- /examples/pke/iterative-ckks-bootstrapping.py: -------------------------------------------------------------------------------- 1 | from openfhe import * 2 | import math 3 | import random 4 | 5 | def main(): 6 | iterative_bootstrap_example() 7 | 8 | def calculate_approximation_error(result,expected_result): 9 | if len(result) != len(expected_result): 10 | raise Exception("Cannot compare vectors with different numbers of elements") 11 | # using the infinity norm 12 | # error is abs of the difference of real parts 13 | max_error = max([abs(el1.real - el2.real) for (el1, el2) in zip(result, expected_result)]) 14 | # return absolute value of log base2 of the error 15 | return abs(math.log(max_error,2)) 16 | def iterative_bootstrap_example(): 17 | # Step 1: Set CryptoContext 18 | parameters = CCParamsCKKSRNS() 19 | secret_key_dist = SecretKeyDist.UNIFORM_TERNARY 20 | parameters.SetSecretKeyDist(secret_key_dist) 21 | parameters.SetSecurityLevel(SecurityLevel.HEStd_NotSet) 22 | parameters.SetRingDim(1 << 12) 23 | 24 | if get_native_int()==128: 25 | rescale_tech = ScalingTechnique.FIXEDAUTO 26 | dcrt_bits = 78 27 | first_mod = 89 28 | else: 29 | rescale_tech = ScalingTechnique.FLEXIBLEAUTO 30 | dcrt_bits = 59 31 | first_mod = 60 32 | 33 | parameters.SetScalingModSize(dcrt_bits) 34 | parameters.SetScalingTechnique(rescale_tech) 35 | parameters.SetFirstModSize(first_mod) 36 | 37 | # Here, we specify the number of iterations to run bootstrapping. 38 | # Note that we currently only support 1 or 2 iterations. 39 | # Two iterations should give us approximately double the precision of one iteration. 40 | num_iterations = 2 41 | 42 | level_budget = [3, 3] 43 | bsgs_dim = [0,0] 44 | 45 | levels_available_after_bootstrap = 10 46 | depth = levels_available_after_bootstrap = 10 + FHECKKSRNS.GetBootstrapDepth(level_budget, secret_key_dist) + (num_iterations - 1) 47 | parameters.SetMultiplicativeDepth(depth) 48 | 49 | # Generate crypto context 50 | cryptocontext = GenCryptoContext(parameters) 51 | 52 | # Enable features that you wish to use. Note, we must enable FHE to use bootstrapping. 53 | 54 | cryptocontext.Enable(PKESchemeFeature.PKE) 55 | cryptocontext.Enable(PKESchemeFeature.KEYSWITCH) 56 | cryptocontext.Enable(PKESchemeFeature.LEVELEDSHE) 57 | cryptocontext.Enable(PKESchemeFeature.ADVANCEDSHE) 58 | cryptocontext.Enable(PKESchemeFeature.FHE) 59 | 60 | ring_dim = cryptocontext.GetRingDimension() 61 | print(f"CKKS is using ring dimension {ring_dim}\n\n") 62 | 63 | # Step 2: Precomputations for bootstrapping 64 | # We use a sparse packing 65 | num_slots = 8 66 | cryptocontext.EvalBootstrapSetup(level_budget, bsgs_dim, num_slots) 67 | 68 | # Step 3: Key generation 69 | key_pair = cryptocontext.KeyGen() 70 | cryptocontext.EvalMultKeyGen(key_pair.secretKey) 71 | # Generate bootstrapping keys. 72 | cryptocontext.EvalBootstrapKeyGen(key_pair.secretKey, num_slots) 73 | 74 | # Step 4: Encoding and encryption of inputs 75 | # Generate random input 76 | x = [random.uniform(0, 1) for i in range(num_slots)] 77 | 78 | """ Encoding as plaintexts 79 | We specify the number of slots as num_slots to achieve a performance improvement. 80 | We use the other default values of depth 1, levels 0, and no params. 81 | Alternatively, you can also set batch size as a parameter in the CryptoContext as follows: 82 | parameters.SetBatchSize(num_slots); 83 | Here, we assume all ciphertexts in the cryptoContext will have num_slots slots. 84 | We start with a depleted ciphertext that has used up all of its levels.""" 85 | ptxt = cryptocontext.MakeCKKSPackedPlaintext(x, 1, depth -1,None,num_slots) 86 | ptxt.SetLength(num_slots) 87 | print(f"Input: {ptxt}") 88 | 89 | # Encrypt the encoded vectors 90 | ciph = cryptocontext.Encrypt(key_pair.publicKey, ptxt) 91 | 92 | # Step 5: Measure the precision of a single bootstrapping operation. 93 | ciphertext_after = cryptocontext.EvalBootstrap(ciph) 94 | 95 | result = cryptocontext.Decrypt(ciphertext_after,key_pair.secretKey) 96 | result.SetLength(num_slots) 97 | precision = calculate_approximation_error(result.GetCKKSPackedValue(),ptxt.GetCKKSPackedValue()) 98 | print(f"Bootstrapping precision after 1 iteration: {precision} bits\n") 99 | 100 | # Set the precision equal to empirically measured value after many test runs. 101 | precision = 17 102 | print(f"Precision input to algorithm: {precision}\n") 103 | 104 | # Step 6: Run bootstrapping with multiple iterations 105 | ciphertext_two_iterations = cryptocontext.EvalBootstrap(ciph,num_iterations,precision) 106 | 107 | result_two_iterations = cryptocontext.Decrypt(ciphertext_two_iterations,key_pair.secretKey) 108 | result_two_iterations.SetLength(num_slots) 109 | actual_result = result_two_iterations.GetCKKSPackedValue() 110 | 111 | print(f"Output after two interations of bootstrapping: {actual_result}\n") 112 | precision_multiple_iterations = calculate_approximation_error(actual_result,ptxt.GetCKKSPackedValue()) 113 | 114 | print(f"Bootstrapping precision after 2 iterations: {precision_multiple_iterations} bits\n") 115 | print(f"Number of levels remaining after 2 bootstrappings: {depth - ciphertext_two_iterations.GetLevel()}\n") 116 | 117 | if __name__ == "__main__": 118 | main() -------------------------------------------------------------------------------- /examples/pke/polynomial-evaluation.py: -------------------------------------------------------------------------------- 1 | from openfhe import * 2 | import time 3 | 4 | def main(): 5 | 6 | print("\n======EXAMPLE FOR EVALPOLY========\n") 7 | parameters = CCParamsCKKSRNS() 8 | parameters.SetMultiplicativeDepth(6) 9 | parameters.SetScalingModSize(50) 10 | 11 | cc = GenCryptoContext(parameters) 12 | cc.Enable(PKESchemeFeature.PKE) 13 | cc.Enable(PKESchemeFeature.KEYSWITCH) 14 | cc.Enable(PKESchemeFeature.LEVELEDSHE) 15 | cc.Enable(PKESchemeFeature.ADVANCEDSHE) 16 | 17 | input = [complex(a,0) for a in [0.5, 0.7, 0.9, 0.95, 0.93]] 18 | # input = [0.5, 0.7, 0.9, 0.95, 0.93] 19 | encoded_length = len(input) 20 | coefficients1 = [0.15, 0.75, 0, 1.25, 0, 0, 1, 0, 1, 2, 0, 1, 0, 0, 0, 0, 1] 21 | coefficients2 = [1, 2, 3, 4, 5, -1, -2, -3, -4, -5, 22 | 0.1, 0.2, 0.3, 0.4, 0.5, -0.1, -0.2, -0.3, -0.4, -0.5, 23 | 0.1, 0.2, 0.3, 0.4, 0.5, -0.1, -0.2, -0.3, -0.4, -0.5] 24 | plaintext1 = cc.MakeCKKSPackedPlaintext(input) 25 | 26 | key_pair = cc.KeyGen() 27 | 28 | print("Generating evaluation key for homomorphic multiplication...") 29 | cc.EvalMultKeyGen(key_pair.secretKey) 30 | print("Completed.\n") 31 | 32 | ciphertext1 = cc.Encrypt(key_pair.publicKey, plaintext1) 33 | 34 | t = time.time() 35 | result = cc.EvalPoly(ciphertext1, coefficients1) 36 | time_eval_poly1 = time.time() - t 37 | 38 | t = time.time() 39 | result2 = cc.EvalPoly(ciphertext1, coefficients2) 40 | time_eval_poly2 = time.time() - t 41 | 42 | plaintext_dec = cc.Decrypt(result, key_pair.secretKey) 43 | 44 | plaintext_dec.SetLength(encoded_length) 45 | 46 | plaintext_dec2 = cc.Decrypt(result2, key_pair.secretKey) 47 | 48 | plaintext_dec2.SetLength(encoded_length) 49 | 50 | print("\n Original Plaintext #1: \n") 51 | print(plaintext1) 52 | 53 | print(f"\n Result of evaluating a polynomial with coefficients {coefficients1}: \n") 54 | print(plaintext_dec) 55 | 56 | print("\n Expected result: (0.70519107, 1.38285078, 3.97211180, " 57 | "5.60215665, 4.86357575) \n") 58 | 59 | print(f"\n Evaluation time: {time_eval_poly1*1000} ms \n") 60 | 61 | print(f"\n Result of evaluating a polynomial with coefficients {coefficients2}: \n") 62 | print(plaintext_dec2) 63 | 64 | print("\n Expected result: (3.4515092326, 5.3752765397, 4.8993108833, " 65 | "3.2495023573, 4.0485229982) \n") 66 | 67 | print(f"\n Evaluation time: {time_eval_poly2*1000} ms \n") 68 | 69 | if __name__ == '__main__': 70 | main() 71 | -------------------------------------------------------------------------------- /examples/pke/pre-buffer.py: -------------------------------------------------------------------------------- 1 | import time 2 | import random 3 | from math import log2 4 | from openfhe import * 5 | 6 | def main(): 7 | passed = run_demo_pre() 8 | 9 | if not passed: # there could be an error 10 | return 1 11 | return 0 # successful return 12 | 13 | def run_demo_pre(): 14 | # Generate parameters. 15 | print("setting up BFV RNS crypto system") 16 | start_time = time.time() 17 | plaintextModulus = 65537 # can encode shorts 18 | 19 | parameters = CCParamsBFVRNS() 20 | parameters.SetPlaintextModulus(plaintextModulus) 21 | parameters.SetScalingModSize(60) 22 | 23 | cc = GenCryptoContext(parameters) 24 | print(f"\nParam generation time: {time.time() - start_time} ms") 25 | 26 | # Turn on features 27 | cc.Enable(PKE) 28 | cc.Enable(KEYSWITCH) 29 | cc.Enable(LEVELEDSHE) 30 | cc.Enable(PRE) 31 | 32 | print(f"p = {cc.GetPlaintextModulus()}") 33 | print(f"n = {cc.GetCyclotomicOrder()/2}") 34 | print(f"log2 q = {log2(cc.GetModulus())}") 35 | print(f"r = {cc.GetDigitSize()}") 36 | 37 | ringsize = cc.GetRingDimension() 38 | print(f"Alice can encrypt {ringsize * 2} bytes of data") 39 | 40 | # Perform Key Generation Operation 41 | 42 | print("\nRunning Alice key generation (used for source data)...") 43 | start_time = time.time() 44 | keyPair1 = cc.KeyGen() 45 | print(f"Key generation time: {time.time() - start_time} ms") 46 | 47 | if not keyPair1.good(): 48 | print("Alice Key generation failed!") 49 | return False 50 | 51 | # Encode source data 52 | nshort = ringsize 53 | vShorts = [random.randint(0, 65536) for _ in range(nshort)] 54 | pt = cc.MakePackedPlaintext(vShorts) 55 | 56 | # Encryption 57 | start_time = time.time() 58 | ct1 = cc.Encrypt(keyPair1.publicKey, pt) 59 | print(f"Encryption time: {time.time() - start_time} ms") 60 | 61 | # Decryption of Ciphertext 62 | start_time = time.time() 63 | ptDec1 = cc.Decrypt(keyPair1.secretKey, ct1) 64 | print(f"Decryption time: {time.time() - start_time} ms") 65 | 66 | ptDec1.SetLength(pt.GetLength()) 67 | 68 | # Perform Key Generation Operation 69 | print("Bob Running key generation ...") 70 | start_time = time.time() 71 | keyPair2 = cc.KeyGen() 72 | print(f"Key generation time: {time.time() - start_time} ms") 73 | 74 | if not keyPair2.good(): 75 | print("Bob Key generation failed!") 76 | return False 77 | 78 | # Perform the proxy re-encryption key generation operation. 79 | # This generates the keys which are used to perform the key switching. 80 | 81 | print("\nGenerating proxy re-encryption key...") 82 | start_time = time.time() 83 | reencryptionKey12 = cc.ReKeyGen(keyPair1.secretKey, keyPair2.publicKey) 84 | print(f"Key generation time: {time.time() - start_time} ms") 85 | 86 | # Re-Encryption 87 | start_time = time.time() 88 | ct2 = cc.ReEncrypt(ct1, reencryptionKey12) 89 | print(f"Re-Encryption time: {time.time() - start_time} ms") 90 | 91 | # Decryption of Ciphertext 92 | start_time = time.time() 93 | ptDec2 = cc.Decrypt(keyPair2.secretKey, ct2) 94 | print(f"Decryption time: {time.time() - start_time} ms") 95 | 96 | ptDec2.SetLength(pt.GetLength()) 97 | 98 | unpacked0 = pt.GetPackedValue() 99 | unpacked1 = ptDec1.GetPackedValue() 100 | unpacked2 = ptDec2.GetPackedValue() 101 | good = True 102 | 103 | # note that OpenFHE assumes that plaintext is in the range of -p/2..p/2 104 | # to recover 0...q simply add q if the unpacked value is negative 105 | for j in range(pt.GetLength()): 106 | if unpacked1[j] < 0: 107 | unpacked1[j] += plaintextModulus 108 | if unpacked2[j] < 0: 109 | unpacked2[j] += plaintextModulus 110 | 111 | # compare all the results for correctness 112 | for j in range(pt.GetLength()): 113 | if (unpacked0[j] != unpacked1[j]) or (unpacked0[j] != unpacked2[j]): 114 | print(f"{j}, {unpacked0[j]}, {unpacked1[j]}, {unpacked2[j]}") 115 | good = False 116 | 117 | if good: 118 | print("PRE passes") 119 | else: 120 | print("PRE fails") 121 | 122 | print("Execution Completed.") 123 | 124 | return good 125 | 126 | if __name__ == "__main__": 127 | main() 128 | -------------------------------------------------------------------------------- /examples/pke/simple-ckks-bootstrapping.py: -------------------------------------------------------------------------------- 1 | from openfhe import * 2 | 3 | def main(): 4 | simple_bootstrap_example() 5 | 6 | def simple_bootstrap_example(): 7 | parameters = CCParamsCKKSRNS() 8 | 9 | secret_key_dist = SecretKeyDist.UNIFORM_TERNARY 10 | parameters.SetSecretKeyDist(secret_key_dist) 11 | 12 | parameters.SetSecurityLevel(SecurityLevel.HEStd_NotSet) 13 | parameters.SetRingDim(1<<12) 14 | 15 | if get_native_int()==128: 16 | rescale_tech = ScalingTechnique.FIXEDAUTO 17 | dcrt_bits = 78 18 | first_mod = 89 19 | else: 20 | rescale_tech = ScalingTechnique.FLEXIBLEAUTO 21 | dcrt_bits = 59 22 | first_mod = 60 23 | 24 | parameters.SetScalingModSize(dcrt_bits) 25 | parameters.SetScalingTechnique(rescale_tech) 26 | parameters.SetFirstModSize(first_mod) 27 | 28 | level_budget = [4, 4] 29 | 30 | levels_available_after_bootstrap = 10 31 | 32 | depth = levels_available_after_bootstrap + FHECKKSRNS.GetBootstrapDepth(level_budget, secret_key_dist) 33 | 34 | parameters.SetMultiplicativeDepth(depth) 35 | 36 | cryptocontext = GenCryptoContext(parameters) 37 | cryptocontext.Enable(PKESchemeFeature.PKE) 38 | cryptocontext.Enable(PKESchemeFeature.KEYSWITCH) 39 | cryptocontext.Enable(PKESchemeFeature.LEVELEDSHE) 40 | cryptocontext.Enable(PKESchemeFeature.ADVANCEDSHE) 41 | cryptocontext.Enable(PKESchemeFeature.FHE) 42 | 43 | ring_dim = cryptocontext.GetRingDimension() 44 | # This is the mazimum number of slots that can be used full packing. 45 | 46 | num_slots = int(ring_dim / 2) 47 | print(f"CKKS is using ring dimension {ring_dim}") 48 | 49 | cryptocontext.EvalBootstrapSetup(level_budget) 50 | 51 | key_pair = cryptocontext.KeyGen() 52 | cryptocontext.EvalMultKeyGen(key_pair.secretKey) 53 | cryptocontext.EvalBootstrapKeyGen(key_pair.secretKey, num_slots) 54 | 55 | x = [0.25, 0.5, 0.75, 1.0, 2.0, 3.0, 4.0, 5.0] 56 | encoded_length = len(x) 57 | 58 | ptxt = cryptocontext.MakeCKKSPackedPlaintext(x,1,depth-1) 59 | ptxt.SetLength(encoded_length) 60 | 61 | print(f"Input: {ptxt}") 62 | 63 | ciph = cryptocontext.Encrypt(key_pair.publicKey, ptxt) 64 | 65 | print(f"Initial number of levels remaining: {depth - ciph.GetLevel()}") 66 | 67 | ciphertext_after = cryptocontext.EvalBootstrap(ciph) 68 | 69 | print(f"Number of levels remaining after bootstrapping: {depth - ciphertext_after.GetLevel() - (ciphertext_after.GetNoiseScaleDeg() - 1)}") 70 | 71 | result = cryptocontext.Decrypt(ciphertext_after,key_pair.secretKey) 72 | result.SetLength(encoded_length) 73 | print(f"Output after bootstrapping: {result}") 74 | 75 | if __name__ == '__main__': 76 | main() -------------------------------------------------------------------------------- /examples/pke/simple-integers-bgvrns.py: -------------------------------------------------------------------------------- 1 | # Initial Settings 2 | from openfhe import * 3 | import os 4 | 5 | # import openfhe.PKESchemeFeature as Feature 6 | 7 | 8 | def main(): 9 | # Sample Program: Step 1: Set CryptoContext 10 | parameters = CCParamsBGVRNS() 11 | parameters.SetPlaintextModulus(65537) 12 | parameters.SetMultiplicativeDepth(2) 13 | 14 | crypto_context = GenCryptoContext(parameters) 15 | # Enable features that you wish to use 16 | crypto_context.Enable(PKESchemeFeature.PKE) 17 | crypto_context.Enable(PKESchemeFeature.KEYSWITCH) 18 | crypto_context.Enable(PKESchemeFeature.LEVELEDSHE) 19 | 20 | # Sample Program: Step 2: Key Generation 21 | 22 | # Generate a public/private key pair 23 | key_pair = crypto_context.KeyGen() 24 | 25 | # Generate the relinearization key 26 | crypto_context.EvalMultKeyGen(key_pair.secretKey) 27 | 28 | # Generate the rotation evaluation keys 29 | crypto_context.EvalRotateKeyGen(key_pair.secretKey, [1, 2, -1, -2]) 30 | 31 | # Sample Program: Step 3: Encryption 32 | 33 | # First plaintext vector is encoded 34 | vector_of_ints1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 35 | plaintext1 = crypto_context.MakePackedPlaintext(vector_of_ints1) 36 | 37 | # Second plaintext vector is encoded 38 | vector_of_ints2 = [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12] 39 | plaintext2 = crypto_context.MakePackedPlaintext(vector_of_ints2) 40 | 41 | # Third plaintext vector is encoded 42 | vector_of_ints3 = [1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12] 43 | plaintext3 = crypto_context.MakePackedPlaintext(vector_of_ints3) 44 | 45 | # The encoded vectors are encrypted 46 | ciphertext1 = crypto_context.Encrypt(key_pair.publicKey, plaintext1) 47 | ciphertext2 = crypto_context.Encrypt(key_pair.publicKey, plaintext2) 48 | ciphertext3 = crypto_context.Encrypt(key_pair.publicKey, plaintext3) 49 | 50 | # Sample Program: Step 4: Evaluation 51 | 52 | # Homomorphic additions 53 | ciphertext_add12 = crypto_context.EvalAdd(ciphertext1, ciphertext2) 54 | ciphertext_add_result = crypto_context.EvalAdd(ciphertext_add12, ciphertext3) 55 | 56 | # Homomorphic Multiplication 57 | ciphertext_mult12 = crypto_context.EvalMult(ciphertext1, ciphertext2) 58 | ciphertext_mult_result = crypto_context.EvalMult(ciphertext_mult12, ciphertext3) 59 | 60 | # Homomorphic Rotations 61 | ciphertext_rot1 = crypto_context.EvalRotate(ciphertext1, 1) 62 | ciphertext_rot2 = crypto_context.EvalRotate(ciphertext1, 2) 63 | ciphertext_rot3 = crypto_context.EvalRotate(ciphertext1, -1) 64 | ciphertext_rot4 = crypto_context.EvalRotate(ciphertext1, -2) 65 | 66 | # Sample Program: Step 5: Decryption 67 | 68 | # Decrypt the result of additions 69 | plaintext_add_result = crypto_context.Decrypt( 70 | ciphertext_add_result, key_pair.secretKey 71 | ) 72 | 73 | # Decrypt the result of multiplications 74 | plaintext_mult_result = crypto_context.Decrypt( 75 | ciphertext_mult_result, key_pair.secretKey 76 | ) 77 | 78 | # Decrypt the result of rotations 79 | plaintextRot1 = crypto_context.Decrypt(ciphertext_rot1, key_pair.secretKey) 80 | plaintextRot2 = crypto_context.Decrypt(ciphertext_rot2, key_pair.secretKey) 81 | plaintextRot3 = crypto_context.Decrypt(ciphertext_rot3, key_pair.secretKey) 82 | plaintextRot4 = crypto_context.Decrypt(ciphertext_rot4, key_pair.secretKey) 83 | 84 | plaintextRot1.SetLength(len(vector_of_ints1)) 85 | plaintextRot2.SetLength(len(vector_of_ints1)) 86 | plaintextRot3.SetLength(len(vector_of_ints1)) 87 | plaintextRot4.SetLength(len(vector_of_ints1)) 88 | 89 | print("Plaintext #1: " + str(plaintext1)) 90 | print("Plaintext #2: " + str(plaintext2)) 91 | print("Plaintext #3: " + str(plaintext3)) 92 | 93 | # Output Results 94 | print("\nResults of homomorphic computations") 95 | print("#1 + #2 + #3 = " + str(plaintext_add_result)) 96 | print("#1 * #2 * #3 = " + str(plaintext_mult_result)) 97 | print("Left rotation of #1 by 1 = " + str(plaintextRot1)) 98 | print("Left rotation of #1 by 2 = " + str(plaintextRot2)) 99 | print("Right rotation of #1 by 1 = " + str(plaintextRot3)) 100 | print("Right rotation of #1 by 2 = " + str(plaintextRot4)) 101 | 102 | 103 | if __name__ == "__main__": 104 | main() 105 | -------------------------------------------------------------------------------- /examples/pke/simple-integers-serial-bgvrns.py: -------------------------------------------------------------------------------- 1 | # Initial Settings 2 | from openfhe import * 3 | import tempfile 4 | import os 5 | 6 | # import openfhe.PKESchemeFeature as Feature 7 | 8 | datafolder = "demoData" 9 | 10 | 11 | def main_action(): 12 | serType = BINARY # BINARY or JSON 13 | print( 14 | "This program requres the subdirectory `" 15 | + datafolder 16 | + "' to exist, otherwise you will get an error writing serializations." 17 | ) 18 | 19 | # Sample Program: Step 1: Set CryptoContext 20 | parameters = CCParamsBGVRNS() 21 | parameters.SetPlaintextModulus(65537) 22 | parameters.SetMultiplicativeDepth(2) 23 | 24 | cryptoContext = GenCryptoContext(parameters) 25 | # Enable features that you wish to use 26 | cryptoContext.Enable(PKESchemeFeature.PKE) 27 | cryptoContext.Enable(PKESchemeFeature.KEYSWITCH) 28 | cryptoContext.Enable(PKESchemeFeature.LEVELEDSHE) 29 | 30 | # Serialize cryptocontext 31 | if not SerializeToFile(datafolder + "/cryptocontext.txt", cryptoContext, serType): 32 | raise Exception( 33 | "Error writing serialization of the crypto context to cryptocontext.txt" 34 | ) 35 | print("The cryptocontext has been serialized.") 36 | 37 | # Sample Program: Step 2: Key Generation 38 | 39 | # Generate a public/private key pair 40 | keypair = cryptoContext.KeyGen() 41 | print("The keypair has been generated.") 42 | 43 | # Serialize the public key 44 | if not SerializeToFile(datafolder + "/key-public.txt", keypair.publicKey, serType): 45 | raise Exception( 46 | "Error writing serialization of the public key to key-public.txt" 47 | ) 48 | print("The public key has been serialized.") 49 | 50 | # Serialize the secret key 51 | if not SerializeToFile(datafolder + "/key-private.txt", keypair.secretKey, serType): 52 | raise Exception( 53 | "Error writing serialization of the secret key to key-private.txt" 54 | ) 55 | print("The secret key has been serialized.") 56 | 57 | # Generate the relinearization key 58 | cryptoContext.EvalMultKeyGen(keypair.secretKey) 59 | print("The relinearization key has been generated.") 60 | 61 | # Serialize the relinearization key 62 | if not cryptoContext.SerializeEvalMultKey( 63 | datafolder + "/key-eval-mult.txt", serType 64 | ): 65 | raise Exception( 66 | 'Error writing serialization of the eval mult keys to "key-eval-mult.txt"' 67 | ) 68 | print("The relinearization key has been serialized.") 69 | 70 | # Generate the rotation evaluation keys 71 | cryptoContext.EvalRotateKeyGen(keypair.secretKey, [1, 2, -1, -2]) 72 | print("The rotation evaluation keys have been generated.") 73 | 74 | # Serialize the rotation evaluation keys 75 | if not cryptoContext.SerializeEvalAutomorphismKey( 76 | datafolder + "/key-eval-rot.txt", serType 77 | ): 78 | raise Exception( 79 | 'Error writing serialization of the eval rotate keys to "key-eval-rot.txt"' 80 | ) 81 | print("The rotation evaluation keys have been serialized.") 82 | 83 | # Sample Program: Step 3: Encryption 84 | 85 | # First plaintext vector is encoded 86 | vectorOfInts1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 87 | plaintext1 = cryptoContext.MakePackedPlaintext(vectorOfInts1) 88 | 89 | # Second plaintext vector is encoded 90 | vectorOfInts2 = [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12] 91 | plaintext2 = cryptoContext.MakePackedPlaintext(vectorOfInts2) 92 | 93 | # Third plaintext vector is encoded 94 | vectorOfInts3 = [1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12] 95 | plaintext3 = cryptoContext.MakePackedPlaintext(vectorOfInts3) 96 | 97 | # The encoded vectors are encrypted 98 | ciphertext1 = cryptoContext.Encrypt(keypair.publicKey, plaintext1) 99 | ciphertext2 = cryptoContext.Encrypt(keypair.publicKey, plaintext2) 100 | ciphertext3 = cryptoContext.Encrypt(keypair.publicKey, plaintext3) 101 | print("The plaintexts have been encrypted.") 102 | 103 | if not SerializeToFile(datafolder + "/ciphertext1.txt", ciphertext1, serType): 104 | raise Exception( 105 | "Error writing serialization of ciphertext 1 to ciphertext1.txt" 106 | ) 107 | print("The first ciphertext has been serialized.") 108 | 109 | if not SerializeToFile(datafolder + "/ciphertext2.txt", ciphertext2, serType): 110 | raise Exception("Error writing serialization of ciphertext2 to ciphertext2.txt") 111 | print("The second ciphertext has been serialized.") 112 | 113 | if not SerializeToFile(datafolder + "/ciphertext3.txt", ciphertext3, serType): 114 | raise Exception("Error writing serialization of ciphertext3 to ciphertext3.txt") 115 | print("The third ciphertext has been serialized.") 116 | 117 | # Sample Program: Step 4: Evaluation 118 | 119 | # OpenFHE maintains an internal map of CryptoContext objects which are 120 | # indexed by a tag and the tag is applied to both the CryptoContext and some 121 | # of the keys. When deserializing a context, OpenFHE checks for the tag and 122 | # if it finds it in the CryptoContext map, it will return the stored version. 123 | # Hence, we need to clear the context and clear the keys. 124 | ClearEvalMultKeys() 125 | cryptoContext.ClearEvalAutomorphismKeys() 126 | ReleaseAllContexts() 127 | 128 | # Deserialize the crypto context 129 | 130 | cc, res = DeserializeCryptoContext(datafolder + "/cryptocontext.txt", serType) 131 | if not res: 132 | raise Exception( 133 | "Error reading serialization of the crypto context from cryptocontext.txt" 134 | ) 135 | print("The cryptocontext has been deserialized.") 136 | 137 | # Deserialize the public key 138 | pk, res = DeserializePublicKey(datafolder + "/key-public.txt", serType) 139 | 140 | if not res: 141 | raise Exception( 142 | "Error reading serialization of the public key from key-public.txt" 143 | ) 144 | print("The public key has been deserialized.") 145 | 146 | if not cc.DeserializeEvalMultKey(datafolder + "/key-eval-mult.txt", serType): 147 | raise Exception("Could not deserialize the eval mult key file") 148 | 149 | print("The relinearization key has been deserialized.") 150 | 151 | if not cc.DeserializeEvalAutomorphismKey(datafolder + "/key-eval-rot.txt", serType): 152 | raise Exception("Could not deserialize the eval rotation key file") 153 | 154 | print("Deserialized the eval rotation keys.") 155 | 156 | # Deserialize the ciphertexts 157 | ct1, res = DeserializeCiphertext(datafolder + "/ciphertext1.txt", serType) 158 | 159 | if not res: 160 | raise Exception("Could not read the ciphertext") 161 | print("The first ciphertext has been deserialized.") 162 | 163 | ct2, res = DeserializeCiphertext(datafolder + "/ciphertext2.txt", serType) 164 | 165 | if not res: 166 | raise Exception("Could not read the ciphertext") 167 | print("The second ciphertext has been deserialized.") 168 | 169 | ct3, res = DeserializeCiphertext(datafolder + "/ciphertext3.txt", serType) 170 | if not res: 171 | raise Exception("Could not read the ciphertext") 172 | print("The third ciphertext has been deserialized.") 173 | 174 | # Homomorphic addition 175 | 176 | ciphertextAdd12 = cc.EvalAdd(ct1, ct2) 177 | ciphertextAddResult = cc.EvalAdd(ciphertextAdd12, ct3) 178 | 179 | # Homomorphic multiplication 180 | ciphertextMult12 = cc.EvalMult(ct1, ct2) 181 | ciphertextMultResult = cc.EvalMult(ciphertextMult12, ct3) 182 | 183 | # Homomorphic rotation 184 | ciphertextRot1 = cc.EvalRotate(ct1, 1) 185 | ciphertextRot2 = cc.EvalRotate(ct2, 2) 186 | ciphertextRot3 = cc.EvalRotate(ct3, -1) 187 | ciphertextRot4 = cc.EvalRotate(ct3, -2) 188 | 189 | # Sample Program: Step 5: Decryption 190 | 191 | sk, res = DeserializePrivateKey(datafolder + "/key-private.txt", serType) 192 | if not res: 193 | raise Exception("Could not read secret key") 194 | print("The secret key has been deserialized.") 195 | 196 | # Decrypt the result of additions 197 | plaintextAddResult = cc.Decrypt(sk, ciphertextAddResult) 198 | 199 | # Decrypt the result of multiplications 200 | plaintextMultResult = cc.Decrypt(sk, ciphertextMultResult) 201 | 202 | # Decrypt the result of rotations 203 | plaintextRot1 = cc.Decrypt(sk, ciphertextRot1) 204 | plaintextRot2 = cc.Decrypt(sk, ciphertextRot2) 205 | plaintextRot3 = cc.Decrypt(sk, ciphertextRot3) 206 | plaintextRot4 = cc.Decrypt(sk, ciphertextRot4) 207 | 208 | # Shows only the same number of elements as in the original plaintext vector 209 | # By default it will show all coefficients in the BFV-encoded polynomial 210 | plaintextRot1.SetLength(len(vectorOfInts1)) 211 | plaintextRot2.SetLength(len(vectorOfInts1)) 212 | plaintextRot3.SetLength(len(vectorOfInts1)) 213 | plaintextRot4.SetLength(len(vectorOfInts1)) 214 | 215 | # Output results 216 | print("\nResults of homomorphic computations") 217 | print("#1 + #2 + #3: " + str(plaintextAddResult)) 218 | print("#1 * #2 * #3: " + str(plaintextMultResult)) 219 | print("Left rotation of #1 by 1: " + str(plaintextRot1)) 220 | print("Left rotation of #1 by 2: " + str(plaintextRot2)) 221 | print("Right rotation of #1 by 1: " + str(plaintextRot3)) 222 | print("Right rotation of #1 by 2: " + str(plaintextRot4)) 223 | 224 | 225 | def main(): 226 | global datafolder 227 | with tempfile.TemporaryDirectory() as td: 228 | datafolder = td + "/" + datafolder 229 | os.mkdir(datafolder) 230 | main_action() 231 | 232 | 233 | if __name__ == "__main__": 234 | main() 235 | -------------------------------------------------------------------------------- /examples/pke/simple-integers-serial.py: -------------------------------------------------------------------------------- 1 | # Initial Settings 2 | from openfhe import * 3 | 4 | # import openfhe.PKESchemeFeature as Feature 5 | import tempfile 6 | import os 7 | 8 | datafolder = "demoData" 9 | 10 | 11 | def main_action(): 12 | serType = BINARY # BINARY or JSON 13 | print( 14 | "This program requres the subdirectory `" 15 | + datafolder 16 | + "' to exist, otherwise you will get an error writing serializations." 17 | ) 18 | 19 | # Sample Program: Step 1: Set CryptoContext 20 | parameters = CCParamsBFVRNS() 21 | parameters.SetPlaintextModulus(65537) 22 | parameters.SetMultiplicativeDepth(2) 23 | 24 | cryptoContext = GenCryptoContext(parameters) 25 | # Enable features that you wish to use 26 | cryptoContext.Enable(PKESchemeFeature.PKE) 27 | cryptoContext.Enable(PKESchemeFeature.KEYSWITCH) 28 | cryptoContext.Enable(PKESchemeFeature.LEVELEDSHE) 29 | 30 | # Serialize cryptocontext 31 | if not SerializeToFile(datafolder + "/cryptocontext.txt", cryptoContext, serType): 32 | raise Exception( 33 | "Error writing serialization of the crypto context to cryptocontext.txt" 34 | ) 35 | print("The cryptocontext has been serialized.") 36 | 37 | # Sample Program: Step 2: Key Generation 38 | 39 | # Generate a public/private key pair 40 | keypair = cryptoContext.KeyGen() 41 | print("The keypair has been generated.") 42 | 43 | # Serialize the public key 44 | if not SerializeToFile(datafolder + "/key-public.txt", keypair.publicKey, serType): 45 | raise Exception( 46 | "Error writing serialization of the public key to key-public.txt" 47 | ) 48 | print("The public key has been serialized.") 49 | 50 | # Serialize the secret key 51 | if not SerializeToFile(datafolder + "/key-private.txt", keypair.secretKey, serType): 52 | raise Exception( 53 | "Error writing serialization of the secret key to key-private.txt" 54 | ) 55 | print("The secret key has been serialized.") 56 | 57 | # Generate the relinearization key 58 | cryptoContext.EvalMultKeyGen(keypair.secretKey) 59 | print("The relinearization key has been generated.") 60 | 61 | # Serialize the relinearization key 62 | if not cryptoContext.SerializeEvalMultKey( 63 | datafolder + "/key-eval-mult.txt", serType 64 | ): 65 | raise Exception( 66 | 'Error writing serialization of the eval mult keys to "key-eval-mult.txt"' 67 | ) 68 | print("The relinearization key has been serialized.") 69 | 70 | # Generate the rotation evaluation keys 71 | cryptoContext.EvalRotateKeyGen(keypair.secretKey, [1, 2, -1, -2]) 72 | print("The rotation evaluation keys have been generated.") 73 | 74 | # Serialize the rotation evaluation keys 75 | if not cryptoContext.SerializeEvalAutomorphismKey( 76 | datafolder + "/key-eval-rot.txt", serType 77 | ): 78 | raise Exception( 79 | 'Error writing serialization of the eval rotate keys to "key-eval-rot.txt"' 80 | ) 81 | print("The rotation evaluation keys have been serialized.") 82 | 83 | # Sample Program: Step 3: Encryption 84 | 85 | # First plaintext vector is encoded 86 | vectorOfInts1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 87 | plaintext1 = cryptoContext.MakePackedPlaintext(vectorOfInts1) 88 | 89 | # Second plaintext vector is encoded 90 | vectorOfInts2 = [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12] 91 | plaintext2 = cryptoContext.MakePackedPlaintext(vectorOfInts2) 92 | 93 | # Third plaintext vector is encoded 94 | vectorOfInts3 = [1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12] 95 | plaintext3 = cryptoContext.MakePackedPlaintext(vectorOfInts3) 96 | 97 | # The encoded vectors are encrypted 98 | ciphertext1 = cryptoContext.Encrypt(keypair.publicKey, plaintext1) 99 | ciphertext2 = cryptoContext.Encrypt(keypair.publicKey, plaintext2) 100 | ciphertext3 = cryptoContext.Encrypt(keypair.publicKey, plaintext3) 101 | print("The plaintexts have been encrypted.") 102 | 103 | if not SerializeToFile(datafolder + "/ciphertext1.txt", ciphertext1, serType): 104 | raise Exception( 105 | "Error writing serialization of ciphertext 1 to ciphertext1.txt" 106 | ) 107 | print("The first ciphertext has been serialized.") 108 | 109 | if not SerializeToFile(datafolder + "/ciphertext2.txt", ciphertext2, serType): 110 | raise Exception("Error writing serialization of ciphertext2 to ciphertext2.txt") 111 | print("The second ciphertext has been serialized.") 112 | 113 | if not SerializeToFile(datafolder + "/ciphertext3.txt", ciphertext3, serType): 114 | raise Exception("Error writing serialization of ciphertext3 to ciphertext3.txt") 115 | print("The third ciphertext has been serialized.") 116 | 117 | # Sample Program: Step 4: Evaluation 118 | 119 | # OpenFHE maintains an internal map of CryptoContext objects which are 120 | # indexed by a tag and the tag is applied to both the CryptoContext and some 121 | # of the keys. When deserializing a context, OpenFHE checks for the tag and 122 | # if it finds it in the CryptoContext map, it will return the stored version. 123 | # Hence, we need to clear the context and clear the keys. 124 | ClearEvalMultKeys() 125 | cryptoContext.ClearEvalAutomorphismKeys() 126 | ReleaseAllContexts() 127 | 128 | # Deserialize the crypto context 129 | 130 | cc, res = DeserializeCryptoContext(datafolder + "/cryptocontext.txt", serType) 131 | if not res: 132 | raise Exception( 133 | "Error reading serialization of the crypto context from cryptocontext.txt" 134 | ) 135 | print("The cryptocontext has been deserialized.") 136 | 137 | # Deserialize the public key 138 | pk, res = DeserializePublicKey(datafolder + "/key-public.txt", serType) 139 | 140 | if not res: 141 | raise Exception( 142 | "Error reading serialization of the public key from key-public.txt" 143 | ) 144 | print("The public key has been deserialized.") 145 | 146 | if not cc.DeserializeEvalMultKey(datafolder + "/key-eval-mult.txt", serType): 147 | raise Exception("Could not deserialize the eval mult key file") 148 | 149 | print("The relinearization key has been deserialized.") 150 | 151 | if not cc.DeserializeEvalAutomorphismKey(datafolder + "/key-eval-rot.txt", serType): 152 | raise Exception("Could not deserialize the eval rotation key file") 153 | 154 | print("Deserialized the eval rotation keys.") 155 | 156 | # Deserialize the ciphertexts 157 | ct1, res = DeserializeCiphertext(datafolder + "/ciphertext1.txt", serType) 158 | 159 | if not res: 160 | raise Exception("Could not read the ciphertext") 161 | print("The first ciphertext has been deserialized.") 162 | 163 | ct2, res = DeserializeCiphertext(datafolder + "/ciphertext2.txt", serType) 164 | 165 | if not res: 166 | raise Exception("Could not read the ciphertext") 167 | print("The second ciphertext has been deserialized.") 168 | 169 | ct3, res = DeserializeCiphertext(datafolder + "/ciphertext3.txt", serType) 170 | if not res: 171 | raise Exception("Could not read the ciphertext") 172 | print("The third ciphertext has been deserialized.") 173 | 174 | # Homomorphic addition 175 | 176 | ciphertextAdd12 = cc.EvalAdd(ct1, ct2) 177 | ciphertextAddResult = cc.EvalAdd(ciphertextAdd12, ct3) 178 | 179 | # Homomorphic multiplication 180 | ciphertextMult12 = cc.EvalMult(ct1, ct2) 181 | ciphertextMultResult = cc.EvalMult(ciphertextMult12, ct3) 182 | 183 | # Homomorphic rotation 184 | ciphertextRot1 = cc.EvalRotate(ct1, 1) 185 | ciphertextRot2 = cc.EvalRotate(ct2, 2) 186 | ciphertextRot3 = cc.EvalRotate(ct3, -1) 187 | ciphertextRot4 = cc.EvalRotate(ct3, -2) 188 | 189 | # Sample Program: Step 5: Decryption 190 | 191 | sk, res = DeserializePrivateKey(datafolder + "/key-private.txt", serType) 192 | if not res: 193 | raise Exception("Could not read secret key") 194 | print("The secret key has been deserialized.") 195 | 196 | # Decrypt the result of additions 197 | plaintextAddResult = cc.Decrypt(sk, ciphertextAddResult) 198 | 199 | # Decrypt the result of multiplications 200 | plaintextMultResult = cc.Decrypt(sk, ciphertextMultResult) 201 | 202 | # Decrypt the result of rotations 203 | plaintextRot1 = cc.Decrypt(sk, ciphertextRot1) 204 | plaintextRot2 = cc.Decrypt(sk, ciphertextRot2) 205 | plaintextRot3 = cc.Decrypt(sk, ciphertextRot3) 206 | plaintextRot4 = cc.Decrypt(sk, ciphertextRot4) 207 | 208 | # Shows only the same number of elements as in the original plaintext vector 209 | # By default it will show all coefficients in the BFV-encoded polynomial 210 | plaintextRot1.SetLength(len(vectorOfInts1)) 211 | plaintextRot2.SetLength(len(vectorOfInts1)) 212 | plaintextRot3.SetLength(len(vectorOfInts1)) 213 | plaintextRot4.SetLength(len(vectorOfInts1)) 214 | 215 | # Output results 216 | print("\nResults of homomorphic computations") 217 | print("#1 + #2 + #3: " + str(plaintextAddResult)) 218 | print("#1 * #2 * #3: " + str(plaintextMultResult)) 219 | print("Left rotation of #1 by 1: " + str(plaintextRot1)) 220 | print("Left rotation of #1 by 2: " + str(plaintextRot2)) 221 | print("Right rotation of #1 by 1: " + str(plaintextRot3)) 222 | print("Right rotation of #1 by 2: " + str(plaintextRot4)) 223 | 224 | 225 | def main(): 226 | global datafolder 227 | with tempfile.TemporaryDirectory() as td: 228 | datafolder = td + "/" + datafolder 229 | os.mkdir(datafolder) 230 | main_action() 231 | 232 | 233 | if __name__ == "__main__": 234 | main() 235 | -------------------------------------------------------------------------------- /examples/pke/simple-integers.py: -------------------------------------------------------------------------------- 1 | # Initial Settings 2 | from openfhe import * 3 | 4 | # import openfhe.PKESchemeFeature as Feature 5 | 6 | 7 | def main(): 8 | # Sample Program: Step 1: Set CryptoContext 9 | parameters = CCParamsBFVRNS() 10 | parameters.SetPlaintextModulus(65537) 11 | parameters.SetMultiplicativeDepth(2) 12 | 13 | crypto_context = GenCryptoContext(parameters) 14 | # Enable features that you wish to use 15 | crypto_context.Enable(PKESchemeFeature.PKE) 16 | crypto_context.Enable(PKESchemeFeature.KEYSWITCH) 17 | crypto_context.Enable(PKESchemeFeature.LEVELEDSHE) 18 | 19 | # Sample Program: Step 2: Key Generation 20 | 21 | # Generate a public/private key pair 22 | key_pair = crypto_context.KeyGen() 23 | 24 | # Generate the relinearization key 25 | crypto_context.EvalMultKeyGen(key_pair.secretKey) 26 | 27 | # Generate the rotation evaluation keys 28 | crypto_context.EvalRotateKeyGen(key_pair.secretKey, [1, 2, -1, -2]) 29 | 30 | # Sample Program: Step 3: Encryption 31 | 32 | # First plaintext vector is encoded 33 | vector_of_ints1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 34 | plaintext1 = crypto_context.MakePackedPlaintext(vector_of_ints1) 35 | 36 | # Second plaintext vector is encoded 37 | vector_of_ints2 = [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12] 38 | plaintext2 = crypto_context.MakePackedPlaintext(vector_of_ints2) 39 | 40 | # Third plaintext vector is encoded 41 | vector_of_ints3 = [1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12] 42 | plaintext3 = crypto_context.MakePackedPlaintext(vector_of_ints3) 43 | 44 | # The encoded vectors are encrypted 45 | ciphertext1 = crypto_context.Encrypt(key_pair.publicKey, plaintext1) 46 | ciphertext2 = crypto_context.Encrypt(key_pair.publicKey, plaintext2) 47 | ciphertext3 = crypto_context.Encrypt(key_pair.publicKey, plaintext3) 48 | 49 | # Sample Program: Step 4: Evaluation 50 | 51 | # Homomorphic additions 52 | ciphertext_add12 = crypto_context.EvalAdd(ciphertext1, ciphertext2) 53 | ciphertext_add_result = crypto_context.EvalAdd(ciphertext_add12, ciphertext3) 54 | 55 | # Homomorphic Multiplication 56 | ciphertext_mult12 = crypto_context.EvalMult(ciphertext1, ciphertext2) 57 | ciphertext_mult_result = crypto_context.EvalMult(ciphertext_mult12, ciphertext3) 58 | 59 | # Homomorphic Rotations 60 | ciphertext_rot1 = crypto_context.EvalRotate(ciphertext1, 1) 61 | ciphertext_rot2 = crypto_context.EvalRotate(ciphertext1, 2) 62 | ciphertext_rot3 = crypto_context.EvalRotate(ciphertext1, -1) 63 | ciphertext_rot4 = crypto_context.EvalRotate(ciphertext1, -2) 64 | 65 | # Sample Program: Step 5: Decryption 66 | 67 | # Decrypt the result of additions 68 | plaintext_add_result = crypto_context.Decrypt( 69 | ciphertext_add_result, key_pair.secretKey 70 | ) 71 | 72 | # Decrypt the result of multiplications 73 | plaintext_mult_result = crypto_context.Decrypt( 74 | ciphertext_mult_result, key_pair.secretKey 75 | ) 76 | 77 | # Decrypt the result of rotations 78 | plaintextRot1 = crypto_context.Decrypt(ciphertext_rot1, key_pair.secretKey) 79 | plaintextRot2 = crypto_context.Decrypt(ciphertext_rot2, key_pair.secretKey) 80 | plaintextRot3 = crypto_context.Decrypt(ciphertext_rot3, key_pair.secretKey) 81 | plaintextRot4 = crypto_context.Decrypt(ciphertext_rot4, key_pair.secretKey) 82 | 83 | plaintextRot1.SetLength(len(vector_of_ints1)) 84 | plaintextRot2.SetLength(len(vector_of_ints1)) 85 | plaintextRot3.SetLength(len(vector_of_ints1)) 86 | plaintextRot4.SetLength(len(vector_of_ints1)) 87 | 88 | print("Plaintext #1: " + str(plaintext1)) 89 | print("Plaintext #2: " + str(plaintext2)) 90 | print("Plaintext #3: " + str(plaintext3)) 91 | 92 | # Output Results 93 | print("\nResults of homomorphic computations") 94 | print("#1 + #2 + #3 = " + str(plaintext_add_result)) 95 | print("#1 * #2 * #3 = " + str(plaintext_mult_result)) 96 | print("Left rotation of #1 by 1 = " + str(plaintextRot1)) 97 | print("Left rotation of #1 by 2 = " + str(plaintextRot2)) 98 | print("Right rotation of #1 by 1 = " + str(plaintextRot3)) 99 | print("Right rotation of #1 by 2 = " + str(plaintextRot4)) 100 | 101 | 102 | if __name__ == "__main__": 103 | main() 104 | -------------------------------------------------------------------------------- /examples/pke/simple-real-numbers.py: -------------------------------------------------------------------------------- 1 | from openfhe import * 2 | 3 | 4 | def main(): 5 | mult_depth = 1 6 | scale_mod_size = 50 7 | batch_size = 8 8 | 9 | parameters = CCParamsCKKSRNS() 10 | parameters.SetMultiplicativeDepth(mult_depth) 11 | parameters.SetScalingModSize(scale_mod_size) 12 | parameters.SetBatchSize(batch_size) 13 | 14 | cc = GenCryptoContext(parameters) 15 | cc.Enable(PKESchemeFeature.PKE) 16 | cc.Enable(PKESchemeFeature.KEYSWITCH) 17 | cc.Enable(PKESchemeFeature.LEVELEDSHE) 18 | 19 | print("The CKKS scheme is using ring dimension: " + str(cc.GetRingDimension())) 20 | 21 | keys = cc.KeyGen() 22 | cc.EvalMultKeyGen(keys.secretKey) 23 | cc.EvalRotateKeyGen(keys.secretKey, [1, -2]) 24 | 25 | x1 = [0.25, 0.5, 0.75, 1.0, 2.0, 3.0, 4.0, 5.0] 26 | x2 = [5.0, 4.0, 3.0, 2.0, 1.0, 0.75, 0.5, 0.25] 27 | 28 | ptx1 = cc.MakeCKKSPackedPlaintext(x1) 29 | ptx2 = cc.MakeCKKSPackedPlaintext(x2) 30 | 31 | print("Input x1: " + str(ptx1)) 32 | print("Input x2: " + str(ptx2)) 33 | 34 | # Encrypt the encoded vectors 35 | c1 = cc.Encrypt(keys.publicKey, ptx1) 36 | c2 = cc.Encrypt(keys.publicKey, ptx2) 37 | 38 | # Step 4: Evaluation 39 | # Homomorphic additions 40 | c_add = cc.EvalAdd(c1, c2) 41 | # Homomorphic subtraction 42 | c_sub = cc.EvalSub(c1, c2) 43 | # Homomorphic scalar multiplication 44 | c_scalar = cc.EvalMult(c1, 4) 45 | # Homomorphic multiplication 46 | c_mult = cc.EvalMult(c1, c2) 47 | # Homomorphic rotations 48 | c_rot1 = cc.EvalRotate(c1, 1) 49 | c_rot2 = cc.EvalRotate(c1, -2) 50 | 51 | # Step 5: Decryption and output 52 | # Decrypt the result of additions 53 | ptAdd = cc.Decrypt(c_add, keys.secretKey) 54 | print("\nResults of homomorphic additions: ") 55 | print(ptAdd) 56 | 57 | # We set the precision to 8 decimal digits for a nicer output. 58 | # If you want to see the error/noise introduced by CKKS, bump it up 59 | # to 15 and it should become visible. 60 | 61 | precision = 8 62 | print("\nResults of homomorphic computations:") 63 | result = cc.Decrypt(c1, keys.secretKey) 64 | result.SetLength(batch_size) 65 | print("x1 = " + result.GetFormattedValues(precision)) 66 | 67 | # Decrypt the result of scalar multiplication 68 | result = cc.Decrypt(c_scalar, keys.secretKey) 69 | result.SetLength(batch_size) 70 | print("4 * x1 = " + result.GetFormattedValues(precision)) 71 | 72 | # Decrypt the result of multiplication 73 | result = cc.Decrypt(c_mult, keys.secretKey) 74 | result.SetLength(batch_size) 75 | print("x1 * x2 = " + result.GetFormattedValues(precision)) 76 | 77 | # Decrypt the result of rotations 78 | result = cc.Decrypt(c_rot1, keys.secretKey) 79 | result.SetLength(batch_size) 80 | print("\nIn rotations, very small outputs (~10^-10 here) correspond to 0's:") 81 | print("x1 rotated by 1 = " + result.GetFormattedValues(precision)) 82 | 83 | result = cc.Decrypt(c_rot2, keys.secretKey) 84 | result.SetLength(batch_size) 85 | print("x1 rotated by -2 = " + result.GetFormattedValues(precision)) 86 | 87 | 88 | if __name__ == "__main__": 89 | main() 90 | -------------------------------------------------------------------------------- /examples/pke/tckks-interactive-mp-bootstrapping-Chebyschev.py: -------------------------------------------------------------------------------- 1 | from openfhe import * 2 | 3 | def main(): 4 | print("Interactive (3P) Bootstrapping Ciphertext [Chebyshev] (TCKKS) started ...") 5 | 6 | # Same test with different rescaling techniques in CKKS 7 | TCKKSCollectiveBoot(FIXEDMANUAL) 8 | TCKKSCollectiveBoot(FIXEDAUTO) 9 | if get_native_int()!=128: 10 | TCKKSCollectiveBoot(FLEXIBLEAUTO) 11 | TCKKSCollectiveBoot(FLEXIBLEAUTOEXT) 12 | 13 | print("Interactive (3P) Bootstrapping Ciphertext [Chebyshev] (TCKKS) terminated gracefully!") 14 | 15 | 16 | 17 | def checkApproximateEquality(a, b, vectorSize, epsilon): 18 | allTrue = [1] * vectorSize 19 | tmp = [abs(a[i] - b[i]) <= epsilon for i in range(vectorSize)] 20 | if tmp != allTrue: 21 | print("IntMPBoot - Ctxt Chebyshev Failed:") 22 | print(f"- is diff <= eps?: {tmp}") 23 | else: 24 | print("SUCCESSFUL Bootstrapping!") 25 | 26 | def TCKKSCollectiveBoot(scaleTech): 27 | if scaleTech not in [FIXEDMANUAL, FIXEDAUTO, FLEXIBLEAUTO, FLEXIBLEAUTOEXT]: 28 | errMsg = "ERROR: Scaling technique is not supported!" 29 | raise Exception(errMsg) 30 | 31 | parameters = CCParamsCKKSRNS() 32 | 33 | secretKeyDist = UNIFORM_TERNARY 34 | parameters.SetSecretKeyDist(secretKeyDist) 35 | 36 | parameters.SetSecurityLevel(HEStd_128_classic) 37 | 38 | dcrtBits = 50 39 | firstMod = 60 40 | 41 | parameters.SetScalingModSize(dcrtBits) 42 | parameters.SetScalingTechnique(scaleTech) 43 | parameters.SetFirstModSize(firstMod) 44 | 45 | multiplicativeDepth = 10 # Adjust according to your requirements 46 | parameters.SetMultiplicativeDepth(multiplicativeDepth) 47 | parameters.SetKeySwitchTechnique(HYBRID) 48 | 49 | batchSize = 16 # Adjust batch size if needed 50 | parameters.SetBatchSize(batchSize) 51 | 52 | compressionLevel = COMPRESSION_LEVEL.COMPACT # or COMPRESSION_LEVEL.SLACK 53 | parameters.SetInteractiveBootCompressionLevel(compressionLevel) 54 | 55 | cryptoContext = GenCryptoContext(parameters) 56 | cryptoContext.Enable(PKE) 57 | cryptoContext.Enable(KEYSWITCH) 58 | cryptoContext.Enable(LEVELEDSHE) 59 | cryptoContext.Enable(ADVANCEDSHE) 60 | cryptoContext.Enable(MULTIPARTY) 61 | 62 | ringDim = cryptoContext.GetRingDimension() 63 | maxNumSlots = ringDim // 2 64 | 65 | print(f"TCKKS scheme is using ring dimension {ringDim}") 66 | print(f"TCKKS scheme number of slots {batchSize}") 67 | print(f"TCKKS scheme max number of slots {maxNumSlots}") 68 | print(f"TCKKS example with Scaling Technique {scaleTech}") 69 | 70 | numParties = 3 71 | 72 | print("\n===========================IntMPBoot protocol parameters===========================\n") 73 | print(f"number of parties: {numParties}\n") 74 | print("===============================================================\n") 75 | 76 | # Round 1 (party A) 77 | kp1 = cryptoContext.KeyGen() 78 | 79 | # Generate evalmult key part for A 80 | evalMultKey = cryptoContext.KeySwitchGen(kp1.secretKey, kp1.secretKey) 81 | 82 | # Generate evalsum key part for A 83 | cryptoContext.EvalSumKeyGen(kp1.secretKey) 84 | evalSumKeys = cryptoContext.GetEvalSumKeyMap(kp1.secretKey.GetKeyTag()) 85 | 86 | # Round 2 (party B) 87 | kp2 = cryptoContext.MultipartyKeyGen(kp1.publicKey) 88 | evalMultKey2 = cryptoContext.MultiKeySwitchGen(kp2.secretKey, kp2.secretKey, evalMultKey) 89 | evalMultAB = cryptoContext.MultiAddEvalKeys(evalMultKey, evalMultKey2, kp2.publicKey.GetKeyTag()) 90 | evalMultBAB = cryptoContext.MultiMultEvalKey(kp2.secretKey, evalMultAB, kp2.publicKey.GetKeyTag()) 91 | evalSumKeysB = cryptoContext.MultiEvalSumKeyGen(kp2.secretKey, evalSumKeys, kp2.publicKey.GetKeyTag()) 92 | evalSumKeysJoin = cryptoContext.MultiAddEvalSumKeys(evalSumKeys, evalSumKeysB, kp2.publicKey.GetKeyTag()) 93 | cryptoContext.InsertEvalSumKey(evalSumKeysJoin) 94 | evalMultAAB = cryptoContext.MultiMultEvalKey(kp1.secretKey, evalMultAB, kp2.publicKey.GetKeyTag()) 95 | evalMultFinal = cryptoContext.MultiAddEvalMultKeys(evalMultAAB, evalMultBAB, evalMultAB.GetKeyTag()) 96 | cryptoContext.InsertEvalMultKey([evalMultFinal]) 97 | 98 | # Round 3 (party C) - Lead Party (who encrypts and finalizes the bootstrapping protocol) 99 | kp3 = cryptoContext.MultipartyKeyGen(kp2.publicKey) 100 | evalMultKey3 = cryptoContext.MultiKeySwitchGen(kp3.secretKey, kp3.secretKey, evalMultKey) 101 | evalMultABC = cryptoContext.MultiAddEvalKeys(evalMultAB, evalMultKey3, kp3.publicKey.GetKeyTag()) 102 | evalMultBABC = cryptoContext.MultiMultEvalKey(kp2.secretKey, evalMultABC, kp3.publicKey.GetKeyTag()) 103 | evalMultAABC = cryptoContext.MultiMultEvalKey(kp1.secretKey, evalMultABC, kp3.publicKey.GetKeyTag()) 104 | evalMultCABC = cryptoContext.MultiMultEvalKey(kp3.secretKey, evalMultABC, kp3.publicKey.GetKeyTag()) 105 | evalMultABABC = cryptoContext.MultiAddEvalMultKeys(evalMultBABC, evalMultAABC, evalMultBABC.GetKeyTag()) 106 | evalMultFinal2 = cryptoContext.MultiAddEvalMultKeys(evalMultABABC, evalMultCABC, evalMultCABC.GetKeyTag()) 107 | cryptoContext.InsertEvalMultKey([evalMultFinal2]) 108 | 109 | if not kp1.good(): 110 | print("Key generation failed!") 111 | exit(1) 112 | if not kp2.good(): 113 | print("Key generation failed!") 114 | exit(1) 115 | if not kp3.good(): 116 | print("Key generation failed!") 117 | exit(1) 118 | 119 | # END of Key Generation 120 | 121 | input = [-4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0] 122 | 123 | # Chebyshev coefficients 124 | coefficients = [1.0, 0.558971, 0.0, -0.0943712, 0.0, 0.0215023, 0.0, -0.00505348, 0.0, 0.00119324, 125 | 0.0, -0.000281928, 0.0, 0.0000664347, 0.0, -0.0000148709] 126 | # Input range 127 | a = -4 128 | b = 4 129 | 130 | pt1 = cryptoContext.MakeCKKSPackedPlaintext(input) 131 | encodedLength = len(input) 132 | 133 | ct1 = cryptoContext.Encrypt(kp3.publicKey, pt1) 134 | 135 | ct1 = cryptoContext.EvalChebyshevSeries(ct1, coefficients, a, b) 136 | 137 | # INTERACTIVE BOOTSTRAPPING STARTS 138 | 139 | ct1 = cryptoContext.IntMPBootAdjustScale(ct1) 140 | 141 | # Leading party (party B) generates a Common Random Poly (crp) at max coefficient modulus (QNumPrime). 142 | # a is sampled at random uniformly from R_{Q} 143 | crp = cryptoContext.IntMPBootRandomElementGen(kp3.publicKey) 144 | # Each party generates its own shares: maskedDecryptionShare and reEncryptionShare 145 | # (h_{0,i}, h_{1,i}) = (masked decryption share, re-encryption share) 146 | 147 | # extract c1 - element-wise 148 | c1 = ct1.Clone() 149 | c1.RemoveElement(0) 150 | sharesPair0 = cryptoContext.IntMPBootDecrypt(kp1.secretKey, c1, crp) 151 | sharesPair1 = cryptoContext.IntMPBootDecrypt(kp2.secretKey, c1, crp) 152 | sharesPair2 = cryptoContext.IntMPBootDecrypt(kp3.secretKey, c1, crp) 153 | 154 | sharesPairVec = [sharesPair0, sharesPair1, sharesPair2] 155 | 156 | # Party B finalizes the protocol by aggregating the shares and reEncrypting the results 157 | aggregatedSharesPair = cryptoContext.IntMPBootAdd(sharesPairVec) 158 | ciphertextOutput = cryptoContext.IntMPBootEncrypt(kp3.publicKey, aggregatedSharesPair, crp, ct1) 159 | 160 | # INTERACTIVE BOOTSTRAPPING ENDS 161 | 162 | # distributed decryption 163 | 164 | ciphertextPartial1 = cryptoContext.MultipartyDecryptMain([ciphertextOutput], kp1.secretKey) 165 | ciphertextPartial2 = cryptoContext.MultipartyDecryptMain([ciphertextOutput], kp2.secretKey) 166 | ciphertextPartial3 = cryptoContext.MultipartyDecryptLead([ciphertextOutput], kp3.secretKey) 167 | partialCiphertextVec = [ciphertextPartial1[0], ciphertextPartial2[0], ciphertextPartial3[0]] 168 | 169 | plaintextMultiparty = cryptoContext.MultipartyDecryptFusion(partialCiphertextVec) 170 | plaintextMultiparty.SetLength(encodedLength) 171 | 172 | # Ground truth result 173 | result = [0.0179885, 0.0474289, 0.119205, 0.268936, 0.5, 0.731064, 0.880795, 0.952571, 0.982011] 174 | plaintextResult = cryptoContext.MakeCKKSPackedPlaintext(result) 175 | 176 | print("Ground Truth:") 177 | print("\t", plaintextResult.GetCKKSPackedValue()) 178 | print("Computed Result:") 179 | print("\t", plaintextMultiparty.GetCKKSPackedValue()) 180 | 181 | checkApproximateEquality(plaintextResult.GetCKKSPackedValue(), plaintextMultiparty.GetCKKSPackedValue(), encodedLength, 0.0001) 182 | 183 | print("\n============================ INTERACTIVE DECRYPTION ENDED ============================") 184 | 185 | print(f"\nTCKKSCollectiveBoot FHE example with rescaling technique: {scaleTech} Completed!") 186 | 187 | if __name__ == "__main__": 188 | main() 189 | -------------------------------------------------------------------------------- /examples/pke/tckks-interactive-mp-bootstrapping.py: -------------------------------------------------------------------------------- 1 | from openfhe import * 2 | 3 | # 4 | # A utility class defining a party that is involved in the collective bootstrapping protocol 5 | # 6 | class Party: 7 | def __init__(self, id, sharesPair, kpShard): 8 | self.id = id 9 | self.sharesPair = sharesPair 10 | self.kpShard = kpShard 11 | def __init__(self): 12 | self.id = None 13 | self.sharesPair = None 14 | self.kpShard = None 15 | def __str__(self): 16 | return f"Party {self.id}" 17 | 18 | def main(): 19 | print( "Interactive Multi-Party Bootstrapping Ciphertext (TCKKS) started ...\n") 20 | 21 | # Same test with different rescaling techniques in CKKS 22 | TCKKSCollectiveBoot(FIXEDMANUAL) 23 | TCKKSCollectiveBoot(FIXEDAUTO) 24 | if get_native_int()!=128: 25 | TCKKSCollectiveBoot(FLEXIBLEAUTO) 26 | TCKKSCollectiveBoot(FLEXIBLEAUTOEXT) 27 | 28 | print("Interactive Multi-Party Bootstrapping Ciphertext (TCKKS) terminated gracefully!\n") 29 | 30 | # Demonstrate interactive multi-party bootstrapping for 3 parties 31 | # We follow Protocol 5 in https://eprint.iacr.org/2020/304, "Multiparty 32 | # Homomorphic Encryption from Ring-Learning-With-Errors" 33 | 34 | def TCKKSCollectiveBoot(scaleTech): 35 | if scaleTech != FIXEDMANUAL and scaleTech != FIXEDAUTO and scaleTech != FLEXIBLEAUTO and scaleTech != FLEXIBLEAUTOEXT: 36 | errMsg = "ERROR: Scaling technique is not supported!" 37 | raise Exception(errMsg) 38 | 39 | parameters = CCParamsCKKSRNS() 40 | 41 | secretKeyDist = UNIFORM_TERNARY 42 | parameters.SetSecretKeyDist(secretKeyDist) 43 | 44 | parameters.SetSecurityLevel(HEStd_128_classic) 45 | 46 | dcrtBits = 50 47 | firstMod = 60 48 | 49 | parameters.SetScalingModSize(dcrtBits) 50 | parameters.SetScalingTechnique(scaleTech) 51 | parameters.SetFirstModSize(firstMod) 52 | 53 | multiplicativeDepth = 7 54 | parameters.SetMultiplicativeDepth(multiplicativeDepth) 55 | parameters.SetKeySwitchTechnique(HYBRID) 56 | 57 | batchSize = 4 58 | parameters.SetBatchSize(batchSize) 59 | 60 | compressionLevel = COMPRESSION_LEVEL.SLACK 61 | parameters.SetInteractiveBootCompressionLevel(compressionLevel) 62 | 63 | cryptoContext = GenCryptoContext(parameters) 64 | cryptoContext.Enable(PKE) 65 | cryptoContext.Enable(KEYSWITCH) 66 | cryptoContext.Enable(LEVELEDSHE) 67 | cryptoContext.Enable(ADVANCEDSHE) 68 | cryptoContext.Enable(MULTIPARTY) 69 | 70 | ringDim = cryptoContext.GetRingDimension() 71 | maxNumSlots = ringDim / 2 72 | 73 | print(f"TCKKS scheme is using ring dimension {ringDim}") 74 | print(f"TCKKS scheme number of slots {maxNumSlots}") 75 | print(f"TCKKS scheme max number of slots {maxNumSlots}") 76 | print(f"TCKKS example with Scaling Technique {scaleTech}") 77 | 78 | numParties = 3 79 | 80 | print("\n===========================IntMPBoot protocol parameters===========================\n") 81 | print(f"number of parties: {numParties}\n") 82 | print("===============================================================\n") 83 | 84 | # List to store parties objects 85 | parties = [Party()]*numParties 86 | 87 | print("Running key generation (used for source data)...\n") 88 | 89 | for i in range(numParties): 90 | #define id of parties[i] as i 91 | parties[i].id = i 92 | print(f"Party {parties[i].id} started.") 93 | if i == 0: 94 | parties[i].kpShard = cryptoContext.KeyGen() 95 | else: 96 | parties[i].kpShard = cryptoContext.MultipartyKeyGen(parties[0].kpShard.publicKey) 97 | print(f"Party {i} key generation completed.\n") 98 | 99 | print("Joint public key for (s_0 + s_1 + ... + s_n) is generated...") 100 | 101 | # Assert everything is good 102 | for i in range(numParties): 103 | if not parties[i].kpShard.good(): 104 | print(f"Key generation failed for party {i}!\n") 105 | return 1 106 | 107 | # Generate collective public key 108 | secretKeys = [] 109 | for i in range(numParties): 110 | secretKeys.append(parties[i].kpShard.secretKey) 111 | kpMultiparty = cryptoContext.MultipartyKeyGen(secretKeys) 112 | 113 | # Prepare input vector 114 | msg1 = [-0.9, -0.8, 0.2, 0.4] 115 | ptxt1 = cryptoContext.MakeCKKSPackedPlaintext(msg1) 116 | 117 | # Encryption 118 | inCtxt = cryptoContext.Encrypt(kpMultiparty.publicKey, ptxt1) 119 | 120 | print("Compressing ctxt to the smallest possible number of towers!\n") 121 | inCtxt = cryptoContext.IntMPBootAdjustScale(inCtxt) 122 | 123 | print("\n============================ INTERACTIVE BOOTSTRAPPING STARTS ============================\n") 124 | 125 | #Leading party (P0) generates a Common Random Poly (a) at max coefficient modulus (QNumPrime). 126 | # a is sampled at random uniformly from R_{Q} 127 | a = cryptoContext.IntMPBootRandomElementGen(parties[0].kpShard.publicKey) 128 | print("Common Random Poly (a) has been generated with coefficient modulus Q\n") 129 | 130 | # Each party generates its own shares: maskedDecryptionShare and reEncryptionShare 131 | sharePairVec = [] 132 | 133 | # Make a copy of input ciphertext and remove the first element (c0), we only 134 | # c1 for IntMPBootDecrypt 135 | c1 = inCtxt.Clone() 136 | c1.RemoveElement(0) 137 | 138 | for i in range(numParties): 139 | print(f"Party {i} started its part in Collective Bootstrapping Protocol.\n") 140 | parties[i].sharesPair = cryptoContext.IntMPBootDecrypt(parties[i].kpShard.secretKey, c1, a) 141 | sharePairVec.append(parties[i].sharesPair) 142 | 143 | # P0 finalizes the protocol by aggregating the shares and reEncrypting the results 144 | aggregatedSharesPair = cryptoContext.IntMPBootAdd(sharePairVec); 145 | # Make sure you provide the non-striped ciphertext (inCtxt) in IntMPBootEncrypt 146 | outCtxt = cryptoContext.IntMPBootEncrypt(parties[0].kpShard.publicKey, aggregatedSharesPair, a, inCtxt) 147 | 148 | # INTERACTIVE BOOTSTRAPPING ENDS 149 | print("\n============================ INTERACTIVE BOOTSTRAPPING ENDED ============================\n") 150 | 151 | # Distributed Decryption 152 | print("\n============================ INTERACTIVE DECRYPTION STARTED ============================ \n") 153 | 154 | partialCiphertextVec = [] 155 | print("Party 0 started its part in the collective decryption protocol\n") 156 | partialCiphertextVec.append(cryptoContext.MultipartyDecryptLead([outCtxt], parties[0].kpShard.secretKey)[0]) 157 | 158 | for i in range(1, numParties): 159 | print(f"Party {i} started its part in the collective decryption protocol\n") 160 | partialCiphertextVec.append(cryptoContext.MultipartyDecryptMain([outCtxt], parties[i].kpShard.secretKey)[0]) 161 | 162 | # Checking the results 163 | print("MultipartyDecryptFusion ...\n") 164 | plaintextMultiparty = cryptoContext.MultipartyDecryptFusion(partialCiphertextVec) 165 | plaintextMultiparty.SetLength(len(msg1)) 166 | 167 | # transform to python: 168 | print(f"Original plaintext \n\t {ptxt1.GetCKKSPackedValue()}\n") 169 | print(f"Result after bootstrapping \n\t {plaintextMultiparty.GetCKKSPackedValue()}\n") 170 | 171 | print("\n============================ INTERACTIVE DECRYPTION ENDED ============================\n") 172 | 173 | if __name__ == "__main__": 174 | main() 175 | -------------------------------------------------------------------------------- /examples/pke/threshold-fhe-5p.py: -------------------------------------------------------------------------------- 1 | from openfhe import * 2 | from math import log2 3 | 4 | def main(): 5 | print("\n=================RUNNING FOR BFVrns======================\n") 6 | RunBFVrns() 7 | 8 | def RunBFVrns(): 9 | plaintextModulus = 65537 10 | sigma = 3.2 11 | securityLevel = SecurityLevel.HEStd_128_classic 12 | 13 | batchSize = 16 14 | multDepth = 4 15 | digitSize = 30 16 | dcrtBits = 60 17 | 18 | parameters = CCParamsBFVRNS() 19 | parameters.SetPlaintextModulus(plaintextModulus) 20 | parameters.SetSecurityLevel(securityLevel) 21 | parameters.SetStandardDeviation(sigma) 22 | parameters.SetSecretKeyDist(UNIFORM_TERNARY) 23 | parameters.SetMultiplicativeDepth(multDepth) 24 | parameters.SetBatchSize(batchSize) 25 | parameters.SetDigitSize(digitSize) 26 | parameters.SetScalingModSize(dcrtBits) 27 | parameters.SetThresholdNumOfParties(5) 28 | parameters.SetMultiplicationTechnique(HPSPOVERQLEVELED) 29 | 30 | cc = GenCryptoContext(parameters) 31 | # Enable features you wish to use 32 | cc.Enable(PKE) 33 | cc.Enable(KEYSWITCH) 34 | cc.Enable(LEVELEDSHE) 35 | cc.Enable(ADVANCEDSHE) 36 | cc.Enable(MULTIPARTY) 37 | 38 | ########################################################## 39 | # Set-up of parameters 40 | ########################################################## 41 | 42 | # Output the generated parameters 43 | print(f"p = {cc.GetPlaintextModulus()}") 44 | print(f"n = {cc.GetCyclotomicOrder() / 2}") 45 | print(f"log2 q = {log2(cc.GetModulus())}") 46 | 47 | ############################################################ 48 | ## Perform Key Generation Operation 49 | ############################################################ 50 | 51 | print("Running key generation (used for source data)...") 52 | 53 | # Round 1 (party A) 54 | 55 | print("Round 1 (party A) started.") 56 | 57 | kp1 = cc.KeyGen() 58 | kp2 = cc.MultipartyKeyGen(kp1.publicKey) 59 | kp3 = cc.MultipartyKeyGen(kp2.publicKey) 60 | kp4 = cc.MultipartyKeyGen(kp3.publicKey) 61 | kp5 = cc.MultipartyKeyGen(kp4.publicKey) 62 | 63 | # Generate evalmult key part for A 64 | evalMultKey = cc.KeySwitchGen(kp1.secretKey, kp1.secretKey) 65 | evalMultKey2 = cc.MultiKeySwitchGen(kp2.secretKey, kp2.secretKey, evalMultKey) 66 | evalMultKey3 = cc.MultiKeySwitchGen(kp3.secretKey, kp3.secretKey, evalMultKey) 67 | evalMultKey4 = cc.MultiKeySwitchGen(kp4.secretKey, kp4.secretKey, evalMultKey) 68 | evalMultKey5 = cc.MultiKeySwitchGen(kp5.secretKey, kp5.secretKey, evalMultKey) 69 | 70 | evalMultAB = cc.MultiAddEvalKeys(evalMultKey, evalMultKey2, kp2.publicKey.GetKeyTag()) 71 | evalMultABC = cc.MultiAddEvalKeys(evalMultAB, evalMultKey3, kp3.publicKey.GetKeyTag()) 72 | evalMultABCD = cc.MultiAddEvalKeys(evalMultABC, evalMultKey4, kp4.publicKey.GetKeyTag()) 73 | evalMultABCDE = cc.MultiAddEvalKeys(evalMultABCD, evalMultKey5, kp5.publicKey.GetKeyTag()) 74 | 75 | evalMultEABCDE = cc.MultiMultEvalKey(kp5.secretKey, evalMultABCDE, kp5.publicKey.GetKeyTag()) 76 | evalMultDABCDE = cc.MultiMultEvalKey(kp4.secretKey, evalMultABCDE, kp5.publicKey.GetKeyTag()) 77 | evalMultCABCDE = cc.MultiMultEvalKey(kp3.secretKey, evalMultABCDE, kp5.publicKey.GetKeyTag()) 78 | evalMultBABCDE = cc.MultiMultEvalKey(kp2.secretKey, evalMultABCDE, kp5.publicKey.GetKeyTag()) 79 | evalMultAABCDE = cc.MultiMultEvalKey(kp1.secretKey, evalMultABCDE, kp5.publicKey.GetKeyTag()) 80 | 81 | evalMultDEABCDE = cc.MultiAddEvalMultKeys(evalMultEABCDE, evalMultDABCDE, evalMultEABCDE.GetKeyTag()) 82 | evalMultCDEABCDE = cc.MultiAddEvalMultKeys(evalMultCABCDE, evalMultDEABCDE, evalMultCABCDE.GetKeyTag()) 83 | evalMultBCDEABCDE = cc.MultiAddEvalMultKeys(evalMultBABCDE, evalMultCDEABCDE, evalMultBABCDE.GetKeyTag()) 84 | 85 | evalMultFinal = cc.MultiAddEvalMultKeys(evalMultAABCDE, evalMultBCDEABCDE, kp5.publicKey.GetKeyTag()) 86 | cc.InsertEvalMultKey([evalMultFinal]) 87 | 88 | print("Round 1 of key generation completed.") 89 | 90 | ############################################################ 91 | ## EvalSum Key Generation 92 | ############################################################ 93 | 94 | print("Running evalsum key generation (used for source data)...") 95 | 96 | # Generate evalsum key part for A 97 | cc.EvalSumKeyGen(kp1.secretKey) 98 | evalSumKeys = cc.GetEvalSumKeyMap(kp1.secretKey.GetKeyTag()) 99 | 100 | evalSumKeysB = cc.MultiEvalSumKeyGen(kp2.secretKey, evalSumKeys, kp2.publicKey.GetKeyTag()) 101 | evalSumKeysC = cc.MultiEvalSumKeyGen(kp3.secretKey, evalSumKeys, kp3.publicKey.GetKeyTag()) 102 | evalSumKeysD = cc.MultiEvalSumKeyGen(kp4.secretKey, evalSumKeys, kp4.publicKey.GetKeyTag()) 103 | evalSumKeysE = cc.MultiEvalSumKeyGen(kp5.secretKey, evalSumKeys, kp5.publicKey.GetKeyTag()) 104 | 105 | evalSumKeysAB = cc.MultiAddEvalSumKeys(evalSumKeys, evalSumKeysB, kp2.publicKey.GetKeyTag()) 106 | evalSumKeysABC = cc.MultiAddEvalSumKeys(evalSumKeysC, evalSumKeysAB, kp3.publicKey.GetKeyTag()) 107 | evalSumKeysABCD = cc.MultiAddEvalSumKeys(evalSumKeysABC, evalSumKeysD, kp4.publicKey.GetKeyTag()) 108 | 109 | evalSumKeysJoin = cc.MultiAddEvalSumKeys(evalSumKeysE, evalSumKeysABCD, kp5.publicKey.GetKeyTag()) 110 | cc.InsertEvalSumKey(evalSumKeysJoin) 111 | 112 | print("Evalsum key generation completed.") 113 | 114 | ############################################################ 115 | ## Encode source data 116 | ############################################################ 117 | 118 | vectorOfInts1 = [1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1, 0] 119 | vectorOfInts2 = [1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0] 120 | vectorOfInts3 = [2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0] 121 | 122 | plaintext1 = cc.MakePackedPlaintext(vectorOfInts1) 123 | plaintext2 = cc.MakePackedPlaintext(vectorOfInts2) 124 | plaintext3 = cc.MakePackedPlaintext(vectorOfInts3) 125 | 126 | ############################################################ 127 | ## Encryption 128 | ############################################################ 129 | 130 | ciphertext1 = cc.Encrypt(kp5.publicKey, plaintext1) 131 | ciphertext2 = cc.Encrypt(kp5.publicKey, plaintext2) 132 | ciphertext3 = cc.Encrypt(kp5.publicKey, plaintext3) 133 | 134 | ############################################################ 135 | ## Homomorphic Operations 136 | ############################################################ 137 | 138 | ciphertextAdd12 = cc.EvalAdd(ciphertext1, ciphertext2) 139 | ciphertextAdd123 = cc.EvalAdd(ciphertextAdd12, ciphertext3) 140 | 141 | ciphertextMult1 = cc.EvalMult(ciphertext1, ciphertext1) 142 | ciphertextMult2 = cc.EvalMult(ciphertextMult1, ciphertext1) 143 | ciphertextMult3 = cc.EvalMult(ciphertextMult2, ciphertext1) 144 | ciphertextMult = cc.EvalMult(ciphertextMult3, ciphertext1) 145 | 146 | ciphertextEvalSum = cc.EvalSum(ciphertext3, batchSize) 147 | 148 | ############################################################ 149 | ## Decryption after Accumulation Operation on Encrypted Data with Multiparty 150 | ############################################################ 151 | 152 | # Distributed decryption 153 | # partial decryption by party A 154 | ciphertextPartial1 = cc.MultipartyDecryptLead([ciphertextAdd123], kp1.secretKey) 155 | 156 | # partial decryption by party B 157 | ciphertextPartial2 = cc.MultipartyDecryptMain([ciphertextAdd123], kp2.secretKey) 158 | 159 | # partial decryption by party C 160 | ciphertextPartial3 = cc.MultipartyDecryptMain([ciphertextAdd123], kp3.secretKey) 161 | 162 | # partial decryption by party D 163 | ciphertextPartial4 = cc.MultipartyDecryptMain([ciphertextAdd123], kp4.secretKey) 164 | 165 | # partial decryption by party E 166 | ciphertextPartial5 = cc.MultipartyDecryptMain([ciphertextAdd123], kp5.secretKey) 167 | 168 | partialCiphertextVec = [ciphertextPartial1[0], ciphertextPartial2[0], ciphertextPartial3[0], 169 | ciphertextPartial4[0], ciphertextPartial5[0]] 170 | 171 | plaintextMultipartyNew = cc.MultipartyDecryptFusion(partialCiphertextVec) 172 | 173 | print("\n Original Plaintext: \n") 174 | print(plaintext1) 175 | print(plaintext2) 176 | print(plaintext3) 177 | 178 | plaintextMultipartyNew.SetLength(plaintext1.GetLength()) 179 | 180 | print("\n Resulting Fused Plaintext: \n") 181 | print(plaintextMultipartyNew) 182 | 183 | print("\n") 184 | 185 | ciphertextPartial1 = cc.MultipartyDecryptLead([ciphertextMult], kp1.secretKey) 186 | ciphertextPartial2 = cc.MultipartyDecryptMain([ciphertextMult], kp2.secretKey) 187 | ciphertextPartial3 = cc.MultipartyDecryptMain([ciphertextMult], kp3.secretKey) 188 | ciphertextPartial4 = cc.MultipartyDecryptMain([ciphertextMult], kp4.secretKey) 189 | ciphertextPartial5 = cc.MultipartyDecryptMain([ciphertextMult], kp5.secretKey) 190 | 191 | partialCiphertextVecMult = [ciphertextPartial1[0], ciphertextPartial2[0], ciphertextPartial3[0], 192 | ciphertextPartial4[0], ciphertextPartial5[0]] 193 | 194 | plaintextMultipartyMult = cc.MultipartyDecryptFusion(partialCiphertextVecMult) 195 | 196 | plaintextMultipartyMult.SetLength(plaintext1.GetLength()) 197 | 198 | print("\n Resulting Fused Plaintext after Multiplication of plaintexts 1 and 3: \n") 199 | print(plaintextMultipartyMult) 200 | 201 | print("\n") 202 | 203 | ciphertextPartial1 = cc.MultipartyDecryptLead([ciphertextEvalSum], kp1.secretKey) 204 | ciphertextPartial2 = cc.MultipartyDecryptMain([ciphertextEvalSum], kp2.secretKey) 205 | ciphertextPartial3 = cc.MultipartyDecryptMain([ciphertextEvalSum], kp3.secretKey) 206 | ciphertextPartial4 = cc.MultipartyDecryptMain([ciphertextEvalSum], kp4.secretKey) 207 | ciphertextPartial5 = cc.MultipartyDecryptMain([ciphertextEvalSum], kp5.secretKey) 208 | 209 | partialCiphertextVecEvalSum = [ciphertextPartial1[0], ciphertextPartial2[0], ciphertextPartial3[0], 210 | ciphertextPartial4[0], ciphertextPartial5[0]] 211 | 212 | plaintextMultipartyEvalSum = cc.MultipartyDecryptFusion(partialCiphertextVecEvalSum) 213 | 214 | plaintextMultipartyEvalSum.SetLength(plaintext1.GetLength()) 215 | 216 | print("\n Fused result after the Summation of ciphertext 3: \n") 217 | print(plaintextMultipartyEvalSum) 218 | 219 | if __name__ == "__main__": 220 | main() 221 | -------------------------------------------------------------------------------- /openfhe/__init__.py: -------------------------------------------------------------------------------- 1 | from openfhe.openfhe import * 2 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | testpaths = 3 | tests 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | import sys 4 | from setuptools import setup, Extension 5 | from setuptools.command.sdist import sdist as _sdist 6 | from setuptools.command.build_ext import build_ext as _build_ext 7 | from wheel.bdist_wheel import bdist_wheel as _bdist_wheel 8 | import glob 9 | import shutil 10 | 11 | __version__ = '0.9.0' 12 | OPENFHE_PATH = 'openfhe/' 13 | OPENFHE_LIB = 'openfhe.so' 14 | 15 | class CMakeExtension(Extension): 16 | def __init__(self, name, sourcedir=''): 17 | super().__init__(name, sources=[]) 18 | self.sourcedir = os.path.abspath(sourcedir) 19 | 20 | class CMakeBuild(_build_ext): 21 | 22 | def run(self): 23 | for ext in self.extensions: 24 | self.build_cmake(ext) 25 | 26 | def build_cmake(self, ext): 27 | if os.path.exists(OPENFHE_PATH + OPENFHE_LIB): 28 | return 29 | extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name))) 30 | print(extdir) 31 | cmake_args = ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + extdir, 32 | '-DPYTHON_EXECUTABLE=' + sys.executable] 33 | 34 | cfg = 'Debug' if self.debug else 'Release' 35 | build_args = ['--config', cfg] 36 | 37 | build_temp = os.path.abspath(self.build_temp) 38 | os.makedirs(build_temp, exist_ok=True) 39 | 40 | num_cores = os.cpu_count() or 1 41 | build_args += ['--parallel', str(num_cores)] 42 | 43 | subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd=build_temp) 44 | subprocess.check_call(['cmake', '--build', '.', '--target', ext.name] + build_args, cwd=build_temp) 45 | 46 | so_files = glob.glob(os.path.join(extdir, '*.so')) 47 | if not so_files: 48 | raise RuntimeError("Cannot find any built .so file in " + extdir) 49 | 50 | src_file = so_files[0] 51 | dst_file = os.path.join('openfhe', OPENFHE_LIB) 52 | shutil.move(src_file, dst_file) 53 | 54 | # Run build_ext before sdist 55 | class SDist(_sdist): 56 | def run(self): 57 | if os.path.exists(OPENFHE_PATH + OPENFHE_LIB): 58 | os.remove(OPENFHE_PATH + OPENFHE_LIB) 59 | self.run_command('build_ext') 60 | super().run() 61 | 62 | setup( 63 | name='openfhe', 64 | version=__version__, 65 | description='Python wrapper for OpenFHE C++ library.', 66 | author='OpenFHE Team', 67 | author_email='contact@openfhe.org', 68 | url='https://github.com/openfheorg/openfhe-python', 69 | license='BSD-2-Clause', 70 | packages=['openfhe'], 71 | package_data={'openfhe': ['*.so', '*.pyi']}, 72 | ext_modules=[CMakeExtension('openfhe', sourcedir='')], 73 | cmdclass={ 74 | 'build_ext': CMakeBuild, 75 | 'sdist': SDist 76 | }, 77 | include_package_data=True, 78 | python_requires=">=3.6", 79 | install_requires=['pybind11', 'pybind11-global', 'pybind11-stubgen'], 80 | tests_require = ['pytest'], 81 | ) 82 | -------------------------------------------------------------------------------- /src/include/bindings.h: -------------------------------------------------------------------------------- 1 | //================================================================================== 2 | // BSD 2-Clause License 3 | // 4 | // Copyright (c) 2023-2025, Duality Technologies Inc. and other contributors 5 | // 6 | // All rights reserved. 7 | // 8 | // Author TPOC: contact@openfhe.org 9 | // 10 | // Redistribution and use in source and binary forms, with or without 11 | // modification, are permitted provided that the following conditions are met: 12 | // 13 | // 1. Redistributions of source code must retain the above copyright notice, this 14 | // list of conditions and the following disclaimer. 15 | // 16 | // 2. Redistributions in binary form must reproduce the above copyright notice, 17 | // this list of conditions and the following disclaimer in the documentation 18 | // and/or other materials provided with the distribution. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | //================================================================================== 31 | #ifndef __BINDINGS_H__ 32 | #define __BINDINGS_H__ 33 | 34 | #include 35 | 36 | void bind_parameters(pybind11::module &m); 37 | void bind_crypto_context(pybind11::module &m); 38 | void bind_enums_and_constants(pybind11::module &m); 39 | void bind_keys(pybind11::module &m); 40 | void bind_encodings(pybind11::module &m); 41 | void bind_ciphertext(pybind11::module &m); 42 | void bind_serialization(pybind11::module &m); 43 | void bind_schemes(pybind11::module &m); 44 | void bind_sch_swch_params(pybind11::module &m); 45 | 46 | #endif // __BINDINGS_H__ 47 | -------------------------------------------------------------------------------- /src/include/binfhe/binfhecontext_wrapper.h: -------------------------------------------------------------------------------- 1 | //================================================================================== 2 | // BSD 2-Clause License 3 | // 4 | // Copyright (c) 2023-2025, Duality Technologies Inc. and other contributors 5 | // 6 | // All rights reserved. 7 | // 8 | // Author TPOC: contact@openfhe.org 9 | // 10 | // Redistribution and use in source and binary forms, with or without 11 | // modification, are permitted provided that the following conditions are met: 12 | // 13 | // 1. Redistributions of source code must retain the above copyright notice, this 14 | // list of conditions and the following disclaimer. 15 | // 16 | // 2. Redistributions in binary form must reproduce the above copyright notice, 17 | // this list of conditions and the following disclaimer in the documentation 18 | // and/or other materials provided with the distribution. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | //================================================================================== 31 | #ifndef __BINFHECONTEXT_WRAPPER_H__ 32 | #define __BINFHECONTEXT_WRAPPER_H__ 33 | 34 | #include 35 | #include 36 | #include "openfhe.h" 37 | #include "binfhecontext.h" 38 | #include 39 | #include 40 | 41 | namespace py = pybind11; 42 | using namespace lbcrypto; 43 | LWECiphertext binfhe_EncryptWrapper(BinFHEContext &self, 44 | ConstLWEPrivateKey sk, 45 | const LWEPlaintext &m, 46 | BINFHE_OUTPUT output, 47 | LWEPlaintextModulus p, 48 | uint64_t mod); 49 | LWEPlaintext binfhe_DecryptWrapper(BinFHEContext &self, 50 | ConstLWEPrivateKey sk, 51 | ConstLWECiphertext ct, 52 | LWEPlaintextModulus p); 53 | 54 | uint32_t GetnWrapper(BinFHEContext &self); 55 | 56 | const uint64_t GetqWrapper(BinFHEContext &self) ; 57 | 58 | const uint64_t GetMaxPlaintextSpaceWrapper(BinFHEContext &self); 59 | 60 | const uint64_t GetBetaWrapper(BinFHEContext &self); 61 | 62 | const uint64_t GetLWECiphertextModulusWrapper(LWECiphertext &self); 63 | 64 | std::vector GenerateLUTviaFunctionWrapper(BinFHEContext &self, py::function f, uint64_t p); 65 | 66 | NativeInteger StaticFunction(NativeInteger m, NativeInteger p); 67 | 68 | // Define static variables to hold the state 69 | // extern py::function static_f; 70 | 71 | LWECiphertext EvalFuncWrapper(BinFHEContext &self, ConstLWECiphertext &ct, const std::vector &LUT); 72 | 73 | #endif // __BINFHECONTEXT_WRAPPER_H__ -------------------------------------------------------------------------------- /src/include/binfhe_bindings.h: -------------------------------------------------------------------------------- 1 | //================================================================================== 2 | // BSD 2-Clause License 3 | // 4 | // Copyright (c) 2023-2025, Duality Technologies Inc. and other contributors 5 | // 6 | // All rights reserved. 7 | // 8 | // Author TPOC: contact@openfhe.org 9 | // 10 | // Redistribution and use in source and binary forms, with or without 11 | // modification, are permitted provided that the following conditions are met: 12 | // 13 | // 1. Redistributions of source code must retain the above copyright notice, this 14 | // list of conditions and the following disclaimer. 15 | // 16 | // 2. Redistributions in binary form must reproduce the above copyright notice, 17 | // this list of conditions and the following disclaimer in the documentation 18 | // and/or other materials provided with the distribution. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | //================================================================================== 31 | #ifndef __BINFHE_BINDINGS_H__ 32 | #define __BINFHE_BINDINGS_H__ 33 | 34 | #include 35 | 36 | void bind_binfhe_enums(pybind11::module &m); 37 | void bind_binfhe_context(pybind11::module &m); 38 | void bind_binfhe_keys(pybind11::module &m); 39 | void bind_binfhe_ciphertext(pybind11::module &m); 40 | #endif // __BINFHE_BINDINGS_H__ -------------------------------------------------------------------------------- /src/include/docstrings/binfhecontext_docs.h: -------------------------------------------------------------------------------- 1 | //================================================================================== 2 | // BSD 2-Clause License 3 | // 4 | // Copyright (c) 2023-2025, Duality Technologies Inc. and other contributors 5 | // 6 | // All rights reserved. 7 | // 8 | // Author TPOC: contact@openfhe.org 9 | // 10 | // Redistribution and use in source and binary forms, with or without 11 | // modification, are permitted provided that the following conditions are met: 12 | // 13 | // 1. Redistributions of source code must retain the above copyright notice, this 14 | // list of conditions and the following disclaimer. 15 | // 16 | // 2. Redistributions in binary form must reproduce the above copyright notice, 17 | // this list of conditions and the following disclaimer in the documentation 18 | // and/or other materials provided with the distribution. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | //================================================================================== 31 | #ifndef __BINFHECONTEXT_DOCS_H 32 | #define __BINFHECONTEXT_DOCS_H 33 | 34 | // GenerateBinFHEContext 35 | const char* binfhe_GenerateBinFHEContext_parset_docs = R"pbdoc( 36 | Creates a crypto context using predefined parameters sets. Recommended for most users. 37 | 38 | :param set: the parameter set: TOY, MEDIUM, STD128, STD192, STD256 with variants 39 | :type set: BINFHE_PARAMSET 40 | :param method: the bootstrapping method (DM or CGGI or LMKCDEY) 41 | :type method: BINFHE_METHOD 42 | :return: The created crypto context. 43 | :rtype: BinFHEContext 44 | )pbdoc"; 45 | 46 | ////void GenerateBinFHEContext(BINFHE_PARAMSET set, bool arbFunc, uint32_t logQ = 11, int64_t N = 0, BINFHE_METHOD method = GINX, bool timeOptimization = false) 47 | const char* binfhe_GenerateBinFHEContext_docs = R"pbdoc( 48 | Creates a crypto context using custom parameters. Should be used with care (only for advanced users familiar with LWE parameter selection). 49 | 50 | :param set: The parameter set: TOY, MEDIUM, STD128, STD192, STD256 with variants. 51 | :type set: BINFHE_PARAMSET 52 | :param arbFunc: whether need to evaluate an arbitrary function using functional bootstrapping 53 | :type arbFunc: bool 54 | :param logQ: log(input ciphertext modulus) 55 | :type logQ: int 56 | :param N: ring dimension for RingGSW/RLWE used in bootstrapping 57 | :type N: int 58 | :param method: the bootstrapping method (DM or CGGI or LMKCDEY) 59 | :type method: BINFHE_METHOD 60 | :param timeOptimization: whether to use dynamic bootstrapping technique 61 | :type timeOptimization: bool 62 | :return: creates the cryptocontext. 63 | :rtype: BinFHEContext 64 | )pbdoc"; 65 | 66 | // KeyGen 67 | const char* binfhe_KeyGen_docs = R"pbdoc( 68 | Generates a secret key for the main LWE scheme. 69 | 70 | :return: The secret key. 71 | :rtype: LWEPrivateKey 72 | )pbdoc"; 73 | 74 | // BTKeyGen 75 | const char* binfhe_BTKeyGen_docs = R"pbdoc( 76 | Generates bootstrapping keys. 77 | 78 | :param sk: The secret key. 79 | :type sk: LWEPrivateKey 80 | )pbdoc"; 81 | 82 | // Encrypt 83 | const char* binfhe_Encrypt_docs = R"pbdoc( 84 | Encrypts a bit or integer using a secret key (symmetric key encryption). 85 | 86 | :param sk: The secret key. 87 | :type sk: LWEPrivateKey 88 | :param m: The plaintext. 89 | :type m: int 90 | :param output: FRESH to generate a fresh ciphertext, BOOTSTRAPPED to generate a refreshed ciphertext (default). 91 | :type output: BINFHE_OUTPUT 92 | :param p: Plaintext modulus (default 4). 93 | :type p: int 94 | :param mod: Encrypt according to mod instead of m_q if mod != 0. 95 | :type mod: int 96 | :return: The ciphertext. 97 | :rtype: LWECiphertext 98 | )pbdoc"; 99 | 100 | // Decrypt 101 | const char* binfhe_Decrypt_docs = R"pbdoc( 102 | Decrypts a ciphertext using a secret key. 103 | 104 | :param sk: The secret key. 105 | :type sk: LWEPrivateKey 106 | :param ct: The ciphertext. 107 | :type ct: LWECiphertext 108 | :param p: Plaintext modulus (default 4). 109 | :type p: int 110 | :return: The plaintext. 111 | :rtype: int 112 | )pbdoc"; 113 | 114 | // EvalBinGate 115 | const char* binfhe_EvalBinGate_docs = R"pbdoc( 116 | Evaluates a binary gate (calls bootstrapping as a subroutine). 117 | 118 | :param gate: The gate; can be AND, OR, NAND, NOR, XOR, or XNOR. 119 | :type gate: BINGATE 120 | :param ct1: First ciphertext. 121 | :type ct1: LWECiphertext 122 | :param ct2: Second ciphertext. 123 | :type ct2: LWECiphertext 124 | :return: The resulting ciphertext. 125 | :rtype: LWECiphertext 126 | )pbdoc"; 127 | 128 | // EvalNOT 129 | const char* binfhe_EvalNOT_docs = R"pbdoc( 130 | Evaluates the NOT gate. 131 | 132 | :param ct: The input ciphertext. 133 | :type ct: LWECiphertext 134 | :return: The resulting ciphertext. 135 | :rtype: LWECiphertext 136 | )pbdoc"; 137 | 138 | const char* binfhe_EvalDecomp_docs = R"pbdoc( 139 | Evaluate ciphertext decomposition 140 | 141 | :param ct: ciphertext to be bootstrapped 142 | :type ct: LWECiphertext 143 | :return: a list with the resulting ciphertexts 144 | :rtype: List[LWECiphertext] 145 | )pbdoc"; 146 | 147 | const char* binfhe_EvalFloor_docs = R"pbdoc( 148 | Evaluate a round down function 149 | 150 | :param ct: ciphertext to be bootstrapped 151 | :type ct: LWECiphertext 152 | :param roundbits: number of bits to be rounded 153 | :type roundbits: int 154 | :return: the resulting ciphertext 155 | :rtype: LWECiphertext 156 | )pbdoc"; 157 | 158 | const char* binfhe_GenerateLUTviaFunction_docs = R"pbdoc( 159 | Generate the LUT for the to-be-evaluated function 160 | 161 | :param f: the to-be-evaluated function on an integer message and a plaintext modulus 162 | :type f: function(int, int) -> int 163 | :param p: plaintext modulus 164 | :type p: int 165 | :return: the resulting ciphertext 166 | :rtype: List[int] 167 | )pbdoc"; 168 | 169 | const char* binfhe_EvalFunc_docs = R"pbdoc( 170 | Evaluate an arbitrary function 171 | 172 | :param ct: ciphertext to be bootstrapped 173 | :type ct: LWECiphertext 174 | :param LUT: the look-up table of the to-be-evaluated function 175 | :type LUT: List[int] 176 | :return: the resulting ciphertext 177 | :rtype: LWECiphertext 178 | )pbdoc"; 179 | 180 | //LWECiphertext EvalSign(ConstLWECiphertext &ct, bool schemeSwitch = false) 181 | const char* binfhe_EvalSign_docs = R"pbdoc( 182 | Evaluate a sign function over large precisions 183 | 184 | :param ct: ciphertext to be bootstrapped 185 | :type ct: LWECiphertext 186 | :param schemeSwitch: flag that indicates if it should be compatible to scheme switching 187 | :type schemeSwitch: bool 188 | :return: the resulting ciphertext 189 | :rtype: LWECiphertext 190 | )pbdoc"; 191 | 192 | const char* binfhe_SerializedVersion_docs = R"pbdoc( 193 | Return the serialized version number in use. 194 | 195 | :return: the version number 196 | :rtype: uint32_t 197 | )pbdoc"; 198 | 199 | const char* binfhe_SerializedObjectName_docs = R"pbdoc( 200 | Return the serialized object name 201 | 202 | :return: object name 203 | :rtype: std::string 204 | )pbdoc"; 205 | #endif // __BINFHECONTEXT_DOCS_H 206 | -------------------------------------------------------------------------------- /src/include/docstrings/ciphertext_docs.h: -------------------------------------------------------------------------------- 1 | //================================================================================== 2 | // BSD 2-Clause License 3 | // 4 | // Copyright (c) 2023-2025, Duality Technologies Inc. and other contributors 5 | // 6 | // All rights reserved. 7 | // 8 | // Author TPOC: contact@openfhe.org 9 | // 10 | // Redistribution and use in source and binary forms, with or without 11 | // modification, are permitted provided that the following conditions are met: 12 | // 13 | // 1. Redistributions of source code must retain the above copyright notice, this 14 | // list of conditions and the following disclaimer. 15 | // 16 | // 2. Redistributions in binary form must reproduce the above copyright notice, 17 | // this list of conditions and the following disclaimer in the documentation 18 | // and/or other materials provided with the distribution. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | //================================================================================== 31 | #ifndef __CIPHERTEXT_DOCS_H__ 32 | #define __CIPHERTEXT_DOCS_H__ 33 | 34 | // GetLevel 35 | const char* ctx_GetLevel_docs = R"pbdoc( 36 | Get the number of scalings performed. 37 | 38 | :return: The level of the ciphertext. 39 | :rtype: int 40 | )pbdoc"; 41 | 42 | // SetLevel 43 | const char* ctx_SetLevel_docs = R"pbdoc( 44 | Set the number of scalings. 45 | 46 | :param level: The level to set. 47 | :type level: int 48 | )pbdoc"; 49 | 50 | //KeyPair Docs 51 | const char* kp_good_docs = R"pbdoc( 52 | Checks whether both public key and secret key are non-null, or correctly initialized. 53 | 54 | :return: Result. 55 | :rtype: bool 56 | )pbdoc"; 57 | 58 | const char* cc_RemoveElement_docs = R"pbdoc( 59 | Remove an element from the ciphertext inner vector given its index. 60 | 61 | :param index: The index of the element to remove. 62 | :type index: int 63 | )pbdoc"; 64 | #endif // __CIPHERTEXT_DOCS_H__ 65 | -------------------------------------------------------------------------------- /src/include/docstrings/cryptoparameters_docs.h: -------------------------------------------------------------------------------- 1 | //================================================================================== 2 | // BSD 2-Clause License 3 | // 4 | // Copyright (c) 2023-2025, Duality Technologies Inc. and other contributors 5 | // 6 | // All rights reserved. 7 | // 8 | // Author TPOC: contact@openfhe.org 9 | // 10 | // Redistribution and use in source and binary forms, with or without 11 | // modification, are permitted provided that the following conditions are met: 12 | // 13 | // 1. Redistributions of source code must retain the above copyright notice, this 14 | // list of conditions and the following disclaimer. 15 | // 16 | // 2. Redistributions in binary form must reproduce the above copyright notice, 17 | // this list of conditions and the following disclaimer in the documentation 18 | // and/or other materials provided with the distribution. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | //================================================================================== 31 | #ifndef __CRYPTOPARAMETERS_DOCS_H__ 32 | #define __CRYPTOPARAMETERS_DOCS_H__ 33 | 34 | const char* ccparams_doc = R"doc( 35 | Crypto parameters for the BFV, BGV and CKKS scheme. 36 | 37 | :ivar SCHEME scheme: Scheme ID 38 | :ivar PlaintextModulus ptModulus: PlaintextModulus ptModulus is used in BGV/BFV type schemes and impacts noise growth 39 | :ivar int digitSize: digitSize is used in BV Key Switching only (KeySwitchTechnique = BV) and impacts noise growth 40 | :ivar float standardDeviation: standardDeviation is used for Gaussian error generation 41 | :ivar SecretKeyDist secretKeyDist: Secret key distribution: GAUSSIAN, UNIFORM_TERNARY, etc. 42 | :ivar int maxRelinSkDeg: Max relinearization degree of secret key polynomial (used for lazy relinearization) 43 | :ivar KeySwitchTechnique ksTech: key switching technique: BV or HYBRID currently 44 | :ivar ScalingTechnique scalTech: rescaling/modulus switching technique used in CKKS/BGV: FLEXIBLEAUTOEXT, FIXEDMANUL, FLEXIBLEAUTO, etc. 45 | :ivar int batchSize: max batch size of messages to be packed in encoding (number of slots) 46 | :ivar ProxyReEncryptionMode PREMode: PRE security mode 47 | :ivar MultipartyMode multipartyMode: Multiparty security mode in BFV/BGV 48 | :ivar ExecutionMode executionMode: Execution mode in CKKS 49 | :ivar DecryptionNoiseMode decryptionNoiseMode: Decryption noise mode in CKKS 50 | :ivar float noiseEstimate: Noise estimate in CKKS for NOISE_FLOODING_DECRYPT mode. 51 | :ivar float desiredPrecision: Desired precision for 128-bit CKKS. We use this value in NOISE_FLOODING_DECRYPT mode to determine the scaling factor. 52 | :ivar float statisticalSecurity: Statistical security of CKKS in NOISE_FLOODING_DECRYPT mode. This is the bound on the probability of success that any adversary can have. Specifically, they a probability of success of at most 2^(-statisticalSecurity). 53 | :ivar float numAdversarialQueries: This is the number of adversarial queries a user is expecting for their application, which we use to ensure security of CKKS in NOISE_FLOODING_DECRYPT mode. 54 | :ivar int thresholdNumOfParties: This is the number of parties in a threshold application, which is used for bound on the joint secret key 55 | :ivar int firstModSize: firstModSize and scalingModSize are used to calculate ciphertext modulus. The ciphertext modulus should be seen as: Q = q_0 * q_1 * ... * q_n * q' where q_0 is first prime, and it's number of bits is firstModSize other q_i have same number of bits and is equal to scalingModSize the prime q' is not explicitly given, but it is used internally in CKKS and BGV schemes (in *EXT scaling methods) 56 | :ivar int scalingModSize: firstModSize and scalingModSize are used to calculate ciphertext modulus. The ciphertext modulus should be seen as: Q = q_0 * q_1 * ... * q_n * q' where q_0 is first prime, and it's number of bits is firstModSize other q_i have same number of bits and is equal to scalingModSize the prime q' is not explicitly given, but it is used internally in CKKS and BGV schemes (in *EXT scaling methods) 57 | :ivar int numLargeDigits: see KeySwitchTechnique - number of digits in HYBRID key switching 58 | :ivar int multiplicativeDepth: multiplicative depth 59 | :ivar SecurityLevel securityLevel: security level: We use the values from the security standard at http://homomorphicencryption.org/wp-content/uploads/2018/11/HomomorphicEncryptionStandardv1.1.pdf For given ring dimension and security level we have upper bound of possible highest modulus (Q for BV or P*Q for HYBRID) 60 | :ivar int ringDim: ring dimension N of the scheme : the ring is Z_Q[x] / (X^N+1) 61 | :ivar int evalAddCount: number of additions (used for setting noise in BGV and BFV) 62 | :ivar int keySwitchCount: number of key switching operations (used for setting noise in BGV and BFV) 63 | :ivar int multiHopModSize: size of moduli used for PRE in the provable HRA setting 64 | :ivar EncryptionTechnique encryptionTechnique: STANDARD or EXTENDED mode for BFV encryption 65 | :ivar MultiplicationTechnique multiplicationTechnique: multiplication method in BFV: BEHZ, HPS, etc. 66 | :ivar CKKSDataType ckksDataType: CKKS data type: real or complex. Noise flooding is only enabled for real values. 67 | :ivar uint32_t compositeDegree: parameter to support high-precision CKKS RNS with small word sizes 68 | :ivar uint32_t registerWordSize: parameter to support high-precision CKKS RNS with small word sizes 69 | )doc"; 70 | 71 | const char* cc_GetScalingFactorReal_docs = R"pbdoc( 72 | Method to retrieve the scaling factor of level l. For FIXEDMANUAL scaling technique method always returns 2^p, where p corresponds to plaintext modulus 73 | 74 | :param l: For FLEXIBLEAUTO scaling technique the level whose scaling factor we want to learn. Levels start from 0 (no scaling done - all towers) and go up to K-1, where K is the number of towers supported. 75 | :type l: int 76 | :return: the scaling factor. 77 | :rtype: float 78 | )pbdoc"; 79 | 80 | 81 | #endif // __CRYPTOPARAMETERS_DOCS_H__ 82 | -------------------------------------------------------------------------------- /src/include/docstrings/plaintext_docs.h: -------------------------------------------------------------------------------- 1 | //================================================================================== 2 | // BSD 2-Clause License 3 | // 4 | // Copyright (c) 2023-2025, Duality Technologies Inc. and other contributors 5 | // 6 | // All rights reserved. 7 | // 8 | // Author TPOC: contact@openfhe.org 9 | // 10 | // Redistribution and use in source and binary forms, with or without 11 | // modification, are permitted provided that the following conditions are met: 12 | // 13 | // 1. Redistributions of source code must retain the above copyright notice, this 14 | // list of conditions and the following disclaimer. 15 | // 16 | // 2. Redistributions in binary form must reproduce the above copyright notice, 17 | // this list of conditions and the following disclaimer in the documentation 18 | // and/or other materials provided with the distribution. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | //================================================================================== 31 | #ifndef __PLAINTEXT_DOCS_H__ 32 | #define __PLAINTEXT_DOCS_H__ 33 | 34 | // GetScalingFactor 35 | const char* ptx_GetScalingFactor_docs = R"doc( 36 | Get the scaling factor of the plaintext for CKKS-based plaintexts. 37 | 38 | :return: The scaling factor of the plaintext. 39 | :rtype: float 40 | )doc"; 41 | 42 | // SetScalingFactor 43 | const char* ptx_SetScalingFactor_docs = R"pbdoc( 44 | Set the scaling factor of the plaintext for CKKS-based plaintexts. 45 | 46 | :param sf: The scaling factor to set. 47 | :type sf: float 48 | )pbdoc"; 49 | 50 | // GetLength 51 | const char* ptx_GetLength_docs = R"pbdoc( 52 | Get method to return the length of the plaintext. 53 | 54 | :return: The length of the plaintext in terms of the number of bits. 55 | :rtype: int 56 | )pbdoc"; 57 | 58 | // GetSchemeID 59 | const char* ptx_GetSchemeID_docs = R"pbdoc( 60 | Get the encryption technique of the plaintext for BFV-based plaintexts. 61 | 62 | :return: The scheme ID of the plaintext. 63 | :rtype: SCHEME 64 | )pbdoc"; 65 | 66 | // SetLength 67 | const char* ptx_SetLength_docs = R"pbdoc( 68 | Resize the plaintext; only works for plaintexts that support a resizable vector (coefpacked). 69 | 70 | :param newSize: The new size of the plaintext. 71 | :type newSize: int 72 | )pbdoc"; 73 | 74 | // IsEncoded 75 | const char* ptx_IsEncoded_docs = R"pbdoc( 76 | Check if the plaintext is encoded. 77 | 78 | :return: True if the plaintext is encoded, False otherwise. 79 | :rtype: bool 80 | )pbdoc"; 81 | 82 | // GetLogPrecision 83 | const char* ptx_GetLogPrecision_docs = R"pbdoc( 84 | Get the log of the plaintext precision. 85 | 86 | :return: The log of the plaintext precision. 87 | :rtype: float 88 | )pbdoc"; 89 | 90 | // Encode 91 | const char* ptx_Encode_docs = R"pbdoc( 92 | Encode the plaintext into a polynomial. 93 | )pbdoc"; 94 | 95 | // Decode 96 | const char* ptx_Decode_docs = R"pbdoc( 97 | Decode the polynomial into a plaintext. 98 | )pbdoc"; 99 | 100 | const char* ptx_LowBound_docs = R"pbdoc( 101 | Calculate and return lower bound that can be encoded with the plaintext modulus the number to encode MUST be greater than this value 102 | 103 | :return: floor(-p/2) 104 | :rtype: int 105 | )pbdoc"; 106 | 107 | const char* ptx_HighBound_docs = R"pbdoc( 108 | Calculate and return upper bound that can be encoded with the plaintext modulus the number to encode MUST be less than this value 109 | 110 | :return: floor(p/2) 111 | :rtype: int 112 | )pbdoc"; 113 | 114 | const char* ptx_SetFormat_docs = R"pbdoc( 115 | SetFormat - allows format to be changed for openfhe.Plaintext evaluations 116 | 117 | :param fmt: 118 | :type format: Format 119 | )pbdoc"; 120 | 121 | // GetCKKSPackedValue 122 | const char* ptx_GetCKKSPackedValue_docs = R"pbdoc( 123 | Get the packed value of the plaintext for CKKS-based plaintexts. 124 | 125 | :return: The packed value of the plaintext. 126 | :rtype: List[complex] 127 | )pbdoc"; 128 | 129 | 130 | //GetRealPackedValue 131 | const char* ptx_GetRealPackedValue_docs = R"pbdoc( 132 | Get the real component of the packed value of the plaintext for CKKS-based plaintexts. 133 | 134 | :return: The real-component of the packed value of the plaintext. 135 | :rtype: List[double] 136 | )pbdoc"; 137 | 138 | 139 | #endif // __PLAINTEXT_DOCS_H__ 140 | -------------------------------------------------------------------------------- /src/include/pke/cryptocontext_wrapper.h: -------------------------------------------------------------------------------- 1 | //================================================================================== 2 | // BSD 2-Clause License 3 | // 4 | // Copyright (c) 2023-2025, Duality Technologies Inc. and other contributors 5 | // 6 | // All rights reserved. 7 | // 8 | // Author TPOC: contact@openfhe.org 9 | // 10 | // Redistribution and use in source and binary forms, with or without 11 | // modification, are permitted provided that the following conditions are met: 12 | // 13 | // 1. Redistributions of source code must retain the above copyright notice, this 14 | // list of conditions and the following disclaimer. 15 | // 16 | // 2. Redistributions in binary form must reproduce the above copyright notice, 17 | // this list of conditions and the following disclaimer in the documentation 18 | // and/or other materials provided with the distribution. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | //================================================================================== 31 | #ifndef __CRYPTOCONTEXT_WRAPPER_H__ 32 | #define __CRYPTOCONTEXT_WRAPPER_H__ 33 | 34 | #include "openfhe.h" 35 | 36 | using namespace lbcrypto; 37 | 38 | 39 | Ciphertext EvalFastRotationPrecomputeWrapper(CryptoContext &self, 40 | ConstCiphertext ciphertext); 41 | 42 | Ciphertext EvalFastRotationWrapper(CryptoContext &self, 43 | ConstCiphertext ciphertext, 44 | uint32_t index, 45 | uint32_t m, 46 | ConstCiphertext digits); 47 | Ciphertext EvalFastRotationExtWrapper(CryptoContext &self, ConstCiphertext ciphertext, uint32_t index, ConstCiphertext digits, bool addFirst); 48 | 49 | Plaintext DecryptWrapper(CryptoContext &self, 50 | ConstCiphertext ciphertext, const PrivateKey privateKey); 51 | Plaintext DecryptWrapper(CryptoContext &self, 52 | const PrivateKey privateKey, ConstCiphertext ciphertext); 53 | Plaintext MultipartyDecryptFusionWrapper(CryptoContext& self,const std::vector>& partialCiphertextVec); 54 | 55 | const std::shared_ptr>> GetEvalSumKeyMapWrapper(CryptoContext& self, const std::string &id); 56 | PlaintextModulus GetPlaintextModulusWrapper(CryptoContext& self); 57 | double GetModulusWrapper(CryptoContext& self); 58 | void RemoveElementWrapper(Ciphertext& self, uint32_t index); 59 | double GetScalingFactorRealWrapper(CryptoContext& self, uint32_t l); 60 | uint64_t GetModulusCKKSWrapper(CryptoContext& self); 61 | ScalingTechnique GetScalingTechniqueWrapper(CryptoContext& self); 62 | uint32_t GetDigitSizeWrapper(CryptoContext& self); 63 | 64 | void ClearEvalMultKeysWrapper(); 65 | 66 | #endif // __CRYPTOCONTEXT_WRAPPER_H__ 67 | -------------------------------------------------------------------------------- /src/include/pke/serialization.h: -------------------------------------------------------------------------------- 1 | //================================================================================== 2 | // BSD 2-Clause License 3 | // 4 | // Copyright (c) 2023-2025, Duality Technologies Inc. and other contributors 5 | // 6 | // All rights reserved. 7 | // 8 | // Author TPOC: contact@openfhe.org 9 | // 10 | // Redistribution and use in source and binary forms, with or without 11 | // modification, are permitted provided that the following conditions are met: 12 | // 13 | // 1. Redistributions of source code must retain the above copyright notice, this 14 | // list of conditions and the following disclaimer. 15 | // 16 | // 2. Redistributions in binary form must reproduce the above copyright notice, 17 | // this list of conditions and the following disclaimer in the documentation 18 | // and/or other materials provided with the distribution. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | //================================================================================== 31 | #ifndef __SERIALIZATION_H__ 32 | #define __SERIALIZATION_H__ 33 | 34 | #include 35 | 36 | 37 | template 38 | bool SerializeEvalMultKeyWrapper(const std::string& filename, const ST& sertype, std::string id); 39 | 40 | template 41 | bool SerializeEvalAutomorphismKeyWrapper(const std::string& filename, const ST& sertype, std::string id); 42 | 43 | template 44 | bool DeserializeEvalMultKeyWrapper(const std::string& filename, const ST& sertype); 45 | 46 | template 47 | std::string SerializeToStringWrapper(const T& obj, const ST& sertype); 48 | 49 | template 50 | pybind11::bytes SerializeToBytesWrapper(const T& obj, const ST& sertype); 51 | 52 | template 53 | T DeserializeFromStringWrapper(const std::string& str, const ST& sertype); 54 | 55 | template 56 | T DeserializeFromBytesWrapper(const pybind11::bytes& bytes, const ST& sertype); 57 | 58 | template 59 | std::string SerializeEvalMultKeyToStringWrapper(const ST& sertype, const std::string& id); 60 | 61 | template 62 | pybind11::bytes SerializeEvalMultKeyToBytesWrapper(const ST& sertype, const std::string& id); 63 | 64 | template 65 | std::string SerializeEvalAutomorphismKeyToStringWrapper(const ST& sertype, const std::string& id); 66 | 67 | template 68 | pybind11::bytes SerializeEvalAutomorphismKeyToBytesWrapper(const ST& sertype, const std::string& id); 69 | 70 | template 71 | void DeserializeEvalMultKeyFromStringWrapper(const std::string& data, const ST& sertype); 72 | 73 | template 74 | void DeserializeEvalMultKeyFromBytesWrapper(const std::string& data, const ST& sertype); 75 | 76 | template 77 | void DeserializeEvalAutomorphismKeyFromStringWrapper(const std::string& data, const ST& sertype); 78 | 79 | template 80 | void DeserializeEvalAutomorphismKeyFromBytesWrapper(const std::string& data, const ST& sertype); 81 | 82 | #endif // __SERIALIZATION_H__ -------------------------------------------------------------------------------- /src/lib/binfhe/binfhecontext_wrapper.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================== 2 | // BSD 2-Clause License 3 | // 4 | // Copyright (c) 2023-2025, Duality Technologies Inc. and other contributors 5 | // 6 | // All rights reserved. 7 | // 8 | // Author TPOC: contact@openfhe.org 9 | // 10 | // Redistribution and use in source and binary forms, with or without 11 | // modification, are permitted provided that the following conditions are met: 12 | // 13 | // 1. Redistributions of source code must retain the above copyright notice, this 14 | // list of conditions and the following disclaimer. 15 | // 16 | // 2. Redistributions in binary form must reproduce the above copyright notice, 17 | // this list of conditions and the following disclaimer in the documentation 18 | // and/or other materials provided with the distribution. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | //================================================================================== 31 | #include 32 | #include 33 | #include 34 | #include "binfhecontext_wrapper.h" 35 | 36 | using namespace lbcrypto; 37 | namespace py = pybind11; 38 | 39 | LWECiphertext binfhe_EncryptWrapper(BinFHEContext &self, ConstLWEPrivateKey sk, const LWEPlaintext &m, BINFHE_OUTPUT output, 40 | LWEPlaintextModulus p, uint64_t mod) 41 | { 42 | NativeInteger mod_native_int = NativeInteger(mod); 43 | return self.Encrypt(sk, m, output, p, mod_native_int); 44 | } 45 | 46 | LWEPlaintext binfhe_DecryptWrapper(BinFHEContext &self, 47 | ConstLWEPrivateKey sk, 48 | ConstLWECiphertext ct, 49 | LWEPlaintextModulus p) 50 | { 51 | 52 | LWEPlaintext result; 53 | self.Decrypt(sk, ct, &result, p); 54 | return result; 55 | } 56 | 57 | uint32_t GetnWrapper(BinFHEContext &self) 58 | { 59 | return self.GetParams()->GetLWEParams()->Getn(); 60 | } 61 | 62 | const uint64_t GetqWrapper(BinFHEContext &self) 63 | { 64 | return self.GetParams()->GetLWEParams()->Getq().ConvertToInt(); 65 | } 66 | 67 | const uint64_t GetMaxPlaintextSpaceWrapper(BinFHEContext &self) 68 | { 69 | return self.GetMaxPlaintextSpace().ConvertToInt(); 70 | } 71 | 72 | const uint64_t GetBetaWrapper(BinFHEContext &self) 73 | { 74 | return self.GetBeta().ConvertToInt(); 75 | } 76 | 77 | const uint64_t GetLWECiphertextModulusWrapper(LWECiphertext &self) 78 | { 79 | return self->GetModulus().ConvertToInt(); 80 | } 81 | 82 | // Define static variables to hold the state 83 | py::function* static_f = nullptr; 84 | 85 | // Define a static function that uses the static variables 86 | NativeInteger StaticFunction(NativeInteger m, NativeInteger p) { 87 | // Convert the arguments to int 88 | uint64_t m_int = m.ConvertToInt(); 89 | uint64_t p_int = p.ConvertToInt(); 90 | // Call the Python function 91 | py::object result_py = (*static_f)(m_int, p_int); 92 | // Convert the result to a NativeInteger 93 | return NativeInteger(py::cast(result_py)); 94 | } 95 | 96 | std::vector GenerateLUTviaFunctionWrapper(BinFHEContext &self, py::function f, uint64_t p) 97 | { 98 | NativeInteger p_native_int = NativeInteger(p); 99 | static_f = &f; 100 | std::vector result = self.GenerateLUTviaFunction(StaticFunction, p_native_int); 101 | static_f = nullptr; 102 | std::vector result_uint64_t; 103 | // int size_int = static_cast(result.size()); 104 | for (const auto& value : result) 105 | { 106 | result_uint64_t.push_back(value.ConvertToInt()); 107 | } 108 | return result_uint64_t; 109 | } 110 | 111 | // LWECiphertext EvalFunc(ConstLWECiphertext &ct, const std::vector &LUT) const 112 | LWECiphertext EvalFuncWrapper(BinFHEContext &self, ConstLWECiphertext &ct, const std::vector &LUT) 113 | { 114 | std::vector LUT_native_int; 115 | LUT_native_int.reserve(LUT.size()); // Reserve space for the elements 116 | for (const auto& value : LUT) 117 | { 118 | LUT_native_int.push_back(NativeInteger(value)); 119 | } 120 | return self.EvalFunc(ct, LUT_native_int); 121 | } 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /src/lib/binfhe_bindings.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================== 2 | // BSD 2-Clause License 3 | // 4 | // Copyright (c) 2023-2025, Duality Technologies Inc. and other contributors 5 | // 6 | // All rights reserved. 7 | // 8 | // Author TPOC: contact@openfhe.org 9 | // 10 | // Redistribution and use in source and binary forms, with or without 11 | // modification, are permitted provided that the following conditions are met: 12 | // 13 | // 1. Redistributions of source code must retain the above copyright notice, this 14 | // list of conditions and the following disclaimer. 15 | // 16 | // 2. Redistributions in binary form must reproduce the above copyright notice, 17 | // this list of conditions and the following disclaimer in the documentation 18 | // and/or other materials provided with the distribution. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | //================================================================================== 31 | #include "binfhe_bindings.h" 32 | 33 | #include 34 | 35 | #include "openfhe.h" 36 | #include "binfhecontext.h" 37 | #include "binfhecontext_docs.h" 38 | #include "binfhecontext_wrapper.h" 39 | 40 | #include "cereal/archives/binary.hpp" 41 | // #include "cereal/archives/portable_binary.hpp" 42 | // #include "core/utils/serial.h" 43 | 44 | using namespace lbcrypto; 45 | namespace py = pybind11; 46 | 47 | void bind_binfhe_enums(py::module &m) { 48 | py::enum_(m, "BINFHE_PARAMSET") 49 | .value("TOY", BINFHE_PARAMSET::TOY) 50 | .value("MEDIUM", BINFHE_PARAMSET::MEDIUM) 51 | .value("STD128_LMKCDEY", BINFHE_PARAMSET::STD128_LMKCDEY) 52 | .value("STD128_AP", BINFHE_PARAMSET::STD128_AP) 53 | .value("STD128", BINFHE_PARAMSET::STD128) 54 | .value("STD192", BINFHE_PARAMSET::STD192) 55 | .value("STD256", BINFHE_PARAMSET::STD256) 56 | .value("STD128Q", BINFHE_PARAMSET::STD128Q) 57 | .value("STD128Q_LMKCDEY", BINFHE_PARAMSET::STD128Q_LMKCDEY) 58 | .value("STD192Q", BINFHE_PARAMSET::STD192Q) 59 | .value("STD256Q", BINFHE_PARAMSET::STD256Q) 60 | .value("STD128_3", BINFHE_PARAMSET::STD128_3) 61 | .value("STD128_3_LMKCDEY", BINFHE_PARAMSET::STD128_3_LMKCDEY) 62 | .value("STD128Q_3", BINFHE_PARAMSET::STD128Q_3) 63 | .value("STD128Q_3_LMKCDEY", BINFHE_PARAMSET::STD128Q_3_LMKCDEY) 64 | .value("STD192Q_3", BINFHE_PARAMSET::STD192Q_3) 65 | .value("STD256Q_3", BINFHE_PARAMSET::STD256Q_3) 66 | .value("STD128_4", BINFHE_PARAMSET::STD128_4) 67 | .value("STD128_4_LMKCDEY", BINFHE_PARAMSET::STD128_4_LMKCDEY) 68 | .value("STD128Q_4", BINFHE_PARAMSET::STD128Q_4) 69 | .value("STD128Q_4_LMKCDEY", BINFHE_PARAMSET::STD128Q_4_LMKCDEY) 70 | .value("STD192Q_4", BINFHE_PARAMSET::STD192Q_4) 71 | .value("STD256Q_4", BINFHE_PARAMSET::STD256Q_4) 72 | .value("SIGNED_MOD_TEST", BINFHE_PARAMSET::SIGNED_MOD_TEST); 73 | m.attr("TOY") = py::cast(BINFHE_PARAMSET::TOY); 74 | m.attr("MEDIUM") = py::cast(BINFHE_PARAMSET::MEDIUM); 75 | m.attr("STD128_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128_LMKCDEY); 76 | m.attr("STD128_AP") = py::cast(BINFHE_PARAMSET::STD128_AP); 77 | m.attr("STD128") = py::cast(BINFHE_PARAMSET::STD128); 78 | m.attr("STD192") = py::cast(BINFHE_PARAMSET::STD192); 79 | m.attr("STD256") = py::cast(BINFHE_PARAMSET::STD256); 80 | m.attr("STD128Q") = py::cast(BINFHE_PARAMSET::STD128Q); 81 | m.attr("STD128Q_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128Q_LMKCDEY); 82 | m.attr("STD192Q") = py::cast(BINFHE_PARAMSET::STD192Q); 83 | m.attr("STD256Q") = py::cast(BINFHE_PARAMSET::STD256Q); 84 | m.attr("STD128_3") = py::cast(BINFHE_PARAMSET::STD128_3); 85 | m.attr("STD128_3_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128_3_LMKCDEY); 86 | m.attr("STD128Q_3") = py::cast(BINFHE_PARAMSET::STD128Q_3); 87 | m.attr("STD128Q_3_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128Q_3_LMKCDEY); 88 | m.attr("STD192Q_3") = py::cast(BINFHE_PARAMSET::STD192Q_3); 89 | m.attr("STD256Q_3") = py::cast(BINFHE_PARAMSET::STD256Q_3); 90 | m.attr("STD128_4") = py::cast(BINFHE_PARAMSET::STD128_4); 91 | m.attr("STD128_4_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128_4_LMKCDEY); 92 | m.attr("STD128Q_4") = py::cast(BINFHE_PARAMSET::STD128Q_4); 93 | m.attr("STD128Q_4_LMKCDEY") = py::cast(BINFHE_PARAMSET::STD128Q_4_LMKCDEY); 94 | m.attr("STD192Q_4") = py::cast(BINFHE_PARAMSET::STD192Q_4); 95 | m.attr("STD256Q_4") = py::cast(BINFHE_PARAMSET::STD256Q_4); 96 | m.attr("SIGNED_MOD_TEST") = py::cast(BINFHE_PARAMSET::SIGNED_MOD_TEST); 97 | 98 | py::enum_(m, "BINFHE_METHOD") 99 | .value("INVALID_METHOD", BINFHE_METHOD::INVALID_METHOD) 100 | .value("AP", BINFHE_METHOD::AP) 101 | .value("GINX", BINFHE_METHOD::GINX) 102 | .value("LMKCDEY", BINFHE_METHOD::LMKCDEY); 103 | m.attr("INVALID_METHOD") = py::cast(BINFHE_METHOD::INVALID_METHOD); 104 | m.attr("GINX") = py::cast(BINFHE_METHOD::GINX); 105 | m.attr("AP") = py::cast(BINFHE_METHOD::AP); 106 | m.attr("LMKCDEY") = py::cast(BINFHE_METHOD::LMKCDEY); 107 | 108 | py::enum_(m, "KEYGEN_MODE") 109 | .value("SYM_ENCRYPT", KEYGEN_MODE::SYM_ENCRYPT) 110 | .value("PUB_ENCRYPT", KEYGEN_MODE::PUB_ENCRYPT); 111 | m.attr("SYM_ENCRYPT") = py::cast(KEYGEN_MODE::SYM_ENCRYPT); 112 | m.attr("PUB_ENCRYPT") = py::cast(KEYGEN_MODE::PUB_ENCRYPT); 113 | 114 | py::enum_(m, "BINFHE_OUTPUT") 115 | .value("INVALID_OUTPUT", BINFHE_OUTPUT::INVALID_OUTPUT) 116 | .value("FRESH", BINFHE_OUTPUT::FRESH) 117 | .value("BOOTSTRAPPED", BINFHE_OUTPUT::BOOTSTRAPPED); 118 | m.attr("INVALID_OUTPUT") = py::cast(BINFHE_OUTPUT::INVALID_OUTPUT); 119 | m.attr("FRESH") = py::cast(BINFHE_OUTPUT::FRESH); 120 | m.attr("BOOTSTRAPPED") = py::cast(BINFHE_OUTPUT::BOOTSTRAPPED); 121 | 122 | py::enum_(m, "BINGATE") 123 | .value("OR", BINGATE::OR) 124 | .value("AND", BINGATE::AND) 125 | .value("NOR", BINGATE::NOR) 126 | .value("NAND", BINGATE::NAND) 127 | .value("XOR_FAST", BINGATE::XOR_FAST) 128 | .value("XNOR_FAST", BINGATE::XNOR_FAST) 129 | .value("XOR", BINGATE::XOR) 130 | .value("XNOR", BINGATE::XNOR); 131 | m.attr("OR") = py::cast(BINGATE::OR); 132 | m.attr("AND") = py::cast(BINGATE::AND); 133 | m.attr("NOR") = py::cast(BINGATE::NOR); 134 | m.attr("NAND") = py::cast(BINGATE::NAND); 135 | m.attr("XOR_FAST") = py::cast(BINGATE::XOR_FAST); 136 | m.attr("XNOR_FAST") = py::cast(BINGATE::XNOR_FAST); 137 | m.attr("XOR") = py::cast(BINGATE::XOR); 138 | m.attr("XNOR") = py::cast(BINGATE::XNOR); 139 | } 140 | 141 | void bind_binfhe_keys(py::module &m) { 142 | py::class_>( 143 | m, "LWEPrivateKey") 144 | .def(py::init<>()) 145 | .def("GetLength", &LWEPrivateKeyImpl::GetLength) 146 | .def(py::self == py::self) 147 | .def(py::self != py::self); 148 | } 149 | void bind_binfhe_ciphertext(py::module &m) { 150 | py::class_>( 151 | m, "LWECiphertext") 152 | .def(py::init<>()) 153 | .def("GetLength", &LWECiphertextImpl::GetLength) 154 | .def("GetModulus", &GetLWECiphertextModulusWrapper) 155 | .def(py::self == py::self) 156 | .def(py::self != py::self); 157 | } 158 | 159 | void bind_binfhe_context(py::module &m) { 160 | py::class_>(m, "BinFHEContext") 161 | .def(py::init<>()) 162 | .def("GenerateBinFHEContext", 163 | static_cast( 164 | &BinFHEContext::GenerateBinFHEContext), 165 | binfhe_GenerateBinFHEContext_parset_docs, py::arg("set"), 166 | py::arg("method") = GINX) 167 | // void GenerateBinFHEContext(BINFHE_PARAMSET set, bool arbFunc, uint32_t 168 | // logQ = 11, int64_t N = 0, BINFHE_METHOD method = GINX, bool 169 | // timeOptimization = false) 170 | .def("GenerateBinFHEContext", 171 | static_cast( 173 | &BinFHEContext::GenerateBinFHEContext), 174 | binfhe_GenerateBinFHEContext_docs, py::arg("set"), 175 | py::arg("arbFunc"), py::arg("logQ") = 11, py::arg("N") = 0, 176 | py::arg("method") = GINX, py::arg("timeOptimization") = false) 177 | .def("KeyGen", &BinFHEContext::KeyGen, binfhe_KeyGen_docs) 178 | .def("KeyGenN", &BinFHEContext::KeyGenN) 179 | .def("KeyGenPair", &BinFHEContext::KeyGenPair) 180 | .def("BTKeyGen", &BinFHEContext::BTKeyGen, binfhe_BTKeyGen_docs, 181 | py::arg("sk"), py::arg("keygenMode") = SYM_ENCRYPT) 182 | .def("Encrypt", &binfhe_EncryptWrapper, binfhe_Encrypt_docs, 183 | py::arg("sk"), py::arg("m"), py::arg("output") = BOOTSTRAPPED, 184 | py::arg("p") = 4, py::arg("mod") = 0) 185 | .def("Decrypt", &binfhe_DecryptWrapper, binfhe_Decrypt_docs, 186 | py::arg("sk"), py::arg("ct"), py::arg("p") = 4) 187 | .def("EvalBinGate", 188 | static_cast( 190 | &BinFHEContext::EvalBinGate), 191 | binfhe_EvalBinGate_docs, py::arg("gate"), py::arg("ct1"), 192 | py::arg("ct2"), py::arg("extended") = false) 193 | .def("EvalBinGate", 194 | static_cast &, bool) const>( 196 | &BinFHEContext::EvalBinGate), 197 | py::arg("gate"), py::arg("ctvector"), py::arg("extended") = false) 198 | .def("EvalNOT", &BinFHEContext::EvalNOT, binfhe_EvalNOT_docs, 199 | py::arg("ct")) 200 | .def("Getn", &GetnWrapper) 201 | .def("Getq", &GetqWrapper) 202 | .def("GetMaxPlaintextSpace", &GetMaxPlaintextSpaceWrapper) 203 | .def("GetBeta", &GetBetaWrapper) 204 | .def("EvalDecomp", &BinFHEContext::EvalDecomp, binfhe_EvalDecomp_docs, 205 | py::arg("ct")) 206 | .def("EvalFloor", &BinFHEContext::EvalFloor, binfhe_EvalFloor_docs, 207 | py::arg("ct"), py::arg("roundbits") = 0) 208 | .def("GenerateLUTviaFunction", &GenerateLUTviaFunctionWrapper, 209 | binfhe_GenerateLUTviaFunction_docs, py::arg("f"), py::arg("p")) 210 | .def("EvalFunc", &EvalFuncWrapper, binfhe_EvalFunc_docs, py::arg("ct"), 211 | py::arg("LUT")) 212 | .def("EvalSign", &BinFHEContext::EvalSign, binfhe_EvalSign_docs, 213 | py::arg("ct"), py::arg("schemeSwitch") = false) 214 | .def("EvalNOT", &BinFHEContext::EvalNOT) 215 | .def("EvalConstant", &BinFHEContext::EvalConstant) 216 | .def("ClearBTKeys", &BinFHEContext::ClearBTKeys) 217 | .def("Bootstrap", &BinFHEContext::Bootstrap, py::arg("ct"), py::arg("extended") = false) 218 | .def("SerializedVersion", &BinFHEContext::SerializedVersion, 219 | binfhe_SerializedVersion_docs) 220 | .def("SerializedObjectName", &BinFHEContext::SerializedObjectName, 221 | binfhe_SerializedObjectName_docs) 222 | .def("SaveJSON", &BinFHEContext::save) 223 | .def("LoadJSON", &BinFHEContext::load) 224 | .def("SaveBinary", &BinFHEContext::save) 225 | .def("LoadBinary", &BinFHEContext::load) 226 | .def("SavePortableBinary", 227 | &BinFHEContext::save) 228 | .def("LoadPortableBinary", 229 | &BinFHEContext::load) 230 | .def("GetPublicKey", &BinFHEContext::GetPublicKey) 231 | .def("GetSwitchKey", &BinFHEContext::GetSwitchKey) 232 | .def("GetRefreshKey", &BinFHEContext::GetRefreshKey) 233 | .def("GetBinFHEScheme", &BinFHEContext::GetBinFHEScheme) 234 | .def("GetLWEScheme", &BinFHEContext::GetLWEScheme) 235 | .def("GetParams", &BinFHEContext::GetParams); 236 | } 237 | -------------------------------------------------------------------------------- /src/lib/pke/cryptocontext_wrapper.cpp: -------------------------------------------------------------------------------- 1 | //================================================================================== 2 | // BSD 2-Clause License 3 | // 4 | // Copyright (c) 2023-2025, Duality Technologies Inc. and other contributors 5 | // 6 | // All rights reserved. 7 | // 8 | // Author TPOC: contact@openfhe.org 9 | // 10 | // Redistribution and use in source and binary forms, with or without 11 | // modification, are permitted provided that the following conditions are met: 12 | // 13 | // 1. Redistributions of source code must retain the above copyright notice, this 14 | // list of conditions and the following disclaimer. 15 | // 16 | // 2. Redistributions in binary form must reproduce the above copyright notice, 17 | // this list of conditions and the following disclaimer in the documentation 18 | // and/or other materials provided with the distribution. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | //================================================================================== 31 | #include "cryptocontext_wrapper.h" 32 | 33 | 34 | Ciphertext EvalFastRotationPrecomputeWrapper(CryptoContext &self,ConstCiphertext ciphertext) { 35 | std::shared_ptr> precomp = self->EvalFastRotationPrecompute(ciphertext); 36 | std::vector elements = *(precomp.get()); 37 | CiphertextImpl cipherdigits = CiphertextImpl(self); 38 | std::shared_ptr> cipherdigitsPtr = std::make_shared>(cipherdigits); 39 | cipherdigitsPtr->SetElements(elements); 40 | return cipherdigitsPtr; 41 | } 42 | Ciphertext EvalFastRotationWrapper(CryptoContext& self,ConstCiphertext ciphertext, uint32_t index, uint32_t m,ConstCiphertext digits) { 43 | 44 | std::vector digitsElements = digits->GetElements(); 45 | std::shared_ptr> digitsElementsPtr = std::make_shared>(digitsElements); 46 | return self->EvalFastRotation(ciphertext, index, m, digitsElementsPtr); 47 | } 48 | 49 | Ciphertext EvalFastRotationExtWrapper(CryptoContext& self,ConstCiphertext ciphertext, uint32_t index, ConstCiphertext digits, bool addFirst) { 50 | std::vector digitsElements = digits->GetElements(); 51 | std::shared_ptr> digitsElementsPtr = std::make_shared>(digitsElements); 52 | return self->EvalFastRotationExt(ciphertext, index, digitsElementsPtr, addFirst); 53 | } 54 | 55 | 56 | Plaintext DecryptWrapper(CryptoContext& self,ConstCiphertext ciphertext,const PrivateKey privateKey){ 57 | Plaintext plaintextDecResult; 58 | self->Decrypt(privateKey, ciphertext,&plaintextDecResult); 59 | return plaintextDecResult; 60 | } 61 | Plaintext DecryptWrapper(CryptoContext& self,const PrivateKey privateKey,ConstCiphertext ciphertext){ 62 | Plaintext plaintextDecResult; 63 | self->Decrypt(privateKey, ciphertext,&plaintextDecResult); 64 | return plaintextDecResult; 65 | } 66 | 67 | Plaintext MultipartyDecryptFusionWrapper(CryptoContext& self,const std::vector>& partialCiphertextVec){ 68 | Plaintext plaintextDecResult; 69 | self->MultipartyDecryptFusion(partialCiphertextVec,&plaintextDecResult); 70 | return plaintextDecResult; 71 | } 72 | 73 | const std::shared_ptr>> GetEvalSumKeyMapWrapper(CryptoContext& self,const std::string &keyTag){ 74 | return std::make_shared>>(CryptoContextImpl::GetEvalSumKeyMap(keyTag));; 75 | } 76 | 77 | PlaintextModulus GetPlaintextModulusWrapper(CryptoContext& self){ 78 | return self->GetCryptoParameters()->GetPlaintextModulus(); 79 | } 80 | 81 | double GetModulusWrapper(CryptoContext& self){ 82 | return self->GetCryptoParameters()->GetElementParams()->GetModulus().ConvertToDouble(); 83 | } 84 | 85 | void RemoveElementWrapper(Ciphertext &self, uint32_t index){ 86 | self->GetElements().erase(self->GetElements().begin()+index); 87 | } 88 | uint32_t GetDigitSizeWrapper(CryptoContext& self){ 89 | return self->GetCryptoParameters()->GetDigitSize(); 90 | } 91 | 92 | double GetScalingFactorRealWrapper(CryptoContext& self, uint32_t l){ 93 | if(self->getSchemeId()==SCHEME::CKKSRNS_SCHEME){ 94 | const auto cryptoParams = std::dynamic_pointer_cast(self->GetCryptoParameters()); 95 | double scFactor = cryptoParams->GetScalingFactorReal(l); 96 | return scFactor; 97 | } 98 | else if(self->getSchemeId()==SCHEME::BFVRNS_SCHEME){ 99 | const auto cryptoParams = std::dynamic_pointer_cast(self->GetCryptoParameters()); 100 | double scFactor = cryptoParams->GetScalingFactorReal(l); 101 | return scFactor; 102 | } 103 | else if(self->getSchemeId()==SCHEME::BGVRNS_SCHEME){ 104 | const auto cryptoParams = std::dynamic_pointer_cast(self->GetCryptoParameters()); 105 | double scFactor = cryptoParams->GetScalingFactorReal(l); 106 | return scFactor; 107 | } 108 | else{ 109 | OPENFHE_THROW("Invalid scheme"); 110 | return 0; 111 | } 112 | } 113 | 114 | uint64_t GetModulusCKKSWrapper(CryptoContext &self) 115 | { 116 | 117 | const auto cryptoParams = std::dynamic_pointer_cast(self->GetCryptoParameters()); 118 | ILDCRTParams elementParams = *(cryptoParams->GetElementParams()); 119 | auto paramsQ = elementParams.GetParams(); 120 | uint64_t modulus_CKKS_from = paramsQ[0]->GetModulus().ConvertToInt(); 121 | return modulus_CKKS_from; 122 | } 123 | 124 | ScalingTechnique GetScalingTechniqueWrapper(CryptoContext & self){ 125 | if(self->getSchemeId()==SCHEME::CKKSRNS_SCHEME){ 126 | const auto cryptoParams = std::dynamic_pointer_cast(self->GetCryptoParameters()); 127 | return cryptoParams->GetScalingTechnique(); 128 | } 129 | else if(self->getSchemeId()==SCHEME::BFVRNS_SCHEME){ 130 | const auto cryptoParams = std::dynamic_pointer_cast(self->GetCryptoParameters()); 131 | return cryptoParams->GetScalingTechnique(); 132 | } 133 | else if(self->getSchemeId()==SCHEME::BGVRNS_SCHEME){ 134 | const auto cryptoParams = std::dynamic_pointer_cast(self->GetCryptoParameters()); 135 | return cryptoParams->GetScalingTechnique(); 136 | } 137 | else{ 138 | OPENFHE_THROW("Invalid scheme"); 139 | } 140 | 141 | } 142 | 143 | void ClearEvalMultKeysWrapper() { 144 | CryptoContextImpl::ClearEvalMultKeys(); 145 | } -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # Working with Tests 2 | 3 | These tests use [Pytest](https://docs.pytest.org/). 4 | 5 | ## Running and Using Tests 6 | 7 | These tests assume that openfhe-python is installed in the current python environment, which you can check by importing openfhe. 8 | ```bash 9 | python -c "__import__('openfhe')" 10 | ``` 11 | and that the `pytest` package is installed, either through pip or by installing `python3-pytest` in the operating system package manager. 12 | 13 | ### Specific to the OpenFHE unit tests 14 | 15 | Some tests are marked with `@pytest.mark.long` if they are not meant to run 16 | on Github Actions. Run these locally with: 17 | 18 | ```bash 19 | pytest --run-long 20 | pytest --run-all 21 | ``` 22 | 23 | ### General Pytest usage 24 | 25 | This is a quick reminder of pytest's features. To test a particular file: 26 | 27 | ```bash 28 | pytest test_particular_file.py 29 | ``` 30 | 31 | Test all functions matching a name. For instance, this would pick up 32 | `test_add_two_numbers`: 33 | 34 | ```bash 35 | pytest -k add 36 | ``` 37 | 38 | As a reminder, pytest can be helpful for debugging. This command-line option 39 | shows debug output from logging statements. 40 | 41 | ```bash 42 | pytest --log-cli-level=debug 43 | ``` 44 | 45 | If a test is failing, pytest can drop into the debugger when an exception 46 | happens. 47 | 48 | ```bash 49 | pytest --pdb 50 | ``` 51 | 52 | ## Guidelines for Writing Tests 53 | 54 | **Mark long-running tests with long** -- These tests run with default settings 55 | on Github Actions, which can be underpowered, so there is a way to mark tests 56 | that can be run by hand or on other automation servers. 57 | 58 | ```python 59 | @pytest.mark.long 60 | def test_ckks_large_context(): 61 | assert true 62 | ``` 63 | 64 | The goal is for the Github Actions tests to reassure a committer that they have 65 | not broken the Python wrapper. 66 | 67 | **Import OpenFHE as fhe** -- Unit tests tend to use more imports than most 68 | code, for instance JSON, which conflicts with an OpenFHE name, so qualify 69 | imports in the tests. 70 | 71 | ```python 72 | import openfhe as fhe 73 | 74 | def test_something(): 75 | parameters = fhe.CCParamsCKKSRNS() 76 | ``` 77 | 78 | **Use logging instead of print statements** -- Pytest has nice support for 79 | making logging statements visible, in the case that you are using tests 80 | for debugging. 81 | 82 | ```python 83 | import logging 84 | 85 | LOGGER = logging.getLogger("test_file_name") 86 | 87 | def test_something(): 88 | arg = 3 89 | LOGGER.debug("My message has an argument %s", arg) 90 | ``` 91 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is a specially-named file that pytest finds in order to 3 | configure testing. Most of the logic comes from 4 | https://docs.pytest.org/en/7.1.x/example/simple.html#control-skipping-of-tests-according-to-command-line-option 5 | """ 6 | import pytest 7 | 8 | 9 | class CustomMarker: 10 | """ 11 | Custom Markers are used to annotate tests. 12 | 13 | Tests marked with a custom marker will be skipped by default. Pass either 14 | 15 | --run-NAME_OF_MARKER or --run-NAME-OF-MARKER 16 | 17 | to override this behavior. 18 | 19 | --run-all may also be used to run all marked tests. 20 | """ 21 | def __init__(self, name, desc, dest=None): 22 | self.name = name 23 | self.desc = desc 24 | self.dest = name if dest is None else dest 25 | 26 | def option_flags(self): 27 | """ 28 | Return option flags for this marker. 29 | 30 | >>> marker = CustomMarker('foo_bar', 'my desc') 31 | >>> marker.option_flags() 32 | ['--run-foo_bar', '--run-foo-bar'] 33 | >>> marker2 = CustomMarker('foo', 'my desc') 34 | >>> marker2.option_flags() 35 | ['--run-foo'] 36 | """ 37 | # NOTE: pytest is not testing the above doctest 38 | # instead, run this file directly (see doctest.testmod at bottom) 39 | result = ['--run-{}'.format(self.name)] 40 | as_hyphen = '--run-{}'.format(self.name.replace('_', '-')) 41 | if as_hyphen != result[0]: 42 | result.append(as_hyphen) 43 | 44 | return result 45 | 46 | 47 | CUSTOM_MARKERS = ( 48 | CustomMarker('long', 49 | 'this test runs too long for Github Actions'), 50 | CustomMarker('uses_card', 51 | 'must have acceleration card installed to run test'), 52 | ) 53 | 54 | 55 | def pytest_addoption(parser): 56 | """ 57 | pytest hook - adds options to argument parser. 58 | """ 59 | 60 | parser.addoption('--run-all', 61 | dest='run_all', 62 | action='store_true', 63 | help='Run all tests normally skipped by default') 64 | 65 | for marker in CUSTOM_MARKERS: 66 | parser.addoption(*marker.option_flags(), 67 | dest=marker.dest, 68 | action='store_true', 69 | help='Run tests marked with {}'.format(marker.name)) 70 | 71 | 72 | def pytest_configure(config): 73 | # Adds explicit marker definitions 74 | # with these, pytest will error if `--strict` is applied and unregistered 75 | # markers are present. 76 | for marker in CUSTOM_MARKERS: 77 | config.addinivalue_line("markers", 78 | "{}: {}".format(marker.name, marker.desc)) 79 | 80 | 81 | def pytest_collection_modifyitems(config, items): 82 | """ 83 | pytest hook which runs after tests have been collected. 84 | """ 85 | skip_marked_tests(config, items) 86 | 87 | 88 | def skip_marked_tests(config, items): 89 | """ 90 | Dynamically applies pytest.mark.skip to tests with custom markers. 91 | 92 | Tests with explicit --run-FOO flags are not skipped. 93 | 94 | This keeps `pytest` from footshooting with tests that should only be run 95 | under particular conditions. 96 | """ 97 | run_all = config.getoption('--run-all', default=False) 98 | run_mark = {marker.name: config.getoption(marker.dest) 99 | for marker in CUSTOM_MARKERS} 100 | 101 | for item in items: 102 | for marker_name, run_marker in run_mark.items(): 103 | if marker_name in item.keywords and not (run_all or run_marker): 104 | item.add_marker(pytest.mark.skip) 105 | break 106 | -------------------------------------------------------------------------------- /tests/test_bgv.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import random 3 | 4 | import pytest 5 | import openfhe as fhe 6 | 7 | pytestmark = pytest.mark.skipif(fhe.get_native_int() == 32, reason="Doesn't work for NATIVE_INT=32") 8 | 9 | LOGGER = logging.getLogger("test_bgv") 10 | 11 | 12 | @pytest.fixture(scope="module") 13 | def bgv_context(): 14 | """ 15 | This fixture creates a small CKKS context, with its paramters and keys. 16 | We make it because context creation can be slow. 17 | """ 18 | parameters = fhe.CCParamsBGVRNS() 19 | parameters.SetPlaintextModulus(65537) 20 | parameters.SetMultiplicativeDepth(2) 21 | 22 | crypto_context = fhe.GenCryptoContext(parameters) 23 | crypto_context.Enable(fhe.PKESchemeFeature.PKE) 24 | crypto_context.Enable(fhe.PKESchemeFeature.KEYSWITCH) 25 | crypto_context.Enable(fhe.PKESchemeFeature.LEVELEDSHE) 26 | key_pair = crypto_context.KeyGen() 27 | # Generate the relinearization key 28 | crypto_context.EvalMultKeyGen(key_pair.secretKey) 29 | # Generate the rotation evaluation keys 30 | crypto_context.EvalRotateKeyGen(key_pair.secretKey, [1, 2, -1, -2]) 31 | return parameters, crypto_context, key_pair 32 | 33 | 34 | def bgv_equal(raw, ciphertext, cc, keys): 35 | """Compare an unencrypted list of values with encrypted values""" 36 | pt = cc.Decrypt(ciphertext, keys.secretKey) 37 | pt.SetLength(len(raw)) 38 | compare = pt.GetPackedValue() 39 | success = all([a == b for (a, b) in zip(raw, compare)]) 40 | if not success: 41 | LOGGER.info("Mismatch between %s %s", raw, compare) 42 | return success 43 | 44 | 45 | def roll(a, n): 46 | """Circularly rotate a list, like numpy.roll but without numpy.""" 47 | return [a[i % len(a)] for i in range(-n, len(a) - n)] 48 | 49 | 50 | @pytest.mark.parametrize("n,final", [ 51 | (0, [0, 1, 2, 3, 4, 5, 6, 7]), 52 | (2, [6, 7, 0, 1, 2, 3, 4, 5]), 53 | (3, [5, 6, 7, 0, 1, 2, 3, 4]), 54 | (-1, [1, 2, 3, 4, 5, 6, 7, 0]), 55 | ]) 56 | def test_roll(n, final): 57 | assert roll(list(range(8)), n) == final 58 | 59 | 60 | def shift(a, n): 61 | """Rotate a list with infill of 0.""" 62 | return [(a[i] if 0 <= i < len(a) else 0) for i in range(-n, len(a) - n)] 63 | 64 | 65 | @pytest.mark.parametrize("n,final", [ 66 | (0, [1, 2, 3, 4, 5, 6, 7, 8]), 67 | (2, [0, 0, 1, 2, 3, 4, 5, 6]), 68 | (3, [0, 0, 0, 1, 2, 3, 4, 5]), 69 | (-1, [2, 3, 4, 5, 6, 7, 8, 0]), 70 | ]) 71 | def test_shift(n, final): 72 | assert shift(list(range(1, 9)), n) == final 73 | 74 | 75 | def test_simple_integers(bgv_context): 76 | parameters, crypto_context, key_pair = bgv_context 77 | rng = random.Random(342342) 78 | cnt = 12 79 | raw = [[rng.randint(1, 12) for _ in range(cnt)] for _ in range(3)] 80 | plaintext = [crypto_context.MakePackedPlaintext(r) for r in raw] 81 | ciphertext = [crypto_context.Encrypt(key_pair.publicKey, pt) for pt in plaintext] 82 | assert bgv_equal(raw[0], ciphertext[0], crypto_context, key_pair) 83 | 84 | # Homomorphic additions 85 | ciphertext_add12 = crypto_context.EvalAdd(ciphertext[0], ciphertext[1]) 86 | ciphertext_add_result = crypto_context.EvalAdd(ciphertext_add12, ciphertext[2]) 87 | assert bgv_equal( 88 | [a + b + c for (a, b, c) in zip(*raw)], 89 | ciphertext_add_result, crypto_context, key_pair 90 | ) 91 | 92 | # Homomorphic Multiplication 93 | ciphertext_mult12 = crypto_context.EvalMult(ciphertext[0], ciphertext[1]) 94 | ciphertext_mult_result = crypto_context.EvalMult(ciphertext_mult12, ciphertext[2]) 95 | assert bgv_equal( 96 | [a * b * c for (a, b, c) in zip(*raw)], 97 | ciphertext_mult_result, crypto_context, key_pair 98 | ) 99 | 100 | # Homomorphic Rotations. These values must be initialized with EvalRotateKeyGen. 101 | for rotation in [1, 2, -1, -2]: 102 | ciphertext_rot1 = crypto_context.EvalRotate(ciphertext[0], rotation) 103 | # This is a rotation with infill of 0, NOT a circular rotation. 104 | assert bgv_equal(shift(raw[0], -rotation), ciphertext_rot1, crypto_context, key_pair) 105 | -------------------------------------------------------------------------------- /tests/test_boolean.py: -------------------------------------------------------------------------------- 1 | from openfhe import * 2 | import pytest 3 | 4 | 5 | ## Sample Program: Step 1: Set CryptoContext 6 | @pytest.mark.parametrize("a", [0, 1]) 7 | @pytest.mark.parametrize("b", [0, 1]) 8 | def test_boolean_AND(a, b): 9 | cc = BinFHEContext() 10 | 11 | """ 12 | STD128 is the security level of 128 bits of security based on LWE Estimator 13 | and HE standard. Other common options are TOY, MEDIUM, STD192, and STD256. 14 | MEDIUM corresponds to the level of more than 100 bits for both quantum and 15 | classical computer attacks 16 | """ 17 | cc.GenerateBinFHEContext(STD128, GINX) 18 | 19 | ## Sample Program: Step 2: Key Generation 20 | 21 | # Generate the secret key 22 | sk = cc.KeyGen() 23 | 24 | print("Generating the bootstrapping keys...\n") 25 | 26 | # Generate the bootstrapping keys (refresh and switching keys) 27 | cc.BTKeyGen(sk) 28 | 29 | # Sample Program: Step 3: Encryption 30 | """ 31 | Encrypt two ciphertexts representing Boolean True (1). 32 | By default, freshly encrypted ciphertexts are bootstrapped. 33 | If you wish to get a fresh encryption without bootstrapping, write 34 | ct1 = cc.Encrypt(sk, 1, FRESH) 35 | """ 36 | 37 | ct1 = cc.Encrypt(sk, a) 38 | ct2 = cc.Encrypt(sk, b) 39 | 40 | # Sample Program: Step 4: Evaluation 41 | 42 | # Compute (1 AND 1) = 1; Other binary gate options are OR, NAND, and NOR 43 | ctAND1 = cc.EvalBinGate(AND, ct1, ct2) 44 | 45 | # Compute (NOT 1) = 0 46 | ct2Not = cc.EvalNOT(ct2) 47 | 48 | # Compute (1 AND (NOT 1)) = 0 49 | ctAND2 = cc.EvalBinGate(AND, ct2Not, ct1) 50 | 51 | # Compute OR of the result in ctAND1 and ctAND2 52 | ctResult = cc.EvalBinGate(OR, ctAND1, ctAND2) 53 | 54 | # Sample Program: Step 5: Decryption 55 | 56 | result = cc.Decrypt(sk, ctResult) 57 | 58 | print( 59 | f"Result of encrypted computation of ({a} AND {b}) OR ({a} AND (NOT {b})) = {result}" 60 | ) 61 | plaintext_result = (a and b) or (a and (not b)) 62 | assert ( 63 | result == plaintext_result 64 | ), "Logical AND in plaintext and ciphertext should be same" 65 | -------------------------------------------------------------------------------- /tests/test_ckks.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | import pytest 4 | import openfhe as fhe 5 | 6 | pytestmark = pytest.mark.skipif(fhe.get_native_int() == 32, reason="Doesn't work for NATIVE_INT=32") 7 | 8 | @pytest.fixture(scope="module") 9 | def ckks_context(): 10 | """ 11 | This fixture creates a small CKKS context, with its paramters and keys. 12 | We make it because context creation can be slow. 13 | """ 14 | batch_size = 8 15 | parameters = fhe.CCParamsCKKSRNS() 16 | parameters.SetMultiplicativeDepth(5) 17 | if fhe.get_native_int() == 128: 18 | parameters.SetFirstModSize(89) 19 | parameters.SetScalingModSize(78) 20 | parameters.SetBatchSize(batch_size) 21 | parameters.SetScalingTechnique(fhe.ScalingTechnique.FIXEDAUTO) 22 | parameters.SetNumLargeDigits(2) 23 | 24 | elif fhe.get_native_int() == 64: 25 | parameters.SetFirstModSize(60) 26 | parameters.SetScalingModSize(56) 27 | parameters.SetBatchSize(batch_size) 28 | parameters.SetScalingTechnique(fhe.ScalingTechnique.FLEXIBLEAUTO) 29 | parameters.SetNumLargeDigits(2) 30 | 31 | else: 32 | raise ValueError("Expected a native int size 64 or 128.") 33 | 34 | cc = fhe.GenCryptoContext(parameters) 35 | cc.Enable(fhe.PKESchemeFeature.PKE) 36 | cc.Enable(fhe.PKESchemeFeature.KEYSWITCH) 37 | cc.Enable(fhe.PKESchemeFeature.LEVELEDSHE) 38 | keys = cc.KeyGen() 39 | cc.EvalRotateKeyGen(keys.secretKey, [1, -2]) 40 | return parameters, cc, keys 41 | 42 | 43 | def test_add_two_numbers(ckks_context): 44 | params, cc, keys = ckks_context 45 | batch_size = params.GetBatchSize() 46 | rng = random.Random(42429842) 47 | raw = [[rng.uniform(-1, 1) for _ in range(batch_size)] for _ in range(2)] 48 | ptxt = [cc.MakeCKKSPackedPlaintext(x) for x in raw] 49 | ctxt = [cc.Encrypt(keys.publicKey, y) for y in ptxt] 50 | 51 | ct_added = cc.EvalAdd(ctxt[0], ctxt[1]) 52 | pt_added = cc.Decrypt(ct_added, keys.secretKey) 53 | pt_added.SetLength(batch_size) 54 | final_added = pt_added.GetCKKSPackedValue() 55 | raw_added = [a + b for (a, b) in zip(*raw)] 56 | total = sum(abs(a - b) for (a, b) in zip(raw_added, final_added)) 57 | assert total < 1e-3 58 | -------------------------------------------------------------------------------- /tests/test_cryptocontext.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import openfhe as fhe 3 | 4 | pytestmark = pytest.mark.skipif(fhe.get_native_int() != 128, reason="Only for NATIVE_INT=128") 5 | 6 | @pytest.mark.parametrize("scaling", [fhe.FIXEDAUTO, fhe.FIXEDMANUAL]) 7 | def test_ckks_context(scaling): 8 | batch_size = 8 9 | parameters = fhe.CCParamsCKKSRNS() 10 | parameters.SetMultiplicativeDepth(5) 11 | parameters.SetScalingModSize(78) 12 | parameters.SetBatchSize(batch_size) 13 | parameters.SetScalingTechnique(scaling) 14 | parameters.SetNumLargeDigits(2) 15 | cc = fhe.GenCryptoContext(parameters) 16 | assert isinstance(cc, fhe.CryptoContext) 17 | -------------------------------------------------------------------------------- /tests/test_examples.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from pathlib import Path 4 | import importlib.util 5 | import pytest 6 | import tempfile 7 | import shutil 8 | import openfhe as fhe 9 | 10 | pytestmark = pytest.mark.skipif(fhe.get_native_int() == 32, reason="Doesn't work for NATIVE_INT=32") 11 | 12 | EXAMPLES_SCRIPTS_PATH = os.path.join(Path(__file__).parent.parent, "examples", "pke") 13 | 14 | 15 | def importhelper(path, modulename): 16 | spec = importlib.util.spec_from_file_location( 17 | modulename, os.path.join(path, modulename + ".py") 18 | ) 19 | module = importlib.util.module_from_spec(spec) 20 | sys.modules[modulename] = module 21 | spec.loader.exec_module(module) 22 | return module 23 | 24 | 25 | @pytest.mark.parametrize( 26 | "raw_modulename", 27 | [ 28 | "simple-ckks-bootstrapping.py", 29 | "simple-integers-serial-bgvrns.py", 30 | "function-evaluation.py", 31 | "advanced-real-numbers-128.py", 32 | "simple-integers-bgvrns.py", 33 | "simple-integers-serial.py", 34 | "polynomial-evaluation.py", 35 | "scheme-switching.py", 36 | "tckks-interactive-mp-bootstrapping.py", 37 | "advanced-real-numbers.py", 38 | "threshold-fhe-5p.py", 39 | "simple-integers.py", 40 | "simple-real-numbers-serial.py", 41 | "iterative-ckks-bootstrapping.py", 42 | "tckks-interactive-mp-bootstrapping-Chebyschev.py", 43 | "simple-real-numbers.py", 44 | "threshold-fhe.py", 45 | "pre-buffer.py", 46 | ], 47 | ) 48 | def test_run_scripts(raw_modulename): 49 | with tempfile.TemporaryDirectory() as td: 50 | os.mkdir(td + "/demoData") 51 | modulename_py = raw_modulename.replace("-", "_") 52 | shutil.copyfile( 53 | os.path.join(EXAMPLES_SCRIPTS_PATH, raw_modulename), 54 | os.path.join(td, modulename_py), 55 | ) 56 | sys.path.insert(0, td) 57 | modulename = modulename_py.split(".")[0] 58 | print(f"-*- running module {modulename} -*-") 59 | module = importhelper(td, modulename) 60 | module.main() 61 | -------------------------------------------------------------------------------- /tests/test_serial_cc.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import pytest 3 | 4 | import openfhe as fhe 5 | 6 | pytestmark = pytest.mark.skipif(fhe.get_native_int() == 32, reason="Doesn't work for NATIVE_INT=32") 7 | 8 | LOGGER = logging.getLogger("test_serial_cc") 9 | 10 | 11 | def test_serial_cryptocontext(tmp_path): 12 | parameters = fhe.CCParamsBFVRNS() 13 | parameters.SetPlaintextModulus(65537) 14 | parameters.SetMultiplicativeDepth(2) 15 | 16 | cryptoContext = fhe.GenCryptoContext(parameters) 17 | cryptoContext.Enable(fhe.PKESchemeFeature.PKE) 18 | 19 | keypair = cryptoContext.KeyGen() 20 | vectorOfInts1 = list(range(12)) 21 | plaintext1 = cryptoContext.MakePackedPlaintext(vectorOfInts1) 22 | ciphertext1 = cryptoContext.Encrypt(keypair.publicKey, plaintext1) 23 | 24 | assert fhe.SerializeToFile(str(tmp_path / "cryptocontext.json"), cryptoContext, fhe.JSON) 25 | LOGGER.debug("The cryptocontext has been serialized.") 26 | assert fhe.SerializeToFile(str(tmp_path / "ciphertext1.json"), ciphertext1, fhe.JSON) 27 | 28 | fhe.ClearEvalMultKeys() 29 | cryptoContext.ClearEvalAutomorphismKeys() 30 | fhe.ReleaseAllContexts() 31 | 32 | cc, success = fhe.DeserializeCryptoContext(str(tmp_path / "cryptocontext.json"), fhe.JSON) 33 | assert success 34 | assert isinstance(cc, fhe.CryptoContext) 35 | assert fhe.SerializeToFile(str(tmp_path / "cryptocontext2.json"), cc, fhe.JSON) 36 | LOGGER.debug("The cryptocontext has been serialized.") 37 | 38 | ct1, success = fhe.DeserializeCiphertext(str(tmp_path / "ciphertext1.json"), fhe.JSON) 39 | assert success 40 | assert isinstance(ct1, fhe.Ciphertext) 41 | LOGGER.debug("Cryptocontext deserializes to %s %s", success, ct1) 42 | assert fhe.SerializeToFile(str(tmp_path / "ciphertext12.json"), ct1, fhe.JSON) 43 | 44 | 45 | VECTOR1_ROTATION = 1 46 | VECTOR2_ROTATION = 2 47 | VECTOR3_ROTATION = -1 48 | VECTOR4_ROTATION = -2 49 | 50 | @pytest.mark.parametrize("mode", [fhe.JSON, fhe.BINARY]) 51 | def test_serial_cryptocontext_str(mode): 52 | parameters = fhe.CCParamsBFVRNS() 53 | parameters.SetPlaintextModulus(65537) 54 | parameters.SetMultiplicativeDepth(2) 55 | 56 | cryptoContext = fhe.GenCryptoContext(parameters) 57 | cryptoContext.Enable(fhe.PKE) 58 | cryptoContext.Enable(fhe.KEYSWITCH) 59 | cryptoContext.Enable(fhe.LEVELEDSHE) 60 | cryptoContext.Enable(fhe.PKESchemeFeature.PRE) 61 | 62 | keypair = cryptoContext.KeyGen() 63 | 64 | # First plaintext vector is encoded 65 | vectorOfInts1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 66 | plaintext1 = cryptoContext.MakePackedPlaintext(vectorOfInts1) 67 | 68 | # Second plaintext vector is encoded 69 | vectorOfInts2 = [3, 2, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12] 70 | plaintext2 = cryptoContext.MakePackedPlaintext(vectorOfInts2) 71 | 72 | # Third plaintext vector is encoded 73 | vectorOfInts3 = [1, 2, 5, 2, 5, 6, 7, 8, 9, 10, 11, 12] 74 | plaintext3 = cryptoContext.MakePackedPlaintext(vectorOfInts3) 75 | 76 | # Create a final array adding the three vectors 77 | initialPlaintextAddResult = [vectorOfInts1[i] + vectorOfInts2[i] + vectorOfInts3[i] for i in range(len(vectorOfInts1))] 78 | initialPlaintextAddResult = cryptoContext.MakePackedPlaintext(initialPlaintextAddResult) 79 | 80 | # Multiply the values 81 | initialPlaintextMultResult = [vectorOfInts1[i] * vectorOfInts2[i] * vectorOfInts3[i] for i in range(len(vectorOfInts1))] 82 | initialPlaintextMultResult = cryptoContext.MakePackedPlaintext(initialPlaintextMultResult) 83 | 84 | # Rotate the values 85 | initialPlaintextRot1 = rotate_vector(vectorOfInts1, VECTOR1_ROTATION) 86 | initialPlaintextRot1 = cryptoContext.MakePackedPlaintext(initialPlaintextRot1) 87 | initialPlaintextRot2 = rotate_vector(vectorOfInts2, VECTOR2_ROTATION) 88 | initialPlaintextRot2 = cryptoContext.MakePackedPlaintext(initialPlaintextRot2) 89 | initialPlaintextRot3 = rotate_vector(vectorOfInts3, VECTOR3_ROTATION) 90 | initialPlaintextRot3 = cryptoContext.MakePackedPlaintext(initialPlaintextRot3) 91 | initialPlaintextRot4 = rotate_vector(vectorOfInts3, VECTOR4_ROTATION) 92 | initialPlaintextRot4 = cryptoContext.MakePackedPlaintext(initialPlaintextRot4) 93 | 94 | # The encoded vectors are encrypted 95 | ciphertext1 = cryptoContext.Encrypt(keypair.publicKey, plaintext1) 96 | ciphertext2 = cryptoContext.Encrypt(keypair.publicKey, plaintext2) 97 | ciphertext3 = cryptoContext.Encrypt(keypair.publicKey, plaintext3) 98 | 99 | evalKey = cryptoContext.ReKeyGen(keypair.secretKey, keypair.publicKey) 100 | cryptoContext.EvalMultKeyGen(keypair.secretKey) 101 | cryptoContext.EvalRotateKeyGen(keypair.secretKey, [VECTOR1_ROTATION, VECTOR2_ROTATION, VECTOR3_ROTATION, VECTOR4_ROTATION]) 102 | 103 | cryptoContext_ser = fhe.Serialize(cryptoContext, mode) 104 | LOGGER.debug("The cryptocontext has been serialized.") 105 | publickey_ser = fhe.Serialize(keypair.publicKey, mode) 106 | LOGGER.debug("The public key has been serialized.") 107 | secretkey_ser = fhe.Serialize(keypair.secretKey, mode) 108 | LOGGER.debug("The private key has been serialized.") 109 | ciphertext1_ser = fhe.Serialize(ciphertext1, mode) 110 | LOGGER.debug("The ciphertext 1 has been serialized.") 111 | ciphertext2_ser = fhe.Serialize(ciphertext2, mode) 112 | LOGGER.debug("The ciphertext 2 has been serialized.") 113 | ciphertext3_ser = fhe.Serialize(ciphertext3, mode) 114 | LOGGER.debug("The ciphertext 3 has been serialized.") 115 | evalKey_ser = fhe.Serialize(evalKey, mode) 116 | LOGGER.debug("The evaluation key has been serialized.") 117 | multKey_ser = fhe.SerializeEvalMultKeyString(mode, "") 118 | LOGGER.debug("The relinearization key has been serialized.") 119 | automorphismKey_ser = fhe.SerializeEvalAutomorphismKeyString(mode, "") 120 | LOGGER.debug("The rotation evaluation keys have been serialized.") 121 | 122 | fhe.ClearEvalMultKeys() 123 | cryptoContext.ClearEvalAutomorphismKeys() 124 | fhe.ReleaseAllContexts() 125 | 126 | cc = fhe.DeserializeCryptoContextString(cryptoContext_ser, mode) 127 | assert isinstance(cc, fhe.CryptoContext) 128 | LOGGER.debug("The cryptocontext has been deserialized.") 129 | 130 | pk = fhe.DeserializePublicKeyString(publickey_ser, mode) 131 | assert isinstance(pk, fhe.PublicKey) 132 | LOGGER.debug("The public key has been deserialized.") 133 | 134 | sk = fhe.DeserializePrivateKeyString(secretkey_ser, mode) 135 | assert isinstance(sk, fhe.PrivateKey) 136 | LOGGER.debug("The private key has been deserialized.") 137 | 138 | ct1 = fhe.DeserializeCiphertextString(ciphertext1_ser, mode) 139 | assert isinstance(ct1, fhe.Ciphertext) 140 | LOGGER.debug("The ciphertext 1 has been reserialized.") 141 | 142 | ct2 = fhe.DeserializeCiphertextString(ciphertext2_ser, mode) 143 | assert isinstance(ct2, fhe.Ciphertext) 144 | LOGGER.debug("The ciphertext 2 has been reserialized.") 145 | 146 | ct3 = fhe.DeserializeCiphertextString(ciphertext3_ser, mode) 147 | assert isinstance(ct3, fhe.Ciphertext) 148 | LOGGER.debug("The ciphertext 3 has been reserialized.") 149 | 150 | ek = fhe.DeserializeEvalKeyString(evalKey_ser, mode) 151 | assert isinstance(ek, fhe.EvalKey) 152 | LOGGER.debug("The evaluation key has been deserialized.") 153 | 154 | fhe.DeserializeEvalMultKeyString(multKey_ser, mode) 155 | LOGGER.debug("The relinearization key has been deserialized.") 156 | 157 | fhe.DeserializeEvalAutomorphismKeyString(automorphismKey_ser, mode) 158 | LOGGER.debug("The rotation evaluation keys have been deserialized.") 159 | 160 | # Homomorphic addition 161 | 162 | ciphertextAdd12 = cc.EvalAdd(ct1, ct2) 163 | ciphertextAddResult = cc.EvalAdd(ciphertextAdd12, ct3) 164 | 165 | # Homomorphic multiplication 166 | ciphertextMult12 = cc.EvalMult(ct1, ct2) 167 | ciphertextMultResult = cc.EvalMult(ciphertextMult12, ct3) 168 | 169 | # Homomorphic rotation 170 | ciphertextRot1 = cc.EvalRotate(ct1, VECTOR1_ROTATION) 171 | ciphertextRot2 = cc.EvalRotate(ct2, VECTOR2_ROTATION) 172 | ciphertextRot3 = cc.EvalRotate(ct3, VECTOR3_ROTATION) 173 | ciphertextRot4 = cc.EvalRotate(ct3, VECTOR4_ROTATION) 174 | 175 | # Decrypt the result of additions 176 | plaintextAddResult = cc.Decrypt(sk, ciphertextAddResult) 177 | 178 | # Decrypt the result of multiplications 179 | plaintextMultResult = cc.Decrypt(sk, ciphertextMultResult) 180 | 181 | # Decrypt the result of rotations 182 | plaintextRot1 = cc.Decrypt(sk, ciphertextRot1) 183 | plaintextRot2 = cc.Decrypt(sk, ciphertextRot2) 184 | plaintextRot3 = cc.Decrypt(sk, ciphertextRot3) 185 | plaintextRot4 = cc.Decrypt(sk, ciphertextRot4) 186 | 187 | # Shows only the same number of elements as in the original plaintext vector 188 | # By default it will show all coefficients in the BFV-encoded polynomial 189 | plaintextRot1.SetLength(len(vectorOfInts1)) 190 | plaintextRot2.SetLength(len(vectorOfInts1)) 191 | plaintextRot3.SetLength(len(vectorOfInts1)) 192 | plaintextRot4.SetLength(len(vectorOfInts1)) 193 | 194 | assert str(plaintextAddResult) == str(initialPlaintextAddResult) 195 | assert str(plaintextMultResult) == str(initialPlaintextMultResult) 196 | assert str(plaintextRot1) == str(initialPlaintextRot1) 197 | assert str(plaintextRot2) == str(initialPlaintextRot2) 198 | assert str(plaintextRot3) == str(initialPlaintextRot3) 199 | assert str(plaintextRot4) == str(initialPlaintextRot4) 200 | 201 | def rotate_vector(vector, rotation): 202 | """ 203 | Rotate a vector by a specified number of positions. 204 | Positive values rotate left, negative values rotate right. 205 | 206 | :param vector: List[int], the vector to rotate. 207 | :param rotation: int, the number of positions to rotate. 208 | :return: List[int], the rotated vector. 209 | """ 210 | n = len(vector) 211 | if rotation > 0: 212 | rotated = vector[rotation:] + [0] * rotation 213 | elif rotation < 0: 214 | rotation = abs(rotation) 215 | rotated = [0] * rotation + vector[:n - rotation] 216 | else: 217 | rotated = vector 218 | return rotated 219 | -------------------------------------------------------------------------------- /utils/print-used-modules-and-libraries-linux.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | def print_python_imported_modules(): 4 | # print imported Python modules with their paths 5 | print(" ===== imported Python modules =====") 6 | for module_name, module in sorted(sys.modules.items()): 7 | try: 8 | module_file = module.__file__ 9 | if module_file: 10 | print(f"{module_name}: {module_file}") 11 | except AttributeError: 12 | pass 13 | 14 | def print_loaded_shared_libraries(): 15 | # print loaded shared libraries from /proc/self/maps 16 | print(" ===== loaded shared C/C++ libraries =====") 17 | with open("/proc/self/maps", "r") as maps_file: 18 | lines = maps_file.readlines() 19 | for line in lines: 20 | if ".so" in line: 21 | parts = line.split() 22 | if len(parts) > 5: 23 | print(parts[5]) 24 | 25 | if __name__ == "__main__": 26 | # import numpy 27 | # import pandas 28 | 29 | print("") 30 | print_python_imported_modules() 31 | print("") 32 | print_loaded_shared_libraries() 33 | print("") 34 | --------------------------------------------------------------------------------