diff --git a/Cargo.lock b/Cargo.lock index 0c2c921..c03b3df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -464,7 +464,7 @@ dependencies = [ [[package]] name = "round-based" -version = "0.4.1" +version = "0.5.0-alpha.1" dependencies = [ "anyhow", "digest", @@ -488,7 +488,7 @@ dependencies = [ [[package]] name = "round-based-derive" -version = "0.2.2" +version = "0.5.0-alpha.1" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 7fc2c2b..13ed421 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,6 @@ members = [ exclude = [ "wasm/no_std", ] + +[workspace.package] +edition = "2024" diff --git a/examples/random-generation-protocol/Cargo.toml b/examples/random-generation-protocol/Cargo.toml index edd0188..2fa50bd 100644 --- a/examples/random-generation-protocol/Cargo.toml +++ b/examples/random-generation-protocol/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "random-generation-protocol" version = "0.1.0" -edition = "2021" +edition.workspace = true publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/examples/random-generation-protocol/src/lib.rs b/examples/random-generation-protocol/src/lib.rs index cbd59ff..d7da15b 100644 --- a/examples/random-generation-protocol/src/lib.rs +++ b/examples/random-generation-protocol/src/lib.rs @@ -16,11 +16,11 @@ mod _unused_deps { use alloc::{vec, vec::Vec}; use serde::{Deserialize, Serialize}; -use sha2::{digest::Output, Digest, Sha256}; +use sha2::{Digest, Sha256, digest::Output}; use round_based::{ - mpc::{Mpc, MpcExecution}, MsgId, + mpc::{Mpc, MpcExecution}, }; /// Protocol message @@ -211,16 +211,16 @@ mod tests { fn state_machine() { use super::{CommitMsg, DecommitMsg, Msg}; use round_based::{ - state_machine::{ProceedResult, StateMachine}, Incoming, Outgoing, + state_machine::{ProceedResult, StateMachine}, }; let mut rng = rand_dev::DevRng::new(); - let party1_rng: [u8; 32] = rng.gen(); + let party1_rng: [u8; 32] = rng.r#gen(); let party1_com = Sha256::digest(party1_rng); - let party2_rng: [u8; 32] = rng.gen(); + let party2_rng: [u8; 32] = rng.r#gen(); let party2_com = Sha256::digest(party2_rng); // Start the protocol diff --git a/round-based-derive/CHANGELOG.md b/round-based-derive/CHANGELOG.md index 897a0a6..04ff091 100644 --- a/round-based-derive/CHANGELOG.md +++ b/round-based-derive/CHANGELOG.md @@ -1,3 +1,6 @@ +## v0.5.0 +* Update derive macros to be compatible with new round-based API + ## v0.2.2 * Update links in crate settings [#11] diff --git a/round-based-derive/Cargo.toml b/round-based-derive/Cargo.toml index 9631215..c23f9ae 100644 --- a/round-based-derive/Cargo.toml +++ b/round-based-derive/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "round-based-derive" -version = "0.2.2" -edition = "2021" +version = "0.5.0-alpha.1" +edition.workspace = true license = "MIT OR Apache-2.0" description = "Proc-macro for deriving `round-based` traits" repository = "https://github.com/LFDT-Lockness/round-based" diff --git a/round-based-derive/src/lib.rs b/round-based-derive/src/lib.rs index c701e65..9e81eff 100644 --- a/round-based-derive/src/lib.rs +++ b/round-based-derive/src/lib.rs @@ -4,7 +4,7 @@ use syn::ext::IdentExt; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; -use syn::{parse_macro_input, Data, DeriveInput, Fields, Generics, Ident, Token, Variant}; +use syn::{Data, DeriveInput, Fields, Generics, Ident, Token, Variant, parse_macro_input}; #[proc_macro_derive(ProtocolMsg, attributes(protocol_msg))] pub fn protocol_msg(input: proc_macro::TokenStream) -> proc_macro::TokenStream { diff --git a/round-based-tests/Cargo.toml b/round-based-tests/Cargo.toml index 0e7e65e..f1cd8d9 100644 --- a/round-based-tests/Cargo.toml +++ b/round-based-tests/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "round-based-tests" version = "0.1.0" -edition = "2021" +edition.workspace = true publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/round-based-tests/src/lib.rs b/round-based-tests/src/lib.rs index 0f46494..9b0ab7e 100644 --- a/round-based-tests/src/lib.rs +++ b/round-based-tests/src/lib.rs @@ -1,4 +1,4 @@ -use round_based::{state_machine::ProceedResult, Incoming, Outgoing}; +use round_based::{Incoming, Outgoing, state_machine::ProceedResult}; /// Wraps a state machine and provides convenient methods for feeding to and receiving messages from /// the state machine, removing a boilerplate for handling `Yield`-ing, and providing convenient diff --git a/round-based-tests/tests/random_beacon.rs b/round-based-tests/tests/random_beacon.rs index c2790f0..55a214b 100644 --- a/round-based-tests/tests/random_beacon.rs +++ b/round-based-tests/tests/random_beacon.rs @@ -1,14 +1,14 @@ use std::convert::Infallible; -use futures::{sink, stream, SinkExt}; +use futures::{SinkExt, sink, stream}; use hex_literal::hex; use matches::assert_matches; use rand_chacha::rand_core::SeedableRng; use random_generation_protocol::{ - protocol_of_random_generation, CommitMsg, DecommitMsg, Error, Msg, + CommitMsg, DecommitMsg, Error, Msg, protocol_of_random_generation, }; -use round_based::{mpc::party::CompleteRoundError, Incoming, MessageType}; +use round_based::{Incoming, MessageType, mpc::party::CompleteRoundError}; const PARTY0_SEED: [u8; 32] = hex!("6772d079d5c984b3936a291e36b0d3dc6c474e36ed4afdfc973ef79a431ca870"); diff --git a/round-based-tests/tests/random_beacon_with_echo.rs b/round-based-tests/tests/random_beacon_with_echo.rs index d6f2ec8..24db271 100644 --- a/round-based-tests/tests/random_beacon_with_echo.rs +++ b/round-based-tests/tests/random_beacon_with_echo.rs @@ -2,8 +2,8 @@ use hex_literal::hex; use matches::assert_matches; use rand_chacha::rand_core::SeedableRng; -use random_generation_protocol::{protocol_of_random_generation, CommitMsg, DecommitMsg, Msg}; -use round_based::{echo_broadcast as echo, Incoming, MessageType, Outgoing}; +use random_generation_protocol::{CommitMsg, DecommitMsg, Msg, protocol_of_random_generation}; +use round_based::{Incoming, MessageType, Outgoing, echo_broadcast as echo}; const PARTY0_SEED: [u8; 32] = hex!("6772d079d5c984b3936a291e36b0d3dc6c474e36ed4afdfc973ef79a431ca870"); diff --git a/round-based/CHANGELOG.md b/round-based/CHANGELOG.md index 1d9cb1c..6528c5a 100644 --- a/round-based/CHANGELOG.md +++ b/round-based/CHANGELOG.md @@ -1,6 +1,106 @@ +## v0.5.0 +**For protocol devs:** if you developed an MPC protocol on `round_based`, here's a list of relevant API changes: +* `round_based::rounds_router` is removed \ + Previously, protocol implementations used to use `round_based::rounds_router::RoundsRouter` to + register rounds of the protocol. This was a typical workflow: + ```rust + // Construct a router builder + let mut rounds = RoundsRouter::::builder(); + // Register rounds + let round1 = rounds.add_round(RoundInput::::broadcast(i, n)); + let round2 = rounds.add_round(RoundInput::::broadcast(i, n)); + // Complete the router + let mut rounds = rounds.listen(incoming); + + // ... run the protocol + + // use the router to receive messages in the round: + let commitments = rounds + .complete(round1) + .await + .map_err(Error::Round1Receive)?; + ``` + With the new API, all of this is integrated into `Mpc` trait. Given `mut mpc: M` provided as an input + to the protocol (where `M: Mpc`), this is how typical setup looks like: + ```rust + // Register rounds + let round1 = mpc.add_round(round_based::round::reliable_broadcast::(i, n)); + let round2 = mpc.add_round(round_based::round::broadcast::(i, n)); + // Complete the router + let mut mpc = mpc.finish_setup(); + + // ... run the protocol + + // use `mpc` to send messages in the round: + mpc.reliably_broadcast(Msg::CommitMsg(CommitMsg { commitment })) + .await + .map_err(Error::Round1Send)?; + + // use `mpc` to receive messages in the round: + let commitments = mpc.complete(round1).await.map_err(Error::Round1Receive)?; + ``` +* We now distinguish reliable broadcast messages: + * Message is reliably broadcasted if on reception the receiver knows that all other honest + parties received exactly the same message. + * For incoming messages, `round_based::Incoming` has field `msg_type` which contains a flag + `reliable: bool` for broadcast messages that indicates whether message was verified to be + reliably broadcasted + * For outgoing messages, `round_based::Outgoing` has field `recipient` which contains a flag + `reliable: bool` for broadcast messages that indicates whether message has to be reliably + broadcasted + * Protocols can use `round_based::round::reliable_broadcast(i, n)` to create a reliable broadcast + round. If received message wasn't reliably broadcasted (`reliable` flag is set to `false`), + round fails with an error. + * Delivery implementations must take into account the new flag. If protocol wants to send + a reliable broadcast message, but delivery layer doesn't support this, an error must be + returned. + * For any delivery implementation that does not support reliable broadcast, we provide a + `round_based::echo_broadcast` primitive that implements cryptographic reliable broadcast + for any protocol. Check out this module docs if you need more info. +* **TL;DR** of new API: + * Use `Mpc::add_round` to register rounds of the protocol + * Once all rounds are registered, use `Mpc::finish_setup` that returns `MpcExecution` + * To send messages, use: + * `MpcExecution::{send, send_p2p, send_broadcast, reliably_broadcast}` to send one message + * `MpcExecution::send_many` to send many messages at once + * To receive messages from a round `r`, use `MpcExecution::complete(r)` + * Use `MpcExecution::yield_now` to temporarily return execution to async runtime. Use it to + break a long execution into smaller pieces. + * `round_based::{Incoming, Outgoing}` now explicitly specify if message was (needs to be) + reliably broadcasted. +* Check out changes in our example protocol for randomness generation to see changes that were + needed to upgrade to latest API: [see diff](https://github.com/LFDT-Lockness/round-based/compare/bc9dcd8..v0.4.1#diff-fc41689d56219af09956ddb6d614b77f6974566ccc616356befa8cdece36bf19) + +**For protocol users:** if you use a protocol that is built on top of `round_based`, here's a list +of relevant changes in API: +* `MpcParty` construction flow: + * Previously, you used to construct a `MpcParty` by providing `Delivery` implementation via + `MpcParty::connected`, then it was provided to the protocol as an input. + * Now, `Delivery` trait was removed. Instead you need to construct a `channel` that implements both + `Stream, Error>>` and `Sink, Error = Error>`. Then construct an + `MpcParty` by calling `round_based::mpc::connected(channel)` (if you have separate stream and sink + channels, use `round_based::mpc::connected_halves(stream, sink)`). + * Provide `MpcParty` to the protocol as an input. +* Reliable broadcast + * Message is reliably broadcasted if on reception the receiver knows that all other honest parties + received exactly the same message. + * Some protocols require messages at some rounds to be reliably broadcasted + * If they do, it will be indicated in `round_based::Outgoing` in field `msg_type` that now has a + flag `reliable: bool` which indicates if message has to be reliably broadcasted. + * Delivery implementation that doesn't support reliable broadcast must return an error if protocol + tries to send a reliable broadcast message + * Delivery implementation must set `reliable` flag to `true` for incoming message only if it + was cryptographically (or through other trust assumptions) checked that message was reliably + broacasted + * For any delivery implementation that does not support reliable broadcast, we provide a + `round_based::echo_broadcast` primitive that implements cryptographic reliable broadcast + for any protocol. Check out this module docs if you need more info. + ## v0.4.1 * Add methods to MpcParty to change its components [#15] +[#15]: https://github.com/LFDT-Lockness/round-based/pull/15 + ## v0.4.0 * BREAKING: Improve ergonomics of protocol simulation, which is used for writing tests [#14] * Remove `dev` feature, it's replaced with `sim` and `sim-async` diff --git a/round-based/Cargo.toml b/round-based/Cargo.toml index dacd8ba..7ee4949 100644 --- a/round-based/Cargo.toml +++ b/round-based/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "round-based" -version = "0.4.1" -edition = "2021" +version = "0.5.0-alpha.1" +edition.workspace = true license = "MIT OR Apache-2.0" description = "Driver for MPC protocols" repository = "https://github.com/LFDT-Lockness/round-based" @@ -21,7 +21,7 @@ phantom-type = { version = "0.3", default-features = false } tracing = { version = "0.1", default-features = false } thiserror = { version = "2", default-features = false } -round-based-derive = { version = "0.2", optional = true, path = "../round-based-derive" } +round-based-derive = { version = "0.5.0-alpha.0", optional = true, path = "../round-based-derive" } tokio = { version = "1", features = ["rt"], optional = true } tokio-stream = { version = "0.1", features = ["sync"], optional = true } diff --git a/round-based/src/_docs.rs b/round-based/src/_docs.rs index dc57265..a1bab33 100644 --- a/round-based/src/_docs.rs +++ b/round-based/src/_docs.rs @@ -2,8 +2,8 @@ use futures_util::{Sink, SinkExt, Stream}; use crate::{Incoming, Outgoing}; -pub fn fake_delivery( -) -> impl Stream, E>> + Sink, Error = E> + Unpin { +pub fn fake_delivery() +-> impl Stream, E>> + Sink, Error = E> + Unpin { crate::mpc::Halves::new( futures_util::stream::pending::, E>>(), futures_util::sink::drain().sink_map_err(|e| match e {}), diff --git a/round-based/src/echo_broadcast/mod.rs b/round-based/src/echo_broadcast/mod.rs index 3598e6d..5673b17 100644 --- a/round-based/src/echo_broadcast/mod.rs +++ b/round-based/src/echo_broadcast/mod.rs @@ -61,8 +61,8 @@ use alloc::collections::btree_map::BTreeMap; use digest::Digest; use crate::{ - round::{RoundInfo, RoundStore, RoundStoreExt}, Mpc, MpcExecution, Outgoing, ProtocolMsg, RoundMsg, + round::{RoundInfo, RoundStore, RoundStoreExt}, }; mod error; diff --git a/round-based/src/echo_broadcast/store.rs b/round-based/src/echo_broadcast/store.rs index 507cc7f..7534d97 100644 --- a/round-based/src/echo_broadcast/store.rs +++ b/round-based/src/echo_broadcast/store.rs @@ -3,8 +3,8 @@ use core::marker::PhantomData; use digest::Digest; use crate::{ - round::{RoundInfo, RoundInput, RoundMsgs, RoundStore}, Incoming, RoundMsg, + round::{RoundInfo, RoundInput, RoundMsgs, RoundStore}, }; use super::{error, sub_msg}; @@ -99,7 +99,7 @@ where } MainRoundState::Gone => return Err(error::Reason::StateGone.into()), MainRoundState::Output { .. } | MainRoundState::Finished => { - return Err(error::Reason::ReceivedMainMsgWhenRoundOver.into()) + return Err(error::Reason::ReceivedMainMsgWhenRoundOver.into()); } }; diff --git a/round-based/src/mpc/mod.rs b/round-based/src/mpc/mod.rs index afeb401..2eda512 100644 --- a/round-based/src/mpc/mod.rs +++ b/round-based/src/mpc/mod.rs @@ -36,8 +36,8 @@ //! ``` use crate::{ - round::{RoundInfo, RoundStore}, Outgoing, PartyIndex, + round::{RoundInfo, RoundStore}, }; pub mod party; diff --git a/round-based/src/mpc/party/mod.rs b/round-based/src/mpc/party/mod.rs index 866b0f7..f84bbe5 100644 --- a/round-based/src/mpc/party/mod.rs +++ b/round-based/src/mpc/party/mod.rs @@ -3,8 +3,8 @@ use futures_util::{Sink, SinkExt, Stream, StreamExt}; use crate::{ - round::{RoundInfo, RoundStore}, Incoming, Outgoing, + round::{RoundInfo, RoundStore}, }; use super::{Mpc, MpcExecution, ProtocolMsg, RoundMsg}; @@ -12,7 +12,7 @@ use super::{Mpc, MpcExecution, ProtocolMsg, RoundMsg}; mod router; pub mod runtime; -pub use self::router::{errors::RouterError, Round}; +pub use self::router::{Round, errors::RouterError}; #[doc(no_inline)] pub use self::runtime::AsyncRuntime; diff --git a/round-based/src/mpc/party/router.rs b/round-based/src/mpc/party/router.rs index f1e5d73..6cdee44 100644 --- a/round-based/src/mpc/party/router.rs +++ b/round-based/src/mpc/party/router.rs @@ -10,8 +10,8 @@ use phantom_type::PhantomType; use tracing::{error, trace_span, warn}; use crate::{ - round::{RoundInfo, RoundStore}, Incoming, ProtocolMsg, RoundMsg, + round::{RoundInfo, RoundStore}, }; /// Routes received messages between protocol rounds @@ -70,7 +70,7 @@ where return Err(errors::UnregisteredRound { n: msg_round_n, witness_provided: false, - }) + }); } }; if message_round.needs_more_messages().no() { @@ -102,7 +102,7 @@ where n: M::ROUND, witness_provided: true, } - .into())) + .into())); } }; if message_round.needs_more_messages().yes() { diff --git a/round-based/src/round/mod.rs b/round-based/src/round/mod.rs index 1684edd..036059d 100644 --- a/round-based/src/round/mod.rs +++ b/round-based/src/round/mod.rs @@ -5,7 +5,7 @@ use core::any::Any; use crate::Incoming; pub use self::simple_store::{ - broadcast, p2p, reliable_broadcast, RoundInput, RoundInputError, RoundMsgs, + RoundInput, RoundInputError, RoundMsgs, broadcast, p2p, reliable_broadcast, }; mod simple_store; diff --git a/round-based/src/sim/async_env.rs b/round-based/src/sim/async_env.rs index 727d093..c568d69 100644 --- a/round-based/src/sim/async_env.rs +++ b/round-based/src/sim/async_env.rs @@ -74,13 +74,13 @@ use core::{ use futures_util::{Sink, Stream}; use tokio::sync::broadcast; -use tokio_stream::wrappers::{errors::BroadcastStreamRecvError, BroadcastStream}; +use tokio_stream::wrappers::{BroadcastStream, errors::BroadcastStreamRecvError}; +use crate::{MessageDestination, MessageType, MpcParty, MsgId, PartyIndex}; use crate::{ - delivery::{Incoming, Outgoing}, ProtocolMsg, + delivery::{Incoming, Outgoing}, }; -use crate::{MessageDestination, MessageType, MpcParty, MsgId, PartyIndex}; use super::SimResult; diff --git a/round-based/src/sim/mod.rs b/round-based/src/sim/mod.rs index e1974f5..df686e9 100644 --- a/round-based/src/sim/mod.rs +++ b/round-based/src/sim/mod.rs @@ -69,7 +69,7 @@ use alloc::{boxed::Box, collections::VecDeque, string::ToString, vec::Vec}; use core::future::Future; use crate::{ - state_machine::ProceedResult, Incoming, MessageDestination, MessageType, Outgoing, ProtocolMsg, + Incoming, MessageDestination, MessageType, Outgoing, ProtocolMsg, state_machine::ProceedResult, }; #[cfg(feature = "sim-async")] diff --git a/round-based/src/state_machine/delivery.rs b/round-based/src/state_machine/delivery.rs index 9a710ff..e53977b 100644 --- a/round-based/src/state_machine/delivery.rs +++ b/round-based/src/state_machine/delivery.rs @@ -1,4 +1,4 @@ -use core::task::{ready, Poll}; +use core::task::{Poll, ready}; /// Provides a stream of incoming and sink for outgoing messages pub struct Delivery { diff --git a/round-based/src/state_machine/runtime.rs b/round-based/src/state_machine/runtime.rs index 6d64577..e342e23 100644 --- a/round-based/src/state_machine/runtime.rs +++ b/round-based/src/state_machine/runtime.rs @@ -1,4 +1,4 @@ -use core::task::{ready, Poll}; +use core::task::{Poll, ready}; /// State machine runtime pub struct Runtime { diff --git a/round-based/src/state_machine/shared_state.rs b/round-based/src/state_machine/shared_state.rs index 86bc622..0b666bf 100644 --- a/round-based/src/state_machine/shared_state.rs +++ b/round-based/src/state_machine/shared_state.rs @@ -133,8 +133,8 @@ impl core::fmt::Debug for SharedStateRef { pub struct CanSchedule(T); impl CanSchedule<&SharedStateRef> { - fn borrow_mut(&self) -> core::cell::RefMut> { - self.0 .0.borrow_mut() + fn borrow_mut(&self) -> core::cell::RefMut<'_, SharedState> { + self.0.0.borrow_mut() } /// Flushes slot of outgoing message diff --git a/wasm/no_std/Cargo.toml b/wasm/no_std/Cargo.toml index 09e591c..901139c 100644 --- a/wasm/no_std/Cargo.toml +++ b/wasm/no_std/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "wasm_nostd_compiles" version = "0.1.0" -edition = "2021" +edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html