mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-07 22:04:10 -05:00
Artifact AsiaCrypt 2026: Accelerating TFHE with Sorted-Bootstrapping Techniques.
Co-authored-by: Loris Bergerat <loris.bergerat@zama.ai> Co-authored-by: Arthur Meyre <arthur.meyre@zama.ai> Co-authored-by: Jean-Baptiste Orfila <jb.orfila@zama.ai> Co-authored-by: Adeline Roux Langlois <adeline.roux-langlois@cnrs.fr> Co-authored-by: Samuel Tap <samuel.tap@zama.ai>
This commit is contained in:
40
Makefile
40
Makefile
@@ -967,7 +967,45 @@ bench_pbs128: install_rs_check_toolchain
|
||||
bench_pbs_gpu: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" __TFHE_RS_FAST_BENCH=$(FAST_BENCH) cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
|
||||
--bench pbs-bench \
|
||||
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,gpu,internal-keycache,nightly-avx512 -p $(TFHE_SPEC)
|
||||
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,gpu,internal-keycache,nightly-avx512 -p $(TFHE_SPEC)\
|
||||
|
||||
|
||||
.PHONY: bench_pbs_asiacrypt # Run benchmarks for PBS for asiacrypt artifact
|
||||
bench_pbs_asiacrypt: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS) -A dead_code" cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
|
||||
--bench pbs-bench \
|
||||
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,internal-keycache,nightly-avx512,pbs_asiacrypt -p $(TFHE_SPEC)
|
||||
|
||||
.PHONY: bench_ly # Run benchmarks for LY23 for asiacrypt artifact
|
||||
bench_ly: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS) -A dead_code" cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
|
||||
--bench pbs-bench \
|
||||
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,internal-keycache,nightly-avx512,ly -p $(TFHE_SPEC)
|
||||
|
||||
.PHONY: bench_sorted # Run benchmarks for Sorted PBS for asiacrypt artifact
|
||||
bench_sorted: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS) -A dead_code" cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
|
||||
--bench pbs-bench \
|
||||
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,internal-keycache,nightly-avx512,sorted -p $(TFHE_SPEC)
|
||||
|
||||
.PHONY: bench_cms # Run benchmarks for Sorted PBS with CMS for asiacrypt artifact
|
||||
bench_cms: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS) -A dead_code" cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
|
||||
--bench pbs-bench \
|
||||
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,internal-keycache,nightly-avx512,cms -p $(TFHE_SPEC)
|
||||
|
||||
.PHONY: bench_ly23_parallelized # Run benchmarks for PBS
|
||||
bench_ly23_parallelized: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS) -A dead_code" cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
|
||||
--bench pbs-bench \
|
||||
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,internal-keycache,nightly-avx512,ly23_parallelized -p $(TFHE_SPEC)
|
||||
|
||||
.PHONY: bench_sorted_parallelized # Run benchmarks for PBS
|
||||
bench_sorted_parallelized: install_rs_check_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS) -A dead_code" cargo $(CARGO_RS_CHECK_TOOLCHAIN) bench \
|
||||
--bench pbs-bench \
|
||||
--features=$(TARGET_ARCH_FEATURE),boolean,shortint,internal-keycache,nightly-avx512,sorted_parallelized -p $(TFHE_SPEC)
|
||||
|
||||
|
||||
.PHONY: bench_ks # Run benchmarks for keyswitch
|
||||
bench_ks: install_rs_check_toolchain
|
||||
|
||||
280
README-TFHE-rs.md
Normal file
280
README-TFHE-rs.md
Normal file
@@ -0,0 +1,280 @@
|
||||
<p align="center">
|
||||
<!-- product name logo -->
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/zama-ai/tfhe-rs/assets/157474013/5283e0ba-da1e-43af-9f2a-c5221367a12b">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://github.com/zama-ai/tfhe-rs/assets/157474013/b94a8c96-7595-400b-9311-70765c706955">
|
||||
<img width=600 alt="Zama TFHE-rs">
|
||||
</picture>
|
||||
</p>
|
||||
|
||||
<hr/>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://docs.zama.ai/tfhe-rs"> 📒 Documentation</a> | <a href="https://zama.ai/community"> 💛 Community support</a> | <a href="https://github.com/zama-ai/awesome-zama"> 📚 FHE resources by Zama</a>
|
||||
</p>
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/zama-ai/tfhe-rs/releases"><img src="https://img.shields.io/github/v/release/zama-ai/tfhe-rs?style=flat-square"></a>
|
||||
<a href="LICENSE"><img src="https://img.shields.io/badge/License-BSD--3--Clause--Clear-%23ffb243?style=flat-square"></a>
|
||||
<a href="https://github.com/zama-ai/bounty-program"><img src="https://img.shields.io/badge/Contribute-Zama%20Bounty%20Program-%23ffd208?style=flat-square"></a>
|
||||
</p>
|
||||
|
||||
## About
|
||||
|
||||
### 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** API
|
||||
- a **C** API
|
||||
- and a **client-side WASM** API
|
||||
|
||||
TFHE-rs is designed for developers and researchers who want full control over
|
||||
what they can do with TFHE, while not having to worry about the low-level
|
||||
implementation. The goal is to have a stable, simple, high-performance, and
|
||||
production-ready library for all the advanced features of TFHE.
|
||||
<br></br>
|
||||
|
||||
### Main features
|
||||
|
||||
- **Low-level cryptographic library** that implements Zama’s variant of TFHE, including programmable bootstrapping
|
||||
- **Implementation of the original TFHE boolean API** that can be used as a drop-in replacement for other TFHE libraries
|
||||
- **Short integer API** that enables exact, unbounded FHE integer arithmetics with up to 8 bits of message space
|
||||
- **Size-efficient public key encryption**
|
||||
- **Ciphertext and server key compression** for efficient data transfer
|
||||
- **Full Rust API, C bindings to the Rust High-Level API, and client-side Javascript API using WASM**.
|
||||
|
||||
*Learn more about TFHE-rs features in the [documentation](https://docs.zama.ai/tfhe-rs/readme).*
|
||||
<br></br>
|
||||
|
||||
## Table of Contents
|
||||
- **[Getting started](#getting-started)**
|
||||
- [Cargo.toml configuration](#cargotoml-configuration)
|
||||
- [A simple example](#a-simple-example)
|
||||
- **[Resources](#resources)**
|
||||
- [TFHE deep dive](#tfhe-deep-dive)
|
||||
- [Tutorials](#tutorials)
|
||||
- [Documentation](#documentation)
|
||||
- **[Working with TFHE-rs](#working-with-tfhe-rs)**
|
||||
- [Disclaimers](#disclaimers)
|
||||
- [Citations](#citations)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
- **[Support](#support)**
|
||||
<br></br>
|
||||
|
||||
## Getting started
|
||||
|
||||
### Cargo.toml configuration
|
||||
To use the latest version of `TFHE-rs` in your project, you first need to add it as a dependency in your `Cargo.toml`:
|
||||
|
||||
+ For x86_64-based machines running Unix-like OSes:
|
||||
|
||||
```toml
|
||||
tfhe = { version = "*", features = ["boolean", "shortint", "integer", "x86_64-unix"] }
|
||||
```
|
||||
|
||||
+ For Apple Silicon or aarch64-based machines running Unix-like OSes:
|
||||
|
||||
```toml
|
||||
tfhe = { version = "*", features = ["boolean", "shortint", "integer", "aarch64-unix"] }
|
||||
```
|
||||
|
||||
+ For x86_64-based machines with the [`rdseed instruction`](https://en.wikipedia.org/wiki/RDRAND) running Windows:
|
||||
|
||||
```toml
|
||||
tfhe = { version = "*", features = ["boolean", "shortint", "integer", "x86_64"] }
|
||||
```
|
||||
|
||||
> [!Note]
|
||||
> Note: You need to use a Rust version >= 1.73 to compile TFHE-rs.
|
||||
|
||||
> [!Note]
|
||||
> Note: aarch64-based machines are not yet supported for Windows as it's currently missing an entropy source to be able to seed the [CSPRNGs](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator) used in TFHE-rs.
|
||||
|
||||
<p align="right">
|
||||
<a href="#about" > ↑ Back to top </a>
|
||||
</p>
|
||||
|
||||
### A simple example
|
||||
|
||||
Here is a full example:
|
||||
|
||||
``` rust
|
||||
use tfhe::prelude::*;
|
||||
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint32, FheUint8};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Basic configuration to use homomorphic integers
|
||||
let config = ConfigBuilder::default().build();
|
||||
|
||||
// Key generation
|
||||
let (client_key, server_keys) = generate_keys(config);
|
||||
|
||||
let clear_a = 1344u32;
|
||||
let clear_b = 5u32;
|
||||
let clear_c = 7u8;
|
||||
|
||||
// Encrypting the input data using the (private) client_key
|
||||
// FheUint32: Encrypted equivalent to u32
|
||||
let mut encrypted_a = FheUint32::try_encrypt(clear_a, &client_key)?;
|
||||
let encrypted_b = FheUint32::try_encrypt(clear_b, &client_key)?;
|
||||
|
||||
// FheUint8: Encrypted equivalent to u8
|
||||
let encrypted_c = FheUint8::try_encrypt(clear_c, &client_key)?;
|
||||
|
||||
// On the server side:
|
||||
set_server_key(server_keys);
|
||||
|
||||
// Clear equivalent computations: 1344 * 5 = 6720
|
||||
let encrypted_res_mul = &encrypted_a * &encrypted_b;
|
||||
|
||||
// Clear equivalent computations: 6720 >> 5 = 210
|
||||
encrypted_a = &encrypted_res_mul >> &encrypted_b;
|
||||
|
||||
// Clear equivalent computations: let casted_a = a as u8;
|
||||
let casted_a: FheUint8 = encrypted_a.cast_into();
|
||||
|
||||
// Clear equivalent computations: min(210, 7) = 7
|
||||
let encrypted_res_min = &casted_a.min(&encrypted_c);
|
||||
|
||||
// Operation between clear and encrypted data:
|
||||
// Clear equivalent computations: 7 & 1 = 1
|
||||
let encrypted_res = encrypted_res_min & 1_u8;
|
||||
|
||||
// Decrypting on the client side:
|
||||
let clear_res: u8 = encrypted_res.decrypt(&client_key);
|
||||
assert_eq!(clear_res, 1_u8);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
To run this code, use the following command:
|
||||
<p align="center"> <code> cargo run --release </code> </p>
|
||||
|
||||
> [!Note]
|
||||
> Note that when running code that uses `TFHE-rs`, it is highly recommended
|
||||
to run in release mode with cargo's `--release` flag to have the best performances possible.
|
||||
|
||||
*Find an example with more explanations in [this part of the documentation](https://docs.zama.ai/tfhe-rs/getting-started/quick_start)*
|
||||
|
||||
<p align="right">
|
||||
<a href="#about" > ↑ Back to top </a>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
## Resources
|
||||
|
||||
### TFHE deep dive
|
||||
- [TFHE Deep Dive - Part I - Ciphertext types](https://www.zama.ai/post/tfhe-deep-dive-part-1)
|
||||
- [TFHE Deep Dive - Part II - Encodings and linear leveled operations](https://www.zama.ai/post/tfhe-deep-dive-part-2)
|
||||
- [TFHE Deep Dive - Part III - Key switching and leveled multiplications](https://www.zama.ai/post/tfhe-deep-dive-part-3)
|
||||
- [TFHE Deep Dive - Part IV - Programmable Bootstrapping](https://www.zama.ai/post/tfhe-deep-dive-part-4)
|
||||
<br></br>
|
||||
|
||||
### Tutorials
|
||||
- [[Video tutorial] Implement signed integers using TFHE-rs ](https://www.zama.ai/post/video-tutorial-implement-signed-integers-ssing-tfhe-rs)
|
||||
- [Homomorphic parity bit](https://docs.zama.ai/tfhe-rs/tutorials/parity_bit)
|
||||
- [Homomorphic case changing on Ascii string](https://docs.zama.ai/tfhe-rs/tutorials/ascii_fhe_string)
|
||||
- [Boolean SHA256 with TFHE-rs](https://www.zama.ai/post/boolean-sha256-tfhe-rs)
|
||||
- [Dark market with TFHE-rs](https://www.zama.ai/post/dark-market-tfhe-rs)
|
||||
- [Regular expression engine with TFHE-rs](https://www.zama.ai/post/regex-engine-tfhe-rs)
|
||||
|
||||
*Explore more useful resources in [TFHE-rs tutorials](https://docs.zama.ai/tfhe-rs/tutorials) and [Awesome Zama repo](https://github.com/zama-ai/awesome-zama)*
|
||||
<br></br>
|
||||
### Documentation
|
||||
|
||||
Full, comprehensive documentation is available here: [https://docs.zama.ai/tfhe-rs](https://docs.zama.ai/tfhe-rs).
|
||||
<p align="right">
|
||||
<a href="#about" > ↑ Back to top </a>
|
||||
</p>
|
||||
|
||||
|
||||
## Working with TFHE-rs
|
||||
|
||||
### Disclaimers
|
||||
|
||||
#### Security estimation
|
||||
|
||||
Security estimations are done using the
|
||||
[Lattice Estimator](https://github.com/malb/lattice-estimator)
|
||||
with `red_cost_model = reduction.RC.BDGL16`.
|
||||
|
||||
When a new update is published in the Lattice Estimator, we update parameters accordingly.
|
||||
|
||||
### Security model
|
||||
|
||||
The default parameters for the TFHE-rs library are chosen considering the IND-CPA security model, and are selected with a bootstrapping failure probability fixed at p_error = $2^{-64}$. In particular, it is assumed that the results of decrypted computations are not shared by the secret key owner with any third parties, as such an action can lead to leakage of the secret encryption key. If you are designing an application where decryptions must be shared, you will need to craft custom encryption parameters which are chosen in consideration of the IND-CPA^D security model [1].
|
||||
|
||||
[1] Li, Baiyu, et al. "Securing approximate homomorphic encryption using differential privacy." Annual International Cryptology Conference. Cham: Springer Nature Switzerland, 2022. https://eprint.iacr.org/2022/816.pdf
|
||||
|
||||
#### Side-channel attacks
|
||||
|
||||
Mitigation for side-channel attacks has not yet been implemented in TFHE-rs,
|
||||
and will be released in upcoming versions.
|
||||
<br></br>
|
||||
|
||||
### Citations
|
||||
To cite TFHE-rs in academic papers, please use the following entry:
|
||||
|
||||
```text
|
||||
@Misc{TFHE-rs,
|
||||
title={{TFHE-rs: A Pure Rust Implementation of the TFHE Scheme for Boolean and Integer Arithmetics Over Encrypted Data}},
|
||||
author={Zama},
|
||||
year={2022},
|
||||
note={\url{https://github.com/zama-ai/tfhe-rs}},
|
||||
}
|
||||
```
|
||||
|
||||
### Contributing
|
||||
|
||||
There are two ways to contribute to TFHE-rs:
|
||||
|
||||
- [Open issues](https://github.com/zama-ai/tfhe-rs/issues/new/choose) to report bugs and typos, or to suggest new ideas
|
||||
- Request to become an official contributor by emailing [hello@zama.ai](mailto:hello@zama.ai).
|
||||
|
||||
Becoming an approved contributor involves signing our Contributor License Agreement (CLA). Only approved contributors can send pull requests, so please make sure to get in touch before you do!
|
||||
<br></br>
|
||||
|
||||
### License
|
||||
This software is distributed under the **BSD-3-Clause-Clear** license. Read [this](LICENSE) for more details.
|
||||
|
||||
#### FAQ
|
||||
**Is Zama’s technology free to use?**
|
||||
>Zama’s libraries are free to use under the BSD 3-Clause Clear license only for development, research, prototyping, and experimentation purposes. However, for any commercial use of Zama's open source code, companies must purchase Zama’s commercial patent license.
|
||||
>
|
||||
>Everything we do is open source and we are very transparent on what it means for our users, you can read more about how we monetize our open source products at Zama in [this blogpost](https://www.zama.ai/post/open-source).
|
||||
|
||||
**What do I need to do if I want to use Zama’s technology for commercial purposes?**
|
||||
>To commercially use Zama’s technology you need to be granted Zama’s patent license. Please contact us hello@zama.ai for more information.
|
||||
|
||||
**Do you file IP on your technology?**
|
||||
>Yes, all Zama’s technologies are patented.
|
||||
|
||||
**Can you customize a solution for my specific use case?**
|
||||
>We are open to collaborating and advancing the FHE space with our partners. If you have specific needs, please email us at hello@zama.ai.
|
||||
|
||||
<p align="right">
|
||||
<a href="#about" > ↑ Back to top </a>
|
||||
</p>
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
<a target="_blank" href="https://community.zama.ai">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/zama-ai/tfhe-rs/assets/157474013/08656d0a-3f44-4126-b8b6-8c601dff5380">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://github.com/zama-ai/tfhe-rs/assets/157474013/1c9c9308-50ac-4aab-a4b9-469bb8c536a4">
|
||||
<img alt="Support">
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
🌟 If you find this project helpful or interesting, please consider giving it a star on GitHub! Your support helps to grow the community and motivates further development.
|
||||
|
||||
<p align="right">
|
||||
<a href="#about" > ↑ Back to top </a>
|
||||
</p>
|
||||
330
README.md
330
README.md
@@ -1,280 +1,114 @@
|
||||
<p align="center">
|
||||
<!-- product name logo -->
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/zama-ai/tfhe-rs/assets/157474013/5283e0ba-da1e-43af-9f2a-c5221367a12b">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://github.com/zama-ai/tfhe-rs/assets/157474013/b94a8c96-7595-400b-9311-70765c706955">
|
||||
<img width=600 alt="Zama TFHE-rs">
|
||||
</picture>
|
||||
</p>
|
||||
|
||||
<hr/>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://docs.zama.ai/tfhe-rs"> 📒 Documentation</a> | <a href="https://zama.ai/community"> 💛 Community support</a> | <a href="https://github.com/zama-ai/awesome-zama"> 📚 FHE resources by Zama</a>
|
||||
</p>
|
||||
# Artifact: Accelerating TFHE with Sorted-Bootstrapping Techniques
|
||||
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/zama-ai/tfhe-rs/releases"><img src="https://img.shields.io/github/v/release/zama-ai/tfhe-rs?style=flat-square"></a>
|
||||
<a href="LICENSE"><img src="https://img.shields.io/badge/License-BSD--3--Clause--Clear-%23ffb243?style=flat-square"></a>
|
||||
<a href="https://github.com/zama-ai/bounty-program"><img src="https://img.shields.io/badge/Contribute-Zama%20Bounty%20Program-%23ffd208?style=flat-square"></a>
|
||||
</p>
|
||||
## Description
|
||||
|
||||
## About
|
||||
In what follows, we provide instructions on how to run the benchmarks given in **Table 3** (page 29), from the paper titled **Accelerating TFHE with Sorted Bootstrapping Techniques**.
|
||||
The implementation of the techniques described in the aforementioned paper has been integrated into the **TFHE-rs** library, version `0.8.0-alpha.2`.
|
||||
The code related to the extended PBS (EBS), the sorted PBS (SBS) and the version with the companion modulus switch are located in ```tfhe/src/core_crypto/fft_impl/fft64/crypto/bootstrap.rs```.
|
||||
All the benchmarks can be found in ```tfhe/benches/core_crypto/pbs_bench.rs```.
|
||||
|
||||
### What is TFHE-rs
|
||||
|
||||
**TFHE-rs** is a pure Rust implementation of TFHE for boolean and integer arithmetics over encrypted data.
|
||||
## Setup and Dependencies
|
||||
|
||||
It includes:
|
||||
- a **Rust** API
|
||||
- a **C** API
|
||||
- and a **client-side WASM** API
|
||||
Tested on Linux and macOS with Rust version ≥ 1.85 (we recommend installing Rust via [rustup](https://www.rust-lang.org/tools/install), as rustup is required later by the provided Makefile).
|
||||
The complete list of dependencies and a guide on how to install TFHE-rs can be found in the online documentation [here](https://docs.zama.ai/tfhe-rs/0.8) or in the local file [here](./README-TFHE-rs.md).
|
||||
|
||||
TFHE-rs is designed for developers and researchers who want full control over
|
||||
what they can do with TFHE, while not having to worry about the low-level
|
||||
implementation. The goal is to have a stable, simple, high-performance, and
|
||||
production-ready library for all the advanced features of TFHE.
|
||||
<br></br>
|
||||
## How to run benchmarks
|
||||
The benchmarks run across all precision and all failure probabilities, progressing from lower precision (4 bits) to higher precision (9 bits) and from higher failure probabilities ($2^{-64}$) to the lower failure probabilities ($2^{-128}$).
|
||||
All the following benchmarks are **sequential**.
|
||||
At the root of the project (i.e., in the TFHE-rs folder), enter the following commands to run the different benchmarks:
|
||||
|
||||
### Main features
|
||||
- ```make bench_ly```: returns the timings associated with the extended PBS (EBS[LY23] in **Table 3**).
|
||||
- ```make bench_sorted```: returns the timings associated with the sorted PBS (SBS in **Table 3**).
|
||||
- ```make bench_cms```: returns the timings associated with the SBS with the companion modulus switch (cms) (SBS + CMS in **Table 3**).
|
||||
|
||||
- **Low-level cryptographic library** that implements Zama’s variant of TFHE, including programmable bootstrapping
|
||||
- **Implementation of the original TFHE boolean API** that can be used as a drop-in replacement for other TFHE libraries
|
||||
- **Short integer API** that enables exact, unbounded FHE integer arithmetics with up to 8 bits of message space
|
||||
- **Size-efficient public key encryption**
|
||||
- **Ciphertext and server key compression** for efficient data transfer
|
||||
- **Full Rust API, C bindings to the Rust High-Level API, and client-side Javascript API using WASM**.
|
||||
|
||||
*Learn more about TFHE-rs features in the [documentation](https://docs.zama.ai/tfhe-rs/readme).*
|
||||
<br></br>
|
||||
To modify the performed benchmarks, only a few lines need to be commented and modified in ```tfhe/benches/core_crypto/pbs_bench.rs```.
|
||||
To focus only on specific benchmarks, you only need to keep the wanted precision and failure probabilities and adjust the number of tests with ```[ParametersLY23; X]```, where `X` must be equal to the number of uncommented parameters.
|
||||
|
||||
## Table of Contents
|
||||
- **[Getting started](#getting-started)**
|
||||
- [Cargo.toml configuration](#cargotoml-configuration)
|
||||
- [A simple example](#a-simple-example)
|
||||
- **[Resources](#resources)**
|
||||
- [TFHE deep dive](#tfhe-deep-dive)
|
||||
- [Tutorials](#tutorials)
|
||||
- [Documentation](#documentation)
|
||||
- **[Working with TFHE-rs](#working-with-tfhe-rs)**
|
||||
- [Disclaimers](#disclaimers)
|
||||
- [Citations](#citations)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
- **[Support](#support)**
|
||||
<br></br>
|
||||
All parameter sets follow a syntax of the form: ```{Name}_{Precision}_{-Log2(pfail)}```.
|
||||
For instance, ```LY_5_64``` means that the parameter set is associated to the algorithm referred as *LY* in the paper, with *5* bits of precision for input message and $2^{-64}$ as failure probability.
|
||||
|
||||
## Getting started
|
||||
For the EBS and the SBS, you need to modify lines 1502 to 1507 and lines 1612 to 1616 for the SBS with CMS.
|
||||
For instance, changing lines 1502 to 1507:
|
||||
```rust
|
||||
const PARAM_BENCHES_LY23: [ParametersLY23; 16] = [
|
||||
//LY_5_40, LY_6_40, LY_7_40, LY_8_40, LY_9_40
|
||||
LY_5_64, LY_6_64, LY_7_64, LY_8_64, LY_9_64,
|
||||
LY_5_80, LY_6_80, LY_7_81, LY_8_81, LY_9_81,
|
||||
LY_4_128, LY_5_128, LY_6_129, LY_7_128, LY_8_128, LY_9_129,
|
||||
];
|
||||
```
|
||||
into:
|
||||
```rust
|
||||
const PARAM_BENCHES_LY23: [ParametersLY23; 6] = [
|
||||
//LY_5_40, LY_6_40, LY_7_40, LY_8_40, LY_9_40,
|
||||
//LY_5_64, LY_6_64, LY_7_64, LY_8_64, LY_9_64,
|
||||
//LY_5_80, LY_6_80, LY_7_81, LY_8_81, LY_9_81,
|
||||
LY_4_128, LY_5_128, LY_6_129, LY_7_128, LY_8_128, LY_9_129,
|
||||
];
|
||||
```
|
||||
and using the command ```make bench_ly``` launches only benchmarks for the EBS experiment with a failure probability of $2^{-128}$.
|
||||
|
||||
### Cargo.toml configuration
|
||||
To use the latest version of `TFHE-rs` in your project, you first need to add it as a dependency in your `Cargo.toml`:
|
||||
|
||||
+ For x86_64-based machines running Unix-like OSes:
|
||||
### Sample Output Structure
|
||||
|
||||
```toml
|
||||
tfhe = { version = "*", features = ["boolean", "shortint", "integer", "x86_64-unix"] }
|
||||
A typical benchmark result looks like this:
|
||||
|
||||
```
|
||||
KS_Extended_PBS_LY23/PRECISION_6_BITS__EXTENDED_FACTOR_2^2__PFAIL_2^-64
|
||||
time: [123.38 ms 123.46 ms 123.55 ms]
|
||||
Found 19 outliers among 500 measurements (3.80%)
|
||||
```
|
||||
|
||||
+ For Apple Silicon or aarch64-based machines running Unix-like OSes:
|
||||
The first line indicates the operation whose latency is measured.
|
||||
|
||||
```toml
|
||||
tfhe = { version = "*", features = ["boolean", "shortint", "integer", "aarch64-unix"] }
|
||||
**Examples:**
|
||||
```
|
||||
|
||||
+ For x86_64-based machines with the [`rdseed instruction`](https://en.wikipedia.org/wiki/RDRAND) running Windows:
|
||||
|
||||
```toml
|
||||
tfhe = { version = "*", features = ["boolean", "shortint", "integer", "x86_64"] }
|
||||
KS_Extended_PBS_LY23/PRECISION_6_BITS__EXTENDED_FACTOR_2^2__PFAIL_2^-64
|
||||
```
|
||||
means that this benchmark is measuring the latency of a Keyswitch (KS) followed by an Extended Bootstrapping (EBS [LY23]) with 6 bits of message, an extended factor equal to $2^2$, and a failure probability pfail $=2^{-64}$.
|
||||
|
||||
> [!Note]
|
||||
> Note: You need to use a Rust version >= 1.73 to compile TFHE-rs.
|
||||
#### Understanding Benchmark Output (Criterion.rs)
|
||||
This project uses Criterion.rs for benchmarking. Criterion is a powerful and statistically robust benchmarking framework for Rust, and it may produce outputs that are unfamiliar at first glance. Here is a short explanation:
|
||||
|
||||
> [!Note]
|
||||
> Note: aarch64-based machines are not yet supported for Windows as it's currently missing an entropy source to be able to seed the [CSPRNGs](https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator) used in TFHE-rs.
|
||||
|
||||
<p align="right">
|
||||
<a href="#about" > ↑ Back to top </a>
|
||||
</p>
|
||||
|
||||
### A simple example
|
||||
|
||||
Here is a full example:
|
||||
|
||||
``` rust
|
||||
use tfhe::prelude::*;
|
||||
use tfhe::{generate_keys, set_server_key, ConfigBuilder, FheUint32, FheUint8};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Basic configuration to use homomorphic integers
|
||||
let config = ConfigBuilder::default().build();
|
||||
|
||||
// Key generation
|
||||
let (client_key, server_keys) = generate_keys(config);
|
||||
|
||||
let clear_a = 1344u32;
|
||||
let clear_b = 5u32;
|
||||
let clear_c = 7u8;
|
||||
|
||||
// Encrypting the input data using the (private) client_key
|
||||
// FheUint32: Encrypted equivalent to u32
|
||||
let mut encrypted_a = FheUint32::try_encrypt(clear_a, &client_key)?;
|
||||
let encrypted_b = FheUint32::try_encrypt(clear_b, &client_key)?;
|
||||
|
||||
// FheUint8: Encrypted equivalent to u8
|
||||
let encrypted_c = FheUint8::try_encrypt(clear_c, &client_key)?;
|
||||
|
||||
// On the server side:
|
||||
set_server_key(server_keys);
|
||||
|
||||
// Clear equivalent computations: 1344 * 5 = 6720
|
||||
let encrypted_res_mul = &encrypted_a * &encrypted_b;
|
||||
|
||||
// Clear equivalent computations: 6720 >> 5 = 210
|
||||
encrypted_a = &encrypted_res_mul >> &encrypted_b;
|
||||
|
||||
// Clear equivalent computations: let casted_a = a as u8;
|
||||
let casted_a: FheUint8 = encrypted_a.cast_into();
|
||||
|
||||
// Clear equivalent computations: min(210, 7) = 7
|
||||
let encrypted_res_min = &casted_a.min(&encrypted_c);
|
||||
|
||||
// Operation between clear and encrypted data:
|
||||
// Clear equivalent computations: 7 & 1 = 1
|
||||
let encrypted_res = encrypted_res_min & 1_u8;
|
||||
|
||||
// Decrypting on the client side:
|
||||
let clear_res: u8 = encrypted_res.decrypt(&client_key);
|
||||
assert_eq!(clear_res, 1_u8);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
To run this code, use the following command:
|
||||
<p align="center"> <code> cargo run --release </code> </p>
|
||||
|
||||
> [!Note]
|
||||
> Note that when running code that uses `TFHE-rs`, it is highly recommended
|
||||
to run in release mode with cargo's `--release` flag to have the best performances possible.
|
||||
|
||||
*Find an example with more explanations in [this part of the documentation](https://docs.zama.ai/tfhe-rs/getting-started/quick_start)*
|
||||
|
||||
<p align="right">
|
||||
<a href="#about" > ↑ Back to top </a>
|
||||
</p>
|
||||
time: [low est. median high est.]: The estimated execution time of the function.
|
||||
change: The performance change compared to a previous run (if available).
|
||||
outliers: Some runs deviated from the typical time. Criterion detects and accounts for these using statistical methods.
|
||||
|
||||
|
||||
#### Common Warnings and What They Mean
|
||||
##### `Found X outliers among Y measurements`
|
||||
Criterion runs each benchmark many times (default: 100) to get statistically significant results.
|
||||
An *outlier* is a run that was significantly faster or slower than the others.
|
||||
|
||||
## Resources
|
||||
- **Why does this happen?** Often, it's due to **other processes on the machine** (e.g., background services, OS interrupts, or CPU scheduling) affecting performance temporarily.
|
||||
- **Why it doesn't invalidate results:** Criterion uses statistical techniques to minimize the impact of these outliers when estimating performance.
|
||||
- **Best practice to reduce outliers:** Run the benchmarks on a **freshly rebooted machine**, with as few background processes as possible. Ideally, let the system idle for a minute after boot to stabilize before running benchmarks.
|
||||
|
||||
### TFHE deep dive
|
||||
- [TFHE Deep Dive - Part I - Ciphertext types](https://www.zama.ai/post/tfhe-deep-dive-part-1)
|
||||
- [TFHE Deep Dive - Part II - Encodings and linear leveled operations](https://www.zama.ai/post/tfhe-deep-dive-part-2)
|
||||
- [TFHE Deep Dive - Part III - Key switching and leveled multiplications](https://www.zama.ai/post/tfhe-deep-dive-part-3)
|
||||
- [TFHE Deep Dive - Part IV - Programmable Bootstrapping](https://www.zama.ai/post/tfhe-deep-dive-part-4)
|
||||
<br></br>
|
||||
##### `Unable to complete 100 samples in 5.0s.`
|
||||
The benchmark took longer than the expected 5 seconds.
|
||||
This is merely a warning indicating that the full set of 100 samples could not be collected within the default 5-second measurement window.
|
||||
|
||||
### Tutorials
|
||||
- [[Video tutorial] Implement signed integers using TFHE-rs ](https://www.zama.ai/post/video-tutorial-implement-signed-integers-ssing-tfhe-rs)
|
||||
- [Homomorphic parity bit](https://docs.zama.ai/tfhe-rs/tutorials/parity_bit)
|
||||
- [Homomorphic case changing on Ascii string](https://docs.zama.ai/tfhe-rs/tutorials/ascii_fhe_string)
|
||||
- [Boolean SHA256 with TFHE-rs](https://www.zama.ai/post/boolean-sha256-tfhe-rs)
|
||||
- [Dark market with TFHE-rs](https://www.zama.ai/post/dark-market-tfhe-rs)
|
||||
- [Regular expression engine with TFHE-rs](https://www.zama.ai/post/regex-engine-tfhe-rs)
|
||||
- **No action is required**: Criterion will still proceed to run all 100 samples, and the results remain statistically valid.
|
||||
- **Why the warning appears**: It's there to inform you that benchmarking is taking longer than expected and to help you tune settings if needed.
|
||||
- **Optional**: If you're constrained by time (e.g., running in CI), you can:
|
||||
- Reduce the sample size (e.g., to 10 or 20 samples).
|
||||
- Or increase the measurement time using:
|
||||
```bash
|
||||
cargo bench -- --measurement-time 30
|
||||
```
|
||||
|
||||
*Explore more useful resources in [TFHE-rs tutorials](https://docs.zama.ai/tfhe-rs/tutorials) and [Awesome Zama repo](https://github.com/zama-ai/awesome-zama)*
|
||||
<br></br>
|
||||
### Documentation
|
||||
## Other Experiments (See long-paper version)
|
||||
This section explains how to run more benchmarks related to the paper results appearing in the long version.
|
||||
At the root of the project, run:
|
||||
|
||||
Full, comprehensive documentation is available here: [https://docs.zama.ai/tfhe-rs](https://docs.zama.ai/tfhe-rs).
|
||||
<p align="right">
|
||||
<a href="#about" > ↑ Back to top </a>
|
||||
</p>
|
||||
- ```make bench_pbs_asiacrypt```: returns the timings associated to the vanilla PBS. Can be used as another baseline comparison to see the impact of the EBS, SBS and SBS+CMS.
|
||||
|
||||
- ```make bench_ly23_parallelized```: returns the timings associated to the parallelized version of the extended PBS (EBS) from LY.
|
||||
- ```make bench_sorted_parallelized```: returns the timings associated to the parallelized sorted PBS (SBS).
|
||||
|
||||
## Working with TFHE-rs
|
||||
These benchmarks can be used to see the impact of the sorted PBS in a parallelized context.
|
||||
|
||||
### Disclaimers
|
||||
|
||||
#### Security estimation
|
||||
|
||||
Security estimations are done using the
|
||||
[Lattice Estimator](https://github.com/malb/lattice-estimator)
|
||||
with `red_cost_model = reduction.RC.BDGL16`.
|
||||
|
||||
When a new update is published in the Lattice Estimator, we update parameters accordingly.
|
||||
|
||||
### Security model
|
||||
|
||||
The default parameters for the TFHE-rs library are chosen considering the IND-CPA security model, and are selected with a bootstrapping failure probability fixed at p_error = $2^{-64}$. In particular, it is assumed that the results of decrypted computations are not shared by the secret key owner with any third parties, as such an action can lead to leakage of the secret encryption key. If you are designing an application where decryptions must be shared, you will need to craft custom encryption parameters which are chosen in consideration of the IND-CPA^D security model [1].
|
||||
|
||||
[1] Li, Baiyu, et al. "Securing approximate homomorphic encryption using differential privacy." Annual International Cryptology Conference. Cham: Springer Nature Switzerland, 2022. https://eprint.iacr.org/2022/816.pdf
|
||||
|
||||
#### Side-channel attacks
|
||||
|
||||
Mitigation for side-channel attacks has not yet been implemented in TFHE-rs,
|
||||
and will be released in upcoming versions.
|
||||
<br></br>
|
||||
|
||||
### Citations
|
||||
To cite TFHE-rs in academic papers, please use the following entry:
|
||||
|
||||
```text
|
||||
@Misc{TFHE-rs,
|
||||
title={{TFHE-rs: A Pure Rust Implementation of the TFHE Scheme for Boolean and Integer Arithmetics Over Encrypted Data}},
|
||||
author={Zama},
|
||||
year={2022},
|
||||
note={\url{https://github.com/zama-ai/tfhe-rs}},
|
||||
}
|
||||
```
|
||||
|
||||
### Contributing
|
||||
|
||||
There are two ways to contribute to TFHE-rs:
|
||||
|
||||
- [Open issues](https://github.com/zama-ai/tfhe-rs/issues/new/choose) to report bugs and typos, or to suggest new ideas
|
||||
- Request to become an official contributor by emailing [hello@zama.ai](mailto:hello@zama.ai).
|
||||
|
||||
Becoming an approved contributor involves signing our Contributor License Agreement (CLA). Only approved contributors can send pull requests, so please make sure to get in touch before you do!
|
||||
<br></br>
|
||||
|
||||
### License
|
||||
This software is distributed under the **BSD-3-Clause-Clear** license. Read [this](LICENSE) for more details.
|
||||
|
||||
#### FAQ
|
||||
**Is Zama’s technology free to use?**
|
||||
>Zama’s libraries are free to use under the BSD 3-Clause Clear license only for development, research, prototyping, and experimentation purposes. However, for any commercial use of Zama's open source code, companies must purchase Zama’s commercial patent license.
|
||||
>
|
||||
>Everything we do is open source and we are very transparent on what it means for our users, you can read more about how we monetize our open source products at Zama in [this blogpost](https://www.zama.ai/post/open-source).
|
||||
|
||||
**What do I need to do if I want to use Zama’s technology for commercial purposes?**
|
||||
>To commercially use Zama’s technology you need to be granted Zama’s patent license. Please contact us hello@zama.ai for more information.
|
||||
|
||||
**Do you file IP on your technology?**
|
||||
>Yes, all Zama’s technologies are patented.
|
||||
|
||||
**Can you customize a solution for my specific use case?**
|
||||
>We are open to collaborating and advancing the FHE space with our partners. If you have specific needs, please email us at hello@zama.ai.
|
||||
|
||||
<p align="right">
|
||||
<a href="#about" > ↑ Back to top </a>
|
||||
</p>
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
<a target="_blank" href="https://community.zama.ai">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/zama-ai/tfhe-rs/assets/157474013/08656d0a-3f44-4126-b8b6-8c601dff5380">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://github.com/zama-ai/tfhe-rs/assets/157474013/1c9c9308-50ac-4aab-a4b9-469bb8c536a4">
|
||||
<img alt="Support">
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
🌟 If you find this project helpful or interesting, please consider giving it a star on GitHub! Your support helps to grow the community and motivates further development.
|
||||
|
||||
<p align="right">
|
||||
<a href="#about" > ↑ Back to top </a>
|
||||
</p>
|
||||
As with the previous benchmarks, the launched experiment can be modified to only be performed on the wanted precision and failure probabilities by changing lines 1619 to 1628 for the PBS and lines 1630 to 1663 for the parallelized version.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
#![allow(deprecated)]
|
||||
//! Cryptographically secure pseudo random number generator.
|
||||
//!
|
||||
//! Welcome to the `concrete-csprng` documentation.
|
||||
|
||||
@@ -64,7 +64,7 @@ rayon = { version = "1.5.0" }
|
||||
bincode = "1.3.3"
|
||||
concrete-fft = { version = "0.4.1", features = ["serde", "fft128"] }
|
||||
concrete-ntt = { version = "0.1.2" }
|
||||
pulp = "0.18.8"
|
||||
pulp = "=0.18.21"
|
||||
tfhe-cuda-backend = { version = "0.4.0-alpha.0", path = "../backends/tfhe-cuda-backend", optional = true }
|
||||
aligned-vec = { version = "0.5", features = ["serde"] }
|
||||
dyn-stack = { version = "0.9" }
|
||||
@@ -97,6 +97,14 @@ internal-keycache = ["dep:lazy_static", "dep:fs2"]
|
||||
gpu = ["dep:tfhe-cuda-backend"]
|
||||
zk-pok = ["dep:tfhe-zk-pok"]
|
||||
|
||||
ly = []
|
||||
sorted = []
|
||||
cms = []
|
||||
ly23_parallelized = []
|
||||
sorted_parallelized = []
|
||||
pbs_asiacrypt = []
|
||||
|
||||
|
||||
pbs-stats = []
|
||||
|
||||
# Experimental section
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
266
tfhe/examples/ly23_perf.rs
Normal file
266
tfhe/examples/ly23_perf.rs
Normal file
@@ -0,0 +1,266 @@
|
||||
#![allow(dead_code)]
|
||||
use tfhe::core_crypto::prelude::*;
|
||||
use tfhe::shortint::parameters::*;
|
||||
|
||||
////////LY23///////////
|
||||
struct ParametersLY23 {
|
||||
param: ClassicPBSParameters,
|
||||
log_extension_factor: u64,
|
||||
}
|
||||
|
||||
const LY23_1: ParametersLY23 = ParametersLY23 {
|
||||
param: PARAM_MESSAGE_1_CARRY_0_LY23_EXT_FACT_0_64,
|
||||
log_extension_factor: 0,
|
||||
};
|
||||
|
||||
const LY23_2: ParametersLY23 = ParametersLY23 {
|
||||
param: PARAM_MESSAGE_1_CARRY_1_LY23_EXT_FACT_0_64,
|
||||
log_extension_factor: 0,
|
||||
};
|
||||
|
||||
const LY23_3: ParametersLY23 = ParametersLY23 {
|
||||
param: PARAM_MESSAGE_1_CARRY_2_LY23_EXT_FACT_0_64,
|
||||
log_extension_factor: 0,
|
||||
};
|
||||
|
||||
const LY23_4: ParametersLY23 = ParametersLY23 {
|
||||
param: PARAM_MESSAGE_2_CARRY_2_LY23_EXT_FACT_0_64,
|
||||
log_extension_factor: 0,
|
||||
};
|
||||
|
||||
const LY23_5: ParametersLY23 = ParametersLY23 {
|
||||
param: PARAM_MESSAGE_2_CARRY_3_LY23_EXT_FACT_1_64,
|
||||
log_extension_factor: 1,
|
||||
};
|
||||
|
||||
const LY23_6: ParametersLY23 = ParametersLY23 {
|
||||
param: PARAM_MESSAGE_3_CARRY_3_LY23_EXT_FACT_2_64,
|
||||
log_extension_factor: 2,
|
||||
};
|
||||
|
||||
const LY23_7: ParametersLY23 = ParametersLY23 {
|
||||
param: PARAM_MESSAGE_3_CARRY_4_LY23_EXT_FACT_3_64,
|
||||
log_extension_factor: 3,
|
||||
};
|
||||
|
||||
const LY23_8: ParametersLY23 = ParametersLY23 {
|
||||
param: PARAM_MESSAGE_4_CARRY_4_LY23_EXT_FACT_4_64,
|
||||
log_extension_factor: 4,
|
||||
};
|
||||
|
||||
const PARAM_BENCHES_LY23: [ParametersLY23; 8] = [
|
||||
LY23_1, LY23_2, LY23_3, LY23_4, LY23_5, LY23_6, LY23_7, LY23_8,
|
||||
];
|
||||
|
||||
pub fn generate_programmable_bootstrap_glwe_lut<F, Scalar: UnsignedTorus + CastFrom<usize>>(
|
||||
polynomial_size: PolynomialSize,
|
||||
glwe_size: GlweSize,
|
||||
message_modulus: usize,
|
||||
ciphertext_modulus: tfhe::core_crypto::prelude::CiphertextModulus<Scalar>,
|
||||
delta: Scalar,
|
||||
f: F,
|
||||
) -> GlweCiphertextOwned<Scalar>
|
||||
where
|
||||
F: Fn(Scalar) -> Scalar,
|
||||
{
|
||||
// N/(p/2) = size of each block, to correct noise from the input we introduce the
|
||||
// notion of box, which manages redundancy to yield a denoised value
|
||||
// for several noisy values around a true input value.
|
||||
let box_size = polynomial_size.0 / message_modulus;
|
||||
|
||||
// Create the accumulator
|
||||
let mut accumulator_scalar = vec![Scalar::ZERO; polynomial_size.0];
|
||||
|
||||
// Fill each box with the encoded denoised value
|
||||
for i in 0..message_modulus {
|
||||
let index = i * box_size;
|
||||
accumulator_scalar[index..index + box_size]
|
||||
.iter_mut()
|
||||
.for_each(|a| *a = f(Scalar::cast_from(i)) * delta);
|
||||
}
|
||||
|
||||
let half_box_size = box_size / 2;
|
||||
|
||||
if ciphertext_modulus.is_compatible_with_native_modulus() {
|
||||
// Negate the first half_box_size coefficients to manage negacyclicity and rotate
|
||||
for a_i in accumulator_scalar[0..half_box_size].iter_mut() {
|
||||
*a_i = (*a_i).wrapping_neg();
|
||||
}
|
||||
} else {
|
||||
let modulus: Scalar = ciphertext_modulus.get_custom_modulus().cast_into();
|
||||
for a_i in accumulator_scalar[0..half_box_size].iter_mut() {
|
||||
*a_i = (*a_i).wrapping_neg_custom_mod(modulus);
|
||||
}
|
||||
}
|
||||
|
||||
// Rotate the accumulator
|
||||
accumulator_scalar.rotate_left(half_box_size);
|
||||
|
||||
let accumulator_plaintext = PlaintextList::from_container(accumulator_scalar);
|
||||
|
||||
allocate_and_trivially_encrypt_new_glwe_ciphertext(
|
||||
glwe_size,
|
||||
&accumulator_plaintext,
|
||||
ciphertext_modulus,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn keygen(
|
||||
param: ParametersLY23,
|
||||
) -> (
|
||||
LweSecretKeyOwned<u64>,
|
||||
GlweSecretKeyOwned<u64>,
|
||||
FourierLweBootstrapKeyOwned,
|
||||
) {
|
||||
// Create the PRNG
|
||||
let mut seeder = new_seeder();
|
||||
let seeder = seeder.as_mut();
|
||||
let mut encryption_generator =
|
||||
EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
|
||||
let mut secret_generator =
|
||||
SecretRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed());
|
||||
|
||||
let params = param.param;
|
||||
|
||||
// Create the LweSecretKey
|
||||
let input_lwe_secret_key = allocate_and_generate_new_binary_lwe_secret_key(
|
||||
params.lwe_dimension,
|
||||
&mut secret_generator,
|
||||
);
|
||||
let output_glwe_secret_key: GlweSecretKeyOwned<u64> =
|
||||
allocate_and_generate_new_binary_glwe_secret_key(
|
||||
params.glwe_dimension,
|
||||
params.polynomial_size,
|
||||
&mut secret_generator,
|
||||
);
|
||||
|
||||
// Create the empty bootstrapping key in the Fourier domain
|
||||
let mut fourier_bsk = FourierLweBootstrapKey::new(
|
||||
params.lwe_dimension,
|
||||
params.glwe_dimension.to_glwe_size(),
|
||||
params.polynomial_size,
|
||||
params.pbs_base_log,
|
||||
params.pbs_level,
|
||||
);
|
||||
|
||||
let bsk = par_allocate_and_generate_new_lwe_bootstrap_key(
|
||||
&input_lwe_secret_key,
|
||||
&output_glwe_secret_key,
|
||||
params.pbs_base_log,
|
||||
params.pbs_level,
|
||||
params.glwe_noise_distribution,
|
||||
params.ciphertext_modulus,
|
||||
&mut encryption_generator,
|
||||
);
|
||||
|
||||
par_convert_standard_lwe_bootstrap_key_to_fourier(&bsk, &mut fourier_bsk);
|
||||
|
||||
(input_lwe_secret_key, output_glwe_secret_key, fourier_bsk)
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn run() {
|
||||
let mut seeder = new_seeder();
|
||||
let seeder = seeder.as_mut();
|
||||
let mut encryption_generator =
|
||||
EncryptionRandomGenerator::<ActivatedRandomGenerator>::new(seeder.seed(), seeder);
|
||||
|
||||
let param = LY23_6;
|
||||
|
||||
let params = param.param;
|
||||
|
||||
let glwe_dimension = params.glwe_dimension;
|
||||
let polynomial_size = params.polynomial_size;
|
||||
|
||||
let extension_factor = Ly23ExtensionFactor(1 << param.log_extension_factor);
|
||||
let extended_polynomial_size = PolynomialSize(polynomial_size.0 * extension_factor.0);
|
||||
|
||||
let (input_lwe_secret_key, output_glwe_secret_key, fourier_bsk) = keygen(param);
|
||||
let output_lwe_secret_key = output_glwe_secret_key.as_lwe_secret_key();
|
||||
|
||||
// for param in PARAM_BENCHES_LY23.iter() {
|
||||
// }
|
||||
// Allocate a new LweCiphertext and encrypt our plaintext
|
||||
let lwe_ciphertext_in: LweCiphertextOwned<u64> = allocate_and_encrypt_new_lwe_ciphertext(
|
||||
&input_lwe_secret_key,
|
||||
Plaintext(0u64),
|
||||
params.lwe_noise_distribution,
|
||||
params.ciphertext_modulus,
|
||||
&mut encryption_generator,
|
||||
);
|
||||
|
||||
let total_modulus = params.message_modulus.0 * params.carry_modulus.0;
|
||||
|
||||
let accumulator = generate_programmable_bootstrap_glwe_lut(
|
||||
extended_polynomial_size,
|
||||
glwe_dimension.to_glwe_size(),
|
||||
total_modulus,
|
||||
params.ciphertext_modulus,
|
||||
(1u64 << 63) >> total_modulus.ilog2(),
|
||||
|x| x,
|
||||
);
|
||||
|
||||
// Allocate the LweCiphertext to store the result of the PBS
|
||||
let mut out_pbs_ct = LweCiphertext::new(
|
||||
0u64,
|
||||
output_lwe_secret_key.lwe_dimension().to_lwe_size(),
|
||||
params.ciphertext_modulus,
|
||||
);
|
||||
|
||||
let fft = Fft::new(fourier_bsk.polynomial_size());
|
||||
let fft = fft.as_view();
|
||||
|
||||
let mut buffers = ComputationBuffers::new();
|
||||
|
||||
buffers.resize(
|
||||
programmable_bootstrap_lwe_ciphertext_mem_optimized_requirement_ly23::<u64>(
|
||||
glwe_dimension.to_glwe_size(),
|
||||
polynomial_size,
|
||||
extension_factor,
|
||||
fft,
|
||||
)
|
||||
.unwrap()
|
||||
.unaligned_bytes_required(),
|
||||
);
|
||||
|
||||
// let mut thread_buffers = Vec::with_capacity(extension_factor.0);
|
||||
// for _ in 0..extension_factor.0 {
|
||||
// let mut buffer = ComputationBuffers::new();
|
||||
// buffer.resize(
|
||||
// add_external_product_assign_mem_optimized_requirement::<u64>(
|
||||
// glwe_dimension.to_glwe_size(),
|
||||
// params.polynomial_size,
|
||||
// fft,
|
||||
// )
|
||||
// .unwrap()
|
||||
// .unaligned_bytes_required(),
|
||||
// );
|
||||
// thread_buffers.push(buffer);
|
||||
// }
|
||||
|
||||
// let mut thread_stacks: Vec<_> = thread_buffers.iter_mut().map(|x| x.stack()).collect();
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
const LOOPS: u32 = 2000;
|
||||
for _ in 0..LOOPS {
|
||||
fourier_bsk.as_view().bootstrap_ly23(
|
||||
out_pbs_ct.as_mut_view(),
|
||||
lwe_ciphertext_in.as_view(),
|
||||
accumulator.as_view(),
|
||||
extension_factor,
|
||||
fft,
|
||||
buffers.stack(),
|
||||
);
|
||||
}
|
||||
let elapsed = start.elapsed();
|
||||
|
||||
let elapsed_per_pbs = elapsed / LOOPS;
|
||||
|
||||
println!("Elapsed: {elapsed:?}");
|
||||
println!("Runtime per PBS: {elapsed_per_pbs:?}");
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
run()
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,9 @@ use crate::core_crypto::commons::math::decomposition::SignedDecomposer;
|
||||
use crate::core_crypto::commons::parameters::*;
|
||||
use crate::core_crypto::commons::traits::*;
|
||||
use crate::core_crypto::entities::*;
|
||||
use crate::core_crypto::fft_impl::fft64::crypto::bootstrap::bootstrap_scratch;
|
||||
use crate::core_crypto::fft_impl::fft64::crypto::bootstrap::{
|
||||
bootstrap_ly23_scratch, bootstrap_scratch, FourierLweBootstrapKey,
|
||||
};
|
||||
use crate::core_crypto::fft_impl::fft64::crypto::ggsw::{
|
||||
add_external_product_assign as impl_add_external_product_assign,
|
||||
add_external_product_assign_scratch as impl_add_external_product_assign_scratch, cmux,
|
||||
@@ -1071,3 +1073,12 @@ pub fn programmable_bootstrap_lwe_ciphertext_mem_optimized_requirement<OutputSca
|
||||
) -> Result<StackReq, SizeOverflow> {
|
||||
bootstrap_scratch::<OutputScalar>(glwe_size, polynomial_size, fft)
|
||||
}
|
||||
|
||||
pub fn programmable_bootstrap_lwe_ciphertext_mem_optimized_requirement_ly23<Scalar>(
|
||||
glwe_size: GlweSize,
|
||||
small_polynomial_size: PolynomialSize,
|
||||
extension_factor: Ly23ExtensionFactor,
|
||||
fft: FftView<'_>,
|
||||
) -> Result<StackReq, SizeOverflow> {
|
||||
bootstrap_ly23_scratch::<Scalar>(glwe_size, small_polynomial_size, extension_factor, fft)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ pub mod lwe_bootstrap_key_generation;
|
||||
pub mod lwe_compact_ciphertext_list_expansion;
|
||||
pub mod lwe_compact_public_key_generation;
|
||||
pub mod lwe_encryption;
|
||||
pub mod lwe_extended_programmable_bootstrapping;
|
||||
pub mod lwe_keyswitch;
|
||||
pub mod lwe_keyswitch_key_generation;
|
||||
pub mod lwe_linear_algebra;
|
||||
@@ -61,6 +62,7 @@ pub use lwe_bootstrap_key_generation::*;
|
||||
pub use lwe_compact_ciphertext_list_expansion::*;
|
||||
pub use lwe_compact_public_key_generation::*;
|
||||
pub use lwe_encryption::*;
|
||||
pub use lwe_extended_programmable_bootstrapping::*;
|
||||
pub use lwe_keyswitch::*;
|
||||
pub use lwe_keyswitch_key_generation::*;
|
||||
pub use lwe_linear_algebra::*;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -270,7 +270,11 @@ pub struct LweBskGroupingFactor(pub usize);
|
||||
|
||||
impl LweBskGroupingFactor {
|
||||
pub fn ggsw_per_multi_bit_element(&self) -> GgswPerLweMultiBitBskElement {
|
||||
GgswPerLweMultiBitBskElement(1 << self.0)
|
||||
GgswPerLweMultiBitBskElement(self.group_power_set_size())
|
||||
}
|
||||
|
||||
pub fn group_power_set_size(&self) -> usize {
|
||||
1 << self.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,3 +381,9 @@ impl std::ops::Mul<EncryptionNoiseSampleCount> for usize {
|
||||
/// A quantity representing a number of bytes used for noise generation during encryption.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub struct EncryptionNoiseByteCount(pub usize);
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct Ly23ExtensionFactor(pub usize);
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct Ly23ShortcutCoeffCount(pub usize);
|
||||
|
||||
@@ -52,6 +52,12 @@ impl<T> Container for aligned_vec::AVec<T> {
|
||||
|
||||
impl<T> ContainerMut for aligned_vec::AVec<T> {}
|
||||
|
||||
impl<'data, T> Container for dyn_stack::DynArray<'data, T> {
|
||||
type Element = T;
|
||||
}
|
||||
|
||||
impl<'data, T> ContainerMut for dyn_stack::DynArray<'data, T> {}
|
||||
|
||||
pub trait IntoContainerOwned: Container + AsMut<[Self::Element]> {
|
||||
fn collect<I: Iterator<Item = Self::Element>>(iter: I) -> Self;
|
||||
}
|
||||
|
||||
@@ -500,4 +500,16 @@ pub trait ContiguousEntityContainerMut: ContiguousEntityContainer + AsMut<[Self:
|
||||
.zip(rayon::iter::repeatn(meta, entity_count))
|
||||
.map(|(elt, meta)| Self::SelfMutView::<'_>::create_from(elt, meta))
|
||||
}
|
||||
|
||||
fn rotate_left(&mut self, count: usize) {
|
||||
let entity_view_pod_size = self.get_entity_view_pod_size();
|
||||
let pod_rotation = entity_view_pod_size * count;
|
||||
self.as_mut().rotate_left(pod_rotation);
|
||||
}
|
||||
|
||||
fn rotate_right(&mut self, count: usize) {
|
||||
let entity_view_pod_size = self.get_entity_view_pod_size();
|
||||
let pod_rotation = entity_view_pod_size * count;
|
||||
self.as_mut().rotate_right(pod_rotation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +164,29 @@ impl<Scalar: UnsignedInteger, C: Container<Element = Scalar>> GlweCiphertextList
|
||||
pub fn ciphertext_modulus(&self) -> CiphertextModulus<C::Element> {
|
||||
self.ciphertext_modulus
|
||||
}
|
||||
|
||||
pub fn as_view(&self) -> GlweCiphertextListView<C::Element> {
|
||||
GlweCiphertextListView::from_container(
|
||||
self.as_ref(),
|
||||
self.glwe_size(),
|
||||
self.polynomial_size(),
|
||||
self.ciphertext_modulus(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Scalar: UnsignedInteger, C: ContainerMut<Element = Scalar>> GlweCiphertextList<C> {
|
||||
pub fn as_mut_view(&mut self) -> GlweCiphertextListMutView<C::Element> {
|
||||
let glwe_size = self.glwe_size();
|
||||
let polynomial_size = self.polynomial_size();
|
||||
let ciphertext_modulus = self.ciphertext_modulus();
|
||||
GlweCiphertextListMutView::from_container(
|
||||
self.as_mut(),
|
||||
glwe_size,
|
||||
polynomial_size,
|
||||
ciphertext_modulus,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`GlweCiphertextList`] owning the memory for its own storage.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::*;
|
||||
use std::io::ErrorKind::Interrupted;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct StairKSParam<Scalar: UnsignedInteger> {
|
||||
@@ -298,3 +299,335 @@ fn lwe_encrypt_stair_keyswitch_pbs_decrypt_custom_mod<
|
||||
fn lwe_encrypt_stair_keyswitch_pbs_decrypt_custom_mod_params_stair_4() {
|
||||
lwe_encrypt_stair_keyswitch_pbs_decrypt_custom_mod(PRECISION_4_STAIR)
|
||||
}
|
||||
|
||||
pub struct StairKSParamOneStepLY<Scalar: UnsignedInteger> {
|
||||
pub log_precision: MessageModulusLog,
|
||||
/// This value is unused but allows to identify the parameter optimization that was done
|
||||
pub _log_mu: usize,
|
||||
pub glwe_dimension: GlweDimension,
|
||||
pub polynomial_size: PolynomialSize,
|
||||
pub partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount,
|
||||
pub bsk_glwe_noise_distribution: DynamicDistribution<Scalar>,
|
||||
pub lwe_dimension: LweDimension,
|
||||
pub ks_lwe_noise_distribution: DynamicDistribution<Scalar>,
|
||||
pub pbs_level: DecompositionLevelCount,
|
||||
pub pbs_base_log: DecompositionBaseLog,
|
||||
pub ks_level: DecompositionLevelCount,
|
||||
pub ks_base_log: DecompositionBaseLog,
|
||||
/// The number of elements being dropped when going from the large key to the inter key
|
||||
pub ks_unshared_coeff_count: LweSecretKeyUnsharedCoefCount,
|
||||
pub ciphertext_modulus: CiphertextModulus<Scalar>,
|
||||
pub log_extension_factor: u64,
|
||||
}
|
||||
pub const PRECISION_2_STAIR_ONE_STEP: StairKSParamOneStepLY<u64> = StairKSParamOneStepLY {
|
||||
log_precision: MessageModulusLog(2),
|
||||
_log_mu: 2,
|
||||
glwe_dimension: GlweDimension(3),
|
||||
polynomial_size: PolynomialSize(512),
|
||||
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(3 * 512),
|
||||
bsk_glwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
|
||||
8.390846778442423e-12,
|
||||
)),
|
||||
lwe_dimension: LweDimension(709),
|
||||
ks_lwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
|
||||
2.0944272028597803e-05,
|
||||
)),
|
||||
pbs_level: DecompositionLevelCount(1),
|
||||
pbs_base_log: DecompositionBaseLog(18),
|
||||
ks_level: DecompositionLevelCount(4),
|
||||
ks_base_log: DecompositionBaseLog(3),
|
||||
ks_unshared_coeff_count: LweSecretKeyUnsharedCoefCount(827),
|
||||
ciphertext_modulus: CiphertextModulus::new_native(),
|
||||
log_extension_factor: 1,
|
||||
};
|
||||
|
||||
pub const PRECISION_4_STAIR_ONE_STEP: StairKSParamOneStepLY<u64> = StairKSParamOneStepLY {
|
||||
log_precision: MessageModulusLog(4),
|
||||
_log_mu: 4,
|
||||
glwe_dimension: GlweDimension(1),
|
||||
polynomial_size: PolynomialSize(2048),
|
||||
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2048),
|
||||
bsk_glwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
|
||||
9.188173694010523e-16,
|
||||
)),
|
||||
lwe_dimension: LweDimension(790),
|
||||
ks_lwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
|
||||
4.948683445911403e-06,
|
||||
)),
|
||||
pbs_level: DecompositionLevelCount(1),
|
||||
pbs_base_log: DecompositionBaseLog(23),
|
||||
ks_level: DecompositionLevelCount(5),
|
||||
ks_base_log: DecompositionBaseLog(3),
|
||||
ks_unshared_coeff_count: LweSecretKeyUnsharedCoefCount(1258),
|
||||
ciphertext_modulus: CiphertextModulus::new_native(),
|
||||
log_extension_factor: 1,
|
||||
};
|
||||
|
||||
pub const PRECISION_6_STAIR_ONE_STEP: StairKSParamOneStepLY<u64> = StairKSParamOneStepLY {
|
||||
log_precision: MessageModulusLog(6),
|
||||
_log_mu: 6,
|
||||
glwe_dimension: GlweDimension(1),
|
||||
polynomial_size: PolynomialSize(2048),
|
||||
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2048),
|
||||
bsk_glwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
|
||||
9.188173694010523e-16,
|
||||
)),
|
||||
lwe_dimension: LweDimension(853),
|
||||
ks_lwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
|
||||
1.6112135273032647e-06,
|
||||
)),
|
||||
pbs_level: DecompositionLevelCount(2),
|
||||
pbs_base_log: DecompositionBaseLog(15),
|
||||
ks_level: DecompositionLevelCount(8),
|
||||
ks_base_log: DecompositionBaseLog(2),
|
||||
ks_unshared_coeff_count: LweSecretKeyUnsharedCoefCount(1195),
|
||||
ciphertext_modulus: CiphertextModulus::new_native(),
|
||||
log_extension_factor: 2,
|
||||
};
|
||||
|
||||
pub const PRECISION_8_STAIR_ONE_STEP: StairKSParamOneStepLY<u64> = StairKSParamOneStepLY {
|
||||
log_precision: MessageModulusLog(8),
|
||||
_log_mu: 8,
|
||||
glwe_dimension: GlweDimension(1),
|
||||
polynomial_size: PolynomialSize(2048),
|
||||
partial_glwe_secret_key_fill: PartialGlweSecretKeyRandomCoefCount(2048),
|
||||
bsk_glwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
|
||||
9.188173694010523e-16,
|
||||
)),
|
||||
lwe_dimension: LweDimension(925),
|
||||
ks_lwe_noise_distribution: DynamicDistribution::new_gaussian_from_std_dev(StandardDev(
|
||||
4.468862725257972e-07,
|
||||
)),
|
||||
pbs_level: DecompositionLevelCount(2),
|
||||
pbs_base_log: DecompositionBaseLog(16),
|
||||
ks_level: DecompositionLevelCount(19),
|
||||
ks_base_log: DecompositionBaseLog(1),
|
||||
ks_unshared_coeff_count: LweSecretKeyUnsharedCoefCount(1123),
|
||||
ciphertext_modulus: CiphertextModulus::new_native(),
|
||||
log_extension_factor: 4,
|
||||
};
|
||||
|
||||
fn lwe_encrypt_stair_keyswitch_pbs_decrypt_custom_mod_one_step<
|
||||
Scalar: UnsignedTorus + Send + Sync + CastFrom<usize> + CastInto<usize>,
|
||||
>(
|
||||
params: StairKSParamOneStepLY<Scalar>,
|
||||
) {
|
||||
let StairKSParamOneStepLY {
|
||||
log_precision,
|
||||
_log_mu,
|
||||
glwe_dimension,
|
||||
polynomial_size,
|
||||
partial_glwe_secret_key_fill,
|
||||
bsk_glwe_noise_distribution,
|
||||
lwe_dimension,
|
||||
ks_lwe_noise_distribution,
|
||||
pbs_level,
|
||||
pbs_base_log,
|
||||
ks_level,
|
||||
ks_base_log,
|
||||
ks_unshared_coeff_count,
|
||||
ciphertext_modulus,
|
||||
log_extension_factor,
|
||||
} = params;
|
||||
let shortcut_coeff_count = Ly23ShortcutCoeffCount(1);
|
||||
let extension_factor = Ly23ExtensionFactor(1 << log_extension_factor);
|
||||
let extended_polynomial_size = PolynomialSize(polynomial_size.0 * extension_factor.0);
|
||||
let msg_modulus = Scalar::ONE.shl(log_precision.0);
|
||||
let encoding_with_padding = get_encoding_with_padding(ciphertext_modulus);
|
||||
|
||||
let mut rsc = TestResources::new();
|
||||
|
||||
const NB_TESTS: usize = 10;
|
||||
let mut msg = msg_modulus;
|
||||
let delta: Scalar = encoding_with_padding / msg_modulus;
|
||||
|
||||
let large_lwe_dimension = glwe_dimension.to_equivalent_lwe_dimension(polynomial_size);
|
||||
// Our algorithm is set up so that this equality holds, but in practice it could be more generic
|
||||
// if we had an intermediate LweDimension being defined
|
||||
assert_eq!(
|
||||
partial_glwe_secret_key_fill.0,
|
||||
lwe_dimension.0 + ks_unshared_coeff_count.0
|
||||
);
|
||||
|
||||
while msg != Scalar::ZERO {
|
||||
msg = msg.wrapping_sub(Scalar::ONE);
|
||||
|
||||
let glwe_secret_key = allocate_and_generate_new_partial_binary_glwe_secret_key(
|
||||
glwe_dimension,
|
||||
polynomial_size,
|
||||
partial_glwe_secret_key_fill,
|
||||
&mut rsc.secret_random_generator,
|
||||
);
|
||||
|
||||
let large_lwe_secret_key = glwe_secret_key.as_lwe_secret_key();
|
||||
let large_lwe_dimension_without_zeros = LweDimension(partial_glwe_secret_key_fill.0);
|
||||
|
||||
let inter_lwe_dimension = LweDimension(
|
||||
large_lwe_dimension_without_zeros
|
||||
.shared_coef_count_from(ks_unshared_coeff_count)
|
||||
.0,
|
||||
);
|
||||
let inter_lwe_secret_key = allocate_and_generate_fully_shared_binary_lwe_secret_key(
|
||||
&large_lwe_secret_key,
|
||||
inter_lwe_dimension,
|
||||
);
|
||||
|
||||
//Shrinking KSK generations
|
||||
let ksk_large_to_inter = allocate_and_generate_new_lwe_shrinking_keyswitch_key(
|
||||
&large_lwe_secret_key,
|
||||
LweSecretKeySharedCoefCount(inter_lwe_dimension.0),
|
||||
ks_base_log,
|
||||
ks_level,
|
||||
ks_lwe_noise_distribution,
|
||||
ciphertext_modulus,
|
||||
&mut rsc.encryption_random_generator,
|
||||
);
|
||||
|
||||
assert!(check_encrypted_content_respects_mod(
|
||||
&ksk_large_to_inter,
|
||||
ciphertext_modulus
|
||||
));
|
||||
|
||||
//PBS PART
|
||||
let mut bsk = LweBootstrapKey::new(
|
||||
Scalar::ZERO,
|
||||
glwe_dimension.to_glwe_size(),
|
||||
polynomial_size,
|
||||
pbs_base_log,
|
||||
pbs_level,
|
||||
lwe_dimension,
|
||||
ciphertext_modulus,
|
||||
);
|
||||
|
||||
par_generate_lwe_bootstrap_key(
|
||||
&inter_lwe_secret_key,
|
||||
&glwe_secret_key,
|
||||
&mut bsk,
|
||||
bsk_glwe_noise_distribution,
|
||||
&mut rsc.encryption_random_generator,
|
||||
);
|
||||
|
||||
assert!(check_encrypted_content_respects_mod(
|
||||
&*bsk,
|
||||
ciphertext_modulus
|
||||
));
|
||||
|
||||
let mut fbsk = FourierLweBootstrapKey::new(
|
||||
inter_lwe_secret_key.lwe_dimension(),
|
||||
glwe_dimension.to_glwe_size(),
|
||||
polynomial_size,
|
||||
pbs_base_log,
|
||||
pbs_level,
|
||||
);
|
||||
|
||||
convert_standard_lwe_bootstrap_key_to_fourier(&bsk, &mut fbsk);
|
||||
drop(bsk);
|
||||
|
||||
let accumulator = generate_programmable_bootstrap_glwe_lut(
|
||||
extended_polynomial_size,
|
||||
glwe_dimension.to_glwe_size(),
|
||||
msg_modulus.cast_into(),
|
||||
ciphertext_modulus,
|
||||
delta,
|
||||
|x| x,
|
||||
);
|
||||
|
||||
let mut buffers = ComputationBuffers::new();
|
||||
|
||||
let fft = Fft::new(polynomial_size);
|
||||
let fft = fft.as_view();
|
||||
|
||||
buffers.resize(
|
||||
programmable_bootstrap_lwe_ciphertext_mem_optimized_requirement_ly23::<u64>(
|
||||
glwe_dimension.to_glwe_size(),
|
||||
polynomial_size,
|
||||
extension_factor,
|
||||
fft,
|
||||
)
|
||||
.unwrap()
|
||||
.unaligned_bytes_required(),
|
||||
);
|
||||
|
||||
for _ in 0..NB_TESTS {
|
||||
let plaintext = Plaintext(msg * delta);
|
||||
|
||||
//Encryption
|
||||
let mut large_lwe = LweCiphertext::new(
|
||||
Scalar::ZERO,
|
||||
large_lwe_dimension.to_lwe_size(),
|
||||
ciphertext_modulus,
|
||||
);
|
||||
|
||||
encrypt_lwe_ciphertext(
|
||||
&large_lwe_secret_key,
|
||||
&mut large_lwe,
|
||||
plaintext,
|
||||
bsk_glwe_noise_distribution,
|
||||
&mut rsc.encryption_random_generator,
|
||||
);
|
||||
|
||||
assert!(check_encrypted_content_respects_mod(
|
||||
&large_lwe,
|
||||
ciphertext_modulus
|
||||
));
|
||||
|
||||
//Shrinking KS
|
||||
let mut inter_lwe = LweCiphertext::new(
|
||||
Scalar::ZERO,
|
||||
inter_lwe_secret_key.lwe_dimension().to_lwe_size(),
|
||||
ciphertext_modulus,
|
||||
);
|
||||
|
||||
let mut out_pbs_ct = LweCiphertext::new(
|
||||
Scalar::ZERO,
|
||||
large_lwe_secret_key.lwe_dimension().to_lwe_size(),
|
||||
ciphertext_modulus,
|
||||
);
|
||||
|
||||
// Check the AP works for several iterations
|
||||
for _ in 0..NB_TESTS {
|
||||
shrinking_keyswitch_lwe_ciphertext(&ksk_large_to_inter, &large_lwe, &mut inter_lwe);
|
||||
|
||||
assert!(check_encrypted_content_respects_mod(
|
||||
&inter_lwe,
|
||||
ciphertext_modulus
|
||||
));
|
||||
|
||||
let dec_inter = decrypt_lwe_ciphertext(&inter_lwe_secret_key, &inter_lwe);
|
||||
let decoded = round_decode(dec_inter.0, delta) % msg_modulus;
|
||||
assert_eq!(decoded, msg, "Err after first shrinking KS");
|
||||
|
||||
fbsk.as_view().bootstrap_bergerat24(
|
||||
out_pbs_ct.as_mut_view(),
|
||||
inter_lwe.as_view(),
|
||||
accumulator.as_view(),
|
||||
extension_factor,
|
||||
shortcut_coeff_count,
|
||||
fft,
|
||||
buffers.stack(),
|
||||
);
|
||||
|
||||
assert!(check_encrypted_content_respects_mod(
|
||||
&out_pbs_ct,
|
||||
ciphertext_modulus
|
||||
));
|
||||
|
||||
let dec_large = decrypt_lwe_ciphertext(&large_lwe_secret_key, &out_pbs_ct);
|
||||
let decoded = round_decode(dec_large.0, delta) % msg_modulus;
|
||||
assert_eq!(decoded, msg, "Err after PBS");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lwe_encrypt_stair_keyswitch_pbs_decrypt_custom_mod_params_stair_4_one_step() {
|
||||
lwe_encrypt_stair_keyswitch_pbs_decrypt_custom_mod_one_step(PRECISION_2_STAIR_ONE_STEP);
|
||||
println!("2ok");
|
||||
lwe_encrypt_stair_keyswitch_pbs_decrypt_custom_mod_one_step(PRECISION_4_STAIR_ONE_STEP);
|
||||
println!("4ok");
|
||||
lwe_encrypt_stair_keyswitch_pbs_decrypt_custom_mod_one_step(PRECISION_6_STAIR_ONE_STEP);
|
||||
println!("6ok");
|
||||
lwe_encrypt_stair_keyswitch_pbs_decrypt_custom_mod_one_step(PRECISION_8_STAIR_ONE_STEP);
|
||||
println!("8ok");
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -32,8 +32,8 @@
|
||||
#![allow(clippy::bool_to_int_with_if)] // 6
|
||||
#![allow(clippy::unsafe_derive_deserialize)] // 1
|
||||
#![allow(clippy::cast_possible_wrap)]
|
||||
#![allow(deprecated)]
|
||||
// 1
|
||||
|
||||
// These pedantic lints are deemed to bring too little value therefore they are allowed (which are
|
||||
// their natural state anyways, being pedantic lints)
|
||||
|
||||
|
||||
@@ -242,6 +242,123 @@ named_params_impl!( ShortintParameterSet =>
|
||||
COVERAGE_PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_PBS_KS,
|
||||
#[cfg(tarpaulin)]
|
||||
COVERAGE_PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_KS_PBS,
|
||||
//
|
||||
//new params Bench LY
|
||||
PARAM_MESSAGE_2_PBS_MS_0_EF_0_40,
|
||||
PARAM_MESSAGE_3_PBS_MS_0_EF_0_40,
|
||||
PARAM_MESSAGE_4_PBS_MS_0_EF_0_40,
|
||||
PARAM_MESSAGE_5_PBS_MS_0_EF_0_40,
|
||||
PARAM_MESSAGE_6_PBS_MS_0_EF_0_40,
|
||||
PARAM_MESSAGE_7_PBS_MS_0_EF_0_40,
|
||||
PARAM_MESSAGE_8_PBS_MS_0_EF_0_40,
|
||||
PARAM_MESSAGE_9_PBS_MS_0_EF_0_40,
|
||||
//
|
||||
PARAM_MESSAGE_5_SORTED_PBS_MS_0_EF_1_40,
|
||||
PARAM_MESSAGE_6_SORTED_PBS_MS_0_EF_3_40,
|
||||
PARAM_MESSAGE_7_SORTED_PBS_MS_0_EF_3_40,
|
||||
PARAM_MESSAGE_8_SORTED_PBS_MS_0_EF_4_40,
|
||||
PARAM_MESSAGE_9_SORTED_PBS_MS_0_EF_5_40,
|
||||
//
|
||||
PARAM_MESSAGE_5_BEST_PBS_MS_20_EF_1_40,
|
||||
PARAM_MESSAGE_6_BEST_PBS_MS_1_EF_3_40,
|
||||
PARAM_MESSAGE_7_BEST_PBS_MS_94_EF_3_40,
|
||||
PARAM_MESSAGE_8_BEST_PBS_MS_90_EF_4_40,
|
||||
PARAM_MESSAGE_9_BEST_PBS_MS_76_EF_5_40,
|
||||
//
|
||||
PARAM_MESSAGE_2_PBS_MS_0_EF_0_64,
|
||||
PARAM_MESSAGE_3_PBS_MS_0_EF_0_64,
|
||||
PARAM_MESSAGE_4_PBS_MS_0_EF_0_64,
|
||||
PARAM_MESSAGE_5_PBS_MS_0_EF_0_64,
|
||||
PARAM_MESSAGE_6_PBS_MS_0_EF_0_64,
|
||||
PARAM_MESSAGE_7_PBS_MS_0_EF_0_64,
|
||||
PARAM_MESSAGE_8_PBS_MS_0_EF_0_64,
|
||||
PARAM_MESSAGE_9_PBS_MS_0_EF_0_64,
|
||||
//
|
||||
PARAM_MESSAGE_5_SORTED_PBS_MS_0_EF_2_64,
|
||||
PARAM_MESSAGE_6_SORTED_PBS_MS_0_EF_2_64,
|
||||
PARAM_MESSAGE_7_SORTED_PBS_MS_0_EF_3_64,
|
||||
PARAM_MESSAGE_8_SORTED_PBS_MS_0_EF_4_64,
|
||||
PARAM_MESSAGE_9_SORTED_PBS_MS_0_EF_5_64,
|
||||
//
|
||||
PARAM_MESSAGE_5_BEST_PBS_MS_151_EF_2_80,
|
||||
PARAM_MESSAGE_6_BEST_PBS_MS_255_EF_3_80,
|
||||
PARAM_MESSAGE_7_BEST_PBS_MS_256_EF_4_80,
|
||||
PARAM_MESSAGE_8_BEST_PBS_MS_256_EF_5_80,
|
||||
PARAM_MESSAGE_9_BEST_PBS_MS_255_EF_6_80,
|
||||
//
|
||||
PARAM_MESSAGE_2_PBS_MS_0_EF_0_80,
|
||||
PARAM_MESSAGE_3_PBS_MS_0_EF_0_80,
|
||||
PARAM_MESSAGE_4_PBS_MS_0_EF_0_80,
|
||||
PARAM_MESSAGE_5_PBS_MS_0_EF_0_81,
|
||||
PARAM_MESSAGE_6_PBS_MS_0_EF_0_81,
|
||||
PARAM_MESSAGE_7_PBS_MS_0_EF_0_80,
|
||||
PARAM_MESSAGE_8_PBS_MS_0_EF_0_81,
|
||||
PARAM_MESSAGE_9_PBS_MS_0_EF_0_80,
|
||||
//
|
||||
PARAM_MESSAGE_5_SORTED_PBS_MS_0_EF_2_80,
|
||||
PARAM_MESSAGE_6_SORTED_PBS_MS_0_EF_4_80,
|
||||
PARAM_MESSAGE_7_SORTED_PBS_MS_0_EF_4_81,
|
||||
PARAM_MESSAGE_8_SORTED_PBS_MS_0_EF_5_81,
|
||||
PARAM_MESSAGE_9_SORTED_PBS_MS_0_EF_6_81,
|
||||
//
|
||||
PARAM_MESSAGE_2_PBS_MS_0_EF_0_129,
|
||||
PARAM_MESSAGE_3_PBS_MS_0_EF_0_130,
|
||||
PARAM_MESSAGE_4_PBS_MS_0_EF_0_129,
|
||||
PARAM_MESSAGE_5_PBS_MS_0_EF_0_130,
|
||||
PARAM_MESSAGE_6_PBS_MS_0_EF_0_129,
|
||||
PARAM_MESSAGE_7_PBS_MS_0_EF_0_129,
|
||||
PARAM_MESSAGE_8_PBS_MS_0_EF_0_129,
|
||||
PARAM_MESSAGE_9_PBS_MS_0_EF_0_129,
|
||||
//
|
||||
PARAM_MESSAGE_4_SORTED_PBS_MS_0_EF_1_128,
|
||||
PARAM_MESSAGE_5_SORTED_PBS_MS_0_EF_2_128,
|
||||
PARAM_MESSAGE_6_SORTED_PBS_MS_0_EF_3_129,
|
||||
PARAM_MESSAGE_7_SORTED_PBS_MS_0_EF_4_128,
|
||||
PARAM_MESSAGE_8_SORTED_PBS_MS_0_EF_5_128,
|
||||
PARAM_MESSAGE_9_SORTED_PBS_MS_0_EF_6_129,
|
||||
//
|
||||
PARAM_MESSAGE_4_BEST_PBS_MS_123_EF_1_128,
|
||||
PARAM_MESSAGE_5_BEST_PBS_MS_0_EF_2_128,
|
||||
PARAM_MESSAGE_6_BEST_PBS_MS_150_EF_3_128,
|
||||
PARAM_MESSAGE_7_BEST_PBS_MS_148_EF_4_128,
|
||||
PARAM_MESSAGE_8_BEST_PBS_MS_137_EF_5_128,
|
||||
PARAM_MESSAGE_9_BEST_PBS_MS_96_EF_6_128,
|
||||
//
|
||||
PARAM_MESSAGE_1_CARRY_1_PARALLEL_PBS_MS_0_EF_4_128,
|
||||
PARAM_MESSAGE_1_CARRY_2_PARALLEL_PBS_MS_0_EF_4_128,
|
||||
PARAM_MESSAGE_2_CARRY_2_PARALLEL_PBS_MS_0_EF_4_128,
|
||||
PARAM_MESSAGE_2_CARRY_3_PARALLEL_PBS_MS_0_EF_4_128,
|
||||
PARAM_MESSAGE_3_CARRY_3_PARALLEL_PBS_MS_0_EF_4_128,
|
||||
PARAM_MESSAGE_3_CARRY_4_PARALLEL_PBS_MS_0_EF_4_128,
|
||||
PARAM_MESSAGE_4_CARRY_4_PARALLEL_PBS_MS_0_EF_4_128,
|
||||
PARAM_MESSAGE_4_CARRY_5_PARALLEL_PBS_MS_0_EF_4_128,
|
||||
//
|
||||
PARAM_MESSAGE_1_CARRY_1_PARALLEL_PBS_MS_0_EF_4_80,
|
||||
PARAM_MESSAGE_1_CARRY_2_PARALLEL_PBS_MS_0_EF_4_80,
|
||||
PARAM_MESSAGE_2_CARRY_2_PARALLEL_PBS_MS_0_EF_4_80,
|
||||
PARAM_MESSAGE_2_CARRY_3_PARALLEL_PBS_MS_0_EF_4_80,
|
||||
PARAM_MESSAGE_3_CARRY_3_PARALLEL_PBS_MS_0_EF_4_80,
|
||||
PARAM_MESSAGE_3_CARRY_4_PARALLEL_PBS_MS_0_EF_4_80,
|
||||
PARAM_MESSAGE_4_CARRY_4_PARALLEL_PBS_MS_0_EF_4_80,
|
||||
PARAM_MESSAGE_4_CARRY_5_PARALLEL_PBS_MS_0_EF_4_80,
|
||||
//
|
||||
PARAM_MESSAGE_1_CARRY_1_PARALLEL_PBS_MS_0_EF_4_64,
|
||||
PARAM_MESSAGE_1_CARRY_2_PARALLEL_PBS_MS_0_EF_4_64,
|
||||
PARAM_MESSAGE_2_CARRY_2_PARALLEL_PBS_MS_0_EF_4_64,
|
||||
PARAM_MESSAGE_2_CARRY_3_PARALLEL_PBS_MS_0_EF_4_64,
|
||||
PARAM_MESSAGE_3_CARRY_3_PARALLEL_PBS_MS_0_EF_4_64,
|
||||
PARAM_MESSAGE_3_CARRY_4_PARALLEL_PBS_MS_0_EF_4_64,
|
||||
PARAM_MESSAGE_4_CARRY_4_PARALLEL_PBS_MS_0_EF_4_64,
|
||||
PARAM_MESSAGE_4_CARRY_5_PARALLEL_PBS_MS_0_EF_4_64,
|
||||
//
|
||||
PARAM_MESSAGE_1_CARRY_1_PARALLEL_PBS_MS_0_EF_4_40,
|
||||
PARAM_MESSAGE_1_CARRY_2_PARALLEL_PBS_MS_0_EF_4_40,
|
||||
PARAM_MESSAGE_2_CARRY_2_PARALLEL_PBS_MS_0_EF_4_40,
|
||||
PARAM_MESSAGE_2_CARRY_3_PARALLEL_PBS_MS_0_EF_4_40,
|
||||
PARAM_MESSAGE_3_CARRY_3_PARALLEL_PBS_MS_0_EF_4_40,
|
||||
PARAM_MESSAGE_3_CARRY_4_PARALLEL_PBS_MS_0_EF_4_40,
|
||||
PARAM_MESSAGE_4_CARRY_4_PARALLEL_PBS_MS_0_EF_4_40,
|
||||
PARAM_MESSAGE_4_CARRY_5_PARALLEL_PBS_MS_0_EF_4_40,
|
||||
);
|
||||
|
||||
impl NamedParam for ClassicPBSParameters {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user