Skip to content

Commit

Permalink
Merge pull request #60 from fjarri/combinators
Browse files Browse the repository at this point in the history
Protocol combinators
  • Loading branch information
fjarri authored Nov 13, 2024
2 parents c98e50c + 600cf85 commit b8dc733
Show file tree
Hide file tree
Showing 24 changed files with 1,313 additions and 583 deletions.
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `SessionId::new()` renamed to `from_seed()`. ([#41])
- `FirstRound::new()` takes a `&[u8]` instead of a `SessionId` object. ([#41])
- The signatures of `Round::make_echo_broadcast()`, `Round::make_direct_message()`, and `Round::receive_message()`, take messages without `Option`s. ([#46])
- `Round::make_direct_message_with_artifact()` is the method returning an artifact now; `Round::make_direct_message()` is a shortcut for cases where no artifact is returned. ([#46])
- `Artifact::empty()` removed, the user should return `None` instead. ([#46])
- `EchoBroadcast` and `DirectMessage` now use `ProtocolMessagePart` trait for their methods. ([#47])
- Added normal broadcasts support in addition to echo ones; signatures of `Round` methods changed accordingly; added `Round::make_normal_broadcast()`. ([#47])
- Serialization format is a part of `SessionParameters` now; `Round` and `Protocol` methods receive dynamic serializers/deserializers. ([#33])
- Renamed `(Verified)MessageBundle` to `(Verified)Message`. Both are now generic over `Verifier`. ([#56])
- `Session::preprocess_message()` now returns a `PreprocessOutcome` instead of just an `Option`. ([#57])
- `Session::terminate_due_to_errors()` replaces `terminate()`; `terminate()` now signals user interrupt. ([#58])
- Renamed `FirstRound` trait to `EntryPoint`. ([#60])
- Added `Protocol` type to `EntryPoint`. ([#60])
- `EntryPoint` and `FinalizeOutcome::AnotherRound` now use a new `BoxedRound` wrapper type. ([#60])
- `PartyId` and `ProtocolError` are now bound on `Serialize`/`Deserialize`. ([#60])


### Added
Expand All @@ -31,6 +34,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Re-export `digest` from the `session` module. ([#56])
- Added `Message::destination()`. ([#56])
- `PartyId` trait alias for the combination of bounds needed for a party identifier. ([#59])
- An impl of `ProtocolError` for `()` for protocols that don't use errors. ([#60])
- A dummy `CorrectnessProof` trait. ([#60])
- A `misbehave` combinator, intended primarily for testing. ([#60])
- A `chain` combinator for chaining two protocols. ([#60])
- `EntryPoint::ENTRY_ROUND` constant. ([#60])


[#32]: https://github.com/entropyxyz/manul/pull/32
Expand All @@ -45,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#57]: https://github.com/entropyxyz/manul/pull/57
[#58]: https://github.com/entropyxyz/manul/pull/58
[#59]: https://github.com/entropyxyz/manul/pull/59
[#60]: https://github.com/entropyxyz/manul/pull/60


## [0.0.1] - 2024-10-12
Expand Down
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
extern crate alloc;

pub mod simple;
pub mod simple_chain;

#[cfg(test)]
mod simple_malicious;
25 changes: 14 additions & 11 deletions examples/src/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,15 @@ struct Round1Payload {
x: u8,
}

impl<Id: PartyId> FirstRound<Id> for Round1<Id> {
impl<Id: PartyId> EntryPoint<Id> for Round1<Id> {
type Inputs = Inputs<Id>;
type Protocol = SimpleProtocol;
fn new(
_rng: &mut impl CryptoRngCore,
_shared_randomness: &[u8],
id: Id,
inputs: Self::Inputs,
) -> Result<Self, LocalError> {
) -> Result<BoxedRound<Id, Self::Protocol>, LocalError> {
// Just some numbers associated with IDs to use in the dummy protocol.
// They will be the same on each node since IDs are ordered.
let ids_to_positions = inputs
Expand All @@ -169,13 +170,13 @@ impl<Id: PartyId> FirstRound<Id> for Round1<Id> {
let mut ids = inputs.all_ids;
ids.remove(&id);

Ok(Self {
Ok(BoxedRound::new_dynamic(Self {
context: Context {
id,
other_ids: ids,
ids_to_positions,
},
})
}))
}
}

Expand Down Expand Up @@ -228,14 +229,15 @@ impl<Id: PartyId> Round<Id> for Round1<Id> {
_rng: &mut impl CryptoRngCore,
serializer: &Serializer,
destination: &Id,
) -> Result<DirectMessage, LocalError> {
) -> Result<(DirectMessage, Option<Artifact>), LocalError> {
debug!("{:?}: making direct message for {:?}", self.context.id, destination);

let message = Round1Message {
my_position: self.context.ids_to_positions[&self.context.id],
your_position: self.context.ids_to_positions[destination],
};
DirectMessage::new(serializer, message)
let dm = DirectMessage::new(serializer, message)?;
Ok((dm, None))
}

fn receive_message(
Expand Down Expand Up @@ -281,11 +283,11 @@ impl<Id: PartyId> Round<Id> for Round1<Id> {
let sum = self.context.ids_to_positions[&self.context.id]
+ typed_payloads.iter().map(|payload| payload.x).sum::<u8>();

let round2 = Round2 {
let round2 = BoxedRound::new_dynamic(Round2 {
round1_sum: sum,
context: self.context,
};
Ok(FinalizeOutcome::another_round(round2))
});
Ok(FinalizeOutcome::AnotherRound(round2))
}

fn expecting_messages_from(&self) -> &BTreeSet<Id> {
Expand Down Expand Up @@ -325,14 +327,15 @@ impl<Id: PartyId> Round<Id> for Round2<Id> {
_rng: &mut impl CryptoRngCore,
serializer: &Serializer,
destination: &Id,
) -> Result<DirectMessage, LocalError> {
) -> Result<(DirectMessage, Option<Artifact>), LocalError> {
debug!("{:?}: making direct message for {:?}", self.context.id, destination);

let message = Round2Message {
my_position: self.context.ids_to_positions[&self.context.id],
your_position: self.context.ids_to_positions[destination],
};
DirectMessage::new(serializer, message)
let dm = DirectMessage::new(serializer, message)?;
Ok((dm, None))
}

fn receive_message(
Expand Down
85 changes: 85 additions & 0 deletions examples/src/simple_chain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use core::fmt::Debug;

use manul::{
combinators::chain::{Chained, ChainedEntryPoint},
protocol::PartyId,
};

use super::simple::{Inputs, Round1};

pub struct ChainedSimple;

#[derive(Debug)]
pub struct NewInputs<Id>(Inputs<Id>);

impl<'a, Id: PartyId> From<&'a NewInputs<Id>> for Inputs<Id> {
fn from(source: &'a NewInputs<Id>) -> Self {
source.0.clone()
}
}

impl<Id: PartyId> From<(NewInputs<Id>, u8)> for Inputs<Id> {
fn from(source: (NewInputs<Id>, u8)) -> Self {
let (inputs, _result) = source;
inputs.0
}
}

impl<Id: PartyId> Chained<Id> for ChainedSimple {
type Inputs = NewInputs<Id>;
type EntryPoint1 = Round1<Id>;
type EntryPoint2 = Round1<Id>;
}

pub type DoubleSimpleEntryPoint<Id> = ChainedEntryPoint<Id, ChainedSimple>;

#[cfg(test)]
mod tests {
use alloc::collections::BTreeSet;

use manul::{
session::{signature::Keypair, SessionOutcome},
testing::{run_sync, BinaryFormat, TestSessionParams, TestSigner, TestVerifier},
};
use rand_core::OsRng;
use tracing_subscriber::EnvFilter;

use super::{DoubleSimpleEntryPoint, NewInputs};
use crate::simple::Inputs;

#[test]
fn round() {
let signers = (0..3).map(TestSigner::new).collect::<Vec<_>>();
let all_ids = signers
.iter()
.map(|signer| signer.verifying_key())
.collect::<BTreeSet<_>>();
let inputs = signers
.into_iter()
.map(|signer| {
(
signer,
NewInputs(Inputs {
all_ids: all_ids.clone(),
}),
)
})
.collect::<Vec<_>>();

let my_subscriber = tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env())
.finish();
let reports = tracing::subscriber::with_default(my_subscriber, || {
run_sync::<DoubleSimpleEntryPoint<TestVerifier>, TestSessionParams<BinaryFormat>>(&mut OsRng, inputs)
.unwrap()
});

for (_id, report) in reports {
if let SessionOutcome::Result(result) = report.outcome {
assert_eq!(result, 3); // 0 + 1 + 2
} else {
panic!("Session did not finish successfully");
}
}
}
}
Loading

0 comments on commit b8dc733

Please sign in to comment.