Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
⭐️ Star the repo on Github | 🗣 Community support forum | 📁 Contribute to the project
TFHE-rs is a pure Rust implementation of TFHE for boolean and small integer arithmetics over encrypted data. It includes a Rust and C API, as well as a client-side WASM API.
TFHE-rs is meant for developers and researchers who want full control over what they can do with TFHE, while not having to worry about the low level implementation.
The goal is to have a stable, simple, high-performance, and production-ready library for all the advanced features of TFHE.
The TFHE-rs library implements Zama’s variant of Fully Homomorphic Encryption over the Torus (TFHE). TFHE is based on Learning With Errors (LWE), a well-studied cryptographic primitive believed to be secure even against quantum computers.
In cryptography, a raw value is called a message (also sometimes called a cleartext), while an encoded message is called a plaintext and an encrypted plaintext is called a ciphertext.
Zama's variant of TFHE is fully homomorphic and deals with fixed-precision numbers as messages. It implements all needed homomorphic operations, such as addition and function evaluation via Programmable Bootstrapping. You can read more about Zama's TFHE variant in the preliminary whitepaper.
Using FHE in a Rust program with TFHE-rs consists in:
generating a client key and a server key using secure parameters:
a client key encrypts/decrypts data and must be kept secret
a server key is used to perform operations on encrypted data and could be public (also called an evaluation key)
encrypting plaintexts using the client key to produce ciphertexts
operating homomorphically on ciphertexts with the server key
decrypting the resulting ciphertexts into plaintexts using the client key
If you would like to know more about the problems that FHE solves, we suggest you review our 6 minute introduction to homomorphic encryption.
The idea of homomorphic encryption is that you can compute on ciphertexts while not knowing messages encrypted within them. A scheme is said to be fully homomorphic, meaning any program can be evaluated with it, if at least two of the following operations are supported (is a plaintext and is the corresponding ciphertext):
homomorphic univariate function evaluation:
homomorphic addition:
homomorphic multiplication:
This library makes it possible to execute homomorphic operations over encrypted data, where the data are either Booleans or short integers (named shortint in the rest of this documentation). It allows one to execute a circuit on an untrusted server because both circuit inputs and outputs are kept private. Data are indeed encrypted on the client side, before being sent to the server. On the server side, every computation is performed on ciphertexts.
The server, however, has to know the circuit to be evaluated. At the end of the computation, the server returns the encryption of the result to the user. She can then decrypt it with her secret key
.
The overall process to write an homomorphic program is the same for both Boolean and shortint types. In a nutshell, the basic steps for using the TFHE-rs library are the following:
Choose a data type (Boolean or shortint)
Import the library
Create client and server keys
Encrypt data with the client key
Compute over encrypted data using the server key
Decrypt data with the client key
Here is an example to illustrate how the library can be used to evaluate a Boolean circuit:
And here is a full example using shortint:
The library is pretty simple to use, and can evaluate homomorphic circuits of arbitrary length. The description of the algorithms can be found in the TFHE paper (also available as ePrint 2018/421).
This library is meant to be used both on the server side and on the client side. The typical use case should follow the subsequent steps:
On the client side, generate the client
and server keys
.
Send the server key
to the server.
Then any number of times:
On the client side, encryption of the input data with the client key
.
Transmit the encrypted input to the server.
On the server side, homomorphic computation with the server key
.
Transmit the encrypted output to the client.
On the client side, decryption of the output data with the client key
.
In the first step, the client creates two keys: the client key
and the server key
, with the concrete_boolean::gen_keys
function:
The client_key
is of type ClientKey
. It is secret, and must never be transmitted. This key will only be used to encrypt and decrypt data.
The server_key
is of type ServerKey
. It is a public key, and can be shared with any party. This key has to be sent to the server because it is required for homomorphic computation.
Note that both the client_key
and server_key
implement the Serialize
and Deserialize
traits. This way you can use any compatible serializer to store/send the data. For instance, to store the server_key
in a binary file, you can use the bincode
library:
Once the server key is available on the server side, it is possible to perform some homomorphic computations. The client simply needs to encrypt some data and send it to the server. Again, the Ciphertext
type implements the Serialize
and the Deserialize
traits, so that any serializer and communication tool suiting your use case can be employed:
Once the server key is available on the server side, it is possible to perform some homomorphic computations. The client simply needs to encrypt some data and send it to the server. Again, the Ciphertext
type implements the Serialize
and the Deserialize
traits, so that any serializer and communication tool suiting your use case can be utilized:
Once the encrypted inputs are on the server side, the server_key
can be used to homomorphically execute the desired Boolean circuit:
Once the encrypted output is on the client side, the client_key
can be used to decrypt it:
Due to their nature, homomorphic operations are obviously slower than their clear equivalent. In what follows, some timings are exposed for basic operations. For completeness, some benchmarks of other libraries are also given.
All the benchmarks had been launched on an AWS m6i.metal with the following specifications: Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz and 512GB of RAM.
This measures the execution time of a single binary boolean gate.
Parameter set | concrete-fft | concrete-fft + avx512 |
---|---|---|
Parameter set | fftw | spqlios-fma |
---|---|---|
Parameter set | GINX | GINX (Intel HEXL) |
---|---|---|
This measures the execution time for some operations and some parameter sets of shortint.
This uses the concrete-fft + avx512 configuration.
The list of supported operations by the homomorphic Booleans is:
Operation Name | type |
---|---|
A walk-through using homomorphic Booleans can be found here.
In TFHE-rs, shortint represents short unsigned integers encoded over a maximum of 8 bits. A complete homomorphic arithmetic is provided, along with the possibility to compute univariate and bi-variate functions. Some operations are only available for integers up to 4 bits. More technical details can be found here.
The list of supported operations is:
Operation name | Type |
---|---|
* The division operation implements a subtlety: since data is encrypted, it might be possible to compute a division by 0. In this case, the division is tweaked so that dividing by 0 returns 0.
A walk-through example can be found here, and more examples and explanations can be found here.
TFHE-rs is a cryptographic library dedicated to Fully Homomorphic Encryption. As its name suggests, it is based on the TFHE scheme.
It is interesting to understand some basics about TFHE in order to comprehend where the limitations are coming from, both in terms of precision (number of bits used to represent the plaintext values) and execution time (why TFHE operations are slower than native operations).
Although there are many kinds of ciphertexts in TFHE, all the encrypted values in TFHE-rs are mainly stored as LWE ciphertexts.
The security of TFHE relies on the LWE problem, which stands for Learning With Errors. The problem is believed to be secure against quantum attacks.
An LWE Ciphertext is a collection of 32-bit or 64-bit unsigned integers. Before encrypting a message in an LWE ciphertext, one must first encode it as a plaintext. This is done by shifting the message to the most significant bits of the unsigned integer type used.
Then, a little random value called noise is added to the least significant bits. This noise (also called error for Learning With Errors) is crucial to the security of the ciphertext.
To go from a plaintext to a ciphertext, one must encrypt the plaintext using a secret key.
An LWE secret key is a list of n
random integers: . is called the
A LWE ciphertext, is composed of two parts:
The mask
The body
The mask of a fresh ciphertext (one that is the result of an encryption and not an operation, such as ciphertext addition) is a list of n
uniformly random values.
The body is computed as follows:
Now that the encryption scheme is defined, to illustrate why it is slower to compute over encrypted data, let us show the example of the addition between ciphertexts.
To add two ciphertexts, we must add their $mask$ and $body$, as is done below.
To add ciphertexts, it is sufficient to add their masks and bodies. Instead of just adding 2 integers, one needs to add elements. The addition is an intuitive example to show the slowdown of FHE computation compared to plaintext computation, but other operations are far more expensive (e.g., the computation of a lookup table using the Programmable Bootstrapping).
In FHE, there are two types of operations that can be applied to ciphertexts:
leveled operations, which increase the noise in the ciphertext
bootstrapped operations, which reduce the noise in the ciphertext
In FHE, the noise must be tracked and managed in order to guarantee the correctness of the computation.
Bootstrapping operations are used across the computation to decrease the noise in the ciphertexts, preventing it from tampering the message. The rest of the operations are called leveled because they do not need bootstrapping operations and, thus, are usually really fast.
The following sections explain the concept of noise and padding in ciphertexts.
For it to be secure, LWE requires random noise to be added to the message at encryption time.
In TFHE, this random noise is drawn from a Centered Normal Distribution parameterized by a standard deviation. This standard deviation is a security parameter. With all other security parameters set, the larger the standard deviation is, the more secure the encryption is.
In TFHE-rs
, the noise is encoded in the least significant bits of the plaintexts. Each leveled computation will increase the noise. Thus, if too many computations are performed, the noise will eventually overflow onto the significant data bits of the message and lead to an incorrect result.
The figure below illustrates this problem in case of an addition, where an extra bit of noise is incurred as a result.
TFHE-rs offers the ability to automatically manage noise by performing bootstrapping operations to reset the noise when needed.
Since encoded values have a fixed precision, operating on them can sometimes produce results that are outside the original interval. To avoid losing precision or wrapping around the interval, TFHE-rs uses additional bits by defining bits of padding on the most significant bits.
As an example, consider adding two ciphertexts. Adding two values could end up outside the range of either ciphertext, and thus necessitate a carry, which would then be carried onto the first padding bit. In the figure below, each plaintext over 32 bits has one bit of padding on its left (i.e., the most significant bit). After the addition, the padding bit is no longer available, as it has been used in order for the carry. This is referred to as consuming bits of padding. Since no padding is left, there is no guarantee that further additions would yield correct results.
If you would like to know more about TFHE, you can find more information in our TFHE Deep Dive.
By default, the cryptographic parameters provided by TFHE-rs
ensure at least 128 bits of security. The security has been evaluated using the latest versions of the Lattice Estimator (repository) with red_cost_model = reduction.RC.BDGL16
.
For all sets of parameters, the error probability when computing a univariate function over one ciphertext is . Note that univariate functions might be performed when arithmetic functions are computed (for instance, the multiplication of two ciphertexts).
In public key encryption, the public key contains a given number of ciphertexts all encrypting the value 0. By setting the number of encryptions of 0 in the public key at , where is the LWE dimension, is the ciphertext modulus, and is the number of security bits. In a nutshell, this construction is secure due to the leftover hash lemma, which is essentially related to the impossibility of breaking the underlying multiple subset sum problem. By using this formula, this guarantees both a high-density subset sum and an exponentially large number of possible associated random vectors per LWE sample (a,b).
tfhe::shortint
provides 2 key types:
ClientKey
ServerKey
The ClientKey
is the key that encrypts and decrypts messages (integer values up to 8 bits here), thus this key is meant to be kept private and should never be shared. This key is created from parameter values that will dictate both the security and efficiency of computations. The parameters also set the maximum number of bits of message encrypted in a ciphertext.
The ServerKey
is the key that is used to actually do the FHE computations. It contains (among other things) a bootstrapping key and a keyswitching key. This key is created from a ClientKey
that needs to be shared to the server, therefore it is not meant to be kept private. A user with a ServerKey
can compute on the encrypted data sent by the owner of the associated ClientKey
.
To reflect that, computation/operation methods are tied to the ServerKey
type.
Once the keys have been generated, the client key is used to encrypt data:
Once the keys have been generated, the client key is used to encrypt data:
With our server_key
and encrypted values, we can now do an addition and then decrypt the result.
Since the ServerKey
and ClientKey
types both implement the Serialize
and Deserialize
traits, you are free to use any serializer that suits you to save and load the keys to disk.
Here is an example using the bincode
serialization library, which serializes to a binary format:
The TFHE cryptographic scheme relies on a variant of , and is based on a problem so hard to solve that it is even post-quantum resistant.
In practice, you need to tune some cryptographic parameters in order to ensure both the correctness of the result and the security of the computation.
To make it simpler, we provide two sets of parameters, which ensure correct computations for a certain probability with the standard security of 128 bits. There exists an error probability due to the probabilistic nature of the encryption, which requires adding randomness (called noise) following a Gaussian distribution. If this noise is too large, the decryption will not give a correct result. There is a trade-off between efficiency and correctness: generally, using a less efficient parameter set (in terms of computation time) leads to a smaller risk of having an error during homomorphic evaluation.
In the two proposed sets of parameters, the only difference lies in this probability error. The default parameter set ensures a probability error of at most when computing a programmable bootstrapping (i.e., any gates but the not
). The other one is closer to the error probability claimed into the original , namely , but it is up-to-date regarding security requirements.
The following array summarizes this:
Parameter set | Error probability |
---|
Note that, if you desire, you can also create your own set of parameters. This is an unsafe
operation as failing to properly fix the parameters will potentially result in an incorrect and/or insecure computation:
In tfhe::boolean, the available operations are mainly related to their equivalent Boolean gates (i.e., AND, OR... etc). What follows is an example of a unary gate (NOT) and one about a binary gate (XOR). The last one is about the ternary MUX gate, which gives the possibility to homomorphically compute conditional statements of the form If..Then..Else
.
Let ct_1, ct_2, ct_3
be three Boolean ciphertexts. Then, the MUX gate (abbreviation of MUltipleXer) is equivalent to the operation:
This example shows how to use the MUX ternary gate:
To use TFHE-rs
in your project, you first need to add it as a dependency in your Cargo.toml
:
TFHE-rs
exposes different cargo features
to customize the types and features used.
This crate exposes two kinds of data types. Each kind is enabled by activating its corresponding feature in the TOML line. Each kind may have multiple types:
Kind | Features | Type(s) |
---|
The different data types and keys exposed by the crate can be serialized / deserialized.
More information can be found for boolean and for shortint.
TFHE-rs is supported on Linux (x86, aarch64), macOS (x86, aarch64) and Windows (x86 with RDSEED
instruction).
Users who have ARM devices can use TFHE-rs
by compiling using the nightly
toolchain.
First, install the needed Rust toolchain:
Then, you can either:
Manually specify the toolchain to use in each of the cargo commands:
For example:
Or override the toolchain to use for the current project:
To check the toolchain that Cargo will use by default, you can use the following command:
Parameter set | unchecked_add | unchecked_mul_lsb | keyswitch_programmable_bootstrap |
---|---|---|---|
OS | x86 | aarch64 |
---|
DEFAULT_PARAMETERS
8.8ms
6.8ms
TFHE_LIB_PARAMETERS
13.6ms
10.9ms
default_128bit_gate_bootstrapping_parameters
28.9ms
15.7ms
STD_128
172ms
78ms
MEDIUM
113ms
50.2ms
PARAM_MESSAGE_1_CARRY_1
338 ns
8.3 ms
8.1 ms
PARAM_MESSAGE_2_CARRY_2
406 ns
18.4 ms
18.4 ms
PARAM_MESSAGE_3_CARRY_3
3.06 µs
134 ms
134 ms
PARAM_MESSAGE_4_CARRY_4
11.7 µs
854 ms
945 ms
not
Unary
and
Binary
or
Binary
xor
Binary
nor
Binary
xnor
Binary
cmux
Ternary
Negation
Unary
Addition
Binary
Subtraction
Binary
Multiplication
Binary
Division*
Binary
Modular reduction
Binary
Comparisons
Binary
Left/Right Shift
Binary
And
Binary
Or
Binary
Xor
Binary
Exact Function Evaluation
Unary/Binary
Linux |
|
|
macOS |
|
|
Windows |
| Unsupported |
Booleans |
| Booleans |
ShortInts |
| Short unsigned integers |
As explained in the introduction, some types (Serverkey
, Ciphertext
) are meant to be shared with the server that performs the computations.
The easiest way to send these data to a server is to use the serialization and deserialization features. tfhe::shortint uses the serde framework. Serde's Serialize and Deserialize are then implemented on tfhe::shortint's types.
To be able to serialize our data, we need to pick a data format. For our use case, bincode is a good choice, mainly because it is binary format.
core_crypto
primitivesWelcome to this tutorial about TFHE-rs core_crypto
module!
core_crypto
moduleTo use TFHE-rs
, first it has to be added as a dependency in the Cargo.toml
:
Here, this enables the x86_64-unix
feature to have efficient implementations of various algorithms for x86_64
CPUs on a Unix-like system. The 'unix' suffix indicates that the UnixSeeder
, which uses /dev/random
to generate random numbers, is actived as a fallback if no hardware number generator is available, like rdseed
on x86_64
or if the Randomization Services
on Apple platforms are not available. To avoid having the UnixSeeder
as a potential fallback or to run on non-Unix systems (e.g., Windows), the x86_64
feature is sufficient.
For Apple Silicon, the aarch64-unix
or aarch64
feature should be enabled. Note that aarch64
is not supported on Windows as it's currently missing an entropy source required to seed the CSPRNGs used in TFHE-rs.
In short: For x86_64-based machines running Unix-like OSes:
For Apple Silicon or aarch64-based machines running Unix-like OSes:
For x86_64-based machines with the rdseed instruction
running Windows:
core_crypto
module.As a complete example showing the usage of some common primitives of the core_crypto
APIs, the following Rust code homomorphically computes 2 * 3 using two different methods. First using a cleartext multiplication and second using a PBS.
Welcome to this TFHE-rs JS on WASM API tutorial!
TFHE-rs uses WASM to expose a JS binding to the client-side primitives, like key generation and encryption, of the Boolean and shortint modules.
There are several limitations at this time. Due to a lack of threading support in WASM, key generation can be too slow to be practical for bigger parameter sets.
Some parameter sets lead to FHE keys that are too big to fit in the 2GB memory space of WASM. This means that some parameters sets are virtually unusable.
To build the JS on WASM bindings for TFHE-rs, you will first need to install wasm-pack
in addition to a compatible (>= 1.65) rust toolchain
.
Then, in a shell run the following to clone the TFHE-rs repo (one may want to checkout a specific tag, here the default branch is used for the build):
The command above targets nodejs. A binding for a web browser can be generated as well using --target=web
. This use case will not be discussed in this tutorial.
Both Boolean and shortint features are enabled here but it's possible to use one without the other.
After the build, a new directory pkg is present in the tfhe
directory.
Be sure to update the path of the required clause in the example below for the TFHE package that was just built.
The example.js
script can then be run using node
like so:
Welcome to this TFHE-rs C API tutorial!
This library exposes a C binding to the TFHE-rs primitives to implement Fully Homomorphic Encryption (FHE) programs.
TFHE-rs C API can be built on a Unix x86_64 machine using the following command:
or on a Unix aarch64 machine using the following command
All features are opt-in, but for simplicity here, the C API is enabled for boolean and shortint.
The tfhe.h
header as well as the static (.a) and dynamic (.so) libtfhe
binaries can then be found in "${REPO_ROOT}/target/release/"
The build system needs to be set up so that the C or C++ program links against TFHE-rs C API binaries.
Here is a minimal CMakeLists.txt allowing to do just that:
TFHE-rs C API
.The steps required to perform the multiplication by 2 of a 2 bits ciphertext using a PBS are detailed. This is NOT the most efficient way of doing this operation, but it can help to show the management required to run a PBS manually using the C API.
WARNING: The following example does not have proper memory management in the error case to make it easier to fit the code on this page.
To run the example below, the above CMakeLists.txt and main.c files need to be in the same directory. The commands to run are:
Programmers wishing to use TFHE-rs but who are unable to use Rust (for various reasons) can use these bindings in their language of choice, as long as it can interface with C code to bring TFHE-rs functionalities to said language.
All parameter sets provide at least 128-bits of security according to the Lattice-Estimator, with an error probability equal to when computing a programmable bootstrapping. This error probability is due to the randomness added at each encryption (see here for more details about the encryption process).
shortint
comes with sets of parameters that permit the use of the library functionalities securely and efficiently. Each parameter set is associated to the message and carry precisions. Thus, each key pair is entangled to precision.
The user is allowed to choose which set of parameters to use when creating the pair of keys.
The difference between the parameter sets is the total amount of space dedicated to the plaintext and how it is split between the message buffer and the carry buffer. The syntax chosen for the name of a parameter is: PARAM_MESSAGE_{number of message bits}_CARRY_{number of carry bits}
. For example, the set of parameters for a message buffer of 5 bits and a carry buffer of 2 bits is PARAM_MESSAGE_5_CARRY_2
.
In what follows, there is an example where keys are generated to have messages encoded over 2 bits i.e., computations are done modulus ), with 2 bits of carry.
Note that the PARAM_MESSAGE_2_CARRY_2
parameter set is the default shortint
parameter set that you can also use through the tfhe::shortint::prelude::DEFAULT_PARAMETERS
constant.
As shown here, the choice of the parameter set impacts the operations available and their efficiency.
The computations of bi-variate functions is based on a trick, concatenating two ciphertexts into one. In the case where the carry buffer is not at least as large as the message one, this trick no longer works. Then, many bi-variate operations, such as comparisons cannot be correctly computed. The only exception concerns the multiplication.
In the case of the multiplication, two algorithms are implemented: the first one relies on the bi-variate function trick, where the other one is based on the quarter square method. In order to correctly compute a multiplication, the only requirement is to have at least one bit of carry (i.e., using parameter sets PARAM_MESSAGE_X_CARRY_Y with Y>=1). This method is, in general, slower than using the other one. Note that using the smart
version of the multiplication automatically chooses which algorithm is used depending on the chosen parameters.
Beyond the predefined parameter sets, it is possible to define new parameter sets. To do so, it is sufficient to use the function unsecure_parameters()
or to manually fill the Parameter
structure fields.
For instance:
The core_crypto
module from TFHE-rs is dedicated to the implementation of the cryptographic tools related to TFHE. To construct an FHE application, the shortint and/or Boolean modules (based on this one) are recommended.
The core_crypto
module offers an API to low-level cryptographic primitives and objects, like lwe_encryption
or rlwe_ciphertext
. Its goal is to propose an easy-to-use API for cryptographers.
The overall code architecture is split in two parts: one for the entity definitions, and another one focused on the algorithms. For instance, the entities contain the definition of useful types, like LWE ciphertext or bootstrapping keys. The algorithms are then naturally defined to work using these entities.
The API is convenient to easily add or modify existing algorithms or to have direct access to the raw data. For instance, even if the LWE ciphertext object is defined along with functions giving access to he body, this is also possible to bypass these to get directly the element of LWE mask.
For instance, the code to encrypt and then decrypt a message looks like:
There are two ways to contribute to TFHE-rs:
you can open issues to report bugs and typos and to suggest ideas
you can ask to become an official contributor by emailing hello@zama.ai. Only approved contributors can end pull requests, so please make sure to get in touch before you do!
DEFAULT_PARAMETERS |
TFHE_LIB_PARAMETERS |
In shortint
, the encrypted data is stored in an LWE ciphertext.
Conceptually, the message stored in an LWE ciphertext is divided into a carry buffer and a message buffer.
The message buffer is the space where the actual message is stored. This represents the modulus of the input messages (denoted by MessageModulus
in the code). When doing computations on a ciphertext, the encrypted message can overflow the message modulus: the exceeding information is stored in the carry buffer. The size of the carry buffer is defined by another modulus, called CarryModulus
.
Together, the message modulus and the carry modulus form the plaintext space that is available in a ciphertext. This space cannot be overflowed, otherwise the computation may result in incorrect outputs.
In order to ensure the correctness of the computation, we keep track of the maximum value encrypted in a ciphertext via an associated attribute called the degree. When the degree reaches a defined threshold, the carry buffer may be emptied to safely resume the computations. Therefore, in shortint
the carry modulus is mainly considered as a means to do more computations.
The operations available via a ServerKey
may come in different variants:
operations that take their inputs as encrypted values.
scalar operations that take at least one non-encrypted value as input.
For example, the addition has both variants:
ServerKey::unchecked_add
which takes two encrypted values and adds them.
ServerKey::unchecked_scalar_add
which takes an encrypted value and a clear value (the so-called scalar) and adds them.
Each operation may come in different 'flavors':
unchecked
: Always does the operation, without checking if the result may exceed the capacity of the plaintext space. Using this operation might have an impact on the correctness of the following operations;
checked
: Checks are done before computing the operation, returning an error if operation cannot be done safely;
smart
: Always does the operation - if the operation cannot be computed safely, the smart operation will clear the carry modulus to make the operation possible.
Not all operations have these 3 flavors, as some of them are implemented in a way that the operation is always possible without ever exceeding the plaintext space capacity.
Let's try to do a circuit evaluation using the different flavours of operations we already introduced. For a very small circuit, the unchecked
flavour may be enough to do the computation correctly. Otherwise, the checked
and smart
are the best options.
As an example, let's do a scalar multiplication, a subtraction, and a multiplication.
During this computation, the carry buffer has been overflowed and, as all the operations were unchecked
, the output may be incorrect.
If we redo this same circuit with the checked
flavour, a panic will occur.
Therefore, the checked
flavour permits manual management of the overflow of the carry buffer by raising an error if the correctness is not guaranteed.
Lastly, using the smart
flavour will output the correct result all the time. However, the computation may be slower as the carry buffer may be cleaned during the computations.
#List of available operations
Currently, certain operations can only be used if the parameter set chosen is compatible with the bivariate programmable bootstrapping, meaning the carry buffer is larger than or equal to the message buffer. These operations are marked with a star (*).
The list of implemented operations for shortint is:
addition between two ciphertexts
addition between a ciphertext and an unencrypted scalar
comparisons <
, <=
, >
, >=
, ==
between a ciphertext and an unencrypted scalar
division of a ciphertext by an unencrypted scalar
LSB multiplication between two ciphertexts returning the result truncated to fit in the message buffer
multiplication of a ciphertext by an unencrypted scalar
bitwise shift <<
, >>
subtraction of a ciphertext by another ciphertext
subtraction of a ciphertext by an unencrypted scalar
negation of a ciphertext
bitwise and, or and xor (*)
comparisons <
, <=
, >
, >=
, ==
between two ciphertexts (*)
division between two ciphertexts (*)
MSB multiplication between two ciphertexts returning the part overflowing the message buffer
(*)
In what follows, some simple code examples are given.
TFHE-rs supports both private and public key encryption methods. Note that the only difference between both lies into the encryption step: in this case, the encryption method is called using public_key
instead of client_key
.
Here is a small example on how to use public encryption:
In what follows, all examples are related to private key encryption.
Classical arithmetic operations are supported by shortint:
Short homomorphic integer types support some bitwise operations.
A simple example on how to use these operations:
Short homomorphic integer types support comparison operations.
A simple example on how to use these operations:
A simple example on how to use this operation to homomorphically compute the hamming weight (i.e., the number of bits equal to one) of an encrypted number.
Using the shortint types offers the possibility to evaluate bi-variate functions, i.e., functions that takes two ciphertexts as input. This requires choosing a parameter set such that the carry buffer size is at least as large as the message one i.e., PARAM_MESSAGE_X_CARRY_Y with X <= Y.
Here is a simple code example: