From 86201f9ba89f5faecf0b8a09d2b518e4e1799eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=BA=C3=B1ez?= Date: Fri, 28 Jul 2023 16:49:43 +0200 Subject: [PATCH] Refactor Ciphertext implementation. Fixes #144 * Remove unused Ciphertext.construct_tag_hash() * Refactor Ciphertext.check() to take the functionality of check_ciphertext_validity() function --- tpke/benches/tpke.rs | 3 +- tpke/src/ciphertext.rs | 73 ++++++++++++++++-------------------------- tpke/src/context.rs | 12 +++---- tpke/src/decryption.rs | 8 ++--- 4 files changed, 36 insertions(+), 60 deletions(-) diff --git a/tpke/benches/tpke.rs b/tpke/benches/tpke.rs index 952c4947..89fef191 100644 --- a/tpke/benches/tpke.rs +++ b/tpke/benches/tpke.rs @@ -388,8 +388,7 @@ pub fn bench_ciphertext_validity_checks(c: &mut Criterion) { let mut rng = rng.clone(); let setup = SetupFast::new(shares_num, msg_size, &mut rng); move || { - black_box(check_ciphertext_validity( - &setup.shared.ciphertext, + black_box(setup.shared.ciphertext.check( &setup.shared.aad, &setup.contexts[0].setup_params.g_inv, )) diff --git a/tpke/src/ciphertext.rs b/tpke/src/ciphertext.rs index 814a72d2..fe6af03d 100644 --- a/tpke/src/ciphertext.rs +++ b/tpke/src/ciphertext.rs @@ -32,22 +32,32 @@ pub struct Ciphertext { } impl Ciphertext { - pub fn check(&self, g_inv: &E::G1Prepared) -> Result { - let hash_g2 = E::G2Prepared::from(self.construct_tag_hash()?); - - Ok(E::multi_pairing( + pub fn check(&self, aad: &[u8], g_inv: &E::G1Prepared) -> Result { + // Implements a variant of the check in section 4.4.2 of the Ferveo paper: + // 'TPKE.CheckCiphertextValidity(U,W,aad)' + // See: https://eprint.iacr.org/2022/898.pdf + // See: https://nikkolasg.github.io/ferveo/tpke.html#to-validate-ciphertext-for-ind-cca2-security + + // H_G2(U, sym_ctxt, aad) + let hash_g2 = E::G2Prepared::from(construct_tag_hash::( + self.commitment, + &self.ciphertext[..], + aad, + )?); + + let is_ciphertext_valid = E::multi_pairing( + // e(U, H_G2(U, sym_ctxt, aad)) = e(G, W) ==> + // e(U, H_G2(U, sym_ctxt, aad)) * e(G_inv, W) = 1 [self.commitment.into(), g_inv.to_owned()], [hash_g2, self.auth_tag.into()], ) - .0 == E::TargetField::one()) - } - - fn construct_tag_hash(&self) -> Result { - let mut hash_input = Vec::::new(); - self.commitment.serialize_compressed(&mut hash_input)?; - hash_input.extend_from_slice(&self.ciphertext); + .0 == E::TargetField::one(); - hash_to_g2(&hash_input) + if is_ciphertext_valid { + Ok(true) + } else { + Err(Error::CiphertextVerificationFailed) + } } pub fn serialized_length(&self) -> usize { @@ -95,42 +105,13 @@ pub fn encrypt( }) } -/// Implements the check section 4.4.2 of the Ferveo paper, 'TPKE.CheckCiphertextValidity(U,W,aad)' -/// See: https://eprint.iacr.org/2022/898.pdf -/// See: https://nikkolasg.github.io/ferveo/tpke.html#to-validate-ciphertext-for-ind-cca2-security -pub fn check_ciphertext_validity( - c: &Ciphertext, - aad: &[u8], - g_inv: &E::G1Prepared, -) -> Result<()> { - // H_G2(U, aad) - let hash_g2 = E::G2Prepared::from(construct_tag_hash::( - c.commitment, - &c.ciphertext[..], - aad, - )?); - - let is_ciphertext_valid = E::multi_pairing( - // e(U, H_G2(U, aad)) = e(G, W) - [c.commitment.into(), g_inv.to_owned()], - [hash_g2, c.auth_tag.into()], - ) - .0 == E::TargetField::one(); - - if is_ciphertext_valid { - Ok(()) - } else { - Err(Error::CiphertextVerificationFailed) - } -} - pub fn decrypt_symmetric( ciphertext: &Ciphertext, aad: &[u8], private_key: &E::G2Affine, g_inv: &E::G1Prepared, ) -> Result> { - check_ciphertext_validity(ciphertext, aad, g_inv)?; + ciphertext.check(aad, g_inv)?; let shared_secret = E::pairing( E::G1Prepared::from(ciphertext.commitment), E::G2Prepared::from(*private_key), @@ -161,7 +142,7 @@ pub fn decrypt_with_shared_secret( shared_secret: &SharedSecret, g_inv: &E::G1Prepared, ) -> Result> { - check_ciphertext_validity(ciphertext, aad, g_inv)?; + ciphertext.check(aad, g_inv)?; decrypt_with_shared_secret_unchecked(ciphertext, shared_secret) } @@ -267,14 +248,14 @@ mod tests { encrypt::(SecretBox::new(msg), aad, &pubkey, rng).unwrap(); // So far, the ciphertext is valid - assert!(check_ciphertext_validity(&ciphertext, aad, &g_inv).is_ok()); + assert!(ciphertext.check(aad, &g_inv).is_ok()); // Malformed the ciphertext ciphertext.ciphertext[0] += 1; - assert!(check_ciphertext_validity(&ciphertext, aad, &g_inv).is_err()); + assert!(ciphertext.check(aad, &g_inv).is_err()); // Malformed the AAD let aad = "bad aad".as_bytes(); - assert!(check_ciphertext_validity(&ciphertext, aad, &g_inv).is_err()); + assert!(ciphertext.check(aad, &g_inv).is_err()); } } diff --git a/tpke/src/context.rs b/tpke/src/context.rs index 74f60c07..4a471925 100644 --- a/tpke/src/context.rs +++ b/tpke/src/context.rs @@ -3,9 +3,9 @@ use std::ops::Mul; use ark_ec::{pairing::Pairing, CurveGroup}; use crate::{ - check_ciphertext_validity, prepare_combine_simple, BlindedKeyShare, - Ciphertext, DecryptionShareFast, DecryptionSharePrecomputed, - DecryptionShareSimple, PrivateKeyShare, PublicKeyShare, Result, + prepare_combine_simple, BlindedKeyShare, Ciphertext, DecryptionShareFast, + DecryptionSharePrecomputed, DecryptionShareSimple, PrivateKeyShare, + PublicKeyShare, Result, }; #[derive(Clone, Debug)] @@ -51,11 +51,7 @@ impl PrivateDecryptionContextFast { ciphertext: &Ciphertext, aad: &[u8], ) -> Result> { - check_ciphertext_validity::( - ciphertext, - aad, - &self.setup_params.g_inv, - )?; + ciphertext.check(aad, &self.setup_params.g_inv)?; let decryption_share = ciphertext .commitment diff --git a/tpke/src/decryption.rs b/tpke/src/decryption.rs index c3b85eb5..ad319783 100644 --- a/tpke/src/decryption.rs +++ b/tpke/src/decryption.rs @@ -9,8 +9,8 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde_with::serde_as; use crate::{ - check_ciphertext_validity, generate_random, Ciphertext, PrivateKeyShare, - PublicDecryptionContextFast, PublicDecryptionContextSimple, Result, + generate_random, Ciphertext, PrivateKeyShare, PublicDecryptionContextFast, + PublicDecryptionContextSimple, Result, }; #[serde_as] @@ -94,7 +94,7 @@ impl DecryptionShareSimple { aad: &[u8], g_inv: &E::G1Prepared, ) -> Result { - check_ciphertext_validity::(ciphertext, aad, g_inv)?; + ciphertext.check(aad, g_inv)?; Self::create_unchecked( validator_decryption_key, private_key_share, @@ -165,7 +165,7 @@ impl DecryptionSharePrecomputed { lagrange_coeff: &E::ScalarField, g_inv: &E::G1Prepared, ) -> Result { - check_ciphertext_validity::(ciphertext, aad, g_inv)?; + ciphertext.check(aad, g_inv)?; Self::create_unchecked( validator_index, validator_decryption_key,