round_based/mpc/
mod.rs

1//! Party of MPC protocol
2//!
3//! [`MpcParty`] is party of MPC protocol, connected to network, ready to start carrying out the protocol.
4//!
5//! ```rust
6//! use round_based::{Incoming, Outgoing};
7//!
8//! # #[derive(round_based::ProtocolMsg)]
9//! # enum KeygenMsg {}
10//! # struct KeyShare;
11//! # struct Error;
12//! # type Result<T> = std::result::Result<T, Error>;
13//! # async fn doc() -> Result<()> {
14//! async fn keygen<M>(party: M, i: u16, n: u16) -> Result<KeyShare>
15//! where
16//!     M: round_based::Mpc<Msg = KeygenMsg>
17//! {
18//!     // ...
19//! # unimplemented!()
20//! }
21//! async fn connect() ->
22//!     impl futures::Stream<Item = Result<Incoming<KeygenMsg>>>
23//!         + futures::Sink<Outgoing<KeygenMsg>, Error = Error>
24//!         + Unpin
25//! {
26//!     // ...
27//! # round_based::_docs::fake_delivery()
28//! }
29//!
30//! let delivery = connect().await;
31//! let party = round_based::mpc::connected(delivery);
32//!
33//! # let (i, n) = (1, 3);
34//! let keyshare = keygen(party, i, n).await?;
35//! # Ok(()) }
36//! ```
37
38use crate::{
39    Outgoing, PartyIndex,
40    round::{RoundInfo, RoundStore},
41};
42
43pub mod party;
44
45#[doc(no_inline)]
46pub use self::party::{Halves, MpcParty};
47
48/// Abstracts functionalities needed for creating an MPC protocol execution.
49///
50/// An object implementing this trait is accepted as a parameter of a protocol. It is used to
51/// configure the protocol with [`Mpc::add_round`], and then finalized into a protocol executor
52/// with [`Mpc::finish_setup`]
53pub trait Mpc {
54    /// Protocol message
55    type Msg;
56
57    /// A type of a finalized instatiation of a party for this protocol
58    ///
59    /// After being created with [`Mpc::finish_setup`], you can use an object with this type to
60    /// drive the protocol execution using the methods of [`MpcExecution`].
61    type Exec: MpcExecution<Msg = Self::Msg, SendErr = Self::SendErr>;
62    /// Error indicating that sending a message has failed
63    type SendErr;
64
65    /// Registers a round
66    fn add_round<R>(&mut self, round: R) -> <Self::Exec as MpcExecution>::Round<R>
67    where
68        R: RoundStore,
69        Self::Msg: RoundMsg<R::Msg>;
70
71    /// Completes network setup
72    ///
73    /// Once this method is called, no more rounds can be added,
74    /// but the protocol can receive and send messages.
75    fn finish_setup(self) -> Self::Exec;
76}
77
78/// Abstracts functionalities needed for MPC protocol execution
79pub trait MpcExecution {
80    /// Witness that round was registered
81    ///
82    /// It's obtained by registering round in [`Mpc::add_round`], which then can be used to retrieve
83    /// messages from associated round by calling [`MpcExecution::complete`].
84    type Round<R: RoundInfo>;
85
86    /// Protocol message
87    type Msg;
88
89    /// Error indicating that completing a round has failed
90    type CompleteRoundErr<E>;
91    /// Error indicating that sending a message has failed
92    type SendErr;
93
94    /// Returned by [`.send_many()`](Self::send_many)
95    type SendMany: SendMany<Exec = Self, Msg = Self::Msg, SendErr = Self::SendErr>;
96
97    /// Completes the round
98    ///
99    /// Waits until we receive all the messages in the round `R` from other parties. Returns
100    /// received messages.
101    async fn complete<R>(
102        &mut self,
103        round: Self::Round<R>,
104    ) -> Result<R::Output, Self::CompleteRoundErr<R::Error>>
105    where
106        R: RoundInfo,
107        Self::Msg: RoundMsg<R::Msg>;
108
109    /// Sends a message
110    ///
111    /// This method awaits until the message is sent, which might be not the best method to use if you
112    /// need to send many messages at once. If it's the case, prefer using [`.send_many()`](Self::send_many).
113    async fn send(&mut self, msg: Outgoing<Self::Msg>) -> Result<(), Self::SendErr>;
114
115    /// Sends a p2p message to another party
116    ///
117    /// Note: when you send many messages at once (it's most likely the case when you send a p2p message), this method
118    /// is not efficient, prefer using [`.send_many()`](Self::send_many).
119    async fn send_p2p(
120        &mut self,
121        recipient: PartyIndex,
122        msg: Self::Msg,
123    ) -> Result<(), Self::SendErr> {
124        self.send(Outgoing::p2p(recipient, msg)).await
125    }
126
127    /// Sends a message that will be received by all parties
128    ///
129    /// Message will be broadcasted, but not reliably. If you need a reliable broadcast, use
130    /// [`MpcExecution::reliably_broadcast`] method.
131    async fn send_to_all(&mut self, msg: Self::Msg) -> Result<(), Self::SendErr> {
132        self.send(Outgoing::all_parties(msg)).await
133    }
134
135    /// Reliably broadcasts a message
136    ///
137    /// Message will be received by all participants of the protocol. Moreover, when recipient receives a
138    /// message, it will be assured (cryptographically or through other trust assumptions) that all honest
139    /// participants of the protocol received the same message.
140    ///
141    /// It's a responsibility of a message delivery layer to provide the reliable broadcast mechanism. If
142    /// it's not supported, this method returns an error. Note that not every MPC protocol requires the
143    /// reliable broadcast, so it's totally normal to have a message delivery implementation that does
144    /// not support it.
145    async fn reliably_broadcast(&mut self, msg: Self::Msg) -> Result<(), Self::SendErr> {
146        self.send(Outgoing::reliable_broadcast(msg)).await
147    }
148
149    /// Creates a buffer of outgoing messages so they can be sent all at once
150    ///
151    /// When you have many messages that you want to send at once, using [`.send()`](Self::send)
152    /// may be inefficient, as delivery implementation may pause the execution until the message is
153    /// received by the recipient. Use this method to send many messages in a batch.
154    ///
155    /// This method takes ownership of `self` to create the [impl SendMany](SendMany) object. After
156    /// enqueueing all the messages, you need to reclaim `self` back by calling [`SendMany::flush`].
157    fn send_many(self) -> Self::SendMany;
158
159    /// Yields execution back to the async runtime
160    ///
161    /// Used in MPC protocols with many heavy synchronous computations. The protocol implementors
162    /// can manually insert yield points to ease the CPU contention
163    async fn yield_now(&self);
164}
165
166/// Buffer, optimized for sending many messages at once
167///
168/// It's obtained by calling [`MpcExecution::send_many`], which takes ownership of `MpcExecution`. To reclaim
169/// ownership, call [`SendMany::flush`].
170pub trait SendMany {
171    /// MPC executor, returned after successful [`.flush()`](Self::flush)
172    type Exec: MpcExecution<Msg = Self::Msg, SendErr = Self::SendErr>;
173    /// Protocol message
174    type Msg;
175    /// Error indicating that sending a message has failed
176    type SendErr;
177
178    /// Adds a message to the sending queue
179    ///
180    /// Similar to [`MpcExecution::send`], but possibly buffers a message until [`.flush()`](Self::flush) is
181    /// called.
182    ///
183    /// A call to this function may send the message, but this is not guaranteed by the API. To
184    /// flush the sending queue and send all messages, use [`.flush()`](Self::flush).
185    async fn send(&mut self, msg: Outgoing<Self::Msg>) -> Result<(), Self::SendErr>;
186
187    /// Adds a p2p message to the sending queue
188    ///
189    /// Similar to [`MpcExecution::send_p2p`], but possibly buffers a message until [`.flush()`](Self::flush) is
190    /// called.
191    ///
192    /// A call to this function may send the message, but this is not guaranteed by the API. To
193    /// flush the sending queue and send all messages, use [`.flush()`](Self::flush).
194    async fn send_p2p(
195        &mut self,
196        recipient: PartyIndex,
197        msg: Self::Msg,
198    ) -> Result<(), Self::SendErr> {
199        self.send(Outgoing::p2p(recipient, msg)).await
200    }
201
202    /// Adds a broadcast message to the sending queue
203    ///
204    /// Similar to [`MpcExecution::send_to_all`], but possibly buffers a message until [`.flush()`](Self::flush) is
205    /// called.
206    ///
207    /// A call to this function may send the message, but this is not guaranteed by the API. To
208    /// flush the sending queue and send all messages, use [`.flush()`](Self::flush).
209    async fn send_to_all(&mut self, msg: Self::Msg) -> Result<(), Self::SendErr> {
210        self.send(Outgoing::all_parties(msg)).await
211    }
212
213    /// Adds a reliable broadcast message to the sending queue
214    ///
215    /// Similar to [`MpcExecution::reliably_broadcast`], but possibly buffers a message until [`.flush()`](Self::flush) is
216    /// called.
217    ///
218    /// A call to this function may send the message, but this is not guaranteed by the API. To
219    /// flush the sending queue and send all messages, use [`Self::flush`]
220    async fn reliably_broadcast(&mut self, msg: Self::Msg) -> Result<(), Self::SendErr> {
221        self.send(Outgoing::reliable_broadcast(msg)).await
222    }
223
224    /// Flushes internal buffer by sending all messages in the queue
225    async fn flush(self) -> Result<Self::Exec, Self::SendErr>;
226}
227
228/// Alias to `<<M as Mpc>::Exec as MpcExecution>::CompleteRoundErr<E>`
229pub type CompleteRoundErr<M, E> = <<M as Mpc>::Exec as MpcExecution>::CompleteRoundErr<E>;
230
231/// Message of MPC protocol
232///
233/// MPC protocols typically consist of several rounds, each round has differently typed message.
234/// `ProtocolMsg` and [`RoundMsg`] traits are used to examine received message: `ProtocolMsg::round`
235/// determines which round message belongs to, and then `RoundMsg` trait can be used to retrieve
236/// actual round-specific message.
237///
238/// You should derive these traits using proc macro (requires `derive` feature):
239/// ```rust
240/// use round_based::ProtocolMsg;
241///
242/// #[derive(ProtocolMsg)]
243/// pub enum Message {
244///     Round1(Msg1),
245///     Round2(Msg2),
246///     // ...
247/// }
248///
249/// pub struct Msg1 { /* ... */ }
250/// pub struct Msg2 { /* ... */ }
251/// ```
252///
253/// This desugars into:
254///
255/// ```rust
256/// use round_based::{ProtocolMsg, RoundMsg};
257///
258/// pub enum Message {
259///     Round1(Msg1),
260///     Round2(Msg2),
261///     // ...
262/// }
263///
264/// pub struct Msg1 { /* ... */ }
265/// pub struct Msg2 { /* ... */ }
266///
267/// impl ProtocolMsg for Message {
268///     fn round(&self) -> u16 {
269///         match self {
270///             Message::Round1(_) => 1,
271///             Message::Round2(_) => 2,
272///             // ...
273///         }
274///     }
275/// }
276/// impl RoundMsg<Msg1> for Message {
277///     const ROUND: u16 = 1;
278///     fn to_protocol_msg(round_msg: Msg1) -> Self {
279///         Message::Round1(round_msg)
280///     }
281///     fn from_protocol_msg(protocol_msg: Self) -> Result<Msg1, Self> {
282///         match protocol_msg {
283///             Message::Round1(msg) => Ok(msg),
284///             msg => Err(msg),
285///         }
286///     }
287/// }
288/// impl RoundMsg<Msg2> for Message {
289///     const ROUND: u16 = 2;
290///     fn to_protocol_msg(round_msg: Msg2) -> Self {
291///         Message::Round2(round_msg)
292///     }
293///     fn from_protocol_msg(protocol_msg: Self) -> Result<Msg2, Self> {
294///         match protocol_msg {
295///             Message::Round2(msg) => Ok(msg),
296///             msg => Err(msg),
297///         }
298///     }
299/// }
300/// ```
301pub trait ProtocolMsg: Sized {
302    /// Number of the round that this message originates from
303    fn round(&self) -> u16;
304}
305
306/// Round message
307///
308/// See [`ProtocolMsg`] trait documentation.
309pub trait RoundMsg<M>: ProtocolMsg {
310    /// Number of the round this message belongs to
311    const ROUND: u16;
312
313    /// Converts round message into protocol message (never fails)
314    fn to_protocol_msg(round_msg: M) -> Self;
315    /// Extracts round message from protocol message
316    ///
317    /// Returns `Err(protocol_message)` if `protocol_message.round() != Self::ROUND`, otherwise
318    /// returns `Ok(round_message)`
319    fn from_protocol_msg(protocol_msg: Self) -> Result<M, Self>;
320}
321
322/// Construct an [`MpcParty`] that can be used to carry out MPC protocol
323///
324/// Accepts a channels with incoming and outgoing messages.
325///
326/// Alias to [`MpcParty::connected`]
327pub fn connected<M, D>(delivery: D) -> MpcParty<M, D>
328where
329    M: ProtocolMsg + 'static,
330    D: futures_util::Stream<Item = Result<crate::Incoming<M>, D::Error>> + Unpin,
331    D: futures_util::Sink<Outgoing<M>> + Unpin,
332{
333    MpcParty::connected(delivery)
334}
335
336/// Construct an [`MpcParty`] that can be used to carry out MPC protocol
337///
338/// Accepts separately a channel for incoming and a channel for outgoing messages.
339///
340/// Alias to [`MpcParty::connected_halves`]
341pub fn connected_halves<M, In, Out>(incomings: In, outgoings: Out) -> MpcParty<M, Halves<In, Out>>
342where
343    M: ProtocolMsg + 'static,
344    In: futures_util::Stream<Item = Result<crate::Incoming<M>, Out::Error>> + Unpin,
345    Out: futures_util::Sink<Outgoing<M>> + Unpin,
346{
347    MpcParty::connected_halves(incomings, outgoings)
348}