mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-11 15:48:20 -05:00
Compare commits
16 Commits
bb/fix/sum
...
0.1.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b772fc29f | ||
|
|
0107efcda4 | ||
|
|
08981bb716 | ||
|
|
76c57c8c3c | ||
|
|
78f94be1a1 | ||
|
|
e2bcad8fe7 | ||
|
|
c39d6ca753 | ||
|
|
1c8f3859dd | ||
|
|
d62bc1cb4c | ||
|
|
7a32e54469 | ||
|
|
8ebbac0dae | ||
|
|
45f503ae56 | ||
|
|
4b1e648848 | ||
|
|
94b9f62c17 | ||
|
|
62f8ecc568 | ||
|
|
aa7129baf1 |
4
.github/workflows/aws_tfhe_tests.yml
vendored
4
.github/workflows/aws_tfhe_tests.yml
vendored
@@ -22,6 +22,9 @@ on:
|
||||
runner_name:
|
||||
description: "Action runner name"
|
||||
type: string
|
||||
request_id:
|
||||
description: 'Slab request ID'
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
shortint-tests:
|
||||
@@ -36,6 +39,7 @@ jobs:
|
||||
echo "ID: ${{ github.event.inputs.instance_id }}"
|
||||
echo "AMI: ${{ github.event.inputs.instance_image_id }}"
|
||||
echo "Type: ${{ github.event.inputs.instance_type }}"
|
||||
echo "Request ID: ${{ github.event.inputs.request_id }}"
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
|
||||
4
.github/workflows/aws_tfhe_tests_w_gpu.yml
vendored
4
.github/workflows/aws_tfhe_tests_w_gpu.yml
vendored
@@ -17,6 +17,9 @@ on:
|
||||
runner_name:
|
||||
description: "Action runner name"
|
||||
type: string
|
||||
request_id:
|
||||
description: 'Slab request ID'
|
||||
type: string
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
@@ -50,6 +53,7 @@ jobs:
|
||||
echo "IDs: ${{ github.event.inputs.instance_id }}"
|
||||
echo "AMI: ${{ github.event.inputs.instance_image_id }}"
|
||||
echo "Type: ${{ github.event.inputs.instance_type }}"
|
||||
echo "Request ID: ${{ github.event.inputs.request_id }}"
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up home
|
||||
run: |
|
||||
|
||||
7
.github/workflows/cargo_build.yml
vendored
7
.github/workflows/cargo_build.yml
vendored
@@ -67,3 +67,10 @@ jobs:
|
||||
- name: Build Release c_api
|
||||
run: |
|
||||
make build_c_api
|
||||
|
||||
- name: wasm API Clippy
|
||||
run: |
|
||||
make clippy_js_wasm_api
|
||||
|
||||
# The wasm build check is a bit annoying to set-up here and is done during the tests in
|
||||
# aws_tfhe_tests.yml
|
||||
|
||||
3
.github/workflows/check_commit.yml
vendored
3
.github/workflows/check_commit.yml
vendored
@@ -2,9 +2,6 @@
|
||||
name: Check commit and PR compliance
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- dev
|
||||
jobs:
|
||||
check-commit-pr:
|
||||
name: Check commit and PR
|
||||
|
||||
61
LICENSE
61
LICENSE
@@ -1,33 +1,28 @@
|
||||
BSD 3-Clause Clear License
|
||||
|
||||
Copyright © 2022 ZAMA.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of ZAMA nor the names of its contributors may be used to endorse
|
||||
or promote products derived from this software without specific prior written permission.
|
||||
|
||||
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE*.
|
||||
THIS SOFTWARE IS PROVIDED BY THE ZAMA AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
ZAMA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*In addition to the rights carried by this license, ZAMA grants to the user a non-exclusive,
|
||||
free and non-commercial license on all patents filed in its name relating to the open-source
|
||||
code (the "Patents") for the sole purpose of evaluation, development, research, prototyping
|
||||
and experimentation.
|
||||
BSD 3-Clause Clear License
|
||||
|
||||
Copyright © 2022 ZAMA.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of ZAMA nor the names of its contributors may be used to endorse
|
||||
or promote products derived from this software without specific prior written permission.
|
||||
|
||||
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
|
||||
THIS SOFTWARE IS PROVIDED BY THE ZAMA AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
ZAMA OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
8
Makefile
8
Makefile
@@ -75,6 +75,12 @@ clippy_cuda: install_rs_check_toolchain
|
||||
--features=$(TARGET_ARCH_FEATURE),cuda,boolean-c-api,shortint-c-api \
|
||||
-p tfhe -- --no-deps -D warnings
|
||||
|
||||
.PHONY: clippy_js_wasm_api # Run clippy lints enabling the boolean, shortint and the js wasm API
|
||||
clippy_js_wasm_api: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo "$(CARGO_RS_CHECK_TOOLCHAIN)" clippy \
|
||||
--features=boolean-client-js-wasm-api,shortint-client-js-wasm-api \
|
||||
-p tfhe -- --no-deps -D warnings
|
||||
|
||||
.PHONY: gen_key_cache # Run the script to generate keys and cache them for shortint tests
|
||||
gen_key_cache: install_rs_build_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) run --release \
|
||||
@@ -98,7 +104,7 @@ build_boolean_and_shortint: install_rs_build_toolchain
|
||||
|
||||
.PHONY: build_c_api # Build the C API for boolean and shortint
|
||||
build_c_api: install_rs_build_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) build --release
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) build --release \
|
||||
--features=$(TARGET_ARCH_FEATURE),boolean-c-api,shortint-c-api -p tfhe
|
||||
|
||||
.PHONY: test_core_crypto # Run the tests of the core_crypto module
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tfhe"
|
||||
version = "0.1.0"
|
||||
version = "0.1.5"
|
||||
edition = "2021"
|
||||
readme = "../README.md"
|
||||
keywords = ["fully", "homomorphic", "encryption", "fhe", "cryptography"]
|
||||
@@ -8,7 +8,7 @@ homepage = "https://zama.ai/"
|
||||
documentation = "https://docs.zama.ai/tfhe-rs"
|
||||
repository = "https://github.com/zama-ai/tfhe-rs"
|
||||
license = "BSD-3-Clause-Clear"
|
||||
description = "Concrete is a fully homomorphic encryption (FHE) library that implements Zama's variant of TFHE."
|
||||
description = "TFHE-rs is a fully homomorphic encryption (FHE) library that implements Zama's variant of TFHE."
|
||||
build = "build.rs"
|
||||
exclude = ["/docs/", "/c_api_tests/", "/CMakeLists.txt"]
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ materials provided with the distribution.
|
||||
|
||||
3. Neither the name of ZAMA nor the names of its contributors may be used to endorse
|
||||
or promote products derived from this software without specific prior written permission.
|
||||
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE*.
|
||||
|
||||
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
|
||||
THIS SOFTWARE IS PROVIDED BY THE ZAMA AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
@@ -25,8 +26,3 @@ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CA
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*In addition to the rights carried by this license, ZAMA grants to the user a non-exclusive,
|
||||
free and non-commercial license on all patents filed in its name relating to the open-source
|
||||
code (the "Patents") for the sole purpose of evaluation, development, research, prototyping
|
||||
and experimentation.
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
# Operations and Examples
|
||||
# Operations
|
||||
|
||||
In thfe::boolean, the available operations are mainly related to their equivalent Boolean gates,
|
||||
i.e., AND, OR,... In what follows, an example of a unary gate (NOT) and one about a binary gate
|
||||
(XOR). The last one is about the ternary MUX gate are detailed, which gives the possibility to
|
||||
homomorphically compute conditional statements of the form ``If..Then..Else``.
|
||||
In thfe::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`.
|
||||
|
||||
## The NOT unary gate
|
||||
|
||||
@@ -26,7 +23,6 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Binary gates
|
||||
|
||||
```rust
|
||||
@@ -49,10 +45,10 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## The MUX ternary gate
|
||||
Let ``ct_1, ct_2, ct_3`` be three Boolean
|
||||
ciphertexts. Then, the MUX gate (abbreviation of MUtipleXer) is equivalent to the operation:
|
||||
|
||||
Let `ct_1, ct_2, ct_3` be three Boolean ciphertexts. Then, the MUX gate (abbreviation of MUtipleXer) is equivalent to the operation:
|
||||
|
||||
```r
|
||||
if ct_1 {
|
||||
return ct_2
|
||||
@@ -61,7 +57,7 @@ if ct_1 {
|
||||
}
|
||||
```
|
||||
|
||||
This example show how to use the MUX ternary gate.
|
||||
This example shows how to use the MUX ternary gate:
|
||||
|
||||
```rust
|
||||
use tfhe::boolean::prelude::*;
|
||||
|
||||
@@ -1,35 +1,27 @@
|
||||
# Cryptographic parameters
|
||||
# Cryptographic Parameters
|
||||
|
||||
## Default parameters
|
||||
|
||||
The TFHE cryptographic scheme relies on a variant of [Regev cryptosystem](https://cims.nyu.edu/~regev/papers/lwesurvey.pdf), and is based on a problem so hard to solve, that is even post-quantum resistant.
|
||||
The TFHE cryptographic scheme relies on a variant of [Regev cryptosystem](https://cims.nyu.edu/\~regev/papers/lwesurvey.pdf), 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 the correctness of the result, and the security of the computation.
|
||||
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 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.
|
||||
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 into this probability error.
|
||||
The default parameter set ensures a probability error of at most $$2^{-40}$$ 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 [TFHE paper](https://eprint.iacr.org/2018/421),
|
||||
namely $$2^{-165}$$, but up to date regarding security requirements.
|
||||
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 $$2^{-40}$$ 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 [TFHE paper](https://eprint.iacr.org/2018/421), namely $$2^{-165}$$, but it is up-to-date regarding security requirements.
|
||||
|
||||
The following array summarizes this:
|
||||
|
||||
| Parameter set | Error probability |
|
||||
|:-------------------:|:-----------------:|
|
||||
| DEFAULT_PARAMETERS | $$ 2^{-40} $$ |
|
||||
| TFHE_LIB_PARAMETERS | $$ 2^{-165} $$ |
|
||||
|
||||
| Parameter set | Error probability |
|
||||
| :-------------------: | :---------------: |
|
||||
| DEFAULT\_PARAMETERS | $$2^{-40}$$ |
|
||||
| TFHE\_LIB\_PARAMETERS | $$2^{-165}$$ |
|
||||
|
||||
## User-defined parameters
|
||||
|
||||
|
||||
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 with an incorrect and/or insecure computation:
|
||||
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:
|
||||
|
||||
```rust
|
||||
|
||||
use tfhe::boolean::prelude::*;
|
||||
|
||||
fn main() {
|
||||
@@ -50,5 +42,3 @@ fn main() {
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
# Tutorial: a first boolean circuit
|
||||
# Tutorial
|
||||
|
||||
This library is meant to be used both on the **server side** and on the **client side**.
|
||||
The usual use case would follow those steps:
|
||||
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:
|
||||
|
||||
1. On the **client side**, generate the `client` and `server keys`.
|
||||
2. Send the `server key` to the **server**.
|
||||
3. 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 `client key`.
|
||||
* 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`.
|
||||
|
||||
## 1. Setup
|
||||
## Setup
|
||||
|
||||
In the first step, the client creates two keys: the `client key` and the `server key`, with the `concrete_boolean::gen_keys` function:
|
||||
|
||||
In the first step, the client creates two keys: the `client key` and the `server key`,
|
||||
with the
|
||||
`concrete_boolean::gen_keys` function:
|
||||
```rust
|
||||
use tfhe::boolean::prelude::*;
|
||||
|
||||
@@ -28,17 +26,11 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
In more details:
|
||||
* 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.
|
||||
|
||||
+ 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 the 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:
|
||||
|
||||
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:
|
||||
```rust
|
||||
use std::fs::File;
|
||||
use std::io::{Write, Read};
|
||||
@@ -80,15 +72,10 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Encrypting Inputs
|
||||
## Encrypting Inputs
|
||||
|
||||
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
|
||||
used:
|
||||
```rust
|
||||
use tfhe::boolean::prelude::*;
|
||||
|
||||
@@ -112,15 +99,10 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
## 2bis. Encrypting Inputs using public key
|
||||
## Encrypting Inputs using a public key
|
||||
|
||||
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 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
|
||||
used:
|
||||
```rust
|
||||
use tfhe::boolean::prelude::*;
|
||||
|
||||
@@ -145,11 +127,9 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
## Executing a Boolean circuit
|
||||
|
||||
## Executing a Boolean Circuit
|
||||
|
||||
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 inputs are on the **server side**, the `server_key` can be used to homomorphically execute the desired Boolean circuit:
|
||||
|
||||
```rust
|
||||
use std::fs::File;
|
||||
@@ -191,8 +171,7 @@ fn main() {
|
||||
|
||||
## Decrypting the output
|
||||
|
||||
Once the encrypted output is on the client side, the `client_key` can be used to
|
||||
decrypt it:
|
||||
Once the encrypted output is on the client side, the `client_key` can be used to decrypt it:
|
||||
|
||||
```rust
|
||||
use std::fs::File;
|
||||
@@ -218,29 +197,3 @@ fn main() {
|
||||
assert_eq!(output, true);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# What is TFHE-rs?
|
||||
|
||||
<mark style="background-color:yellow;">⭐️</mark> [<mark style="background-color:yellow;">Star the repo on Github</mark>](https://github.com/zama-ai/tfhe-rs) <mark style="background-color:yellow;">| 🗣</mark> [<mark style="background-color:yellow;">Community support forum</mark> ](https://community.zama.ai)<mark style="background-color:yellow;">| 📁</mark> [<mark style="background-color:yellow;">Contribute to the project</mark>](https://docs.zama.ai/tfhe-rs/developers/contributing)<mark style="background-color:yellow;"></mark>
|
||||
<mark style="background-color:yellow;">⭐️</mark> [<mark style="background-color:yellow;">Star the repo on Github</mark>](https://github.com/zama-ai/tfhe-rs) <mark style="background-color:yellow;">| 🗣</mark> [<mark style="background-color:yellow;">Community support forum</mark> ](https://community.zama.ai)<mark style="background-color:yellow;">| 📁</mark> [<mark style="background-color:yellow;">Contribute to the project</mark>](https://docs.zama.ai/tfhe-rs/developers/contributing)
|
||||
|
||||

|
||||

|
||||
|
||||
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.
|
||||
|
||||
@@ -10,14 +10,13 @@ TFHE-rs is meant for developers and researchers who want full control over what
|
||||
|
||||
The goal is to have a stable, simple, high-performance, and production-ready library for all the advanced features of TFHE.
|
||||
|
||||
### Key Cryptographic concepts
|
||||
## Key cryptographic concepts
|
||||
|
||||
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.
|
||||
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), an encoded message is called a plaintext and an encrypted plaintext is called a ciphertext.
|
||||
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 in 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\):
|
||||
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]$$
|
||||
@@ -28,9 +27,8 @@ Zama's variant of TFHE is fully homomorphic and deals with fixed-precision numbe
|
||||
Using FHE in a Rust program with TFHE-rs consists in:
|
||||
|
||||
* generating a client key and a server key using secure parameters:
|
||||
* client key encrypts/decrypts data and must be kept secret
|
||||
* server key is used to perform operations on encrypted data and could be
|
||||
public (also called evaluation key)
|
||||
* 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
|
||||
|
||||
BIN
tfhe/docs/_static/ciphertext-representation.png
vendored
Normal file
BIN
tfhe/docs/_static/ciphertext-representation.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
16
tfhe/docs/_static/ciphertext-representation.svg
vendored
16
tfhe/docs/_static/ciphertext-representation.svg
vendored
@@ -1,16 +0,0 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 424 173" width="424" height="173">
|
||||
<!-- svg-source:excalidraw -->
|
||||
|
||||
<defs>
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: "Virgil";
|
||||
src: url("https://excalidraw.com/Virgil.woff2");
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Cascadia";
|
||||
src: url("https://excalidraw.com/Cascadia.woff2");
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g stroke-linecap="round" transform="translate(26 44) rotate(0 194 38.60598503740641)"><path d="M-0.72 -1.78 C148.22 -1.79, 298.89 -0.4, 389.35 -0.66 M0.64 -0.29 C96.57 -1.4, 195.57 -0.99, 387.19 -1.07 M388.14 2.03 C392.43 23.61, 391.39 49, 385.98 75.21 M389.42 -0.67 C389.81 14.73, 390.33 33.43, 388.78 76.49 M387.8 79.39 C277.29 77.61, 166.8 75.17, -1.18 76.59 M387.01 76.05 C246.87 81.15, 103.96 81.92, 0.98 78.37 M-3.84 75.76 C-2.18 57.07, 4.75 34.74, -0.59 -2.81 M1 77.36 C-0.79 48.54, -1.41 22.74, 1.4 1.83" stroke="#364fc7" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(43.27283572239912 63.29950568870447) rotate(0 35.31670822942641 19.35162094763092)"><path d="M0.11 -2.85 C28.93 -4.68, 48.62 2.97, 73.79 0.71 M0.92 1.49 C21.03 0.46, 41.01 -1.23, 70.4 0.64 M70.88 3.15 C68.43 11.93, 69.14 26.71, 68.06 39.17 M69.56 -1.68 C71.59 8.67, 68.48 17.57, 70.35 40.23 M68.74 39.32 C48.28 40.85, 30.28 35.73, -0.92 40.56 M69.59 37.89 C48.04 38.14, 23.44 38.86, -0.31 39.89 M2.24 36.95 C-1.92 26.09, -1.01 13.79, -3.25 -2.11 M0.55 39.03 C1.24 29.93, -1.56 22.42, 0.25 1.64" stroke="#0b7285" stroke-width="1" fill="none"></path></g><g stroke-linecap="round" transform="translate(244.47880299251847 58.546134663341206) rotate(0 77.40648379052368 25.15710723192018)"><path d="M0.5 3.27 C41.25 1.83, 85.12 4.03, 158.28 2.64 M1.74 -0.75 C60.33 -2.64, 122.13 -1.19, 153.85 -0.7 M155.49 -2.28 C158.86 11.5, 154.4 20.06, 153.49 51.17 M153.03 -0.55 C152.94 16.04, 156.21 35.59, 154.41 49.32 M157.56 51.63 C96.68 46.86, 29.51 52.23, -2.5 49.76 M155.17 52.19 C121.59 51.66, 87.99 54.57, -0.92 50.35 M-1.24 51.37 C-0.7 37.8, 0.93 29.69, -2.96 2.02 M-1.48 52.03 C0.44 36.29, -0.71 20.9, 1.27 0.34" stroke="#a61e4d" stroke-width="1" fill="none"></path></g><g transform="translate(249.47880299251847 71.70324189526139) rotate(0 72.40648379052368 12)"><text x="72.40648379052374" y="17" font-family="Virgil, Segoe UI Emoji" font-size="19.30839567747301px" fill="#a61e4d" text-anchor="middle" style="white-space: pre;" direction="ltr">noise</text></g><g stroke-linecap="round" transform="translate(35.610972568578745 52.67581047381532) rotate(0 89.501246882793 30.962593516209466)"><path d="M3.48 2.12 C42.75 -4.16, 86.77 -1.56, 177.5 3.84 M-1.92 1.02 C66.55 2.87, 130.16 1.88, 179.45 -1.63 M179.35 -3.41 C181.95 11.53, 178.24 25.72, 176.46 63.54 M180.52 0.51 C178.89 22.76, 177.57 49.34, 177.3 60.97 M175.68 59.6 C140.66 62.47, 97.79 56.72, 3.94 58.21 M177.14 61.73 C134.25 62.89, 91.18 61.47, 1.89 60.4 M-0.84 60.36 C-0.67 48.08, 3.19 30.78, -2.25 -3.82 M0.14 61.15 C-2.52 41.13, 0.16 19.4, -0.06 -0.75" stroke="#087f5b" stroke-width="1" fill="none"></path></g><g transform="translate(48.27283572239912 70.65112663633539) rotate(0 30.31670822942641 12)"><text x="30.316708229426418" y="17" font-family="Virgil, Segoe UI Emoji" font-size="19.248703637731044px" fill="#087f5b" text-anchor="middle" style="white-space: pre;" direction="ltr">carry</text></g><g stroke-linecap="round" transform="translate(123.17705735660911 63.319201995012975) rotate(0 43.5411471321695 21.286783042394035)"><path d="M3.78 -1.95 C21.85 2.27, 33.36 -1.31, 85.7 0.15 M0.95 -1.99 C30.47 0.73, 63.7 1.15, 87.61 0.81 M83.5 1.56 C89.47 15.22, 83.3 24.69, 84.55 46.54 M85.31 -0.87 C84.54 12.96, 85.46 26.61, 85.69 43.87 M85.54 45.92 C71.62 40.51, 50.01 40.74, -2.16 41.74 M85.45 44.45 C55.35 43.91, 24.36 42.43, 0.99 42.77 M-3.26 44.49 C1.26 31.11, -1.14 19.41, -1.89 2.33 M-1.27 43.89 C-1.22 30.47, 1.35 21.91, -0.8 -1.4" stroke="#0b7285" stroke-width="1" fill="none"></path></g><g transform="translate(128.1770573566091 72.60598503740698) rotate(0 38.5411471321695 12)"><text x="38.54114713216951" y="17" font-family="Virgil, Segoe UI Emoji" font-size="19.27057356608477px" fill="#087f5b" text-anchor="middle" style="white-space: pre;" direction="ltr">message</text></g><g transform="translate(371 138) rotate(0 20 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#364fc7" text-anchor="start" style="white-space: pre;" direction="ltr">LSB</text></g><g transform="translate(10 135) rotate(0 21.5 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#364fc7" text-anchor="start" style="white-space: pre;" direction="ltr">MSB</text></g><g transform="translate(162 10) rotate(0 51 12.5)"><text x="0" y="18" font-family="Virgil, Segoe UI Emoji" font-size="20px" fill="#364fc7" text-anchor="start" style="white-space: pre;" direction="ltr">Ciphertext</text></g></svg>
|
||||
|
Before Width: | Height: | Size: 4.8 KiB |
@@ -1,25 +1,26 @@
|
||||
# Tutorial: using the C API
|
||||
# Tutorial
|
||||
|
||||
## Using the C API
|
||||
|
||||
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.
|
||||
|
||||
# First steps using `TFHE-rs` C API
|
||||
## First steps using `TFHE-rs` C API
|
||||
|
||||
## Setting-up `TFHE-rs` C API for use in a C program.
|
||||
### Setting-up `TFHE-rs` C API for use in a C program.
|
||||
|
||||
`TFHE-rs` C API can be built on a Unix x86_64 machine using the following command:
|
||||
`TFHE-rs` C API can be built on a Unix x86\_64 machine using the following command:
|
||||
|
||||
```shell
|
||||
RUSTFLAGS="-C target-cpu=native" cargo build --release --features=x86_64-unix,boolean-c-api,shortint-c-api -p tfhe
|
||||
```
|
||||
|
||||
All features are opt-in, but for simplicity here, the C API is enabled for booleans and shortints.
|
||||
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 `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.
|
||||
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:
|
||||
|
||||
@@ -51,17 +52,14 @@ endif()
|
||||
target_compile_options(${EXECUTABLE_NAME} PRIVATE -Werror)
|
||||
```
|
||||
|
||||
## Commented code of a PBS doubling a 2 bits encrypted message using `TFHE-rs C API`
|
||||
### Commented code of a PBS doubling a 2 bits encrypted message using `TFHE-rs C API`.
|
||||
|
||||
The steps required to perform the mutiplication 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 allows to show the management required to run a PBS manually using the C API.
|
||||
The steps required to perform the mutiplication 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:
|
||||
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:
|
||||
|
||||
```shell
|
||||
# /!\ Be sure to update CMakeLists.txt to give the absolute path to the compiled tfhe library
|
||||
$ ls
|
||||
@@ -169,6 +167,6 @@ int main(void)
|
||||
}
|
||||
```
|
||||
|
||||
# Audience
|
||||
## Audience
|
||||
|
||||
Programmers wishing to use `TFHE-rs` but 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.
|
||||
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.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Contribute
|
||||
# Contributing
|
||||
|
||||
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!
|
||||
* 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!
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
# Benchmarks
|
||||
|
||||
Due to their nature, homomorphic operations are obviously slower than their clear equivalent. In what follows, some timings are exposed for the basic operations. For completeness, some benchmarks of other libraries are also given.
|
||||
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.
|
||||
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.
|
||||
|
||||
## Booleans
|
||||
|
||||
This measures the execution time of a single binary boolean gate.
|
||||
|
||||
### thfe.rs::booleans
|
||||
### thfe.rs::booleans.
|
||||
|
||||
| Parameter set | concrete-fft | concrete-fft + avx512 |
|
||||
| --- | --- | --- |
|
||||
| DEFAULT_PARAMETERS | 8.8ms | 6.8ms |
|
||||
| TFHE_LIB_PARAMETERS | 13.6ms | 10.9ms |
|
||||
| Parameter set | concrete-fft | concrete-fft + avx512 |
|
||||
| --------------------- | ------------ | --------------------- |
|
||||
| DEFAULT\_PARAMETERS | 8.8ms | 6.8ms |
|
||||
| TFHE\_LIB\_PARAMETERS | 13.6ms | 10.9ms |
|
||||
|
||||
### tfhe-lib
|
||||
### tfhe-lib.
|
||||
|
||||
| Parameter set | fftw | spqlios-fma|
|
||||
| --- | --- | --- |
|
||||
| default_128bit_gate_bootstrapping_parameters | 28.9ms | 15.7ms |
|
||||
| Parameter set | fftw | spqlios-fma |
|
||||
| ------------------------------------------------ | ------ | ----------- |
|
||||
| default\_128bit\_gate\_bootstrapping\_parameters | 28.9ms | 15.7ms |
|
||||
|
||||
### OpenFHE
|
||||
### OpenFHE.
|
||||
|
||||
| Parameter set | GINX | GINX (Intel HEXL) |
|
||||
| --- | --- | --- |
|
||||
| STD_128 | 172ms | 78ms |
|
||||
| MEDIUM | 113ms | 50.2ms |
|
||||
| Parameter set | GINX | GINX (Intel HEXL) |
|
||||
| ------------- | ----- | ----------------- |
|
||||
| STD\_128 | 172ms | 78ms |
|
||||
| MEDIUM | 113ms | 50.2ms |
|
||||
|
||||
## Shortints
|
||||
This measures the execution time for some operations and some parameter sets of shortints.
|
||||
## Shortint
|
||||
|
||||
This measures the execution time for some operations and some parameter sets of shortint.
|
||||
|
||||
### thfe.rs::shortint.
|
||||
|
||||
### thfe.rs::shortint
|
||||
This uses the concrete-fft + avx512 configuration.
|
||||
|
||||
|
||||
| Parameter set | unchecked_add | unchecked_mul_lsb | keyswitch_programmable_bootstrap |
|
||||
| --- | --- | --- | --- |
|
||||
| PARAM_MESSAGE_1_CARRY_1 | 337 ns | 10.1 ms | 9.91 ms |
|
||||
| PARAM_MESSAGE_2_CARRY_2 | 407 ns | 21.7 ms | 21.4 ms |
|
||||
| PARAM_MESSAGE_3_CARRY_3 | 3.06 µs | 161 ms | 159 ms |
|
||||
| PARAM_MESSAGE_4_CARRY_4 | 11.7 µs | 1.03 s | 956 ms |
|
||||
| Parameter set | unchecked\_add | unchecked\_mul\_lsb | keyswitch\_programmable\_bootstrap |
|
||||
| --------------------------- | -------------- | ------------------- | ---------------------------------- |
|
||||
| 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 |
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
To use `TFHE-rs` in your project, you first need to add it as a dependency in your `Cargo.toml`:
|
||||
|
||||
|
||||
```toml
|
||||
tfhe = { version = "0.1.0", features = [ "boolean", "shortint", "x86_64-unix" ] }
|
||||
```
|
||||
@@ -17,36 +16,32 @@ tfhe = { version = "0.1.0", features = [ "boolean", "shortint", "x86_64-unix" ]
|
||||
|
||||
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) |
|
||||
| --------- | ------------- |------------------------------------------|
|
||||
| Booleans | `boolean` | Booleans |
|
||||
| ShortInts | `shortint` | Short unsigned integers |
|
||||
|
||||
| Kind | Features | Type(s) |
|
||||
| --------- | ---------- | ----------------------- |
|
||||
| Booleans | `boolean` | Booleans |
|
||||
| ShortInts | `shortint` | Short unsigned integers |
|
||||
|
||||
### Serialization.
|
||||
|
||||
The different data types and keys exposed by the crate can be serialized / deserialized.
|
||||
|
||||
More information can be found [here](../Booleans/serialization.md) for Booleans and [here](../shortint/serialization.md) for shortint.
|
||||
More information can be found [here](../Booleans/serialization.md) for boolean and [here](../shortint/serialization.md) for shortint.
|
||||
|
||||
## Supported platforms
|
||||
|
||||
TFHE-rs is supported on Linux (x86, aarch64), macOS (x86, aarch64) and Windows (x86 with `RDSEED`
|
||||
instruction).
|
||||
TFHE-rs is supported on Linux (x86, aarch64), macOS (x86, aarch64) and Windows (x86 with `RDSEED` instruction).
|
||||
|
||||
| OS | x86 | aarch64 |
|
||||
| --------- | ------------- |------------------|
|
||||
| Linux | `x86_64-unix` | `aarch64-unix`* |
|
||||
| macOS | `x86_64-unix` | `aarch64-unix`* |
|
||||
| Windows | `x86_64` | Unsupported |
|
||||
| OS | x86 | aarch64 |
|
||||
| ------- | ------------- | ---------------- |
|
||||
| Linux | `x86_64-unix` | `aarch64-unix`\* |
|
||||
| macOS | `x86_64-unix` | `aarch64-unix`\* |
|
||||
| Windows | `x86_64` | Unsupported |
|
||||
|
||||
{% hint style="info" %}
|
||||
Users who have ARM devices can use `TFHE-rs` by compiling using the
|
||||
`nightly` toolchain.
|
||||
Users who have ARM devices can use `TFHE-rs` by compiling using the `nightly` toolchain.
|
||||
{% endhint %}
|
||||
|
||||
|
||||
### Using TFHE-rs with nightly toolchain
|
||||
### Using TFHE-rs with nightly toolchain.
|
||||
|
||||
First, install the needed Rust toolchain:
|
||||
|
||||
|
||||
@@ -2,52 +2,43 @@
|
||||
|
||||
## Boolean
|
||||
|
||||
The list of supported operations by the homomorphic booleans is:
|
||||
|
||||
|Operation Name | type |
|
||||
| ------ | ------ |
|
||||
| `not` | Unary |
|
||||
| `and` | Binary |
|
||||
| `or` | Binary |
|
||||
| `xor` | Binary |
|
||||
| `nor` | Binary |
|
||||
| `xnor` | Binary |
|
||||
| `cmux` | Ternary |
|
||||
The list of supported operations by the homomorphic Booleans is:
|
||||
|
||||
| Operation Name | type |
|
||||
| -------------- | ------- |
|
||||
| `not` | Unary |
|
||||
| `and` | Binary |
|
||||
| `or` | Binary |
|
||||
| `xor` | Binary |
|
||||
| `nor` | Binary |
|
||||
| `xnor` | Binary |
|
||||
| `cmux` | Ternary |
|
||||
|
||||
A walk-through using homomorphic Booleans can be found [here](../Booleans/tutorial.md).
|
||||
|
||||
|
||||
## ShortInt
|
||||
|
||||
In TFHE-rs, the shortints represent short unsigned integers encoded over 8 bits maximum. 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](../shortint/operations.md).
|
||||
|
||||
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](../shortint/operations.md).
|
||||
|
||||
The list of supported operations is:
|
||||
|
||||
| Operation name | Type |
|
||||
|--------------- | ------ |
|
||||
| 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 |
|
||||
| Operation name | Type |
|
||||
| ------------------------- | ------------ |
|
||||
| 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 |
|
||||
|
||||
{% hint style="info" %}
|
||||
\* 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.
|
||||
{% endhint %}
|
||||
|
||||
A walk-through example can be found [here](../shortint/tutorial.md) and more examples and
|
||||
explanations can be found [here](../shortint/operations.md)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
A walk-through example can be found [here](../shortint/tutorial.md), and more examples and explanations can be found [here](../shortint/operations.md).[ ](../shortint/operations.md)
|
||||
|
||||
@@ -1,25 +1,21 @@
|
||||
# Quick start
|
||||
# Quick Start
|
||||
|
||||
This library makes it possible to execute **homomorphic operations over encrypted data**, where the data are either Booleans or short integers (named shortints 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.
|
||||
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 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`.
|
||||
|
||||
## General method to write an homomorphic circuit program
|
||||
|
||||
## General method to write homomorphic circuit program
|
||||
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:
|
||||
|
||||
The overall process to write an homomorphic program is the same for both Boolean and short integers 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
|
||||
* 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
|
||||
|
||||
|
||||
### Boolean example
|
||||
### Boolean example.
|
||||
|
||||
Here is an example to illustrate how the library can be used to evaluate a Boolean circuit:
|
||||
|
||||
@@ -47,9 +43,9 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
### Shortint example
|
||||
### Shortint example.
|
||||
|
||||
and here is a full example using shortints:
|
||||
And here is a full example using shortint:
|
||||
|
||||
```rust
|
||||
use tfhe::shortint::prelude::*;
|
||||
@@ -76,5 +72,4 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
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](https://doi.org/10.1007/s00145-019-09319-x) paper (also available as [ePrint 2018/421](https://ia.cr/2018/421)).
|
||||
|
||||
@@ -1,74 +1,49 @@
|
||||
# Cryptography & Security
|
||||
# Security and Cryptography
|
||||
|
||||
# TFHE
|
||||
## TFHE
|
||||
|
||||
TFHE-rs is a cryptographic library dedicated to Fully Homomorphic Encryption. As its name
|
||||
suggests, it is based on the TFHE scheme.
|
||||
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 apprehend 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).
|
||||
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).
|
||||
|
||||
# LWE Ciphertexts
|
||||
## LWE ciphertexts
|
||||
|
||||
Although there are many kinds of ciphertexts in TFHE,
|
||||
all the encrypted values in TFHE-rs are mainly stored as LWE ciphertexts.
|
||||
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.
|
||||
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-bits or 64-bits unsigned integers.
|
||||
Before encrypting a message in an LWE ciphertext, one needs to first encode it as a plaintext.
|
||||
This is done by shifting the message to the most significant bits of the unsigned integer type used.
|
||||
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.
|
||||
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.
|
||||
|
||||
$$ plaintext = (\Delta * m) + e $$
|
||||
$$plaintext = (\Delta * m) + e$$
|
||||
|
||||

|
||||

|
||||
|
||||
To go from a **plaintext** to a **ciphertext** one needs to encrypt the plaintext using a secret key.
|
||||
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: $$S = (s_0, ..., s_n)$$.
|
||||
$$n$$ is called the $$LweDimension$$
|
||||
An LWE secret key is a list of `n` random integers: $$S = (s_0, ..., s_n)$$. $$n$$ is called the $$LweDimension$$
|
||||
|
||||
A LWE ciphertext, is composed of two parts:
|
||||
- The mask $$(a_0, ..., a_{n-1})$$
|
||||
- The body $$b$$
|
||||
|
||||
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 mask $$(a_0, ..., a_{n-1})$$
|
||||
* The body $$b$$
|
||||
|
||||
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:
|
||||
|
||||
$$ b = (\sum_{i = 0}^{n-1}{a_i * s_i}) + plaintext $$
|
||||
$$b = (\sum_{i = 0}^{n-1}{a_i * s_i}) + plaintext$$
|
||||
|
||||
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.
|
||||
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 done below.
|
||||
To add two ciphertexts, we must add their $mask$ and $body$, as is done below.
|
||||
|
||||
$$
|
||||
ct_0 = (a_{0}, ..., a_{n}, b) \\
|
||||
ct_1 = (a_{1}^{'}, ..., a_{n}^{'}, b^{'}) \\
|
||||
|
||||
ct_{2} = ct_0 + ct_1 \\
|
||||
ct_{2} = (a_{0} + a_{0}^{'}, ..., a_{n} + a_{n}^{'}, b + b^{'})\\
|
||||
|
||||
b + b^{'} = (\sum_{i = 0}^{n-1}{a_i * s_i}) + plaintext + (\sum_{i = 0}^{n-1}{a_i^{'} * s_i}) + plaintext^{'}\\
|
||||
|
||||
b + b^{'} = (\sum_{i = 0}^{n-1}{(a_i + a_i^{'})* s_i}) + \Delta m + \Delta m^{'} + e + e^{'}\\
|
||||
ct_0 = (a_{0}, ..., a_{n}, b) \\ ct_1 = (a_{1}^{'}, ..., a_{n}^{'}, b^{'}) \\ ct_{2} = ct_0 + ct_1 \\ ct_{2} = (a_{0} + a_{0}^{'}, ..., a_{n} + a_{n}^{'}, b + b^{'})\\ b + b^{'} = (\sum_{i = 0}^{n-1}{a_i * s_i}) + plaintext + (\sum_{i = 0}^{n-1}{a_i^{'} * s_i}) + plaintext^{'}\\ b + b^{'} = (\sum_{i = 0}^{n-1}{(a_i + a_i^{'})* s_i}) + \Delta m + \Delta m^{'} + e + e^{'}\\
|
||||
$$
|
||||
|
||||
To add ciphertexts, it is sufficient to add their masks and bodies.
|
||||
Instead of just adding 2 integers, one needs to add $$n + 1$$ 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)
|
||||
|
||||
# Ciphertexts Operations
|
||||
To add ciphertexts, it is sufficient to add their masks and bodies. Instead of just adding 2 integers, one needs to add $$n + 1$$ 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).
|
||||
|
||||
## Understanding noise and padding
|
||||
|
||||
@@ -79,43 +54,40 @@ In FHE, there are two types of operations that can be applied to ciphertexts:
|
||||
|
||||
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 most of the time really fast.
|
||||
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.
|
||||
|
||||
### Noise
|
||||
### Noise.
|
||||
|
||||
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, 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, and thus if too many computations are done, the noise will eventually overflow onto the significant data bits of the message and lead to an incorrect result.
|
||||
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 possibility to automatically manage the noise, by performing bootstrapping operations to reset the noise when needed.
|
||||
TFHE-rs offers the ability to automatically manage noise by performing bootstrapping operations to reset the noise when needed.
|
||||
|
||||
### Padding.
|
||||
|
||||
### Padding
|
||||
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.
|
||||
|
||||
Since encoded values have a fixed precision, operating on them can sometime 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.
|
||||
|
||||
As an example, consider adding two ciphertexts. Adding two values could en up outside the range of either ciphertexts, 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 additional additions would yield correct results.
|
||||
|
||||

|
||||

|
||||
|
||||
If you would like to know more about TFHE, you can find more information in our [TFHE Deep Dive](https://www.zama.ai/post/tfhe-deep-dive-part-1).
|
||||
|
||||
## Security
|
||||
### Security.
|
||||
|
||||
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](https://github.com/malb/lattice-estimator)) with `red_cost_model = reduction.RC.BDGL16`.
|
||||
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](https://github.com/malb/lattice-estimator)) with `red_cost_model = reduction.RC.BDGL16`.
|
||||
|
||||
For all sets of parameters, the error probability when computing a univariate function over one ciphertext is $$2^{-40}$$. Note that univariate functions might be performed when arithmetic functions are computed (for instance, the multiplication of two ciphertexts).
|
||||
|
||||
## Public key encryption
|
||||
### Public key encryption.
|
||||
|
||||
In public key encryption, the public key consists in providing a given number of message encrypting the value 0. By setting the number of encryptions of 0 in the public key at $$m = \lceil (n+1) \log(q) \rceil + \lambda$$, where $$n$$ is the LWE dimension, $$q$$ is the ciphertext modulus and $$\lambda$$ is the number of security bits. In a nutshell, this construction is secure due to the left-over-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)
|
||||
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 $$m = \lceil (n+1) \log(q) \rceil + \lambda$$, where $$n$$ is the LWE dimension, $$q$$ is the ciphertext modulus, and $$\lambda$$ 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).
|
||||
|
||||
@@ -1,54 +1,44 @@
|
||||
# How Shortint are represented
|
||||
# Operations
|
||||
|
||||
## How shortint is represented
|
||||
|
||||
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**.
|
||||
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 computation correctness, 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 resume safely the computations. Therefore, in `shortint` the carry modulus is mainly considered as a means to do more computations.
|
||||
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.
|
||||
|
||||
# Types of operations
|
||||
## Types of operations
|
||||
|
||||
The operations available via a `ServerKey` may come in different variants:
|
||||
|
||||
- operations that take their inputs as encrypted values.
|
||||
- scalar operations take at least one non-encrypted value as input.
|
||||
* 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.
|
||||
* `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 operations 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.
|
||||
* `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.
|
||||
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.
|
||||
|
||||
## How to use operation types
|
||||
|
||||
# How to use operation types
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
```rust
|
||||
use tfhe::shortint::prelude::*;
|
||||
@@ -78,10 +68,9 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
During this computation the carry buffer has been overflowed and as all the operations were `unchecked` the output
|
||||
may be incorrect.
|
||||
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 but using the `checked` flavour, a panic will occur.
|
||||
If we redo this same circuit with the `checked` flavour, a panic will occur.
|
||||
|
||||
```rust
|
||||
use tfhe::shortint::prelude::*;
|
||||
@@ -123,12 +112,9 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
Therefore, the `checked` flavour permits to manually manage the overflow of the carry buffer
|
||||
by raising an error if the correctness is not guaranteed.
|
||||
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.
|
||||
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.
|
||||
|
||||
```rust
|
||||
use tfhe::shortint::prelude::*;
|
||||
@@ -157,61 +143,60 @@ fn main() {
|
||||
assert_eq!(output, ((msg1 * scalar as u64 - msg2) * msg2) % modulus as u64);
|
||||
}
|
||||
```
|
||||
#List of available operations
|
||||
|
||||
\#List of available operations
|
||||
|
||||
{% hint style="warning" %}
|
||||
|
||||
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 or equal than the
|
||||
message buffer. These operations are marked with a star (*).
|
||||
|
||||
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 (\*).
|
||||
{% endhint %}
|
||||
|
||||
The list of implemented operations for shortint is:
|
||||
|
||||
The list of implemented operations for shortints 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` (*)
|
||||
* 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.
|
||||
|
||||
## Public key encryption
|
||||
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`.
|
||||
### Public key encryption.
|
||||
|
||||
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:
|
||||
|
||||
Here a small example on how to use public encryption:
|
||||
```rust
|
||||
use tfhe::boolean::prelude::*;
|
||||
use tfhe::shortint::prelude::*;
|
||||
|
||||
fn main() {
|
||||
// Generate the client key and the server key:
|
||||
let (cks, mut sks) = gen_keys();
|
||||
let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
|
||||
let pks = PublicKey::new(&cks);
|
||||
|
||||
let msg = 2;
|
||||
// Encryption of one message:
|
||||
let ct = pks.encrypt(true);
|
||||
let ct = pks.encrypt(&sks, msg);
|
||||
// Decryption:
|
||||
let dec = cks.decrypt(&ct);
|
||||
assert_eq!(true, dec);
|
||||
assert_eq!(dec, msg);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
In what follows, all examples are related to private key encryption.
|
||||
|
||||
## Arithmetic operations
|
||||
Classical arithmetic operations are supported by shortints:
|
||||
### Arithmetic operations.
|
||||
|
||||
Classical arithmetic operations are supported by shortint:
|
||||
|
||||
```rust
|
||||
use tfhe::shortint::prelude::*;
|
||||
@@ -238,15 +223,13 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Bitwise operations
|
||||
#### bitwise operations
|
||||
|
||||
Short homomorphic integer types support some bitwise operations.
|
||||
|
||||
A simple example on how to use these operations:
|
||||
```rust
|
||||
|
||||
```rust
|
||||
use tfhe::shortint::prelude::*;
|
||||
|
||||
fn main() {
|
||||
@@ -271,14 +254,13 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
### Comparisons
|
||||
#### comparisons
|
||||
|
||||
Short homomorphic integer types support comparison operations.
|
||||
|
||||
A simple example on how to use these operations:
|
||||
|
||||
```rust
|
||||
|
||||
use tfhe::shortint::prelude::*;
|
||||
|
||||
fn main() {
|
||||
@@ -303,14 +285,11 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
### Univariate function evaluations
|
||||
#### univariate function evaluations
|
||||
|
||||
A simple example on how to use this operation to homomorphically compute
|
||||
the hamming weight (i.e., the number of bit equals to one) of an encrypted
|
||||
number.
|
||||
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.
|
||||
|
||||
```rust
|
||||
|
||||
use tfhe::shortint::prelude::*;
|
||||
|
||||
fn main() {
|
||||
@@ -337,17 +316,13 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
### Bi-variate function evaluations
|
||||
#### bi-variate function evaluations
|
||||
|
||||
Using the shortint types offers the possibility to evaluate bi-variate functions, i.e.,
|
||||
functions that takes two ciphertexts as input. This requires to choose 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.
|
||||
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.
|
||||
|
||||
In what follows, a simple code example:
|
||||
Here is a simple code example:
|
||||
|
||||
```rust
|
||||
|
||||
use tfhe::shortint::prelude::*;
|
||||
|
||||
fn main() {
|
||||
@@ -374,5 +349,3 @@ fn main() {
|
||||
assert_eq!(output, (msg1.count_ones() as u64 + msg2.count_ones() as u64) % modulus);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
# Cryptographic parameters
|
||||
|
||||
All parameter sets provides at least 128-bits of security according to the [Lattice-Estimator](https://github.com/malb/lattice-estimator), with an error probability equals to $$2^{-40}$$ when computing a 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).
|
||||
# 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 computing a 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
|
||||
|
||||
`shortint` comes with sets of parameters that permit to use the functionalities of the library securely and efficiently. Each parameter sets is associated to the message and carry precisions. Thus, each key pair is entangled to precision.
|
||||
`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`.
|
||||
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 3 bits i.e., computations are done modulus $$2^3 = 8$$), with 3 bits of carry.
|
||||
|
||||
|
||||
```rust
|
||||
use tfhe::shortint::prelude::*;
|
||||
|
||||
@@ -33,21 +30,19 @@ 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
|
||||
### Generic bi-variate functions.
|
||||
|
||||
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 is not working anymore. Then, many bi-variate operations, such as comparisons cannot be correctly computed anymore. The only exception concerns the multiplication.
|
||||
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.
|
||||
|
||||
### Multiplication
|
||||
### 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](https://en.wikipedia.org/wiki/Multiplication_algorithm#Quarter_square_multiplication). 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.
|
||||
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](https://en.wikipedia.org/wiki/Multiplication\_algorithm#Quarter\_square\_multiplication). 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.
|
||||
|
||||
## User-defined parameter sets
|
||||
|
||||
Beyond the predefined parameter sets, this is possible to define new parameter sets.
|
||||
To do so, it is sufficient to use the function `unsecure_parameters()` or to manually fulfill the
|
||||
`Parameter` structure fields.
|
||||
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:
|
||||
|
||||
@@ -77,12 +72,3 @@ fn main() {
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
# Serialization / Deserialization
|
||||
# Serialization/Deserialization
|
||||
|
||||
As explained in the introduction, some types (`Serverkey`, `Ciphertext`) are meant to be shared with the server that does the computations.
|
||||
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](https://crates.io/crates/serde) framework, serde's Serialize and Deserialize are implemented on tfhe::shortint's types.
|
||||
|
||||
To be able to serialize our data, we need to pick a [data format](https://serde.rs/#data-formats), for our use case, [bincode](https://crates.io/crates/bincode) is a good choice, mainly because it is binary format.
|
||||
The easiest way to send these data to a server is to use the serialization and deserialization features. tfhe::shortint uses the [serde](https://crates.io/crates/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](https://serde.rs/#data-formats). For our use case, [bincode](https://crates.io/crates/bincode) is a good choice, mainly because it is binary format.
|
||||
|
||||
```toml
|
||||
# Cargo.toml
|
||||
@@ -15,7 +14,6 @@ To be able to serialize our data, we need to pick a [data format](https://serde.
|
||||
bincode = "1.3.3"
|
||||
```
|
||||
|
||||
|
||||
```rust
|
||||
// main.rs
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
# Tutorial: Writing an homomorphic circuit using shortints
|
||||
# Tutorial
|
||||
|
||||
# 1. Key Generation
|
||||
## Writing an homomorphic circuit using shortint
|
||||
|
||||
## Key Generation
|
||||
|
||||
`tfhe::shortint` provides 2 key types:
|
||||
- `ClientKey`
|
||||
- `ServerKey`
|
||||
|
||||
* `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.
|
||||
|
||||
@@ -12,7 +15,6 @@ The `ServerKey` is the key that is used to actually do the FHE computations. It
|
||||
|
||||
To reflect that, computation/operation methods are tied to the `ServerKey` type.
|
||||
|
||||
|
||||
```rust
|
||||
use tfhe::shortint::prelude::*;
|
||||
|
||||
@@ -22,8 +24,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
# 2. Encrypting values
|
||||
## Encrypting values
|
||||
|
||||
Once the keys have been generated, the client key is used to encrypt data:
|
||||
|
||||
@@ -43,7 +44,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
# 2 bis. Encrypting values using a public key
|
||||
## Encrypting values using a public key
|
||||
|
||||
Once the keys have been generated, the client key is used to encrypt data:
|
||||
|
||||
@@ -64,11 +65,9 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
## Computing and decrypting
|
||||
|
||||
# 3. Computing and decrypting
|
||||
|
||||
With our `server_key`, and encrypted values, we can now do an addition
|
||||
and then decrypt the result.
|
||||
With our `server_key` and encrypted values, we can now do an addition and then decrypt the result.
|
||||
|
||||
```rust
|
||||
use tfhe::shortint::prelude::*;
|
||||
|
||||
15
tfhe/katex-header.html
Normal file
15
tfhe/katex-header.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.3/dist/katex.min.css" integrity="sha384-KiWOvVjnN8qwAZbuQyWDIbfCLFhLXNETzBQjA/92pIowpC0d2O3nppDGQVgwd2nB" crossorigin="anonymous">
|
||||
<script src="https://cdn.jsdelivr.net/npm/katex@0.15.3/dist/katex.min.js" integrity="sha384-0fdwu/T/EQMsQlrHCCHoH10pkPLlKA1jL5dFyUOvB3lfeT2540/2g6YgSi2BL14p" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/katex@0.15.3/dist/contrib/auto-render.min.js" integrity="sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
renderMathInElement(document.body, {
|
||||
delimiters: [
|
||||
{left: "$$", right: "$$", display: true},
|
||||
{left: "\\(", right: "\\)", display: false},
|
||||
{left: "$", right: "$", display: false},
|
||||
{left: "\\[", right: "\\]", display: true}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -92,8 +92,8 @@ impl BooleanEngine<CudaBootstrapper> {
|
||||
}
|
||||
}
|
||||
|
||||
// We have q = 32 so log2q = 5
|
||||
const LOG2_Q_32: usize = 5;
|
||||
// We have q = 2^32 so log2q = 32
|
||||
const LOG2_Q_32: usize = 32;
|
||||
|
||||
impl<B> BooleanEngine<B> {
|
||||
pub fn create_client_key(&mut self, parameters: BooleanParameters) -> ClientKey {
|
||||
|
||||
@@ -14,6 +14,9 @@ pub struct BooleanClientKey(pub(crate) crate::boolean::client_key::ClientKey);
|
||||
#[wasm_bindgen]
|
||||
pub struct BooleanPublicKey(pub(crate) crate::boolean::public_key::PublicKey);
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct BooleanServerKey(pub(crate) crate::boolean::server_key::ServerKey);
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct Boolean {}
|
||||
|
||||
@@ -57,6 +60,7 @@ impl Boolean {
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new_boolean_parameters(
|
||||
lwe_dimension: usize,
|
||||
glwe_dimension: usize,
|
||||
@@ -117,6 +121,13 @@ impl Boolean {
|
||||
BooleanPublicKey(crate::boolean::public_key::PublicKey::new(&client_key.0))
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn new_server_key(client_key: &BooleanClientKey) -> BooleanServerKey {
|
||||
set_hook(Box::new(console_error_panic_hook::hook));
|
||||
|
||||
BooleanServerKey(crate::boolean::server_key::ServerKey::new(&client_key.0))
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn encrypt(client_key: &BooleanClientKey, message: bool) -> BooleanCiphertext {
|
||||
set_hook(Box::new(console_error_panic_hook::hook));
|
||||
@@ -191,4 +202,19 @@ impl Boolean {
|
||||
.map_err(|e| wasm_bindgen::JsError::new(format!("{:?}", e).as_str()))
|
||||
.map(BooleanPublicKey)
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn serialize_boolean_server_key(server_key: &BooleanServerKey) -> Result<Vec<u8>, JsError> {
|
||||
set_hook(Box::new(console_error_panic_hook::hook));
|
||||
bincode::serialize(&server_key.0)
|
||||
.map_err(|e| wasm_bindgen::JsError::new(format!("{:?}", e).as_str()))
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn deserialize_boolean_server_key(buffer: &[u8]) -> Result<BooleanServerKey, JsError> {
|
||||
set_hook(Box::new(console_error_panic_hook::hook));
|
||||
bincode::deserialize(buffer)
|
||||
.map_err(|e| wasm_bindgen::JsError::new(format!("{:?}", e).as_str()))
|
||||
.map(BooleanServerKey)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ impl Shortint {
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new_shortint_parameters(
|
||||
lwe_dimension: usize,
|
||||
glwe_dimension: usize,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::core_crypto::commons::math::random::Seeder;
|
||||
#[cfg(target_os = "macos")]
|
||||
#[cfg(all(target_os = "macos", not(feature = "__wasm_api")))]
|
||||
use concrete_csprng::seeders::AppleSecureEnclaveSeeder;
|
||||
#[cfg(feature = "seeder_x86_64_rdseed")]
|
||||
use concrete_csprng::seeders::RdseedSeeder;
|
||||
|
||||
@@ -5,8 +5,8 @@ use crate::shortint::ciphertext::Degree;
|
||||
use crate::shortint::parameters::{CarryModulus, MessageModulus};
|
||||
use crate::shortint::{Ciphertext, ClientKey, PublicKey, ServerKey};
|
||||
|
||||
// We have q = 64 so log2q = 6
|
||||
const LOG2_Q_64: usize = 6;
|
||||
// We have q = 2^64 so log2q = 64
|
||||
const LOG2_Q_64: usize = 64;
|
||||
|
||||
impl ShortintEngine {
|
||||
pub(crate) fn new_public_key(&mut self, client_key: &ClientKey) -> EngineResult<PublicKey> {
|
||||
|
||||
Reference in New Issue
Block a user