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(