diff --git a/Cargo.lock b/Cargo.lock index 07d3e39c1..2b7834ebb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2382,15 +2382,14 @@ dependencies = [ [[package]] name = "ecdsa" -version = "0.16.7" +version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der 0.7.7", "digest 0.10.7", - "elliptic-curve 0.13.5", + "elliptic-curve 0.13.7", "rfc6979 0.4.0", - "serdect", "signature 2.1.0", "spki 0.7.2", ] @@ -2462,9 +2461,9 @@ dependencies = [ [[package]] name = "elliptic-curve" -version = "0.13.5" +version = "0.13.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +checksum = "e9775b22bc152ad86a0cf23f0f348b884b26add12bf741e7ffc4d4ab2ab4d205" dependencies = [ "base16ct 0.2.0", "crypto-bigint 0.5.3", @@ -2475,7 +2474,6 @@ dependencies = [ "pkcs8 0.10.2", "rand_core 0.6.4", "sec1 0.7.3", - "serdect", "subtle 2.4.1", "zeroize", ] @@ -4606,15 +4604,14 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +checksum = "3f01b677d82ef7a676aa37e099defd83a28e15687112cafdd112d60236b6115b" dependencies = [ "cfg-if", - "ecdsa 0.16.7", - "elliptic-curve 0.13.5", + "ecdsa 0.16.9", + "elliptic-curve 0.13.7", "once_cell 1.18.0", - "serdect", "sha2 0.10.7", ] @@ -8441,28 +8438,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "rmp" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f" -dependencies = [ - "byteorder", - "num-traits", - "paste 1.0.13", -] - -[[package]] -name = "rmp-serde" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b13be192e0220b8afb7222aa5813cb62cc269ebb5cac346ca6487681d2913e" -dependencies = [ - "byteorder", - "rmp", - "serde", -] - [[package]] name = "rocksdb" version = "0.21.0" @@ -10056,7 +10031,6 @@ dependencies = [ "der 0.7.7", "generic-array 0.14.7", "pkcs8 0.10.2", - "serdect", "subtle 2.4.1", "zeroize", ] @@ -12207,10 +12181,11 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "synedrion" -version = "0.0.11" -source = "git+ssh://git@github.com/entropyxyz/synedrion.git?branch=fix-32bit#d536131c819f993e4627033f98d20307e0d47a5e" +version = "0.0.12" +source = "git+ssh://git@github.com/entropyxyz/synedrion.git?tag=release/v0.0.12#aef04ad5cf40db30981354da554e2a529b96af30" dependencies = [ "base64 0.21.2", + "bincode", "cfg-if", "crypto-bigint 0.5.3", "crypto-primes", @@ -12218,7 +12193,6 @@ dependencies = [ "hex", "k256", "rand_core 0.6.4", - "rmp-serde", "serde", "sha2 0.10.7", "sha3", diff --git a/crypto/kvdb/Cargo.toml b/crypto/kvdb/Cargo.toml index 8bfdc4248..35a54d855 100644 --- a/crypto/kvdb/Cargo.toml +++ b/crypto/kvdb/Cargo.toml @@ -22,7 +22,7 @@ zeroize ={ version="1.4", features=["zeroize_derive"], default-features= rpassword ={ version="5.0", default-features=false } scrypt ={ version="0.11.0", default-features=false, features=["std"] } chacha20poly1305={ version="0.9", features=["alloc"], default-features=false } -synedrion ={ git="ssh://git@github.com/entropyxyz/synedrion.git", branch="fix-32bit" } +synedrion ={ git="ssh://git@github.com/entropyxyz/synedrion.git", tag="release/v0.0.12" } # Async tokio ={ version="1.16", features=["macros", "sync", "fs", "rt-multi-thread", "io-util"] } diff --git a/crypto/protocol/Cargo.toml b/crypto/protocol/Cargo.toml index cf57d5677..8bb632d13 100644 --- a/crypto/protocol/Cargo.toml +++ b/crypto/protocol/Cargo.toml @@ -11,7 +11,7 @@ edition ='2021' [dependencies] async-trait="0.1.73" entropy-shared={ path="../shared", default-features=false } -synedrion={ git="ssh://git@github.com/entropyxyz/synedrion.git", branch="fix-32bit" } +synedrion={ git="ssh://git@github.com/entropyxyz/synedrion.git", tag="release/v0.0.12" } serde={ version="1.0", features=["derive"], default-features=false } subxt={ package="subxt", git="https://github.com/paritytech/subxt.git", tag="v0.32.1", default-features=false } sp-core={ version="21.0.0", default-features=false, features=["full_crypto", "serde"] } diff --git a/crypto/protocol/src/errors.rs b/crypto/protocol/src/errors.rs index 8a422f135..466ded9e4 100644 --- a/crypto/protocol/src/errors.rs +++ b/crypto/protocol/src/errors.rs @@ -1,18 +1,84 @@ +use synedrion::{ + sessions, InteractiveSigningResult, KeyRefreshResult, KeygenAndAuxResult, ProtocolResult, +}; use thiserror::Error; use crate::{ protocol_message::ProtocolMessage, protocol_transport::errors::EncryptedConnectionErr, + KeyParams, PartyId, }; +#[derive(Debug, Error)] +pub enum GenericProtocolError { + #[error("Synedrion session error {0}")] + Joined(Box>), + #[error("Incoming message stream error: {0}")] + IncomingStream(String), + #[error("Broadcast error: {0}")] + Broadcast(#[from] Box>), +} + +impl From for GenericProtocolError { + fn from(err: sessions::LocalError) -> Self { + Self::Joined(Box::new(sessions::Error::Local(err))) + } +} + +impl From> for GenericProtocolError { + fn from(err: sessions::RemoteError) -> Self { + Self::Joined(Box::new(sessions::Error::Remote(err))) + } +} + +impl From> for GenericProtocolError { + fn from(err: sessions::Error) -> Self { + Self::Joined(Box::new(err)) + } +} + +impl From>> for ProtocolExecutionErr { + fn from(err: GenericProtocolError>) -> Self { + match err { + GenericProtocolError::Joined(err) => ProtocolExecutionErr::SigningProtocolError(err), + GenericProtocolError::IncomingStream(err) => ProtocolExecutionErr::IncomingStream(err), + GenericProtocolError::Broadcast(err) => ProtocolExecutionErr::Broadcast(err), + } + } +} + +impl From>> for ProtocolExecutionErr { + fn from(err: GenericProtocolError>) -> Self { + match err { + GenericProtocolError::Joined(err) => ProtocolExecutionErr::KeyGenProtocolError(err), + GenericProtocolError::IncomingStream(err) => ProtocolExecutionErr::IncomingStream(err), + GenericProtocolError::Broadcast(err) => ProtocolExecutionErr::Broadcast(err), + } + } +} + +impl From>> for ProtocolExecutionErr { + fn from(err: GenericProtocolError>) -> Self { + match err { + GenericProtocolError::Joined(err) => ProtocolExecutionErr::KeyRefreshProtocolError(err), + GenericProtocolError::IncomingStream(err) => ProtocolExecutionErr::IncomingStream(err), + GenericProtocolError::Broadcast(err) => ProtocolExecutionErr::Broadcast(err), + } + } +} + /// An error during or while setting up a protocol session #[derive(Debug, Error)] pub enum ProtocolExecutionErr { - #[error("Session Creation Error: {0}")] - SessionCreationError(synedrion::InitError), #[error("Incoming message stream error: {0}")] IncomingStream(String), - #[error("Synedrion session error {0}")] - SynedrionSession(synedrion::sessions::Error), + #[error("Synedrion session creation error: {0}")] + SessionCreation(sessions::LocalError), + #[error("Synedrion signing session error {0}")] + SigningProtocolError(Box, PartyId>>), + #[error("Synedrion keygen session error {0}")] + KeyGenProtocolError(Box, PartyId>>), + #[error("Synedrion key refresh session error {0}")] + KeyRefreshProtocolError(Box, PartyId>>), #[error("Broadcast error: {0}")] Broadcast(#[from] Box>), #[error("Bad keyshare error {0}")] @@ -25,6 +91,8 @@ pub enum UserRunningProtocolErr { #[error("Encrypted Connection Error: {0}")] EncryptedConnection(#[from] EncryptedConnectionErr), #[error("Protocol Execution Error {0}")] + SigningProtocolExecution(#[from] GenericProtocolError>), + #[error("Protocol Execution Error {0}")] ProtocolExecution(#[from] ProtocolExecutionErr), #[error("Serialization Error: {0:?}")] Serialization(#[from] bincode::Error), diff --git a/crypto/protocol/src/execute_protocol.rs b/crypto/protocol/src/execute_protocol.rs index 83277006b..026883fbc 100644 --- a/crypto/protocol/src/execute_protocol.rs +++ b/crypto/protocol/src/execute_protocol.rs @@ -1,5 +1,4 @@ //! A wrapper for the threshold signing library to handle sending and receiving messages. -use std::collections::HashMap; use rand_core::{CryptoRngCore, OsRng}; use sp_core::{sr25519, Pair}; @@ -7,19 +6,18 @@ use subxt::utils::AccountId32; use synedrion::{ sessions::{ make_interactive_signing_session, make_key_refresh_session, make_keygen_and_aux_session, - FinalizeOutcome, PrehashedMessage, ToSend, + FinalizeOutcome, PrehashedMessage, Session, }, - signature::{ - self, - hazmat::{PrehashVerifier, RandomizedPrehashSigner}, - }, - KeyShare, PartyIdx, RecoverableSignature, + signature::{self, hazmat::RandomizedPrehashSigner}, + KeyShare, ProtocolResult, RecoverableSignature, }; use tokio::sync::mpsc; use crate::{ - errors::ProtocolExecutionErr, protocol_message::ProtocolMessage, - protocol_transport::Broadcaster, KeyParams, PartyId, + errors::{GenericProtocolError, ProtocolExecutionErr}, + protocol_message::ProtocolMessage, + protocol_transport::Broadcaster, + KeyParams, PartyId, }; pub type ChannelIn = mpsc::Receiver; @@ -28,12 +26,17 @@ pub type ChannelOut = Broadcaster; /// Thin wrapper broadcasting channel out and messages from other nodes in pub struct Channels(pub ChannelOut, pub ChannelIn); -struct SignerWrapper(sr25519::Pair); +struct PairWrapper(sr25519::Pair); + +impl signature::Keypair for PairWrapper { + type VerifyingKey = PartyId; -#[derive(Clone)] -struct VerifierWrapper(sr25519::Public); + fn verifying_key(&self) -> Self::VerifyingKey { + self.0.public().into() + } +} -impl RandomizedPrehashSigner for SignerWrapper { +impl RandomizedPrehashSigner for PairWrapper { fn sign_prehash_with_rng( &self, _rng: &mut impl CryptoRngCore, @@ -44,16 +47,81 @@ impl RandomizedPrehashSigner for SignerWrapper { } } -impl PrehashVerifier for VerifierWrapper { - fn verify_prehash( - &self, - prehash: &[u8], - signature: &sr25519::Signature, - ) -> Result<(), signature::Error> { - if sr25519::Pair::verify(signature, prehash, &self.0) { - Ok(()) - } else { - Err(signature::Error::new()) +async fn execute_protocol_generic( + mut chans: Channels, + session: Session, +) -> Result> { + let tx = &chans.0; + let rx = &mut chans.1; + + let my_id = session.verifier(); + + let mut session = session; + let mut cached_messages = Vec::new(); + + loop { + let mut accum = session.make_accumulator(); + + // Send out broadcasts + let destinations = session.broadcast_destinations(); + if let Some(destinations) = destinations { + // TODO: this can happen in a spawned task + let message = session.make_broadcast(&mut OsRng)?; + for destination in destinations.iter() { + tx.send(ProtocolMessage::new(&my_id, destination, message.clone()))?; + } + } + + // Send out direct messages + let destinations = session.direct_message_destinations(); + if let Some(destinations) = destinations { + for destination in destinations.iter() { + // TODO: this can happen in a spawned task. + // The artefact will be sent back to the host task + // to be added to the accumulator. + let (message, artefact) = session.make_direct_message(&mut OsRng, destination)?; + tx.send(ProtocolMessage::new(&my_id, destination, message))?; + + // This will happen in a host task + accum.add_artefact(artefact)?; + } + } + + for preprocessed in cached_messages { + // TODO: this may happen in a spawned task. + let processed = session.process_message(preprocessed)?; + + // This will happen in a host task. + accum.add_processed_message(processed)??; + } + + while !session.can_finalize(&accum)? { + let message = rx.recv().await.ok_or_else(|| { + GenericProtocolError::IncomingStream(format!("{:?}", session.current_round())) + })?; + + // Perform quick checks before proceeding with the verification. + let preprocessed = + session.preprocess_message(&mut accum, &message.from, message.payload)?; + + if let Some(preprocessed) = preprocessed { + // TODO: this may happen in a spawned task. + let result = session.process_message(preprocessed)?; + + // This will happen in a host task. + accum.add_processed_message(result)??; + } + } + + match session.finalize_round(&mut OsRng, accum)? { + FinalizeOutcome::Success(res) => break Ok(res), + FinalizeOutcome::AnotherRound { + session: new_session, + cached_messages: new_cached_messages, + } => { + session = new_session; + cached_messages = new_cached_messages; + }, } } } @@ -65,97 +133,35 @@ impl PrehashVerifier for VerifierWrapper { level = tracing::Level::DEBUG )] pub async fn execute_signing_protocol( - mut chans: Channels, + chans: Channels, key_share: &KeyShare, prehashed_message: &PrehashedMessage, - threshold_signer: &sr25519::Pair, + threshold_pair: &sr25519::Pair, threshold_accounts: Vec, ) -> Result { tracing::debug!("Executing signing protocol"); tracing::trace!("Using key share {:?}", &key_share); - let party_ids: Vec = - threshold_accounts.clone().into_iter().map(PartyId::new).collect(); - let my_idx = key_share.party_index(); - let my_id = party_ids.get(my_idx.as_usize()).ok_or(ProtocolExecutionErr::BadKeyShare( - "Keyshare index is greater than the number of parties".to_string(), - ))?; - - let id_to_index = party_ids - .iter() - .enumerate() - .map(|(idx, id)| (id, PartyIdx::from_usize(idx))) - .collect::>(); - - let tx = &chans.0; - let rx = &mut chans.1; + let party_ids: Vec = threshold_accounts.iter().cloned().map(PartyId::new).collect(); - let signer = SignerWrapper(threshold_signer.clone()); - // TODO (#376): while `Public::from_raw` happens to work here, it is not the correct way. - // We should have `Public` objects at this point, not `AccountId32`. - let verifiers = threshold_accounts - .into_iter() - .map(|acc| VerifierWrapper(sr25519::Public(acc.0))) - .collect::>(); + let pair = PairWrapper(threshold_pair.clone()); // TODO (#375): this should come from whoever initiates the signing process, // (or as some deterministic function, e.g. the hash of the last block mined) // and be the same for all participants. let shared_randomness = b"123456"; - let mut sending = make_interactive_signing_session( + let session = make_interactive_signing_session( &mut OsRng, shared_randomness, - signer, - &verifiers, + pair, + &party_ids, key_share, prehashed_message, ) - .map_err(ProtocolExecutionErr::SessionCreationError)?; - - loop { - let (mut receiving, to_send) = - sending.start_receiving(&mut OsRng).map_err(ProtocolExecutionErr::SynedrionSession)?; - - match to_send { - ToSend::Broadcast(message) => { - tx.send(ProtocolMessage::new_bcast(my_id, message))?; - }, - ToSend::Direct(msgs) => { - for (id_to, message) in msgs.into_iter() { - tx.send(ProtocolMessage::new_p2p( - my_id, - &party_ids[id_to.as_usize()], - message, - ))?; - } - }, - }; - - while receiving.has_cached_messages() { - receiving.receive_cached_message().map_err(ProtocolExecutionErr::SynedrionSession)?; - } - - while !receiving.can_finalize() { - let signing_message = rx.recv().await.ok_or_else(|| { - ProtocolExecutionErr::IncomingStream(format!("{:?}", receiving.current_stage())) - })?; + .map_err(ProtocolExecutionErr::SessionCreation)?; - // TODO: we shouldn't send broadcasts to ourselves in the first place. - if &signing_message.from == my_id { - continue; - } - let from_idx = id_to_index[&signing_message.from]; - receiving - .receive(from_idx, signing_message.payload) - .map_err(ProtocolExecutionErr::SynedrionSession)?; - } - - match receiving.finalize(&mut OsRng).map_err(ProtocolExecutionErr::SynedrionSession)? { - FinalizeOutcome::Result(res) => break Ok(res), - FinalizeOutcome::AnotherRound(new_sending) => sending = new_sending, - } - } + Ok(execute_protocol_generic(chans, session).await?) } /// Execute dkg. @@ -165,91 +171,25 @@ pub async fn execute_signing_protocol( level = tracing::Level::DEBUG )] pub async fn execute_dkg( - mut chans: Channels, - threshold_signer: &sr25519::Pair, + chans: Channels, + threshold_pair: &sr25519::Pair, threshold_accounts: Vec, - my_idx: &u8, ) -> Result, ProtocolExecutionErr> { tracing::debug!("Executing DKG"); - let party_ids: Vec = - threshold_accounts.clone().into_iter().map(PartyId::new).collect(); - let my_id = PartyId::new(threshold_accounts[*my_idx as usize].clone()); + let party_ids: Vec = threshold_accounts.iter().cloned().map(PartyId::new).collect(); - let id_to_index = party_ids - .iter() - .enumerate() - .map(|(idx, id)| (id, PartyIdx::from_usize(idx))) - .collect::>(); - - let tx = &chans.0; - let rx = &mut chans.1; - - let signer = SignerWrapper(threshold_signer.clone()); - // TODO (#376): while `Public::from_raw` happens to work here, it is not the correct way. - // We should have `Public` objects at this point, not `AccountId32`. - let verifiers = threshold_accounts - .into_iter() - .map(|acc| VerifierWrapper(sr25519::Public(acc.0))) - .collect::>(); + let pair = PairWrapper(threshold_pair.clone()); // TODO (#375): this should come from whoever initiates the signing process, // (or as some deterministic function, e.g. the hash of the last block mined) // and be the same for all participants. let shared_randomness = b"123456"; - let mut sending = make_keygen_and_aux_session( - &mut OsRng, - shared_randomness, - signer, - &verifiers, - PartyIdx::from_usize(*my_idx as usize), - ) - .map_err(ProtocolExecutionErr::SessionCreationError)?; - - loop { - let (mut receiving, to_send) = - sending.start_receiving(&mut OsRng).map_err(ProtocolExecutionErr::SynedrionSession)?; - - match to_send { - ToSend::Broadcast(message) => { - tx.send(ProtocolMessage::new_bcast(&my_id, message))?; - }, - ToSend::Direct(msgs) => { - for (id_to, message) in msgs.into_iter() { - tx.send(ProtocolMessage::new_p2p( - &my_id, - &party_ids[id_to.as_usize()], - message, - ))?; - } - }, - }; - - while receiving.has_cached_messages() { - receiving.receive_cached_message().map_err(ProtocolExecutionErr::SynedrionSession)?; - } - - while !receiving.can_finalize() { - let signing_message = rx.recv().await.ok_or_else(|| { - ProtocolExecutionErr::IncomingStream(format!("{:?}", receiving.current_stage())) - })?; - - // TODO: we shouldn't send broadcasts to ourselves in the first place. - if signing_message.from == my_id { - continue; - } - let from_idx = id_to_index[&signing_message.from]; - receiving - .receive(from_idx, signing_message.payload) - .map_err(ProtocolExecutionErr::SynedrionSession)?; - } + let session = make_keygen_and_aux_session(&mut OsRng, shared_randomness, pair, &party_ids) + .map_err(ProtocolExecutionErr::SessionCreation)?; - match receiving.finalize(&mut OsRng).map_err(ProtocolExecutionErr::SynedrionSession)? { - FinalizeOutcome::Result(res) => break Ok(res), - FinalizeOutcome::AnotherRound(new_sending) => sending = new_sending, - } - } + Ok(execute_protocol_generic(chans, session).await?) } /// Execute proactive refresh. @@ -259,92 +199,28 @@ pub async fn execute_dkg( level = tracing::Level::DEBUG )] pub async fn execute_proactive_refresh( - mut chans: Channels, - threshold_signer: &sr25519::Pair, + chans: Channels, + threshold_pair: &sr25519::Pair, threshold_accounts: Vec, - my_idx: &u8, old_key: KeyShare, ) -> Result, ProtocolExecutionErr> { tracing::debug!("Executing proactive refresh"); - tracing::debug!("Signing with {:?}", &threshold_signer.public()); + tracing::debug!("Signing with {:?}", &threshold_pair.public()); tracing::trace!("Previous key {:?}", &old_key); - let party_ids: Vec = - threshold_accounts.clone().into_iter().map(PartyId::new).collect(); - let my_id = PartyId::new(threshold_accounts[*my_idx as usize].clone()); - let id_to_index = party_ids - .iter() - .enumerate() - .map(|(idx, id)| (id, PartyIdx::from_usize(idx))) - .collect::>(); + let party_ids: Vec = threshold_accounts.iter().cloned().map(PartyId::new).collect(); - let tx = &chans.0; - let rx = &mut chans.1; - - let signer = SignerWrapper(threshold_signer.clone()); - // TODO (#376): while `Public::from_raw` happens to work here, it is not the correct way. - // We should have `Public` objects at this point, not `AccountId32`. - let verifiers = threshold_accounts - .into_iter() - .map(|acc| VerifierWrapper(sr25519::Public(acc.0))) - .collect::>(); + let pair = PairWrapper(threshold_pair.clone()); // TODO (#375): this should come from whoever initiates the signing process, // (or as some deterministic function, e.g. the hash of the last block mined) // and be the same for all participants. let shared_randomness = b"123456"; - let mut sending = make_key_refresh_session( - &mut OsRng, - shared_randomness, - signer, - &verifiers, - PartyIdx::from_usize(*my_idx as usize), - ) - .map_err(ProtocolExecutionErr::SessionCreationError)?; - let key_change = loop { - let (mut receiving, to_send) = - sending.start_receiving(&mut OsRng).map_err(ProtocolExecutionErr::SynedrionSession)?; - - match to_send { - ToSend::Broadcast(message) => { - tx.send(ProtocolMessage::new_bcast(&my_id, message))?; - }, - ToSend::Direct(msgs) => { - for (id_to, message) in msgs.into_iter() { - tx.send(ProtocolMessage::new_p2p( - &my_id, - &party_ids[id_to.as_usize()], - message, - ))?; - } - }, - }; - - while receiving.has_cached_messages() { - receiving.receive_cached_message().map_err(ProtocolExecutionErr::SynedrionSession)?; - } + let session = make_key_refresh_session(&mut OsRng, shared_randomness, pair, &party_ids) + .map_err(ProtocolExecutionErr::SessionCreation)?; - while !receiving.can_finalize() { - let signing_message = rx.recv().await.ok_or_else(|| { - ProtocolExecutionErr::IncomingStream(format!("{:?}", receiving.current_stage())) - })?; - - // TODO: we shouldn't send broadcasts to ourselves in the first place. - if signing_message.from == my_id { - continue; - } - let from_idx = id_to_index[&signing_message.from]; - receiving - .receive(from_idx, signing_message.payload) - .map_err(ProtocolExecutionErr::SynedrionSession)?; - } - - match receiving.finalize(&mut OsRng).map_err(ProtocolExecutionErr::SynedrionSession)? { - FinalizeOutcome::Result(res) => break res, - FinalizeOutcome::AnotherRound(new_sending) => sending = new_sending, - } - }; + let key_change = execute_protocol_generic(chans, session).await?; Ok(old_key.update(key_change)) } diff --git a/crypto/protocol/src/lib.rs b/crypto/protocol/src/lib.rs index bf6e701ee..b6726bdac 100644 --- a/crypto/protocol/src/lib.rs +++ b/crypto/protocol/src/lib.rs @@ -11,11 +11,15 @@ use std::fmt; use entropy_shared::X25519PublicKey; pub use protocol_message::ProtocolMessage; use serde::{Deserialize, Serialize}; +use sp_core::{sr25519, Pair}; use subxt::utils::AccountId32; -use synedrion::k256::ecdsa::{RecoveryId, Signature}; +use synedrion::{ + k256::ecdsa::{RecoveryId, Signature}, + signature::{self, hazmat::PrehashVerifier}, +}; /// Identifies a party participating in a protocol session -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub struct PartyId(AccountId32); impl std::hash::Hash for PartyId { @@ -28,6 +32,34 @@ impl PartyId { pub fn new(acc: AccountId32) -> Self { Self(acc) } + + fn to_public(&self) -> sr25519::Public { + // TODO (#376): assuming that `Public` and `AccountId32` represent the same 32 bytes. + // Ideally we should use only one of those throughout the code, probably `Public`. + sr25519::Public(self.0 .0) + } +} + +impl From for PartyId { + fn from(public_key: sr25519::Public) -> Self { + // TODO (#376): assuming that `Public` and `AccountId32` represent the same 32 bytes. + // Ideally we should use only one of those throughout the code, probably `Public`. + Self(AccountId32(public_key.0)) + } +} + +impl PrehashVerifier for PartyId { + fn verify_prehash( + &self, + prehash: &[u8], + signature: &sr25519::Signature, + ) -> Result<(), signature::Error> { + if sr25519::Pair::verify(signature, prehash, &self.to_public()) { + Ok(()) + } else { + Err(signature::Error::new()) + } + } } impl From for String { diff --git a/crypto/protocol/src/protocol_message.rs b/crypto/protocol/src/protocol_message.rs index 11eb31628..059a6d2ff 100644 --- a/crypto/protocol/src/protocol_message.rs +++ b/crypto/protocol/src/protocol_message.rs @@ -12,8 +12,8 @@ use crate::{protocol_transport::errors::ProtocolMessageErr, PartyId}; pub struct ProtocolMessage { /// Identifier of the author of this message pub from: PartyId, - /// If `None`, it's a broadcast message sent to all parties - pub to: Option, + /// Identifier of the destination of this message + pub to: PartyId, /// The signed protocol message pub payload: SignedMessage, } @@ -28,15 +28,11 @@ impl TryFrom<&[u8]> for ProtocolMessage { } impl ProtocolMessage { - pub(crate) fn new_bcast(from: &PartyId, payload: SignedMessage) -> Self { - Self { from: from.clone(), to: None, payload } - } - - pub(crate) fn new_p2p( + pub(crate) fn new( from: &PartyId, to: &PartyId, payload: SignedMessage, ) -> Self { - Self { from: from.clone(), to: Some(to.clone()), payload } + Self { from: from.clone(), to: to.clone(), payload } } } diff --git a/crypto/protocol/src/protocol_transport/mod.rs b/crypto/protocol/src/protocol_transport/mod.rs index 0d282e77b..0caa1d47e 100644 --- a/crypto/protocol/src/protocol_transport/mod.rs +++ b/crypto/protocol/src/protocol_transport/mod.rs @@ -124,10 +124,8 @@ pub async fn ws_to_channels( msg_result = ws_channels.broadcast.recv() => { if let Ok(msg) = msg_result { // Check that the message is for this peer - if let Some(party_id) = &msg.to { - if party_id != &remote_party_id { - continue; - } + if msg.to != remote_party_id { + continue; } let message_vec = bincode::serialize(&msg)?; // TODO if this fails, the ws connection has been dropped during the protocol diff --git a/crypto/protocol/src/user/mod.rs b/crypto/protocol/src/user/mod.rs index 18a97fabc..2179327a7 100644 --- a/crypto/protocol/src/user/mod.rs +++ b/crypto/protocol/src/user/mod.rs @@ -1,6 +1,5 @@ #[cfg(feature = "wasm")] pub mod wasm; -use entropy_shared::SIGNING_PARTY_SIZE; use futures::{future, Future}; use sp_core::{sr25519, Pair}; use subxt::utils::AccountId32; @@ -75,13 +74,8 @@ pub async fn user_participates_in_dkg_protocol( ) .await?; - // The user's subgroup id is SIGNING_PARTY_SIZE. They will always be alone in their subgroup - // as all other subgroup id's are < SIGNING_PARTY_SIZE - let user_subgroup = SIGNING_PARTY_SIZE as u8; - let keyshare = - execute_protocol::execute_dkg(channels, user_signing_keypair, tss_accounts, &user_subgroup) - .await?; + execute_protocol::execute_dkg(channels, user_signing_keypair, tss_accounts).await?; Ok(keyshare) } diff --git a/crypto/protocol/src/user/wasm.rs b/crypto/protocol/src/user/wasm.rs index 1ee197c9e..7e33d1d6b 100644 --- a/crypto/protocol/src/user/wasm.rs +++ b/crypto/protocol/src/user/wasm.rs @@ -222,6 +222,6 @@ impl KeyShare { /// Get the party index of this keyshare (a number indentiying which party we are) #[wasm_bindgen(js_name = partyIndex)] pub fn party_index(&self) -> usize { - self.0.party_index().as_usize() + self.0.party_index() } } diff --git a/crypto/server/Cargo.toml b/crypto/server/Cargo.toml index 4dd849312..fe0e964a5 100644 --- a/crypto/server/Cargo.toml +++ b/crypto/server/Cargo.toml @@ -20,7 +20,7 @@ zeroize ="1.5.7" hex ="*" reqwest-eventsource="0.4" serde_derive ="1.0.147" -synedrion ={ git="ssh://git@github.com/entropyxyz/synedrion.git", branch="fix-32bit" } +synedrion ={ git="ssh://git@github.com/entropyxyz/synedrion.git", tag="release/v0.0.12" } # Async futures="0.3" diff --git a/crypto/server/src/helpers/user.rs b/crypto/server/src/helpers/user.rs index 0f1fc339b..fe7ebb174 100644 --- a/crypto/server/src/helpers/user.rs +++ b/crypto/server/src/helpers/user.rs @@ -27,7 +27,6 @@ pub async fn do_dkg( signer: &PairSigner, state: &ListenerState, sig_request_account: AccountId32, - my_subgroup: &u8, key_visibility: KeyVisibility, ) -> Result, UserErr> { let session_uid = sig_request_account.to_string(); @@ -87,7 +86,8 @@ pub async fn do_dkg( Channels(broadcast_out, rx_from_others) }; - let result = execute_dkg(channels, signer.signer(), tss_accounts, my_subgroup).await?; + let result = execute_dkg(channels, signer.signer(), tss_accounts).await?; + Ok(result) } diff --git a/crypto/server/src/signing_client/api.rs b/crypto/server/src/signing_client/api.rs index e6161614a..3c2c02bca 100644 --- a/crypto/server/src/signing_client/api.rs +++ b/crypto/server/src/signing_client/api.rs @@ -105,7 +105,6 @@ pub async fn proactive_refresh( &signer, &app_state.listener_state, sig_request_address, - &my_subgroup, deserialized_old_key, ) .await?; @@ -152,7 +151,6 @@ pub async fn do_proactive_refresh( signer: &PairSigner, state: &ListenerState, sig_request_account: AccountId32, - my_subgroup: &u8, old_key: KeyShare, ) -> Result, ProtocolErr> { tracing::debug!("Preparing to perform proactive refresh"); @@ -203,8 +201,7 @@ pub async fn do_proactive_refresh( Channels(broadcast_out, rx_from_others) }; let result = - execute_proactive_refresh(channels, signer.signer(), tss_accounts, my_subgroup, old_key) - .await?; + execute_proactive_refresh(channels, signer.signer(), tss_accounts, old_key).await?; Ok(result) } diff --git a/crypto/server/src/user/api.rs b/crypto/server/src/user/api.rs index 752a40833..f7d758935 100644 --- a/crypto/server/src/user/api.rs +++ b/crypto/server/src/user/api.rs @@ -254,7 +254,6 @@ async fn setup_dkg( &signer, &app_state.listener_state, sig_request_address.clone(), - &my_subgroup, *user_details.key_visibility, ) .await?; diff --git a/crypto/testing-utils/Cargo.toml b/crypto/testing-utils/Cargo.toml index 525f4f0e5..671c73ffc 100644 --- a/crypto/testing-utils/Cargo.toml +++ b/crypto/testing-utils/Cargo.toml @@ -24,7 +24,7 @@ entropy-protocol ={ path="../protocol" } axum ={ version="0.6.18" } rand_core ="0.6.4" kvdb ={ path="../kvdb", default-features=false } -synedrion ={ git="ssh://git@github.com/entropyxyz/synedrion.git", branch="fix-32bit" } +synedrion ={ git="ssh://git@github.com/entropyxyz/synedrion.git", tag="release/v0.0.12" } server ={ path="../server" } tokio ={ version="1.16", features=["macros", "fs", "rt-multi-thread", "io-util", "process"] } subxt-signer ="0.31.0"