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}