1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//! Party of MPC protocol
//!
//! [`MpcParty`] is party of MPC protocol, connected to network, ready to start carrying out the protocol.
//!
//! ```rust
//! use round_based::{Mpc, MpcParty, Delivery, PartyIndex};
//!
//! # struct KeygenMsg;
//! # struct KeyShare;
//! # struct Error;
//! # type Result<T> = std::result::Result<T, Error>;
//! # async fn doc() -> Result<()> {
//! async fn keygen<M>(party: M, i: PartyIndex, n: u16) -> Result<KeyShare>
//! where
//!     M: Mpc<ProtocolMessage = KeygenMsg>
//! {
//!     // ...
//! # unimplemented!()
//! }
//! async fn connect() -> impl Delivery<KeygenMsg> {
//!     // ...
//! # round_based::_docs::fake_delivery()
//! }
//!
//! let delivery = connect().await;
//! let party = MpcParty::connected(delivery);
//!
//! # let (i, n) = (1, 3);
//! let keyshare = keygen(party, i, n).await?;
//! # Ok(()) }
//! ```

use phantom_type::PhantomType;

use crate::delivery::Delivery;
use crate::runtime::{self, AsyncRuntime};
use crate::StdError;

/// Party of MPC protocol (trait)
///
/// [`MpcParty`] is the only struct that implement this trait. Motivation to have this trait is to fewer amount of
/// generic bounds that are needed to be specified.
///
/// Typical usage of this trait when implementing MPC protocol:
///
/// ```rust
/// use round_based::{Mpc, MpcParty, PartyIndex};
///
/// # struct Msg;
/// async fn keygen<M>(party: M, i: PartyIndex, n: u16)
/// where
///     M: Mpc<ProtocolMessage = Msg>
/// {
///     let MpcParty{ delivery, .. } = party.into_party();
///     // ...
/// }
/// ```
///
/// If we didn't have this trait, generics would be less readable:
/// ```rust
/// use round_based::{MpcParty, Delivery, runtime::AsyncRuntime, PartyIndex};
///
/// # struct Msg;
/// async fn keygen<D, R>(party: MpcParty<Msg, D, R>, i: PartyIndex, n: u16)
/// where
///     D: Delivery<Msg>,
///     R: AsyncRuntime
/// {
///     // ...
/// }
/// ```
pub trait Mpc: internal::Sealed {
    /// MPC message
    type ProtocolMessage;
    /// Transport layer implementation
    type Delivery: Delivery<
        Self::ProtocolMessage,
        SendError = Self::SendError,
        ReceiveError = Self::ReceiveError,
    >;
    /// Async runtime
    type Runtime: AsyncRuntime;

    /// Sending message error
    type SendError: StdError + Send + Sync + 'static;
    /// Receiving message error
    type ReceiveError: StdError + Send + Sync + 'static;

    /// Converts into [`MpcParty`]
    fn into_party(self) -> MpcParty<Self::ProtocolMessage, Self::Delivery, Self::Runtime>;
}

mod internal {
    pub trait Sealed {}
}

/// Party of MPC protocol
#[non_exhaustive]
pub struct MpcParty<M, D, R = runtime::DefaultRuntime> {
    /// Defines transport layer
    pub delivery: D,
    /// Defines how computationally heavy tasks should be handled
    pub runtime: R,
    _msg: PhantomType<M>,
}

impl<M, D> MpcParty<M, D>
where
    D: Delivery<M>,
{
    /// Party connected to the network
    ///
    /// Takes the delivery object determining how to deliver/receive other parties' messages
    pub fn connected(delivery: D) -> Self {
        Self {
            delivery,
            runtime: Default::default(),
            _msg: PhantomType::new(),
        }
    }
}

impl<M, D, X> MpcParty<M, D, X>
where
    D: Delivery<M>,
{
    /// Specifies a [async runtime](runtime)
    pub fn set_runtime<R>(self, runtime: R) -> MpcParty<M, D, R>
    where
        R: AsyncRuntime,
    {
        MpcParty {
            delivery: self.delivery,
            runtime,
            _msg: self._msg,
        }
    }
}

impl<M, D, B> internal::Sealed for MpcParty<M, D, B> {}

impl<M, D, R> Mpc for MpcParty<M, D, R>
where
    D: Delivery<M>,
    D::SendError: StdError + Send + Sync + 'static,
    D::ReceiveError: StdError + Send + Sync + 'static,
    R: AsyncRuntime,
{
    type ProtocolMessage = M;
    type Delivery = D;
    type Runtime = R;

    type SendError = D::SendError;
    type ReceiveError = D::ReceiveError;

    fn into_party(self) -> MpcParty<Self::ProtocolMessage, Self::Delivery, Self::Runtime> {
        self
    }
}