Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Am/chore/doc casting #1261

Merged
merged 2 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 83 additions & 5 deletions tfhe/docs/guides/zk-pok.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,92 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
}
```

In terms of performance one can expect the following numbers:

* Encrypting and proving a `CompactFheUint64` takes **6.9 s** on a `Dell XPS 15 9500` (simulating a client machine).
* Verification takes **123 ms** on an `hpc7a.96xlarge` AWS instances.

Performance can be improved by setting `lto="fat"` in `Cargo.toml`
```toml
[profile.release]
lto = "fat"
```
and by building the code for the native CPU architecture and in release mode, e.g. by calling `RUSTFLAGS="-C target-cpu=native" cargo run --release`.

{% hint style="info" %}
You can choose a more costly proof with `ZkComputeLoad::Proof`, which has a faster verification time. Alternatively, you can select `ZkComputeLoad::Verify` for a faster proof and slower verification.
{% endhint %}

## Using dedicated Compact Public Key parameters

### A first example
You can use dedicated parameters for the compact public key encryption to reduce the size of encrypted data and speed up the zero-knowledge proof computation.

This works essentially in the same way as before. Additionally, you need to indicate the dedicated parameters to use:

```rust
use rand::prelude::*;
use tfhe::prelude::FheDecrypt;
use tfhe::set_server_key;
use tfhe::zk::{CompactPkeCrs, ZkComputeLoad};

pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut rng = thread_rng();

let params = tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
// Indicate which parameters to use for the Compact Public Key encryption
let cpk_params = tfhe::shortint::parameters::compact_public_key_only::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
// And parameters allowing to keyswitch/cast to the computation parameters.
let casting_params = tfhe::shortint::parameters::key_switching::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
// Enable the dedicated parameters on the config
let config = tfhe::ConfigBuilder::with_custom_parameters(params, None)
.use_dedicated_compact_public_key_parameters((cpk_params, casting_params));

// Then use TFHE-rs as usual
let client_key = tfhe::ClientKey::generate(config.clone());
// This is done in an offline phase and the CRS is shared to all clients and the server
let crs = CompactPkeCrs::from_config(config.into(), 64).unwrap();
let public_zk_params = crs.public_params();
let server_key = tfhe::ServerKey::new(&client_key);
let public_key = tfhe::CompactPublicKey::try_new(&client_key).unwrap();

let clear_a = rng.gen::<u64>();
let clear_b = rng.gen::<u64>();

let proven_compact_list = tfhe::ProvenCompactCiphertextList::builder(&public_key)
.push(clear_a)
.push(clear_b)
.build_with_proof_packed(public_zk_params, ZkComputeLoad::Verify)?;

// Server side
let result = {
set_server_key(server_key);

// Verify the ciphertexts
let mut expander = proven_compact_list.verify_and_expand(&public_zk_params, &public_key)?;
let a: tfhe::FheUint64 = expander.get(0).unwrap()?;
let b: tfhe::FheUint64 = expander.get(1).unwrap()?;

a + b
};

// Back on the client side
let a_plus_b: u64 = result.decrypt(&client_key);
assert_eq!(a_plus_b, clear_a.wrapping_add(clear_b));

Ok(())
}
```

### Benchmarks
Benchmarks for the proofs have been run on a `m6i.4xlarge` with 16 cores to simulate an usual client configuration. The verification are done on a `hpc7a.96xlarge` AWS instances to mimic a powerful server.

Timings in the case where the workload is mainly on the prover, i.e., with the `ZkComputeLoad::Proof` option.

| Inputs | Proving | Verifying |
|--------------|---------|-----------|
| 1xFheUint64 | 2.79s | 197ms |
| 10xFheUint64 | 3.68s | 251ms |


Timings in the case where the workload is mainly on the verifier, i.e., with the `ZkComputeLoad::Verify` option.

| Inputs | Proving | Verifying |
|--------------|---------|-----------|
| 1xFheUint64 | 730ms | 522ms |
| 10xFheUint64 | 1.08s | 682ms |
3 changes: 2 additions & 1 deletion tfhe/src/shortint/ciphertext/compact_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub use crate::shortint::parameters::ShortintCompactCiphertextListCastingMode;
use crate::shortint::parameters::{
CarryModulus, CompactCiphertextListExpansionKind, MessageModulus,
};
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;

Expand Down Expand Up @@ -94,7 +95,7 @@ impl CompactCiphertextList {
let pbs_order = casting_key.dest_server_key.pbs_order;

let res = output_lwe_ciphertext_list
.iter()
.par_iter()
.map(|lwe_view| {
let lwe_to_cast = LweCiphertext::from_container(
lwe_view.as_ref().to_vec(),
Expand Down
Loading