Skip to content

Commit

Permalink
Refactor Ciphertext implementation. Fixes #144
Browse files Browse the repository at this point in the history
* Remove unused Ciphertext.construct_tag_hash()
* Refactor Ciphertext.check() to take the functionality of check_ciphertext_validity() function
  • Loading branch information
cygnusv committed Jul 31, 2023
1 parent 12c8b5c commit 86201f9
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 60 deletions.
3 changes: 1 addition & 2 deletions tpke/benches/tpke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
))
Expand Down
73 changes: 27 additions & 46 deletions tpke/src/ciphertext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,32 @@ pub struct Ciphertext<E: Pairing> {
}

impl<E: Pairing> Ciphertext<E> {
pub fn check(&self, g_inv: &E::G1Prepared) -> Result<bool> {
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<bool> {
// 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::<E>(
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<E::G2Affine> {
let mut hash_input = Vec::<u8>::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 {
Expand Down Expand Up @@ -95,42 +105,13 @@ pub fn encrypt<E: Pairing>(
})
}

/// 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<E: Pairing>(
c: &Ciphertext<E>,
aad: &[u8],
g_inv: &E::G1Prepared,
) -> Result<()> {
// H_G2(U, aad)
let hash_g2 = E::G2Prepared::from(construct_tag_hash::<E>(
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<E: Pairing>(
ciphertext: &Ciphertext<E>,
aad: &[u8],
private_key: &E::G2Affine,
g_inv: &E::G1Prepared,
) -> Result<Vec<u8>> {
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),
Expand Down Expand Up @@ -161,7 +142,7 @@ pub fn decrypt_with_shared_secret<E: Pairing>(
shared_secret: &SharedSecret<E>,
g_inv: &E::G1Prepared,
) -> Result<Vec<u8>> {
check_ciphertext_validity(ciphertext, aad, g_inv)?;
ciphertext.check(aad, g_inv)?;
decrypt_with_shared_secret_unchecked(ciphertext, shared_secret)
}

Expand Down Expand Up @@ -267,14 +248,14 @@ mod tests {
encrypt::<E>(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());
}
}
12 changes: 4 additions & 8 deletions tpke/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -51,11 +51,7 @@ impl<E: Pairing> PrivateDecryptionContextFast<E> {
ciphertext: &Ciphertext<E>,
aad: &[u8],
) -> Result<DecryptionShareFast<E>> {
check_ciphertext_validity::<E>(
ciphertext,
aad,
&self.setup_params.g_inv,
)?;
ciphertext.check(aad, &self.setup_params.g_inv)?;

let decryption_share = ciphertext
.commitment
Expand Down
8 changes: 4 additions & 4 deletions tpke/src/decryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -94,7 +94,7 @@ impl<E: Pairing> DecryptionShareSimple<E> {
aad: &[u8],
g_inv: &E::G1Prepared,
) -> Result<Self> {
check_ciphertext_validity::<E>(ciphertext, aad, g_inv)?;
ciphertext.check(aad, g_inv)?;
Self::create_unchecked(
validator_decryption_key,
private_key_share,
Expand Down Expand Up @@ -165,7 +165,7 @@ impl<E: Pairing> DecryptionSharePrecomputed<E> {
lagrange_coeff: &E::ScalarField,
g_inv: &E::G1Prepared,
) -> Result<Self> {
check_ciphertext_validity::<E>(ciphertext, aad, g_inv)?;
ciphertext.check(aad, g_inv)?;
Self::create_unchecked(
validator_index,
validator_decryption_key,
Expand Down

0 comments on commit 86201f9

Please sign in to comment.