From d5ec5e0f9d1303e51a805c4dafbab7ed2efcb7be Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Thu, 6 Jul 2023 13:41:46 +0200
Subject: [PATCH] fix using bad number of domain points
---
ferveo/src/api.rs | 9 +-
ferveo/src/lib.rs | 170 +++++++++++++++++++-----------------
ferveo/src/pvss.rs | 2 +
subproductdomain/src/lib.rs | 4 +-
tpke/src/combine.rs | 3 +-
tpke/src/decryption.rs | 1 -
tpke/src/lib.rs | 12 ++-
7 files changed, 114 insertions(+), 87 deletions(-)
diff --git a/ferveo/src/api.rs b/ferveo/src/api.rs
index 47e28a7d..8f5ebe87 100644
--- a/ferveo/src/api.rs
+++ b/ferveo/src/api.rs
@@ -238,7 +238,12 @@ impl AggregatedTranscript {
aad: &[u8],
validator_keypair: &Keypair,
) -> Result {
- let domain_points: Vec<_> = dkg.0.domain.elements().collect();
+ let domain_points: Vec<_> = dkg
+ .0
+ .domain
+ .elements()
+ .take(dkg.0.dkg_params.shares_num as usize)
+ .collect();
self.0.make_decryption_share_simple_precomputed(
ciphertext,
aad,
@@ -428,6 +433,8 @@ mod test_ferveo_api {
assert!(pvss_aggregated
.verify(shares_num, &messages)
.unwrap());
+
+ // And then each validator creates their own decryption share
aggregate
.create_decryption_share_precomputed(
&dkg,
diff --git a/ferveo/src/lib.rs b/ferveo/src/lib.rs
index c520b3f3..0a225536 100644
--- a/ferveo/src/lib.rs
+++ b/ferveo/src/lib.rs
@@ -166,17 +166,17 @@ mod test_dkg_full {
})
.collect();
- let domain = &dkg
+ let domain_points = &dkg
.domain
.elements()
.take(decryption_shares.len())
.collect::>();
- assert_eq!(domain.len(), decryption_shares.len());
+ assert_eq!(domain_points.len(), decryption_shares.len());
// TODO: Consider refactor this part into tpke::combine_simple and expose it
// as a public API in tpke::api
- let lagrange_coeffs = tpke::prepare_combine_simple::(domain);
+ let lagrange_coeffs = tpke::prepare_combine_simple::(domain_points);
let shared_secret = tpke::share_combine_simple::(
&decryption_shares,
&lagrange_coeffs,
@@ -189,89 +189,103 @@ mod test_dkg_full {
fn test_dkg_simple_tdec() {
let rng = &mut test_rng();
- let (dkg, validator_keypairs) = setup_dealt_dkg_with_n_validators(3, 4);
- let msg = "my-msg".as_bytes().to_vec();
- let aad: &[u8] = "my-aad".as_bytes();
- let public_key = dkg.public_key();
- let ciphertext = tpke::encrypt::(
- SecretBox::new(msg.clone()),
- aad,
- &public_key,
- rng,
- )
- .unwrap();
+ // Works for both power of 2 and non-power of 2
+ for shares_num in [4, 7] {
+ let threshold = shares_num / 2 + 1;
+ let (dkg, validator_keypairs) =
+ setup_dealt_dkg_with_n_validators(threshold, shares_num);
+ let msg = "my-msg".as_bytes().to_vec();
+ let aad: &[u8] = "my-aad".as_bytes();
+ let public_key = dkg.public_key();
+ let ciphertext = tpke::encrypt::(
+ SecretBox::new(msg.clone()),
+ aad,
+ &public_key,
+ rng,
+ )
+ .unwrap();
- let (_, _, shared_secret) = make_shared_secret_simple_tdec(
- &dkg,
- aad,
- &ciphertext,
- &validator_keypairs,
- );
+ let (_, _, shared_secret) = make_shared_secret_simple_tdec(
+ &dkg,
+ aad,
+ &ciphertext,
+ &validator_keypairs,
+ );
- let plaintext = tpke::decrypt_with_shared_secret(
- &ciphertext,
- aad,
- &shared_secret,
- &dkg.pvss_params.g_inv(),
- )
- .unwrap();
- assert_eq!(plaintext, msg);
+ let plaintext = tpke::decrypt_with_shared_secret(
+ &ciphertext,
+ aad,
+ &shared_secret,
+ &dkg.pvss_params.g_inv(),
+ )
+ .unwrap();
+ assert_eq!(plaintext, msg);
+ }
}
#[test]
fn test_dkg_simple_tdec_precomputed() {
let rng = &mut test_rng();
- let (dkg, validator_keypairs) = setup_dealt_dkg_with_n_validators(3, 4);
- let msg = "my-msg".as_bytes().to_vec();
- let aad: &[u8] = "my-aad".as_bytes();
- let public_key = dkg.public_key();
- let ciphertext = tpke::encrypt::(
- SecretBox::new(msg.clone()),
- aad,
- &public_key,
- rng,
- )
- .unwrap();
-
- let pvss_aggregated = aggregate(&dkg.vss);
- pvss_aggregated.verify_aggregation(&dkg).unwrap();
- let domain_points = dkg
- .domain
- .elements()
- .take(validator_keypairs.len())
- .collect::>();
-
- let decryption_shares: Vec> =
- validator_keypairs
- .iter()
- .enumerate()
- .map(|(validator_address, validator_keypair)| {
- pvss_aggregated
- .make_decryption_share_simple_precomputed(
- &ciphertext,
- aad,
- &validator_keypair.decryption_key,
- validator_address,
- &domain_points,
- &dkg.pvss_params.g_inv(),
- )
- .unwrap()
- })
- .collect();
-
- let shared_secret =
- tpke::share_combine_precomputed::(&decryption_shares);
-
- // Combination works, let's decrypt
- let plaintext = tpke::decrypt_with_shared_secret(
- &ciphertext,
- aad,
- &shared_secret,
- &dkg.pvss_params.g_inv(),
- )
- .unwrap();
- assert_eq!(plaintext, msg);
+ // Works for both power of 2 and non-power of 2
+ for shares_num in [4, 7] {
+ // In precomputed variant, threshold must be equal to shares_num
+ let threshold = shares_num;
+ let (dkg, validator_keypairs) =
+ setup_dealt_dkg_with_n_validators(threshold, shares_num);
+ let msg = "my-msg".as_bytes().to_vec();
+ let aad: &[u8] = "my-aad".as_bytes();
+ let public_key = dkg.public_key();
+ let ciphertext = tpke::encrypt::(
+ SecretBox::new(msg.clone()),
+ aad,
+ &public_key,
+ rng,
+ )
+ .unwrap();
+
+ let pvss_aggregated = aggregate(&dkg.vss);
+ pvss_aggregated.verify_aggregation(&dkg).unwrap();
+ let domain_points = dkg
+ .domain
+ .elements()
+ .take(validator_keypairs.len())
+ .collect::>();
+
+ let decryption_shares: Vec> =
+ validator_keypairs
+ .iter()
+ .map(|validator_keypair| {
+ let validator = dkg
+ .get_validator(&validator_keypair.public_key())
+ .unwrap();
+ pvss_aggregated
+ .make_decryption_share_simple_precomputed(
+ &ciphertext,
+ aad,
+ &validator_keypair.decryption_key,
+ validator.share_index,
+ &domain_points,
+ &dkg.pvss_params.g_inv(),
+ )
+ .unwrap()
+ })
+ .collect();
+ assert_eq!(domain_points.len(), decryption_shares.len());
+
+ let shared_secret =
+ tpke::share_combine_precomputed::(&decryption_shares);
+
+ // Combination works, let's decrypt
+ let plaintext = tpke::decrypt_with_shared_secret(
+ &ciphertext,
+ aad,
+ &shared_secret,
+ &dkg.pvss_params.g_inv(),
+ )
+ .unwrap();
+ assert_eq!(plaintext, msg);
+ }
}
#[test]
diff --git a/ferveo/src/pvss.rs b/ferveo/src/pvss.rs
index 50c7066c..cfc47925 100644
--- a/ferveo/src/pvss.rs
+++ b/ferveo/src/pvss.rs
@@ -346,6 +346,7 @@ impl PubliclyVerifiableSS {
)
.map_err(|e| e.into())
}
+
pub fn make_decryption_share_simple_precomputed(
&self,
ciphertext: &Ciphertext,
@@ -358,6 +359,7 @@ impl PubliclyVerifiableSS {
let private_key_share = self
.decrypt_private_key_share(validator_decryption_key, share_index);
+ // We use the `prepare_combine_simple` function to precompute the lagrange coefficients
let lagrange_coeffs = prepare_combine_simple::(domain_points);
DecryptionSharePrecomputed::new(
diff --git a/subproductdomain/src/lib.rs b/subproductdomain/src/lib.rs
index 63dd11cf..d1bc5fd0 100644
--- a/subproductdomain/src/lib.rs
+++ b/subproductdomain/src/lib.rs
@@ -9,7 +9,7 @@ use ark_ec::{
use ark_ff::{FftField, Field, Zero};
use ark_poly::{
univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain,
- Polynomial, Radix2EvaluationDomain,
+ MixedRadixEvaluationDomain, Polynomial,
};
/// Compute a fast multiexp of many scalars times the same base
@@ -342,7 +342,7 @@ pub fn toeplitz_mul(
let m = polynomial.coeffs.len() - 1;
let size = ark_std::cmp::max(size, m);
- let domain = Radix2EvaluationDomain::::new(2 * size)
+ let domain = MixedRadixEvaluationDomain::::new(2 * size)
.ok_or_else(|| {
anyhow::anyhow!("toeplitz multiplication on too large a domain")
})?;
diff --git a/tpke/src/combine.rs b/tpke/src/combine.rs
index 39091e88..dced0df5 100644
--- a/tpke/src/combine.rs
+++ b/tpke/src/combine.rs
@@ -161,7 +161,8 @@ mod tests {
use ark_poly::EvaluationDomain;
use ark_std::One;
let fft_domain =
- ark_poly::Radix2EvaluationDomain::::new(500).unwrap();
+ ark_poly::MixedRadixEvaluationDomain::::new(500)
+ .unwrap();
let mut domain = Vec::with_capacity(500);
let mut point = ScalarField::one();
diff --git a/tpke/src/decryption.rs b/tpke/src/decryption.rs
index 9eb62471..c3b85eb5 100644
--- a/tpke/src/decryption.rs
+++ b/tpke/src/decryption.rs
@@ -166,7 +166,6 @@ impl DecryptionSharePrecomputed {
g_inv: &E::G1Prepared,
) -> Result {
check_ciphertext_validity::(ciphertext, aad, g_inv)?;
-
Self::create_unchecked(
validator_index,
validator_decryption_key,
diff --git a/tpke/src/lib.rs b/tpke/src/lib.rs
index 43ebdaa4..fcd35e9a 100644
--- a/tpke/src/lib.rs
+++ b/tpke/src/lib.rs
@@ -94,8 +94,10 @@ pub mod test_common {
DensePolynomial::::rand(threshold - 1, rng);
// Domain, or omega Ω
let fft_domain =
- ark_poly::Radix2EvaluationDomain::::new(shares_num)
- .unwrap();
+ ark_poly::MixedRadixEvaluationDomain::::new(
+ shares_num,
+ )
+ .unwrap();
// `evals` are evaluations of the polynomial f over the domain, omega: f(ω_j) for ω_j in Ω
let evals = threshold_poly.evaluate_over_domain_by_ref(fft_domain);
@@ -193,8 +195,10 @@ pub mod test_common {
DensePolynomial::::rand(threshold - 1, rng);
// Domain, or omega Ω
let fft_domain =
- ark_poly::Radix2EvaluationDomain::::new(shares_num)
- .unwrap();
+ ark_poly::MixedRadixEvaluationDomain::::new(
+ shares_num,
+ )
+ .unwrap();
// `evals` are evaluations of the polynomial f over the domain, omega: f(ω_j) for ω_j in Ω
let evals = threshold_poly.evaluate_over_domain_by_ref(fft_domain);