|
| 1 | +# Zero-knowledge proofs |
| 2 | + |
| 3 | +Zero-knowledge proofs (ZK) are a powerful tool to assert that the encryption of a message is correct, as discussed in [advanced features](../../fhe-computation/advanced-features/zk-pok.md). |
| 4 | +However, computation is not possible on verifiable ciphertexts. This document explains how to use the GPU to accelerate the |
| 5 | +preprocessing step needed to convert formatted for ZK to ciphertexts in the right format for computation purposes on GPU. This |
| 6 | +operation is called "expansion". |
| 7 | + |
| 8 | +## Proven compact ciphertext list |
| 9 | + |
| 10 | +A proven compact list of ciphertexts can be seen as a compacted collection of ciphertexts which encryption can be verified. |
| 11 | +This verification is currently only supported on the CPU, but the expansion can be accelerated using the GPU. |
| 12 | +This way, verification and expansion can be performed in parallel, efficiently using all the available computational resources. |
| 13 | + |
| 14 | +## Supported types |
| 15 | +Encrypted messages can be integers (as FheUint64) or booleans. The GPU backend does not currently support encrypted strings. |
| 16 | + |
| 17 | +{% hint style="info" %} |
| 18 | +You can enable this feature using the flag: `--features=zk-pok,gpu` when building **TFHE-rs**. |
| 19 | +{% endhint %} |
| 20 | + |
| 21 | + |
| 22 | +## Example |
| 23 | + |
| 24 | +The following example shows how a client can encrypt and prove a ciphertext, and how a server can verify the proof, preprocess the ciphertext and run a computation on it on GPU: |
| 25 | + |
| 26 | +```rust |
| 27 | +use rand::random; |
| 28 | +use tfhe::CompressedServerKey; |
| 29 | +use tfhe::prelude::*; |
| 30 | +use tfhe::set_server_key; |
| 31 | +use tfhe::zk::{CompactPkeCrs, ZkComputeLoad}; |
| 32 | + |
| 33 | +pub fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 34 | + let params = tfhe::shortint::parameters::PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128; |
| 35 | + // Indicate which parameters to use for the Compact Public Key encryption |
| 36 | + let cpk_params = tfhe::shortint::parameters::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128; |
| 37 | + // And parameters allowing to keyswitch/cast to the computation parameters. |
| 38 | + let casting_params = tfhe::shortint::parameters::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128; |
| 39 | + // Enable the dedicated parameters on the config |
| 40 | + let config = tfhe::ConfigBuilder::with_custom_parameters(params) |
| 41 | + .use_dedicated_compact_public_key_parameters((cpk_params, casting_params)).build(); |
| 42 | + |
| 43 | + // The CRS should be generated in an offline phase then shared to all clients and the server |
| 44 | + let crs = CompactPkeCrs::from_config(config, 64).unwrap(); |
| 45 | + |
| 46 | + // Then use TFHE-rs as usual |
| 47 | + let client_key = tfhe::ClientKey::generate(config); |
| 48 | + let compressed_server_key = CompressedServerKey::new(&client_key); |
| 49 | + let gpu_server_key = compressed_server_key.decompress_to_gpu(); |
| 50 | + let public_key = tfhe::CompactPublicKey::try_new(&client_key).unwrap(); |
| 51 | + // This can be left empty, but if provided allows to tie the proof to arbitrary data |
| 52 | + let metadata = [b'T', b'F', b'H', b'E', b'-', b'r', b's']; |
| 53 | + |
| 54 | + let clear_a = random::<u64>(); |
| 55 | + let clear_b = random::<u64>(); |
| 56 | + |
| 57 | + let proven_compact_list = tfhe::ProvenCompactCiphertextList::builder(&public_key) |
| 58 | + .push(clear_a) |
| 59 | + .push(clear_b) |
| 60 | + .build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Verify)?; |
| 61 | + |
| 62 | + // Server side |
| 63 | + let result = { |
| 64 | + set_server_key(gpu_server_key); |
| 65 | + |
| 66 | + // Verify the ciphertexts |
| 67 | + let expander = |
| 68 | + proven_compact_list.verify_and_expand(&crs, &public_key, &metadata)?; |
| 69 | + let a: tfhe::FheUint64 = expander.get(0)?.unwrap(); |
| 70 | + let b: tfhe::FheUint64 = expander.get(1)?.unwrap(); |
| 71 | + |
| 72 | + a + b |
| 73 | + }; |
| 74 | + |
| 75 | + // Back on the client side |
| 76 | + let a_plus_b: u64 = result.decrypt(&client_key); |
| 77 | + assert_eq!(a_plus_b, clear_a.wrapping_add(clear_b)); |
| 78 | + |
| 79 | + Ok(()) |
| 80 | +} |
| 81 | +``` |
0 commit comments