diff --git a/Cargo.lock b/Cargo.lock index 5388c439ce..b810ebd1a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1299,6 +1299,7 @@ dependencies = [ "commonware-cryptography", "commonware-macros", "commonware-p2p", + "commonware-parallel", "commonware-runtime", "commonware-storage", "commonware-utils", diff --git a/consensus/fuzz/fuzz_targets/simplex_bls12381_threshold_minpk.rs b/consensus/fuzz/fuzz_targets/simplex_bls12381_threshold_minpk.rs index 0e09ab98ba..f723b843b2 100644 --- a/consensus/fuzz/fuzz_targets/simplex_bls12381_threshold_minpk.rs +++ b/consensus/fuzz/fuzz_targets/simplex_bls12381_threshold_minpk.rs @@ -6,14 +6,13 @@ use commonware_cryptography::{ bls12381::primitives::variant::MinPk, certificate::mocks::Fixture, ed25519::PublicKey as Ed25519PublicKey, }; -use commonware_parallel::Sequential; use commonware_runtime::deterministic; use libfuzzer_sys::fuzz_target; struct SimplexBls12381MinPk; impl Simplex for SimplexBls12381MinPk { - type Scheme = bls12381_threshold::Scheme; + type Scheme = bls12381_threshold::Scheme; type Elector = Random; fn fixture( diff --git a/consensus/fuzz/fuzz_targets/simplex_bls12381_threshold_minsig.rs b/consensus/fuzz/fuzz_targets/simplex_bls12381_threshold_minsig.rs index 7b19f93cf7..81f066ee40 100644 --- a/consensus/fuzz/fuzz_targets/simplex_bls12381_threshold_minsig.rs +++ b/consensus/fuzz/fuzz_targets/simplex_bls12381_threshold_minsig.rs @@ -6,14 +6,13 @@ use commonware_cryptography::{ bls12381::primitives::variant::MinSig, certificate::mocks::Fixture, ed25519::PublicKey as Ed25519PublicKey, }; -use commonware_parallel::Sequential; use commonware_runtime::deterministic; use libfuzzer_sys::fuzz_target; struct SimplexBls12381MinSig; impl Simplex for SimplexBls12381MinSig { - type Scheme = bls12381_threshold::Scheme; + type Scheme = bls12381_threshold::Scheme; type Elector = Random; fn fixture( diff --git a/consensus/fuzz/fuzz_targets/simplex_elector.rs b/consensus/fuzz/fuzz_targets/simplex_elector.rs index f14ace31bb..f021866326 100644 --- a/consensus/fuzz/fuzz_targets/simplex_elector.rs +++ b/consensus/fuzz/fuzz_targets/simplex_elector.rs @@ -15,7 +15,6 @@ use commonware_cryptography::{ Sha256, Signer, }; use commonware_math::algebra::Random as _; -use commonware_parallel::Sequential; use commonware_utils::{ordered::Set, TryCollect}; use libfuzzer_sys::fuzz_target; use rand::{rngs::StdRng, SeedableRng}; @@ -77,18 +76,10 @@ fuzz_target!(|input: FuzzInput| { fuzz::(&input, RoundRobin::::shuffled(seed), None); } FuzzElector::RandomMinPk(certificate) => { - fuzz::, _>( - &input, - Random, - Some(certificate), - ); + fuzz::, _>(&input, Random, Some(certificate)); } FuzzElector::RandomMinSig(certificate) => { - fuzz::, _>( - &input, - Random, - Some(certificate), - ); + fuzz::, _>(&input, Random, Some(certificate)); } } }); diff --git a/consensus/fuzz/fuzz_targets/simplex_messages.rs b/consensus/fuzz/fuzz_targets/simplex_messages.rs index 2b362b1435..327bd6c9cd 100644 --- a/consensus/fuzz/fuzz_targets/simplex_messages.rs +++ b/consensus/fuzz/fuzz_targets/simplex_messages.rs @@ -15,14 +15,13 @@ use commonware_cryptography::{ ed25519::PublicKey, sha256, }; -use commonware_parallel::Sequential; use libfuzzer_sys::fuzz_target; type Ed25519Scheme = ed25519::Scheme; type Bls12381MultisigMinPk = bls12381_multisig::Scheme; type Bls12381MultisigMinSig = bls12381_multisig::Scheme; -type ThresholdSchemeMinPk = bls12381_threshold::Scheme; -type ThresholdSchemeMinSig = bls12381_threshold::Scheme; +type ThresholdSchemeMinPk = bls12381_threshold::Scheme; +type ThresholdSchemeMinSig = bls12381_threshold::Scheme; #[derive(Arbitrary, Debug)] enum FuzzInput { diff --git a/consensus/fuzz/src/lib.rs b/consensus/fuzz/src/lib.rs index 409203cc80..e92b30be02 100644 --- a/consensus/fuzz/src/lib.rs +++ b/consensus/fuzz/src/lib.rs @@ -27,6 +27,7 @@ use commonware_cryptography::{ Sha256, }; use commonware_p2p::simulated::{Config as NetworkConfig, Link, Network}; +use commonware_parallel::Sequential; use commonware_runtime::{buffer::PoolRef, deterministic, Clock, Metrics, Runner, Spawner}; use commonware_utils::{max_faults, NZUsize, NZU16}; use futures::{channel::mpsc::Receiver, future::join_all, StreamExt}; @@ -262,6 +263,7 @@ fn run(input: FuzzInput) { replay_buffer: NZUsize!(1024 * 1024), write_buffer: NZUsize!(1024 * 1024), buffer_pool: PoolRef::new(PAGE_SIZE, PAGE_CACHE_SIZE), + strategy: Sequential, }; let engine = Engine::new(context.with_label("engine"), engine_cfg); engine.start(pending, recovered, resolver); diff --git a/consensus/src/aggregation/config.rs b/consensus/src/aggregation/config.rs index ecd4ab19f8..792113877a 100644 --- a/consensus/src/aggregation/config.rs +++ b/consensus/src/aggregation/config.rs @@ -8,6 +8,7 @@ use commonware_cryptography::{ Digest, }; use commonware_p2p::Blocker; +use commonware_parallel::Strategy; use commonware_runtime::buffer::PoolRef; use commonware_utils::NonZeroDuration; use std::num::{NonZeroU64, NonZeroUsize}; @@ -20,6 +21,7 @@ pub struct Config< Z: Reporter>, M: Monitor, B: Blocker::PublicKey>, + T: Strategy, > { /// Tracks the current state of consensus (to determine which participants should /// be involved in the current broadcast attempt). @@ -77,4 +79,7 @@ pub struct Config< /// Buffer pool for the journal. pub journal_buffer_pool: PoolRef, + + /// Strategy for parallel operations. + pub strategy: T, } diff --git a/consensus/src/aggregation/engine.rs b/consensus/src/aggregation/engine.rs index 000769ac26..7bd05418a2 100644 --- a/consensus/src/aggregation/engine.rs +++ b/consensus/src/aggregation/engine.rs @@ -20,6 +20,7 @@ use commonware_p2p::{ utils::codec::{wrap, WrappedSender}, Blocker, Receiver, Recipients, Sender, }; +use commonware_parallel::Strategy; use commonware_runtime::{ buffer::PoolRef, spawn_cell, @@ -77,6 +78,7 @@ pub struct Engine< Z: Reporter>, M: Monitor, B: Blocker::PublicKey>, + T: Strategy, > { // ---------- Interfaces ---------- context: ContextCell, @@ -85,6 +87,7 @@ pub struct Engine< provider: P, reporter: Z, blocker: B, + strategy: T, // Pruning /// A tuple representing the epochs to keep in memory. @@ -158,10 +161,11 @@ impl< Z: Reporter>, M: Monitor, B: Blocker::PublicKey>, - > Engine + T: Strategy, + > Engine { /// Creates a new engine with the given context and configuration. - pub fn new(context: E, cfg: Config) -> Self { + pub fn new(context: E, cfg: Config) -> Self { // TODO(#1833): Metrics should use the post-start context let metrics = metrics::Metrics::init(context.clone()); @@ -172,6 +176,7 @@ impl< monitor: cfg.monitor, provider: cfg.provider, blocker: cfg.blocker, + strategy: cfg.strategy, epoch_bounds: cfg.epoch_bounds, window: HeightDelta::new(cfg.window.into()), activity_timeout: cfg.activity_timeout, @@ -519,7 +524,7 @@ impl< .filter(|a| a.item.digest == ack.item.digest) .collect::>(); if filtered.len() >= quorum as usize { - if let Some(certificate) = Certificate::from_acks(&*scheme, filtered) { + if let Some(certificate) = Certificate::from_acks(&*scheme, filtered, &self.strategy) { self.metrics.certificates.inc(); self.handle_certificate(certificate).await; } @@ -666,7 +671,7 @@ impl< } // Validate signature - if !ack.verify(&mut self.context, &*scheme) { + if !ack.verify(&mut self.context, &*scheme, &self.strategy) { return Err(Error::InvalidAckSignature); } diff --git a/consensus/src/aggregation/mocks/reporter.rs b/consensus/src/aggregation/mocks/reporter.rs index 0353371f48..f5d47c26a6 100644 --- a/consensus/src/aggregation/mocks/reporter.rs +++ b/consensus/src/aggregation/mocks/reporter.rs @@ -7,6 +7,7 @@ use crate::{ }; use commonware_codec::{Decode, DecodeExt, Encode}; use commonware_cryptography::{certificate::Scheme, Digest}; +use commonware_parallel::Sequential; use futures::{ channel::{mpsc, oneshot}, SinkExt, StreamExt, @@ -77,7 +78,7 @@ where match msg { Message::Ack(ack) => { // Verify properly constructed (not needed in production) - assert!(ack.verify(&mut self.rng, &self.scheme)); + assert!(ack.verify(&mut self.rng, &self.scheme, &Sequential)); // Test encoding/decoding let encoded = ack.encode(); @@ -91,7 +92,7 @@ where } Message::Certified(certificate) => { // Verify certificate - assert!(certificate.verify(&mut self.rng, &self.scheme)); + assert!(certificate.verify(&mut self.rng, &self.scheme, &Sequential)); // Test encoding/decoding let encoded = certificate.encode(); diff --git a/consensus/src/aggregation/mod.rs b/consensus/src/aggregation/mod.rs index 9c75b4a8eb..9931bde05b 100644 --- a/consensus/src/aggregation/mod.rs +++ b/consensus/src/aggregation/mod.rs @@ -98,6 +98,7 @@ mod tests { }; use commonware_macros::{select, test_group, test_traced}; use commonware_p2p::simulated::{Link, Network, Oracle, Receiver, Sender}; + use commonware_parallel::Sequential; use commonware_runtime::{ buffer::PoolRef, deterministic::{self, Context}, @@ -249,6 +250,7 @@ mod tests { journal_heights_per_section: std::num::NonZeroU64::new(6).unwrap(), journal_compression: Some(3), journal_buffer_pool: PoolRef::new(PAGE_SIZE, PAGE_CACHE_SIZE), + strategy: Sequential, }, ); @@ -492,6 +494,7 @@ mod tests { journal_heights_per_section: std::num::NonZeroU64::new(6).unwrap(), journal_compression: Some(3), journal_buffer_pool: PoolRef::new(PAGE_SIZE, PAGE_CACHE_SIZE), + strategy: Sequential, }, ); @@ -640,6 +643,7 @@ mod tests { journal_heights_per_section: std::num::NonZeroU64::new(6).unwrap(), journal_compression: Some(3), journal_buffer_pool: PoolRef::new(PAGE_SIZE, PAGE_CACHE_SIZE), + strategy: Sequential, }, ); @@ -722,6 +726,7 @@ mod tests { journal_heights_per_section: std::num::NonZeroU64::new(6).unwrap(), journal_compression: Some(3), journal_buffer_pool: PoolRef::new(PAGE_SIZE, PAGE_CACHE_SIZE), + strategy: Sequential, }, ); @@ -1062,6 +1067,7 @@ mod tests { journal_heights_per_section: std::num::NonZeroU64::new(6).unwrap(), journal_compression: Some(3), journal_buffer_pool: PoolRef::new(PAGE_SIZE, PAGE_CACHE_SIZE), + strategy: Sequential, }, ); diff --git a/consensus/src/aggregation/types.rs b/consensus/src/aggregation/types.rs index 3fd5bb7931..b642431a9a 100644 --- a/consensus/src/aggregation/types.rs +++ b/consensus/src/aggregation/types.rs @@ -11,6 +11,7 @@ use commonware_cryptography::{ certificate::{self, Attestation, Scheme, Subject}, Digest, }; +use commonware_parallel::Strategy; use commonware_utils::union; use futures::channel::oneshot; use rand_core::CryptoRngCore; @@ -181,12 +182,12 @@ impl Ack { /// /// Returns `true` if the attestation is valid for the given namespace and public key. /// Domain separation is automatically applied to prevent signature reuse. - pub fn verify(&self, rng: &mut R, scheme: &S) -> bool + pub fn verify(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool where R: CryptoRngCore, S: scheme::Scheme, { - scheme.verify_attestation::<_, D>(rng, &self.item, &self.attestation) + scheme.verify_attestation::<_, D>(rng, &self.item, &self.attestation, strategy) } /// Creates a new acknowledgment by signing an item with a validator's key. @@ -313,7 +314,11 @@ pub struct Certificate { } impl Certificate { - pub fn from_acks<'a>(scheme: &S, acks: impl IntoIterator>) -> Option + pub fn from_acks<'a>( + scheme: &S, + acks: impl IntoIterator>, + strategy: &impl Strategy, + ) -> Option where S: scheme::Scheme, { @@ -322,18 +327,18 @@ impl Certificate { let attestations = iter .filter(|ack| ack.item == item) .map(|ack| ack.attestation.clone()); - let certificate = scheme.assemble(attestations)?; + let certificate = scheme.assemble(attestations, strategy)?; Some(Self { item, certificate }) } /// Verifies the recovered certificate for the item. - pub fn verify(&self, rng: &mut R, scheme: &S) -> bool + pub fn verify(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool where R: CryptoRngCore, S: scheme::Scheme, { - scheme.verify_certificate::<_, D>(rng, &self.item, &self.certificate) + scheme.verify_certificate::<_, D>(rng, &self.item, &self.certificate, strategy) } } @@ -464,6 +469,7 @@ mod tests { certificate::mocks::Fixture, Hasher, Sha256, }; + use commonware_parallel::Sequential; use commonware_utils::{ordered::Quorum, test_rng}; use rand::rngs::StdRng; @@ -504,7 +510,7 @@ mod tests { // Verify the restored ack assert_eq!(restored_ack.item, item); assert_eq!(restored_ack.epoch, Epoch::new(1)); - assert!(restored_ack.verify(&mut rng, &schemes[0])); + assert!(restored_ack.verify(&mut rng, &schemes[0], &Sequential)); // Test TipAck codec let tip_ack = TipAck { @@ -537,8 +543,8 @@ mod tests { .filter_map(|scheme| Ack::sign(scheme, Epoch::new(1), item.clone())) .collect(); - let certificate = Certificate::from_acks(&schemes[0], &acks).unwrap(); - assert!(certificate.verify(&mut rng, &schemes[0])); + let certificate = Certificate::from_acks(&schemes[0], &acks, &Sequential).unwrap(); + assert!(certificate.verify(&mut rng, &schemes[0], &Sequential)); let activity_certified = Activity::Certified(certificate.clone()); let encoded_certified = activity_certified.encode(); @@ -546,7 +552,7 @@ mod tests { Activity::decode_cfg(encoded_certified, &cfg).unwrap(); if let Activity::Certified(restored) = restored_activity_certified { assert_eq!(restored.item, item); - assert!(restored.verify(&mut rng, &schemes[0])); + assert!(restored.verify(&mut rng, &schemes[0], &Sequential)); } else { panic!("Expected Activity::Certified"); } diff --git a/consensus/src/marshal/actor.rs b/consensus/src/marshal/actor.rs index 48f5aa1314..4bf3097f5d 100644 --- a/consensus/src/marshal/actor.rs +++ b/consensus/src/marshal/actor.rs @@ -27,6 +27,7 @@ use commonware_cryptography::{ }; use commonware_macros::select; use commonware_p2p::Recipients; +use commonware_parallel::Strategy; use commonware_resolver::Resolver; use commonware_runtime::{ spawn_cell, telemetry::metrics::status::GaugeExt, Clock, ContextCell, Handle, Metrics, Spawner, @@ -101,7 +102,7 @@ struct BlockSubscription { /// finalization for a block that is ahead of its current view, it will request the missing blocks /// from its peers. This ensures that the actor can catch up to the rest of the network if it falls /// behind. -pub struct Actor +pub struct Actor where E: CryptoRngCore + Spawner + Metrics + Clock + Storage, B: Block, @@ -109,6 +110,7 @@ where FC: Certificates, FB: Blocks, ES: Epocher, + T: Strategy, A: Acknowledgement, { // ---------- Context ---------- @@ -129,6 +131,8 @@ where max_repair: NonZeroUsize, // Codec configuration for block type block_codec_config: B::Cfg, + // Strategy for parallel operations + strategy: T, // ---------- State ---------- // Last view processed @@ -159,7 +163,7 @@ where processed_height: Gauge, } -impl Actor +impl Actor where E: CryptoRngCore + Spawner + Metrics + Clock + Storage, B: Block, @@ -167,6 +171,7 @@ where FC: Certificates, FB: Blocks, ES: Epocher, + T: Strategy, A: Acknowledgement, { /// Create a new application actor. @@ -174,7 +179,7 @@ where context: E, finalizations_by_height: FC, finalized_blocks: FB, - config: Config, + config: Config, ) -> (Self, Mailbox, Height) { // Initialize cache let prunable_config = cache::Config { @@ -233,6 +238,7 @@ where view_retention_timeout: config.view_retention_timeout, max_repair: config.max_repair, block_codec_config: config.block_codec_config, + strategy: config.strategy, last_processed_round: Round::zero(), last_processed_height, pending_ack: None.into(), @@ -645,7 +651,7 @@ where // Validation if block.height() != height || finalization.proposal.payload != block.commitment() - || !finalization.verify(&mut self.context, &scheme) + || !finalization.verify(&mut self.context, &scheme, &self.strategy) { response.send_lossy(false); continue; @@ -685,7 +691,7 @@ where // Validation if notarization.round() != round || notarization.proposal.payload != block.commitment() - || !notarization.verify(&mut self.context, &scheme) + || !notarization.verify(&mut self.context, &scheme, &self.strategy) { response.send_lossy(false); continue; diff --git a/consensus/src/marshal/config.rs b/consensus/src/marshal/config.rs index 3449fd41ea..a8459fd453 100644 --- a/consensus/src/marshal/config.rs +++ b/consensus/src/marshal/config.rs @@ -3,15 +3,17 @@ use crate::{ Block, }; use commonware_cryptography::certificate::Provider; +use commonware_parallel::Strategy; use commonware_runtime::buffer::PoolRef; use std::num::{NonZeroU64, NonZeroUsize}; /// Marshal configuration. -pub struct Config +pub struct Config where B: Block, P: Provider, ES: Epocher, + T: Strategy, { /// Provider for epoch-specific signing schemes. pub provider: P, @@ -50,4 +52,7 @@ where /// Maximum number of blocks to repair at once. pub max_repair: NonZeroUsize, + + /// Strategy for parallel operations. + pub strategy: T, } diff --git a/consensus/src/marshal/mod.rs b/consensus/src/marshal/mod.rs index 938ff9aadf..7474d57ff9 100644 --- a/consensus/src/marshal/mod.rs +++ b/consensus/src/marshal/mod.rs @@ -148,7 +148,7 @@ mod tests { type B = Block; type K = PublicKey; type V = MinPk; - type S = bls12381_threshold::Scheme; + type S = bls12381_threshold::Scheme; type P = ConstantProvider; const PAGE_SIZE: NonZeroU16 = NZU16!(1024); @@ -193,6 +193,7 @@ mod tests { key_write_buffer: NZUsize!(1024), value_write_buffer: NZUsize!(1024), buffer_pool: PoolRef::new(PAGE_SIZE, PAGE_CACHE_SIZE), + strategy: Sequential, }; // Create the resolver @@ -330,7 +331,7 @@ mod tests { .collect(); // Generate certificate signatures - Finalization::from_finalizes(&schemes[0], &finalizes).unwrap() + Finalization::from_finalizes(&schemes[0], &finalizes, &Sequential).unwrap() } fn make_notarization(proposal: Proposal, schemes: &[S], quorum: u32) -> Notarization { @@ -342,7 +343,7 @@ mod tests { .collect(); // Generate certificate signatures - Notarization::from_notarizes(&schemes[0], ¬arizes).unwrap() + Notarization::from_notarizes(&schemes[0], ¬arizes, &Sequential).unwrap() } fn setup_network( diff --git a/consensus/src/ordered_broadcast/ack_manager.rs b/consensus/src/ordered_broadcast/ack_manager.rs index db4a405382..08a7a310a6 100644 --- a/consensus/src/ordered_broadcast/ack_manager.rs +++ b/consensus/src/ordered_broadcast/ack_manager.rs @@ -4,6 +4,7 @@ use commonware_cryptography::{ certificate::{Attestation, Scheme}, Digest, PublicKey, }; +use commonware_parallel::Strategy; use std::collections::{BTreeMap, HashMap, HashSet}; /// A struct representing a set of votes for a payload digest. @@ -60,7 +61,12 @@ impl AckManager { /// Adds a vote to the evidence. /// /// If-and-only-if the quorum is newly-reached, the certificate is returned. - pub fn add_ack(&mut self, ack: &Ack, scheme: &S) -> Option { + pub fn add_ack( + &mut self, + ack: &Ack, + scheme: &S, + strategy: &impl Strategy, + ) -> Option { let evidence = self .acks .entry(ack.chunk.sequencer.clone()) @@ -83,7 +89,7 @@ impl AckManager { attestations.push(ack.attestation.clone()); // Try to assemble certificate - let certificate = scheme.assemble(attestations.iter().cloned())?; + let certificate = scheme.assemble(attestations.iter().cloned(), strategy)?; // Take ownership of the votes, which must exist p.attestations.remove(&ack.chunk.payload); @@ -164,6 +170,7 @@ mod tests { ed25519::PublicKey, Hasher, Sha256, }; + use commonware_parallel::Sequential; use commonware_utils::test_rng; use helpers::Sha256Digest; use rand::{rngs::StdRng, SeedableRng as _}; @@ -232,7 +239,7 @@ mod tests { let acks = create_acks_for_indices(schemes, chunk, epoch, indices); let mut certificate = None; for ack in acks { - if let Some(cert) = manager.add_ack(&ack, &schemes[0]) { + if let Some(cert) = manager.add_ack(&ack, &schemes[0], &Sequential) { certificate = Some(cert); } } @@ -504,8 +511,12 @@ mod tests { let chunk = Chunk::new(sequencer, height, Sha256::hash(b"payload")); let ack = helpers::create_ack(&fixture.schemes[0], chunk, epoch); - assert!(acks.add_ack(&ack, &fixture.schemes[0]).is_none()); - assert!(acks.add_ack(&ack, &fixture.schemes[0]).is_none()); + assert!(acks + .add_ack(&ack, &fixture.schemes[0], &Sequential) + .is_none()); + assert!(acks + .add_ack(&ack, &fixture.schemes[0], &Sequential) + .is_none()); } #[test] @@ -536,14 +547,16 @@ mod tests { helpers::create_acks_for_indices(&fixture.schemes, chunk.clone(), epoch, &[0, 1, 2]); let mut produced = None; for ack in acks_vec { - if let Some(cert) = acks.add_ack(&ack, &fixture.schemes[0]) { + if let Some(cert) = acks.add_ack(&ack, &fixture.schemes[0], &Sequential) { produced = Some(cert); } } assert!(produced.is_some()); let ack = helpers::create_ack(&fixture.schemes[3], chunk, epoch); - assert!(acks.add_ack(&ack, &fixture.schemes[0]).is_none()); + assert!(acks + .add_ack(&ack, &fixture.schemes[0], &Sequential) + .is_none()); } #[test] @@ -612,7 +625,9 @@ mod tests { let acks_vec = helpers::create_acks_for_indices(&fixture.schemes, chunk, epoch, &[0, 1]); for ack in acks_vec { - assert!(acks.add_ack(&ack, &fixture.schemes[0]).is_none()); + assert!(acks + .add_ack(&ack, &fixture.schemes[0], &Sequential) + .is_none()); } assert_eq!(acks.get_certificate(&sequencer, height), None); } @@ -656,14 +671,14 @@ mod tests { for i in 0..14 { // Add payload1 ack let ack1 = helpers::create_ack(&fixture.schemes[i], chunk1.clone(), epoch); - if let Some(cert) = acks.add_ack(&ack1, &fixture.schemes[0]) { + if let Some(cert) = acks.add_ack(&ack1, &fixture.schemes[0], &Sequential) { certificates.push((chunk1.payload, cert)); } // Add payload2 ack (from validators 6-19) if i + 6 < 20 { let ack2 = helpers::create_ack(&fixture.schemes[i + 6], chunk2.clone(), epoch); - if let Some(cert) = acks.add_ack(&ack2, &fixture.schemes[0]) { + if let Some(cert) = acks.add_ack(&ack2, &fixture.schemes[0], &Sequential) { certificates.push((chunk2.payload, cert)); } } diff --git a/consensus/src/ordered_broadcast/config.rs b/consensus/src/ordered_broadcast/config.rs index d95df411f8..98fe20ba2e 100644 --- a/consensus/src/ordered_broadcast/config.rs +++ b/consensus/src/ordered_broadcast/config.rs @@ -4,6 +4,7 @@ use crate::{ Automaton, Monitor, Relay, Reporter, }; use commonware_cryptography::{certificate::Provider, Digest, Signer}; +use commonware_parallel::Strategy; use commonware_runtime::buffer::PoolRef; use std::{ num::{NonZeroU64, NonZeroUsize}, @@ -20,6 +21,7 @@ pub struct Config< R: Relay, Z: Reporter>, M: Monitor, + T: Strategy, > { /// The signer used when this engine acts as a sequencer. /// @@ -94,4 +96,7 @@ pub struct Config< /// Buffer pool for the journal. pub journal_buffer_pool: PoolRef, + + /// Strategy for parallel operations. + pub strategy: T, } diff --git a/consensus/src/ordered_broadcast/engine.rs b/consensus/src/ordered_broadcast/engine.rs index 86da34c935..a8429aa875 100644 --- a/consensus/src/ordered_broadcast/engine.rs +++ b/consensus/src/ordered_broadcast/engine.rs @@ -29,6 +29,7 @@ use commonware_p2p::{ utils::codec::{wrap, WrappedSender}, Receiver, Recipients, Sender, }; +use commonware_parallel::Strategy; use commonware_runtime::{ buffer::PoolRef, spawn_cell, @@ -72,6 +73,7 @@ pub struct Engine< R: Relay, Z: Reporter>, M: Monitor, + T: Strategy, > { //////////////////////////////////////// // Interfaces @@ -84,6 +86,7 @@ pub struct Engine< relay: R, monitor: M, reporter: Z, + strategy: T, //////////////////////////////////////// // Namespace Constants @@ -208,10 +211,11 @@ impl< R: Relay, Z: Reporter>, M: Monitor, - > Engine + T: Strategy, + > Engine { /// Creates a new engine with the given context and configuration. - pub fn new(context: E, cfg: Config) -> Self { + pub fn new(context: E, cfg: Config) -> Self { // TODO(#1833): Metrics should use the post-start context let metrics = metrics::Metrics::init(context.clone()); @@ -224,6 +228,7 @@ impl< relay: cfg.relay, reporter: cfg.reporter, monitor: cfg.monitor, + strategy: cfg.strategy, chunk_verifier: cfg.chunk_verifier, rebroadcast_timeout: cfg.rebroadcast_timeout, rebroadcast_deadline: None, @@ -610,7 +615,10 @@ impl< }; // Add the vote. If a new certificate is formed, handle it. - if let Some(certificate) = self.ack_manager.add_ack(ack, scheme.as_ref()) { + if let Some(certificate) = self + .ack_manager + .add_ack(ack, scheme.as_ref(), &self.strategy) + { debug!(epoch = %ack.epoch, sequencer = ?ack.chunk.sequencer, height = %ack.chunk.height, "recovered certificate"); self.metrics.certificates.inc(); self.handle_certificate(&ack.chunk, ack.epoch, certificate) @@ -885,6 +893,7 @@ impl< &mut self.context, &self.chunk_verifier, &self.validators_provider, + &self.strategy, ) } @@ -942,7 +951,7 @@ impl< } // Validate the vote signature - if !ack.verify(&mut self.context, scheme.as_ref()) { + if !ack.verify(&mut self.context, scheme.as_ref(), &self.strategy) { return Err(Error::InvalidAckSignature); } diff --git a/consensus/src/ordered_broadcast/mocks/reporter.rs b/consensus/src/ordered_broadcast/mocks/reporter.rs index 7b3cde7608..7504326246 100644 --- a/consensus/src/ordered_broadcast/mocks/reporter.rs +++ b/consensus/src/ordered_broadcast/mocks/reporter.rs @@ -7,6 +7,7 @@ use crate::{ }; use commonware_codec::{Decode, DecodeExt, Encode}; use commonware_cryptography::{certificate::Scheme, Digest, PublicKey}; +use commonware_parallel::Sequential; use futures::{ channel::{mpsc, oneshot}, SinkExt, StreamExt, @@ -101,7 +102,7 @@ where } Message::Locked(lock) => { // Verify properly constructed (not needed in production) - if !lock.verify(&mut self.rng, &self.scheme) { + if !lock.verify(&mut self.rng, &self.scheme, &Sequential) { panic!("Invalid proof"); } diff --git a/consensus/src/ordered_broadcast/mod.rs b/consensus/src/ordered_broadcast/mod.rs index 25381b7b56..fc7e7bf9ae 100644 --- a/consensus/src/ordered_broadcast/mod.rs +++ b/consensus/src/ordered_broadcast/mod.rs @@ -92,6 +92,7 @@ mod tests { }; use commonware_macros::{select, test_group, test_traced}; use commonware_p2p::simulated::{Link, Network, Oracle, Receiver, Sender}; + use commonware_parallel::Sequential; use commonware_runtime::{ buffer::PoolRef, deterministic::{self, Context}, @@ -259,6 +260,7 @@ mod tests { journal_name_prefix: format!("ordered-broadcast-seq-{validator}-"), journal_compression: Some(3), journal_buffer_pool: PoolRef::new(PAGE_SIZE, PAGE_CACHE_SIZE), + strategy: Sequential, }, ); @@ -784,6 +786,7 @@ mod tests { journal_name_prefix: format!("ordered-broadcast-seq-{validator}-"), journal_compression: Some(3), journal_buffer_pool: PoolRef::new(PAGE_SIZE, PAGE_CACHE_SIZE), + strategy: Sequential, }, ); @@ -941,6 +944,7 @@ mod tests { journal_name_prefix: format!("ordered-broadcast-seq-{validator}-"), journal_compression: Some(3), journal_buffer_pool: PoolRef::new(PAGE_SIZE, PAGE_CACHE_SIZE), + strategy: Sequential, }, ); @@ -994,6 +998,7 @@ mod tests { ), journal_compression: Some(3), journal_buffer_pool: PoolRef::new(PAGE_SIZE, PAGE_CACHE_SIZE), + strategy: Sequential, }, ); diff --git a/consensus/src/ordered_broadcast/types.rs b/consensus/src/ordered_broadcast/types.rs index 94d219c8cd..07a3d07bff 100644 --- a/consensus/src/ordered_broadcast/types.rs +++ b/consensus/src/ordered_broadcast/types.rs @@ -11,6 +11,7 @@ use commonware_cryptography::{ certificate::{self, Attestation, Namespace, Provider, Scheme}, Digest, PublicKey, Signer, }; +use commonware_parallel::Strategy; use commonware_utils::{ordered::Set, union}; use futures::channel::oneshot; use rand_core::CryptoRngCore; @@ -637,6 +638,7 @@ impl Node { rng: &mut R, verifier: &ChunkVerifier, provider: &impl Provider, + strategy: &impl Strategy, ) -> Result>, Error> where S: scheme::Scheme, @@ -662,7 +664,7 @@ impl Node { chunk: &parent_chunk, epoch: parent.epoch, }; - if !parent_scheme.verify_certificate::(rng, ctx, &parent.certificate) { + if !parent_scheme.verify_certificate::(rng, ctx, &parent.certificate, strategy) { return Err(Error::InvalidCertificate); } Ok(Some(parent_chunk)) @@ -792,7 +794,7 @@ impl Ack { /// using the provided scheme. /// /// Returns true if the attestation is valid, false otherwise. - pub fn verify(&self, rng: &mut R, scheme: &S) -> bool + pub fn verify(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool where R: CryptoRngCore, S: scheme::Scheme, @@ -801,7 +803,7 @@ impl Ack { chunk: &self.chunk, epoch: self.epoch, }; - scheme.verify_attestation::<_, D>(rng, ctx, &self.attestation) + scheme.verify_attestation::<_, D>(rng, ctx, &self.attestation, strategy) } /// Generate a new Ack by signing with the provided scheme. @@ -1064,7 +1066,7 @@ impl Lock { /// using the provided scheme. /// /// Returns true if the signature is valid, false otherwise. - pub fn verify(&self, rng: &mut R, scheme: &S) -> bool + pub fn verify(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool where R: CryptoRngCore, S: scheme::Scheme, @@ -1073,7 +1075,7 @@ impl Lock { chunk: &self.chunk, epoch: self.epoch, }; - scheme.verify_certificate::(rng, ctx, &self.certificate) + scheme.verify_certificate::(rng, ctx, &self.certificate, strategy) } } @@ -1140,6 +1142,7 @@ mod tests { sha256::Digest as Sha256Digest, Signer, }; + use commonware_parallel::Sequential; use commonware_utils::{quorum, test_rng}; use rand::{rngs::StdRng, SeedableRng}; use std::panic::catch_unwind; @@ -1209,7 +1212,7 @@ mod tests { // Assemble certificate let certificate = fixture.schemes[0] - .assemble(attestations) + .assemble(attestations, &Sequential) .expect("Should assemble certificate"); // Create and test parent @@ -1270,7 +1273,7 @@ mod tests { .collect(); let parent_certificate = fixture.schemes[0] - .assemble(parent_attestations) + .assemble(parent_attestations, &Sequential) .expect("Should assemble certificate"); // Create proper parent with valid certificate @@ -1352,7 +1355,7 @@ mod tests { .map(|scheme| scheme.sign::(parent_ctx.clone()).unwrap()) .collect(); let parent_certificate = fixture.schemes[0] - .assemble(parent_attestations) + .assemble(parent_attestations, &Sequential) .expect("Should assemble certificate"); let parent = @@ -1494,14 +1497,14 @@ mod tests { // Assemble certificate let certificate = fixture.schemes[0] - .assemble(attestations) + .assemble(attestations, &Sequential) .expect("Should assemble certificate"); // Create lock let lock = Lock::::new(chunk.clone(), epoch, certificate); // Verify lock - assert!(lock.verify(&mut rng, &fixture.verifier)); + assert!(lock.verify(&mut rng, &fixture.verifier, &Sequential)); // Test activity with the lock let activity = Activity::::Lock(lock.clone()); @@ -1513,7 +1516,7 @@ mod tests { Activity::Lock(l) => { assert_eq!(l.chunk, chunk); assert_eq!(l.epoch, epoch); - assert!(l.verify(&mut rng, &fixture.verifier)); + assert!(l.verify(&mut rng, &fixture.verifier, &Sequential)); } _ => panic!("Decoded activity has wrong type"), } @@ -1576,7 +1579,7 @@ mod tests { // Assemble certificate let certificate = fixture.schemes[0] - .assemble(attestations) + .assemble(attestations, &Sequential) .expect("Should assemble certificate"); // Create lock, encode and decode @@ -1590,7 +1593,7 @@ mod tests { assert_eq!(decoded.epoch, lock.epoch); // Verify the signature in the decoded lock - assert!(decoded.verify(&mut rng, &fixture.verifier)); + assert!(decoded.verify(&mut rng, &fixture.verifier, &Sequential)); } #[test] @@ -1620,7 +1623,7 @@ mod tests { let node: Node = Node::sign(&mut signer, Height::zero(), sample_digest(1), None); let provider = ConstantProvider::new(fixture.verifier.clone()); - let result = node.verify(&mut rng, &verifier, &provider); + let result = node.verify(&mut rng, &verifier, &provider, &Sequential); assert!(result.is_ok()); assert!(result.unwrap().is_none()); @@ -1638,7 +1641,7 @@ mod tests { .map(|scheme| scheme.sign::(parent_ctx.clone()).unwrap()) .collect(); let parent_certificate = fixture.schemes[0] - .assemble(parent_attestations) + .assemble(parent_attestations, &Sequential) .expect("Should assemble certificate"); let parent = Some(Parent::::new( @@ -1649,7 +1652,7 @@ mod tests { let node: Node = Node::sign(&mut signer, Height::new(1), sample_digest(2), parent); - let result = node.verify(&mut rng, &verifier, &provider); + let result = node.verify(&mut rng, &verifier, &provider, &Sequential); assert!(result.is_ok()); assert!(result.unwrap().is_some()); } @@ -1676,7 +1679,7 @@ mod tests { let epoch = Epoch::new(5); let ack = Ack::sign(&fixture.schemes[0], chunk, epoch).expect("Should sign ack"); - assert!(ack.verify(&mut rng, &fixture.verifier)); + assert!(ack.verify(&mut rng, &fixture.verifier, &Sequential)); } #[test] @@ -1713,14 +1716,14 @@ mod tests { // Assemble certificate let certificate = fixture.schemes[0] - .assemble(attestations) + .assemble(attestations, &Sequential) .expect("Should assemble certificate"); // Create lock with certificate let lock = Lock::::new(chunk, epoch, certificate); // Verify lock - assert!(lock.verify(&mut rng, &fixture.verifier)); + assert!(lock.verify(&mut rng, &fixture.verifier, &Sequential)); } #[test] @@ -1755,14 +1758,14 @@ mod tests { .map(|scheme| scheme.sign::(ctx.clone()).unwrap()) .collect(); let certificate = fixture.schemes[0] - .assemble(attestations) + .assemble(attestations, &Sequential) .expect("Should assemble certificate"); // Create lock let lock = Lock::::new(chunk, epoch, certificate); // Verify lock - assert!(lock.verify(&mut rng, &fixture.verifier)); + assert!(lock.verify(&mut rng, &fixture.verifier, &Sequential)); } #[test] @@ -1819,7 +1822,9 @@ mod tests { // Verification should succeed let provider = ConstantProvider::new(fixture.verifier); let verifier = chunk_verifier(); - assert!(node.verify(&mut rng, &verifier, &provider).is_ok()); + assert!(node + .verify(&mut rng, &verifier, &provider, &Sequential) + .is_ok()); // Now create a node with invalid signature let tampered_signature = scheme.sign(chunk_namespace.as_ref(), &node.encode()); @@ -1827,7 +1832,7 @@ mod tests { // Verification should fail assert!(matches!( - invalid_node.verify(&mut rng, &verifier, &provider), + invalid_node.verify(&mut rng, &verifier, &provider, &Sequential), Err(Error::InvalidSequencerSignature) )); } @@ -1868,7 +1873,7 @@ mod tests { .map(|scheme| scheme.sign::(parent_ctx.clone()).unwrap()) .collect(); let certificate = fixture.schemes[0] - .assemble(parent_attestations) + .assemble(parent_attestations, &Sequential) .expect("Should assemble certificate"); // Create parent with valid certificate @@ -1887,7 +1892,9 @@ mod tests { // Verification should succeed let provider = ConstantProvider::new(fixture.verifier.clone()); let verifier = chunk_verifier(); - assert!(node.verify(&mut rng, &verifier, &provider).is_ok()); + assert!(node + .verify(&mut rng, &verifier, &provider, &Sequential) + .is_ok()); // Now create a parent with invalid certificate // Generate certificate with the wrong keys (sign with schemes[1..] but pretend it's from schemes[0..]) @@ -1900,7 +1907,7 @@ mod tests { .map(|scheme| scheme.sign::(wrong_ctx.clone()).unwrap()) .collect(); let wrong_certificate = fixture.schemes[0] - .assemble(wrong_attestations) + .assemble(wrong_attestations, &Sequential) .expect("Should assemble certificate"); // Create parent with certificate signed for wrong context (wrong epoch) @@ -1916,7 +1923,7 @@ mod tests { // Verification should fail because the parent certificate was signed for different epoch assert!(matches!( - node.verify(&mut rng, &verifier, &provider), + node.verify(&mut rng, &verifier, &provider, &Sequential), Err(Error::InvalidCertificate) )); } @@ -1949,7 +1956,7 @@ mod tests { .expect("Should sign ack"); // Verification should succeed - assert!(ack.verify(&mut rng, &fixture.verifier)); + assert!(ack.verify(&mut rng, &fixture.verifier, &Sequential)); // Create an ack with tampered signature by signing with a different scheme let ctx = AckSubject { @@ -1965,7 +1972,7 @@ mod tests { let invalid_ack = Ack::::new(chunk, epoch, tampered_vote); // Verification should fail because the signer index doesn't match the signature - assert!(!invalid_ack.verify(&mut rng, &fixture.verifier)); + assert!(!invalid_ack.verify(&mut rng, &fixture.verifier, &Sequential)); } #[test] @@ -1996,10 +2003,10 @@ mod tests { .expect("Should sign ack"); // Verification should succeed with correct verifier - assert!(ack.verify(&mut rng, &fixture.verifier)); + assert!(ack.verify(&mut rng, &fixture.verifier, &Sequential)); // Verification should fail with wrong verifier - assert!(!ack.verify(&mut rng, &wrong_fixture.verifier)); + assert!(!ack.verify(&mut rng, &wrong_fixture.verifier, &Sequential)); } #[test] @@ -2035,14 +2042,14 @@ mod tests { .map(|scheme| scheme.sign::(ctx.clone()).unwrap()) .collect(); let certificate = fixture.schemes[0] - .assemble(attestations) + .assemble(attestations, &Sequential) .expect("Should assemble certificate"); // Create lock let lock = Lock::::new(chunk.clone(), epoch, certificate); // Verification should succeed - assert!(lock.verify(&mut rng, &fixture.verifier)); + assert!(lock.verify(&mut rng, &fixture.verifier, &Sequential)); // Generate certificate with the wrong keys let wrong_attestations: Vec<_> = wrong_fixture.schemes[..quorum_size] @@ -2050,17 +2057,17 @@ mod tests { .map(|scheme| scheme.sign::(ctx.clone()).unwrap()) .collect(); let wrong_certificate = wrong_fixture.schemes[0] - .assemble(wrong_attestations) + .assemble(wrong_attestations, &Sequential) .expect("Should assemble certificate"); // Create lock with wrong signature let wrong_lock = Lock::::new(chunk, epoch, wrong_certificate); // Verification should fail with the original public key - assert!(!wrong_lock.verify(&mut rng, &fixture.verifier)); + assert!(!wrong_lock.verify(&mut rng, &fixture.verifier, &Sequential)); // But succeed with the matching wrong verifier - assert!(wrong_lock.verify(&mut rng, &wrong_fixture.verifier)); + assert!(wrong_lock.verify(&mut rng, &wrong_fixture.verifier, &Sequential)); } #[test] @@ -2139,7 +2146,7 @@ mod tests { .map(|scheme| scheme.sign::(ctx.clone()).unwrap()) .collect(); let certificate = fixture.schemes[0] - .assemble(attestations) + .assemble(attestations, &Sequential) .expect("Should assemble certificate"); let parent = Parent::::new(sample_digest(0), Epoch::new(5), certificate); @@ -2224,7 +2231,7 @@ mod tests { .map(|scheme| scheme.sign::(parent_ctx.clone()).unwrap()) .collect(); let parent_certificate = fixture.schemes[0] - .assemble(parent_attestations) + .assemble(parent_attestations, &Sequential) .expect("Should assemble certificate"); let parent = diff --git a/consensus/src/simplex/actors/batcher/actor.rs b/consensus/src/simplex/actors/batcher/actor.rs index 0029a12e45..c45405bd7c 100644 --- a/consensus/src/simplex/actors/batcher/actor.rs +++ b/consensus/src/simplex/actors/batcher/actor.rs @@ -13,6 +13,7 @@ use crate::{ use commonware_cryptography::Digest; use commonware_macros::select; use commonware_p2p::{utils::codec::WrappedReceiver, Blocker, Receiver}; +use commonware_parallel::Strategy; use commonware_runtime::{ spawn_cell, telemetry::metrics::{ @@ -39,6 +40,7 @@ pub struct Actor< B: Blocker, D: Digest, R: Reporter>, + T: Strategy, > { context: ContextCell, @@ -47,6 +49,7 @@ pub struct Actor< blocker: B, reporter: R, + strategy: T, activity_timeout: ViewDelta, skip_timeout: ViewDelta, @@ -69,9 +72,10 @@ impl< B: Blocker, D: Digest, R: Reporter>, - > Actor + T: Strategy, + > Actor { - pub fn new(context: E, cfg: Config) -> (Self, Mailbox) { + pub fn new(context: E, cfg: Config) -> (Self, Mailbox) { let added = Counter::default(); let verified = Counter::default(); let inbound_messages = Family::::default(); @@ -126,6 +130,7 @@ impl< blocker: cfg.blocker, reporter: cfg.reporter, + strategy: cfg.strategy, activity_timeout: cfg.activity_timeout, skip_timeout: cfg.skip_timeout, @@ -301,6 +306,7 @@ impl< if !notarization.verify( &mut self.context, &self.scheme, + &self.strategy, ) { warn!(?sender, %view, "blocking peer for invalid notarization"); self.blocker.block(sender).await; @@ -327,6 +333,7 @@ impl< if !nullification.verify::<_, D>( &mut self.context, &self.scheme, + &self.strategy, ) { warn!(?sender, %view, "blocking peer for invalid nullification"); self.blocker.block(sender).await; @@ -353,6 +360,7 @@ impl< if !finalization.verify( &mut self.context, &self.scheme, + &self.strategy, ) { warn!(?sender, %view, "blocking peer for invalid finalization"); self.blocker.block(sender).await; @@ -463,11 +471,11 @@ impl< // Batch verify votes if ready let mut timer = self.verify_latency.timer(); let verified = if round.ready_notarizes() { - Some(round.verify_notarizes(&mut self.context)) + Some(round.verify_notarizes(&mut self.context, &self.strategy)) } else if round.ready_nullifies() { - Some(round.verify_nullifies(&mut self.context)) + Some(round.verify_nullifies(&mut self.context, &self.strategy)) } else if round.ready_finalizes() { - Some(round.verify_finalizes(&mut self.context)) + Some(round.verify_finalizes(&mut self.context, &self.strategy)) } else { None }; @@ -506,7 +514,7 @@ impl< // Try to construct and forward certificates if let Some(notarization) = self .recover_latency - .time_some(|| round.try_construct_notarization(&self.scheme)) + .time_some(|| round.try_construct_notarization(&self.scheme, &self.strategy)) { debug!(view = %updated_view, "constructed notarization, forwarding to voter"); voter @@ -515,7 +523,7 @@ impl< } if let Some(nullification) = self .recover_latency - .time_some(|| round.try_construct_nullification(&self.scheme)) + .time_some(|| round.try_construct_nullification(&self.scheme, &self.strategy)) { debug!(view = %updated_view, "constructed nullification, forwarding to voter"); voter @@ -524,7 +532,7 @@ impl< } if let Some(finalization) = self .recover_latency - .time_some(|| round.try_construct_finalization(&self.scheme)) + .time_some(|| round.try_construct_finalization(&self.scheme, &self.strategy)) { debug!(view = %updated_view, "constructed finalization, forwarding to voter"); voter diff --git a/consensus/src/simplex/actors/batcher/mod.rs b/consensus/src/simplex/actors/batcher/mod.rs index 4fcc699d64..41077bf080 100644 --- a/consensus/src/simplex/actors/batcher/mod.rs +++ b/consensus/src/simplex/actors/batcher/mod.rs @@ -10,16 +10,20 @@ use crate::{ pub use actor::Actor; use commonware_cryptography::certificate::Scheme; use commonware_p2p::Blocker; +use commonware_parallel::Strategy; pub use ingress::{Mailbox, Message}; pub use round::Round; pub use verifier::Verifier; -pub struct Config { +pub struct Config { pub scheme: S, pub blocker: B, pub reporter: R, + /// Strategy for parallel operations. + pub strategy: T, + pub activity_timeout: ViewDelta, pub skip_timeout: ViewDelta, pub epoch: Epoch, @@ -56,6 +60,7 @@ mod tests { simulated::{Config as NConfig, Link, Network}, Recipients, Sender as _, }; + use commonware_parallel::Sequential; use commonware_runtime::{deterministic, Clock, Metrics, Quota, Runner}; use commonware_utils::quorum; use futures::{channel::mpsc, StreamExt}; @@ -74,7 +79,7 @@ mod tests { .take(count) .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); - Notarization::from_notarizes(&schemes[0], &votes) + Notarization::from_notarizes(&schemes[0], &votes, &Sequential) .expect("notarization requires a quorum of votes") } @@ -88,7 +93,7 @@ mod tests { .take(count) .map(|scheme| Nullify::sign::(scheme, round).unwrap()) .collect(); - Nullification::from_nullifies(&schemes[0], &votes) + Nullification::from_nullifies(&schemes[0], &votes, &Sequential) .expect("nullification requires a quorum of votes") } @@ -102,7 +107,7 @@ mod tests { .take(count) .map(|scheme| Finalize::sign(scheme, proposal.clone()).unwrap()) .collect(); - Finalization::from_finalizes(&schemes[0], &votes) + Finalization::from_finalizes(&schemes[0], &votes, &Sequential) .expect("finalization requires a quorum of votes") } @@ -150,6 +155,7 @@ mod tests { scheme: schemes[0].clone(), blocker: oracle.control(me.clone()), reporter: reporter.clone(), + strategy: Sequential, activity_timeout: ViewDelta::new(10), skip_timeout: ViewDelta::new(5), epoch, @@ -310,6 +316,7 @@ mod tests { scheme: schemes[0].clone(), blocker: oracle.control(me.clone()), reporter: reporter.clone(), + strategy: Sequential, activity_timeout: ViewDelta::new(10), skip_timeout: ViewDelta::new(5), epoch, @@ -455,6 +462,7 @@ mod tests { scheme: schemes[0].clone(), blocker: oracle.control(me.clone()), reporter: reporter.clone(), + strategy: Sequential, activity_timeout: ViewDelta::new(10), skip_timeout: ViewDelta::new(5), epoch, @@ -645,6 +653,7 @@ mod tests { scheme: schemes[0].clone(), blocker: oracle.control(me.clone()), reporter: reporter.clone(), + strategy: Sequential, activity_timeout: ViewDelta::new(10), skip_timeout: ViewDelta::new(5), epoch, @@ -848,6 +857,7 @@ mod tests { scheme: schemes[0].clone(), blocker: oracle.control(me.clone()), reporter: reporter.clone(), + strategy: Sequential, activity_timeout: ViewDelta::new(10), skip_timeout: ViewDelta::new(5), epoch, @@ -974,6 +984,7 @@ mod tests { scheme: schemes[0].clone(), blocker: oracle.control(me.clone()), reporter: reporter.clone(), + strategy: Sequential, activity_timeout: ViewDelta::new(10), skip_timeout: ViewDelta::new(5), epoch, @@ -1102,6 +1113,7 @@ mod tests { scheme: schemes[0].clone(), blocker: oracle.control(me.clone()), reporter: reporter.clone(), + strategy: Sequential, activity_timeout: ViewDelta::new(10), skip_timeout: ViewDelta::new(skip_timeout), epoch, @@ -1250,6 +1262,7 @@ mod tests { scheme: schemes[0].clone(), blocker: oracle.control(me.clone()), reporter: reporter.clone(), + strategy: Sequential, activity_timeout: ViewDelta::new(10), skip_timeout: ViewDelta::new(5), epoch, @@ -1448,6 +1461,7 @@ mod tests { scheme: schemes[0].clone(), blocker: oracle.control(me.clone()), reporter: reporter.clone(), + strategy: Sequential, activity_timeout: ViewDelta::new(10), skip_timeout: ViewDelta::new(5), epoch, diff --git a/consensus/src/simplex/actors/batcher/round.rs b/consensus/src/simplex/actors/batcher/round.rs index 7879ef73f0..e85321b131 100644 --- a/consensus/src/simplex/actors/batcher/round.rs +++ b/consensus/src/simplex/actors/batcher/round.rs @@ -12,6 +12,7 @@ use crate::{ }; use commonware_cryptography::Digest; use commonware_p2p::Blocker; +use commonware_parallel::Strategy; use commonware_utils::ordered::{Quorum, Set}; use rand_core::CryptoRngCore; use tracing::warn; @@ -313,8 +314,9 @@ impl< pub fn verify_notarizes( &mut self, rng: &mut E, + strategy: &impl Strategy, ) -> (Vec>, Vec) { - self.verifier.verify_notarizes(rng) + self.verifier.verify_notarizes(rng, strategy) } pub fn ready_nullifies(&self) -> bool { @@ -328,8 +330,9 @@ impl< pub fn verify_nullifies( &mut self, rng: &mut E, + strategy: &impl Strategy, ) -> (Vec>, Vec) { - self.verifier.verify_nullifies(rng) + self.verifier.verify_nullifies(rng, strategy) } pub fn ready_finalizes(&self) -> bool { @@ -343,8 +346,9 @@ impl< pub fn verify_finalizes( &mut self, rng: &mut E, + strategy: &impl Strategy, ) -> (Vec>, Vec) { - self.verifier.verify_finalizes(rng) + self.verifier.verify_finalizes(rng, strategy) } /// Returns true if the leader was active in this round. @@ -380,7 +384,11 @@ impl< /// Attempts to construct a notarization certificate from verified votes. /// /// Returns the certificate if we have quorum and haven't already constructed one. - pub fn try_construct_notarization(&mut self, scheme: &S) -> Option> { + pub fn try_construct_notarization( + &mut self, + scheme: &S, + strategy: &impl Strategy, + ) -> Option> { if self.has_notarization() { return None; } @@ -388,7 +396,7 @@ impl< return None; } let notarization = - Notarization::from_notarizes(scheme, self.verified_votes.iter_notarizes())?; + Notarization::from_notarizes(scheme, self.verified_votes.iter_notarizes(), strategy)?; self.set_notarization(notarization.clone()); Some(notarization) } @@ -396,7 +404,11 @@ impl< /// Attempts to construct a nullification certificate from verified votes. /// /// Returns the certificate if we have quorum and haven't already constructed one. - pub fn try_construct_nullification(&mut self, scheme: &S) -> Option> { + pub fn try_construct_nullification( + &mut self, + scheme: &S, + strategy: &impl Strategy, + ) -> Option> { if self.has_nullification() { return None; } @@ -404,7 +416,7 @@ impl< return None; } let nullification = - Nullification::from_nullifies(scheme, self.verified_votes.iter_nullifies())?; + Nullification::from_nullifies(scheme, self.verified_votes.iter_nullifies(), strategy)?; self.set_nullification(nullification.clone()); Some(nullification) } @@ -412,7 +424,11 @@ impl< /// Attempts to construct a finalization certificate from verified votes. /// /// Returns the certificate if we have quorum and haven't already constructed one. - pub fn try_construct_finalization(&mut self, scheme: &S) -> Option> { + pub fn try_construct_finalization( + &mut self, + scheme: &S, + strategy: &impl Strategy, + ) -> Option> { if self.has_finalization() { return None; } @@ -420,7 +436,7 @@ impl< return None; } let finalization = - Finalization::from_finalizes(scheme, self.verified_votes.iter_finalizes())?; + Finalization::from_finalizes(scheme, self.verified_votes.iter_finalizes(), strategy)?; self.set_finalization(finalization.clone()); Some(finalization) } diff --git a/consensus/src/simplex/actors/batcher/verifier.rs b/consensus/src/simplex/actors/batcher/verifier.rs index 8bb1e4d410..db00389bcb 100644 --- a/consensus/src/simplex/actors/batcher/verifier.rs +++ b/consensus/src/simplex/actors/batcher/verifier.rs @@ -6,6 +6,7 @@ use crate::{ types::Participant, }; use commonware_cryptography::{certificate::Verification, Digest}; +use commonware_parallel::Strategy; use rand_core::CryptoRngCore; /// `Verifier` is a utility for tracking and verifying consensus messages. @@ -200,6 +201,7 @@ impl, D: Digest> Verifier { pub fn verify_notarizes( &mut self, rng: &mut R, + strategy: &impl Strategy, ) -> (Vec>, Vec) { let notarizes = std::mem::take(&mut self.notarizes); @@ -219,6 +221,7 @@ impl, D: Digest> Verifier { rng, Subject::Notarize { proposal }, attestations, + strategy, ); self.notarizes_verified += verified.len(); @@ -292,6 +295,7 @@ impl, D: Digest> Verifier { pub fn verify_nullifies( &mut self, rng: &mut R, + strategy: &impl Strategy, ) -> (Vec>, Vec) { let nullifies = std::mem::take(&mut self.nullifies); @@ -306,6 +310,7 @@ impl, D: Digest> Verifier { rng, Subject::Nullify { round }, nullifies.into_iter().map(|nullify| nullify.attestation), + strategy, ); self.nullifies_verified += verified.len(); @@ -366,6 +371,7 @@ impl, D: Digest> Verifier { pub fn verify_finalizes( &mut self, rng: &mut R, + strategy: &impl Strategy, ) -> (Vec>, Vec) { let finalizes = std::mem::take(&mut self.finalizes); @@ -385,6 +391,7 @@ impl, D: Digest> Verifier { rng, Subject::Finalize { proposal }, attestations, + strategy, ); self.finalizes_verified += verified.len(); @@ -456,6 +463,7 @@ mod tests { ed25519::PublicKey, sha256::Digest as Sha256, }; + use commonware_parallel::Sequential; use commonware_utils::{quorum_from_slice, test_rng}; use rand::rngs::StdRng; @@ -632,7 +640,7 @@ mod tests { assert!(verifier.ready_notarizes()); assert_eq!(verifier.notarizes.len(), 4); - let (verified_bulk, failed_bulk) = verifier.verify_notarizes(&mut rng); + let (verified_bulk, failed_bulk) = verifier.verify_notarizes(&mut rng, &Sequential); assert_eq!(verified_bulk.len(), 4); assert!(failed_bulk.is_empty()); assert_eq!(verifier.notarizes_verified, 4); @@ -656,7 +664,7 @@ mod tests { } assert!(verifier2.ready_notarizes()); - let (verified_second, failed_second) = verifier2.verify_notarizes(&mut rng); + let (verified_second, failed_second) = verifier2.verify_notarizes(&mut rng, &Sequential); assert!(verified_second .iter() .any(|v| matches!(v, Vote::Notarize(ref n) if n == &leader_vote))); @@ -731,7 +739,7 @@ mod tests { assert!(verifier.ready_nullifies()); assert_eq!(verifier.nullifies.len(), 3); - let (verified, failed) = verifier.verify_nullifies(&mut rng); + let (verified, failed) = verifier.verify_nullifies(&mut rng, &Sequential); assert_eq!(verified.len(), 3); assert!(failed.is_empty()); assert_eq!(verifier.nullifies_verified, 4); @@ -827,7 +835,7 @@ mod tests { verifier.add(Vote::Finalize(finalizes[3].clone()), false); assert!(verifier.ready_finalizes()); - let (verified, failed) = verifier.verify_finalizes(&mut rng); + let (verified, failed) = verifier.verify_finalizes(&mut rng, &Sequential); assert_eq!(verified.len(), 3); assert!(failed.is_empty()); assert_eq!(verifier.finalizes_verified, 4); @@ -966,7 +974,7 @@ mod tests { } assert!(verifier.ready_notarizes(), "Should be ready at quorum"); - let (verified, _) = verifier.verify_notarizes(&mut rng); + let (verified, _) = verifier.verify_notarizes(&mut rng, &Sequential); assert_eq!(verified.len(), quorum as usize); assert!(!verifier.ready_notarizes()); } @@ -1103,7 +1111,7 @@ mod tests { let mut verifier = Verifier::::new(schemes[0].clone(), quorum); assert!(verifier.nullifies.is_empty()); assert!(!verifier.ready_nullifies()); - let (verified, failed) = verifier.verify_nullifies(&mut rng); + let (verified, failed) = verifier.verify_nullifies(&mut rng, &Sequential); assert!(verified.is_empty()); assert!(failed.is_empty()); assert_eq!(verifier.nullifies_verified, 0); @@ -1131,7 +1139,7 @@ mod tests { verifier.set_leader(Participant::new(0)); assert!(verifier.finalizes.is_empty()); assert!(!verifier.ready_finalizes()); - let (verified, failed) = verifier.verify_finalizes(&mut rng); + let (verified, failed) = verifier.verify_finalizes(&mut rng, &Sequential); assert!(verified.is_empty()); assert!(failed.is_empty()); assert_eq!(verifier.finalizes_verified, 0); @@ -1183,7 +1191,7 @@ mod tests { } } - let (verified, failed) = verifier.verify_notarizes(&mut rng); + let (verified, failed) = verifier.verify_notarizes(&mut rng, &Sequential); assert_eq!(verified.len(), quorum as usize - 1); assert!(failed.is_empty()); assert_eq!(verifier.notarizes_verified, quorum as usize); diff --git a/consensus/src/simplex/actors/resolver/actor.rs b/consensus/src/simplex/actors/resolver/actor.rs index c71ac8b200..be6117da3b 100644 --- a/consensus/src/simplex/actors/resolver/actor.rs +++ b/consensus/src/simplex/actors/resolver/actor.rs @@ -16,6 +16,7 @@ use commonware_codec::{Decode, Encode}; use commonware_cryptography::Digest; use commonware_macros::select_loop; use commonware_p2p::{utils::StaticManager, Blocker, Receiver, Sender}; +use commonware_parallel::Strategy; use commonware_resolver::p2p; use commonware_runtime::{spawn_cell, Clock, ContextCell, Handle, Metrics, Spawner}; use commonware_utils::{channels::fallible::OneshotExt, ordered::Quorum, sequence::U64}; @@ -30,10 +31,12 @@ pub struct Actor< S: Scheme, B: Blocker, D: Digest, + T: Strategy, > { context: ContextCell, scheme: S, blocker: Option, + strategy: T, epoch: Epoch, mailbox_size: usize, @@ -49,15 +52,17 @@ impl< S: Scheme, B: Blocker, D: Digest, - > Actor + T: Strategy, + > Actor { - pub fn new(context: E, cfg: Config) -> (Self, Mailbox) { + pub fn new(context: E, cfg: Config) -> (Self, Mailbox) { let (sender, receiver) = mpsc::channel(cfg.mailbox_size); ( Self { context: ContextCell::new(context), scheme: cfg.scheme, blocker: Some(cfg.blocker), + strategy: cfg.strategy, epoch: cfg.epoch, mailbox_size: cfg.mailbox_size, @@ -174,7 +179,7 @@ impl< ); return None; } - if !notarization.verify(&mut self.context, &self.scheme) { + if !notarization.verify(&mut self.context, &self.scheme, &self.strategy) { debug!(%view, "notarization failed verification"); return None; } @@ -194,7 +199,7 @@ impl< ); return None; } - if !finalization.verify(&mut self.context, &self.scheme) { + if !finalization.verify(&mut self.context, &self.scheme, &self.strategy) { debug!(%view, "finalization failed verification"); return None; } @@ -214,7 +219,7 @@ impl< ); return None; } - if !nullification.verify::<_, D>(&mut self.context, &self.scheme) { + if !nullification.verify::<_, D>(&mut self.context, &self.scheme, &self.strategy) { debug!(%view, "nullification failed verification"); return None; } diff --git a/consensus/src/simplex/actors/resolver/mod.rs b/consensus/src/simplex/actors/resolver/mod.rs index 01dfce0f0e..5bede0a2a3 100644 --- a/consensus/src/simplex/actors/resolver/mod.rs +++ b/consensus/src/simplex/actors/resolver/mod.rs @@ -6,16 +6,20 @@ use crate::types::Epoch; pub use actor::Actor; use commonware_cryptography::certificate::Scheme; use commonware_p2p::Blocker; +use commonware_parallel::Strategy; pub use ingress::Mailbox; #[cfg(test)] pub use ingress::MailboxMessage; use std::time::Duration; -pub struct Config { +pub struct Config { pub scheme: S, pub blocker: B, + /// Strategy for parallel operations. + pub strategy: T, + pub epoch: Epoch, pub mailbox_size: usize, pub fetch_concurrent: usize, diff --git a/consensus/src/simplex/actors/resolver/state.rs b/consensus/src/simplex/actors/resolver/state.rs index f44696e9b3..47b2e72f5f 100644 --- a/consensus/src/simplex/actors/resolver/state.rs +++ b/consensus/src/simplex/actors/resolver/state.rs @@ -224,6 +224,7 @@ mod tests { certificate::mocks::Fixture, ed25519::PublicKey, sha256::Digest as Sha256Digest, }; use commonware_macros::test_async; + use commonware_parallel::Sequential; use commonware_utils::{test_rng, vec::NonEmptyVec}; use std::{ collections::BTreeSet, @@ -311,7 +312,7 @@ mod tests { .iter() .map(|scheme| Nullify::sign::(scheme, round).unwrap()) .collect(); - Nullification::from_nullifies(verifier, &votes).expect("nullification quorum") + Nullification::from_nullifies(verifier, &votes, &Sequential).expect("nullification quorum") } fn build_notarization( @@ -328,7 +329,7 @@ mod tests { .iter() .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); - Notarization::from_notarizes(verifier, &votes).expect("notarization quorum") + Notarization::from_notarizes(verifier, &votes, &Sequential).expect("notarization quorum") } fn build_finalization( @@ -345,7 +346,7 @@ mod tests { .iter() .map(|scheme| Finalize::sign(scheme, proposal.clone()).unwrap()) .collect(); - Finalization::from_finalizes(verifier, &votes).expect("finalization quorum") + Finalization::from_finalizes(verifier, &votes, &Sequential).expect("finalization quorum") } #[test_async] diff --git a/consensus/src/simplex/actors/voter/mod.rs b/consensus/src/simplex/actors/voter/mod.rs index 039c5fec52..daddb544b7 100644 --- a/consensus/src/simplex/actors/voter/mod.rs +++ b/consensus/src/simplex/actors/voter/mod.rs @@ -70,6 +70,7 @@ mod tests { }; use commonware_macros::{select, test_traced}; use commonware_p2p::simulated::{Config as NConfig, Network}; + use commonware_parallel::Sequential; use commonware_runtime::{deterministic, Clock, Metrics, Quota, Runner}; use commonware_utils::{quorum, NZUsize, NZU16}; use futures::{channel::mpsc, FutureExt, StreamExt}; @@ -96,7 +97,7 @@ mod tests { .take(count as usize) .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); - let certificate = Notarization::from_notarizes(&schemes[0], &votes) + let certificate = Notarization::from_notarizes(&schemes[0], &votes, &Sequential) .expect("notarization requires a quorum of votes"); (votes, certificate) } @@ -114,7 +115,7 @@ mod tests { .take(count as usize) .map(|scheme| Finalize::sign(scheme, proposal.clone()).unwrap()) .collect(); - let certificate = Finalization::from_finalizes(&schemes[0], &votes) + let certificate = Finalization::from_finalizes(&schemes[0], &votes, &Sequential) .expect("finalization requires a quorum of votes"); (votes, certificate) } diff --git a/consensus/src/simplex/actors/voter/round.rs b/consensus/src/simplex/actors/voter/round.rs index 6a3c20c048..876ea8973d 100644 --- a/consensus/src/simplex/actors/voter/round.rs +++ b/consensus/src/simplex/actors/voter/round.rs @@ -562,6 +562,7 @@ mod tests { types::{Epoch, Participant, View}, }; use commonware_cryptography::{certificate::mocks::Fixture, sha256::Digest as Sha256Digest}; + use commonware_parallel::Sequential; use commonware_utils::{futures::AbortablePool, test_rng}; #[test] @@ -603,7 +604,8 @@ mod tests { .map(|scheme| Notarize::sign(scheme, proposal_b.clone()).unwrap()) .collect(); let certificate = - Notarization::from_notarizes(&verifier, notarization_votes.iter()).unwrap(); + Notarization::from_notarizes(&verifier, notarization_votes.iter(), &Sequential) + .unwrap(); let (accepted, equivocator) = round.add_notarization(certificate.clone()); assert!(accepted); assert!(equivocator.is_some()); @@ -656,7 +658,8 @@ mod tests { .map(|scheme| Finalize::sign(scheme, proposal_b.clone()).unwrap()) .collect(); let certificate = - Finalization::from_finalizes(&verifier, finalization_votes.iter()).unwrap(); + Finalization::from_finalizes(&verifier, finalization_votes.iter(), &Sequential) + .unwrap(); let (accepted, equivocator) = round.add_finalization(certificate.clone()); assert!(accepted); assert!(equivocator.is_some()); @@ -670,7 +673,8 @@ mod tests { .map(|scheme| Notarize::sign(scheme, proposal_b.clone()).unwrap()) .collect(); let certificate = - Notarization::from_notarizes(&verifier, notarization_votes.iter()).unwrap(); + Notarization::from_notarizes(&verifier, notarization_votes.iter(), &Sequential) + .unwrap(); let (accepted, equivocator) = round.add_notarization(certificate.clone()); assert!(accepted); assert_eq!(equivocator, None); // already detected @@ -708,7 +712,8 @@ mod tests { .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); let certificate = - Notarization::from_notarizes(&verifier, notarization_votes.iter()).unwrap(); + Notarization::from_notarizes(&verifier, notarization_votes.iter(), &Sequential) + .unwrap(); let (accepted, equivocator) = round.add_notarization(certificate); assert!(accepted); assert!(equivocator.is_none()); @@ -736,7 +741,8 @@ mod tests { .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); let notarization = - Notarization::from_notarizes(&verifier, notarize_votes.iter()).expect("notarization"); + Notarization::from_notarizes(&verifier, notarize_votes.iter(), &Sequential) + .expect("notarization"); // Create nullification let nullify_local = Nullify::sign::(&local_scheme, round).expect("nullify"); @@ -744,8 +750,8 @@ mod tests { .iter() .map(|scheme| Nullify::sign::(scheme, round).expect("nullify")) .collect(); - let nullification = - Nullification::from_nullifies(&verifier, &nullify_votes).expect("nullification"); + let nullification = Nullification::from_nullifies(&verifier, &nullify_votes, &Sequential) + .expect("nullification"); // Create finalize let finalize_local = Finalize::sign(&local_scheme, proposal.clone()).expect("finalize"); @@ -754,7 +760,8 @@ mod tests { .map(|scheme| Finalize::sign(scheme, proposal.clone()).unwrap()) .collect(); let finalization = - Finalization::from_finalizes(&verifier, finalize_votes.iter()).expect("finalization"); + Finalization::from_finalizes(&verifier, finalize_votes.iter(), &Sequential) + .expect("finalization"); // Replay messages and verify broadcast flags let mut round = Round::new(local_scheme, round, now); @@ -850,7 +857,8 @@ mod tests { .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); let notarization = - Notarization::from_notarizes(&verifier, notarization_votes.iter()).unwrap(); + Notarization::from_notarizes(&verifier, notarization_votes.iter(), &Sequential) + .unwrap(); let (added, _) = round.add_notarization(notarization); assert!(added); @@ -891,7 +899,8 @@ mod tests { .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); let notarization = - Notarization::from_notarizes(&verifier, notarization_votes.iter()).unwrap(); + Notarization::from_notarizes(&verifier, notarization_votes.iter(), &Sequential) + .unwrap(); let (added, _) = round.add_notarization(notarization); assert!(added); @@ -931,7 +940,8 @@ mod tests { .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); let notarization = - Notarization::from_notarizes(&verifier, notarization_votes.iter()).unwrap(); + Notarization::from_notarizes(&verifier, notarization_votes.iter(), &Sequential) + .unwrap(); let (added, _) = round.add_notarization(notarization); assert!(added); @@ -973,7 +983,8 @@ mod tests { .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); let notarization = - Notarization::from_notarizes(&verifier, notarization_votes.iter()).unwrap(); + Notarization::from_notarizes(&verifier, notarization_votes.iter(), &Sequential) + .unwrap(); let (added, _) = round.add_notarization(notarization); assert!(added); @@ -1005,7 +1016,8 @@ mod tests { .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); let notarization = - Notarization::from_notarizes(&verifier, notarization_votes.iter()).unwrap(); + Notarization::from_notarizes(&verifier, notarization_votes.iter(), &Sequential) + .unwrap(); let (added, _) = round.add_notarization(notarization); assert!(added); diff --git a/consensus/src/simplex/actors/voter/state.rs b/consensus/src/simplex/actors/voter/state.rs index 875dae9e66..e7796ba9e0 100644 --- a/consensus/src/simplex/actors/voter/state.rs +++ b/consensus/src/simplex/actors/voter/state.rs @@ -625,6 +625,7 @@ mod tests { types::{Finalization, Finalize, Notarization, Notarize, Nullification, Nullify, Proposal}, }; use commonware_cryptography::{certificate::mocks::Fixture, sha256::Digest as Sha256Digest}; + use commonware_parallel::Sequential; use commonware_runtime::{deterministic, Runner}; use commonware_utils::futures::AbortablePool; use std::time::Duration; @@ -664,8 +665,9 @@ mod tests { .iter() .map(|scheme| Notarize::sign(scheme, notarize_proposal.clone()).unwrap()) .collect(); - let notarization = Notarization::from_notarizes(&verifier, notarize_votes.iter()) - .expect("notarization"); + let notarization = + Notarization::from_notarizes(&verifier, notarize_votes.iter(), &Sequential) + .expect("notarization"); state.add_notarization(notarization); // Produce candidate once @@ -683,7 +685,8 @@ mod tests { }) .collect(); let nullification = - Nullification::from_nullifies(&verifier, &nullify_votes).expect("nullification"); + Nullification::from_nullifies(&verifier, &nullify_votes, &Sequential) + .expect("nullification"); state.add_nullification(nullification); // Produce candidate once @@ -700,8 +703,9 @@ mod tests { .iter() .map(|scheme| Finalize::sign(scheme, finalize_proposal.clone()).unwrap()) .collect(); - let finalization = Finalization::from_finalizes(&verifier, finalize_votes.iter()) - .expect("finalization"); + let finalization = + Finalization::from_finalizes(&verifier, finalize_votes.iter(), &Sequential) + .expect("finalization"); state.add_finalization(finalization); // Produce candidate once @@ -803,8 +807,9 @@ mod tests { .iter() .map(|scheme| Finalize::sign(scheme, proposal_a.clone()).unwrap()) .collect(); - let finalization = Finalization::from_finalizes(&verifier, finalization_votes.iter()) - .expect("finalization"); + let finalization = + Finalization::from_finalizes(&verifier, finalization_votes.iter(), &Sequential) + .expect("finalization"); state.add_finalization(finalization); // Update last finalize to be in the future @@ -867,7 +872,8 @@ mod tests { .map(|scheme| Notarize::sign(scheme, parent_proposal.clone()).unwrap()) .collect(); let notarization = - Notarization::from_notarizes(&verifier, notarization_votes.iter()).unwrap(); + Notarization::from_notarizes(&verifier, notarization_votes.iter(), &Sequential) + .unwrap(); state.add_notarization(notarization); // The parent is still not certified @@ -912,8 +918,9 @@ mod tests { .iter() .map(|scheme| Notarize::sign(scheme, parent_proposal.clone()).unwrap()) .collect(); - let notarization = Notarization::from_notarizes(&verifier, notarize_votes.iter()) - .expect("notarization"); + let notarization = + Notarization::from_notarizes(&verifier, notarize_votes.iter(), &Sequential) + .expect("notarization"); state.add_notarization(notarization.clone()); // Insert proposal at view 2 with parent at view 1 @@ -933,8 +940,9 @@ mod tests { .iter() .map(|scheme| Finalize::sign(scheme, parent_proposal.clone()).unwrap()) .collect(); - let finalization = Finalization::from_finalizes(&verifier, finalize_votes.iter()) - .expect("finalization"); + let finalization = + Finalization::from_finalizes(&verifier, finalize_votes.iter(), &Sequential) + .expect("finalization"); state.add_finalization(finalization.clone()); // parent_certificate now returns the finalization (preferred) @@ -975,7 +983,8 @@ mod tests { .map(|scheme| Notarize::sign(scheme, parent_proposal.clone()).unwrap()) .collect(); let notarization = - Notarization::from_notarizes(&verifier, notarization_votes.iter()).unwrap(); + Notarization::from_notarizes(&verifier, notarization_votes.iter(), &Sequential) + .unwrap(); state.add_notarization(notarization); state.create_round(View::new(2)); @@ -1017,7 +1026,8 @@ mod tests { .unwrap() }) .collect(); - let nullification = Nullification::from_nullifies(&verifier, &nullify_votes).unwrap(); + let nullification = + Nullification::from_nullifies(&verifier, &nullify_votes, &Sequential).unwrap(); state.add_nullification(nullification); // Get genesis payload @@ -1062,8 +1072,9 @@ mod tests { .iter() .map(|scheme| Finalize::sign(scheme, proposal_a.clone()).unwrap()) .collect(); - let finalization = Finalization::from_finalizes(&verifier, finalization_votes.iter()) - .expect("finalization"); + let finalization = + Finalization::from_finalizes(&verifier, finalization_votes.iter(), &Sequential) + .expect("finalization"); state.add_finalization(finalization); // Attempt to verify before finalized @@ -1116,8 +1127,8 @@ mod tests { .take(3) .map(|scheme| Notarize::sign(scheme, proposal_b.clone()).unwrap()) .collect(); - let conflicting = - Notarization::from_notarizes(&verifier, votes_b.iter()).expect("certificate"); + let conflicting = Notarization::from_notarizes(&verifier, votes_b.iter(), &Sequential) + .expect("certificate"); state.add_notarization(conflicting.clone()); state.replay(&Artifact::Notarization(conflicting.clone())); @@ -1178,7 +1189,7 @@ mod tests { .iter() .map(|s| Notarize::sign(s, proposal.clone()).unwrap()) .collect(); - Notarization::from_notarizes(&verifier, votes.iter()).unwrap() + Notarization::from_notarizes(&verifier, votes.iter(), &Sequential).unwrap() }; // Helper to create finalization for a view @@ -1192,7 +1203,7 @@ mod tests { .iter() .map(|s| Finalize::sign(s, proposal.clone()).unwrap()) .collect(); - Finalization::from_finalizes(&verifier, votes.iter()).unwrap() + Finalization::from_finalizes(&verifier, votes.iter(), &Sequential).unwrap() }; let mut pool = AbortablePool::<()>::default(); diff --git a/consensus/src/simplex/config.rs b/consensus/src/simplex/config.rs index 4636fa66aa..14e15501a9 100644 --- a/consensus/src/simplex/config.rs +++ b/consensus/src/simplex/config.rs @@ -8,6 +8,7 @@ use crate::{ }; use commonware_cryptography::{certificate::Scheme, Digest}; use commonware_p2p::Blocker; +use commonware_parallel::Strategy; use commonware_runtime::buffer::PoolRef; use std::{num::NonZeroUsize, time::Duration}; @@ -20,6 +21,7 @@ pub struct Config< A: CertifiableAutomaton>, R: Relay, F: Reporter>, + T: Strategy, > { /// Signing scheme for the consensus engine. /// @@ -58,6 +60,9 @@ pub struct Config< /// automatically filter and verify activities based on scheme attributability. pub reporter: F, + /// Strategy for parallel operations. + pub strategy: T, + /// Partition for the consensus engine. pub partition: String, @@ -115,7 +120,8 @@ impl< A: CertifiableAutomaton>, R: Relay, F: Reporter>, - > Config + T: Strategy, + > Config { /// Assert enforces that all configuration values are valid. pub fn assert(&self) { diff --git a/consensus/src/simplex/elector.rs b/consensus/src/simplex/elector.rs index 357f82d55b..7ae16c25e6 100644 --- a/consensus/src/simplex/elector.rs +++ b/consensus/src/simplex/elector.rs @@ -33,7 +33,6 @@ use commonware_codec::Encode; use commonware_cryptography::{ bls12381::primitives::variant::Variant, certificate::Scheme, Hasher, PublicKey, Sha256, }; -use commonware_parallel::Strategy; use commonware_utils::{modulo, ordered::Set}; use std::marker::PhantomData; @@ -185,15 +184,14 @@ impl Random { } } -impl Config> for Random +impl Config> for Random where P: PublicKey, V: Variant, - S: Strategy, { - type Elector = RandomElector>; + type Elector = RandomElector>; - fn build(self, participants: &Set

) -> RandomElector> { + fn build(self, participants: &Set

) -> RandomElector> { assert!(!participants.is_empty(), "no participants"); RandomElector { n: participants.len() as u32, @@ -211,12 +209,11 @@ pub struct RandomElector { _phantom: PhantomData, } -impl Elector> - for RandomElector> +impl Elector> + for RandomElector> where P: PublicKey, V: Variant, - S: Strategy, { fn elect( &self, @@ -247,7 +244,7 @@ mod tests { const NAMESPACE: &[u8] = b"test"; type ThresholdScheme = - bls12381_threshold::Scheme; + bls12381_threshold::Scheme; #[test] fn round_robin_rotates_through_participants() { @@ -431,7 +428,7 @@ mod tests { .unwrap() }) .collect(); - let cert1 = schemes[0].assemble(attestations1).unwrap(); + let cert1 = schemes[0].assemble(attestations1, &Sequential).unwrap(); // Create certificate for round (1, 3) (different round -> different seed signature) let round2 = Round::new(Epoch::new(1), View::new(3)); @@ -443,7 +440,7 @@ mod tests { .unwrap() }) .collect(); - let cert2 = schemes[0].assemble(attestations2).unwrap(); + let cert2 = schemes[0].assemble(attestations2, &Sequential).unwrap(); // Same certificate always gives same leader let leader1a = elector.elect(round1, Some(&cert1)); @@ -550,7 +547,7 @@ mod tests { .take(quorum) .map(|s| s.sign::(Subject::Nullify { round }).unwrap()) .collect(); - let cert = schemes[0].assemble(attestations).unwrap(); + let cert = schemes[0].assemble(attestations, &Sequential).unwrap(); // Elect leader using the certificate let leader = elector.elect(round, Some(&cert)); diff --git a/consensus/src/simplex/engine.rs b/consensus/src/simplex/engine.rs index 753d02555d..9970d20b62 100644 --- a/consensus/src/simplex/engine.rs +++ b/consensus/src/simplex/engine.rs @@ -8,6 +8,7 @@ use crate::{simplex::scheme::Scheme, CertifiableAutomaton, Relay, Reporter}; use commonware_cryptography::Digest; use commonware_macros::select; use commonware_p2p::{Blocker, Receiver, Sender}; +use commonware_parallel::Strategy; use commonware_runtime::{spawn_cell, Clock, ContextCell, Handle, Metrics, Spawner, Storage}; use rand_core::CryptoRngCore; use tracing::debug; @@ -22,16 +23,17 @@ pub struct Engine< A: CertifiableAutomaton, Digest = D>, R: Relay, F: Reporter>, + T: Strategy, > { context: ContextCell, voter: voter::Actor, voter_mailbox: voter::Mailbox, - batcher: batcher::Actor, + batcher: batcher::Actor, batcher_mailbox: batcher::Mailbox, - resolver: resolver::Actor, + resolver: resolver::Actor, resolver_mailbox: resolver::Mailbox, } @@ -44,10 +46,11 @@ impl< A: CertifiableAutomaton, Digest = D>, R: Relay, F: Reporter>, - > Engine + T: Strategy, + > Engine { /// Create a new `simplex` consensus engine. - pub fn new(context: E, cfg: Config) -> Self { + pub fn new(context: E, cfg: Config) -> Self { // Ensure configuration is valid cfg.assert(); @@ -58,6 +61,7 @@ impl< scheme: cfg.scheme.clone(), blocker: cfg.blocker.clone(), reporter: cfg.reporter.clone(), + strategy: cfg.strategy.clone(), epoch: cfg.epoch, mailbox_size: cfg.mailbox_size, activity_timeout: cfg.activity_timeout, @@ -94,6 +98,7 @@ impl< resolver::Config { blocker: cfg.blocker, scheme: cfg.scheme, + strategy: cfg.strategy, mailbox_size: cfg.mailbox_size, epoch: cfg.epoch, fetch_concurrent: cfg.fetch_concurrent, diff --git a/consensus/src/simplex/mocks/reporter.rs b/consensus/src/simplex/mocks/reporter.rs index d7211b9e25..8da608cc2c 100644 --- a/consensus/src/simplex/mocks/reporter.rs +++ b/consensus/src/simplex/mocks/reporter.rs @@ -14,6 +14,7 @@ use crate::{ }; use commonware_codec::{Decode, DecodeExt, Encode}; use commonware_cryptography::{certificate::Scheme, Digest}; +use commonware_parallel::Sequential; use commonware_utils::{ channels::fallible::AsyncFallibleExt, ordered::{Quorum, Set}, @@ -121,7 +122,7 @@ where let verified = activity.verified(); match &activity { Activity::Notarize(notarize) => { - if !notarize.verify(&mut self.context, &self.scheme) { + if !notarize.verify(&mut self.context, &self.scheme, &Sequential) { assert!(!verified); *self.invalid.lock().unwrap() += 1; return; @@ -147,6 +148,7 @@ where proposal: ¬arization.proposal, }, ¬arization.certificate, + &Sequential, ) { assert!(!verified); *self.invalid.lock().unwrap() += 1; @@ -162,7 +164,7 @@ where self.certified(notarization.round(), ¬arization.certificate); } Activity::Nullify(nullify) => { - if !nullify.verify(&mut self.context, &self.scheme) { + if !nullify.verify(&mut self.context, &self.scheme, &Sequential) { assert!(!verified); *self.invalid.lock().unwrap() += 1; return; @@ -186,6 +188,7 @@ where round: nullification.round, }, &nullification.certificate, + &Sequential, ) { assert!(!verified); *self.invalid.lock().unwrap() += 1; @@ -201,7 +204,7 @@ where self.certified(nullification.round, &nullification.certificate); } Activity::Finalize(finalize) => { - if !finalize.verify(&mut self.context, &self.scheme) { + if !finalize.verify(&mut self.context, &self.scheme, &Sequential) { assert!(!verified); *self.invalid.lock().unwrap() += 1; return; @@ -227,6 +230,7 @@ where proposal: &finalization.proposal, }, &finalization.certificate, + &Sequential, ) { assert!(!verified); *self.invalid.lock().unwrap() += 1; @@ -250,7 +254,7 @@ where } Activity::ConflictingNotarize(conflicting) => { let view = conflicting.view(); - if !conflicting.verify(&mut self.context, &self.scheme) { + if !conflicting.verify(&mut self.context, &self.scheme, &Sequential) { assert!(!verified); *self.invalid.lock().unwrap() += 1; return; @@ -269,7 +273,7 @@ where } Activity::ConflictingFinalize(conflicting) => { let view = conflicting.view(); - if !conflicting.verify(&mut self.context, &self.scheme) { + if !conflicting.verify(&mut self.context, &self.scheme, &Sequential) { assert!(!verified); *self.invalid.lock().unwrap() += 1; return; @@ -288,7 +292,7 @@ where } Activity::NullifyFinalize(conflicting) => { let view = conflicting.view(); - if !conflicting.verify(&mut self.context, &self.scheme) { + if !conflicting.verify(&mut self.context, &self.scheme, &Sequential) { assert!(!verified); *self.invalid.lock().unwrap() += 1; return; diff --git a/consensus/src/simplex/mod.rs b/consensus/src/simplex/mod.rs index adc8f439a2..e1f3b57355 100644 --- a/consensus/src/simplex/mod.rs +++ b/consensus/src/simplex/mod.rs @@ -620,6 +620,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -887,6 +888,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -1053,6 +1055,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -1242,6 +1245,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -1361,6 +1365,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: me.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -1501,6 +1506,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -1762,6 +1768,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -1938,6 +1945,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -2151,6 +2159,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -2361,6 +2370,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -2599,6 +2609,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -2785,6 +2796,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.clone().to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -2963,6 +2975,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.clone().to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -3137,6 +3150,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -3226,6 +3240,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -3434,6 +3449,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -3600,6 +3616,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.clone().to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -3780,6 +3797,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.clone().to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -3929,6 +3947,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -4095,6 +4114,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: participants[0].clone().to_string(), mailbox_size: 64, epoch: Epoch::new(333), @@ -4256,6 +4276,7 @@ mod tests { context.with_label("rng"), schemes[idx].clone(), mock_reporter.clone(), + Sequential, true, // Enable verification ); reporters.push(mock_reporter.clone()); @@ -4282,6 +4303,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: attributable_reporter, + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -4517,6 +4539,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -4544,20 +4567,23 @@ mod tests { let votes: Vec<_> = (0..=quorum) .map(|i| TFinalize::sign(&schemes[i], proposal.clone()).unwrap()) .collect(); - TFinalization::from_finalizes(&schemes[0], &votes).expect("finalization quorum") + TFinalization::from_finalizes(&schemes[0], &votes, &Sequential) + .expect("finalization quorum") }; // Helper: assemble notarization from explicit signer indices let build_notarization = |proposal: &Proposal| -> TNotarization<_, D> { let votes: Vec<_> = (0..=quorum) .map(|i| TNotarize::sign(&schemes[i], proposal.clone()).unwrap()) .collect(); - TNotarization::from_notarizes(&schemes[0], &votes).expect("notarization quorum") + TNotarization::from_notarizes(&schemes[0], &votes, &Sequential) + .expect("notarization quorum") }; let build_nullification = |round: Round| -> TNullification<_> { let votes: Vec<_> = (0..=quorum) .map(|i| TNullify::sign::(&schemes[i], round).unwrap()) .collect(); - TNullification::from_nullifies(&schemes[0], &votes).expect("nullification quorum") + TNullification::from_nullifies(&schemes[0], &votes, &Sequential) + .expect("nullification quorum") }; // Choose F=1 and construct B_1, B_2A, B_2B let f_view = 1; @@ -4764,7 +4790,7 @@ mod tests { fn tle() where V: Variant, - L: Elector>, + L: Elector>, { // Create context let n = 4; @@ -4848,6 +4874,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -4997,6 +5024,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -5092,6 +5120,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: selected_reporter, + strategy: Sequential, partition: validator.to_string(), mailbox_size: 1024, epoch: Epoch::new(333), @@ -5497,6 +5526,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: label, mailbox_size: 1024, epoch: Epoch::new(333), @@ -5553,6 +5583,7 @@ mod tests { automaton: application.clone(), relay: application.clone(), reporter: reporter.clone(), + strategy: Sequential, partition: label, mailbox_size: 1024, epoch: Epoch::new(333), diff --git a/consensus/src/simplex/scheme/bls12381_threshold.rs b/consensus/src/simplex/scheme/bls12381_threshold.rs index c01835a7eb..67a87697f1 100644 --- a/consensus/src/simplex/scheme/bls12381_threshold.rs +++ b/consensus/src/simplex/scheme/bls12381_threshold.rs @@ -29,7 +29,7 @@ use commonware_cryptography::{ certificate::{self, Attestation, Subject as CertificateSubject, Verification}, Digest, PublicKey, }; -use commonware_parallel::{Sequential, Strategy}; +use commonware_parallel::Strategy; use commonware_utils::ordered::Set; use rand_core::CryptoRngCore; use std::{ @@ -71,16 +71,12 @@ enum Role { /// It is possible for a node to play one of the following roles: a signer (with its share), /// a verifier (with evaluated public polynomial), or an external verifier that /// only checks recovered certificates. -/// -/// The scheme is generic over a [`Strategy`] which determines whether cryptographic -/// operations such as signature recovery and batch verification run sequentially or in parallel. #[derive(Clone, Debug)] -pub struct Scheme { +pub struct Scheme { role: Role, - strategy: S, } -impl Scheme { +impl Scheme { /// Constructs a signer instance with a private share and evaluated public polynomial. /// /// The participant identity keys are used for committee ordering and indexing. @@ -93,13 +89,11 @@ impl Scheme { /// * `participants` - ordered set of participant identity keys /// * `polynomial` - public polynomial for threshold verification /// * `share` - local threshold share for signing - /// * `strategy` - execution strategy for parallel cryptographic operations pub fn signer( namespace: &[u8], participants: Set

, polynomial: Sharing, share: Share, - strategy: S, ) -> Option { assert_eq!( polynomial.total().get() as usize, @@ -118,7 +112,6 @@ impl Scheme { share, namespace: Namespace::new(namespace), }, - strategy, }) } else { None @@ -134,13 +127,7 @@ impl Scheme { /// * `namespace` - base namespace for domain separation /// * `participants` - ordered set of participant identity keys /// * `polynomial` - public polynomial for threshold verification - /// * `strategy` - execution strategy for parallel cryptographic operations - pub fn verifier( - namespace: &[u8], - participants: Set

, - polynomial: Sharing, - strategy: S, - ) -> Self { + pub fn verifier(namespace: &[u8], participants: Set

, polynomial: Sharing) -> Self { assert_eq!( polynomial.total().get() as usize, participants.len(), @@ -154,7 +141,6 @@ impl Scheme { polynomial, namespace: Namespace::new(namespace), }, - strategy, } } @@ -165,14 +151,12 @@ impl Scheme { /// /// * `namespace` - base namespace for domain separation /// * `identity` - public identity of the committee (constant across reshares) - /// * `strategy` - execution strategy for parallel cryptographic operations - pub fn certificate_verifier(namespace: &[u8], identity: V::Public, strategy: S) -> Self { + pub fn certificate_verifier(namespace: &[u8], identity: V::Public) -> Self { Self { role: Role::CertificateVerifier { identity, namespace: Namespace::new(namespace), }, - strategy, } } @@ -274,7 +258,7 @@ pub fn fixture( namespace: &[u8], n: u32, ) -> commonware_cryptography::certificate::mocks::Fixture< - Scheme, + Scheme, > where V: Variant, @@ -285,11 +269,9 @@ where namespace, n, |namespace, participants, polynomial, share| { - Scheme::signer(namespace, participants, polynomial, share, Sequential) - }, - |namespace, participants, polynomial| { - Scheme::verifier(namespace, participants, polynomial, Sequential) + Scheme::signer(namespace, participants, polynomial, share) }, + |namespace, participants, polynomial| Scheme::verifier(namespace, participants, polynomial), ) } @@ -356,7 +338,7 @@ impl Seed { } /// Verifies the threshold signature on this [Seed]. - pub fn verify(&self, scheme: &Scheme) -> bool { + pub fn verify(&self, scheme: &Scheme) -> bool { let seed_message = self.round.encode(); ops::verify_message::( @@ -446,17 +428,13 @@ pub trait Seedable { fn seed(&self) -> Seed; } -impl Seedable - for Notarization, D> -{ +impl Seedable for Notarization, D> { fn seed(&self) -> Seed { Seed::new(self.proposal.round, self.certificate.seed_signature) } } -impl Seedable - for Finalization, D> -{ +impl Seedable for Finalization, D> { fn seed(&self) -> Seed { Seed::new(self.proposal.round, self.certificate.seed_signature) } @@ -472,7 +450,7 @@ fn seed_message_from_subject(subject: &Subject<'_, D>) -> bytes::Byte } } -impl certificate::Scheme for Scheme { +impl certificate::Scheme for Scheme { type Subject<'a, D: Digest> = Subject<'a, D>; type PublicKey = P; type Signature = Signature; @@ -518,6 +496,7 @@ impl certificate::Scheme for Scheme, attestation: &Attestation, + strategy: &impl Strategy, ) -> bool where R: CryptoRngCore, @@ -544,7 +523,7 @@ impl certificate::Scheme for Scheme(rng, &evaluated, entries, &self.strategy).is_ok() + batch::verify_same_signer::<_, V, _, _>(rng, &evaluated, entries, strategy).is_ok() } fn verify_attestations( @@ -552,6 +531,7 @@ impl certificate::Scheme for Scheme, attestations: I, + _strategy: &impl Strategy, ) -> Verification where R: CryptoRngCore, @@ -622,7 +602,7 @@ impl certificate::Scheme for Scheme(&self, attestations: I) -> Option + fn assemble(&self, attestations: I, strategy: &impl Strategy) -> Option where I: IntoIterator>, { @@ -651,7 +631,7 @@ impl certificate::Scheme for Scheme certificate::Scheme for Scheme, certificate: &Self::Certificate, + strategy: &impl Strategy, ) -> bool { let identity = self.identity(); let namespace = self.namespace(); @@ -686,10 +667,15 @@ impl certificate::Scheme for Scheme(rng, identity, entries, &self.strategy).is_ok() + batch::verify_same_signer::<_, V, _, _>(rng, identity, entries, strategy).is_ok() } - fn verify_certificates<'a, R, D, I>(&self, rng: &mut R, certificates: I) -> bool + fn verify_certificates<'a, R, D, I>( + &self, + rng: &mut R, + certificates: I, + strategy: &impl Strategy, + ) -> bool where R: CryptoRngCore, D: Digest, @@ -728,8 +714,7 @@ impl certificate::Scheme for Scheme(rng, identity, &entries_refs, &self.strategy) - .is_ok() + batch::verify_same_signer::<_, V, _, _>(rng, identity, &entries_refs, strategy).is_ok() } fn is_attributable() -> bool { @@ -772,12 +757,13 @@ mod tests { Hasher, Sha256, }; use commonware_math::algebra::{CryptoGroup, Random}; + use commonware_parallel::Sequential; use commonware_utils::{quorum_from_slice, test_rng, NZU32}; use rand::{rngs::StdRng, SeedableRng}; const NAMESPACE: &[u8] = b"bls-threshold-signing-scheme"; - type Scheme = super::Scheme; + type Scheme = super::Scheme; type Signature = super::Signature; fn setup_signers(n: u32, seed: u64) -> (Vec>, Scheme) { @@ -808,7 +794,6 @@ mod tests { participants.keys().clone(), polynomial, shares[0].clone(), - Sequential, ); } @@ -832,7 +817,6 @@ mod tests { participants.keys().clone(), polynomial, shares[0].clone(), - Sequential, ); } @@ -852,12 +836,7 @@ mod tests { let mut rng = test_rng(); let participants = ed25519_participants(&mut rng, 5); let (polynomial, _) = deal_anonymous::(&mut rng, Default::default(), NZU32!(4)); - Scheme::::verifier( - NAMESPACE, - participants.keys().clone(), - polynomial, - Sequential, - ); + Scheme::::verifier(NAMESPACE, participants.keys().clone(), polynomial); } #[test] @@ -900,7 +879,8 @@ mod tests { Subject::Notarize { proposal: &proposal, }, - ¬arize_vote + ¬arize_vote, + &Sequential, )); let nullify_vote = scheme @@ -913,7 +893,8 @@ mod tests { Subject::Nullify { round: proposal.round, }, - &nullify_vote + &nullify_vote, + &Sequential, )); let finalize_vote = scheme @@ -926,7 +907,8 @@ mod tests { Subject::Finalize { proposal: &proposal, }, - &finalize_vote + &finalize_vote, + &Sequential, )); } @@ -969,7 +951,8 @@ mod tests { Subject::Notarize { proposal: &proposal, }, - &vote + &vote, + &Sequential, )); } @@ -1003,6 +986,7 @@ mod tests { proposal: &proposal, }, votes.clone(), + &Sequential, ); assert!(verification.invalid.is_empty()); assert_eq!(verification.verified.len(), quorum); @@ -1014,6 +998,7 @@ mod tests { proposal: &proposal, }, votes, + &Sequential, ); assert_eq!(verification.invalid, vec![Participant::new(999)]); assert_eq!(verification.verified.len(), quorum - 1); @@ -1042,7 +1027,7 @@ mod tests { }) .collect(); - assert!(schemes[0].assemble(votes).is_none()); + assert!(schemes[0].assemble(votes, &Sequential).is_none()); } #[test] @@ -1068,7 +1053,9 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(votes).expect("assemble certificate"); + let certificate = schemes[0] + .assemble(votes, &Sequential) + .expect("assemble certificate"); assert!(verifier.verify_certificate( &mut test_rng(), @@ -1076,6 +1063,7 @@ mod tests { proposal: &proposal, }, &certificate, + &Sequential, )); } @@ -1103,7 +1091,9 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(votes).expect("assemble certificate"); + let certificate = schemes[0] + .assemble(votes, &Sequential) + .expect("assemble certificate"); assert!(verifier.verify_certificate( &mut rng, @@ -1111,6 +1101,7 @@ mod tests { proposal: &proposal, }, &certificate, + &Sequential, )); let mut corrupted = certificate; @@ -1121,6 +1112,7 @@ mod tests { proposal: &proposal, }, &corrupted, + &Sequential, )); } @@ -1147,7 +1139,9 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(votes).expect("assemble certificate"); + let certificate = schemes[0] + .assemble(votes, &Sequential) + .expect("assemble certificate"); let encoded = certificate.encode(); let decoded = Signature::::decode_cfg(encoded, &()).expect("decode certificate"); @@ -1177,7 +1171,9 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(votes).expect("assemble certificate"); + let certificate = schemes[0] + .assemble(votes, &Sequential) + .expect("assemble certificate"); let seed = Seed::new(proposal.round, certificate.seed_signature); @@ -1209,7 +1205,9 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(votes).expect("assemble certificate"); + let certificate = schemes[0] + .assemble(votes, &Sequential) + .expect("assemble certificate"); let seed = Seed::new(proposal.round, certificate.seed_signature); @@ -1241,7 +1239,8 @@ mod tests { .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); - let notarization = Notarization::from_notarizes(&schemes[0], ¬arizes).unwrap(); + let notarization = + Notarization::from_notarizes(&schemes[0], ¬arizes, &Sequential).unwrap(); let finalizes: Vec<_> = schemes .iter() @@ -1249,7 +1248,8 @@ mod tests { .map(|scheme| Finalize::sign(scheme, proposal.clone()).unwrap()) .collect(); - let finalization = Finalization::from_finalizes(&schemes[0], &finalizes).unwrap(); + let finalization = + Finalization::from_finalizes(&schemes[0], &finalizes, &Sequential).unwrap(); assert_eq!(notarization.seed(), finalization.seed()); assert!(notarization.seed().verify(&schemes[0])); @@ -1308,10 +1308,12 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(votes).expect("assemble certificate"); + let certificate = schemes[0] + .assemble(votes, &Sequential) + .expect("assemble certificate"); let certificate_verifier = - Scheme::::certificate_verifier(NAMESPACE, *schemes[0].identity(), Sequential); + Scheme::::certificate_verifier(NAMESPACE, *schemes[0].identity()); assert!( certificate_verifier .sign(Subject::Finalize { @@ -1326,6 +1328,7 @@ mod tests { proposal: &proposal, }, &certificate, + &Sequential, )); } @@ -1338,7 +1341,7 @@ mod tests { fn certificate_verifier_panics_on_vote() { let (schemes, _) = setup_signers::(4, 37); let certificate_verifier = - Scheme::::certificate_verifier(NAMESPACE, *schemes[0].identity(), Sequential); + Scheme::::certificate_verifier(NAMESPACE, *schemes[0].identity()); let proposal = sample_proposal(Epoch::new(0), View::new(15), 8); let vote = schemes[1] .sign(Subject::Finalize { @@ -1352,6 +1355,7 @@ mod tests { proposal: &proposal, }, &vote, + &Sequential, ); } @@ -1384,7 +1388,9 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(votes).expect("assemble certificate"); + let certificate = schemes[0] + .assemble(votes, &Sequential) + .expect("assemble certificate"); let seed = Seed::::new(proposal.round, certificate.seed_signature); assert_eq!(seed.signature, certificate.seed_signature); @@ -1413,7 +1419,9 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(votes).expect("assemble certificate"); + let certificate = schemes[0] + .assemble(votes, &Sequential) + .expect("assemble certificate"); let mut encoded = certificate.encode(); let truncated = encoded.split_to(encoded.len() - 1); @@ -1482,7 +1490,9 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(votes).expect("assemble certificate"); + let certificate = schemes[0] + .assemble(votes, &Sequential) + .expect("assemble certificate"); assert!(verifier.verify_certificate::<_, Sha256Digest>( &mut rng, @@ -1490,6 +1500,7 @@ mod tests { round: proposal.round, }, &certificate, + &Sequential, )); let mut corrupted = certificate; @@ -1500,6 +1511,7 @@ mod tests { round: proposal.round, }, &corrupted, + &Sequential, )); } @@ -1534,7 +1546,8 @@ mod tests { .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); - let notarization = Notarization::from_notarizes(&schemes[0], ¬arizes).unwrap(); + let notarization = + Notarization::from_notarizes(&schemes[0], ¬arizes, &Sequential).unwrap(); // Decrypt using the seed let seed = notarization.seed(); @@ -1567,7 +1580,8 @@ mod tests { Subject::Notarize { proposal: &proposal, }, - &attestation + &attestation, + &Sequential, )); let random_scalar = Scalar::random(&mut rng); @@ -1592,7 +1606,8 @@ mod tests { Subject::Notarize { proposal: &proposal, }, - &forged_attestation + &forged_attestation, + &Sequential, ), "forged attestation should be rejected" ); @@ -1626,6 +1641,7 @@ mod tests { proposal: &proposal, }, vec![attestation1.clone(), attestation2.clone()], + &Sequential, ); assert!(verification.invalid.is_empty()); assert_eq!(verification.verified.len(), 2); @@ -1662,6 +1678,7 @@ mod tests { proposal: &proposal, }, vec![forged_attestation1, forged_attestation2], + &Sequential, ); assert!( !verification.invalid.is_empty(), @@ -1693,7 +1710,9 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(votes).expect("assemble certificate"); + let certificate = schemes[0] + .assemble(votes, &Sequential) + .expect("assemble certificate"); assert!(verifier.verify_certificate( &mut rng, @@ -1701,6 +1720,7 @@ mod tests { proposal: &proposal, }, &certificate, + &Sequential, )); let random_scalar = Scalar::random(&mut rng); @@ -1721,6 +1741,7 @@ mod tests { proposal: &proposal, }, &forged_certificate, + &Sequential, ), "forged certificate should be rejected" ); @@ -1762,8 +1783,12 @@ mod tests { }) .collect(); - let certificate1 = schemes[0].assemble(votes1).expect("assemble certificate1"); - let certificate2 = schemes[0].assemble(votes2).expect("assemble certificate2"); + let certificate1 = schemes[0] + .assemble(votes1, &Sequential) + .expect("assemble certificate1"); + let certificate2 = schemes[0] + .assemble(votes2, &Sequential) + .expect("assemble certificate2"); assert!(verifier.verify_certificates::<_, Sha256Digest, _>( &mut rng, @@ -1782,6 +1807,7 @@ mod tests { ), ] .into_iter(), + &Sequential, )); let random_scalar = Scalar::random(&mut rng); @@ -1821,6 +1847,7 @@ mod tests { ), ] .into_iter(), + &Sequential, ), "forged certificates should be rejected" ); diff --git a/consensus/src/simplex/scheme/reporter.rs b/consensus/src/simplex/scheme/reporter.rs index 36367ef35b..ab035c1291 100644 --- a/consensus/src/simplex/scheme/reporter.rs +++ b/consensus/src/simplex/scheme/reporter.rs @@ -23,6 +23,7 @@ use crate::{ Reporter, }; use commonware_cryptography::{certificate, Digest}; +use commonware_parallel::Strategy; use rand_core::CryptoRngCore; /// Reporter wrapper that filters and verifies activities based on scheme attributability. @@ -35,6 +36,7 @@ pub struct AttributableReporter< E: Clone + CryptoRngCore + Send + 'static, S: certificate::Scheme, D: Digest, + T: Strategy, R: Reporter>, > { /// RNG for certificate verification @@ -43,6 +45,8 @@ pub struct AttributableReporter< scheme: S, /// Inner reporter that receives filtered activities reporter: R, + /// Strategy for parallel operations. + strategy: T, /// Whether to always verify peer activities verify: bool, } @@ -51,15 +55,17 @@ impl< E: Clone + CryptoRngCore + Send + 'static, S: certificate::Scheme, D: Digest, + T: Strategy, R: Reporter>, - > AttributableReporter + > AttributableReporter { /// Creates a new `AttributableReporter` that wraps an inner reporter. - pub const fn new(rng: E, scheme: S, reporter: R, verify: bool) -> Self { + pub const fn new(rng: E, scheme: S, reporter: R, strategy: T, verify: bool) -> Self { Self { rng, scheme, reporter, + strategy, verify, } } @@ -69,14 +75,18 @@ impl< E: Clone + CryptoRngCore + Send + 'static, S: Scheme, D: Digest, + T: Strategy, R: Reporter>, - > Reporter for AttributableReporter + > Reporter for AttributableReporter { type Activity = Activity; async fn report(&mut self, activity: Self::Activity) { // Verify peer activities if verification is enabled - if self.verify && !activity.verified() && !activity.verify(&mut self.rng, &self.scheme) { + if self.verify + && !activity.verified() + && !activity.verify(&mut self.rng, &self.scheme, &self.strategy) + { // Drop unverified peer activity return; } @@ -185,7 +195,7 @@ mod tests { ); let mock = MockReporter::new(); - let mut reporter = AttributableReporter::new(rng, verifier, mock.clone(), true); + let mut reporter = AttributableReporter::new(rng, verifier, mock.clone(), Sequential, true); // Create an invalid activity (signed with wrong namespace scheme) let proposal = create_proposal(0, 1); @@ -228,6 +238,7 @@ mod tests { rng, verifier, mock.clone(), + Sequential, false, // Disable verification ); @@ -261,12 +272,12 @@ mod tests { } = bls12381_threshold::fixture::(&mut rng, NAMESPACE, 4); assert!( - !bls12381_threshold::Scheme::::is_attributable(), + !bls12381_threshold::Scheme::::is_attributable(), "BLS threshold must be non-attributable" ); let mock = MockReporter::new(); - let mut reporter = AttributableReporter::new(rng, verifier, mock.clone(), true); + let mut reporter = AttributableReporter::new(rng, verifier, mock.clone(), Sequential, true); // Create a certificate from multiple validators let proposal = create_proposal(0, 1); @@ -282,7 +293,7 @@ mod tests { .collect(); let certificate = schemes[0] - .assemble(votes) + .assemble(votes, &Sequential) .expect("failed to assemble certificate"); let notarization = Notarization { @@ -308,12 +319,12 @@ mod tests { } = bls12381_threshold::fixture::(&mut rng, NAMESPACE, 4); assert!( - !bls12381_threshold::Scheme::::is_attributable(), + !bls12381_threshold::Scheme::::is_attributable(), "BLS threshold must be non-attributable" ); let mock = MockReporter::new(); - let mut reporter = AttributableReporter::new(rng, verifier, mock.clone(), true); + let mut reporter = AttributableReporter::new(rng, verifier, mock.clone(), Sequential, true); // Create peer activity (from validator 1) let proposal = create_proposal(0, 1); @@ -349,7 +360,7 @@ mod tests { ); let mock = MockReporter::new(); - let mut reporter = AttributableReporter::new(rng, verifier, mock.clone(), true); + let mut reporter = AttributableReporter::new(rng, verifier, mock.clone(), Sequential, true); // Create a peer activity (from validator 1) let proposal = create_proposal(0, 1); diff --git a/consensus/src/simplex/types.rs b/consensus/src/simplex/types.rs index 5885aad5d5..9b7fb18ae0 100644 --- a/consensus/src/simplex/types.rs +++ b/consensus/src/simplex/types.rs @@ -11,6 +11,7 @@ use commonware_cryptography::{ certificate::{Attestation, Scheme}, Digest, PublicKey, }; +use commonware_parallel::Strategy; use rand_core::CryptoRngCore; use std::{collections::HashSet, fmt::Debug, hash::Hash}; @@ -786,7 +787,7 @@ impl Notarize { /// Verifies the notarize vote against the provided signing scheme. /// /// This ensures that the notarize signature is valid for the claimed proposal. - pub fn verify(&self, rng: &mut R, scheme: &S) -> bool + pub fn verify(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool where R: CryptoRngCore, S: scheme::Scheme, @@ -797,6 +798,7 @@ impl Notarize { proposal: &self.proposal, }, &self.attestation, + strategy, ) } @@ -901,10 +903,11 @@ impl Notarization { pub fn from_notarizes<'a>( scheme: &S, notarizes: impl IntoIterator>, + strategy: &impl Strategy, ) -> Option { let mut iter = notarizes.into_iter().peekable(); let proposal = iter.peek()?.proposal.clone(); - let certificate = scheme.assemble(iter.map(|n| n.attestation.clone()))?; + let certificate = scheme.assemble(iter.map(|n| n.attestation.clone()), strategy)?; Some(Self { proposal, @@ -915,7 +918,12 @@ impl Notarization { /// Verifies the notarization certificate against the provided signing scheme. /// /// This ensures that the certificate is valid for the claimed proposal. - pub fn verify(&self, rng: &mut R, scheme: &S) -> bool + pub fn verify( + &self, + rng: &mut R, + scheme: &S, + strategy: &impl Strategy, + ) -> bool where S: scheme::Scheme, { @@ -925,6 +933,7 @@ impl Notarization { proposal: &self.proposal, }, &self.certificate, + strategy, ) } @@ -1043,7 +1052,7 @@ impl Nullify { /// Verifies the nullify vote against the provided signing scheme. /// /// This ensures that the nullify signature is valid for the given round. - pub fn verify(&self, rng: &mut R, scheme: &S) -> bool + pub fn verify(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool where R: CryptoRngCore, S: scheme::Scheme, @@ -1052,6 +1061,7 @@ impl Nullify { rng, Subject::Nullify { round: self.round }, &self.attestation, + strategy, ) } @@ -1130,10 +1140,11 @@ impl Nullification { pub fn from_nullifies<'a>( scheme: &S, nullifies: impl IntoIterator>, + strategy: &impl Strategy, ) -> Option { let mut iter = nullifies.into_iter().peekable(); let round = iter.peek()?.round; - let certificate = scheme.assemble(iter.map(|n| n.attestation.clone()))?; + let certificate = scheme.assemble(iter.map(|n| n.attestation.clone()), strategy)?; Some(Self { round, certificate }) } @@ -1141,7 +1152,12 @@ impl Nullification { /// Verifies the nullification certificate against the provided signing scheme. /// /// This ensures that the certificate is valid for the claimed round. - pub fn verify(&self, rng: &mut R, scheme: &S) -> bool + pub fn verify( + &self, + rng: &mut R, + scheme: &S, + strategy: &impl Strategy, + ) -> bool where S: scheme::Scheme, { @@ -1149,6 +1165,7 @@ impl Nullification { rng, Subject::Nullify { round: self.round }, &self.certificate, + strategy, ) } @@ -1251,7 +1268,7 @@ impl Finalize { /// Verifies the finalize vote against the provided signing scheme. /// /// This ensures that the finalize signature is valid for the claimed proposal. - pub fn verify(&self, rng: &mut R, scheme: &S) -> bool + pub fn verify(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool where R: CryptoRngCore, S: scheme::Scheme, @@ -1262,6 +1279,7 @@ impl Finalize { proposal: &self.proposal, }, &self.attestation, + strategy, ) } @@ -1366,10 +1384,11 @@ impl Finalization { pub fn from_finalizes<'a>( scheme: &S, finalizes: impl IntoIterator>, + strategy: &impl Strategy, ) -> Option { let mut iter = finalizes.into_iter().peekable(); let proposal = iter.peek()?.proposal.clone(); - let certificate = scheme.assemble(iter.map(|f| f.attestation.clone()))?; + let certificate = scheme.assemble(iter.map(|f| f.attestation.clone()), strategy)?; Some(Self { proposal, @@ -1380,7 +1399,12 @@ impl Finalization { /// Verifies the finalization certificate against the provided signing scheme. /// /// This ensures that the certificate is valid for the claimed proposal. - pub fn verify(&self, rng: &mut R, scheme: &S) -> bool + pub fn verify( + &self, + rng: &mut R, + scheme: &S, + strategy: &impl Strategy, + ) -> bool where S: scheme::Scheme, { @@ -1390,6 +1414,7 @@ impl Finalization { proposal: &self.proposal, }, &self.certificate, + strategy, ) } @@ -1649,7 +1674,12 @@ impl Response { } /// Verifies the certificates contained in this response against the signing scheme. - pub fn verify(&self, rng: &mut R, scheme: &S) -> bool + pub fn verify( + &self, + rng: &mut R, + scheme: &S, + strategy: &impl Strategy, + ) -> bool where S: scheme::Scheme, { @@ -1674,7 +1704,7 @@ impl Response { (context, &nullification.certificate) }); - scheme.verify_certificates::<_, D, _>(rng, notarizations.chain(nullifications)) + scheme.verify_certificates::<_, D, _>(rng, notarizations.chain(nullifications), strategy) } } @@ -1883,21 +1913,26 @@ impl Activity { /// This method **always** performs verification regardless of whether the activity has been /// previously verified. Callers can use [`Activity::verified`] to check if verification is /// necessary before calling this method. - pub fn verify(&self, rng: &mut R, scheme: &S) -> bool + pub fn verify( + &self, + rng: &mut R, + scheme: &S, + strategy: &impl Strategy, + ) -> bool where S: scheme::Scheme, { match self { - Self::Notarize(n) => n.verify(rng, scheme), - Self::Notarization(n) => n.verify(rng, scheme), - Self::Certification(n) => n.verify(rng, scheme), - Self::Nullify(n) => n.verify(rng, scheme), - Self::Nullification(n) => n.verify(rng, scheme), - Self::Finalize(f) => f.verify(rng, scheme), - Self::Finalization(f) => f.verify(rng, scheme), - Self::ConflictingNotarize(c) => c.verify(rng, scheme), - Self::ConflictingFinalize(c) => c.verify(rng, scheme), - Self::NullifyFinalize(c) => c.verify(rng, scheme), + Self::Notarize(n) => n.verify(rng, scheme, strategy), + Self::Notarization(n) => n.verify(rng, scheme, strategy), + Self::Certification(n) => n.verify(rng, scheme, strategy), + Self::Nullify(n) => n.verify(rng, scheme, strategy), + Self::Nullification(n) => n.verify(rng, scheme, strategy), + Self::Finalize(f) => f.verify(rng, scheme, strategy), + Self::Finalization(f) => f.verify(rng, scheme, strategy), + Self::ConflictingNotarize(c) => c.verify(rng, scheme, strategy), + Self::ConflictingFinalize(c) => c.verify(rng, scheme, strategy), + Self::NullifyFinalize(c) => c.verify(rng, scheme, strategy), } } } @@ -2147,12 +2182,13 @@ impl ConflictingNotarize { } /// Verifies that both conflicting signatures are valid, proving Byzantine behavior. - pub fn verify(&self, rng: &mut R, scheme: &S) -> bool + pub fn verify(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool where R: CryptoRngCore, S: scheme::Scheme, { - self.notarize_1.verify(rng, scheme) && self.notarize_2.verify(rng, scheme) + self.notarize_1.verify(rng, scheme, strategy) + && self.notarize_2.verify(rng, scheme, strategy) } } @@ -2262,12 +2298,13 @@ impl ConflictingFinalize { } /// Verifies that both conflicting signatures are valid, proving Byzantine behavior. - pub fn verify(&self, rng: &mut R, scheme: &S) -> bool + pub fn verify(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool where R: CryptoRngCore, S: scheme::Scheme, { - self.finalize_1.verify(rng, scheme) && self.finalize_2.verify(rng, scheme) + self.finalize_1.verify(rng, scheme, strategy) + && self.finalize_2.verify(rng, scheme, strategy) } } @@ -2375,12 +2412,12 @@ impl NullifyFinalize { } /// Verifies that both the nullify and finalize signatures are valid, proving Byzantine behavior. - pub fn verify(&self, rng: &mut R, scheme: &S) -> bool + pub fn verify(&self, rng: &mut R, scheme: &S, strategy: &impl Strategy) -> bool where R: CryptoRngCore, S: scheme::Scheme, { - self.nullify.verify(rng, scheme) && self.finalize.verify(rng, scheme) + self.nullify.verify(rng, scheme, strategy) && self.finalize.verify(rng, scheme, strategy) } } @@ -2458,6 +2495,7 @@ mod tests { certificate::mocks::Fixture, sha256::Digest as Sha256, }; + use commonware_parallel::Sequential; use commonware_utils::{quorum, quorum_from_slice, test_rng}; use rand::{rngs::StdRng, SeedableRng}; @@ -2512,7 +2550,7 @@ mod tests { let decoded = Notarize::decode(encoded).unwrap(); assert_eq!(notarize, decoded); - assert!(decoded.verify(&mut rng, &fixture.schemes[0])); + assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential)); } #[test] @@ -2542,12 +2580,13 @@ mod tests { .iter() .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); - let notarization = Notarization::from_notarizes(&fixture.schemes[0], ¬arizes).unwrap(); + let notarization = + Notarization::from_notarizes(&fixture.schemes[0], ¬arizes, &Sequential).unwrap(); let encoded = notarization.encode(); let cfg = fixture.schemes[0].certificate_codec_config(); let decoded = Notarization::decode_cfg(encoded, &cfg).unwrap(); assert_eq!(notarization, decoded); - assert!(decoded.verify(&mut rng, &fixture.schemes[0])); + assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential)); } #[test] @@ -2572,7 +2611,7 @@ mod tests { let encoded = nullify.encode(); let decoded = Nullify::decode(encoded).unwrap(); assert_eq!(nullify, decoded); - assert!(decoded.verify::<_, Sha256>(&mut rng, &fixture.schemes[0])); + assert!(decoded.verify::<_, Sha256>(&mut rng, &fixture.schemes[0], &Sequential)); } #[test] @@ -2598,12 +2637,13 @@ mod tests { .iter() .map(|scheme| Nullify::sign::(scheme, round).unwrap()) .collect(); - let nullification = Nullification::from_nullifies(&fixture.schemes[0], &nullifies).unwrap(); + let nullification = + Nullification::from_nullifies(&fixture.schemes[0], &nullifies, &Sequential).unwrap(); let encoded = nullification.encode(); let cfg = fixture.schemes[0].certificate_codec_config(); let decoded = Nullification::decode_cfg(encoded, &cfg).unwrap(); assert_eq!(nullification, decoded); - assert!(decoded.verify::<_, Sha256>(&mut rng, &fixture.schemes[0])); + assert!(decoded.verify::<_, Sha256>(&mut rng, &fixture.schemes[0], &Sequential)); } #[test] @@ -2629,7 +2669,7 @@ mod tests { let encoded = finalize.encode(); let decoded = Finalize::decode(encoded).unwrap(); assert_eq!(finalize, decoded); - assert!(decoded.verify(&mut rng, &fixture.schemes[0])); + assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential)); } #[test] @@ -2656,12 +2696,13 @@ mod tests { .iter() .map(|scheme| Finalize::sign(scheme, proposal.clone()).unwrap()) .collect(); - let finalization = Finalization::from_finalizes(&fixture.schemes[0], &finalizes).unwrap(); + let finalization = + Finalization::from_finalizes(&fixture.schemes[0], &finalizes, &Sequential).unwrap(); let encoded = finalization.encode(); let cfg = fixture.schemes[0].certificate_codec_config(); let decoded = Finalization::decode_cfg(encoded, &cfg).unwrap(); assert_eq!(finalization, decoded); - assert!(decoded.verify(&mut rng, &fixture.schemes[0])); + assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential)); } #[test] @@ -2700,14 +2741,16 @@ mod tests { .iter() .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); - let notarization = Notarization::from_notarizes(&fixture.schemes[0], ¬arizes).unwrap(); + let notarization = + Notarization::from_notarizes(&fixture.schemes[0], ¬arizes, &Sequential).unwrap(); let nullifies: Vec<_> = fixture .schemes .iter() .map(|scheme| Nullify::sign::(scheme, round).unwrap()) .collect(); - let nullification = Nullification::from_nullifies(&fixture.schemes[0], &nullifies).unwrap(); + let nullification = + Nullification::from_nullifies(&fixture.schemes[0], &nullifies, &Sequential).unwrap(); let response = Response::::new(1, vec![notarization], vec![nullification]); let encoded_response = Backfiller::::Response(response.clone()).encode(); @@ -2753,14 +2796,16 @@ mod tests { .iter() .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); - let notarization = Notarization::from_notarizes(&fixture.schemes[0], ¬arizes).unwrap(); + let notarization = + Notarization::from_notarizes(&fixture.schemes[0], ¬arizes, &Sequential).unwrap(); let nullifies: Vec<_> = fixture .schemes .iter() .map(|scheme| Nullify::sign::(scheme, round).unwrap()) .collect(); - let nullification = Nullification::from_nullifies(&fixture.schemes[0], &nullifies).unwrap(); + let nullification = + Nullification::from_nullifies(&fixture.schemes[0], &nullifies, &Sequential).unwrap(); let response = Response::::new(1, vec![notarization], vec![nullification]); let cfg = fixture.schemes[0].certificate_codec_config(); @@ -2770,13 +2815,13 @@ mod tests { assert_eq!(response.notarizations.len(), decoded.notarizations.len()); assert_eq!(response.nullifications.len(), decoded.nullifications.len()); - assert!(decoded.verify(&mut rng, &fixture.schemes[0])); + assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential)); decoded.nullifications[0].round = Round::new( decoded.nullifications[0].round.epoch(), decoded.nullifications[0].round.view().next(), ); - assert!(!decoded.verify(&mut rng, &fixture.schemes[0])); + assert!(!decoded.verify(&mut rng, &fixture.schemes[0], &Sequential)); } #[test] @@ -2814,7 +2859,7 @@ mod tests { let decoded = ConflictingNotarize::::decode(encoded).unwrap(); assert_eq!(conflicting, decoded); - assert!(decoded.verify(&mut rng, &fixture.schemes[0])); + assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential)); } #[test] @@ -2852,7 +2897,7 @@ mod tests { let decoded = ConflictingFinalize::::decode(encoded).unwrap(); assert_eq!(conflicting, decoded); - assert!(decoded.verify(&mut rng, &fixture.schemes[0])); + assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential)); } #[test] @@ -2882,7 +2927,7 @@ mod tests { let decoded = NullifyFinalize::::decode(encoded).unwrap(); assert_eq!(conflict, decoded); - assert!(decoded.verify(&mut rng, &fixture.schemes[0])); + assert!(decoded.verify(&mut rng, &fixture.schemes[0], &Sequential)); } #[test] @@ -2908,8 +2953,8 @@ mod tests { let proposal = Proposal::new(round, View::new(5), sample_digest(1)); let notarize = Notarize::sign(&fixture.schemes[0], proposal).unwrap(); - assert!(notarize.verify(&mut rng, &fixture.schemes[0])); - assert!(!notarize.verify(&mut rng, &wrong_fixture.schemes[0])); + assert!(notarize.verify(&mut rng, &fixture.schemes[0], &Sequential)); + assert!(!notarize.verify(&mut rng, &wrong_fixture.schemes[0], &Sequential)); } #[test] @@ -2934,8 +2979,8 @@ mod tests { let proposal = Proposal::new(round, View::new(5), sample_digest(2)); let notarize = Notarize::sign(&fixture.schemes[0], proposal).unwrap(); - assert!(notarize.verify(&mut rng, &fixture.schemes[0])); - assert!(!notarize.verify(&mut rng, &wrong_fixture.verifier)); + assert!(notarize.verify(&mut rng, &fixture.schemes[0], &Sequential)); + assert!(!notarize.verify(&mut rng, &wrong_fixture.verifier, &Sequential)); } #[test] @@ -2966,10 +3011,11 @@ mod tests { .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); - let notarization = Notarization::from_notarizes(&fixture.schemes[0], ¬arizes) - .expect("quorum notarization"); - assert!(notarization.verify(&mut rng, &fixture.schemes[0])); - assert!(!notarization.verify(&mut rng, &wrong_fixture.verifier)); + let notarization = + Notarization::from_notarizes(&fixture.schemes[0], ¬arizes, &Sequential) + .expect("quorum notarization"); + assert!(notarization.verify(&mut rng, &fixture.schemes[0], &Sequential)); + assert!(!notarization.verify(&mut rng, &wrong_fixture.verifier, &Sequential)); } #[test] @@ -3001,11 +3047,12 @@ mod tests { .map(|scheme| Notarize::sign(scheme, proposal.clone()).unwrap()) .collect(); - let notarization = Notarization::from_notarizes(&fixture.schemes[0], ¬arizes) - .expect("quorum notarization"); - assert!(notarization.verify(&mut rng, &fixture.schemes[0])); + let notarization = + Notarization::from_notarizes(&fixture.schemes[0], ¬arizes, &Sequential) + .expect("quorum notarization"); + assert!(notarization.verify(&mut rng, &fixture.schemes[0], &Sequential)); - assert!(!notarization.verify(&mut rng, &wrong_fixture.schemes[0])); + assert!(!notarization.verify(&mut rng, &wrong_fixture.schemes[0], &Sequential)); } #[test] @@ -3037,7 +3084,7 @@ mod tests { .collect(); assert!( - Notarization::from_notarizes(&fixture.schemes[0], ¬arizes).is_none(), + Notarization::from_notarizes(&fixture.schemes[0], ¬arizes, &Sequential).is_none(), "insufficient votes should not form a notarization" ); } @@ -3070,9 +3117,9 @@ mod tests { let notarize2 = Notarize::sign(&fixture.schemes[0], proposal2).unwrap(); let conflict = ConflictingNotarize::new(notarize1, notarize2); - assert!(conflict.verify(&mut rng, &fixture.schemes[0])); - assert!(!conflict.verify(&mut rng, &wrong_ns_fixture.schemes[0])); - assert!(!conflict.verify(&mut rng, &wrong_scheme_fixture.verifier)); + assert!(conflict.verify(&mut rng, &fixture.schemes[0], &Sequential)); + assert!(!conflict.verify(&mut rng, &wrong_ns_fixture.schemes[0], &Sequential)); + assert!(!conflict.verify(&mut rng, &wrong_scheme_fixture.verifier, &Sequential)); } #[test] @@ -3102,9 +3149,9 @@ mod tests { let finalize = Finalize::sign(&fixture.schemes[0], proposal).unwrap(); let conflict = NullifyFinalize::new(nullify, finalize); - assert!(conflict.verify(&mut rng, &fixture.schemes[0])); - assert!(!conflict.verify(&mut rng, &wrong_ns_fixture.schemes[0])); - assert!(!conflict.verify(&mut rng, &wrong_scheme_fixture.verifier)); + assert!(conflict.verify(&mut rng, &fixture.schemes[0], &Sequential)); + assert!(!conflict.verify(&mut rng, &wrong_ns_fixture.schemes[0], &Sequential)); + assert!(!conflict.verify(&mut rng, &wrong_scheme_fixture.verifier, &Sequential)); } #[test] @@ -3135,10 +3182,11 @@ mod tests { .map(|scheme| Finalize::sign(scheme, proposal.clone()).unwrap()) .collect(); - let finalization = Finalization::from_finalizes(&fixture.schemes[0], &finalizes) - .expect("quorum finalization"); - assert!(finalization.verify(&mut rng, &fixture.schemes[0])); - assert!(!finalization.verify(&mut rng, &wrong_fixture.verifier)); + let finalization = + Finalization::from_finalizes(&fixture.schemes[0], &finalizes, &Sequential) + .expect("quorum finalization"); + assert!(finalization.verify(&mut rng, &fixture.schemes[0], &Sequential)); + assert!(!finalization.verify(&mut rng, &wrong_fixture.verifier, &Sequential)); } #[test] @@ -3239,9 +3287,7 @@ mod tests { use crate::simplex::scheme::bls12381_threshold; use commonware_codec::conformance::CodecConformance; use commonware_cryptography::{ed25519::PublicKey, sha256::Digest as Sha256Digest}; - use commonware_parallel::Sequential; - - type Scheme = bls12381_threshold::Scheme; + type Scheme = bls12381_threshold::Scheme; commonware_conformance::conformance_tests! { CodecConformance>, diff --git a/cryptography/fuzz/fuzz_targets/bls12381_threshold_operations.rs b/cryptography/fuzz/fuzz_targets/bls12381_threshold_operations.rs index 5bc87dd241..16a7746fef 100644 --- a/cryptography/fuzz/fuzz_targets/bls12381_threshold_operations.rs +++ b/cryptography/fuzz/fuzz_targets/bls12381_threshold_operations.rs @@ -381,11 +381,11 @@ fn fuzz(op: FuzzOperation) { } FuzzOperation::RecoverMinPk { sharing, partials } => { - let _ = threshold::recover::(&sharing, &partials); + let _ = threshold::recover::(&sharing, &partials, &Sequential); } FuzzOperation::RecoverMinSig { sharing, partials } => { - let _ = threshold::recover::(&sharing, &partials); + let _ = threshold::recover::(&sharing, &partials, &Sequential); } FuzzOperation::RecoverMultipleMinPk { diff --git a/cryptography/src/bls12381/benches/threshold_recover.rs b/cryptography/src/bls12381/benches/threshold_recover.rs index 292aa90f45..203f9ffe9b 100644 --- a/cryptography/src/bls12381/benches/threshold_recover.rs +++ b/cryptography/src/bls12381/benches/threshold_recover.rs @@ -6,6 +6,7 @@ use commonware_cryptography::{ ed25519::PrivateKey, Signer, }; +use commonware_parallel::Sequential; use commonware_utils::{quorum, TryCollect}; use criterion::{criterion_group, BatchSize, Criterion}; use rand::{rngs::StdRng, SeedableRng}; @@ -41,9 +42,10 @@ fn benchmark_threshold_recover(c: &mut Criterion) { }, |(public, partials)| { black_box( - primitives::ops::threshold::recover::( + primitives::ops::threshold::recover::( public.public(), &partials, + &Sequential, ) .unwrap(), ); diff --git a/cryptography/src/bls12381/certificate/multisig/mod.rs b/cryptography/src/bls12381/certificate/multisig/mod.rs index a1b84099ef..0ff992213b 100644 --- a/cryptography/src/bls12381/certificate/multisig/mod.rs +++ b/cryptography/src/bls12381/certificate/multisig/mod.rs @@ -472,6 +472,7 @@ mod macros { _rng: &mut R, subject: Self::Subject<'_, D>, attestation: &$crate::certificate::Attestation, + _strategy: &impl commonware_parallel::Strategy, ) -> bool where R: rand_core::CryptoRngCore, @@ -486,6 +487,7 @@ mod macros { rng: &mut R, subject: Self::Subject<'_, D>, attestations: I, + _strategy: &impl commonware_parallel::Strategy, ) -> $crate::certificate::Verification where R: rand_core::CryptoRngCore, @@ -496,7 +498,11 @@ mod macros { .verify_attestations::<_, _, D, _>(rng, subject, attestations) } - fn assemble(&self, attestations: I) -> Option + fn assemble( + &self, + attestations: I, + _strategy: &impl commonware_parallel::Strategy, + ) -> Option where I: IntoIterator>, { @@ -511,12 +517,18 @@ mod macros { rng: &mut R, subject: Self::Subject<'_, D>, certificate: &Self::Certificate, + _strategy: &impl commonware_parallel::Strategy, ) -> bool { self.generic .verify_certificate::(rng, subject, certificate) } - fn verify_certificates<'a, R, D, I>(&self, rng: &mut R, certificates: I) -> bool + fn verify_certificates<'a, R, D, I>( + &self, + rng: &mut R, + certificates: I, + _strategy: &impl commonware_parallel::Strategy, + ) -> bool where R: rand_core::CryptoRngCore, D: $crate::Digest, @@ -566,6 +578,7 @@ mod tests { use bytes::Bytes; use commonware_codec::{Decode, Encode}; use commonware_math::algebra::{CryptoGroup, Random}; + use commonware_parallel::Sequential; use commonware_utils::{ordered::BiMap, quorum, test_rng, Participant, TryCollect}; const NAMESPACE: &[u8] = b"test-bls12381-multisig"; @@ -654,7 +667,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &attestation + &attestation, + &Sequential, )); } @@ -702,6 +716,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, attestations.clone(), + &Sequential, ); assert!(result.invalid.is_empty()); assert_eq!(result.verified.len(), quorum); @@ -715,6 +730,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, attestations_corrupted, + &Sequential, ); assert_eq!(result.invalid, vec![Participant::new(999)]); assert_eq!(result.verified.len(), quorum - 1); @@ -728,6 +744,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, attestations_corrupted, + &Sequential, ); assert_eq!(result.invalid.len(), 1); assert_eq!(result.verified.len(), quorum - 1); @@ -755,7 +772,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); assert_eq!(certificate.signers.count(), quorum); } @@ -792,7 +809,7 @@ mod tests { .unwrap(), ]; - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Verify signers are sorted by signer index let expected: Vec<_> = indexed.iter().map(|(idx, _)| *idx).collect(); @@ -821,14 +838,15 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); assert!(verifier.verify_certificate::<_, Sha256Digest>( &mut rng, TestSubject { message: Bytes::from_static(MESSAGE) }, - &certificate + &certificate, + &Sequential, )); } @@ -854,7 +872,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Valid certificate passes assert!(verifier.verify_certificate::<_, Sha256Digest>( @@ -862,7 +880,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); // Corrupted certificate fails @@ -873,7 +892,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &corrupted + &corrupted, + &Sequential, )); } @@ -899,7 +919,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); let encoded = certificate.encode(); let decoded = Certificate::::decode_cfg(encoded, &schemes.len()).expect("decode certificate"); @@ -928,7 +948,7 @@ mod tests { }) .collect(); - assert!(schemes[0].assemble(attestations).is_none()); + assert!(schemes[0].assemble(attestations, &Sequential).is_none()); } #[test] @@ -956,7 +976,7 @@ mod tests { // Corrupt signer index to be out of range attestations[0].signer = Participant::new(999); - assert!(schemes[0].assemble(attestations).is_none()); + assert!(schemes[0].assemble(attestations, &Sequential).is_none()); } #[test] @@ -981,7 +1001,7 @@ mod tests { }) .collect(); - let mut certificate = schemes[0].assemble(attestations).unwrap(); + let mut certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Artificially truncate to below quorum let mut signers: Vec = certificate.signers.iter().collect(); @@ -993,7 +1013,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); } @@ -1019,7 +1040,7 @@ mod tests { }) .collect(); - let mut certificate = schemes[0].assemble(attestations).unwrap(); + let mut certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Make the signers bitmap size larger than participants let signers: Vec = certificate.signers.iter().collect(); @@ -1030,7 +1051,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); } @@ -1062,7 +1084,7 @@ mod tests { .unwrap() }) .collect(); - certificates.push(schemes[0].assemble(attestations).unwrap()); + certificates.push(schemes[0].assemble(attestations, &Sequential).unwrap()); } let certs_iter = messages.iter().zip(&certificates).map(|(msg, cert)| { @@ -1074,7 +1096,11 @@ mod tests { ) }); - assert!(verifier.verify_certificates::<_, Sha256Digest, _>(&mut rng, certs_iter)); + assert!(verifier.verify_certificates::<_, Sha256Digest, _>( + &mut rng, + certs_iter, + &Sequential + )); } #[test] @@ -1105,7 +1131,7 @@ mod tests { .unwrap() }) .collect(); - certificates.push(schemes[0].assemble(attestations).unwrap()); + certificates.push(schemes[0].assemble(attestations, &Sequential).unwrap()); } // Corrupt second certificate @@ -1120,7 +1146,11 @@ mod tests { ) }); - assert!(!verifier.verify_certificates::<_, Sha256Digest, _>(&mut rng, certs_iter)); + assert!(!verifier.verify_certificates::<_, Sha256Digest, _>( + &mut rng, + certs_iter, + &Sequential + )); } #[test] @@ -1148,7 +1178,7 @@ mod tests { attestations.push(attestations.last().unwrap().clone()); // This should panic due to duplicate signer - schemes[0].assemble(attestations); + schemes[0].assemble(attestations, &Sequential); } #[test] @@ -1211,7 +1241,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Well-formed certificate decodes successfully let encoded = certificate.encode(); @@ -1258,7 +1288,7 @@ mod tests { }) .collect(); - let mut certificate = schemes[0].assemble(attestations).unwrap(); + let mut certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Add an unknown signer (out of range) let mut signers: Vec = certificate.signers.iter().collect(); @@ -1271,6 +1301,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, &certificate, + &Sequential, )); } @@ -1301,6 +1332,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, vec![attestation1.clone(), attestation2.clone()], + &Sequential, ); assert!(verification.invalid.is_empty()); assert_eq!(verification.verified.len(), 2); @@ -1326,6 +1358,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, vec![forged_attestation1, forged_attestation2], + &Sequential, ); assert!( !verification.invalid.is_empty(), diff --git a/cryptography/src/bls12381/certificate/threshold/mod.rs b/cryptography/src/bls12381/certificate/threshold/mod.rs index 6ddd507715..21aa191f66 100644 --- a/cryptography/src/bls12381/certificate/threshold/mod.rs +++ b/cryptography/src/bls12381/certificate/threshold/mod.rs @@ -23,7 +23,7 @@ use crate::{ }; #[cfg(not(feature = "std"))] use alloc::{collections::BTreeSet, vec::Vec}; -use commonware_parallel::Sequential; +use commonware_parallel::Strategy; use commonware_utils::{ordered::Set, Participant}; use core::fmt::Debug; use rand_core::CryptoRngCore; @@ -294,10 +294,11 @@ impl Generic { } /// Assembles a certificate from a collection of attestations. - pub fn assemble(&self, attestations: I) -> Option + pub fn assemble(&self, attestations: I, strategy: &T) -> Option where S: Scheme, I: IntoIterator>, + T: Strategy, { let partials: Vec<_> = attestations .into_iter() @@ -312,7 +313,7 @@ impl Generic { return None; } - threshold::recover::(quorum, partials.iter()).ok() + threshold::recover::(quorum, partials.iter(), strategy).ok() } /// Verifies a certificate. @@ -338,13 +339,19 @@ impl Generic { } /// Verifies multiple certificates in a batch. - pub fn verify_certificates<'a, S, R, D, I>(&self, rng: &mut R, certificates: I) -> bool + pub fn verify_certificates<'a, S, R, D, I, T>( + &self, + rng: &mut R, + certificates: I, + strategy: &T, + ) -> bool where S: Scheme, S::Subject<'a, D>: Subject, R: CryptoRngCore, D: Digest, I: Iterator, &'a V::Signature)>, + T: Strategy, { let mut entries: Vec<_> = Vec::new(); @@ -363,7 +370,7 @@ impl Generic { .map(|(ns, msg, sig)| (ns.as_ref(), msg.as_ref(), *sig)) .collect(); - batch::verify_same_signer::<_, V, _, _>(rng, self.identity(), &entries_refs, &Sequential) + batch::verify_same_signer::<_, V, _, _>(rng, self.identity(), &entries_refs, strategy) .is_ok() } @@ -528,6 +535,7 @@ mod macros { _rng: &mut R, subject: Self::Subject<'_, D>, attestation: &$crate::certificate::Attestation, + _strategy: &impl commonware_parallel::Strategy, ) -> bool where R: rand_core::CryptoRngCore, @@ -542,6 +550,7 @@ mod macros { rng: &mut R, subject: Self::Subject<'_, D>, attestations: I, + _strategy: &impl commonware_parallel::Strategy, ) -> $crate::certificate::Verification where R: rand_core::CryptoRngCore, @@ -552,11 +561,15 @@ mod macros { .verify_attestations::<_, _, D, _>(rng, subject, attestations) } - fn assemble(&self, attestations: I) -> Option + fn assemble( + &self, + attestations: I, + strategy: &impl commonware_parallel::Strategy, + ) -> Option where I: IntoIterator>, { - self.generic.assemble(attestations) + self.generic.assemble(attestations, strategy) } fn verify_certificate( @@ -564,19 +577,25 @@ mod macros { rng: &mut R, subject: Self::Subject<'_, D>, certificate: &Self::Certificate, + _strategy: &impl commonware_parallel::Strategy, ) -> bool { self.generic .verify_certificate::(rng, subject, certificate) } - fn verify_certificates<'a, R, D, I>(&self, rng: &mut R, certificates: I) -> bool + fn verify_certificates<'a, R, D, I>( + &self, + rng: &mut R, + certificates: I, + strategy: &impl commonware_parallel::Strategy, + ) -> bool where R: rand::Rng + rand::CryptoRng, D: $crate::Digest, I: Iterator, &'a Self::Certificate)>, { self.generic - .verify_certificates::(rng, certificates) + .verify_certificates::(rng, certificates, strategy) } fn is_attributable() -> bool { @@ -622,6 +641,7 @@ mod tests { use bytes::Bytes; use commonware_codec::{DecodeExt, Encode}; use commonware_math::algebra::{Additive, Random}; + use commonware_parallel::Sequential; use commonware_utils::{ordered::Set, quorum, test_rng, TryCollect, NZU32}; const NAMESPACE: &[u8] = b"test-bls12381-threshold"; @@ -698,7 +718,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &attestation + &attestation, + &Sequential, )); } @@ -746,6 +767,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, attestations.clone(), + &Sequential, ); assert!(result.invalid.is_empty()); assert_eq!(result.verified.len(), quorum); @@ -759,6 +781,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, attestations_corrupted, + &Sequential, ); assert_eq!(result.invalid, vec![Participant::new(999)]); assert_eq!(result.verified.len(), quorum - 1); @@ -772,6 +795,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, attestations_corrupted, + &Sequential, ); assert_eq!(result.invalid.len(), 1); assert_eq!(result.verified.len(), quorum - 1); @@ -799,7 +823,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Verify the assembled certificate assert!(verifier.verify_certificate::<_, Sha256Digest>( @@ -807,7 +831,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); } @@ -833,14 +858,15 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); assert!(verifier.verify_certificate::<_, Sha256Digest>( &mut rng, TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); } @@ -866,7 +892,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Valid certificate passes assert!(verifier.verify_certificate::<_, Sha256Digest>( @@ -874,7 +900,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); // Corrupted certificate fails @@ -884,7 +911,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &corrupted + &corrupted, + &Sequential, )); } @@ -910,7 +938,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); let encoded = certificate.encode(); let decoded = V::Signature::decode(encoded).expect("decode certificate"); assert_eq!(decoded, certificate); @@ -938,7 +966,7 @@ mod tests { }) .collect(); - assert!(schemes[0].assemble(attestations).is_none()); + assert!(schemes[0].assemble(attestations, &Sequential).is_none()); } #[test] @@ -970,7 +998,7 @@ mod tests { .unwrap() }) .collect(); - certificates.push(schemes[0].assemble(attestations).unwrap()); + certificates.push(schemes[0].assemble(attestations, &Sequential).unwrap()); } let certs_iter = messages.iter().zip(&certificates).map(|(msg, cert)| { @@ -982,7 +1010,11 @@ mod tests { ) }); - assert!(verifier.verify_certificates::<_, Sha256Digest, _>(&mut rng, certs_iter)); + assert!(verifier.verify_certificates::<_, Sha256Digest, _>( + &mut rng, + certs_iter, + &Sequential + )); } #[test] @@ -1010,7 +1042,7 @@ mod tests { .unwrap() }) .collect(); - certificates.push(schemes[0].assemble(attestations).unwrap()); + certificates.push(schemes[0].assemble(attestations, &Sequential).unwrap()); } // Corrupt second certificate @@ -1025,7 +1057,11 @@ mod tests { ) }); - assert!(!verifier.verify_certificates::<_, Sha256Digest, _>(&mut rng, certs_iter)); + assert!(!verifier.verify_certificates::<_, Sha256Digest, _>( + &mut rng, + certs_iter, + &Sequential + )); } #[test] @@ -1050,7 +1086,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Create a certificate-only verifier using the identity from the polynomial let identity = polynomial.public(); @@ -1063,7 +1099,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); // Should not be able to sign @@ -1110,7 +1147,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &vote + &vote, + &Sequential, )); } @@ -1173,6 +1211,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, &vote, + &Sequential, ); } @@ -1299,7 +1338,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); let mut encoded = certificate.encode(); encoded.truncate(encoded.len() - 1); assert!(V::Signature::decode(encoded).is_err()); diff --git a/cryptography/src/bls12381/dkg.rs b/cryptography/src/bls12381/dkg.rs index 3054b4968c..858347e593 100644 --- a/cryptography/src/bls12381/dkg.rs +++ b/cryptography/src/bls12381/dkg.rs @@ -2241,9 +2241,10 @@ mod test_plan { } let threshold = observer_output.quorum(); - let threshold_sig = threshold::recover::( + let threshold_sig = threshold::recover::( &observer_output.public, &partial_sigs[0..threshold as usize], + &Sequential, ) .expect("Should recover threshold signature"); diff --git a/cryptography/src/bls12381/primitives/mod.rs b/cryptography/src/bls12381/primitives/mod.rs index 5b1b9325df..19fa387dc2 100644 --- a/cryptography/src/bls12381/primitives/mod.rs +++ b/cryptography/src/bls12381/primitives/mod.rs @@ -36,7 +36,7 @@ //! } //! //! // Aggregate partial signatures -//! let threshold_sig = threshold::recover::(&sharing, &partials).unwrap(); +//! let threshold_sig = threshold::recover::(&sharing, &partials, &commonware_parallel::Sequential).unwrap(); //! //! // Verify threshold signature //! let threshold_pub = sharing.public(); diff --git a/cryptography/src/bls12381/primitives/ops/threshold.rs b/cryptography/src/bls12381/primitives/ops/threshold.rs index c203a1a3da..0f59032951 100644 --- a/cryptography/src/bls12381/primitives/ops/threshold.rs +++ b/cryptography/src/bls12381/primitives/ops/threshold.rs @@ -20,7 +20,7 @@ use super::{ #[cfg(not(feature = "std"))] use alloc::{vec, vec::Vec}; use commonware_codec::Encode; -use commonware_parallel::{Sequential, Strategy}; +use commonware_parallel::Strategy; use commonware_utils::{ordered::Map, union_unique, Participant}; use rand_core::CryptoRngCore; @@ -249,16 +249,21 @@ where /// # Warning /// /// This function assumes that each partial signature is unique. -pub fn recover<'a, V, I>(sharing: &Sharing, partials: I) -> Result +pub fn recover<'a, V, I, S>( + sharing: &Sharing, + partials: I, + strategy: &S, +) -> Result where V: Variant, I: IntoIterator>, V::Signature: 'a, + S: Strategy, { let evals = prepare_evaluations::(sharing.required(), partials)?; sharing .interpolator(evals.keys())? - .interpolate(&evals, &Sequential) + .interpolate(&evals, strategy) .ok_or(Error::InvalidRecovery) } @@ -394,7 +399,7 @@ mod tests { verify_proof_of_possession::(&sharing, namespace, p) .expect("signature should be valid"); } - let threshold_sig = recover::(&sharing, &partials).unwrap(); + let threshold_sig = recover::(&sharing, &partials, &Sequential).unwrap(); let threshold_pub = sharing.public(); ops::verify_proof_of_possession::(threshold_pub, namespace, &threshold_sig) @@ -449,7 +454,7 @@ mod tests { for p in &partials { verify_message::(&sharing, namespace, msg, p).expect("signature should be valid"); } - let threshold_sig = recover::(&sharing, &partials).unwrap(); + let threshold_sig = recover::(&sharing, &partials, &Sequential).unwrap(); let threshold_pub = sharing.public(); ops::verify_message::(threshold_pub, namespace, msg, &threshold_sig) @@ -587,7 +592,7 @@ mod tests { .map(|s| sign_message::(s, b"test", b"payload")) .collect(); - let sig1 = recover::(&sharing, &partials).unwrap(); + let sig1 = recover::(&sharing, &partials, &Sequential).unwrap(); ops::verify_message::(sharing.public(), b"test", b"payload", &sig1).unwrap(); } @@ -651,7 +656,7 @@ mod tests { verify_message::(&sharing, namespace, msg, partial).unwrap(); }); - let threshold_sig = recover::(&sharing, &partials).unwrap(); + let threshold_sig = recover::(&sharing, &partials, &Sequential).unwrap(); ops::verify_message::(sharing.public(), namespace, msg, &threshold_sig).unwrap(); } @@ -682,7 +687,7 @@ mod tests { )); }); - let threshold_sig = recover::(&sharing, &partials).unwrap(); + let threshold_sig = recover::(&sharing, &partials, &Sequential).unwrap(); assert!(matches!( ops::verify_message::(sharing.public(), namespace, msg, &threshold_sig).unwrap_err(), Error::InvalidSignature @@ -715,7 +720,7 @@ mod tests { }); assert!(matches!( - recover::(&group, &partials).unwrap_err(), + recover::(&group, &partials, &Sequential).unwrap_err(), Error::NotEnoughPartialSignatures(4, 3) )); } @@ -747,7 +752,7 @@ mod tests { verify_message::(&sharing, namespace, msg, partial).unwrap(); }); - let threshold_sig = recover::(&sharing, &partials).unwrap(); + let threshold_sig = recover::(&sharing, &partials, &Sequential).unwrap(); ops::verify_message::(sharing.public(), namespace, msg, &threshold_sig).unwrap(); } diff --git a/cryptography/src/certificate.rs b/cryptography/src/certificate.rs index b2e0ec5b94..97d2338851 100644 --- a/cryptography/src/certificate.rs +++ b/cryptography/src/certificate.rs @@ -69,6 +69,7 @@ use crate::{Digest, PublicKey}; use alloc::{collections::BTreeSet, sync::Arc, vec::Vec}; use bytes::{Buf, BufMut, Bytes}; use commonware_codec::{Codec, CodecFixed, EncodeSize, Error, Read, ReadExt, Write}; +use commonware_parallel::Strategy; use commonware_utils::{bitmap::BitMap, ordered::Set, Participant}; use core::{fmt::Debug, hash::Hash}; use rand_core::CryptoRngCore; @@ -210,6 +211,7 @@ pub trait Scheme: Clone + Debug + Send + Sync + 'static { rng: &mut R, subject: Self::Subject<'_, D>, attestation: &Attestation, + strategy: &impl Strategy, ) -> bool where R: CryptoRngCore, @@ -224,6 +226,7 @@ pub trait Scheme: Clone + Debug + Send + Sync + 'static { rng: &mut R, subject: Self::Subject<'_, D>, attestations: I, + strategy: &impl Strategy, ) -> Verification where R: CryptoRngCore, @@ -233,7 +236,7 @@ pub trait Scheme: Clone + Debug + Send + Sync + 'static { let mut invalid = BTreeSet::new(); let verified = attestations.into_iter().filter_map(|attestation| { - if self.verify_attestation(&mut *rng, subject.clone(), &attestation) { + if self.verify_attestation(&mut *rng, subject.clone(), &attestation, strategy) { Some(attestation) } else { invalid.insert(attestation.signer); @@ -247,7 +250,7 @@ pub trait Scheme: Clone + Debug + Send + Sync + 'static { /// Assembles attestations into a certificate, returning `None` if the threshold is not met. /// /// Callers must not include duplicate attestations from the same signer. - fn assemble(&self, attestations: I) -> Option + fn assemble(&self, attestations: I, strategy: &impl Strategy) -> Option where I: IntoIterator>; @@ -257,17 +260,23 @@ pub trait Scheme: Clone + Debug + Send + Sync + 'static { rng: &mut R, subject: Self::Subject<'_, D>, certificate: &Self::Certificate, + strategy: &impl Strategy, ) -> bool; /// Verifies a stream of certificates, returning `false` at the first failure. - fn verify_certificates<'a, R, D, I>(&self, rng: &mut R, certificates: I) -> bool + fn verify_certificates<'a, R, D, I>( + &self, + rng: &mut R, + certificates: I, + strategy: &impl Strategy, + ) -> bool where R: CryptoRngCore, D: Digest, I: Iterator, &'a Self::Certificate)>, { for (subject, certificate) in certificates { - if !self.verify_certificate(rng, subject, certificate) { + if !self.verify_certificate(rng, subject, certificate, strategy) { return false; } } diff --git a/cryptography/src/ed25519/certificate/mod.rs b/cryptography/src/ed25519/certificate/mod.rs index 876a1d7aac..3dbca22f82 100644 --- a/cryptography/src/ed25519/certificate/mod.rs +++ b/cryptography/src/ed25519/certificate/mod.rs @@ -584,6 +584,7 @@ mod macros { _rng: &mut R, subject: Self::Subject<'_, D>, attestation: &$crate::certificate::Attestation, + _strategy: &impl commonware_parallel::Strategy, ) -> bool where R: rand_core::CryptoRngCore, @@ -598,6 +599,7 @@ mod macros { rng: &mut R, subject: Self::Subject<'_, D>, attestations: I, + _strategy: &impl commonware_parallel::Strategy, ) -> $crate::certificate::Verification where R: rand_core::CryptoRngCore, @@ -608,7 +610,11 @@ mod macros { .verify_attestations::<_, _, D, _>(rng, subject, attestations) } - fn assemble(&self, attestations: I) -> Option + fn assemble( + &self, + attestations: I, + _strategy: &impl commonware_parallel::Strategy, + ) -> Option where I: IntoIterator>, { @@ -620,12 +626,18 @@ mod macros { rng: &mut R, subject: Self::Subject<'_, D>, certificate: &Self::Certificate, + _strategy: &impl commonware_parallel::Strategy, ) -> bool { self.generic .verify_certificate::(rng, subject, certificate) } - fn verify_certificates<'a, R, D, I>(&self, rng: &mut R, certificates: I) -> bool + fn verify_certificates<'a, R, D, I>( + &self, + rng: &mut R, + certificates: I, + _strategy: &impl commonware_parallel::Strategy, + ) -> bool where R: rand::Rng + rand::CryptoRng, D: $crate::Digest, @@ -667,6 +679,7 @@ mod tests { use bytes::Bytes; use commonware_codec::{Decode, Encode}; use commonware_math::algebra::Random; + use commonware_parallel::Sequential; use commonware_utils::{ordered::Set, quorum, test_rng, Participant, TryCollect}; const NAMESPACE: &[u8] = b"test-ed25519"; @@ -747,7 +760,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &attestation + &attestation, + &Sequential, )); } @@ -785,6 +799,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, attestations.clone(), + &Sequential, ); assert!(result.invalid.is_empty()); assert_eq!(result.verified.len(), quorum); @@ -798,6 +813,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, attestations_corrupted, + &Sequential, ); assert_eq!(result.invalid, vec![Participant::new(999)]); assert_eq!(result.verified.len(), quorum - 1); @@ -811,6 +827,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, attestations_corrupted, + &Sequential, ); // Batch verification may detect either signer 0 (wrong sig) or signer 1 (duplicate sig) assert_eq!(result.invalid.len(), 1); @@ -834,7 +851,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Verify certificate has correct number of signers assert_eq!(certificate.signers.count(), quorum); @@ -869,7 +886,7 @@ mod tests { .unwrap(), ]; - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Verify signers are sorted by signer index let expected: Vec<_> = indexed.iter().map(|(idx, _)| *idx).collect(); @@ -893,14 +910,15 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); assert!(verifier.verify_certificate::<_, Sha256Digest>( &mut rng, TestSubject { message: Bytes::from_static(MESSAGE) }, - &certificate + &certificate, + &Sequential, )); } @@ -921,7 +939,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Valid certificate passes assert!(verifier.verify_certificate::<_, Sha256Digest>( @@ -929,7 +947,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); // Corrupted certificate fails @@ -940,7 +959,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &corrupted + &corrupted, + &Sequential, )); } @@ -961,7 +981,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); let encoded = certificate.encode(); let decoded = Certificate::decode_cfg(encoded, &schemes.len()).expect("decode certificate"); assert_eq!(decoded, certificate); @@ -984,7 +1004,7 @@ mod tests { }) .collect(); - assert!(schemes[0].assemble(attestations).is_none()); + assert!(schemes[0].assemble(attestations, &Sequential).is_none()); } #[test] @@ -1007,7 +1027,7 @@ mod tests { // Corrupt signer index to be out of range attestations[0].signer = Participant::new(999); - assert!(schemes[0].assemble(attestations).is_none()); + assert!(schemes[0].assemble(attestations, &Sequential).is_none()); } #[test] @@ -1027,7 +1047,7 @@ mod tests { }) .collect(); - let mut certificate = schemes[0].assemble(attestations).unwrap(); + let mut certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Artificially truncate to below quorum let mut signers: Vec = certificate.signers.iter().collect(); @@ -1040,7 +1060,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); } @@ -1060,7 +1081,7 @@ mod tests { }) .collect(); - let mut certificate = schemes[0].assemble(attestations).unwrap(); + let mut certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Remove one signature but keep signers bitmap unchanged certificate.signatures.pop(); @@ -1070,7 +1091,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); } @@ -1097,7 +1119,7 @@ mod tests { .unwrap() }) .collect(); - certificates.push(schemes[0].assemble(attestations).unwrap()); + certificates.push(schemes[0].assemble(attestations, &Sequential).unwrap()); } let certs_iter = messages.iter().zip(&certificates).map(|(msg, cert)| { @@ -1109,7 +1131,11 @@ mod tests { ) }); - assert!(verifier.verify_certificates::<_, Sha256Digest, _>(&mut rng, certs_iter)); + assert!(verifier.verify_certificates::<_, Sha256Digest, _>( + &mut rng, + certs_iter, + &Sequential + )); } #[test] @@ -1135,7 +1161,7 @@ mod tests { .unwrap() }) .collect(); - certificates.push(schemes[0].assemble(attestations).unwrap()); + certificates.push(schemes[0].assemble(attestations, &Sequential).unwrap()); } // Corrupt second certificate @@ -1150,7 +1176,11 @@ mod tests { ) }); - assert!(!verifier.verify_certificates::<_, Sha256Digest, _>(&mut rng, certs_iter)); + assert!(!verifier.verify_certificates::<_, Sha256Digest, _>( + &mut rng, + certs_iter, + &Sequential + )); } #[test] @@ -1174,7 +1204,7 @@ mod tests { attestations.push(attestations.last().unwrap().clone()); // This should panic due to duplicate signer - schemes[0].assemble(attestations); + schemes[0].assemble(attestations, &Sequential); } #[test] @@ -1223,7 +1253,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Well-formed certificate decodes successfully let encoded = certificate.encode(); @@ -1274,7 +1304,7 @@ mod tests { }) .collect(); - let mut certificate = schemes[0].assemble(attestations).unwrap(); + let mut certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Add an unknown signer (out of range) let mut signers: Vec = certificate.signers.iter().collect(); @@ -1290,6 +1320,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, &certificate, + &Sequential, )); } @@ -1310,7 +1341,7 @@ mod tests { }) .collect(); - let mut certificate = schemes[0].assemble(attestations).unwrap(); + let mut certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Valid certificate passes assert!(verifier.verify_certificate::<_, Sha256Digest>( @@ -1319,6 +1350,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, &certificate, + &Sequential, )); // Make the signers bitmap size larger (mismatched with participants) @@ -1332,6 +1364,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, &certificate, + &Sequential, )); } @@ -1352,7 +1385,7 @@ mod tests { }) .collect(); - let mut certificate = schemes[0].assemble(attestations).unwrap(); + let mut certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Make the signers bitmap size larger than participants let signers: Vec = certificate.signers.iter().collect(); @@ -1366,7 +1399,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); } diff --git a/cryptography/src/secp256r1/certificate/mod.rs b/cryptography/src/secp256r1/certificate/mod.rs index 16849bcd4f..0c562e2dda 100644 --- a/cryptography/src/secp256r1/certificate/mod.rs +++ b/cryptography/src/secp256r1/certificate/mod.rs @@ -415,6 +415,7 @@ mod macros { _rng: &mut R, subject: Self::Subject<'_, D>, attestation: &$crate::certificate::Attestation, + _strategy: &impl commonware_parallel::Strategy, ) -> bool where R: rand_core::CryptoRngCore, @@ -429,6 +430,7 @@ mod macros { rng: &mut R, subject: Self::Subject<'_, D>, attestations: I, + _strategy: &impl commonware_parallel::Strategy, ) -> $crate::certificate::Verification where R: rand_core::CryptoRngCore, @@ -442,7 +444,11 @@ mod macros { ) } - fn assemble(&self, attestations: I) -> Option + fn assemble( + &self, + attestations: I, + _strategy: &impl commonware_parallel::Strategy, + ) -> Option where I: IntoIterator>, { @@ -454,6 +460,7 @@ mod macros { rng: &mut R, subject: Self::Subject<'_, D>, certificate: &Self::Certificate, + _strategy: &impl commonware_parallel::Strategy, ) -> bool { self.generic.verify_certificate::( rng, @@ -493,6 +500,7 @@ mod tests { use bytes::Bytes; use commonware_codec::{Decode, Encode}; use commonware_math::algebra::Random; + use commonware_parallel::Sequential; use commonware_utils::{ordered::BiMap, quorum, test_rng, TryCollect}; use rand_core::CryptoRngCore; @@ -574,7 +582,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &attestation + &attestation, + &Sequential, )); } @@ -612,6 +621,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, attestations.clone(), + &Sequential, ); assert!(result.invalid.is_empty()); assert_eq!(result.verified.len(), quorum); @@ -625,6 +635,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, attestations_corrupted, + &Sequential, ); assert_eq!(result.invalid, vec![Participant::new(999)]); assert_eq!(result.verified.len(), quorum - 1); @@ -639,6 +650,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, attestations_corrupted, + &Sequential, ); // Without batch verification, we detect exactly which signer has invalid sig assert_eq!(result.invalid, vec![first_signer]); @@ -662,7 +674,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Verify certificate has correct number of signers assert_eq!(certificate.signers.count(), quorum); @@ -697,7 +709,7 @@ mod tests { .unwrap(), ]; - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Verify signers are sorted by signer index let expected: Vec<_> = indexed.iter().map(|(idx, _)| *idx).collect(); @@ -721,14 +733,15 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); assert!(verifier.verify_certificate::<_, Sha256Digest>( &mut rng, TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); } @@ -749,7 +762,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Valid certificate passes assert!(verifier.verify_certificate::<_, Sha256Digest>( @@ -757,7 +770,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); // Corrupted certificate fails @@ -768,7 +782,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &corrupted + &corrupted, + &Sequential, )); } @@ -789,7 +804,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); let encoded = certificate.encode(); let decoded = Certificate::decode_cfg(encoded, &schemes.len()).expect("decode certificate"); assert_eq!(decoded, certificate); @@ -812,7 +827,7 @@ mod tests { }) .collect(); - assert!(schemes[0].assemble(attestations).is_none()); + assert!(schemes[0].assemble(attestations, &Sequential).is_none()); } #[test] @@ -835,7 +850,7 @@ mod tests { // Corrupt signer index to be out of range attestations[0].signer = Participant::new(999); - assert!(schemes[0].assemble(attestations).is_none()); + assert!(schemes[0].assemble(attestations, &Sequential).is_none()); } #[test] @@ -855,7 +870,7 @@ mod tests { }) .collect(); - let mut certificate = schemes[0].assemble(attestations).unwrap(); + let mut certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Artificially truncate to below quorum let mut signers: Vec = certificate.signers.iter().collect(); @@ -868,7 +883,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); } @@ -888,7 +904,7 @@ mod tests { }) .collect(); - let mut certificate = schemes[0].assemble(attestations).unwrap(); + let mut certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Remove one signature but keep signers bitmap unchanged certificate.signatures.pop(); @@ -898,7 +914,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); } @@ -925,7 +942,7 @@ mod tests { .unwrap() }) .collect(); - certificates.push(schemes[0].assemble(attestations).unwrap()); + certificates.push(schemes[0].assemble(attestations, &Sequential).unwrap()); } let certs_iter = messages.iter().zip(&certificates).map(|(msg, cert)| { @@ -937,7 +954,11 @@ mod tests { ) }); - assert!(verifier.verify_certificates::<_, Sha256Digest, _>(&mut rng, certs_iter)); + assert!(verifier.verify_certificates::<_, Sha256Digest, _>( + &mut rng, + certs_iter, + &Sequential + )); } #[test] @@ -963,7 +984,7 @@ mod tests { .unwrap() }) .collect(); - certificates.push(schemes[0].assemble(attestations).unwrap()); + certificates.push(schemes[0].assemble(attestations, &Sequential).unwrap()); } // Corrupt second certificate @@ -978,7 +999,11 @@ mod tests { ) }); - assert!(!verifier.verify_certificates::<_, Sha256Digest, _>(&mut rng, certs_iter)); + assert!(!verifier.verify_certificates::<_, Sha256Digest, _>( + &mut rng, + certs_iter, + &Sequential + )); } #[test] @@ -1002,7 +1027,7 @@ mod tests { attestations.push(attestations.last().unwrap().clone()); // This should panic due to duplicate signer - schemes[0].assemble(attestations); + schemes[0].assemble(attestations, &Sequential); } #[test] @@ -1051,7 +1076,7 @@ mod tests { }) .collect(); - let certificate = schemes[0].assemble(attestations).unwrap(); + let certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Well-formed certificate decodes successfully let encoded = certificate.encode(); @@ -1102,7 +1127,7 @@ mod tests { }) .collect(); - let mut certificate = schemes[0].assemble(attestations).unwrap(); + let mut certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Add an unknown signer (out of range) let mut signers: Vec = certificate.signers.iter().collect(); @@ -1118,6 +1143,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, &certificate, + &Sequential, )); } @@ -1138,7 +1164,7 @@ mod tests { }) .collect(); - let mut certificate = schemes[0].assemble(attestations).unwrap(); + let mut certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Valid certificate passes assert!(verifier.verify_certificate::<_, Sha256Digest>( @@ -1147,6 +1173,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, &certificate, + &Sequential, )); // Make the signers bitmap size larger (mismatched with participants) @@ -1160,6 +1187,7 @@ mod tests { message: Bytes::from_static(MESSAGE), }, &certificate, + &Sequential, )); } @@ -1180,7 +1208,7 @@ mod tests { }) .collect(); - let mut certificate = schemes[0].assemble(attestations).unwrap(); + let mut certificate = schemes[0].assemble(attestations, &Sequential).unwrap(); // Make the signers bitmap size larger than participants let signers: Vec = certificate.signers.iter().collect(); @@ -1194,7 +1222,8 @@ mod tests { TestSubject { message: Bytes::from_static(MESSAGE), }, - &certificate + &certificate, + &Sequential, )); } diff --git a/examples/bridge/src/application/actor.rs b/examples/bridge/src/application/actor.rs index 54c6222d5c..6ff5f12f9f 100644 --- a/examples/bridge/src/application/actor.rs +++ b/examples/bridge/src/application/actor.rs @@ -16,6 +16,7 @@ use commonware_cryptography::{ bls12381::primitives::variant::{MinSig, Variant}, Hasher, }; +use commonware_parallel::Sequential; use commonware_runtime::{Sink, Spawner, Stream}; use commonware_stream::{Receiver, Sender}; use futures::{channel::mpsc, StreamExt}; @@ -104,7 +105,11 @@ impl Application Application { - let result = - finalization.verify(&mut self.context, &self.other_network); + let result = finalization.verify( + &mut self.context, + &self.other_network, + &Sequential, + ); let _ = response.send(result); } } diff --git a/examples/bridge/src/bin/indexer.rs b/examples/bridge/src/bin/indexer.rs index 5f6dc2b94e..1f850ac5f0 100644 --- a/examples/bridge/src/bin/indexer.rs +++ b/examples/bridge/src/bin/indexer.rs @@ -22,10 +22,10 @@ use commonware_cryptography::{ sha256::Digest as Sha256Digest, Digest, Hasher, Sha256, Signer as _, }; -use commonware_parallel::Rayon; -use commonware_runtime::{tokio, Listener, Metrics, Network, RayonPoolSpawner, Runner, Spawner}; +use commonware_parallel::Sequential; +use commonware_runtime::{tokio, Listener, Metrics, Network, Runner, Spawner}; use commonware_stream::{listen, Config as StreamConfig}; -use commonware_utils::{from_hex, ordered::Set, union, NZUsize, TryCollect}; +use commonware_utils::{from_hex, ordered::Set, union, TryCollect}; use futures::{ channel::{mpsc, oneshot}, SinkExt, StreamExt, @@ -37,7 +37,7 @@ use std::{ }; use tracing::{debug, info}; -type Scheme = bls12381_threshold::Scheme; +type Scheme = bls12381_threshold::Scheme; #[allow(clippy::large_enum_variant)] enum Message { @@ -137,8 +137,6 @@ fn main() { // Create context let executor = tokio::Runner::default(); executor.start(|context| async move { - let strategy = context.clone().create_strategy(NZUsize!(2)).unwrap(); - for network in networks { let network = from_hex(network).expect("Network not well-formed"); let public = ::Public::decode(network.as_ref()) @@ -146,11 +144,7 @@ fn main() { let namespace = union(APPLICATION_NAMESPACE, CONSENSUS_SUFFIX); verifiers.insert( public, - bls12381_threshold::Scheme::certificate_verifier( - &namespace, - public, - strategy.clone(), - ), + bls12381_threshold::Scheme::certificate_verifier(&namespace, public), ); blocks.insert(public, HashMap::new()); finalizations.insert(public, BTreeMap::new()); @@ -204,7 +198,10 @@ fn main() { let _ = response.send(false); continue; }; - if !incoming.finalization.verify(&mut ctx, verifier) { + if !incoming + .finalization + .verify(&mut ctx, verifier, &Sequential) + { let _ = response.send(false); continue; } diff --git a/examples/bridge/src/bin/validator.rs b/examples/bridge/src/bin/validator.rs index 420adce080..db3469b485 100644 --- a/examples/bridge/src/bin/validator.rs +++ b/examples/bridge/src/bin/validator.rs @@ -221,16 +221,10 @@ fn main() { // Initialize application let strategy = context.clone().create_strategy(NZUsize!(2)).unwrap(); let consensus_namespace = union(APPLICATION_NAMESPACE, CONSENSUS_SUFFIX); - let this_network = Scheme::signer( - &consensus_namespace, - validators.clone(), - identity, - share, - strategy.clone(), - ) - .expect("share must be in participants"); - let other_network = - Scheme::certificate_verifier(&consensus_namespace, other_public, strategy); + let this_network = + Scheme::signer(&consensus_namespace, validators.clone(), identity, share) + .expect("share must be in participants"); + let other_network = Scheme::certificate_verifier(&consensus_namespace, other_public); let (application, scheme, mailbox) = application::Application::new( context.with_label("application"), application::Config { @@ -265,6 +259,7 @@ fn main() { skip_timeout: ViewDelta::new(5), fetch_concurrent: 32, buffer_pool: PoolRef::new(NZU16!(16_384), NZUsize!(10_000)), + strategy, }, ); diff --git a/examples/bridge/src/lib.rs b/examples/bridge/src/lib.rs index 46f17d2968..5edfd97cee 100644 --- a/examples/bridge/src/lib.rs +++ b/examples/bridge/src/lib.rs @@ -155,9 +155,7 @@ use commonware_consensus::simplex::scheme::bls12381_threshold; use commonware_cryptography::{bls12381::primitives::variant::MinSig, ed25519::PublicKey}; -use commonware_parallel::Rayon; - -pub type Scheme = bls12381_threshold::Scheme; +pub type Scheme = bls12381_threshold::Scheme; #[doc(hidden)] pub mod application; diff --git a/examples/log/Cargo.toml b/examples/log/Cargo.toml index 265924e22f..6cf332ce5d 100644 --- a/examples/log/Cargo.toml +++ b/examples/log/Cargo.toml @@ -21,6 +21,7 @@ commonware-consensus.workspace = true commonware-cryptography.workspace = true commonware-macros.workspace = true commonware-p2p.workspace = true +commonware-parallel.workspace = true commonware-runtime.workspace = true commonware-storage = { workspace = true, features = ["std"] } commonware-utils.workspace = true diff --git a/examples/log/src/main.rs b/examples/log/src/main.rs index b61ad3775c..889c559b78 100644 --- a/examples/log/src/main.rs +++ b/examples/log/src/main.rs @@ -54,6 +54,7 @@ use commonware_consensus::{ }; use commonware_cryptography::{ed25519, Sha256, Signer as _}; use commonware_p2p::{authenticated::discovery, Manager}; +use commonware_parallel::Sequential; use commonware_runtime::{buffer::PoolRef, tokio, Metrics, Quota, Runner}; use commonware_utils::{ordered::Set, union, NZUsize, TryCollect, NZU16, NZU32}; use std::{ @@ -224,6 +225,7 @@ fn main() { skip_timeout: ViewDelta::new(5), fetch_concurrent: 32, buffer_pool: PoolRef::new(NZU16!(16_384), NZUsize!(10_000)), + strategy: Sequential, }; let engine = simplex::Engine::new(context.with_label("engine"), cfg); diff --git a/examples/reshare/src/application/scheme.rs b/examples/reshare/src/application/scheme.rs index a96eb96563..ec288dd010 100644 --- a/examples/reshare/src/application/scheme.rs +++ b/examples/reshare/src/application/scheme.rs @@ -11,47 +11,38 @@ use commonware_cryptography::{ certificate::{self, Scheme}, ed25519, PublicKey, Signer, }; -use commonware_parallel::Strategy; use std::{ collections::HashMap, sync::{Arc, Mutex}, }; /// The BLS12-381 threshold signing scheme used in simplex. -pub type ThresholdScheme = - simplex::scheme::bls12381_threshold::Scheme; +pub type ThresholdScheme = simplex::scheme::bls12381_threshold::Scheme; /// The ED25519 signing scheme used in simplex. pub type EdScheme = simplex::scheme::ed25519::Scheme; /// Provides signing schemes for different epochs. #[derive(Clone)] -pub struct Provider { +pub struct Provider { schemes: Arc>>>, namespace: Vec, certificate_verifier: Option>, signer: C, - strategy: St, } -impl Provider { - pub fn new( - namespace: Vec, - signer: C, - certificate_verifier: Option, - strategy: St, - ) -> Self { +impl Provider { + pub fn new(namespace: Vec, signer: C, certificate_verifier: Option) -> Self { Self { schemes: Arc::new(Mutex::new(HashMap::new())), namespace, certificate_verifier: certificate_verifier.map(Arc::new), signer, - strategy, } } } -impl Provider { +impl Provider { /// Registers a new signing scheme for the given epoch. /// /// Returns `false` if a scheme was already registered for the epoch. @@ -69,7 +60,7 @@ impl Provider { } } -impl certificate::Provider for Provider { +impl certificate::Provider for Provider { type Scope = Epoch; type Scheme = S; @@ -87,7 +78,6 @@ pub trait EpochProvider { type Variant: Variant; type PublicKey: PublicKey; type Scheme: Scheme; - type Strategy: Strategy; /// Returns a [Scheme] for the given [EpochTransition]. fn scheme_for_epoch( @@ -102,17 +92,13 @@ pub trait EpochProvider { fn certificate_verifier( namespace: &[u8], output: &dkg::Output, - strategy: Self::Strategy, ) -> Option; } -impl EpochProvider - for Provider, ed25519::PrivateKey, St> -{ +impl EpochProvider for Provider, ed25519::PrivateKey> { type Variant = V; type PublicKey = ed25519::PublicKey; - type Scheme = ThresholdScheme; - type Strategy = St; + type Scheme = ThresholdScheme; fn scheme_for_epoch( &self, @@ -127,7 +113,6 @@ impl EpochProvider .poly .clone() .expect("group polynomial must exist"), - self.strategy.clone(), ) }, |share| { @@ -139,7 +124,6 @@ impl EpochProvider .clone() .expect("group polynomial must exist"), share.clone(), - self.strategy.clone(), ) .expect("share must be in dealers") }, @@ -149,21 +133,18 @@ impl EpochProvider fn certificate_verifier( namespace: &[u8], output: &dkg::Output, - strategy: Self::Strategy, ) -> Option { Some(ThresholdScheme::certificate_verifier( namespace, *output.public().public(), - strategy, )) } } -impl EpochProvider for Provider { +impl EpochProvider for Provider { type Variant = MinSig; type PublicKey = ed25519::PublicKey; type Scheme = EdScheme; - type Strategy = St; fn scheme_for_epoch( &self, @@ -180,7 +161,6 @@ impl EpochProvider for Provider fn certificate_verifier( _namespace: &[u8], _output: &dkg::Output, - _strategy: Self::Strategy, ) -> Option { // Ed25519 doesn't support epoch-independent certificate verification // since certificates require the full participant list which changes per epoch. diff --git a/examples/reshare/src/engine.rs b/examples/reshare/src/engine.rs index 48edc03173..d194ca76b8 100644 --- a/examples/reshare/src/engine.rs +++ b/examples/reshare/src/engine.rs @@ -53,13 +53,13 @@ const BUFFER_POOL_PAGE_SIZE: NonZeroU16 = NZU16!(4_096); // 4KB const BUFFER_POOL_CAPACITY: NonZero = NZUsize!(8_192); // 32MB const MAX_REPAIR: NonZero = NZUsize!(50); -pub struct Config +pub struct Config where P: Manager>, C: Signer, B: Blocker, V: Variant, - St: Strategy, + T: Strategy, { pub signer: C, pub manager: P, @@ -70,10 +70,10 @@ where pub peer_config: PeerConfig, pub partition_prefix: String, pub freezer_table_initial_size: u32, - pub strategy: St, + pub strategy: T, } -pub struct Engine +pub struct Engine where E: Spawner + Metrics + CryptoRngCore + Clock + Storage + Network, C: Signer, @@ -83,12 +83,11 @@ where V: Variant, S: Scheme, L: Elector, - St: Strategy, - Provider: - EpochProvider, + T: Strategy, + Provider: EpochProvider, { context: ContextCell, - config: Config, + config: Config, dkg: dkg::Actor, dkg_mailbox: dkg::Mailbox, buffer: buffered::Engine>, @@ -97,10 +96,11 @@ where marshal: marshal::Actor< E, Block, - Provider, + Provider, immutable::Archive>, immutable::Archive>, FixedEpocher, + T, >, #[allow(clippy::type_complexity)] orchestrator: orchestrator::Actor< @@ -112,12 +112,12 @@ where Marshaled, Block, FixedEpocher>, S, L, - St, + T, >, orchestrator_mailbox: orchestrator::Mailbox, } -impl Engine +impl Engine where E: Spawner + Metrics + CryptoRngCore + Clock + Storage + Network, C: Signer, @@ -127,11 +127,10 @@ where V: Variant, S: Scheme, L: Elector, - St: Strategy, - Provider: - EpochProvider, + T: Strategy, + Provider: EpochProvider, { - pub async fn new(context: E, config: Config) -> Self { + pub async fn new(context: E, config: Config) -> Self { let buffer_pool = PoolRef::new(BUFFER_POOL_PAGE_SIZE, BUFFER_POOL_CAPACITY); let consensus_namespace = union(&config.namespace, b"_CONSENSUS"); let num_participants = NZU32!(config.peer_config.max_participants_per_round()); @@ -245,17 +244,12 @@ where // Create the certificate verifier from the initial output (if available). // This allows epoch-independent certificate verification after the DKG is complete. let certificate_verifier = config.output.as_ref().and_then(|output| { - as EpochProvider>::certificate_verifier( - &consensus_namespace, - output, - config.strategy.clone(), - ) + as EpochProvider>::certificate_verifier(&consensus_namespace, output) }); let provider = Provider::new( consensus_namespace.clone(), config.signer.clone(), certificate_verifier, - config.strategy.clone(), ); let (marshal, marshal_mailbox, _processed_height) = marshal::Actor::init( @@ -279,6 +273,7 @@ where value_write_buffer: WRITE_BUFFER, block_codec_config: num_participants, max_repair: MAX_REPAIR, + strategy: config.strategy.clone(), }, ) .await; @@ -297,6 +292,7 @@ where application, provider, marshal: marshal_mailbox, + strategy: config.strategy.clone(), muxer_size: MAILBOX_SIZE, mailbox_size: MAILBOX_SIZE, partition_prefix: format!("{}_consensus", config.partition_prefix), diff --git a/examples/reshare/src/main.rs b/examples/reshare/src/main.rs index cbbba86a0e..7b8405d117 100644 --- a/examples/reshare/src/main.rs +++ b/examples/reshare/src/main.rs @@ -9,7 +9,6 @@ use clap::{Args, Parser, Subcommand}; use commonware_codec::Encode; use commonware_consensus::simplex::elector::{Random, RoundRobin}; use commonware_cryptography::{bls12381::primitives::variant::MinSig, ed25519::PublicKey}; -use commonware_parallel::Rayon; use commonware_runtime::{ tokio::{self, telemetry::Logging}, Metrics, Runner, @@ -181,7 +180,7 @@ fn main() { .await; } Subcommands::Validator(args) => { - validator::run::, Random>( + validator::run::, Random>( context, args, ContinueOnUpdate::boxed(), diff --git a/examples/reshare/src/orchestrator/actor.rs b/examples/reshare/src/orchestrator/actor.rs index 3f4fe9a44b..90a0f153f3 100644 --- a/examples/reshare/src/orchestrator/actor.rs +++ b/examples/reshare/src/orchestrator/actor.rs @@ -30,7 +30,7 @@ use std::{collections::BTreeMap, marker::PhantomData, time::Duration}; use tracing::{debug, info, warn}; /// Configuration for the orchestrator. -pub struct Config +pub struct Config where B: Blocker, V: Variant, @@ -40,12 +40,13 @@ where + Relay, S: Scheme, L: Elector, - St: Strategy, + T: Strategy, { pub oracle: B, pub application: A, - pub provider: Provider, + pub provider: Provider, pub marshal: marshal::Mailbox>, + pub strategy: T, pub muxer_size: usize, pub mailbox_size: usize, @@ -56,7 +57,7 @@ where pub _phantom: PhantomData, } -pub struct Actor +pub struct Actor where E: Spawner + Metrics + CryptoRngCore + Clock + Storage + Network, B: Blocker, @@ -67,9 +68,8 @@ where + Relay, S: Scheme, L: Elector, - St: Strategy, - Provider: - EpochProvider, + T: Strategy, + Provider: EpochProvider, { context: ContextCell, mailbox: mpsc::Receiver>, @@ -77,7 +77,8 @@ where oracle: B, marshal: marshal::Mailbox>, - provider: Provider, + provider: Provider, + strategy: T, muxer_size: usize, partition_prefix: String, @@ -85,7 +86,7 @@ where _phantom: PhantomData, } -impl Actor +impl Actor where E: Spawner + Metrics + CryptoRngCore + Clock + Storage + Network, B: Blocker, @@ -96,13 +97,12 @@ where + Relay, S: scheme::Scheme, L: Elector, - St: Strategy, - Provider: - EpochProvider, + T: Strategy, + Provider: EpochProvider, { pub fn new( context: E, - config: Config, + config: Config, ) -> (Self, Mailbox) { let (sender, mailbox) = mpsc::channel(config.mailbox_size); let pool_ref = PoolRef::new(NZU16!(16_384), NZUsize!(10_000)); @@ -115,6 +115,7 @@ where oracle: config.oracle, marshal: config.marshal, provider: config.provider, + strategy: config.strategy, muxer_size: config.muxer_size, partition_prefix: config.partition_prefix, pool_ref, @@ -315,6 +316,7 @@ where skip_timeout: ViewDelta::new(10), fetch_concurrent: 32, buffer_pool: self.pool_ref.clone(), + strategy: self.strategy.clone(), }, ); diff --git a/examples/reshare/src/validator.rs b/examples/reshare/src/validator.rs index e919a99af3..0da2cb50b3 100644 --- a/examples/reshare/src/validator.rs +++ b/examples/reshare/src/validator.rs @@ -14,7 +14,6 @@ use commonware_cryptography::{ bls12381::primitives::variant::MinSig, ed25519, Hasher, Sha256, Signer, }; use commonware_p2p::authenticated::discovery; -use commonware_parallel::Rayon; use commonware_runtime::{tokio, Metrics, Quota, RayonPoolSpawner}; use commonware_utils::{union, union_unique, NZUsize, NZU32}; use futures::future::try_join_all; @@ -43,12 +42,8 @@ pub async fn run( ) where S: Scheme<::Digest, PublicKey = ed25519::PublicKey>, L: Elector, - Provider: EpochProvider< - Variant = MinSig, - PublicKey = ed25519::PublicKey, - Scheme = S, - Strategy = Rayon, - >, + Provider: + EpochProvider, { // Load the participant configuration. let config_str = std::fs::read_to_string(&args.config_path) @@ -335,12 +330,8 @@ mod test { ) where S: Scheme<::Digest, PublicKey = PublicKey>, L: Elector, - Provider: EpochProvider< - Variant = MinSig, - PublicKey = PublicKey, - Scheme = S, - Strategy = Sequential, - >, + Provider: + EpochProvider, { if let Some(handle) = self.handles.remove(&pk) { handle.abort(); @@ -428,10 +419,8 @@ mod test { self.start_one::(ctx, oracle, updates, pk) .await; } else { - self.start_one::, Random>( - ctx, oracle, updates, pk, - ) - .await; + self.start_one::, Random>(ctx, oracle, updates, pk) + .await; } } @@ -725,7 +714,7 @@ mod test { if team.output.is_none() { team.start_one::(&ctx, &mut oracle, updates_in.clone(), pk).await; } else { - team.start_one::, Random>(&ctx, &mut oracle, updates_in.clone(), pk).await; + team.start_one::, Random>(&ctx, &mut oracle, updates_in.clone(), pk).await; } }, _ = crash_receiver.next() => {