Skip to content

Commit 4ac63df

Browse files
authored
Merge pull request #94 from fjarri/housekeeping
Make `Round` dyn-safe
2 parents 93f62ec + e777fca commit 4ac63df

19 files changed

+375
-648
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2929
- Removed `Send` bound on `ProtocolError`. ([#92])
3030
- Merged `Round::id()`, `possible_next_rounds()` and `may_produce_result()` into `transition_info()`. ([#93])
3131
- Merged `Round::message_destinations()`, `expecting_messages_from()` and `echo_round_participation()` into `communication_info()`. ([#93])
32+
- Renamed `Payload::try_to_typed()` and `Artifact::try_to_typed()` to `downcast()`. ([#94])
33+
- `Round` methods take `dyn CryptoRngCore` instead of `impl CryptoRngCore`. ([#94])
34+
- `Round` is now dyn-safe. `serializer` and `deserializer` arguments to `Round` and related traits are merged into `format`. `Round::finalize()` takes `self: Box<Self>`. ([#94])
3235

3336

3437
### Added
@@ -64,6 +67,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6467
[#91]: https://github.com/entropyxyz/manul/pull/91
6568
[#92]: https://github.com/entropyxyz/manul/pull/92
6669
[#93]: https://github.com/entropyxyz/manul/pull/93
70+
[#94]: https://github.com/entropyxyz/manul/pull/94
6771

6872

6973
## [0.1.0] - 2024-11-19

Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/src/simple.rs

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ use alloc::collections::{BTreeMap, BTreeSet};
22
use core::fmt::Debug;
33

44
use manul::protocol::{
5-
Artifact, BoxedRound, CommunicationInfo, Deserializer, DirectMessage, EchoBroadcast, EntryPoint, FinalizeOutcome,
5+
Artifact, BoxedFormat, BoxedRound, CommunicationInfo, DirectMessage, EchoBroadcast, EntryPoint, FinalizeOutcome,
66
LocalError, MessageValidationError, NormalBroadcast, PartyId, Payload, Protocol, ProtocolError, ProtocolMessage,
77
ProtocolMessagePart, ProtocolValidationError, ReceiveError, RequiredMessageParts, RequiredMessages, Round, RoundId,
8-
Serializer, TransitionInfo,
8+
TransitionInfo,
99
};
1010
use rand_core::CryptoRngCore;
1111
use serde::{Deserialize, Serialize};
@@ -39,7 +39,7 @@ impl<Id> ProtocolError<Id> for SimpleProtocolError {
3939

4040
fn verify_messages_constitute_error(
4141
&self,
42-
deserializer: &Deserializer,
42+
format: &BoxedFormat,
4343
_guilty_party: &Id,
4444
_shared_randomness: &[u8],
4545
_associated_data: &Self::AssociatedData,
@@ -49,20 +49,20 @@ impl<Id> ProtocolError<Id> for SimpleProtocolError {
4949
) -> Result<(), ProtocolValidationError> {
5050
match self {
5151
SimpleProtocolError::Round1InvalidPosition => {
52-
let _message = message.direct_message.deserialize::<Round1Message>(deserializer)?;
52+
let _message = message.direct_message.deserialize::<Round1Message>(format)?;
5353
// Message contents would be checked here
5454
Ok(())
5555
}
5656
SimpleProtocolError::Round2InvalidPosition => {
57-
let _r1_message = message.direct_message.deserialize::<Round1Message>(deserializer)?;
57+
let _r1_message = message.direct_message.deserialize::<Round1Message>(format)?;
5858
let r1_echos_serialized = combined_echos
5959
.get(&1.into())
6060
.ok_or_else(|| LocalError::new("Could not find combined echos for Round 1"))?;
6161

6262
// Deserialize the echos
6363
let _r1_echos = r1_echos_serialized
6464
.iter()
65-
.map(|(_id, echo)| echo.deserialize::<Round1Echo>(deserializer))
65+
.map(|(_id, echo)| echo.deserialize::<Round1Echo>(format))
6666
.collect::<Result<Vec<_>, _>>()?;
6767

6868
// Message contents would be checked here
@@ -77,36 +77,36 @@ impl<Id> Protocol<Id> for SimpleProtocol {
7777
type ProtocolError = SimpleProtocolError;
7878

7979
fn verify_direct_message_is_invalid(
80-
deserializer: &Deserializer,
80+
format: &BoxedFormat,
8181
round_id: &RoundId,
8282
message: &DirectMessage,
8383
) -> Result<(), MessageValidationError> {
8484
match round_id {
85-
r if r == &1 => message.verify_is_not::<Round1Message>(deserializer),
86-
r if r == &2 => message.verify_is_not::<Round2Message>(deserializer),
85+
r if r == &1 => message.verify_is_not::<Round1Message>(format),
86+
r if r == &2 => message.verify_is_not::<Round2Message>(format),
8787
_ => Err(MessageValidationError::InvalidEvidence("Invalid round number".into())),
8888
}
8989
}
9090

9191
fn verify_echo_broadcast_is_invalid(
92-
deserializer: &Deserializer,
92+
format: &BoxedFormat,
9393
round_id: &RoundId,
9494
message: &EchoBroadcast,
9595
) -> Result<(), MessageValidationError> {
9696
match round_id {
97-
r if r == &1 => message.verify_is_not::<Round1Echo>(deserializer),
97+
r if r == &1 => message.verify_is_not::<Round1Echo>(format),
9898
r if r == &2 => message.verify_is_some(),
9999
_ => Err(MessageValidationError::InvalidEvidence("Invalid round number".into())),
100100
}
101101
}
102102

103103
fn verify_normal_broadcast_is_invalid(
104-
deserializer: &Deserializer,
104+
format: &BoxedFormat,
105105
round_id: &RoundId,
106106
message: &NormalBroadcast,
107107
) -> Result<(), MessageValidationError> {
108108
match round_id {
109-
r if r == &1 => message.verify_is_not::<Round1Broadcast>(deserializer),
109+
r if r == &1 => message.verify_is_not::<Round1Broadcast>(format),
110110
r if r == &2 => message.verify_is_some(),
111111
_ => Err(MessageValidationError::InvalidEvidence("Invalid round number".into())),
112112
}
@@ -166,7 +166,7 @@ impl<Id: PartyId> EntryPoint<Id> for SimpleProtocolEntryPoint<Id> {
166166

167167
fn make_round(
168168
self,
169-
_rng: &mut impl CryptoRngCore,
169+
_rng: &mut dyn CryptoRngCore,
170170
_shared_randomness: &[u8],
171171
id: &Id,
172172
) -> Result<BoxedRound<Id, Self::Protocol>, LocalError> {
@@ -205,8 +205,8 @@ impl<Id: PartyId> Round<Id> for Round1<Id> {
205205

206206
fn make_normal_broadcast(
207207
&self,
208-
_rng: &mut impl CryptoRngCore,
209-
serializer: &Serializer,
208+
_rng: &mut dyn CryptoRngCore,
209+
format: &BoxedFormat,
210210
) -> Result<NormalBroadcast, LocalError> {
211211
debug!("{:?}: making normal broadcast", self.context.id);
212212

@@ -215,27 +215,27 @@ impl<Id: PartyId> Round<Id> for Round1<Id> {
215215
my_position: self.context.ids_to_positions[&self.context.id],
216216
};
217217

218-
NormalBroadcast::new(serializer, message)
218+
NormalBroadcast::new(format, message)
219219
}
220220

221221
fn make_echo_broadcast(
222222
&self,
223-
_rng: &mut impl CryptoRngCore,
224-
serializer: &Serializer,
223+
_rng: &mut dyn CryptoRngCore,
224+
format: &BoxedFormat,
225225
) -> Result<EchoBroadcast, LocalError> {
226226
debug!("{:?}: making echo broadcast", self.context.id);
227227

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

232-
EchoBroadcast::new(serializer, message)
232+
EchoBroadcast::new(format, message)
233233
}
234234

235235
fn make_direct_message(
236236
&self,
237-
_rng: &mut impl CryptoRngCore,
238-
serializer: &Serializer,
237+
_rng: &mut dyn CryptoRngCore,
238+
format: &BoxedFormat,
239239
destination: &Id,
240240
) -> Result<(DirectMessage, Option<Artifact>), LocalError> {
241241
debug!("{:?}: making direct message for {:?}", self.context.id, destination);
@@ -244,21 +244,21 @@ impl<Id: PartyId> Round<Id> for Round1<Id> {
244244
my_position: self.context.ids_to_positions[&self.context.id],
245245
your_position: self.context.ids_to_positions[destination],
246246
};
247-
let dm = DirectMessage::new(serializer, message)?;
247+
let dm = DirectMessage::new(format, message)?;
248248
Ok((dm, None))
249249
}
250250

251251
fn receive_message(
252252
&self,
253-
deserializer: &Deserializer,
253+
format: &BoxedFormat,
254254
from: &Id,
255255
message: ProtocolMessage,
256256
) -> Result<Payload, ReceiveError<Id, Self::Protocol>> {
257257
debug!("{:?}: receiving message from {:?}", self.context.id, from);
258258

259-
let _echo = message.echo_broadcast.deserialize::<Round1Echo>(deserializer)?;
260-
let _normal = message.normal_broadcast.deserialize::<Round1Broadcast>(deserializer)?;
261-
let message = message.direct_message.deserialize::<Round1Message>(deserializer)?;
259+
let _echo = message.echo_broadcast.deserialize::<Round1Echo>(format)?;
260+
let _normal = message.normal_broadcast.deserialize::<Round1Broadcast>(format)?;
261+
let message = message.direct_message.deserialize::<Round1Message>(format)?;
262262

263263
debug!("{:?}: received message: {:?}", self.context.id, message);
264264

@@ -270,8 +270,8 @@ impl<Id: PartyId> Round<Id> for Round1<Id> {
270270
}
271271

272272
fn finalize(
273-
self,
274-
_rng: &mut impl CryptoRngCore,
273+
self: Box<Self>,
274+
_rng: &mut dyn CryptoRngCore,
275275
payloads: BTreeMap<Id, Payload>,
276276
_artifacts: BTreeMap<Id, Artifact>,
277277
) -> Result<FinalizeOutcome<Id, Self::Protocol>, LocalError> {
@@ -283,7 +283,7 @@ impl<Id: PartyId> Round<Id> for Round1<Id> {
283283

284284
let typed_payloads = payloads
285285
.into_values()
286-
.map(|payload| payload.try_to_typed::<Round1Payload>())
286+
.map(|payload| payload.downcast::<Round1Payload>())
287287
.collect::<Result<Vec<_>, _>>()?;
288288
let sum = self.context.ids_to_positions[&self.context.id]
289289
+ typed_payloads.iter().map(|payload| payload.x).sum::<u8>();
@@ -321,8 +321,8 @@ impl<Id: PartyId> Round<Id> for Round2<Id> {
321321

322322
fn make_direct_message(
323323
&self,
324-
_rng: &mut impl CryptoRngCore,
325-
serializer: &Serializer,
324+
_rng: &mut dyn CryptoRngCore,
325+
format: &BoxedFormat,
326326
destination: &Id,
327327
) -> Result<(DirectMessage, Option<Artifact>), LocalError> {
328328
debug!("{:?}: making direct message for {:?}", self.context.id, destination);
@@ -331,13 +331,13 @@ impl<Id: PartyId> Round<Id> for Round2<Id> {
331331
my_position: self.context.ids_to_positions[&self.context.id],
332332
your_position: self.context.ids_to_positions[destination],
333333
};
334-
let dm = DirectMessage::new(serializer, message)?;
334+
let dm = DirectMessage::new(format, message)?;
335335
Ok((dm, None))
336336
}
337337

338338
fn receive_message(
339339
&self,
340-
deserializer: &Deserializer,
340+
format: &BoxedFormat,
341341
from: &Id,
342342
message: ProtocolMessage,
343343
) -> Result<Payload, ReceiveError<Id, Self::Protocol>> {
@@ -346,7 +346,7 @@ impl<Id: PartyId> Round<Id> for Round2<Id> {
346346
message.echo_broadcast.assert_is_none()?;
347347
message.normal_broadcast.assert_is_none()?;
348348

349-
let message = message.direct_message.deserialize::<Round1Message>(deserializer)?;
349+
let message = message.direct_message.deserialize::<Round1Message>(format)?;
350350

351351
debug!("{:?}: received message: {:?}", self.context.id, message);
352352

@@ -358,8 +358,8 @@ impl<Id: PartyId> Round<Id> for Round2<Id> {
358358
}
359359

360360
fn finalize(
361-
self,
362-
_rng: &mut impl CryptoRngCore,
361+
self: Box<Self>,
362+
_rng: &mut dyn CryptoRngCore,
363363
payloads: BTreeMap<Id, Payload>,
364364
_artifacts: BTreeMap<Id, Artifact>,
365365
) -> Result<FinalizeOutcome<Id, Self::Protocol>, LocalError> {
@@ -371,7 +371,7 @@ impl<Id: PartyId> Round<Id> for Round2<Id> {
371371

372372
let typed_payloads = payloads
373373
.into_values()
374-
.map(|payload| payload.try_to_typed::<Round1Payload>())
374+
.map(|payload| payload.downcast::<Round1Payload>())
375375
.collect::<Result<Vec<_>, _>>()?;
376376
let sum = self.context.ids_to_positions[&self.context.id]
377377
+ typed_payloads.iter().map(|payload| payload.x).sum::<u8>();

examples/src/simple_malicious.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ use manul::{
55
combinators::misbehave::{Misbehaving, MisbehavingEntryPoint},
66
dev::{run_sync, BinaryFormat, TestSessionParams, TestSigner},
77
protocol::{
8-
Artifact, BoxedRound, Deserializer, DirectMessage, EntryPoint, LocalError, PartyId, ProtocolMessagePart,
9-
Serializer,
8+
Artifact, BoxedFormat, BoxedRound, DirectMessage, EntryPoint, LocalError, PartyId, ProtocolMessagePart,
109
},
1110
signature::Keypair,
1211
};
@@ -28,25 +27,24 @@ impl<Id: PartyId> Misbehaving<Id, Behavior> for MaliciousLogic {
2827
type EntryPoint = SimpleProtocolEntryPoint<Id>;
2928

3029
fn modify_direct_message(
31-
_rng: &mut impl CryptoRngCore,
30+
_rng: &mut dyn CryptoRngCore,
3231
round: &BoxedRound<Id, <Self::EntryPoint as EntryPoint<Id>>::Protocol>,
3332
behavior: &Behavior,
34-
serializer: &Serializer,
35-
_deserializer: &Deserializer,
33+
format: &BoxedFormat,
3634
_destination: &Id,
3735
direct_message: DirectMessage,
3836
artifact: Option<Artifact>,
3937
) -> Result<(DirectMessage, Option<Artifact>), LocalError> {
4038
let dm = if round.id() == 1 {
4139
match behavior {
42-
Behavior::SerializedGarbage => DirectMessage::new(serializer, [99u8])?,
40+
Behavior::SerializedGarbage => DirectMessage::new(format, [99u8])?,
4341
Behavior::AttributableFailure => {
4442
let round1 = round.downcast_ref::<Round1<Id>>()?;
4543
let message = Round1Message {
4644
my_position: round1.context.ids_to_positions[&round1.context.id],
4745
your_position: round1.context.ids_to_positions[&round1.context.id],
4846
};
49-
DirectMessage::new(serializer, message)?
47+
DirectMessage::new(format, message)?
5048
}
5149
_ => direct_message,
5250
}
@@ -58,7 +56,7 @@ impl<Id: PartyId> Misbehaving<Id, Behavior> for MaliciousLogic {
5856
my_position: round2.context.ids_to_positions[&round2.context.id],
5957
your_position: round2.context.ids_to_positions[&round2.context.id],
6058
};
61-
DirectMessage::new(serializer, message)?
59+
DirectMessage::new(format, message)?
6260
}
6361
_ => direct_message,
6462
}

manul/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ categories = ["cryptography", "no-std"]
1313
[dependencies]
1414
serde = { version = "1", default-features = false, features = ["alloc", "serde_derive"] }
1515
erased-serde = { version = "0.4", default-features = false, features = ["alloc"] }
16-
serde-encoded-bytes = { version = "0.1", default-features = false, features = ["hex", "base64"] }
16+
serde-encoded-bytes = { version = "0.2", default-features = false, features = ["hex", "base64"] }
1717
digest = { version = "0.10", default-features = false }
1818
signature = { version = "2", default-features = false, features = ["digest", "rand_core"] }
1919
rand_core = { version = "0.6.4", default-features = false }

0 commit comments

Comments
 (0)