Skip to content

Commit

Permalink
Merge pull request #54 from fjarri/fix-evidence
Browse files Browse the repository at this point in the history
Various evidence-related fixes
  • Loading branch information
fjarri authored Oct 30, 2024
2 parents c960b6c + f2459c9 commit cef7fab
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 48 deletions.
10 changes: 9 additions & 1 deletion examples/src/simple.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use alloc::collections::{BTreeMap, BTreeSet};
use alloc::{
collections::{BTreeMap, BTreeSet},
format,
string::String,
};
use core::fmt::Debug;

use manul::protocol::*;
Expand All @@ -15,6 +19,10 @@ pub enum SimpleProtocolError {
}

impl ProtocolError for SimpleProtocolError {
fn description(&self) -> String {
format!("{:?}", self)
}

fn required_direct_messages(&self) -> BTreeSet<RoundId> {
match self {
Self::Round1InvalidPosition => BTreeSet::new(),
Expand Down
12 changes: 6 additions & 6 deletions examples/src/simple_malicious.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@ fn serialized_garbage() {
let report1 = reports.remove(&v1).unwrap();
let report2 = reports.remove(&v2).unwrap();

assert!(report1.provable_errors[&v0].verify(&v0).is_ok());
assert!(report2.provable_errors[&v0].verify(&v0).is_ok());
assert!(report1.provable_errors[&v0].verify().is_ok());
assert!(report2.provable_errors[&v0].verify().is_ok());
}

#[test]
Expand Down Expand Up @@ -234,8 +234,8 @@ fn attributable_failure() {
let report1 = reports.remove(&v1).unwrap();
let report2 = reports.remove(&v2).unwrap();

assert!(report1.provable_errors[&v0].verify(&v0).is_ok());
assert!(report2.provable_errors[&v0].verify(&v0).is_ok());
assert!(report1.provable_errors[&v0].verify().is_ok());
assert!(report2.provable_errors[&v0].verify().is_ok());
}

#[test]
Expand Down Expand Up @@ -280,6 +280,6 @@ fn attributable_failure_round2() {
let report1 = reports.remove(&v1).unwrap();
let report2 = reports.remove(&v2).unwrap();

assert!(report1.provable_errors[&v0].verify(&v0).is_ok());
assert!(report2.provable_errors[&v0].verify(&v0).is_ok());
assert!(report1.provable_errors[&v0].verify().is_ok());
assert!(report2.provable_errors[&v0].verify().is_ok());
}
8 changes: 7 additions & 1 deletion manul/benches/empty_rounds.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
extern crate alloc;

use alloc::collections::{BTreeMap, BTreeSet};
use alloc::{
collections::{BTreeMap, BTreeSet},
string::String,
};
use core::fmt::Debug;

use criterion::{criterion_group, criterion_main, Criterion};
Expand All @@ -23,6 +26,9 @@ pub struct EmptyProtocol;
pub struct EmptyProtocolError;

impl ProtocolError for EmptyProtocolError {
fn description(&self) -> String {
unimplemented!()
}
fn verify_messages_constitute_error(
&self,
_deserializer: &Deserializer,
Expand Down
14 changes: 13 additions & 1 deletion manul/src/protocol/round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use alloc::{
boxed::Box,
collections::{BTreeMap, BTreeSet},
format,
string::String,
vec::Vec,
};
use core::{any::Any, fmt::Debug};
Expand Down Expand Up @@ -84,6 +85,11 @@ impl RoundId {
}
}

/// Returns `true` if this is an ID of an echo broadcast round.
pub(crate) fn is_echo(&self) -> bool {
self.is_echo
}

/// Returns the identifier of the echo round corresponding to the given non-echo round.
///
/// Panics if `self` is already an echo round identifier.
Expand Down Expand Up @@ -116,7 +122,7 @@ impl RoundId {
}

/// A distributed protocol.
pub trait Protocol: 'static + Sized {
pub trait Protocol: 'static {
/// The successful result of an execution of this protocol.
type Result: Debug;

Expand Down Expand Up @@ -161,6 +167,7 @@ pub trait Protocol: 'static + Sized {
///
/// Normally one would use [`EchoBroadcast::verify_is_not`] when implementing this.
fn verify_normal_broadcast_is_invalid(
#[allow(unused_variables)] deserializer: &Deserializer,
round_id: RoundId,
#[allow(unused_variables)] message: &NormalBroadcast,
) -> Result<(), MessageValidationError> {
Expand All @@ -175,6 +182,11 @@ pub trait Protocol: 'static + Sized {
/// Provable here means that we can create an evidence object entirely of messages signed by some party,
/// which, in combination, prove the party's malicious actions.
pub trait ProtocolError: Debug + Clone + Send {
/// A description of the error that will be included in the generated evidence.
///
/// Make it short and informative.
fn description(&self) -> String;

/// The rounds direct messages from which are required to prove malicious behavior for this error.
///
/// **Note:** Should not include the round where the error happened.
Expand Down
1 change: 1 addition & 0 deletions manul/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod transcript;
mod wire_format;

pub use crate::protocol::{LocalError, RemoteError};
pub use evidence::{Evidence, EvidenceError};
pub use message::MessageBundle;
pub use session::{CanFinalize, RoundAccumulator, RoundOutcome, Session, SessionId, SessionParameters};
pub use transcript::{SessionOutcome, SessionReport};
Expand Down
38 changes: 35 additions & 3 deletions manul/src/session/echo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use alloc::{
boxed::Box,
collections::{BTreeMap, BTreeSet},
format,
string::String,
vec::Vec,
};
use core::fmt::Debug;
Expand All @@ -17,8 +18,9 @@ use super::{
};
use crate::{
protocol::{
Artifact, Deserializer, DirectMessage, EchoBroadcast, FinalizeError, FinalizeOutcome, NormalBroadcast,
ObjectSafeRound, Payload, Protocol, ProtocolMessagePart, ReceiveError, Round, RoundId, Serializer,
Artifact, Deserializer, DirectMessage, EchoBroadcast, FinalizeError, FinalizeOutcome, MessageValidationError,
NormalBroadcast, ObjectSafeRound, Payload, Protocol, ProtocolMessagePart, ReceiveError, Round, RoundId,
Serializer,
},
utils::SerializableMap,
};
Expand All @@ -45,6 +47,17 @@ pub(crate) enum EchoRoundError<Id> {
},
}

impl<Id> EchoRoundError<Id> {
pub(crate) fn description(&self) -> String {
match self {
Self::InvalidEcho(_) => "Invalid message received among the ones echoed".into(),
Self::MismatchedBroadcasts { .. } => {
"The echoed message is different from the originally received one".into()
}
}
}
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub(crate) enum MismatchedBroadcastsError {
/// The originally received message and the echoed one had different payloads.
Expand All @@ -55,7 +68,7 @@ pub(crate) enum MismatchedBroadcastsError {

#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct EchoRoundMessage<SP: SessionParameters> {
pub(crate) echo_broadcasts: SerializableMap<SP::Verifier, SignedMessage<EchoBroadcast>>,
pub(super) echo_broadcasts: SerializableMap<SP::Verifier, SignedMessage<EchoBroadcast>>,
}

/// Each protocol round can contain one `EchoRound` with "echo messages" that are sent to all
Expand Down Expand Up @@ -105,6 +118,25 @@ where
artifacts,
}
}

// Since the echo round doesn't have its own `Protocol`, these methods live here.

pub fn verify_direct_message_is_invalid(message: &DirectMessage) -> Result<(), MessageValidationError> {
// We don't send any direct messages in the echo round
message.verify_is_some()
}

pub fn verify_echo_broadcast_is_invalid(message: &EchoBroadcast) -> Result<(), MessageValidationError> {
// We don't send any echo broadcasts in the echo round
message.verify_is_some()
}

pub fn verify_normal_broadcast_is_invalid(
deserializer: &Deserializer,
message: &NormalBroadcast,
) -> Result<(), MessageValidationError> {
message.verify_is_not::<EchoRoundMessage<SP>>(deserializer)
}
}

impl<P, SP> Round<SP::Verifier> for EchoRound<P, SP>
Expand Down
Loading

0 comments on commit cef7fab

Please sign in to comment.