Zero-knowledge proofs
This document explains how to implement the zero-knowledge proofs function for compact public key encryption to verify the encryption process without revealing the encrypted information.
TFHE-rs can generate zero-knowledge proofs to verify that the compact public key encryption process is correct. In other words, TFHE-rs generates the proof without revealing any information other than the already known range of the encrypted message. This technique is derived from Libert’s work.
Using this feature is straightforward: during encryption, the client generates the proof, and the server validates it before conducting any homomorphic computations. The following example demonstrates how a client can encrypt and prove a ciphertext, and how a server can verify the ciphertext and compute it:
use rand::prelude::*;
use tfhe::prelude::FheDecrypt;
use tfhe::shortint::parameters::DynamicDistribution;
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 max_num_message = 1;
let mut params =
tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_COMPACT_PK_KS_PBS_TUNIFORM_2M40;
let client_key = tfhe::ClientKey::generate(tfhe::ConfigBuilder::with_custom_parameters(params, None));
// This is done in an offline phase and the CRS is shared to all clients and the server
let crs = CompactPkeCrs::from_shortint_params(params, max_num_message).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 a = tfhe::ProvenCompactFheUint64::try_encrypt(
clear_a,
public_zk_params,
&public_key,
ZkComputeLoad::Proof,
)?;
let b = tfhe::ProvenCompactFheUint64::try_encrypt(
clear_b,
public_zk_params,
&public_key,
ZkComputeLoad::Proof,
)?;
// Server side
let result = {
set_server_key(server_key);
// Verify the ciphertexts
let a = a.verify_and_expand(&public_zk_params, &public_key)?;
let b = b.verify_and_expand(&public_zk_params, &public_key)?;
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(())
}
In terms of performance:
Encrypting and proving a
CompactFheUint64
takes 6.9 s on aDell XPS 15 9500
(simulating a client machine).Verification takes 123 ms on an
hpc7a.96xlarge
AWS instances.
Last updated
Was this helpful?