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;