From 5444f65a56b12d06f481a9ad44a89674944c27cc Mon Sep 17 00:00:00 2001 From: Bogdan Opanchuk Date: Mon, 4 Nov 2024 22:27:46 -0800 Subject: [PATCH] KeyResharing converted --- .../cggmp21/protocols/interactive_signing.rs | 2 +- .../cggmp21/protocols/signing_malicious.rs | 2 +- synedrion/src/lib.rs | 16 +- synedrion/src/tools/sss.rs | 11 +- synedrion/src/www02.rs | 2 +- synedrion/src/www02/entities.rs | 36 +- synedrion/src/www02/key_resharing.rs | 441 ++++++++++-------- 7 files changed, 279 insertions(+), 231 deletions(-) diff --git a/synedrion/src/cggmp21/protocols/interactive_signing.rs b/synedrion/src/cggmp21/protocols/interactive_signing.rs index 76985fac..1bdde1ea 100644 --- a/synedrion/src/cggmp21/protocols/interactive_signing.rs +++ b/synedrion/src/cggmp21/protocols/interactive_signing.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; use manul::{ - combinators::{Chained, ChainedEntryPoint, ChainedProtocol}, + combinators::chain::{Chained, ChainedEntryPoint, ChainedProtocol}, protocol::PartyId, }; diff --git a/synedrion/src/cggmp21/protocols/signing_malicious.rs b/synedrion/src/cggmp21/protocols/signing_malicious.rs index 815bced2..38861282 100644 --- a/synedrion/src/cggmp21/protocols/signing_malicious.rs +++ b/synedrion/src/cggmp21/protocols/signing_malicious.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use k256::ecdsa::{signature::hazmat::PrehashVerifier, VerifyingKey}; use manul::{ - combinators::{Misbehaving, MisbehavingEntryPoint, MisbehavingInputs}, + combinators::misbehave::{Misbehaving, MisbehavingEntryPoint, MisbehavingInputs}, protocol::{ Artifact, BoxedRound, Deserializer, DirectMessage, EntryPoint, LocalError, NormalBroadcast, PartyId, ProtocolMessagePart, RoundId, Serializer, diff --git a/synedrion/src/lib.rs b/synedrion/src/lib.rs index ab76199d..c4273653 100644 --- a/synedrion/src/lib.rs +++ b/synedrion/src/lib.rs @@ -29,7 +29,7 @@ mod paillier; //pub mod sessions; mod tools; mod uint; -//mod www02; +mod www02; // Some re-exports to avoid the need for version-matching pub use bip32; @@ -37,12 +37,14 @@ pub use k256; pub use k256::ecdsa; pub use signature; -/*pub use cggmp21::{ - AuxGenError, AuxGenResult, AuxInfo, InteractiveSigningError, InteractiveSigningProof, - InteractiveSigningResult, KeyGenError, KeyGenProof, KeyGenResult, KeyInitError, KeyInitResult, - KeyRefreshResult, KeyShare, KeyShareChange, PresigningError, PresigningProof, PresigningResult, - ProductionParams, SchemeParams, SigningProof, SigningResult, TestParams, -};*/ +pub use cggmp21::{ + SchemeParams, + TestParams, + //AuxGenError, AuxGenResult, AuxInfo, InteractiveSigningError, InteractiveSigningProof, + //InteractiveSigningResult, KeyGenError, KeyGenProof, KeyGenResult, KeyInitError, KeyInitResult, + //KeyRefreshResult, KeyShare, KeyShareChange, PresigningError, PresigningProof, PresigningResult, + //ProductionParams, SigningProof, SigningResult, +}; //pub use constructors::{ // make_aux_gen_session, make_interactive_signing_session, make_key_gen_session, // make_key_init_session, make_key_refresh_session, make_key_resharing_session, PrehashedMessage, diff --git a/synedrion/src/tools/sss.rs b/synedrion/src/tools/sss.rs index 3a3955e4..09ded1ae 100644 --- a/synedrion/src/tools/sss.rs +++ b/synedrion/src/tools/sss.rs @@ -4,8 +4,12 @@ use core::ops::{Add, Mul}; use rand_core::CryptoRngCore; use serde::{Deserialize, Serialize}; +use zeroize::ZeroizeOnDrop; -use crate::curve::{Point, Scalar}; +use crate::{ + curve::{Point, Scalar}, + tools::HideDebug, +}; #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub struct ShareId(Scalar); @@ -37,7 +41,8 @@ where res } -pub(crate) struct Polynomial(Vec); +#[derive(Debug, ZeroizeOnDrop)] +pub(crate) struct Polynomial(HideDebug>); impl Polynomial { pub fn random(rng: &mut impl CryptoRngCore, coeff0: &Scalar, degree: usize) -> Self { @@ -46,7 +51,7 @@ impl Polynomial { for _ in 1..degree { coeffs.push(Scalar::random_nonzero(rng)); } - Self(coeffs) + Self(coeffs.into()) } pub fn evaluate(&self, x: &ShareId) -> Scalar { diff --git a/synedrion/src/www02.rs b/synedrion/src/www02.rs index 0ec176df..bf0b8dbb 100644 --- a/synedrion/src/www02.rs +++ b/synedrion/src/www02.rs @@ -2,4 +2,4 @@ mod entities; pub(crate) mod key_resharing; pub use entities::{DeriveChildKey, ThresholdKeyShare}; -pub use key_resharing::{KeyResharingInputs, KeyResharingResult, NewHolder, OldHolder}; +pub use key_resharing::{KeyResharingInputs, KeyResharingProtocol, NewHolder, OldHolder}; diff --git a/synedrion/src/www02/entities.rs b/synedrion/src/www02/entities.rs index 1df98b62..a5e67774 100644 --- a/synedrion/src/www02/entities.rs +++ b/synedrion/src/www02/entities.rs @@ -291,32 +291,44 @@ mod tests { use alloc::collections::BTreeSet; use k256::ecdsa::SigningKey; + use manul::{ + session::signature::Keypair, + testing::{TestSigner, TestVerifier}, + }; use rand_core::OsRng; use secrecy::ExposeSecret; use super::ThresholdKeyShare; use crate::cggmp21::TestParams; use crate::curve::Scalar; - use crate::rounds::test_utils::Id; #[test] fn threshold_key_share_centralized() { let sk = SigningKey::random(&mut OsRng); - let ids = BTreeSet::from([Id(0), Id(1), Id(2)]); - - let shares = - ThresholdKeyShare::::new_centralized(&mut OsRng, &ids, 2, Some(&sk)); + let signers = (0..3).map(TestSigner::new).collect::>(); + let ids = signers + .iter() + .map(|signer| signer.verifying_key()) + .collect::>(); + let ids_set = ids.iter().cloned().collect::>(); + + let shares = ThresholdKeyShare::::new_centralized( + &mut OsRng, + &ids_set, + 2, + Some(&sk), + ); - assert_eq!(&shares[&Id(0)].verifying_key(), sk.verifying_key()); - assert_eq!(&shares[&Id(1)].verifying_key(), sk.verifying_key()); - assert_eq!(&shares[&Id(2)].verifying_key(), sk.verifying_key()); + assert_eq!(&shares[&ids[0]].verifying_key(), sk.verifying_key()); + assert_eq!(&shares[&ids[1]].verifying_key(), sk.verifying_key()); + assert_eq!(&shares[&ids[2]].verifying_key(), sk.verifying_key()); - assert_eq!(&shares[&Id(0)].verifying_key(), sk.verifying_key()); + assert_eq!(&shares[&ids[0]].verifying_key(), sk.verifying_key()); - let ids_subset = BTreeSet::from([Id(2), Id(0)]); - let nt_share0 = shares[&Id(0)].to_key_share(&ids_subset); - let nt_share1 = shares[&Id(2)].to_key_share(&ids_subset); + let ids_subset = BTreeSet::from([ids[2], ids[0]]); + let nt_share0 = shares[&ids[0]].to_key_share(&ids_subset); + let nt_share1 = shares[&ids[2]].to_key_share(&ids_subset); assert_eq!( nt_share0.secret_share.expose_secret() + nt_share1.secret_share.expose_secret(), diff --git a/synedrion/src/www02/key_resharing.rs b/synedrion/src/www02/key_resharing.rs index 67d00c0a..20cfe4a9 100644 --- a/synedrion/src/www02/key_resharing.rs +++ b/synedrion/src/www02/key_resharing.rs @@ -7,52 +7,90 @@ use alloc::boxed::Box; use alloc::collections::{BTreeMap, BTreeSet}; +use alloc::string::String; use alloc::vec::Vec; use core::fmt::Debug; use core::marker::PhantomData; use k256::ecdsa::VerifyingKey; +use manul::protocol::{ + Artifact, BoxedRound, DeserializationError, Deserializer, DirectMessage, EchoBroadcast, + EchoRoundParticipation, EntryPoint, FinalizeError, FinalizeOutcome, LocalError, + NormalBroadcast, PartyId, Payload, Protocol, ProtocolError, ProtocolMessagePart, + ProtocolValidationError, ReceiveError, Round, RoundId, Serializer, +}; use rand_core::CryptoRngCore; use secrecy::{ExposeSecret, SecretBox}; use serde::{Deserialize, Serialize}; use super::ThresholdKeyShare; use crate::curve::{Point, Scalar}; -use crate::rounds::{ - FinalizableToResult, FinalizationRequirement, FinalizeError, FirstRound, InitError, - ProtocolResult, Round, ToResult, -}; -use crate::tools::sss::{ - interpolation_coeff, shamir_join_points, shamir_join_scalars, Polynomial, PublicPolynomial, - ShareId, +use crate::tools::{ + sss::{ + interpolation_coeff, shamir_join_points, shamir_join_scalars, Polynomial, PublicPolynomial, + ShareId, + }, + DowncastMap, Without, }; use crate::SchemeParams; /// The outcomes of KeyResharing protocol. #[derive(Debug)] -pub struct KeyResharingResult(PhantomData

, PhantomData); +pub struct KeyResharingProtocol(PhantomData<(P, I)>); -impl ProtocolResult for KeyResharingResult { - type Success = Option>; - type ProvableError = KeyResharingError; +impl Protocol for KeyResharingProtocol { + type Result = Option>; + type ProtocolError = KeyResharingError; type CorrectnessProof = (); } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] pub enum KeyResharingError { UnexpectedSender, SubshareMismatch, } +impl ProtocolError for KeyResharingError { + fn description(&self) -> String { + unimplemented!() + } + + fn required_direct_messages(&self) -> BTreeSet { + unimplemented!() + } + + fn required_echo_broadcasts(&self) -> BTreeSet { + unimplemented!() + } + + fn required_combined_echos(&self) -> BTreeSet { + unimplemented!() + } + + fn verify_messages_constitute_error( + &self, + _deserializer: &Deserializer, + _echo_broadcast: &EchoBroadcast, + _normal_broadcat: &NormalBroadcast, + _direct_message: &DirectMessage, + _echo_broadcasts: &BTreeMap, + _normal_broadcasts: &BTreeMap, + _direct_messages: &BTreeMap, + _combined_echos: &BTreeMap>, + ) -> Result<(), ProtocolValidationError> { + unimplemented!() + } +} + /// Old share data. -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct OldHolder { /// The threshold key share. pub key_share: ThresholdKeyShare, } /// New share data. -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct NewHolder { /// The verifying key the old shares add up to. pub verifying_key: VerifyingKey, @@ -75,36 +113,41 @@ pub struct KeyResharingInputs { pub new_threshold: usize, } +#[derive(Debug)] struct OldHolderData { share_id: ShareId, polynomial: Polynomial, public_polynomial: PublicPolynomial, } +#[derive(Debug)] struct NewHolderData { inputs: NewHolder, } +#[derive(Debug)] pub struct Round1 { old_holder: Option, new_holder: Option>, new_share_ids: BTreeMap, new_threshold: usize, - other_ids: BTreeSet, my_id: I, message_destinations: BTreeSet, + expecting_messages_from: BTreeSet, + echo_round_participation: EchoRoundParticipation, phantom: PhantomData

, } -impl FirstRound for Round1 { +impl EntryPoint for Round1 { type Inputs = KeyResharingInputs; + type Protocol = KeyResharingProtocol; + fn new( rng: &mut impl CryptoRngCore, _shared_randomness: &[u8], - other_ids: BTreeSet, - my_id: I, + id: I, inputs: Self::Inputs, - ) -> Result { + ) -> Result, LocalError> { // Start new share indices from 1. let new_share_ids = inputs .new_holders @@ -114,21 +157,37 @@ impl FirstRound for Round1 { .collect(); if inputs.old_holder.is_none() && inputs.new_holder.is_none() { - return Err(InitError( - "Either old holder or new holder data must be provided".into(), + return Err(LocalError::new( + "Either old holder or new holder data must be provided", )); }; let message_destinations = if inputs.old_holder.is_some() { // It is possible that a party is both an old holder and a new holder. // This will be processed separately. - let mut new_holders_except_me = inputs.new_holders; - new_holders_except_me.remove(&my_id); - new_holders_except_me + inputs.new_holders.clone().without(&id) + } else { + BTreeSet::new() + }; + + let expecting_messages_from = if let Some(new_holder) = inputs.new_holder.as_ref() { + // TODO: we only need `old_threshold` of them, but it is not supported yet in `manul`. + new_holder.old_holders.clone().without(&id) } else { BTreeSet::new() }; + let echo_round_participation = + if inputs.old_holder.is_some() && !inputs.new_holder.is_some() { + EchoRoundParticipation::Send + } else if inputs.new_holder.is_some() && !inputs.old_holder.is_some() { + EchoRoundParticipation::Receive { + echo_targets: inputs.new_holders.without(&id), + } + } else { + EchoRoundParticipation::Default + }; + let old_holder = inputs.old_holder.map(|old_holder| { let polynomial = Polynomial::random( rng, @@ -148,16 +207,17 @@ impl FirstRound for Round1 { .new_holder .map(|new_holder| NewHolderData { inputs: new_holder }); - Ok(Round1 { + Ok(BoxedRound::new_dynamic(Round1 { old_holder, new_holder, new_share_ids, new_threshold: inputs.new_threshold, - other_ids, - my_id, + my_id: id, message_destinations, + expecting_messages_from, + echo_round_participation, phantom: PhantomData, - }) + })) } } @@ -178,136 +238,115 @@ pub struct Round1Payload { old_share_id: ShareId, } -impl Round for Round1 { - type Type = ToResult; - type Result = KeyResharingResult; - const ROUND_NUM: u8 = 1; - const NEXT_ROUND_NUM: Option = None; +impl Round for Round1 { + type Protocol = KeyResharingProtocol; - fn other_ids(&self) -> &BTreeSet { - &self.other_ids + fn id(&self) -> RoundId { + RoundId::new(1) } - fn my_id(&self) -> &I { - &self.my_id + fn possible_next_rounds(&self) -> BTreeSet { + BTreeSet::new() } - const REQUIRES_ECHO: bool = true; - type BroadcastMessage = Round1BroadcastMessage; - type DirectMessage = Round1DirectMessage; - type Payload = Round1Payload; - type Artifact = (); - fn message_destinations(&self) -> &BTreeSet { &self.message_destinations } - fn make_broadcast_message( + fn expecting_messages_from(&self) -> &BTreeSet { + &self.expecting_messages_from + } + + fn echo_round_participation(&self) -> EchoRoundParticipation { + self.echo_round_participation.clone() + } + + fn make_echo_broadcast( &self, _rng: &mut impl CryptoRngCore, - ) -> Option { - self.old_holder - .as_ref() - .map(|old_holder| Round1BroadcastMessage { - public_polynomial: old_holder.public_polynomial.clone(), - old_share_id: old_holder.share_id, - }) + serializer: &Serializer, + ) -> Result { + if let Some(old_holder) = self.old_holder.as_ref() { + EchoBroadcast::new( + serializer, + Round1BroadcastMessage { + public_polynomial: old_holder.public_polynomial.clone(), + old_share_id: old_holder.share_id, + }, + ) + } else { + Ok(EchoBroadcast::none()) + } } fn make_direct_message( &self, _rng: &mut impl CryptoRngCore, + serializer: &Serializer, destination: &I, - ) -> (Self::DirectMessage, Self::Artifact) { + ) -> Result<(DirectMessage, Option), LocalError> { if let Some(old_holder) = self.old_holder.as_ref() { let subshare = old_holder .polynomial .evaluate(&self.new_share_ids[destination]); - (Round1DirectMessage { subshare }, ()) + let dm = DirectMessage::new(serializer, Round1DirectMessage { subshare })?; + Ok((dm, None)) } else { - // TODO (#54): this should be prevented by type system - panic!("This node does not send messages in this round"); + Ok((DirectMessage::none(), None)) } } - fn verify_message( + fn receive_message( &self, _rng: &mut impl CryptoRngCore, + deserializer: &Deserializer, from: &I, - broadcast_msg: Self::BroadcastMessage, - direct_msg: Self::DirectMessage, - ) -> Result::ProvableError> { + echo_broadcast: EchoBroadcast, + normal_broadcast: NormalBroadcast, + direct_message: DirectMessage, + ) -> Result> { + normal_broadcast.assert_is_none()?; + let echo_broadcast = echo_broadcast.deserialize::(deserializer)?; + let direct_message = direct_message.deserialize::(deserializer)?; + if let Some(new_holder) = self.new_holder.as_ref() { if new_holder.inputs.old_holders.contains(from) { - let public_subshare_from_poly = broadcast_msg + let public_subshare_from_poly = echo_broadcast .public_polynomial - .evaluate(&self.new_share_ids[self.my_id()]); - let public_subshare_from_private = direct_msg.subshare.mul_by_generator(); + .evaluate(&self.new_share_ids[&self.my_id]); + let public_subshare_from_private = direct_message.subshare.mul_by_generator(); // Check that the public polynomial sent in the broadcast corresponds to the secret share // sent in the direct message. if public_subshare_from_poly != public_subshare_from_private { - return Err(KeyResharingError::SubshareMismatch); + return Err(ReceiveError::protocol(KeyResharingError::SubshareMismatch)); } - return Ok(Round1Payload { - subshare: direct_msg.subshare, - public_polynomial: broadcast_msg.public_polynomial, - old_share_id: broadcast_msg.old_share_id, - }); + return Ok(Payload::new(Round1Payload { + subshare: direct_message.subshare, + public_polynomial: echo_broadcast.public_polynomial, + old_share_id: echo_broadcast.old_share_id, + })); } } - Err(KeyResharingError::UnexpectedSender) + Err(ReceiveError::protocol(KeyResharingError::UnexpectedSender)) } - fn finalization_requirement() -> FinalizationRequirement { - FinalizationRequirement::Custom - } - - fn can_finalize(&self, received: &BTreeSet) -> bool { - if let Some(new_holder) = self.new_holder.as_ref() { - let threshold = if self.old_holder.is_some() && self.new_holder.is_some() { - new_holder.inputs.old_threshold - 1 - } else { - new_holder.inputs.old_threshold - }; - received.len() >= threshold - } else { - true - } - } - - fn missing_messages(&self, received: &BTreeSet) -> BTreeSet { - if let Some(new_holder) = self.new_holder.as_ref() { - new_holder - .inputs - .old_holders - .iter() - .filter(|id| !received.contains(id) && id != &self.my_id()) - .cloned() - .collect() - } else { - BTreeSet::new() - } - } -} - -impl FinalizableToResult for Round1 { - fn finalize_to_result( + fn finalize( self, _rng: &mut impl CryptoRngCore, - payloads: BTreeMap>::Payload>, - _artifacts: BTreeMap>::Artifact>, - ) -> Result<::Success, FinalizeError> { + payloads: BTreeMap, + _artifacts: BTreeMap, + ) -> Result, FinalizeError> { // If this party is not a new holder, exit. let new_holder = match self.new_holder.as_ref() { Some(new_holder) => new_holder, - None => return Ok(None), + None => return Ok(FinalizeOutcome::Result(None)), }; - let share_id = self.new_share_ids[self.my_id()]; + let mut payloads = payloads.downcast_all::()?; - let mut payloads = payloads; + let share_id = self.new_share_ids[&self.my_id]; // If this node is both an old and a new holder, // add a simulated payload to the mapping, as if it sent a message to itself. @@ -319,7 +358,7 @@ impl FinalizableToResult for Round1< public_polynomial: old_holder.public_polynomial.clone(), old_share_id: old_holder.share_id, }; - payloads.insert(self.my_id().clone(), my_payload); + payloads.insert(self.my_id.clone(), my_payload); } } @@ -367,14 +406,14 @@ impl FinalizableToResult for Round1< }) .collect(); - Ok(Some(ThresholdKeyShare { - owner: self.my_id().clone(), + Ok(FinalizeOutcome::Result(Some(ThresholdKeyShare { + owner: self.my_id.clone(), threshold: self.new_threshold as u32, secret_share, share_ids: self.new_share_ids, public_shares, phantom: PhantomData, - })) + }))) } } @@ -382,114 +421,104 @@ impl FinalizableToResult for Round1< mod tests { use alloc::collections::{BTreeMap, BTreeSet}; + use manul::{ + session::{signature::Keypair, SessionOutcome}, + testing::{run_sync, BinaryFormat, TestSessionParams, TestSigner, TestVerifier}, + }; use rand_core::{OsRng, RngCore}; use secrecy::ExposeSecret; use super::ThresholdKeyShare; use super::{KeyResharingInputs, NewHolder, OldHolder, Round1}; - use crate::rounds::{ - test_utils::{step_result, step_round, Id}, - FirstRound, - }; use crate::TestParams; #[test] fn execute_key_reshare() { - let mut shared_randomness = [0u8; 32]; - OsRng.fill_bytes(&mut shared_randomness); - - let ids = [Id(0), Id(1), Id(2), Id(3)]; + let signers = (0..4).map(TestSigner::new).collect::>(); + let ids = signers + .iter() + .map(|signer| signer.verifying_key()) + .collect::>(); let old_holders = BTreeSet::from([ids[0], ids[1], ids[2]]); let new_holders = BTreeSet::from([ids[1], ids[2], ids[3]]); - let old_key_shares = - ThresholdKeyShare::::new_centralized(&mut OsRng, &old_holders, 2, None); + let old_key_shares = ThresholdKeyShare::::new_centralized( + &mut OsRng, + &old_holders, + 2, + None, + ); let old_vkey = old_key_shares[&ids[0]].verifying_key(); - let party0 = Round1::new( - &mut OsRng, - &shared_randomness, - BTreeSet::from([ids[1], ids[2], ids[3]]), - ids[0], - KeyResharingInputs { - old_holder: Some(OldHolder { - key_share: old_key_shares[&ids[0]].clone(), - }), - new_holder: None, - new_holders: new_holders.clone(), - new_threshold: 2, - }, - ) - .unwrap(); - - let party1 = Round1::new( - &mut OsRng, - &shared_randomness, - BTreeSet::from([ids[0], ids[2], ids[3]]), - ids[1], - KeyResharingInputs { - old_holder: Some(OldHolder { - key_share: old_key_shares[&ids[1]].clone(), - }), - new_holder: Some(NewHolder { - verifying_key: old_vkey, - old_threshold: 2, - old_holders: old_holders.clone(), - }), - new_holders: new_holders.clone(), - new_threshold: 2, - }, - ) - .unwrap(); - - let party2 = Round1::new( - &mut OsRng, - &shared_randomness, - BTreeSet::from([ids[0], ids[1], ids[3]]), - ids[2], - KeyResharingInputs { - old_holder: Some(OldHolder { - key_share: old_key_shares[&ids[2]].clone(), - }), - new_holder: Some(NewHolder { - verifying_key: old_vkey, - old_threshold: 2, - old_holders: old_holders.clone(), - }), - new_holders: new_holders.clone(), - new_threshold: 2, - }, - ) - .unwrap(); - - let party3 = Round1::new( - &mut OsRng, - &shared_randomness, - BTreeSet::from([ids[0], ids[1], ids[2]]), - ids[3], - KeyResharingInputs { - old_holder: None, - new_holder: Some(NewHolder { - verifying_key: old_vkey, - old_threshold: 2, - old_holders: old_holders.clone(), - }), - new_holders: new_holders.clone(), - new_threshold: 2, - }, - ) - .unwrap(); - - let r1 = BTreeMap::from([ - (ids[0], party0), - (ids[1], party1), - (ids[2], party2), - (ids[3], party3), - ]); - - let r1a = step_round(&mut OsRng, r1).unwrap(); - let shares = step_result(&mut OsRng, r1a).unwrap(); + let party0 = KeyResharingInputs { + old_holder: Some(OldHolder { + key_share: old_key_shares[&ids[0]].clone(), + }), + new_holder: None, + new_holders: new_holders.clone(), + new_threshold: 2, + }; + + let party1 = KeyResharingInputs { + old_holder: Some(OldHolder { + key_share: old_key_shares[&ids[1]].clone(), + }), + new_holder: Some(NewHolder { + verifying_key: old_vkey, + old_threshold: 2, + old_holders: old_holders.clone(), + }), + new_holders: new_holders.clone(), + new_threshold: 2, + }; + + let party2 = KeyResharingInputs { + old_holder: Some(OldHolder { + key_share: old_key_shares[&ids[2]].clone(), + }), + new_holder: Some(NewHolder { + verifying_key: old_vkey, + old_threshold: 2, + old_holders: old_holders.clone(), + }), + new_holders: new_holders.clone(), + new_threshold: 2, + }; + + let party3 = KeyResharingInputs { + old_holder: None, + new_holder: Some(NewHolder { + verifying_key: old_vkey, + old_threshold: 2, + old_holders: old_holders.clone(), + }), + new_holders: new_holders.clone(), + new_threshold: 2, + }; + + let inputs = signers + .into_iter() + .zip([party0, party1, party2, party3]) + .collect::>(); + + let reports = + run_sync::, TestSessionParams>( + &mut OsRng, inputs, + ) + .unwrap(); + + let shares = reports + .into_iter() + .map(|(id, report)| { + if let SessionOutcome::Result(result) = report.outcome { + Ok((id, result)) + } else { + Err("Session did not finish successfully".to_string()) + } + }) + .collect::, _>>() + .unwrap(); // Check that the party that is not among the new holders gets None as a result assert!(shares[&ids[0]].is_none());