diff --git a/legogroth16/src/lib.rs b/legogroth16/src/lib.rs index 6f049749..08d209b6 100644 --- a/legogroth16/src/lib.rs +++ b/legogroth16/src/lib.rs @@ -10,10 +10,6 @@ // #[macro_use] // extern crate bench_utils; -#[cfg(feature = "r1cs")] -#[macro_use] -extern crate derivative; - /// Reduce an R1CS instance to a *Quadratic Arithmetic Program* instance. pub(crate) mod r1cs_to_qap; diff --git a/proof_system/Cargo.toml b/proof_system/Cargo.toml index b8c0685f..a3afc586 100644 --- a/proof_system/Cargo.toml +++ b/proof_system/Cargo.toml @@ -39,6 +39,8 @@ bulletproofs_plus_plus = { version = "0.6.0", default-features = false, path = " smc_range_proof = { version = "0.6.0", default-features = false, path = "../smc_range_proof" } short_group_sig = { version = "0.4.0", default-features = false, path = "../short_group_sig" } kvac = { version = "0.5.0", default-features = false, path = "../kvac" } +verifiable_encryption = { version = "0.1.0", default-features = false, path = "../verifiable_encryption" } +sha3 = { version = "0.10.6", default-features = false } [dev-dependencies] ark-bls12-381.workspace = true @@ -49,8 +51,8 @@ test_utils = { default-features = false, path = "../test_utils" } [features] default = ["parallel"] -std = ["ark-ff/std", "ark-ec/std", "ark-std/std", "ark-serialize/std", "schnorr_pok/std", "dock_crypto_utils/std", "serde/std", "saver/std", "ark-groth16/std", "legogroth16/std", "ark-r1cs-std/std", "ark-relations/std", "merlin/std", "coconut-crypto/std", "bulletproofs_plus_plus/std", "smc_range_proof/std", "short_group_sig/std", "kvac/std"] +std = ["ark-ff/std", "ark-ec/std", "ark-std/std", "ark-serialize/std", "schnorr_pok/std", "dock_crypto_utils/std", "serde/std", "saver/std", "ark-groth16/std", "legogroth16/std", "ark-r1cs-std/std", "ark-relations/std", "merlin/std", "coconut-crypto/std", "bulletproofs_plus_plus/std", "smc_range_proof/std", "short_group_sig/std", "kvac/std", "verifiable_encryption/std"] print-trace = ["ark-std/print-trace", "schnorr_pok/print-trace", "bbs_plus/print-trace", "vb_accumulator/print-trace", "dock_crypto_utils/print-trace"] -parallel = ["std", "ark-ff/parallel", "ark-ec/parallel", "ark-std/parallel", "rayon", "schnorr_pok/parallel", "bbs_plus/parallel", "vb_accumulator/parallel", "saver/parallel", "ark-groth16/parallel", "legogroth16/parallel", "ark-r1cs-std/parallel", "dock_crypto_utils/parallel", "coconut-crypto/parallel", "bulletproofs_plus_plus/parallel", "smc_range_proof/parallel", "short_group_sig/parallel", "kvac/parallel"] +parallel = ["std", "ark-ff/parallel", "ark-ec/parallel", "ark-std/parallel", "rayon", "schnorr_pok/parallel", "bbs_plus/parallel", "vb_accumulator/parallel", "saver/parallel", "ark-groth16/parallel", "legogroth16/parallel", "ark-r1cs-std/parallel", "dock_crypto_utils/parallel", "coconut-crypto/parallel", "bulletproofs_plus_plus/parallel", "smc_range_proof/parallel", "short_group_sig/parallel", "kvac/parallel", "verifiable_encryption/parallel"] wasmer-js = ["legogroth16/wasmer-js"] wasmer-sys = ["legogroth16/wasmer-sys"] diff --git a/proof_system/src/constants.rs b/proof_system/src/constants.rs index 8a8fc7a9..f0f001b7 100644 --- a/proof_system/src/constants.rs +++ b/proof_system/src/constants.rs @@ -22,3 +22,5 @@ pub const KB_POS_ACCUM_MEM_LABEL: &'static [u8; 34] = b"KB-positive-accumulator- pub const KB_POS_ACCUM_CDH_MEM_LABEL: &'static [u8; 38] = b"KB-positive-accumulator-CDH-membership"; pub const BBDT16_KVAC_LABEL: &'static [u8; 14] = b"BDDT-2016-KVAC"; +pub const VE_TZ_21_LABEL: &'static [u8; 8] = b"VE-TZ-21"; +pub const VE_TZ_21_ROBUST_LABEL: &'static [u8; 15] = b"VE-TZ-21-Robust"; diff --git a/proof_system/src/error.rs b/proof_system/src/error.rs index 3a2e62e0..4ceac469 100644 --- a/proof_system/src/error.rs +++ b/proof_system/src/error.rs @@ -9,6 +9,7 @@ use saver::error::SaverError; use schnorr_pok::error::SchnorrError; use smc_range_proof::prelude::SmcRangeProofError; use vb_accumulator::error::VBAccumulatorError; +use verifiable_encryption::error::VerifiableEncryptionError; #[derive(Debug)] pub enum ProofSystemError { @@ -111,6 +112,10 @@ pub enum ProofSystemError { UnequalResponseOfSaverCiphertextAndChunk(usize), ResponseForWitnessNotFoundForStatement(usize), NoResponseFoundForWitnessRef(usize, usize), + MissingBlindingForStatementAtIndex(usize, usize), + VerifiableEncryption(u32, VerifiableEncryptionError), + NotALegoGroth16StatementProof, + NotAVeTZ21StatementProof, } impl From for ProofSystemError { diff --git a/proof_system/src/lib.rs b/proof_system/src/lib.rs index bf51861c..b5679efc 100644 --- a/proof_system/src/lib.rs +++ b/proof_system/src/lib.rs @@ -164,7 +164,7 @@ extern crate core; pub mod setup_params; #[macro_use] mod derived_params; -mod constants; +pub mod constants; pub mod error; mod macros; pub mod meta_statement; diff --git a/proof_system/src/prover.rs b/proof_system/src/prover.rs index 3055a1c5..e232607d 100644 --- a/proof_system/src/prover.rs +++ b/proof_system/src/prover.rs @@ -26,7 +26,8 @@ use crate::{ COMPOSITE_PROOF_LABEL, CONTEXT_LABEL, KB_POS_ACCUM_CDH_MEM_LABEL, KB_POS_ACCUM_MEM_LABEL, KB_UNI_ACCUM_CDH_MEM_LABEL, KB_UNI_ACCUM_CDH_NON_MEM_LABEL, KB_UNI_ACCUM_MEM_LABEL, KB_UNI_ACCUM_NON_MEM_LABEL, NONCE_LABEL, PS_LABEL, VB_ACCUM_CDH_MEM_LABEL, - VB_ACCUM_CDH_NON_MEM_LABEL, VB_ACCUM_MEM_LABEL, VB_ACCUM_NON_MEM_LABEL, + VB_ACCUM_CDH_NON_MEM_LABEL, VB_ACCUM_MEM_LABEL, VB_ACCUM_NON_MEM_LABEL, VE_TZ_21_LABEL, + VE_TZ_21_ROBUST_LABEL, }, meta_statement::{EqualWitnesses, WitnessRef}, prelude::SnarkpackSRS, @@ -63,9 +64,11 @@ use crate::{ r1cs_legogorth16::R1CSLegogroth16Protocol, saver::SaverProtocol, schnorr::SchnorrProtocol, + verifiable_encryption_tz_21::VeTZ21Protocol, }, }; use dock_crypto_utils::{ + aliases::FullDigest, expect_equality, hashing_utils::field_elem_from_try_and_incr, signature::MultiMessageSignatureParams, @@ -136,7 +139,7 @@ impl Proof { /// Also returns the randomness used by statements using SAVER and LegoGroth16 proofs which can /// then be used as helpers in subsequent proof creations where these proofs are reused than /// creating fresh proofs. - pub fn new( + pub fn new( rng: &mut R, proof_spec: ProofSpec, witnesses: Witnesses, @@ -248,6 +251,36 @@ impl Proof { }}; } + macro_rules! ve_tz_21_init { + ($rng: ident, $s_idx: ident, $s: ident, $w: ident, $init_name: ident, $label: ident) => {{ + let witness_count = $w.len(); + let comm_key = $s.get_comm_key(&proof_spec.setup_params, $s_idx)?; + // +1 since commitment includes randomness as well to make it perfectly hiding + if comm_key.len() < (witness_count + 1) { + return Err(ProofSystemError::IncompatiblePedCommSetupParamAtIndex( + $s_idx, + )); + } + // Get blindings for all the witnesses + let mut b = Vec::with_capacity(witness_count); + for i in 0..witness_count { + if let Some(blinding) = blindings.remove(&($s_idx, i)) { + b.push(blinding); + } else { + return Err(ProofSystemError::MissingBlindingForStatementAtIndex( + $s_idx, i, + )); + } + } + let enc_params = $s.get_enc_params(&proof_spec.setup_params, $s_idx)?; + let mut sp = VeTZ21Protocol::new($s_idx, comm_key, enc_params); + sp.$init_name::($rng, $w, b)?; + transcript.set_label($label); + sp.challenge_contribution(&mut transcript)?; + sub_protocols.push(SubProtocol::VeTZ21(sp)); + }}; + } + /// Build a map of blindings for witnesses of given the statement index. The key is the witness /// index and value is the blinding. Also removes that blinding from the global blindings map /// containing blinding for each witness reference. @@ -771,6 +804,18 @@ impl Proof { } _ => err_incompat_witness!(s_idx, s, witness), }, + Statement::VeTZ21(s) => match witness { + Witness::VeTZ21(w) => { + ve_tz_21_init!(rng, s_idx, s, w, init, VE_TZ_21_LABEL); + } + _ => err_incompat_witness!(s_idx, s, witness), + }, + Statement::VeTZ21Robust(s) => match witness { + Witness::VeTZ21Robust(w) => { + ve_tz_21_init!(rng, s_idx, s, w, init_robust, VE_TZ_21_ROBUST_LABEL); + } + _ => err_incompat_witness!(s_idx, s, witness), + }, _ => return Err(ProofSystemError::InvalidStatement), } } @@ -979,6 +1024,13 @@ impl Proof { SubProtocol::KBUniversalAccumulatorNonMembershipKV(mut sp) => { sp.gen_proof_contribution(&challenge)? } + SubProtocol::VeTZ21(mut sp) => { + if sp.ve_proof.is_some() { + sp.gen_proof_contribution(&challenge)? + } else { + sp.gen_proof_contribution_robust(&challenge)? + } + } }); } @@ -1086,30 +1138,6 @@ impl Proof { field_elem_from_try_and_incr::(bytes) } - pub fn get_saver_ciphertext_and_proof( - &self, - index: usize, - ) -> Result<(&Ciphertext, &ark_groth16::Proof), ProofSystemError> { - let st = self.statement_proof(index)?; - if let StatementProof::Saver(s) = st { - Ok((&s.ciphertext, &s.snark_proof)) - } else { - Err(ProofSystemError::NotASaverStatementProof) - } - } - - pub fn get_legogroth16_proof( - &self, - index: usize, - ) -> Result<&legogroth16::Proof, ProofSystemError> { - let st = self.statement_proof(index)?; - match st { - StatementProof::BoundCheckLegoGroth16(s) => Ok(&s.snark_proof), - StatementProof::R1CSLegoGroth16(s) => Ok(&s.snark_proof), - _ => Err(ProofSystemError::NotASaverStatementProof), - } - } - pub fn for_aggregate(&self) -> Self { let mut statement_proofs = vec![]; for sp in self.statement_proofs() { @@ -1177,4 +1205,22 @@ impl Proof { } } } + + // fn get_ve_func_args<'a, 'b: 'a>(s_idx: usize, s: &'a VerifiableEncryptionTZ21, proof_spec: &'b ProofSpec, witness_count: usize, blindings: &'b mut BTreeMap) -> Result<(Vec, &'a [E::G1Affine], &'a ElgamalEncryptionParams), ProofSystemError> { + // let comm_key = s.get_comm_key(&proof_spec.setup_params, s_idx)?; + // // +1 since commitment includes randomness as well to make it perfectly hiding + // if comm_key.len() < (witness_count + 1) { + // return Err(ProofSystemError::IncompatiblePedCommSetupParamAtIndex(s_idx)) + // } + // let mut b = Vec::with_capacity(witness_count); + // for i in 0..witness_count { + // if let Some(blinding) = blindings.remove(&(s_idx, i)) { + // b.push(blinding); + // } else { + // return Err(ProofSystemError::MissingBlindingForStatementAtIndex(s_idx, i)) + // } + // } + // let enc_params = s.get_enc_params(&proof_spec.setup_params, s_idx)?; + // Ok((b, comm_key.as_slice(), enc_params)) + // } } diff --git a/proof_system/src/setup_params.rs b/proof_system/src/setup_params.rs index 99a89209..9c693d6d 100644 --- a/proof_system/src/setup_params.rs +++ b/proof_system/src/setup_params.rs @@ -9,7 +9,8 @@ use crate::{ prelude::bound_check_smc::SmcParamsAndCommitmentKey, statement::bound_check_smc_with_kv::SmcParamsAndCommitmentKeyAndSecretKey, }; -use ark_ec::pairing::Pairing; +use ark_ec::{pairing::Pairing, AffineRepr}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::vec::Vec; use bbs_plus::prelude::{ PublicKeyG2 as BBSPublicKeyG2, SignatureParams23G1 as BBSSignatureParams23G1, @@ -74,6 +75,7 @@ pub enum SetupParams { BBDT16MACParams(MACParams), PedersenCommitmentKeyG2(#[serde_as(as = "Vec")] Vec), CommitmentKeyG2(#[serde_as(as = "ArkObjectBytes")] PedersenCommitmentKey), + ElgamalEncryption(ElgamalEncryptionParams), } macro_rules! delegate { @@ -109,7 +111,8 @@ macro_rules! delegate { KBPositiveAccumulatorPublicKey, BBDT16MACParams, PedersenCommitmentKeyG2, - CommitmentKeyG2 + CommitmentKeyG2, + ElgamalEncryption : $($tt)+ } }}; @@ -148,7 +151,8 @@ macro_rules! delegate_reverse { KBPositiveAccumulatorPublicKey, BBDT16MACParams, PedersenCommitmentKeyG2, - CommitmentKeyG2 + CommitmentKeyG2, + ElgamalEncryption : $($tt)+ } @@ -176,6 +180,19 @@ macro_rules! extract_param { }}; } +/// Elgamal encryption parameters generated by the decryptor +#[serde_as] +#[derive( + Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize, +)] +pub struct ElgamalEncryptionParams { + /// Generator used in the scheme to generate public key and ephemeral public key by sender/encryptor + #[serde_as(as = "ArkObjectBytes")] + pub gen: G, + #[serde_as(as = "ArkObjectBytes")] + pub public_key: G, +} + mod serialization { use super::*; use ark_serialize::{ diff --git a/proof_system/src/statement/mod.rs b/proof_system/src/statement/mod.rs index b736d702..2b77eb24 100644 --- a/proof_system/src/statement/mod.rs +++ b/proof_system/src/statement/mod.rs @@ -21,6 +21,7 @@ pub mod ped_comm; pub mod ps_signature; pub mod r1cs_legogroth16; pub mod saver; +pub mod verifiable_encryption_tz_21; /// Type of relation being proved and the public values for the relation #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -128,6 +129,12 @@ pub enum Statement { ), PoKBBSSignature23IETFG1Prover(bbs_23_ietf::PoKBBSSignature23IETFG1Prover), PoKBBSSignature23IETFG1Verifier(bbs_23_ietf::PoKBBSSignature23IETFG1Verifier), + /// Verifiable Encryption using DKGith protocol in the scheme TZ21 + // TODO: This should have the const generics used by the corresponding protocol + VeTZ21(verifiable_encryption_tz_21::VerifiableEncryptionTZ21), + /// Verifiable Encryption using Robust DKGith protocol in the scheme TZ21 + // TODO: This should have the const generics used by the corresponding protocol + VeTZ21Robust(verifiable_encryption_tz_21::VerifiableEncryptionTZ21), } /// A collection of statements @@ -205,7 +212,9 @@ macro_rules! delegate { KBUniversalAccumulatorNonMembershipKV, KBUniversalAccumulatorNonMembershipKVFullVerifier, PoKBBSSignature23IETFG1Prover, - PoKBBSSignature23IETFG1Verifier + PoKBBSSignature23IETFG1Verifier, + VeTZ21, + VeTZ21Robust : $($tt)+ } }} @@ -260,7 +269,9 @@ macro_rules! delegate_reverse { KBUniversalAccumulatorNonMembershipKV, KBUniversalAccumulatorNonMembershipKVFullVerifier, PoKBBSSignature23IETFG1Prover, - PoKBBSSignature23IETFG1Verifier + PoKBBSSignature23IETFG1Verifier, + VeTZ21, + VeTZ21Robust : $($tt)+ } diff --git a/proof_system/src/statement/verifiable_encryption_tz_21.rs b/proof_system/src/statement/verifiable_encryption_tz_21.rs new file mode 100644 index 00000000..f23f8bd0 --- /dev/null +++ b/proof_system/src/statement/verifiable_encryption_tz_21.rs @@ -0,0 +1,108 @@ +use crate::{ + error::ProofSystemError, + prelude::{SetupParams, Statement}, + setup_params::ElgamalEncryptionParams, +}; +use ark_ec::{pairing::Pairing, AffineRepr}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::vec::Vec; +use dock_crypto_utils::serde_utils::ArkObjectBytes; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; + +#[serde_as] +#[derive( + Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize, +)] +#[serde(bound = "")] +pub struct VerifiableEncryptionTZ21 { + pub enc_params: Option>, + pub enc_params_ref: Option, + #[serde_as(as = "Option>")] + pub comm_key: Option>, + pub comm_key_ref: Option, +} + +impl VerifiableEncryptionTZ21 { + /// Get statement for DKGitH protocol + pub fn new_statement_from_params>( + enc_params: ElgamalEncryptionParams, + comm_key: Vec, + ) -> Statement { + Statement::VeTZ21(Self { + enc_params: Some(enc_params), + comm_key: Some(comm_key), + enc_params_ref: None, + comm_key_ref: None, + }) + } + + /// Get statement for Robust DKGitH protocol + pub fn new_statement_from_params_for_robust>( + enc_params: ElgamalEncryptionParams, + comm_key: Vec, + ) -> Statement { + Statement::VeTZ21Robust(Self { + enc_params: Some(enc_params), + comm_key: Some(comm_key), + enc_params_ref: None, + comm_key_ref: None, + }) + } + + /// Get statement for DKGitH protocol + pub fn new_statement_from_params_ref>( + enc_params: usize, + comm_key: usize, + ) -> Statement { + Statement::VeTZ21(Self { + enc_params: None, + comm_key: None, + enc_params_ref: Some(enc_params), + comm_key_ref: Some(comm_key), + }) + } + + /// Get statement for Robust DKGitH protocol + pub fn new_statement_from_params_ref_for_robust>( + enc_params: usize, + comm_key: usize, + ) -> Statement { + Statement::VeTZ21Robust(Self { + enc_params: None, + comm_key: None, + enc_params_ref: Some(enc_params), + comm_key_ref: Some(comm_key), + }) + } + + pub fn get_comm_key<'a, E: Pairing>( + &'a self, + setup_params: &'a [SetupParams], + st_idx: usize, + ) -> Result<&'a Vec, ProofSystemError> { + extract_param!( + setup_params, + &self.comm_key, + self.comm_key_ref, + PedersenCommitmentKey, + IncompatibleBoundCheckSetupParamAtIndex, + st_idx + ) + } + + pub fn get_enc_params<'a, E: Pairing>( + &'a self, + setup_params: &'a [SetupParams], + st_idx: usize, + ) -> Result<&'a ElgamalEncryptionParams, ProofSystemError> { + extract_param!( + setup_params, + &self.enc_params, + self.enc_params_ref, + ElgamalEncryption, + IncompatibleBoundCheckSetupParamAtIndex, + st_idx + ) + } +} diff --git a/proof_system/src/statement_proof.rs b/proof_system/src/statement_proof.rs index a7dfd6f7..17e34f82 100644 --- a/proof_system/src/statement_proof.rs +++ b/proof_system/src/statement_proof.rs @@ -1,4 +1,7 @@ -use crate::error::ProofSystemError; +use crate::{ + error::ProofSystemError, + sub_protocols::verifiable_encryption_tz_21::{dkgith_decls, rdkgith_decls}, +}; use ark_ec::{pairing::Pairing, AffineRepr}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError}; use ark_std::{ @@ -64,6 +67,8 @@ pub enum StatementProof { PoKBBSSignature23IETFG1(bbs_plus::proof_23_ietf::PoKOfSignature23G1Proof), PedersenCommitmentPartial(PedersenCommitmentPartialProof), PedersenCommitmentG2Partial(PedersenCommitmentPartialProof), + VeTZ21(VeTZ21Proof), + VeTZ21Robust(VeTZ21RobustProof), } macro_rules! delegate { @@ -103,7 +108,9 @@ macro_rules! delegate { KBUniversalAccumulatorNonMembershipKV, PoKBBSSignature23IETFG1, PedersenCommitmentPartial, - PedersenCommitmentG2Partial + PedersenCommitmentG2Partial, + VeTZ21, + VeTZ21Robust : $($tt)+ } }}; @@ -146,7 +153,9 @@ macro_rules! delegate_reverse { KBUniversalAccumulatorNonMembershipKV, PoKBBSSignature23IETFG1, PedersenCommitmentPartial, - PedersenCommitmentG2Partial + PedersenCommitmentG2Partial, + VeTZ21, + VeTZ21Robust : $($tt)+ } @@ -420,6 +429,36 @@ pub struct DetachedAccumulatorNonMembershipProof { pub encrypted: ecies::Encryption, } +/// Verifiable Encryption using DKGith protocol in the scheme TZ21 +#[serde_as] +#[derive( + Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize, +)] +#[serde(bound = "")] +pub struct VeTZ21Proof { + #[serde_as(as = "ArkObjectBytes")] + pub ve_proof: dkgith_decls::Proof, + /// The commitment to the encrypted messages + #[serde_as(as = "ArkObjectBytes")] + pub commitment: G, + pub sp: PedersenCommitmentPartialProof, +} + +/// Verifiable Encryption using Robust DKGith protocol in the scheme TZ21 +#[serde_as] +#[derive( + Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize, +)] +#[serde(bound = "")] +pub struct VeTZ21RobustProof { + #[serde_as(as = "ArkObjectBytes")] + pub ve_proof: rdkgith_decls::Proof, + /// The commitment to the encrypted messages + #[serde_as(as = "ArkObjectBytes")] + pub commitment: G, + pub sp: PedersenCommitmentPartialProof, +} + mod serialization { use super::{ CanonicalDeserialize, CanonicalSerialize, Pairing, Read, SerializationError, diff --git a/proof_system/src/sub_protocols/inequality.rs b/proof_system/src/sub_protocols/inequality.rs index 4ddd90d8..9044d8e7 100644 --- a/proof_system/src/sub_protocols/inequality.rs +++ b/proof_system/src/sub_protocols/inequality.rs @@ -130,7 +130,7 @@ impl<'a, G: AffineRepr> InequalityProtocol<'a, G> { .take() .unwrap() .gen_proof(challenge); - // Don't generated response for index 0 since its response will come from proofs of one of the signatures. + // Don't generate response for index 0 since its response will come from proofs of one of the signatures. let skip_for = BTreeSet::from([0]); Ok(StatementProof::Inequality(InequalityProof { proof, diff --git a/proof_system/src/sub_protocols/mod.rs b/proof_system/src/sub_protocols/mod.rs index e61e596e..1e5a8345 100644 --- a/proof_system/src/sub_protocols/mod.rs +++ b/proof_system/src/sub_protocols/mod.rs @@ -13,6 +13,7 @@ pub mod ps_signature; pub mod r1cs_legogorth16; pub mod saver; pub mod schnorr; +pub mod verifiable_encryption_tz_21; use core::borrow::Borrow; @@ -44,6 +45,7 @@ use crate::sub_protocols::{ bound_check_smc_with_kv::BoundCheckSmcWithKVProtocol, inequality::InequalityProtocol, r1cs_legogorth16::R1CSLegogroth16Protocol, + verifiable_encryption_tz_21::VeTZ21Protocol, }; use accumulator::{ detached::{ @@ -97,6 +99,7 @@ pub enum SubProtocol<'a, E: Pairing> { KBUniversalAccumulatorNonMembershipKV( KBUniversalAccumulatorNonMembershipKVSubProtocol, ), + VeTZ21(VeTZ21Protocol<'a, E::G1Affine>), } macro_rules! delegate { @@ -131,7 +134,8 @@ macro_rules! delegate { PoKDiscreteLogsG2, VBAccumulatorMembershipKV, KBUniversalAccumulatorMembershipKV, - KBUniversalAccumulatorNonMembershipKV + KBUniversalAccumulatorNonMembershipKV, + VeTZ21 : $($tt)+ } }}; diff --git a/proof_system/src/sub_protocols/schnorr.rs b/proof_system/src/sub_protocols/schnorr.rs index 47e8c04b..e4f82c3f 100644 --- a/proof_system/src/sub_protocols/schnorr.rs +++ b/proof_system/src/sub_protocols/schnorr.rs @@ -49,9 +49,6 @@ impl<'a, G: AffineRepr> SchnorrProtocol<'a, G> { mut blindings: BTreeMap, witnesses: Vec, ) -> Result<(), ProofSystemError> { - if self.commitment_to_randomness.is_some() { - return Err(ProofSystemError::SubProtocolAlreadyInitialized(self.id)); - } let blindings = (0..witnesses.len()) .map(|i| { blindings @@ -59,6 +56,17 @@ impl<'a, G: AffineRepr> SchnorrProtocol<'a, G> { .unwrap_or_else(|| G::ScalarField::rand(rng)) }) .collect::>(); + self.init_with_all_blindings_given(blindings, witnesses) + } + + pub fn init_with_all_blindings_given( + &mut self, + blindings: Vec, + witnesses: Vec, + ) -> Result<(), ProofSystemError> { + if self.commitment_to_randomness.is_some() { + return Err(ProofSystemError::SubProtocolAlreadyInitialized(self.id)); + } self.commitment_to_randomness = Some(SchnorrCommitment::new(self.commitment_key, blindings)); self.witnesses = Some(witnesses); diff --git a/proof_system/src/sub_protocols/verifiable_encryption_tz_21.rs b/proof_system/src/sub_protocols/verifiable_encryption_tz_21.rs new file mode 100644 index 00000000..0960a0be --- /dev/null +++ b/proof_system/src/sub_protocols/verifiable_encryption_tz_21.rs @@ -0,0 +1,261 @@ +use crate::{ + error::ProofSystemError, + prelude::{ElgamalEncryptionParams, StatementProof}, + statement_proof::{VeTZ21Proof, VeTZ21RobustProof}, + sub_protocols::schnorr::SchnorrProtocol, +}; +use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup, VariableBaseMSM}; +use ark_serialize::CanonicalSerialize; +use ark_std::{ + collections::{BTreeMap, BTreeSet}, + io::Write, + rand::RngCore, + vec::Vec, + UniformRand, +}; +use digest::Digest; +use dock_crypto_utils::{aliases::FullDigest, elgamal::BatchedHashedElgamalCiphertext}; +use sha3::Shake256; +use zeroize::{Zeroize, ZeroizeOnDrop}; + +// TODO: The parameters used for both protocols are hardcoded here but they should be generic as +// different curves or different applications might need different values than these. + +// NOTE: Some of the parameters used can cause a stackoverflow due to large number of arrays being +// allocated on stack. An ideal solution would be to find a library that can grow the stack as needed. +// Without that, using a bigger stack of 8MB with `RUST_MIN_STACK` flag like `RUST_MIN_STACK=8388608 cargo test` +// successfully runs the test on MacOS. However, such a large stack might not be possible on other platforms + +pub mod dkgith_decls { + use super::BatchedHashedElgamalCiphertext; + use ark_ec::AffineRepr; + use verifiable_encryption::tz_21::dkgith::{CompressedCiphertext, DkgithProof}; + + // Very large values for repetitions cause stack overflow + // pub const NUM_PARTIES: usize = 4; + // pub const NUM_REPS: usize = 64; + // pub const SUBSET_SIZE: usize = 48; + // pub const DEPTH: usize = 2; + // pub const NUM_NODES: usize = 7; + + pub const NUM_PARTIES: usize = 16; + pub const NUM_REPS: usize = 32; + pub const SUBSET_SIZE: usize = 30; + pub const DEPTH: usize = 4; + pub const NUM_NODES: usize = 31; + + pub const SEED_SIZE: usize = 16; + pub const SALT_SIZE: usize = 32; + + pub type Proof = DkgithProof< + G, + BatchedHashedElgamalCiphertext, + NUM_PARTIES, + DEPTH, + NUM_NODES, + NUM_REPS, + SEED_SIZE, + SALT_SIZE, + >; + pub type Ciphertext = + CompressedCiphertext, SUBSET_SIZE>; +} + +pub mod rdkgith_decls { + use ark_ec::AffineRepr; + use dock_crypto_utils::elgamal::BatchedHashedElgamalCiphertext; + use verifiable_encryption::tz_21::rdkgith::{CompressedCiphertext, RdkgithProof}; + + // Very large values cause stack overflow + // pub const NUM_PARTIES: usize = 192; + // pub const THRESHOLD: usize = 36; + // pub const NUM_PARTIES_MINUS_THRESHOLD: usize = 156; + // pub const SUBSET_SIZE: usize = 145; + + pub const NUM_PARTIES: usize = 50; + pub const THRESHOLD: usize = 35; + pub const NUM_PARTIES_MINUS_THRESHOLD: usize = 15; + pub const SUBSET_SIZE: usize = 10; + + pub type Proof = RdkgithProof< + G, + BatchedHashedElgamalCiphertext, + NUM_PARTIES, + THRESHOLD, + NUM_PARTIES_MINUS_THRESHOLD, + >; + pub type Ciphertext = + CompressedCiphertext, SUBSET_SIZE>; +} + +#[derive(Clone, Debug, PartialEq, Zeroize, ZeroizeOnDrop)] +pub struct VeTZ21Protocol<'a, G: AffineRepr> { + #[zeroize(skip)] + pub id: usize, + #[zeroize(skip)] + pub comm_key: &'a [G], + #[zeroize(skip)] + pub enc_params: &'a ElgamalEncryptionParams, + #[zeroize(skip)] + pub ve_proof: Option>, + #[zeroize(skip)] + pub ve_robust_proof: Option>, + pub sp: Option>, +} + +macro_rules! impl_common_funcs { + ($group: ident, $proof_gen_func: path, $proof_ver_func: path, $proof_field_name: ident, $proof_struct_name: ident, $sp_variant: ident, $init_fn_name: ident, $chal_fn_name: ident, $proof_gen_fn_name: ident, $proof_ver_fn_name: ident) => { + pub fn $init_fn_name( + &mut self, + rng: &mut R, + mut witnesses: Vec<$group::ScalarField>, + mut blindings: Vec<$group::ScalarField>, + ) -> Result<(), ProofSystemError> { + if self.sp.is_some() { + return Err(ProofSystemError::SubProtocolAlreadyInitialized(self.id)); + } + // witnesses will be the messages from signature(s) that need to be encrypted. Since the VE + // protocol requires a commitment to them, add randomness to the commitment to make it perfectly + // hiding. + witnesses.push($group::ScalarField::rand(rng)); + blindings.push($group::ScalarField::rand(rng)); + // Commit to the witneses + let comm_key = &self.comm_key[..witnesses.len()]; + let commitment = $group::Group::msm_unchecked(comm_key, &witnesses).into_affine(); + // Generate the VE proof + let ve_proof = $proof_gen_func( + rng, + witnesses.clone(), + &commitment, + &comm_key, + &self.enc_params.public_key, + &self.enc_params.gen, + ); + self.$proof_field_name = Some(ve_proof); + self.init_schnorr_protocol(witnesses, blindings, commitment, comm_key) + } + + pub fn $chal_fn_name( + comm_key: &[G], + proof: &$proof_struct_name<$group>, + mut writer: W, + ) -> Result<(), ProofSystemError> { + let ck = comm_key[0..proof.ve_proof.witness_count()].as_ref(); + ck.serialize_compressed(&mut writer)?; + proof.commitment.serialize_compressed(&mut writer)?; + proof.sp.t.serialize_compressed(&mut writer)?; + Ok(()) + } + + pub fn $proof_gen_fn_name>( + &mut self, + challenge: &$group::ScalarField, + ) -> Result, ProofSystemError> { + if self.sp.is_none() { + return Err(ProofSystemError::SubProtocolNotReadyToGenerateProof( + self.id, + )); + } + // Don't generate response for all indices except for the last one since their response will come from proofs of one of the signatures. + let witness_count = self.sp.as_ref().unwrap().commitment_key.len(); + let skip_for = BTreeSet::from_iter(0..(witness_count - 1)); + Ok(StatementProof::$sp_variant($proof_struct_name { + ve_proof: self.$proof_field_name.take().unwrap(), + commitment: self.sp.as_ref().unwrap().commitment.clone(), + sp: self + .sp + .take() + .unwrap() + .gen_partial_proof_contribution_as_struct(challenge, &skip_for)?, + })) + } + + pub fn $proof_ver_fn_name( + &self, + challenge: &$group::ScalarField, + proof: &$proof_struct_name<$group>, + missing_resps: BTreeMap, + ) -> Result<(), ProofSystemError> { + let witness_count = proof.ve_proof.witness_count(); + let comm_key = &self.comm_key[..witness_count]; + $proof_ver_func( + &proof.ve_proof, + &proof.commitment, + comm_key, + &self.enc_params.public_key, + &self.enc_params.gen, + ) + .map_err(|e| ProofSystemError::VerifiableEncryption(self.id as u32, e))?; + // NOTE: value of id is dummy + let sp = SchnorrProtocol::new(10000, comm_key, proof.commitment); + sp.verify_partial_proof_contribution(challenge, &proof.sp, missing_resps) + .map_err(|e| ProofSystemError::SchnorrProofContributionFailed(self.id as u32, e)) + } + }; +} + +impl<'a, G: AffineRepr> VeTZ21Protocol<'a, G> { + pub fn new(id: usize, comm_key: &'a [G], enc_params: &'a ElgamalEncryptionParams) -> Self { + Self { + id, + comm_key, + enc_params, + sp: None, + ve_proof: None, + ve_robust_proof: None, + } + } + + // TODO: Make XOF generic by making `Proof::new` and `Proof::verify` accept it + impl_common_funcs!( + G, + dkgith_decls::Proof::new::, + dkgith_decls::Proof::verify::, + ve_proof, + VeTZ21Proof, + VeTZ21, + init, + compute_challenge_contribution, + gen_proof_contribution, + verify_proof_contribution + ); + + impl_common_funcs!( + G, + rdkgith_decls::Proof::new::, + rdkgith_decls::Proof::verify::, + ve_robust_proof, + VeTZ21RobustProof, + VeTZ21Robust, + init_robust, + compute_challenge_contribution_robust, + gen_proof_contribution_robust, + verify_proof_contribution_robust + ); + + fn init_schnorr_protocol( + &mut self, + witnesses: Vec, + blindings: Vec, + commitment: G, + comm_key: &'a [G], + ) -> Result<(), ProofSystemError> { + let mut sp = SchnorrProtocol::new(10000, &comm_key, commitment); + sp.init_with_all_blindings_given(blindings, witnesses)?; + self.sp = Some(sp); + Ok(()) + } + + pub fn challenge_contribution(&self, mut writer: W) -> Result<(), ProofSystemError> { + if self.sp.is_none() { + return Err(ProofSystemError::SubProtocolNotReadyToGenerateChallenge( + self.id, + )); + } + self.sp + .as_ref() + .unwrap() + .challenge_contribution(&mut writer)?; + Ok(()) + } +} diff --git a/proof_system/src/verifier.rs b/proof_system/src/verifier.rs index e8000481..1191158e 100644 --- a/proof_system/src/verifier.rs +++ b/proof_system/src/verifier.rs @@ -4,7 +4,8 @@ use crate::{ COMPOSITE_PROOF_LABEL, CONTEXT_LABEL, KB_POS_ACCUM_CDH_MEM_LABEL, KB_POS_ACCUM_MEM_LABEL, KB_UNI_ACCUM_CDH_MEM_LABEL, KB_UNI_ACCUM_CDH_NON_MEM_LABEL, KB_UNI_ACCUM_MEM_LABEL, KB_UNI_ACCUM_NON_MEM_LABEL, NONCE_LABEL, PS_LABEL, VB_ACCUM_CDH_MEM_LABEL, - VB_ACCUM_CDH_NON_MEM_LABEL, VB_ACCUM_MEM_LABEL, VB_ACCUM_NON_MEM_LABEL, + VB_ACCUM_CDH_NON_MEM_LABEL, VB_ACCUM_MEM_LABEL, VB_ACCUM_NON_MEM_LABEL, VE_TZ_21_LABEL, + VE_TZ_21_ROBUST_LABEL, }, error::ProofSystemError, prelude::EqualWitnesses, @@ -43,6 +44,7 @@ use crate::{ r1cs_legogorth16::R1CSLegogroth16Protocol, saver::SaverProtocol, schnorr::SchnorrProtocol, + verifiable_encryption_tz_21::{dkgith_decls, rdkgith_decls, VeTZ21Protocol}, }, }; use ark_ec::pairing::Pairing; @@ -56,12 +58,14 @@ use ark_std::{ }; use digest::Digest; use dock_crypto_utils::{ + aliases::FullDigest, expect_equality, randomized_pairing_check::RandomizedPairingChecker, signature::MultiMessageSignatureParams, transcript::{MerlinTranscript, Transcript}, }; use saver::encryption::Ciphertext; +use sha3::Shake256; /// Passed to the verifier during proof verification #[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize, Default)] @@ -121,7 +125,7 @@ macro_rules! check_resp_for_equalities_with_err { impl Proof { /// Verify the `Proof` given the `ProofSpec`, `nonce` and `config` - pub fn verify( + pub fn verify( self, rng: &mut R, proof_spec: ProofSpec, @@ -137,7 +141,7 @@ impl Proof { } } - fn _verify( + fn _verify( self, rng: &mut R, proof_spec: ProofSpec, @@ -659,6 +663,30 @@ impl Proof { } _ => err_incompat_proof!(s_idx, s, proof), }, + Statement::VeTZ21(s) => match proof { + StatementProof::VeTZ21(p) => { + let comm_key = s.get_comm_key(&proof_spec.setup_params, s_idx)?.as_slice(); + transcript.set_label(VE_TZ_21_LABEL); + VeTZ21Protocol::compute_challenge_contribution( + comm_key, + p, + &mut transcript, + )? + } + _ => err_incompat_proof!(s_idx, s, proof), + }, + Statement::VeTZ21Robust(s) => match proof { + StatementProof::VeTZ21Robust(p) => { + let comm_key = s.get_comm_key(&proof_spec.setup_params, s_idx)?.as_slice(); + transcript.set_label(VE_TZ_21_ROBUST_LABEL); + VeTZ21Protocol::compute_challenge_contribution_robust( + comm_key, + p, + &mut transcript, + )? + } + _ => err_incompat_proof!(s_idx, s, proof), + }, _ => return Err(ProofSystemError::InvalidStatement), } } @@ -766,6 +794,29 @@ impl Proof { }}; } + macro_rules! tz_21_verify { + ($s: ident, $s_idx: ident, $p: ident, $func_name: ident) => { + let comm_key = $s.get_comm_key(&proof_spec.setup_params, $s_idx)?; + let enc_params = $s.get_enc_params(&proof_spec.setup_params, $s_idx)?; + let sp = VeTZ21Protocol::new($s_idx, comm_key.as_slice(), enc_params); + // Won't have response for all indices except for last one since their responses will come from proofs of the signatures. + let mut missing_resps = BTreeMap::new(); + // The last witness is the randomness of the commitment so skip that + for i in 0..$p.ve_proof.witness_count() - 1 { + missing_resps.insert( + i, + Self::get_resp_for_message( + $s_idx, + i, + &disjoint_equalities, + &resp_for_equalities, + )?, + ); + } + sp.$func_name::(&challenge, $p, missing_resps)? + } + } + // Verify the proof for each statement for (s_idx, (statement, proof)) in proof_spec .statements @@ -840,6 +891,7 @@ impl Proof { &mut pairing_checker, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -867,6 +919,7 @@ impl Proof { &mut pairing_checker, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -894,6 +947,7 @@ impl Proof { &mut pairing_checker, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -921,6 +975,7 @@ impl Proof { &mut pairing_checker, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -946,6 +1001,7 @@ impl Proof { &mut pairing_checker, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -972,6 +1028,7 @@ impl Proof { &mut pairing_checker, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -997,6 +1054,7 @@ impl Proof { &mut pairing_checker, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1023,6 +1081,7 @@ impl Proof { &mut pairing_checker, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1050,6 +1109,7 @@ impl Proof { &mut pairing_checker, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1077,6 +1137,7 @@ impl Proof { &mut pairing_checker, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1181,6 +1242,7 @@ impl Proof { &mut pairing_checker, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1203,6 +1265,7 @@ impl Proof { &cc_keys.1, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1236,6 +1299,7 @@ impl Proof { &mut pairing_checker, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1254,6 +1318,7 @@ impl Proof { comm_key, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1400,6 +1465,7 @@ impl Proof { &mut transcript, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1421,6 +1487,7 @@ impl Proof { &mut pairing_checker, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1445,6 +1512,7 @@ impl Proof { comm_key_slice.as_slice(), Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1463,6 +1531,7 @@ impl Proof { comm_key.as_slice(), Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1541,6 +1610,7 @@ impl Proof { p, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1558,6 +1628,7 @@ impl Proof { &s.secret_key, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1576,6 +1647,7 @@ impl Proof { p, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1595,6 +1667,7 @@ impl Proof { &s.secret_key, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1613,6 +1686,7 @@ impl Proof { p, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1632,6 +1706,7 @@ impl Proof { &s.secret_key, Self::get_resp_for_message( s_idx, + 0, &disjoint_equalities, &resp_for_equalities, )?, @@ -1639,6 +1714,18 @@ impl Proof { } _ => err_incompat_proof!(s_idx, s, proof), }, + Statement::VeTZ21(s) => match proof { + StatementProof::VeTZ21(ref p) => { + tz_21_verify!(s, s_idx, p, verify_proof_contribution); + } + _ => err_incompat_proof!(s_idx, s, proof), + }, + Statement::VeTZ21Robust(s) => match proof { + StatementProof::VeTZ21Robust(ref p) => { + tz_21_verify!(s, s_idx, p, verify_proof_contribution_robust); + } + _ => err_incompat_proof!(s_idx, s, proof), + }, _ => return Err(ProofSystemError::InvalidStatement), } } @@ -1744,6 +1831,61 @@ impl Proof { Ok(()) } + pub fn get_saver_ciphertext_and_proof( + &self, + index: usize, + ) -> Result<(&Ciphertext, &ark_groth16::Proof), ProofSystemError> { + let st = self.statement_proof(index)?; + if let StatementProof::Saver(s) = st { + Ok((&s.ciphertext, &s.snark_proof)) + } else { + Err(ProofSystemError::NotASaverStatementProof) + } + } + + pub fn get_legogroth16_proof( + &self, + index: usize, + ) -> Result<&legogroth16::Proof, ProofSystemError> { + let st = self.statement_proof(index)?; + match st { + StatementProof::BoundCheckLegoGroth16(s) => Ok(&s.snark_proof), + StatementProof::R1CSLegoGroth16(s) => Ok(&s.snark_proof), + _ => Err(ProofSystemError::NotALegoGroth16StatementProof), + } + } + + /// Get the compressed ciphertext and commitment to needed to decrypt message encrypted using DKGitH protocol + pub fn get_tz21_ciphertext_and_commitment( + &self, + index: usize, + ) -> Result<(dkgith_decls::Ciphertext, E::G1Affine), ProofSystemError> { + let st = self.statement_proof(index)?; + if let StatementProof::VeTZ21(s) = st { + let ve_proof = &s.ve_proof; + // TODO: Make Shake256 a generic and ensure it matches the one used on proof generation + let ct = ve_proof.compress::<{ dkgith_decls::SUBSET_SIZE }, D, Shake256>(); + Ok((ct, s.commitment)) + } else { + Err(ProofSystemError::NotAVeTZ21StatementProof) + } + } + + /// Get the compressed ciphertext and commitment to needed to decrypt message encrypted using Robust DKGitH protocol + pub fn get_tz21_robust_ciphertext_and_commitment( + &self, + index: usize, + ) -> Result<(rdkgith_decls::Ciphertext, E::G1Affine), ProofSystemError> { + let st = self.statement_proof(index)?; + if let StatementProof::VeTZ21Robust(s) = st { + let ve_proof = &s.ve_proof; + let ct = ve_proof.compress::<{ rdkgith_decls::SUBSET_SIZE }, D>(); + Ok((ct, s.commitment)) + } else { + Err(ProofSystemError::NotAVeTZ21StatementProof) + } + } + /// Used to check if response (from Schnorr protocol) for a witness is equal to other witnesses that /// it must be equal to. This is required when the `ProofSpec` demands certain witnesses to be equal. fn check_response_for_equality<'a>( @@ -1762,27 +1904,33 @@ impl Proof { Ok(()) } - /// Get the response for a witness from the tracked responses of witness equalities. Expects the response - /// to exists else throws error. This is not to be called for signature proof protocols but others whose - /// responses are expected to come from them or pedersen commitment protocols. + /// Get the response for a witness from the tracked responses of witness equalities. + /// Expects the response to exist else throws error. This is not to be called for signature proof protocols + /// but others whose responses are expected to come from them or pedersen commitment protocols. fn get_resp_for_message( - s_idx: usize, + statement_idx: usize, + witness_idx: usize, disjoint_equalities: &[EqualWitnesses], resp_for_equalities: &BTreeMap, ) -> Result { - let wit_ref = (s_idx, 0); + let wit_ref = (statement_idx, witness_idx); let mut resp = None; for (i, eq) in disjoint_equalities.iter().enumerate() { if eq.has_wit_ref(&wit_ref) { if let Some(r) = resp_for_equalities.get(&i) { resp = Some(*r); } else { - return Err(ProofSystemError::NoResponseFoundForWitnessRef(s_idx, 0)); + return Err(ProofSystemError::NoResponseFoundForWitnessRef( + statement_idx, + witness_idx, + )); } // Exit loop because equalities are disjoint break; } } - resp.ok_or_else(|| ProofSystemError::NoResponseFoundForWitnessRef(s_idx, 0)) + resp.ok_or_else(|| { + ProofSystemError::NoResponseFoundForWitnessRef(statement_idx, witness_idx) + }) } } diff --git a/proof_system/src/witness.rs b/proof_system/src/witness.rs index 3155bfb4..51f9df73 100644 --- a/proof_system/src/witness.rs +++ b/proof_system/src/witness.rs @@ -39,6 +39,8 @@ pub enum Witness { KBUniAccumulatorNonMembership(KBUniNonMembership), KBPosAccumulatorMembership(KBPosMembership), PoKOfBBDT16MAC(PoKOfBBDT16MAC), + VeTZ21(#[serde_as(as = "Vec")] Vec), + VeTZ21Robust(#[serde_as(as = "Vec")] Vec), } macro_rules! delegate { @@ -61,7 +63,9 @@ macro_rules! delegate { KBUniAccumulatorMembership, KBUniAccumulatorNonMembership, KBPosAccumulatorMembership, - PoKOfBBDT16MAC + PoKOfBBDT16MAC, + VeTZ21, + VeTZ21Robust : $($tt)+ } }} @@ -87,7 +91,9 @@ macro_rules! delegate_reverse { KBUniAccumulatorMembership, KBUniAccumulatorNonMembership, KBPosAccumulatorMembership, - PoKOfBBDT16MAC + PoKOfBBDT16MAC, + VeTZ21, + VeTZ21Robust : $($tt)+ } diff --git a/proof_system/tests/saver.rs b/proof_system/tests/saver.rs index 8155cd7d..3a468338 100644 --- a/proof_system/tests/saver.rs +++ b/proof_system/tests/saver.rs @@ -676,16 +676,16 @@ macro_rules! gen_tests { } gen_tests!( - pok_of_bbs_plus_sig_and_verifiable_encryption, - pok_of_bbs_plus_sig_and_verifiable_encryption_of_many_messages, + pok_of_bbs_plus_sig_and_verifiable_encryption_using_saver, + pok_of_bbs_plus_sig_and_verifiable_encryption_of_many_messages_using_saver, bbs_plus_sig_setup, PoKSignatureBBSG1ProverStmt, PoKSignatureBBSG1VerifierStmt, PoKSignatureBBSG1Wit ); gen_tests!( - pok_of_bbs_sig_and_verifiable_encryption, - pok_of_bbs_sig_and_verifiable_encryption_of_many_messages, + pok_of_bbs_sig_and_verifiable_encryption_using_saver, + pok_of_bbs_sig_and_verifiable_encryption_of_many_messages_using_saver, bbs_sig_setup, PoKSignatureBBS23G1ProverStmt, PoKSignatureBBS23G1VerifierStmt, diff --git a/proof_system/tests/verifiable_encrytion_tz21.rs b/proof_system/tests/verifiable_encrytion_tz21.rs new file mode 100644 index 00000000..9c1297f2 --- /dev/null +++ b/proof_system/tests/verifiable_encrytion_tz21.rs @@ -0,0 +1,323 @@ +use ark_bls12_381::{Bls12_381, G1Affine}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::{ + rand::{prelude::StdRng, SeedableRng}, + UniformRand, +}; +use blake2::Blake2b512; +use dock_crypto_utils::elgamal::keygen; +use proof_system::{ + prelude::{EqualWitnesses, MetaStatements, ProofSpec, Witness, WitnessRef, Witnesses}, + proof::Proof, + setup_params::ElgamalEncryptionParams, + statement::{ + bbs_plus::{ + PoKBBSSignatureG1Prover as PoKSignatureBBSG1ProverStmt, + PoKBBSSignatureG1Verifier as PoKSignatureBBSG1VerifierStmt, + }, + verifiable_encryption_tz_21::VerifiableEncryptionTZ21, + Statements, + }, + witness::PoKBBSSignatureG1 as PoKSignatureBBSG1Wit, +}; +use std::{ + collections::{BTreeMap, BTreeSet}, + time::Instant, +}; +use test_utils::{bbs::*, test_serialization}; + +macro_rules! gen_tests { + ($test1_name: ident, $test2_name: ident, $stmt_func_name: ident, $wit_variant: ident, $cptxt_getter: ident) => { + #[test] + fn $test1_name() { + let mut rng = StdRng::seed_from_u64(0u64); + let enc_gen = G1Affine::rand(&mut rng); + let (dec_key, enc_key) = keygen::<_, G1Affine>(&mut rng, &enc_gen); + + let msg_count = 5; + let (msgs, sig_params, sig_keypair, sig) = bbs_plus_sig_setup(&mut rng, msg_count); + + // Message with index `enc_msg_idx` is verifiably encrypted + let enc_msg_idx = 1; + let enc_msg = msgs[enc_msg_idx]; + + // +1 as the commitment to the encrypted message will have the randomness as well which is encrypted as well. + let comm_key_for_ve = (0..1 + 1) + .map(|_| G1Affine::rand(&mut rng)) + .collect::>(); + + let mut prover_statements = Statements::new(); + prover_statements.add(PoKSignatureBBSG1ProverStmt::new_statement_from_params( + sig_params.clone(), + BTreeMap::new(), + )); + prover_statements.add(VerifiableEncryptionTZ21::$stmt_func_name( + ElgamalEncryptionParams { + gen: enc_gen, + public_key: enc_key.0, + }, + comm_key_for_ve.clone(), + )); + + let mut meta_statements = MetaStatements::new(); + meta_statements.add_witness_equality(EqualWitnesses( + vec![(0, enc_msg_idx), (1, 0)] + .into_iter() + .collect::>(), + )); + + test_serialization!(Statements, prover_statements); + test_serialization!(MetaStatements, meta_statements); + + let prover_proof_spec = ProofSpec::new( + prover_statements.clone(), + meta_statements.clone(), + vec![], + None, + ); + prover_proof_spec.validate().unwrap(); + + let mut witnesses = Witnesses::new(); + witnesses.add(PoKSignatureBBSG1Wit::new_as_witness( + sig.clone(), + msgs.clone().into_iter().enumerate().collect(), + )); + witnesses.add(Witness::$wit_variant(vec![enc_msg])); + + test_serialization!(Witnesses, witnesses); + + let start = Instant::now(); + let (proof, _) = Proof::new::( + &mut rng, + prover_proof_spec.clone(), + witnesses.clone(), + None, + Default::default(), + ) + .unwrap(); + + println!( + "Time taken to create proof of 1 encrypted message in signature over {} messages {:?}", + msg_count, + start.elapsed() + ); + + test_serialization!(Proof, proof); + + let mut verifier_statements = Statements::new(); + verifier_statements.add(PoKSignatureBBSG1VerifierStmt::new_statement_from_params( + sig_params, + sig_keypair.public_key.clone(), + BTreeMap::new(), + )); + verifier_statements.add(VerifiableEncryptionTZ21::$stmt_func_name( + ElgamalEncryptionParams { + gen: enc_gen, + public_key: enc_key.0, + }, + comm_key_for_ve.clone(), + )); + + let verifier_proof_spec = ProofSpec::new( + verifier_statements.clone(), + meta_statements.clone(), + vec![], + None, + ); + verifier_proof_spec.validate().unwrap(); + + let start = Instant::now(); + proof + .clone() + .verify::( + &mut rng, + verifier_proof_spec.clone(), + None, + Default::default(), + ) + .unwrap(); + println!( + "Time taken to verify proof of 1 encrypted message in signature over {} messages {:?}", + msg_count, + start.elapsed() + ); + + let start = Instant::now(); + let (ct, comm) = proof + .$cptxt_getter::(1) + .unwrap(); + println!( + "Time taken to get (compressed) ciphertext of 1 encrypted message in signature over {} messages {:?}", + msg_count, + start.elapsed() + ); + + let start = Instant::now(); + assert_eq!( + ct.decrypt::(&dec_key.0, &comm, &comm_key_for_ve) + .unwrap()[..1], + [enc_msg] + ); + println!( + "Time taken to decrypt ciphertext of 1 encrypted message in signature over {} messages {:?}", + msg_count, + start.elapsed() + ); + } + + #[test] + fn $test2_name() { + let mut rng = StdRng::seed_from_u64(0u64); + let enc_gen = G1Affine::rand(&mut rng); + let (dec_key, enc_key) = keygen::<_, G1Affine>(&mut rng, &enc_gen); + + let msg_count = 5; + let (msgs, sig_params, sig_keypair, sig) = bbs_plus_sig_setup(&mut rng, msg_count); + + // Message with following indices are verifiably encrypted + let enc_msg_indices = vec![0, 2, 3]; + let enc_msgs = enc_msg_indices.iter().map(|i| msgs[*i]).collect::>(); + + // +1 as the commitment to the encrypted messages will have the randomness as well which is encrypted as well. + let comm_key_for_ve = (0..enc_msgs.len() + 1) + .map(|_| G1Affine::rand(&mut rng)) + .collect::>(); + + let mut prover_statements = Statements::new(); + prover_statements.add(PoKSignatureBBSG1ProverStmt::new_statement_from_params( + sig_params.clone(), + BTreeMap::new(), + )); + prover_statements.add(VerifiableEncryptionTZ21::$stmt_func_name( + ElgamalEncryptionParams { + gen: enc_gen, + public_key: enc_key.0, + }, + comm_key_for_ve.clone(), + )); + + let mut meta_statements = MetaStatements::new(); + for (i, j) in enc_msg_indices.iter().enumerate() { + meta_statements.add_witness_equality(EqualWitnesses( + vec![(0, *j), (1, i)] + .into_iter() + .collect::>(), + )); + } + + let prover_proof_spec = ProofSpec::new( + prover_statements.clone(), + meta_statements.clone(), + vec![], + None, + ); + prover_proof_spec.validate().unwrap(); + + let mut witnesses = Witnesses::new(); + witnesses.add(PoKSignatureBBSG1Wit::new_as_witness( + sig.clone(), + msgs.clone().into_iter().enumerate().collect(), + )); + witnesses.add(Witness::$wit_variant(enc_msgs.clone())); + + let start = Instant::now(); + let (proof, _) = Proof::new::( + &mut rng, + prover_proof_spec.clone(), + witnesses.clone(), + None, + Default::default(), + ) + .unwrap(); + + println!( + "Time taken to create proof of {} encrypted message in signature over {} messages {:?}", + enc_msg_indices.len(), + msg_count, + start.elapsed() + ); + + test_serialization!(Proof, proof); + + let mut verifier_statements = Statements::new(); + verifier_statements.add(PoKSignatureBBSG1VerifierStmt::new_statement_from_params( + sig_params, + sig_keypair.public_key.clone(), + BTreeMap::new(), + )); + verifier_statements.add(VerifiableEncryptionTZ21::$stmt_func_name( + ElgamalEncryptionParams { + gen: enc_gen, + public_key: enc_key.0, + }, + comm_key_for_ve.clone(), + )); + + let verifier_proof_spec = ProofSpec::new( + verifier_statements.clone(), + meta_statements.clone(), + vec![], + None, + ); + verifier_proof_spec.validate().unwrap(); + + let start = Instant::now(); + proof + .clone() + .verify::( + &mut rng, + verifier_proof_spec.clone(), + None, + Default::default(), + ) + .unwrap(); + println!( + "Time taken to verify proof of {} encrypted message in signature over {} messages {:?}", + enc_msg_indices.len(), + msg_count, + start.elapsed() + ); + + let start = Instant::now(); + let (ct, comm) = proof + .$cptxt_getter::(1) + .unwrap(); + println!( + "Time taken to get (compressed) ciphertext of {} encrypted message in signature over {} messages {:?}", + enc_msg_indices.len(), + msg_count, + start.elapsed() + ); + + let start = Instant::now(); + assert_eq!( + ct.decrypt::(&dec_key.0, &comm, &comm_key_for_ve) + .unwrap()[..enc_msg_indices.len()] + .to_vec(), + enc_msgs + ); + println!( + "Time taken to decrypt ciphertext of {} encrypted message in signature over {} messages {:?}", + enc_msg_indices.len(), + msg_count, + start.elapsed() + ); + } + } +} + +gen_tests!( + pok_of_bbs_plus_sig_and_verifiable_encryption_using_tz21, + pok_of_bbs_plus_sig_and_verifiable_encryption_of_many_messages_using_tz21, + new_statement_from_params, + VeTZ21, + get_tz21_ciphertext_and_commitment +); + +gen_tests!( + pok_of_bbs_plus_sig_and_verifiable_encryption_using_tz21_robust, + pok_of_bbs_plus_sig_and_verifiable_encryption_of_many_messages_using_tz21_robust, + new_statement_from_params_for_robust, + VeTZ21Robust, + get_tz21_robust_ciphertext_and_commitment +); diff --git a/schnorr_pok/src/partial.rs b/schnorr_pok/src/partial.rs index 0d8592c8..be30b290 100644 --- a/schnorr_pok/src/partial.rs +++ b/schnorr_pok/src/partial.rs @@ -170,8 +170,8 @@ impl PokTwoDiscreteLogsProtocol { } impl PartialSchnorrResponse { - /// Keys of `missing_responses` are the witness indices whose response was generated while creating this. Instead - /// these comes from some other Schnorr protocol. + /// Keys of `missing_responses` are the witness indices whose response was generated while creating this. Instead, + /// these come from some other Schnorr protocol. pub fn is_valid( &self, bases: &[G], diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index a8dd8c84..5ffae8df 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -19,5 +19,5 @@ oblivious_transfer_protocols = { default-features = false, path = "../oblivious_ [features] default = ["parallel"] -std = ["ark-ff/std", "ark-ec/std", "ark-std/std", "ark-serialize/std", "bbs_plus/std", "bbs_plus/std", "vb_accumulator/std", "kvac/std", "oblivious_transfer_protocols/std"] -parallel = ["bbs_plus/parallel", "vb_accumulator/parallel", "kvac/parallel", "oblivious_transfer_protocols/parallel"] +std = ["ark-ff/std", "ark-ec/std", "ark-std/std", "ark-serialize/std", "bbs_plus/std", "vb_accumulator/std", "kvac/std", "oblivious_transfer_protocols/std"] +parallel = ["std", "ark-ff/parallel", "ark-ec/parallel", "ark-std/parallel", "bbs_plus/parallel", "vb_accumulator/parallel", "kvac/parallel", "oblivious_transfer_protocols/parallel"] diff --git a/utils/src/elgamal.rs b/utils/src/elgamal.rs index 4209b930..6a6e65d6 100644 --- a/utils/src/elgamal.rs +++ b/utils/src/elgamal.rs @@ -39,6 +39,7 @@ impl PublicKey { } } +/// `gen` is the generator used in the scheme to generate public key and ephemeral public key by sender/encryptor pub fn keygen( rng: &mut R, gen: &G, @@ -72,6 +73,7 @@ pub struct Ciphertext { impl Ciphertext { /// Returns the ciphertext and randomness created for encryption + /// `gen` is the generator used in the scheme to generate public key and ephemeral public key by sender/encryptor pub fn new( rng: &mut R, msg: &G, @@ -86,6 +88,7 @@ impl Ciphertext { } /// Returns the ciphertext + /// `gen` is the generator used in the scheme to generate public key and ephemeral public key by sender/encryptor pub fn new_given_randomness( msg: &G, randomness: &G::ScalarField, @@ -102,6 +105,7 @@ impl Ciphertext { /// Returns the ciphertext but takes the window tables for the public key and generator. Useful when a lot /// of encryptions have to be done using the same public key + /// `gen` is the generator used in the scheme to generate public key and ephemeral public key by sender/encryptor pub fn new_given_randomness_and_window_tables( msg: &G, randomness: &G::ScalarField, @@ -146,6 +150,7 @@ pub struct HashedElgamalCiphertext { impl HashedElgamalCiphertext { /// Returns the ciphertext and randomness created for encryption + /// `gen` is the generator used in the scheme to generate public key and ephemeral public key by sender/encryptor pub fn new( rng: &mut R, msg: &G::ScalarField, @@ -160,6 +165,7 @@ impl HashedElgamalCiphertext { } /// Returns the ciphertext + /// `gen` is the generator used in the scheme to generate public key and ephemeral public key by sender/encryptor pub fn new_given_randomness( msg: &G::ScalarField, randomness: &G::ScalarField, @@ -176,6 +182,7 @@ impl HashedElgamalCiphertext { /// Returns the ciphertext but takes the window tables for the public key and generator. Useful when a lot /// of encryptions have to be done using the same public key + /// `gen` is the generator used in the scheme to generate public key and ephemeral public key by sender/encryptor pub fn new_given_randomness_and_window_tables( msg: &G::ScalarField, randomness: &G::ScalarField, @@ -231,6 +238,7 @@ pub struct BatchedHashedElgamalCiphertext { impl BatchedHashedElgamalCiphertext { /// Returns the ciphertext and randomness created for encryption + /// `gen` is the generator used in the scheme to generate public key and ephemeral public key by sender/encryptor pub fn new( rng: &mut R, msgs: &[G::ScalarField], @@ -245,6 +253,7 @@ impl BatchedHashedElgamalCiphertext { } /// Returns the ciphertext + /// `gen` is the generator used in the scheme to generate public key and ephemeral public key by sender/encryptor pub fn new_given_randomness( msgs: &[G::ScalarField], randomness: &G::ScalarField, @@ -261,6 +270,7 @@ impl BatchedHashedElgamalCiphertext { /// Returns the ciphertext but takes the window tables for the public key and generator. Useful when a lot /// of encryptions have to be done using the same public key + /// `gen` is the generator used in the scheme to generate public key and ephemeral public key by sender/encryptor pub fn new_given_randomness_and_window_tables( msgs: &[G::ScalarField], randomness: &G::ScalarField, diff --git a/verifiable_encryption/Cargo.toml b/verifiable_encryption/Cargo.toml index 6532b5d3..7d26b775 100644 --- a/verifiable_encryption/Cargo.toml +++ b/verifiable_encryption/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "verifiable-encryption" +name = "verifiable_encryption" version = "0.1.0" edition.workspace = true authors.workspace = true diff --git a/verifiable_encryption/src/tz_21/dkgith.rs b/verifiable_encryption/src/tz_21/dkgith.rs index 5e10c3db..69180bae 100644 --- a/verifiable_encryption/src/tz_21/dkgith.rs +++ b/verifiable_encryption/src/tz_21/dkgith.rs @@ -42,7 +42,7 @@ use crate::tz_21::encryption::BatchCiphertext; use rayon::prelude::*; /// Ciphertext and the proof of encryption. `CT` is the variant of Elgamal encryption used. See test for usage -#[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize)] +#[derive(Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct DkgithProof< G: AffineRepr, CT: BatchCiphertext, @@ -240,7 +240,10 @@ impl< NUM_REPETITIONS]; for i in 0..NUM_REPETITIONS { - ciphertexts[i] = cts[i][indices_to_hide[i] as usize].clone(); + core::mem::swap( + &mut ciphertexts[i], + &mut cts[i][indices_to_hide[i] as usize], + ); } cfg_iter_mut!(tree_openings).enumerate().for_each(|(i, t)| { *t = seed_trees[i].open_seeds(indices_to_hide[i]); @@ -255,7 +258,7 @@ impl< } } - fn verify( + pub fn verify( &self, commitment: &G, comm_key: &[G], @@ -436,6 +439,10 @@ impl< CompressedCiphertext(compressed_cts, PhantomData) } + pub fn witness_count(&self) -> usize { + self.ciphertexts[0].batch_size() + } + // NOTE: Ideally the verifier will compress the ciphertext and since functions `verify` and `compress` share some code, it will be more efficient to // have a function called `verify_and_compress` than calling `verify` and then `compress` } @@ -460,6 +467,10 @@ impl, const SUBSET_SIZE: usize> } Err(VerifiableEncryptionError::DecryptionFailed) } + + pub fn encrypted_count(&self) -> usize { + self.0[0].batch_size() + } } #[cfg(test)] diff --git a/verifiable_encryption/src/tz_21/encryption.rs b/verifiable_encryption/src/tz_21/encryption.rs index cf5fe898..71d26789 100644 --- a/verifiable_encryption/src/tz_21/encryption.rs +++ b/verifiable_encryption/src/tz_21/encryption.rs @@ -15,15 +15,23 @@ use rayon::prelude::*; /// A list of Elgamal ciphertexts, one for each message. For each message, encryptor creates fresh /// randomness and a thus a new shared secret using Diffie-Hellman key exchange -#[derive(Clone, Debug, Default, CanonicalSerialize, CanonicalDeserialize)] +#[derive(Clone, Debug, Default, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct SimpleBatchElgamalCiphertext(Vec>); /// A trait implemented by schemes encrypting a batch of messages pub trait BatchCiphertext: - Sized + Clone + Default + Debug + Send + Sync + CanonicalSerialize + CanonicalDeserialize + Sized + + Clone + + Default + + PartialEq + + Debug + + Send + + Sync + + CanonicalSerialize + + CanonicalDeserialize { /// Randomness used in the encryption - type Randomness: Clone + Default + CanonicalSerialize + CanonicalDeserialize; + type Randomness: Clone + Default + PartialEq + CanonicalSerialize + CanonicalDeserialize; /// Create a new ciphertext for the batch of messages fn new( diff --git a/verifiable_encryption/src/tz_21/rdkgith.rs b/verifiable_encryption/src/tz_21/rdkgith.rs index 9bfbe942..5f28b87c 100644 --- a/verifiable_encryption/src/tz_21/rdkgith.rs +++ b/verifiable_encryption/src/tz_21/rdkgith.rs @@ -49,7 +49,7 @@ use secret_sharing_and_dkg::{ use rayon::prelude::*; /// Ciphertext and the proof of encryption. `CT` is the variant of Elgamal encryption used. See test for usage -#[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize)] +#[derive(Clone, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct RdkgithProof< G: AffineRepr, CT: BatchCiphertext, @@ -178,7 +178,7 @@ impl< for i in 0..NUM_PARTIES { if indices_to_hide.contains(&(i as u16)) { ciphertexts[ctx_idx].0 = i as u16; - ciphertexts[ctx_idx].1 = cts[i].clone(); + core::mem::swap(&mut ciphertexts[ctx_idx].1, &mut cts[i]); ctx_idx += 1; } else { shares_and_enc_rands[s_idx].0 = i as u16; @@ -201,7 +201,7 @@ impl< } } - fn verify( + pub fn verify( &self, commitment: &G, comm_key: &[G], @@ -274,6 +274,8 @@ impl< hash_elem!(cts[i], hasher, to_hash); } + core::mem::drop(cts); + let challenge = Box::new(hasher).finalize().to_vec(); if challenge != self.challenge { return Err(VerifiableEncryptionError::InvalidProof); @@ -445,6 +447,10 @@ impl< CompressedCiphertext(compressed_cts, lagrange_basis_for_hidden_indices) } + + pub fn witness_count(&self) -> usize { + self.ciphertexts[0].1.batch_size() + } } impl, const SUBSET_SIZE: usize> @@ -466,6 +472,10 @@ impl, const SUBSET_SIZE: usize> } Err(VerifiableEncryptionError::DecryptionFailed) } + + pub fn encrypted_count(&self) -> usize { + self.0[0].batch_size() + } } #[cfg(test)]