Compare commits

..

2 Commits

Author SHA1 Message Date
Arthur Meyre
0ce0567cef chore(tfhe): bump version to 0.5.3 2024-02-28 14:59:18 +01:00
Arthur Meyre
e9c19b419d fix(shortint): use proper noise value during compact list encryption 2024-02-28 14:59:18 +01:00
70 changed files with 343 additions and 378 deletions

View File

@@ -1,6 +1,6 @@
[package]
name = "tfhe"
version = "0.5.2"
version = "0.5.3"
edition = "2021"
readme = "../README.md"
keywords = ["fully", "homomorphic", "encryption", "fhe", "cryptography"]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -1,42 +1,36 @@
# Welcome to TFHE-rs
# What is TFHE-rs?
⭐️ [Star the repo on Github](https://github.com/zama-ai/tfhe-rs) | 📚 [FHE resources by Zama](https://github.com/zama-ai/awesome-zama/tree/main) | 💬 [Community support](https://community.zama.ai/)
📁 [Github](https://github.com/zama-ai/tfhe-rs) | 💛 [Community support](https://zama.ai/community) | 🟨 [Zama Bounty Program](https://github.com/zama-ai/bounty-program)
<figure><img src=".gitbook/assets/doc header.png" alt=""><figcaption></figcaption></figure>
![](\_static/tfhe-rs-doc-home.png)
TFHE-rs is a pure Rust implementation of TFHE for Boolean and integer arithmetics over encrypted data. It includes a Rust and C API, as well as a client-side WASM API.
### Start here
TFHE-rs is meant for developers and researchers who want full control over what they can do with TFHE, while not worrying about the low level implementation.
Learn the basics of TFHE-rs, set it up, and make it run with ease.
The goal is to have a stable, simple, high-performance, and production-ready library for all the advanced features of TFHE.
<table data-view="cards"><thead><tr><th align="center"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center">What is TFHE-rs?</td><td><a href="getting-started/what-is-tfhe-rs.md">what-is-tfhe-rs.md</a></td></tr><tr><td align="center">Installation</td><td><a href="getting_started/installation.md">installation.md</a></td></tr><tr><td align="center">Quick start</td><td><a href="getting_started/quick_start.md">quick_start.md</a></td></tr></tbody></table>
## Key cryptographic concepts
### Build with TFHE-rs
The TFHE-rs library implements Zamas 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.
Start building with TFHE-rs by exploring its core features, discovering essential guides, and learning more with user-friendly tutorials.
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.
<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Fundamentals</strong></td><td>Explore the core features and basics of TFHE-rs.</td><td><ul><li><a href="fundamentals/configure-and-create-keys.md">Configure and create keys</a></li><li><a href="fundamentals/set-the-server-key.md">Set the server key</a></li><li><a href="fundamentals/encrypt-data.md">Encrypt data</a></li><li><a href="fundamentals/compute-and-decrypt.md">Compute and decrypt</a></li></ul></td><td><a href=".gitbook/assets/3.png">3.png</a></td><td></td></tr><tr><td><strong>Guides</strong></td><td>Discover essential guides to work with TFHE-rs.</td><td><ul><li><a href="guides/run_on_gpu.md">Run on GPU</a></li><li><a href="guides/rust_configuration.md">Configure Rust</a></li><li><a href="guides/overflow_operations.md">Detect overflow</a></li><li><a href="guides/trait_bounds.md">Generic function bounds</a></li></ul></td><td><a href=".gitbook/assets/2 (1).png">2 (1).png</a></td><td></td></tr><tr><td><strong>Tutorials</strong></td><td>Learn more about TFHE-rs with our tutorials.</td><td><p></p><ul><li><a href="tutorials/see-all-tutorials.md#start-here">Start here</a></li><li><a href="tutorials/see-all-tutorials.md#go-further">Go further</a></li><li><a href="tutorials/see-all-tutorials.md">See all tutorials</a></li></ul></td><td><a href=".gitbook/assets/1 (1).png">1 (1).png</a></td><td></td></tr></tbody></table>
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 ($$x$$ is a plaintext and $$E[x]$$ is the corresponding ciphertext):
### References
* homomorphic univariate function evaluation: $$f(E[x]) = E[f(x)]$$
* homomorphic addition: $$E[x] + E[y] = E[x + y]$$
* homomorphic multiplication: $$E[x] * E[y] = E[x * y]$$
Take a deep dive into TFHE-rs, exploring APIs from the highest to the lowest level of abstraction.
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](https://whitepaper.zama.ai/).
<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>API References</strong></td><td>High-level API that abstracts cryptographic complexities and simplifies the development process</td><td><a href="https://docs.rs/tfhe/latest/tfhe/">https://docs.rs/tfhe/latest/tfhe/</a></td></tr><tr><td><strong>Fine-grained APIs</strong></td><td>Mid-level API that enables evaluation of Boolean, short integer, and integer circuits</td><td><a href="references/fine-grained-apis/">fine-grained-apis</a></td></tr><tr><td><strong>Crypto core API</strong></td><td>Low-level API with the primitive functions and types of the TFHE scheme</td><td><a href="references/crypto-core-api/">crypto-core-api</a></td></tr></tbody></table>
Using FHE in a Rust program with TFHE-rs consists in:
### Support
* 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
Our team of experts usually answers within 24 hours in working days.
<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td>💬 <strong>Community Forum</strong></td><td>Ask technical questions to the Zama team and find solutions to common issues</td><td><a href="https://community.zama.ai/">https://community.zama.ai/</a></td></tr><tr><td>👾 <strong>Discord Channel</strong></td><td>Discuss FHE-related topics with the FHE community in real-time</td><td><a href="https://discord.com/invite/fhe-org">https://discord.com/invite/fhe-org</a></td></tr></tbody></table>
### Developers
* [Contribute to TFHE-rs](dev/contributing.md)
* Read the l[atest release note](https://github.com/zama-ai/tfhe-rs/releases)
* Request a f[eature ](https://github.com/zama-ai/tfhe-rs/issues/new?assignees=\&labels=feature\_request\&projects=\&template=feature\_request.md\&title=)
* Report a b[ug](https://github.com/zama-ai/tfhe-rs/issues/new?assignees=\&labels=triage\_required\&projects=\&template=bug\_report.md\&title=)
***
<figure><picture><source srcset=".gitbook/assets/feedback_banner_dark.png" media="(prefers-color-scheme: dark)"><img src=".gitbook/assets/feedback_banner_light.png" alt=""></picture><figcaption></figcaption></figure>
If you would like to know more about the problems that FHE solves, we suggest you review our [6 minute introduction to homomorphic encryption](https://6min.zama.ai/).

View File

@@ -1,73 +1,63 @@
# Table of contents
* [Welcome to TFHE-rs](README.md)
* [What is TFHE-rs?](README.md)
## Getting Started
* [What is TFHE-rs?](getting-started/what-is-tfhe-rs.md)
* [Installation](getting\_started/installation.md)
* [Quick start](getting\_started/quick\_start.md)
* [Types & Operations](getting\_started/operations.md)
* [Benchmarks](getting\_started/benchmarks.md)
* [Security and cryptography](getting\_started/security\_and\_cryptography.md)
## Fundamentals
* [Configure and create keys](fundamentals/configure-and-create-keys.md)
* [Set the server key](fundamentals/set-the-server-key.md)
* [Encrypt data](fundamentals/encrypt-data.md)
* [Compute and decrypt](fundamentals/compute-and-decrypt.md)
* [Serialize/Deserialize](fundamentals/serialization.md)
* [Compress ciphertexts/keys](fundamentals/compress.md)
* [Simulator mode](fundamentals/trivial\_ciphertext.md)
## Guides
* [Run on GPU](guides/run\_on\_gpu.md)
* [Configure Rust](guides/rust\_configuration.md)
* [Detect overflow](guides/overflow\_operations.md)
* [Generic function bounds](guides/trait\_bounds.md)
* [Use public key encryption](guides/public\_key.md)
* [Use parallelized PBS](guides/parallelized\_pbs.md)
* [Migrate data to newer versions of TFHE-rs](guides/migrate\_data.md)
* [Use the C API](guides/c\_api.md)
* [Use the JS on WASM API](guides/js\_on\_wasm\_api.md)
* [Use multi-threading using the rayon crate](guides/rayon\_crate.md)
* [Debug](guides/debug.md)
* [Count PBS](guides/count-pbs.md)
* [PRF Generate homomorphic randomness](guides/prf-generate-homomorphic-randomness.md)
* [Installation](getting_started/installation.md)
* [Quick Start](getting_started/quick_start.md)
* [Types & Operations](getting_started/operations.md)
* [Benchmarks](getting_started/benchmarks.md)
* [Security and Cryptography](getting_started/security_and_cryptography.md)
## Tutorials
* [Homomorphic Parity Bit](tutorials/parity_bit.md)
* [Homomorphic Case Changing on Ascii String](tutorials/ascii_fhe_string.md)
* [See all tutorials](tutorials/see-all-tutorials.md)
* [Homomorphic parity bit](tutorials/parity\_bit.md)
* [Homomorphic case changing on Ascii string](tutorials/ascii\_fhe\_string.md)
* [SHA256 with Boolean API](tutorials/sha256\_bool.md)
* [Dark market with integer API](tutorials/dark\_market.md)
* [Homomorphic regular expressions integer API](tutorials/regex.md)
## How To
* [Run on GPU](how_to/run_on_gpu.md)
* [Configure Rust](how_to/rust_configuration.md)
* [Detect Overflow](how_to/overflow_operations.md)
* [Serialize/Deserialize](how_to/serialization.md)
* [Migrate Data to Newer Versions of TFHE-rs](how_to/migrate_data.md)
* [Compress Ciphertexts/Keys](how_to/compress.md)
* [Use Public Key Encryption](how_to/public_key.md)
* [Use Trivial Ciphertext](how_to/trivial_ciphertext.md)
* [Generic Function Bounds](how_to/trait_bounds.md)
* [Use Parallelized PBS](how_to/parallelized_pbs.md)
* [Use the C API](how_to/c_api.md)
* [Use the JS on WASM API](how_to/js_on_wasm_api.md)
* [Use multi-threading using the rayon crate](how_to/rayon_crate.md)
* [Debug](how_to/debug.md)
## References
## Fine-grained APIs
* [Quick Start](fine_grained_api/quick_start.md)
* [Boolean](fine_grained_api/Boolean/readme.md)
* [Operations](fine_grained_api/Boolean/operations.md)
* [Cryptographic Parameters](fine_grained_api/Boolean/parameters.md)
* [Serialization/Deserialization](fine_grained_api/Boolean/serialization.md)
* [API references](references/api-references/README.md)
* [docs.rs](https://docs.rs/tfhe/)
* [Fine-grained APIs](references/fine-grained-apis/README.md)
* [Quick Start](references/fine-grained-apis/quick\_start.md)
* [Boolean](references/fine-grained-apis/boolean/README.md)
* [Operations](references/fine-grained-apis/boolean/operations.md)
* [Cryptographic Parameters](references/fine-grained-apis/boolean/parameters.md)
* [Serialization/Deserialization](references/fine-grained-apis/boolean/serialization.md)
* [Shortint](references/fine-grained-apis/shortint/README.md)
* [Operations](references/fine-grained-apis/shortint/operations.md)
* [Cryptographic Parameters](references/fine-grained-apis/shortint/parameters.md)
* [Serialization/Deserialization](references/fine-grained-apis/shortint/serialization.md)
* [Integer](references/fine-grained-apis/integer/README.md)
* [Operations](references/fine-grained-apis/integer/operations.md)
* [Cryptographic Parameters](references/fine-grained-apis/integer/parameters.md)
* [Serialization/Deserialization](references/fine-grained-apis/integer/serialization.md)
* [Crypto core API](references/crypto-core-api/README.md)
* [Quick Start](references/crypto-core-api/presentation.md)
* [Tutorial](references/crypto-core-api/tutorial.md)
* [Shortint](fine_grained_api/shortint/readme.md)
* [Operations](fine_grained_api/shortint/operations.md)
* [Cryptographic Parameters](fine_grained_api/shortint/parameters.md)
* [Serialization/Deserialization](fine_grained_api/shortint/serialization.md)
* [Integer](fine_grained_api/integer/readme.md)
* [Operations](fine_grained_api/integer/operations.md)
* [Cryptographic Parameters](fine_grained_api/integer/parameters.md)
* [Serialization/Deserialization](fine_grained_api/integer/serialization.md)
## Application Tutorials
* [SHA256 with *Boolean API*](application_tutorials/sha256_bool.md)
* [Dark Market with *Integer API*](application_tutorials/dark_market.md)
* [Homomorphic Regular Expressions *Integer API*](application_tutorials/regex.md)
## Crypto Core API [Advanced users]
* [Quick Start](core_crypto/presentation.md)
* [Tutorial](core_crypto/tutorial.md)
## Developers
* [Contributing](dev/contributing.md)
* [Contribute](dev/contributing.md)
## API references
* [docs.rs](https://docs.rs/tfhe/)

View File

@@ -1,6 +1,6 @@
# Quick Start
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](../../fine\_grained\_api/shortint/tutorial.md) and/or [Boolean](../../fine\_grained\_api/Boolean/tutorial.md) modules (based on `core_crypto`) are recommended.
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](../fine_grained_api/shortint/tutorial.md) and/or [Boolean](../fine_grained_api/Boolean/tutorial.md) modules (based on `core_crypto`) are recommended.
The `core_crypto` module offers an API to low-level cryptographic primitives and objects, like `lwe_encryption` or `rlwe_ciphertext`. The goal is to propose an easy-to-use API for cryptographers.

View File

@@ -9,7 +9,7 @@ Welcome to this tutorial about `TFHE-rs` `core_crypto` module.
To use `TFHE-rs`, it first has to be added as a dependency in the `Cargo.toml`:
```toml
tfhe = { version = "0.5.2", features = [ "x86_64-unix" ] }
tfhe = { version = "0.5.3", features = [ "x86_64-unix" ] }
```
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 activated as a fallback if no hardware number generator is available (like `rdseed` on `x86_64` or if the [`Randomization Services`](https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc) 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.
@@ -19,19 +19,19 @@ For Apple Silicon, the `aarch64-unix` or `aarch64` feature should be enabled. `a
In short: For `x86_64`-based machines running Unix-like OSes:
```toml
tfhe = { version = "0.5.2", features = ["x86_64-unix"] }
tfhe = { version = "0.5.3", features = ["x86_64-unix"] }
```
For Apple Silicon or aarch64-based machines running Unix-like OSes:
```toml
tfhe = { version = "0.5.2", features = ["aarch64-unix"] }
tfhe = { version = "0.5.3", features = ["aarch64-unix"] }
```
For `x86_64`-based machines with the [`rdseed instruction`](https://en.wikipedia.org/wiki/RDRAND) running Windows:
```toml
tfhe = { version = "0.5.2", features = ["x86_64"] }
tfhe = { version = "0.5.3", features = ["x86_64"] }
```
### Commented code to double a 2-bit message in a leveled fashion and using a PBS with the `core_crypto` module.

View File

@@ -6,7 +6,7 @@ The structure and operations related to integers are described in this section.
In `integer`, the encrypted data is split amongst many ciphertexts encrypted with the `shortint` library. Below is a scheme representing an integer composed by k shortint ciphertexts.
![](../../../\_static/integer-ciphertext.png)
![](../../_static/integer-ciphertext.png)
This crate implements two ways to represent an integer:
@@ -48,7 +48,8 @@ fn main() {
}
```
This representation has many advantages: no carry propagation is required, cleaning the carry buffer of each ciphertext block is enough. This implies that operations can easily be parallelized. It also allows the efficient computation of PBS in the case where the function is CRT-compliant.
This representation has many advantages: no carry propagation is required, cleaning the carry buffer of each ciphertext block is enough. This implies that operations can easily be
parallelized. It also allows the efficient computation of PBS in the case where the function is CRT-compliant.
A variant of the CRT is proposed where each block might be associated to a different key couple. Here, a keychain to the computations is required, but this may result in a performance improvement.
@@ -56,20 +57,20 @@ A variant of the CRT is proposed where each block might be associated to a diffe
The list of operations available in `integer` depends on the type of representation:
| Operation name | Radix-based | CRT-based |
| ------------------------------ | -------------------- | -------------------------- |
| Negation | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Addition | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Scalar Addition | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Subtraction | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Scalar Subtraction | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Multiplication | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Scalar Multiplication | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Bitwise OR, AND, XOR | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Equality | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Left/Right Shift | :heavy\_check\_mark: | :heavy\_multiplication\_x: |
| Comparisons `<`,`<=`,`>`, `>=` | :heavy\_check\_mark: | :heavy\_multiplication\_x: |
| Min, Max | :heavy\_check\_mark: | :heavy\_multiplication\_x: |
| Operation name | Radix-based | CRT-based |
| ------------------------------ | -------------------- | -------------------------- |
| Negation | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Addition | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Scalar Addition | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Subtraction | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Scalar Subtraction | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Multiplication | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Scalar Multiplication | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Bitwise OR, AND, XOR | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Equality | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Left/Right Shift | :heavy\_check\_mark: | :heavy\_multiplication\_x: |
| Comparisons `<`,`<=`,`>`, `>=` | :heavy\_check\_mark: | :heavy\_multiplication\_x: |
| Min, Max | :heavy\_check\_mark: | :heavy\_multiplication\_x: |
## Types of operations
@@ -214,12 +215,12 @@ fn main() {
{% hint style="warning" %}
You must avoid cloning the inputs when calling `smart` operations to preserve performance. For instance, you SHOULD NOT have these kind of patterns in the code:
```Rust
sks.smart_add(&mut a.clone(), &mut b.clone());
```
{% endhint %}
The main advantage of the default flavor is to ensure predictable timings, as long as only this kind of operation is used. Only the parallelized version of the operations is provided.
{% hint style="warning" %}

View File

@@ -8,7 +8,7 @@ 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**.
![](../../../\_static/ciphertext-representation.png)
![](../../_static/ciphertext-representation.png)
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 part of the message which exceeds the message modulus is stored in the carry buffer. The size of the carry buffer is defined by another modulus, called `CarryModulus`.
@@ -41,8 +41,10 @@ Not all operations have these 4 flavors, as some of them are implemented in a wa
If you don't know which flavor to use, you should use the `default` one.
{% endhint %}
## How to use operation types
Let's try to do a circuit evaluation using the different flavors of operations that we have already introduced. For a very small circuit, the `unchecked` flavour may be enough to do the computation correctly. Otherwise,`checked` and `smart` are the best options.
Let's do a scalar multiplication, a subtraction, and a multiplication.
@@ -151,7 +153,7 @@ fn main() {
}
```
The main advantage of the default flavor is to ensure predictable timings as long as this is the only kind of operation which is used.
The main advantage of the default flavor is to ensure predictable timings as long as this is the only kind of operation which is used.
{% hint style="warning" %}
Using `default` could **slow-down** computations.

View File

@@ -1,6 +1,6 @@
# Cryptographic Parameters
All parameter sets provide at least 128-bits of security according to the [Lattice-Estimator](https://github.com/malb/lattice-estimator), with an error probability equal to $$2^{-40}$$ when using programmable bootstrapping. This error probability is due to the randomness added at each encryption (see [here](../../../getting\_started/security\_and\_cryptography.md) for more details about the encryption process).
All parameter sets provide at least 128-bits of security according to the [Lattice-Estimator](https://github.com/malb/lattice-estimator), with an error probability equal to $$2^{-40}$$ when using programmable bootstrapping. This error probability is due to the randomness added at each encryption (see [here](../../getting_started/security_and_cryptography.md) for more details about the encryption process).
## Parameters and message precision
@@ -34,7 +34,7 @@ fn main() {
## Impact of parameters on the operations
As shown [here](../../../getting\_started/benchmarks.md), the choice of the parameter set impacts the operations available and their efficiency.
As shown [here](../../getting_started/benchmarks.md), the choice of the parameter set impacts the operations available and their efficiency.
### Generic bi-variate functions.

View File

@@ -1,17 +0,0 @@
# Compute and decrypt
Computations should be as easy as normal Rust to write, thanks to the usage of operator overloading.
```Rust
let result = a + b;
```
The decryption is achieved by using the `decrypt` method, which comes from the FheDecrypt trait.
```Rust
let decrypted_result: u8 = result.decrypt(&client_key);
let clear_result = clear_a + clear_b;
assert_eq!(decrypted_result, clear_result);
```

View File

@@ -1,24 +0,0 @@
# Configure and create keys
The first step is the creation of the configuration. The configuration is used to declare which type you will (or will not) use, as well as enabling you to use custom crypto-parameters for these types. Custom parameters should only be used for more advanced usage and/or testing.
A configuration can be created by using the ConfigBuilder type.
In this example, 8-bit unsigned integers with default parameters are used. The `integers` feature must also be enabled, as per the table on [this page](../guides/rust\_configuration.md#choosing-your-features).
The config is generated by first creating a builder with all types deactivated. Then, the integer types with default parameters are activated, since we are going to use FheUint8 values.
```rust
use tfhe::{ConfigBuilder, generate_keys};
fn main() {
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
}
```
The `generate_keys` command returns a client key and a server key.
The `client_key` is meant to stay private and not leave the client, whereas the `server_key` can be made public and sent to a server for it to enable FHE computations.

View File

@@ -1,13 +0,0 @@
# Encrypt data
Encrypting data is achieved via the `encrypt` associated function of the FheEncrypt trait.
Types exposed by this crate implement at least one of FheEncrypt or FheTryEncrypt to allow encryption.
```Rust
let clear_a = 27u8;
let clear_b = 128u8;
let a = FheUint8::encrypt(clear_a, &client_key);
let b = FheUint8::encrypt(clear_b, &client_key);
```

View File

@@ -1,17 +0,0 @@
# Set the server key
The next step is to call `set_server_key`
This function will **move** the server key to an internal state of the crate and manage the details to give a simpler interface.
```rust
use tfhe::{ConfigBuilder, generate_keys, set_server_key};
fn main() {
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
set_server_key(server_key);
}
```

View File

@@ -1,32 +0,0 @@
# What is TFHE-rs?
TFHE-rs is a pure Rust implementation of TFHE for Boolean and 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 worrying 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.
## Key cryptographic concepts
The TFHE-rs library implements Zamas 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.
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 ($$x$$ is a plaintext and $$E[x]$$ is the corresponding ciphertext):
* homomorphic univariate function evaluation: $$f(E[x]) = E[f(x)]$$
* homomorphic addition: $$E[x] + E[y] = E[x + y]$$
* homomorphic multiplication: $$E[x] * E[y] = E[x * y]$$
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](https://whitepaper.zama.ai/).
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](https://6min.zama.ai/).

View File

@@ -13,34 +13,36 @@ This measures the execution time for some operation sets of tfhe-rs::integer (th
The table below reports the timing when the inputs of the benchmarked operation are encrypted.
| Operation \ Size | `FheUint8` | `FheUint16` | `FheUint32` | `FheUint64` | `FheUint128` | `FheUint256` |
| ------------------------------------------------------ | ---------- | ----------- | ----------- | ----------- | ------------ | ------------ |
|--------------------------------------------------------|------------|-------------|-------------|-------------|--------------|--------------|
| Negation (`-`) | 55.4 ms | 79.7 ms | 105 ms | 133 ms | 163 ms | 199 ms |
| Add / Sub (`+`,`-`) | 58.9 ms | 86.0 ms | 106 ms | 124 ms | 151 ms | 193 ms |
| Mul (`x`) | 122 ms | 164 ms | 227 ms | 410 ms | 1,04 s | 3,41 s |
| Equal / Not Equal (`eq`, `ne`) | 32.0 ms | 32.0 ms | 50.4 ms | 50.9 ms | 53.1 ms | 54.6 ms |
| Comparisons (`ge`, `gt`, `le`, `lt`) | 43.7 ms | 65.2 ms | 84.3 ms | 107 ms | 132 ms | 159 ms |
| Max / Min (`max`,`min`) | 68.4 ms | 86.8 ms | 106 ms | 132 ms | 160 ms | 200 ms |
| Comparisons (`ge`, `gt`, `le`, `lt`) | 43.7 ms | 65.2 ms | 84.3 ms | 107 ms | 132 ms | 159 ms |
| Max / Min (`max`,`min`) | 68.4 ms | 86.8 ms | 106 ms | 132 ms | 160 ms | 200 ms |
| Bitwise operations (`&`, `\|`, `^`) | 17.1 ms | 17.3 ms | 17.8 ms | 18.8 ms | 20.2 ms | 22.2 ms |
| Div / Rem (`/`, `%`) | 631 ms | 1.59 s | 3.77 s | 8,64 s | 20,3 s | 53,4 s |
| Div / Rem (`/`, `%`) | 631 ms | 1.59 s | 3.77 s | 8,64 s | 20,3 s | 53,4 s |
| Left / Right Shifts (`<<`, `>>`) | 82.8 ms | 99.2 ms | 121 ms | 149 ms | 194 ms | 401 ms |
| Left / Right Rotations (`left_rotate`, `right_rotate`) | 82.1 ms | 99.4 ms | 120 ms | 149 ms | 194 ms | 402 ms |
The table below reports the timing when the left input of the benchmarked operation is encrypted and the other is a clear scalar of the same size.
| Operation \ Size | `FheUint8` | `FheUint16` | `FheUint32` | `FheUint64` | `FheUint128` | `FheUint256` |
| ------------------------------------------------------ | ---------- | ----------- | ----------- | ----------- | ------------ | ------------ |
|--------------------------------------------------------|------------|-------------|-------------|-------------|--------------|--------------|
| Add / Sub (`+`,`-`) | 68.3 ms | 82.4 ms | 102 ms | 122 ms | 151 ms | 191 ms |
| Mul (`x`) | 93.7 ms | 139 ms | 178 ms | 242 ms | 516 ms | 1.02 s |
| Equal / Not Equal (`eq`, `ne`) | 30.2 ms | 30.8 ms | 32.7 ms | 50.4 ms | 51.2 ms | 54.8 ms |
| Comparisons (`ge`, `gt`, `le`, `lt`) | 47.3 ms | 69.9 ms | 96.3 ms | 102 ms | 138 ms | 141 ms |
| Max / Min (`max`,`min`) | 75.4 ms | 99.7 ms | 120 ms | 126 ms | 150 ms | 186 ms |
| Comparisons (`ge`, `gt`, `le`, `lt`) | 47.3 ms | 69.9 ms | 96.3 ms | 102 ms | 138 ms | 141 ms |
| Max / Min (`max`,`min`) | 75.4 ms | 99.7 ms | 120 ms | 126 ms | 150 ms | 186 ms |
| Bitwise operations (`&`, `\|`, `^`) | 17.1 ms | 17.4 ms | 18.2 ms | 19.2 ms | 19.7 ms | 22.6 ms |
| Div (`/`) | 160 ms | 212 ms | 272 ms | 402 ms | 796 ms | 2.27 s |
| Rem (`%`) | 315 ms | 428 ms | 556 ms | 767 ms | 1.27 s | 2.86 s |
| Left / Right Shifts (`<<`, `>>`) | 16.8 ms | 16.8 ms | 17.3 ms | 18.0 ms | 18.9 ms | 22.6 ms |
| Left / Right Rotations (`left_rotate`, `right_rotate`) | 16.8 ms | 16.9 ms | 17.3 ms | 18.3 ms | 19.0 ms | 22.8 ms |
All timings are related to parallelized Radix-based integer operations, where each block is encrypted using the default parameters (i.e., PARAM\_MESSAGE\_2\_CARRY\_2\_KS\_PBS, more information about parameters can be found [here](../references/fine-grained-apis/shortint/parameters.md)). To ensure predictable timings, the operation flavor is the `default` one: the carry is propagated if needed. The operation costs may be reduced by using `unchecked`, `checked`, or `smart`.
All timings are related to parallelized Radix-based integer operations, where each block is encrypted using the default parameters (i.e., PARAM\_MESSAGE\_2\_CARRY\_2\_KS\_PBS, more information about parameters can be found [here](../fine_grained_api/shortint/parameters.md)).
To ensure predictable timings, the operation flavor is the `default` one: the carry is propagated if needed. The operation costs may be reduced by using `unchecked`, `checked`, or `smart`.
## Shortint
@@ -49,12 +51,13 @@ This measures the execution time for some operations using various parameter set
This uses the Concrete FFT + AVX-512 configuration.
| Parameter set | PARAM\_MESSAGE\_1\_CARRY\_1 | PARAM\_MESSAGE\_2\_CARRY\_2 | PARAM\_MESSAGE\_3\_CARRY\_3 | PARAM\_MESSAGE\_4\_CARRY\_4 |
| ---------------------------------- | --------------------------- | --------------------------- | --------------------------- | --------------------------- |
|------------------------------------|-----------------------------|-----------------------------|-----------------------------|-----------------------------|
| unchecked\_add | 341 ns | 555 ns | 2.47 µs | 9.77 µs |
| add | 5.96 ms | 12.6 ms | 102 ms | 508 ms |
| mul\_lsb | 5.99 ms | 12.3 ms | 101 ms | 500 ms |
| keyswitch\_programmable\_bootstrap | 6.40 ms | 12.9 ms | 104 ms | 489 ms |
## Boolean
This measures the execution time of a single binary Boolean gate.
@@ -62,25 +65,26 @@ This measures the execution time of a single binary Boolean gate.
### tfhe-rs::boolean.
| Parameter set | Concrete FFT + AVX-512 |
| ---------------------------------------------------- | ---------------------- |
|------------------------------------------------------|------------------------|
| DEFAULT\_PARAMETERS\_KS\_PBS | 8.49 ms |
| PARAMETERS\_ERROR\_PROB\_2\_POW\_MINUS\_165\_KS\_PBS | 13.7 ms |
| TFHE\_LIB\_PARAMETERS | 9.90 ms |
### tfhe-lib.
Using the same hpc7a.96xlarge machine as the one for tfhe-rs, the timings are:
| Parameter set | spqlios-fma |
| ------------------------------------------------ | ----------- |
|--------------------------------------------------|-------------|
| default\_128bit\_gate\_bootstrapping\_parameters | 13.5 ms |
### OpenFHE (v1.1.2).
Following the official instructions from OpenFHE, `clang14` and the following command are used to setup the project: `cmake -DNATIVE_SIZE=32 -DWITH_NATIVEOPT=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DWITH_OPENMP=OFF ..`
Following the official instructions from OpenFHE, `clang14` and the following command are used to setup the project:
`cmake -DNATIVE_SIZE=32 -DWITH_NATIVEOPT=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DWITH_OPENMP=OFF ..`
To use the HEXL library, the configuration used is as follows:
```bash
export CXX=clang++
export CC=clang
@@ -94,10 +98,11 @@ scripts/build-openfhe-development-hexl.sh
Using the same hpc7a.96xlarge machine as the one for tfhe-rs, the timings are:
| Parameter set | GINX | GINX w/ Intel HEXL |
| --------------------------------- | ------- | ------------------ |
| FHEW\_BINGATE/STD128\_OR | 25.5 ms | 21,6 ms |
| FHEW\_BINGATE/STD128\_LMKCDEY\_OR | 25.4 ms | 19.9 ms |
| Parameter set | GINX | GINX w/ Intel HEXL |
|----------------------------------|---------|--------------------|
| FHEW\_BINGATE/STD128\_OR | 25.5 ms | 21,6 ms |
| FHEW\_BINGATE/STD128\_LMKCDEY_OR | 25.4 ms | 19.9 ms |
## How to reproduce TFHE-rs benchmarks

View File

@@ -8,12 +8,12 @@ To use `TFHE-rs` in your project, you first need to add it as a dependency in yo
If you are using an `x86` machine:
```toml
tfhe = { version = "0.5.2", features = [ "boolean", "shortint", "integer", "x86_64-unix" ] }
tfhe = { version = "0.5.3", features = [ "boolean", "shortint", "integer", "x86_64-unix" ] }
```
If you are using an `ARM` machine:
```toml
tfhe = { version = "0.5.2", features = [ "boolean", "shortint", "integer", "aarch64-unix" ] }
tfhe = { version = "0.5.3", features = [ "boolean", "shortint", "integer", "aarch64-unix" ] }
```
{% hint style="info" %}

View File

@@ -1,11 +1,9 @@
# Types & Operations
# Homomorphic Types and Operations
## Types
`TFHE-rs` includes two main types to represent encrypted data:
* `FheUint`: this is the homomorphic equivalent of Rust unsigned integers `u8, u16, ...`
* `FheInt`: this is the homomorphic equivalent of Rust (signed) integers `i8, i16, ...`
- `FheUint`: this is the homomorphic equivalent of Rust unsigned integers `u8, u16, ...`
- `FheInt`: this is the homomorphic equivalent of Rust (signed) integers `i8, i16, ...`
In the same manner as many programming languages, the number of bits used to represent the data must be chosen when declaring a variable. For instance:
@@ -21,35 +19,35 @@ In the same manner as many programming languages, the number of bits used to rep
```
## Operation list
The table below contains an overview of the available operations in `TFHE-rs`. The notation `Enc` (for Encrypted) either refers to `FheInt` or `FheUint`, for any size between 1 and 256-bits.
The table below contains an overview of the available operations in `TFHE-rs`. The notation `Enc` (for Encypted) either refers to `FheInt` or `FheUint`, for any size between 1 and 256-bits.
More details, and further examples, are given in the following sections.
| name | symbol | `Enc`/`Enc` | `Enc`/ `Int` |
| --------------------- | -------------- | -------------------- | -------------------------- |
| Neg | `-` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Add | `+` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Sub | `-` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Mul | `*` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Div | `/` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Rem | `%` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Not | `!` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| BitAnd | `&` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| BitOr | `\|` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| BitXor | `^` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Shr | `>>` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Shl | `<<` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Min | `min` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Max | `max` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Greater than | `gt` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Greater or equal than | `ge` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Lower than | `lt` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Lower or equal than | `le` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Equal | `eq` | :heavy\_check\_mark: | :heavy\_check\_mark: |
| Cast (into dest type) | `cast_into` | :heavy\_check\_mark: | :heavy\_multiplication\_x: |
| Cast (from src type) | `cast_from` | :heavy\_check\_mark: | :heavy\_multiplication\_x: |
| Ternary operator | `if_then_else` | :heavy\_check\_mark: | :heavy\_multiplication\_x: |
| name | symbol | `Enc`/`Enc` | `Enc`/ `Int` |
|-----------------------|----------------|--------------------|--------------------------|
| Neg | `-` | :heavy_check_mark: | :heavy_check_mark: |
| Add | `+` | :heavy_check_mark: | :heavy_check_mark: |
| Sub | `-` | :heavy_check_mark: | :heavy_check_mark: |
| Mul | `*` | :heavy_check_mark: | :heavy_check_mark: |
| Div | `/` | :heavy_check_mark: | :heavy_check_mark: |
| Rem | `%` | :heavy_check_mark: | :heavy_check_mark: |
| Not | `!` | :heavy_check_mark: | :heavy_check_mark: |
| BitAnd | `&` | :heavy_check_mark: | :heavy_check_mark: |
| BitOr | `\|` | :heavy_check_mark: | :heavy_check_mark: |
| BitXor | `^` | :heavy_check_mark: | :heavy_check_mark: |
| Shr | `>>` | :heavy_check_mark: | :heavy_check_mark: |
| Shl | `<<` | :heavy_check_mark: | :heavy_check_mark: |
| Min | `min` | :heavy_check_mark: | :heavy_check_mark: |
| Max | `max` | :heavy_check_mark: | :heavy_check_mark: |
| Greater than | `gt` | :heavy_check_mark: | :heavy_check_mark: |
| Greater or equal than | `ge` | :heavy_check_mark: | :heavy_check_mark: |
| Lower than | `lt` | :heavy_check_mark: | :heavy_check_mark: |
| Lower or equal than | `le` | :heavy_check_mark: | :heavy_check_mark: |
| Equal | `eq` | :heavy_check_mark: | :heavy_check_mark: |
| Cast (into dest type) | `cast_into` | :heavy_check_mark: | :heavy_multiplication_x: |
| Cast (from src type) | `cast_from` | :heavy_check_mark: | :heavy_multiplication_x: |
| Ternary operator | `if_then_else` | :heavy_check_mark: | :heavy_multiplication_x: |
## Integer
@@ -61,16 +59,17 @@ Homomorphic integer types support arithmetic operations.
The list of supported operations is:
| name | symbol | type |
| --------------------------------------------------------- | ------ | ------ |
| [Neg](https://doc.rust-lang.org/std/ops/trait.Neg.html) | `-` | Unary |
| [Add](https://doc.rust-lang.org/std/ops/trait.Add.html) | `+` | Binary |
| [Sub](https://doc.rust-lang.org/std/ops/trait.Sub.html) | `-` | Binary |
| [Mul](https://doc.rust-lang.org/std/ops/trait.Mul.html) | `*` | Binary |
| [Div](https://doc.rust-lang.org/std/ops/trait.Div.html)\* | `/` | Binary |
| [Rem](https://doc.rust-lang.org/std/ops/trait.Rem.html)\* | `%` | Binary |
| name | symbol | type |
|----------------------------------------------------------|--------|--------|
| [Neg](https://doc.rust-lang.org/std/ops/trait.Neg.html) | `-` | Unary |
| [Add](https://doc.rust-lang.org/std/ops/trait.Add.html) | `+` | Binary |
| [Sub](https://doc.rust-lang.org/std/ops/trait.Sub.html) | `-` | Binary |
| [Mul](https://doc.rust-lang.org/std/ops/trait.Mul.html) | `*` | Binary |
| [Div](https://doc.rust-lang.org/std/ops/trait.Div.html)* | `/` | Binary |
| [Rem](https://doc.rust-lang.org/std/ops/trait.Rem.html)* | `%` | Binary |
For division by 0, the convention is to return `modulus - 1`. For instance, for `FheUint8`, the modulus is $$2^8=256$$, so a division by 0 will return an encryption of 255. For the remainder operator, the convention is to return the first input without any modification. For instance, if `ct1 = FheUint8(63)` and `ct2 = FheUint8(0)` then `ct1 % ct2` will return `FheUint8(63)`.
For division by 0, the convention is to return `modulus - 1`. For instance, for `FheUint8`, the modulus is $$2^8=256$$, so a division by 0 will return an encryption of 255.
For the remainder operator, the convention is to return the first input without any modification. For instance, if `ct1 = FheUint8(63)` and `ct2 = FheUint8(0)` then `ct1 % ct2` will return `FheUint8(63)`.
A simple example of how to use these operations:
@@ -117,16 +116,16 @@ Homomorphic integer types support some bitwise operations.
The list of supported operations is:
| name | symbol | type |
| ------------------------------------------------------------------------------------- | -------------- | ------ |
| [Not](https://doc.rust-lang.org/std/ops/trait.Not.html) | `!` | Unary |
| [BitAnd](https://doc.rust-lang.org/std/ops/trait.BitAnd.html) | `&` | Binary |
| [BitOr](https://doc.rust-lang.org/std/ops/trait.BitOr.html) | `\|` | Binary |
| [BitXor](https://doc.rust-lang.org/std/ops/trait.BitXor.html) | `^` | Binary |
| [Shr](https://doc.rust-lang.org/std/ops/trait.Shr.html) | `>>` | Binary |
| [Shl](https://doc.rust-lang.org/std/ops/trait.Shl.html) | `<<` | Binary |
| [Rotate Right](https://doc.rust-lang.org/std/primitive.u32.html#method.rotate\_right) | `rotate_right` | Binary |
| [Rotate Left](https://doc.rust-lang.org/std/primitive.u32.html#method.rotate\_left) | `rotate_left` | Binary |
| name | symbol | type |
|--------------------------------------------------------------------------------------|----------------|--------|
| [Not](https://doc.rust-lang.org/std/ops/trait.Not.html) | `!` | Unary |
| [BitAnd](https://doc.rust-lang.org/std/ops/trait.BitAnd.html) | `&` | Binary |
| [BitOr](https://doc.rust-lang.org/std/ops/trait.BitOr.html) | `\|` | Binary |
| [BitXor](https://doc.rust-lang.org/std/ops/trait.BitXor.html) | `^` | Binary |
| [Shr](https://doc.rust-lang.org/std/ops/trait.Shr.html) | `>>` | Binary |
| [Shl](https://doc.rust-lang.org/std/ops/trait.Shl.html) | `<<` | Binary |
| [Rotate Right](https://doc.rust-lang.org/std/primitive.u32.html#method.rotate_right) | `rotate_right` | Binary |
| [Rotate Left](https://doc.rust-lang.org/std/primitive.u32.html#method.rotate_left) | `rotate_left` | Binary |
A simple example of how to use these operations:
@@ -174,13 +173,13 @@ You will need to use different methods instead of using symbols for the comparis
The list of supported operations is:
| name | symbol | type |
| --------------------------------------------------------------------------- | ------ | ------ |
| [Equal](https://doc.rust-lang.org/std/cmp/trait.PartialEq.html) | `eq` | Binary |
| [Not Equal](https://doc.rust-lang.org/std/cmp/trait.PartialEq.html) | `ne` | Binary |
| [Greater Than](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `gt` | Binary |
|-----------------------------------------------------------------------------|--------|--------|
| [Equal ](https://doc.rust-lang.org/std/cmp/trait.PartialEq.html) | `eq` | Binary |
| [Not Equal ](https://doc.rust-lang.org/std/cmp/trait.PartialEq.html) | `ne` | Binary |
| [Greater Than ](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `gt` | Binary |
| [Greater or Equal](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `ge` | Binary |
| [Lower](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `lt` | Binary |
| [Lower or Equal](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `le` | Binary |
| [Lower ](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `lt` | Binary |
| [Lower or Equal ](https://doc.rust-lang.org/std/cmp/trait.PartialOrd.html) | `le` | Binary |
A simple example of how to use these operations:
@@ -261,11 +260,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
```
### Ternary conditional operator.
The ternary conditional operator allows computing conditional instructions of the form `if cond { choice_if } else { choice_else }`.
| name | symbol | type |
| ---------------- | -------------- | ------- |
|------------------|----------------|---------|
| Ternary operator | `if_then_else` | Ternary |
The syntax is `encrypted_condition.if_then_else(encrypted_choice_if, encrypted_choice_else)`. The `encrypted_condition` should be an encryption of 0 or 1 in order to be valid.
@@ -311,9 +309,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
```
### Casting.
Casting between integer types is possible via the `cast_from` associated function or the `cast_into` method.
### Casting.
Casting between integer types is possible via the `cast_from` associated function
or the `cast_into` method.
```rust
use tfhe::prelude::*;
@@ -371,6 +370,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
```
## Boolean Operations
Native homomorphic Booleans support common Boolean operations.

View File

@@ -1,13 +1,15 @@
# Quick start
# Tutorial
## Quick Start
The basic steps for using the high-level API of TFHE-rs are:
1. [Importing the TFHE-rs prelude;](quick\_start.md#imports)
2. Client-side: [Configuring and creating keys;](../fundamentals/configure-and-create-keys.md)
3. Client-side: [Encrypting data;](../fundamentals/encrypt-data.md)
4. Server-side: [Setting the server key;](../fundamentals/set-the-server-key.md)
5. Server-side: [Computing over encrypted data;](../fundamentals/compute-and-decrypt.md)
6. Client-side: [Decrypting data.](../fundamentals/compute-and-decrypt.md)
1. Importing the TFHE-rs prelude;
2. Client-side: Configuring and creating keys;
3. Client-side: Encrypting data;
4. Server-side: Setting the server key;
5. Server-side: Computing over encrypted data;
6. Client-side: Decrypting data.
Here is a full example (combining the client and server parts):
@@ -41,19 +43,94 @@ fn main() {
```
The default configuration for x86 Unix machines:
```toml
tfhe = { version = "0.5.2", features = ["integer", "x86_64-unix"]}
tfhe = { version = "0.5.3", features = ["integer", "x86_64-unix"]}
```
Configuration options for different platforms can be found [here](installation.md). Other rust and homomorphic types features can be found [here](../guides/rust\_configuration.md).
Configuration options for different platforms can be found [here](../getting_started/installation.md). Other rust and homomorphic types features can be found [here](../how_to/rust_configuration.md).
### Imports
### Imports.
`tfhe` uses `traits` to have a consistent API for creating FHE types and enable users to write generic functions. To be able to use associated functions and methods of a trait, the trait has to be in scope.
To make it easier, the `prelude` 'pattern' is used. All of the important `tfhe` traits are in a `prelude` module that you can **glob import**. With this, there is no need to remember or know the traits that you want to import.
```rust
use tfhe::prelude::*;
use tfhe::prelude::*;
```
### 1. Configuring and creating keys.
The first step is the creation of the configuration. The configuration is used to declare which type you will (or will not) use, as well as enabling you to use custom crypto-parameters for these types. Custom parameters should only be used for more advanced usage and/or testing.
A configuration can be created by using the ConfigBuilder type.
In this example, 8-bit unsigned integers with default parameters are used. The `integers`
feature must also be enabled, as per the table on [this page](../how_to/rust_configuration.md#choosing-your-features).
The config is generated by first creating a builder with all types deactivated. Then, the integer types with default parameters are activated, since we are going to use FheUint8 values.
```rust
use tfhe::{ConfigBuilder, generate_keys};
fn main() {
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
}
```
The `generate_keys` command returns a client key and a server key.
The `client_key` is meant to stay private and not leave the client, whereas the `server_key` can be made public and sent to a server for it to enable FHE computations.
### 2. Setting the server key.
The next step is to call `set_server_key`
This function will **move** the server key to an internal state of the crate and manage the details to give a simpler interface.
```rust
use tfhe::{ConfigBuilder, generate_keys, set_server_key};
fn main() {
let config = ConfigBuilder::default().build();
let (client_key, server_key) = generate_keys(config);
set_server_key(server_key);
}
```
### 3. Encrypting data.
Encrypting data is achieved via the `encrypt` associated function of the FheEncrypt trait.
Types exposed by this crate implement at least one of FheEncrypt or FheTryEncrypt to allow encryption.
```Rust
let clear_a = 27u8;
let clear_b = 128u8;
let a = FheUint8::encrypt(clear_a, &client_key);
let b = FheUint8::encrypt(clear_b, &client_key);
```
### 4. Computation and decryption.
Computations should be as easy as normal Rust to write, thanks to the usage of operator overloading.
```Rust
let result = a + b;
```
The decryption is achieved by using the `decrypt` method, which comes from the FheDecrypt trait.
```Rust
let decrypted_result: u8 = result.decrypt(&client_key);
let clear_result = clear_a + clear_b;
assert_eq!(decrypted_result, clear_result);
```

View File

@@ -1,2 +0,0 @@
# How to count PBS

View File

@@ -1,2 +0,0 @@
# PRF How to generate homomorphic randomness

View File

@@ -1,5 +1,4 @@
# Compress Ciphertexts/Keys
# Reducing the size of keys and ciphertexts
TFHE-rs includes features to reduce the size of both keys and ciphertexts, by compressing them. Most TFHE-rs entities contain random numbers generated by a Pseudo Random Number Generator (PRNG). A PRNG is deterministic, therefore storing only the random seed used to generate those numbers is enough to keep all the required information: using the same PRNG and the same seed, the full chain of random values can be reconstructed when decompressing the entity.
In the library, entities that can be compressed are prefixed by `Compressed`. For instance, the type of a compressed `FheUint256` is `CompressedFheUint256`.
@@ -7,7 +6,6 @@ In the library, entities that can be compressed are prefixed by `Compressed`. Fo
In the following example code, we use the `bincode` crate dependency to serialize in a binary format and compare serialized sizes.
## Compressed ciphertexts
This example shows how to compress a ciphertext encypting messages over 16 bits.
```rust
@@ -37,8 +35,8 @@ fn main() {
}
```
## Compressed server keys
## Compressed server keys
This example shows how to compress the server keys.
```rust
@@ -77,8 +75,8 @@ fn main() {
```
## Compressed public keys
## Compressed public keys
This example shows how to compress the classical public keys.
{% hint style="warning" %}
@@ -108,10 +106,11 @@ fn main() {
}
```
## Compressed compact public key
## Compressed compact public key
This example shows how to use compressed compact public keys.
```rust
use tfhe::prelude::*;
use tfhe::{generate_keys, set_server_key, CompressedCompactPublicKey, ConfigBuilder, FheUint8};

View File

@@ -1,16 +1,21 @@
# Debug
# Debugging FHE Code
Since tfhe-rs 0.5, [trivial ciphertexts](broken-reference) have another application. They can be used to allow debugging via a debugger or print statements as well as speeding-up execution time so that you won't have to spend minutes waiting for execution to progress.
Since tfhe-rs 0.5, [trivial ciphertexts](./trivial_ciphertext.md) have another application.
They can be used to allow debugging via a debugger or print statements as well as speeding-up execution time
so that you won't have to spend minutes waiting for execution to progress.
This can greatly improve the pace at which one develops FHE applications.
{% hint style="warning" %}
Keep in mind that trivial ciphertexts are not secure at all, thus an application released/deployed in production must never receive trivial ciphertext from a client.
Keep in mind that trivial ciphertexts are not secure at all, thus an application released/deployed in production
must never receive trivial ciphertext from a client.
{% endhint %}
## Example
To use this feature, simply call your circuits/functions with trivially encrypted values (made using `encrypt_trivial`) instead of real encryptions (made using `encrypt`)
To use this feature, simply call your circuits/functions with trivially encrypted values (made using `encrypt_trivial`)
instead of real encryptions (made using `encrypt`)
```rust
use tfhe::prelude::*;
@@ -50,17 +55,18 @@ fn main() {
```
This example is going to print.
```
```text
a: Ok(1234), b: Ok(4567), c: Ok(89101112)
a * b = Ok(5635678)
```
If any input to `mul_all` is not a trivial ciphertexts, the computations would be done 100% in FHE, and the program would output:
If any input to `mul_all` is not a trivial ciphertexts, the computations would be done 100% in FHE, and the program
would output:
```
```text
a: Err(NotTrivialCiphertextError), b: Err(NotTrivialCiphertextError), c: Err(NotTrivialCiphertextError)
a * b = Err(NotTrivialCiphertextError)
```
Using trivial encryptions as input, the example runs in **980 ms** on a standard 12 cores laptop, using real encryptions it would run in **7.5 seconds** on a 128-core machine.
Using trivial encryptions as input, the example runs in **980 ms** on a standard 12 cores laptop, using real encryptions
it would run in **7.5 seconds** on a 128-core machine.

View File

@@ -1,3 +1,3 @@
# Migrating Data to TFHE-rs 0.5.2 (This Release)
# Migrating Data to TFHE-rs 0.5.3 (This Release)
Forward compatibility code to migrate data from TFHE-rs 0.4 to TFHE-rs 0.5 has been added in a minor release of TFHE-rs 0.4, the documentation about the process can be found [here](https://docs.zama.ai/tfhe-rs/v/0.4-1/how-to/migrate_data).

View File

@@ -1,11 +1,10 @@
# Use Public Key Encryption
Public key encryption refers to the cryptographic paradigm where the encryption key can be publicly distributed, whereas the decryption key remains secret to the owner. This differs from usual case where the same secret key is used to encrypt and decrypt the data. In TFHE-rs, there exists two methods for public key encryptions. First, the usual one, where the public key contains ma y encryption of zeroes. More details can be found in [Guide to Fully Homomorphic Encryption over the \[Discretized\] Torus, Appendix A.](https://eprint.iacr.org/2021/1402). The second method is based on the paper entitled [TFHE Public-Key Encryption Revisited](https://eprint.iacr.org/2023/603). The main advantage of the latter method in comparison with the former lies into the key sizes, which are drastically reduced.
# Public Key Encryption
Public key encryption refers to the cryptographic paradigm where the encryption key can be publicly distributed, whereas the decryption key remains secret to the owner. This differs from usual case where the same secret key is used to encrypt and decrypt the data. In TFHE-rs, there exists two methods for public key encryptions. First, the usual one, where the public key contains ma y encryption of zeroes. More details can be found in [Guide to Fully Homomorphic Encryption over the [Discretized] Torus, Appendix A.](https://eprint.iacr.org/2021/1402). The second method is based on the paper entitled [TFHE Public-Key Encryption Revisited](https://eprint.iacr.org/2023/603). The main advantage of the latter method in comparison with the former lies into the key sizes, which are drastically reduced.
Note that public keys can be [compressed](../foundamentals/compress.md)
## classical public key
Note that public keys can be [compressed](./compress.md)
## classical public key
This example shows how to use public keys.
```rust
@@ -25,9 +24,9 @@ fn main() {
```
## compact public key
This example shows how to use compact public keys. The main difference is in the ConfigBuilder, where the parameter set has been changed.
```rust
use tfhe::prelude::*;
use tfhe::{ConfigBuilder, generate_keys, set_server_key, FheUint8, CompactPublicKey};

View File

@@ -13,12 +13,12 @@ To use the `TFHE-rs GPU backend` in your project, you first need to add it as a
If you are using an `x86` machine:
```toml
tfhe = { version = "0.5.2", features = [ "boolean", "shortint", "integer", "x86_64-unix", "gpu" ] }
tfhe = { version = "0.5.3", features = [ "boolean", "shortint", "integer", "x86_64-unix", "gpu" ] }
```
If you are using an `ARM` machine:
```toml
tfhe = { version = "0.5.2", features = [ "boolean", "shortint", "integer", "aarch64-unix", "gpu" ] }
tfhe = { version = "0.5.3", features = [ "boolean", "shortint", "integer", "aarch64-unix", "gpu" ] }
```

View File

@@ -1,6 +1,4 @@
# Serialize/Deserialize
## Serialization/Deserialization
# Serialization/Deserialization
As explained in the Introduction, most types are meant to be shared with the server that performs the computations.
@@ -13,7 +11,7 @@ To serialize our data, a [data format](https://serde.rs/#data-formats) should be
[dependencies]
# ...
tfhe = { version = "0.5.2", features = ["integer","x86_64-unix"]}
tfhe = { version = "0.5.3", features = ["integer","x86_64-unix"]}
bincode = "1.3.3"
```
@@ -72,17 +70,25 @@ fn server_function(serialized_data: &[u8]) -> Result<Vec<u8>, Box<dyn std::error
}
```
## Safe Serialization/Deserialization
For some types, safe serialization and deserialization functions are available. Bincode is used internally.
# Safe Serialization/Deserialization
Safe-deserialization must take as input the output of a safe-serialization. On this condition, validation of the following is done:
For some types, safe serialization and deserialization functions are available.
Bincode is used internally.
* type: trying to deserialize `type A` from a serialized `type B` raises an error along the lines of _On deserialization, expected type A, got type B_ instead of a generic deserialization error (or less likely a meaningless result of `type A`)
* version: trying to deserialize `type A` (version 0.2) from a serialized `type A` (incompatible version 0.1) raises an error along the lines of _On deserialization, expected serialization version 0.2, got version 0.1_ instead of a generic deserialization error (or less likely a meaningless result of `type A` (version 0.2))
* parameter compatibility: trying to deserialize into an object of `type A` with some crypto parameters from a an object of `type A` with other crypto parameters raises an error along the lines of _Deserialized object of type A not conformant with given parameter set_. If both parameters sets 1 and 2 have the same lwe dimension for ciphertexts, a ciphertext from param 1 may not fail this deserialization check with param 2 even if doing this deserialization may not make sense. Also, this check can't distinguish ciphertexts/server keys from independant client keys with the same parameters (which makes no sense combining to do homomorphic operations). This check is meant to prevent runtime errors in server homomorphic operations by checking that server keys and ciphertexts are compatible with the same parameter set.
Safe-deserialization must take as input the output of a safe-serialization.
On this condition, validation of the following is done:
- type: trying to deserialize `type A` from a serialized `type B` raises an error along the lines of *On deserialization, expected type A, got type B* instead of a generic deserialization error (or less likely a meaningless result of `type A`)
- version: trying to deserialize `type A` (version 0.2) from a serialized `type A` (incompatible version 0.1) raises an error along the lines of *On deserialization, expected serialization version 0.2, got version 0.1* instead of a generic deserialization error (or less likely a meaningless result of `type A` (version 0.2))
- parameter compatibility: trying to deserialize into an object of `type A` with some crypto parameters from a an object of `type A` with other crypto parameters raises an error along the lines of *Deserialized object of type A not conformant with given parameter set*.
If both parameters sets 1 and 2 have the same lwe dimension for ciphertexts, a ciphertext from param 1 may not fail this deserialization check with param 2 even if doing this deserialization may not make sense.
Also, this check can't distinguish ciphertexts/server keys from independant client keys with the same parameters (which makes no sense combining to do homomorphic operations).
This check is meant to prevent runtime errors in server homomorphic operations by checking that server keys and ciphertexts are compatible with the same parameter set.
Moreover, a size limit (in number of bytes) for the serialized data is expected on both serialization and deserialization. On serialization, an error is raised if the serialized output would be bigger than the given limit. On deserialization, an error is raised if the serialized input is bigger than the given limit. It is meant to gracefully return an error in case of an attacker trying to cause an out of memory error on deserialization.
Moreover, a size limit (in number of bytes) for the serialized data is expected on both serialization and deserialization.
On serialization, an error is raised if the serialized output would be bigger than the given limit.
On deserialization, an error is raised if the serialized input is bigger than the given limit.
It is meant to gracefully return an error in case of an attacker trying to cause an out of memory error on deserialization.
A standalone `is_conformant` method is also available on those types to do a parameter compatibility check.

View File

@@ -1,8 +1,11 @@
# Use Trivial Ciphertext
# Trivial Ciphertext
Sometimes, the server side needs to initialize a value. For example, when computing the sum of a list of ciphertext, one might want to initialize the `sum` variable to `0`.
Sometimes, the server side needs to initialize a value.
For example, when computing the sum of a list of ciphertext,
one might want to initialize the `sum` variable to `0`.
Instead of asking the client to send a real encryption of zero, the server can do a _trivial encryption_
Instead of asking the client to send a real encryption of zero,
the server can do a *trivial encryption*
```rust
use tfhe::prelude::*;
@@ -19,9 +22,13 @@ let clear: u8 = a.decrypt(&client_key);
assert_eq!(clear, 234);
```
A _trivial encryption_ will create a ciphertext that contains the desired value, however, the 'encryption' is trivial that is, it is not really encrypted: anyone, any key can decrypt it.
A *trivial encryption* will create a ciphertext that contains
the desired value, however, the 'encryption' is trivial that is,
it is not really encrypted: anyone, any key can decrypt it.
Note that when you want to do an operation that involves a ciphertext and a clear value, you should only use a trivial encryption of the clear value if the ciphertext/clear-value operation (often called scalar operation) you want to run is not supported.
Note that when you want to do an operation that involves a ciphertext
and a clear value, you should only use a trivial encryption of the clear
value if the ciphertext/clear-value operation (often called scalar operation) you want to run is not supported.
### Example

View File

@@ -1,2 +0,0 @@
# API References

View File

@@ -1,2 +0,0 @@
# Cyrpto Core API

View File

@@ -1,2 +0,0 @@
# Fine-grained APIs

View File

@@ -24,7 +24,7 @@ To use the `FheUint8` type, the `integer` feature must be activated:
[dependencies]
# Default configuration for x86 Unix machines:
tfhe = { version = "0.5.2", features = ["integer", "x86_64-unix"]}
tfhe = { version = "0.5.3", features = ["integer", "x86_64-unix"]}
```
Other configurations can be found [here](../getting_started/installation.md).

View File

@@ -19,7 +19,7 @@ This function returns a Boolean that will be either `true` or `false` so that th
# Cargo.toml
# Default configuration for x86 Unix machines:
tfhe = { version = "0.5.2", features = ["integer", "x86_64-unix"]}
tfhe = { version = "0.5.3", features = ["integer", "x86_64-unix"]}
```
Other configurations can be found [here](../getting_started/installation.md).

View File

@@ -1,13 +0,0 @@
# See all tutorials
### Start here
* [Homomorphic parity bit](parity\_bit.md)
* [Homomorphic case changing on Ascii string ](ascii\_fhe\_string.md)
* [SHA 256 with Boolean API ](sha256\_bool.md)
### Go further
* [\[Video tutorial\] Implement signed integers using TFHE-rs](https://www.youtube.com/watch?v=O0aGj\_xUo40) &#x20;
* [Dark market with integer API](dark\_market.md)
* [Homomorphic regular expressions integer API](regex.md)&#x20;

View File

@@ -211,6 +211,11 @@ impl CompactPublicKey {
self.parameters.ciphertext_modulus(),
);
let encryption_noise = match self.pbs_order {
crate::shortint::PBSOrder::KeyswitchBootstrap => self.parameters.glwe_modular_std_dev(),
crate::shortint::PBSOrder::BootstrapKeyswitch => self.parameters.lwe_modular_std_dev(),
};
// No parallelism allowed
#[cfg(all(feature = "__wasm_api", not(feature = "parallel-wasm-api")))]
{
@@ -220,8 +225,8 @@ impl CompactPublicKey {
&self.key,
&mut ct_list,
&plaintext_list,
self.parameters.glwe_modular_std_dev(),
self.parameters.lwe_modular_std_dev(),
encryption_noise,
encryption_noise,
&mut engine.secret_generator,
&mut engine.encryption_generator,
);
@@ -237,8 +242,8 @@ impl CompactPublicKey {
&self.key,
&mut ct_list,
&plaintext_list,
self.parameters.glwe_modular_std_dev(),
self.parameters.lwe_modular_std_dev(),
encryption_noise,
encryption_noise,
&mut engine.secret_generator,
&mut engine.encryption_generator,
);