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
//! # Round-based protocols execution
//!
//! Crate defines a generic round-based protocol and provides utilities for it. We give
//! formal definition below, but you may have already seen such protocols: most of [MPC] protocols
//! follow round-based communication model.
//!
//! By defining the generic round-based protocol, we can implement generic transport
//! layer for it. See [AsyncProtocol]\: it allows executing the protocol by providing
//! channels of incoming and outgoing messages.
//!
//! [MPC]: https://en.wikipedia.org/wiki/Secure_multi-party_computation
//!
//! ## What is round-based protocol?
//! In round-based protocol we have `n` parties that can send messages to and receive messages
//! from other parties within rounds (number of parties `n` is known prior to starting protocol).
//!
//! At every round party may send a P2P or broadcast message, and it receives all broadcast
//! messages sent by other parties and P2P messages sent directly to it. After
//! party's received enough round messages in this round, it either proceeds (evaluates something on
//! received messages and goes to next round) or finishes the protocol.
//!
//! ## How to define own round-based protocol
//! To define own round-based protocol, you need to implement [StateMachine] trait. I.e.
//! you need to define type of [protocol message](StateMachine::MessageBody) which will be
//! transmitted on wire, determine rules how to
//! [handle incoming message](StateMachine::handle_incoming) and how to
//! [proceed state](StateMachine::proceed), etc.
//!
//! We divide methods in StateMachine on which can block and which can not. Most of MPC protocols
//! rely on computationally expensive math operations, such operations should not be executed
//! in async environment (i.e. on green-thread), that's why the only method which capable of
//! doing expensive operations is [proceed](StateMachine::proceed).
//!
//! ## How to execute round-based protocol
//! To run round-based protocol you need only to provide incoming and outgoing channels.
//! Then you can execute the protocol using [AsyncProtocol]:
//! ```no_run
//! # use futures::stream::{self, Stream, FusedStream};
//! # use futures::sink::{self, Sink, SinkExt};
//! # use round_based::{Msg, StateMachine, AsyncProtocol};
//! # struct M;
//! # #[derive(Debug)] struct Error;
//! # impl From<std::convert::Infallible> for Error {
//! #    fn from(_: std::convert::Infallible) -> Error { Error }
//! # }
//! # trait Constructable { fn initial() -> Self; }
//! fn incoming() -> impl Stream<Item=Result<Msg<M>, Error>> + FusedStream + Unpin {
//!     // ...
//! # stream::pending()
//! }
//! fn outgoing() -> impl Sink<Msg<M>, Error=Error> + Unpin {
//!     // ...
//! # sink::drain().with(|x| futures::future::ok(x))
//! }
//! # async fn execute_protocol<State>() -> Result<(), round_based::async_runtime::Error<State::Err, Error, Error>>
//! # where State: StateMachine<MessageBody = M, Err = Error> + Constructable + Send + 'static
//! # {
//! let output: State::Output = AsyncProtocol::new(State::initial(), incoming(), outgoing())
//!     .run().await?;
//! // ...
//! # let _ = output; Ok(())
//! # }
//! ```
//!
//! Usually protocols assume that P2P messages are encrypted and every message is authenticated, in
//! this case underlying sink and stream must meet such requirements.
//!
//! For development purposes, you can also find useful [Simulation](crate::dev::Simulation) and
//! [AsyncSimulation](dev::AsyncSimulation) simulations that can run protocols locally.

#![cfg_attr(docsrs, feature(doc_cfg))]

pub mod containers;

#[cfg(feature = "dev")]
#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
pub mod dev;

mod sm;
pub use sm::*;

#[cfg(feature = "async-runtime")]
#[cfg_attr(docsrs, doc(cfg(feature = "async-runtime")))]
pub mod async_runtime;
#[cfg(feature = "async-runtime")]
pub use async_runtime::AsyncProtocol;