diff --git a/Cargo.lock b/Cargo.lock index 696f28ce1c1..7034440ffee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4146,8 +4146,9 @@ dependencies = [ [[package]] name = "mithril-stm" -version = "0.5.5" +version = "0.6.0" dependencies = [ + "anyhow", "blake2 0.10.6", "blst", "criterion", diff --git a/mithril-aggregator/src/multi_signer.rs b/mithril-aggregator/src/multi_signer.rs index cac34987ca2..2fba5d8ce20 100644 --- a/mithril-aggregator/src/multi_signer.rs +++ b/mithril-aggregator/src/multi_signer.rs @@ -130,17 +130,19 @@ impl MultiSigner for MultiSignerImpl { self.aggregate_signature_type, ) { Ok(multi_signature) => Ok(Some(multi_signature)), - Err(ProtocolAggregationError::NotEnoughSignatures(actual, expected)) => { - warn!( - self.logger, - "Could not compute multi-signature: Not enough signatures. Got only {actual} out of {expected}." - ); - Ok(None) - } - Err(err) => Err(anyhow!(err).context(format!( - "Multi Signer can not create multi-signature for entity type '{:?}'", - open_message.signed_entity_type - ))), + Err(err) => match err.downcast_ref::() { + Some(ProtocolAggregationError::NotEnoughSignatures(actual, expected)) => { + warn!( + self.logger, + "Could not compute multi-signature: Not enough signatures. Got only {actual} out of {expected}." + ); + Ok(None) + } + _ => Err(anyhow!(err).context(format!( + "Multi Signer can not create multi-signature for entity type '{:?}'", + open_message.signed_entity_type + ))), + }, } } } diff --git a/mithril-common/src/crypto_helper/cardano/key_certification.rs b/mithril-common/src/crypto_helper/cardano/key_certification.rs index 0a6449a78bb..cdaebfec1e2 100644 --- a/mithril-common/src/crypto_helper/cardano/key_certification.rs +++ b/mithril-common/src/crypto_helper/cardano/key_certification.rs @@ -5,6 +5,7 @@ use std::{collections::HashMap, sync::Arc}; +use anyhow::anyhow; use blake2::{ Blake2b, Digest, digest::{FixedOutput, consts::U32}, @@ -173,13 +174,8 @@ impl StmInitializerWrapper { /// * the current total stake (according to the registration service) /// # Error /// This function fails if the initializer is not registered. - pub fn new_signer( - self, - closed_reg: ClosedKeyRegistration, - ) -> Result, ProtocolRegistrationErrorWrapper> { - self.stm_initializer - .create_signer(closed_reg) - .map_err(ProtocolRegistrationErrorWrapper::CoreRegister) + pub fn new_signer(self, closed_reg: ClosedKeyRegistration) -> StdResult> { + self.stm_initializer.create_signer(closed_reg) } /// Convert to bytes @@ -199,7 +195,7 @@ impl StmInitializerWrapper { /// Convert a slice of bytes to an `StmInitializerWrapper` /// # 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]) -> StdResult { let stm_initializer = Initializer::from_bytes(bytes.get(..256).ok_or(RegisterError::SerializationError)?)?; let bytes = bytes.get(256..).ok_or(RegisterError::SerializationError)?; @@ -250,7 +246,7 @@ impl KeyRegWrapper { kes_sig: Option, // Used for only for testing when SPO pool id is not certified kes_period: Option, pk: ProtocolSignerVerificationKey, - ) -> Result { + ) -> StdResult { let pool_id_bech32: ProtocolPartyId = if let Some(opcert) = opcert { let signature = kes_sig.ok_or(ProtocolRegistrationErrorWrapper::KesSignatureMissing)?; let kes_period = @@ -264,9 +260,11 @@ impl KeyRegWrapper { .compute_protocol_party_id() .map_err(|_| ProtocolRegistrationErrorWrapper::PoolAddressEncoding)? } else { - return Err(ProtocolRegistrationErrorWrapper::KesSignatureInvalid( - kes_period, - opcert.get_start_kes_period(), + return Err(anyhow!( + ProtocolRegistrationErrorWrapper::KesSignatureInvalid( + kes_period, + opcert.get_start_kes_period(), + ) )); } } else { @@ -277,12 +275,12 @@ impl KeyRegWrapper { }; if let Some(&stake) = self.stake_distribution.get(&pool_id_bech32) { - self.stm_key_reg - .register(stake, pk.into()) - .map_err(ProtocolRegistrationErrorWrapper::CoreRegister)?; + self.stm_key_reg.register(stake, pk.into())?; return Ok(pool_id_bech32); } - Err(ProtocolRegistrationErrorWrapper::PartyIdNonExisting) + Err(anyhow!( + ProtocolRegistrationErrorWrapper::PartyIdNonExisting + )) } /// Finalize the key registration. diff --git a/mithril-common/src/crypto_helper/codec/binary.rs b/mithril-common/src/crypto_helper/codec/binary.rs index 65eb2edc266..7d87eb86321 100644 --- a/mithril-common/src/crypto_helper/codec/binary.rs +++ b/mithril-common/src/crypto_helper/codec/binary.rs @@ -61,7 +61,7 @@ mod binary_mithril_stm { impl TryFromBytes for SingleSignature { fn try_from_bytes(bytes: &[u8]) -> StdResult { - Self::from_bytes::(bytes).map_err(|e| e.into()) + Self::from_bytes::(bytes) } } @@ -73,7 +73,7 @@ mod binary_mithril_stm { impl TryFromBytes for SingleSignatureWithRegisteredParty { fn try_from_bytes(bytes: &[u8]) -> StdResult { - Self::from_bytes::(bytes).map_err(|e| e.into()) + Self::from_bytes::(bytes) } } @@ -97,7 +97,7 @@ mod binary_mithril_stm { impl TryFromBytes for VerificationKey { fn try_from_bytes(bytes: &[u8]) -> StdResult { - Self::from_bytes(bytes).map_err(|e| e.into()) + Self::from_bytes(bytes) } } @@ -109,7 +109,7 @@ mod binary_mithril_stm { impl TryFromBytes for VerificationKeyProofOfPossession { fn try_from_bytes(bytes: &[u8]) -> StdResult { - Self::from_bytes(bytes).map_err(|e| e.into()) + Self::from_bytes(bytes) } } @@ -139,7 +139,7 @@ mod binary_mithril_stm { impl TryFromBytes for Initializer { fn try_from_bytes(bytes: &[u8]) -> StdResult { - Self::from_bytes(bytes).map_err(|e| e.into()) + Self::from_bytes(bytes) } } } diff --git a/mithril-common/src/protocol/multi_signer.rs b/mithril-common/src/protocol/multi_signer.rs index ab629db9f90..b3476640263 100644 --- a/mithril-common/src/protocol/multi_signer.rs +++ b/mithril-common/src/protocol/multi_signer.rs @@ -3,10 +3,7 @@ use mithril_stm::{AggregateSignatureType, Parameters}; use crate::{ StdResult, - crypto_helper::{ - ProtocolAggregateVerificationKey, ProtocolAggregationError, ProtocolClerk, - ProtocolMultiSignature, - }, + crypto_helper::{ProtocolAggregateVerificationKey, ProtocolClerk, ProtocolMultiSignature}, entities::SingleSignature, protocol::ToMessage, }; @@ -31,7 +28,7 @@ impl MultiSigner { single_signatures: &[SingleSignature], message: &T, aggregate_signature_type: AggregateSignatureType, - ) -> Result { + ) -> StdResult { let protocol_signatures: Vec<_> = single_signatures .iter() .map(|single_signature| single_signature.to_protocol_signature()) @@ -94,9 +91,10 @@ impl MultiSigner { #[cfg(test)] mod test { - use mithril_stm::StmSignatureError; + use mithril_stm::MultiSignatureError; use crate::{ + crypto_helper::ProtocolAggregationError, entities::{ProtocolMessage, ProtocolMessagePartKey, ProtocolParameters}, protocol::SignerBuilder, test::{ @@ -129,7 +127,10 @@ mod test { ); assert!( - matches!(error, ProtocolAggregationError::NotEnoughSignatures(_, _)), + matches!( + error.downcast_ref::(), + Some(ProtocolAggregationError::NotEnoughSignatures(_, _)) + ), "Expected ProtocolAggregationError::NotEnoughSignatures, got: {error:?}" ) } @@ -194,8 +195,8 @@ mod test { "Verify single signature should fail if the signer isn't in the registered parties", ); - match error.downcast_ref::() { - Some(StmSignatureError::SignatureInvalid(_)) => (), + match error.downcast_ref::() { + Some(MultiSignatureError::SignatureInvalid(_)) => (), _ => panic!("Expected an SignatureInvalid error, got: {error:?}"), } } @@ -220,8 +221,8 @@ mod test { .verify_single_signature(&ProtocolMessage::default(), &single_signature) .expect_err("Verify single signature should fail"); - match error.downcast_ref::() { - Some(StmSignatureError::SignatureInvalid(_)) => (), + match error.downcast_ref::() { + Some(MultiSignatureError::SignatureInvalid(_)) => (), _ => panic!("Expected an SignatureInvalid error, got: {error:?}"), } } diff --git a/mithril-common/src/protocol/signer_builder.rs b/mithril-common/src/protocol/signer_builder.rs index e6c9c9f448d..c5ca72ecc02 100644 --- a/mithril-common/src/protocol/signer_builder.rs +++ b/mithril-common/src/protocol/signer_builder.rs @@ -177,7 +177,7 @@ mod test { use mithril_stm::RegisterError; use crate::{ - crypto_helper::{KesSignerStandard, ProtocolRegistrationErrorWrapper}, + crypto_helper::KesSignerStandard, test::{builder::MithrilFixtureBuilder, double::fake_data}, }; @@ -220,8 +220,8 @@ mod test { "We should not be able to construct a signer builder if a signer registration fail", ); - match error.downcast_ref::() { - Some(ProtocolRegistrationErrorWrapper::CoreRegister(_)) => (), + match error.downcast_ref::() { + Some(RegisterError::KeyRegistered { .. }) => (), _ => panic!("Expected an CoreRegister error, got: {error:?}"), } } @@ -264,10 +264,8 @@ mod test { "We should not be able to construct a single signer from a not registered party", ); - match error.downcast_ref::() { - Some(ProtocolRegistrationErrorWrapper::CoreRegister( - RegisterError::UnregisteredInitializer, - )) => (), + match error.downcast_ref::() { + Some(RegisterError::UnregisteredInitializer) => (), _ => panic!( "Expected an ProtocolRegistrationErrorWrapper::CoreRegister error, got: {error:?}" ), diff --git a/mithril-stm/CHANGELOG.md b/mithril-stm/CHANGELOG.md index 4f2ba827bdb..2df9af05561 100644 --- a/mithril-stm/CHANGELOG.md +++ b/mithril-stm/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.6.0 (11-19-2025) + +### Changed + +- Stm error handling is done with `anyhow`. + ## 0.5.5 (10-13-2025) ### Fixed diff --git a/mithril-stm/Cargo.toml b/mithril-stm/Cargo.toml index 27248eb7503..a22098e9ffc 100644 --- a/mithril-stm/Cargo.toml +++ b/mithril-stm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mithril-stm" -version = "0.5.5" +version = "0.6.0" edition = { workspace = true } authors = { workspace = true } homepage = { workspace = true } @@ -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"] } diff --git a/mithril-stm/README.md b/mithril-stm/README.md index 6a9160c524d..5a1d5d86523 100644 --- a/mithril-stm/README.md +++ b/mithril-stm/README.md @@ -136,16 +136,19 @@ 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) => match error.downcast_ref::() { + Some(AggregationError::NotEnoughSignatures(n, k)) => { + println!("Not enough signatures"); + assert!(n < ¶ms.k && k == ¶ms.k) + }, + + Some(AggregationError::UnsupportedProofSystem(aggregate_signature_type)) => { + println!("Unsupported proof system: {:?}", aggregate_signature_type); + }, + _ => { + println!("Unexpected error during aggregation: {:?}", error); + } + }, } ``` diff --git a/mithril-stm/src/aggregate_signature/basic_verifier.rs b/mithril-stm/src/aggregate_signature/basic_verifier.rs index ab59658650f..cad572f0176 100644 --- a/mithril-stm/src/aggregate_signature/basic_verifier.rs +++ b/mithril-stm/src/aggregate_signature/basic_verifier.rs @@ -1,11 +1,12 @@ +use anyhow::{Context, anyhow}; use std::collections::{BTreeMap, HashMap, HashSet}; use crate::bls_multi_signature::{BlsSignature, BlsVerificationKey}; use crate::key_registration::RegisteredParty; use crate::merkle_tree::MerkleTreeLeaf; use crate::{ - AggregationError, CoreVerifierError, Index, Parameters, SingleSignature, - SingleSignatureWithRegisteredParty, Stake, + AggregationError, Index, Parameters, SingleSignature, SingleSignatureWithRegisteredParty, + Stake, StmResult, }; /// Full node verifier including the list of eligible signers and the total stake of the system. @@ -56,14 +57,15 @@ impl BasicVerifier { signatures: &[SingleSignatureWithRegisteredParty], parameters: &Parameters, msg: &[u8], - ) -> Result<(), CoreVerifierError> { + ) -> StmResult<()> { let mut nr_indices = 0; let mut unique_indices = HashSet::new(); for sig_reg in signatures { sig_reg .sig - .check_indices(parameters, &sig_reg.reg_party.1, msg, total_stake)?; + .check_indices(parameters, &sig_reg.reg_party.1, msg, total_stake) + .with_context(|| "Preliminary verification for basic verifier failed.")?; for &index in &sig_reg.sig.indexes { unique_indices.insert(index); nr_indices += 1; @@ -71,10 +73,13 @@ impl BasicVerifier { } if nr_indices != unique_indices.len() { - return Err(CoreVerifierError::IndexNotUnique); + return Err(anyhow!(AggregationError::IndexNotUnique)); } if (nr_indices as u64) < parameters.k { - return Err(CoreVerifierError::NoQuorum(nr_indices as u64, parameters.k)); + return Err(anyhow!(AggregationError::NotEnoughSignatures( + nr_indices as u64, + parameters.k + ))); } Ok(()) @@ -93,7 +98,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 +174,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 +196,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 +225,7 @@ impl BasicVerifier { signatures: &[SingleSignature], parameters: &Parameters, msg: &[u8], - ) -> Result<(), CoreVerifierError> { + ) -> StmResult<()> { let sig_reg_list = signatures .iter() .map(|sig| SingleSignatureWithRegisteredParty { @@ -232,13 +239,16 @@ impl BasicVerifier { parameters, msg, &sig_reg_list, - )?; + ) + .with_context(|| "Basic verification failed during selection of unique k indices.")?; Self::preliminary_verify(&self.total_stake, &unique_sigs, parameters, msg)?; let (sigs, vks) = Self::collect_signatures_verification_keys(&unique_sigs); - BlsSignature::verify_aggregate(msg.to_vec().as_slice(), &vks, &sigs)?; + BlsSignature::verify_aggregate(msg.to_vec().as_slice(), &vks, &sigs).with_context( + || "Basic verifier failed during BLS aggregate signature verification.", + )?; Ok(()) } diff --git a/mithril-stm/src/aggregate_signature/clerk.rs b/mithril-stm/src/aggregate_signature/clerk.rs index 62fe9459587..c540305c4b1 100644 --- a/mithril-stm/src/aggregate_signature/clerk.rs +++ b/mithril-stm/src/aggregate_signature/clerk.rs @@ -1,10 +1,16 @@ -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 anyhow::Context; +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 +68,7 @@ impl Clerk { &self, sigs: &[SingleSignature], msg: &[u8], - ) -> Result, AggregationError> { + ) -> StmResult> { self.aggregate_signatures_with_type(sigs, msg, AggregateSignatureType::default()) } @@ -72,14 +78,19 @@ 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)?, + ConcatenationProof::aggregate_signatures(self, sigs, msg).with_context(|| { + format!( + "Signatures failed to aggregate for type {}", + AggregateSignatureType::Concatenation + ) + })?, )), #[cfg(feature = "future_proof_system")] - AggregateSignatureType::Future => Err(AggregationError::UnsupportedProofSystem( - aggregate_signature_type, + AggregateSignatureType::Future => Err(anyhow!( + AggregationError::UnsupportedProofSystem(aggregate_signature_type) )), } } @@ -96,7 +107,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/mod.rs b/mithril-stm/src/aggregate_signature/mod.rs index 39525a65490..65b009189ee 100644 --- a/mithril-stm/src/aggregate_signature/mod.rs +++ b/mithril-stm/src/aggregate_signature/mod.rs @@ -23,12 +23,12 @@ mod tests { 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, + Initializer, KeyRegistration, Parameters, Signer, SingleSignature, SingleSignatureWithRegisteredParty, Stake, bls_multi_signature::BlsVerificationKey, }; + use crate::{StmResult, merkle_tree::MerkleBatchPath}; type Sig = AggregateSignature; type D = Blake2b; @@ -147,7 +147,7 @@ mod tests { #[derive(Debug)] struct ProofTest { - msig: Result, + msig: StmResult, clerk: Clerk, msg: [u8; 16], } @@ -259,15 +259,21 @@ mod tests { 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:?}"); + println!("Aggregate ok"); + assert!(aggr.verify(&msg, &clerk.compute_aggregate_verification_key(), ¶ms).is_ok()); } - Err(AggregationError::NotEnoughSignatures(n, k)) => - assert!(n < params.k || k == params.k), - Err(AggregationError::UsizeConversionInvalid) => - unreachable!(), - Err(AggregationError::UnsupportedProofSystem(_)) => - unreachable!(), + Err(error) => match error.downcast_ref::() { + Some(AggregationError::NotEnoughSignatures(n, k)) => { + println!("Not enough signatures"); + assert!(n < ¶ms.k && k == ¶ms.k) + }, + Some(AggregationError::UnsupportedProofSystem(aggregate_signature_type)) => { + panic!("Unsupported proof system: {:?}", aggregate_signature_type); + }, + _ => { + panic!("Unexpected error during aggregation: {:?}", error); + } + }, } } @@ -303,11 +309,13 @@ mod tests { batch_msgs.push(msg.to_vec()); batch_params.push(params); } - Err(AggregationError::NotEnoughSignatures(_n, _k)) => { - assert!(sigs.len() < params.k as usize) + Err(error) => { assert!( + matches!( + error.downcast_ref::(), + Some(AggregationError::NotEnoughSignatures{..}) + ), + "Unexpected error: {error:?}"); } - Err(AggregationError::UsizeConversionInvalid) => unreachable!(), - Err(AggregationError::UnsupportedProofSystem(_)) => unreachable!(), } } @@ -428,14 +436,14 @@ mod tests { 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!(), + 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! { @@ -561,11 +569,13 @@ mod tests { Ok(_) => { assert!(verify_result.is_ok(), "Verification failed: {verify_result:?}"); } - Err(CoreVerifierError::NoQuorum(nr_indices, _k)) => { - assert!((nr_indices) < params.k); + Err(error) => { assert!( + matches!( + error.downcast_ref::(), + Some(AggregationError::NotEnoughSignatures{..}) + ), + "Unexpected error: {error:?}"); } - Err(CoreVerifierError::IndexNotUnique) => unreachable!(), - _ => unreachable!(), } } diff --git a/mithril-stm/src/aggregate_signature/proof/concatenation.rs b/mithril-stm/src/aggregate_signature/proof/concatenation.rs index bafc5ddac69..f619b359efe 100644 --- a/mithril-stm/src/aggregate_signature/proof/concatenation.rs +++ b/mithril-stm/src/aggregate_signature/proof/concatenation.rs @@ -1,3 +1,4 @@ +use anyhow::Context; use blake2::digest::{Digest, FixedOutput}; use serde::{Deserialize, Serialize}; @@ -7,8 +8,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, + AggregateSignatureError, AggregateVerificationKey, BasicVerifier, Parameters, SingleSignature, + SingleSignatureWithRegisteredParty, StmResult, }; /// `ConcatenationProof` uses the "concatenation" proving system (as described in Section 4.3 of the original paper.) @@ -36,7 +37,7 @@ impl ConcatenationProof { clerk: &Clerk, sigs: &[SingleSignature], msg: &[u8], - ) -> Result, AggregationError> { + ) -> StmResult> { let sig_reg_list = sigs .iter() .map(|sig| SingleSignatureWithRegisteredParty { @@ -52,6 +53,9 @@ impl ConcatenationProof { &clerk.params, &msgp, &sig_reg_list, + ) + .with_context( + || "Failed to aggregate unique signatures during selection for the k indices.", )?; unique_sigs.sort_unstable(); @@ -83,14 +87,15 @@ 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(), &self.signatures, parameters, &msgp, - )?; + ) + .with_context(|| "Preliminary verification of aggregate signatures failed.")?; let leaves = self .signatures @@ -99,7 +104,8 @@ impl ConcatenationProof { .collect::>(); avk.get_merkle_tree_batch_commitment() - .verify_leaves_membership_from_batch_path(&leaves, &self.batch_proof)?; + .verify_leaves_membership_from_batch_path(&leaves, &self.batch_proof) + .with_context(|| "Batch proof is invalid in preliminary verification.")?; Ok(BasicVerifier::collect_signatures_verification_keys( &self.signatures, @@ -117,11 +123,14 @@ 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)?; + let (sigs, vks) = self + .preliminary_verify(msg, avk, parameters) + .with_context(|| "Aggregate signature verification failed")?; - BlsSignature::verify_aggregate(msgp.as_slice(), &vks, &sigs)?; + BlsSignature::verify_aggregate(msgp.as_slice(), &vks, &sigs) + .with_context(|| "Aggregate signature verification failed")?; Ok(()) } @@ -131,7 +140,7 @@ impl ConcatenationProof { msgs: &[Vec], avks: &[AggregateVerificationKey], parameters: &[Parameters], - ) -> Result<(), StmAggregateSignatureError> { + ) -> StmResult<()> { let batch_size = stm_signatures.len(); assert_eq!( batch_size, @@ -195,19 +204,17 @@ 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]; u64_bytes.copy_from_slice( bytes .get(bytes_index..bytes_index + 8) - .ok_or(StmAggregateSignatureError::SerializationError)?, + .ok_or(AggregateSignatureError::SerializationError)?, ); let total_sigs = usize::try_from(u64::from_be_bytes(u64_bytes)) - .map_err(|_| StmAggregateSignatureError::SerializationError)?; + .map_err(|_| AggregateSignatureError::SerializationError)?; bytes_index += 8; let mut sig_reg_list = Vec::with_capacity(total_sigs); @@ -215,14 +222,14 @@ impl ConcatenationProof { u64_bytes.copy_from_slice( bytes .get(bytes_index..bytes_index + 8) - .ok_or(StmAggregateSignatureError::SerializationError)?, + .ok_or(AggregateSignatureError::SerializationError)?, ); let sig_reg_size = usize::try_from(u64::from_be_bytes(u64_bytes)) - .map_err(|_| StmAggregateSignatureError::SerializationError)?; + .map_err(|_| AggregateSignatureError::SerializationError)?; let sig_reg = SingleSignatureWithRegisteredParty::from_bytes::( bytes .get(bytes_index + 8..bytes_index + 8 + sig_reg_size) - .ok_or(StmAggregateSignatureError::SerializationError)?, + .ok_or(AggregateSignatureError::SerializationError)?, )?; bytes_index += 8 + sig_reg_size; sig_reg_list.push(sig_reg); @@ -231,7 +238,7 @@ impl ConcatenationProof { let batch_proof = MerkleBatchPath::from_bytes( bytes .get(bytes_index..) - .ok_or(StmAggregateSignatureError::SerializationError)?, + .ok_or(AggregateSignatureError::SerializationError)?, )?; Ok(ConcatenationProof { diff --git a/mithril-stm/src/aggregate_signature/signature.rs b/mithril-stm/src/aggregate_signature/signature.rs index 82d7fa01cda..dc8c6fb3a77 100644 --- a/mithril-stm/src/aggregate_signature/signature.rs +++ b/mithril-stm/src/aggregate_signature/signature.rs @@ -2,12 +2,13 @@ use std::collections::HashMap; use std::fmt::Display; use std::hash::Hash; +use anyhow::anyhow; use blake2::digest::{Digest, FixedOutput}; use serde::{Deserialize, Serialize}; -use crate::error::StmAggregateSignatureError; +use crate::error::AggregateSignatureError; 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!( + AggregateSignatureError::UnsupportedProofSystem(self.into()) )), } } @@ -113,42 +114,32 @@ 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!(AggregateSignatureError::BatchInvalid)); } + + ConcatenationProof::batch_verify(&concatenation_proofs, msgs, avks, parameters) } - }) - .map_err(|_| StmAggregateSignatureError::BatchInvalid) + #[cfg(feature = "future_proof_system")] + AggregateSignatureType::Future => Err(anyhow!( + AggregateSignatureError::UnsupportedProofSystem(aggregate_signature_type) + )), + }, + ) } /// Convert an aggregate signature to bytes @@ -171,12 +162,11 @@ impl AggregateSignature { } /// Extract an aggregate signature from a byte slice. - pub fn from_bytes(bytes: &[u8]) -> Result> { - let proof_type_byte = - bytes.first().ok_or(StmAggregateSignatureError::SerializationError)?; + pub fn from_bytes(bytes: &[u8]) -> StmResult { + let proof_type_byte = bytes.first().ok_or(AggregateSignatureError::SerializationError)?; let proof_bytes = &bytes[1..]; let proof_type = AggregateSignatureType::from_byte_encoding_prefix(*proof_type_byte) - .ok_or(StmAggregateSignatureError::SerializationError)?; + .ok_or(AggregateSignatureError::SerializationError)?; match proof_type { AggregateSignatureType::Concatenation => Ok(AggregateSignature::Concatenation( ConcatenationProof::from_bytes(proof_bytes)?, 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/mod.rs b/mithril-stm/src/bls_multi_signature/mod.rs index 9f91df30e53..9f0ba22cc01 100644 --- a/mithril-stm/src/bls_multi_signature/mod.rs +++ b/mithril-stm/src/bls_multi_signature/mod.rs @@ -94,8 +94,9 @@ mod tests { use rand_chacha::ChaCha20Rng; use rand_core::{RngCore, SeedableRng}; + use crate::RegisterError; 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 +132,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 +151,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 +170,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 +196,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(RegisterError::KeyInvalid(_)) + ), + "Unexpected error: {error:?}"); } #[test] @@ -272,8 +295,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/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..8c428b9da3c 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::{Context, 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> { - let (aggr_vk, aggr_sig) = Self::aggregate(vks, sigs)?; + ) -> StmResult<()> { + let (aggr_vk, aggr_sig) = Self::aggregate(vks, sigs).with_context(|| "Multi signature verification failed in aggregation of verification keys and signatures.")?; - 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(|_| 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 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 c56f2e29c7b..800777d2514 100644 --- a/mithril-stm/src/error.rs +++ b/mithril-stm/src/error.rs @@ -1,12 +1,12 @@ //! Crate specific errors -use blake2::digest::{Digest, FixedOutput}; +use anyhow::anyhow; use blst::BLST_ERROR; +use crate::StmResult; 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,71 +42,36 @@ 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. #[derive(Debug, Clone, thiserror::Error)] -pub enum StmSignatureError { +pub enum SignatureError { /// There is an index out of bounds #[error("Received index, {0}, is higher than what the security parameter allows, {1}.")] IndexBoundFailed(u64, u64), - /// MSP.Eval was computed incorrectly - #[error("The claimed evaluation of function phi is incorrect.")] - EvalInvalid([u8; 64]), - /// The lottery was actually lost for the signature #[error("Lottery for this epoch was lost.")] LotteryLost, - /// A party submitted an invalid signature - #[error("A provided signature is invalid")] - SignatureInvalid(BlsSignature), - - /// Batch verification of STM signatures failed - #[error("Batch verification of STM signatures failed")] - BatchInvalid, - /// This error occurs when the the serialization of the raw bytes failed #[error("Invalid bytes")] SerializationError, } -impl From for StmSignatureError { - fn from(e: MultiSignatureError) -> Self { - match e { - MultiSignatureError::SerializationError => Self::SerializationError, - MultiSignatureError::SignatureInvalid(e) => Self::SignatureInvalid(e), - MultiSignatureError::BatchInvalid => unreachable!(), - MultiSignatureError::KeyInvalid(_) => unreachable!(), - MultiSignatureError::AggregateSignatureInvalid => unreachable!(), - MultiSignatureError::SignatureInfinity(_) => unreachable!(), - MultiSignatureError::VerificationKeyInfinity(_) => unreachable!(), - } - } -} - -impl From> for StmSignatureError { - fn from(e: MerkleTreeError) -> Self { - match e { - MerkleTreeError::SerializationError => Self::SerializationError, - _ => unreachable!(), - } - } -} - /// Error types for aggregation. #[derive(Debug, Clone, thiserror::Error)] pub enum AggregationError { @@ -114,140 +79,30 @@ pub enum AggregationError { #[error("Not enough signatures. Got only {0} out of {1}.")] NotEnoughSignatures(u64, u64), - /// This error happens when we try to convert a u64 to a usize and it does not fit - #[error("Invalid usize conversion")] - UsizeConversionInvalid, - - /// The proof system used in the aggregate signature is not supported #[error("Unsupported proof system: {0}")] UnsupportedProofSystem(AggregateSignatureType), -} - -/// Errors which can be output by `CoreVerifier`. -#[derive(Debug, Clone, thiserror::Error)] -pub enum CoreVerifierError { - /// No quorum was found - #[error("No Quorum was found. Expected {0} signatures but got {1}")] - NoQuorum(u64, u64), /// There is a duplicate index #[error("Indices are not unique.")] IndexNotUnique, - - /// The aggregated signature is invalid - #[error("Aggregate signature is invalid")] - AggregateSignatureInvalid, - - /// One of the aggregated signatures is invalid - #[error("Individual signature is invalid: {0}")] - IndividualSignatureInvalid(#[source] StmSignatureError), -} - -impl From for CoreVerifierError { - fn from(e: AggregationError) -> Self { - match e { - AggregationError::NotEnoughSignatures(e, _e) => Self::NoQuorum(e, e), - AggregationError::UsizeConversionInvalid => unreachable!(), - AggregationError::UnsupportedProofSystem(_) => unreachable!(), - } - } -} - -impl From for CoreVerifierError { - fn from(e: MultiSignatureError) -> Self { - match e { - MultiSignatureError::AggregateSignatureInvalid => Self::AggregateSignatureInvalid, - MultiSignatureError::BatchInvalid => unreachable!(), - MultiSignatureError::SerializationError => unreachable!(), - MultiSignatureError::KeyInvalid(_) => unreachable!(), - MultiSignatureError::SignatureInvalid(_e) => unreachable!(), - MultiSignatureError::SignatureInfinity(_) => unreachable!(), - MultiSignatureError::VerificationKeyInfinity(_) => unreachable!(), - } - } -} - -impl From for CoreVerifierError { - fn from(e: StmSignatureError) -> Self { - CoreVerifierError::IndividualSignatureInvalid(e) - } } /// Errors which can be output by Mithril aggregate verification. #[derive(Debug, Clone, thiserror::Error)] -pub enum StmAggregateSignatureError { - /// The IVK is invalid after aggregating the keys - #[error("Aggregated key does not correspond to the expected key.")] - IvkInvalid(Box), - +pub enum AggregateSignatureError { /// This error occurs when the the serialization of the raw bytes failed #[error("Invalid bytes")] SerializationError, - /// Invalid merkle batch path - #[error("Batch path does not verify against root")] - PathInvalid(MerkleBatchPath), - /// Batch verification of STM aggregate signatures failed #[error("Batch verification of STM aggregate signatures failed")] BatchInvalid, - /// `CoreVerifier` check failed - #[error("Core verification error: {0}")] - CoreVerificationError(#[source] CoreVerifierError), - /// The proof system used in the aggregate signature is not supported #[error("Unsupported proof system: {0}")] UnsupportedProofSystem(AggregateSignatureType), } -impl From> for StmAggregateSignatureError { - fn from(e: MerkleTreeError) -> Self { - match e { - MerkleTreeError::BatchPathInvalid(e) => Self::PathInvalid(e), - MerkleTreeError::SerializationError => Self::SerializationError, - MerkleTreeError::PathInvalid(_e) => unreachable!(), - } - } -} - -impl From for StmAggregateSignatureError { - fn from(e: MultiSignatureError) -> Self { - match e { - MultiSignatureError::AggregateSignatureInvalid => { - Self::from(CoreVerifierError::from(e)) - } - MultiSignatureError::BatchInvalid => Self::BatchInvalid, - MultiSignatureError::SerializationError => unreachable!(), - MultiSignatureError::KeyInvalid(_) => unreachable!(), - MultiSignatureError::SignatureInvalid(_) => { - Self::CoreVerificationError(CoreVerifierError::from(e)) - } - MultiSignatureError::SignatureInfinity(_) => { - Self::CoreVerificationError(CoreVerifierError::from(e)) - } - MultiSignatureError::VerificationKeyInfinity(_) => { - Self::CoreVerificationError(CoreVerifierError::from(e)) - } - } - } -} - -impl From for StmAggregateSignatureError { - fn from(e: CoreVerifierError) -> Self { - Self::CoreVerificationError(e) - } -} - -impl From for StmAggregateSignatureError { - fn from(e: StmSignatureError) -> Self { - match e { - StmSignatureError::SerializationError => Self::SerializationError, - _ => unreachable!(), - } - } -} - /// Errors which can be outputted by key registration. #[derive(Debug, Clone, thiserror::Error, PartialEq, Eq)] pub enum RegisterError { @@ -255,10 +110,6 @@ pub enum RegisterError { #[error("This key has already been registered.")] KeyRegistered(Box), - /// Verification key is the infinity - #[error("Verification key is the infinity")] - VerificationKeyInfinity(Box), - /// The supplied key is not valid #[error("The verification of correctness of the supplied key is invalid.")] KeyInvalid(Box), @@ -272,42 +123,31 @@ pub enum RegisterError { UnregisteredInitializer, } -impl From for RegisterError { - fn from(e: MultiSignatureError) -> Self { - match e { - MultiSignatureError::SerializationError => Self::SerializationError, - MultiSignatureError::KeyInvalid(e) => Self::KeyInvalid(e), - MultiSignatureError::VerificationKeyInfinity(e) => Self::VerificationKeyInfinity(e), - _ => unreachable!(), - } - } -} - -/// If verifying a single signature, the signature should be provided. If verifying a multi-sig, -/// no need to provide the signature -pub(crate) fn blst_err_to_mithril( +pub(crate) fn blst_error_to_stm_error( e: BLST_ERROR, sig: Option, key: Option, -) -> Result<(), MultiSignatureError> { +) -> StmResult<()> { match e { BLST_ERROR::BLST_SUCCESS => Ok(()), BLST_ERROR::BLST_PK_IS_INFINITY => { if let Some(s) = sig { - return Err(MultiSignatureError::SignatureInfinity(s)); + return Err(anyhow!(MultiSignatureError::SignatureInfinity(s))); } if let Some(vk) = key { - return Err(MultiSignatureError::VerificationKeyInfinity(Box::new(vk))); + return Err(anyhow!(MultiSignatureError::VerificationKeyInfinity( + Box::new(vk) + ))); } - Err(MultiSignatureError::SerializationError) + Err(anyhow!(MultiSignatureError::SerializationError)) } BLST_ERROR::BLST_VERIFY_FAIL => { if let Some(s) = sig { - Err(MultiSignatureError::SignatureInvalid(s)) + Err(anyhow!(MultiSignatureError::SignatureInvalid(s))) } else { - Err(MultiSignatureError::AggregateSignatureInvalid) + Err(anyhow!(MultiSignatureError::AggregateSignatureInvalid)) } } - _ => Err(MultiSignatureError::SerializationError), + _ => Err(anyhow!(MultiSignatureError::SerializationError)), } } diff --git a/mithril-stm/src/key_registration.rs b/mithril-stm/src/key_registration.rs index 839ea005267..319325ba463 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,14 @@ 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()?; + pk.verify_proof_of_possession() + .map_err(|_| RegisterError::KeyInvalid(Box::new(pk)))?; e.insert(stake); return Ok(()); } - Err(RegisterError::KeyRegistered(Box::new(pk.vk))) + Err(anyhow!(RegisterError::KeyRegistered(Box::new(pk.vk)))) } /// Finalize the key registration. @@ -126,23 +128,24 @@ mod tests { } 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(error) => match error.downcast_ref::(){ + Some(RegisterError::KeyRegistered(pk1)) => { + assert!(pk1.as_ref() == &pk.vk); + assert!(keys.contains_key(&pk.vk)); + }, + Some(RegisterError::KeyInvalid(a)) => { + assert_eq!(fake_it, 0); + assert!(a.verify_proof_of_possession().is_err()); + }, + _ => {panic!("Unexpected error: {error}")} } - 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::>(); diff --git a/mithril-stm/src/lib.rs b/mithril-stm/src/lib.rs index 2ca7313521b..9030ebd3993 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(()) //! # } @@ -123,8 +125,7 @@ pub use aggregate_signature::{ AggregateSignature, AggregateSignatureType, AggregateVerificationKey, BasicVerifier, Clerk, }; pub use error::{ - AggregationError, CoreVerifierError, RegisterError, StmAggregateSignatureError, - StmSignatureError, + AggregateSignatureError, AggregationError, MultiSignatureError, RegisterError, SignatureError, }; pub use key_registration::{ClosedKeyRegistration, KeyRegistration}; pub use parameters::Parameters; @@ -144,6 +145,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; diff --git a/mithril-stm/src/merkle_tree/commitment.rs b/mithril-stm/src/merkle_tree/commitment.rs index d54873fc33f..131a02c8ebb 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::{Context, 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.clone())) + 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,11 +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, { @@ -104,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 { @@ -171,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.clone())); + 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.clone())); + return Err(anyhow!(MerkleTreeError::BatchPathInvalid(proof.to_bytes()))); } let nr_nodes = self.nr_leaves + self.nr_leaves.next_power_of_two() - 1; @@ -211,7 +208,14 @@ impl MerkleTreeBatchCommitment { if ordered_indices[i] & 1 == 0 { new_hashes.push( D::new() - .chain(values.first().ok_or(MerkleTreeError::SerializationError)?) + .chain( + values + .first() + .ok_or(MerkleTreeError::SerializationError) + .with_context(|| { + format!("Could not verify leave membership from batch path for idx = {} and ordered_indices[{}]", idx, i) + })?, + ) .chain(&leaves[i]) .finalize() .to_vec(), @@ -228,7 +232,16 @@ impl MerkleTreeBatchCommitment { new_hashes.push( D::new() .chain(&leaves[i]) - .chain(values.first().ok_or(MerkleTreeError::SerializationError)?) + .chain( + values + .first() + .ok_or(MerkleTreeError::SerializationError) + .with_context(|| { + format!( + "Could not verify leave membership from batch path for idx = {} where sibling < nr_nodes", idx + ) + })?, + ) .finalize() .to_vec(), ); @@ -249,7 +262,7 @@ impl MerkleTreeBatchCommitment { return Ok(()); } - Err(MerkleTreeError::BatchPathInvalid(proof.clone())) + Err(anyhow!(MerkleTreeError::BatchPathInvalid(proof.to_bytes()))) } /// Check a proof of a batched opening. The indices must be ordered. @@ -263,11 +276,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, { @@ -286,7 +295,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 675bfb77bf5..de01655d850 100644 --- a/mithril-stm/src/merkle_tree/leaf.rs +++ b/mithril-stm/src/merkle_tree/leaf.rs @@ -1,20 +1,18 @@ use std::cmp::Ordering; -use blake2::Blake2b; -use digest::consts::U32; 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 565de41692a..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 3fae57f6d71..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)) 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); diff --git a/mithril-stm/src/single_signature/signature.rs b/mithril-stm/src/single_signature/signature.rs index 4094998f369..e55d6cab48d 100644 --- a/mithril-stm/src/single_signature/signature.rs +++ b/mithril-stm/src/single_signature/signature.rs @@ -9,8 +9,9 @@ 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, SignatureError, Stake, StmResult, VerificationKey, }; +use anyhow::{Context, anyhow}; /// Signature created by a single party who has won the lottery. #[derive(Debug, Clone, Serialize, Deserialize)] @@ -33,9 +34,15 @@ 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())?; + self.basic_verify(params, pk, stake, &msgp, &avk.get_total_stake()) + .with_context(|| { + format!( + "Single signature verification failed for signer index {}.", + self.signer_index + ) + })?; Ok(()) } @@ -46,16 +53,16 @@ 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!(SignatureError::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!(SignatureError::LotteryLost)); } } @@ -86,12 +93,10 @@ 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)?); + u64_bytes.copy_from_slice(bytes.get(0..8).ok_or(SignatureError::SerializationError)?); let nr_indexes = u64::from_be_bytes(u64_bytes) as usize; let mut indexes = Vec::new(); @@ -99,7 +104,7 @@ impl SingleSignature { u64_bytes.copy_from_slice( bytes .get(8 + i * 8..16 + i * 8) - .ok_or(StmSignatureError::SerializationError)?, + .ok_or(SignatureError::SerializationError)?, ); indexes.push(u64::from_be_bytes(u64_bytes)); } @@ -108,13 +113,13 @@ impl SingleSignature { let sigma = BlsSignature::from_bytes( bytes .get(offset..offset + 48) - .ok_or(StmSignatureError::SerializationError)?, + .ok_or(SignatureError::SerializationError)?, )?; u64_bytes.copy_from_slice( bytes .get(offset + 48..offset + 56) - .ok_or(StmSignatureError::SerializationError)?, + .ok_or(SignatureError::SerializationError)?, ); let signer_index = u64::from_be_bytes(u64_bytes); @@ -145,9 +150,12 @@ impl SingleSignature { stake: &Stake, msg: &[u8], total_stake: &Stake, - ) -> Result<(), StmSignatureError> { - self.sigma.verify(msg, pk)?; - self.check_indices(params, stake, msg, total_stake)?; + ) -> StmResult<()> { + self.sigma + .verify(msg, pk) + .with_context(|| "Basic verification of single signature failed.")?; + self.check_indices(params, stake, msg, total_stake) + .with_context(|| "Basic verification of single signature failed.")?; Ok(()) } @@ -161,7 +169,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..b3db1bd6e16 100644 --- a/mithril-stm/src/single_signature/signature_registered_party.rs +++ b/mithril-stm/src/single_signature/signature_registered_party.rs @@ -1,8 +1,9 @@ use blake2::digest::{Digest, FixedOutput}; use serde::{Deserialize, Serialize, Serializer, ser::SerializeTuple}; +use crate::StmResult; use crate::key_registration::RegisteredParty; -use crate::{SingleSignature, StmSignatureError}; +use crate::{SignatureError, SingleSignature}; /// Signature with its registered party. #[derive(Debug, Clone, Hash, Deserialize, Eq, PartialEq, Ord, PartialOrd)] @@ -28,12 +29,12 @@ 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)?, + bytes.get(0..104).ok_or(SignatureError::SerializationError)?, )?; let sig = SingleSignature::from_bytes::( - bytes.get(104..).ok_or(StmSignatureError::SerializationError)?, + bytes.get(104..).ok_or(SignatureError::SerializationError)?, )?; Ok(SingleSignatureWithRegisteredParty { sig, reg_party }) diff --git a/mithril-stm/tests/stm_basic.rs b/mithril-stm/tests/stm_basic.rs index 8cc4ff71ac2..1c37026143f 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,13 @@ 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) => match error.downcast_ref::() { + Some(AggregationError::NotEnoughSignatures(nr_indices, _k)) => { + assert!((nr_indices) < ¶ms.k) + } + _ => { + panic!("Unexpected error: {:?}", error); + } + }, } } diff --git a/mithril-stm/tests/stm_protocol.rs b/mithril-stm/tests/stm_protocol.rs index 48a8ab44a2e..e2cf9c7df07 100644 --- a/mithril-stm/tests/stm_protocol.rs +++ b/mithril-stm/tests/stm_protocol.rs @@ -34,16 +34,19 @@ 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) => match error.downcast_ref::() { + Some(AggregationError::NotEnoughSignatures(n, k)) => { + println!("Not enough signatures"); + assert!(n < ¶ms.k && k == ¶ms.k) + } + + Some(AggregationError::UnsupportedProofSystem(aggregate_signature_type)) => { + panic!("Unsupported proof system: {:?}", aggregate_signature_type); + } + _ => { + panic!("Unexpected error during aggregation: {:?}", 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, }