diff --git a/CHANGELOG.md b/CHANGELOG.md index ebeb76f..1be1f1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `MessageBundle` is not generic anymore. ([#36]) - `ProcessedArtifact` is now also generic on `SessionParameters`. ([#37]) - 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]) ### Added @@ -22,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#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 ## [0.0.1] - 2024-10-12 diff --git a/examples/src/simple.rs b/examples/src/simple.rs index 9bb9db1..47a1162 100644 --- a/examples/src/simple.rs +++ b/examples/src/simple.rs @@ -130,7 +130,7 @@ impl FirstRound for Round1< type Inputs = Inputs; fn new( _rng: &mut impl CryptoRngCore, - _session_id: &SessionId, + _shared_randomness: &[u8], id: Id, inputs: Self::Inputs, ) -> Result { diff --git a/examples/src/simple_malicious.rs b/examples/src/simple_malicious.rs index b7ea83f..ab070d3 100644 --- a/examples/src/simple_malicious.rs +++ b/examples/src/simple_malicious.rs @@ -2,9 +2,7 @@ use alloc::collections::{BTreeMap, BTreeSet}; use core::fmt::Debug; use manul::{ - protocol::{ - Artifact, DirectMessage, FinalizeError, FinalizeOutcome, FirstRound, LocalError, Payload, Round, SessionId, - }, + protocol::{Artifact, DirectMessage, FinalizeError, FinalizeOutcome, FirstRound, LocalError, Payload, Round}, session::signature::Keypair, testing::{round_override, run_sync, RoundOverride, RoundWrapper, TestSessionParams, TestSigner, TestVerifier}, }; @@ -46,11 +44,11 @@ impl FirstRound for Malicio type Inputs = MaliciousInputs; fn new( rng: &mut impl CryptoRngCore, - session_id: &SessionId, + shared_randomness: &[u8], id: Id, inputs: Self::Inputs, ) -> Result { - let round = Round1::new(rng, session_id, id, inputs.inputs)?; + let round = Round1::new(rng, shared_randomness, id, inputs.inputs)?; Ok(Self { round, behavior: inputs.behavior, diff --git a/examples/tests/async_runner.rs b/examples/tests/async_runner.rs index 6ec71f7..7e52af0 100644 --- a/examples/tests/async_runner.rs +++ b/examples/tests/async_runner.rs @@ -249,7 +249,7 @@ async fn async_run() { .iter() .map(|signer| signer.verifying_key()) .collect::>(); - let session_id = SessionId::random(&mut OsRng); + let session_id = SessionId::random::(&mut OsRng); // Create 4 `Session`s let sessions = signers diff --git a/manul/benches/empty_rounds.rs b/manul/benches/empty_rounds.rs index 2019380..2b58cf3 100644 --- a/manul/benches/empty_rounds.rs +++ b/manul/benches/empty_rounds.rs @@ -9,7 +9,7 @@ use manul::{ Artifact, DeserializationError, DirectMessage, EchoBroadcast, FinalizeError, FinalizeOutcome, FirstRound, LocalError, Payload, Protocol, ProtocolError, ProtocolValidationError, ReceiveError, Round, RoundId, }, - session::{signature::Keypair, SessionId, SessionOutcome}, + session::{signature::Keypair, SessionOutcome}, testing::{run_sync, TestSessionParams, TestSigner, TestVerifier}, }; use rand_core::{CryptoRngCore, OsRng}; @@ -78,7 +78,7 @@ impl FirstRound for EmptyRo type Inputs = Inputs; fn new( _rng: &mut impl CryptoRngCore, - _session_id: &SessionId, + _shared_randomness: &[u8], _id: Id, inputs: Self::Inputs, ) -> Result { diff --git a/manul/src/protocol.rs b/manul/src/protocol.rs index 9133cc7..942b4b3 100644 --- a/manul/src/protocol.rs +++ b/manul/src/protocol.rs @@ -15,7 +15,6 @@ mod errors; mod object_safe; mod round; -pub use crate::session::SessionId; pub use errors::{ DeserializationError, DirectMessageError, EchoBroadcastError, FinalizeError, LocalError, MessageValidationError, ProtocolValidationError, ReceiveError, RemoteError, diff --git a/manul/src/protocol/round.rs b/manul/src/protocol/round.rs index 71e4724..b22aa6b 100644 --- a/manul/src/protocol/round.rs +++ b/manul/src/protocol/round.rs @@ -17,7 +17,6 @@ use super::{ }, object_safe::{ObjectSafeRound, ObjectSafeRoundWrapper}, }; -use crate::session::SessionId; /// Possible successful outcomes of [`Round::finalize`]. #[derive(Debug)] @@ -347,7 +346,7 @@ pub trait FirstRound: Round + Sized { /// `id` is the ID of this node. fn new( rng: &mut impl CryptoRngCore, - session_id: &SessionId, + shared_randomness: &[u8], id: Id, inputs: Self::Inputs, ) -> Result; diff --git a/manul/src/session/session.rs b/manul/src/session/session.rs index 395aa65..8552fbc 100644 --- a/manul/src/session/session.rs +++ b/manul/src/session/session.rs @@ -9,7 +9,7 @@ use core::fmt::Debug; use digest::Digest; use rand_core::CryptoRngCore; use serde::{Deserialize, Serialize}; -use serde_encoded_bytes::{Base64, SliceLike}; +use serde_encoded_bytes::{Hex, SliceLike}; use signature::{DigestVerifier, Keypair, RandomizedDigestSigner}; use tracing::{debug, trace}; @@ -52,7 +52,7 @@ pub trait SessionParameters { /// A session identifier shared between the parties. #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord, Hash)] -pub struct SessionId(#[serde(with = "SliceLike::")] Box<[u8]>); +pub struct SessionId(#[serde(with = "SliceLike::")] Box<[u8]>); /// A session ID. /// @@ -61,15 +61,34 @@ pub struct SessionId(#[serde(with = "SliceLike::")] Box<[u8]>); /// Must be created uniquely for each session execution, otherwise there is a danger of replay attacks. impl SessionId { /// Creates a random session identifier. - pub fn random(rng: &mut impl CryptoRngCore) -> Self { - let mut buffer = [0u8; 256]; + /// + /// **Warning:** this should generally be used for testing; creating a random session ID in a centralized way + /// usually defeats the purpose of having a distributed protocol. + #[cfg(any(test, feature = "testing"))] + pub fn random(rng: &mut impl CryptoRngCore) -> Self { + let mut buffer = digest::Output::::default(); rng.fill_bytes(&mut buffer); - Self(buffer.into()) + Self(buffer.as_ref().into()) } - /// Creates a session identifier from the given bytestring. - pub fn new(bytes: &[u8]) -> Self { - Self(bytes.into()) + /// Creates a session identifier deterministically from the given bytestring. + /// + /// Every node executing a session must be given the same session ID. + /// + /// **Warning:** make sure the bytestring you provide will not be reused within your application, + /// and cannot be predicted in advance. + /// Session ID collisions will affect error attribution and evidence verification. + /// + /// In a blockchain setting, it may be some combination of the current block hash with the public parameters + /// (identities of the parties, hash of the inputs). + pub fn from_seed(bytes: &[u8]) -> Self { + Self( + SP::Digest::new_with_prefix(b"SessionId") + .chain_update(bytes) + .finalize() + .as_ref() + .into(), + ) } } @@ -125,7 +144,7 @@ where let verifier = signer.verifying_key(); let first_round = Box::new(ObjectSafeRoundWrapper::new(R::new( rng, - &session_id, + session_id.as_ref(), verifier.clone(), inputs, )?)); diff --git a/manul/src/testing/run_sync.rs b/manul/src/testing/run_sync.rs index 19d6670..c338f8c 100644 --- a/manul/src/testing/run_sync.rs +++ b/manul/src/testing/run_sync.rs @@ -99,7 +99,7 @@ where R: 'static + FirstRound, SP: 'static + SessionParameters + Debug, { - let session_id = SessionId::random(rng); + let session_id = SessionId::random::(rng); let mut messages = Vec::new(); let mut states = BTreeMap::new();