From 1800d3c5db164947c7cae35433fb8e3ad2650b66 Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Mon, 14 Aug 2023 15:21:28 +0200
Subject: [PATCH 1/3] feat!: add ciphertext header to ciphertext api
---
.../examples/server_api_precomputed.py | 2 +-
ferveo-python/examples/server_api_simple.py | 2 +-
ferveo-python/ferveo/__init__.py | 1 +
ferveo-python/ferveo/__init__.pyi | 17 +++++-
ferveo-python/test/test_ferveo.py | 2 +-
ferveo-wasm/examples/node/src/main.test.ts | 10 ++--
ferveo-wasm/tests/node.rs | 4 +-
ferveo/benches/benchmarks/validity_checks.rs | 2 +-
ferveo/examples/bench_ark_sizes.rs | 7 +--
ferveo/examples/bench_primitives_size.rs | 14 ++---
ferveo/src/api.rs | 58 +++++++++++--------
ferveo/src/bindings_python.rs | 45 +++++++++++---
ferveo/src/bindings_wasm.rs | 36 ++++++++++--
ferveo/src/dkg.rs | 2 +-
ferveo/src/lib.rs | 24 ++++----
ferveo/src/pvss.rs | 12 ++--
tpke/benches/tpke.rs | 12 ++--
tpke/src/api.rs | 3 +
tpke/src/ciphertext.rs | 40 +++++++++++--
tpke/src/context.rs | 14 ++---
tpke/src/decryption.rs | 41 +++++++------
tpke/src/lib.rs | 31 +++++++---
22 files changed, 256 insertions(+), 123 deletions(-)
diff --git a/ferveo-python/examples/server_api_precomputed.py b/ferveo-python/examples/server_api_precomputed.py
index 0916738d..7c433e96 100644
--- a/ferveo-python/examples/server_api_precomputed.py
+++ b/ferveo-python/examples/server_api_precomputed.py
@@ -82,7 +82,7 @@ def gen_eth_addr(i: int) -> str:
# Create a decryption share for the ciphertext
decryption_share = aggregate.create_decryption_share_precomputed(
- dkg, ciphertext, aad, validator_keypair
+ dkg, ciphertext.header, aad, validator_keypair
)
decryption_shares.append(decryption_share)
diff --git a/ferveo-python/examples/server_api_simple.py b/ferveo-python/examples/server_api_simple.py
index e41c9f24..4f9e8447 100644
--- a/ferveo-python/examples/server_api_simple.py
+++ b/ferveo-python/examples/server_api_simple.py
@@ -85,7 +85,7 @@ def gen_eth_addr(i: int) -> str:
# Create a decryption share for the ciphertext
decryption_share = aggregate.create_decryption_share_simple(
- dkg, ciphertext, aad, validator_keypair
+ dkg, ciphertext.header, aad, validator_keypair
)
decryption_shares.append(decryption_share)
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..3549d751 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:
...
@@ -159,7 +172,7 @@ class AggregatedTranscript:
def create_decryption_share_simple(
self,
dkg: Dkg,
- ciphertext: Ciphertext,
+ ciphertext_header: CiphertextHeader,
aad: bytes,
validator_keypair: Keypair
) -> DecryptionShareSimple:
@@ -168,7 +181,7 @@ class AggregatedTranscript:
def create_decryption_share_precomputed(
self,
dkg: Dkg,
- ciphertext: Ciphertext,
+ ciphertext_header: CiphertextHeader,
aad: bytes,
validator_keypair: Keypair
) -> DecryptionSharePrecomputed:
diff --git a/ferveo-python/test/test_ferveo.py b/ferveo-python/test/test_ferveo.py
index 7d93c637..42a82a84 100644
--- a/ferveo-python/test/test_ferveo.py
+++ b/ferveo-python/test/test_ferveo.py
@@ -91,7 +91,7 @@ def scenario_for_variant(variant: FerveoVariant, shares_num, threshold, shares_t
assert pvss_aggregated.verify(shares_num, messages)
decryption_share = decryption_share_for_variant(variant, pvss_aggregated)(
- dkg, ciphertext, aad, validator_keypair
+ dkg, ciphertext.header, aad, validator_keypair
)
decryption_shares.append(decryption_share)
diff --git a/ferveo-wasm/examples/node/src/main.test.ts b/ferveo-wasm/examples/node/src/main.test.ts
index 69ec9f8a..28144861 100644
--- a/ferveo-wasm/examples/node/src/main.test.ts
+++ b/ferveo-wasm/examples/node/src/main.test.ts
@@ -27,11 +27,11 @@ function setupTest() {
const sharesNum = 4;
const threshold = Math.floor((sharesNum * 2) / 3);
- const validator_keypairs: Keypair[] = [];
+ const validatorKeypairs: Keypair[] = [];
const validators: Validator[] = [];
for (let i = 0; i < sharesNum; i++) {
const keypair = Keypair.random();
- validator_keypairs.push(keypair);
+ validatorKeypairs.push(keypair);
const validator = new Validator(genEthAddr(i), keypair.publicKey);
validators.push(validator);
}
@@ -66,7 +66,7 @@ function setupTest() {
tau,
sharesNum,
threshold,
- validatorKeypairs: validator_keypairs,
+ validatorKeypairs,
validators,
dkg,
messages,
@@ -103,7 +103,7 @@ describe("ferveo-wasm", () => {
const decryptionShare = aggregate.createDecryptionShareSimple(
dkg,
- ciphertext,
+ ciphertext.header,
aad,
keypair
);
@@ -150,7 +150,7 @@ describe("ferveo-wasm", () => {
const decryptionShare = aggregate.createDecryptionSharePrecomputed(
dkg,
- ciphertext,
+ ciphertext.header,
aad,
keypair
);
diff --git a/ferveo-wasm/tests/node.rs b/ferveo-wasm/tests/node.rs
index c1564c82..b4234d07 100644
--- a/ferveo-wasm/tests/node.rs
+++ b/ferveo-wasm/tests/node.rs
@@ -125,7 +125,7 @@ fn tdec_simple() {
aggregate
.create_decryption_share_simple(
&dkg,
- &ciphertext,
+ &ciphertext.header().unwrap(),
&aad,
&keypair,
)
@@ -179,7 +179,7 @@ fn tdec_precomputed() {
aggregate
.create_decryption_share_precomputed(
&dkg,
- &ciphertext,
+ &ciphertext.header().unwrap(),
&aad,
&keypair,
)
diff --git a/ferveo/benches/benchmarks/validity_checks.rs b/ferveo/benches/benchmarks/validity_checks.rs
index 00972c05..a6dd9f48 100644
--- a/ferveo/benches/benchmarks/validity_checks.rs
+++ b/ferveo/benches/benchmarks/validity_checks.rs
@@ -22,7 +22,7 @@ fn gen_keypairs(num: u32) -> Vec> {
}
pub fn gen_address(i: usize) -> EthereumAddress {
- EthereumAddress::from_str(&format!("0x{:040}", i)).unwrap()
+ EthereumAddress::from_str(&format!("0x{i:040}")).unwrap()
}
fn gen_validators(
diff --git a/ferveo/examples/bench_ark_sizes.rs b/ferveo/examples/bench_ark_sizes.rs
index 7b211597..95ad35f6 100644
--- a/ferveo/examples/bench_ark_sizes.rs
+++ b/ferveo/examples/bench_ark_sizes.rs
@@ -47,8 +47,7 @@ pub fn save_data(
let mut file = OpenOptions::new().append(true).open(&file_path).unwrap();
writeln!(
file,
- "{}|{}|{}|",
- n_of_elements, type_of_element, serialized_size_in_bytes
+ "{n_of_elements}|{type_of_element}|{serialized_size_in_bytes}|"
)
.unwrap();
}
@@ -66,10 +65,10 @@ fn main() {
.map(|(n, element)| (n, element))
.collect::>();
- println!("Running benchmarks for {:?}", configs);
+ println!("Running benchmarks for {configs:?}");
for (n, element) in configs {
- println!("number_of_elements: {}, type_of_elements: {}", n, element);
+ println!("number_of_elements: {n}, type_of_elements: {element}");
let g1_affine =
(0..*n).map(|_| G1Affine::rand(rng)).collect::>();
diff --git a/ferveo/examples/bench_primitives_size.rs b/ferveo/examples/bench_primitives_size.rs
index e84c64a6..18adf673 100644
--- a/ferveo/examples/bench_primitives_size.rs
+++ b/ferveo/examples/bench_primitives_size.rs
@@ -42,12 +42,8 @@ pub fn save_data(
eprintln!("Appending to file: {}", file_path.display());
let mut file = OpenOptions::new().append(true).open(&file_path).unwrap();
- writeln!(
- file,
- "{}|{}|{}|",
- shares_num, threshold, transcript_size_bytes
- )
- .unwrap();
+ writeln!(file, "{shares_num}|{threshold}|{transcript_size_bytes}|")
+ .unwrap();
}
// TODO: Find a way to deduplicate the following methods with benchmarks and test setup
@@ -60,7 +56,7 @@ fn gen_keypairs(num: u32) -> Vec> {
}
pub fn gen_address(i: usize) -> EthereumAddress {
- EthereumAddress::from_str(&format!("0x{:040}", i)).unwrap()
+ EthereumAddress::from_str(&format!("0x{i:040}")).unwrap()
}
fn gen_validators(
@@ -132,10 +128,10 @@ fn main() {
})
.collect::>();
- println!("Running benchmarks for {:?}", configs);
+ println!("Running benchmarks for {configs:?}");
for (shares_num, threshold) in configs {
- println!("shares_num: {}, threshold: {}", shares_num, threshold);
+ println!("shares_num: {shares_num}, threshold: {threshold}");
let dkg = setup(*shares_num as u32, threshold, rng);
let transcript = &dkg.vss.values().next().unwrap();
let transcript_bytes = bincode::serialize(&transcript).unwrap();
diff --git a/ferveo/src/api.rs b/ferveo/src/api.rs
index ccf9ff5f..16ede060 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,23 @@ pub fn decrypt_with_shared_secret(
.map_err(Error::from)
}
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Eq)]
+pub struct Ciphertext(tpke::api::Ciphertext);
+
+impl Ciphertext {
+ pub fn header(&self) -> Result {
+ Ok(CiphertextHeader(self.0.header()?))
+ }
+
+ pub fn payload(&self) -> Vec {
+ self.0.payload()
+ }
+}
+
+#[serde_as]
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
+pub struct CiphertextHeader(tpke::api::CiphertextHeader);
+
/// The ferveo variant to use for the decryption share derivation.
#[derive(
PartialEq, Eq, Debug, Serialize, Deserialize, Copy, Clone, PartialOrd,
@@ -286,7 +303,7 @@ impl AggregatedTranscript {
pub fn create_decryption_share_precomputed(
&self,
dkg: &Dkg,
- ciphertext: &Ciphertext,
+ ciphertext_header: &CiphertextHeader,
aad: &[u8],
validator_keypair: &Keypair,
) -> Result {
@@ -297,7 +314,7 @@ impl AggregatedTranscript {
.take(dkg.0.dkg_params.shares_num as usize)
.collect();
self.0.make_decryption_share_simple_precomputed(
- ciphertext,
+ &ciphertext_header.0,
aad,
&validator_keypair.decryption_key,
dkg.0.me.share_index,
@@ -309,12 +326,12 @@ impl AggregatedTranscript {
pub fn create_decryption_share_simple(
&self,
dkg: &Dkg,
- ciphertext: &Ciphertext,
+ ciphertext_header: &CiphertextHeader,
aad: &[u8],
validator_keypair: &Keypair,
) -> Result {
let share = self.0.make_decryption_share_simple(
- ciphertext,
+ &ciphertext_header.0,
aad,
&validator_keypair.decryption_key,
dkg.0.me.share_index,
@@ -458,14 +475,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<_> =
@@ -490,7 +503,7 @@ mod test_ferveo_api {
aggregate
.create_decryption_share_precomputed(
&dkg,
- &ciphertext,
+ &ciphertext.header().unwrap(),
aad,
validator_keypair,
)
@@ -557,14 +570,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<_> =
@@ -587,7 +595,7 @@ mod test_ferveo_api {
aggregate
.create_decryption_share_simple(
&dkg,
- &ciphertext,
+ &ciphertext.header().unwrap(),
aad,
validator_keypair,
)
diff --git a/ferveo/src/bindings_python.rs b/ferveo/src/bindings_python.rs
index 3cc88202..ed965f3e 100644
--- a/ferveo/src/bindings_python.rs
+++ b/ferveo/src/bindings_python.rs
@@ -509,8 +509,38 @@ impl Dkg {
)]
pub struct Ciphertext(api::Ciphertext);
+#[pymethods]
+impl Ciphertext {
+ #[getter]
+ pub fn header(&self) -> PyResult {
+ let header = self.0.header().map_err(FerveoPythonError::from)?;
+ Ok(CiphertextHeader(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);
@@ -555,7 +585,7 @@ impl AggregatedTranscript {
pub fn create_decryption_share_precomputed(
&self,
dkg: &Dkg,
- ciphertext: &Ciphertext,
+ ciphertext_header: &CiphertextHeader,
aad: &[u8],
validator_keypair: &Keypair,
) -> PyResult {
@@ -563,7 +593,7 @@ impl AggregatedTranscript {
.0
.create_decryption_share_precomputed(
&dkg.0,
- &ciphertext.0,
+ &ciphertext_header.0,
aad,
&validator_keypair.0,
)
@@ -574,7 +604,7 @@ impl AggregatedTranscript {
pub fn create_decryption_share_simple(
&self,
dkg: &Dkg,
- ciphertext: &Ciphertext,
+ ciphertext_header: &CiphertextHeader,
aad: &[u8],
validator_keypair: &Keypair,
) -> PyResult {
@@ -582,7 +612,7 @@ impl AggregatedTranscript {
.0
.create_decryption_share_simple(
&dkg.0,
- &ciphertext.0,
+ &ciphertext_header.0,
aad,
&validator_keypair.0,
)
@@ -628,6 +658,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::()?;
@@ -712,7 +743,7 @@ mod test_ferveo_python {
.iter()
.enumerate()
.map(|(i, keypair)| {
- Validator::new(format!("0x{:040}", i), &keypair.public_key())
+ Validator::new(format!("0x{i:040}"), &keypair.public_key())
.unwrap()
})
.collect();
@@ -799,7 +830,7 @@ mod test_ferveo_python {
aggregate
.create_decryption_share_precomputed(
&dkg,
- &ciphertext,
+ &ciphertext.header().unwrap(),
aad,
validator_keypair,
)
@@ -876,7 +907,7 @@ mod test_ferveo_python {
aggregate
.create_decryption_share_simple(
&dkg,
- &ciphertext,
+ &ciphertext.header().unwrap(),
aad,
validator_keypair,
)
diff --git a/ferveo/src/bindings_wasm.rs b/ferveo/src/bindings_wasm.rs
index b31866c4..e686f8a9 100644
--- a/ferveo/src/bindings_wasm.rs
+++ b/ferveo/src/bindings_wasm.rs
@@ -229,8 +229,36 @@ generate_boxed_bytes_serialization!(FerveoPublicKey, InnerPublicKey);
)]
pub struct Ciphertext(api::Ciphertext);
+#[wasm_bindgen]
+impl Ciphertext {
+ #[wasm_bindgen(js_name = "header", getter)]
+ pub fn header(&self) -> JsResult {
+ let header = self.0.header().map_err(map_js_err)?;
+ Ok(CiphertextHeader(header))
+ }
+
+ #[wasm_bindgen(js_name = "payload", getter)]
+ pub fn payload(&self) -> Vec {
+ self.0.payload()
+ }
+}
+
generate_common_methods!(Ciphertext);
+#[wasm_bindgen]
+#[derive(
+ Clone,
+ Debug,
+ PartialEq,
+ Eq,
+ derive_more::From,
+ derive_more::AsRef,
+ derive_more::Into,
+)]
+pub struct CiphertextHeader(api::CiphertextHeader);
+
+generate_common_methods!(CiphertextHeader);
+
#[wasm_bindgen(js_name = "ferveoEncrypt")]
pub fn ferveo_encrypt(
message: &[u8],
@@ -497,7 +525,7 @@ impl AggregatedTranscript {
pub fn create_decryption_share_precomputed(
&self,
dkg: &Dkg,
- ciphertext: &Ciphertext,
+ ciphertext_header: &CiphertextHeader,
aad: &[u8],
validator_keypair: &Keypair,
) -> JsResult {
@@ -506,7 +534,7 @@ impl AggregatedTranscript {
.0
.create_decryption_share_precomputed(
&dkg.0,
- &ciphertext.0,
+ &ciphertext_header.0,
aad,
&validator_keypair.0,
)
@@ -518,7 +546,7 @@ impl AggregatedTranscript {
pub fn create_decryption_share_simple(
&self,
dkg: &Dkg,
- ciphertext: &Ciphertext,
+ ciphertext_header: &CiphertextHeader,
aad: &[u8],
validator_keypair: &Keypair,
) -> JsResult {
@@ -527,7 +555,7 @@ impl AggregatedTranscript {
.0
.create_decryption_share_simple(
&dkg.0,
- &ciphertext.0,
+ &ciphertext_header.0,
aad,
&validator_keypair.0,
)
diff --git a/ferveo/src/dkg.rs b/ferveo/src/dkg.rs
index 07dee015..ed183b72 100644
--- a/ferveo/src/dkg.rs
+++ b/ferveo/src/dkg.rs
@@ -333,7 +333,7 @@ pub(crate) mod test_common {
}
pub fn gen_address(i: usize) -> EthereumAddress {
- EthereumAddress::from_str(&format!("0x{:040}", i)).unwrap()
+ EthereumAddress::from_str(&format!("0x{i:040}")).unwrap()
}
pub fn gen_validators(keypairs: &[Keypair]) -> Vec> {
diff --git a/ferveo/src/lib.rs b/ferveo/src/lib.rs
index 214f9444..1ddd54e0 100644
--- a/ferveo/src/lib.rs
+++ b/ferveo/src/lib.rs
@@ -127,8 +127,8 @@ mod test_dkg_full {
use ferveo_common::Keypair;
use group_threshold_cryptography as tpke;
use group_threshold_cryptography::{
- Ciphertext, DecryptionSharePrecomputed, DecryptionShareSimple,
- SecretBox, SharedSecret,
+ DecryptionSharePrecomputed, DecryptionShareSimple, SecretBox,
+ SharedSecret,
};
use itertools::izip;
@@ -140,7 +140,7 @@ mod test_dkg_full {
fn make_shared_secret_simple_tdec(
dkg: &PubliclyVerifiableDkg,
aad: &[u8],
- ciphertext: &Ciphertext,
+ ciphertext_header: &tpke::CiphertextHeader,
validator_keypairs: &[Keypair],
) -> (
PubliclyVerifiableSS,
@@ -159,7 +159,7 @@ mod test_dkg_full {
.unwrap();
pvss_aggregated
.make_decryption_share_simple(
- ciphertext,
+ ciphertext_header,
aad,
&validator_keypair.decryption_key,
validator.share_index,
@@ -211,7 +211,7 @@ mod test_dkg_full {
let (_, _, shared_secret) = make_shared_secret_simple_tdec(
&dkg,
aad,
- &ciphertext,
+ &ciphertext.header().unwrap(),
&validator_keypairs,
);
@@ -264,7 +264,7 @@ mod test_dkg_full {
.unwrap();
pvss_aggregated
.make_decryption_share_simple_precomputed(
- &ciphertext,
+ &ciphertext.header().unwrap(),
aad,
&validator_keypair.decryption_key,
validator.share_index,
@@ -307,7 +307,7 @@ mod test_dkg_full {
make_shared_secret_simple_tdec(
&dkg,
aad,
- &ciphertext,
+ &ciphertext.header().unwrap(),
&validator_keypairs,
);
@@ -367,7 +367,7 @@ mod test_dkg_full {
let (_, _, old_shared_secret) = make_shared_secret_simple_tdec(
&dkg,
aad,
- &ciphertext,
+ &ciphertext.header().unwrap(),
&validator_keypairs,
);
@@ -443,7 +443,7 @@ mod test_dkg_full {
.map(|(share_index, validator_keypair)| {
pvss_aggregated
.make_decryption_share_simple(
- &ciphertext,
+ &ciphertext.header().unwrap(),
aad,
&validator_keypair.decryption_key,
share_index,
@@ -459,7 +459,7 @@ mod test_dkg_full {
DecryptionShareSimple::create(
&new_validator_decryption_key,
&new_private_key_share,
- &ciphertext,
+ &ciphertext.header().unwrap(),
aad,
&dkg.pvss_params.g_inv(),
)
@@ -491,7 +491,7 @@ mod test_dkg_full {
let (_, _, old_shared_secret) = make_shared_secret_simple_tdec(
&dkg,
aad,
- &ciphertext,
+ &ciphertext.header().unwrap(),
&validator_keypairs,
);
@@ -514,7 +514,7 @@ mod test_dkg_full {
.map(|(validator_address, validator_keypair)| {
pvss_aggregated
.refresh_decryption_share(
- &ciphertext,
+ &ciphertext.header().unwrap(),
aad,
&validator_keypair.decryption_key,
validator_address,
diff --git a/ferveo/src/pvss.rs b/ferveo/src/pvss.rs
index 0d6433fd..547bb16c 100644
--- a/ferveo/src/pvss.rs
+++ b/ferveo/src/pvss.rs
@@ -14,7 +14,7 @@ use serde_with::serde_as;
use subproductdomain::fast_multiexp;
use tpke::{
prepare_combine_simple, refresh_private_key_share,
- update_share_for_recovery, Ciphertext, DecryptionSharePrecomputed,
+ update_share_for_recovery, CiphertextHeader, DecryptionSharePrecomputed,
DecryptionShareSimple, PrivateKeyShare,
};
use zeroize::{self, Zeroize, ZeroizeOnDrop};
@@ -329,7 +329,7 @@ impl PubliclyVerifiableSS {
pub fn make_decryption_share_simple(
&self,
- ciphertext: &Ciphertext,
+ ciphertext: &CiphertextHeader,
aad: &[u8],
validator_decryption_key: &E::ScalarField,
share_index: usize,
@@ -349,7 +349,7 @@ impl PubliclyVerifiableSS {
pub fn make_decryption_share_simple_precomputed(
&self,
- ciphertext: &Ciphertext,
+ ciphertext_header: &CiphertextHeader,
aad: &[u8],
validator_decryption_key: &E::ScalarField,
share_index: usize,
@@ -366,7 +366,7 @@ impl PubliclyVerifiableSS {
share_index,
validator_decryption_key,
&private_key_share,
- ciphertext,
+ ciphertext_header,
aad,
&lagrange_coeffs[share_index],
g_inv,
@@ -376,7 +376,7 @@ impl PubliclyVerifiableSS {
pub fn refresh_decryption_share(
&self,
- ciphertext: &Ciphertext,
+ ciphertext_header: &CiphertextHeader,
aad: &[u8],
validator_decryption_key: &E::ScalarField,
share_index: usize,
@@ -396,7 +396,7 @@ impl PubliclyVerifiableSS {
DecryptionShareSimple::create(
validator_decryption_key,
&refreshed_private_key_share,
- ciphertext,
+ ciphertext_header,
aad,
&dkg.pvss_params.g_inv(),
)
diff --git a/tpke/benches/tpke.rs b/tpke/benches/tpke.rs
index 89fef191..c6ad85ae 100644
--- a/tpke/benches/tpke.rs
+++ b/tpke/benches/tpke.rs
@@ -118,7 +118,11 @@ impl SetupSimple {
// Creating decryption shares
let decryption_shares: Vec<_> = contexts
.iter()
- .map(|context| context.create_share(&ciphertext, aad).unwrap())
+ .map(|context| {
+ context
+ .create_share(&ciphertext.header().unwrap(), aad)
+ .unwrap()
+ })
.collect();
let pub_contexts = contexts[0].clone().public_decryption_contexts;
@@ -190,7 +194,7 @@ pub fn bench_create_decryption_share(c: &mut Criterion) {
DecryptionShareSimple::create_unchecked(
&ctx.validator_private_key,
&ctx.private_key_share,
- &setup.shared.ciphertext,
+ &setup.shared.ciphertext.header().unwrap(),
)
})
.collect::>()
@@ -206,7 +210,7 @@ pub fn bench_create_decryption_share(c: &mut Criterion) {
.iter()
.map(|context| {
context.create_share_precomputed(
- &setup.shared.ciphertext,
+ &setup.shared.ciphertext.header().unwrap(),
&setup.shared.aad,
)
})
@@ -301,7 +305,7 @@ pub fn bench_share_combine(c: &mut Criterion) {
.map(|context| {
context
.create_share_precomputed(
- &setup.shared.ciphertext,
+ &setup.shared.ciphertext.header().unwrap(),
&setup.shared.aad,
)
.unwrap()
diff --git a/tpke/src/api.rs b/tpke/src/api.rs
index 3ebba690..3e283d77 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;
@@ -11,6 +12,8 @@ pub type PrivateDecryptionContextSimple =
pub type DecryptionSharePrecomputed = crate::DecryptionSharePrecomputed;
pub type DecryptionShareSimple = crate::DecryptionShareSimple;
pub type Ciphertext = crate::Ciphertext;
+
+pub type CiphertextHeader = crate::CiphertextHeader;
pub type TargetField = ::TargetField;
pub use crate::{
diff --git a/tpke/src/ciphertext.rs b/tpke/src/ciphertext.rs
index f7137dbc..81f79389 100644
--- a/tpke/src/ciphertext.rs
+++ b/tpke/src/ciphertext.rs
@@ -32,17 +32,47 @@ pub struct Ciphertext {
}
impl Ciphertext {
+ pub fn check(&self, aad: &[u8], g_inv: &E::G1Prepared) -> Result {
+ self.header()?.check(aad, g_inv)
+ }
+
+ pub fn ciphertext_hash(&self) -> [u8; 32] {
+ sha256(&self.ciphertext)
+ }
+
+ pub fn header(&self) -> Result> {
+ Ok(CiphertextHeader {
+ commitment: self.commitment,
+ auth_tag: self.auth_tag,
+ ciphertext_hash: self.ciphertext_hash(),
+ })
+ }
+ pub fn payload(&self) -> Vec {
+ self.ciphertext.clone()
+ }
+}
+
+#[serde_as]
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
+pub struct CiphertextHeader {
+ #[serde_as(as = "serialization::SerdeAs")]
+ pub commitment: E::G1Affine,
+ #[serde_as(as = "serialization::SerdeAs")]
+ pub auth_tag: E::G2Affine,
+ pub ciphertext_hash: [u8; 32],
+}
+
+impl CiphertextHeader {
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)'
+ // '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_digest, aad)
- let ciphertext_hash = sha256(&self.ciphertext[..]);
let hash_g2 = E::G2Prepared::from(construct_tag_hash::(
self.commitment,
- &ciphertext_hash,
+ &self.ciphertext_hash,
aad,
)?);
@@ -152,11 +182,11 @@ pub fn decrypt_with_shared_secret(
decrypt_with_shared_secret_unchecked(ciphertext, aad, 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(
diff --git a/tpke/src/context.rs b/tpke/src/context.rs
index 4a471925..32fa91fb 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::{
- prepare_combine_simple, BlindedKeyShare, Ciphertext, DecryptionShareFast,
- DecryptionSharePrecomputed, DecryptionShareSimple, PrivateKeyShare,
- PublicKeyShare, Result,
+ prepare_combine_simple, BlindedKeyShare, Ciphertext, CiphertextHeader,
+ DecryptionShareFast, DecryptionSharePrecomputed, DecryptionShareSimple,
+ PrivateKeyShare, PublicKeyShare, Result,
};
#[derive(Clone, Debug)]
@@ -78,13 +78,13 @@ pub struct PrivateDecryptionContextSimple {
impl PrivateDecryptionContextSimple {
pub fn create_share(
&self,
- ciphertext: &Ciphertext,
+ ciphertext_header: &CiphertextHeader,
aad: &[u8],
) -> Result> {
DecryptionShareSimple::create(
&self.validator_private_key,
&self.private_key_share,
- ciphertext,
+ ciphertext_header,
aad,
&self.setup_params.g_inv,
)
@@ -92,7 +92,7 @@ impl PrivateDecryptionContextSimple {
pub fn create_share_precomputed(
&self,
- ciphertext: &Ciphertext,
+ ciphertext_header: &CiphertextHeader,
aad: &[u8],
) -> Result> {
let domain = self
@@ -106,7 +106,7 @@ impl PrivateDecryptionContextSimple {
self.index,
&self.validator_private_key,
&self.private_key_share,
- ciphertext,
+ ciphertext_header,
aad,
&lagrange_coeffs[self.index],
&self.setup_params.g_inv,
diff --git a/tpke/src/decryption.rs b/tpke/src/decryption.rs
index ad319783..01ae5df7 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::{
- generate_random, Ciphertext, PrivateKeyShare, PublicDecryptionContextFast,
- PublicDecryptionContextSimple, Result,
+ generate_random, Ciphertext, CiphertextHeader, PrivateKeyShare,
+ PublicDecryptionContextFast, PublicDecryptionContextSimple, Result,
};
#[serde_as]
@@ -31,10 +31,10 @@ pub struct ValidatorShareChecksum {
impl ValidatorShareChecksum {
pub fn new(
validator_decryption_key: &E::ScalarField,
- ciphertext: &Ciphertext,
+ ciphertext_header: &CiphertextHeader,
) -> Result {
// C_i = dk_i^{-1} * U
- let checksum = ciphertext
+ let checksum = ciphertext_header
.commitment
// TODO: Should we panic here? I think we should since that would mean that the decryption key is invalid.
// And so, the validator should not be able to create a decryption share.
@@ -90,15 +90,15 @@ impl DecryptionShareSimple {
pub fn create(
validator_decryption_key: &E::ScalarField,
private_key_share: &PrivateKeyShare,
- ciphertext: &Ciphertext,
+ ciphertext_header: &CiphertextHeader,
aad: &[u8],
g_inv: &E::G1Prepared,
) -> Result {
- ciphertext.check(aad, g_inv)?;
+ ciphertext_header.check(aad, g_inv)?;
Self::create_unchecked(
validator_decryption_key,
private_key_share,
- ciphertext,
+ ciphertext_header,
)
}
@@ -107,17 +107,19 @@ impl DecryptionShareSimple {
pub fn create_unchecked(
validator_decryption_key: &E::ScalarField,
private_key_share: &PrivateKeyShare,
- ciphertext: &Ciphertext,
+ ciphertext_header: &CiphertextHeader,
) -> Result {
// D_i = e(U, Z_i)
let decryption_share = E::pairing(
- ciphertext.commitment,
+ ciphertext_header.commitment,
private_key_share.private_key_share,
)
.0;
- let validator_checksum =
- ValidatorShareChecksum::new(validator_decryption_key, ciphertext)?;
+ let validator_checksum = ValidatorShareChecksum::new(
+ validator_decryption_key,
+ ciphertext_header,
+ )?;
Ok(Self {
decryption_share,
@@ -160,17 +162,17 @@ impl DecryptionSharePrecomputed {
validator_index: usize,
validator_decryption_key: &E::ScalarField,
private_key_share: &PrivateKeyShare,
- ciphertext: &Ciphertext,
+ ciphertext_header: &CiphertextHeader,
aad: &[u8],
lagrange_coeff: &E::ScalarField,
g_inv: &E::G1Prepared,
) -> Result {
- ciphertext.check(aad, g_inv)?;
+ ciphertext_header.check(aad, g_inv)?;
Self::create_unchecked(
validator_index,
validator_decryption_key,
private_key_share,
- ciphertext,
+ ciphertext_header,
lagrange_coeff,
)
}
@@ -179,11 +181,12 @@ impl DecryptionSharePrecomputed {
validator_index: usize,
validator_decryption_key: &E::ScalarField,
private_key_share: &PrivateKeyShare,
- ciphertext: &Ciphertext,
+ ciphertext_header: &CiphertextHeader,
lagrange_coeff: &E::ScalarField,
) -> Result {
// U_{λ_i} = [λ_{i}(0)] U
- let u_to_lagrange_coeff = ciphertext.commitment.mul(lagrange_coeff);
+ let u_to_lagrange_coeff =
+ ciphertext_header.commitment.mul(lagrange_coeff);
// C_{λ_i} = e(U_{λ_i}, Z_i)
let decryption_share = E::pairing(
u_to_lagrange_coeff,
@@ -191,8 +194,10 @@ impl DecryptionSharePrecomputed {
)
.0;
- let validator_checksum =
- ValidatorShareChecksum::new(validator_decryption_key, ciphertext)?;
+ let validator_checksum = ValidatorShareChecksum::new(
+ validator_decryption_key,
+ ciphertext_header,
+ )?;
Ok(Self {
decrypter_index: validator_index,
diff --git a/tpke/src/lib.rs b/tpke/src/lib.rs
index 651935ae..46a78f24 100644
--- a/tpke/src/lib.rs
+++ b/tpke/src/lib.rs
@@ -309,7 +309,9 @@ mod tests {
) -> SharedSecret {
let decryption_shares: Vec<_> = contexts
.iter()
- .map(|c| c.create_share(ciphertext, aad).unwrap())
+ .map(|c| {
+ c.create_share(&ciphertext.header().unwrap(), aad).unwrap()
+ })
.collect();
make_shared_secret(
&contexts[0].public_decryption_contexts,
@@ -459,7 +461,9 @@ mod tests {
encrypt::(SecretBox::new(msg), aad, &pubkey, rng).unwrap();
let bad_aad = "bad aad".as_bytes();
- assert!(contexts[0].create_share(&ciphertext, bad_aad).is_err());
+ assert!(contexts[0]
+ .create_share(&ciphertext.header().unwrap(), bad_aad)
+ .is_err());
}
#[test]
@@ -531,7 +535,9 @@ mod tests {
// We need at least threshold shares to decrypt
let decryption_shares: Vec<_> = contexts
.iter()
- .map(|c| c.create_share(&ciphertext, aad).unwrap())
+ .map(|c| {
+ c.create_share(&ciphertext.header().unwrap(), aad).unwrap()
+ })
.take(threshold)
.collect();
let pub_contexts =
@@ -575,7 +581,12 @@ mod tests {
let decryption_shares: Vec<_> = contexts
.iter()
.map(|context| {
- context.create_share_precomputed(&ciphertext, aad).unwrap()
+ context
+ .create_share_precomputed(
+ &ciphertext.header().unwrap(),
+ aad,
+ )
+ .unwrap()
})
.collect();
@@ -620,7 +631,9 @@ mod tests {
let decryption_shares: Vec<_> = contexts
.iter()
- .map(|c| c.create_share(&ciphertext, aad).unwrap())
+ .map(|c| {
+ c.create_share(&ciphertext.header().unwrap(), aad).unwrap()
+ })
.collect();
// In simple tDec variant, we verify decryption shares only after decryption fails.
@@ -772,7 +785,9 @@ mod tests {
// Get decryption shares from remaining participants
let mut decryption_shares: Vec<_> = remaining_participants
.iter()
- .map(|c| c.create_share(&ciphertext, aad).unwrap())
+ .map(|c| {
+ c.create_share(&ciphertext.header().unwrap(), aad).unwrap()
+ })
.collect();
// Create a decryption share from a recovered private key share
@@ -781,7 +796,7 @@ mod tests {
DecryptionShareSimple::create(
&new_validator_decryption_key,
&new_private_key_share,
- &ciphertext,
+ &ciphertext.header().unwrap(),
aad,
g_inv,
)
@@ -845,7 +860,7 @@ mod tests {
DecryptionShareSimple::create(
&p.validator_private_key,
&private_key_share,
- &ciphertext,
+ &ciphertext.header().unwrap(),
aad,
g_inv,
)
From 191b81fc6ea0d62be671c4456e3d82c567447acd Mon Sep 17 00:00:00 2001
From: piotr-roslaniec <39299780+piotr-roslaniec@users.noreply.github.com>
Date: Mon, 21 Aug 2023 17:35:46 +0200
Subject: [PATCH 2/3] Update ferveo-python/ferveo/__init__.pyi
Co-authored-by: Derek Pierre
---
ferveo-python/ferveo/__init__.pyi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ferveo-python/ferveo/__init__.pyi b/ferveo-python/ferveo/__init__.pyi
index 3549d751..ff17fd19 100644
--- a/ferveo-python/ferveo/__init__.pyi
+++ b/ferveo-python/ferveo/__init__.pyi
@@ -133,7 +133,7 @@ class Ciphertext:
@final
class CiphertextHeader:
@staticmethod
- def from_bytes(data: bytes) -> Ciphertext:
+ def from_bytes(data: bytes) -> CiphertextHeader:
...
def __bytes__(self) -> bytes:
From c06217c06e16df17d0525027312d5c368f443cb6 Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Wed, 23 Aug 2023 16:21:41 +0200
Subject: [PATCH 3/3] apply pr suggestions
---
ferveo/src/api.rs | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/ferveo/src/api.rs b/ferveo/src/api.rs
index 16ede060..b2179ee6 100644
--- a/ferveo/src/api.rs
+++ b/ferveo/src/api.rs
@@ -394,7 +394,7 @@ pub struct SharedSecret(pub tpke::api::SharedSecret);
#[cfg(test)]
mod test_ferveo_api {
use itertools::izip;
- use rand::{prelude::StdRng, thread_rng, SeedableRng};
+ use rand::{prelude::StdRng, SeedableRng};
use tpke::SecretBox;
use crate::{api::*, dkg::test_common::*};
@@ -475,7 +475,6 @@ 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 =
encrypt(SecretBox::new(msg.clone()), aad, &dkg_public_key)
.unwrap();
@@ -570,7 +569,6 @@ 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 =
encrypt(SecretBox::new(msg.clone()), aad, &public_key).unwrap();