From b2ff616f4b885a51c59e72a29701e3e2ce86bea0 Mon Sep 17 00:00:00 2001 From: curiecrypt Date: Wed, 5 Nov 2025 15:39:33 +0300 Subject: [PATCH 01/11] stm error and result types defined --- Cargo.lock | 1 + mithril-stm/Cargo.toml | 1 + mithril-stm/src/lib.rs | 6 ++++++ 3 files changed, 8 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 1976d4de071..ed7384443a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4147,6 +4147,7 @@ dependencies = [ name = "mithril-stm" version = "0.5.5" dependencies = [ + "anyhow", "blake2 0.10.6", "blst", "criterion", diff --git a/mithril-stm/Cargo.toml b/mithril-stm/Cargo.toml index 27248eb7503..2094d32f64b 100644 --- a/mithril-stm/Cargo.toml +++ b/mithril-stm/Cargo.toml @@ -29,6 +29,7 @@ rand_core = { workspace = true } rayon = { workspace = true } serde = { workspace = true } thiserror = { workspace = true } +anyhow = { workspace = true } [target.'cfg(any(target_family = "wasm", target_env = "musl", windows))'.dependencies] # WASM and Windows don't support rug backend, fallback to num-integer only diff --git a/mithril-stm/src/lib.rs b/mithril-stm/src/lib.rs index 2ca7313521b..76855976846 100644 --- a/mithril-stm/src/lib.rs +++ b/mithril-stm/src/lib.rs @@ -144,6 +144,12 @@ pub type Stake = u64; /// An aggregate signature (`StmMultiSig`) must have at least `k` unique indices. pub type Index = u64; +/// Mithril-stm error type +pub type StmError = anyhow::Error; + +/// Mithril-stm result type +pub type StmResult = anyhow::Result; + // Aliases #[deprecated(since = "0.5.0", note = "Use `AggregateSignature` instead")] pub use aggregate_signature::AggregateSignature as StmAggrSig; From 41fbcfb9348b75ba9244c1bb0aeb64b4efc6aafd Mon Sep 17 00:00:00 2001 From: curiecrypt Date: Wed, 5 Nov 2025 15:55:12 +0300 Subject: [PATCH 02/11] sorting --- mithril-stm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mithril-stm/Cargo.toml b/mithril-stm/Cargo.toml index 2094d32f64b..af54d8f9c3a 100644 --- a/mithril-stm/Cargo.toml +++ b/mithril-stm/Cargo.toml @@ -21,6 +21,7 @@ benchmark-internals = [] # For benchmarking multi_sig future_proof_system = [] # For activating future proof systems [dependencies] +anyhow = { workspace = true } blake2 = "0.10.6" # Enforce blst portable feature for runtime detection of Intel ADX instruction set. blst = { version = "0.3.16", features = ["portable"] } @@ -29,7 +30,6 @@ rand_core = { workspace = true } rayon = { workspace = true } serde = { workspace = true } thiserror = { workspace = true } -anyhow = { workspace = true } [target.'cfg(any(target_family = "wasm", target_env = "musl", windows))'.dependencies] # WASM and Windows don't support rug backend, fallback to num-integer only From 344f3c3dde26a49b721437ae3d108fc3817643a2 Mon Sep 17 00:00:00 2001 From: curiecrypt Date: Thu, 6 Nov 2025 17:19:50 +0300 Subject: [PATCH 03/11] remove generics from error enums --- .../proof/concatenation.rs | 10 +++---- .../src/aggregate_signature/signature.rs | 6 ++--- mithril-stm/src/error.rs | 26 +++++++++---------- mithril-stm/src/merkle_tree/commitment.rs | 24 +++++++---------- mithril-stm/src/merkle_tree/leaf.rs | 4 +-- mithril-stm/src/merkle_tree/path.rs | 4 +-- mithril-stm/src/merkle_tree/tree.rs | 2 +- 7 files changed, 33 insertions(+), 43 deletions(-) diff --git a/mithril-stm/src/aggregate_signature/proof/concatenation.rs b/mithril-stm/src/aggregate_signature/proof/concatenation.rs index bafc5ddac69..e019f9e7fcf 100644 --- a/mithril-stm/src/aggregate_signature/proof/concatenation.rs +++ b/mithril-stm/src/aggregate_signature/proof/concatenation.rs @@ -83,7 +83,7 @@ impl ConcatenationProof { msg: &[u8], avk: &AggregateVerificationKey, parameters: &Parameters, - ) -> Result<(Vec, Vec), StmAggregateSignatureError> { + ) -> Result<(Vec, Vec), StmAggregateSignatureError> { let msgp = avk.get_merkle_tree_batch_commitment().concatenate_with_message(msg); BasicVerifier::preliminary_verify( &avk.get_total_stake(), @@ -117,7 +117,7 @@ impl ConcatenationProof { msg: &[u8], avk: &AggregateVerificationKey, parameters: &Parameters, - ) -> Result<(), StmAggregateSignatureError> { + ) -> Result<(), StmAggregateSignatureError> { let msgp = avk.get_merkle_tree_batch_commitment().concatenate_with_message(msg); let (sigs, vks) = self.preliminary_verify(msg, avk, parameters)?; @@ -131,7 +131,7 @@ impl ConcatenationProof { msgs: &[Vec], avks: &[AggregateVerificationKey], parameters: &[Parameters], - ) -> Result<(), StmAggregateSignatureError> { + ) -> Result<(), StmAggregateSignatureError> { let batch_size = stm_signatures.len(); assert_eq!( batch_size, @@ -195,9 +195,7 @@ impl ConcatenationProof { } ///Extract a concatenation proof from a byte slice. - pub fn from_bytes( - bytes: &[u8], - ) -> Result, StmAggregateSignatureError> { + pub fn from_bytes(bytes: &[u8]) -> Result, StmAggregateSignatureError> { let mut bytes_index = 0; let mut u64_bytes = [0u8; 8]; diff --git a/mithril-stm/src/aggregate_signature/signature.rs b/mithril-stm/src/aggregate_signature/signature.rs index 82d7fa01cda..31ca7e84797 100644 --- a/mithril-stm/src/aggregate_signature/signature.rs +++ b/mithril-stm/src/aggregate_signature/signature.rs @@ -95,7 +95,7 @@ impl AggregateSignature { msg: &[u8], avk: &AggregateVerificationKey, parameters: &Parameters, - ) -> Result<(), StmAggregateSignatureError> { + ) -> Result<(), StmAggregateSignatureError> { match self { AggregateSignature::Concatenation(concatenation_proof) => { concatenation_proof.verify(msg, avk, parameters) @@ -113,7 +113,7 @@ impl AggregateSignature { msgs: &[Vec], avks: &[AggregateVerificationKey], parameters: &[Parameters], - ) -> Result<(), StmAggregateSignatureError> { + ) -> Result<(), StmAggregateSignatureError> { let stm_signatures: HashMap> = stm_signatures.iter().fold(HashMap::new(), |mut acc, sig| { acc.entry(sig.into()).or_default().push(sig.clone()); @@ -171,7 +171,7 @@ impl AggregateSignature { } /// Extract an aggregate signature from a byte slice. - pub fn from_bytes(bytes: &[u8]) -> Result> { + pub fn from_bytes(bytes: &[u8]) -> Result { let proof_type_byte = bytes.first().ok_or(StmAggregateSignatureError::SerializationError)?; let proof_bytes = &bytes[1..]; diff --git a/mithril-stm/src/error.rs b/mithril-stm/src/error.rs index c56f2e29c7b..9dadcb0a532 100644 --- a/mithril-stm/src/error.rs +++ b/mithril-stm/src/error.rs @@ -1,12 +1,10 @@ //! Crate specific errors -use blake2::digest::{Digest, FixedOutput}; use blst::BLST_ERROR; use crate::aggregate_signature::AggregateSignatureType; use crate::bls_multi_signature::{ BlsSignature, BlsVerificationKey, BlsVerificationKeyProofOfPossession, }; -use crate::merkle_tree::{MerkleBatchPath, MerklePath}; /// Error types for multi signatures. #[derive(Debug, thiserror::Error, Eq, PartialEq)] @@ -42,18 +40,18 @@ pub enum MultiSignatureError { /// Error types related to merkle trees. #[derive(Debug, Clone, thiserror::Error)] -pub enum MerkleTreeError { +pub enum MerkleTreeError { /// Serialization error #[error("Serialization of a merkle tree failed")] SerializationError, /// Invalid merkle path #[error("Path does not verify against root")] - PathInvalid(MerklePath), + PathInvalid(Vec), /// Invalid merkle batch path #[error("Batch path does not verify against root")] - BatchPathInvalid(MerkleBatchPath), + BatchPathInvalid(Vec), } /// Errors which can be output by Mithril single signature verification. @@ -98,8 +96,8 @@ impl From for StmSignatureError { } } -impl From> for StmSignatureError { - fn from(e: MerkleTreeError) -> Self { +impl From for StmSignatureError { + fn from(e: MerkleTreeError) -> Self { match e { MerkleTreeError::SerializationError => Self::SerializationError, _ => unreachable!(), @@ -175,7 +173,7 @@ impl From for CoreVerifierError { /// Errors which can be output by Mithril aggregate verification. #[derive(Debug, Clone, thiserror::Error)] -pub enum StmAggregateSignatureError { +pub enum StmAggregateSignatureError { /// The IVK is invalid after aggregating the keys #[error("Aggregated key does not correspond to the expected key.")] IvkInvalid(Box), @@ -186,7 +184,7 @@ pub enum StmAggregateSignatureError { /// Invalid merkle batch path #[error("Batch path does not verify against root")] - PathInvalid(MerkleBatchPath), + PathInvalid(Vec), /// Batch verification of STM aggregate signatures failed #[error("Batch verification of STM aggregate signatures failed")] @@ -201,8 +199,8 @@ pub enum StmAggregateSignatureError { UnsupportedProofSystem(AggregateSignatureType), } -impl From> for StmAggregateSignatureError { - fn from(e: MerkleTreeError) -> Self { +impl From for StmAggregateSignatureError { + fn from(e: MerkleTreeError) -> Self { match e { MerkleTreeError::BatchPathInvalid(e) => Self::PathInvalid(e), MerkleTreeError::SerializationError => Self::SerializationError, @@ -211,7 +209,7 @@ impl From> for StmAggregateSignature } } -impl From for StmAggregateSignatureError { +impl From for StmAggregateSignatureError { fn from(e: MultiSignatureError) -> Self { match e { MultiSignatureError::AggregateSignatureInvalid => { @@ -233,13 +231,13 @@ impl From for StmAggregateSignatur } } -impl From for StmAggregateSignatureError { +impl From for StmAggregateSignatureError { fn from(e: CoreVerifierError) -> Self { Self::CoreVerificationError(e) } } -impl From for StmAggregateSignatureError { +impl From for StmAggregateSignatureError { fn from(e: StmSignatureError) -> Self { match e { StmSignatureError::SerializationError => Self::SerializationError, diff --git a/mithril-stm/src/merkle_tree/commitment.rs b/mithril-stm/src/merkle_tree/commitment.rs index d54873fc33f..52eca880ddd 100644 --- a/mithril-stm/src/merkle_tree/commitment.rs +++ b/mithril-stm/src/merkle_tree/commitment.rs @@ -31,7 +31,7 @@ impl MerkleTreeCommitment { &self, val: &MerkleTreeLeaf, proof: &MerklePath, - ) -> Result<(), MerkleTreeError> + ) -> Result<(), MerkleTreeError> where D: FixedOutput + Clone, { @@ -50,7 +50,7 @@ impl MerkleTreeCommitment { if h == self.root { return Ok(()); } - Err(MerkleTreeError::PathInvalid(proof.clone())) + Err(MerkleTreeError::PathInvalid(proof.to_bytes())) } /// Check an inclusion proof that `val` is part of the tree by traveling the whole path until the root. @@ -60,11 +60,7 @@ impl MerkleTreeCommitment { since = "0.5.0", note = "Use `verify_leaf_membership_from_path` instead" )] - pub fn check( - &self, - val: &MerkleTreeLeaf, - proof: &MerklePath, - ) -> Result<(), MerkleTreeError> + pub fn check(&self, val: &MerkleTreeLeaf, proof: &MerklePath) -> Result<(), MerkleTreeError> where D: FixedOutput + Clone, { @@ -104,7 +100,7 @@ impl MerkleTreeCommitment { } /// Extract a `MerkleTreeCommitment` from a byte slice. - pub fn from_bytes(bytes: &[u8]) -> Result, MerkleTreeError> { + pub fn from_bytes(bytes: &[u8]) -> Result, MerkleTreeError> { let root = bytes.to_vec(); Ok(Self { @@ -171,18 +167,18 @@ impl MerkleTreeBatchCommitment { &self, batch_val: &[MerkleTreeLeaf], proof: &MerkleBatchPath, - ) -> Result<(), MerkleTreeError> + ) -> Result<(), MerkleTreeError> where D: FixedOutput + Clone, { if batch_val.len() != proof.indices.len() { - return Err(MerkleTreeError::BatchPathInvalid(proof.clone())); + return Err(MerkleTreeError::BatchPathInvalid(proof.to_bytes())); } let mut ordered_indices: Vec = proof.indices.clone(); ordered_indices.sort_unstable(); if ordered_indices != proof.indices { - return Err(MerkleTreeError::BatchPathInvalid(proof.clone())); + return Err(MerkleTreeError::BatchPathInvalid(proof.to_bytes())); } let nr_nodes = self.nr_leaves + self.nr_leaves.next_power_of_two() - 1; @@ -249,7 +245,7 @@ impl MerkleTreeBatchCommitment { return Ok(()); } - Err(MerkleTreeError::BatchPathInvalid(proof.clone())) + Err(MerkleTreeError::BatchPathInvalid(proof.to_bytes())) } /// Check a proof of a batched opening. The indices must be ordered. @@ -267,7 +263,7 @@ impl MerkleTreeBatchCommitment { &self, batch_val: &[MerkleTreeLeaf], proof: &MerkleBatchPath, - ) -> Result<(), MerkleTreeError> + ) -> Result<(), MerkleTreeError> where D: FixedOutput + Clone, { @@ -286,7 +282,7 @@ impl MerkleTreeBatchCommitment { } /// Extract a `MerkleTreeBatchCommitment` from a byte slice. - pub fn from_bytes(bytes: &[u8]) -> Result, MerkleTreeError> { + pub fn from_bytes(bytes: &[u8]) -> Result, MerkleTreeError> { let mut u64_bytes = [0u8; 8]; u64_bytes.copy_from_slice(bytes.get(..8).ok_or(MerkleTreeError::SerializationError)?); let nr_leaves = usize::try_from(u64::from_be_bytes(u64_bytes)) diff --git a/mithril-stm/src/merkle_tree/leaf.rs b/mithril-stm/src/merkle_tree/leaf.rs index 675bfb77bf5..72febeca975 100644 --- a/mithril-stm/src/merkle_tree/leaf.rs +++ b/mithril-stm/src/merkle_tree/leaf.rs @@ -1,7 +1,5 @@ use std::cmp::Ordering; -use blake2::Blake2b; -use digest::consts::U32; use serde::{Deserialize, Serialize}; use crate::bls_multi_signature::BlsVerificationKey; @@ -14,7 +12,7 @@ use crate::{Stake, VerificationKey}; pub struct MerkleTreeLeaf(pub BlsVerificationKey, pub Stake); impl MerkleTreeLeaf { - pub(crate) fn from_bytes(bytes: &[u8]) -> Result>> { + pub(crate) fn from_bytes(bytes: &[u8]) -> Result { let pk = VerificationKey::from_bytes(bytes).map_err(|_| MerkleTreeError::SerializationError)?; let mut u64_bytes = [0u8; 8]; diff --git a/mithril-stm/src/merkle_tree/path.rs b/mithril-stm/src/merkle_tree/path.rs index 565de41692a..bca8dc08023 100644 --- a/mithril-stm/src/merkle_tree/path.rs +++ b/mithril-stm/src/merkle_tree/path.rs @@ -43,7 +43,7 @@ impl MerklePath { /// Extract a `Path` from a byte slice. /// # Error /// This function fails if the bytes cannot retrieve path. - pub fn from_bytes(bytes: &[u8]) -> Result, MerkleTreeError> { + pub fn from_bytes(bytes: &[u8]) -> Result, MerkleTreeError> { let mut u64_bytes = [0u8; 8]; u64_bytes.copy_from_slice(bytes.get(..8).ok_or(MerkleTreeError::SerializationError)?); let index = usize::try_from(u64::from_be_bytes(u64_bytes)) @@ -118,7 +118,7 @@ impl MerkleBatchPath { } /// Try to convert a byte string into a `BatchPath`. - pub fn from_bytes(bytes: &[u8]) -> Result> { + pub fn from_bytes(bytes: &[u8]) -> Result { let mut u64_bytes = [0u8; 8]; u64_bytes.copy_from_slice(&bytes[..8]); let len_v = usize::try_from(u64::from_be_bytes(u64_bytes)) diff --git a/mithril-stm/src/merkle_tree/tree.rs b/mithril-stm/src/merkle_tree/tree.rs index 3fae57f6d71..7d624540dd6 100644 --- a/mithril-stm/src/merkle_tree/tree.rs +++ b/mithril-stm/src/merkle_tree/tree.rs @@ -194,7 +194,7 @@ impl MerkleTree { /// Try to convert a byte string into a `MerkleTree`. /// # Error /// It returns error if conversion fails. - pub fn from_bytes(bytes: &[u8]) -> Result> { + pub fn from_bytes(bytes: &[u8]) -> Result { let mut u64_bytes = [0u8; 8]; u64_bytes.copy_from_slice(bytes.get(..8).ok_or(MerkleTreeError::SerializationError)?); let n = usize::try_from(u64::from_be_bytes(u64_bytes)) From ff75c7a5dc1ddb8059239f9a8041a98253af5e70 Mon Sep 17 00:00:00 2001 From: curiecrypt Date: Fri, 7 Nov 2025 15:08:30 +0300 Subject: [PATCH 04/11] aggregate signature with StmResult --- .../src/aggregate_signature/basic_verifier.rs | 22 ++++--- mithril-stm/src/aggregate_signature/clerk.rs | 23 ++++--- .../proof/concatenation.rs | 12 ++-- .../src/aggregate_signature/signature.rs | 60 ++++++++----------- 4 files changed, 60 insertions(+), 57 deletions(-) diff --git a/mithril-stm/src/aggregate_signature/basic_verifier.rs b/mithril-stm/src/aggregate_signature/basic_verifier.rs index ab59658650f..57e4bb49f6d 100644 --- a/mithril-stm/src/aggregate_signature/basic_verifier.rs +++ b/mithril-stm/src/aggregate_signature/basic_verifier.rs @@ -1,3 +1,4 @@ +use anyhow::anyhow; use std::collections::{BTreeMap, HashMap, HashSet}; use crate::bls_multi_signature::{BlsSignature, BlsVerificationKey}; @@ -5,7 +6,7 @@ use crate::key_registration::RegisteredParty; use crate::merkle_tree::MerkleTreeLeaf; use crate::{ AggregationError, CoreVerifierError, Index, Parameters, SingleSignature, - SingleSignatureWithRegisteredParty, Stake, + SingleSignatureWithRegisteredParty, Stake, StmResult, }; /// Full node verifier including the list of eligible signers and the total stake of the system. @@ -56,7 +57,7 @@ impl BasicVerifier { signatures: &[SingleSignatureWithRegisteredParty], parameters: &Parameters, msg: &[u8], - ) -> Result<(), CoreVerifierError> { + ) -> StmResult<()> { let mut nr_indices = 0; let mut unique_indices = HashSet::new(); @@ -71,10 +72,13 @@ impl BasicVerifier { } if nr_indices != unique_indices.len() { - return Err(CoreVerifierError::IndexNotUnique); + return Err(anyhow!(CoreVerifierError::IndexNotUnique)); } if (nr_indices as u64) < parameters.k { - return Err(CoreVerifierError::NoQuorum(nr_indices as u64, parameters.k)); + return Err(anyhow!(CoreVerifierError::NoQuorum( + nr_indices as u64, + parameters.k + ))); } Ok(()) @@ -93,7 +97,7 @@ impl BasicVerifier { params: &Parameters, msg: &[u8], sigs: &[SingleSignatureWithRegisteredParty], - ) -> Result, AggregationError> { + ) -> StmResult> { let mut sig_by_index: BTreeMap = BTreeMap::new(); let mut removal_idx_by_vk: HashMap<&SingleSignatureWithRegisteredParty, Vec> = @@ -169,7 +173,9 @@ impl BasicVerifier { } } } - Err(AggregationError::NotEnoughSignatures(count, params.k)) + Err(anyhow!(AggregationError::NotEnoughSignatures( + count, params.k + ))) } /// Given a slice of `sig_reg_list`, this function returns a new list of `sig_reg_list` with only valid indices. @@ -189,7 +195,7 @@ impl BasicVerifier { params: &Parameters, msg: &[u8], sigs: &[SingleSignatureWithRegisteredParty], - ) -> Result, AggregationError> { + ) -> StmResult> { Self::select_valid_signatures_for_k_indices(total_stake, params, msg, sigs) } @@ -218,7 +224,7 @@ impl BasicVerifier { signatures: &[SingleSignature], parameters: &Parameters, msg: &[u8], - ) -> Result<(), CoreVerifierError> { + ) -> StmResult<()> { let sig_reg_list = signatures .iter() .map(|sig| SingleSignatureWithRegisteredParty { diff --git a/mithril-stm/src/aggregate_signature/clerk.rs b/mithril-stm/src/aggregate_signature/clerk.rs index 62fe9459587..a1f20a38bd7 100644 --- a/mithril-stm/src/aggregate_signature/clerk.rs +++ b/mithril-stm/src/aggregate_signature/clerk.rs @@ -1,10 +1,15 @@ -use blake2::digest::{Digest, FixedOutput}; - use crate::{ - AggregateSignature, AggregateSignatureType, AggregateVerificationKey, AggregationError, - ClosedKeyRegistration, Index, Parameters, Signer, SingleSignature, Stake, VerificationKey, + AggregateSignature, AggregateSignatureType, AggregateVerificationKey, ClosedKeyRegistration, + Index, Parameters, Signer, SingleSignature, Stake, StmResult, VerificationKey, aggregate_signature::ConcatenationProof, }; +use blake2::digest::{Digest, FixedOutput}; + +#[cfg(feature = "future_proof_system")] +use anyhow::anyhow; + +#[cfg(feature = "future_proof_system")] +use crate::AggregationError; /// `Clerk` can verify and aggregate `SingleSignature`s and verify `AggregateSignature`s. /// Clerks can only be generated with the registration closed. @@ -62,7 +67,7 @@ impl Clerk { &self, sigs: &[SingleSignature], msg: &[u8], - ) -> Result, AggregationError> { + ) -> StmResult> { self.aggregate_signatures_with_type(sigs, msg, AggregateSignatureType::default()) } @@ -72,14 +77,14 @@ impl Clerk { sigs: &[SingleSignature], msg: &[u8], aggregate_signature_type: AggregateSignatureType, - ) -> Result, AggregationError> { + ) -> StmResult> { match aggregate_signature_type { AggregateSignatureType::Concatenation => Ok(AggregateSignature::Concatenation( ConcatenationProof::aggregate_signatures(self, sigs, msg)?, )), #[cfg(feature = "future_proof_system")] - AggregateSignatureType::Future => Err(AggregationError::UnsupportedProofSystem( - aggregate_signature_type, + AggregateSignatureType::Future => Err(anyhow!( + AggregationError::UnsupportedProofSystem(aggregate_signature_type) )), } } @@ -96,7 +101,7 @@ impl Clerk { &self, sigs: &[SingleSignature], msg: &[u8], - ) -> Result, AggregationError> { + ) -> StmResult> { Self::aggregate_signatures(self, sigs, msg) } diff --git a/mithril-stm/src/aggregate_signature/proof/concatenation.rs b/mithril-stm/src/aggregate_signature/proof/concatenation.rs index e019f9e7fcf..8b1b47c6236 100644 --- a/mithril-stm/src/aggregate_signature/proof/concatenation.rs +++ b/mithril-stm/src/aggregate_signature/proof/concatenation.rs @@ -7,8 +7,8 @@ use crate::bls_multi_signature::{BlsSignature, BlsVerificationKey}; use crate::key_registration::RegisteredParty; use crate::merkle_tree::MerkleBatchPath; use crate::{ - AggregateVerificationKey, AggregationError, BasicVerifier, Parameters, SingleSignature, - SingleSignatureWithRegisteredParty, StmAggregateSignatureError, + AggregateVerificationKey, BasicVerifier, Parameters, SingleSignature, + SingleSignatureWithRegisteredParty, StmAggregateSignatureError, StmResult, }; /// `ConcatenationProof` uses the "concatenation" proving system (as described in Section 4.3 of the original paper.) @@ -36,7 +36,7 @@ impl ConcatenationProof { clerk: &Clerk, sigs: &[SingleSignature], msg: &[u8], - ) -> Result, AggregationError> { + ) -> StmResult> { let sig_reg_list = sigs .iter() .map(|sig| SingleSignatureWithRegisteredParty { @@ -83,7 +83,7 @@ impl ConcatenationProof { msg: &[u8], avk: &AggregateVerificationKey, parameters: &Parameters, - ) -> Result<(Vec, Vec), StmAggregateSignatureError> { + ) -> StmResult<(Vec, Vec)> { let msgp = avk.get_merkle_tree_batch_commitment().concatenate_with_message(msg); BasicVerifier::preliminary_verify( &avk.get_total_stake(), @@ -117,7 +117,7 @@ impl ConcatenationProof { msg: &[u8], avk: &AggregateVerificationKey, parameters: &Parameters, - ) -> Result<(), StmAggregateSignatureError> { + ) -> StmResult<()> { let msgp = avk.get_merkle_tree_batch_commitment().concatenate_with_message(msg); let (sigs, vks) = self.preliminary_verify(msg, avk, parameters)?; @@ -131,7 +131,7 @@ impl ConcatenationProof { msgs: &[Vec], avks: &[AggregateVerificationKey], parameters: &[Parameters], - ) -> Result<(), StmAggregateSignatureError> { + ) -> StmResult<()> { let batch_size = stm_signatures.len(); assert_eq!( batch_size, diff --git a/mithril-stm/src/aggregate_signature/signature.rs b/mithril-stm/src/aggregate_signature/signature.rs index 31ca7e84797..dc3e80585b4 100644 --- a/mithril-stm/src/aggregate_signature/signature.rs +++ b/mithril-stm/src/aggregate_signature/signature.rs @@ -1,3 +1,4 @@ +use anyhow::anyhow; use std::collections::HashMap; use std::fmt::Display; use std::hash::Hash; @@ -7,7 +8,7 @@ use serde::{Deserialize, Serialize}; use crate::error::StmAggregateSignatureError; use crate::merkle_tree::MerkleBatchPath; -use crate::{AggregateVerificationKey, Parameters}; +use crate::{AggregateVerificationKey, Parameters, StmResult}; use super::ConcatenationProof; @@ -95,14 +96,14 @@ impl AggregateSignature { msg: &[u8], avk: &AggregateVerificationKey, parameters: &Parameters, - ) -> Result<(), StmAggregateSignatureError> { + ) -> StmResult<()> { match self { AggregateSignature::Concatenation(concatenation_proof) => { concatenation_proof.verify(msg, avk, parameters) } #[cfg(feature = "future_proof_system")] - AggregateSignature::Future => Err(StmAggregateSignatureError::UnsupportedProofSystem( - self.into(), + AggregateSignature::Future => Err(anyhow!( + StmAggregateSignatureError::UnsupportedProofSystem(self.into()) )), } } @@ -113,42 +114,33 @@ impl AggregateSignature { msgs: &[Vec], avks: &[AggregateVerificationKey], parameters: &[Parameters], - ) -> Result<(), StmAggregateSignatureError> { + ) -> StmResult<()> { let stm_signatures: HashMap> = stm_signatures.iter().fold(HashMap::new(), |mut acc, sig| { acc.entry(sig.into()).or_default().push(sig.clone()); acc }); - stm_signatures - .into_iter() - .try_for_each(|(aggregate_signature_type, aggregate_signatures)| { - match aggregate_signature_type { - AggregateSignatureType::Concatenation => { - let aggregate_signatures_length = aggregate_signatures.len(); - let concatenation_proofs = aggregate_signatures - .into_iter() - .filter_map(|s| s.to_concatenation_proof().cloned()) - .collect::>(); - if concatenation_proofs.len() != aggregate_signatures_length { - return Err(StmAggregateSignatureError::BatchInvalid); - } - - ConcatenationProof::batch_verify( - &concatenation_proofs, - msgs, - avks, - parameters, - ) - } - #[cfg(feature = "future_proof_system")] - AggregateSignatureType::Future => { - Err(StmAggregateSignatureError::UnsupportedProofSystem( - aggregate_signature_type, - )) + stm_signatures.into_iter().try_for_each( + |(aggregate_signature_type, aggregate_signatures)| match aggregate_signature_type { + AggregateSignatureType::Concatenation => { + let aggregate_signatures_length = aggregate_signatures.len(); + let concatenation_proofs = aggregate_signatures + .into_iter() + .filter_map(|s| s.to_concatenation_proof().cloned()) + .collect::>(); + if concatenation_proofs.len() != aggregate_signatures_length { + return Err(anyhow!(StmAggregateSignatureError::BatchInvalid)); } + + ConcatenationProof::batch_verify(&concatenation_proofs, msgs, avks, parameters) } - }) - .map_err(|_| StmAggregateSignatureError::BatchInvalid) + #[cfg(feature = "future_proof_system")] + AggregateSignatureType::Future => Err(anyhow!( + StmAggregateSignatureError::UnsupportedProofSystem(aggregate_signature_type) + )), + }, + ) + // .map_err(|_| StmAggregateSignatureError::BatchInvalid) } /// Convert an aggregate signature to bytes @@ -171,7 +163,7 @@ impl AggregateSignature { } /// Extract an aggregate signature from a byte slice. - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> StmResult { let proof_type_byte = bytes.first().ok_or(StmAggregateSignatureError::SerializationError)?; let proof_bytes = &bytes[1..]; From bcd20e4525737c424e4de7a6939898f198feb75a Mon Sep 17 00:00:00 2001 From: curiecrypt Date: Fri, 7 Nov 2025 15:38:20 +0300 Subject: [PATCH 05/11] merkle tree with StmResult --- .../proof/concatenation.rs | 2 +- mithril-stm/src/merkle_tree/commitment.rs | 27 +++++++++---------- mithril-stm/src/merkle_tree/leaf.rs | 4 +-- mithril-stm/src/merkle_tree/path.rs | 8 +++--- mithril-stm/src/merkle_tree/tree.rs | 3 ++- 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/mithril-stm/src/aggregate_signature/proof/concatenation.rs b/mithril-stm/src/aggregate_signature/proof/concatenation.rs index 8b1b47c6236..bdb9fcca4f0 100644 --- a/mithril-stm/src/aggregate_signature/proof/concatenation.rs +++ b/mithril-stm/src/aggregate_signature/proof/concatenation.rs @@ -195,7 +195,7 @@ impl ConcatenationProof { } ///Extract a concatenation proof from a byte slice. - pub fn from_bytes(bytes: &[u8]) -> Result, StmAggregateSignatureError> { + pub fn from_bytes(bytes: &[u8]) -> StmResult> { let mut bytes_index = 0; let mut u64_bytes = [0u8; 8]; diff --git a/mithril-stm/src/merkle_tree/commitment.rs b/mithril-stm/src/merkle_tree/commitment.rs index 52eca880ddd..d768d5b4070 100644 --- a/mithril-stm/src/merkle_tree/commitment.rs +++ b/mithril-stm/src/merkle_tree/commitment.rs @@ -3,9 +3,10 @@ use std::marker::PhantomData; use blake2::digest::{Digest, FixedOutput}; use serde::{Deserialize, Serialize}; +use crate::StmResult; use crate::error::MerkleTreeError; use crate::merkle_tree::{MerkleBatchPath, MerklePath, MerkleTreeLeaf, parent, sibling}; - +use anyhow::anyhow; /// `MerkleTree` commitment. /// This structure differs from `MerkleTree` in that it does not contain all elements, which are not always necessary. /// Instead, it only contains the root of the tree. @@ -31,7 +32,7 @@ impl MerkleTreeCommitment { &self, val: &MerkleTreeLeaf, proof: &MerklePath, - ) -> Result<(), MerkleTreeError> + ) -> StmResult<()> where D: FixedOutput + Clone, { @@ -50,7 +51,7 @@ impl MerkleTreeCommitment { if h == self.root { return Ok(()); } - Err(MerkleTreeError::PathInvalid(proof.to_bytes())) + Err(anyhow!(MerkleTreeError::PathInvalid(proof.to_bytes()))) } /// Check an inclusion proof that `val` is part of the tree by traveling the whole path until the root. @@ -60,7 +61,7 @@ impl MerkleTreeCommitment { since = "0.5.0", note = "Use `verify_leaf_membership_from_path` instead" )] - pub fn check(&self, val: &MerkleTreeLeaf, proof: &MerklePath) -> Result<(), MerkleTreeError> + pub fn check(&self, val: &MerkleTreeLeaf, proof: &MerklePath) -> StmResult<()> where D: FixedOutput + Clone, { @@ -100,7 +101,7 @@ impl MerkleTreeCommitment { } /// Extract a `MerkleTreeCommitment` from a byte slice. - pub fn from_bytes(bytes: &[u8]) -> Result, MerkleTreeError> { + pub fn from_bytes(bytes: &[u8]) -> StmResult> { let root = bytes.to_vec(); Ok(Self { @@ -167,18 +168,18 @@ impl MerkleTreeBatchCommitment { &self, batch_val: &[MerkleTreeLeaf], proof: &MerkleBatchPath, - ) -> Result<(), MerkleTreeError> + ) -> StmResult<()> where D: FixedOutput + Clone, { if batch_val.len() != proof.indices.len() { - return Err(MerkleTreeError::BatchPathInvalid(proof.to_bytes())); + return Err(anyhow!(MerkleTreeError::BatchPathInvalid(proof.to_bytes()))); } let mut ordered_indices: Vec = proof.indices.clone(); ordered_indices.sort_unstable(); if ordered_indices != proof.indices { - return Err(MerkleTreeError::BatchPathInvalid(proof.to_bytes())); + return Err(anyhow!(MerkleTreeError::BatchPathInvalid(proof.to_bytes()))); } let nr_nodes = self.nr_leaves + self.nr_leaves.next_power_of_two() - 1; @@ -245,7 +246,7 @@ impl MerkleTreeBatchCommitment { return Ok(()); } - Err(MerkleTreeError::BatchPathInvalid(proof.to_bytes())) + Err(anyhow!(MerkleTreeError::BatchPathInvalid(proof.to_bytes()))) } /// Check a proof of a batched opening. The indices must be ordered. @@ -259,11 +260,7 @@ impl MerkleTreeBatchCommitment { since = "0.5.0", note = "Use `verify_leaves_membership_from_batch_path` instead" )] - pub fn check( - &self, - batch_val: &[MerkleTreeLeaf], - proof: &MerkleBatchPath, - ) -> Result<(), MerkleTreeError> + pub fn check(&self, batch_val: &[MerkleTreeLeaf], proof: &MerkleBatchPath) -> StmResult<()> where D: FixedOutput + Clone, { @@ -282,7 +279,7 @@ impl MerkleTreeBatchCommitment { } /// Extract a `MerkleTreeBatchCommitment` from a byte slice. - pub fn from_bytes(bytes: &[u8]) -> Result, MerkleTreeError> { + pub fn from_bytes(bytes: &[u8]) -> StmResult> { let mut u64_bytes = [0u8; 8]; u64_bytes.copy_from_slice(bytes.get(..8).ok_or(MerkleTreeError::SerializationError)?); let nr_leaves = usize::try_from(u64::from_be_bytes(u64_bytes)) diff --git a/mithril-stm/src/merkle_tree/leaf.rs b/mithril-stm/src/merkle_tree/leaf.rs index 72febeca975..de01655d850 100644 --- a/mithril-stm/src/merkle_tree/leaf.rs +++ b/mithril-stm/src/merkle_tree/leaf.rs @@ -2,17 +2,17 @@ use std::cmp::Ordering; use serde::{Deserialize, Serialize}; +use crate::StmResult; use crate::bls_multi_signature::BlsVerificationKey; use crate::error::MerkleTreeError; use crate::{Stake, VerificationKey}; - /// The values that are committed in the Merkle Tree. /// Namely, a verified `VerificationKey` and its corresponding stake. #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, Hash)] pub struct MerkleTreeLeaf(pub BlsVerificationKey, pub Stake); impl MerkleTreeLeaf { - pub(crate) fn from_bytes(bytes: &[u8]) -> Result { + pub(crate) fn from_bytes(bytes: &[u8]) -> StmResult { let pk = VerificationKey::from_bytes(bytes).map_err(|_| MerkleTreeError::SerializationError)?; let mut u64_bytes = [0u8; 8]; diff --git a/mithril-stm/src/merkle_tree/path.rs b/mithril-stm/src/merkle_tree/path.rs index bca8dc08023..5ba011bffa0 100644 --- a/mithril-stm/src/merkle_tree/path.rs +++ b/mithril-stm/src/merkle_tree/path.rs @@ -1,10 +1,10 @@ use std::marker::PhantomData; +use crate::StmResult; +use crate::error::MerkleTreeError; use blake2::digest::{Digest, FixedOutput}; use serde::{Deserialize, Serialize}; -use crate::error::MerkleTreeError; - /// Path of hashes from root to leaf in a Merkle Tree. /// Contains all hashes on the path, and the index of the leaf. /// Used to verify that signatures come from eligible signers. @@ -43,7 +43,7 @@ impl MerklePath { /// Extract a `Path` from a byte slice. /// # Error /// This function fails if the bytes cannot retrieve path. - pub fn from_bytes(bytes: &[u8]) -> Result, MerkleTreeError> { + pub fn from_bytes(bytes: &[u8]) -> StmResult> { let mut u64_bytes = [0u8; 8]; u64_bytes.copy_from_slice(bytes.get(..8).ok_or(MerkleTreeError::SerializationError)?); let index = usize::try_from(u64::from_be_bytes(u64_bytes)) @@ -118,7 +118,7 @@ impl MerkleBatchPath { } /// Try to convert a byte string into a `BatchPath`. - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> StmResult { let mut u64_bytes = [0u8; 8]; u64_bytes.copy_from_slice(&bytes[..8]); let len_v = usize::try_from(u64::from_be_bytes(u64_bytes)) diff --git a/mithril-stm/src/merkle_tree/tree.rs b/mithril-stm/src/merkle_tree/tree.rs index 7d624540dd6..68c947f1504 100644 --- a/mithril-stm/src/merkle_tree/tree.rs +++ b/mithril-stm/src/merkle_tree/tree.rs @@ -3,6 +3,7 @@ use std::marker::PhantomData; use blake2::digest::{Digest, FixedOutput}; use serde::{Deserialize, Serialize}; +use crate::StmResult; use crate::error::MerkleTreeError; use crate::merkle_tree::{ MerkleBatchPath, MerklePath, MerkleTreeBatchCommitment, MerkleTreeCommitment, MerkleTreeLeaf, @@ -194,7 +195,7 @@ impl MerkleTree { /// Try to convert a byte string into a `MerkleTree`. /// # Error /// It returns error if conversion fails. - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> StmResult { let mut u64_bytes = [0u8; 8]; u64_bytes.copy_from_slice(bytes.get(..8).ok_or(MerkleTreeError::SerializationError)?); let n = usize::try_from(u64::from_be_bytes(u64_bytes)) From a7364edc260bebf8cd8dc96e66ba092004bad9f9 Mon Sep 17 00:00:00 2001 From: curiecrypt Date: Fri, 7 Nov 2025 15:41:32 +0300 Subject: [PATCH 06/11] participant with StmResult --- mithril-stm/src/participant/initializer.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mithril-stm/src/participant/initializer.rs b/mithril-stm/src/participant/initializer.rs index 63e428511c5..5471e25adfb 100644 --- a/mithril-stm/src/participant/initializer.rs +++ b/mithril-stm/src/participant/initializer.rs @@ -4,8 +4,9 @@ use rand_core::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; use crate::bls_multi_signature::{BlsSigningKey, BlsVerificationKeyProofOfPossession}; -use crate::key_registration::*; use crate::{Parameters, RegisterError, Signer, Stake}; +use crate::{StmResult, key_registration::*}; +use anyhow::anyhow; /// Wrapper of the MultiSignature Verification key with proof of possession pub type VerificationKeyProofOfPossession = BlsVerificationKeyProofOfPossession; @@ -75,7 +76,7 @@ impl Initializer { pub fn create_signer( self, closed_reg: ClosedKeyRegistration, - ) -> Result, RegisterError> { + ) -> StmResult> { let mut my_index = None; for (i, rp) in closed_reg.reg_parties.iter().enumerate() { if rp.0 == self.pk.vk { @@ -84,7 +85,7 @@ impl Initializer { } } if my_index.is_none() { - return Err(RegisterError::UnregisteredInitializer); + return Err(anyhow!(RegisterError::UnregisteredInitializer)); } Ok(Signer::set_signer( @@ -113,7 +114,7 @@ impl Initializer { pub fn new_signer( self, closed_reg: ClosedKeyRegistration, - ) -> Result, RegisterError> { + ) -> StmResult> { Self::create_signer(self, closed_reg) } @@ -177,7 +178,7 @@ impl Initializer { /// Convert a slice of bytes to an `Initializer` /// # Error /// The function fails if the given string of bytes is not of required size. - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> StmResult { let mut u64_bytes = [0u8; 8]; u64_bytes.copy_from_slice(bytes.get(..8).ok_or(RegisterError::SerializationError)?); let stake = u64::from_be_bytes(u64_bytes); From 678a747c13d91a62488a4c537c4695fdf1b3f849 Mon Sep 17 00:00:00 2001 From: curiecrypt Date: Fri, 7 Nov 2025 15:46:20 +0300 Subject: [PATCH 07/11] single signature with StmResult --- mithril-stm/src/single_signature/signature.rs | 22 ++++++++++--------- .../signature_registered_party.rs | 3 ++- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/mithril-stm/src/single_signature/signature.rs b/mithril-stm/src/single_signature/signature.rs index 4094998f369..43bf8140190 100644 --- a/mithril-stm/src/single_signature/signature.rs +++ b/mithril-stm/src/single_signature/signature.rs @@ -9,8 +9,10 @@ use serde::{Deserialize, Serialize}; use crate::bls_multi_signature::BlsSignature; use crate::eligibility_check::is_lottery_won; use crate::{ - AggregateVerificationKey, Index, Parameters, Stake, StmSignatureError, VerificationKey, + AggregateVerificationKey, Index, Parameters, Stake, StmResult, StmSignatureError, + VerificationKey, }; +use anyhow::anyhow; /// Signature created by a single party who has won the lottery. #[derive(Debug, Clone, Serialize, Deserialize)] @@ -33,7 +35,7 @@ impl SingleSignature { stake: &Stake, avk: &AggregateVerificationKey, msg: &[u8], - ) -> Result<(), StmSignatureError> { + ) -> StmResult<()> { let msgp = avk.get_merkle_tree_batch_commitment().concatenate_with_message(msg); self.basic_verify(params, pk, stake, &msgp, &avk.get_total_stake())?; Ok(()) @@ -46,16 +48,18 @@ impl SingleSignature { stake: &Stake, msg: &[u8], total_stake: &Stake, - ) -> Result<(), StmSignatureError> { + ) -> StmResult<()> { for &index in &self.indexes { if index > params.m { - return Err(StmSignatureError::IndexBoundFailed(index, params.m)); + return Err(anyhow!(StmSignatureError::IndexBoundFailed( + index, params.m + ))); } let ev = self.sigma.evaluate_dense_mapping(msg, index); if !is_lottery_won(params.phi_f, ev, *stake, *total_stake) { - return Err(StmSignatureError::LotteryLost); + return Err(anyhow!(StmSignatureError::LotteryLost)); } } @@ -86,9 +90,7 @@ impl SingleSignature { } /// Extract a batch compatible `SingleSignature` from a byte slice. - pub fn from_bytes( - bytes: &[u8], - ) -> Result { + pub fn from_bytes(bytes: &[u8]) -> StmResult { let mut u64_bytes = [0u8; 8]; u64_bytes.copy_from_slice(bytes.get(0..8).ok_or(StmSignatureError::SerializationError)?); @@ -145,7 +147,7 @@ impl SingleSignature { stake: &Stake, msg: &[u8], total_stake: &Stake, - ) -> Result<(), StmSignatureError> { + ) -> StmResult<()> { self.sigma.verify(msg, pk)?; self.check_indices(params, stake, msg, total_stake)?; @@ -161,7 +163,7 @@ impl SingleSignature { stake: &Stake, msg: &[u8], total_stake: &Stake, - ) -> Result<(), StmSignatureError> { + ) -> StmResult<()> { Self::basic_verify(self, params, pk, stake, msg, total_stake) } } diff --git a/mithril-stm/src/single_signature/signature_registered_party.rs b/mithril-stm/src/single_signature/signature_registered_party.rs index 80169a12e1e..23c176e2a13 100644 --- a/mithril-stm/src/single_signature/signature_registered_party.rs +++ b/mithril-stm/src/single_signature/signature_registered_party.rs @@ -1,6 +1,7 @@ use blake2::digest::{Digest, FixedOutput}; use serde::{Deserialize, Serialize, Serializer, ser::SerializeTuple}; +use crate::StmResult; use crate::key_registration::RegisteredParty; use crate::{SingleSignature, StmSignatureError}; @@ -28,7 +29,7 @@ impl SingleSignatureWithRegisteredParty { ///Extract a `SingleSignatureWithRegisteredParty` from a byte slice. pub fn from_bytes( bytes: &[u8], - ) -> Result { + ) -> StmResult { let reg_party = RegisteredParty::from_bytes( bytes.get(0..104).ok_or(StmSignatureError::SerializationError)?, )?; From 0b3b96f6edd16dc2522d27b92e8604873be4c039 Mon Sep 17 00:00:00 2001 From: curiecrypt Date: Fri, 7 Nov 2025 15:48:18 +0300 Subject: [PATCH 08/11] key reg with StmResult --- mithril-stm/src/key_registration.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mithril-stm/src/key_registration.rs b/mithril-stm/src/key_registration.rs index 839ea005267..82d9fa5eb9b 100644 --- a/mithril-stm/src/key_registration.rs +++ b/mithril-stm/src/key_registration.rs @@ -4,12 +4,13 @@ use std::{ sync::Arc, }; +use anyhow::anyhow; use blake2::digest::{Digest, FixedOutput}; -use crate::Stake; use crate::bls_multi_signature::{BlsVerificationKey, BlsVerificationKeyProofOfPossession}; use crate::error::RegisterError; use crate::merkle_tree::{MerkleTree, MerkleTreeLeaf}; +use crate::{Stake, StmResult}; /// Stores a registered party with its public key and the associated stake. pub type RegisteredParty = MerkleTreeLeaf; @@ -35,13 +36,13 @@ impl KeyRegistration { &mut self, stake: Stake, pk: BlsVerificationKeyProofOfPossession, - ) -> Result<(), RegisterError> { + ) -> StmResult<()> { if let Entry::Vacant(e) = self.keys.entry(pk.vk) { pk.verify_proof_of_possession()?; e.insert(stake); return Ok(()); } - Err(RegisterError::KeyRegistered(Box::new(pk.vk))) + Err(anyhow!(RegisterError::KeyRegistered(Box::new(pk.vk)))) } /// Finalize the key registration. From 328a1d25c78004a14d2a54cec1060649e5d2cd1f Mon Sep 17 00:00:00 2001 From: curiecrypt Date: Fri, 7 Nov 2025 16:38:29 +0300 Subject: [PATCH 09/11] bls sig StmResult --- mithril-stm/src/bls_multi_signature/helper.rs | 12 ++++-- .../proof_of_possession.rs | 15 +++++--- .../src/bls_multi_signature/signature.rs | 38 ++++++++++--------- .../src/bls_multi_signature/signing_key.rs | 7 ++-- .../bls_multi_signature/verification_key.rs | 24 +++++++----- mithril-stm/src/error.rs | 32 ++++++++++++++++ 6 files changed, 88 insertions(+), 40 deletions(-) diff --git a/mithril-stm/src/bls_multi_signature/helper.rs b/mithril-stm/src/bls_multi_signature/helper.rs index d2be6e32d16..bdc09056fee 100644 --- a/mithril-stm/src/bls_multi_signature/helper.rs +++ b/mithril-stm/src/bls_multi_signature/helper.rs @@ -1,4 +1,5 @@ pub(crate) mod unsafe_helpers { + use anyhow::anyhow; use blst::{ blst_fp12, blst_fp12_finalverify, blst_p1, blst_p1_affine, blst_p1_affine_generator, blst_p1_compress, blst_p1_from_affine, blst_p1_to_affine, blst_p1_uncompress, blst_p2, @@ -7,8 +8,11 @@ pub(crate) mod unsafe_helpers { min_sig::{PublicKey as BlstVk, SecretKey as BlstSk, Signature as BlstSig}, }; - use crate::bls_multi_signature::{BlsProofOfPossession, BlsVerificationKey}; - use crate::error::{MultiSignatureError, MultiSignatureError::SerializationError}; + use crate::error::MultiSignatureError::SerializationError; + use crate::{ + StmResult, + bls_multi_signature::{BlsProofOfPossession, BlsVerificationKey}, + }; /// Check manually if the pairing `e(g1,mvk) = e(k2,g2)` holds. pub(crate) fn verify_pairing(vk: &BlsVerificationKey, pop: &BlsProofOfPossession) -> bool { @@ -33,7 +37,7 @@ pub(crate) mod unsafe_helpers { bytes } - pub(crate) fn uncompress_p1(bytes: &[u8]) -> Result { + pub(crate) fn uncompress_p1(bytes: &[u8]) -> StmResult { unsafe { if bytes.len() == 48 { let mut point = blst_p1_affine::default(); @@ -42,7 +46,7 @@ pub(crate) mod unsafe_helpers { blst_p1_from_affine(&mut out, &point); Ok(out) } else { - Err(SerializationError) + Err(anyhow!(SerializationError)) } } } diff --git a/mithril-stm/src/bls_multi_signature/proof_of_possession.rs b/mithril-stm/src/bls_multi_signature/proof_of_possession.rs index 86f60c7e329..ae645143db2 100644 --- a/mithril-stm/src/bls_multi_signature/proof_of_possession.rs +++ b/mithril-stm/src/bls_multi_signature/proof_of_possession.rs @@ -1,10 +1,13 @@ use blst::{blst_p1, min_sig::Signature as BlstSig}; -use crate::bls_multi_signature::{ - BlsSigningKey, POP, - helper::unsafe_helpers::{compress_p1, scalar_to_pk_in_g1, uncompress_p1}, +use crate::error::{MultiSignatureError, blst_error_to_stm_error}; +use crate::{ + StmResult, + bls_multi_signature::{ + BlsSigningKey, POP, + helper::unsafe_helpers::{compress_p1, scalar_to_pk_in_g1, uncompress_p1}, + }, }; -use crate::error::{MultiSignatureError, blst_err_to_mithril}; /// MultiSig proof of possession, which contains two elements from G1. However, /// the two elements have different types: `k1` is represented as a BlstSig @@ -33,13 +36,13 @@ impl BlsProofOfPossession { } /// Deserialize a byte string to a `PublicKeyPoP`. - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> StmResult { let k1 = match BlstSig::from_bytes( bytes.get(..48).ok_or(MultiSignatureError::SerializationError)?, ) { Ok(key) => key, Err(e) => { - return Err(blst_err_to_mithril(e, None, None) + return Err(blst_error_to_stm_error(e, None, None) .expect_err("If it passed, blst returns and error different to SUCCESS.")); } }; diff --git a/mithril-stm/src/bls_multi_signature/signature.rs b/mithril-stm/src/bls_multi_signature/signature.rs index 455af44a8e8..71a0ad5db93 100644 --- a/mithril-stm/src/bls_multi_signature/signature.rs +++ b/mithril-stm/src/bls_multi_signature/signature.rs @@ -1,3 +1,4 @@ +use anyhow::anyhow; use std::{cmp::Ordering, iter::Sum}; use blake2::{Blake2b, Blake2b512, Digest}; @@ -8,13 +9,16 @@ use blst::{ }; use digest::consts::U16; -use crate::bls_multi_signature::{ - BlsVerificationKey, - helper::unsafe_helpers::{p1_affine_to_sig, p2_affine_to_vk, sig_to_p1, vk_from_p2_affine}, -}; use crate::{ Index, - error::{MultiSignatureError, blst_err_to_mithril}, + error::{MultiSignatureError, blst_error_to_stm_error}, +}; +use crate::{ + StmResult, + bls_multi_signature::{ + BlsVerificationKey, + helper::unsafe_helpers::{p1_affine_to_sig, p2_affine_to_vk, sig_to_p1, vk_from_p2_affine}, + }, }; /// MultiSig signature, which is a wrapper over the `BlstSig` type. @@ -23,8 +27,8 @@ pub struct BlsSignature(pub BlstSig); impl BlsSignature { /// Verify a signature against a verification key. - pub fn verify(&self, msg: &[u8], mvk: &BlsVerificationKey) -> Result<(), MultiSignatureError> { - blst_err_to_mithril( + pub fn verify(&self, msg: &[u8], mvk: &BlsVerificationKey) -> StmResult<()> { + blst_error_to_stm_error( self.0.validate(true).map_or_else( |e| e, |_| { @@ -64,11 +68,11 @@ impl BlsSignature { /// /// # Error /// Returns an error if the byte string does not represent a point in the curve. - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> StmResult { let bytes = bytes.get(..48).ok_or(MultiSignatureError::SerializationError)?; match BlstSig::sig_validate(bytes, true) { Ok(sig) => Ok(Self(sig)), - Err(e) => Err(blst_err_to_mithril(e, None, None) + Err(e) => Err(blst_error_to_stm_error(e, None, None) .expect_err("If deserialization is not successful, blst returns and error different to SUCCESS.")) } } @@ -96,9 +100,9 @@ impl BlsSignature { pub fn aggregate( vks: &[BlsVerificationKey], sigs: &[BlsSignature], - ) -> Result<(BlsVerificationKey, BlsSignature), MultiSignatureError> { + ) -> StmResult<(BlsVerificationKey, BlsSignature)> { if vks.len() != sigs.len() || vks.is_empty() { - return Err(MultiSignatureError::AggregateSignatureInvalid); + return Err(anyhow!(MultiSignatureError::AggregateSignatureInvalid)); } if vks.len() < 2 { @@ -138,10 +142,10 @@ impl BlsSignature { msg: &[u8], vks: &[BlsVerificationKey], sigs: &[BlsSignature], - ) -> Result<(), MultiSignatureError> { + ) -> StmResult<()> { let (aggr_vk, aggr_sig) = Self::aggregate(vks, sigs)?; - blst_err_to_mithril( + blst_error_to_stm_error( aggr_sig.0.verify( false, msg, @@ -160,25 +164,25 @@ impl BlsSignature { msgs: &[Vec], vks: &[BlsVerificationKey], sigs: &[BlsSignature], - ) -> Result<(), MultiSignatureError> { + ) -> StmResult<()> { let batched_sig: BlstSig = match AggregateSignature::aggregate( &(sigs.iter().map(|sig| &sig.0).collect::>()), false, ) { Ok(sig) => BlstSig::from_aggregate(&sig), - Err(e) => return blst_err_to_mithril(e, None, None), + Err(e) => return blst_error_to_stm_error(e, None, None), }; let p2_vks: Vec = vks.iter().map(|vk| vk.to_blst_verification_key()).collect(); let p2_vks_ref: Vec<&BlstVk> = p2_vks.iter().collect(); let slice_msgs = msgs.iter().map(|msg| msg.as_slice()).collect::>(); - blst_err_to_mithril( + blst_error_to_stm_error( batched_sig.aggregate_verify(false, &slice_msgs, &[], &p2_vks_ref, false), None, None, ) - .map_err(|_| MultiSignatureError::BatchInvalid) + //.map_err(|_| MultiSignatureError::BatchInvalid) } } diff --git a/mithril-stm/src/bls_multi_signature/signing_key.rs b/mithril-stm/src/bls_multi_signature/signing_key.rs index 11985c08c7e..d3f0a18d85d 100644 --- a/mithril-stm/src/bls_multi_signature/signing_key.rs +++ b/mithril-stm/src/bls_multi_signature/signing_key.rs @@ -1,8 +1,9 @@ use blst::min_sig::SecretKey as BlstSk; use rand_core::{CryptoRng, RngCore}; +use crate::StmResult; use crate::bls_multi_signature::signature::BlsSignature; -use crate::error::{MultiSignatureError, blst_err_to_mithril}; +use crate::error::{MultiSignatureError, blst_error_to_stm_error}; /// MultiSig secret key, which is a wrapper over the BlstSk type from the blst /// library. @@ -34,11 +35,11 @@ impl BlsSigningKey { /// /// # Error /// Fails if the byte string represents a scalar larger than the group order. - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> StmResult { let bytes = bytes.get(..32).ok_or(MultiSignatureError::SerializationError)?; match BlstSk::from_bytes(bytes) { Ok(sk) => Ok(Self(sk)), - Err(e) => Err(blst_err_to_mithril(e, None, None) + Err(e) => Err(blst_error_to_stm_error(e, None, None) .expect_err("If deserialization is not successful, blst returns and error different to SUCCESS.")) } } diff --git a/mithril-stm/src/bls_multi_signature/verification_key.rs b/mithril-stm/src/bls_multi_signature/verification_key.rs index dfbebe2b197..f9e0182d6ce 100644 --- a/mithril-stm/src/bls_multi_signature/verification_key.rs +++ b/mithril-stm/src/bls_multi_signature/verification_key.rs @@ -1,3 +1,4 @@ +use anyhow::anyhow; use std::{ cmp::Ordering, fmt::{Display, Formatter}, @@ -11,10 +12,13 @@ use blst::{ }; use serde::{Deserialize, Serialize}; -use crate::bls_multi_signature::{ - BlsProofOfPossession, BlsSigningKey, POP, helper::unsafe_helpers::verify_pairing, +use crate::error::{MultiSignatureError, blst_error_to_stm_error}; +use crate::{ + StmResult, + bls_multi_signature::{ + BlsProofOfPossession, BlsSigningKey, POP, helper::unsafe_helpers::verify_pairing, + }, }; -use crate::error::{MultiSignatureError, blst_err_to_mithril}; /// MultiSig verification key, which is a wrapper over the BlstVk (element in G2) /// from the blst library. @@ -32,11 +36,11 @@ impl BlsVerificationKey { /// # Error /// This function fails if the bytes do not represent a compressed point of the prime /// order subgroup of the curve Bls12-381. - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> StmResult { let bytes = bytes.get(..96).ok_or(MultiSignatureError::SerializationError)?; match BlstVk::key_validate(bytes) { Ok(vk) => Ok(Self(vk)), - Err(e) => Err(blst_err_to_mithril(e, None, None) + Err(e) => Err(blst_error_to_stm_error(e, None, None) .expect_err("If deserialization is not successful, blst returns and error different to SUCCESS.")) } } @@ -136,7 +140,7 @@ impl BlsVerificationKeyProofOfPossession { /// manually. // If we are really looking for performance improvements, we can combine the // two final exponentiations (for verifying k1 and k2) into a single one. - pub(crate) fn verify_proof_of_possession(&self) -> Result<(), MultiSignatureError> { + pub(crate) fn verify_proof_of_possession(&self) -> StmResult<()> { match self.vk.to_blst_verification_key().validate() { Ok(_) => { let result = verify_pairing(&self.vk, &self.pop); @@ -150,11 +154,11 @@ impl BlsVerificationKeyProofOfPossession { ) == BLST_ERROR::BLST_SUCCESS && result) { - return Err(MultiSignatureError::KeyInvalid(Box::new(*self))); + return Err(anyhow!(MultiSignatureError::KeyInvalid(Box::new(*self)))); } Ok(()) } - Err(e) => blst_err_to_mithril(e, None, Some(self.vk)), + Err(e) => blst_error_to_stm_error(e, None, Some(self.vk)), } } @@ -168,7 +172,7 @@ impl BlsVerificationKeyProofOfPossession { since = "0.5.0", note = "The verification of the proof of possession is not part of the public API any more" )] - pub fn check(&self) -> Result<(), MultiSignatureError> { + pub fn check(&self) -> StmResult<()> { Self::verify_proof_of_possession(self) } @@ -186,7 +190,7 @@ impl BlsVerificationKeyProofOfPossession { } /// Deserialize a byte string to a `BlsVerificationKeyProofOfPossession`. - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> StmResult { let mvk = BlsVerificationKey::from_bytes( bytes.get(..96).ok_or(MultiSignatureError::SerializationError)?, )?; diff --git a/mithril-stm/src/error.rs b/mithril-stm/src/error.rs index 9dadcb0a532..e1efe91f7c3 100644 --- a/mithril-stm/src/error.rs +++ b/mithril-stm/src/error.rs @@ -1,6 +1,8 @@ //! Crate specific errors +use anyhow::anyhow; use blst::BLST_ERROR; +use crate::StmResult; use crate::aggregate_signature::AggregateSignatureType; use crate::bls_multi_signature::{ BlsSignature, BlsVerificationKey, BlsVerificationKeyProofOfPossession, @@ -283,6 +285,7 @@ impl From for RegisterError { /// If verifying a single signature, the signature should be provided. If verifying a multi-sig, /// no need to provide the signature +#[allow(dead_code)] pub(crate) fn blst_err_to_mithril( e: BLST_ERROR, sig: Option, @@ -309,3 +312,32 @@ pub(crate) fn blst_err_to_mithril( _ => Err(MultiSignatureError::SerializationError), } } + +pub(crate) fn blst_error_to_stm_error( + e: BLST_ERROR, + sig: Option, + key: Option, +) -> StmResult<()> { + match e { + BLST_ERROR::BLST_SUCCESS => Ok(()), + BLST_ERROR::BLST_PK_IS_INFINITY => { + if let Some(s) = sig { + return Err(anyhow!(MultiSignatureError::SignatureInfinity(s))); + } + if let Some(vk) = key { + return Err(anyhow!(MultiSignatureError::VerificationKeyInfinity( + Box::new(vk) + ))); + } + Err(anyhow!(MultiSignatureError::SerializationError)) + } + BLST_ERROR::BLST_VERIFY_FAIL => { + if let Some(s) = sig { + Err(anyhow!(MultiSignatureError::SignatureInvalid(s))) + } else { + Err(anyhow!(MultiSignatureError::AggregateSignatureInvalid)) + } + } + _ => Err(anyhow!(MultiSignatureError::SerializationError)), + } +} From 751b7bd8f1ced18bd42018e47e571fe944833393 Mon Sep 17 00:00:00 2001 From: curiecrypt Date: Mon, 10 Nov 2025 13:56:51 +0300 Subject: [PATCH 10/11] revising tests --- mithril-stm/src/aggregate_signature/mod.rs | 1140 ++++++++--------- mithril-stm/src/bls_multi_signature/mod.rs | 49 +- .../src/bls_multi_signature/signature.rs | 2 +- .../src/bls_multi_signature/signing_key.rs | 50 +- mithril-stm/src/key_registration.rs | 132 +- 5 files changed, 700 insertions(+), 673 deletions(-) diff --git a/mithril-stm/src/aggregate_signature/mod.rs b/mithril-stm/src/aggregate_signature/mod.rs index 39525a65490..9f712ca9d95 100644 --- a/mithril-stm/src/aggregate_signature/mod.rs +++ b/mithril-stm/src/aggregate_signature/mod.rs @@ -10,573 +10,573 @@ pub use clerk::*; pub use proof::*; pub use signature::*; -#[cfg(test)] -mod tests { - use std::collections::{HashMap, HashSet}; - - use blake2::{Blake2b, digest::consts::U32}; - use proptest::{ - collection::{hash_map, vec}, - prelude::*, - test_runner::{RngAlgorithm::ChaCha, TestRng}, - }; - use rand_chacha::ChaCha20Rng; - use rand_core::{RngCore, SeedableRng}; - - use crate::merkle_tree::MerkleBatchPath; - use crate::{ - AggregateSignature, AggregateSignatureType, AggregationError, BasicVerifier, Clerk, - CoreVerifierError, Initializer, KeyRegistration, Parameters, Signer, SingleSignature, - SingleSignatureWithRegisteredParty, Stake, bls_multi_signature::BlsVerificationKey, - }; - - type Sig = AggregateSignature; - type D = Blake2b; - - fn setup_equal_parties(params: Parameters, nparties: usize) -> Vec> { - let stake = vec![1; nparties]; - setup_parties(params, stake) - } - - fn setup_parties(params: Parameters, stake: Vec) -> Vec> { - let mut kr = KeyRegistration::init(); - let mut trng = TestRng::deterministic_rng(ChaCha); - let mut rng = ChaCha20Rng::from_seed(trng.random()); - - #[allow(clippy::needless_collect)] - let ps = stake - .into_iter() - .map(|stake| { - let p = Initializer::new(params, stake, &mut rng); - kr.register(stake, p.pk).unwrap(); - p - }) - .collect::>(); - let closed_reg = kr.close(); - ps.into_iter() - .map(|p| p.create_signer(closed_reg.clone()).unwrap()) - .collect() - } - - /// Generate a vector of stakes that should sum to `honest_stake` - /// when ignoring the indices in `adversaries` - fn arb_honest_for_adversaries( - num_parties: usize, - honest_stake: Stake, - adversaries: HashMap, - ) -> impl Strategy> { - vec(1..honest_stake, num_parties).prop_map(move |parties| { - let honest_sum = parties.iter().enumerate().fold(0, |acc, (i, s)| { - if !adversaries.contains_key(&i) { - acc + s - } else { - acc - } - }); - - parties - .iter() - .enumerate() - .map(|(i, s)| { - if let Some(a) = adversaries.get(&i) { - *a - } else { - (*s * honest_stake) / honest_sum - } - }) - .collect() - }) - } - - /// Generate a vector of `num_parties` stakes summing to `num_parties * total_stake`, - /// plus a subset S of 0..num_parties such that the sum of the stakes at indices - /// in S is adversary_stake * N - fn arb_parties_with_adversaries( - num_parties: usize, - num_adversaries: usize, - total_stake: Stake, - adversary_stake: Stake, - ) -> impl Strategy, Vec)> { - hash_map(0..num_parties, 1..total_stake, num_adversaries).prop_flat_map( - move |adversaries| { - let adversary_sum: Stake = adversaries.values().sum(); - let adversaries_normed = adversaries - .iter() - .map(|(a, stake)| (*a, (stake * adversary_stake) / adversary_sum)) - .collect(); - - let adversaries = adversaries.into_keys().collect(); - ( - Just(adversaries), - arb_honest_for_adversaries( - num_parties, - total_stake - adversary_stake, - adversaries_normed, - ), - ) - }, - ) - } - - fn find_signatures(msg: &[u8], ps: &[Signer], is: &[usize]) -> Vec { - let mut sigs = Vec::new(); - for i in is { - if let Some(sig) = ps[*i].sign(msg) { - sigs.push(sig); - } - } - sigs - } - - /// Pick N between min and max, and then - /// generate a vector of N stakes summing to N * tstake, - /// plus a subset S of 0..N such that the sum of the stakes at indices - /// in S is astake * N - fn arb_parties_adversary_stake( - min: usize, - max: usize, - tstake: Stake, - astake: Stake, - ) -> impl Strategy, Vec)> { - (min..max) - .prop_flat_map(|n| (Just(n), 1..=n / 2)) - .prop_flat_map(move |(n, nadv)| { - arb_parties_with_adversaries(n, nadv, tstake * n as Stake, astake * n as Stake) - }) - } - - #[derive(Debug)] - struct ProofTest { - msig: Result, - clerk: Clerk, - msg: [u8; 16], - } - /// Run the protocol up to aggregation. This will produce a valid aggregation of signatures. - /// The following tests mutate this aggregation so that the proof is no longer valid. - fn arb_proof_setup(max_parties: usize) -> impl Strategy { - any::<[u8; 16]>().prop_flat_map(move |msg| { - (2..max_parties).prop_map(move |n| { - let params = Parameters { - m: 5, - k: 5, - phi_f: 1.0, - }; - let ps = setup_equal_parties(params, n); - let clerk = Clerk::new_clerk_from_signer(&ps[0]); - - let all_ps: Vec = (0..n).collect(); - let sigs = find_signatures(&msg, &ps, &all_ps); - - let aggr_sig_type = AggregateSignatureType::Concatenation; - let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); - ProofTest { msig, clerk, msg } - }) - }) - } - - fn with_proof_mod(mut tc: ProofTest, f: F) - where - F: Fn(&mut Sig, &mut Clerk, &mut [u8; 16]), - { - match tc.msig { - Ok(mut aggr) => { - f(&mut aggr, &mut tc.clerk, &mut tc.msg); - assert!( - aggr.verify( - &tc.msg, - &tc.clerk.compute_aggregate_verification_key(), - &tc.clerk.params - ) - .is_err() - ) - } - Err(e) => unreachable!("Reached an unexpected error: {:?}", e), - } - } - - proptest! { - #![proptest_config(ProptestConfig::with_cases(50))] - - #[test] - /// Test that `dedup_sigs_for_indices` only takes valid signatures. - fn test_dedup(msg in any::<[u8; 16]>()) { - let false_msg = [1u8; 20]; - let params = Parameters { m: 1, k: 1, phi_f: 1.0 }; - let ps = setup_equal_parties(params, 1); - let clerk = Clerk::new_clerk_from_signer(&ps[0]); - let avk = clerk.compute_aggregate_verification_key(); - let mut sigs = Vec::with_capacity(2); - - if let Some(sig) = ps[0].sign(&false_msg) { - sigs.push(sig); - } - - if let Some(sig) = ps[0].sign(&msg) { - sigs.push(sig); - } - - let sig_reg_list = sigs - .iter() - .map(|sig| SingleSignatureWithRegisteredParty { - sig: sig.clone(), - reg_party: clerk.closed_reg.reg_parties[sig.signer_index as usize], - }) - .collect::>(); - - let msgp = avk.get_merkle_tree_batch_commitment().concatenate_with_message(&msg); - let dedup_result = BasicVerifier::select_valid_signatures_for_k_indices( - &clerk.closed_reg.total_stake, - ¶ms, - &msgp, - &sig_reg_list, - ); - assert!(dedup_result.is_ok(), "dedup failure {dedup_result:?}"); - for passed_sigs in dedup_result.unwrap() { - let verify_result = passed_sigs.sig.verify(¶ms, &ps[0].get_verification_key(), &ps[0].get_stake(), &avk, &msg); - assert!(verify_result.is_ok(), "verify {verify_result:?}"); - } - } - } - - proptest! { - #![proptest_config(ProptestConfig::with_cases(50))] - - #[test] - /// Test that when a quorum is found, the aggregate signature can be verified by anyone with - /// access to the avk and the parameters. - fn test_aggregate_sig(nparties in 2_usize..30, - m in 10_u64..20, - k in 1_u64..5, - msg in any::<[u8;16]>()) { - let params = Parameters { m, k, phi_f: 0.2 }; - let ps = setup_equal_parties(params, nparties); - let clerk = Clerk::new_clerk_from_signer(&ps[0]); - let aggr_sig_type = AggregateSignatureType::Concatenation; - - let all_ps: Vec = (0..nparties).collect(); - let sigs = find_signatures(&msg, &ps, &all_ps); - let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); - - match msig { - Ok(aggr) => { - let verify_result = aggr.verify(&msg, &clerk.compute_aggregate_verification_key(), ¶ms); - assert!(verify_result.is_ok(), "Verification failed: {verify_result:?}"); - } - Err(AggregationError::NotEnoughSignatures(n, k)) => - assert!(n < params.k || k == params.k), - Err(AggregationError::UsizeConversionInvalid) => - unreachable!(), - Err(AggregationError::UnsupportedProofSystem(_)) => - unreachable!(), - } - } - - #[test] - /// Test that batch verification of certificates works - fn batch_verify(nparties in 2_usize..30, - m in 10_u64..20, - k in 1_u64..4, - seed in any::<[u8;32]>(), - batch_size in 2..10, - ) { - let aggr_sig_type = AggregateSignatureType::Concatenation; - let mut rng = ChaCha20Rng::from_seed(seed); - let mut aggr_avks = Vec::new(); - let mut aggr_stms = Vec::new(); - let mut batch_msgs = Vec::new(); - let mut batch_params = Vec::new(); - for _ in 0..batch_size { - let mut msg = [0u8; 32]; - rng.fill_bytes(&mut msg); - let params = Parameters { m, k, phi_f: 0.95 }; - let ps = setup_equal_parties(params, nparties); - let clerk = Clerk::new_clerk_from_signer(&ps[0]); - - let all_ps: Vec = (0..nparties).collect(); - let sigs = find_signatures(&msg, &ps, &all_ps); - let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); - - match msig { - Ok(aggr) => { - aggr_avks.push(clerk.compute_aggregate_verification_key()); - aggr_stms.push(aggr); - batch_msgs.push(msg.to_vec()); - batch_params.push(params); - } - Err(AggregationError::NotEnoughSignatures(_n, _k)) => { - assert!(sigs.len() < params.k as usize) - } - Err(AggregationError::UsizeConversionInvalid) => unreachable!(), - Err(AggregationError::UnsupportedProofSystem(_)) => unreachable!(), - } - } - - assert!(AggregateSignature::batch_verify(&aggr_stms, &batch_msgs, &aggr_avks, &batch_params).is_ok()); - - let mut msg = [0u8; 32]; - rng.fill_bytes(&mut msg); - let params = Parameters { m, k, phi_f: 0.8 }; - let ps = setup_equal_parties(params, nparties); - let clerk = Clerk::new_clerk_from_signer(&ps[0]); - - let all_ps: Vec = (0..nparties).collect(); - let sigs = find_signatures(&msg, &ps, &all_ps); - let fake_msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); - - aggr_stms[0] = fake_msig.unwrap(); - assert!(AggregateSignature::batch_verify(&aggr_stms, &batch_msgs, &aggr_avks, &batch_params).is_err()); - } - } - - proptest! { - #[test] - /// Test that when a party creates a signature it can be verified - fn test_sig(msg in any::<[u8;16]>()) { - let params = Parameters { m: 1, k: 1, phi_f: 0.2 }; - let ps = setup_equal_parties(params, 1); - let clerk = Clerk::new_clerk_from_signer(&ps[0]); - let avk = clerk.compute_aggregate_verification_key(); - - if let Some(sig) = ps[0].sign(&msg) { - assert!(sig.verify(¶ms, &ps[0].get_verification_key(), &ps[0].get_stake(), &avk, &msg).is_ok()); - } - } - } - - proptest! { - #![proptest_config(ProptestConfig::with_cases(10))] - #[test] - fn test_parameters_serialize_deserialize(m in any::(), k in any::(), phi_f in any::()) { - let params = Parameters { m, k, phi_f }; - - let bytes = params.to_bytes(); - let deserialised = Parameters::from_bytes(&bytes); - assert!(deserialised.is_ok()) - } - - #[test] - fn test_initializer_serialize_deserialize(seed in any::<[u8;32]>()) { - let mut rng = ChaCha20Rng::from_seed(seed); - let params = Parameters { m: 1, k: 1, phi_f: 1.0 }; - let stake = rng.next_u64(); - let initializer = Initializer::new(params, stake, &mut rng); - - let bytes = initializer.to_bytes(); - assert!(Initializer::from_bytes(&bytes).is_ok()); - } - - #[test] - fn test_sig_serialize_deserialize(msg in any::<[u8;16]>()) { - let params = Parameters { m: 1, k: 1, phi_f: 0.2 }; - let ps = setup_equal_parties(params, 1); - let clerk = Clerk::new_clerk_from_signer(&ps[0]); - let avk = clerk.compute_aggregate_verification_key(); - - if let Some(sig) = ps[0].sign(&msg) { - let bytes = sig.to_bytes(); - let sig_deser = SingleSignature::from_bytes::(&bytes).unwrap(); - assert!(sig_deser.verify(¶ms, &ps[0].get_verification_key(), &ps[0].get_stake(), &avk, &msg).is_ok()); - } - } - - #[test] - fn test_multisig_serialize_deserialize(nparties in 2_usize..10, - msg in any::<[u8;16]>()) { - let params = Parameters { m: 10, k: 5, phi_f: 1.0 }; - let ps = setup_equal_parties(params, nparties); - let clerk = Clerk::new_clerk_from_signer(&ps[0]); - let aggr_sig_type = AggregateSignatureType::Concatenation; - - let all_ps: Vec = (0..nparties).collect(); - let sigs = find_signatures(&msg, &ps, &all_ps); - let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); - if let Ok(aggr) = msig { - let bytes: Vec = aggr.to_bytes(); - let aggr2 = AggregateSignature::from_bytes(&bytes).unwrap(); - assert!(aggr2.verify(&msg, &clerk.compute_aggregate_verification_key(), ¶ms).is_ok()); - } - } - } - - proptest! { - #![proptest_config(ProptestConfig::with_cases(10))] - - #[test] - /// Test that when the adversaries do not hold sufficient stake, they can not form a quorum - fn test_adversary_quorum( - (adversaries, parties) in arb_parties_adversary_stake(8, 30, 16, 4), - msg in any::<[u8;16]>(), - ) { - // Test sanity check: - // Check that the adversarial party has less than 40% of the total stake. - let (good, bad) = parties.iter().enumerate().fold((0,0), |(acc1, acc2), (i, st)| { - if adversaries.contains(&i) { - (acc1, acc2 + *st) - } else { - (acc1 + *st, acc2) - } - }); - assert!(bad as f64 / ((good + bad) as f64) < 0.4); - - let params = Parameters { m: 2642, k: 357, phi_f: 0.2 }; // From Table 1 - let ps = setup_parties(params, parties); - - let sigs = find_signatures(&msg, &ps, &adversaries.into_iter().collect::>()); - - assert!(sigs.len() < params.k as usize); - - let clerk = Clerk::new_clerk_from_signer(&ps[0]); - let aggr_sig_type = AggregateSignatureType::Concatenation; - - let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); - match msig { - Err(AggregationError::NotEnoughSignatures(n, k)) => - assert!(n < params.k && params.k == k), - _ => - unreachable!(), - } - } - } - - proptest! { - // Each of the tests below corresponds to falsifying a conjunct in the - // definition of a valid signature - #[test] - fn test_invalid_proof_quorum(tc in arb_proof_setup(10)) { - with_proof_mod(tc, |_aggr, clerk, _msg| { - clerk.params.k += 7; - }) - } - // todo: fn test_invalid_proof_individual_sig - #[test] - fn test_invalid_proof_index_bound(tc in arb_proof_setup(10)) { - with_proof_mod(tc, |_aggr, clerk, _msg| { - clerk.params.m = 1; - }) - } - #[test] - fn test_invalid_proof_index_unique(tc in arb_proof_setup(10)) { - with_proof_mod(tc, |aggr, clerk, _msg| { - let mut concatenation_proof = AggregateSignature::to_concatenation_proof(aggr).unwrap().to_owned(); - for sig_reg in concatenation_proof.signatures.iter_mut() { - for index in sig_reg.sig.indexes.iter_mut() { - *index %= clerk.params.k - 1 - } - } - *aggr = AggregateSignature::Concatenation(concatenation_proof); - }) - } - #[test] - fn test_invalid_proof_path(tc in arb_proof_setup(10)) { - with_proof_mod(tc, |aggr, _, _msg| { - let mut concatenation_proof = AggregateSignature::to_concatenation_proof(aggr).unwrap().to_owned(); - let p = concatenation_proof.batch_proof.clone(); - let mut index_list = p.indices.clone(); - let values = p.values; - let batch_proof = { - index_list[0] += 1; - MerkleBatchPath { - values, - indices: index_list, - hasher: Default::default() - } - }; - concatenation_proof.batch_proof = batch_proof; - *aggr = AggregateSignature::Concatenation(concatenation_proof); - }) - } - } - - // --------------------------------------------------------------------- - // Basic verifier - // --------------------------------------------------------------------- - fn setup_equal_core_parties( - params: Parameters, - nparties: usize, - ) -> (Vec, Vec<(BlsVerificationKey, Stake)>) { - let stake = vec![1; nparties]; - setup_core_parties(params, stake) - } - - fn setup_core_parties( - params: Parameters, - stake: Vec, - ) -> (Vec, Vec<(BlsVerificationKey, Stake)>) { - let mut trng = TestRng::deterministic_rng(ChaCha); - let mut rng = ChaCha20Rng::from_seed(trng.random()); - - let ps = stake - .into_iter() - .map(|stake| Initializer::new(params, stake, &mut rng)) - .collect::>(); - - let public_signers = ps - .iter() - .map(|s| (s.pk.vk, s.stake)) - .collect::>(); - - (ps, public_signers) - } - - fn find_core_signatures( - msg: &[u8], - ps: &[Signer], - total_stake: Stake, - is: &[usize], - ) -> Vec { - let mut sigs = Vec::new(); - for i in is { - if let Some(sig) = ps[*i].basic_sign(msg, total_stake) { - sigs.push(sig); - } - } - sigs - } - - proptest! { - #![proptest_config(ProptestConfig::with_cases(50))] - - #[test] - fn test_core_verifier(nparties in 2_usize..30, - m in 10_u64..20, - k in 1_u64..5, - msg in any::<[u8;16]>()) { - - let params = Parameters { m, k, phi_f: 0.2 }; - let (initializers, public_signers) = setup_equal_core_parties(params, nparties); - let all_ps: Vec = (0..nparties).collect(); - - let core_verifier = BasicVerifier::new(&public_signers); - - let signers = initializers - .into_iter() - .filter_map(|s| s.create_basic_signer(&core_verifier.eligible_parties)) - .collect::>>(); - - let signatures = find_core_signatures(&msg, &signers, core_verifier.total_stake, &all_ps); - - let verify_result = core_verifier.verify(&signatures, ¶ms, &msg); - - match verify_result{ - Ok(_) => { - assert!(verify_result.is_ok(), "Verification failed: {verify_result:?}"); - } - Err(CoreVerifierError::NoQuorum(nr_indices, _k)) => { - assert!((nr_indices) < params.k); - } - Err(CoreVerifierError::IndexNotUnique) => unreachable!(), - _ => unreachable!(), - } - } - - #[test] - fn test_total_stake_core_verifier(nparties in 2_usize..30, - m in 10_u64..20, - k in 1_u64..5,) { - let params = Parameters { m, k, phi_f: 0.2 }; - let (_initializers, public_signers) = setup_equal_core_parties(params, nparties); - let core_verifier = BasicVerifier::new(&public_signers); - assert_eq!(nparties as u64, core_verifier.total_stake, "Total stake expected: {}, got: {}.", nparties, core_verifier.total_stake); - } - } -} +// #[cfg(test)] +// mod tests { +// use std::collections::{HashMap, HashSet}; + +// use blake2::{Blake2b, digest::consts::U32}; +// use proptest::{ +// collection::{hash_map, vec}, +// prelude::*, +// test_runner::{RngAlgorithm::ChaCha, TestRng}, +// }; +// use rand_chacha::ChaCha20Rng; +// use rand_core::{RngCore, SeedableRng}; + +// use crate::merkle_tree::MerkleBatchPath; +// use crate::{ +// AggregateSignature, AggregateSignatureType, AggregationError, BasicVerifier, Clerk, +// CoreVerifierError, Initializer, KeyRegistration, Parameters, Signer, SingleSignature, +// SingleSignatureWithRegisteredParty, Stake, bls_multi_signature::BlsVerificationKey, +// }; + +// type Sig = AggregateSignature; +// type D = Blake2b; + +// fn setup_equal_parties(params: Parameters, nparties: usize) -> Vec> { +// let stake = vec![1; nparties]; +// setup_parties(params, stake) +// } + +// fn setup_parties(params: Parameters, stake: Vec) -> Vec> { +// let mut kr = KeyRegistration::init(); +// let mut trng = TestRng::deterministic_rng(ChaCha); +// let mut rng = ChaCha20Rng::from_seed(trng.random()); + +// #[allow(clippy::needless_collect)] +// let ps = stake +// .into_iter() +// .map(|stake| { +// let p = Initializer::new(params, stake, &mut rng); +// kr.register(stake, p.pk).unwrap(); +// p +// }) +// .collect::>(); +// let closed_reg = kr.close(); +// ps.into_iter() +// .map(|p| p.create_signer(closed_reg.clone()).unwrap()) +// .collect() +// } + +// /// Generate a vector of stakes that should sum to `honest_stake` +// /// when ignoring the indices in `adversaries` +// fn arb_honest_for_adversaries( +// num_parties: usize, +// honest_stake: Stake, +// adversaries: HashMap, +// ) -> impl Strategy> { +// vec(1..honest_stake, num_parties).prop_map(move |parties| { +// let honest_sum = parties.iter().enumerate().fold(0, |acc, (i, s)| { +// if !adversaries.contains_key(&i) { +// acc + s +// } else { +// acc +// } +// }); + +// parties +// .iter() +// .enumerate() +// .map(|(i, s)| { +// if let Some(a) = adversaries.get(&i) { +// *a +// } else { +// (*s * honest_stake) / honest_sum +// } +// }) +// .collect() +// }) +// } + +// /// Generate a vector of `num_parties` stakes summing to `num_parties * total_stake`, +// /// plus a subset S of 0..num_parties such that the sum of the stakes at indices +// /// in S is adversary_stake * N +// fn arb_parties_with_adversaries( +// num_parties: usize, +// num_adversaries: usize, +// total_stake: Stake, +// adversary_stake: Stake, +// ) -> impl Strategy, Vec)> { +// hash_map(0..num_parties, 1..total_stake, num_adversaries).prop_flat_map( +// move |adversaries| { +// let adversary_sum: Stake = adversaries.values().sum(); +// let adversaries_normed = adversaries +// .iter() +// .map(|(a, stake)| (*a, (stake * adversary_stake) / adversary_sum)) +// .collect(); + +// let adversaries = adversaries.into_keys().collect(); +// ( +// Just(adversaries), +// arb_honest_for_adversaries( +// num_parties, +// total_stake - adversary_stake, +// adversaries_normed, +// ), +// ) +// }, +// ) +// } + +// fn find_signatures(msg: &[u8], ps: &[Signer], is: &[usize]) -> Vec { +// let mut sigs = Vec::new(); +// for i in is { +// if let Some(sig) = ps[*i].sign(msg) { +// sigs.push(sig); +// } +// } +// sigs +// } + +// /// Pick N between min and max, and then +// /// generate a vector of N stakes summing to N * tstake, +// /// plus a subset S of 0..N such that the sum of the stakes at indices +// /// in S is astake * N +// fn arb_parties_adversary_stake( +// min: usize, +// max: usize, +// tstake: Stake, +// astake: Stake, +// ) -> impl Strategy, Vec)> { +// (min..max) +// .prop_flat_map(|n| (Just(n), 1..=n / 2)) +// .prop_flat_map(move |(n, nadv)| { +// arb_parties_with_adversaries(n, nadv, tstake * n as Stake, astake * n as Stake) +// }) +// } + +// #[derive(Debug)] +// struct ProofTest { +// msig: Result, +// clerk: Clerk, +// msg: [u8; 16], +// } +// /// Run the protocol up to aggregation. This will produce a valid aggregation of signatures. +// /// The following tests mutate this aggregation so that the proof is no longer valid. +// fn arb_proof_setup(max_parties: usize) -> impl Strategy { +// any::<[u8; 16]>().prop_flat_map(move |msg| { +// (2..max_parties).prop_map(move |n| { +// let params = Parameters { +// m: 5, +// k: 5, +// phi_f: 1.0, +// }; +// let ps = setup_equal_parties(params, n); +// let clerk = Clerk::new_clerk_from_signer(&ps[0]); + +// let all_ps: Vec = (0..n).collect(); +// let sigs = find_signatures(&msg, &ps, &all_ps); + +// let aggr_sig_type = AggregateSignatureType::Concatenation; +// let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); +// ProofTest { msig, clerk, msg } +// }) +// }) +// } + +// fn with_proof_mod(mut tc: ProofTest, f: F) +// where +// F: Fn(&mut Sig, &mut Clerk, &mut [u8; 16]), +// { +// match tc.msig { +// Ok(mut aggr) => { +// f(&mut aggr, &mut tc.clerk, &mut tc.msg); +// assert!( +// aggr.verify( +// &tc.msg, +// &tc.clerk.compute_aggregate_verification_key(), +// &tc.clerk.params +// ) +// .is_err() +// ) +// } +// Err(e) => unreachable!("Reached an unexpected error: {:?}", e), +// } +// } + +// proptest! { +// #![proptest_config(ProptestConfig::with_cases(50))] + +// #[test] +// /// Test that `dedup_sigs_for_indices` only takes valid signatures. +// fn test_dedup(msg in any::<[u8; 16]>()) { +// let false_msg = [1u8; 20]; +// let params = Parameters { m: 1, k: 1, phi_f: 1.0 }; +// let ps = setup_equal_parties(params, 1); +// let clerk = Clerk::new_clerk_from_signer(&ps[0]); +// let avk = clerk.compute_aggregate_verification_key(); +// let mut sigs = Vec::with_capacity(2); + +// if let Some(sig) = ps[0].sign(&false_msg) { +// sigs.push(sig); +// } + +// if let Some(sig) = ps[0].sign(&msg) { +// sigs.push(sig); +// } + +// let sig_reg_list = sigs +// .iter() +// .map(|sig| SingleSignatureWithRegisteredParty { +// sig: sig.clone(), +// reg_party: clerk.closed_reg.reg_parties[sig.signer_index as usize], +// }) +// .collect::>(); + +// let msgp = avk.get_merkle_tree_batch_commitment().concatenate_with_message(&msg); +// let dedup_result = BasicVerifier::select_valid_signatures_for_k_indices( +// &clerk.closed_reg.total_stake, +// ¶ms, +// &msgp, +// &sig_reg_list, +// ); +// assert!(dedup_result.is_ok(), "dedup failure {dedup_result:?}"); +// for passed_sigs in dedup_result.unwrap() { +// let verify_result = passed_sigs.sig.verify(¶ms, &ps[0].get_verification_key(), &ps[0].get_stake(), &avk, &msg); +// assert!(verify_result.is_ok(), "verify {verify_result:?}"); +// } +// } +// } + +// proptest! { +// #![proptest_config(ProptestConfig::with_cases(50))] + +// #[test] +// /// Test that when a quorum is found, the aggregate signature can be verified by anyone with +// /// access to the avk and the parameters. +// fn test_aggregate_sig(nparties in 2_usize..30, +// m in 10_u64..20, +// k in 1_u64..5, +// msg in any::<[u8;16]>()) { +// let params = Parameters { m, k, phi_f: 0.2 }; +// let ps = setup_equal_parties(params, nparties); +// let clerk = Clerk::new_clerk_from_signer(&ps[0]); +// let aggr_sig_type = AggregateSignatureType::Concatenation; + +// let all_ps: Vec = (0..nparties).collect(); +// let sigs = find_signatures(&msg, &ps, &all_ps); +// let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); + +// match msig { +// Ok(aggr) => { +// let verify_result = aggr.verify(&msg, &clerk.compute_aggregate_verification_key(), ¶ms); +// assert!(verify_result.is_ok(), "Verification failed: {verify_result:?}"); +// } +// Err(AggregationError::NotEnoughSignatures(n, k)) => +// assert!(n < params.k || k == params.k), +// Err(AggregationError::UsizeConversionInvalid) => +// unreachable!(), +// Err(AggregationError::UnsupportedProofSystem(_)) => +// unreachable!(), +// } +// } + +// #[test] +// /// Test that batch verification of certificates works +// fn batch_verify(nparties in 2_usize..30, +// m in 10_u64..20, +// k in 1_u64..4, +// seed in any::<[u8;32]>(), +// batch_size in 2..10, +// ) { +// let aggr_sig_type = AggregateSignatureType::Concatenation; +// let mut rng = ChaCha20Rng::from_seed(seed); +// let mut aggr_avks = Vec::new(); +// let mut aggr_stms = Vec::new(); +// let mut batch_msgs = Vec::new(); +// let mut batch_params = Vec::new(); +// for _ in 0..batch_size { +// let mut msg = [0u8; 32]; +// rng.fill_bytes(&mut msg); +// let params = Parameters { m, k, phi_f: 0.95 }; +// let ps = setup_equal_parties(params, nparties); +// let clerk = Clerk::new_clerk_from_signer(&ps[0]); + +// let all_ps: Vec = (0..nparties).collect(); +// let sigs = find_signatures(&msg, &ps, &all_ps); +// let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); + +// match msig { +// Ok(aggr) => { +// aggr_avks.push(clerk.compute_aggregate_verification_key()); +// aggr_stms.push(aggr); +// batch_msgs.push(msg.to_vec()); +// batch_params.push(params); +// } +// Err(AggregationError::NotEnoughSignatures(_n, _k)) => { +// assert!(sigs.len() < params.k as usize) +// } +// Err(AggregationError::UsizeConversionInvalid) => unreachable!(), +// Err(AggregationError::UnsupportedProofSystem(_)) => unreachable!(), +// } +// } + +// assert!(AggregateSignature::batch_verify(&aggr_stms, &batch_msgs, &aggr_avks, &batch_params).is_ok()); + +// let mut msg = [0u8; 32]; +// rng.fill_bytes(&mut msg); +// let params = Parameters { m, k, phi_f: 0.8 }; +// let ps = setup_equal_parties(params, nparties); +// let clerk = Clerk::new_clerk_from_signer(&ps[0]); + +// let all_ps: Vec = (0..nparties).collect(); +// let sigs = find_signatures(&msg, &ps, &all_ps); +// let fake_msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); + +// aggr_stms[0] = fake_msig.unwrap(); +// assert!(AggregateSignature::batch_verify(&aggr_stms, &batch_msgs, &aggr_avks, &batch_params).is_err()); +// } +// } + +// proptest! { +// #[test] +// /// Test that when a party creates a signature it can be verified +// fn test_sig(msg in any::<[u8;16]>()) { +// let params = Parameters { m: 1, k: 1, phi_f: 0.2 }; +// let ps = setup_equal_parties(params, 1); +// let clerk = Clerk::new_clerk_from_signer(&ps[0]); +// let avk = clerk.compute_aggregate_verification_key(); + +// if let Some(sig) = ps[0].sign(&msg) { +// assert!(sig.verify(¶ms, &ps[0].get_verification_key(), &ps[0].get_stake(), &avk, &msg).is_ok()); +// } +// } +// } + +// proptest! { +// #![proptest_config(ProptestConfig::with_cases(10))] +// #[test] +// fn test_parameters_serialize_deserialize(m in any::(), k in any::(), phi_f in any::()) { +// let params = Parameters { m, k, phi_f }; + +// let bytes = params.to_bytes(); +// let deserialised = Parameters::from_bytes(&bytes); +// assert!(deserialised.is_ok()) +// } + +// #[test] +// fn test_initializer_serialize_deserialize(seed in any::<[u8;32]>()) { +// let mut rng = ChaCha20Rng::from_seed(seed); +// let params = Parameters { m: 1, k: 1, phi_f: 1.0 }; +// let stake = rng.next_u64(); +// let initializer = Initializer::new(params, stake, &mut rng); + +// let bytes = initializer.to_bytes(); +// assert!(Initializer::from_bytes(&bytes).is_ok()); +// } + +// #[test] +// fn test_sig_serialize_deserialize(msg in any::<[u8;16]>()) { +// let params = Parameters { m: 1, k: 1, phi_f: 0.2 }; +// let ps = setup_equal_parties(params, 1); +// let clerk = Clerk::new_clerk_from_signer(&ps[0]); +// let avk = clerk.compute_aggregate_verification_key(); + +// if let Some(sig) = ps[0].sign(&msg) { +// let bytes = sig.to_bytes(); +// let sig_deser = SingleSignature::from_bytes::(&bytes).unwrap(); +// assert!(sig_deser.verify(¶ms, &ps[0].get_verification_key(), &ps[0].get_stake(), &avk, &msg).is_ok()); +// } +// } + +// #[test] +// fn test_multisig_serialize_deserialize(nparties in 2_usize..10, +// msg in any::<[u8;16]>()) { +// let params = Parameters { m: 10, k: 5, phi_f: 1.0 }; +// let ps = setup_equal_parties(params, nparties); +// let clerk = Clerk::new_clerk_from_signer(&ps[0]); +// let aggr_sig_type = AggregateSignatureType::Concatenation; + +// let all_ps: Vec = (0..nparties).collect(); +// let sigs = find_signatures(&msg, &ps, &all_ps); +// let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); +// if let Ok(aggr) = msig { +// let bytes: Vec = aggr.to_bytes(); +// let aggr2 = AggregateSignature::from_bytes(&bytes).unwrap(); +// assert!(aggr2.verify(&msg, &clerk.compute_aggregate_verification_key(), ¶ms).is_ok()); +// } +// } +// } + +// proptest! { +// #![proptest_config(ProptestConfig::with_cases(10))] + +// #[test] +// /// Test that when the adversaries do not hold sufficient stake, they can not form a quorum +// fn test_adversary_quorum( +// (adversaries, parties) in arb_parties_adversary_stake(8, 30, 16, 4), +// msg in any::<[u8;16]>(), +// ) { +// // Test sanity check: +// // Check that the adversarial party has less than 40% of the total stake. +// let (good, bad) = parties.iter().enumerate().fold((0,0), |(acc1, acc2), (i, st)| { +// if adversaries.contains(&i) { +// (acc1, acc2 + *st) +// } else { +// (acc1 + *st, acc2) +// } +// }); +// assert!(bad as f64 / ((good + bad) as f64) < 0.4); + +// let params = Parameters { m: 2642, k: 357, phi_f: 0.2 }; // From Table 1 +// let ps = setup_parties(params, parties); + +// let sigs = find_signatures(&msg, &ps, &adversaries.into_iter().collect::>()); + +// assert!(sigs.len() < params.k as usize); + +// let clerk = Clerk::new_clerk_from_signer(&ps[0]); +// let aggr_sig_type = AggregateSignatureType::Concatenation; + +// let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); +// match msig { +// Err(AggregationError::NotEnoughSignatures(n, k)) => +// assert!(n < params.k && params.k == k), +// _ => +// unreachable!(), +// } +// } +// } + +// proptest! { +// // Each of the tests below corresponds to falsifying a conjunct in the +// // definition of a valid signature +// #[test] +// fn test_invalid_proof_quorum(tc in arb_proof_setup(10)) { +// with_proof_mod(tc, |_aggr, clerk, _msg| { +// clerk.params.k += 7; +// }) +// } +// // todo: fn test_invalid_proof_individual_sig +// #[test] +// fn test_invalid_proof_index_bound(tc in arb_proof_setup(10)) { +// with_proof_mod(tc, |_aggr, clerk, _msg| { +// clerk.params.m = 1; +// }) +// } +// #[test] +// fn test_invalid_proof_index_unique(tc in arb_proof_setup(10)) { +// with_proof_mod(tc, |aggr, clerk, _msg| { +// let mut concatenation_proof = AggregateSignature::to_concatenation_proof(aggr).unwrap().to_owned(); +// for sig_reg in concatenation_proof.signatures.iter_mut() { +// for index in sig_reg.sig.indexes.iter_mut() { +// *index %= clerk.params.k - 1 +// } +// } +// *aggr = AggregateSignature::Concatenation(concatenation_proof); +// }) +// } +// #[test] +// fn test_invalid_proof_path(tc in arb_proof_setup(10)) { +// with_proof_mod(tc, |aggr, _, _msg| { +// let mut concatenation_proof = AggregateSignature::to_concatenation_proof(aggr).unwrap().to_owned(); +// let p = concatenation_proof.batch_proof.clone(); +// let mut index_list = p.indices.clone(); +// let values = p.values; +// let batch_proof = { +// index_list[0] += 1; +// MerkleBatchPath { +// values, +// indices: index_list, +// hasher: Default::default() +// } +// }; +// concatenation_proof.batch_proof = batch_proof; +// *aggr = AggregateSignature::Concatenation(concatenation_proof); +// }) +// } +// } + +// // --------------------------------------------------------------------- +// // Basic verifier +// // --------------------------------------------------------------------- +// fn setup_equal_core_parties( +// params: Parameters, +// nparties: usize, +// ) -> (Vec, Vec<(BlsVerificationKey, Stake)>) { +// let stake = vec![1; nparties]; +// setup_core_parties(params, stake) +// } + +// fn setup_core_parties( +// params: Parameters, +// stake: Vec, +// ) -> (Vec, Vec<(BlsVerificationKey, Stake)>) { +// let mut trng = TestRng::deterministic_rng(ChaCha); +// let mut rng = ChaCha20Rng::from_seed(trng.random()); + +// let ps = stake +// .into_iter() +// .map(|stake| Initializer::new(params, stake, &mut rng)) +// .collect::>(); + +// let public_signers = ps +// .iter() +// .map(|s| (s.pk.vk, s.stake)) +// .collect::>(); + +// (ps, public_signers) +// } + +// fn find_core_signatures( +// msg: &[u8], +// ps: &[Signer], +// total_stake: Stake, +// is: &[usize], +// ) -> Vec { +// let mut sigs = Vec::new(); +// for i in is { +// if let Some(sig) = ps[*i].basic_sign(msg, total_stake) { +// sigs.push(sig); +// } +// } +// sigs +// } + +// proptest! { +// #![proptest_config(ProptestConfig::with_cases(50))] + +// #[test] +// fn test_core_verifier(nparties in 2_usize..30, +// m in 10_u64..20, +// k in 1_u64..5, +// msg in any::<[u8;16]>()) { + +// let params = Parameters { m, k, phi_f: 0.2 }; +// let (initializers, public_signers) = setup_equal_core_parties(params, nparties); +// let all_ps: Vec = (0..nparties).collect(); + +// let core_verifier = BasicVerifier::new(&public_signers); + +// let signers = initializers +// .into_iter() +// .filter_map(|s| s.create_basic_signer(&core_verifier.eligible_parties)) +// .collect::>>(); + +// let signatures = find_core_signatures(&msg, &signers, core_verifier.total_stake, &all_ps); + +// let verify_result = core_verifier.verify(&signatures, ¶ms, &msg); + +// match verify_result{ +// Ok(_) => { +// assert!(verify_result.is_ok(), "Verification failed: {verify_result:?}"); +// } +// Err(CoreVerifierError::NoQuorum(nr_indices, _k)) => { +// assert!((nr_indices) < params.k); +// } +// Err(CoreVerifierError::IndexNotUnique) => unreachable!(), +// _ => unreachable!(), +// } +// } + +// #[test] +// fn test_total_stake_core_verifier(nparties in 2_usize..30, +// m in 10_u64..20, +// k in 1_u64..5,) { +// let params = Parameters { m, k, phi_f: 0.2 }; +// let (_initializers, public_signers) = setup_equal_core_parties(params, nparties); +// let core_verifier = BasicVerifier::new(&public_signers); +// assert_eq!(nparties as u64, core_verifier.total_stake, "Total stake expected: {}, got: {}.", nparties, core_verifier.total_stake); +// } +// } +// } diff --git a/mithril-stm/src/bls_multi_signature/mod.rs b/mithril-stm/src/bls_multi_signature/mod.rs index 9f91df30e53..a1fbf2eee68 100644 --- a/mithril-stm/src/bls_multi_signature/mod.rs +++ b/mithril-stm/src/bls_multi_signature/mod.rs @@ -95,7 +95,7 @@ mod tests { use rand_core::{RngCore, SeedableRng}; use crate::bls_multi_signature::helper::unsafe_helpers::{p1_affine_to_sig, p2_affine_to_vk}; - use crate::error::{MultiSignatureError, RegisterError}; + use crate::error::MultiSignatureError; use crate::key_registration::KeyRegistration; use super::*; @@ -131,8 +131,14 @@ mod tests { let sk2 = BlsSigningKey::generate(&mut rng); let fake_sig = sk2.sign(&msg); - let result = fake_sig.verify(&msg, &vk1); - assert_eq!(result, Err(MultiSignatureError::SignatureInvalid(fake_sig))); + let error = fake_sig.verify(&msg, &vk1).expect_err("Fake signature should not be verified"); + + assert!( + matches!( + error.downcast_ref::(), + Some(MultiSignatureError::SignatureInvalid(_)) + ), + "Unexpected error: {error:?}"); } #[test] @@ -144,8 +150,13 @@ mod tests { let p1 = blst_p1::default(); let sig_infinity = BlsSignature(p1_affine_to_sig(&p1)); - let result = sig_infinity.verify(&msg, &vk); - assert_eq!(result, Err(MultiSignatureError::SignatureInfinity(sig_infinity))); + let error = sig_infinity.verify(&msg, &vk).expect_err("Verification should fail"); + assert!( + matches!( + error.downcast_ref::(), + Some(MultiSignatureError::SignatureInfinity(_)) + ), + "Unexpected error: {error:?}"); } #[test] @@ -158,8 +169,13 @@ mod tests { let vk_infinity = BlsVerificationKey(p2_affine_to_vk(&p2)); let vkpop_infinity = BlsVerificationKeyProofOfPossession { vk: vk_infinity, pop }; - let result = vkpop_infinity.verify_proof_of_possession(); - assert_eq!(result, Err(MultiSignatureError::VerificationKeyInfinity(Box::new(vkpop_infinity.vk)))); + let error = vkpop_infinity.verify_proof_of_possession().expect_err("VK pop infinity should fail"); + assert!( + matches!( + error.downcast_ref::(), + Some(MultiSignatureError::VerificationKeyInfinity(_)) + ), + "Unexpected error: {error:?}"); } #[test] @@ -179,8 +195,14 @@ mod tests { let _ = kr.register(1, vkpop); } - let result = kr.register(1, vkpop_infinity); - assert_eq!(result, Err(RegisterError::VerificationKeyInfinity(Box::new(vkpop_infinity.vk)))); + let error = kr.register(1, vkpop_infinity).expect_err("VK pop infinity should not be registered"); + + assert!( + matches!( + error.downcast_ref::(), + Some(MultiSignatureError::VerificationKeyInfinity(_)) + ), + "Unexpected error: {error:?}"); } #[test] @@ -272,8 +294,13 @@ mod tests { let fake_sig = sk.sign(&msg); batch_sig[0] = fake_sig; - let batch_result = BlsSignature::batch_verify_aggregates(&batch_msgs, &batch_vk, &batch_sig); - assert_eq!(batch_result, Err(MultiSignatureError::BatchInvalid)); + let error = BlsSignature::batch_verify_aggregates(&batch_msgs, &batch_vk, &batch_sig).expect_err("Batch verify should fail"); + assert!( + matches!( + error.downcast_ref::(), + Some(MultiSignatureError::BatchInvalid) + ), + "Unexpected error: {error:?}"); } } } diff --git a/mithril-stm/src/bls_multi_signature/signature.rs b/mithril-stm/src/bls_multi_signature/signature.rs index 71a0ad5db93..6f62a691f4a 100644 --- a/mithril-stm/src/bls_multi_signature/signature.rs +++ b/mithril-stm/src/bls_multi_signature/signature.rs @@ -182,7 +182,7 @@ impl BlsSignature { None, None, ) - //.map_err(|_| MultiSignatureError::BatchInvalid) + // .map_err(|_| MultiSignatureError::BatchInvalid) } } diff --git a/mithril-stm/src/bls_multi_signature/signing_key.rs b/mithril-stm/src/bls_multi_signature/signing_key.rs index d3f0a18d85d..4619521c05c 100644 --- a/mithril-stm/src/bls_multi_signature/signing_key.rs +++ b/mithril-stm/src/bls_multi_signature/signing_key.rs @@ -49,35 +49,35 @@ impl BlsSigningKey { } } -#[cfg(test)] -mod tests { - use super::*; +// #[cfg(test)] +// mod tests { +// use super::*; - mod golden { +// mod golden { - use rand_chacha::ChaCha20Rng; - use rand_core::SeedableRng; +// use rand_chacha::ChaCha20Rng; +// use rand_core::SeedableRng; - use super::*; +// use super::*; - const GOLDEN_JSON: &str = r#"[64, 129, 87, 121, 27, 239, 221, 215, 2, 103, 45, 207, 207, 201, 157, 163, 81, 47, 156, 14, 168, 24, 137, 15, 203, 106, 183, 73, 88, 14, 242, 207]"#; +// const GOLDEN_JSON: &str = r#"[64, 129, 87, 121, 27, 239, 221, 215, 2, 103, 45, 207, 207, 201, 157, 163, 81, 47, 156, 14, 168, 24, 137, 15, 203, 106, 183, 73, 88, 14, 242, 207]"#; - fn golden_value() -> BlsSigningKey { - let mut rng = ChaCha20Rng::from_seed([0u8; 32]); - BlsSigningKey::generate(&mut rng) - } +// fn golden_value() -> BlsSigningKey { +// let mut rng = ChaCha20Rng::from_seed([0u8; 32]); +// BlsSigningKey::generate(&mut rng) +// } - #[test] - fn golden_conversions() { - let value = serde_json::from_str(GOLDEN_JSON) - .expect("This JSON deserialization should not fail"); - assert_eq!(golden_value(), value); +// #[test] +// fn golden_conversions() { +// let value = serde_json::from_str(GOLDEN_JSON) +// .expect("This JSON deserialization should not fail"); +// assert_eq!(golden_value(), value); - let serialized = - serde_json::to_string(&value).expect("This JSON serialization should not fail"); - let golden_serialized = serde_json::to_string(&golden_value()) - .expect("This JSON serialization should not fail"); - assert_eq!(golden_serialized, serialized); - } - } -} +// let serialized = +// serde_json::to_string(&value).expect("This JSON serialization should not fail"); +// let golden_serialized = serde_json::to_string(&golden_value()) +// .expect("This JSON serialization should not fail"); +// assert_eq!(golden_serialized, serialized); +// } +// } +// } diff --git a/mithril-stm/src/key_registration.rs b/mithril-stm/src/key_registration.rs index 82d9fa5eb9b..36bc880cc74 100644 --- a/mithril-stm/src/key_registration.rs +++ b/mithril-stm/src/key_registration.rs @@ -86,69 +86,69 @@ pub struct ClosedKeyRegistration { pub merkle_tree: Arc>, } -#[cfg(test)] -mod tests { - use blake2::{Blake2b, digest::consts::U32}; - use proptest::{collection::vec, prelude::*}; - use rand_chacha::ChaCha20Rng; - use rand_core::SeedableRng; - - use crate::bls_multi_signature::BlsSigningKey; - - use super::*; - - proptest! { - #[test] - fn test_keyreg(stake in vec(1..1u64 << 60, 2..=10), - nkeys in 2..10_usize, - fake_it in 0..4usize, - seed in any::<[u8;32]>()) { - let mut rng = ChaCha20Rng::from_seed(seed); - let mut kr = KeyRegistration::init(); - - let gen_keys = (1..nkeys).map(|_| { - let sk = BlsSigningKey::generate(&mut rng); - BlsVerificationKeyProofOfPossession::from(&sk) - }).collect::>(); - - let fake_key = { - let sk = BlsSigningKey::generate(&mut rng); - BlsVerificationKeyProofOfPossession::from(&sk) - }; - - // Record successful registrations - let mut keys = HashMap::new(); - - for (i, &stake) in stake.iter().enumerate() { - let mut pk = gen_keys[i % gen_keys.len()]; - - if fake_it == 0 { - pk.pop = fake_key.pop; - } - - let reg = kr.register(stake, pk); - match reg { - Ok(_) => { - assert!(keys.insert(pk.vk, stake).is_none()); - }, - Err(RegisterError::KeyRegistered(pk1)) => { - assert!(pk1.as_ref() == &pk.vk); - assert!(keys.contains_key(&pk.vk)); - } - Err(RegisterError::KeyInvalid(a)) => { - assert_eq!(fake_it, 0); - assert!(a.verify_proof_of_possession().is_err()); - } - Err(RegisterError::SerializationError) => unreachable!(), - _ => unreachable!(), - } - } - - if !kr.keys.is_empty() { - let closed = kr.close::>(); - let retrieved_keys = closed.reg_parties.iter().map(|r| (r.0, r.1)).collect::>(); - assert!(retrieved_keys == keys); - } - } - } -} +// #[cfg(test)] +// mod tests { +// use blake2::{Blake2b, digest::consts::U32}; +// use proptest::{collection::vec, prelude::*}; +// use rand_chacha::ChaCha20Rng; +// use rand_core::SeedableRng; + +// use crate::bls_multi_signature::BlsSigningKey; + +// use super::*; + +// proptest! { +// #[test] +// fn test_keyreg(stake in vec(1..1u64 << 60, 2..=10), +// nkeys in 2..10_usize, +// fake_it in 0..4usize, +// seed in any::<[u8;32]>()) { +// let mut rng = ChaCha20Rng::from_seed(seed); +// let mut kr = KeyRegistration::init(); + +// let gen_keys = (1..nkeys).map(|_| { +// let sk = BlsSigningKey::generate(&mut rng); +// BlsVerificationKeyProofOfPossession::from(&sk) +// }).collect::>(); + +// let fake_key = { +// let sk = BlsSigningKey::generate(&mut rng); +// BlsVerificationKeyProofOfPossession::from(&sk) +// }; + +// // Record successful registrations +// let mut keys = HashMap::new(); + +// for (i, &stake) in stake.iter().enumerate() { +// let mut pk = gen_keys[i % gen_keys.len()]; + +// if fake_it == 0 { +// pk.pop = fake_key.pop; +// } + +// let reg = kr.register(stake, pk); +// match reg { +// Ok(_) => { +// assert!(keys.insert(pk.vk, stake).is_none()); +// }, +// Err(RegisterError::KeyRegistered(pk1)) => { +// assert!(pk1.as_ref() == &pk.vk); +// assert!(keys.contains_key(&pk.vk)); +// } +// Err(RegisterError::KeyInvalid(a)) => { +// assert_eq!(fake_it, 0); +// assert!(a.verify_proof_of_possession().is_err()); +// } +// Err(RegisterError::SerializationError) => unreachable!(), +// _ => unreachable!(), +// } +// } + +// if !kr.keys.is_empty() { +// let closed = kr.close::>(); +// let retrieved_keys = closed.reg_parties.iter().map(|r| (r.0, r.1)).collect::>(); +// assert!(retrieved_keys == keys); +// } +// } +// } +// } From b2e3a491df29a9b970d31ad7e2bea91ffbf8cfa6 Mon Sep 17 00:00:00 2001 From: curiecrypt Date: Mon, 10 Nov 2025 18:11:45 +0300 Subject: [PATCH 11/11] stm tests run with anyhow --- mithril-stm/README.md | 19 +- mithril-stm/src/aggregate_signature/mod.rs | 1145 +++++++++-------- .../src/aggregate_signature/signature.rs | 47 +- .../src/bls_multi_signature/signature.rs | 2 +- .../src/bls_multi_signature/signing_key.rs | 50 +- mithril-stm/src/key_registration.rs | 132 +- mithril-stm/src/lib.rs | 12 +- mithril-stm/tests/stm_basic.rs | 14 +- mithril-stm/tests/stm_protocol.rs | 19 +- .../tests/test_extensions/protocol_phase.rs | 6 +- 10 files changed, 731 insertions(+), 715 deletions(-) diff --git a/mithril-stm/README.md b/mithril-stm/README.md index 6a9160c524d..be511e4846b 100644 --- a/mithril-stm/README.md +++ b/mithril-stm/README.md @@ -136,16 +136,15 @@ match msig { println!("Aggregate ok"); assert!(aggr.verify(&msg, &clerk.compute_aggregate_verification_key(), ¶ms).is_ok()); } - Err(AggregationError::NotEnoughSignatures(n, k)) => { - println!("Not enough signatures"); - assert!(n < params.k && k == params.k) - } - Err(AggregationError::UsizeConversionInvalid) => { - println!("Invalid usize conversion"); - } - Err(AggregationError::UnsupportedProofSystem(aggregate_signature_type)) => { - println!("Unsupported proof system: {:?}", aggregate_signature_type); - } + Err(error) => assert!( + matches!( + error.downcast_ref::(), + Some(AggregationError::NotEnoughSignatures { .. }) + | Some(AggregationError::UsizeConversionInvalid) + | Some(AggregationError::UnsupportedProofSystem { .. }) + ), + "Unexpected error: {error}" + ), } ``` diff --git a/mithril-stm/src/aggregate_signature/mod.rs b/mithril-stm/src/aggregate_signature/mod.rs index 9f712ca9d95..1ac66ea8923 100644 --- a/mithril-stm/src/aggregate_signature/mod.rs +++ b/mithril-stm/src/aggregate_signature/mod.rs @@ -10,573 +10,578 @@ pub use clerk::*; pub use proof::*; pub use signature::*; -// #[cfg(test)] -// mod tests { -// use std::collections::{HashMap, HashSet}; - -// use blake2::{Blake2b, digest::consts::U32}; -// use proptest::{ -// collection::{hash_map, vec}, -// prelude::*, -// test_runner::{RngAlgorithm::ChaCha, TestRng}, -// }; -// use rand_chacha::ChaCha20Rng; -// use rand_core::{RngCore, SeedableRng}; - -// use crate::merkle_tree::MerkleBatchPath; -// use crate::{ -// AggregateSignature, AggregateSignatureType, AggregationError, BasicVerifier, Clerk, -// CoreVerifierError, Initializer, KeyRegistration, Parameters, Signer, SingleSignature, -// SingleSignatureWithRegisteredParty, Stake, bls_multi_signature::BlsVerificationKey, -// }; - -// type Sig = AggregateSignature; -// type D = Blake2b; - -// fn setup_equal_parties(params: Parameters, nparties: usize) -> Vec> { -// let stake = vec![1; nparties]; -// setup_parties(params, stake) -// } - -// fn setup_parties(params: Parameters, stake: Vec) -> Vec> { -// let mut kr = KeyRegistration::init(); -// let mut trng = TestRng::deterministic_rng(ChaCha); -// let mut rng = ChaCha20Rng::from_seed(trng.random()); - -// #[allow(clippy::needless_collect)] -// let ps = stake -// .into_iter() -// .map(|stake| { -// let p = Initializer::new(params, stake, &mut rng); -// kr.register(stake, p.pk).unwrap(); -// p -// }) -// .collect::>(); -// let closed_reg = kr.close(); -// ps.into_iter() -// .map(|p| p.create_signer(closed_reg.clone()).unwrap()) -// .collect() -// } - -// /// Generate a vector of stakes that should sum to `honest_stake` -// /// when ignoring the indices in `adversaries` -// fn arb_honest_for_adversaries( -// num_parties: usize, -// honest_stake: Stake, -// adversaries: HashMap, -// ) -> impl Strategy> { -// vec(1..honest_stake, num_parties).prop_map(move |parties| { -// let honest_sum = parties.iter().enumerate().fold(0, |acc, (i, s)| { -// if !adversaries.contains_key(&i) { -// acc + s -// } else { -// acc -// } -// }); - -// parties -// .iter() -// .enumerate() -// .map(|(i, s)| { -// if let Some(a) = adversaries.get(&i) { -// *a -// } else { -// (*s * honest_stake) / honest_sum -// } -// }) -// .collect() -// }) -// } - -// /// Generate a vector of `num_parties` stakes summing to `num_parties * total_stake`, -// /// plus a subset S of 0..num_parties such that the sum of the stakes at indices -// /// in S is adversary_stake * N -// fn arb_parties_with_adversaries( -// num_parties: usize, -// num_adversaries: usize, -// total_stake: Stake, -// adversary_stake: Stake, -// ) -> impl Strategy, Vec)> { -// hash_map(0..num_parties, 1..total_stake, num_adversaries).prop_flat_map( -// move |adversaries| { -// let adversary_sum: Stake = adversaries.values().sum(); -// let adversaries_normed = adversaries -// .iter() -// .map(|(a, stake)| (*a, (stake * adversary_stake) / adversary_sum)) -// .collect(); - -// let adversaries = adversaries.into_keys().collect(); -// ( -// Just(adversaries), -// arb_honest_for_adversaries( -// num_parties, -// total_stake - adversary_stake, -// adversaries_normed, -// ), -// ) -// }, -// ) -// } - -// fn find_signatures(msg: &[u8], ps: &[Signer], is: &[usize]) -> Vec { -// let mut sigs = Vec::new(); -// for i in is { -// if let Some(sig) = ps[*i].sign(msg) { -// sigs.push(sig); -// } -// } -// sigs -// } - -// /// Pick N between min and max, and then -// /// generate a vector of N stakes summing to N * tstake, -// /// plus a subset S of 0..N such that the sum of the stakes at indices -// /// in S is astake * N -// fn arb_parties_adversary_stake( -// min: usize, -// max: usize, -// tstake: Stake, -// astake: Stake, -// ) -> impl Strategy, Vec)> { -// (min..max) -// .prop_flat_map(|n| (Just(n), 1..=n / 2)) -// .prop_flat_map(move |(n, nadv)| { -// arb_parties_with_adversaries(n, nadv, tstake * n as Stake, astake * n as Stake) -// }) -// } - -// #[derive(Debug)] -// struct ProofTest { -// msig: Result, -// clerk: Clerk, -// msg: [u8; 16], -// } -// /// Run the protocol up to aggregation. This will produce a valid aggregation of signatures. -// /// The following tests mutate this aggregation so that the proof is no longer valid. -// fn arb_proof_setup(max_parties: usize) -> impl Strategy { -// any::<[u8; 16]>().prop_flat_map(move |msg| { -// (2..max_parties).prop_map(move |n| { -// let params = Parameters { -// m: 5, -// k: 5, -// phi_f: 1.0, -// }; -// let ps = setup_equal_parties(params, n); -// let clerk = Clerk::new_clerk_from_signer(&ps[0]); - -// let all_ps: Vec = (0..n).collect(); -// let sigs = find_signatures(&msg, &ps, &all_ps); - -// let aggr_sig_type = AggregateSignatureType::Concatenation; -// let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); -// ProofTest { msig, clerk, msg } -// }) -// }) -// } - -// fn with_proof_mod(mut tc: ProofTest, f: F) -// where -// F: Fn(&mut Sig, &mut Clerk, &mut [u8; 16]), -// { -// match tc.msig { -// Ok(mut aggr) => { -// f(&mut aggr, &mut tc.clerk, &mut tc.msg); -// assert!( -// aggr.verify( -// &tc.msg, -// &tc.clerk.compute_aggregate_verification_key(), -// &tc.clerk.params -// ) -// .is_err() -// ) -// } -// Err(e) => unreachable!("Reached an unexpected error: {:?}", e), -// } -// } - -// proptest! { -// #![proptest_config(ProptestConfig::with_cases(50))] - -// #[test] -// /// Test that `dedup_sigs_for_indices` only takes valid signatures. -// fn test_dedup(msg in any::<[u8; 16]>()) { -// let false_msg = [1u8; 20]; -// let params = Parameters { m: 1, k: 1, phi_f: 1.0 }; -// let ps = setup_equal_parties(params, 1); -// let clerk = Clerk::new_clerk_from_signer(&ps[0]); -// let avk = clerk.compute_aggregate_verification_key(); -// let mut sigs = Vec::with_capacity(2); - -// if let Some(sig) = ps[0].sign(&false_msg) { -// sigs.push(sig); -// } - -// if let Some(sig) = ps[0].sign(&msg) { -// sigs.push(sig); -// } - -// let sig_reg_list = sigs -// .iter() -// .map(|sig| SingleSignatureWithRegisteredParty { -// sig: sig.clone(), -// reg_party: clerk.closed_reg.reg_parties[sig.signer_index as usize], -// }) -// .collect::>(); - -// let msgp = avk.get_merkle_tree_batch_commitment().concatenate_with_message(&msg); -// let dedup_result = BasicVerifier::select_valid_signatures_for_k_indices( -// &clerk.closed_reg.total_stake, -// ¶ms, -// &msgp, -// &sig_reg_list, -// ); -// assert!(dedup_result.is_ok(), "dedup failure {dedup_result:?}"); -// for passed_sigs in dedup_result.unwrap() { -// let verify_result = passed_sigs.sig.verify(¶ms, &ps[0].get_verification_key(), &ps[0].get_stake(), &avk, &msg); -// assert!(verify_result.is_ok(), "verify {verify_result:?}"); -// } -// } -// } - -// proptest! { -// #![proptest_config(ProptestConfig::with_cases(50))] - -// #[test] -// /// Test that when a quorum is found, the aggregate signature can be verified by anyone with -// /// access to the avk and the parameters. -// fn test_aggregate_sig(nparties in 2_usize..30, -// m in 10_u64..20, -// k in 1_u64..5, -// msg in any::<[u8;16]>()) { -// let params = Parameters { m, k, phi_f: 0.2 }; -// let ps = setup_equal_parties(params, nparties); -// let clerk = Clerk::new_clerk_from_signer(&ps[0]); -// let aggr_sig_type = AggregateSignatureType::Concatenation; - -// let all_ps: Vec = (0..nparties).collect(); -// let sigs = find_signatures(&msg, &ps, &all_ps); -// let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); - -// match msig { -// Ok(aggr) => { -// let verify_result = aggr.verify(&msg, &clerk.compute_aggregate_verification_key(), ¶ms); -// assert!(verify_result.is_ok(), "Verification failed: {verify_result:?}"); -// } -// Err(AggregationError::NotEnoughSignatures(n, k)) => -// assert!(n < params.k || k == params.k), -// Err(AggregationError::UsizeConversionInvalid) => -// unreachable!(), -// Err(AggregationError::UnsupportedProofSystem(_)) => -// unreachable!(), -// } -// } - -// #[test] -// /// Test that batch verification of certificates works -// fn batch_verify(nparties in 2_usize..30, -// m in 10_u64..20, -// k in 1_u64..4, -// seed in any::<[u8;32]>(), -// batch_size in 2..10, -// ) { -// let aggr_sig_type = AggregateSignatureType::Concatenation; -// let mut rng = ChaCha20Rng::from_seed(seed); -// let mut aggr_avks = Vec::new(); -// let mut aggr_stms = Vec::new(); -// let mut batch_msgs = Vec::new(); -// let mut batch_params = Vec::new(); -// for _ in 0..batch_size { -// let mut msg = [0u8; 32]; -// rng.fill_bytes(&mut msg); -// let params = Parameters { m, k, phi_f: 0.95 }; -// let ps = setup_equal_parties(params, nparties); -// let clerk = Clerk::new_clerk_from_signer(&ps[0]); - -// let all_ps: Vec = (0..nparties).collect(); -// let sigs = find_signatures(&msg, &ps, &all_ps); -// let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); - -// match msig { -// Ok(aggr) => { -// aggr_avks.push(clerk.compute_aggregate_verification_key()); -// aggr_stms.push(aggr); -// batch_msgs.push(msg.to_vec()); -// batch_params.push(params); -// } -// Err(AggregationError::NotEnoughSignatures(_n, _k)) => { -// assert!(sigs.len() < params.k as usize) -// } -// Err(AggregationError::UsizeConversionInvalid) => unreachable!(), -// Err(AggregationError::UnsupportedProofSystem(_)) => unreachable!(), -// } -// } - -// assert!(AggregateSignature::batch_verify(&aggr_stms, &batch_msgs, &aggr_avks, &batch_params).is_ok()); - -// let mut msg = [0u8; 32]; -// rng.fill_bytes(&mut msg); -// let params = Parameters { m, k, phi_f: 0.8 }; -// let ps = setup_equal_parties(params, nparties); -// let clerk = Clerk::new_clerk_from_signer(&ps[0]); - -// let all_ps: Vec = (0..nparties).collect(); -// let sigs = find_signatures(&msg, &ps, &all_ps); -// let fake_msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); - -// aggr_stms[0] = fake_msig.unwrap(); -// assert!(AggregateSignature::batch_verify(&aggr_stms, &batch_msgs, &aggr_avks, &batch_params).is_err()); -// } -// } - -// proptest! { -// #[test] -// /// Test that when a party creates a signature it can be verified -// fn test_sig(msg in any::<[u8;16]>()) { -// let params = Parameters { m: 1, k: 1, phi_f: 0.2 }; -// let ps = setup_equal_parties(params, 1); -// let clerk = Clerk::new_clerk_from_signer(&ps[0]); -// let avk = clerk.compute_aggregate_verification_key(); - -// if let Some(sig) = ps[0].sign(&msg) { -// assert!(sig.verify(¶ms, &ps[0].get_verification_key(), &ps[0].get_stake(), &avk, &msg).is_ok()); -// } -// } -// } - -// proptest! { -// #![proptest_config(ProptestConfig::with_cases(10))] -// #[test] -// fn test_parameters_serialize_deserialize(m in any::(), k in any::(), phi_f in any::()) { -// let params = Parameters { m, k, phi_f }; - -// let bytes = params.to_bytes(); -// let deserialised = Parameters::from_bytes(&bytes); -// assert!(deserialised.is_ok()) -// } - -// #[test] -// fn test_initializer_serialize_deserialize(seed in any::<[u8;32]>()) { -// let mut rng = ChaCha20Rng::from_seed(seed); -// let params = Parameters { m: 1, k: 1, phi_f: 1.0 }; -// let stake = rng.next_u64(); -// let initializer = Initializer::new(params, stake, &mut rng); - -// let bytes = initializer.to_bytes(); -// assert!(Initializer::from_bytes(&bytes).is_ok()); -// } - -// #[test] -// fn test_sig_serialize_deserialize(msg in any::<[u8;16]>()) { -// let params = Parameters { m: 1, k: 1, phi_f: 0.2 }; -// let ps = setup_equal_parties(params, 1); -// let clerk = Clerk::new_clerk_from_signer(&ps[0]); -// let avk = clerk.compute_aggregate_verification_key(); - -// if let Some(sig) = ps[0].sign(&msg) { -// let bytes = sig.to_bytes(); -// let sig_deser = SingleSignature::from_bytes::(&bytes).unwrap(); -// assert!(sig_deser.verify(¶ms, &ps[0].get_verification_key(), &ps[0].get_stake(), &avk, &msg).is_ok()); -// } -// } - -// #[test] -// fn test_multisig_serialize_deserialize(nparties in 2_usize..10, -// msg in any::<[u8;16]>()) { -// let params = Parameters { m: 10, k: 5, phi_f: 1.0 }; -// let ps = setup_equal_parties(params, nparties); -// let clerk = Clerk::new_clerk_from_signer(&ps[0]); -// let aggr_sig_type = AggregateSignatureType::Concatenation; - -// let all_ps: Vec = (0..nparties).collect(); -// let sigs = find_signatures(&msg, &ps, &all_ps); -// let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); -// if let Ok(aggr) = msig { -// let bytes: Vec = aggr.to_bytes(); -// let aggr2 = AggregateSignature::from_bytes(&bytes).unwrap(); -// assert!(aggr2.verify(&msg, &clerk.compute_aggregate_verification_key(), ¶ms).is_ok()); -// } -// } -// } - -// proptest! { -// #![proptest_config(ProptestConfig::with_cases(10))] - -// #[test] -// /// Test that when the adversaries do not hold sufficient stake, they can not form a quorum -// fn test_adversary_quorum( -// (adversaries, parties) in arb_parties_adversary_stake(8, 30, 16, 4), -// msg in any::<[u8;16]>(), -// ) { -// // Test sanity check: -// // Check that the adversarial party has less than 40% of the total stake. -// let (good, bad) = parties.iter().enumerate().fold((0,0), |(acc1, acc2), (i, st)| { -// if adversaries.contains(&i) { -// (acc1, acc2 + *st) -// } else { -// (acc1 + *st, acc2) -// } -// }); -// assert!(bad as f64 / ((good + bad) as f64) < 0.4); - -// let params = Parameters { m: 2642, k: 357, phi_f: 0.2 }; // From Table 1 -// let ps = setup_parties(params, parties); - -// let sigs = find_signatures(&msg, &ps, &adversaries.into_iter().collect::>()); - -// assert!(sigs.len() < params.k as usize); - -// let clerk = Clerk::new_clerk_from_signer(&ps[0]); -// let aggr_sig_type = AggregateSignatureType::Concatenation; - -// let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); -// match msig { -// Err(AggregationError::NotEnoughSignatures(n, k)) => -// assert!(n < params.k && params.k == k), -// _ => -// unreachable!(), -// } -// } -// } - -// proptest! { -// // Each of the tests below corresponds to falsifying a conjunct in the -// // definition of a valid signature -// #[test] -// fn test_invalid_proof_quorum(tc in arb_proof_setup(10)) { -// with_proof_mod(tc, |_aggr, clerk, _msg| { -// clerk.params.k += 7; -// }) -// } -// // todo: fn test_invalid_proof_individual_sig -// #[test] -// fn test_invalid_proof_index_bound(tc in arb_proof_setup(10)) { -// with_proof_mod(tc, |_aggr, clerk, _msg| { -// clerk.params.m = 1; -// }) -// } -// #[test] -// fn test_invalid_proof_index_unique(tc in arb_proof_setup(10)) { -// with_proof_mod(tc, |aggr, clerk, _msg| { -// let mut concatenation_proof = AggregateSignature::to_concatenation_proof(aggr).unwrap().to_owned(); -// for sig_reg in concatenation_proof.signatures.iter_mut() { -// for index in sig_reg.sig.indexes.iter_mut() { -// *index %= clerk.params.k - 1 -// } -// } -// *aggr = AggregateSignature::Concatenation(concatenation_proof); -// }) -// } -// #[test] -// fn test_invalid_proof_path(tc in arb_proof_setup(10)) { -// with_proof_mod(tc, |aggr, _, _msg| { -// let mut concatenation_proof = AggregateSignature::to_concatenation_proof(aggr).unwrap().to_owned(); -// let p = concatenation_proof.batch_proof.clone(); -// let mut index_list = p.indices.clone(); -// let values = p.values; -// let batch_proof = { -// index_list[0] += 1; -// MerkleBatchPath { -// values, -// indices: index_list, -// hasher: Default::default() -// } -// }; -// concatenation_proof.batch_proof = batch_proof; -// *aggr = AggregateSignature::Concatenation(concatenation_proof); -// }) -// } -// } - -// // --------------------------------------------------------------------- -// // Basic verifier -// // --------------------------------------------------------------------- -// fn setup_equal_core_parties( -// params: Parameters, -// nparties: usize, -// ) -> (Vec, Vec<(BlsVerificationKey, Stake)>) { -// let stake = vec![1; nparties]; -// setup_core_parties(params, stake) -// } - -// fn setup_core_parties( -// params: Parameters, -// stake: Vec, -// ) -> (Vec, Vec<(BlsVerificationKey, Stake)>) { -// let mut trng = TestRng::deterministic_rng(ChaCha); -// let mut rng = ChaCha20Rng::from_seed(trng.random()); - -// let ps = stake -// .into_iter() -// .map(|stake| Initializer::new(params, stake, &mut rng)) -// .collect::>(); - -// let public_signers = ps -// .iter() -// .map(|s| (s.pk.vk, s.stake)) -// .collect::>(); - -// (ps, public_signers) -// } - -// fn find_core_signatures( -// msg: &[u8], -// ps: &[Signer], -// total_stake: Stake, -// is: &[usize], -// ) -> Vec { -// let mut sigs = Vec::new(); -// for i in is { -// if let Some(sig) = ps[*i].basic_sign(msg, total_stake) { -// sigs.push(sig); -// } -// } -// sigs -// } - -// proptest! { -// #![proptest_config(ProptestConfig::with_cases(50))] - -// #[test] -// fn test_core_verifier(nparties in 2_usize..30, -// m in 10_u64..20, -// k in 1_u64..5, -// msg in any::<[u8;16]>()) { - -// let params = Parameters { m, k, phi_f: 0.2 }; -// let (initializers, public_signers) = setup_equal_core_parties(params, nparties); -// let all_ps: Vec = (0..nparties).collect(); - -// let core_verifier = BasicVerifier::new(&public_signers); - -// let signers = initializers -// .into_iter() -// .filter_map(|s| s.create_basic_signer(&core_verifier.eligible_parties)) -// .collect::>>(); - -// let signatures = find_core_signatures(&msg, &signers, core_verifier.total_stake, &all_ps); - -// let verify_result = core_verifier.verify(&signatures, ¶ms, &msg); - -// match verify_result{ -// Ok(_) => { -// assert!(verify_result.is_ok(), "Verification failed: {verify_result:?}"); -// } -// Err(CoreVerifierError::NoQuorum(nr_indices, _k)) => { -// assert!((nr_indices) < params.k); -// } -// Err(CoreVerifierError::IndexNotUnique) => unreachable!(), -// _ => unreachable!(), -// } -// } - -// #[test] -// fn test_total_stake_core_verifier(nparties in 2_usize..30, -// m in 10_u64..20, -// k in 1_u64..5,) { -// let params = Parameters { m, k, phi_f: 0.2 }; -// let (_initializers, public_signers) = setup_equal_core_parties(params, nparties); -// let core_verifier = BasicVerifier::new(&public_signers); -// assert_eq!(nparties as u64, core_verifier.total_stake, "Total stake expected: {}, got: {}.", nparties, core_verifier.total_stake); -// } -// } -// } +#[cfg(test)] +mod tests { + use std::collections::{HashMap, HashSet}; + + use blake2::{Blake2b, digest::consts::U32}; + use proptest::{ + collection::{hash_map, vec}, + prelude::*, + test_runner::{RngAlgorithm::ChaCha, TestRng}, + }; + use rand_chacha::ChaCha20Rng; + use rand_core::{RngCore, SeedableRng}; + + use crate::{ + AggregateSignature, AggregateSignatureType, AggregationError, BasicVerifier, Clerk, + Initializer, KeyRegistration, Parameters, Signer, SingleSignature, + SingleSignatureWithRegisteredParty, Stake, bls_multi_signature::BlsVerificationKey, + }; + use crate::{StmResult, merkle_tree::MerkleBatchPath}; + + type Sig = AggregateSignature; + type D = Blake2b; + + fn setup_equal_parties(params: Parameters, nparties: usize) -> Vec> { + let stake = vec![1; nparties]; + setup_parties(params, stake) + } + + fn setup_parties(params: Parameters, stake: Vec) -> Vec> { + let mut kr = KeyRegistration::init(); + let mut trng = TestRng::deterministic_rng(ChaCha); + let mut rng = ChaCha20Rng::from_seed(trng.random()); + + #[allow(clippy::needless_collect)] + let ps = stake + .into_iter() + .map(|stake| { + let p = Initializer::new(params, stake, &mut rng); + kr.register(stake, p.pk).unwrap(); + p + }) + .collect::>(); + let closed_reg = kr.close(); + ps.into_iter() + .map(|p| p.create_signer(closed_reg.clone()).unwrap()) + .collect() + } + + /// Generate a vector of stakes that should sum to `honest_stake` + /// when ignoring the indices in `adversaries` + fn arb_honest_for_adversaries( + num_parties: usize, + honest_stake: Stake, + adversaries: HashMap, + ) -> impl Strategy> { + vec(1..honest_stake, num_parties).prop_map(move |parties| { + let honest_sum = parties.iter().enumerate().fold(0, |acc, (i, s)| { + if !adversaries.contains_key(&i) { + acc + s + } else { + acc + } + }); + + parties + .iter() + .enumerate() + .map(|(i, s)| { + if let Some(a) = adversaries.get(&i) { + *a + } else { + (*s * honest_stake) / honest_sum + } + }) + .collect() + }) + } + + /// Generate a vector of `num_parties` stakes summing to `num_parties * total_stake`, + /// plus a subset S of 0..num_parties such that the sum of the stakes at indices + /// in S is adversary_stake * N + fn arb_parties_with_adversaries( + num_parties: usize, + num_adversaries: usize, + total_stake: Stake, + adversary_stake: Stake, + ) -> impl Strategy, Vec)> { + hash_map(0..num_parties, 1..total_stake, num_adversaries).prop_flat_map( + move |adversaries| { + let adversary_sum: Stake = adversaries.values().sum(); + let adversaries_normed = adversaries + .iter() + .map(|(a, stake)| (*a, (stake * adversary_stake) / adversary_sum)) + .collect(); + + let adversaries = adversaries.into_keys().collect(); + ( + Just(adversaries), + arb_honest_for_adversaries( + num_parties, + total_stake - adversary_stake, + adversaries_normed, + ), + ) + }, + ) + } + + fn find_signatures(msg: &[u8], ps: &[Signer], is: &[usize]) -> Vec { + let mut sigs = Vec::new(); + for i in is { + if let Some(sig) = ps[*i].sign(msg) { + sigs.push(sig); + } + } + sigs + } + + /// Pick N between min and max, and then + /// generate a vector of N stakes summing to N * tstake, + /// plus a subset S of 0..N such that the sum of the stakes at indices + /// in S is astake * N + fn arb_parties_adversary_stake( + min: usize, + max: usize, + tstake: Stake, + astake: Stake, + ) -> impl Strategy, Vec)> { + (min..max) + .prop_flat_map(|n| (Just(n), 1..=n / 2)) + .prop_flat_map(move |(n, nadv)| { + arb_parties_with_adversaries(n, nadv, tstake * n as Stake, astake * n as Stake) + }) + } + + #[derive(Debug)] + struct ProofTest { + msig: StmResult, + clerk: Clerk, + msg: [u8; 16], + } + /// Run the protocol up to aggregation. This will produce a valid aggregation of signatures. + /// The following tests mutate this aggregation so that the proof is no longer valid. + fn arb_proof_setup(max_parties: usize) -> impl Strategy { + any::<[u8; 16]>().prop_flat_map(move |msg| { + (2..max_parties).prop_map(move |n| { + let params = Parameters { + m: 5, + k: 5, + phi_f: 1.0, + }; + let ps = setup_equal_parties(params, n); + let clerk = Clerk::new_clerk_from_signer(&ps[0]); + + let all_ps: Vec = (0..n).collect(); + let sigs = find_signatures(&msg, &ps, &all_ps); + + let aggr_sig_type = AggregateSignatureType::Concatenation; + let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); + ProofTest { msig, clerk, msg } + }) + }) + } + + fn with_proof_mod(mut tc: ProofTest, f: F) + where + F: Fn(&mut Sig, &mut Clerk, &mut [u8; 16]), + { + match tc.msig { + Ok(mut aggr) => { + f(&mut aggr, &mut tc.clerk, &mut tc.msg); + assert!( + aggr.verify( + &tc.msg, + &tc.clerk.compute_aggregate_verification_key(), + &tc.clerk.params + ) + .is_err() + ) + } + Err(e) => unreachable!("Reached an unexpected error: {:?}", e), + } + } + + proptest! { + #![proptest_config(ProptestConfig::with_cases(50))] + + #[test] + /// Test that `dedup_sigs_for_indices` only takes valid signatures. + fn test_dedup(msg in any::<[u8; 16]>()) { + let false_msg = [1u8; 20]; + let params = Parameters { m: 1, k: 1, phi_f: 1.0 }; + let ps = setup_equal_parties(params, 1); + let clerk = Clerk::new_clerk_from_signer(&ps[0]); + let avk = clerk.compute_aggregate_verification_key(); + let mut sigs = Vec::with_capacity(2); + + if let Some(sig) = ps[0].sign(&false_msg) { + sigs.push(sig); + } + + if let Some(sig) = ps[0].sign(&msg) { + sigs.push(sig); + } + + let sig_reg_list = sigs + .iter() + .map(|sig| SingleSignatureWithRegisteredParty { + sig: sig.clone(), + reg_party: clerk.closed_reg.reg_parties[sig.signer_index as usize], + }) + .collect::>(); + + let msgp = avk.get_merkle_tree_batch_commitment().concatenate_with_message(&msg); + let dedup_result = BasicVerifier::select_valid_signatures_for_k_indices( + &clerk.closed_reg.total_stake, + ¶ms, + &msgp, + &sig_reg_list, + ); + assert!(dedup_result.is_ok(), "dedup failure {dedup_result:?}"); + for passed_sigs in dedup_result.unwrap() { + let verify_result = passed_sigs.sig.verify(¶ms, &ps[0].get_verification_key(), &ps[0].get_stake(), &avk, &msg); + assert!(verify_result.is_ok(), "verify {verify_result:?}"); + } + } + } + + proptest! { + #![proptest_config(ProptestConfig::with_cases(50))] + + #[test] + /// Test that when a quorum is found, the aggregate signature can be verified by anyone with + /// access to the avk and the parameters. + fn test_aggregate_sig(nparties in 2_usize..30, + m in 10_u64..20, + k in 1_u64..5, + msg in any::<[u8;16]>()) { + let params = Parameters { m, k, phi_f: 0.2 }; + let ps = setup_equal_parties(params, nparties); + let clerk = Clerk::new_clerk_from_signer(&ps[0]); + let aggr_sig_type = AggregateSignatureType::Concatenation; + + let all_ps: Vec = (0..nparties).collect(); + let sigs = find_signatures(&msg, &ps, &all_ps); + let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); + + match msig { + Ok(aggr) => { + let verify_result = aggr.verify(&msg, &clerk.compute_aggregate_verification_key(), ¶ms); + assert!(verify_result.is_ok(), "Verification failed: {verify_result:?}"); + } + Err(error) => { assert!( + matches!( + error.downcast_ref::(), + Some(AggregationError::NotEnoughSignatures{..}) + ), + "Unexpected error: {error:?}"); + } + } + } + + #[test] + /// Test that batch verification of certificates works + fn batch_verify(nparties in 2_usize..30, + m in 10_u64..20, + k in 1_u64..4, + seed in any::<[u8;32]>(), + batch_size in 2..10, + ) { + let aggr_sig_type = AggregateSignatureType::Concatenation; + let mut rng = ChaCha20Rng::from_seed(seed); + let mut aggr_avks = Vec::new(); + let mut aggr_stms = Vec::new(); + let mut batch_msgs = Vec::new(); + let mut batch_params = Vec::new(); + for _ in 0..batch_size { + let mut msg = [0u8; 32]; + rng.fill_bytes(&mut msg); + let params = Parameters { m, k, phi_f: 0.95 }; + let ps = setup_equal_parties(params, nparties); + let clerk = Clerk::new_clerk_from_signer(&ps[0]); + + let all_ps: Vec = (0..nparties).collect(); + let sigs = find_signatures(&msg, &ps, &all_ps); + let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); + + match msig { + Ok(aggr) => { + aggr_avks.push(clerk.compute_aggregate_verification_key()); + aggr_stms.push(aggr); + batch_msgs.push(msg.to_vec()); + batch_params.push(params); + } + Err(error) => { assert!( + matches!( + error.downcast_ref::(), + Some(AggregationError::NotEnoughSignatures{..}) + ), + "Unexpected error: {error:?}"); + } + } + } + + assert!(AggregateSignature::batch_verify(&aggr_stms, &batch_msgs, &aggr_avks, &batch_params).is_ok()); + + let mut msg = [0u8; 32]; + rng.fill_bytes(&mut msg); + let params = Parameters { m, k, phi_f: 0.8 }; + let ps = setup_equal_parties(params, nparties); + let clerk = Clerk::new_clerk_from_signer(&ps[0]); + + let all_ps: Vec = (0..nparties).collect(); + let sigs = find_signatures(&msg, &ps, &all_ps); + let fake_msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); + + aggr_stms[0] = fake_msig.unwrap(); + assert!(AggregateSignature::batch_verify(&aggr_stms, &batch_msgs, &aggr_avks, &batch_params).is_err()); + } + } + + proptest! { + #[test] + /// Test that when a party creates a signature it can be verified + fn test_sig(msg in any::<[u8;16]>()) { + let params = Parameters { m: 1, k: 1, phi_f: 0.2 }; + let ps = setup_equal_parties(params, 1); + let clerk = Clerk::new_clerk_from_signer(&ps[0]); + let avk = clerk.compute_aggregate_verification_key(); + + if let Some(sig) = ps[0].sign(&msg) { + assert!(sig.verify(¶ms, &ps[0].get_verification_key(), &ps[0].get_stake(), &avk, &msg).is_ok()); + } + } + } + + proptest! { + #![proptest_config(ProptestConfig::with_cases(10))] + #[test] + fn test_parameters_serialize_deserialize(m in any::(), k in any::(), phi_f in any::()) { + let params = Parameters { m, k, phi_f }; + + let bytes = params.to_bytes(); + let deserialised = Parameters::from_bytes(&bytes); + assert!(deserialised.is_ok()) + } + + #[test] + fn test_initializer_serialize_deserialize(seed in any::<[u8;32]>()) { + let mut rng = ChaCha20Rng::from_seed(seed); + let params = Parameters { m: 1, k: 1, phi_f: 1.0 }; + let stake = rng.next_u64(); + let initializer = Initializer::new(params, stake, &mut rng); + + let bytes = initializer.to_bytes(); + assert!(Initializer::from_bytes(&bytes).is_ok()); + } + + #[test] + fn test_sig_serialize_deserialize(msg in any::<[u8;16]>()) { + let params = Parameters { m: 1, k: 1, phi_f: 0.2 }; + let ps = setup_equal_parties(params, 1); + let clerk = Clerk::new_clerk_from_signer(&ps[0]); + let avk = clerk.compute_aggregate_verification_key(); + + if let Some(sig) = ps[0].sign(&msg) { + let bytes = sig.to_bytes(); + let sig_deser = SingleSignature::from_bytes::(&bytes).unwrap(); + assert!(sig_deser.verify(¶ms, &ps[0].get_verification_key(), &ps[0].get_stake(), &avk, &msg).is_ok()); + } + } + + #[test] + fn test_multisig_serialize_deserialize(nparties in 2_usize..10, + msg in any::<[u8;16]>()) { + let params = Parameters { m: 10, k: 5, phi_f: 1.0 }; + let ps = setup_equal_parties(params, nparties); + let clerk = Clerk::new_clerk_from_signer(&ps[0]); + let aggr_sig_type = AggregateSignatureType::Concatenation; + + let all_ps: Vec = (0..nparties).collect(); + let sigs = find_signatures(&msg, &ps, &all_ps); + let msig = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type); + if let Ok(aggr) = msig { + let bytes: Vec = aggr.to_bytes(); + let aggr2 = AggregateSignature::from_bytes(&bytes).unwrap(); + assert!(aggr2.verify(&msg, &clerk.compute_aggregate_verification_key(), ¶ms).is_ok()); + } + } + } + + proptest! { + #![proptest_config(ProptestConfig::with_cases(10))] + + #[test] + /// Test that when the adversaries do not hold sufficient stake, they can not form a quorum + fn test_adversary_quorum( + (adversaries, parties) in arb_parties_adversary_stake(8, 30, 16, 4), + msg in any::<[u8;16]>(), + ) { + // Test sanity check: + // Check that the adversarial party has less than 40% of the total stake. + let (good, bad) = parties.iter().enumerate().fold((0,0), |(acc1, acc2), (i, st)| { + if adversaries.contains(&i) { + (acc1, acc2 + *st) + } else { + (acc1 + *st, acc2) + } + }); + assert!(bad as f64 / ((good + bad) as f64) < 0.4); + + let params = Parameters { m: 2642, k: 357, phi_f: 0.2 }; // From Table 1 + let ps = setup_parties(params, parties); + + let sigs = find_signatures(&msg, &ps, &adversaries.into_iter().collect::>()); + + assert!(sigs.len() < params.k as usize); + + let clerk = Clerk::new_clerk_from_signer(&ps[0]); + let aggr_sig_type = AggregateSignatureType::Concatenation; + + let error = clerk.aggregate_signatures_with_type(&sigs, &msg, aggr_sig_type).expect_err("Not enough quorum should fail!"); + assert!( + matches!( + error.downcast_ref::(), + Some(AggregationError::NotEnoughSignatures{..}) + ), + "Unexpected error: {error:?}"); + } + } + + proptest! { + // Each of the tests below corresponds to falsifying a conjunct in the + // definition of a valid signature + #[test] + fn test_invalid_proof_quorum(tc in arb_proof_setup(10)) { + with_proof_mod(tc, |_aggr, clerk, _msg| { + clerk.params.k += 7; + }) + } + // todo: fn test_invalid_proof_individual_sig + #[test] + fn test_invalid_proof_index_bound(tc in arb_proof_setup(10)) { + with_proof_mod(tc, |_aggr, clerk, _msg| { + clerk.params.m = 1; + }) + } + #[test] + fn test_invalid_proof_index_unique(tc in arb_proof_setup(10)) { + with_proof_mod(tc, |aggr, clerk, _msg| { + let mut concatenation_proof = AggregateSignature::to_concatenation_proof(aggr).unwrap().to_owned(); + for sig_reg in concatenation_proof.signatures.iter_mut() { + for index in sig_reg.sig.indexes.iter_mut() { + *index %= clerk.params.k - 1 + } + } + *aggr = AggregateSignature::Concatenation(concatenation_proof); + }) + } + #[test] + fn test_invalid_proof_path(tc in arb_proof_setup(10)) { + with_proof_mod(tc, |aggr, _, _msg| { + let mut concatenation_proof = AggregateSignature::to_concatenation_proof(aggr).unwrap().to_owned(); + let p = concatenation_proof.batch_proof.clone(); + let mut index_list = p.indices.clone(); + let values = p.values; + let batch_proof = { + index_list[0] += 1; + MerkleBatchPath { + values, + indices: index_list, + hasher: Default::default() + } + }; + concatenation_proof.batch_proof = batch_proof; + *aggr = AggregateSignature::Concatenation(concatenation_proof); + }) + } + } + + // --------------------------------------------------------------------- + // Basic verifier + // --------------------------------------------------------------------- + fn setup_equal_core_parties( + params: Parameters, + nparties: usize, + ) -> (Vec, Vec<(BlsVerificationKey, Stake)>) { + let stake = vec![1; nparties]; + setup_core_parties(params, stake) + } + + fn setup_core_parties( + params: Parameters, + stake: Vec, + ) -> (Vec, Vec<(BlsVerificationKey, Stake)>) { + let mut trng = TestRng::deterministic_rng(ChaCha); + let mut rng = ChaCha20Rng::from_seed(trng.random()); + + let ps = stake + .into_iter() + .map(|stake| Initializer::new(params, stake, &mut rng)) + .collect::>(); + + let public_signers = ps + .iter() + .map(|s| (s.pk.vk, s.stake)) + .collect::>(); + + (ps, public_signers) + } + + fn find_core_signatures( + msg: &[u8], + ps: &[Signer], + total_stake: Stake, + is: &[usize], + ) -> Vec { + let mut sigs = Vec::new(); + for i in is { + if let Some(sig) = ps[*i].basic_sign(msg, total_stake) { + sigs.push(sig); + } + } + sigs + } + + proptest! { + #![proptest_config(ProptestConfig::with_cases(50))] + + #[test] + fn test_core_verifier(nparties in 2_usize..30, + m in 10_u64..20, + k in 1_u64..5, + msg in any::<[u8;16]>()) { + + let params = Parameters { m, k, phi_f: 0.2 }; + let (initializers, public_signers) = setup_equal_core_parties(params, nparties); + let all_ps: Vec = (0..nparties).collect(); + + let core_verifier = BasicVerifier::new(&public_signers); + + let signers = initializers + .into_iter() + .filter_map(|s| s.create_basic_signer(&core_verifier.eligible_parties)) + .collect::>>(); + + let signatures = find_core_signatures(&msg, &signers, core_verifier.total_stake, &all_ps); + + let verify_result = core_verifier.verify(&signatures, ¶ms, &msg); + + match verify_result{ + Ok(_) => { + assert!(verify_result.is_ok(), "Verification failed: {verify_result:?}"); + } + Err(error) => { assert!( + matches!( + error.downcast_ref::(), + Some(AggregationError::NotEnoughSignatures{..}) + ), + "Unexpected error: {error:?}"); + } + } + } + + #[test] + fn test_total_stake_core_verifier(nparties in 2_usize..30, + m in 10_u64..20, + k in 1_u64..5,) { + let params = Parameters { m, k, phi_f: 0.2 }; + let (_initializers, public_signers) = setup_equal_core_parties(params, nparties); + let core_verifier = BasicVerifier::new(&public_signers); + assert_eq!(nparties as u64, core_verifier.total_stake, "Total stake expected: {}, got: {}.", nparties, core_verifier.total_stake); + } + } +} diff --git a/mithril-stm/src/aggregate_signature/signature.rs b/mithril-stm/src/aggregate_signature/signature.rs index dc3e80585b4..182de87957c 100644 --- a/mithril-stm/src/aggregate_signature/signature.rs +++ b/mithril-stm/src/aggregate_signature/signature.rs @@ -120,27 +120,36 @@ impl AggregateSignature { acc.entry(sig.into()).or_default().push(sig.clone()); acc }); - stm_signatures.into_iter().try_for_each( - |(aggregate_signature_type, aggregate_signatures)| match aggregate_signature_type { - AggregateSignatureType::Concatenation => { - let aggregate_signatures_length = aggregate_signatures.len(); - let concatenation_proofs = aggregate_signatures - .into_iter() - .filter_map(|s| s.to_concatenation_proof().cloned()) - .collect::>(); - if concatenation_proofs.len() != aggregate_signatures_length { - return Err(anyhow!(StmAggregateSignatureError::BatchInvalid)); - } + stm_signatures + .into_iter() + .try_for_each(|(aggregate_signature_type, aggregate_signatures)| { + match aggregate_signature_type { + AggregateSignatureType::Concatenation => { + let aggregate_signatures_length = aggregate_signatures.len(); + let concatenation_proofs = aggregate_signatures + .into_iter() + .filter_map(|s| s.to_concatenation_proof().cloned()) + .collect::>(); + if concatenation_proofs.len() != aggregate_signatures_length { + return Err(anyhow!(StmAggregateSignatureError::BatchInvalid)); + } - ConcatenationProof::batch_verify(&concatenation_proofs, msgs, avks, parameters) + ConcatenationProof::batch_verify( + &concatenation_proofs, + msgs, + avks, + parameters, + ) + } + #[cfg(feature = "future_proof_system")] + AggregateSignatureType::Future => { + Err(anyhow!(StmAggregateSignatureError::UnsupportedProofSystem( + aggregate_signature_type + ))) + } } - #[cfg(feature = "future_proof_system")] - AggregateSignatureType::Future => Err(anyhow!( - StmAggregateSignatureError::UnsupportedProofSystem(aggregate_signature_type) - )), - }, - ) - // .map_err(|_| StmAggregateSignatureError::BatchInvalid) + }) + .map_err(|_| anyhow!(StmAggregateSignatureError::BatchInvalid)) } /// Convert an aggregate signature to bytes diff --git a/mithril-stm/src/bls_multi_signature/signature.rs b/mithril-stm/src/bls_multi_signature/signature.rs index 6f62a691f4a..288d22b7673 100644 --- a/mithril-stm/src/bls_multi_signature/signature.rs +++ b/mithril-stm/src/bls_multi_signature/signature.rs @@ -182,7 +182,7 @@ impl BlsSignature { None, None, ) - // .map_err(|_| MultiSignatureError::BatchInvalid) + .map_err(|_| anyhow!(MultiSignatureError::BatchInvalid)) } } diff --git a/mithril-stm/src/bls_multi_signature/signing_key.rs b/mithril-stm/src/bls_multi_signature/signing_key.rs index 4619521c05c..d3f0a18d85d 100644 --- a/mithril-stm/src/bls_multi_signature/signing_key.rs +++ b/mithril-stm/src/bls_multi_signature/signing_key.rs @@ -49,35 +49,35 @@ impl BlsSigningKey { } } -// #[cfg(test)] -// mod tests { -// use super::*; +#[cfg(test)] +mod tests { + use super::*; -// mod golden { + mod golden { -// use rand_chacha::ChaCha20Rng; -// use rand_core::SeedableRng; + use rand_chacha::ChaCha20Rng; + use rand_core::SeedableRng; -// use super::*; + use super::*; -// const GOLDEN_JSON: &str = r#"[64, 129, 87, 121, 27, 239, 221, 215, 2, 103, 45, 207, 207, 201, 157, 163, 81, 47, 156, 14, 168, 24, 137, 15, 203, 106, 183, 73, 88, 14, 242, 207]"#; + const GOLDEN_JSON: &str = r#"[64, 129, 87, 121, 27, 239, 221, 215, 2, 103, 45, 207, 207, 201, 157, 163, 81, 47, 156, 14, 168, 24, 137, 15, 203, 106, 183, 73, 88, 14, 242, 207]"#; -// fn golden_value() -> BlsSigningKey { -// let mut rng = ChaCha20Rng::from_seed([0u8; 32]); -// BlsSigningKey::generate(&mut rng) -// } + fn golden_value() -> BlsSigningKey { + let mut rng = ChaCha20Rng::from_seed([0u8; 32]); + BlsSigningKey::generate(&mut rng) + } -// #[test] -// fn golden_conversions() { -// let value = serde_json::from_str(GOLDEN_JSON) -// .expect("This JSON deserialization should not fail"); -// assert_eq!(golden_value(), value); + #[test] + fn golden_conversions() { + let value = serde_json::from_str(GOLDEN_JSON) + .expect("This JSON deserialization should not fail"); + assert_eq!(golden_value(), value); -// let serialized = -// serde_json::to_string(&value).expect("This JSON serialization should not fail"); -// let golden_serialized = serde_json::to_string(&golden_value()) -// .expect("This JSON serialization should not fail"); -// assert_eq!(golden_serialized, serialized); -// } -// } -// } + let serialized = + serde_json::to_string(&value).expect("This JSON serialization should not fail"); + let golden_serialized = serde_json::to_string(&golden_value()) + .expect("This JSON serialization should not fail"); + assert_eq!(golden_serialized, serialized); + } + } +} diff --git a/mithril-stm/src/key_registration.rs b/mithril-stm/src/key_registration.rs index 36bc880cc74..1a6c680d9ae 100644 --- a/mithril-stm/src/key_registration.rs +++ b/mithril-stm/src/key_registration.rs @@ -86,69 +86,69 @@ pub struct ClosedKeyRegistration { pub merkle_tree: Arc>, } -// #[cfg(test)] -// mod tests { -// use blake2::{Blake2b, digest::consts::U32}; -// use proptest::{collection::vec, prelude::*}; -// use rand_chacha::ChaCha20Rng; -// use rand_core::SeedableRng; - -// use crate::bls_multi_signature::BlsSigningKey; - -// use super::*; - -// proptest! { -// #[test] -// fn test_keyreg(stake in vec(1..1u64 << 60, 2..=10), -// nkeys in 2..10_usize, -// fake_it in 0..4usize, -// seed in any::<[u8;32]>()) { -// let mut rng = ChaCha20Rng::from_seed(seed); -// let mut kr = KeyRegistration::init(); - -// let gen_keys = (1..nkeys).map(|_| { -// let sk = BlsSigningKey::generate(&mut rng); -// BlsVerificationKeyProofOfPossession::from(&sk) -// }).collect::>(); - -// let fake_key = { -// let sk = BlsSigningKey::generate(&mut rng); -// BlsVerificationKeyProofOfPossession::from(&sk) -// }; - -// // Record successful registrations -// let mut keys = HashMap::new(); - -// for (i, &stake) in stake.iter().enumerate() { -// let mut pk = gen_keys[i % gen_keys.len()]; - -// if fake_it == 0 { -// pk.pop = fake_key.pop; -// } - -// let reg = kr.register(stake, pk); -// match reg { -// Ok(_) => { -// assert!(keys.insert(pk.vk, stake).is_none()); -// }, -// Err(RegisterError::KeyRegistered(pk1)) => { -// assert!(pk1.as_ref() == &pk.vk); -// assert!(keys.contains_key(&pk.vk)); -// } -// Err(RegisterError::KeyInvalid(a)) => { -// assert_eq!(fake_it, 0); -// assert!(a.verify_proof_of_possession().is_err()); -// } -// Err(RegisterError::SerializationError) => unreachable!(), -// _ => unreachable!(), -// } -// } - -// if !kr.keys.is_empty() { -// let closed = kr.close::>(); -// let retrieved_keys = closed.reg_parties.iter().map(|r| (r.0, r.1)).collect::>(); -// assert!(retrieved_keys == keys); -// } -// } -// } -// } +#[cfg(test)] +mod tests { + use blake2::{Blake2b, digest::consts::U32}; + use proptest::{collection::vec, prelude::*}; + use rand_chacha::ChaCha20Rng; + use rand_core::SeedableRng; + + use crate::{bls_multi_signature::BlsSigningKey, error::MultiSignatureError}; + + use super::*; + + proptest! { + #[test] + fn test_keyreg(stake in vec(1..1u64 << 60, 2..=10), + nkeys in 2..10_usize, + fake_it in 0..4usize, + seed in any::<[u8;32]>()) { + let mut rng = ChaCha20Rng::from_seed(seed); + let mut kr = KeyRegistration::init(); + + let gen_keys = (1..nkeys).map(|_| { + let sk = BlsSigningKey::generate(&mut rng); + BlsVerificationKeyProofOfPossession::from(&sk) + }).collect::>(); + + let fake_key = { + let sk = BlsSigningKey::generate(&mut rng); + BlsVerificationKeyProofOfPossession::from(&sk) + }; + + // Record successful registrations + let mut keys = HashMap::new(); + + for (i, &stake) in stake.iter().enumerate() { + let mut pk = gen_keys[i % gen_keys.len()]; + + if fake_it == 0 { + pk.pop = fake_key.pop; + } + + let reg = kr.register(stake, pk); + + match reg { + Ok(_) => { + assert!(keys.insert(pk.vk, stake).is_none()); + }, + Err(error) => { assert!( + matches!( + error.downcast_ref::(), + Some(RegisterError::KeyRegistered{..}) + ) | matches!( + error.downcast_ref::(), + Some(MultiSignatureError::KeyInvalid{..}) + ), + "Unexpected error: {error:?}"); + } + } + } + if !kr.keys.is_empty() { + let closed = kr.close::>(); + let retrieved_keys = closed.reg_parties.iter().map(|r| (r.0, r.1)).collect::>(); + assert!(retrieved_keys == keys); + } + } + } +} diff --git a/mithril-stm/src/lib.rs b/mithril-stm/src/lib.rs index 76855976846..cb23a152f95 100644 --- a/mithril-stm/src/lib.rs +++ b/mithril-stm/src/lib.rs @@ -99,11 +99,13 @@ //! .verify(&msg, &clerk.compute_avk(), ¶ms) //! .is_ok()); //! } -//! Err(AggregationError::NotEnoughSignatures(n, k)) => { -//! println!("Not enough signatures"); -//! assert!(n < params.k && k == params.k) -//! } -//! Err(_) => unreachable!(), +//! Err(error) => assert!( +//! matches!( +//! error.downcast_ref::(), +//! Some(AggregationError::NotEnoughSignatures { .. }) +//! ), +//! "Unexpected error: {error}" +//! ), //! } //! # Ok(()) //! # } diff --git a/mithril-stm/tests/stm_basic.rs b/mithril-stm/tests/stm_basic.rs index 8cc4ff71ac2..6ef382ca72d 100644 --- a/mithril-stm/tests/stm_basic.rs +++ b/mithril-stm/tests/stm_basic.rs @@ -1,7 +1,7 @@ use blake2::Blake2b; use digest::consts::U32; use mithril_stm::{ - BasicVerifier, CoreVerifierError, Initializer, Parameters, Signer, SingleSignature, Stake, + AggregationError, BasicVerifier, Initializer, Parameters, Signer, SingleSignature, Stake, VerificationKey, }; use rand_chacha::ChaCha20Rng; @@ -64,10 +64,12 @@ fn test_core_verifier() { "Verification failed: {verify_result:?}" ); } - Err(CoreVerifierError::NoQuorum(nr_indices, _k)) => { - assert!((nr_indices) < params.k); - } - Err(CoreVerifierError::IndexNotUnique) => unreachable!(), - _ => unreachable!(), + Err(error) => assert!( + matches!( + error.downcast_ref::(), + Some(AggregationError::NotEnoughSignatures { .. }) + ), + "Unexpected error: {error}" + ), } } diff --git a/mithril-stm/tests/stm_protocol.rs b/mithril-stm/tests/stm_protocol.rs index 48a8ab44a2e..f78b761fa9c 100644 --- a/mithril-stm/tests/stm_protocol.rs +++ b/mithril-stm/tests/stm_protocol.rs @@ -34,16 +34,15 @@ fn test_full_protocol() { println!("Aggregate ok"); assert!(aggr.verify(&msg, &avk, ¶ms).is_ok()); } - Err(AggregationError::NotEnoughSignatures(n, k)) => { - println!("Not enough signatures"); - assert!(n < params.k && k == params.k) - } - Err(AggregationError::UsizeConversionInvalid) => { - println!("Invalid usize conversion"); - } - Err(AggregationError::UnsupportedProofSystem(_)) => { - println!("Unsupported proof system"); - } + Err(error) => assert!( + matches!( + error.downcast_ref::(), + Some(AggregationError::NotEnoughSignatures { .. }) + | Some(AggregationError::UsizeConversionInvalid) + | Some(AggregationError::UnsupportedProofSystem { .. }) + ), + "Unexpected error: {error}" + ), } } diff --git a/mithril-stm/tests/test_extensions/protocol_phase.rs b/mithril-stm/tests/test_extensions/protocol_phase.rs index 568048ad45d..063ece4fdb8 100644 --- a/mithril-stm/tests/test_extensions/protocol_phase.rs +++ b/mithril-stm/tests/test_extensions/protocol_phase.rs @@ -4,8 +4,8 @@ use rand_core::RngCore; use rayon::prelude::*; use mithril_stm::{ - AggregateSignature, AggregateSignatureType, AggregateVerificationKey, AggregationError, Clerk, - Initializer, KeyRegistration, Parameters, Signer, SingleSignature, Stake, VerificationKey, + AggregateSignature, AggregateSignatureType, AggregateVerificationKey, Clerk, Initializer, + KeyRegistration, Parameters, Signer, SingleSignature, Stake, StmResult, VerificationKey, }; type H = Blake2b; @@ -19,7 +19,7 @@ pub struct InitializationPhaseResult { /// The result of the operation phase of the STM protocol. pub struct OperationPhaseResult { - pub msig: Result, AggregationError>, + pub msig: StmResult>, pub avk: AggregateVerificationKey, pub sigs: Vec, }