From 5062f40280ff9bc5dd1ca98d5fcd19d3344ab71f Mon Sep 17 00:00:00 2001 From: Piotr Roslaniec Date: Mon, 14 Aug 2023 15:21:28 +0200 Subject: [PATCH] draft new ciphertext api --- ferveo-python/ferveo/__init__.py | 1 + ferveo-python/ferveo/__init__.pyi | 13 +++++++ ferveo/src/api.rs | 62 ++++++++++++++++++++----------- ferveo/src/bindings_python.rs | 30 +++++++++++++++ tpke/src/api.rs | 1 + tpke/src/ciphertext.rs | 8 +++- 6 files changed, 92 insertions(+), 23 deletions(-) diff --git a/ferveo-python/ferveo/__init__.py b/ferveo-python/ferveo/__init__.py index f89aa778..478628b1 100644 --- a/ferveo-python/ferveo/__init__.py +++ b/ferveo-python/ferveo/__init__.py @@ -9,6 +9,7 @@ Transcript, Dkg, Ciphertext, + CiphertextHeader, DecryptionShareSimple, DecryptionSharePrecomputed, AggregatedTranscript, diff --git a/ferveo-python/ferveo/__init__.pyi b/ferveo-python/ferveo/__init__.pyi index 1dfab2f0..adbc896f 100644 --- a/ferveo-python/ferveo/__init__.pyi +++ b/ferveo-python/ferveo/__init__.pyi @@ -119,6 +119,19 @@ class Dkg: @final class Ciphertext: + header: CiphertextHeader + payload: bytes + + @staticmethod + def from_bytes(data: bytes) -> Ciphertext: + ... + + def __bytes__(self) -> bytes: + ... + + +@final +class CiphertextHeader: @staticmethod def from_bytes(data: bytes) -> Ciphertext: ... diff --git a/ferveo/src/api.rs b/ferveo/src/api.rs index ccf9ff5f..31063258 100644 --- a/ferveo/src/api.rs +++ b/ferveo/src/api.rs @@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize}; use serde_with::serde_as; pub use tpke::api::{ prepare_combine_simple, share_combine_precomputed, share_combine_simple, - Ciphertext, Fr, G1Affine, G1Prepared, SecretBox, E, + Fr, G1Affine, G1Prepared, G2Affine, SecretBox, E, }; pub type PublicKey = ferveo_common::PublicKey; @@ -55,7 +55,7 @@ pub fn encrypt( ) -> Result { let mut rng = rand::thread_rng(); let ciphertext = tpke::api::encrypt(message, aad, &pubkey.0, &mut rng)?; - Ok(ciphertext) + Ok(Ciphertext(ciphertext)) } pub fn decrypt_with_shared_secret( @@ -65,7 +65,7 @@ pub fn decrypt_with_shared_secret( ) -> Result> { let dkg_public_params = DkgPublicParameters::default(); tpke::api::decrypt_with_shared_secret( - ciphertext, + &ciphertext.0, aad, &shared_secret.0, &dkg_public_params.g1_inv, @@ -73,6 +73,35 @@ pub fn decrypt_with_shared_secret( .map_err(Error::from) } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Eq)] +pub struct Ciphertext(pub(crate) tpke::api::Ciphertext); + +impl Ciphertext { + pub fn header(&self) -> CiphertextHeader { + let ciphertext_hash = self.0.ciphertext_hash(); + CiphertextHeader { + commitment: self.0.commitment, + auth_tag: self.0.auth_tag, + ciphertext_hash, + } + } + + pub fn payload(&self) -> Vec { + // TODO: Do we want to return a Vec here or rather obfuscate the type with a newtype/struct? + self.0.ciphertext.clone() + } +} + +#[serde_as] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +pub struct CiphertextHeader { + #[serde_as(as = "serialization::SerdeAs")] + commitment: G1Affine, + #[serde_as(as = "serialization::SerdeAs")] + auth_tag: G2Affine, + ciphertext_hash: [u8; 32], +} + /// The ferveo variant to use for the decryption share derivation. #[derive( PartialEq, Eq, Debug, Serialize, Deserialize, Copy, Clone, PartialOrd, @@ -297,7 +326,7 @@ impl AggregatedTranscript { .take(dkg.0.dkg_params.shares_num as usize) .collect(); self.0.make_decryption_share_simple_precomputed( - ciphertext, + &ciphertext.0, aad, &validator_keypair.decryption_key, dkg.0.me.share_index, @@ -314,7 +343,7 @@ impl AggregatedTranscript { validator_keypair: &Keypair, ) -> Result { let share = self.0.make_decryption_share_simple( - ciphertext, + &ciphertext.0, aad, &validator_keypair.decryption_key, dkg.0.me.share_index, @@ -458,14 +487,10 @@ mod test_ferveo_api { // In the meantime, the client creates a ciphertext and decryption request let msg = "my-msg".as_bytes().to_vec(); let aad: &[u8] = "my-aad".as_bytes(); - let rng = &mut thread_rng(); - let ciphertext = tpke::api::encrypt( - SecretBox::new(msg.clone()), - aad, - &dkg_public_key.0, - rng, - ) - .unwrap(); + let _rng = &mut thread_rng(); + let ciphertext = + encrypt(SecretBox::new(msg.clone()), aad, &dkg_public_key) + .unwrap(); // Having aggregated the transcripts, the validators can now create decryption shares let decryption_shares: Vec<_> = @@ -557,14 +582,9 @@ mod test_ferveo_api { // In the meantime, the client creates a ciphertext and decryption request let msg = "my-msg".as_bytes().to_vec(); let aad: &[u8] = "my-aad".as_bytes(); - let rng = &mut thread_rng(); - let ciphertext = tpke::api::encrypt( - SecretBox::new(msg.clone()), - aad, - &public_key.0, - rng, - ) - .unwrap(); + let _rng = &mut thread_rng(); + let ciphertext = + encrypt(SecretBox::new(msg.clone()), aad, &public_key).unwrap(); // Having aggregated the transcripts, the validators can now create decryption shares let decryption_shares: Vec<_> = diff --git a/ferveo/src/bindings_python.rs b/ferveo/src/bindings_python.rs index 7d1cb93b..3ea3c0e0 100644 --- a/ferveo/src/bindings_python.rs +++ b/ferveo/src/bindings_python.rs @@ -512,8 +512,37 @@ impl Dkg { )] pub struct Ciphertext(api::Ciphertext); +#[pymethods] +impl Ciphertext { + #[getter] + pub fn header(&self) -> CiphertextHeader { + CiphertextHeader(self.0.header()) + } + + #[getter] + pub fn payload(&self) -> Vec { + self.0.payload().to_vec() + } +} + generate_bytes_serialization!(Ciphertext); +#[pyclass(module = "ferveo")] +#[derive( + Clone, + Debug, + PartialEq, + Eq, + Serialize, + Deserialize, + derive_more::From, + derive_more::AsRef, + derive_more::Into, +)] +pub struct CiphertextHeader(api::CiphertextHeader); + +generate_bytes_serialization!(CiphertextHeader); + #[pyclass(module = "ferveo")] #[derive(Clone, derive_more::AsRef, derive_more::From)] pub struct DecryptionShareSimple(api::DecryptionShareSimple); @@ -631,6 +660,7 @@ pub fn make_ferveo_py_module(py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; + m.add_class::()?; m.add_class::()?; m.add_class::()?; m.add_class::()?; diff --git a/tpke/src/api.rs b/tpke/src/api.rs index 3ebba690..94bc98fa 100644 --- a/tpke/src/api.rs +++ b/tpke/src/api.rs @@ -3,6 +3,7 @@ pub type E = ark_bls12_381::Bls12_381; pub type G1Prepared = ::G1Prepared; pub type G1Affine = ::G1Affine; +pub type G2Affine = ::G2Affine; pub type Fr = ark_bls12_381::Fr; pub type PrivateKey = ark_bls12_381::G2Affine; pub type Result = crate::Result; diff --git a/tpke/src/ciphertext.rs b/tpke/src/ciphertext.rs index 814a72d2..49d7ff3a 100644 --- a/tpke/src/ciphertext.rs +++ b/tpke/src/ciphertext.rs @@ -55,6 +55,10 @@ impl Ciphertext { + self.auth_tag.serialized_size(Compress::No) + self.ciphertext.len() } + + pub fn ciphertext_hash(&self) -> [u8; 32] { + sha256(&self.ciphertext) + } } pub fn encrypt( @@ -165,11 +169,11 @@ pub fn decrypt_with_shared_secret( decrypt_with_shared_secret_unchecked(ciphertext, shared_secret) } -fn sha256(input: &[u8]) -> Vec { +fn sha256(input: &[u8]) -> [u8; 32] { let mut hasher = Sha256::new(); hasher.update(input); let result = hasher.finalize(); - result.to_vec() + result.into() } pub fn shared_secret_to_chacha(