Skip to content

Commit

Permalink
Remove consensus-encoding for Scope and SessionId
Browse files Browse the repository at this point in the history
Use custom conversion and more docs in coupl of places
  • Loading branch information
Velnbur committed Jan 22, 2025
1 parent 70e0c6e commit 97c99a4
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 112 deletions.
6 changes: 3 additions & 3 deletions crates/types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
45 changes: 14 additions & 31 deletions crates/types/src/scope.rs
Original file line number Diff line number Diff line change
@@ -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<Self, Error> {
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<u8> {
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<sha256::Hash> for Scope {
fn from(value: sha256::Hash) -> Self {
Self(value)
}
}

impl Decodable for Scope {
fn consensus_decode<R: bitcoin::io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
Ok(Self(sha256::Hash::consensus_decode(reader)?))
}
}

impl Encodable for Scope {
fn consensus_encode<W: bitcoin::io::Write + ?Sized>(
&self,
writer: &mut W,
) -> Result<usize, bitcoin::io::Error> {
self.0.consensus_encode(writer)
Self(value.to_byte_array())
}
}
44 changes: 13 additions & 31 deletions crates/types/src/sessionid.rs
Original file line number Diff line number Diff line change
@@ -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<Self, Error> {
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<u8> {
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<sha256::Hash> for SessionId {
fn from(value: sha256::Hash) -> Self {
Self(value)
}
}

impl Decodable for SessionId {
fn consensus_decode<R: bitcoin::io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
Ok(Self(sha256::Hash::consensus_decode(reader)?))
}
}

impl Encodable for SessionId {
fn consensus_encode<W: bitcoin::io::Write + ?Sized>(
&self,
writer: &mut W,
) -> Result<usize, bitcoin::io::Error> {
self.0.consensus_encode(writer)
Self(value.to_byte_array())
}
}
116 changes: 69 additions & 47 deletions crates/wire/src/p2p/v1/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<GetMessageRequest, DecodeError> {
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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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 } => {
Expand Down Expand Up @@ -195,50 +204,63 @@ pub enum UnsignedGossipsubMsg<DepositSetupPayload: Message> {
}

impl<DSP: Message + Default> UnsignedGossipsubMsg<DSP> {
/// Convert [`proto::GossipsubMsgBody`] into typed
/// [`UnsignedGossipsubMsg`] with specific types instead of raw vectors.
pub fn from_msg_proto(proto: &ProtoGossipsubMsgBody) -> Result<Self, DecodeError> {
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::<Result<Vec<_>, _>>()
.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::<Result<Vec<_>, _>>()
.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::<Result<Vec<_>, _>>()
.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::<Result<Vec<_>, _>>()
.map_err(|err| DecodeError::new(err.to_string()))?;

Self::Musig2SignaturesExchange {
session_id,
signatures: partial_sigs,
}
}
};

Ok(unsigned)
}
Expand Down

0 comments on commit 97c99a4

Please sign in to comment.