The FHE C++ Transpiler is an open-sourced technology that will allow any C++ developer to perform transformations on encrypted data without decrypting it.
This transpiler connects Google’s XLS library to multiple FHE backends (currently the TFHE library and OpenFHE's BinFHE library). It will allow developers (including those without expertise in cryptography) to write code that runs on encrypted data, without revealing the data contents or the computations’ result. This system should help lay the groundwork for further advancements on practical FHE systems.
This system is currently only supported on Linux, and requires GCC version 9 (or later) and Bazel 4.0.0.
This is currently an exploratory proof-of-concept. While it could be deployed in practice, the run-times of the FHE-C++ operations are likely to be too long to be practical at this time. This transpiler heavily relies on the chosen FHE library for security guarantees. Since both the OpenFHE and TFHE libraries are relatively new, there are not yet robust widely-accepted cryptanalyses for them. Thus, before including this system's output in a live production deployment, be aware that there may be yet undiscovered vulnerabilities in either library.
This section describes how to install and run the FHE C++ Transpiler. If you have any problems, please see the Troubleshooting section near the bottom of this document.
This repository offers two ways to install the FHE C++ Transpiler.
In order to install the FHE C++ Transpiler on your Linux machine:
-
Install Bazel version 4.0.0, if you don't have it already. Bazel 4.0.0 can be installed directly or Bazel versions can be managed through Bazelisk.
-
Install the following additional required packages using your Linux distribution's package manager:
gcc
in version 9 or higher.git
, which is required for downloading some dependencies using Bazel.libtinfo5
orncurses5-compat-libs
python2
python3
python3-pip
bison
(foryosys
)flex
(foryosys
)
You can install all of the above by running the following commands, depending on you distribution.
-
On Debian-based distributions:
sudo apt install gcc git libtinfo5 python python3 python3-pip bison flex
-
On Arch-based distributions with AUR enabled:
sudo pacman -Syu gcc git ncurses5-compat-libs python2 python python-pip \ bison flex
-
Download the latest version of this repository and extract it. Alternatively, you can use
git
to clone the repository on your local machine using the following command:git clone https://github.com/google/fully-homomorphic-encryption.git
-
Download the latest version of this repository and extract it. Navigate to the extracted folder. Alternatively, you can also use
git
to clone the repository using the following command:git clone https://github.com/google/fully-homomorphic-encryption.git
-
(macOS only) Ensure sufficient Docker system resources for macOS: Navigate to
Preferences
>Resources
>Advanced
and set the runtime memory limit to at least 6GB. The default settings for other system resources (swap, disk size, etc.) should be sufficient. In our tests on a 2017 MacBook Pro, these defaults were set to:- CPU: 4 cores
- Swap: 1GB
- Disk image: 60GB
Note that increases to these other system resources may help improve image build times and container performance. See more about setting resource limits in Docker Desktop here.
-
Navigate to the root of this repository, which contains the
Dockerfile
and rundocker build -t google-fhe-transpiler -f docker/debian-bullseye.Dockerfile .
This may take around 1 hour, depending on your system configuration.
-
Execute
docker run --rm -i -t google-fhe-transpiler bash
to connect to a fresh instance that has the transpiler installed. You can then run the examples as described in the following section.
To run the FHE C++ Transpiler, go to the fully-homomorphic-encryption/
directory that contains the FHE C++ Transpiler code, and run the following
command to start the hangman
demo:
bazel run //transpiler/examples/hangman:hangman_client
This will automatically build the core FHE C++ Transpiler toolchain, which may take a long time (i.e., over an hour) when building the first time. Once the demo is running, a game of Hangman will be playable, illustrating that the player's letter guesses and game progress are unknown to the server.
To run the FHE C++ Transpiler on your own C++ code, follow these steps:
- Create a subdirectory in
fully-homomorphic-encryption/transpiler/examples/
(e.g.,fn
). - Add the C++ file that contains the code to be transpiled into the aforementioned subdirectory.
- Create a testbench (e.g.,
fn_tfhe_testbench
) andBUILD
file similar to those in the repository’s examples, but that uses your FHE-C++ instead. - Run the transpiler with the following command, replacing
fn
with the name of your subdirectory and testbench file names, followed by two dashes, and any needed additional arguments (e.g.,"arg1"
,"arg2"
):
bazel run //transpiler/examples/fn:fn_tfhe_testbench -- "arg1" "arg2"
A more comprehensive guide on building your own demo can be found at g3doc/build_your_own_demo.md.
This section lists the demos included in this repository that are intended to be simple, yet effective, examples of possible uses for the FHE C++ Transpiler.
There are also bazel
commands to compile and run each demo. For demos with a
choice of two commands, the first "baseline" command generates FHE-C++ that uses
only a single processor core (i.e., slow), while the second "interpreter"
command generates FHE-C++ that utilizes multiple cores (i.e., significantly
faster). Both commands assume your working directory is within the workspace
fully-homomorphic-encryption/
.
Note: All demos are for illustrative purposes only, and are not designed for live production deployments. For example, the demos' encryption keys all use a hard coded simple seed, which is not secure in a production service. Live production deployments should use cryptographically secure seeds that are securely stored, as well as implement all appropriate design, security, privacy, and other best practices.
The Calculator demo adds, subtracts, or multiples two encrypted short integers, without the server knowing the integers or the result.
- Baseline FHE-C++ translation command:
- Using TFHE:
shell bazel run //transpiler/examples/calculator:calculator_tfhe_testbench
- Using OpenFHE:
shell bazel run //transpiler/examples/calculator:calculator_openfhe_testbench
- Using TFHE:
- Multi-core interpreter command:
- Using TFHE:
shell bazel run //transpiler/examples/calculator:calculator_interpreted_tfhe_testbench
- Using OpenFHE
shell bazel run //transpiler/examples/calculator:calculator_interpreted_openfhe_testbench
- Using TFHE:
The Fibonacci demo calculates the sum of the Fibonacci sequence up to the nth integer in the sequence.
- Baseline FHE-C++ translation command:
- Using TFHE:
shell bazel run //transpiler/examples/fibonacci:fibonacci_tfhe_testbench
- Using OpenFHE:
shell bazel run //transpiler/examples/fibonacci:fibonacci_openfhe_testbench
- Using TFHE:
- Multi-core interpreter command:
- Using TFHE:
shell bazel run //transpiler/examples/fibonacci:fibonacci_interpreted_tfhe_testbench
- Using OpenFHE:
shell bazel run //transpiler/examples/fibonacci:fibonacci_interpreted_openfhe_testbench
- Using TFHE:
The Hangman demo is a classical game of Hangman, but with privacy. The server does not know which letters the player is choosing or whether they won or lost.
bazel run //transpiler/examples/hangman:hangman_client
This demo highlights single-server private information retrieval (PIR). User- provided characters are retrieved by index without the server knowing the query or the data it's storing. This is an O(N) operation, where N is the number of records in the database.
- Baseline FHE-C++ translation command:
shell bazel run //transpiler/examples/pir:pir_client
- Multi-core interpreter command:
shell bazel run //transpiler/examples/pir:pir_interpreted_client
This demo reverses an encrypted string without the server knowing the string.
- Baseline FHE-C++ translation command:
shell bazel run //transpiler/examples/string_reverse:string_reverse_tfhe_testbench "hello"
- Multi-core interpreter command:
shell bazel run //transpiler/examples/string_reverse:string_reverse_interpreted_tfhe_testbench "hello"
This demo adds two encrypted integers without the server knowing either integer or the resulting sum.
- Baseline FHE-C++ translation command:
- Using TFHE:
shell bazel run //transpiler/examples/simple_sum:simple_sum_tfhe_testbench
- Using OpenFHE:
shell bazel run //transpiler/examples/simple_sum:simple_sum_openfhe_testbench
- Using TFHE:
- Multi-core interpreter command:
- Using TFHE:
shell bazel run //transpiler/examples/simple_sum:simple_sum_interpreted_tfhe_testbench
- Using OpenFHE:
shell bazel run //transpiler/examples/simple_sum:simple_sum_interpreted_openfhe_testbench
- Using TFHE:
In this demo, each word in an encrypted sentence can be capitalized without the server knowing the sentence.
There are two versions of this demo:
-
In the
string_cap
example, the FHE-C++ code inputs the entire encrypted string and internally iterates over each character.- Baseline FHE-C++ translation command:
- Using TFHE:
shell bazel run //transpiler/examples/string_cap:string_cap_tfhe_xls_transpiled_testbench -- "do or do not; there is no try"
- Using OpenFHE:
shell bazel run //transpiler/examples/string_cap:string_cap_openfhe_xls_transpiled_testbench -- "do or do not; there is no try"
- Using TFHE:
- Multi-core interpreter command:
- Using TFHE:
shell bazel run //transpiler/examples/string_cap:string_cap_tfhe_xls_interpreted_testbench -- "do or do not; there is no try"
- Using OpenFHE:
shell bazel run //transpiler/examples/string_cap:string_cap_openfhe_xls_interpreted_testbench -- "do or do not; there is no try"
- Using TFHE:
- Baseline FHE-C++ translation command:
-
In the
string_cap_char
example, the FHE-C++ code operates on one character at a time. This example can provide more output regarding the string transformation process, for illustrative purposes.- Baseline FHE-C++ translation command:
- Using TFHE:
shell bazel run //transpiler/examples/string_cap_char:string_cap_char_tfhe_xls_transpiled_testbench -- "do or do not; there is no try"
- Using OpenFHE:
shell bazel run //transpiler/examples/string_cap_char:string_cap_char_openfhe_xls_transpiled_testbench -- "do or do not; there is no try"
- Using TFHE:
- Multi-core interpreter command:
- Using TFHE:
shell bazel run //transpiler/examples/string_cap_char:string_cap_char_tfhe_xls_interpreted_testbench -- "do or do not; there is no try"
- Using OpenFHE:
shell bazel run //transpiler/examples/string_cap_char:string_cap_char_openfhe_xls_interpreted_testbench -- "do or do not; there is no try"
```
- Using TFHE:
- Baseline FHE-C++ translation command:
This demo computes the square root of an encrypted short integer, without the server knowing the input or the result.
- Baseline FHE-C++ translation command:
- Using TFHE:
shell bazel run //transpiler/examples/sqrt:sqrt_tfhe_testbench -- 15875
- Using OpenFHE:
shell bazel run //transpiler/examples/sqrt:sqrt_openfhe_testbench -- 15875
- Using TFHE:
- Multi-core interpreter command:
- Using TFHE:
shell bazel run //transpiler/examples/sqrt:sqrt_interpreted_tfhe_testbench -- 15875
- Using OpenFHE:
shell bazel run //transpiler/examples/sqrt:sqrt_interpreted_openfhe_testbench -- 15875
- Using TFHE:
This demo allows to you to play rock paper scissors with the server. The input of the players is provided and the server will evaluate the outcome of the game, without discovering the input or the outcome.
-
Baseline FHE-C++ translation command:
shell bazel run //transpiler/examples/rock_paper_scissor:rock_paper_scissor_tfhe_testbench PLAYER_A PLAYER_B
-
Multi-core interpreter command:
shell bazel run //transpiler/examples/rock_paper_scissor:rock_paper_scissor_interpreted_tfhe_testbench PLAYER_A PLAYER_B
where PLAYER_A
and PLAYER_B
are the choice R
(rock), P
(paper), or S
(scissors). The server will return the winning player (i.e., either A
or B
)
or =
in the case of a tie.
These subdirectories include examples of programming using structs and templates, respectively: how structs can be used both inside and outside the FHE environment and how templates can be used within the FHE environment to tailor code to more precise specifications. Since they are not functional examples, we mostly provide only TFHE testbenches, e.g.:
bazel run -c opt //transpiler/examples/structs:struct_with_struct_array_tfhe_testbench
and
bazel run -c opt //transpiler/examples/templates:mul_interpreted_tfhe_testbench
See detailed design at g3doc/transpiler_design.md.
This section explains the FHE C++ Transpiler's threat model and the estimated bits of security provided by the system's choice of TFHE parameters.
The FHE C++ Transpiler is built with the honest-but-curious-server threat model in mind.
TFHE guarantees that, without the decryption key, the only information that a
collection of FHE ciphertexts (i.e., LweSample*
) reveals about the encrypted
plaintexts is the data type when used correctly. The computed function (i.e.,
transform) is assumed to be known by both server and client.
Given the parameters our testbenches use for TFHE, we currently estimate (using the TFHE estimator) that the FHE C++ Transpiler provides between 97 and 127 bits of security based on this running-time estimator for solving LWE instances.
To ensure secure usage of the FHE C++ Transpiler, we recommend following the guidance given in the TFHE security estimates and parameter choices documentation. Should you wish to modify the TFHE parameters and estimate the resulting bits of security, be aware that the estimators might not be completely up to date, so proceed with caution.
This section describes known limitations of the FHE C++ Transpiler.
Due to the transpiler's dependency on XLS[cc], they share the following limitations:
- Variable-length arrays are not supported, since there is no way to inspect the contents of the variable before trying to access it (which is the main benefit of FHE). One workaround is to use arrays with the largest number of values that may be needed. This also protects privacy since array sizes will not be leaked.
- While-loops and for-loops with a variable end-condition are not supported. This is because FHE evaluates all code branches, which requires knowing the number of loop iterations beforehand. See this XLS feature request for updates. One workaround is to set the for-loop to terminate after the most expected number of iterations and add an if-statement that will cause the for-loop break once the index reaches the variable length instead. This is illustrated in the following code:
- Floating-point data types are not supported.
#pragma hls_top
int some_func(int image[8], int length) {
int sum = 0;
#pragma hls_unroll yes
for (int i = 0; i < 8; i++) { // "length" would not be visible on this line
sum += image[i];
if(i == (length-1))
break;
}
return sum;
}
In the near future, we intend to add additional optimizations to the interpreter in the FHE IR Translation stage that will be especially useful for heterogeneous compute environments, such as mixed CPU/GPU execution.
Here are possible solutions to known issues with the FHE C++ Transpiler. If you encounter an issue that is not addressed here, please file an issue on GitHub describing the problem in as much detail as possible.
If Bazel requires a python
binary present, but the python2
and python3
binaries are already installed1, this can be
fixed by creating a symlink to from python
to python2
with the following
command:
ln -s /usr/bin/python2 /usr/bin/python
If Bazel reports an error about an unknown LLVM release, try replacing the
llvm_version
in the WORKSPACE
file from 10.0.0
to
10.0.1
.
- XLS, the Software Development Kit (SDK) for the End of Moore's Law (EoML) era.
- TFHE Library, Fast Fully Homomorphic Encryption Library
1: Both python2
and python3
are required
for this system because it uses the LLVM toolchain
(which requires python2
) and XLS (which
requires python3
).