Skip to content

Commit

Permalink
Sign and send empty messages if a round doesn't send a specific messa…
Browse files Browse the repository at this point in the history
…ge part
  • Loading branch information
fjarri committed Oct 25, 2024
1 parent 794de35 commit 0c8843b
Show file tree
Hide file tree
Showing 15 changed files with 353 additions and 211 deletions.
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

0 comments on commit 0c8843b

Please sign in to comment.