Skip to content

Commit

Permalink
Docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Denis Varlakov committed Sep 7, 2021
1 parent 8951a1a commit f0955be
Show file tree
Hide file tree
Showing 8 changed files with 320 additions and 45 deletions.
7 changes: 6 additions & 1 deletion round-based-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ pub fn protocol_message(input: proc_macro::TokenStream) -> proc_macro::TokenStre

let name = input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let variant_id_method = variant_id(&name, enum_data.variants.iter());
let variant_id_method = if !enum_data.variants.is_empty() {
variant_id(&name, enum_data.variants.iter())
} else {
// Special case for empty enum. Empty protocol message is useless, but let it be
quote! { match *self {} }
};

let impl_protocol_message = quote! {
impl #impl_generics round_based::rounds::ProtocolMessage for #name #ty_generics #where_clause {
Expand Down
7 changes: 4 additions & 3 deletions round-based/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ async-stream = "0.3"
tokio-stream = { version = "0.1", features = ["sync"] }
round-based-derive = { path = "../round-based-derive", optional = true }

rustls = { version = "0.19", features = ["dangerous_configuration"] }
webpki = "0.21"
tokio-rustls = "0.22"
rustls = { version = "0.19", features = ["dangerous_configuration"], optional = true }
webpki = { version = "0.21", optional = true }
tokio-rustls = { version = "0.22", optional = true }

[dev-dependencies]
rand = "0.8"
Expand All @@ -40,6 +40,7 @@ rcgen = "0.8"
[features]
default = []
derive = ["round-based-derive"]
tls = ["rustls", "webpki", "tokio-rustls"]

[[example]]
name = "mpc_random_generation"
Expand Down
108 changes: 106 additions & 2 deletions round-based/src/delivery/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
//! # Messages sending/receiving
//!
//! In this module we provide traits determining a way of exchanging messages between parties. Prior to
//! carrying out any protocol, you typically need to obtain an instance of [`Delivery`] trait, basically
//! it's a pair of delivery channels of incoming and outgoing messages.
//!
//! Receiving channel (or channel of incoming messages) is a [`Stream`], quite popular asynchronous
//! abstraction. Sending channel (or channel of outgoing messages) is defined with [`DeliverOutgoing`]
//! trait that's introduced in this module, it gives us more control on sending messages and fits
//! library needs nicely than similar traits like `Sink`.
//!
//! We provide several delivery implementations for most common cases. See [two_party] module.

use std::future::Future;
use std::iter;
use std::pin::Pin;
Expand All @@ -8,65 +21,154 @@ use phantom_type::PhantomType;

pub mod two_party;

/// A pair of incoming and outgoing delivery channels
pub trait Delivery<M> {
/// Outgoing delivery channel
type Send: DeliverOutgoing<M> + Send + Unpin;
/// Incoming delivery channel
type Receive: Stream<Item = Result<Incoming<M>, Self::ReceiveError>> + Send + Unpin + 'static;
/// Error of incoming delivery channel
type ReceiveError: Send + 'static;
/// Returns a pair of incoming and outgoing delivery channels
fn split(self) -> (Self::Receive, Self::Send);
}

/// Delivers outgoing messages, asynchronously
///
/// The trait defines all the logic related to delivery of outgoing messages. Specifically, given the
/// message which needs to be sent and an index of recipient party, it finds the way to reach that
/// party and sends the message. Also, the trait should authenticate and encrypt messages as
/// most of the protocols expect it to be done at network layer.
///
/// [DeliverOutgoingExt] trait extends this trait and defines convenient `.await`-friendly methods, like
/// [send_all] or [shutdown].
///
/// [send_all]: DeliverOutgoingExt::send_all
/// [shutdown]: DeliverOutgoingExt::shutdown
pub trait DeliverOutgoing<M> {
/// Message prepared to be sent
type Prepared: Unpin;
/// Delivery error
type Error;

//TODO: open issue - prepare should return `Self::Prepared<'m>`, it must be updated once GATs
// are stabilized
/// Prepares the message to be sent
///
/// Performs one-time calculation on sending message. For instance, it can estimate size of
/// serialized message to know how much space it needs to claim in a socket buffer.
fn prepare(self: Pin<&Self>, msg: Outgoing<&M>) -> Result<Self::Prepared, Self::Error>;
/// Queues sending the message
///
/// Once it returned `Poll::Ready(Ok(()))`, the message is queued. In order to actually send the
/// message, you need to flush it via [poll_flush](Self::poll_flush).
fn poll_start_send(
self: Pin<&mut Self>,
cx: &mut Context,
msg: &Self::Prepared,
) -> Poll<Result<(), Self::Error>>;
/// Flushes the underlying I/O
///
/// After it returned `Poll::Ready(Ok(()))`, all the queued messages prior the call are sent.
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>>;
/// Closes the underlying I/O
///
/// Flushes and closes the channel
fn poll_close(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>>;
}

/// Incoming message
///
/// Contains a received message and index of party who sent the message
#[derive(Debug, Clone, PartialEq)]
pub struct Incoming<M> {
/// Index of a party who sent the message
pub sender: u16,
/// Received message
pub msg: M,
}

/// Outgoing message
///
/// Contains a message that local party needs to send, and index of recipient party (`None` if it's
/// broadcast message)
#[derive(Debug, Clone, PartialEq)]
pub struct Outgoing<M> {
/// Index of recipient
///
/// `None` if the message is meant to be received by all the parties (ie. it's broadcast message)
pub recipient: Option<u16>,
/// Message being sent
pub msg: M,
}

/// An extension trait for [DeliverOutgoing] that provides a variety of convenient functions
pub trait DeliverOutgoingExt<M>: DeliverOutgoing<M> {
/// Sends a sequence of messages
///
/// Method signature is similar to:
/// ```rust,ignore
/// async fn send_all(&mut self, messages: impl IntoIterator<Item = Outgoing<&M>>) -> Result<()>;
/// ```
///
/// Method sends messages one-by-one and then flushes the channel.
///
/// ## Example
/// ```rust,no_run
/// # async fn async_main() -> Result<(), Box<dyn std::error::Error>> {
/// # let mut outgoing: round_based::simulation::SimulationOutgoing<&'static str> = unimplemented!();
/// use round_based::{DeliverOutgoingExt, Outgoing};
/// let msgs = vec!["Hello", "Goodbye"];
/// outgoing.send_all(msgs.iter().map(|msg| Outgoing{ recipient: Some(1), msg })).await?;
/// # Ok(()) }
/// ```
fn send_all<'d, 'm, I>(&'d mut self, messages: I) -> SendAll<'d, 'm, M, Self, I::IntoIter>
where
Self: Unpin,
Self::Prepared: Unpin,
I: IntoIterator<Item = Outgoing<&'m M>>,
I::IntoIter: Unpin,
M: 'm,
{
SendAll::new(self, messages.into_iter())
}

/// Sends one message
///
/// Method signature is similar to:
/// ```rust,ignore
/// async fn send(&mut self, messages: Outgoing<&M>) -> Result<()>;
/// ```
///
/// Method sends one message and flushes the channel.
///
/// ## Example
/// ```rust,no_run
/// # async fn async_main() -> Result<(), Box<dyn std::error::Error>> {
/// # let mut outgoing: round_based::simulation::SimulationOutgoing<&'static str> = unimplemented!();
/// use round_based::{DeliverOutgoingExt, Outgoing};
/// outgoing.send(Outgoing{ recipient: Some(1), msg: &"Ping" }).await?;
/// # Ok(()) }
/// ```
fn send<'d, 'm>(
&'d mut self,
message: Outgoing<&'m M>,
) -> SendAll<'d, 'm, M, Self, iter::Once<Outgoing<&'m M>>>
where
Self: Unpin,
Self::Prepared: Unpin,
M: 'm,
{
self.send_all(iter::once(message))
}

/// Shuts down the outgoing channel
///
/// Method signature is similar to:
/// ```rust,ignore
/// async fn shutdown(&mut self) -> Result<()>;
/// ```
///
/// Once there is nothing else to send, the channel must be utilized by calling this method which
/// flushes and closes underlying I/O.
fn shutdown(&mut self) -> Shutdown<M, Self>
where
Self: Unpin,
Expand All @@ -77,6 +179,7 @@ pub trait DeliverOutgoingExt<M>: DeliverOutgoing<M> {

impl<M, D> DeliverOutgoingExt<M> for D where D: DeliverOutgoing<M> {}

/// A future for [`send_all`](DeliverOutgoingExt::send_all) method
pub struct SendAll<'d, 'm, M, D, I>
where
I: Iterator<Item = Outgoing<&'m M>>,
Expand Down Expand Up @@ -142,6 +245,7 @@ where
}
}

/// A future for [`shutdown`](DeliverOutgoingExt::shutdown) method
pub struct Shutdown<'d, M, D>
where
D: DeliverOutgoing<M> + Unpin + ?Sized,
Expand Down
66 changes: 57 additions & 9 deletions round-based/src/delivery/two_party/insecure.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,52 @@
//! Two party delivery over plain TCP socket
//!
//! __*Warning:*__ it does not encrypt/authenticate messages, anything you send on the wire can be
//! easily forged. Use it for development purposes only. See [tls](super::tls) delivery if you need
//! a secure communication channel.
//!
//! ## Example: Server
//! ```rust,no_run
//! use round_based::delivery::two_party::insecure::Server;
//! use round_based::MpcParty;
//! # use serde::{Serialize, Deserialize};
//! # async fn async_main() -> Result<(), Box<dyn std::error::Error>> {
//! # #[derive(Serialize, Deserialize, Clone, round_based::ProtocolMessage)] enum Msg {}
//! # async fn protocol_of_random_generation<R: rand::RngCore, M: round_based::Mpc<ProtocolMessage = Msg>>(party: M,i: u16,n: u16,mut rng: R) -> Result<[u8; 32], Box<dyn std::error::Error>> { todo!() }
//!
//! let mut server = Server::<Msg>::bind("127.0.0.1:9090").await?;
//! loop {
//! let (client, _client_addr) = server.accept().await?;
//! let party = MpcParty::connect(client);
//! // ... run mpc here, e.g.:
//! let randomness = protocol_of_random_generation(party, 0, 2, rand::rngs::OsRng).await?;
//! println!("Randomness: {}", hex::encode(randomness));
//! }
//! #
//! # Ok(()) }
//! ```
//!
//! ## Example: Client
//! ```rust,no_run
//! use round_based::delivery::two_party::insecure::ClientBuilder;
//! use round_based::MpcParty;
//! # use serde::{Serialize, Deserialize};
//! # async fn async_main() -> Result<(), Box<dyn std::error::Error>> {
//! # #[derive(Serialize, Deserialize, Clone, round_based::ProtocolMessage)] enum Msg {}
//! # async fn protocol_of_random_generation<R: rand::RngCore, M: round_based::Mpc<ProtocolMessage = Msg>>(party: M,i: u16,n: u16,mut rng: R) -> Result<[u8; 32], Box<dyn std::error::Error>> { todo!() }
//!
//! let conn = ClientBuilder::new().connect::<Msg, _>("127.0.0.1:9090").await?;
//! let party = MpcParty::connect(conn);
//! // ... run mpc here, e.g.:
//! let randomness = protocol_of_random_generation(party, 1, 2, rand::rngs::OsRng).await?;
//! println!("Randomness: {}", hex::encode(randomness));
//! #
//! # Ok(()) }
//! ```
//!
//! _Note:_ `protocol_of_random_generation` is defined in [examples/mpc_random_generation.rs]
//!
//! [examples/mpc_random_generation.rs]: https://github.com/ZenGo-X/round-based-protocol/blob/main/round-based/examples/mpc_random_generation.rs

use std::net::SocketAddr;
use std::ops;

Expand All @@ -14,15 +63,15 @@ use serde::Serialize;

use super::{Side, TwoParty};

/// A connection established between two parties over plain TCP
pub type TwoPartyTcp<M> = TwoParty<M, OwnedReadHalf, OwnedWriteHalf>;

/// A party of twoparty protocol who runs a TCP server
/// A party of two party protocol who runs a TCP server
///
/// A wrapper around tokio [TcpListener](net::TcpListener) with overloaded [`accept`](Self::accept)
/// Server is a wrapper around tokio [TcpListener](net::TcpListener) with overloaded [`accept`](Self::accept)
/// method that returns [TwoPartyTcp] implementing [Delivery] trait.
///
/// If you need twoparty delivery for different transport (eg. QUIC), you'll have to construct
/// [TwoParty] structure manually.
/// [Delivery]: crate::Delivery
pub struct Server<M> {
listener: net::TcpListener,
buffer_capacity: usize,
Expand Down Expand Up @@ -81,6 +130,8 @@ where
/// Accepts a new incoming connection
///
/// Returns a [TwoPartyTcp] that implements [Delivery] trait, and address of the client.
///
/// [Delivery]: crate::Delivery
pub async fn accept(&mut self) -> io::Result<(TwoPartyTcp<M>, SocketAddr)> {
let (conn, remote_addr) = self.listener.accept().await?;
let (recv, send) = conn.into_split();
Expand Down Expand Up @@ -109,6 +160,7 @@ impl<M> ops::DerefMut for Server<M> {
}
}

/// Builds a party of two party protocol who acts as TCP client
pub struct ClientBuilder {
buffer_capacity: usize,
msg_len_limit: usize,
Expand Down Expand Up @@ -181,13 +233,9 @@ impl ClientBuilder {
#[cfg(test)]
mod tests {
use std::fmt::Debug;



use futures::TryStreamExt;

use futures::{TryStreamExt};


use serde::{Deserialize, Serialize};

use crate::delivery::{DeliverOutgoingExt, Delivery, Incoming, Outgoing};
Expand Down
Loading

0 comments on commit f0955be

Please sign in to comment.