From 03c446745e0e604709759f16dee0816a87d9bbe1 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 30 Mar 2022 17:58:19 +0200 Subject: [PATCH 1/7] TIP 29 compliance --- bee-message/src/error.rs | 15 +-- bee-message/src/payload/milestone/essence.rs | 50 +------- bee-message/src/payload/milestone/mod.rs | 115 +++++-------------- bee-message/src/payload/mod.rs | 2 +- bee-message/src/signature/ed25519.rs | 24 ++++ 5 files changed, 58 insertions(+), 148 deletions(-) diff --git a/bee-message/src/error.rs b/bee-message/src/error.rs index 7121172e00..a41e2b4f14 100644 --- a/bee-message/src/error.rs +++ b/bee-message/src/error.rs @@ -10,8 +10,7 @@ use crate::{ }, parent::ParentCount, payload::{ - InputCount, MigratedFundsAmount, OutputCount, PublicKeyCount, ReceiptFundsCount, SignatureCount, TagLength, - TaggedDataLength, + InputCount, MigratedFundsAmount, OutputCount, ReceiptFundsCount, SignatureCount, TagLength, TaggedDataLength, }, unlock_block::{UnlockBlockCount, UnlockBlockIndex}, }; @@ -84,10 +83,9 @@ pub enum Error { InvalidUnlockConditionCount(>::Error), InvalidUnlockConditionKind(u8), MigratedFundsNotSorted, - MilestoneInvalidPublicKeyCount(>::Error), MilestoneInvalidSignatureCount(>::Error), - MilestonePublicKeysNotUniqueSorted, MilestonePublicKeysSignaturesCountMismatch { key_count: usize, sig_count: usize }, + MilestoneSignaturesNotUniqueSorted, MissingAddressUnlockCondition, MissingField(&'static str), MissingGovernorUnlockCondition, @@ -240,15 +238,9 @@ impl fmt::Display for Error { Error::MigratedFundsNotSorted => { write!(f, "migrated funds are not sorted") } - Error::MilestoneInvalidPublicKeyCount(count) => { - write!(f, "invalid milestone public key count: {}", count) - } Error::MilestoneInvalidSignatureCount(count) => { write!(f, "invalid milestone signature count: {}", count) } - Error::MilestonePublicKeysNotUniqueSorted => { - write!(f, "milestone public keys are not unique and/or sorted") - } Error::MilestonePublicKeysSignaturesCountMismatch { key_count, sig_count } => { write!( f, @@ -256,6 +248,9 @@ impl fmt::Display for Error { key_count, sig_count ) } + Error::MilestoneSignaturesNotUniqueSorted => { + write!(f, "milestone signatures are not unique and/or sorted") + } Error::MissingAddressUnlockCondition => write!(f, "missing address unlock condition"), Error::MissingField(s) => write!(f, "missing required field: {}", s), Error::MissingGovernorUnlockCondition => write!(f, "missing governor unlock condition"), diff --git a/bee-message/src/payload/milestone/essence.rs b/bee-message/src/payload/milestone/essence.rs index 58731739db..45926a68e5 100644 --- a/bee-message/src/payload/milestone/essence.rs +++ b/bee-message/src/payload/milestone/essence.rs @@ -8,28 +8,14 @@ use crate::{ Error, }; -use crypto::{ - hashes::{blake2b::Blake2b256, Digest}, - signatures::ed25519::PUBLIC_KEY_LENGTH, -}; -use iterator_sorted::is_unique_sorted; +use crypto::hashes::{blake2b::Blake2b256, Digest}; use packable::{ - bounded::BoundedU8, error::{UnpackError, UnpackErrorExt}, packer::Packer, - prefix::VecPrefix, unpacker::Unpacker, Packable, PackableExt, }; -use alloc::vec::Vec; -use core::ops::RangeInclusive; - -pub(crate) type PublicKeyCount = BoundedU8< - { *MilestoneEssence::PUBLIC_KEY_COUNT_RANGE.start() }, - { *MilestoneEssence::PUBLIC_KEY_COUNT_RANGE.end() }, ->; - /// Essence of a milestone payload. /// This is the signed part of a milestone payload. #[derive(Clone, Debug, Eq, PartialEq)] @@ -41,17 +27,12 @@ pub struct MilestoneEssence { merkle_proof: [u8; MilestoneEssence::MERKLE_PROOF_LENGTH], next_pow_score: u32, next_pow_score_milestone_index: u32, - public_keys: VecPrefix<[u8; MilestoneEssence::PUBLIC_KEY_LENGTH], PublicKeyCount>, receipt: OptionalPayload, } impl MilestoneEssence { /// Length of a milestone merkle proof. pub const MERKLE_PROOF_LENGTH: usize = 32; - /// Range of allowed milestones public key numbers. - pub const PUBLIC_KEY_COUNT_RANGE: RangeInclusive = 1..=255; - /// Length of a milestone public key. - pub const PUBLIC_KEY_LENGTH: usize = PUBLIC_KEY_LENGTH; /// Creates a new [`MilestoneEssence`]. #[allow(clippy::too_many_arguments)] @@ -62,16 +43,10 @@ impl MilestoneEssence { merkle_proof: [u8; MilestoneEssence::MERKLE_PROOF_LENGTH], next_pow_score: u32, next_pow_score_milestone_index: u32, - public_keys: Vec<[u8; MilestoneEssence::PUBLIC_KEY_LENGTH]>, receipt: Option, ) -> Result { verify_pow_scores(index, next_pow_score, next_pow_score_milestone_index)?; - let public_keys = VecPrefix::<[u8; MilestoneEssence::PUBLIC_KEY_LENGTH], PublicKeyCount>::try_from(public_keys) - .map_err(Error::MilestoneInvalidPublicKeyCount)?; - - verify_public_keys(&public_keys)?; - let receipt = OptionalPayload::from(receipt); verify_payload(&receipt)?; @@ -83,7 +58,6 @@ impl MilestoneEssence { merkle_proof, next_pow_score, next_pow_score_milestone_index, - public_keys, receipt, }) } @@ -118,11 +92,6 @@ impl MilestoneEssence { self.next_pow_score_milestone_index } - /// Returns the public keys of a [`MilestoneEssence`]. - pub fn public_keys(&self) -> &Vec<[u8; MilestoneEssence::PUBLIC_KEY_LENGTH]> { - &self.public_keys - } - /// Returns the optional receipt of a [`MilestoneEssence`]. pub fn receipt(&self) -> Option<&Payload> { self.receipt.as_ref() @@ -144,7 +113,6 @@ impl Packable for MilestoneEssence { self.merkle_proof.pack(packer)?; self.next_pow_score.pack(packer)?; self.next_pow_score_milestone_index.pack(packer)?; - self.public_keys.pack(packer)?; self.receipt.pack(packer)?; Ok(()) @@ -166,13 +134,6 @@ impl Packable for MilestoneEssence { verify_pow_scores(index, next_pow_score, next_pow_score_milestone_index).map_err(UnpackError::Packable)?; } - let public_keys = VecPrefix::<[u8; Self::PUBLIC_KEY_LENGTH], PublicKeyCount>::unpack::<_, VERIFY>(unpacker) - .map_packable_err(|err| Error::MilestoneInvalidSignatureCount(err.into_prefix_err().into()))?; - - if VERIFY { - verify_public_keys(&public_keys).map_err(UnpackError::Packable)?; - } - let receipt = OptionalPayload::unpack::<_, VERIFY>(unpacker)?; if VERIFY { @@ -186,7 +147,6 @@ impl Packable for MilestoneEssence { merkle_proof, next_pow_score, next_pow_score_milestone_index, - public_keys, receipt, }) } @@ -209,14 +169,6 @@ fn verify_pow_scores( } } -fn verify_public_keys(public_keys: &[[u8; MilestoneEssence::PUBLIC_KEY_LENGTH]]) -> Result<(), Error> { - if !is_unique_sorted(public_keys.iter()) { - Err(Error::MilestonePublicKeysNotUniqueSorted) - } else { - Ok(()) - } -} - fn verify_payload(payload: &OptionalPayload) -> Result<(), Error> { match &payload.0 { Some(Payload::Receipt(_)) | None => Ok(()), diff --git a/bee-message/src/payload/milestone/mod.rs b/bee-message/src/payload/milestone/mod.rs index 04cf1a1943..2819f7d007 100644 --- a/bee-message/src/payload/milestone/mod.rs +++ b/bee-message/src/payload/milestone/mod.rs @@ -7,24 +7,17 @@ mod essence; mod milestone_id; pub use essence::MilestoneEssence; -pub(crate) use essence::PublicKeyCount; pub use milestone_id::MilestoneId; -use crate::Error; +use crate::{signature::Ed25519Signature, Error}; use crypto::{ hashes::{blake2b::Blake2b256, Digest}, signatures::ed25519, Error as CryptoError, }; -use packable::{ - bounded::BoundedU8, - error::{UnpackError, UnpackErrorExt}, - packer::Packer, - prefix::VecPrefix, - unpacker::Unpacker, - Packable, PackableExt, -}; +use iterator_sorted::is_unique_sorted; +use packable::{bounded::BoundedU8, prefix::VecPrefix, Packable, PackableExt}; use alloc::{string::String, vec::Vec}; use core::{fmt::Debug, ops::RangeInclusive}; @@ -46,22 +39,17 @@ impl From for MilestoneValidationError { } } -#[derive(Clone, Debug, Eq, PartialEq, Packable)] -#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] -#[repr(transparent)] -struct Signature( - #[cfg_attr(feature = "serde1", serde(with = "serde_big_array::BigArray"))] [u8; MilestonePayload::SIGNATURE_LENGTH], -); - pub(crate) type SignatureCount = BoundedU8<{ *MilestonePayload::SIGNATURE_COUNT_RANGE.start() }, { *MilestonePayload::SIGNATURE_COUNT_RANGE.end() }>; /// A payload which defines the inclusion set of other messages in the Tangle. -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq, Packable)] #[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))] +#[packable(unpack_error = Error)] pub struct MilestonePayload { essence: MilestoneEssence, - signatures: VecPrefix, + #[packable(verify_with = verify_signatures)] + signatures: VecPrefix, } impl MilestonePayload { @@ -73,16 +61,9 @@ impl MilestonePayload { pub const SIGNATURE_LENGTH: usize = 64; /// Creates a new [`MilestonePayload`]. - pub fn new( - essence: MilestoneEssence, - signatures: Vec<[u8; MilestonePayload::SIGNATURE_LENGTH]>, - ) -> Result { - let signatures = VecPrefix::::try_from( - signatures.into_iter().map(Signature).collect::>(), - ) - .map_err(Error::MilestoneInvalidSignatureCount)?; - - verify_essence_signatures(&essence, &signatures)?; + pub fn new(essence: MilestoneEssence, signatures: Vec) -> Result { + let signatures = VecPrefix::::try_from(signatures) + .map_err(Error::MilestoneInvalidSignatureCount)?; Ok(Self { essence, signatures }) } @@ -93,8 +74,8 @@ impl MilestonePayload { } /// Returns the signatures of a [`MilestonePayload`]. - pub fn signatures(&self) -> impl Iterator + '_ { - self.signatures.iter().map(|s| &s.0) + pub fn signatures(&self) -> &[Ed25519Signature] { + &self.signatures } /// Computes the identifier of a [`MilestonePayload`]. @@ -133,27 +114,21 @@ impl MilestonePayload { let essence_hash = self.essence().hash(); - for (index, (public_key, signature)) in self - .essence() - .public_keys() - .iter() - .zip(self.signatures.iter()) - .enumerate() - { - if !applicable_public_keys.contains(&prefix_hex::encode(public_key)) { + for (index, signature) in self.signatures().iter().enumerate() { + if !applicable_public_keys.contains(&prefix_hex::encode(signature.public_key())) { return Err(MilestoneValidationError::UnapplicablePublicKey(prefix_hex::encode( - *public_key, + *signature.public_key(), ))); } - let ed25519_public_key = - ed25519::PublicKey::try_from_bytes(*public_key).map_err(MilestoneValidationError::Crypto)?; - let ed25519_signature = ed25519::Signature::from_bytes(signature.0); + let ed25519_public_key = ed25519::PublicKey::try_from_bytes(*signature.public_key()) + .map_err(MilestoneValidationError::Crypto)?; + let ed25519_signature = ed25519::Signature::from_bytes(*signature.signature()); if !ed25519_public_key.verify(&ed25519_signature, &essence_hash) { return Err(MilestoneValidationError::InvalidSignature( index, - prefix_hex::encode(public_key), + prefix_hex::encode(signature.public_key()), )); } } @@ -162,37 +137,9 @@ impl MilestonePayload { } } -impl Packable for MilestonePayload { - type UnpackError = Error; - - fn pack(&self, packer: &mut P) -> Result<(), P::Error> { - self.essence.pack(packer)?; - self.signatures.pack(packer)?; - - Ok(()) - } - - fn unpack( - unpacker: &mut U, - ) -> Result> { - let essence = MilestoneEssence::unpack::<_, VERIFY>(unpacker)?; - let signatures = VecPrefix::::unpack::<_, VERIFY>(unpacker) - .map_packable_err(|err| Error::MilestoneInvalidSignatureCount(err.into_prefix_err().into()))?; - - if VERIFY { - verify_essence_signatures(&essence, &signatures).map_err(UnpackError::Packable)?; - } - - Ok(Self { essence, signatures }) - } -} - -fn verify_essence_signatures(essence: &MilestoneEssence, signatures: &[Signature]) -> Result<(), Error> { - if essence.public_keys().len() != signatures.len() { - Err(Error::MilestonePublicKeysSignaturesCountMismatch { - key_count: essence.public_keys().len(), - sig_count: signatures.len(), - }) +fn verify_signatures(signatures: &[Ed25519Signature]) -> Result<(), Error> { + if VERIFY && !is_unique_sorted(signatures.iter().map(|s| s.public_key())) { + Err(Error::MilestoneSignaturesNotUniqueSorted) } else { Ok(()) } @@ -205,7 +152,8 @@ pub mod dto { use super::*; use crate::{ - error::dto::DtoError, milestone::MilestoneIndex, parent::Parents, payload::dto::PayloadDto, MessageId, + error::dto::DtoError, milestone::MilestoneIndex, parent::Parents, payload::dto::PayloadDto, + signature::dto::Ed25519SignatureDto, MessageId, }; /// The payload type to define a milestone. @@ -223,11 +171,9 @@ pub mod dto { pub next_pow_score: u32, #[serde(rename = "nextPoWScoreMilestoneIndex")] pub next_pow_score_milestone_index: u32, - #[serde(rename = "publicKeys")] - pub public_keys: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub receipt: Option, - pub signatures: Vec, + pub signatures: Vec, } impl From<&MilestonePayload> for MilestonePayloadDto { @@ -240,9 +186,8 @@ pub mod dto { inclusion_merkle_proof: prefix_hex::encode(value.essence().merkle_proof()), next_pow_score: value.essence().next_pow_score(), next_pow_score_milestone_index: value.essence().next_pow_score_milestone_index(), - public_keys: value.essence().public_keys().iter().map(prefix_hex::encode).collect(), receipt: value.essence().receipt().map(Into::into), - signatures: value.signatures().map(prefix_hex::encode).collect(), + signatures: value.signatures().iter().map(From::from).collect(), } } } @@ -266,10 +211,6 @@ pub mod dto { .map_err(|_| DtoError::InvalidField("inclusionMerkleProof"))?; let next_pow_score = value.next_pow_score; let next_pow_score_milestone_index = value.next_pow_score_milestone_index; - let mut public_keys = Vec::new(); - for v in &value.public_keys { - public_keys.push(prefix_hex::decode(v).map_err(|_| DtoError::InvalidField("publicKeys"))?); - } let receipt = if let Some(receipt) = value.receipt.as_ref() { Some(receipt.try_into()?) } else { @@ -282,14 +223,12 @@ pub mod dto { merkle_proof, next_pow_score, next_pow_score_milestone_index, - public_keys, receipt, )? }; let mut signatures = Vec::new(); for v in &value.signatures { - let sig: Vec = prefix_hex::decode(v).map_err(|_| DtoError::InvalidField("signatures"))?; - signatures.push(sig.try_into().map_err(|_| DtoError::InvalidField("signatures"))?) + signatures.push(v.try_into().map_err(|_| DtoError::InvalidField("signatures"))?) } Ok(MilestonePayload::new(essence, signatures)?) diff --git a/bee-message/src/payload/mod.rs b/bee-message/src/payload/mod.rs index 8c8ddbb525..8b177aa5d6 100644 --- a/bee-message/src/payload/mod.rs +++ b/bee-message/src/payload/mod.rs @@ -10,7 +10,7 @@ pub mod transaction; pub mod treasury_transaction; pub use milestone::MilestonePayload; -pub(crate) use milestone::{PublicKeyCount, SignatureCount}; +pub(crate) use milestone::SignatureCount; pub use receipt::ReceiptPayload; pub(crate) use receipt::{MigratedFundsAmount, ReceiptFundsCount}; pub use tagged_data::TaggedDataPayload; diff --git a/bee-message/src/signature/ed25519.rs b/bee-message/src/signature/ed25519.rs index fa4e0f0383..953051f917 100644 --- a/bee-message/src/signature/ed25519.rs +++ b/bee-message/src/signature/ed25519.rs @@ -66,6 +66,9 @@ impl Ed25519Signature { pub mod dto { use serde::{Deserialize, Serialize}; + use super::*; + use crate::error::dto::DtoError; + /// Defines an Ed25519 signature. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Ed25519SignatureDto { @@ -75,4 +78,25 @@ pub mod dto { pub public_key: String, pub signature: String, } + + impl From<&Ed25519Signature> for Ed25519SignatureDto { + fn from(value: &Ed25519Signature) -> Self { + Ed25519SignatureDto { + kind: Ed25519Signature::KIND, + public_key: prefix_hex::encode(value.public_key), + signature: prefix_hex::encode(value.signature), + } + } + } + + impl TryFrom<&Ed25519SignatureDto> for Ed25519Signature { + type Error = DtoError; + + fn try_from(value: &Ed25519SignatureDto) -> Result { + Ok(Ed25519Signature::new( + prefix_hex::decode(&value.public_key).map_err(|_| DtoError::InvalidField("publicKey"))?, + prefix_hex::decode(&value.signature).map_err(|_| DtoError::InvalidField("signature"))?, + )) + } + } } From 8084639c477baae43efb5eb0fb155f96c334cdc9 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 30 Mar 2022 11:08:25 -0500 Subject: [PATCH 2/7] give beta for the pink one in the corner --- bee-message/src/payload/milestone/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bee-message/src/payload/milestone/mod.rs b/bee-message/src/payload/milestone/mod.rs index 2819f7d007..baa2d81a4b 100644 --- a/bee-message/src/payload/milestone/mod.rs +++ b/bee-message/src/payload/milestone/mod.rs @@ -49,6 +49,7 @@ pub(crate) type SignatureCount = pub struct MilestonePayload { essence: MilestoneEssence, #[packable(verify_with = verify_signatures)] + #[packable(unpack_error_with = |e| Error::MilestoneInvalidSignatureCount(e.into_prefix_err().into()))] signatures: VecPrefix, } From 14b0cbe001abd573bb9fe42c4f38194f280c36a0 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 30 Mar 2022 18:43:13 +0200 Subject: [PATCH 3/7] Fix tests --- bee-message/tests/milestone_payload.rs | 76 ++++-------- .../tests/milestone_payload_essence.rs | 117 ++---------------- bee-message/tests/payload.rs | 17 ++- 3 files changed, 43 insertions(+), 167 deletions(-) diff --git a/bee-message/tests/milestone_payload.rs b/bee-message/tests/milestone_payload.rs index 5214df1efc..bcb0861b7a 100644 --- a/bee-message/tests/milestone_payload.rs +++ b/bee-message/tests/milestone_payload.rs @@ -5,6 +5,7 @@ use bee_message::{ milestone::MilestoneIndex, parent::Parents, payload::milestone::{MilestoneEssence, MilestonePayload}, + signature::Ed25519Signature, Error, }; use bee_test::rand::{self, message::rand_message_ids, parents::rand_parents}; @@ -18,23 +19,20 @@ fn kind() { #[test] fn new_valid() { - assert!( - MilestonePayload::new( - MilestoneEssence::new( - MilestoneIndex(0), - 0, - rand_parents(), - [0; MilestoneEssence::MERKLE_PROOF_LENGTH], - 0, - 0, - vec![[0; 32]], - None, - ) - .unwrap(), - vec![[0; 64]], + assert!(MilestonePayload::new( + MilestoneEssence::new( + MilestoneIndex(0), + 0, + rand_parents(), + [0; MilestoneEssence::MERKLE_PROOF_LENGTH], + 0, + 0, + None, ) - .is_ok() - ); + .unwrap(), + vec![Ed25519Signature::new([0; 32], [0; 64])] + ) + .is_ok()); } #[test] @@ -48,7 +46,6 @@ fn new_invalid_no_signature() { [0; MilestoneEssence::MERKLE_PROOF_LENGTH], 0, 0, - vec![[0; 32]], None, ) .unwrap(), @@ -69,11 +66,10 @@ fn new_invalid_too_many_signatures() { [0; MilestoneEssence::MERKLE_PROOF_LENGTH], 0, 0, - vec![[0; 32]], None, ) .unwrap(), - vec![[0u8; 64]; 300], + vec![Ed25519Signature::new([0; 32], [0; 64]); 300] ), Err(Error::MilestoneInvalidSignatureCount(TryIntoBoundedU8Error::Truncated( 300 @@ -81,30 +77,6 @@ fn new_invalid_too_many_signatures() { )); } -#[test] -fn new_invalid_public_keys_sgnatures_count_mismatch() { - assert!(matches!( - MilestonePayload::new( - MilestoneEssence::new( - MilestoneIndex(0), - 0, - rand_parents(), - [0; MilestoneEssence::MERKLE_PROOF_LENGTH], - 0, - 0, - vec![[0; 32], [1; 32]], - None, - ) - .unwrap(), - vec![[0; 64], [1; 64], [3; 64]], - ), - Err(Error::MilestonePublicKeysSignaturesCountMismatch { - key_count: 2, - sig_count: 3 - }) - )); -} - #[test] fn packed_len() { let ms = MilestonePayload::new( @@ -115,16 +87,18 @@ fn packed_len() { [0; MilestoneEssence::MERKLE_PROOF_LENGTH], 0, 0, - vec![[0; 32], [1; 32]], None, ) .unwrap(), - vec![[0; 64], [1; 64]], + vec![ + Ed25519Signature::new([0; 32], [0; 64]), + Ed25519Signature::new([1; 32], [1; 64]), + ], ) .unwrap(); - assert_eq!(ms.packed_len(), 379); - assert_eq!(ms.pack_to_vec().len(), 379); + assert_eq!(ms.packed_len(), 378); + assert_eq!(ms.pack_to_vec().len(), 378); } #[test] @@ -137,11 +111,10 @@ fn pack_unpack_valid() { [0; MilestoneEssence::MERKLE_PROOF_LENGTH], 0, 0, - vec![[0; 32]], None, ) .unwrap(), - vec![[0; 64]], + vec![Ed25519Signature::new([0; 32], [0; 64])], ) .unwrap(); @@ -160,16 +133,15 @@ fn getters() { [0; MilestoneEssence::MERKLE_PROOF_LENGTH], 0, 0, - vec![[0; 32]], None, ) .unwrap(); - let signatures = vec![[0; 64]]; + let signatures = vec![Ed25519Signature::new([0; 32], [0; 64])]; let milestone = MilestonePayload::new(essence.clone(), signatures.clone()).unwrap(); assert_eq!(essence, *milestone.essence()); - assert_eq!(signatures.len(), milestone.signatures().count()); + assert_eq!(signatures.len(), milestone.signatures().len()); for (s1, s2) in signatures.iter().zip(milestone.signatures()) { assert_eq!(s1, s2); } diff --git a/bee-message/tests/milestone_payload_essence.rs b/bee-message/tests/milestone_payload_essence.rs index aca0b613ee..4f6c6181b4 100644 --- a/bee-message/tests/milestone_payload_essence.rs +++ b/bee-message/tests/milestone_payload_essence.rs @@ -10,7 +10,7 @@ use bee_message::{ }; use bee_test::rand::{self, bytes::rand_bytes, parents::rand_parents}; -use packable::{bounded::TryIntoBoundedU8Error, PackableExt}; +use packable::PackableExt; #[test] fn new_invalid_pow_score_non_zero() { @@ -22,7 +22,6 @@ fn new_invalid_pow_score_non_zero() { [0; MilestoneEssence::MERKLE_PROOF_LENGTH], 0, 4242, - vec![[0u8; 32]; 1], None, ), Err(Error::InvalidPowScoreValues { nps: 0, npsmi: 4242 }) @@ -39,7 +38,6 @@ fn new_invalid_pow_score_lower_than_index() { [0; MilestoneEssence::MERKLE_PROOF_LENGTH], 4000, 4241, - vec![[0u8; 32]; 1], None, ), Err(Error::InvalidPowScoreValues { nps: 4000, npsmi: 4241 }) @@ -47,96 +45,17 @@ fn new_invalid_pow_score_lower_than_index() { } #[test] -fn new_invalid_no_public_key() { - assert!(matches!( - MilestoneEssence::new( - MilestoneIndex(0), - 0, - rand_parents(), - [0; MilestoneEssence::MERKLE_PROOF_LENGTH], - 0, - 0, - vec![], - None, - ), - Err(Error::MilestoneInvalidPublicKeyCount(TryIntoBoundedU8Error::Invalid(0))) - )); -} - -#[test] -fn new_invalid_too_many_public_keys() { - assert!(matches!( - MilestoneEssence::new( - MilestoneIndex(0), - 0, - rand_parents(), - [0; MilestoneEssence::MERKLE_PROOF_LENGTH], - 0, - 0, - vec![[0u8; 32]; 300], - None, - ), - Err(Error::MilestoneInvalidPublicKeyCount(TryIntoBoundedU8Error::Truncated( - 300 - ))) - )); -} - -#[test] -fn new_valid_sorted_unique_public_keys() { - assert!( - MilestoneEssence::new( - MilestoneIndex(0), - 0, - rand_parents(), - [0; MilestoneEssence::MERKLE_PROOF_LENGTH], - 0, - 0, - vec![ - [0; 32], [1; 32], [2; 32], [3; 32], [4; 32], [5; 32], [6; 32], [7; 32], [8; 32], [9; 32] - ], - None, - ) - .is_ok() - ); -} - -#[test] -fn new_invalid_sorted_not_unique_public_keys() { - assert!(matches!( - MilestoneEssence::new( - MilestoneIndex(0), - 0, - rand_parents(), - [0; MilestoneEssence::MERKLE_PROOF_LENGTH], - 0, - 0, - vec![ - [0; 32], [1; 32], [2; 32], [3; 32], [4; 32], [4; 32], [6; 32], [7; 32], [8; 32], [9; 32] - ], - None, - ), - Err(Error::MilestonePublicKeysNotUniqueSorted) - )); -} - -#[test] -fn new_invalid_not_sorted_unique_public_keys() { - assert!(matches!( - MilestoneEssence::new( - MilestoneIndex(0), - 0, - rand_parents(), - [0; MilestoneEssence::MERKLE_PROOF_LENGTH], - 0, - 0, - vec![ - [0; 32], [1; 32], [3; 32], [2; 32], [4; 32], [5; 32], [6; 32], [7; 32], [8; 32], [9; 32] - ], - None, - ), - Err(Error::MilestonePublicKeysNotUniqueSorted) - )); +fn new_valid() { + assert!(MilestoneEssence::new( + MilestoneIndex(0), + 0, + rand_parents(), + [0; MilestoneEssence::MERKLE_PROOF_LENGTH], + 0, + 0, + None, + ) + .is_ok()); } #[test] @@ -149,9 +68,6 @@ fn new_invalid_payload_kind() { [0; MilestoneEssence::MERKLE_PROOF_LENGTH], 0, 0, - vec![ - [0; 32], [1; 32], [2; 32], [3; 32], [4; 32], [5; 32], [6; 32], [7; 32], [8; 32], [9; 32] - ], Some(Payload::TaggedData(Box::new( TaggedDataPayload::new(rand_bytes(32), vec![]).unwrap() ))), @@ -168,10 +84,6 @@ fn getters() { let merkel_proof = [0; MilestoneEssence::MERKLE_PROOF_LENGTH]; let next_pow_score = 0; let next_pow_score_milestone_index = 0; - let public_keys = vec![ - [0; 32], [1; 32], [2; 32], [3; 32], [4; 32], [5; 32], [6; 32], [7; 32], [8; 32], [9; 32], - ]; - let receipt = Some(Payload::Receipt(Box::new( ReceiptPayload::new( index, @@ -193,7 +105,6 @@ fn getters() { merkel_proof, next_pow_score, next_pow_score_milestone_index, - public_keys.clone(), receipt.clone(), ) .unwrap(); @@ -207,7 +118,6 @@ fn getters() { milestone_payload.next_pow_score_milestone_index(), next_pow_score_milestone_index ); - assert_eq!(*milestone_payload.public_keys(), public_keys); assert_eq!(*milestone_payload.receipt().unwrap(), receipt.unwrap()); } @@ -220,9 +130,6 @@ fn pack_unpack_valid() { [0; MilestoneEssence::MERKLE_PROOF_LENGTH], 0, 0, - vec![ - [0; 32], [1; 32], [2; 32], [3; 32], [4; 32], [5; 32], [6; 32], [7; 32], [8; 32], [9; 32], - ], None, ) .unwrap(); diff --git a/bee-message/tests/payload.rs b/bee-message/tests/payload.rs index 9b3d7cd062..236c86f76f 100644 --- a/bee-message/tests/payload.rs +++ b/bee-message/tests/payload.rs @@ -86,11 +86,10 @@ fn milestone() { [0; MilestoneEssence::MERKLE_PROOF_LENGTH], 0, 0, - vec![[0; 32]], None, ) .unwrap(), - vec![[0; 64]], + vec![Ed25519Signature::new([0; 32], [0; 64])], ) .unwrap() .into(); @@ -119,14 +118,12 @@ fn receipt() { let payload: Payload = ReceiptPayload::new( MilestoneIndex::new(0), true, - vec![ - MigratedFundsEntry::new( - TailTransactionHash::new(TAIL_TRANSACTION_HASH_BYTES).unwrap(), - Address::from(Ed25519Address::from_str(ED25519_ADDRESS).unwrap()), - 1_000_000, - ) - .unwrap(), - ], + vec![MigratedFundsEntry::new( + TailTransactionHash::new(TAIL_TRANSACTION_HASH_BYTES).unwrap(), + Address::from(Ed25519Address::from_str(ED25519_ADDRESS).unwrap()), + 1_000_000, + ) + .unwrap()], TreasuryTransactionPayload::new( TreasuryInput::new(MilestoneId::from_str(MILESTONE_ID).unwrap()), TreasuryOutput::new(1_000_000).unwrap(), From fbc3bbfe8c01350c29384242d709d838b2b01685 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Wed, 30 Mar 2022 18:44:35 +0200 Subject: [PATCH 4/7] Fmt --- bee-message/tests/milestone_payload.rs | 28 ++++++++++--------- .../tests/milestone_payload_essence.rs | 22 ++++++++------- bee-message/tests/payload.rs | 14 ++++++---- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/bee-message/tests/milestone_payload.rs b/bee-message/tests/milestone_payload.rs index bcb0861b7a..402c371570 100644 --- a/bee-message/tests/milestone_payload.rs +++ b/bee-message/tests/milestone_payload.rs @@ -19,20 +19,22 @@ fn kind() { #[test] fn new_valid() { - assert!(MilestonePayload::new( - MilestoneEssence::new( - MilestoneIndex(0), - 0, - rand_parents(), - [0; MilestoneEssence::MERKLE_PROOF_LENGTH], - 0, - 0, - None, + assert!( + MilestonePayload::new( + MilestoneEssence::new( + MilestoneIndex(0), + 0, + rand_parents(), + [0; MilestoneEssence::MERKLE_PROOF_LENGTH], + 0, + 0, + None, + ) + .unwrap(), + vec![Ed25519Signature::new([0; 32], [0; 64])] ) - .unwrap(), - vec![Ed25519Signature::new([0; 32], [0; 64])] - ) - .is_ok()); + .is_ok() + ); } #[test] diff --git a/bee-message/tests/milestone_payload_essence.rs b/bee-message/tests/milestone_payload_essence.rs index 4f6c6181b4..1bccd23166 100644 --- a/bee-message/tests/milestone_payload_essence.rs +++ b/bee-message/tests/milestone_payload_essence.rs @@ -46,16 +46,18 @@ fn new_invalid_pow_score_lower_than_index() { #[test] fn new_valid() { - assert!(MilestoneEssence::new( - MilestoneIndex(0), - 0, - rand_parents(), - [0; MilestoneEssence::MERKLE_PROOF_LENGTH], - 0, - 0, - None, - ) - .is_ok()); + assert!( + MilestoneEssence::new( + MilestoneIndex(0), + 0, + rand_parents(), + [0; MilestoneEssence::MERKLE_PROOF_LENGTH], + 0, + 0, + None, + ) + .is_ok() + ); } #[test] diff --git a/bee-message/tests/payload.rs b/bee-message/tests/payload.rs index 236c86f76f..309f89707f 100644 --- a/bee-message/tests/payload.rs +++ b/bee-message/tests/payload.rs @@ -118,12 +118,14 @@ fn receipt() { let payload: Payload = ReceiptPayload::new( MilestoneIndex::new(0), true, - vec![MigratedFundsEntry::new( - TailTransactionHash::new(TAIL_TRANSACTION_HASH_BYTES).unwrap(), - Address::from(Ed25519Address::from_str(ED25519_ADDRESS).unwrap()), - 1_000_000, - ) - .unwrap()], + vec![ + MigratedFundsEntry::new( + TailTransactionHash::new(TAIL_TRANSACTION_HASH_BYTES).unwrap(), + Address::from(Ed25519Address::from_str(ED25519_ADDRESS).unwrap()), + 1_000_000, + ) + .unwrap(), + ], TreasuryTransactionPayload::new( TreasuryInput::new(MilestoneId::from_str(MILESTONE_ID).unwrap()), TreasuryOutput::new(1_000_000).unwrap(), From 0458ecacdcc1752767b9e1f36b3ebc31f86a5d11 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Thu, 31 Mar 2022 10:10:24 +0200 Subject: [PATCH 5/7] Fix MilestonePayload KIND --- bee-message/src/payload/milestone/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bee-message/src/payload/milestone/mod.rs b/bee-message/src/payload/milestone/mod.rs index baa2d81a4b..88c5a552a7 100644 --- a/bee-message/src/payload/milestone/mod.rs +++ b/bee-message/src/payload/milestone/mod.rs @@ -55,7 +55,7 @@ pub struct MilestonePayload { impl MilestonePayload { /// The payload kind of a [`MilestonePayload`]. - pub const KIND: u32 = 1; + pub const KIND: u32 = 7 /// Range of allowed milestones signatures key numbers. pub const SIGNATURE_COUNT_RANGE: RangeInclusive = 1..=255; /// Length of a milestone signature. From 4983e2bdbb0d211535da0e0e3970c9c0f048d881 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Thu, 31 Mar 2022 10:49:29 +0200 Subject: [PATCH 6/7] Use generic signature --- bee-message/src/payload/milestone/mod.rs | 29 +++++++++++++++--------- bee-message/src/signature/mod.rs | 20 ++++++++++++++++ bee-message/tests/milestone_payload.rs | 20 ++++++++-------- bee-message/tests/payload.rs | 4 ++-- 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/bee-message/src/payload/milestone/mod.rs b/bee-message/src/payload/milestone/mod.rs index 88c5a552a7..8dba6fc7e2 100644 --- a/bee-message/src/payload/milestone/mod.rs +++ b/bee-message/src/payload/milestone/mod.rs @@ -9,7 +9,7 @@ mod milestone_id; pub use essence::MilestoneEssence; pub use milestone_id::MilestoneId; -use crate::{signature::Ed25519Signature, Error}; +use crate::{signature::Signature, Error}; use crypto::{ hashes::{blake2b::Blake2b256, Digest}, @@ -49,21 +49,21 @@ pub(crate) type SignatureCount = pub struct MilestonePayload { essence: MilestoneEssence, #[packable(verify_with = verify_signatures)] - #[packable(unpack_error_with = |e| Error::MilestoneInvalidSignatureCount(e.into_prefix_err().into()))] - signatures: VecPrefix, + #[packable(unpack_error_with = |e| e.unwrap_item_err_or_else(|p| Error::MilestoneInvalidSignatureCount(p.into())))] + signatures: VecPrefix, } impl MilestonePayload { /// The payload kind of a [`MilestonePayload`]. - pub const KIND: u32 = 7 + pub const KIND: u32 = 7; /// Range of allowed milestones signatures key numbers. pub const SIGNATURE_COUNT_RANGE: RangeInclusive = 1..=255; /// Length of a milestone signature. pub const SIGNATURE_LENGTH: usize = 64; /// Creates a new [`MilestonePayload`]. - pub fn new(essence: MilestoneEssence, signatures: Vec) -> Result { - let signatures = VecPrefix::::try_from(signatures) + pub fn new(essence: MilestoneEssence, signatures: Vec) -> Result { + let signatures = VecPrefix::::try_from(signatures) .map_err(Error::MilestoneInvalidSignatureCount)?; Ok(Self { essence, signatures }) @@ -75,7 +75,7 @@ impl MilestonePayload { } /// Returns the signatures of a [`MilestonePayload`]. - pub fn signatures(&self) -> &[Ed25519Signature] { + pub fn signatures(&self) -> &[Signature] { &self.signatures } @@ -116,6 +116,8 @@ impl MilestonePayload { let essence_hash = self.essence().hash(); for (index, signature) in self.signatures().iter().enumerate() { + let Signature::Ed25519(signature) = signature; + if !applicable_public_keys.contains(&prefix_hex::encode(signature.public_key())) { return Err(MilestoneValidationError::UnapplicablePublicKey(prefix_hex::encode( *signature.public_key(), @@ -138,8 +140,13 @@ impl MilestonePayload { } } -fn verify_signatures(signatures: &[Ed25519Signature]) -> Result<(), Error> { - if VERIFY && !is_unique_sorted(signatures.iter().map(|s| s.public_key())) { +fn verify_signatures(signatures: &[Signature]) -> Result<(), Error> { + if VERIFY + && !is_unique_sorted(signatures.iter().map(|signature| { + let Signature::Ed25519(signature) = signature; + signature.public_key() + })) + { Err(Error::MilestoneSignaturesNotUniqueSorted) } else { Ok(()) @@ -154,7 +161,7 @@ pub mod dto { use super::*; use crate::{ error::dto::DtoError, milestone::MilestoneIndex, parent::Parents, payload::dto::PayloadDto, - signature::dto::Ed25519SignatureDto, MessageId, + signature::dto::SignatureDto, MessageId, }; /// The payload type to define a milestone. @@ -174,7 +181,7 @@ pub mod dto { pub next_pow_score_milestone_index: u32, #[serde(skip_serializing_if = "Option::is_none")] pub receipt: Option, - pub signatures: Vec, + pub signatures: Vec, } impl From<&MilestonePayload> for MilestonePayloadDto { diff --git a/bee-message/src/signature/mod.rs b/bee-message/src/signature/mod.rs index 77a3c8d113..6537ec22bf 100644 --- a/bee-message/src/signature/mod.rs +++ b/bee-message/src/signature/mod.rs @@ -43,6 +43,8 @@ pub mod dto { use serde::{Deserialize, Serialize}; pub use super::ed25519::dto::Ed25519SignatureDto; + use super::*; + use crate::error::dto::DtoError; /// Describes all the different signature types. #[derive(Clone, Debug, Serialize, Deserialize)] @@ -50,4 +52,22 @@ pub mod dto { pub enum SignatureDto { Ed25519(Ed25519SignatureDto), } + + impl From<&Signature> for SignatureDto { + fn from(value: &Signature) -> Self { + match value { + Signature::Ed25519(s) => SignatureDto::Ed25519(s.into()), + } + } + } + + impl TryFrom<&SignatureDto> for Signature { + type Error = DtoError; + + fn try_from(value: &SignatureDto) -> Result { + match value { + SignatureDto::Ed25519(s) => Ok(Signature::Ed25519(s.try_into()?)), + } + } + } } diff --git a/bee-message/tests/milestone_payload.rs b/bee-message/tests/milestone_payload.rs index 402c371570..dd80c5e033 100644 --- a/bee-message/tests/milestone_payload.rs +++ b/bee-message/tests/milestone_payload.rs @@ -5,7 +5,7 @@ use bee_message::{ milestone::MilestoneIndex, parent::Parents, payload::milestone::{MilestoneEssence, MilestonePayload}, - signature::Ed25519Signature, + signature::{Ed25519Signature, Signature}, Error, }; use bee_test::rand::{self, message::rand_message_ids, parents::rand_parents}; @@ -14,7 +14,7 @@ use packable::{bounded::TryIntoBoundedU8Error, PackableExt}; #[test] fn kind() { - assert_eq!(MilestonePayload::KIND, 1); + assert_eq!(MilestonePayload::KIND, 7); } #[test] @@ -31,7 +31,7 @@ fn new_valid() { None, ) .unwrap(), - vec![Ed25519Signature::new([0; 32], [0; 64])] + vec![Signature::from(Ed25519Signature::new([0; 32], [0; 64]))] ) .is_ok() ); @@ -71,7 +71,7 @@ fn new_invalid_too_many_signatures() { None, ) .unwrap(), - vec![Ed25519Signature::new([0; 32], [0; 64]); 300] + vec![Signature::from(Ed25519Signature::new([0; 32], [0; 64])); 300] ), Err(Error::MilestoneInvalidSignatureCount(TryIntoBoundedU8Error::Truncated( 300 @@ -93,14 +93,14 @@ fn packed_len() { ) .unwrap(), vec![ - Ed25519Signature::new([0; 32], [0; 64]), - Ed25519Signature::new([1; 32], [1; 64]), + Signature::from(Ed25519Signature::new([0; 32], [0; 64])), + Signature::from(Ed25519Signature::new([1; 32], [1; 64])), ], ) .unwrap(); - assert_eq!(ms.packed_len(), 378); - assert_eq!(ms.pack_to_vec().len(), 378); + assert_eq!(ms.packed_len(), 380); + assert_eq!(ms.pack_to_vec().len(), 380); } #[test] @@ -116,7 +116,7 @@ fn pack_unpack_valid() { None, ) .unwrap(), - vec![Ed25519Signature::new([0; 32], [0; 64])], + vec![Signature::from(Ed25519Signature::new([0; 32], [0; 64]))], ) .unwrap(); @@ -138,7 +138,7 @@ fn getters() { None, ) .unwrap(); - let signatures = vec![Ed25519Signature::new([0; 32], [0; 64])]; + let signatures = vec![Signature::from(Ed25519Signature::new([0; 32], [0; 64]))]; let milestone = MilestonePayload::new(essence.clone(), signatures.clone()).unwrap(); assert_eq!(essence, *milestone.essence()); diff --git a/bee-message/tests/payload.rs b/bee-message/tests/payload.rs index 309f89707f..8eb5b73aec 100644 --- a/bee-message/tests/payload.rs +++ b/bee-message/tests/payload.rs @@ -89,14 +89,14 @@ fn milestone() { None, ) .unwrap(), - vec![Ed25519Signature::new([0; 32], [0; 64])], + vec![Signature::from(Ed25519Signature::new([0; 32], [0; 64]))], ) .unwrap() .into(); let packed = payload.pack_to_vec(); - assert_eq!(payload.kind(), 1); + assert_eq!(payload.kind(), 7); assert_eq!(payload.packed_len(), packed.len()); assert!(matches!(payload, Payload::Milestone(_))); assert_eq!(payload, PackableExt::unpack_verified(&mut packed.as_slice()).unwrap()); From 3ca0003cefa401bfe39f52e26eb34a9d8d03d1a3 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Thu, 31 Mar 2022 10:58:02 +0200 Subject: [PATCH 7/7] Fmt --- .../bee-gossip/src/swarm/protocols/iota_gossip/handler.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bee-network/bee-gossip/src/swarm/protocols/iota_gossip/handler.rs b/bee-network/bee-gossip/src/swarm/protocols/iota_gossip/handler.rs index 571506ac23..26ff30076d 100644 --- a/bee-network/bee-gossip/src/swarm/protocols/iota_gossip/handler.rs +++ b/bee-network/bee-gossip/src/swarm/protocols/iota_gossip/handler.rs @@ -66,9 +66,9 @@ impl ProtocolsHandler for GossipProtocolHandler { /// substreams to negotiate the desired protocols. /// /// > **Note**: The returned `InboundUpgrade` should always accept all the generally - /// > supported protocols, even if in a specific context a particular one is - /// > not supported, (eg. when only allowing one substream at a time for a protocol). - /// > This allows a remote to put the list of supported protocols in a cache. + /// > supported protocols, even if in a specific context a particular one is + /// > not supported, (eg. when only allowing one substream at a time for a protocol). + /// > This allows a remote to put the list of supported protocols in a cache. fn listen_protocol(&self) -> SubstreamProtocol { debug!("gossip handler: responding to listen protocol request.");