From 3e3737eb79becea1a0277f7d5a3c172f15b9e9fd Mon Sep 17 00:00:00 2001 From: Nicolas Sarlin Date: Wed, 4 Dec 2024 10:27:13 +0100 Subject: [PATCH 1/6] feat(versionable): "Version" macro now handles transparent attribute --- .../tfhe-versionable-derive/src/associated.rs | 50 ++++- .../src/dispatch_type.rs | 12 +- .../src/version_type.rs | 173 ++++++++++++++---- .../src/versionize_attribute.rs | 37 +++- .../tfhe-versionable/examples/transparent.rs | 6 +- .../examples/transparent_then_not.rs | 173 ++++++++++++++++++ 6 files changed, 394 insertions(+), 57 deletions(-) create mode 100644 utils/tfhe-versionable/examples/transparent_then_not.rs diff --git a/utils/tfhe-versionable-derive/src/associated.rs b/utils/tfhe-versionable-derive/src/associated.rs index d9e86e3238..a07842e008 100644 --- a/utils/tfhe-versionable-derive/src/associated.rs +++ b/utils/tfhe-versionable-derive/src/associated.rs @@ -94,9 +94,9 @@ pub(crate) enum AssociatedTypeKind { /// [`VersionType`]: crate::dispatch_type::VersionType pub(crate) trait AssociatedType: Sized { /// Bounds that will be added on the fields of the ref type definition - const REF_BOUNDS: &'static [&'static str]; + fn ref_bounds(&self) -> &'static [&'static str]; /// Bounds that will be added on the fields of the owned type definition - const OWNED_BOUNDS: &'static [&'static str]; + fn owned_bounds(&self) -> &'static [&'static str]; /// This will create the alternative of the type that holds a reference to the underlying data fn new_ref(orig_type: &DeriveInput) -> syn::Result; @@ -109,6 +109,10 @@ pub(crate) trait AssociatedType: Sized { /// Returns the kind of associated type, a ref or an owned type fn kind(&self) -> &AssociatedTypeKind; + /// Returns true if the type is transparent and trait implementation is actually deferred to the + /// inner type + fn is_transparent(&self) -> bool; + /// Returns the generics found in the original type definition fn orig_type_generics(&self) -> &Generics; @@ -119,9 +123,9 @@ pub(crate) trait AssociatedType: Sized { if let Some(lifetime) = opt_lifetime { add_lifetime_param(&mut generics, lifetime); } - add_trait_where_clause(&mut generics, self.inner_types()?, Self::REF_BOUNDS)?; + add_trait_where_clause(&mut generics, self.inner_types()?, self.ref_bounds())?; } else { - add_trait_where_clause(&mut generics, self.inner_types()?, Self::OWNED_BOUNDS)?; + add_trait_where_clause(&mut generics, self.inner_types()?, self.owned_bounds())?; } Ok(generics) @@ -254,14 +258,27 @@ impl AssociatingTrait { ) ]}; + let owned_attributes = if self.owned_type.is_transparent() { + quote! { + #[derive(#serialize_trait, #deserialize_trait)] + #[repr(transparent)] + #[serde(bound = "")] + #ignored_lints + } + } else { + quote! { + #[derive(#serialize_trait, #deserialize_trait)] + #[serde(bound = "")] + #ignored_lints + } + }; + // Creates the type declaration. These types are the output of the versioning process, so // they should be serializable. Serde might try to add automatic bounds on the type generics // even if we don't need them, so we use `#[serde(bound = "")]` to disable this. The bounds // on the generated types should be sufficient. let owned_tokens = quote! { - #[derive(#serialize_trait, #deserialize_trait)] - #[serde(bound = "")] - #ignored_lints + #owned_attributes #owned_decla #(#owned_conversion)* @@ -271,10 +288,23 @@ impl AssociatingTrait { let ref_conversion = self.ref_type.generate_conversion()?; + let ref_attributes = if self.ref_type.is_transparent() { + quote! { + #[derive(#serialize_trait)] + #[repr(transparent)] + #[serde(bound = "")] + #ignored_lints + } + } else { + quote! { + #[derive(#serialize_trait)] + #[serde(bound = "")] + #ignored_lints + } + }; + let ref_tokens = quote! { - #[derive(#serialize_trait)] - #[serde(bound = "")] - #ignored_lints + #ref_attributes #ref_decla #(#ref_conversion)* diff --git a/utils/tfhe-versionable-derive/src/dispatch_type.rs b/utils/tfhe-versionable-derive/src/dispatch_type.rs index b2f9363625..c47572afba 100644 --- a/utils/tfhe-versionable-derive/src/dispatch_type.rs +++ b/utils/tfhe-versionable-derive/src/dispatch_type.rs @@ -47,9 +47,13 @@ fn derive_input_to_enum(input: &DeriveInput) -> syn::Result { } impl AssociatedType for DispatchType { - const REF_BOUNDS: &'static [&'static str] = &[VERSION_TRAIT_NAME]; + fn ref_bounds(&self) -> &'static [&'static str] { + &[VERSION_TRAIT_NAME] + } - const OWNED_BOUNDS: &'static [&'static str] = &[VERSION_TRAIT_NAME]; + fn owned_bounds(&self) -> &'static [&'static str] { + &[VERSION_TRAIT_NAME] + } fn new_ref(orig_type: &DeriveInput) -> syn::Result { for lt in orig_type.generics.lifetimes() { @@ -109,6 +113,10 @@ impl AssociatedType for DispatchType { &self.kind } + fn is_transparent(&self) -> bool { + false + } + fn orig_type_generics(&self) -> &Generics { &self.orig_type.generics } diff --git a/utils/tfhe-versionable-derive/src/version_type.rs b/utils/tfhe-versionable-derive/src/version_type.rs index 6725878863..dc4d745b9a 100644 --- a/utils/tfhe-versionable-derive/src/version_type.rs +++ b/utils/tfhe-versionable-derive/src/version_type.rs @@ -15,10 +15,12 @@ use crate::associated::{ generate_from_trait_impl, generate_try_from_trait_impl, AssociatedType, AssociatedTypeKind, ConversionDirection, }; +use crate::versionize_attribute::is_transparent; use crate::{ add_trait_where_clause, parse_const_str, parse_trait_bound, punctuated_from_iter_result, - LIFETIME_NAME, UNVERSIONIZE_ERROR_NAME, UNVERSIONIZE_TRAIT_NAME, VERSIONIZE_OWNED_TRAIT_NAME, - VERSIONIZE_TRAIT_NAME, + INTO_TRAIT_NAME, LIFETIME_NAME, TRY_INTO_TRAIT_NAME, UNVERSIONIZE_ERROR_NAME, + UNVERSIONIZE_TRAIT_NAME, VERSIONIZE_OWNED_TRAIT_NAME, VERSIONIZE_TRAIT_NAME, + VERSION_TRAIT_NAME, }; /// The types generated for a specific version of a given exposed type. These types are identical to @@ -27,13 +29,29 @@ use crate::{ pub(crate) struct VersionType { orig_type: DeriveInput, kind: AssociatedTypeKind, + is_transparent: bool, } impl AssociatedType for VersionType { - const REF_BOUNDS: &'static [&'static str] = &[VERSIONIZE_TRAIT_NAME]; - const OWNED_BOUNDS: &'static [&'static str] = &[VERSIONIZE_OWNED_TRAIT_NAME]; + fn ref_bounds(&self) -> &'static [&'static str] { + if self.is_transparent { + &[VERSION_TRAIT_NAME] + } else { + &[VERSIONIZE_TRAIT_NAME] + } + } + + fn owned_bounds(&self) -> &'static [&'static str] { + if self.is_transparent { + &[VERSION_TRAIT_NAME] + } else { + &[VERSIONIZE_OWNED_TRAIT_NAME] + } + } fn new_ref(orig_type: &DeriveInput) -> syn::Result { + let is_transparent = is_transparent(&orig_type.attrs)?; + let lifetime = if is_unit(orig_type) { None } else { @@ -54,13 +72,17 @@ impl AssociatedType for VersionType { Ok(Self { orig_type: orig_type.clone(), kind: AssociatedTypeKind::Ref(lifetime), + is_transparent, }) } fn new_owned(orig_type: &DeriveInput) -> syn::Result { + let is_transparent = is_transparent(&orig_type.attrs)?; + Ok(Self { orig_type: orig_type.clone(), kind: AssociatedTypeKind::Owned, + is_transparent, }) } @@ -191,6 +213,10 @@ impl AssociatedType for VersionType { &self.kind } + fn is_transparent(&self) -> bool { + self.is_transparent + } + fn orig_type_generics(&self) -> &Generics { &self.orig_type.generics } @@ -198,13 +224,15 @@ impl AssociatedType for VersionType { fn conversion_generics(&self, direction: ConversionDirection) -> syn::Result { let mut generics = self.type_generics()?; - if let ConversionDirection::AssociatedToOrig = direction { - if let AssociatedTypeKind::Owned = &self.kind { - add_trait_where_clause( - &mut generics, - self.inner_types()?, - &[UNVERSIONIZE_TRAIT_NAME], - )?; + if !self.is_transparent { + if let ConversionDirection::AssociatedToOrig = direction { + if let AssociatedTypeKind::Owned = &self.kind { + add_trait_where_clause( + &mut generics, + self.inner_types()?, + &[UNVERSIONIZE_TRAIT_NAME], + )?; + } } } @@ -323,25 +351,46 @@ impl VersionType { fields_iter: I, ) -> impl IntoIterator> + 'a { let kind = self.kind.clone(); + let is_transparent = self.is_transparent; + fields_iter.into_iter().map(move |field| { let unver_ty = field.ty.clone(); - let versionize_trait = parse_trait_bound(VERSIONIZE_TRAIT_NAME)?; - let versionize_owned_trait = parse_trait_bound(VERSIONIZE_OWNED_TRAIT_NAME)?; + if is_transparent { + // If the type is transparent, we reuse the "Version" impl of the inner type + let version_trait = parse_trait_bound(VERSION_TRAIT_NAME)?; - let ty: Type = match &kind { - AssociatedTypeKind::Ref(lifetime) => parse_quote! { - <#unver_ty as #versionize_trait>::Versioned<#lifetime> - }, - AssociatedTypeKind::Owned => parse_quote! { - <#unver_ty as #versionize_owned_trait>::VersionedOwned - }, - }; + let ty: Type = match &kind { + AssociatedTypeKind::Ref(lifetime) => parse_quote! { + <#unver_ty as #version_trait>::Ref<#lifetime> + }, + AssociatedTypeKind::Owned => parse_quote! { + <#unver_ty as #version_trait>::Owned + }, + }; - Ok(Field { - ty, - ..field.clone() - }) + Ok(Field { + ty, + ..field.clone() + }) + } else { + let versionize_trait = parse_trait_bound(VERSIONIZE_TRAIT_NAME)?; + let versionize_owned_trait = parse_trait_bound(VERSIONIZE_OWNED_TRAIT_NAME)?; + + let ty: Type = match &kind { + AssociatedTypeKind::Ref(lifetime) => parse_quote! { + <#unver_ty as #versionize_trait>::Versioned<#lifetime> + }, + AssociatedTypeKind::Owned => parse_quote! { + <#unver_ty as #versionize_owned_trait>::VersionedOwned + }, + }; + + Ok(Field { + ty, + ..field.clone() + }) + } }) } @@ -520,7 +569,11 @@ impl VersionType { let ty = &field.ty; let param = quote! { #arg_ident.#field_ident }; - let rhs = self.generate_constructor_field_rhs(ty, param, false, direction)?; + let rhs = if self.is_transparent() { + self.generate_constructor_transparent_rhs(param, direction)? + } else { + self.generate_constructor_field_rhs(ty, param, false, direction)? + }; Ok(quote! { #field_ident: #rhs @@ -542,12 +595,16 @@ impl VersionType { .map(move |(arg_name, field)| { // Ok to unwrap because the field is named so field.ident is Some let field_ident = field.ident.as_ref().unwrap(); - let rhs = self.generate_constructor_field_rhs( - &field.ty, - quote! {#arg_name}, - true, - direction, - )?; + let rhs = if self.is_transparent() { + self.generate_constructor_transparent_rhs(quote! {#arg_name}, direction)? + } else { + self.generate_constructor_field_rhs( + &field.ty, + quote! {#arg_name}, + true, + direction, + )? + }; Ok(quote! { #field_ident: #rhs }) @@ -596,7 +653,11 @@ impl VersionType { let ty = &field.ty; let param = quote! { #arg_ident.#idx }; - self.generate_constructor_field_rhs(ty, param, false, direction) + if self.is_transparent { + self.generate_constructor_transparent_rhs(param, direction) + } else { + self.generate_constructor_field_rhs(ty, param, false, direction) + } } /// Generates the constructor for the fields of an unnamed enum variant. @@ -612,7 +673,16 @@ impl VersionType { ) -> syn::Result { let fields: syn::Result> = zip(arg_names, fields) .map(move |(arg_name, field)| { - self.generate_constructor_field_rhs(&field.ty, quote! {#arg_name}, true, direction) + if self.is_transparent { + self.generate_constructor_transparent_rhs(quote! {#arg_name}, direction) + } else { + self.generate_constructor_field_rhs( + &field.ty, + quote! {#arg_name}, + true, + direction, + ) + } }) .collect(); let fields = fields?; @@ -664,6 +734,41 @@ panic!("No conversion should be generated between associated ref type to origina }; Ok(field_constructor) } + + fn generate_constructor_transparent_rhs( + &self, + field_param: TokenStream, + direction: ConversionDirection, + ) -> syn::Result { + let into_trait: Path = parse_const_str(INTO_TRAIT_NAME); + let try_into_trait: Path = parse_const_str(TRY_INTO_TRAIT_NAME); + + let field_constructor = match direction { + ConversionDirection::OrigToAssociated => match self.kind { + AssociatedTypeKind::Ref(_) => { + quote! { + #into_trait::into(&#field_param) + } + } + AssociatedTypeKind::Owned => { + quote! { + #into_trait::into(#field_param) + } + } + }, + ConversionDirection::AssociatedToOrig => match self.kind { + AssociatedTypeKind::Ref(_) => { + panic!("No conversion should be generated between associated ref type to original type"); + } + AssociatedTypeKind::Owned => { + quote! { + #try_into_trait::try_into(#field_param)? + } + } + }, + }; + Ok(field_constructor) + } } /// Generates a list of argument names. This is used to create a pattern matching of a diff --git a/utils/tfhe-versionable-derive/src/versionize_attribute.rs b/utils/tfhe-versionable-derive/src/versionize_attribute.rs index f077f3b27b..4629a4a855 100644 --- a/utils/tfhe-versionable-derive/src/versionize_attribute.rs +++ b/utils/tfhe-versionable-derive/src/versionize_attribute.rs @@ -11,7 +11,7 @@ use syn::{Attribute, Expr, Lit, Meta, Path, Token}; const VERSIONIZE_ATTR_NAME: &str = "versionize"; /// Transparent mode can also be activated using `#[repr(transparent)]` -const REPR_ATTR_NAME: &str = "repr"; +pub(crate) const REPR_ATTR_NAME: &str = "repr"; /// Represent the parsed `#[versionize(...)]` attribute pub(crate) enum VersionizeAttribute { @@ -167,16 +167,14 @@ impl VersionizeAttribute { .filter(|attr| attr.path().is_ident(VERSIONIZE_ATTR_NAME)) .collect(); - let repr_attributes: Vec<&Attribute> = attributes - .iter() - .filter(|attr| attr.path().is_ident(REPR_ATTR_NAME)) - .collect(); + // Check if transparent mode is enabled via repr(transparent). It can also be enabled with + // the versionize attribute. + let type_is_transparent = is_transparent(attributes)?; match version_attributes.as_slice() { [] => { - // transparent mode can also be enabled via `#[repr(transparent)]` - if let Some(attr) = repr_attributes.first() { - Self::parse_from_attribute(attr) + if type_is_transparent { + Ok(Self::Transparent) } else { Err(syn::Error::new( Span::call_site(), @@ -298,3 +296,26 @@ fn parse_path_ignore_quotes(value: &Expr) -> syn::Result { )), } } + +/// Check if the target type has the `#[repr(transparent)]` attribute in its attributes list +pub(crate) fn is_transparent(attributes: &[Attribute]) -> syn::Result { + if let Some(attr) = attributes + .iter() + .find(|attr| attr.path().is_ident(REPR_ATTR_NAME)) + { + let nested = attr.parse_args_with(Punctuated::::parse_terminated)?; + + for meta in nested.iter() { + match meta { + Meta::Path(path) => { + if path.is_ident("transparent") { + return Ok(true); + } + } + _ => {} + } + } + } + + Ok(false) +} diff --git a/utils/tfhe-versionable/examples/transparent.rs b/utils/tfhe-versionable/examples/transparent.rs index 007b355399..f2869dc9c5 100644 --- a/utils/tfhe-versionable/examples/transparent.rs +++ b/utils/tfhe-versionable/examples/transparent.rs @@ -48,9 +48,9 @@ enum MyStructVersions { mod v0 { use tfhe_versionable::{Versionize, VersionsDispatch}; - // This struct cannot change as it is not itself versioned. If you ever make a change that - // should impact the serialized layout of the data, you need to update all the types that use - // it. + // If you ever change the layout of this struct to make it "not transparent", you should create + // a MyStructWrapperVersions enum where the first versions are the same than the ones of + // MyStructVersions. See `transparent_then_not.rs` for a full example. #[derive(Versionize)] #[versionize(transparent)] pub(super) struct MyStructWrapper(pub(super) MyStruct); diff --git a/utils/tfhe-versionable/examples/transparent_then_not.rs b/utils/tfhe-versionable/examples/transparent_then_not.rs new file mode 100644 index 0000000000..b01f4d0529 --- /dev/null +++ b/utils/tfhe-versionable/examples/transparent_then_not.rs @@ -0,0 +1,173 @@ +//! This example is similar to the "transparent" one, except that the wrapper type is transparent at +//! a point in time, then converted into its own type that is not transparent. +//! +//! Here we have a type, `MyStructWrapper`, that was a transparent wrapper for `MyStruct` in the v0 +//! and v1 of the application. `MyStruct` has been upgraded between v0 and v1. In v2, +//! `MyStructWrapper` was transformed into an enum. Since it was transparent before, it has no +//! history (dispatch enum) before v2. +//! +//! To make this work, we consider that the inner and the wrapper type share the same history up to +//! the version where the transparent attribute has been removed. + +use std::convert::Infallible; + +use tfhe_versionable::{Unversionize, Upgrade, Version, Versionize, VersionsDispatch}; + +// This type was transparent before, but it has now been transformed to a full type, for example by +// adding a new kind of metadata. +#[derive(Versionize)] +#[versionize(MyStructWrapperVersions)] +struct MyStructWrapper { + inner: MyStruct, + count: u64, +} + +// We need to create a dispatch enum that has the same history as the inner type until the point +// where the wrapper is not transparent anymore. +#[derive(VersionsDispatch)] +#[allow(unused)] +enum MyStructWrapperVersions { + V0(MyStructWrapperV0), + V1(MyStructWrapperV1), + V2(MyStructWrapper), +} + +// We copy the upgrade path of the internal struct for the wrapper for the first 2 versions. To do +// that, we recreate the "transparent" `MyStructWrapper` from v0 and v1 and upgrade them by calling +// the upgrade method of the inner type. +#[derive(Version)] +#[repr(transparent)] +struct MyStructWrapperV0(MyStructV0); + +impl Upgrade> for MyStructWrapperV0 { + type Error = Infallible; + + fn upgrade(self) -> Result, Self::Error> { + Ok(MyStructWrapperV1(self.0.upgrade()?)) + } +} + +// Then we define the upgrade from the last transparent version to the first "full" version +#[derive(Version)] +#[repr(transparent)] +struct MyStructWrapperV1(MyStruct); + +impl Upgrade> for MyStructWrapperV1 { + type Error = Infallible; + + fn upgrade(self) -> Result, Self::Error> { + Ok(MyStructWrapper { + inner: self.0, + count: 0, + }) + } +} + +#[derive(Versionize)] +#[versionize(MyStructVersions)] +struct MyStruct { + attr: T, + builtin: u32, +} + +#[derive(Version)] +struct MyStructV0 { + builtin: u32, +} + +impl Upgrade> for MyStructV0 { + type Error = Infallible; + + fn upgrade(self) -> Result, Self::Error> { + Ok(MyStruct { + attr: T::default(), + builtin: self.builtin, + }) + } +} + +#[derive(VersionsDispatch)] +#[allow(unused)] +enum MyStructVersions { + V0(MyStructV0), + V1(MyStruct), +} + +// v0 of the app defined the type as a transparent wrapper +mod v0 { + use tfhe_versionable::{Versionize, VersionsDispatch}; + + #[derive(Versionize)] + #[versionize(transparent)] + pub(super) struct MyStructWrapper(pub(super) MyStruct); + + #[derive(Versionize)] + #[versionize(MyStructVersions)] + pub(super) struct MyStruct { + pub(super) builtin: u32, + } + + #[derive(VersionsDispatch)] + #[allow(unused)] + pub(super) enum MyStructVersions { + V0(MyStruct), + } +} + +// In v1, MyStructWrapper is still transparent but MyStruct got an upgrade compared to v0. +mod v1 { + use std::convert::Infallible; + + use tfhe_versionable::{Upgrade, Version, Versionize, VersionsDispatch}; + + #[derive(Versionize)] + #[repr(transparent)] + struct MyStructWrapper(MyStruct); + + #[derive(Versionize)] + #[versionize(MyStructVersions)] + struct MyStruct { + attr: T, + builtin: u32, + } + + #[derive(Version)] + struct MyStructV0 { + builtin: u32, + } + + impl Upgrade> for MyStructV0 { + type Error = Infallible; + + fn upgrade(self) -> Result, Self::Error> { + Ok(MyStruct { + attr: T::default(), + builtin: self.builtin, + }) + } + } + + #[derive(VersionsDispatch)] + #[allow(unused)] + enum MyStructVersions { + V0(MyStructV0), + V1(MyStruct), + } +} + +fn main() { + let value = 1234; + let ms = v0::MyStructWrapper(v0::MyStruct { builtin: value }); + + let serialized = bincode::serialize(&ms.versionize()).unwrap(); + + let unserialized = + MyStructWrapper::::unversionize(bincode::deserialize(&serialized).unwrap()).unwrap(); + + assert_eq!(unserialized.inner.builtin, value) +} + +#[test] +fn test() { + main() +} From 2a23976057927bf012274bc729010f788de94fc5 Mon Sep 17 00:00:00 2001 From: Nicolas Sarlin Date: Wed, 4 Dec 2024 10:29:54 +0100 Subject: [PATCH 2/6] fix(zk-pok): missing Versionize for ComputeLoadProofFields --- tfhe-zk-pok/src/backward_compatibility/pke_v2.rs | 6 +++--- tfhe-zk-pok/src/proofs/pke_v2.rs | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/tfhe-zk-pok/src/backward_compatibility/pke_v2.rs b/tfhe-zk-pok/src/backward_compatibility/pke_v2.rs index 43af705592..70894811d6 100644 --- a/tfhe-zk-pok/src/backward_compatibility/pke_v2.rs +++ b/tfhe-zk-pok/src/backward_compatibility/pke_v2.rs @@ -62,8 +62,8 @@ pub enum ProofVersions { } #[derive(VersionsDispatch)] -#[allow(dead_code)] -pub(crate) enum ComputeLoadProofFieldVersions { +pub(crate) enum ComputeLoadProofFieldsVersions { + #[allow(dead_code)] V0(ComputeLoadProofFields), } @@ -132,11 +132,11 @@ where } #[derive(VersionsDispatch)] -#[allow(dead_code)] pub(crate) enum CompressedComputeLoadProofFieldsVersions where G::G1: Compressible, G::G2: Compressible, { + #[allow(dead_code)] V0(CompressedComputeLoadProofFields), } diff --git a/tfhe-zk-pok/src/proofs/pke_v2.rs b/tfhe-zk-pok/src/proofs/pke_v2.rs index b018c85111..4d1a82c2bc 100644 --- a/tfhe-zk-pok/src/proofs/pke_v2.rs +++ b/tfhe-zk-pok/src/proofs/pke_v2.rs @@ -2,7 +2,7 @@ #![allow(non_snake_case)] use super::*; -use crate::backward_compatibility::pke_v2::{CompressedProofVersions, ProofVersions}; +use crate::backward_compatibility::pke_v2::*; use crate::backward_compatibility::BoundVersions; use crate::curve_api::{CompressedG1, CompressedG2}; use crate::four_squares::*; @@ -29,7 +29,7 @@ fn bit_iter(x: u64, nbits: u32) -> impl Iterator { serialize = "PublicParams: Into" ) )] -#[versionize(convert = SerializablePKEv2PublicParams)] +#[versionize(try_convert = SerializablePKEv2PublicParams)] pub struct PublicParams { pub(crate) g_lists: GroupElements, pub(crate) D: usize, @@ -300,7 +300,8 @@ impl Proof { /// These fields can be pre-computed on the prover side in the faster Verifier scheme. If that's the /// case, they should be included in the proof. -#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] +#[derive(Clone, Debug, serde::Serialize, serde::Deserialize, Versionize)] +#[versionize(ComputeLoadProofFieldsVersions)] pub(crate) struct ComputeLoadProofFields { pub(crate) C_hat_h3: G::G2, pub(crate) C_hat_w: G::G2, @@ -332,11 +333,12 @@ where pub(crate) compute_load_proof_fields: Option>, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Versionize)] #[serde(bound( deserialize = "G: Curve, CompressedG1: serde::Deserialize<'de>, CompressedG2: serde::Deserialize<'de>", serialize = "G: Curve, CompressedG1: serde::Serialize, CompressedG2: serde::Serialize" ))] +#[versionize(CompressedComputeLoadProofFieldsVersions)] pub(crate) struct CompressedComputeLoadProofFields where G::G1: Compressible, From f3a62c5b04bcb80bcf2f8404a128466bab6ea48a Mon Sep 17 00:00:00 2001 From: Nicolas Sarlin Date: Wed, 4 Dec 2024 10:32:06 +0100 Subject: [PATCH 3/6] feat(zk)!: plug zk v2 BREAKING CHANGE: - The object ZkVerificationOutCome has been renamed ZkVerificationOutcome. - Conformance of proofs now checks the scheme version of the CRS. This is breaking at the shortint and core_crypto levels, and for manually built integer conformance params. New CRS will be generated with the V2 Scheme by default, but V1 CRS and proofs are still accepted, so this is not breaking. New methods have been added to generate a V1 CRS. --- tfhe/benches/integer/zk_pke.rs | 15 +- tfhe/src/c_api/high_level_api/zk.rs | 11 +- .../core_crypto/algorithms/lwe_encryption.rs | 214 +---- .../lwe_zero_knowledge_verification.rs | 92 +- .../algorithms/test/lwe_encryption.rs | 124 +-- tfhe/src/core_crypto/commons/parameters.rs | 4 +- tfhe/src/high_level_api/compact_list.rs | 2 +- tfhe/src/high_level_api/zk.rs | 6 +- tfhe/src/integer/ciphertext/compact_list.rs | 24 +- .../js_on_wasm_api/js_high_level_api/zk.rs | 7 +- tfhe/src/shortint/ciphertext/zk.rs | 63 +- tfhe/src/shortint/public_key/compact.rs | 2 +- tfhe/src/zk.rs | 417 ---------- tfhe/src/zk/backward_compatibility.rs | 82 ++ tfhe/src/zk/mod.rs | 787 ++++++++++++++++++ .../backward_compatibility/high_level_api.rs | 10 +- tfhe/tests/zk_wasm_x86_test.rs | 4 +- .../src/versionize_attribute.rs | 9 +- 18 files changed, 1100 insertions(+), 773 deletions(-) delete mode 100644 tfhe/src/zk.rs create mode 100644 tfhe/src/zk/backward_compatibility.rs create mode 100644 tfhe/src/zk/mod.rs diff --git a/tfhe/benches/integer/zk_pke.rs b/tfhe/benches/integer/zk_pke.rs index 2c97a64acd..3708a08d6e 100644 --- a/tfhe/benches/integer/zk_pke.rs +++ b/tfhe/benches/integer/zk_pke.rs @@ -8,6 +8,7 @@ use rayon::prelude::*; use std::fs::{File, OpenOptions}; use std::io::Write; use std::path::Path; +use tfhe::core_crypto::prelude::LweCiphertextCount; use tfhe::integer::key_switching_key::KeySwitchingKey; use tfhe::integer::parameters::IntegerCompactCiphertextListExpansionMode; use tfhe::integer::{ClientKey, CompactPrivateKey, CompactPublicKey, ServerKey}; @@ -64,8 +65,11 @@ fn pke_zk_proof(c: &mut Criterion) { let fhe_uint_count = bits / 64; - let crs = - CompactPkeCrs::from_shortint_params(param_pke, num_block * fhe_uint_count).unwrap(); + let crs = CompactPkeCrs::from_shortint_params( + param_pke, + LweCiphertextCount(num_block * fhe_uint_count), + ) + .unwrap(); for compute_load in [ZkComputeLoad::Proof, ZkComputeLoad::Verify] { let zk_load = match compute_load { @@ -183,8 +187,11 @@ fn pke_zk_verify(c: &mut Criterion, results_file: &Path) { let fhe_uint_count = bits / 64; println!("Generating CRS... "); - let crs = - CompactPkeCrs::from_shortint_params(param_pke, num_block * fhe_uint_count).unwrap(); + let crs = CompactPkeCrs::from_shortint_params( + param_pke, + LweCiphertextCount(num_block * fhe_uint_count), + ) + .unwrap(); let shortint_params: PBSParameters = param_fhe.into(); diff --git a/tfhe/src/c_api/high_level_api/zk.rs b/tfhe/src/c_api/high_level_api/zk.rs index 868d025ba9..6c7cc18a03 100644 --- a/tfhe/src/c_api/high_level_api/zk.rs +++ b/tfhe/src/c_api/high_level_api/zk.rs @@ -23,13 +23,6 @@ impl From for crate::zk::ZkComputeLoad { pub struct CompactPkeCrs(pub(crate) crate::core_crypto::entities::CompactPkeCrs); impl_destroy_on_type!(CompactPkeCrs); -// Because we use a repr(transparent) for the CompactPkeCrs, cbindgen will define CompactPkeCrs as -// an alias for CompactPkePublicParams. We need to define this struct even if it will not actually -// be used in the C api. -#[allow(unused)] -pub struct CompactPkePublicParams(pub(crate) crate::core_crypto::entities::CompactPkePublicParams); -impl_destroy_on_type!(CompactPkePublicParams); - /// Serializes the CRS /// /// If compress is true, the data will be compressed (less serialized bytes), however, this makes @@ -144,7 +137,7 @@ pub unsafe extern "C" fn compact_pke_crs_deserialize_from_params( *result = std::ptr::null_mut(); - let deserialized: crate::core_crypto::entities::CompactPkePublicParams = + let deserialized: crate::core_crypto::entities::ZkCompactPkeV1PublicParams = bincode::deserialize(buffer_view.as_slice()).unwrap(); let crs = deserialized.into(); @@ -170,7 +163,7 @@ pub unsafe extern "C" fn compact_pke_crs_safe_deserialize_from_params( let buffer_view: &[u8] = buffer_view.as_slice(); - let deserialized: crate::core_crypto::entities::CompactPkePublicParams = + let deserialized: crate::core_crypto::entities::ZkCompactPkeV1PublicParams = crate::safe_serialization::DeserializationConfig::new(serialized_size_limit) .disable_conformance() .deserialize_from(buffer_view) diff --git a/tfhe/src/core_crypto/algorithms/lwe_encryption.rs b/tfhe/src/core_crypto/algorithms/lwe_encryption.rs index 0e82160348..51eb3238d9 100644 --- a/tfhe/src/core_crypto/algorithms/lwe_encryption.rs +++ b/tfhe/src/core_crypto/algorithms/lwe_encryption.rs @@ -15,8 +15,6 @@ use crate::core_crypto::commons::parameters::*; use crate::core_crypto::commons::traits::*; use crate::core_crypto::entities::*; use rayon::prelude::*; -#[cfg(feature = "zk-pok")] -use tfhe_zk_pok::proofs::pke::{commit, prove}; /// Convenience function to share the core logic of the LWE encryption between all functions needing /// it. @@ -1858,8 +1856,7 @@ where BodyDistribution: BoundedDistribution, KeyCont: Container, { - let public_params = crs.public_params(); - let exclusive_max = public_params.exclusive_max_noise(); + let exclusive_max = crs.exclusive_max_noise(); if Scalar::BITS < 64 && (1u64 << Scalar::BITS) >= exclusive_max { return Err( "The given random distribution would create random values out \ @@ -1893,28 +1890,23 @@ where return Err("Zero knowledge proof do not support moduli greater than 2**64".into()); } - let expected_q = if Scalar::BITS == 64 { - 0u64 - } else { - 164 << Scalar::BITS - }; - - if expected_q != public_params.q { + if ciphertext_modulus != crs.ciphertext_modulus() { return Err("Mismatched modulus between CRS and ciphertexts".into()); } - if ciphertext_count.0 > public_params.k { + if ciphertext_count > crs.max_num_messages() { return Err(format!( "CRS allows at most {} ciphertexts to be proven at once, {} contained in the list", - public_params.k, ciphertext_count.0 + crs.max_num_messages().0, + ciphertext_count.0 ) .into()); } - if lwe_compact_public_key.lwe_dimension().0 > public_params.d { + if lwe_compact_public_key.lwe_dimension() > crs.lwe_dimension() { return Err(format!( "CRS allows a LweDimension of at most {}, current dimension: {}", - public_params.d, + crs.lwe_dimension().0, lwe_compact_public_key.lwe_dimension().0 ) .into()); @@ -1922,10 +1914,10 @@ where // 2**64 /delta == ((2**63) / delta) *2 let plaintext_modulus = ((1u64 << (u64::BITS - 1) as usize) / u64::cast_from(delta)) * 2; - if plaintext_modulus != public_params.t { + if plaintext_modulus != crs.plaintext_modulus() { return Err(format!( "Mismatched plaintext modulus: CRS expects {}, requested modulus: {plaintext_modulus:?}", - public_params.t + crs.plaintext_modulus() ).into()); } @@ -2174,7 +2166,7 @@ pub fn encrypt_lwe_ciphertext_with_compact_public_key< /// /// let crs = CompactPkeCrs::new( /// lwe_dimension, -/// 1, +/// LweCiphertextCount(1), /// glwe_noise_distribution, /// ciphertext_modulus, /// zk_plaintext_modulus, @@ -2291,52 +2283,18 @@ where encryption_generator, ); - let (c1, c2) = output.get_mask_and_body(); - - let (public_commit, private_commit) = commit( - lwe_compact_public_key - .get_mask() - .as_ref() - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - lwe_compact_public_key - .get_body() - .as_ref() - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - c1.as_ref() - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - vec![i64::cast_from(*c2.data)], - binary_random_vector - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - mask_noise - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - vec![i64::cast_from(message.0)], - body_noise - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - crs.public_params(), - random_generator, - ); - - Ok(prove( - (crs.public_params(), &public_commit), - &private_commit, + Ok(crs.prove( + lwe_compact_public_key, + &vec![message.0], + &LweCompactCiphertextList::from_container( + output.as_ref(), + output.lwe_size(), + LweCiphertextCount(1), + output.ciphertext_modulus(), + ), + &binary_random_vector, + &mask_noise, + &body_noise, metadata, load, random_generator, @@ -2652,7 +2610,7 @@ pub fn encrypt_lwe_compact_ciphertext_list_with_compact_public_key< /// /// let crs = CompactPkeCrs::new( /// lwe_dimension, -/// lwe_ciphertext_count.0, +/// lwe_ciphertext_count, /// glwe_noise_distribution, /// ciphertext_modulus, /// zk_plaintext_modulus, @@ -2807,61 +2765,13 @@ where encryption_generator, ); - let (c1, c2) = output.get_mask_and_body_list(); - - let (public_commit, private_commit) = commit( - lwe_compact_public_key - .get_mask() - .as_ref() - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - lwe_compact_public_key - .get_body() - .as_ref() - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - c1.as_ref() - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - c2.as_ref() - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - binary_random_vector - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - mask_noise - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - messages - .as_ref() - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - body_noise - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - crs.public_params(), - random_generator, - ); - - Ok(prove( - (crs.public_params(), &public_commit), - &private_commit, + Ok(crs.prove( + lwe_compact_public_key, + messages, + output, + &binary_random_vector, + &mask_noise, + &body_noise, metadata, load, random_generator, @@ -3186,7 +3096,7 @@ pub fn par_encrypt_lwe_compact_ciphertext_list_with_compact_public_key< /// /// let crs = CompactPkeCrs::new( /// lwe_dimension, -/// lwe_ciphertext_count.0, +/// lwe_ciphertext_count, /// glwe_noise_distribution, /// ciphertext_modulus, /// zk_plaintext_modulus, @@ -3341,61 +3251,13 @@ where encryption_generator, ); - let (c1, c2) = output.get_mask_and_body_list(); - - let (public_commit, private_commit) = commit( - lwe_compact_public_key - .get_mask() - .as_ref() - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - lwe_compact_public_key - .get_body() - .as_ref() - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - c1.as_ref() - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - c2.as_ref() - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - binary_random_vector - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - mask_noise - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - messages - .as_ref() - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - body_noise - .iter() - .copied() - .map(CastFrom::cast_from) - .collect::>(), - crs.public_params(), - random_generator, - ); - - Ok(prove( - (crs.public_params(), &public_commit), - &private_commit, + Ok(crs.prove( + lwe_compact_public_key, + messages, + output, + &binary_random_vector, + &mask_noise, + &body_noise, metadata, load, random_generator, diff --git a/tfhe/src/core_crypto/algorithms/lwe_zero_knowledge_verification.rs b/tfhe/src/core_crypto/algorithms/lwe_zero_knowledge_verification.rs index 529ad681ae..54545b24f7 100644 --- a/tfhe/src/core_crypto/algorithms/lwe_zero_knowledge_verification.rs +++ b/tfhe/src/core_crypto/algorithms/lwe_zero_knowledge_verification.rs @@ -1,7 +1,8 @@ use crate::core_crypto::entities::{LweCompactCiphertextList, LweCompactPublicKey}; -use crate::core_crypto::prelude::{CastFrom, Container, LweCiphertext, UnsignedInteger}; -use crate::zk::{CompactPkeCrs, CompactPkeProof, ZkVerificationOutCome}; -use tfhe_zk_pok::proofs::pke::{verify, PublicCommit}; +use crate::core_crypto::prelude::{ + CastFrom, Container, LweCiphertext, LweCiphertextCount, UnsignedInteger, +}; +use crate::zk::{CompactPkeCrs, CompactPkeProof, ZkVerificationOutcome}; /// Verifies with the given proof that a [`LweCompactCiphertextList`] /// is valid. @@ -11,94 +12,39 @@ pub fn verify_lwe_compact_ciphertext_list( proof: &CompactPkeProof, crs: &CompactPkeCrs, metadata: &[u8], -) -> ZkVerificationOutCome +) -> ZkVerificationOutcome where Scalar: UnsignedInteger, i64: CastFrom, ListCont: Container, KeyCont: Container, { - if Scalar::BITS > 64 { - return ZkVerificationOutCome::Invalid; - } - let public_commit = PublicCommit::new( - compact_public_key - .get_mask() - .as_ref() - .iter() - .copied() - .map(|x| i64::cast_from(x)) - .collect(), - compact_public_key - .get_body() - .as_ref() - .iter() - .copied() - .map(|x| i64::cast_from(x)) - .collect(), - lwe_compact_list - .get_mask_list() - .as_ref() - .iter() - .copied() - .map(|x| i64::cast_from(x)) - .collect(), - lwe_compact_list - .get_body_list() - .as_ref() - .iter() - .copied() - .map(|x| i64::cast_from(x)) - .collect(), - ); - match verify(proof, (crs.public_params(), &public_commit), metadata) { - Ok(_) => ZkVerificationOutCome::Valid, - Err(_) => ZkVerificationOutCome::Invalid, - } + crs.verify(lwe_compact_list, compact_public_key, proof, metadata) } +/// Verifies with the given proof that a single [`LweCiphertext`] is valid. pub fn verify_lwe_ciphertext( lwe_ciphertext: &LweCiphertext, compact_public_key: &LweCompactPublicKey, proof: &CompactPkeProof, crs: &CompactPkeCrs, metadata: &[u8], -) -> ZkVerificationOutCome +) -> ZkVerificationOutcome where Scalar: UnsignedInteger, i64: CastFrom, Cont: Container, KeyCont: Container, { - if Scalar::BITS > 64 { - return ZkVerificationOutCome::Invalid; - } - let public_commit = PublicCommit::new( - compact_public_key - .get_mask() - .as_ref() - .iter() - .copied() - .map(|x| i64::cast_from(x)) - .collect(), - compact_public_key - .get_body() - .as_ref() - .iter() - .copied() - .map(|x| i64::cast_from(x)) - .collect(), - lwe_ciphertext - .get_mask() - .as_ref() - .iter() - .copied() - .map(|x| i64::cast_from(x)) - .collect(), - vec![i64::cast_from(*lwe_ciphertext.get_body().data); 1], - ); - match verify(proof, (crs.public_params(), &public_commit), metadata) { - Ok(_) => ZkVerificationOutCome::Valid, - Err(_) => ZkVerificationOutCome::Invalid, - } + crs.verify( + &LweCompactCiphertextList::from_container( + lwe_ciphertext.as_ref(), + lwe_ciphertext.lwe_size(), + LweCiphertextCount(1), + lwe_ciphertext.ciphertext_modulus(), + ), + compact_public_key, + proof, + metadata, + ) } diff --git a/tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs b/tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs index 6b5f09adb9..51d3922607 100644 --- a/tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs +++ b/tfhe/src/core_crypto/algorithms/test/lwe_encryption.rs @@ -1022,9 +1022,10 @@ fn lwe_compact_public_encrypt_prove_verify_decrypt_custom_mod( let mut msg = msg_modulus; let delta: Scalar = encoding_with_padding / msg_modulus; - let crs = CompactPkeCrs::new( + // Test zk scheme v1 and v2 + let crs_v2 = CompactPkeCrs::new( lwe_dimension, - 1, + LweCiphertextCount(1), glwe_noise_distribution, ciphertext_modulus, msg_modulus * Scalar::TWO, @@ -1033,68 +1034,81 @@ fn lwe_compact_public_encrypt_prove_verify_decrypt_custom_mod( ) .unwrap(); - while msg != Scalar::ZERO { - msg = msg.wrapping_sub(Scalar::ONE); - for _ in 0..NB_TESTS { - let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key( - lwe_dimension, - &mut rsc.secret_random_generator, - ); + let crs_v1 = CompactPkeCrs::new_legacy_v1( + lwe_dimension, + LweCiphertextCount(1), + glwe_noise_distribution, + ciphertext_modulus, + msg_modulus * Scalar::TWO, + ZkMSBZeroPaddingBitCount(1), + &mut random_generator, + ) + .unwrap(); - let pk = allocate_and_generate_new_lwe_compact_public_key( - &lwe_sk, - glwe_noise_distribution, - ciphertext_modulus, - &mut rsc.encryption_random_generator, - ); + for crs in [&crs_v2, &crs_v1] { + while msg != Scalar::ZERO { + msg = msg.wrapping_sub(Scalar::ONE); + for _ in 0..NB_TESTS { + let lwe_sk = allocate_and_generate_new_binary_lwe_secret_key( + lwe_dimension, + &mut rsc.secret_random_generator, + ); - let mut ct = LweCiphertext::new( - Scalar::ZERO, - lwe_dimension.to_lwe_size(), - ciphertext_modulus, - ); + let pk = allocate_and_generate_new_lwe_compact_public_key( + &lwe_sk, + glwe_noise_distribution, + ciphertext_modulus, + &mut rsc.encryption_random_generator, + ); - let proof = encrypt_and_prove_lwe_ciphertext_with_compact_public_key( - &pk, - &mut ct, - Cleartext(msg), - delta, - glwe_noise_distribution, - glwe_noise_distribution, - &mut rsc.secret_random_generator, - &mut rsc.encryption_random_generator, - &mut random_generator, - &crs, - &metadata, - ZkComputeLoad::Proof, - ) - .unwrap(); + let mut ct = LweCiphertext::new( + Scalar::ZERO, + lwe_dimension.to_lwe_size(), + ciphertext_modulus, + ); - assert!(check_encrypted_content_respects_mod( - &ct, - ciphertext_modulus, - )); + let proof = encrypt_and_prove_lwe_ciphertext_with_compact_public_key( + &pk, + &mut ct, + Cleartext(msg), + delta, + glwe_noise_distribution, + glwe_noise_distribution, + &mut rsc.secret_random_generator, + &mut rsc.encryption_random_generator, + &mut random_generator, + crs, + &metadata, + ZkComputeLoad::Proof, + ) + .unwrap(); - let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct); + assert!(check_encrypted_content_respects_mod( + &ct, + ciphertext_modulus, + )); - let decoded = round_decode(decrypted.0, delta) % msg_modulus; + let decrypted = decrypt_lwe_ciphertext(&lwe_sk, &ct); - assert_eq!(msg, decoded); + let decoded = round_decode(decrypted.0, delta) % msg_modulus; + + assert_eq!(msg, decoded); - // Verify the proof - assert!(verify_lwe_ciphertext(&ct, &pk, &proof, &crs, &metadata).is_valid()); + // Verify the proof + assert!(verify_lwe_ciphertext(&ct, &pk, &proof, crs, &metadata).is_valid()); - // verify proof with invalid ciphertext - let index = random_generator.gen::() % ct.as_ref().len(); - let value_to_add = random_generator.gen::(); - ct.as_mut()[index] = ct.as_mut()[index].wrapping_add(value_to_add); - assert!(verify_lwe_ciphertext(&ct, &pk, &proof, &crs, &metadata).is_invalid()); - } + // verify proof with invalid ciphertext + let index = random_generator.gen::() % ct.as_ref().len(); + let value_to_add = random_generator.gen::(); + ct.as_mut()[index] = ct.as_mut()[index].wrapping_add(value_to_add); + assert!(verify_lwe_ciphertext(&ct, &pk, &proof, crs, &metadata).is_invalid()); + } - // In coverage, we break after one while loop iteration, changing message values does not - // yield higher coverage - #[cfg(tarpaulin)] - break; + // In coverage, we break after one while loop iteration, changing message values does + // not yield higher coverage + #[cfg(tarpaulin)] + break; + } } } @@ -1125,7 +1139,7 @@ fn test_par_compact_lwe_list_public_key_encryption_and_proof() { let max_num_body = 512; let crs = CompactPkeCrs::new( lwe_dimension, - max_num_body, + LweCiphertextCount(max_num_body), glwe_noise_distribution, ciphertext_modulus, plaintext_modulus, diff --git a/tfhe/src/core_crypto/commons/parameters.rs b/tfhe/src/core_crypto/commons/parameters.rs index 0eeb5cac3a..16d1b04258 100644 --- a/tfhe/src/core_crypto/commons/parameters.rs +++ b/tfhe/src/core_crypto/commons/parameters.rs @@ -25,7 +25,9 @@ pub struct CleartextCount(pub usize); pub struct CiphertextCount(pub usize); /// The number of ciphertexts in an lwe ciphertext list. -#[derive(Copy, Clone, Eq, PartialEq, Debug, Serialize, Deserialize, Versionize)] +#[derive( + Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Serialize, Deserialize, Versionize, +)] #[versionize(LweCiphertextCountVersions)] pub struct LweCiphertextCount(pub usize); diff --git a/tfhe/src/high_level_api/compact_list.rs b/tfhe/src/high_level_api/compact_list.rs index e7ff1a640c..60cd98398a 100644 --- a/tfhe/src/high_level_api/compact_list.rs +++ b/tfhe/src/high_level_api/compact_list.rs @@ -218,7 +218,7 @@ mod zk { crs: &CompactPkeCrs, pk: &CompactPublicKey, metadata: &[u8], - ) -> crate::zk::ZkVerificationOutCome { + ) -> crate::zk::ZkVerificationOutcome { self.inner.verify(crs, &pk.key.key, metadata) } diff --git a/tfhe/src/high_level_api/zk.rs b/tfhe/src/high_level_api/zk.rs index 179403877b..1ec291473b 100644 --- a/tfhe/src/high_level_api/zk.rs +++ b/tfhe/src/high_level_api/zk.rs @@ -1,3 +1,4 @@ +use crate::core_crypto::prelude::LweCiphertextCount; use crate::zk::CompactPkeCrs; use crate::{Config, Error}; @@ -24,7 +25,10 @@ impl CompactPkeCrs { * compact_encryption_parameters.message_modulus.0) .ilog2() as usize; let max_num_message = max_bit_size.div_ceil(carry_and_message_bit_capacity); - let crs = Self::from_shortint_params(compact_encryption_parameters, max_num_message)?; + let crs = Self::from_shortint_params( + compact_encryption_parameters, + LweCiphertextCount(max_num_message), + )?; Ok(crs) } } diff --git a/tfhe/src/integer/ciphertext/compact_list.rs b/tfhe/src/integer/ciphertext/compact_list.rs index 1d7d977968..955a5d60d7 100644 --- a/tfhe/src/integer/ciphertext/compact_list.rs +++ b/tfhe/src/integer/ciphertext/compact_list.rs @@ -21,7 +21,7 @@ use crate::shortint::parameters::{ }; use crate::shortint::{CarryModulus, Ciphertext, MessageModulus}; #[cfg(feature = "zk-pok")] -use crate::zk::{CompactPkeCrs, ZkComputeLoad, ZkVerificationOutCome}; +use crate::zk::{CompactPkeCrs, CompactPkeZkScheme, ZkComputeLoad, ZkVerificationOutcome}; use rayon::prelude::*; use serde::{Deserialize, Serialize}; @@ -783,7 +783,7 @@ impl ProvenCompactCiphertextList { crs: &CompactPkeCrs, public_key: &CompactPublicKey, metadata: &[u8], - ) -> ZkVerificationOutCome { + ) -> ZkVerificationOutcome { self.ct_list.verify(crs, &public_key.key, metadata) } @@ -1000,6 +1000,7 @@ pub struct IntegerProvenCompactCiphertextListConformanceParams { pub ciphertext_modulus: CiphertextModulus, pub expansion_kind: CompactCiphertextListExpansionKind, pub max_elements_per_compact_list: usize, + pub zk_scheme: CompactPkeZkScheme, } #[cfg(feature = "zk-pok")] @@ -1021,7 +1022,8 @@ impl IntegerProvenCompactCiphertextListConformanceParams { carry_modulus: value.carry_modulus, ciphertext_modulus: value.ciphertext_modulus, expansion_kind: value.expansion_kind, - max_elements_per_compact_list: crs.max_num_messages(), + max_elements_per_compact_list: crs.max_num_messages().0, + zk_scheme: crs.scheme_version(), } } } @@ -1044,6 +1046,7 @@ impl ParameterSetConformant for ProvenCompactCiphertextList { max_lwe_count_per_compact_list: parameter_set.max_elements_per_compact_list, // packing by 2 total_expected_lwe_count: total_expected_num_blocks.div_ceil(2), + zk_scheme: parameter_set.zk_scheme, }; ct_list.is_conformant(&a) @@ -1062,6 +1065,7 @@ mod tests { } use super::{DataKind, ProvenCompactCiphertextList}; + use crate::core_crypto::prelude::LweCiphertextCount; use crate::integer::ciphertext::CompactCiphertextList; use crate::integer::key_switching_key::KeySwitchingKey; use crate::integer::parameters::IntegerCompactCiphertextListExpansionMode; @@ -1089,7 +1093,7 @@ mod tests { .checked_pow(num_blocks as u32) .unwrap(); - let crs = CompactPkeCrs::from_shortint_params(pke_params, 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); @@ -1148,7 +1152,11 @@ mod tests { 64 / ((pke_params.message_modulus.0 * pke_params.carry_modulus.0).ilog2() as usize); let encryption_num_blocks = 64 / (pke_params.message_modulus.0.ilog2() as usize); - let crs = CompactPkeCrs::from_shortint_params(pke_params, crs_blocks_for_64_bits).unwrap(); + let crs = CompactPkeCrs::from_shortint_params( + pke_params, + LweCiphertextCount(crs_blocks_for_64_bits), + ) + .unwrap(); let cks = ClientKey::new(fhe_params); let sk = ServerKey::new_radix_server_key(&cks); let compact_private_key = CompactPrivateKey::new(pke_params); @@ -1207,7 +1215,11 @@ mod tests { 64 / ((pke_params.message_modulus.0 * pke_params.carry_modulus.0).ilog2() as usize); let encryption_num_blocks = 64 / (pke_params.message_modulus.0.ilog2() as usize); - let crs = CompactPkeCrs::from_shortint_params(pke_params, crs_blocks_for_64_bits).unwrap(); + let crs = CompactPkeCrs::from_shortint_params( + pke_params, + LweCiphertextCount(crs_blocks_for_64_bits), + ) + .unwrap(); let cks = ClientKey::new(fhe_params); let sk = ServerKey::new_radix_server_key(&cks); let compact_private_key = CompactPrivateKey::new(pke_params); diff --git a/tfhe/src/js_on_wasm_api/js_high_level_api/zk.rs b/tfhe/src/js_on_wasm_api/js_high_level_api/zk.rs index 839afaa64f..89fe53987a 100644 --- a/tfhe/src/js_on_wasm_api/js_high_level_api/zk.rs +++ b/tfhe/src/js_on_wasm_api/js_high_level_api/zk.rs @@ -1,5 +1,6 @@ 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; @@ -86,7 +87,7 @@ impl CompactPkeCrs { catch_panic_result(|| { crate::core_crypto::entities::CompactPkeCrs::from_shortint_params( parameters.0, - max_num_message, + LweCiphertextCount(max_num_message), ) .map(CompactPkeCrs) .map_err(into_js_error) @@ -107,7 +108,7 @@ impl CompactPkeCrs { // If buffer is compressed it is automatically detected and uncompressed. catch_panic_result(|| { bincode::deserialize(buffer) - .map(crate::zk::CompactPkePublicParams::into) + .map(crate::zk::ZkCompactPkeV1PublicParams::into) .map(CompactPkeCrs) .map_err(into_js_error) }) @@ -122,7 +123,7 @@ impl CompactPkeCrs { crate::safe_serialization::DeserializationConfig::new(serialized_size_limit) .disable_conformance() .deserialize_from(buffer) - .map(crate::zk::CompactPkePublicParams::into) + .map(crate::zk::ZkCompactPkeV1PublicParams::into) .map(CompactPkeCrs) .map_err(into_js_error) }) diff --git a/tfhe/src/shortint/ciphertext/zk.rs b/tfhe/src/shortint/ciphertext/zk.rs index ac8e8ac000..92ebca740c 100644 --- a/tfhe/src/shortint/ciphertext/zk.rs +++ b/tfhe/src/shortint/ciphertext/zk.rs @@ -1,7 +1,7 @@ use super::Degree; use crate::conformance::{ListSizeConstraint, ParameterSetConformant}; use crate::core_crypto::algorithms::verify_lwe_compact_ciphertext_list; -use crate::core_crypto::prelude::LweCiphertextListParameters; +use crate::core_crypto::prelude::{LweCiphertextCount, LweCiphertextListParameters}; use crate::shortint::backward_compatibility::ciphertext::ProvenCompactCiphertextListVersions; use crate::shortint::ciphertext::CompactCiphertextList; use crate::shortint::parameters::{ @@ -10,7 +10,10 @@ use crate::shortint::parameters::{ MessageModulus, ShortintCompactCiphertextListCastingMode, }; use crate::shortint::{Ciphertext, CompactPublicKey}; -use crate::zk::{CompactPkeCrs, CompactPkeProof, ZkMSBZeroPaddingBitCount, ZkVerificationOutCome}; +use crate::zk::{ + CompactPkeCrs, CompactPkeProof, CompactPkeZkScheme, ZkMSBZeroPaddingBitCount, + ZkVerificationOutcome, +}; use rayon::prelude::*; use serde::{Deserialize, Serialize}; use tfhe_versionable::Versionize; @@ -19,7 +22,10 @@ impl CompactPkeCrs { /// Construct the CRS that corresponds to the given parameters /// /// max_num_message is how many message a single proof can prove - pub fn from_shortint_params(params: P, max_num_message: usize) -> crate::Result + pub fn from_shortint_params( + params: P, + max_num_message: LweCiphertextCount, + ) -> crate::Result where P: TryInto, crate::Error: From, @@ -48,6 +54,42 @@ impl CompactPkeCrs { ) }) } + + /// 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( + params: P, + max_num_message: LweCiphertextCount, + ) -> crate::Result + where + P: TryInto, + crate::Error: From, + { + 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, + ) + }) + } } /// A List of CompactCiphertext with their zero-knowledge proofs @@ -166,7 +208,7 @@ impl ProvenCompactCiphertextList { crs: &CompactPkeCrs, public_key: &CompactPublicKey, metadata: &[u8], - ) -> ZkVerificationOutCome { + ) -> ZkVerificationOutcome { let all_valid = self.proved_lists.par_iter().all(|(ct_list, proof)| { verify_lwe_compact_ciphertext_list( &ct_list.ct_list, @@ -179,9 +221,9 @@ impl ProvenCompactCiphertextList { }); if all_valid { - ZkVerificationOutCome::Valid + ZkVerificationOutcome::Valid } else { - ZkVerificationOutCome::Invalid + ZkVerificationOutcome::Invalid } } @@ -203,6 +245,7 @@ pub struct ProvenCompactCiphertextListConformanceParams { pub expansion_kind: CompactCiphertextListExpansionKind, pub max_lwe_count_per_compact_list: usize, pub total_expected_lwe_count: usize, + pub zk_scheme: CompactPkeZkScheme, } impl ParameterSetConformant for ProvenCompactCiphertextList { @@ -219,6 +262,7 @@ impl ParameterSetConformant for ProvenCompactCiphertextList { message_modulus, carry_modulus, ciphertext_modulus, + zk_scheme, } = parameter_set; let max_elements_per_compact_list = *max_lwe_count_per_compact_list; @@ -226,7 +270,7 @@ impl ParameterSetConformant for ProvenCompactCiphertextList { let mut remaining_len = *total_expected_lwe_count; for (compact_ct_list, proof) in proved_lists { - if !proof.is_conformant(&()) { + if !proof.is_conformant(zk_scheme) { return false; } @@ -272,6 +316,7 @@ impl ParameterSetConformant for ProvenCompactCiphertextList { #[cfg(test)] mod tests { + use crate::core_crypto::prelude::LweCiphertextCount; use crate::shortint::parameters::{ ShortintCompactCiphertextListCastingMode, PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, }; @@ -283,7 +328,7 @@ mod tests { fn test_zk_ciphertext_encryption_ci_run_filter() { let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let crs = CompactPkeCrs::from_shortint_params(params, 4).unwrap(); + let crs = CompactPkeCrs::from_shortint_params(params, LweCiphertextCount(4)).unwrap(); let cks = ClientKey::new(params); let pk = CompactPublicKey::new(&cks); @@ -330,7 +375,7 @@ mod tests { fn test_zk_compact_ciphertext_list_encryption_ci_run_filter() { let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let crs = CompactPkeCrs::from_shortint_params(params, 512).unwrap(); + let crs = CompactPkeCrs::from_shortint_params(params, LweCiphertextCount(512)).unwrap(); let cks = ClientKey::new(params); let pk = CompactPublicKey::new(&cks); diff --git a/tfhe/src/shortint/public_key/compact.rs b/tfhe/src/shortint/public_key/compact.rs index 6cf819febc..0ae568d620 100644 --- a/tfhe/src/shortint/public_key/compact.rs +++ b/tfhe/src/shortint/public_key/compact.rs @@ -383,7 +383,7 @@ impl CompactPublicKey { // encryption let max_ciphertext_per_bin = self.key.lwe_dimension().0; // This is the maximum of lwe message a single proof can prove - let max_num_messages = crs.max_num_messages(); + let max_num_messages = crs.max_num_messages().0; // One of the two is the limiting factor for how much we can pack messages let message_chunk_size = max_num_messages.min(max_ciphertext_per_bin); diff --git a/tfhe/src/zk.rs b/tfhe/src/zk.rs deleted file mode 100644 index 8e616f2e58..0000000000 --- a/tfhe/src/zk.rs +++ /dev/null @@ -1,417 +0,0 @@ -use crate::conformance::ParameterSetConformant; -use crate::core_crypto::commons::math::random::BoundedDistribution; -use crate::core_crypto::prelude::*; -use crate::named::Named; -#[cfg(feature = "shortint")] -use crate::shortint::parameters::CompactPublicKeyEncryptionParameters; -use rand_core::RngCore; -use serde::{Deserialize, Serialize}; -use std::cmp::Ordering; -use std::collections::Bound; -use std::fmt::Debug; -use tfhe_versionable::Versionize; -use tfhe_zk_pok::proofs::pke::crs_gen; - -pub use tfhe_zk_pok::curve_api::Compressible; -pub use tfhe_zk_pok::proofs::ComputeLoad as ZkComputeLoad; -type Curve = tfhe_zk_pok::curve_api::Bls12_446; -pub type CompactPkeProof = tfhe_zk_pok::proofs::pke::Proof; - -impl Named for CompactPkeProof { - const NAME: &'static str = "zk::CompactPkeProof"; -} - -impl ParameterSetConformant for CompactPkeProof { - type ParameterSet = (); - - fn is_conformant(&self, _parameter_set: &Self::ParameterSet) -> bool { - self.is_usable() - } -} - -pub type CompactPkePublicParams = tfhe_zk_pok::proofs::pke::PublicParams; -pub type SerializableCompactPkePublicParams = - tfhe_zk_pok::serialization::SerializablePKEv1PublicParams; - -impl Named for CompactPkePublicParams { - const NAME: &'static str = "zk::CompactPkePublicParams"; -} - -pub struct CompactPkeCrsConformanceParams { - lwe_dim: LweDimension, - max_num_message: usize, - noise_bound: u64, - ciphertext_modulus: u64, - plaintext_modulus: u64, - msbs_zero_padding_bit_count: ZkMSBZeroPaddingBitCount, -} - -#[cfg(feature = "shortint")] -impl CompactPkeCrsConformanceParams { - pub fn new>( - value: P, - max_num_message: usize, - ) -> Result - where - E: Into, - { - let params: CompactPublicKeyEncryptionParameters = - value.try_into().map_err(|e| e.into())?; - - let mut plaintext_modulus = params.message_modulus.0 * params.carry_modulus.0; - // Add 1 bit of modulus for the padding bit - plaintext_modulus *= 2; - - let (lwe_dim, max_num_message, noise_bound, ciphertext_modulus, plaintext_modulus) = - CompactPkeCrs::prepare_crs_parameters( - params.encryption_lwe_dimension, - max_num_message, - params.encryption_noise_distribution, - params.ciphertext_modulus, - plaintext_modulus, - )?; - - Ok(Self { - lwe_dim, - max_num_message, - noise_bound, - ciphertext_modulus, - plaintext_modulus, - // CRS created from shortint params have 1 MSB 0bit - msbs_zero_padding_bit_count: ZkMSBZeroPaddingBitCount(1), - }) - } -} - -impl ParameterSetConformant for CompactPkePublicParams { - type ParameterSet = CompactPkeCrsConformanceParams; - - fn is_conformant(&self, parameter_set: &Self::ParameterSet) -> bool { - self.k <= self.d - && self.d == parameter_set.lwe_dim.0 - && self.k == parameter_set.max_num_message - && self.b == parameter_set.noise_bound - && self.q == parameter_set.ciphertext_modulus - && self.t == parameter_set.plaintext_modulus - && self.msbs_zero_padding_bit_count == parameter_set.msbs_zero_padding_bit_count.0 - && self.is_usable() - } -} - -// If we call `CompactPkePublicParams::compress` we end up with a -// `SerializableCompactPkePublicParams` that should also impl Named to be serializable with -// `safe_serialization`. Since the `CompactPkePublicParams` is transformed into a -// `SerializableCompactPkePublicParams` anyways before serialization, their impl of `Named` should -// return the same string. -impl Named for SerializableCompactPkePublicParams { - const NAME: &'static str = CompactPkePublicParams::NAME; -} - -#[derive(Copy, Clone, Eq, PartialEq)] -pub enum ZkVerificationOutCome { - /// The proof and its entity were valid - Valid, - /// The proof and its entity were not - Invalid, -} - -impl ZkVerificationOutCome { - pub fn is_valid(self) -> bool { - self == Self::Valid - } - - pub fn is_invalid(self) -> bool { - self == Self::Invalid - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct ZkMSBZeroPaddingBitCount(pub u64); - -/// The CRS (Common Reference String) of a ZK scheme is a set of values shared between the prover -/// and the verifier. -/// -/// The same CRS should be used at the prove and verify steps. -#[derive(Clone, Debug, Serialize, Deserialize, Versionize)] -#[repr(transparent)] -pub struct CompactPkeCrs { - public_params: CompactPkePublicParams, -} - -impl Named for CompactPkeCrs { - const NAME: &'static str = "zk::CompactPkeCrs"; -} - -impl From for CompactPkeCrs { - fn from(value: CompactPkePublicParams) -> Self { - Self { - public_params: value, - } - } -} - -impl CompactPkeCrs { - /// Prepare and check the CRS parameters. - /// - /// The output of this function can be used in [tfhe_zk_pok::proofs::pke::compute_crs_params]. - pub fn prepare_crs_parameters( - lwe_dim: LweDimension, - max_num_cleartext: usize, - noise_distribution: NoiseDistribution, - ciphertext_modulus: CiphertextModulus, - plaintext_modulus: Scalar, - ) -> crate::Result<(LweDimension, usize, Scalar, u64, Scalar)> - where - Scalar: UnsignedInteger + CastInto + Debug, - NoiseDistribution: BoundedDistribution, - { - // The bound for the crs has to be a power of two, - // it is [-b, b) (non-inclusive for the high bound) - // so we may have to give a bound that is bigger than - // what the distribution generates - let high_bound = match noise_distribution.high_bound() { - Bound::Included(high_b) => { - let high_b = high_b.wrapping_abs().into_unsigned(); - if high_b.is_power_of_two() { - high_b * Scalar::TWO - } else { - high_b.next_power_of_two() - } - } - Bound::Excluded(high_b) => { - let high_b = high_b.wrapping_abs().into_unsigned(); - if high_b.is_power_of_two() { - high_b - } else { - high_b.next_power_of_two() - } - } - Bound::Unbounded => { - return Err("requires bounded distribution".into()); - } - }; - - let abs_low_bound = match noise_distribution.low_bound() { - Bound::Included(low_b) => { - let low_b = low_b.wrapping_abs().into_unsigned(); - if low_b.is_power_of_two() { - low_b * Scalar::TWO - } else { - low_b.next_power_of_two() - } - } - Bound::Excluded(low_b) => { - let low_b = low_b.wrapping_abs().into_unsigned(); - if low_b.is_power_of_two() { - low_b - } else { - low_b.next_power_of_two() - } - } - Bound::Unbounded => { - return Err("requires bounded distribution".into()); - } - }; - - let noise_bound = abs_low_bound.max(high_bound); - - if Scalar::BITS > 64 && noise_bound >= (Scalar::ONE << 64usize) { - return Err("noise bounds exceeds 64 bits modulus".into()); - } - - if Scalar::BITS > 64 && plaintext_modulus >= (Scalar::ONE << 64usize) { - return Err("Plaintext modulus exceeds 64 bits modulus".into()); - } - - let q = if ciphertext_modulus.is_native_modulus() { - match Scalar::BITS.cmp(&64) { - Ordering::Greater => Err( - "Zero Knowledge proof do not support ciphertext modulus > 64 bits".to_string(), - ), - Ordering::Equal => Ok(0u64), - Ordering::Less => Ok(1u64 << Scalar::BITS), - } - } else { - let custom_modulus = ciphertext_modulus.get_custom_modulus(); - if custom_modulus > (u64::MAX) as u128 { - Err("Zero Knowledge proof do not support ciphertext modulus > 64 bits".to_string()) - } else { - Ok(custom_modulus as u64) - } - }?; - - Ok(( - lwe_dim, - max_num_cleartext, - noise_bound, - q, - plaintext_modulus, - )) - } - - /// Generates a new zk CRS from the tfhe parameters. - pub fn new( - lwe_dim: LweDimension, - max_num_cleartext: usize, - noise_distribution: NoiseDistribution, - ciphertext_modulus: CiphertextModulus, - plaintext_modulus: Scalar, - msbs_zero_padding_bit_count: ZkMSBZeroPaddingBitCount, - rng: &mut impl RngCore, - ) -> crate::Result - where - Scalar: UnsignedInteger + CastInto + Debug, - NoiseDistribution: BoundedDistribution, - { - let (d, k, b, q, t) = Self::prepare_crs_parameters( - lwe_dim, - max_num_cleartext, - noise_distribution, - ciphertext_modulus, - plaintext_modulus, - )?; - let public_params = crs_gen( - d.0, - k, - b.cast_into(), - q, - t.cast_into(), - msbs_zero_padding_bit_count.0, - rng, - ); - - Ok(Self { public_params }) - } - - /// Maximum number of messages that can be proven in a single list using this CRS - pub fn max_num_messages(&self) -> usize { - self.public_params().k - } - - pub fn public_params(&self) -> &CompactPkePublicParams { - &self.public_params - } -} - -impl ParameterSetConformant for CompactPkeCrs { - type ParameterSet = CompactPkeCrsConformanceParams; - - fn is_conformant(&self, parameter_set: &Self::ParameterSet) -> bool { - self.public_params.is_conformant(parameter_set) - } -} - -/// The CRS can be compressed by only storing the `x` part of the elliptic curve coordinates. -#[derive(Serialize, Deserialize, Versionize)] -#[repr(transparent)] -pub struct CompressedCompactPkeCrs { - public_params: ::Compressed, -} - -// The NAME impl is the same as CompactPkeCrs because once serialized they are represented with the -// same object. Decompression is done automatically during deserialization. -impl Named for CompressedCompactPkeCrs { - const NAME: &'static str = CompactPkeCrs::NAME; -} - -impl Compressible for CompactPkeCrs { - type Compressed = CompressedCompactPkeCrs; - - type UncompressError = ::UncompressError; - - fn compress(&self) -> Self::Compressed { - CompressedCompactPkeCrs { - public_params: self.public_params.compress(), - } - } - - fn uncompress(compressed: Self::Compressed) -> Result { - Ok(Self { - public_params: Compressible::uncompress(compressed.public_params)?, - }) - } -} - -#[cfg(all(test, feature = "shortint"))] -mod test { - use super::*; - use crate::safe_serialization::{safe_deserialize_conformant, safe_serialize}; - use crate::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - use crate::shortint::{CarryModulus, MessageModulus}; - - #[test] - fn test_crs_conformance() { - let params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let mut bad_params = params; - bad_params.carry_modulus = CarryModulus(8); - bad_params.message_modulus = MessageModulus(8); - - let mut rng = rand::thread_rng(); - - let crs = CompactPkeCrs::new( - params.encryption_lwe_dimension, - 4, - params.encryption_noise_distribution, - params.ciphertext_modulus, - params.message_modulus.0 * params.carry_modulus.0 * 2, - ZkMSBZeroPaddingBitCount(1), - &mut rng, - ) - .unwrap(); - - let conformance_params = CompactPkeCrsConformanceParams::new(params, 4).unwrap(); - - assert!(crs.is_conformant(&conformance_params)); - - let conformance_params = CompactPkeCrsConformanceParams::new(bad_params, 4).unwrap(); - - assert!(!crs.is_conformant(&conformance_params)); - - let conformance_params = CompactPkeCrsConformanceParams::new(params, 2).unwrap(); - - assert!(!crs.is_conformant(&conformance_params)); - } - - #[test] - fn test_crs_serialization() { - let params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - - let mut rng = rand::thread_rng(); - - let crs = CompactPkeCrs::new( - params.encryption_lwe_dimension, - 4, - params.encryption_noise_distribution, - params.ciphertext_modulus, - params.message_modulus.0 * params.carry_modulus.0 * 2, - ZkMSBZeroPaddingBitCount(1), - &mut rng, - ) - .unwrap(); - - let conformance_params = CompactPkeCrsConformanceParams::new(params, 4).unwrap(); - - let mut serialized = Vec::new(); - safe_serialize(&crs, &mut serialized, 1 << 30).unwrap(); - - let _crs_deser: CompactPkeCrs = - safe_deserialize_conformant(serialized.as_slice(), 1 << 30, &conformance_params) - .unwrap(); - - // Check that we are able to load public params - let mut serialized = Vec::new(); - safe_serialize(crs.public_params(), &mut serialized, 1 << 30).unwrap(); - - let _params_deser: CompactPkePublicParams = - safe_deserialize_conformant(serialized.as_slice(), 1 << 30, &conformance_params) - .unwrap(); - - // Check with compression - let mut serialized = Vec::new(); - safe_serialize(&crs.compress(), &mut serialized, 1 << 30).unwrap(); - - let _crs_deser: CompactPkeCrs = - safe_deserialize_conformant(serialized.as_slice(), 1 << 30, &conformance_params) - .unwrap(); - } -} diff --git a/tfhe/src/zk/backward_compatibility.rs b/tfhe/src/zk/backward_compatibility.rs new file mode 100644 index 0000000000..a07dcaea45 --- /dev/null +++ b/tfhe/src/zk/backward_compatibility.rs @@ -0,0 +1,82 @@ +use std::convert::Infallible; + +use tfhe_versionable::{Upgrade, Version, VersionsDispatch}; +use tfhe_zk_pok::backward_compatibility::pke::ProofV0; +use tfhe_zk_pok::backward_compatibility::IncompleteProof; +use tfhe_zk_pok::proofs::pke::Proof; +use tfhe_zk_pok::serialization::InvalidSerializedPublicParamsError; + +type Curve = tfhe_zk_pok::curve_api::Bls12_446; + +use super::{ + CompactPkeCrs, CompactPkeProof, CompressedCompactPkeCrs, SerializableCompactPkePublicParams, +}; + +#[derive(Version)] +#[repr(transparent)] +pub struct CompactPkeCrsV0(SerializableCompactPkePublicParams); + +impl Upgrade for CompactPkeCrsV0 { + type Error = InvalidSerializedPublicParamsError; + + fn upgrade(self) -> Result { + Ok(CompactPkeCrs::PkeV1(self.0.try_into()?)) + } +} + +#[derive(VersionsDispatch)] +#[allow(clippy::large_enum_variant)] +pub enum CompactPkeCrsVersions { + V0(CompactPkeCrsV0), + V1(CompactPkeCrs), +} + +#[derive(Version)] +#[repr(transparent)] +pub struct CompressedCompactPkeCrsV0(SerializableCompactPkePublicParams); + +impl Upgrade for CompressedCompactPkeCrsV0 { + type Error = Infallible; + + fn upgrade(self) -> Result { + Ok(CompressedCompactPkeCrs::PkeV1(self.0)) + } +} + +#[derive(VersionsDispatch)] +pub enum CompressedCompactPkeCrsVersions { + V0(CompressedCompactPkeCrsV0), + V1(CompressedCompactPkeCrs), +} + +#[derive(Version)] +#[repr(transparent)] +pub struct CompactPkeProofV0(ProofV0); + +impl Upgrade for CompactPkeProofV0 { + type Error = IncompleteProof; + + fn upgrade(self) -> Result { + Ok(CompactPkeProofV1(self.0.upgrade()?)) + } +} + +#[derive(Version)] +#[repr(transparent)] +pub struct CompactPkeProofV1(Proof); + +impl Upgrade for CompactPkeProofV1 { + type Error = Infallible; + + fn upgrade(self) -> Result { + Ok(CompactPkeProof::PkeV1(self.0)) + } +} + +#[derive(VersionsDispatch)] +#[allow(clippy::large_enum_variant)] +pub enum CompactPkeProofVersions { + V0(CompactPkeProofV0), + V1(CompactPkeProofV1), + V2(CompactPkeProof), +} diff --git a/tfhe/src/zk/mod.rs b/tfhe/src/zk/mod.rs new file mode 100644 index 0000000000..46c6672fe1 --- /dev/null +++ b/tfhe/src/zk/mod.rs @@ -0,0 +1,787 @@ +pub mod backward_compatibility; + +use crate::conformance::ParameterSetConformant; +use crate::core_crypto::commons::math::random::{ + BoundedDistribution, ByteRandomGenerator, RandomGenerator, +}; +use crate::core_crypto::prelude::*; +use crate::named::Named; +#[cfg(feature = "shortint")] +use crate::shortint::parameters::CompactPublicKeyEncryptionParameters; +use backward_compatibility::*; +use rand_core::RngCore; +use serde::{Deserialize, Serialize}; +use std::cmp::Ordering; +use std::collections::Bound; +use std::fmt::Debug; +use tfhe_versionable::Versionize; + +use tfhe_zk_pok::proofs::pke::{ + commit as commit_v1, crs_gen as crs_gen_v1, prove as prove_v1, verify as verify_v1, + Proof as ProofV1, PublicCommit as PublicCommitV1, +}; +use tfhe_zk_pok::proofs::pke_v2::{ + commit as commit_v2, crs_gen as crs_gen_v2, prove as prove_v2, verify as verify_v2, + Proof as ProofV2, PublicCommit as PublicCommitV2, +}; + +pub use tfhe_zk_pok::curve_api::Compressible; +pub use tfhe_zk_pok::proofs::ComputeLoad as ZkComputeLoad; +type Curve = tfhe_zk_pok::curve_api::Bls12_446; + +#[derive(Clone, Debug, Serialize, Deserialize, Versionize)] +#[versionize(CompactPkeProofVersions)] +#[allow(clippy::large_enum_variant)] +pub enum CompactPkeProof { + PkeV1(ProofV1), + PkeV2(ProofV2), +} + +impl Named for CompactPkeProof { + const NAME: &'static str = "zk::CompactPkeProof"; +} + +impl ParameterSetConformant for CompactPkeProof { + type ParameterSet = CompactPkeZkScheme; + + fn is_conformant(&self, parameter_set: &Self::ParameterSet) -> bool { + match (self, parameter_set) { + (Self::PkeV1(proof), CompactPkeZkScheme::V1) => proof.is_usable(), + (Self::PkeV2(proof), CompactPkeZkScheme::V2) => proof.is_usable(), + (Self::PkeV1(_), CompactPkeZkScheme::V2) | (Self::PkeV2(_), CompactPkeZkScheme::V1) => { + false + } + } + } +} + +pub type ZkCompactPkeV1PublicParams = tfhe_zk_pok::proofs::pke::PublicParams; +pub type ZkCompactPkeV2PublicParams = tfhe_zk_pok::proofs::pke_v2::PublicParams; + +// Keep this to be able to deserialize CRS that were serialized as "CompactPkePublicParams" (TFHE-rs +// 0.10 and before) +pub type SerializableCompactPkePublicParams = + tfhe_zk_pok::serialization::SerializablePKEv1PublicParams; + +impl Named for ZkCompactPkeV1PublicParams { + const NAME: &'static str = "zk::CompactPkePublicParams"; +} + +pub struct CompactPkeCrsConformanceParams { + lwe_dim: LweDimension, + max_num_message: LweCiphertextCount, + noise_bound: u64, + ciphertext_modulus: u64, + plaintext_modulus: u64, + msbs_zero_padding_bit_count: ZkMSBZeroPaddingBitCount, +} + +#[cfg(feature = "shortint")] +impl CompactPkeCrsConformanceParams { + pub fn new>( + value: P, + max_num_message: LweCiphertextCount, + ) -> Result + where + E: Into, + { + let params: CompactPublicKeyEncryptionParameters = + value.try_into().map_err(|e| e.into())?; + + let mut plaintext_modulus = params.message_modulus.0 * params.carry_modulus.0; + // Add 1 bit of modulus for the padding bit + plaintext_modulus *= 2; + + let (lwe_dim, max_num_message, noise_bound, ciphertext_modulus, plaintext_modulus) = + CompactPkeCrs::prepare_crs_parameters( + params.encryption_lwe_dimension, + max_num_message, + params.encryption_noise_distribution, + params.ciphertext_modulus, + plaintext_modulus, + CompactPkeZkScheme::V2, + )?; + + Ok(Self { + lwe_dim, + max_num_message, + noise_bound, + ciphertext_modulus, + plaintext_modulus, + // CRS created from shortint params have 1 MSB 0bit + msbs_zero_padding_bit_count: ZkMSBZeroPaddingBitCount(1), + }) + } +} + +impl ParameterSetConformant for ZkCompactPkeV1PublicParams { + type ParameterSet = CompactPkeCrsConformanceParams; + + fn is_conformant(&self, parameter_set: &Self::ParameterSet) -> bool { + self.k <= self.d + && self.d == parameter_set.lwe_dim.0 + && self.k == parameter_set.max_num_message.0 + && self.b == parameter_set.noise_bound + && self.q == parameter_set.ciphertext_modulus + && self.t == parameter_set.plaintext_modulus + && self.msbs_zero_padding_bit_count == parameter_set.msbs_zero_padding_bit_count.0 + && self.is_usable() + } +} + +impl ParameterSetConformant for ZkCompactPkeV2PublicParams { + type ParameterSet = CompactPkeCrsConformanceParams; + + fn is_conformant(&self, parameter_set: &Self::ParameterSet) -> bool { + self.k <= self.d + && self.d == parameter_set.lwe_dim.0 + && self.k == parameter_set.max_num_message.0 + && self.B_inf == parameter_set.noise_bound + && self.q == parameter_set.ciphertext_modulus + && self.t == parameter_set.plaintext_modulus + && self.msbs_zero_padding_bit_count == parameter_set.msbs_zero_padding_bit_count.0 + && self.is_usable() + } +} + +// If we call `CompactPkePublicParams::compress` we end up with a +// `SerializableCompactPkePublicParams` that should also impl Named to be serializable with +// `safe_serialization`. Since the `CompactPkePublicParams` is transformed into a +// `SerializableCompactPkePublicParams` anyways before serialization, their impl of `Named` should +// return the same string. +impl Named for SerializableCompactPkePublicParams { + const NAME: &'static str = ZkCompactPkeV1PublicParams::NAME; +} + +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum ZkVerificationOutcome { + /// The proof and its entity were valid + Valid, + /// The proof and its entity were not + Invalid, +} + +impl ZkVerificationOutcome { + pub fn is_valid(self) -> bool { + self == Self::Valid + } + + pub fn is_invalid(self) -> bool { + self == Self::Invalid + } +} + +/// The Zk Scheme for compact private key encryption is available in 2 versions. In case of doubt, +/// you should prefer the V2 which is more efficient. +#[derive(Clone, Copy)] +pub enum CompactPkeZkScheme { + V1, + V2, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct ZkMSBZeroPaddingBitCount(pub u64); + +/// The CRS (Common Reference String) of a ZK scheme is a set of values shared between the prover +/// and the verifier. +/// +/// The same CRS should be used at the prove and verify steps. +#[derive(Clone, Debug, Serialize, Deserialize, Versionize)] +#[versionize(CompactPkeCrsVersions)] +#[allow(clippy::large_enum_variant)] +pub enum CompactPkeCrs { + PkeV1(ZkCompactPkeV1PublicParams), + PkeV2(ZkCompactPkeV2PublicParams), +} + +impl Named for CompactPkeCrs { + const NAME: &'static str = "zk::CompactPkeCrs"; +} + +impl From for CompactPkeCrs { + fn from(value: ZkCompactPkeV1PublicParams) -> Self { + Self::PkeV1(value) + } +} + +impl From for CompactPkeCrs { + fn from(value: ZkCompactPkeV2PublicParams) -> Self { + Self::PkeV2(value) + } +} + +impl CompactPkeCrs { + /// Compute the bound used by the V1 Scheme from the noise distribution + fn compute_bound_v1( + noise_distribution: NoiseDistribution, + ) -> Result + where + Scalar: UnsignedInteger + CastInto + Debug, + NoiseDistribution: BoundedDistribution, + { + let high_bound = match noise_distribution.high_bound() { + Bound::Included(high_b) => high_b, + Bound::Excluded(high_b) => high_b - Scalar::Signed::ONE, + Bound::Unbounded => { + return Err("requires bounded distribution".into()); + } + }; + + let low_bound = match noise_distribution.low_bound() { + Bound::Included(low_b) => low_b, + Bound::Excluded(low_b) => low_b + Scalar::Signed::ONE, + Bound::Unbounded => { + return Err("requires bounded distribution".into()); + } + }; + + if high_bound != -low_bound { + return Err("requires a distribution centered around 0".into()); + } + + // The bound for the crs has to be a power of two, + // it is [-b, b) (non-inclusive for the high bound) + // so we may have to give a bound that is bigger than + // what the distribution generates + let high_bound = high_bound.wrapping_abs().into_unsigned(); + if high_bound.is_power_of_two() { + Ok(high_bound * Scalar::TWO) + } else { + Ok(high_bound.next_power_of_two()) + } + } + + /// Compute the bound used by the V2 Scheme from the noise distribution + fn compute_bound_v2( + noise_distribution: NoiseDistribution, + ) -> Result + where + Scalar: UnsignedInteger + CastInto + Debug, + NoiseDistribution: BoundedDistribution, + { + // For zk v2 scheme, the proof is valid for an inclusive range on the noise bound + let high_bound = match noise_distribution.high_bound() { + Bound::Included(high_b) => high_b, + Bound::Excluded(high_b) => high_b - Scalar::Signed::ONE, + Bound::Unbounded => { + return Err("requires bounded distribution".into()); + } + }; + + let low_bound = match noise_distribution.low_bound() { + Bound::Included(low_b) => low_b, + Bound::Excluded(low_b) => low_b + Scalar::Signed::ONE, + Bound::Unbounded => { + return Err("requires bounded distribution".into()); + } + }; + + if high_bound != -low_bound { + return Err("requires a distribution centered around 0".into()); + } + + Ok(high_bound.wrapping_abs().into_unsigned()) + } + + /// Prepare and check the CRS parameters. + /// + /// The output of this function can be used in [tfhe_zk_pok::proofs::pke::compute_crs_params]. + pub fn prepare_crs_parameters( + lwe_dim: LweDimension, + max_num_cleartext: LweCiphertextCount, + noise_distribution: NoiseDistribution, + ciphertext_modulus: CiphertextModulus, + plaintext_modulus: Scalar, + zk_scheme: CompactPkeZkScheme, + ) -> crate::Result<(LweDimension, LweCiphertextCount, Scalar, u64, Scalar)> + where + Scalar: UnsignedInteger + CastInto + Debug, + NoiseDistribution: BoundedDistribution, + { + let noise_bound = match zk_scheme { + CompactPkeZkScheme::V1 => Self::compute_bound_v1(noise_distribution)?, + CompactPkeZkScheme::V2 => Self::compute_bound_v2(noise_distribution)?, + }; + + if Scalar::BITS > 64 && noise_bound >= (Scalar::ONE << 64usize) { + return Err("noise bounds exceeds 64 bits modulus".into()); + } + + if Scalar::BITS > 64 && plaintext_modulus >= (Scalar::ONE << 64usize) { + return Err("Plaintext modulus exceeds 64 bits modulus".into()); + } + + let q = if ciphertext_modulus.is_native_modulus() { + match Scalar::BITS.cmp(&64) { + Ordering::Greater => Err( + "Zero Knowledge proof do not support ciphertext modulus > 64 bits".to_string(), + ), + Ordering::Equal => Ok(0u64), + Ordering::Less => Ok(1u64 << Scalar::BITS), + } + } else { + let custom_modulus = ciphertext_modulus.get_custom_modulus(); + if custom_modulus > (u64::MAX) as u128 { + Err("Zero Knowledge proof do not support ciphertext modulus > 64 bits".to_string()) + } else { + Ok(custom_modulus as u64) + } + }?; + + Ok(( + lwe_dim, + max_num_cleartext, + noise_bound, + q, + plaintext_modulus, + )) + } + + /// Generates a new zk CRS from the tfhe parameters. This the v1 Zk PKE scheme which is less + /// efficient. + pub fn new_legacy_v1( + lwe_dim: LweDimension, + max_num_cleartext: LweCiphertextCount, + noise_distribution: NoiseDistribution, + ciphertext_modulus: CiphertextModulus, + plaintext_modulus: Scalar, + msbs_zero_padding_bit_count: ZkMSBZeroPaddingBitCount, + rng: &mut impl RngCore, + ) -> crate::Result + where + Scalar: UnsignedInteger + CastInto + Debug, + NoiseDistribution: BoundedDistribution, + { + let (d, k, b, q, t) = Self::prepare_crs_parameters( + lwe_dim, + max_num_cleartext, + noise_distribution, + ciphertext_modulus, + plaintext_modulus, + CompactPkeZkScheme::V1, + )?; + let public_params = crs_gen_v1( + d.0, + k.0, + b.cast_into(), + q, + t.cast_into(), + msbs_zero_padding_bit_count.0, + rng, + ); + + Ok(Self::PkeV1(public_params)) + } + + /// Generates a new zk CRS from the tfhe parameters. + pub fn new( + lwe_dim: LweDimension, + max_num_cleartext: LweCiphertextCount, + noise_distribution: NoiseDistribution, + ciphertext_modulus: CiphertextModulus, + plaintext_modulus: Scalar, + msbs_zero_padding_bit_count: ZkMSBZeroPaddingBitCount, + rng: &mut impl RngCore, + ) -> crate::Result + where + Scalar: UnsignedInteger + CastInto + Debug, + NoiseDistribution: BoundedDistribution, + { + let (d, k, b, q, t) = Self::prepare_crs_parameters( + lwe_dim, + max_num_cleartext, + noise_distribution, + ciphertext_modulus, + plaintext_modulus, + CompactPkeZkScheme::V2, + )?; + let public_params = crs_gen_v2( + d.0, + k.0, + b.cast_into(), + q, + t.cast_into(), + msbs_zero_padding_bit_count.0, + rng, + ); + + Ok(Self::PkeV2(public_params)) + } + + /// Maximum number of messages that can be proven in a single list using this CRS + pub fn max_num_messages(&self) -> LweCiphertextCount { + match self { + Self::PkeV1(public_params) => LweCiphertextCount(public_params.k), + Self::PkeV2(public_params) => LweCiphertextCount(public_params.k), + } + } + + /// Lwe dimension supported by this CRS + pub fn lwe_dimension(&self) -> LweDimension { + match self { + Self::PkeV1(public_params) => LweDimension(public_params.d), + Self::PkeV2(public_params) => LweDimension(public_params.d), + } + } + + /// Modulus of the ciphertexts supported by this CRS + pub fn ciphertext_modulus(&self) -> CiphertextModulus { + match self { + Self::PkeV1(public_params) => CiphertextModulus::new(public_params.q as u128), + Self::PkeV2(public_params) => CiphertextModulus::new(public_params.q as u128), + } + } + + /// Modulus of the plaintexts supported by this CRS + pub fn plaintext_modulus(&self) -> u64 { + match self { + Self::PkeV1(public_params) => public_params.t, + Self::PkeV2(public_params) => public_params.t, + } + } + + /// Upper bound on the noise accepted by this CRS + pub fn exclusive_max_noise(&self) -> u64 { + match self { + Self::PkeV1(public_params) => public_params.exclusive_max_noise(), + Self::PkeV2(public_params) => public_params.exclusive_max_noise(), + } + } + + /// Return the version of the zk scheme used by this CRS + pub fn scheme_version(&self) -> CompactPkeZkScheme { + match self { + Self::PkeV1(_) => CompactPkeZkScheme::V1, + Self::PkeV2(_) => CompactPkeZkScheme::V2, + } + } + + /// Prove a ciphertext list encryption using this CRS + #[allow(clippy::too_many_arguments)] + pub fn prove( + &self, + compact_public_key: &LweCompactPublicKey, + messages: &InputCont, + lwe_compact_list: &LweCompactCiphertextList, + binary_random_vector: &[Scalar], + mask_noise: &[Scalar], + body_noise: &[Scalar], + metadata: &[u8], + load: ZkComputeLoad, + random_generator: &mut RandomGenerator, + ) -> CompactPkeProof + where + Scalar: UnsignedInteger, + i64: CastFrom, + KeyCont: Container, + InputCont: Container, + ListCont: Container, + G: ByteRandomGenerator, + { + let key_mask = compact_public_key + .get_mask() + .as_ref() + .iter() + .copied() + .map(|x| i64::cast_from(x)) + .collect(); + let key_body = compact_public_key + .get_body() + .as_ref() + .iter() + .copied() + .map(|x| i64::cast_from(x)) + .collect(); + + let ct_mask = lwe_compact_list + .get_mask_list() + .as_ref() + .iter() + .copied() + .map(|x| i64::cast_from(x)) + .collect(); + let ct_body = lwe_compact_list + .get_body_list() + .as_ref() + .iter() + .copied() + .map(|x| i64::cast_from(x)) + .collect(); + + let binary_random_vector = binary_random_vector + .iter() + .copied() + .map(CastFrom::cast_from) + .collect::>(); + + let mask_noise = mask_noise + .iter() + .copied() + .map(CastFrom::cast_from) + .collect::>(); + + let messages = messages + .as_ref() + .iter() + .copied() + .map(CastFrom::cast_from) + .collect::>(); + + let body_noise = body_noise + .iter() + .copied() + .map(CastFrom::cast_from) + .collect::>(); + + match self { + Self::PkeV1(public_params) => { + let (public_commit, private_commit) = commit_v1( + key_mask, + key_body, + ct_mask, + ct_body, + binary_random_vector, + mask_noise, + messages, + body_noise, + public_params, + random_generator, + ); + + let proof = prove_v1( + (public_params, &public_commit), + &private_commit, + metadata, + load, + random_generator, + ); + + CompactPkeProof::PkeV1(proof) + } + Self::PkeV2(public_params) => { + let (public_commit, private_commit) = commit_v2( + key_mask, + key_body, + ct_mask, + ct_body, + binary_random_vector, + mask_noise, + messages, + body_noise, + public_params, + random_generator, + ); + + let proof = prove_v2( + (public_params, &public_commit), + &private_commit, + metadata, + load, + random_generator, + ); + + CompactPkeProof::PkeV2(proof) + } + } + } + + /// Verify the validity of a proof using this CRS + pub fn verify( + &self, + lwe_compact_list: &LweCompactCiphertextList, + compact_public_key: &LweCompactPublicKey, + proof: &CompactPkeProof, + metadata: &[u8], + ) -> ZkVerificationOutcome + where + Scalar: UnsignedInteger, + i64: CastFrom, + ListCont: Container, + KeyCont: Container, + { + if Scalar::BITS > 64 { + return ZkVerificationOutcome::Invalid; + } + + let key_mask = compact_public_key + .get_mask() + .as_ref() + .iter() + .copied() + .map(|x| i64::cast_from(x)) + .collect(); + let key_body = compact_public_key + .get_body() + .as_ref() + .iter() + .copied() + .map(|x| i64::cast_from(x)) + .collect(); + + let ct_mask = lwe_compact_list + .get_mask_list() + .as_ref() + .iter() + .copied() + .map(|x| i64::cast_from(x)) + .collect(); + let ct_body = lwe_compact_list + .get_body_list() + .as_ref() + .iter() + .copied() + .map(|x| i64::cast_from(x)) + .collect(); + + let res = match (self, proof) { + (Self::PkeV1(public_params), CompactPkeProof::PkeV1(proof)) => { + let public_commit = PublicCommitV1::new(key_mask, key_body, ct_mask, ct_body); + verify_v1(proof, (public_params, &public_commit), metadata) + } + (Self::PkeV2(public_params), CompactPkeProof::PkeV2(proof)) => { + let public_commit = PublicCommitV2::new(key_mask, key_body, ct_mask, ct_body); + verify_v2(proof, (public_params, &public_commit), metadata) + } + + (Self::PkeV1(_), CompactPkeProof::PkeV2(_)) + | (Self::PkeV2(_), CompactPkeProof::PkeV1(_)) => { + // Proof is not compatible with the CRS, so we refuse it right there + Err(()) + } + }; + + match res { + Ok(_) => ZkVerificationOutcome::Valid, + Err(_) => ZkVerificationOutcome::Invalid, + } + } +} + +impl ParameterSetConformant for CompactPkeCrs { + type ParameterSet = CompactPkeCrsConformanceParams; + + fn is_conformant(&self, parameter_set: &Self::ParameterSet) -> bool { + match self { + Self::PkeV1(public_params) => public_params.is_conformant(parameter_set), + Self::PkeV2(public_params) => public_params.is_conformant(parameter_set), + } + } +} + +/// The CRS can be compressed by only storing the `x` part of the elliptic curve coordinates. +#[derive(Serialize, Deserialize, Versionize)] +#[versionize(CompressedCompactPkeCrsVersions)] +pub enum CompressedCompactPkeCrs { + PkeV1(::Compressed), + PkeV2(::Compressed), +} + +// The NAME impl is the same as CompactPkeCrs because once serialized they are represented with the +// same object. Decompression is done automatically during deserialization. +impl Named for CompressedCompactPkeCrs { + const NAME: &'static str = CompactPkeCrs::NAME; +} + +impl Compressible for CompactPkeCrs { + type Compressed = CompressedCompactPkeCrs; + + type UncompressError = ::UncompressError; + + fn compress(&self) -> Self::Compressed { + match self { + Self::PkeV1(public_params) => CompressedCompactPkeCrs::PkeV1(public_params.compress()), + Self::PkeV2(public_params) => CompressedCompactPkeCrs::PkeV2(public_params.compress()), + } + } + + fn uncompress(compressed: Self::Compressed) -> Result { + Ok(match compressed { + CompressedCompactPkeCrs::PkeV1(compressed_params) => { + Self::PkeV1(Compressible::uncompress(compressed_params)?) + } + CompressedCompactPkeCrs::PkeV2(compressed_params) => { + Self::PkeV2(Compressible::uncompress(compressed_params)?) + } + }) + } +} + +#[cfg(all(test, feature = "shortint"))] +mod test { + use super::*; + use crate::safe_serialization::{safe_deserialize_conformant, safe_serialize}; + use crate::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + use crate::shortint::{CarryModulus, MessageModulus}; + + #[test] + fn test_crs_conformance() { + let params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let mut bad_params = params; + bad_params.carry_modulus = CarryModulus(8); + bad_params.message_modulus = MessageModulus(8); + + let mut rng = rand::thread_rng(); + + let crs = CompactPkeCrs::new( + params.encryption_lwe_dimension, + LweCiphertextCount(4), + params.encryption_noise_distribution, + params.ciphertext_modulus, + params.message_modulus.0 * params.carry_modulus.0 * 2, + ZkMSBZeroPaddingBitCount(1), + &mut rng, + ) + .unwrap(); + + let conformance_params = + CompactPkeCrsConformanceParams::new(params, LweCiphertextCount(4)).unwrap(); + + assert!(crs.is_conformant(&conformance_params)); + + let conformance_params = + CompactPkeCrsConformanceParams::new(bad_params, LweCiphertextCount(4)).unwrap(); + + assert!(!crs.is_conformant(&conformance_params)); + + let conformance_params = + CompactPkeCrsConformanceParams::new(params, LweCiphertextCount(2)).unwrap(); + + assert!(!crs.is_conformant(&conformance_params)); + } + + #[test] + fn test_crs_serialization() { + let params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + + let mut rng = rand::thread_rng(); + + let crs = CompactPkeCrs::new( + params.encryption_lwe_dimension, + LweCiphertextCount(4), + params.encryption_noise_distribution, + params.ciphertext_modulus, + params.message_modulus.0 * params.carry_modulus.0 * 2, + ZkMSBZeroPaddingBitCount(1), + &mut rng, + ) + .unwrap(); + + let conformance_params = + CompactPkeCrsConformanceParams::new(params, LweCiphertextCount(4)).unwrap(); + + let mut serialized = Vec::new(); + safe_serialize(&crs, &mut serialized, 1 << 30).unwrap(); + + let _crs_deser: CompactPkeCrs = + safe_deserialize_conformant(serialized.as_slice(), 1 << 30, &conformance_params) + .unwrap(); + + // Check with compression + let mut serialized = Vec::new(); + safe_serialize(&crs.compress(), &mut serialized, 1 << 30).unwrap(); + + let _crs_deser: CompactPkeCrs = + safe_deserialize_conformant(serialized.as_slice(), 1 << 30, &conformance_params) + .unwrap(); + } +} diff --git a/tfhe/tests/backward_compatibility/high_level_api.rs b/tfhe/tests/backward_compatibility/high_level_api.rs index d74ef85d5a..5b4b41de00 100644 --- a/tfhe/tests/backward_compatibility/high_level_api.rs +++ b/tfhe/tests/backward_compatibility/high_level_api.rs @@ -5,8 +5,6 @@ use tfhe::prelude::{CiphertextList, FheDecrypt, FheEncrypt}; use tfhe::shortint::PBSParameters; #[cfg(feature = "zk-pok")] use tfhe::zk::CompactPkeCrs; -#[cfg(feature = "zk-pok")] -use tfhe::zk::CompactPkePublicParams; use tfhe::{ set_server_key, ClientKey, CompactCiphertextList, CompressedCiphertextList, CompressedCompactPublicKey, CompressedFheBool, CompressedFheInt8, CompressedFheUint8, @@ -150,11 +148,6 @@ pub fn test_zk_params( test: &ZkPkePublicParamsTest, format: DataFormat, ) -> Result { - // Since CompactPkeCrs is a repr(transparent) of a CompactPkePublicParams, both can be loaded - // from the same data, so we check this. - #[cfg(feature = "zk-pok")] - let _loaded_params: CompactPkePublicParams = load_and_unversionize(dir, test, format)?; - #[cfg(feature = "zk-pok")] let _loaded_crs: CompactPkeCrs = load_and_unversionize(dir, test, format)?; @@ -187,11 +180,10 @@ pub fn test_hl_heterogeneous_ciphertext_list( #[cfg(feature = "zk-pok")] { let crs_file = dir.join(&*zk_info.params_filename); - let public_params = CompactPkePublicParams::unversionize( + let crs = CompactPkeCrs::unversionize( load_versioned_auxiliary(crs_file).map_err(|e| test.failure(e, format))?, ) .map_err(|e| test.failure(e, format))?; - let crs = CompactPkeCrs::from(public_params); let pubkey_file = dir.join(&*zk_info.public_key_filename); let pubkey = CompactPublicKey::unversionize( diff --git a/tfhe/tests/zk_wasm_x86_test.rs b/tfhe/tests/zk_wasm_x86_test.rs index 6d48a4274b..92fe19c119 100644 --- a/tfhe/tests/zk_wasm_x86_test.rs +++ b/tfhe/tests/zk_wasm_x86_test.rs @@ -64,10 +64,10 @@ fn verify_proof( ) { println!("Verifying proof"); match proven_ct.verify(crs, public_key, &METADATA) { - tfhe::zk::ZkVerificationOutCome::Valid => { + tfhe::zk::ZkVerificationOutcome::Valid => { println!("proof verification succeeded"); } - tfhe::zk::ZkVerificationOutCome::Invalid => { + tfhe::zk::ZkVerificationOutcome::Invalid => { panic!("proof verification failed!!!") } } diff --git a/utils/tfhe-versionable-derive/src/versionize_attribute.rs b/utils/tfhe-versionable-derive/src/versionize_attribute.rs index 4629a4a855..e89f72da5c 100644 --- a/utils/tfhe-versionable-derive/src/versionize_attribute.rs +++ b/utils/tfhe-versionable-derive/src/versionize_attribute.rs @@ -306,13 +306,10 @@ pub(crate) fn is_transparent(attributes: &[Attribute]) -> syn::Result { let nested = attr.parse_args_with(Punctuated::::parse_terminated)?; for meta in nested.iter() { - match meta { - Meta::Path(path) => { - if path.is_ident("transparent") { - return Ok(true); - } + if let Meta::Path(path) = meta { + if path.is_ident("transparent") { + return Ok(true); } - _ => {} } } } From c898e64c7afd462d94337f84d00d3a3bb2481402 Mon Sep 17 00:00:00 2001 From: Nicolas Sarlin Date: Thu, 5 Dec 2024 10:52:21 +0100 Subject: [PATCH 4/6] chore(zk)!: update parameters for zk v2 --- tfhe/benches/integer/zk_pke.rs | 12 +++---- tfhe/docs/guides/zk-pok.md | 4 +-- tfhe/examples/utilities/params_to_file.rs | 4 +-- .../utilities/print_doc_bench_parameters.rs | 12 +++---- tfhe/examples/utilities/shortint_key_sizes.rs | 8 ++--- tfhe/src/c_api/shortint/parameters.rs | 8 ++--- tfhe/src/high_level_api/compact_list.rs | 20 +++++------ .../integers/unsigned/tests/cpu.rs | 12 +++---- tfhe/src/high_level_api/keys/public.rs | 8 ++--- tfhe/src/high_level_api/keys/server.rs | 16 ++++----- .../high_level_api/tests/tags_on_entities.rs | 12 +++---- tfhe/src/integer/ciphertext/compact_list.rs | 16 ++++----- tfhe/src/integer/key_switching_key/test.rs | 14 ++++---- tfhe/src/js_on_wasm_api/shortint.rs | 8 ++--- tfhe/src/shortint/keycache.rs | 6 ++-- .../p_fail_2_minus_64/ks_pbs.rs | 33 +++++++++++++------ .../key_switching/p_fail_2_minus_64/ks_pbs.rs | 28 +++++++++++++--- tfhe/src/zk/mod.rs | 6 ++-- tfhe/tests/zk_wasm_x86_test.rs | 8 ++--- 19 files changed, 134 insertions(+), 101 deletions(-) diff --git a/tfhe/benches/integer/zk_pke.rs b/tfhe/benches/integer/zk_pke.rs index 3708a08d6e..8d789caf1f 100644 --- a/tfhe/benches/integer/zk_pke.rs +++ b/tfhe/benches/integer/zk_pke.rs @@ -14,8 +14,8 @@ use tfhe::integer::parameters::IntegerCompactCiphertextListExpansionMode; use tfhe::integer::{ClientKey, CompactPrivateKey, CompactPublicKey, ServerKey}; use tfhe::keycache::NamedParam; use tfhe::shortint::parameters::classic::tuniform::p_fail_2_minus_64::ks_pbs::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; -use tfhe::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; -use tfhe::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; +use tfhe::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 tfhe::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; use tfhe::shortint::parameters::PBSParameters; use tfhe::zk::{CompactPkeCrs, ZkComputeLoad}; use utilities::{write_to_json, OperatorType}; @@ -34,8 +34,8 @@ fn pke_zk_proof(c: &mut Criterion) { .measurement_time(std::time::Duration::from_secs(60)); for (param_pke, _param_casting, param_fhe) in [( - PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, - PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, )] { let param_name = param_fhe.name(); @@ -156,8 +156,8 @@ fn pke_zk_verify(c: &mut Criterion, results_file: &Path) { .expect("cannot open results file"); for (param_pke, param_casting, param_fhe) in [( - PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, - PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, )] { let param_name = param_fhe.name(); diff --git a/tfhe/docs/guides/zk-pok.md b/tfhe/docs/guides/zk-pok.md index 321719e743..2efcf4c394 100644 --- a/tfhe/docs/guides/zk-pok.md +++ b/tfhe/docs/guides/zk-pok.md @@ -87,9 +87,9 @@ pub fn main() -> Result<(), Box> { 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::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let cpk_params = tfhe::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; // And parameters allowing to keyswitch/cast to the computation parameters. - let casting_params = tfhe::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let casting_params = tfhe::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::V0_11_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) .use_dedicated_compact_public_key_parameters((cpk_params, casting_params)); diff --git a/tfhe/examples/utilities/params_to_file.rs b/tfhe/examples/utilities/params_to_file.rs index 7526649da0..36856ad145 100644 --- a/tfhe/examples/utilities/params_to_file.rs +++ b/tfhe/examples/utilities/params_to_file.rs @@ -7,7 +7,7 @@ use tfhe::core_crypto::prelude::{DynamicDistribution, TUniform, UnsignedInteger} use tfhe::keycache::NamedParam; use tfhe::shortint::parameters::classic::compact_pk::ALL_PARAMETER_VEC_COMPACT_PK; use tfhe::shortint::parameters::classic::gaussian::ALL_PARAMETER_VEC_GAUSSIAN; -use tfhe::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; +use tfhe::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 tfhe::shortint::parameters::multi_bit::gaussian::ALL_MULTI_BIT_PARAMETER_VEC; use tfhe::shortint::parameters::{ CompactPublicKeyEncryptionParameters, CompressionParameters, ShortintParameterSet, @@ -285,7 +285,7 @@ fn main() { write_all_params_in_file( "shortint_cpke_parameters_lattice_estimator.sage", - &[PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64], + &[V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64], ParametersFormat::Lwe, ); diff --git a/tfhe/examples/utilities/print_doc_bench_parameters.rs b/tfhe/examples/utilities/print_doc_bench_parameters.rs index 892ebe6d1d..c13b9558d8 100644 --- a/tfhe/examples/utilities/print_doc_bench_parameters.rs +++ b/tfhe/examples/utilities/print_doc_bench_parameters.rs @@ -1,7 +1,7 @@ use tfhe::keycache::NamedParam; use tfhe::shortint::parameters::classic::tuniform::p_fail_2_minus_64::ks_pbs::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; -use tfhe::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; -use tfhe::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; +use tfhe::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 tfhe::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; use tfhe::shortint::parameters::multi_bit::tuniform::p_fail_2_minus_64::ks_pbs_gpu::PARAM_GPU_MULTI_BIT_GROUP_3_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; pub fn main() { @@ -43,9 +43,9 @@ pub fn main() { println!("Compact Public Key parameters (encryption + ZK):"); println!( "{}", - stringify!(PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64) + stringify!(V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64) ); - println!("{PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64:?}\n"); + println!("{V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64:?}\n"); println!("Corresponding compute FHE parameters:"); println!( @@ -57,7 +57,7 @@ pub fn main() { println!("Keyswitch from encryption + ZK to compute parameters:"); println!( "{}", - stringify!(PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64) + stringify!(V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64) ); - println!("{PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64:?}"); + println!("{V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64:?}"); } diff --git a/tfhe/examples/utilities/shortint_key_sizes.rs b/tfhe/examples/utilities/shortint_key_sizes.rs index 50f25a7781..5ea02c201b 100644 --- a/tfhe/examples/utilities/shortint_key_sizes.rs +++ b/tfhe/examples/utilities/shortint_key_sizes.rs @@ -7,8 +7,8 @@ use std::io::Write; use std::path::Path; use tfhe::keycache::NamedParam; use tfhe::shortint::keycache::KEY_CACHE; -use tfhe::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; -use tfhe::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; +use tfhe::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 tfhe::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; use tfhe::shortint::parameters::list_compression::COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; use tfhe::shortint::parameters::{ PARAM_GPU_MULTI_BIT_GROUP_3_MESSAGE_1_CARRY_1_KS_PBS_GAUSSIAN_2M64, @@ -222,7 +222,7 @@ fn tuniform_key_set_sizes(results_file: &Path) { &mut file, ); - let param_pke = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let param_pke = V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let param_pke_name = stringify!(PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64); let compact_private_key = CompactPrivateKey::new(param_pke); let compressed_pk = CompressedCompactPublicKey::new(&compact_private_key); @@ -266,7 +266,7 @@ fn tuniform_key_set_sizes(results_file: &Path) { &mut file, ); - let param_casting = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let param_casting = V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let param_casting_name = stringify!(PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64); let compressed_casting_key = CompressedKeySwitchingKey::new( (&compact_private_key, None), diff --git a/tfhe/src/c_api/shortint/parameters.rs b/tfhe/src/c_api/shortint/parameters.rs index 969c16bfd4..f71bf9155c 100644 --- a/tfhe/src/c_api/shortint/parameters.rs +++ b/tfhe/src/c_api/shortint/parameters.rs @@ -2,8 +2,8 @@ pub use crate::core_crypto::commons::dispersion::StandardDev; pub use crate::core_crypto::commons::parameters::{ DecompositionBaseLog, DecompositionLevelCount, GlweDimension, LweDimension, PolynomialSize, }; -pub use crate::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; -pub use crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; +pub 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; +pub 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; pub use crate::shortint::parameters::*; #[repr(C)] @@ -243,8 +243,8 @@ impl ShortintCompactPublicKeyEncryptionParameters { pub static SHORTINT_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64: ShortintCompactPublicKeyEncryptionParameters = ShortintCompactPublicKeyEncryptionParameters::convert(( - PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, - PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, )); macro_rules! expose_as_shortint_pbs_parameters( diff --git a/tfhe/src/high_level_api/compact_list.rs b/tfhe/src/high_level_api/compact_list.rs index 60cd98398a..13c040c45a 100644 --- a/tfhe/src/high_level_api/compact_list.rs +++ b/tfhe/src/high_level_api/compact_list.rs @@ -350,9 +350,9 @@ mod zk { 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::PARAM_PKE_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; - let casting_params = crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let casting_params = crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let config = crate::ConfigBuilder::with_custom_parameters(params) .use_dedicated_compact_public_key_parameters((cpk_params, casting_params)); @@ -574,16 +574,16 @@ mod tests { #[test] fn test_compact_list_with_casting() { - use crate::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - use crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + 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; let config = crate::ConfigBuilder::with_custom_parameters( PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, ) .use_dedicated_compact_public_key_parameters(( - PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, - PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + 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(); @@ -720,16 +720,16 @@ mod tests { #[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::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - use crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + 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; let config = crate::ConfigBuilder::with_custom_parameters( PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, ) .use_dedicated_compact_public_key_parameters(( - PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, - PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + 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(); diff --git a/tfhe/src/high_level_api/integers/unsigned/tests/cpu.rs b/tfhe/src/high_level_api/integers/unsigned/tests/cpu.rs index 9fa87c8f3e..9d0a7853bb 100644 --- a/tfhe/src/high_level_api/integers/unsigned/tests/cpu.rs +++ b/tfhe/src/high_level_api/integers/unsigned/tests/cpu.rs @@ -4,8 +4,8 @@ use crate::high_level_api::{generate_keys, set_server_key, ConfigBuilder, FheUin use crate::integer::U256; use crate::safe_serialization::{DeserializationConfig, SerializationConfig}; use crate::shortint::parameters::classic::compact_pk::*; -use crate::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; -use crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; +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::*; use crate::{ ClientKey, CompactCiphertextList, CompactCiphertextListConformanceParams, CompactPublicKey, @@ -505,9 +505,9 @@ fn test_safe_deserialize_conformant_compact_fhe_uint32() { #[test] fn test_cpk_encrypt_cast_compute_hl() { - let param_pke_only = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let param_pke_only = V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let param_fhe = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let param_ksk = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let param_ksk = V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let num_block = 4usize; @@ -554,9 +554,9 @@ fn test_cpk_encrypt_cast_compute_hl() { #[test] fn test_compressed_cpk_encrypt_cast_compute_hl() { - let param_pke_only = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let param_pke_only = V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let param_fhe = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let param_ksk = PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let param_ksk = V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let num_block = 4usize; diff --git a/tfhe/src/high_level_api/keys/public.rs b/tfhe/src/high_level_api/keys/public.rs index 86298c1bab..9233c2b18c 100644 --- a/tfhe/src/high_level_api/keys/public.rs +++ b/tfhe/src/high_level_api/keys/public.rs @@ -304,9 +304,9 @@ mod test { fn conformance_compact_public_key_casting() { 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::PARAM_PKE_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; - let casting_params = crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let casting_params = crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let config = ConfigBuilder::with_custom_parameters(params) .use_dedicated_compact_public_key_parameters((cpk_params, casting_params)); @@ -340,9 +340,9 @@ mod test { fn conformance_compressed_compact_public_key_casting() { 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::PARAM_PKE_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; - let casting_params = crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let casting_params = crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let config = ConfigBuilder::with_custom_parameters(params) .use_dedicated_compact_public_key_parameters((cpk_params, casting_params)); diff --git a/tfhe/src/high_level_api/keys/server.rs b/tfhe/src/high_level_api/keys/server.rs index f5e5467079..9ecb81109a 100644 --- a/tfhe/src/high_level_api/keys/server.rs +++ b/tfhe/src/high_level_api/keys/server.rs @@ -437,9 +437,9 @@ mod test { { let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let cpk_params = ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let cpk_params = ks_pbs::V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let casting_params = crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let casting_params = crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let config = ConfigBuilder::with_custom_parameters(params) .use_dedicated_compact_public_key_parameters((cpk_params, casting_params)); @@ -495,9 +495,9 @@ mod test { { let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let mut cpk_params = ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let mut cpk_params = ks_pbs::V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let casting_params = crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let casting_params = crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let config = ConfigBuilder::with_custom_parameters(params) .use_dedicated_compact_public_key_parameters((cpk_params, casting_params)); @@ -562,9 +562,9 @@ mod test { { let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let cpk_params = ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let cpk_params = ks_pbs::V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let casting_params = crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let casting_params = crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let config = ConfigBuilder::with_custom_parameters(params) .use_dedicated_compact_public_key_parameters((cpk_params, casting_params)); @@ -620,9 +620,9 @@ mod test { { let params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let mut cpk_params = ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let mut cpk_params = ks_pbs::V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let casting_params = crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let casting_params = crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let config = ConfigBuilder::with_custom_parameters(params) .use_dedicated_compact_public_key_parameters((cpk_params, casting_params)); diff --git a/tfhe/src/high_level_api/tests/tags_on_entities.rs b/tfhe/src/high_level_api/tests/tags_on_entities.rs index c963749694..dee88cd3dc 100644 --- a/tfhe/src/high_level_api/tests/tags_on_entities.rs +++ b/tfhe/src/high_level_api/tests/tags_on_entities.rs @@ -1,6 +1,6 @@ use crate::prelude::*; -use crate::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; -use crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; +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::list_compression::COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; use crate::shortint::parameters::*; use crate::shortint::ClassicPBSParameters; @@ -18,13 +18,13 @@ fn test_tag_propagation_cpu() { Device::Cpu, PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, Some(( - PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, - PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, )), Some(COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64), Some(( PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M64, - PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, )), ) } @@ -145,7 +145,7 @@ fn test_tag_propagation_gpu() { Some(COMP_PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64), Some(( PARAM_MESSAGE_2_CARRY_2_KS_PBS_GAUSSIAN_2M64, - PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, )), ) } diff --git a/tfhe/src/integer/ciphertext/compact_list.rs b/tfhe/src/integer/ciphertext/compact_list.rs index 955a5d60d7..2de5c812fc 100644 --- a/tfhe/src/integer/ciphertext/compact_list.rs +++ b/tfhe/src/integer/ciphertext/compact_list.rs @@ -1073,15 +1073,15 @@ mod tests { BooleanBlock, ClientKey, CompactPrivateKey, CompactPublicKey, RadixCiphertext, ServerKey, }; use crate::shortint::parameters::classic::tuniform::p_fail_2_minus_64::ks_pbs::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - use crate::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - use crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + 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::zk::{CompactPkeCrs, ZkComputeLoad}; use rand::random; #[test] fn test_zk_compact_ciphertext_list_encryption_ci_run_filter() { - let pke_params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let ksk_params = PARAM_KEYSWITCH_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 fhe_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let metadata = [b'i', b'n', b't', b'e', b'g', b'e', b'r']; @@ -1142,8 +1142,8 @@ mod tests { #[test] fn test_several_proven_lists() { - let pke_params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let ksk_params = PARAM_KEYSWITCH_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 fhe_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let metadata = [b'i', b'n', b't', b'e', b'g', b'e', b'r']; @@ -1205,8 +1205,8 @@ mod tests { fn test_malicious_boolean_proven_lists() { use super::DataKind; - let pke_params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; - let ksk_params = PARAM_KEYSWITCH_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 fhe_params = PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let metadata = [b'i', b'n', b't', b'e', b'g', b'e', b'r']; diff --git a/tfhe/src/integer/key_switching_key/test.rs b/tfhe/src/integer/key_switching_key/test.rs index 7445e2a47f..5f1e6cd372 100644 --- a/tfhe/src/integer/key_switching_key/test.rs +++ b/tfhe/src/integer/key_switching_key/test.rs @@ -5,10 +5,10 @@ use crate::integer::{ ClientKey, CompactPrivateKey, CompactPublicKey, CrtClientKey, IntegerCiphertext, IntegerKeyKind, RadixCiphertext, RadixClientKey, ServerKey, }; -use crate::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; +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::{ - PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, - PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, }; use crate::shortint::parameters::{ ClassicPBSParameters, CompactPublicKeyEncryptionParameters, ShortintKeySwitchingParameters, @@ -243,17 +243,17 @@ fn test_case_cpk_encrypt_cast_compute( #[test] fn test_cpk_encrypt_cast_to_small_compute_big_ci_run_filter() { test_case_cpk_encrypt_cast_compute( - PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, - PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, ) } #[test] fn test_cpk_encrypt_cast_to_big_compute_big_ci_run_filter() { test_case_cpk_encrypt_cast_compute( - PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, - PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + V0_11_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, ) } diff --git a/tfhe/src/js_on_wasm_api/shortint.rs b/tfhe/src/js_on_wasm_api/shortint.rs index 8a50fd827b..19cf3cf427 100644 --- a/tfhe/src/js_on_wasm_api/shortint.rs +++ b/tfhe/src/js_on_wasm_api/shortint.rs @@ -4,8 +4,8 @@ use crate::core_crypto::commons::math::random::Seed; use crate::core_crypto::prelude::ActivatedRandomGenerator; use crate::js_on_wasm_api::js_high_level_api::into_js_error; use crate::shortint::parameters::classic::compact_pk::*; -use crate::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; -use crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; +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::*; use std::panic::set_hook; use wasm_bindgen::prelude::*; @@ -225,8 +225,8 @@ impl ShortintCompactPublicKeyEncryptionParameters { pub fn new(name: ShortintCompactPublicKeyEncryptionParametersName) -> Self { match name { ShortintCompactPublicKeyEncryptionParametersName::SHORTINT_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64 => Self { - compact_pke_params: PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, - casting_parameters: PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + compact_pke_params: V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + casting_parameters: V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, } } } diff --git a/tfhe/src/shortint/keycache.rs b/tfhe/src/shortint/keycache.rs index f1329b0869..27d74407c7 100644 --- a/tfhe/src/shortint/keycache.rs +++ b/tfhe/src/shortint/keycache.rs @@ -4,7 +4,7 @@ use crate::keycache::utils::named_params_impl; use crate::keycache::*; use crate::shortint::parameters::classic::compact_pk::*; use crate::shortint::parameters::classic::tuniform::p_fail_2_minus_64::ks_pbs::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; -use crate::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; +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; #[cfg(tarpaulin)] use crate::shortint::parameters::coverage_parameters::*; use crate::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_1_1_KS_PBS_TO_2_2_KS_PBS; @@ -323,14 +323,14 @@ impl NamedParam for CompressionParameters { impl NamedParam for CompactPublicKeyEncryptionParameters { fn name(&self) -> String { named_params_impl!(expose - PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64 + V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64 ); named_params_impl!( { *self; Self - } == (PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64) + } == (V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64) ); format!( diff --git a/tfhe/src/shortint/parameters/compact_public_key_only/p_fail_2_minus_64/ks_pbs.rs b/tfhe/src/shortint/parameters/compact_public_key_only/p_fail_2_minus_64/ks_pbs.rs index 02783d7a17..2dc7895d8b 100644 --- a/tfhe/src/shortint/parameters/compact_public_key_only/p_fail_2_minus_64/ks_pbs.rs +++ b/tfhe/src/shortint/parameters/compact_public_key_only/p_fail_2_minus_64/ks_pbs.rs @@ -6,13 +6,26 @@ use crate::shortint::parameters::{ MessageModulus, }; -pub const PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64: CompactPublicKeyEncryptionParameters = - CompactPublicKeyEncryptionParameters { - encryption_lwe_dimension: LweDimension(1024), - encryption_noise_distribution: DynamicDistribution::new_t_uniform(42), - message_modulus: MessageModulus(4), - carry_modulus: CarryModulus(4), - ciphertext_modulus: CiphertextModulus::new_native(), - expansion_kind: CompactCiphertextListExpansionKind::RequiresCasting, - } - .validate(); +/// This parameter set should be used when doing zk proof of public key encryption +pub const V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64: + CompactPublicKeyEncryptionParameters = CompactPublicKeyEncryptionParameters { + encryption_lwe_dimension: LweDimension(2048), + encryption_noise_distribution: DynamicDistribution::new_t_uniform(17), + message_modulus: MessageModulus(4), + carry_modulus: CarryModulus(4), + ciphertext_modulus: CiphertextModulus::new_native(), + expansion_kind: CompactCiphertextListExpansionKind::RequiresCasting, +} +.validate(); + +/// This legacy parameter set should be used with the v1 pke zk scheme of TFHE-rs v0.10 and lower +pub const V0_10_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64: + CompactPublicKeyEncryptionParameters = CompactPublicKeyEncryptionParameters { + encryption_lwe_dimension: LweDimension(1024), + encryption_noise_distribution: DynamicDistribution::new_t_uniform(42), + message_modulus: MessageModulus(4), + carry_modulus: CarryModulus(4), + ciphertext_modulus: CiphertextModulus::new_native(), + expansion_kind: CompactCiphertextListExpansionKind::RequiresCasting, +} +.validate(); diff --git a/tfhe/src/shortint/parameters/key_switching/p_fail_2_minus_64/ks_pbs.rs b/tfhe/src/shortint/parameters/key_switching/p_fail_2_minus_64/ks_pbs.rs index af46e06804..6d16881519 100644 --- a/tfhe/src/shortint/parameters/key_switching/p_fail_2_minus_64/ks_pbs.rs +++ b/tfhe/src/shortint/parameters/key_switching/p_fail_2_minus_64/ks_pbs.rs @@ -13,12 +13,13 @@ pub const PARAM_KEYSWITCH_1_1_KS_PBS_TO_2_2_KS_PBS: ShortintKeySwitchingParamete // these parameters allow to keyswitch from one set of keys of the 2_2 TUniform parameters to // another set of keys. The ciphertext will be under the small key and a PBS with the destination // keys will be applied to finish the keyswitch. -pub const PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64: ShortintKeySwitchingParameters = - PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; +pub const V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64: + ShortintKeySwitchingParameters = + V0_11_PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; // Parameters to keyswitch from input PKE 2_2 TUniform parameters to 2_2 KS_PBS compute parameters // arriving under the small key, requires a PBS to get to the big key -pub const PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64: +pub const V0_11_PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64: ShortintKeySwitchingParameters = ShortintKeySwitchingParameters { ks_level: DecompositionLevelCount(5), ks_base_log: DecompositionBaseLog(3), @@ -27,7 +28,26 @@ pub const PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64: // Parameters to keyswitch from input PKE 2_2 TUniform parameters to 2_2 KS_PBS compute parameters // arriving under the big key, requires a PBS to get to the big key -pub const PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64: +pub const V0_11_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64: + ShortintKeySwitchingParameters = ShortintKeySwitchingParameters { + ks_level: DecompositionLevelCount(1), + ks_base_log: DecompositionBaseLog(23), + destination_key: EncryptionKeyChoice::Big, +}; + +// These are the same parameters as they where defined in TFHE-rs 0.10 and before +pub const V0_10_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64: + ShortintKeySwitchingParameters = + V0_10_PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + +pub const V0_10_PARAM_KEYSWITCH_PKE_TO_SMALL_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64: + ShortintKeySwitchingParameters = ShortintKeySwitchingParameters { + ks_level: DecompositionLevelCount(5), + ks_base_log: DecompositionBaseLog(3), + destination_key: EncryptionKeyChoice::Small, +}; + +pub const V0_10_PARAM_KEYSWITCH_PKE_TO_BIG_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64: ShortintKeySwitchingParameters = ShortintKeySwitchingParameters { ks_level: DecompositionLevelCount(1), ks_base_log: DecompositionBaseLog(27), diff --git a/tfhe/src/zk/mod.rs b/tfhe/src/zk/mod.rs index 46c6672fe1..e039f0655e 100644 --- a/tfhe/src/zk/mod.rs +++ b/tfhe/src/zk/mod.rs @@ -710,12 +710,12 @@ impl Compressible for CompactPkeCrs { mod test { use super::*; use crate::safe_serialization::{safe_deserialize_conformant, safe_serialize}; - use crate::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + 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::{CarryModulus, MessageModulus}; #[test] fn test_crs_conformance() { - let params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let params = V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let mut bad_params = params; bad_params.carry_modulus = CarryModulus(8); bad_params.message_modulus = MessageModulus(8); @@ -751,7 +751,7 @@ mod test { #[test] fn test_crs_serialization() { - let params = PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; + let params = V0_11_PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; let mut rng = rand::thread_rng(); diff --git a/tfhe/tests/zk_wasm_x86_test.rs b/tfhe/tests/zk_wasm_x86_test.rs index 92fe19c119..d341a97c16 100644 --- a/tfhe/tests/zk_wasm_x86_test.rs +++ b/tfhe/tests/zk_wasm_x86_test.rs @@ -11,8 +11,8 @@ use std::fs::File; use std::path::{Path, PathBuf}; use std::process::Command; use tfhe::safe_serialization::{safe_deserialize, safe_serialize}; -use tfhe::shortint::parameters::compact_public_key_only::p_fail_2_minus_64::ks_pbs::PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; -use tfhe::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; +use tfhe::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 tfhe::shortint::parameters::key_switching::p_fail_2_minus_64::ks_pbs::V0_11_PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64; use tfhe::zk::CompactPkeCrs; use tfhe::{ClientKey, CompactPublicKey, ConfigBuilder, ProvenCompactCiphertextList}; @@ -25,8 +25,8 @@ fn gen_key_and_crs() -> (CompactPublicKey, CompactPkeCrs) { let config = crate::ConfigBuilder::with_custom_parameters(PARAM_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64) .use_dedicated_compact_public_key_parameters(( - PARAM_PKE_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, - PARAM_KEYSWITCH_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M64, + 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(); From 1edb808c158f00663fdd18e582bb43e1269b33f4 Mon Sep 17 00:00:00 2001 From: Nicolas Sarlin Date: Thu, 5 Dec 2024 15:26:39 +0100 Subject: [PATCH 5/6] chore(backward): move allow(dead_code) to dispatch variants This allows to detect unused dispatch enums --- tfhe-zk-pok/src/backward_compatibility/mod.rs | 4 ++-- tfhe-zk-pok/src/backward_compatibility/pke.rs | 4 ++-- tfhe/src/integer/backward_compatibility/ciphertext/mod.rs | 2 +- tfhe/src/shortint/backward_compatibility/ciphertext/mod.rs | 2 +- utils/tfhe-versionable/examples/manual_impl.rs | 3 ++- utils/tfhe-versionable/examples/transparent_then_not.rs | 4 ++-- utils/tfhe-versionable/tests/bounds_private_in_public.rs | 2 +- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tfhe-zk-pok/src/backward_compatibility/mod.rs b/tfhe-zk-pok/src/backward_compatibility/mod.rs index 81769bd91d..b1b4b6f4ea 100644 --- a/tfhe-zk-pok/src/backward_compatibility/mod.rs +++ b/tfhe-zk-pok/src/backward_compatibility/mod.rs @@ -60,14 +60,14 @@ impl Display for IncompleteProof { impl Error for IncompleteProof {} #[derive(VersionsDispatch)] -#[allow(dead_code)] pub(crate) enum GroupElementsVersions { + #[allow(dead_code)] V0(GroupElements), } #[derive(VersionsDispatch)] -#[allow(dead_code)] pub(crate) enum SerializableGroupElementsVersions { + #[allow(dead_code)] V0(SerializableGroupElements), } diff --git a/tfhe-zk-pok/src/backward_compatibility/pke.rs b/tfhe-zk-pok/src/backward_compatibility/pke.rs index c84a026474..4ece54522f 100644 --- a/tfhe-zk-pok/src/backward_compatibility/pke.rs +++ b/tfhe-zk-pok/src/backward_compatibility/pke.rs @@ -49,8 +49,8 @@ pub enum ProofVersions { } #[derive(VersionsDispatch)] -#[allow(dead_code)] pub(crate) enum ComputeLoadProofFieldVersions { + #[allow(dead_code)] V0(ComputeLoadProofFields), } @@ -107,11 +107,11 @@ where } #[derive(VersionsDispatch)] -#[allow(dead_code)] pub(crate) enum CompressedComputeLoadProofFieldsVersions where G::G1: Compressible, G::G2: Compressible, { + #[allow(dead_code)] V0(CompressedComputeLoadProofFields), } diff --git a/tfhe/src/integer/backward_compatibility/ciphertext/mod.rs b/tfhe/src/integer/backward_compatibility/ciphertext/mod.rs index 1a2459e83a..3061b8a277 100644 --- a/tfhe/src/integer/backward_compatibility/ciphertext/mod.rs +++ b/tfhe/src/integer/backward_compatibility/ciphertext/mod.rs @@ -77,8 +77,8 @@ pub enum CompressedModulusSwitchedRadixCiphertextVersions { } #[derive(VersionsDispatch)] -#[allow(dead_code)] pub(crate) enum CompressedModulusSwitchedRadixCiphertextGenericVersions { + #[allow(dead_code)] V0(CompressedModulusSwitchedRadixCiphertextGeneric), } diff --git a/tfhe/src/shortint/backward_compatibility/ciphertext/mod.rs b/tfhe/src/shortint/backward_compatibility/ciphertext/mod.rs index 2e4ce9dd17..50a31e00e2 100644 --- a/tfhe/src/shortint/backward_compatibility/ciphertext/mod.rs +++ b/tfhe/src/shortint/backward_compatibility/ciphertext/mod.rs @@ -134,8 +134,8 @@ pub enum CompressedModulusSwitchedCiphertextVersions { } #[derive(VersionsDispatch)] -#[allow(dead_code)] pub(crate) enum InternalCompressedModulusSwitchedCiphertextVersions { + #[allow(dead_code)] V0(InternalCompressedModulusSwitchedCiphertext), } diff --git a/utils/tfhe-versionable/examples/manual_impl.rs b/utils/tfhe-versionable/examples/manual_impl.rs index efc3323218..58b043fd2a 100644 --- a/utils/tfhe-versionable/examples/manual_impl.rs +++ b/utils/tfhe-versionable/examples/manual_impl.rs @@ -84,9 +84,10 @@ impl Deserialize<'de> + Default> Unversio // Since MyStructV0 is only composed of built-in types, it does not need recursive versioning and // can be used as its own "version type". #[derive(Serialize)] -#[allow(dead_code)] enum MyStructVersionsDispatch<'vers, T: 'vers + Versionize> { + #[allow(dead_code)] V0(MyStructV0), + #[allow(dead_code)] V1(MyStructVersion<'vers, T>), } diff --git a/utils/tfhe-versionable/examples/transparent_then_not.rs b/utils/tfhe-versionable/examples/transparent_then_not.rs index b01f4d0529..758409086e 100644 --- a/utils/tfhe-versionable/examples/transparent_then_not.rs +++ b/utils/tfhe-versionable/examples/transparent_then_not.rs @@ -22,8 +22,8 @@ struct MyStructWrapper { count: u64, } -// We need to create a dispatch enum that has the same history as the inner type until the point -// where the wrapper is not transparent anymore. +// We need to create a dispatch enum that follows the version numbers of the inner type, until the +// point where the wrapper is not transparent anymore. #[derive(VersionsDispatch)] #[allow(unused)] enum MyStructWrapperVersions { diff --git a/utils/tfhe-versionable/tests/bounds_private_in_public.rs b/utils/tfhe-versionable/tests/bounds_private_in_public.rs index 489d6ad0fc..2168272bd0 100644 --- a/utils/tfhe-versionable/tests/bounds_private_in_public.rs +++ b/utils/tfhe-versionable/tests/bounds_private_in_public.rs @@ -30,8 +30,8 @@ mod mymod { struct Private(T); #[derive(VersionsDispatch)] - #[allow(dead_code)] enum PrivateVersions { + #[allow(dead_code)] V0(Private), } } From a68f83e59d6465bcb2ce197219c0423fff39bbde Mon Sep 17 00:00:00 2001 From: Nicolas Sarlin Date: Fri, 13 Dec 2024 10:56:49 +0100 Subject: [PATCH 6/6] chore(zk): check that k <= d for zk crs --- tfhe-zk-pok/src/proofs/mod.rs | 1 + tfhe-zk-pok/src/proofs/pke_v2.rs | 8 +++++++- tfhe/src/zk/mod.rs | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tfhe-zk-pok/src/proofs/mod.rs b/tfhe-zk-pok/src/proofs/mod.rs index f3cd1b5305..fceb97ca22 100644 --- a/tfhe-zk-pok/src/proofs/mod.rs +++ b/tfhe-zk-pok/src/proofs/mod.rs @@ -153,6 +153,7 @@ fn assert_pke_proof_preconditions( big_d: usize, big_d_max: usize, ) { + assert!(k_max <= d); assert_eq!(c1.len(), d); assert_eq!(e1.len(), d); diff --git a/tfhe-zk-pok/src/proofs/pke_v2.rs b/tfhe-zk-pok/src/proofs/pke_v2.rs index 4d1a82c2bc..05fc3a38ee 100644 --- a/tfhe-zk-pok/src/proofs/pke_v2.rs +++ b/tfhe-zk-pok/src/proofs/pke_v2.rs @@ -498,6 +498,12 @@ pub fn compute_crs_params( msbs_zero_padding_bit_count: u64, bound_type: Bound, ) -> (usize, usize, u128, usize) { + assert!( + k <= d, + "Invalid parameters for zk_pok, the maximum number of messages k should be smaller \ +than the lwe dimension d. Please pick a smaller k: k = {k}, d = {d}" + ); + let mut B_bound_squared = { (match bound_type { // GHL factor is 9.75, 9.75**2 = 95.0625 @@ -527,7 +533,7 @@ Please select a smaller B, d and/or k" // safely used for this assert!( m_bound <= 64, - "Invalid parameters for zk_pok, w e only support 64 bits integer. \ + "Invalid parameters for zk_pok, we only support 64 bits integer. \ The computed m parameter is {m_bound} > 64. Please select a smaller B, d and/or k" ); diff --git a/tfhe/src/zk/mod.rs b/tfhe/src/zk/mod.rs index e039f0655e..760489d6e7 100644 --- a/tfhe/src/zk/mod.rs +++ b/tfhe/src/zk/mod.rs @@ -298,6 +298,10 @@ impl CompactPkeCrs { Scalar: UnsignedInteger + CastInto + Debug, NoiseDistribution: BoundedDistribution, { + if max_num_cleartext.0 > lwe_dim.0 { + return Err("Maximum number of cleartexts is greater than the lwe dimension".into()); + } + let noise_bound = match zk_scheme { CompactPkeZkScheme::V1 => Self::compute_bound_v1(noise_distribution)?, CompactPkeZkScheme::V2 => Self::compute_bound_v2(noise_distribution)?,