From eccb5eab4a3c3a5340b2294af2d35765e296f37e Mon Sep 17 00:00:00 2001 From: Bogdan Opanchuk Date: Sat, 12 Aug 2023 14:33:34 -0700 Subject: [PATCH] Rearrange KeyShares internal structure --- synedrion/src/centralized_keygen.rs | 81 ++++++++-------- synedrion/src/protocols/auxiliary.rs | 38 ++++---- synedrion/src/protocols/common.rs | 127 ++++++++++---------------- synedrion/src/protocols/keygen.rs | 8 +- synedrion/src/protocols/presigning.rs | 83 ++++++++++------- synedrion/src/protocols/signing.rs | 5 +- synedrion/src/protocols/threshold.rs | 50 ++++------ 7 files changed, 182 insertions(+), 210 deletions(-) diff --git a/synedrion/src/centralized_keygen.rs b/synedrion/src/centralized_keygen.rs index 2e0979b..cf81f8e 100644 --- a/synedrion/src/centralized_keygen.rs +++ b/synedrion/src/centralized_keygen.rs @@ -1,49 +1,38 @@ use alloc::boxed::Box; -use alloc::vec::Vec; use rand_core::CryptoRngCore; -use crate::curve::{Point, Scalar}; +use crate::curve::Scalar; use crate::paillier::uint::Zero; use crate::paillier::{PaillierParams, SecretKeyPaillier}; -use crate::protocols::common::{KeyShare, KeySharePublic, KeyShareSecret, SchemeParams}; +use crate::protocols::common::{KeyShare, PublicAuxInfo, SchemeParams, SecretAuxInfo}; use crate::protocols::threshold::ThresholdKeyShare; use crate::tools::sss::{shamir_evaluation_points, shamir_split}; use crate::PartyIdx; #[allow(clippy::type_complexity)] -fn make_key_shares_from_secrets( +fn make_aux_info( rng: &mut impl CryptoRngCore, - secrets: &[Scalar], -) -> (Box<[KeyShareSecret

]>, Box<[KeySharePublic

]>) { - let paillier_sks = secrets - .iter() - .map(|_| SecretKeyPaillier::::random(rng)) - .collect::>(); + num_parties: usize, +) -> (Box<[SecretAuxInfo

]>, Box<[PublicAuxInfo

]>) { + let secret_aux = (0..num_parties) + .map(|_| SecretAuxInfo { + paillier_sk: SecretKeyPaillier::::random(rng), + el_gamal_sk: Scalar::random(rng), + }) + .collect::>(); - let public = secrets + let public_aux = secret_aux .iter() - .zip(paillier_sks.iter()) - .map(|(share_sk, sk)| KeySharePublic { - share_pk: share_sk.mul_by_generator(), - el_gamal_pk: Point::GENERATOR, // TODO: currently unused in the protocol + .map(|secret| PublicAuxInfo { + paillier_pk: secret.paillier_sk.public_key(), + el_gamal_pk: secret.el_gamal_sk.mul_by_generator(), rp_generator: ::DoubleUint::ZERO, // TODO: currently unused in the protocol rp_power: ::DoubleUint::ZERO, // TODO: currently unused in the protocol - paillier_pk: sk.public_key(), }) .collect(); - let secret = secrets - .iter() - .zip(paillier_sks.iter()) - .map(|(share_sk, paillier_sk)| KeyShareSecret { - share_sk: *share_sk, - paillier_sk: (*paillier_sk).clone(), - el_gamal_sk: Scalar::random(rng), // TODO: currently unused in the protocol - }) - .collect(); - - (secret, public) + (secret_aux, public_aux) } /// Returns `num_parties` of random self-consistent key shares @@ -58,18 +47,24 @@ pub fn make_key_shares( Some(sk) => Scalar::from(sk.as_nonzero_scalar()), }; - let secrets = secret.split(rng, num_parties); + let secret_shares = secret.split(rng, num_parties); + let public_shares = secret_shares + .iter() + .map(|s| s.mul_by_generator()) + .collect::>(); - let (secret_shares, public_shares) = make_key_shares_from_secrets(rng, &secrets); + let (secret_aux, public_aux) = make_aux_info(rng, num_parties); - secret_shares + secret_aux .into_vec() .into_iter() .enumerate() - .map(|(idx, secret)| KeyShare { + .map(|(idx, secret_aux)| KeyShare { index: PartyIdx::from_usize(idx), - secret, - public: public_shares.clone(), + secret_share: secret_shares[idx], + public_shares: public_shares.clone(), + secret_aux, + public_aux: public_aux.clone(), }) .collect() } @@ -87,24 +82,30 @@ pub fn make_threshold_key_shares( Some(sk) => Scalar::from(sk.as_nonzero_scalar()), }; - let secrets = shamir_split( + let secret_shares = shamir_split( rng, &secret, threshold, &shamir_evaluation_points(num_parties), ); + let public_shares = secret_shares + .iter() + .map(|s| s.mul_by_generator()) + .collect::>(); - let (secret_shares, public_shares) = make_key_shares_from_secrets(rng, &secrets); + let (secret_aux, public_aux) = make_aux_info(rng, num_parties); - secret_shares + secret_aux .into_vec() .into_iter() .enumerate() - .map(|(idx, secret)| ThresholdKeyShare { + .map(|(idx, secret_aux)| ThresholdKeyShare { index: PartyIdx::from_usize(idx), threshold: threshold as u32, // TODO: fallible conversion? - secret, - public: public_shares.clone(), + secret_share: secret_shares[idx], + public_shares: public_shares.clone(), + secret_aux, + public_aux: public_aux.clone(), }) .collect() } @@ -137,7 +138,7 @@ mod tests { assert_eq!(&nt_share0.verifying_key(), sk.verifying_key()); assert_eq!(&nt_share1.verifying_key(), sk.verifying_key()); assert_eq!( - nt_share0.secret.share_sk + nt_share1.secret.share_sk, + nt_share0.secret_share + nt_share1.secret_share, Scalar::from(sk.as_nonzero_scalar()) ); } diff --git a/synedrion/src/protocols/auxiliary.rs b/synedrion/src/protocols/auxiliary.rs index 2011d20..a4f4dba 100644 --- a/synedrion/src/protocols/auxiliary.rs +++ b/synedrion/src/protocols/auxiliary.rs @@ -5,9 +5,7 @@ use crypto_bigint::Pow; use rand_core::CryptoRngCore; use serde::{Deserialize, Serialize}; -use super::common::{ - KeyShareChange, KeyShareChangePublic, KeyShareChangeSecret, PartyIdx, SchemeParams, -}; +use super::common::{KeyShareChange, PartyIdx, PublicAuxInfo, SchemeParams, SecretAuxInfo}; use super::generic::{ BaseRound, FinalizeError, FinalizeSuccess, FirstRound, InitError, NonExistent, ReceiveError, Round, ToSendTyped, @@ -454,19 +452,17 @@ impl Round for Round3

{ payloads: HoleVec, ) -> Result, FinalizeError> { let secrets = payloads.into_vec(self.context.xs_secret[self.context.party_idx.as_usize()]); - let share_change = secrets.iter().sum(); + let secret_share_change = secrets.iter().sum(); let datas = self.datas.into_vec(self.context.data); - let public_share_changes: Vec<_> = (0..datas.len()) + let public_share_changes = (0..datas.len()) .map(|idx| datas.iter().map(|data| data.xs_public[idx]).sum()) - .collect(); + .collect::>(); - let public = datas + let public_aux = datas .into_iter() - .enumerate() - .map(|(idx, data)| KeyShareChangePublic { - share_pk: public_share_changes[idx], + .map(|data| PublicAuxInfo { el_gamal_pk: data.el_gamal_pk, paillier_pk: data.paillier_pk, rp_generator: data.rp_generator, @@ -474,16 +470,17 @@ impl Round for Round3

{ }) .collect(); - let secret = KeyShareChangeSecret { - share_sk: share_change, + let secret_aux = SecretAuxInfo { paillier_sk: self.context.paillier_sk, el_gamal_sk: self.context.el_gamal_sk, }; let key_share_change = KeyShareChange { index: self.context.party_idx, - secret, - public, + secret_share_change, + public_share_changes, + secret_aux, + public_aux, }; Ok(FinalizeSuccess::Result(key_share_change)) @@ -543,19 +540,22 @@ mod tests { for (idx, change) in results.iter().enumerate() { for other_change in results.iter() { assert_eq!( - change.secret.share_sk.mul_by_generator(), - other_change.public[idx].share_pk + change.secret_share_change.mul_by_generator(), + other_change.public_share_changes[idx] ); assert_eq!( - change.secret.el_gamal_sk.mul_by_generator(), - other_change.public[idx].el_gamal_pk + change.secret_aux.el_gamal_sk.mul_by_generator(), + other_change.public_aux[idx].el_gamal_pk ); } } // The resulting sum of masks should be zero, since the combined secret key // should not change after applying the masks at each node. - let mask_sum: Scalar = results.iter().map(|change| change.secret.share_sk).sum(); + let mask_sum: Scalar = results + .iter() + .map(|change| change.secret_share_change) + .sum(); assert_eq!(mask_sum, Scalar::ZERO); } } diff --git a/synedrion/src/protocols/common.rs b/synedrion/src/protocols/common.rs index dc7b3e7..b9a2460 100644 --- a/synedrion/src/protocols/common.rs +++ b/synedrion/src/protocols/common.rs @@ -45,87 +45,63 @@ impl Hashable for PartyIdx { #[derive(Clone)] pub struct KeyShareSeed { /// Secret key share of this node. - pub share_sk: Scalar, // `x` + pub secret_share: Scalar, // `x_i` /// Public key shares of all nodes (including this one). - pub share_pk: Box<[Point]>, // `X` + pub public_shares: Box<[Point]>, // `X_j` } #[derive(Clone, Serialize, Deserialize)] -#[serde(bound(serialize = "SecretKeyPaillier: Serialize"))] -#[serde(bound(deserialize = "SecretKeyPaillier: for<'x> Deserialize<'x>"))] -pub struct KeyShareSecret { - pub(crate) share_sk: Scalar, - pub(crate) paillier_sk: SecretKeyPaillier, - pub(crate) el_gamal_sk: Scalar, // `y_i` -} - -#[derive(Clone, Serialize, Deserialize)] -#[serde(bound(serialize = "KeyShareSecret

: Serialize, - KeySharePublic

: Serialize"))] -#[serde(bound(deserialize = "KeyShareSecret

: for<'x> Deserialize<'x>, - KeySharePublic

: for <'x> Deserialize<'x>"))] +#[serde(bound(serialize = "SecretAuxInfo

: Serialize, + PublicAuxInfo

: Serialize"))] +#[serde(bound(deserialize = "SecretAuxInfo

: for<'x> Deserialize<'x>, + PublicAuxInfo

: for <'x> Deserialize<'x>"))] pub struct KeyShare { pub(crate) index: PartyIdx, - pub(crate) secret: KeyShareSecret

, - pub(crate) public: Box<[KeySharePublic

]>, + pub(crate) secret_share: Scalar, + pub(crate) public_shares: Box<[Point]>, + pub(crate) secret_aux: SecretAuxInfo

, + pub(crate) public_aux: Box<[PublicAuxInfo

]>, } impl KeyShare

{ pub fn new(seed: KeyShareSeed, change: KeyShareChange

) -> Self { // TODO: check that party_idx is the same for both, and the number of parties is the same - let secret = KeyShareSecret { - share_sk: seed.share_sk + change.secret.share_sk, - paillier_sk: change.secret.paillier_sk, - el_gamal_sk: change.secret.el_gamal_sk, - }; - let public = seed - .share_pk + let secret_share = seed.secret_share + change.secret_share_change; + let public_shares = seed + .public_shares .iter() - .zip(change.public.into_vec().into_iter()) - .map(|(seed_share_pk, change_public)| KeySharePublic { - share_pk: seed_share_pk + &change_public.share_pk, - el_gamal_pk: change_public.el_gamal_pk, - paillier_pk: change_public.paillier_pk, - rp_generator: change_public.rp_generator, - rp_power: change_public.rp_power, - }) + .zip(change.public_share_changes.into_vec().into_iter()) + .map(|(public_share, public_share_change)| public_share + &public_share_change) .collect(); Self { index: change.index, - secret, - public, + secret_share, + public_shares, + secret_aux: change.secret_aux, + public_aux: change.public_aux, } } pub fn update(self, change: KeyShareChange

) -> Self { // TODO: check that party_idx is the same for both, and the number of parties is the same - let secret = KeyShareSecret { - share_sk: self.secret.share_sk + change.secret.share_sk, - paillier_sk: change.secret.paillier_sk, - el_gamal_sk: change.secret.el_gamal_sk, - }; - let public = self - .public - .into_vec() - .into_iter() - .zip(change.public.into_vec().into_iter()) - .map(|(self_public, change_public)| KeySharePublic { - share_pk: self_public.share_pk + change_public.share_pk, - el_gamal_pk: change_public.el_gamal_pk, - paillier_pk: change_public.paillier_pk, - rp_generator: change_public.rp_generator, - rp_power: change_public.rp_power, - }) + let secret_share = self.secret_share + change.secret_share_change; + let public_shares = self + .public_shares + .iter() + .zip(change.public_share_changes.into_vec().into_iter()) + .map(|(public_share, public_share_change)| public_share + &public_share_change) .collect(); Self { index: change.index, - secret, - public, + secret_share, + public_shares, + secret_aux: change.secret_aux, + public_aux: change.public_aux, } } pub(crate) fn verifying_key_as_point(&self) -> Point { - self.public.iter().map(|p| p.share_pk).sum() + self.public_shares.iter().sum() } pub fn verifying_key(&self) -> VerifyingKey { @@ -137,7 +113,7 @@ impl KeyShare

{ pub fn num_parties(&self) -> usize { // TODO: technically it is `num_shares`, but for now we are equating the two, // since we assume that one party has one share. - self.public.len() + self.public_shares.len() } pub fn party_index(&self) -> PartyIdx { @@ -157,33 +133,18 @@ impl core::fmt::Debug for KeyShare

{ } } -#[derive(Clone, Serialize, Deserialize)] -pub struct KeySharePublic { - pub(crate) share_pk: Point, - pub(crate) el_gamal_pk: Point, // `Y_i` - /// The Paillier public key. - pub(crate) paillier_pk: PublicKeyPaillier, - /// The ring-Pedersen generator. - pub(crate) rp_generator: ::DoubleUint, // `t_i` - /// The ring-Pedersen power (a number belonging to the group produced by the generator). - pub(crate) rp_power: ::DoubleUint, // `s_i` -} - #[derive(Clone, Serialize, Deserialize)] #[serde(bound(serialize = "SecretKeyPaillier: Serialize"))] #[serde(bound(deserialize = "SecretKeyPaillier: for <'x> Deserialize<'x>"))] -pub struct KeyShareChangeSecret { - /// The value to be added to the secret share. - pub(crate) share_sk: Scalar, // `x_i^* - x_i == \sum_{j} x_j^i` +pub(crate) struct SecretAuxInfo { pub(crate) paillier_sk: SecretKeyPaillier, pub(crate) el_gamal_sk: Scalar, // `y_i` } -// TODO: can it be `KeySharePublic`? -#[derive(Clone)] -pub struct KeyShareChangePublic { - /// The value to be added to the public share of a remote node. - pub(crate) share_pk: Point, // `X_k^* - X_k == \sum_j X_j^k`, for all nodes +#[derive(Clone, Serialize, Deserialize)] +#[serde(bound(serialize = "PublicKeyPaillier: Serialize"))] +#[serde(bound(deserialize = "PublicKeyPaillier: for <'x> Deserialize<'x>"))] +pub(crate) struct PublicAuxInfo { pub(crate) el_gamal_pk: Point, // `Y_i` /// The Paillier public key. pub(crate) paillier_pk: PublicKeyPaillier, @@ -197,14 +158,20 @@ pub struct KeyShareChangePublic { #[derive(Clone)] pub struct KeyShareChange { pub(crate) index: PartyIdx, - pub(crate) secret: KeyShareChangeSecret

, - pub(crate) public: Box<[KeyShareChangePublic

]>, + /// The value to be added to the secret share. + pub(crate) secret_share_change: Scalar, // `x_i^* - x_i == \sum_{j} x_j^i` + /// The values to be added to the public shares of remote nodes. + pub(crate) public_share_changes: Box<[Point]>, // `X_k^* - X_k == \sum_j X_j^k`, for all nodes + pub(crate) secret_aux: SecretAuxInfo

, + pub(crate) public_aux: Box<[PublicAuxInfo

]>, } /// The result of the Presigning protocol. #[derive(Clone)] pub struct PresigningData { - pub(crate) big_r: Point, - pub(crate) k: Scalar, - pub(crate) chi: Scalar, + pub(crate) nonce: Point, // `R` + /// An additive share of the ephemeral scalar `k`. + pub(crate) ephemeral_scalar_share: Scalar, // `k_i` + /// An additive share of `k * x` where `x` is the secret key. + pub(crate) product_share: Scalar, } diff --git a/synedrion/src/protocols/keygen.rs b/synedrion/src/protocols/keygen.rs index 6f55350..d4adb5c 100644 --- a/synedrion/src/protocols/keygen.rs +++ b/synedrion/src/protocols/keygen.rs @@ -284,8 +284,8 @@ impl Round for Round3

{ let datas = self.datas.into_vec(self.context.data); let public_keys = datas.into_iter().map(|data| data.public).collect(); Ok(FinalizeSuccess::Result(KeyShareSeed { - share_pk: public_keys, - share_sk: self.context.key_share, + secret_share: self.context.key_share, + public_shares: public_keys, })) } } @@ -343,7 +343,7 @@ mod tests { let public_sets = shares .iter() - .map(|s| s.share_pk.clone()) + .map(|s| s.public_shares.clone()) .collect::>(); assert!(public_sets[1..].iter().all(|pk| pk == &public_sets[0])); @@ -353,7 +353,7 @@ mod tests { let public_from_secret = shares .iter() - .map(|s| s.share_sk.mul_by_generator()) + .map(|s| s.secret_share.mul_by_generator()) .collect(); assert!(public_set == &public_from_secret); diff --git a/synedrion/src/protocols/presigning.rs b/synedrion/src/protocols/presigning.rs index 9cd9da7..b8eafdd 100644 --- a/synedrion/src/protocols/presigning.rs +++ b/synedrion/src/protocols/presigning.rs @@ -22,7 +22,7 @@ pub struct Context { num_parties: usize, party_idx: PartyIdx, key_share: KeyShare

, - k: Scalar, + ephemeral_scalar_share: Scalar, gamma: Scalar, rho: <

::Paillier as PaillierParams>::DoubleUint, nu: <

::Paillier as PaillierParams>::DoubleUint, @@ -54,15 +54,15 @@ impl FirstRound for Round1Part1

{ // TODO: checl that KeyShare is consistent with num_parties/party_idx - let k = Scalar::random(rng); + let ephemeral_scalar_share = Scalar::random(rng); let gamma = Scalar::random(rng); - let pk = key_share.secret.paillier_sk.public_key(); + let pk = key_share.secret_aux.paillier_sk.public_key(); let rho = pk.random_invertible_group_elem(rng).retrieve(); let nu = pk.random_invertible_group_elem(rng).retrieve(); let g_ciphertext = Ciphertext::new_with_randomizer(&pk, &gamma, &nu); - let k_ciphertext = Ciphertext::new_with_randomizer(&pk, &k, &rho); + let k_ciphertext = Ciphertext::new_with_randomizer(&pk, &ephemeral_scalar_share, &rho); Ok(Self { context: Context { @@ -70,7 +70,7 @@ impl FirstRound for Round1Part1

{ num_parties, party_idx, key_share, - k, + ephemeral_scalar_share, gamma, rho, nu, @@ -164,12 +164,12 @@ impl BaseRound for Round1Part2

{ let range = HoleRange::new(self.context.num_parties, self.context.party_idx.as_usize()); let aux = (&self.context.shared_randomness, &self.context.party_idx); let k_ciphertext = &self.k_ciphertexts[self.context.party_idx.as_usize()]; - let pk = self.context.key_share.secret.paillier_sk.public_key(); + let pk = self.context.key_share.secret_aux.paillier_sk.public_key(); let messages = range .map(|idx| { let proof = EncProof::random( rng, - &self.context.k, + &self.context.ephemeral_scalar_share, &self.context.rho, &pk, k_ciphertext, @@ -188,7 +188,7 @@ impl BaseRound for Round1Part2

{ ) -> Result { let aux = (&self.context.shared_randomness, &self.context.party_idx); if msg.0.verify( - &self.context.key_share.public[from.as_usize()].paillier_pk, + &self.context.key_share.public_aux[from.as_usize()].paillier_pk, &self.k_ciphertexts[from.as_usize()], &aux, ) { @@ -298,12 +298,12 @@ impl BaseRound for Round2

{ let gamma = self.context.gamma.mul_by_generator(); // TODO: technically it's already been precalculated somewhere earlier - let big_x = self.context.key_share.secret.share_sk.mul_by_generator(); - let pk = &self.context.key_share.secret.paillier_sk.public_key(); + let big_x = self.context.key_share.secret_share.mul_by_generator(); + let pk = &self.context.key_share.secret_aux.paillier_sk.public_key(); let messages = range .map(|idx| { - let target_pk = &self.context.key_share.public[idx].paillier_pk; + let target_pk = &self.context.key_share.public_aux[idx].paillier_pk; let r = target_pk.random_group_elem_raw(rng); let s = target_pk.random_group_elem_raw(rng); @@ -322,7 +322,7 @@ impl BaseRound for Round2

{ let f = Ciphertext::new_with_randomizer(pk, beta, &r); let d_hat = self.k_ciphertexts[idx] - .homomorphic_mul(target_pk, &self.context.key_share.secret.share_sk) + .homomorphic_mul(target_pk, &self.context.key_share.secret_share) .homomorphic_add( target_pk, &Ciphertext::new_with_randomizer(target_pk, &-beta_hat, &s_hat), @@ -346,7 +346,7 @@ impl BaseRound for Round2

{ let psi_hat = AffGProof::random( rng, - &self.context.key_share.secret.share_sk, + &self.context.key_share.secret_share, beta_hat, &s_hat, &r_hat, @@ -393,11 +393,11 @@ impl BaseRound for Round2

{ msg: Self::Message, ) -> Result { let aux = (&self.context.shared_randomness, &self.context.party_idx); - let pk = &self.context.key_share.secret.paillier_sk.public_key(); - let from_pk = &self.context.key_share.public[from.as_usize()].paillier_pk; + let pk = &self.context.key_share.secret_aux.paillier_sk.public_key(); + let from_pk = &self.context.key_share.public_aux[from.as_usize()].paillier_pk; // TODO: technically it's already been precalculated somewhere earlier - let big_x = self.context.key_share.secret.share_sk.mul_by_generator(); + let big_x = self.context.key_share.secret_share.mul_by_generator(); if !msg.psi.verify( pk, @@ -439,10 +439,12 @@ impl BaseRound for Round2

{ )); } - let alpha = msg.d.decrypt(&self.context.key_share.secret.paillier_sk); + let alpha = msg + .d + .decrypt(&self.context.key_share.secret_aux.paillier_sk); let alpha_hat = msg .d_hat - .decrypt(&self.context.key_share.secret.paillier_sk); + .decrypt(&self.context.key_share.secret_aux.paillier_sk); Ok(Round2Payload { gamma: msg.gamma, @@ -466,7 +468,7 @@ impl Round for Round2

{ let gamma: Point = payloads.iter().map(|payload| payload.gamma).sum(); let gamma = gamma + self.context.gamma.mul_by_generator(); - let big_delta = &gamma * &self.context.k; + let big_delta = &gamma * &self.context.ephemeral_scalar_share; let alpha_sum: Scalar = payloads.iter().map(|payload| payload.alpha).sum(); let alpha_hat_sum: Scalar = payloads.iter().map(|payload| payload.alpha_hat).sum(); @@ -474,14 +476,16 @@ impl Round for Round2

{ let beta_sum: Scalar = self.betas.iter().sum(); let beta_hat_sum: Scalar = self.betas_hat.iter().sum(); - let delta = self.context.gamma * self.context.k + alpha_sum + beta_sum; - let chi = - self.context.key_share.secret.share_sk * self.context.k + alpha_hat_sum + beta_hat_sum; + let delta = self.context.gamma * self.context.ephemeral_scalar_share + alpha_sum + beta_sum; + let product_share = self.context.key_share.secret_share + * self.context.ephemeral_scalar_share + + alpha_hat_sum + + beta_hat_sum; Ok(FinalizeSuccess::AnotherRound(Round3 { context: self.context, delta, - chi, + product_share, big_delta, big_gamma: gamma, k_ciphertexts: self.k_ciphertexts, @@ -501,7 +505,7 @@ pub struct Round3Bcast { pub struct Round3 { context: Context

, delta: Scalar, - chi: Scalar, + product_share: Scalar, big_delta: Point, big_gamma: Point, k_ciphertexts: Vec>, @@ -522,13 +526,13 @@ impl BaseRound for Round3

{ fn to_send(&self, rng: &mut impl CryptoRngCore) -> ToSendTyped { let range = HoleRange::new(self.context.num_parties, self.context.party_idx.as_usize()); let aux = (&self.context.shared_randomness, &self.context.party_idx); - let pk = &self.context.key_share.secret.paillier_sk.public_key(); + let pk = &self.context.key_share.secret_aux.paillier_sk.public_key(); let messages = range .map(|idx| { let psi_hat_pprime = LogStarProof::random( rng, - &self.context.k, + &self.context.ephemeral_scalar_share, &self.context.rho, pk, &self.k_ciphertexts[self.context.party_idx.as_usize()], @@ -554,7 +558,7 @@ impl BaseRound for Round3

{ msg: Self::Message, ) -> Result { let aux = (&self.context.shared_randomness, &self.context.party_idx); - let from_pk = &self.context.key_share.public[from.as_usize()].paillier_pk; + let from_pk = &self.context.key_share.public_aux[from.as_usize()].paillier_pk; if !msg.psi_hat_pprime.verify( from_pk, &self.k_ciphertexts[from.as_usize()], @@ -600,12 +604,12 @@ impl Round for Round3

{ } // TODO: seems like we only need the x-coordinate of this (as a Scalar) - let big_r = &self.big_gamma * &delta.invert().unwrap(); + let nonce = &self.big_gamma * &delta.invert().unwrap(); Ok(FinalizeSuccess::Result(PresigningData { - big_r, - k: self.context.k, - chi: self.chi, + nonce, + ephemeral_scalar_share: self.context.ephemeral_scalar_share, + product_share: self.product_share, })) } } @@ -616,6 +620,7 @@ mod tests { use super::Round1Part1; use crate::centralized_keygen::make_key_shares; + use crate::curve::Scalar; use crate::protocols::common::{PartyIdx, TestSchemeParams}; use crate::protocols::generic::{ tests::{assert_next_round, assert_result, step}, @@ -661,9 +666,17 @@ mod tests { let r3 = assert_next_round(step(&mut OsRng, r2).unwrap()).unwrap(); let presigning_datas = assert_result(step(&mut OsRng, r3).unwrap()).unwrap(); - assert_eq!(presigning_datas[0].big_r, presigning_datas[1].big_r); - assert_eq!(presigning_datas[0].big_r, presigning_datas[2].big_r); - - // TODO: what contracts do we expect? + // Check that each node ends up with the same nonce. + assert_eq!(presigning_datas[0].nonce, presigning_datas[1].nonce); + assert_eq!(presigning_datas[0].nonce, presigning_datas[2].nonce); + + // Check that the additive shares were constructed in a consistent way. + let k: Scalar = presigning_datas + .iter() + .map(|data| data.ephemeral_scalar_share) + .sum(); + let k_times_x: Scalar = presigning_datas.iter().map(|data| data.product_share).sum(); + let x: Scalar = key_shares.iter().map(|share| share.secret_share).sum(); + assert_eq!(x * k, k_times_x); } } diff --git a/synedrion/src/protocols/signing.rs b/synedrion/src/protocols/signing.rs index 23718bb..e8a60dc 100644 --- a/synedrion/src/protocols/signing.rs +++ b/synedrion/src/protocols/signing.rs @@ -32,8 +32,9 @@ impl FirstRound for Round1 { _party_idx: PartyIdx, context: Self::Context, ) -> Result { - let r = context.presigning.big_r.x_coordinate(); - let s_part = context.presigning.k * context.message + r * context.presigning.chi; + let r = context.presigning.nonce.x_coordinate(); + let s_part = context.presigning.ephemeral_scalar_share * context.message + + r * context.presigning.product_share; Ok(Self { r, s_part, context }) } } diff --git a/synedrion/src/protocols/threshold.rs b/synedrion/src/protocols/threshold.rs index 0ccd694..6e369fd 100644 --- a/synedrion/src/protocols/threshold.rs +++ b/synedrion/src/protocols/threshold.rs @@ -4,32 +4,32 @@ use alloc::vec::Vec; use k256::ecdsa::VerifyingKey; use serde::{Deserialize, Serialize}; -use super::common::{KeyShare, KeySharePublic, KeyShareSecret, PartyIdx}; -use crate::curve::Point; +use super::common::{KeyShare, PartyIdx, PublicAuxInfo, SecretAuxInfo}; +use crate::curve::{Point, Scalar}; use crate::tools::sss::{interpolation_coeff, shamir_evaluation_points}; use crate::SchemeParams; #[derive(Clone, Serialize, Deserialize)] -#[serde(bound(serialize = "KeyShareSecret

: Serialize, - KeySharePublic

: Serialize"))] -#[serde(bound(deserialize = "KeyShareSecret

: for <'x> Deserialize<'x>, - KeySharePublic

: for <'x> Deserialize<'x>"))] +#[serde(bound(serialize = "SecretAuxInfo

: Serialize, + PublicAuxInfo

: Serialize"))] +#[serde(bound(deserialize = "SecretAuxInfo

: for <'x> Deserialize<'x>, + PublicAuxInfo

: for <'x> Deserialize<'x>"))] pub struct ThresholdKeyShare { pub(crate) index: PartyIdx, pub(crate) threshold: u32, // TODO: make typed? Can it be `ShareIdx`? - pub(crate) secret: KeyShareSecret

, - pub(crate) public: Box<[KeySharePublic

]>, + pub(crate) secret_share: Scalar, + pub(crate) public_shares: Box<[Point]>, + pub(crate) secret_aux: SecretAuxInfo

, + pub(crate) public_aux: Box<[PublicAuxInfo

]>, } impl ThresholdKeyShare

{ pub(crate) fn verifying_key_as_point(&self) -> Point { let points = shamir_evaluation_points(self.num_parties()); - self.public[0..self.threshold as usize] + self.public_shares[0..self.threshold as usize] .iter() .enumerate() - .map(|(idx, p)| { - &p.share_pk * &interpolation_coeff(&points[0..self.threshold as usize], idx) - }) + .map(|(idx, p)| p * &interpolation_coeff(&points[0..self.threshold as usize], idx)) .sum() } @@ -42,7 +42,7 @@ impl ThresholdKeyShare

{ pub fn num_parties(&self) -> usize { // TODO: technically it is `num_shares`, but for now we are equating the two, // since we assume that one party has one share. - self.public.len() + self.public_shares.len() } pub fn party_index(&self) -> PartyIdx { @@ -69,31 +69,21 @@ impl ThresholdKeyShare

{ .collect::>(); // TODO: make the rescaling a method of KeyShareSecret? - let secret = KeyShareSecret { - share_sk: self.secret.share_sk * interpolation_coeff(&points, mapped_idx), - paillier_sk: self.secret.paillier_sk.clone(), - el_gamal_sk: self.secret.el_gamal_sk, - }; - - let public = party_idxs + let secret_share = self.secret_share * interpolation_coeff(&points, mapped_idx); + let public_shares = party_idxs .iter() .enumerate() .map(|(mapped_idx, idx)| { - let public = &self.public[idx.as_usize()]; - KeySharePublic { - share_pk: &public.share_pk * &interpolation_coeff(&points, mapped_idx), - el_gamal_pk: public.el_gamal_pk, - paillier_pk: public.paillier_pk.clone(), - rp_generator: public.rp_generator, - rp_power: public.rp_power, - } + &self.public_shares[idx.as_usize()] * &interpolation_coeff(&points, mapped_idx) }) .collect(); KeyShare { index: PartyIdx::from_usize(mapped_idx), - secret, - public, + secret_share, + public_shares, + secret_aux: self.secret_aux.clone(), + public_aux: self.public_aux.clone(), } } }