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 the TFHE 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 library should help lay the groundwork for further advancements on practical FHE systems.
This library 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 TFHE library for security guarantees. Since TFHE is relatively new, there are yet to be robust cryptanalyses of TFHE. Thus, before including this library in a live production deployment, be aware that there may be yet undiscovered vulnerabilities in TFHE.
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
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
-
On Arch-based distributions with AUR enabled:
sudo pacman -Syu gcc git ncurses5-compat-libs python2 python python-pip
-
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
-
Navigate to the root of this repository, which contains the
Dockerfile
and rundocker build -t google-fhe-transpiler .
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 have to runbazelisk
(which is automatically installed by theDockerfile
), rather thanbazel
, to build and run the examples in the following steps.
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 library, 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 library’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 docs/build_your_own_demo.md.
This section lists the demos included in this library 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:
bazel run //transpiler/examples/calculator:calculator_tfhe_testbench
- Multi-core interpreter command:
bazel run //transpiler/examples/calculator:calculator_interpreted_tfhe_testbench
The Fibonacci demo calculates the sum of the Fibonacci sequence up to the nth integer in the sequence.
- Baseline FHE-C++ translation command:
bazel run //transpiler/examples/fibonacci:fibonacci_tfhe_testbench
- Multi-core interpreter command:
bazel run //transpiler/examples/fibonacci:fibonacci_interpreted_tfhe_testbench
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:
bazel run //transpiler/examples/pir:pir_client
- Multi-core interpreter command:
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:
bazel run //transpiler/examples/string_reverse:string_reverse_tfhe_testbench "hello"
- Multi-core interpreter command:
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:
bazel run //transpiler/examples/simple_sum:simple_sum_tfhe_testbench
- Multi-core interpreter command:
bazel run //transpiler/examples/simple_sum:simple_sum_interpreted_tfhe_testbench
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:
bazel run //transpiler/examples/string_cap:string_cap_tfhe_testbench "do or do not; there is no try"
- Multi-core interpreter command:
bazel run //transpiler/examples/string_cap:string_cap_interpreted_tfhe_testbench "do or do not; there is no try"
-
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:
bazel run //transpiler/examples/string_cap_char:string_cap_char_tfhe_testbench "do or do not; there is no try"
- Multi-core interpreter command:
bazel run //transpiler/examples/string_cap_char:string_cap_char_interpreted_tfhe_testbench "do or do not; there is no try"
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:
bazel run //transpiler/examples/rock_paper_scissor:rock_paper_scissor_tfhe_testbench PLAYER_A PLAYER_B
-
Multi-core interpreter command:
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.
The FHE C++ Transpiler is designed to run sequentially through each of the following five stages:
- The XLS[cc] stage translates a C++ function into an XLS intermediate representation (IR).
- The Optimizer stage optimizes the XLS IR.
- The Booleanifier stage re-writes the XLS IR in terms of its operations' fundamental boolean operations (e.g., AND, OR, NOT).
- The FHE IR Transpiler stage translates the Booleanified XLS IR into FHE-C++.
- The TFHE testbench stage runs the FHE-C++ with TFHE library.
This library includes the code for the first four stages, but users of this library will need to write their own C++ code to be transpiled, as well as the TFHE testbench for the fifth stage. The included examples have testbenches that illustrate how new testbenches can be structured.
Below are more details about each of the listed stages.
This stage converts a C++ program into an XLS intermediate representation (IR).
In this stage, the XLS IR produced in the previous stage is optimized. For more information, see the XLS Optimizer documentation.
Two things of note occur during this stage. First, the optimized XLS IR is re-written in terms of its operations' fundamental Boolean operations (e.g., AND, OR, NOT). Next, all operations are modified to be carried out on individual bits (since TFHE encrypts data one bit at a time).
This produces a Booleanified graph representing the operations to perform. See the illustration below for an example.
For more information, see the XLS Booleanifier code.
The library includes two options for this stage:
-
By default, the FHE IR Transpiler parses the Booleanified graph and traverses it in topological-sort order.
-
Alternatively, the FHE IR Interpreter does the same as the aforementioned FHE IR Transpiler, but also provides more flexibility in execution strategies, including multicore dispatch for improved performance. This should be especially useful for heterogeneous compute environments, such as mixed CPU/GPU execution. Once the interpreter has been more robustly tested, it will eventually replace the aforementioned FHE IR Transpiler.
Ultimately, both options output C++ code that operates on encrypted input.
Users of the library must write their own TFHE testbench for this stage.
The examples included in this library have testbenches that simulate a client-server interaction as described and illustrated below.
- The client encodes the input data into individual bits.
- The client encrypts the input bits into
LWESample
s. EachLWESample
represents one bit of data. - The client sends the
LWESample
s to the server. - The server transforms the
LWESample
s with its TFHE C++ function. This function was constructed by the preceding four stages described above. - The server sends the transformed
LWESample
s to the client. - The client decrypts the transformed
LWESample
s into the transformed bits of data. - The client decodes the transformed bits of data into the transformed output data.
While this library does not include a working example of the client and server deployed on separate machines, it should be possible to implement and use this library for performing FHE C++ operations over a network.
This section explains the FTE C++ Transpiler's threat model and the estimated bits of security provided by the library's choice of TFHE parameters.
The FTE C++ Transpiler is built with 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 this library uses 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 library because it uses the LLVM toolchain
(which requires python2
) and XLS (which
requires python3
).