round_based/
party.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::{Mpc, MpcParty, Delivery, PartyIndex};
7//!
8//! # struct KeygenMsg;
9//! # struct KeyShare;
10//! # struct Error;
11//! # type Result<T> = std::result::Result<T, Error>;
12//! # async fn doc() -> Result<()> {
13//! async fn keygen<M>(party: M, i: PartyIndex, n: u16) -> Result<KeyShare>
14//! where
15//!     M: Mpc<ProtocolMessage = KeygenMsg>
16//! {
17//!     // ...
18//! # unimplemented!()
19//! }
20//! async fn connect() -> impl Delivery<KeygenMsg> {
21//!     // ...
22//! # round_based::_docs::fake_delivery()
23//! }
24//!
25//! let delivery = connect().await;
26//! let party = MpcParty::connected(delivery);
27//!
28//! # let (i, n) = (1, 3);
29//! let keyshare = keygen(party, i, n).await?;
30//! # Ok(()) }
31//! ```
32
33use phantom_type::PhantomType;
34
35use crate::delivery::Delivery;
36use crate::runtime::{self, AsyncRuntime};
37
38/// Party of MPC protocol (trait)
39///
40/// [`MpcParty`] is the only struct that implement this trait. Motivation to have this trait is to fewer amount of
41/// generic bounds that are needed to be specified.
42///
43/// Typical usage of this trait when implementing MPC protocol:
44///
45/// ```rust
46/// use round_based::{Mpc, MpcParty, PartyIndex};
47///
48/// # struct Msg;
49/// async fn keygen<M>(party: M, i: PartyIndex, n: u16)
50/// where
51///     M: Mpc<ProtocolMessage = Msg>
52/// {
53///     let MpcParty{ delivery, .. } = party.into_party();
54///     // ...
55/// }
56/// ```
57///
58/// If we didn't have this trait, generics would be less readable:
59/// ```rust
60/// use round_based::{MpcParty, Delivery, runtime::AsyncRuntime, PartyIndex};
61///
62/// # struct Msg;
63/// async fn keygen<D, R>(party: MpcParty<Msg, D, R>, i: PartyIndex, n: u16)
64/// where
65///     D: Delivery<Msg>,
66///     R: AsyncRuntime
67/// {
68///     // ...
69/// }
70/// ```
71pub trait Mpc: internal::Sealed {
72    /// MPC message
73    type ProtocolMessage;
74    /// Transport layer implementation
75    type Delivery: Delivery<
76        Self::ProtocolMessage,
77        SendError = Self::SendError,
78        ReceiveError = Self::ReceiveError,
79    >;
80    /// Async runtime
81    type Runtime: AsyncRuntime;
82
83    /// Sending message error
84    type SendError: core::error::Error + Send + Sync + 'static;
85    /// Receiving message error
86    type ReceiveError: core::error::Error + Send + Sync + 'static;
87
88    /// Converts into [`MpcParty`]
89    fn into_party(self) -> MpcParty<Self::ProtocolMessage, Self::Delivery, Self::Runtime>;
90}
91
92mod internal {
93    pub trait Sealed {}
94}
95
96/// Party of MPC protocol
97#[non_exhaustive]
98pub struct MpcParty<M, D, R = runtime::DefaultRuntime> {
99    /// Defines transport layer
100    pub delivery: D,
101    /// Defines how computationally heavy tasks should be handled
102    pub runtime: R,
103    _msg: PhantomType<M>,
104}
105
106impl<M, D> MpcParty<M, D>
107where
108    D: Delivery<M>,
109{
110    /// Party connected to the network
111    ///
112    /// Takes the delivery object determining how to deliver/receive other parties' messages
113    pub fn connected(delivery: D) -> Self {
114        Self {
115            delivery,
116            runtime: Default::default(),
117            _msg: PhantomType::new(),
118        }
119    }
120}
121
122impl<M, D, X> MpcParty<M, D, X>
123where
124    D: Delivery<M>,
125{
126    /// Modify the delivery of this party while keeping everything else the same
127    pub fn map_delivery<D2>(self, f: impl FnOnce(D) -> D2) -> MpcParty<M, D2, X> {
128        let delivery = f(self.delivery);
129        MpcParty {
130            delivery,
131            runtime: self.runtime,
132            _msg: self._msg,
133        }
134    }
135
136    /// Modify the runtime of this party while keeping everything else the same
137    pub fn map_runtime<R>(self, f: impl FnOnce(X) -> R) -> MpcParty<M, D, R> {
138        let runtime = f(self.runtime);
139        MpcParty {
140            delivery: self.delivery,
141            runtime,
142            _msg: self._msg,
143        }
144    }
145
146    /// Specifies a [async runtime](runtime)
147    pub fn set_runtime<R>(self, runtime: R) -> MpcParty<M, D, R>
148    where
149        R: AsyncRuntime,
150    {
151        MpcParty {
152            delivery: self.delivery,
153            runtime,
154            _msg: self._msg,
155        }
156    }
157}
158
159impl<M, D, B> internal::Sealed for MpcParty<M, D, B> {}
160
161impl<M, D, R> Mpc for MpcParty<M, D, R>
162where
163    D: Delivery<M>,
164    D::SendError: core::error::Error + Send + Sync + 'static,
165    D::ReceiveError: core::error::Error + Send + Sync + 'static,
166    R: AsyncRuntime,
167{
168    type ProtocolMessage = M;
169    type Delivery = D;
170    type Runtime = R;
171
172    type SendError = D::SendError;
173    type ReceiveError = D::ReceiveError;
174
175    fn into_party(self) -> MpcParty<Self::ProtocolMessage, Self::Delivery, Self::Runtime> {
176        self
177    }
178}