Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added a `Test` prefix to `testing::Signer`/`Verifier`/`Signature`/`Hasher` and renamed `TestingSessionParams` to `TestSessionParams`. ([#40])
- `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])


### Added

- `SerializableMap` wrapper for `BTreeMap` supporting more formats and providing some safety features. (#[32])
- `DirectMessage::assert_is_none()` and `verify_is_some()`, same for `EchoBroadcast`. Users can now check that a part of the round message (echo or direct) is `None` as expected, and make a verifiable evidence if it is not. ([#46])


[#32]: https://github.com/entropyxyz/manul/pull/32
[#36]: https://github.com/entropyxyz/manul/pull/36
[#37]: https://github.com/entropyxyz/manul/pull/37
[#40]: https://github.com/entropyxyz/manul/pull/40
[#41]: https://github.com/entropyxyz/manul/pull/41
[#46]: https://github.com/entropyxyz/manul/pull/46


## [0.0.1] - 2024-10-12
Expand Down
51 changes: 28 additions & 23 deletions examples/src/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl ProtocolError for SimpleProtocolError {

fn verify_messages_constitute_error(
&self,
_echo_broadcast: &Option<EchoBroadcast>,
_echo_broadcast: &EchoBroadcast,
direct_message: &DirectMessage,
_echo_broadcasts: &BTreeMap<RoundId, EchoBroadcast>,
_direct_messages: &BTreeMap<RoundId, DirectMessage>,
Expand Down Expand Up @@ -87,10 +87,22 @@ impl Protocol for SimpleProtocol {
round_id: RoundId,
message: &DirectMessage,
) -> Result<(), MessageValidationError> {
if round_id == RoundId::new(1) {
return message.verify_is_invalid::<Self, Round1Message>();
match round_id {
r if r == RoundId::new(1) => message.verify_is_not::<Self, Round1Message>(),
r if r == RoundId::new(2) => message.verify_is_not::<Self, Round2Message>(),
_ => Err(MessageValidationError::InvalidEvidence("Invalid round number".into())),
}
}

fn verify_echo_broadcast_is_invalid(
round_id: RoundId,
message: &EchoBroadcast,
) -> Result<(), MessageValidationError> {
match round_id {
r if r == RoundId::new(1) => message.verify_is_some(),
r if r == RoundId::new(2) => message.verify_is_not::<Self, Round2Message>(),
_ => Err(MessageValidationError::InvalidEvidence("Invalid round number".into())),
}
Err(MessageValidationError::InvalidEvidence("Invalid round number".into()))?
}
}

Expand Down Expand Up @@ -171,41 +183,41 @@ impl<Id: 'static + Debug + Clone + Ord + Send + Sync> Round<Id> for Round1<Id> {
&self.context.other_ids
}

fn make_echo_broadcast(&self, _rng: &mut impl CryptoRngCore) -> Option<Result<EchoBroadcast, LocalError>> {
fn make_echo_broadcast(&self, _rng: &mut impl CryptoRngCore) -> Result<EchoBroadcast, LocalError> {
debug!("{:?}: making echo broadcast", self.context.id);

let message = Round1Echo {
my_position: self.context.ids_to_positions[&self.context.id],
};

Some(Self::serialize_echo_broadcast(message))
Self::serialize_echo_broadcast(message)
}

fn make_direct_message(
&self,
_rng: &mut impl CryptoRngCore,
destination: &Id,
) -> Result<(DirectMessage, Artifact), LocalError> {
) -> Result<DirectMessage, 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],
};
let dm = Self::serialize_direct_message(message)?;
let artifact = Artifact::empty();
Ok((dm, artifact))
Ok(dm)
}

fn receive_message(
&self,
_rng: &mut impl CryptoRngCore,
from: &Id,
_echo_broadcast: Option<EchoBroadcast>,
echo_broadcast: EchoBroadcast,
direct_message: DirectMessage,
) -> Result<Payload, ReceiveError<Id, Self::Protocol>> {
debug!("{:?}: receiving message from {:?}", self.context.id, from);

let _echo = echo_broadcast.deserialize::<SimpleProtocol, Round1Echo>()?;
let message = direct_message.deserialize::<SimpleProtocol, Round1Message>()?;

debug!("{:?}: received message: {:?}", self.context.id, message);
Expand Down Expand Up @@ -275,41 +287,34 @@ impl<Id: 'static + Debug + Clone + Ord + Send + Sync> Round<Id> for Round2<Id> {
&self.context.other_ids
}

fn make_echo_broadcast(&self, _rng: &mut impl CryptoRngCore) -> Option<Result<EchoBroadcast, LocalError>> {
debug!("{:?}: making echo broadcast", self.context.id);

let message = Round1Echo {
my_position: self.context.ids_to_positions[&self.context.id],
};

Some(Self::serialize_echo_broadcast(message))
}
// Does not send echo broadcasts

fn make_direct_message(
&self,
_rng: &mut impl CryptoRngCore,
destination: &Id,
) -> Result<(DirectMessage, Artifact), LocalError> {
) -> Result<DirectMessage, 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],
};
let dm = Self::serialize_direct_message(message)?;
let artifact = Artifact::empty();
Ok((dm, artifact))
Ok(dm)
}

fn receive_message(
&self,
_rng: &mut impl CryptoRngCore,
from: &Id,
_echo_broadcast: Option<EchoBroadcast>,
echo_broadcast: EchoBroadcast,
direct_message: DirectMessage,
) -> Result<Payload, ReceiveError<Id, Self::Protocol>> {
debug!("{:?}: receiving message from {:?}", self.context.id, from);

echo_broadcast.assert_is_none()?;

let message = direct_message.deserialize::<SimpleProtocol, Round1Message>()?;

debug!("{:?}: received message: {:?}", self.context.id, message);
Expand Down
18 changes: 5 additions & 13 deletions examples/src/simple_malicious.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,17 @@ impl<Id: 'static + Debug + Clone + Ord + Send + Sync> FirstRound<Id> for Malicio
}

impl<Id: 'static + Debug + Clone + Ord + Send + Sync> RoundOverride<Id> for MaliciousRound1<Id> {
fn make_direct_message(
&self,
rng: &mut impl CryptoRngCore,
destination: &Id,
) -> Result<(DirectMessage, Artifact), LocalError> {
fn make_direct_message(&self, rng: &mut impl CryptoRngCore, destination: &Id) -> Result<DirectMessage, LocalError> {
if matches!(self.behavior, Behavior::SerializedGarbage) {
let dm = DirectMessage::new::<<Self::InnerRound as Round<Id>>::Protocol, _>(&[99u8]).unwrap();
Ok((dm, Artifact::empty()))
Ok(dm)
} else if matches!(self.behavior, Behavior::AttributableFailure) {
let message = Round1Message {
my_position: self.round.context.ids_to_positions[&self.round.context.id],
your_position: self.round.context.ids_to_positions[&self.round.context.id],
};
let dm = DirectMessage::new::<<Self::InnerRound as Round<Id>>::Protocol, _>(&message)?;
Ok((dm, Artifact::empty()))
Ok(dm)
} else {
self.inner_round_ref().make_direct_message(rng, destination)
}
Expand Down Expand Up @@ -121,18 +117,14 @@ impl<Id: 'static + Debug + Clone + Ord + Send + Sync> RoundWrapper<Id> for Malic
}

impl<Id: 'static + Debug + Clone + Ord + Send + Sync> RoundOverride<Id> for MaliciousRound2<Id> {
fn make_direct_message(
&self,
rng: &mut impl CryptoRngCore,
destination: &Id,
) -> Result<(DirectMessage, Artifact), LocalError> {
fn make_direct_message(&self, rng: &mut impl CryptoRngCore, destination: &Id) -> Result<DirectMessage, LocalError> {
if matches!(self.behavior, Behavior::AttributableFailureRound2) {
let message = Round2Message {
my_position: self.round.context.ids_to_positions[&self.round.context.id],
your_position: self.round.context.ids_to_positions[&self.round.context.id],
};
let dm = DirectMessage::new::<<Self::InnerRound as Round<Id>>::Protocol, _>(&message)?;
Ok((dm, Artifact::empty()))
Ok(dm)
} else {
self.inner_round_ref().make_direct_message(rng, destination)
}
Expand Down
24 changes: 13 additions & 11 deletions manul/benches/empty_rounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub struct EmptyProtocolError;
impl ProtocolError for EmptyProtocolError {
fn verify_messages_constitute_error(
&self,
_echo_broadcast: &Option<EchoBroadcast>,
_echo_broadcast: &EchoBroadcast,
_direct_message: &DirectMessage,
_echo_broadcasts: &BTreeMap<RoundId, EchoBroadcast>,
_direct_messages: &BTreeMap<RoundId, DirectMessage>,
Expand Down Expand Up @@ -108,34 +108,36 @@ impl<Id: 'static + Debug + Clone + Ord + Send + Sync> Round<Id> for EmptyRound<I
&self.inputs.other_ids
}

fn make_echo_broadcast(&self, _rng: &mut impl CryptoRngCore) -> Option<Result<EchoBroadcast, LocalError>> {
fn make_echo_broadcast(&self, _rng: &mut impl CryptoRngCore) -> Result<EchoBroadcast, LocalError> {
if self.inputs.echo {
Some(Self::serialize_echo_broadcast(Round1EchoBroadcast))
Self::serialize_echo_broadcast(Round1EchoBroadcast)
} else {
None
Ok(EchoBroadcast::none())
}
}

fn make_direct_message(
fn make_direct_message_with_artifact(
&self,
_rng: &mut impl CryptoRngCore,
_destination: &Id,
) -> Result<(DirectMessage, Artifact), LocalError> {
) -> Result<(DirectMessage, Option<Artifact>), LocalError> {
let dm = Self::serialize_direct_message(Round1DirectMessage)?;
let artifact = Artifact::new(Round1Artifact);
Ok((dm, artifact))
Ok((dm, Some(artifact)))
}

fn receive_message(
&self,
_rng: &mut impl CryptoRngCore,
_from: &Id,
echo_broadcast: Option<EchoBroadcast>,
echo_broadcast: EchoBroadcast,
direct_message: DirectMessage,
) -> Result<Payload, ReceiveError<Id, Self::Protocol>> {
let _echo_broadcast = echo_broadcast
.map(|echo| echo.deserialize::<EmptyProtocol, Round1EchoBroadcast>())
.transpose()?;
if self.inputs.echo {
let _echo_broadcast = echo_broadcast.deserialize::<EmptyProtocol, Round1EchoBroadcast>()?;
} else {
echo_broadcast.assert_is_none()?;
}
let _direct_message = direct_message.deserialize::<EmptyProtocol, Round1DirectMessage>()?;
Ok(Payload::new(Round1Payload))
}
Expand Down
5 changes: 3 additions & 2 deletions manul/src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,17 @@ For more details, see the documentation of the mentioned traits.
*/

mod errors;
mod message;
mod object_safe;
mod round;

pub use errors::{
DeserializationError, DirectMessageError, EchoBroadcastError, FinalizeError, LocalError, MessageValidationError,
ProtocolValidationError, ReceiveError, RemoteError,
};
pub use message::{DirectMessage, EchoBroadcast};
pub use round::{
AnotherRound, Artifact, DirectMessage, EchoBroadcast, FinalizeOutcome, FirstRound, Payload, Protocol,
ProtocolError, Round, RoundId,
AnotherRound, Artifact, FinalizeOutcome, FirstRound, Payload, Protocol, ProtocolError, Round, RoundId,
};

pub(crate) use errors::ReceiveErrorType;
Expand Down
16 changes: 14 additions & 2 deletions manul/src/protocol/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,13 @@ impl From<LocalError> for ProtocolValidationError {
pub struct DirectMessageError(DeserializationError);

impl DirectMessageError {
pub(crate) fn new(error: DeserializationError) -> Self {
pub(crate) fn new(message: impl Into<String>) -> Self {
Self(DeserializationError::new(message))
}
}

impl From<DeserializationError> for DirectMessageError {
fn from(error: DeserializationError) -> Self {
Self(error)
}
}
Expand All @@ -204,7 +210,13 @@ impl DirectMessageError {
pub struct EchoBroadcastError(DeserializationError);

impl EchoBroadcastError {
pub(crate) fn new(error: DeserializationError) -> Self {
pub(crate) fn new(message: impl Into<String>) -> Self {
Self(DeserializationError::new(message))
}
}

impl From<DeserializationError> for EchoBroadcastError {
fn from(error: DeserializationError) -> Self {
Self(error)
}
}
Loading
Loading