mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-09 14:47:56 -05:00
chore(zk)!: store inside the pke params the supported zk scheme
BREAKING_CHANGE: - Zk for compact PKE now requires dedicated encryption parameters
This commit is contained in:
committed by
Nicolas Sarlin
parent
c19683a320
commit
f06b04fd83
@@ -11,6 +11,8 @@ int main(void) {
|
||||
ShortintPBSParameters params = SHORTINT_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
assert(params.encryption_key_choice == ShortintEncryptionKeyChoiceBig);
|
||||
|
||||
ShortintCompactPublicKeyEncryptionParameters pke_params = SHORTINT_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
|
||||
int status;
|
||||
|
||||
ConfigBuilder *builder;
|
||||
@@ -18,6 +20,8 @@ int main(void) {
|
||||
assert(status == 0);
|
||||
status = config_builder_use_custom_parameters(&builder, params);
|
||||
assert(status == 0);
|
||||
status = use_dedicated_compact_public_key_parameters(&builder, pke_params);
|
||||
assert(status == 0);
|
||||
|
||||
Config *config;
|
||||
status = config_builder_build(builder, &config);
|
||||
|
||||
@@ -10,71 +10,7 @@ You can enable this feature using the flag: `--features=zk-pok` when building **
|
||||
|
||||
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:
|
||||
|
||||
```rust
|
||||
use rand::prelude::*;
|
||||
use tfhe::prelude::*;
|
||||
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;
|
||||
let config = tfhe::ConfigBuilder::with_custom_parameters(params);
|
||||
|
||||
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 server_key = tfhe::ServerKey::new(&client_key);
|
||||
let public_key = tfhe::CompactPublicKey::try_new(&client_key).unwrap();
|
||||
// This can be left empty, but if provided allows to tie the proof to arbitrary data
|
||||
let metadata = [b'T', b'F', b'H', b'E', b'-', b'r', b's'];
|
||||
|
||||
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(&crs, &metadata, ZkComputeLoad::Proof)?;
|
||||
|
||||
// Server side
|
||||
let result = {
|
||||
set_server_key(server_key);
|
||||
|
||||
// Verify the ciphertexts
|
||||
let expander = proven_compact_list.verify_and_expand(&crs, &public_key, &metadata)?;
|
||||
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(())
|
||||
}
|
||||
```
|
||||
|
||||
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:
|
||||
Note that you need to use dedicated parameters for the compact public key encryption. This helps to reduce the size of encrypted data and speed up the zero-knowledge proof computation.
|
||||
|
||||
```rust
|
||||
use rand::prelude::*;
|
||||
@@ -132,5 +68,16 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
```
|
||||
|
||||
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 %}
|
||||
|
||||
## Benchmark
|
||||
Please refer to the [Zero-knowledge proof benchmarks](../getting_started/benchmarks/zk_proof_benchmarks.md) for detailed performance benchmark results.
|
||||
|
||||
@@ -500,14 +500,19 @@ test('hlapi_compact_ciphertext_list', (t) => {
|
||||
|
||||
test('hlapi_compact_ciphertext_list_with_proof', (t) => {
|
||||
const block_params = new ShortintParameters(ShortintParametersName.PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64);
|
||||
let publicKeyParams = new ShortintCompactPublicKeyEncryptionParameters(
|
||||
ShortintCompactPublicKeyEncryptionParametersName.SHORTINT_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64,
|
||||
);
|
||||
|
||||
let config = TfheConfigBuilder.default()
|
||||
.use_custom_parameters(block_params)
|
||||
.use_dedicated_compact_public_key_parameters(publicKeyParams)
|
||||
.build();
|
||||
|
||||
let clientKey = TfheClientKey.generate(config);
|
||||
let publicKey = TfheCompactPublicKey.new(clientKey);
|
||||
|
||||
let crs = CompactPkeCrs.from_parameters(block_params, 2 + 32 + 1 + 256);
|
||||
let crs = CompactPkeCrs.from_config(config, 2 + 32 + 1 + 256);
|
||||
|
||||
const compress = false; // We don't compress as it's too slow on wasm
|
||||
let serialized_pke_crs = crs.serialize(compress);
|
||||
|
||||
@@ -163,6 +163,38 @@ impl ShortintCompactCiphertextListCastingParameters {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum SupportedCompactPkeZkScheme {
|
||||
ZkNotSupported,
|
||||
V1,
|
||||
V2,
|
||||
}
|
||||
|
||||
impl From<SupportedCompactPkeZkScheme>
|
||||
for crate::shortint::parameters::SupportedCompactPkeZkScheme
|
||||
{
|
||||
fn from(value: SupportedCompactPkeZkScheme) -> Self {
|
||||
match value {
|
||||
SupportedCompactPkeZkScheme::ZkNotSupported => Self::ZkNotSupported,
|
||||
SupportedCompactPkeZkScheme::V1 => Self::V1,
|
||||
SupportedCompactPkeZkScheme::V2 => Self::V2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SupportedCompactPkeZkScheme {
|
||||
const fn convert(value: crate::shortint::parameters::SupportedCompactPkeZkScheme) -> Self {
|
||||
match value {
|
||||
crate::shortint::parameters::SupportedCompactPkeZkScheme::ZkNotSupported => {
|
||||
Self::ZkNotSupported
|
||||
}
|
||||
crate::shortint::parameters::SupportedCompactPkeZkScheme::V1 => Self::V1,
|
||||
crate::shortint::parameters::SupportedCompactPkeZkScheme::V2 => Self::V2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ShortintCompactPublicKeyEncryptionParameters {
|
||||
@@ -176,6 +208,7 @@ pub struct ShortintCompactPublicKeyEncryptionParameters {
|
||||
// these parameters will always require casting, as they always require casting we add a field
|
||||
// for the casting parameters here.
|
||||
pub casting_parameters: ShortintCompactCiphertextListCastingParameters,
|
||||
pub zk_scheme: SupportedCompactPkeZkScheme,
|
||||
}
|
||||
|
||||
impl TryFrom<ShortintCompactPublicKeyEncryptionParameters>
|
||||
@@ -196,6 +229,7 @@ impl TryFrom<ShortintCompactPublicKeyEncryptionParameters>
|
||||
)?,
|
||||
expansion_kind:
|
||||
crate::shortint::parameters::CompactCiphertextListExpansionKind::RequiresCasting,
|
||||
zk_scheme: c_params.zk_scheme.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -233,6 +267,7 @@ impl ShortintCompactPublicKeyEncryptionParameters {
|
||||
casting_parameters: ShortintCompactCiphertextListCastingParameters::convert(
|
||||
casting_parameters,
|
||||
),
|
||||
zk_scheme: SupportedCompactPkeZkScheme::convert(compact_pke_params.zk_scheme),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,39 +315,6 @@ mod zk {
|
||||
fn conformance_zk_compact_ciphertext_list() {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let params: crate::shortint::ClassicPBSParameters =
|
||||
crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
let config = crate::ConfigBuilder::with_custom_parameters(params);
|
||||
|
||||
let client_key = crate::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_key = crate::CompactPublicKey::try_new(&client_key).unwrap();
|
||||
// This can be left empty, but if provided allows to tie the proof to arbitrary data
|
||||
let metadata = [b'T', b'F', b'H', b'E', b'-', b'r', b's'];
|
||||
|
||||
let clear_a = rng.gen::<u64>();
|
||||
let clear_b = rng.gen::<bool>();
|
||||
|
||||
let proven_compact_list = crate::ProvenCompactCiphertextList::builder(&public_key)
|
||||
.push(clear_a)
|
||||
.push(clear_b)
|
||||
.build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof)
|
||||
.unwrap();
|
||||
|
||||
let params =
|
||||
IntegerProvenCompactCiphertextListConformanceParams::from_crs_and_parameters(
|
||||
params.try_into().unwrap(),
|
||||
&crs,
|
||||
);
|
||||
|
||||
assert!(proven_compact_list.is_conformant(¶ms));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conformance_zk_compact_ciphertext_list_casting() {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let params = crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
|
||||
let cpk_params = crate::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
@@ -637,89 +604,6 @@ mod tests {
|
||||
#[cfg(feature = "zk-pok")]
|
||||
#[test]
|
||||
fn test_proven_compact_list() {
|
||||
use crate::shortint::parameters::classic::tuniform::p_fail_2_minus_64::ks_pbs::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
|
||||
let config = crate::ConfigBuilder::with_custom_parameters(
|
||||
PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64,
|
||||
)
|
||||
.build();
|
||||
|
||||
let ck = crate::ClientKey::generate(config);
|
||||
let pk = crate::CompactPublicKey::new(&ck);
|
||||
let sks = crate::ServerKey::new(&ck);
|
||||
|
||||
set_server_key(sks);
|
||||
|
||||
// Intentionally low to that we test when multiple lists and proofs are needed
|
||||
let crs = CompactPkeCrs::from_config(config, 32).unwrap();
|
||||
|
||||
let metadata = [b'h', b'l', b'a', b'p', b'i'];
|
||||
|
||||
let compact_list = ProvenCompactCiphertextList::builder(&pk)
|
||||
.push(17u32)
|
||||
.push(-1i64)
|
||||
.push(false)
|
||||
.push_with_num_bits(3u32, 2)
|
||||
.unwrap()
|
||||
.build_with_proof_packed(&crs, &metadata, ZkComputeLoad::Proof)
|
||||
.unwrap();
|
||||
|
||||
let serialized = bincode::serialize(&compact_list).unwrap();
|
||||
let compact_list: ProvenCompactCiphertextList = bincode::deserialize(&serialized).unwrap();
|
||||
let expander = compact_list
|
||||
.verify_and_expand(&crs, &pk, &metadata)
|
||||
.unwrap();
|
||||
|
||||
{
|
||||
let a: FheUint32 = expander.get(0).unwrap().unwrap();
|
||||
let b: FheInt64 = expander.get(1).unwrap().unwrap();
|
||||
let c: FheBool = expander.get(2).unwrap().unwrap();
|
||||
let d: FheUint2 = expander.get(3).unwrap().unwrap();
|
||||
|
||||
let a: u32 = a.decrypt(&ck);
|
||||
assert_eq!(a, 17);
|
||||
let b: i64 = b.decrypt(&ck);
|
||||
assert_eq!(b, -1);
|
||||
let c = c.decrypt(&ck);
|
||||
assert!(!c);
|
||||
let d: u8 = d.decrypt(&ck);
|
||||
assert_eq!(d, 3);
|
||||
|
||||
assert!(expander.get::<FheBool>(4).unwrap().is_none());
|
||||
}
|
||||
|
||||
{
|
||||
// Incorrect type
|
||||
assert!(expander.get::<FheInt64>(0).is_err());
|
||||
|
||||
// Correct type but wrong number of bits
|
||||
assert!(expander.get::<FheUint16>(0).is_err());
|
||||
}
|
||||
|
||||
let unverified_expander = compact_list.expand_without_verification().unwrap();
|
||||
|
||||
{
|
||||
let a: FheUint32 = unverified_expander.get(0).unwrap().unwrap();
|
||||
let b: FheInt64 = unverified_expander.get(1).unwrap().unwrap();
|
||||
let c: FheBool = unverified_expander.get(2).unwrap().unwrap();
|
||||
let d: FheUint2 = unverified_expander.get(3).unwrap().unwrap();
|
||||
|
||||
let a: u32 = a.decrypt(&ck);
|
||||
assert_eq!(a, 17);
|
||||
let b: i64 = b.decrypt(&ck);
|
||||
assert_eq!(b, -1);
|
||||
let c = c.decrypt(&ck);
|
||||
assert!(!c);
|
||||
let d: u8 = d.decrypt(&ck);
|
||||
assert_eq!(d, 3);
|
||||
|
||||
assert!(unverified_expander.get::<FheBool>(4).unwrap().is_none());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "zk-pok")]
|
||||
#[test]
|
||||
fn test_proven_compact_list_with_casting() {
|
||||
use crate::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
use crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
use crate::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
|
||||
@@ -36,7 +36,12 @@ fn test_tag_propagation_zk_pok() {
|
||||
use crate::ProvenCompactCiphertextList;
|
||||
|
||||
let config =
|
||||
ConfigBuilder::with_custom_parameters(PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64).build();
|
||||
ConfigBuilder::with_custom_parameters(PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64)
|
||||
.use_dedicated_compact_public_key_parameters((
|
||||
V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64,
|
||||
V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64,
|
||||
))
|
||||
.build();
|
||||
let crs = crate::zk::CompactPkeCrs::from_config(config, (2 * 32) + (2 * 64) + 2).unwrap();
|
||||
|
||||
let metadata = [b'h', b'l', b'a', b'p', b'i'];
|
||||
|
||||
@@ -1164,9 +1164,7 @@ mod tests {
|
||||
.checked_pow(num_blocks as u32)
|
||||
.unwrap();
|
||||
|
||||
let crs =
|
||||
CompactPkeCrs::from_shortint_params_legacy_v1(pke_params, LweCiphertextCount(512))
|
||||
.unwrap();
|
||||
let crs = CompactPkeCrs::from_shortint_params(pke_params, LweCiphertextCount(512)).unwrap();
|
||||
let cks = ClientKey::new(fhe_params);
|
||||
let sk = ServerKey::new_radix_server_key(&cks);
|
||||
let compact_private_key = CompactPrivateKey::new(pke_params);
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use crate::core_crypto::prelude::LweCiphertextCount;
|
||||
use crate::js_on_wasm_api::js_high_level_api::config::TfheConfig;
|
||||
use crate::js_on_wasm_api::js_high_level_api::{catch_panic_result, into_js_error};
|
||||
use crate::js_on_wasm_api::shortint::ShortintParameters;
|
||||
|
||||
use crate::zk::Compressible;
|
||||
|
||||
@@ -79,21 +77,6 @@ impl CompactPkeCrs {
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn from_parameters(
|
||||
parameters: &ShortintParameters,
|
||||
max_num_message: usize,
|
||||
) -> Result<CompactPkeCrs, JsError> {
|
||||
catch_panic_result(|| {
|
||||
crate::core_crypto::entities::CompactPkeCrs::from_shortint_params(
|
||||
parameters.0,
|
||||
LweCiphertextCount(max_num_message),
|
||||
)
|
||||
.map(CompactPkeCrs)
|
||||
.map_err(into_js_error)
|
||||
})
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn from_config(config: &TfheConfig, max_num_bits: usize) -> Result<CompactPkeCrs, JsError> {
|
||||
catch_panic_result(|| {
|
||||
|
||||
@@ -258,7 +258,8 @@ impl ShortintCompactPublicKeyEncryptionParameters {
|
||||
CarryModulus(carry_modulus),
|
||||
ciphertext_modulus,
|
||||
// These parameters always requires casting
|
||||
crate::shortint::parameters::CompactCiphertextListExpansionKind::RequiresCasting
|
||||
crate::shortint::parameters::CompactCiphertextListExpansionKind::RequiresCasting,
|
||||
crate::shortint::parameters::SupportedCompactPkeZkScheme::ZkNotSupported
|
||||
).map_err(into_js_error)?;
|
||||
|
||||
let casting_parameters =
|
||||
|
||||
@@ -1,14 +1,47 @@
|
||||
use tfhe_versionable::VersionsDispatch;
|
||||
use std::convert::Infallible;
|
||||
|
||||
use tfhe_versionable::{Upgrade, Version, VersionsDispatch};
|
||||
|
||||
use super::parameters::compact_public_key_only::CompactPublicKeyEncryptionParameters;
|
||||
use super::parameters::CompactCiphertextListExpansionKind;
|
||||
use super::parameters::{
|
||||
CompactCiphertextListExpansionKind, DynamicDistribution, SupportedCompactPkeZkScheme,
|
||||
};
|
||||
use super::prelude::*;
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum CompactCiphertextListExpansionKindVersions {
|
||||
V0(CompactCiphertextListExpansionKind),
|
||||
}
|
||||
|
||||
#[derive(Version)]
|
||||
pub struct CompactPublicKeyEncryptionParametersV0 {
|
||||
pub encryption_lwe_dimension: LweDimension,
|
||||
pub encryption_noise_distribution: DynamicDistribution<u64>,
|
||||
pub message_modulus: MessageModulus,
|
||||
pub carry_modulus: CarryModulus,
|
||||
pub ciphertext_modulus: CiphertextModulus,
|
||||
pub expansion_kind: CompactCiphertextListExpansionKind,
|
||||
}
|
||||
|
||||
impl Upgrade<CompactPublicKeyEncryptionParameters> for CompactPublicKeyEncryptionParametersV0 {
|
||||
type Error = Infallible;
|
||||
|
||||
fn upgrade(self) -> Result<CompactPublicKeyEncryptionParameters, Self::Error> {
|
||||
Ok(CompactPublicKeyEncryptionParameters {
|
||||
encryption_lwe_dimension: self.encryption_lwe_dimension,
|
||||
encryption_noise_distribution: self.encryption_noise_distribution,
|
||||
message_modulus: self.message_modulus,
|
||||
carry_modulus: self.carry_modulus,
|
||||
ciphertext_modulus: self.ciphertext_modulus,
|
||||
expansion_kind: self.expansion_kind,
|
||||
// TFHE-rs v0.10 and before used only the v1 zk scheme
|
||||
zk_scheme: SupportedCompactPkeZkScheme::V1,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum CompactPublicKeyEncryptionParametersVersions {
|
||||
V0(CompactPublicKeyEncryptionParameters),
|
||||
V0(CompactPublicKeyEncryptionParametersV0),
|
||||
V1(CompactPublicKeyEncryptionParameters),
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ pub mod list_compression;
|
||||
|
||||
use tfhe_versionable::VersionsDispatch;
|
||||
|
||||
use crate::shortint::parameters::ShortintParameterSetInner;
|
||||
use crate::shortint::parameters::*;
|
||||
use crate::shortint::*;
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
@@ -47,3 +47,8 @@ pub enum MultiBitPBSParametersVersions {
|
||||
pub enum WopbsParametersVersions {
|
||||
V0(WopbsParameters),
|
||||
}
|
||||
|
||||
#[derive(VersionsDispatch)]
|
||||
pub enum SupportedCompactPkeZkSchemeVersions {
|
||||
V0(SupportedCompactPkeZkScheme),
|
||||
}
|
||||
|
||||
@@ -7,13 +7,14 @@ use crate::shortint::ciphertext::CompactCiphertextList;
|
||||
use crate::shortint::parameters::{
|
||||
CarryModulus, CiphertextListConformanceParams, CiphertextModulus,
|
||||
CompactCiphertextListExpansionKind, CompactPublicKeyEncryptionParameters, LweDimension,
|
||||
MessageModulus, ShortintCompactCiphertextListCastingMode,
|
||||
MessageModulus, ShortintCompactCiphertextListCastingMode, SupportedCompactPkeZkScheme,
|
||||
};
|
||||
use crate::shortint::{Ciphertext, CompactPublicKey};
|
||||
use crate::zk::{
|
||||
CompactPkeCrs, CompactPkeProof, CompactPkeZkScheme, ZkMSBZeroPaddingBitCount,
|
||||
ZkVerificationOutcome,
|
||||
};
|
||||
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tfhe_versionable::Versionize;
|
||||
@@ -21,7 +22,8 @@ use tfhe_versionable::Versionize;
|
||||
impl CompactPkeCrs {
|
||||
/// Construct the CRS that corresponds to the given parameters
|
||||
///
|
||||
/// max_num_message is how many message a single proof can prove
|
||||
/// max_num_message is how many message a single proof can prove.
|
||||
/// The version of the zk scheme is based on the [`CompactPkeZkScheme`] value in the params.
|
||||
pub fn from_shortint_params<P, E>(
|
||||
params: P,
|
||||
max_num_message: LweCiphertextCount,
|
||||
@@ -43,51 +45,29 @@ impl CompactPkeCrs {
|
||||
// 1 padding bit for the PBS
|
||||
// Note that if we want to we can prove carry bits are 0 should we need it
|
||||
crate::shortint::engine::ShortintEngine::with_thread_local_mut(|engine| {
|
||||
Self::new(
|
||||
size,
|
||||
max_num_message,
|
||||
noise_distribution,
|
||||
params.ciphertext_modulus,
|
||||
plaintext_modulus,
|
||||
ZkMSBZeroPaddingBitCount(1),
|
||||
&mut engine.random_generator,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Construct the CRS for the legacy V1 zk scheme that corresponds to the given parameters
|
||||
///
|
||||
/// max_num_message is how many message a single proof can prove
|
||||
pub fn from_shortint_params_legacy_v1<P, E>(
|
||||
params: P,
|
||||
max_num_message: LweCiphertextCount,
|
||||
) -> crate::Result<Self>
|
||||
where
|
||||
P: TryInto<CompactPublicKeyEncryptionParameters, Error = E>,
|
||||
crate::Error: From<E>,
|
||||
{
|
||||
let params: CompactPublicKeyEncryptionParameters = params.try_into()?;
|
||||
let (size, noise_distribution) = (
|
||||
params.encryption_lwe_dimension,
|
||||
params.encryption_noise_distribution,
|
||||
);
|
||||
|
||||
let mut plaintext_modulus = params.message_modulus.0 * params.carry_modulus.0;
|
||||
// Our plaintext modulus does not take into account the bit of padding
|
||||
plaintext_modulus *= 2;
|
||||
|
||||
// 1 padding bit for the PBS
|
||||
// Note that if we want to we can prove carry bits are 0 should we need it
|
||||
crate::shortint::engine::ShortintEngine::with_thread_local_mut(|engine| {
|
||||
Self::new_legacy_v1(
|
||||
size,
|
||||
max_num_message,
|
||||
noise_distribution,
|
||||
params.ciphertext_modulus,
|
||||
plaintext_modulus,
|
||||
ZkMSBZeroPaddingBitCount(1),
|
||||
&mut engine.random_generator,
|
||||
)
|
||||
match params.zk_scheme {
|
||||
SupportedCompactPkeZkScheme::V1 => Self::new_legacy_v1(
|
||||
size,
|
||||
max_num_message,
|
||||
noise_distribution,
|
||||
params.ciphertext_modulus,
|
||||
plaintext_modulus,
|
||||
ZkMSBZeroPaddingBitCount(1),
|
||||
&mut engine.random_generator,
|
||||
),
|
||||
SupportedCompactPkeZkScheme::V2 => Self::new(
|
||||
size,
|
||||
max_num_message,
|
||||
noise_distribution,
|
||||
params.ciphertext_modulus,
|
||||
plaintext_modulus,
|
||||
ZkMSBZeroPaddingBitCount(1),
|
||||
&mut engine.random_generator,
|
||||
),
|
||||
SupportedCompactPkeZkScheme::ZkNotSupported => {
|
||||
Err("Zk proof of encryption is not supported by the provided parameters".into())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -317,28 +297,42 @@ impl ParameterSetConformant for ProvenCompactCiphertextList {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::core_crypto::prelude::LweCiphertextCount;
|
||||
use crate::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
use crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
use crate::shortint::parameters::{
|
||||
ShortintCompactCiphertextListCastingMode, PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64,
|
||||
};
|
||||
use crate::shortint::{ClientKey, CompactPublicKey};
|
||||
use crate::shortint::{
|
||||
ClientKey, CompactPrivateKey, CompactPublicKey, KeySwitchingKey, ServerKey,
|
||||
};
|
||||
use crate::zk::{CompactPkeCrs, ZkComputeLoad};
|
||||
use rand::random;
|
||||
|
||||
#[test]
|
||||
fn test_zk_ciphertext_encryption_ci_run_filter() {
|
||||
let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
let pke_params = V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
let ksk_params = V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
|
||||
let crs = CompactPkeCrs::from_shortint_params(params, LweCiphertextCount(4)).unwrap();
|
||||
let cks = ClientKey::new(params);
|
||||
let pk = CompactPublicKey::new(&cks);
|
||||
let crs = CompactPkeCrs::from_shortint_params(pke_params, LweCiphertextCount(4)).unwrap();
|
||||
let priv_key = CompactPrivateKey::new(pke_params);
|
||||
let pub_key = CompactPublicKey::new(&priv_key);
|
||||
let ck = ClientKey::new(params);
|
||||
let sk = ServerKey::new(&ck);
|
||||
let ksk = KeySwitchingKey::new((&priv_key, None), (&ck, &sk), ksk_params);
|
||||
|
||||
let id = |x: u64| x;
|
||||
let dyn_id: &(dyn Fn(u64) -> u64 + Sync) = &id;
|
||||
|
||||
let functions = vec![Some(vec![dyn_id; 1]); 1];
|
||||
|
||||
let metadata = [b's', b'h', b'o', b'r', b't', b'i', b'n', b't'];
|
||||
|
||||
let msg = random::<u64>() % params.message_modulus.0;
|
||||
let msg = random::<u64>() % pke_params.message_modulus.0;
|
||||
// No packing
|
||||
let encryption_modulus = params.message_modulus.0;
|
||||
let encryption_modulus = pke_params.message_modulus.0;
|
||||
|
||||
let proven_ct = pk
|
||||
let proven_ct = pub_key
|
||||
.encrypt_and_prove(
|
||||
msg,
|
||||
&crs,
|
||||
@@ -349,35 +343,50 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
{
|
||||
let unproven_ct = proven_ct
|
||||
.expand_without_verification(ShortintCompactCiphertextListCastingMode::NoCasting);
|
||||
assert!(unproven_ct.is_ok());
|
||||
let unproven_ct = proven_ct.expand_without_verification(
|
||||
ShortintCompactCiphertextListCastingMode::CastIfNecessary {
|
||||
casting_key: ksk.as_view(),
|
||||
functions: Some(functions.as_slice()),
|
||||
},
|
||||
);
|
||||
let unproven_ct = unproven_ct.unwrap();
|
||||
|
||||
let decrypted = cks.decrypt(&unproven_ct[0]);
|
||||
let decrypted = ck.decrypt(&unproven_ct[0]);
|
||||
assert_eq!(msg, decrypted);
|
||||
}
|
||||
|
||||
let proven_ct = proven_ct.verify_and_expand(
|
||||
&crs,
|
||||
&pk,
|
||||
&pub_key,
|
||||
&metadata,
|
||||
ShortintCompactCiphertextListCastingMode::NoCasting,
|
||||
ShortintCompactCiphertextListCastingMode::CastIfNecessary {
|
||||
casting_key: ksk.as_view(),
|
||||
functions: Some(functions.as_slice()),
|
||||
},
|
||||
);
|
||||
assert!(proven_ct.is_ok());
|
||||
let proven_ct = proven_ct.unwrap();
|
||||
|
||||
let decrypted = cks.decrypt(&proven_ct[0]);
|
||||
let decrypted = ck.decrypt(&proven_ct[0]);
|
||||
assert_eq!(msg, decrypted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zk_compact_ciphertext_list_encryption_ci_run_filter() {
|
||||
let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
let pke_params = V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
let ksk_params = V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
|
||||
let crs = CompactPkeCrs::from_shortint_params(params, LweCiphertextCount(512)).unwrap();
|
||||
let cks = ClientKey::new(params);
|
||||
let pk = CompactPublicKey::new(&cks);
|
||||
let crs = CompactPkeCrs::from_shortint_params(pke_params, LweCiphertextCount(4)).unwrap();
|
||||
let priv_key = CompactPrivateKey::new(pke_params);
|
||||
let pub_key = CompactPublicKey::new(&priv_key);
|
||||
let ck = ClientKey::new(params);
|
||||
let sk = ServerKey::new(&ck);
|
||||
let ksk = KeySwitchingKey::new((&priv_key, None), (&ck, &sk), ksk_params);
|
||||
|
||||
let id = |x: u64| x;
|
||||
let dyn_id: &(dyn Fn(u64) -> u64 + Sync) = &id;
|
||||
|
||||
let functions = vec![Some(vec![dyn_id; 1]); 512];
|
||||
|
||||
let metadata = [b's', b'h', b'o', b'r', b't', b'i', b'n', b't'];
|
||||
|
||||
@@ -385,7 +394,7 @@ mod tests {
|
||||
.map(|_| random::<u64>() % params.message_modulus.0)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let proven_ct = pk
|
||||
let proven_ct = pub_key
|
||||
.encrypt_and_prove_slice(
|
||||
&msgs,
|
||||
&crs,
|
||||
@@ -394,19 +403,22 @@ mod tests {
|
||||
params.message_modulus.0,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(proven_ct.verify(&crs, &pk, &metadata).is_valid());
|
||||
assert!(proven_ct.verify(&crs, &pub_key, &metadata).is_valid());
|
||||
|
||||
let expanded = proven_ct
|
||||
.verify_and_expand(
|
||||
&crs,
|
||||
&pk,
|
||||
&pub_key,
|
||||
&metadata,
|
||||
ShortintCompactCiphertextListCastingMode::NoCasting,
|
||||
ShortintCompactCiphertextListCastingMode::CastIfNecessary {
|
||||
casting_key: ksk.as_view(),
|
||||
functions: Some(functions.as_slice()),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let decrypted = expanded
|
||||
.iter()
|
||||
.map(|ciphertext| cks.decrypt(ciphertext))
|
||||
.map(|ciphertext| ck.decrypt(ciphertext))
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(msgs, decrypted);
|
||||
}
|
||||
|
||||
@@ -7,9 +7,10 @@ use crate::shortint::backward_compatibility::parameters::compact_public_key_only
|
||||
};
|
||||
use crate::shortint::parameters::{
|
||||
CarryModulus, ClassicPBSParameters, MessageModulus, MultiBitPBSParameters, PBSParameters,
|
||||
ShortintParameterSet,
|
||||
ShortintParameterSet, SupportedCompactPkeZkScheme,
|
||||
};
|
||||
use crate::shortint::KeySwitchingKeyView;
|
||||
|
||||
use crate::Error;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tfhe_versionable::Versionize;
|
||||
@@ -50,6 +51,8 @@ pub struct CompactPublicKeyEncryptionParameters {
|
||||
pub carry_modulus: CarryModulus,
|
||||
pub ciphertext_modulus: CiphertextModulus,
|
||||
pub expansion_kind: CompactCiphertextListExpansionKind,
|
||||
// Version of the PKE zk scheme compatible with these parameters
|
||||
pub zk_scheme: SupportedCompactPkeZkScheme,
|
||||
}
|
||||
|
||||
impl CompactPublicKeyEncryptionParameters {
|
||||
@@ -60,6 +63,7 @@ impl CompactPublicKeyEncryptionParameters {
|
||||
carry_modulus: CarryModulus,
|
||||
ciphertext_modulus: CiphertextModulus,
|
||||
output_ciphertext_kind: CompactCiphertextListExpansionKind,
|
||||
zk_scheme: SupportedCompactPkeZkScheme,
|
||||
) -> Result<Self, Error> {
|
||||
let parameters = Self {
|
||||
encryption_lwe_dimension,
|
||||
@@ -68,6 +72,7 @@ impl CompactPublicKeyEncryptionParameters {
|
||||
carry_modulus,
|
||||
ciphertext_modulus,
|
||||
expansion_kind: output_ciphertext_kind,
|
||||
zk_scheme,
|
||||
};
|
||||
|
||||
if !parameters.is_valid() {
|
||||
@@ -126,6 +131,8 @@ impl TryFrom<ShortintParameterSet> for CompactPublicKeyEncryptionParameters {
|
||||
carry_modulus,
|
||||
ciphertext_modulus,
|
||||
output_ciphertext_kind,
|
||||
// Zk needs specific pke parameters
|
||||
SupportedCompactPkeZkScheme::ZkNotSupported,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::core_crypto::commons::parameters::{
|
||||
};
|
||||
use crate::shortint::parameters::{
|
||||
CarryModulus, CompactCiphertextListExpansionKind, CompactPublicKeyEncryptionParameters,
|
||||
MessageModulus,
|
||||
MessageModulus, SupportedCompactPkeZkScheme,
|
||||
};
|
||||
|
||||
/// This parameter set should be used when doing zk proof of public key encryption
|
||||
@@ -19,6 +19,7 @@ pub const V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64_ZKV2:
|
||||
carry_modulus: CarryModulus(4),
|
||||
ciphertext_modulus: CiphertextModulus::new_native(),
|
||||
expansion_kind: CompactCiphertextListExpansionKind::RequiresCasting,
|
||||
zk_scheme: SupportedCompactPkeZkScheme::V2,
|
||||
}
|
||||
.validate();
|
||||
|
||||
@@ -33,6 +34,7 @@ pub const V0_11_PARAM_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64_ZKV1:
|
||||
carry_modulus: CarryModulus(4),
|
||||
ciphertext_modulus: CiphertextModulus::new_native(),
|
||||
expansion_kind: CompactCiphertextListExpansionKind::RequiresCasting,
|
||||
zk_scheme: SupportedCompactPkeZkScheme::V1,
|
||||
}
|
||||
.validate();
|
||||
|
||||
@@ -46,5 +48,6 @@ pub const V0_11_PARAM_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64_ZKV1:
|
||||
carry_modulus: CarryModulus(4),
|
||||
ciphertext_modulus: CiphertextModulus::new_native(),
|
||||
expansion_kind: CompactCiphertextListExpansionKind::RequiresCasting,
|
||||
zk_scheme: SupportedCompactPkeZkScheme::V1,
|
||||
}
|
||||
.validate();
|
||||
|
||||
@@ -17,6 +17,8 @@ use crate::core_crypto::prelude::{
|
||||
LweCiphertextListParameters, LweCiphertextParameters, MsDecompressionType,
|
||||
};
|
||||
use crate::shortint::backward_compatibility::parameters::*;
|
||||
#[cfg(feature = "zk-pok")]
|
||||
use crate::zk::CompactPkeZkScheme;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use tfhe_versionable::Versionize;
|
||||
@@ -793,3 +795,29 @@ pub const COMP_PARAM_MESSAGE_2_CARRY_2: CompressionParameters = COMP_PARAM_MESSA
|
||||
// GPU
|
||||
pub const PARAM_GPU_MULTI_BIT_MESSAGE_2_CARRY_2_GROUP_3_KS_PBS: MultiBitPBSParameters =
|
||||
PARAM_GPU_MULTI_BIT_GROUP_3_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64;
|
||||
|
||||
/// The Zk scheme for compact private key encryption supported by these parameters.
|
||||
///
|
||||
/// The Zk Scheme is available in 2 versions. In case of doubt, you should prefer the V2 which is
|
||||
/// more efficient.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Versionize)]
|
||||
#[versionize(SupportedCompactPkeZkSchemeVersions)]
|
||||
pub enum SupportedCompactPkeZkScheme {
|
||||
/// The given parameters do not support zk proof of encryption
|
||||
ZkNotSupported,
|
||||
V1,
|
||||
V2,
|
||||
}
|
||||
|
||||
#[cfg(feature = "zk-pok")]
|
||||
impl TryFrom<SupportedCompactPkeZkScheme> for CompactPkeZkScheme {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: SupportedCompactPkeZkScheme) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
SupportedCompactPkeZkScheme::ZkNotSupported => Err(()),
|
||||
SupportedCompactPkeZkScheme::V1 => Ok(Self::V1),
|
||||
SupportedCompactPkeZkScheme::V2 => Ok(Self::V2),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::core_crypto::commons::parameters::{
|
||||
};
|
||||
use crate::shortint::parameters::{
|
||||
CarryModulus, CompactCiphertextListExpansionKind, CompactPublicKeyEncryptionParameters,
|
||||
MessageModulus,
|
||||
MessageModulus, SupportedCompactPkeZkScheme,
|
||||
};
|
||||
|
||||
/// This legacy parameter set were used with the v1 pke zk scheme on TFHE-rs v0.10 and lower
|
||||
@@ -15,5 +15,6 @@ pub const V0_10_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64_ZKV1:
|
||||
carry_modulus: CarryModulus(4),
|
||||
ciphertext_modulus: CiphertextModulus::new_native(),
|
||||
expansion_kind: CompactCiphertextListExpansionKind::RequiresCasting,
|
||||
zk_scheme: SupportedCompactPkeZkScheme::V1,
|
||||
}
|
||||
.validate();
|
||||
|
||||
Reference in New Issue
Block a user