From 1659b7381c9d464d1044ac583a7200f5b3d2a640 Mon Sep 17 00:00:00 2001 From: lovesh Date: Tue, 8 Oct 2024 18:43:22 +0530 Subject: [PATCH] use randomized pairing checker in SAVER verifiable decryption Signed-off-by: lovesh --- proof_system/tests/saver.rs | 79 +++++++++++++++++++++++++- saver/src/encryption.rs | 107 +++++++++++++++++++++++++++++++++++- 2 files changed, 184 insertions(+), 2 deletions(-) diff --git a/proof_system/tests/saver.rs b/proof_system/tests/saver.rs index 3a468338..1f9a564e 100644 --- a/proof_system/tests/saver.rs +++ b/proof_system/tests/saver.rs @@ -6,6 +6,7 @@ use ark_std::{ UniformRand, }; use blake2::Blake2b512; +use dock_crypto_utils::randomized_pairing_check::RandomizedPairingChecker; use proof_system::{ prelude::{ generate_snark_srs_bound_check, EqualWitnesses, MetaStatements, ProofSpec, ProverConfig, @@ -41,7 +42,6 @@ use saver::{ setup::{setup_for_groth16, ChunkedCommitmentGens, EncryptionGens, PreparedEncryptionGens}, }; use std::time::Instant; - use test_utils::{bbs::*, test_serialization}; pub fn decrypt_and_verify( @@ -54,12 +54,14 @@ pub fn decrypt_and_verify( enc_gens: impl Into>, chunk_bit_size: u8, ) { + let start = Instant::now(); let dk = dk.into(); let enc_gens = enc_gens.into(); let ct = proof.get_saver_ciphertext_and_proof(stmt_idx).unwrap().0; let (decrypted_message, nu) = ct .decrypt_given_groth16_vk(sk, dk.clone(), snark_vk, chunk_bit_size) .unwrap(); + println!("Time to decrypt {:?}", start.elapsed()); assert_eq!(decrypted_message, decrypted); ct.verify_decryption_given_groth16_vk( &decrypted_message, @@ -72,6 +74,38 @@ pub fn decrypt_and_verify( .unwrap(); } +pub fn decrypt_and_verify_with_randomized_pairing_checker( + pairing_checker: &mut RandomizedPairingChecker, + proof: &Proof, + stmt_idx: usize, + snark_vk: &VerifyingKey, + decrypted: Fr, + sk: &SecretKey, + dk: impl Into>, + enc_gens: impl Into>, + chunk_bit_size: u8, +) { + let start = Instant::now(); + let dk = dk.into(); + let enc_gens = enc_gens.into(); + let ct = proof.get_saver_ciphertext_and_proof(stmt_idx).unwrap().0; + let (decrypted_message, nu) = ct + .decrypt_given_groth16_vk(sk, dk.clone(), snark_vk, chunk_bit_size) + .unwrap(); + println!("Time to decrypt {:?}", start.elapsed()); + assert_eq!(decrypted_message, decrypted); + ct.verify_decryption_given_groth16_vk_with_randomized_pairing_checker( + &decrypted_message, + &nu, + chunk_bit_size, + dk, + snark_vk, + enc_gens, + pairing_checker, + ) + .unwrap(); +} + macro_rules! gen_tests { ($test1_name: ident, $test2_name: ident, $setup_fn_name: ident, $prover_stmt: ident, $verifier_stmt: ident, $wit: ident) => { #[test] @@ -262,6 +296,26 @@ macro_rules! gen_tests { start.elapsed() ); + let start = Instant::now(); + let mut checker = RandomizedPairingChecker::::new_using_rng(&mut rng, true); + decrypt_and_verify_with_randomized_pairing_checker( + &mut checker, + &proof, + 1, + &snark_pk.pk.vk, + msgs[enc_msg_idx], + &sk, + prepared_dk.clone(), + prepared_enc_gens.clone(), + chunk_bit_size, + ); + assert!(checker.verify()); + println!( + "Time taken to decrypt and verify 1 encrypted message in signature over {} messages using randomized pairing checker {:?}", + msg_count, + start.elapsed() + ); + let start = Instant::now(); let mut m = BTreeMap::new(); let (c, p) = proof.get_saver_ciphertext_and_proof(1).unwrap(); @@ -616,6 +670,29 @@ macro_rules! gen_tests { start.elapsed() ); + let start = Instant::now(); + let mut checker = RandomizedPairingChecker::::new_using_rng(&mut rng, true); + for (i, j) in enc_msg_indices.iter().enumerate() { + decrypt_and_verify_with_randomized_pairing_checker( + &mut checker, + &proof, + i + 1, + &snark_pk.pk.vk, + msgs[*j], + &sk, + dk.clone(), + enc_gens.clone(), + chunk_bit_size, + ); + } + assert!(checker.verify()); + println!( + "Time taken to decrypt and verify {} encrypted messages in signature over {} messages using randomized pairing checker {:?}", + enc_msg_indices.len(), + msg_count, + start.elapsed() + ); + let start = Instant::now(); let mut m = BTreeMap::new(); for i in 1..=enc_msg_indices.len() { diff --git a/saver/src/encryption.rs b/saver/src/encryption.rs index d64f31c9..53c985f3 100644 --- a/saver/src/encryption.rs +++ b/saver/src/encryption.rs @@ -29,7 +29,10 @@ use serde_with::serde_as; use crate::utils::CHUNK_TYPE; use dock_crypto_utils::{ff::non_zero_random, serde_utils::*}; -use dock_crypto_utils::solve_discrete_log::solve_discrete_log_bsgs_alt; +use dock_crypto_utils::{ + randomized_pairing_check::RandomizedPairingChecker, + solve_discrete_log::solve_discrete_log_bsgs_alt, +}; #[cfg(feature = "parallel")] use rayon::prelude::*; @@ -127,6 +130,31 @@ macro_rules! impl_enc_funcs { gens, ) } + + /// Verify that the decrypted message corresponds to original plaintext in the ciphertext + /// but using randomized pairing checker + pub fn verify_decryption_with_randomized_pairing_checker( + &self, + message: &E::ScalarField, + nu: &E::G1Affine, + chunk_bit_size: u8, + dk: impl Into>, + g_i: &[E::G1Affine], + gens: impl Into>, + pairing_checker: &mut RandomizedPairingChecker, + ) -> crate::Result<()> { + let decomposed = utils::decompose(message, chunk_bit_size)?; + Encryption::verify_decryption_with_randomized_pairing_checker( + &decomposed, + &self.X_r, + &self.enc_chunks, + nu, + dk, + g_i, + gens, + pairing_checker, + ) + } }; } @@ -439,6 +467,61 @@ impl Encryption { Ok(()) } + /// Same as `Self::verify_decryption` but used randomized pairing checker + pub fn verify_decryption_with_randomized_pairing_checker( + messages: &[CHUNK_TYPE], + c_0: &E::G1Affine, + c: &[E::G1Affine], + nu: &E::G1Affine, + dk: impl Into>, + g_i: &[E::G1Affine], + gens: impl Into>, + pairing_checker: &mut RandomizedPairingChecker, + ) -> crate::Result<()> { + let dk = dk.into(); + let gens = gens.into(); + if messages.len() != dk.supported_chunks_count()? as usize { + return Err(SaverError::IncompatibleDecryptionKey( + messages.len(), + dk.supported_chunks_count()? as usize, + )); + } + if messages.len() > g_i.len() { + return Err(SaverError::VectorShorterThanExpected( + messages.len(), + g_i.len(), + )); + } + + // NOTE: A likely optimization is combining all terms involving `nu` and then use a random linear + // combination check but this will require multiplication in group G2, i.e. gens.H and dk.V_1 + // which is not possible given prepared versions of these. So it needs to be compared with the + // other variation + + let minus_nu = nu.into_group().neg().into(); + pairing_checker.add_sources(nu, gens.H, c_0, dk.V_0.clone()); + + let g_i_m_i_c_i = E::G1::normalize_batch( + // g_i * m_i - c_i + &cfg_into_iter!(0..messages.len()) + .map(|i| { + let g_i_m_i = g_i[i].mul(E::ScalarField::from(messages[i] as u64)); + g_i_m_i.sub(&c[i]) + }) + .collect::>(), + ); + + for i in 0..messages.len() { + pairing_checker.add_sources( + &g_i_m_i_c_i[i], + dk.V_2[i].clone(), + &minus_nu, + dk.V_1[i].clone(), + ); + } + Ok(()) + } + /// Same as `Self::verify_decryption` but takes Groth16's verification key instead of the generators used for Elgamal encryption pub fn verify_decryption_given_groth16_vk( messages: &[CHUNK_TYPE], @@ -718,6 +801,28 @@ impl Ciphertext { let g_i = saver_groth16::get_gs_for_encryption(snark_vk); self.verify_decryption(message, nu, chunk_bit_size, dk, g_i, gens) } + + pub fn verify_decryption_given_groth16_vk_with_randomized_pairing_checker( + &self, + message: &E::ScalarField, + nu: &E::G1Affine, + chunk_bit_size: u8, + dk: impl Into>, + snark_vk: &ark_groth16::VerifyingKey, + gens: impl Into>, + pairing_checker: &mut RandomizedPairingChecker, + ) -> crate::Result<()> { + let g_i = saver_groth16::get_gs_for_encryption(snark_vk); + self.verify_decryption_with_randomized_pairing_checker( + message, + nu, + chunk_bit_size, + dk, + g_i, + gens, + pairing_checker, + ) + } } impl CiphertextAlt {