From 97c99a458babc493848e5e8dc7560b7a06e56c62 Mon Sep 17 00:00:00 2001 From: Velnbur Date: Wed, 22 Jan 2025 21:53:32 +0200 Subject: [PATCH] Remove consensus-encoding for `Scope` and `SessionId` Use custom conversion and more docs in coupl of places --- crates/types/src/lib.rs | 6 +- crates/types/src/scope.rs | 45 ++++--------- crates/types/src/sessionid.rs | 44 ++++-------- crates/wire/src/p2p/v1/typed.rs | 116 +++++++++++++++++++------------- 4 files changed, 99 insertions(+), 112 deletions(-) diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index c7ddd4a..f6e1c56 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -1,6 +1,6 @@ -pub mod operator; -pub mod scope; -pub mod sessionid; +mod operator; +mod scope; +mod sessionid; pub use operator::OperatorPubKey; pub use scope::Scope; diff --git a/crates/types/src/scope.rs b/crates/types/src/scope.rs index d009d28..b90bc5b 100644 --- a/crates/types/src/scope.rs +++ b/crates/types/src/scope.rs @@ -1,61 +1,44 @@ use core::fmt; -use bitcoin::{ - consensus::{encode::Error, Decodable, Encodable}, - hashes::{sha256, Hash}, - io::Cursor, -}; +use bitcoin::hashes::{sha256, Hash}; use serde::{Deserialize, Serialize}; /// A unique identifier of deposit setup made by hashing unique data related to it #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)] -pub struct Scope(sha256::Hash); +pub struct Scope([u8; Scope::SIZE]); impl fmt::Display for Scope { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.0.fmt(f) + write!(f, "{}", hex::encode(self.0)) } } impl Scope { - pub const fn hash(data: &[u8]) -> Self { - Self(sha256::Hash::const_hash(data)) + const SIZE: usize = 32; + + /// Construct scope from preimage by hashing it. + pub fn hash(data: &[u8]) -> Self { + Self(sha256::Hash::hash(data).to_byte_array()) } - pub fn from_bytes(bytes: &[u8]) -> Result { - let mut cursor = Cursor::new(bytes); - let scope = Decodable::consensus_decode(&mut cursor)?; - Ok(Self(scope)) + /// Construct scope from array of bytes. + pub fn from_bytes(bytes: [u8; Self::SIZE]) -> Self { + Self(bytes) } pub fn to_vec(&self) -> Vec { - self.0.to_byte_array().to_vec() + self.0.to_vec() } } impl AsRef<[u8]> for Scope { fn as_ref(&self) -> &[u8] { - self.0.as_byte_array().as_ref() + self.0.as_ref() } } impl From for Scope { fn from(value: sha256::Hash) -> Self { - Self(value) - } -} - -impl Decodable for Scope { - fn consensus_decode(reader: &mut R) -> Result { - Ok(Self(sha256::Hash::consensus_decode(reader)?)) - } -} - -impl Encodable for Scope { - fn consensus_encode( - &self, - writer: &mut W, - ) -> Result { - self.0.consensus_encode(writer) + Self(value.to_byte_array()) } } diff --git a/crates/types/src/sessionid.rs b/crates/types/src/sessionid.rs index 27722e5..4dba71e 100644 --- a/crates/types/src/sessionid.rs +++ b/crates/types/src/sessionid.rs @@ -1,62 +1,44 @@ use core::fmt; -use bitcoin::{ - consensus::{encode::Error, Decodable, Encodable}, - hashes::{sha256, Hash}, - io::Cursor, -}; +use bitcoin::hashes::{sha256, Hash}; use serde::{Deserialize, Serialize}; /// A unique identifier of signatures and nonces exchange session made by /// hashing unique data related to it. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)] -pub struct SessionId(sha256::Hash); +pub struct SessionId([u8; SessionId::SIZE]); impl SessionId { - pub const fn hash(data: &[u8]) -> Self { - Self(sha256::Hash::const_hash(data)) + const SIZE: usize = 32; + + /// Construct session ID from preimage by hashing it. + pub fn hash(data: &[u8]) -> Self { + Self(sha256::Hash::const_hash(data).to_byte_array()) } - pub fn from_bytes(bytes: &[u8]) -> Result { - let mut cursor = Cursor::new(bytes); - let session_id = Decodable::consensus_decode(&mut cursor)?; - Ok(Self(session_id)) + pub fn from_bytes(bytes: [u8; Self::SIZE]) -> Self { + Self(bytes) } pub fn to_vec(&self) -> Vec { - self.0.to_byte_array().to_vec() + self.0.to_vec() } } impl fmt::Display for SessionId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.0.fmt(f) + write!(f, "{}", hex::encode(self.0)) } } impl AsRef<[u8]> for SessionId { fn as_ref(&self) -> &[u8] { - self.0.as_byte_array().as_ref() + self.0.as_ref() } } impl From for SessionId { fn from(value: sha256::Hash) -> Self { - Self(value) - } -} - -impl Decodable for SessionId { - fn consensus_decode(reader: &mut R) -> Result { - Ok(Self(sha256::Hash::consensus_decode(reader)?)) - } -} - -impl Encodable for SessionId { - fn consensus_encode( - &self, - writer: &mut W, - ) -> Result { - self.0.consensus_encode(writer) + Self(value.to_byte_array()) } } diff --git a/crates/wire/src/p2p/v1/typed.rs b/crates/wire/src/p2p/v1/typed.rs index ce1a34d..17177b8 100644 --- a/crates/wire/src/p2p/v1/typed.rs +++ b/crates/wire/src/p2p/v1/typed.rs @@ -38,13 +38,17 @@ pub enum GetMessageRequest { } impl GetMessageRequest { + /// Convert [`proto::GetMessageRequest`] into [`typed::GetMessageRequest`] + /// by parsing raw vec values into specific types. pub fn from_msg(msg: ProtoGetMessageRequest) -> Result { let body = msg.body.ok_or(DecodeError::new("Message without body"))?; let request = match body { ProtoGetMessageRequestBody::DepositSetup(DepositRequestKey { scope, operator }) => { - let scope = - Scope::from_bytes(&scope).map_err(|err| DecodeError::new(err.to_string()))?; + let bytes = scope + .try_into() + .map_err(|_| DecodeError::new("invalid length of bytes in scope"))?; + let scope = Scope::from_bytes(bytes); Self::DepositSetup { scope, @@ -55,8 +59,10 @@ impl GetMessageRequest { session_id, operator, }) => { - let session_id = SessionId::from_bytes(&session_id) - .map_err(|err| DecodeError::new(err.to_string()))?; + let bytes = session_id + .try_into() + .map_err(|_| DecodeError::new("invalid length of bytes in session id"))?; + let session_id = SessionId::from_bytes(bytes); Self::Musig2NoncesExchange { session_id, @@ -67,8 +73,10 @@ impl GetMessageRequest { session_id, operator, }) => { - let session_id = SessionId::from_bytes(&session_id) - .map_err(|err| DecodeError::new(err.to_string()))?; + let bytes = session_id + .try_into() + .map_err(|_| DecodeError::new("invalid length of bytes in session id"))?; + let session_id = SessionId::from_bytes(bytes); Self::Musig2SignaturesExchange { session_id, @@ -85,6 +93,7 @@ impl GetMessageRequest { Ok(request) } + /// Convert [`typed::GetMessageRequest`] into raw [`proto::GetMessageRequest`]. pub fn into_msg(self) -> ProtoGetMessageRequest { let body = match self { Self::Genesis { operator_pk } => { @@ -195,50 +204,63 @@ pub enum UnsignedGossipsubMsg { } impl UnsignedGossipsubMsg { + /// Convert [`proto::GossipsubMsgBody`] into typed + /// [`UnsignedGossipsubMsg`] with specific types instead of raw vectors. pub fn from_msg_proto(proto: &ProtoGossipsubMsgBody) -> Result { - let unsigned = match proto { - ProtoGossipsubMsgBody::GenesisInfo(proto) => { - Self::GenesisInfo(GenesisInfo::from_proto_msg(proto)?) - } - ProtoGossipsubMsgBody::Setup(proto) => { - let scope = Scope::from_bytes(&proto.scope) - .map_err(|err| DecodeError::new(err.to_string()))?; - - Self::DepositSetup { - scope, - setup: DepositSetup::from_proto_msg(proto)?, + let unsigned = + match proto { + ProtoGossipsubMsgBody::GenesisInfo(proto) => { + Self::GenesisInfo(GenesisInfo::from_proto_msg(proto)?) } - } - ProtoGossipsubMsgBody::Nonce(proto) => { - let session_id = SessionId::from_bytes(&proto.session_id) - .map_err(|err| DecodeError::new(err.to_string()))?; - - let nonces = proto - .pub_nonces - .iter() - .map(|bytes| PubNonce::from_bytes(bytes)) - .collect::, _>>() - .map_err(|err| DecodeError::new(err.to_string()))?; - - Self::Musig2NoncesExchange { session_id, nonces } - } - ProtoGossipsubMsgBody::Sigs(proto) => { - let session_id = SessionId::from_bytes(&proto.session_id) - .map_err(|err| DecodeError::new(err.to_string()))?; - - let partial_sigs = proto - .partial_sigs - .iter() - .map(|bytes| PartialSignature::from_slice(bytes)) - .collect::, _>>() - .map_err(|err| DecodeError::new(err.to_string()))?; - - Self::Musig2SignaturesExchange { - session_id, - signatures: partial_sigs, + ProtoGossipsubMsgBody::Setup(proto) => { + let bytes = proto + .scope + .as_slice() + .try_into() + .map_err(|_| DecodeError::new("invalid length of bytes for scope"))?; + let scope = Scope::from_bytes(bytes); + + Self::DepositSetup { + scope, + setup: DepositSetup::from_proto_msg(proto)?, + } } - } - }; + ProtoGossipsubMsgBody::Nonce(proto) => { + let bytes = + proto.session_id.as_slice().try_into().map_err(|_| { + DecodeError::new("invalid length of bytes for session id") + })?; + let session_id = SessionId::from_bytes(bytes); + + let nonces = proto + .pub_nonces + .iter() + .map(|bytes| PubNonce::from_bytes(bytes)) + .collect::, _>>() + .map_err(|err| DecodeError::new(err.to_string()))?; + + Self::Musig2NoncesExchange { session_id, nonces } + } + ProtoGossipsubMsgBody::Sigs(proto) => { + let bytes = + proto.session_id.as_slice().try_into().map_err(|_| { + DecodeError::new("invalid length of bytes for session id") + })?; + let session_id = SessionId::from_bytes(bytes); + + let partial_sigs = proto + .partial_sigs + .iter() + .map(|bytes| PartialSignature::from_slice(bytes)) + .collect::, _>>() + .map_err(|err| DecodeError::new(err.to_string()))?; + + Self::Musig2SignaturesExchange { + session_id, + signatures: partial_sigs, + } + } + }; Ok(unsigned) }