From da8614a48c981b842bcaf47f9bfe49321439db9c Mon Sep 17 00:00:00 2001
From: Piotr Roslaniec
Date: Mon, 5 Feb 2024 11:31:35 +0100
Subject: [PATCH] wip
---
ferveo-tdec/benches/tpke.rs | 6 +-
ferveo-tdec/src/ciphertext.rs | 14 ++--
ferveo-tdec/src/decryption.rs | 16 ++++-
ferveo-tdec/src/key_share.rs | 49 +++++++++++---
ferveo-tdec/src/lib.rs | 34 +++++++---
ferveo/src/api.rs | 16 +++--
ferveo/src/dkg.rs | 50 +++++++++-----
ferveo/src/lib.rs | 23 ++++---
ferveo/src/pvss.rs | 33 ++++-----
ferveo/src/refresh.rs | 123 ++++++++++++----------------------
10 files changed, 203 insertions(+), 161 deletions(-)
diff --git a/ferveo-tdec/benches/tpke.rs b/ferveo-tdec/benches/tpke.rs
index 420bf869..0bbba434 100644
--- a/ferveo-tdec/benches/tpke.rs
+++ b/ferveo-tdec/benches/tpke.rs
@@ -1,6 +1,6 @@
#![allow(clippy::redundant_closure)]
-use ark_bls12_381::{Bls12_381, Fr, G1Affine as G1, G2Affine as G2};
+use ark_bls12_381::{Bls12_381, Fr};
use ark_ec::pairing::Pairing;
use criterion::{
black_box, criterion_group, criterion_main, BenchmarkId, Criterion,
@@ -25,8 +25,8 @@ struct SetupShared {
shares_num: usize,
msg: Vec,
aad: Vec,
- pubkey: G1,
- privkey: G2,
+ pubkey: PublicKeyShare,
+ privkey: PrivateKeyShare,
ciphertext: Ciphertext,
shared_secret: SharedSecret,
}
diff --git a/ferveo-tdec/src/ciphertext.rs b/ferveo-tdec/src/ciphertext.rs
index 81f79389..cdaf956c 100644
--- a/ferveo-tdec/src/ciphertext.rs
+++ b/ferveo-tdec/src/ciphertext.rs
@@ -13,7 +13,10 @@ use serde_with::serde_as;
use sha2::{digest::Digest, Sha256};
use zeroize::ZeroizeOnDrop;
-use crate::{htp_bls12381_g2, Error, Result, SecretBox, SharedSecret};
+use crate::{
+ htp_bls12381_g2, Error, PrivateKeyShare, PublicKeyShare, Result, SecretBox,
+ SharedSecret,
+};
#[serde_as]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
@@ -95,7 +98,7 @@ impl CiphertextHeader {
pub fn encrypt(
message: SecretBox>,
aad: &[u8],
- pubkey: &E::G1Affine,
+ pubkey: &PublicKeyShare,
rng: &mut impl rand::Rng,
) -> Result> {
// r
@@ -105,7 +108,8 @@ pub fn encrypt(
// h
let h_gen = E::G2Affine::generator();
- let ry_prep = E::G1Prepared::from(pubkey.mul(rand_element).into());
+ let ry_prep =
+ E::G1Prepared::from(pubkey.public_key_share.mul(rand_element).into());
// s
let product = E::pairing(ry_prep, h_gen).0;
// u
@@ -140,13 +144,13 @@ pub fn encrypt(
pub fn decrypt_symmetric(
ciphertext: &Ciphertext,
aad: &[u8],
- private_key: &E::G2Affine,
+ private_key: &PrivateKeyShare,
g_inv: &E::G1Prepared,
) -> Result> {
ciphertext.check(aad, g_inv)?;
let shared_secret = E::pairing(
E::G1Prepared::from(ciphertext.commitment),
- E::G2Prepared::from(*private_key),
+ E::G2Prepared::from(private_key.private_key_share),
)
.0;
let shared_secret = SharedSecret(shared_secret);
diff --git a/ferveo-tdec/src/decryption.rs b/ferveo-tdec/src/decryption.rs
index 0622e6a8..5c630113 100644
--- a/ferveo-tdec/src/decryption.rs
+++ b/ferveo-tdec/src/decryption.rs
@@ -2,6 +2,7 @@ use std::ops::Mul;
use ark_ec::{pairing::Pairing, CurveGroup};
use ark_ff::{Field, One, Zero};
+use ark_std::UniformRand;
use ferveo_common::serialization;
use itertools::{izip, zip_eq};
use rand_core::RngCore;
@@ -9,8 +10,8 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_with::serde_as;
use crate::{
- generate_random, Ciphertext, CiphertextHeader, PrivateKeyShare,
- PublicDecryptionContextFast, PublicDecryptionContextSimple, Result,
+ Ciphertext, CiphertextHeader, PrivateKeyShare, PublicDecryptionContextFast,
+ PublicDecryptionContextSimple, Result,
};
#[serde_as]
@@ -226,6 +227,15 @@ impl DecryptionSharePrecomputed {
}
}
+pub fn generate_random_scalars(
+ n: usize,
+ rng: &mut R,
+) -> Vec {
+ (0..n)
+ .map(|_| E::ScalarField::rand(rng))
+ .collect::>()
+}
+
// TODO: Remove this code? Currently only used in benchmarks. Move to benchmark suite?
pub fn batch_verify_decryption_shares(
pub_contexts: &[PublicDecryptionContextFast],
@@ -249,7 +259,7 @@ pub fn batch_verify_decryption_shares(
// For each ciphertext, generate num_shares random scalars
let alpha_ij = (0..num_ciphertexts)
- .map(|_| generate_random::<_, E>(num_shares, rng))
+ .map(|_| generate_random_scalars::<_, E>(num_shares, rng))
.collect::>();
let mut pairings_a = Vec::with_capacity(num_shares + 1);
diff --git a/ferveo-tdec/src/key_share.rs b/ferveo-tdec/src/key_share.rs
index 2daaae56..a8c319ae 100644
--- a/ferveo-tdec/src/key_share.rs
+++ b/ferveo-tdec/src/key_share.rs
@@ -1,11 +1,14 @@
use std::ops::Mul;
use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup};
-use ark_ff::One;
+use ark_ff::{One, Zero};
use ark_std::UniformRand;
+use itertools::zip_eq;
use rand_core::RngCore;
use zeroize::ZeroizeOnDrop;
+use crate::lagrange_basis_at;
+
#[derive(Debug, Clone)]
pub struct PublicKeyShare {
pub public_key_share: E::G1Affine, // A_{i, \omega_i}
@@ -18,15 +21,6 @@ pub struct BlindedKeyShare {
pub blinding_key_prepared: E::G2Prepared,
}
-pub fn generate_random(
- n: usize,
- rng: &mut R,
-) -> Vec {
- (0..n)
- .map(|_| E::ScalarField::rand(rng))
- .collect::>()
-}
-
impl BlindedKeyShare {
pub fn verify_blinding(
&self,
@@ -72,4 +66,39 @@ impl PrivateKeyShare {
blinded_key_share: self.private_key_share.mul(b).into_affine(),
}
}
+
+ /// From PSS paper, section 4.2.3, (https://link.springer.com/content/pdf/10.1007/3-540-44750-4_27.pdf)
+ pub fn update_share(
+ &self,
+ share_updates: &[PrivateKeyShareUpdate],
+ ) -> PrivateKeyShare {
+ let updated_key_share = share_updates
+ .iter()
+ .fold(self.private_key_share.into_group(), |acc, delta| {
+ acc + delta.0
+ })
+ .into_affine();
+ PrivateKeyShare {
+ private_key_share: updated_key_share,
+ }
+ }
+
+ /// From the PSS paper, section 4.2.4, (https://link.springer.com/content/pdf/10.1007/3-540-44750-4_27.pdf)
+ pub fn recover_share_from_updated_private_shares(
+ x_r: &E::ScalarField,
+ domain_points: &[E::ScalarField],
+ updated_private_shares: &[PrivateKeyShare],
+ ) -> PrivateKeyShare {
+ // Interpolate new shares to recover y_r
+ let lagrange = lagrange_basis_at::(domain_points, x_r);
+ let prods = zip_eq(updated_private_shares, lagrange)
+ .map(|(y_j, l)| y_j.private_key_share.mul(l));
+ let y_r = prods.fold(E::G2::zero(), |acc, y_j| acc + y_j);
+ PrivateKeyShare {
+ private_key_share: y_r.into_affine(),
+ }
+ }
}
+
+#[derive(Debug, Clone, PartialEq, Eq, ZeroizeOnDrop)]
+pub struct PrivateKeyShareUpdate(pub E::G2Affine);
diff --git a/ferveo-tdec/src/lib.rs b/ferveo-tdec/src/lib.rs
index 297b066c..b5ffed22 100644
--- a/ferveo-tdec/src/lib.rs
+++ b/ferveo-tdec/src/lib.rs
@@ -77,8 +77,8 @@ pub mod test_common {
shares_num: usize,
rng: &mut impl RngCore,
) -> (
- E::G1Affine,
- E::G2Affine,
+ PublicKeyShare,
+ PrivateKeyShare,
Vec>,
) {
assert!(shares_num >= threshold);
@@ -138,7 +138,7 @@ pub mod test_common {
)
.enumerate()
{
- let private_key_share = PrivateKeyShare:: {
+ let private_key_share = PrivateKeyShare {
private_key_share: *private,
};
let b = E::ScalarField::rand(rng);
@@ -171,7 +171,15 @@ pub mod test_common {
private.public_decryption_contexts = public_contexts.clone();
}
- (pubkey.into(), privkey.into(), private_contexts)
+ (
+ PublicKeyShare {
+ public_key_share: pubkey.into(),
+ },
+ PrivateKeyShare {
+ private_key_share: privkey.into(),
+ },
+ private_contexts,
+ )
}
pub fn setup_simple(
@@ -179,8 +187,8 @@ pub mod test_common {
shares_num: usize,
rng: &mut impl rand::Rng,
) -> (
- E::G1Affine,
- E::G2Affine,
+ PublicKeyShare,
+ PrivateKeyShare,
Vec>,
) {
assert!(shares_num >= threshold);
@@ -259,15 +267,23 @@ pub mod test_common {
private.public_decryption_contexts = public_contexts.clone();
}
- (pubkey.into(), privkey.into(), private_contexts)
+ (
+ PublicKeyShare {
+ public_key_share: pubkey.into(),
+ },
+ PrivateKeyShare {
+ private_key_share: privkey.into(),
+ },
+ private_contexts,
+ )
}
pub fn setup_precomputed(
shares_num: usize,
rng: &mut impl rand::Rng,
) -> (
- E::G1Affine,
- E::G2Affine,
+ PublicKeyShare,
+ PrivateKeyShare,
Vec>,
) {
// In precomputed variant, the security threshold is equal to the number of shares
diff --git a/ferveo/src/api.rs b/ferveo/src/api.rs
index caa0d9b4..64037704 100644
--- a/ferveo/src/api.rs
+++ b/ferveo/src/api.rs
@@ -9,6 +9,7 @@ pub use ferveo_tdec::api::{
prepare_combine_simple, share_combine_precomputed, share_combine_simple,
Fr, G1Affine, G1Prepared, G2Affine, SecretBox, E,
};
+use ferveo_tdec::PublicKeyShare;
use generic_array::{
typenum::{Unsigned, U48},
GenericArray,
@@ -58,8 +59,15 @@ pub fn encrypt(
pubkey: &DkgPublicKey,
) -> Result {
let mut rng = rand::thread_rng();
- let ciphertext =
- ferveo_tdec::api::encrypt(message, aad, &pubkey.0, &mut rng)?;
+ let ciphertext = ferveo_tdec::api::encrypt(
+ message,
+ aad,
+ // &pubkey.0,
+ &PublicKeyShare {
+ public_key_share: pubkey.0,
+ },
+ &mut rng,
+ )?;
Ok(Ciphertext(ciphertext))
}
@@ -91,7 +99,7 @@ impl Ciphertext {
}
}
-#[serde_as]
+#[serde_as] // TODO: Redundant serde_as?
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct CiphertextHeader(ferveo_tdec::api::CiphertextHeader);
@@ -218,7 +226,7 @@ impl Dkg {
}
pub fn public_key(&self) -> DkgPublicKey {
- DkgPublicKey(self.0.public_key())
+ DkgPublicKey(self.0.public_key().public_key_share)
}
pub fn generate_transcript(
diff --git a/ferveo/src/dkg.rs b/ferveo/src/dkg.rs
index e8afbe30..b309449e 100644
--- a/ferveo/src/dkg.rs
+++ b/ferveo/src/dkg.rs
@@ -69,9 +69,14 @@ pub type PVSSMap = BTreeMap>;
#[derive(Debug, Clone)]
pub enum DkgState {
// TODO: Do we need to keep track of the block number?
- Sharing { accumulated_shares: u32, block: u32 },
+ Sharing {
+ accumulated_shares: u32,
+ block: u32,
+ },
Dealt,
- Success { public_key: E::G1Affine },
+ Success {
+ public_key: ferveo_tdec::PublicKeyShare,
+ },
Invalid,
}
@@ -178,7 +183,7 @@ impl PubliclyVerifiableDkg {
let pvss_list = self.vss.values().cloned().collect::>();
Ok(Message::Aggregate(Aggregation {
vss: aggregate(&pvss_list)?,
- public_key,
+ public_key: public_key.public_key_share,
}))
}
_ => Err(Error::InvalidDkgStateToAggregate),
@@ -186,12 +191,15 @@ impl PubliclyVerifiableDkg {
}
/// Returns the public key generated by the DKG
- pub fn public_key(&self) -> E::G1Affine {
- self.vss
- .values()
- .map(|vss| vss.coeffs[0].into_group())
- .sum::()
- .into_affine()
+ pub fn public_key(&self) -> ferveo_tdec::PublicKeyShare {
+ ferveo_tdec::PublicKeyShare {
+ public_key_share: self
+ .vss
+ .values()
+ .map(|vss| vss.coeffs[0].into_group())
+ .sum::()
+ .into_affine(),
+ }
}
/// Return a domain point for the share_index
@@ -245,7 +253,7 @@ impl PubliclyVerifiableDkg {
))
} else if vss.verify_aggregation(self).is_err() {
Err(Error::InvalidTranscriptAggregate)
- } else if &self.public_key() == public_key {
+ } else if &self.public_key().public_key_share == public_key {
Ok(())
} else {
Err(Error::InvalidDkgPublicKey)
@@ -382,6 +390,7 @@ mod test_dkg_init {
#[cfg(test)]
mod test_dealing {
use ark_ec::AffineRepr;
+ use ferveo_tdec::PublicKeyShare;
use crate::{
test_common::*, DkgParams, DkgState, DkgState::Dealt, Error,
@@ -587,7 +596,9 @@ mod test_dealing {
));
dkg.state = DkgState::Success {
- public_key: G1::zero(),
+ public_key: PublicKeyShare {
+ public_key_share: G1::zero(),
+ },
};
assert!(dkg.share(rng).is_err());
@@ -614,7 +625,9 @@ mod test_dealing {
let sender = dkg.me.clone();
dkg.state = DkgState::Success {
- public_key: G1::zero(),
+ public_key: PublicKeyShare {
+ public_key_share: G1::zero(),
+ },
};
assert!(dkg.verify_message(&sender, &pvss).is_err());
assert!(dkg.apply_message(&sender, &pvss).is_err());
@@ -631,6 +644,7 @@ mod test_dealing {
#[cfg(test)]
mod test_aggregation {
use ark_ec::AffineRepr;
+ use ferveo_tdec::PublicKeyShare;
use test_case::test_case;
use crate::{dkg::*, test_common::*, DkgState, Message};
@@ -649,7 +663,7 @@ mod test_aggregation {
if let Message::Aggregate(Aggregation { public_key, .. }) =
&aggregate_msg
{
- assert_eq!(public_key, &dkg.public_key());
+ assert_eq!(public_key, &dkg.public_key().public_key_share);
} else {
panic!("Expected aggregate message")
}
@@ -669,7 +683,9 @@ mod test_aggregation {
};
assert!(dkg.aggregate().is_err());
dkg.state = DkgState::Success {
- public_key: G1::zero(),
+ public_key: PublicKeyShare {
+ public_key_share: G1::zero(),
+ },
};
assert!(dkg.aggregate().is_err());
}
@@ -690,7 +706,9 @@ mod test_aggregation {
assert!(dkg.apply_message(&sender, &aggregate).is_err());
dkg.state = DkgState::Success {
- public_key: G1::zero(),
+ public_key: PublicKeyShare {
+ public_key_share: G1::zero(),
+ },
};
assert!(dkg.verify_message(&sender, &aggregate).is_err());
assert!(dkg.apply_message(&sender, &aggregate).is_err())
@@ -713,7 +731,7 @@ mod test_aggregation {
fn test_aggregate_wont_verify_if_wrong_key() {
let (dkg, _) = setup_dealt_dkg();
let mut aggregate = dkg.aggregate().unwrap();
- while dkg.public_key() == G1::zero() {
+ while dkg.public_key().public_key_share == G1::zero() {
let (_dkg, _) = setup_dealt_dkg();
}
if let Message::Aggregate(Aggregation { public_key, .. }) =
diff --git a/ferveo/src/lib.rs b/ferveo/src/lib.rs
index f9d6c1a5..9a002306 100644
--- a/ferveo/src/lib.rs
+++ b/ferveo/src/lib.rs
@@ -136,8 +136,8 @@ mod test_dkg_full {
use ark_std::test_rng;
use ferveo_common::Keypair;
use ferveo_tdec::{
- self, DecryptionSharePrecomputed, DecryptionShareSimple, SecretBox,
- SharedSecret,
+ self, DecryptionSharePrecomputed, DecryptionShareSimple,
+ PrivateKeyShare, SecretBox, SharedSecret,
};
use itertools::izip;
use rand::seq::SliceRandom;
@@ -444,8 +444,9 @@ mod test_dkg_full {
let updates_for_participant: Vec<_> = share_updates
.values()
.map(|updates| {
- *updates.get(validator.share_index as usize).unwrap()
+ updates.get(validator.share_index as usize).unwrap()
})
+ .cloned()
.collect();
// Each validator uses their decryption key to update their share
@@ -471,11 +472,12 @@ mod test_dkg_full {
// TODO: Rename updated_private_shares to something that doesn't imply mutation (see #162, #163)
// Now, we have to combine new share fragments into a new share
- let new_private_key_share = recover_share_from_updated_private_shares(
- &x_r,
- &domain_points,
- &updated_shares,
- );
+ let new_private_key_share =
+ PrivateKeyShare::recover_share_from_updated_private_shares(
+ &x_r,
+ &domain_points,
+ &updated_shares,
+ );
// Get decryption shares from remaining participants
let mut remaining_validator_keypairs = validator_keypairs;
@@ -588,7 +590,10 @@ mod test_dkg_full {
let updates_for_participant: Vec<_> = share_updates
.values()
.map(|updates| {
- *updates.get(validator.share_index as usize).unwrap()
+ updates
+ .get(validator.share_index as usize)
+ .cloned()
+ .unwrap()
})
.collect();
diff --git a/ferveo/src/pvss.rs b/ferveo/src/pvss.rs
index 34695bd3..a29c72b4 100644
--- a/ferveo/src/pvss.rs
+++ b/ferveo/src/pvss.rs
@@ -8,7 +8,7 @@ use ark_poly::{
};
use ferveo_tdec::{
prepare_combine_simple, CiphertextHeader, DecryptionSharePrecomputed,
- DecryptionShareSimple, PrivateKeyShare,
+ DecryptionShareSimple, PrivateKeyShare, PrivateKeyShareUpdate,
};
use itertools::Itertools;
use rand::RngCore;
@@ -18,9 +18,8 @@ use subproductdomain::fast_multiexp;
use zeroize::{self, Zeroize, ZeroizeOnDrop};
use crate::{
- apply_updates_to_private_share, assert_no_share_duplicates,
- batch_to_projective_g1, batch_to_projective_g2, Error, PVSSMap,
- PubliclyVerifiableDkg, Result, Validator,
+ assert_no_share_duplicates, batch_to_projective_g1, batch_to_projective_g2,
+ Error, PVSSMap, PubliclyVerifiableDkg, Result, Validator,
};
/// These are the blinded evaluations of shares of a single random polynomial
@@ -304,7 +303,7 @@ impl PubliclyVerifiableSS {
validator_decryption_key: &E::ScalarField,
share_index: usize,
) -> Result> {
- // Decrypt private key shares https://nikkolasg.github.io/ferveo/pvss.html#validator-decryption-of-private-key-shares
+ // Decrypt private key share https://nikkolasg.github.io/ferveo/pvss.html#validator-decryption-of-private-key-shares
let private_key_share = self
.shares
.get(share_index)
@@ -365,22 +364,16 @@ impl PubliclyVerifiableSS {
.map_err(|e| e.into())
}
- // TODO: Consider relocate to different place, maybe PrivateKeyShare? (see #162, #163)
pub fn update_private_key_share_for_recovery(
&self,
validator_decryption_key: &E::ScalarField,
share_index: usize,
- share_updates: &[E::G2],
+ share_updates: &[PrivateKeyShareUpdate],
) -> Result> {
- // Retrieves their private key share
- let private_key_share = self
- .decrypt_private_key_share(validator_decryption_key, share_index)?;
-
- // And updates their share
- Ok(apply_updates_to_private_share::(
- &private_key_share,
- share_updates,
- ))
+ // Retrieve the private key share and apply the updates
+ Ok(self
+ .decrypt_private_key_share(validator_decryption_key, share_index)?
+ .update_share(share_updates))
}
}
@@ -435,8 +428,8 @@ mod test_pvss {
/// Test the happy flow such that the PVSS with the correct form is created
/// and that appropriate validations pass
- #[test_case(4,4; "number of validators is equal to the number of shares")]
- #[test_case(4,6; "number of validators is greater than the number of shares")]
+ #[test_case(4, 4; "number of validators is equal to the number of shares")]
+ #[test_case(4, 6; "number of validators is greater than the number of shares")]
fn test_new_pvss(shares_num: u32, validators_num: u32) {
let rng = &mut ark_std::test_rng();
let security_threshold = shares_num - 1;
@@ -510,8 +503,8 @@ mod test_pvss {
/// Check that happy flow of aggregating PVSS transcripts
/// has the correct form and it's validations passes
- #[test_case(4,4; "number of validators is equal to the number of shares")]
- #[test_case(4,6; "number of validators is greater than the number of shares")]
+ #[test_case(4, 4; "number of validators is equal to the number of shares")]
+ #[test_case(4, 6; "number of validators is greater than the number of shares")]
fn test_aggregate_pvss(shares_num: u32, validators_num: u32) {
let security_threshold = shares_num - 1;
let (dkg, _) = setup_dealt_dkg_with_n_validators(
diff --git a/ferveo/src/refresh.rs b/ferveo/src/refresh.rs
index b02eba3b..90834204 100644
--- a/ferveo/src/refresh.rs
+++ b/ferveo/src/refresh.rs
@@ -1,10 +1,9 @@
use std::{ops::Mul, usize};
-use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup};
+use ark_ec::{pairing::Pairing, CurveGroup};
use ark_ff::Zero;
use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial, Polynomial};
-use ferveo_tdec::{lagrange_basis_at, PrivateKeyShare};
-use itertools::zip_eq;
+use ferveo_tdec::PrivateKeyShareUpdate;
use rand_core::RngCore;
// SHARE UPDATE FUNCTIONS:
@@ -16,44 +15,11 @@ pub fn prepare_share_updates_for_recovery(
x_r: &E::ScalarField,
threshold: usize,
rng: &mut impl RngCore,
-) -> Vec {
+) -> Vec> {
// Update polynomial has root at x_r
prepare_share_updates_with_root::(domain_points, h, x_r, threshold, rng)
}
-// TODO: Consider relocating to PrivateKeyShare (see #162, #163)
-/// From PSS paper, section 4.2.3, (https://link.springer.com/content/pdf/10.1007/3-540-44750-4_27.pdf)
-pub fn apply_updates_to_private_share(
- private_key_share: &PrivateKeyShare,
- share_updates: &[E::G2],
-) -> PrivateKeyShare {
- let private_key_share = share_updates
- .iter()
- .fold(
- private_key_share.private_key_share.into_group(),
- |acc, delta| acc + delta,
- )
- .into_affine();
- PrivateKeyShare { private_key_share }
-}
-
-/// From the PSS paper, section 4.2.4, (https://link.springer.com/content/pdf/10.1007/3-540-44750-4_27.pdf)
-pub fn recover_share_from_updated_private_shares(
- x_r: &E::ScalarField,
- domain_points: &[E::ScalarField],
- updated_private_shares: &[PrivateKeyShare],
-) -> PrivateKeyShare {
- // Interpolate new shares to recover y_r
- let lagrange = lagrange_basis_at::(domain_points, x_r);
- let prods = zip_eq(updated_private_shares, lagrange)
- .map(|(y_j, l)| y_j.private_key_share.mul(l));
- let y_r = prods.fold(E::G2::zero(), |acc, y_j| acc + y_j);
-
- PrivateKeyShare {
- private_key_share: y_r.into_affine(),
- }
-}
-
// SHARE REFRESH FUNCTIONS:
pub fn prepare_share_updates_for_refresh(
@@ -61,7 +27,7 @@ pub fn prepare_share_updates_for_refresh(
h: &E::G2Affine,
threshold: usize,
rng: &mut impl RngCore,
-) -> Vec {
+) -> Vec> {
// Update polynomial has root at 0
prepare_share_updates_with_root::(
domain_points,
@@ -80,7 +46,7 @@ fn prepare_share_updates_with_root(
root: &E::ScalarField,
threshold: usize,
rng: &mut impl RngCore,
-) -> Vec {
+) -> Vec> {
// Generate a new random polynomial with defined root
let d_i = make_random_polynomial_with_root::(threshold - 1, root, rng);
@@ -89,8 +55,9 @@ fn prepare_share_updates_with_root(
.iter()
.map(|x_i| {
let eval = d_i.evaluate(x_i);
- h.mul(eval)
+ h.mul(eval).into_affine()
})
+ .map(PrivateKeyShareUpdate)
.collect()
}
@@ -130,9 +97,8 @@ mod tests_refresh {
use test_case::test_matrix;
use crate::{
- apply_updates_to_private_share, prepare_share_updates_for_recovery,
- prepare_share_updates_for_refresh,
- recover_share_from_updated_private_shares, test_common::*,
+ prepare_share_updates_for_recovery, prepare_share_updates_for_refresh,
+ test_common::*,
};
fn make_new_share_fragments_for_recovery(
@@ -170,14 +136,12 @@ mod tests_refresh {
// Current participant receives updates from other participants
let updates_for_participant: Vec<_> = share_updates
.values()
- .map(|updates| *updates.get(p.index).unwrap())
+ .map(|updates| updates.get(p.index).cloned().unwrap())
.collect();
// And updates their share
- apply_updates_to_private_share::(
- &p.private_key_share,
- &updates_for_participant,
- )
+
+ p.private_key_share.update_share(&updates_for_participant)
})
.collect();
@@ -225,18 +189,19 @@ mod tests_refresh {
.iter()
.map(|ctxt| ctxt.domain)
.collect::>();
- let new_private_key_share = recover_share_from_updated_private_shares(
- &x_r,
- &domain_points[..security_threshold],
- &new_share_fragments[..security_threshold],
- );
+ let new_private_key_share =
+ PrivateKeyShare::recover_share_from_updated_private_shares(
+ &x_r,
+ &domain_points[..security_threshold],
+ &new_share_fragments[..security_threshold],
+ );
assert_eq!(new_private_key_share, original_private_key_share);
// If we don't have enough private share updates, the resulting private share will be incorrect
assert_eq!(domain_points.len(), new_share_fragments.len());
let incorrect_private_key_share =
- recover_share_from_updated_private_shares(
+ PrivateKeyShare::recover_share_from_updated_private_shares(
&x_r,
&domain_points[..(security_threshold - 1)],
&new_share_fragments[..(security_threshold - 1)],
@@ -283,11 +248,12 @@ mod tests_refresh {
.iter()
.map(|ctxt| ctxt.domain)
.collect::>();
- let new_private_key_share = recover_share_from_updated_private_shares(
- &x_r,
- &domain_points[..threshold],
- &new_share_fragments[..threshold],
- );
+ let new_private_key_share =
+ PrivateKeyShare::recover_share_from_updated_private_shares(
+ &x_r,
+ &domain_points[..threshold],
+ &new_share_fragments[..threshold],
+ );
let mut private_shares = contexts
.iter()
@@ -299,16 +265,14 @@ mod tests_refresh {
domain_points.push(x_r);
private_shares.push(new_private_key_share);
let start_from = shares_num - threshold;
- let new_shared_private_key = recover_share_from_updated_private_shares(
- &ScalarField::zero(),
- &domain_points[start_from..],
- &private_shares[start_from..],
- );
+ let new_shared_private_key =
+ PrivateKeyShare::recover_share_from_updated_private_shares(
+ &ScalarField::zero(),
+ &domain_points[start_from..],
+ &private_shares[start_from..],
+ );
- assert_eq!(
- shared_private_key,
- new_shared_private_key.private_key_share
- );
+ assert_eq!(shared_private_key, new_shared_private_key);
}
/// Ñ parties (where t <= Ñ <= N) jointly execute a "share refresh" algorithm.
@@ -350,27 +314,22 @@ mod tests_refresh {
// Current participant receives updates from other participants
let updates_for_participant: Vec<_> = share_updates
.values()
- .map(|updates| *updates.get(p.index).unwrap())
+ .map(|updates| updates.get(p.index).cloned().unwrap())
.collect();
// And updates their share
- apply_updates_to_private_share::(
- &p.private_key_share,
- &updates_for_participant,
- )
+ p.private_key_share.update_share(&updates_for_participant)
})
.collect();
// Finally, let's recreate the shared private key from the refreshed shares
- let new_shared_private_key = recover_share_from_updated_private_shares(
- &ScalarField::zero(),
- &domain_points[..threshold],
- &refreshed_shares[..threshold],
- );
+ let new_shared_private_key =
+ PrivateKeyShare::recover_share_from_updated_private_shares(
+ &ScalarField::zero(),
+ &domain_points[..threshold],
+ &refreshed_shares[..threshold],
+ );
- assert_eq!(
- shared_private_key,
- new_shared_private_key.private_key_share
- );
+ assert_eq!(shared_private_key, new_shared_private_key);
}
}