diff --git a/Cargo.toml b/Cargo.toml index b5c47c5..79f4843 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,6 +67,7 @@ rng = { path = "crates/rng" } # Core dependencies best-practices = { version = "0.1.0", git = "https://github.com/cryptidtech/best-practices.git" } +blsful = "3.0.0" blockstore = "0.7.1" cid = "0.11.0" criterion = "0.5.1" diff --git a/crates/bs-p2p/src/events/api.rs b/crates/bs-p2p/src/events/api.rs index 71840c7..1033165 100644 --- a/crates/bs-p2p/src/events/api.rs +++ b/crates/bs-p2p/src/events/api.rs @@ -1,11 +1,9 @@ -//! The Events API for interacting witht he netowrk events. -use crate::events::delay; +//! The Events API for interacting witht he netowrk events. pub use crate::behaviour::req_res::{PeerRequest, PeerResponse}; +use crate::behaviour::{Behaviour, BehaviourEvent}; +use crate::events::delay; use crate::events::timeout::with_timeout; -use libp2p::Multiaddr; -use provenance_log::resolver::{Resolver, SuperResolver}; use crate::events::{NetworkError, PublicEvent}; -use crate::behaviour::{Behaviour, BehaviourEvent}; use crate::Error; use blockstore::Blockstore; use futures::stream::StreamExt; @@ -23,7 +21,9 @@ use libp2p::kad::{InboundRequest, Record}; pub use libp2p::multiaddr::Protocol; use libp2p::request_response::{self, OutboundRequestId, ResponseChannel}; use libp2p::swarm::{Swarm, SwarmEvent}; -use libp2p::{identify, kad, ping, PeerId, }; +use libp2p::Multiaddr; +use libp2p::{identify, kad, ping, PeerId}; +use provenance_log::resolver::{Resolver, SuperResolver}; use std::collections::{HashMap, HashSet}; use std::net::Ipv4Addr; use std::pin::Pin; @@ -136,7 +136,7 @@ impl Client { receiver.await.map_err(Error::OneshotCanceled) } - /// Put a record on the DHT + /// Put a record on the DHT pub async fn put_record(&self, key: Vec, value: Vec) -> Result<(), Error> { self.command_sender .send(NetworkCommand::PutRecord { key, value }) @@ -218,14 +218,14 @@ impl Resolver for Client { fn resolve( &self, cid: &multicid::Cid, - // ) -> Pin, Self::Error>> + CondSend>> { + // ) -> Pin, Self::Error>> + CondSend>> { ) -> Pin + '_>> { tracing::debug!("DefaultBsPeer Resolving CID over bitswap: {}", cid); let cid_bytes: Vec = cid.clone().into(); let client = self.clone(); - Box::pin(async move { - with_timeout(client.get_bits(cid_bytes), Duration::from_secs(10)).await? - }) + Box::pin( + async move { with_timeout(client.get_bits(cid_bytes), Duration::from_secs(10)).await? }, + ) } } /// PeerPiper Network Commands (Libp2p) @@ -307,7 +307,6 @@ pub enum Libp2pEvent { PutRecordRequest { source: PeerId }, } - /// The network event loop. /// Handles all the network logic for us. pub struct EventLoop { @@ -457,25 +456,29 @@ impl EventLoop { // pass the address back to the other task, for display, etc. self.event_sender - .try_send(PublicEvent::ListenAddr { - address: p2p_addr, - }) + .try_send(PublicEvent::ListenAddr { address: p2p_addr }) }; // Protocol::Ip is the first item in the address vector match address.iter().next() { Some(Protocol::Ip6(ip6)) => { // Only add our globally available IPv6 addresses to the external addresses list. if !ip6.is_loopback() - && !ip6.is_unspecified() + && !ip6.is_unspecified() && !ip6.is_multicast() && (ip6.segments()[0] & 0xffc0) != 0xfe80 // no fe80::/10 addresses, (!ip6.is_unicast_link_local() requires nightly) - && (ip6.segments()[0] & 0xfe00) != 0xfc00 // Unique Local Addresses (ULAs, fd00::/8) are private IPv6 addresses and should not be advertised. + && (ip6.segments()[0] & 0xfe00) != 0xfc00 + // Unique Local Addresses (ULAs, fd00::/8) are private IPv6 addresses and should not be advertised. { addr_handler()?; } } Some(Protocol::Ip4(ip4)) => { - if !(ip4.is_loopback() || ip4.is_unspecified() || ip4.is_private() || ip4.is_multicast() || ip4 == Ipv4Addr::LOCALHOST || ip4.octets()[0] & 240 == 240 && !ip4.is_broadcast()) + if !(ip4.is_loopback() + || ip4.is_unspecified() + || ip4.is_private() + || ip4.is_multicast() + || ip4 == Ipv4Addr::LOCALHOST + || ip4.octets()[0] & 240 == 240 && !ip4.is_broadcast()) { addr_handler()?; } @@ -506,7 +509,9 @@ impl EventLoop { .await { tracing::error!("Failed to send NewConnection event: {e}"); - return Err(Error::SendFailure("Failed to send NewConnection event".to_string())); + return Err(Error::SendFailure( + "Failed to send NewConnection event".to_string(), + )); } } SwarmEvent::OutgoingConnectionError { peer_id, error, .. } => { @@ -591,7 +596,12 @@ impl EventLoop { // Send ACK back to the sender let ack_topic = format!("ack/{}", message.topic.to_string()); - if let Err(e) = self.swarm.behaviour_mut().gossipsub.publish(libp2p::gossipsub::IdentTopic::new(&ack_topic), message.data) { + if let Err(e) = self + .swarm + .behaviour_mut() + .gossipsub + .publish(libp2p::gossipsub::IdentTopic::new(&ack_topic), message.data) + { tracing::error!("Failed to publish ACK: {e}"); } } @@ -622,27 +632,29 @@ impl EventLoop { .kad .store_mut() .get(&libp2p::kad::RecordKey::new(&key)) - .map(|record| record.into_owned()) { - tracing::debug!("Found record for key {:?}: {:?}", key, record); - // Publish the record to the topic - if let Err(e) = self - .swarm - .behaviour_mut() - .gossipsub - .publish(topic, record.value.clone()) - { - tracing::error!("Failed to publish record to topic: {e}"); - } - } + .map(|record| record.into_owned()) + { + tracing::debug!("Found record for key {:?}: {:?}", key, record); + // Publish the record to the topic + if let Err(e) = self + .swarm + .behaviour_mut() + .gossipsub + .publish(topic, record.value.clone()) + { + tracing::error!("Failed to publish record to topic: {e}"); + } + } } SwarmEvent::Behaviour(BehaviourEvent::PeerRequest( request_response::Event::Message { message, .. }, )) => match message { request_response::Message::Request { - request, channel: _, .. + request, + channel: _, + .. } => { tracing::debug!("Received request: {:?}", &request); - } request_response::Message::Response { request_id, @@ -768,7 +780,6 @@ impl EventLoop { result, .. })) => { - tracing::debug!("Got Kad QueryProgressed: {:?}", result); match result { kad::QueryResult::GetProviders(Ok(kad::GetProvidersOk::FoundProviders { @@ -829,22 +840,14 @@ impl EventLoop { })) => { tracing::debug!("Kademlia Inbound Request: {:?}", request); match request { - InboundRequest::PutRecord { - source, - record, - .. - } => { + InboundRequest::PutRecord { source, record, .. } => { tracing::info!("Received PutRecordRequest from: {:?}", source); // TODO: Filter Providers based on criteria? // for now, add the provider to the DHT as is if let Some(rec) = record { - if let Err(e) = self - .swarm - .behaviour_mut() - .kad - .store_mut() - .put(rec.clone()) + if let Err(e) = + self.swarm.behaviour_mut().kad.store_mut().put(rec.clone()) { tracing::error!("Failed to add provider to DHT: {e}"); } @@ -853,9 +856,7 @@ impl EventLoop { // send evt to external handler plugins to decide whether to include record or not: if let Err(e) = self .event_sender - .send(PublicEvent::Swarm(Libp2pEvent::PutRecordRequest { - source, - })) + .send(PublicEvent::Swarm(Libp2pEvent::PutRecordRequest { source })) .await { tracing::error!("Failed to send PutRecordRequest event: {e}"); @@ -928,7 +929,7 @@ impl EventLoop { } } } - }, + } event => { tracing::debug!("Other type of event: {:?}", event); } @@ -1031,12 +1032,9 @@ impl EventLoop { .with(Protocol::P2p(*self.swarm.local_peer_id())); // emit as Event - if let Err(e) = self - .event_sender - .try_send(PublicEvent::ListenAddr { - address: p2p_addr.clone(), - }) - { + if let Err(e) = self.event_sender.try_send(PublicEvent::ListenAddr { + address: p2p_addr.clone(), + }) { tracing::error!("Failed to send share address event: {e}"); } } @@ -1082,7 +1080,8 @@ impl EventLoop { .swarm .behaviour_mut() .kad - .put_record(record, kad::Quorum::One) { + .put_record(record, kad::Quorum::One) + { tracing::error!("Failed to put record: {e}"); } } @@ -1104,4 +1103,3 @@ impl EventLoop { } } } - diff --git a/crates/comrade-component/src/bindings.rs b/crates/comrade-component/src/bindings.rs index 4079dd3..61b56a0 100644 --- a/crates/comrade-component/src/bindings.rs +++ b/crates/comrade-component/src/bindings.rs @@ -1213,9 +1213,7 @@ macro_rules! __export_wacc_impl { #[doc(inline)] pub(crate) use __export_wacc_impl as export; #[cfg(target_arch = "wasm32")] -#[unsafe( - link_section = "component-type:wit-bindgen:0.41.0:comrade:api:wacc:encoded world" -)] +#[unsafe(link_section = "component-type:wit-bindgen:0.41.0:comrade:api:wacc:encoded world")] #[doc(hidden)] #[allow(clippy::octal_escapes)] pub static __WIT_BINDGEN_COMPONENT_TYPE: [u8; 632] = *b"\ diff --git a/crates/multikey/Cargo.toml b/crates/multikey/Cargo.toml index 5dfd8f3..aef339c 100644 --- a/crates/multikey/Cargo.toml +++ b/crates/multikey/Cargo.toml @@ -16,7 +16,7 @@ wasm = ["getrandom/wasm_js"] # needed for CI testing on wasm32-unknown-unknown [dependencies] bcrypt-pbkdf = "0.10" -blsful = "2.5" +blsful.workspace = true chacha20poly1305 = "0.10.1" ed25519-dalek = { version = "2.1.1", features = ["rand_core"] } elliptic-curve.workspace = true diff --git a/crates/multikey/src/mk.rs b/crates/multikey/src/mk.rs index 0ad0fc2..61ac297 100644 --- a/crates/multikey/src/mk.rs +++ b/crates/multikey/src/mk.rs @@ -672,14 +672,17 @@ impl Builder { } }; let key_share = bls12381::KeyShare::try_from(key_bytes.as_ref())?; - let identifier: Vec = Varuint(key_share.0).into(); + let identifier: Vec = key_share.0 .0.to_be_bytes().to_vec(); let threshold: Vec = Varuint::(key_share.1.into()).into(); let limit: Vec = Varuint::(key_share.2.into()).into(); let mut attributes = Attributes::new(); attributes.insert(AttrId::ShareIdentifier, identifier.into()); attributes.insert(AttrId::Threshold, threshold.into()); attributes.insert(AttrId::Limit, limit.into()); - attributes.insert(AttrId::KeyData, key_share.3.into()); + attributes.insert( + AttrId::KeyData, + key_share.3 .0.to_be_bytes().to_vec().into(), + ); Ok(Builder { codec: Codec::Bls12381G1PubShare, comment: Some(sshkey.comment().to_string()), @@ -717,16 +720,19 @@ impl Builder { } }; let key_share = bls12381::KeyShare::try_from(key_bytes.as_ref())?; - let identifier: Vec = Varuint(key_share.0).into(); + let identifier: Vec = key_share.0 .0.to_be_bytes().to_vec(); let threshold: Vec = Varuint::(key_share.1.into()).into(); let limit: Vec = Varuint::(key_share.2.into()).into(); let mut attributes = Attributes::new(); attributes.insert(AttrId::ShareIdentifier, identifier.into()); attributes.insert(AttrId::Threshold, threshold.into()); attributes.insert(AttrId::Limit, limit.into()); - attributes.insert(AttrId::KeyData, key_share.3.into()); + attributes.insert( + AttrId::KeyData, + key_share.3 .0.to_be_bytes().to_vec().into(), + ); Ok(Builder { - codec: Codec::Bls12381G1PubShare, + codec: Codec::Bls12381G2PubShare, comment: Some(sshkey.comment().to_string()), attributes: Some(attributes), ..Default::default() @@ -887,14 +893,17 @@ impl Builder { } }; let key_share = bls12381::KeyShare::try_from(key_bytes.as_ref())?; - let identifier: Vec = Varuint(key_share.0).into(); + let identifier: Vec = key_share.0 .0.to_be_bytes().to_vec(); let threshold: Vec = Varuint::(key_share.1.into()).into(); let limit: Vec = Varuint::(key_share.2.into()).into(); let mut attributes = Attributes::new(); attributes.insert(AttrId::ShareIdentifier, identifier.into()); attributes.insert(AttrId::Threshold, threshold.into()); attributes.insert(AttrId::Limit, limit.into()); - attributes.insert(AttrId::KeyData, key_share.3.into()); + attributes.insert( + AttrId::KeyData, + key_share.3 .0.to_be_bytes().to_vec().into(), + ); Ok(Builder { codec: Codec::Bls12381G1PrivShare, comment: Some(sshkey.comment().to_string()), @@ -932,14 +941,17 @@ impl Builder { } }; let key_share = bls12381::KeyShare::try_from(key_bytes.as_ref())?; - let identifier: Vec = Varuint(key_share.0).into(); + let identifier: Vec = key_share.0 .0.to_be_bytes().to_vec(); let threshold: Vec = Varuint::(key_share.1.into()).into(); let limit: Vec = Varuint::(key_share.2.into()).into(); let mut attributes = Attributes::new(); attributes.insert(AttrId::ShareIdentifier, identifier.into()); attributes.insert(AttrId::Threshold, threshold.into()); attributes.insert(AttrId::Limit, limit.into()); - attributes.insert(AttrId::KeyData, key_share.3.into()); + attributes.insert( + AttrId::KeyData, + key_share.3 .0.to_be_bytes().to_vec().into(), + ); Ok(Builder { codec: Codec::Bls12381G2PrivShare, comment: Some(sshkey.comment().to_string()), @@ -1052,8 +1064,8 @@ impl Builder { } /// add in the share identifier value - pub fn with_identifier(self, identifier: u8) -> Self { - self.with_attribute(AttrId::ShareIdentifier, &Varuint(identifier).into()) + pub fn with_identifier(self, identifier: impl AsRef<[u8]>) -> Self { + self.with_attribute(AttrId::ShareIdentifier, &identifier.as_ref().to_vec()) } /// add in the threshold data diff --git a/crates/multikey/src/views.rs b/crates/multikey/src/views.rs index 60b28f0..f7f2afc 100644 --- a/crates/multikey/src/views.rs +++ b/crates/multikey/src/views.rs @@ -70,7 +70,7 @@ pub trait ThresholdAttrView { /// get the limit value for the multikey fn limit(&self) -> Result; /// get the share identifier for the multikey - fn identifier(&self) -> Result; + fn identifier(&self) -> Result<&[u8], Error>; /// get the codec-specific threshold data fn threshold_data(&self) -> Result<&[u8], Error>; } diff --git a/crates/multikey/src/views/bls12381.rs b/crates/multikey/src/views/bls12381.rs index e390234..5682ca6 100644 --- a/crates/multikey/src/views/bls12381.rs +++ b/crates/multikey/src/views/bls12381.rs @@ -8,8 +8,8 @@ use crate::{ KdfAttrView, Multikey, SignView, ThresholdAttrView, ThresholdView, VerifyView, Views, }; use blsful::{ - inner_types::{G1Projective, G2Projective}, - vsss_rs::Share, + inner_types::{G1Projective, G2Projective, Scalar}, + vsss_rs::{IdentifierPrimeField, Share, ValueGroup}, Bls12381G1Impl, Bls12381G2Impl, PublicKey, PublicKeyShare, SecretKey, SecretKeyShare, Signature, SignatureSchemes, SignatureShare, SECRET_KEY_BYTES, }; @@ -18,14 +18,17 @@ use multicodec::Codec; use multihash::{mh, Multihash}; use multisig::{ms, views::bls12381::SchemeTypeId, Multisig, Views as SigViews}; use multitrait::TryDecodeFrom; -use multiutil::{Varbytes, Varuint}; +use multiutil::Varuint; use ssh_encoding::{Decode, Encode}; use std::{ array::TryFromSliceError, collections::BTreeMap, num::{NonZero, NonZeroUsize}, }; -use zeroize::Zeroizing; +use zeroize::{Zeroize, Zeroizing}; + +/// ValuePrimeField is a type alias for IdentifierPrimeField in vsss_rs (scalar share value). +type ValuePrimeField = IdentifierPrimeField; /// the RFC 4251 algorithm name for SSH compatibility pub const ALGORITHM_NAME_G1: &str = "bls12_381-g1@multikey"; @@ -37,31 +40,59 @@ pub const ALGORITHM_NAME_G2_SHARE: &str = "bls12_381-g2-share@multikey"; pub const G1_PUBLIC_KEY_BYTES: usize = 48; pub const G2_PUBLIC_KEY_BYTES: usize = 96; +/// Parse 32 bytes to identifier for BLS key/sig shares. +fn bytes_to_identifier(bytes: &[u8]) -> Result, Error> { + let arr: [u8; SECRET_KEY_BYTES] = bytes.try_into().map_err(|_| { + Error::Conversions(ConversionsError::SecretKeyFailure( + "Invalid share identifier length".to_string(), + )) + })?; + Ok(IdentifierPrimeField( + Option::from(Scalar::from_be_bytes(&arr)).ok_or(Error::Conversions( + ConversionsError::SecretKeyFailure("Invalid share identifier bytes".to_string()), + ))?, + )) +} + +/// Parse 32 bytes to value (scalar) for BLS key shares. +fn bytes_to_value(bytes: &[u8]) -> Result, Error> { + let arr: [u8; SECRET_KEY_BYTES] = bytes.try_into().map_err(|_| { + Error::Conversions(ConversionsError::SecretKeyFailure( + "Invalid share value length".to_string(), + )) + })?; + Ok(IdentifierPrimeField( + Option::from(Scalar::from_be_bytes(&arr)).ok_or(Error::Conversions( + ConversionsError::SecretKeyFailure("Invalid share value bytes".to_string()), + ))?, + )) +} + /// tuple of the key share data with threshold attributes // TODO: this should be a struct with the share identifier, threshold, limit, and key bytes #[derive(Clone)] pub struct KeyShare( /// identifier - pub u8, + pub IdentifierPrimeField, /// threshold, pub NonZeroUsize, /// limit pub NonZeroUsize, /// key bytes - pub Vec, + pub ValuePrimeField, ); impl From for Vec { fn from(val: KeyShare) -> Self { let mut v = Vec::default(); // add in the share identifier - v.append(&mut Varuint(val.0).into()); + v.extend_from_slice(&val.0 .0.to_be_bytes()); // add in the threshold v.append(&mut Varuint::(val.1.into()).into()); // add in the limit v.append(&mut Varuint::(val.2.into()).into()); // add in the key share data - v.append(&mut Varbytes(val.3.clone()).into()); + v.extend_from_slice(&val.3 .0.to_be_bytes()); v } } @@ -80,21 +111,35 @@ impl<'a> TryDecodeFrom<'a> for KeyShare { fn try_decode_from(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), Self::Error> { // try to decode the identifier - let (id, ptr) = Varuint::::try_decode_from(bytes)?; + let (id, ptr) = Varuint::<[u8; 32]>::try_decode_from(bytes)?; // try to decode the threshold let (threshold, ptr) = Varuint::::try_decode_from(ptr)?; // try to decode the limit let (limit, ptr) = Varuint::::try_decode_from(ptr)?; // try to decode the key share data - let (key_data, ptr) = Varbytes::try_decode_from(ptr)?; + let (key_data, ptr) = Varuint::<[u8; 32]>::try_decode_from(ptr)?; + + let identifier = IdentifierPrimeField( + Option::::from(Scalar::from_be_bytes(&id.0)).ok_or(Error::Conversions( + ConversionsError::SecretKeyFailure("Invalid share identifier bytes".to_string()), + ))?, + ); + let value = IdentifierPrimeField( + Option::::from(Scalar::from_be_bytes(&key_data.0)).ok_or( + Error::Conversions(ConversionsError::SecretKeyFailure( + "Invalid share value bytes".to_string(), + )), + )?, + ); + Ok(( Self( - id.to_inner(), + identifier, NonZero::new(threshold.clone().to_inner()) .ok_or(Error::Threshold(ThresholdError::MustBeNonZero(*threshold)))?, NonZero::new(limit.clone().to_inner()) .ok_or(Error::Threshold(ThresholdError::MustBeNonZero(*limit)))?, - key_data.to_inner(), + value, ), ptr, )) @@ -102,7 +147,7 @@ impl<'a> TryDecodeFrom<'a> for KeyShare { } #[derive(Clone, Default)] -pub(crate) struct ThresholdData(pub(crate) BTreeMap); +pub(crate) struct ThresholdData(pub(crate) BTreeMap, KeyShare>); impl From for Vec { fn from(val: ThresholdData) -> Self { @@ -110,9 +155,11 @@ impl From for Vec { // add in the number of key shares v.append(&mut Varuint(val.0.len()).into()); // add in the key shares - val.0.iter().for_each(|(_, share)| { - v.append(&mut share.clone().into()); - }); + val.0 + .iter() + .for_each(|(_id, share): (&IdentifierPrimeField, &KeyShare)| { + v.append(&mut share.clone().into()); + }); v } } @@ -216,13 +263,13 @@ impl ThresholdAttrView for View<'_> { Ok(NonZero::new(*Varuint::::try_from(v.as_slice())?).unwrap()) } /// get the share identifier for the multikey - fn identifier(&self) -> Result { + fn identifier(&self) -> Result<&[u8], Error> { let v = self .mk .attributes .get(&AttrId::ShareIdentifier) .ok_or(AttributesError::MissingShareIdentifier)?; - Ok(*Varuint::::try_from(v.as_slice())?) + Ok(v.as_slice()) } /// get the threshold data fn threshold_data(&self) -> Result<&[u8], Error> { @@ -382,23 +429,61 @@ impl ConvView for View<'_> { let av = self.mk.threshold_attr_view()?; let threshold = av.threshold()?; let limit = av.limit()?; - let identifier = av.identifier()?; + let identifier_bytes = av.identifier()?; + if identifier_bytes.len() != SECRET_KEY_BYTES { + return Err(Error::Conversions(ConversionsError::SecretKeyFailure( + "Insufficient number of bytes for secret share identifier".to_string(), + ))); + } + let identifier_array = <[u8; SECRET_KEY_BYTES]>::try_from(identifier_bytes) + .map_err(|_| { + Error::Conversions(ConversionsError::SecretKeyFailure( + "Invalid bytes for secret share identifier".to_string(), + )) + })?; + let identifier = IdentifierPrimeField( + Option::::from(Scalar::from_be_bytes(&identifier_array)).ok_or( + Error::Conversions(ConversionsError::SecretKeyFailure( + "Invalid bytes for secret share identifier".to_string(), + )), + )?, + ); + + if secret_bytes.len() != SECRET_KEY_BYTES { + return Err(Error::Conversions(ConversionsError::SecretKeyFailure( + "Insufficient number of bytes for secret share".to_string(), + ))); + } + let mut secret_array = <[u8; SECRET_KEY_BYTES]>::try_from(secret_bytes.as_slice()) + .map_err(|_| { + Error::Conversions(ConversionsError::SecretKeyFailure( + "Invalid bytes for secret share".to_string(), + )) + })?; - let secret_key: SecretKeyShare = SecretKeyShare( - Share::with_identifier_and_value(identifier, secret_bytes.as_slice()), + let secret = IdentifierPrimeField( + Option::::from(Scalar::from_be_bytes(&secret_array)).ok_or( + Error::Conversions(ConversionsError::SecretKeyFailure( + "Invalid bytes for secret share".to_string(), + )), + )?, ); + secret_array.zeroize(); + + let secret_key: SecretKeyShare = + SecretKeyShare(Share::with_identifier_and_value(identifier, secret)); // get the public key and build a Multikey out of it let public_key = secret_key .public_key() .map_err(|e| ConversionsError::PublicKeyFailure(e.to_string()))?; - let key_bytes = public_key.0 .0.value_vec(); + let key_bytes = public_key.0 .0.value.0.to_compressed(); Builder::new(Codec::Bls12381G1PubShare) .with_comment(&self.mk.comment) .with_key_bytes(&key_bytes) .with_threshold(threshold) .with_limit(limit) - .with_identifier(identifier) + .with_identifier(public_key.0 .0.identifier.0.to_be_bytes()) .try_build() } Codec::Bls12381G2Priv => { @@ -427,23 +512,56 @@ impl ConvView for View<'_> { let av = self.mk.threshold_attr_view()?; let threshold = av.threshold()?; let limit = av.limit()?; - let identifier = av.identifier()?; + let identifier_bytes = av.identifier()?; + let identifier_array = <[u8; SECRET_KEY_BYTES]>::try_from(identifier_bytes) + .map_err(|_| { + Error::Conversions(ConversionsError::SecretKeyFailure( + "Invalid bytes for secret share identifier".to_string(), + )) + })?; + let identifier = IdentifierPrimeField( + Option::::from(Scalar::from_be_bytes(&identifier_array)).ok_or( + Error::Conversions(ConversionsError::SecretKeyFailure( + "Invalid bytes for secret share identifier".to_string(), + )), + )?, + ); + + if secret_bytes.len() != SECRET_KEY_BYTES { + return Err(Error::Conversions(ConversionsError::SecretKeyFailure( + "Insufficient number of bytes for secret share".to_string(), + ))); + } + let mut secret_array = <[u8; SECRET_KEY_BYTES]>::try_from(secret_bytes.as_slice()) + .map_err(|_| { + Error::Conversions(ConversionsError::SecretKeyFailure( + "Invalid bytes for secret share".to_string(), + )) + })?; - let secret_key: SecretKeyShare = SecretKeyShare( - Share::with_identifier_and_value(identifier, secret_bytes.as_slice()), + let secret = IdentifierPrimeField( + Option::::from(Scalar::from_be_bytes(&secret_array)).ok_or( + Error::Conversions(ConversionsError::SecretKeyFailure( + "Invalid bytes for secret share".to_string(), + )), + )?, ); + secret_array.zeroize(); + + let secret_key: SecretKeyShare = + SecretKeyShare(Share::with_identifier_and_value(identifier, secret)); // get the public key and build a Multikey out of it let public_key = secret_key .public_key() .map_err(|e| ConversionsError::PublicKeyFailure(e.to_string()))?; - let key_bytes = public_key.0 .0.value_vec(); + let key_bytes = public_key.0 .0.value.0.to_compressed(); Builder::new(Codec::Bls12381G1PubShare) .with_comment(&self.mk.comment) .with_key_bytes(&key_bytes) .with_threshold(threshold) .with_limit(limit) - .with_identifier(identifier) + .with_identifier(public_key.0 .0.identifier.0.to_be_bytes()) .try_build() } _ => Err(ConversionsError::UnsupportedCodec(self.mk.codec).into()), @@ -475,10 +593,10 @@ impl ConvView for View<'_> { Codec::Bls12381G1PubShare => { let tav = pk.threshold_attr_view()?; let key_share: Vec = KeyShare( - tav.identifier()?, + bytes_to_identifier(tav.identifier()?)?, tav.threshold()?, tav.limit()?, - key_bytes.to_vec(), + bytes_to_value(key_bytes.as_slice())?, ) .into(); key_share @@ -495,10 +613,10 @@ impl ConvView for View<'_> { Codec::Bls12381G2PubShare => { let tav = pk.threshold_attr_view()?; let key_share: Vec = KeyShare( - tav.identifier()?, + bytes_to_identifier(tav.identifier()?)?, tav.threshold()?, tav.limit()?, - key_bytes.to_vec(), + bytes_to_value(key_bytes.as_slice())?, ) .into(); key_share @@ -555,18 +673,18 @@ impl ConvView for View<'_> { Codec::Bls12381G1PrivShare => { let sav = self.mk.threshold_attr_view()?; let secret_key_share: Vec = KeyShare( - sav.identifier()?, + bytes_to_identifier(sav.identifier()?)?, sav.threshold()?, sav.limit()?, - secret_bytes.to_vec(), + bytes_to_value(secret_bytes.as_slice())?, ) .into(); let pav = pk.threshold_attr_view()?; let public_key_share: Vec = KeyShare( - pav.identifier()?, + bytes_to_identifier(pav.identifier()?)?, pav.threshold()?, pav.limit()?, - key_bytes.to_vec(), + bytes_to_value(key_bytes.as_slice())?, ) .into(); secret_key_share @@ -589,18 +707,18 @@ impl ConvView for View<'_> { Codec::Bls12381G2PrivShare => { let sav = self.mk.threshold_attr_view()?; let secret_key_share: Vec = KeyShare( - sav.identifier()?, + bytes_to_identifier(sav.identifier()?)?, sav.threshold()?, sav.limit()?, - secret_bytes.to_vec(), + bytes_to_value(secret_bytes.as_slice())?, ) .into(); let pav = pk.threshold_attr_view()?; let public_key_share: Vec = KeyShare( - pav.identifier()?, + bytes_to_identifier(pav.identifier()?)?, pav.threshold()?, pav.limit()?, - key_bytes.to_vec(), + bytes_to_value(key_bytes.as_slice())?, ) .into(); secret_key_share @@ -689,11 +807,11 @@ impl SignView for View<'_> { let av = self.mk.threshold_attr_view()?; let threshold = av.threshold()?; let limit = av.limit()?; - let identifier = av.identifier()?; + let identifier = bytes_to_identifier(av.identifier()?)?; + let secret_value = bytes_to_value(secret_bytes.as_slice())?; - let secret_key: SecretKeyShare = SecretKeyShare( - Share::with_identifier_and_value(identifier, secret_bytes.as_slice()), - ); + let secret_key: SecretKeyShare = + SecretKeyShare(Share::with_identifier_and_value(identifier, secret_value)); // sign the data let signature = secret_key @@ -736,11 +854,11 @@ impl SignView for View<'_> { let av = self.mk.threshold_attr_view()?; let threshold = av.threshold()?; let limit = av.limit()?; - let identifier = av.identifier()?; + let identifier = bytes_to_identifier(av.identifier()?)?; + let secret_value = bytes_to_value(secret_bytes.as_slice())?; - let secret_key: SecretKeyShare = SecretKeyShare( - Share::with_identifier_and_value(identifier, secret_bytes.as_slice()), - ); + let secret_key: SecretKeyShare = + SecretKeyShare(Share::with_identifier_and_value(identifier, secret_value)); // sign the data let signature = secret_key @@ -801,8 +919,9 @@ impl ThresholdView for View<'_> { key_shares .iter() .try_for_each(|share| -> Result<(), Error> { - let key_bytes = share.as_raw_value().value_vec(); - let identifier = share.as_raw_value().identifier(); + let raw = share.as_raw_value(); + let key_bytes = raw.value().0.to_be_bytes(); + let identifier = raw.identifier().0.to_be_bytes(); let mk = Builder::new(Codec::Bls12381G1PrivShare) .with_comment(&self.mk.comment) @@ -841,8 +960,9 @@ impl ThresholdView for View<'_> { key_shares .iter() .try_for_each(|share| -> Result<(), Error> { - let key_bytes = share.as_raw_value().value_vec(); - let identifier = share.as_raw_value().identifier(); + let raw = share.as_raw_value(); + let key_bytes = raw.value().0.to_be_bytes(); + let identifier = raw.identifier().0.to_be_bytes(); let mk = Builder::new(Codec::Bls12381G2PrivShare) .with_comment(&self.mk.comment) @@ -879,7 +999,7 @@ impl ThresholdView for View<'_> { let (key_share, identifier, threshold, limit) = { // get the share attributes let av = share.threshold_attr_view()?; - let identifier = av.identifier()?; + let identifier = bytes_to_identifier(av.identifier()?)?; let threshold = av.threshold()?; let limit = av.limit()?; // get the key data @@ -887,7 +1007,12 @@ impl ThresholdView for View<'_> { let key_bytes = dv.key_bytes()?; // return the data ( - KeyShare(identifier, threshold, limit, key_bytes.to_vec()), + KeyShare( + identifier, + threshold, + limit, + bytes_to_value(key_bytes.as_slice())?, + ), identifier, threshold, limit, @@ -905,7 +1030,7 @@ impl ThresholdView for View<'_> { tdata.into() }; - // if this multikey doesn't already have the threshold/limi set, then + // if this multikey doesn't already have the threshold/limit set, then // set it to match the values from the first share let av = share.threshold_attr_view()?; let threshold = av.threshold().unwrap_or(threshold); @@ -951,7 +1076,7 @@ impl ThresholdView for View<'_> { .0 .iter() .try_for_each(|(id, share)| -> Result<(), Error> { - let vsss = Share::with_identifier_and_value(*id, share.3.as_slice()); + let vsss = Share::with_identifier_and_value(*id, share.3); shares.push(SecretKeyShare::(vsss)); Ok(()) })?; @@ -969,7 +1094,7 @@ impl ThresholdView for View<'_> { .0 .iter() .try_for_each(|(id, share)| -> Result<(), Error> { - let vsss = Share::with_identifier_and_value(*id, share.3.as_slice()); + let vsss = Share::with_identifier_and_value(*id, share.3); shares.push(SecretKeyShare::(vsss)); Ok(()) })?; @@ -1059,13 +1184,24 @@ impl VerifyView for View<'_> { // get the share identifier let av = multisig.threshold_attr_view()?; - let identifier = av.identifier()?; + let identifier = bytes_to_identifier(av.identifier()?)?; // get the signature data let sv = multisig.data_view()?; - let value = sv.sig_bytes().map_err(|_| VerifyError::MissingSignature)?; + let value_bytes = sv.sig_bytes().map_err(|_| VerifyError::MissingSignature)?; + let value = { + let arr: [u8; G1_PUBLIC_KEY_BYTES] = value_bytes + .as_slice() + .try_into() + .map_err(|e: TryFromSliceError| VerifyError::BadSignature(e.to_string()))?; + Option::from(G1Projective::from_compressed(&arr)).ok_or( + VerifyError::BadSignature( + "failed to deserialize signature share".to_string(), + ), + )? + }; - let share = Share::with_identifier_and_value(identifier, &value); + let share = Share::with_identifier_and_value(identifier, ValueGroup(value)); let sig = match sig_scheme { SchemeTypeId::Basic => SignatureShare::::Basic(share), @@ -1139,21 +1275,32 @@ impl VerifyView for View<'_> { // get the share identifier let av = multisig.threshold_attr_view()?; - let identifier = av.identifier()?; + let identifier = bytes_to_identifier(av.identifier()?)?; // get the signature data let sv = multisig.data_view()?; - let value = sv.sig_bytes().map_err(|_| VerifyError::MissingSignature)?; + let value_bytes = sv.sig_bytes().map_err(|_| VerifyError::MissingSignature)?; + let value = { + let arr: [u8; G2_PUBLIC_KEY_BYTES] = value_bytes + .as_slice() + .try_into() + .map_err(|e: TryFromSliceError| VerifyError::BadSignature(e.to_string()))?; + Option::from(G2Projective::from_compressed(&arr)).ok_or( + VerifyError::BadSignature( + "failed to deserialize signature share".to_string(), + ), + )? + }; - let share = Share::with_identifier_and_value(identifier, &value); + let share = Share::with_identifier_and_value(identifier, ValueGroup(value)); let sig = match sig_scheme { - SchemeTypeId::Basic => SignatureShare::::Basic(share), + SchemeTypeId::Basic => SignatureShare::::Basic(share), SchemeTypeId::MessageAugmentation => { - SignatureShare::::MessageAugmentation(share) + SignatureShare::::MessageAugmentation(share) } SchemeTypeId::ProofOfPossession => { - SignatureShare::::ProofOfPossession(share) + SignatureShare::::ProofOfPossession(share) } }; diff --git a/crates/multisig/Cargo.toml b/crates/multisig/Cargo.toml index fc98424..f3e05f2 100644 --- a/crates/multisig/Cargo.toml +++ b/crates/multisig/Cargo.toml @@ -11,7 +11,7 @@ license = "Apache-2.0" default = ["serde"] [dependencies] -blsful = { version = "2.5.7" } +blsful.workspace = true elliptic-curve.workspace = true multibase.workspace = true multicodec.workspace = true diff --git a/crates/multisig/src/ms.rs b/crates/multisig/src/ms.rs index 1701651..a8c1288 100644 --- a/crates/multisig/src/ms.rs +++ b/crates/multisig/src/ms.rs @@ -7,7 +7,11 @@ use crate::{ }, AttrId, AttrView, ConvView, DataView, Error, ThresholdAttrView, ThresholdView, Views, }; -use blsful::{inner_types::GroupEncoding, vsss_rs::Share, Signature, SignatureShare}; +use blsful::{ + inner_types::{GroupEncoding, PrimeField}, + vsss_rs::Share, + Signature, SignatureShare, +}; use multibase::Base; use multicodec::Codec; use multitrait::{Null, TryDecodeFrom}; @@ -19,7 +23,7 @@ pub const SIG_CODECS: [Codec; 5] = [ Codec::Bls12381G1Msig, Codec::Bls12381G2Msig, Codec::EddsaMsig, - Codec::Es256Msig, // P-256 (WebAuthn/passkey signatures) + Codec::Es256Msig, // P-256 (WebAuthn/passkey signatures) // Codec::Es384Msig, // Codec::Es521Msig, // Codec::Rs256Msig, @@ -300,7 +304,7 @@ impl Builder { } bls12381::ALGORITHM_NAME_G1_SHARE => { let sig_share = bls12381::SigShare::try_from(sig.as_bytes())?; - attributes.insert(AttrId::ShareIdentifier, Varuint(sig_share.0).into()); + attributes.insert(AttrId::ShareIdentifier, sig_share.0 .0.to_be_bytes().into()); attributes.insert(AttrId::Threshold, Varuint(sig_share.1).into()); attributes.insert(AttrId::Limit, Varuint(sig_share.2).into()); attributes.insert(AttrId::Scheme, sig_share.3.into()); @@ -313,7 +317,7 @@ impl Builder { } bls12381::ALGORITHM_NAME_G2_SHARE => { let sig_share = bls12381::SigShare::try_from(sig.as_bytes())?; - attributes.insert(AttrId::ShareIdentifier, Varuint(sig_share.0).into()); + attributes.insert(AttrId::ShareIdentifier, sig_share.0 .0.to_be_bytes().into()); attributes.insert(AttrId::Threshold, Varuint(sig_share.1).into()); attributes.insert(AttrId::Limit, Varuint(sig_share.2).into()); attributes.insert(AttrId::Scheme, sig_share.3.into()); @@ -337,7 +341,6 @@ impl Builder { { let scheme_type_id = SchemeTypeId::from(sig); let sig_bytes: Vec = sig.as_raw_value().to_bytes().as_ref().to_vec(); - println!("signature length: {}", sig_bytes.len()); let codec = match sig_bytes.len() { 48 => Codec::Bls12381G1Msig, // G1Projective::to_compressed() 96 => Codec::Bls12381G2Msig, // G2Projective::to_compressed() @@ -368,8 +371,8 @@ impl Builder { { let scheme_type_id = SchemeTypeId::from(sigshare); let sigshare = sigshare.as_raw_value(); - let identifier = sigshare.identifier(); - let value = sigshare.value_vec(); + let identifier = sigshare.identifier().0.to_repr().as_ref().to_vec(); + let value = sigshare.value().0.to_bytes().as_ref().to_vec(); let codec = match value.len() { 48 => Codec::Bls12381G1ShareMsig, // large pubkeys, small signatures 96 => Codec::Bls12381G2ShareMsig, // small pubkeys, large signatures @@ -381,9 +384,9 @@ impl Builder { }; let mut attributes = BTreeMap::new(); attributes.insert(AttrId::SigData, value); - attributes.insert(AttrId::Threshold, Varuint::(threshold.into()).into()); - attributes.insert(AttrId::Limit, Varuint::(limit.into()).into()); - attributes.insert(AttrId::ShareIdentifier, Varuint(identifier).into()); + attributes.insert(AttrId::Threshold, Varuint::(threshold.get()).into()); + attributes.insert(AttrId::Limit, Varuint::(limit.get()).into()); + attributes.insert(AttrId::ShareIdentifier, identifier); attributes.insert(AttrId::Scheme, scheme_type_id.into()); Ok(Self { codec, @@ -438,8 +441,8 @@ impl Builder { } /// add the threshold signature identifier - pub fn with_identifier(self, identifier: u8) -> Self { - self.with_attribute(AttrId::ShareIdentifier, &Varuint(identifier).into()) + pub fn with_identifier(self, identifier: &impl AsRef<[u8]>) -> Self { + self.with_attribute(AttrId::ShareIdentifier, &identifier.as_ref().to_vec()) } /// add the threshold data diff --git a/crates/multisig/src/views.rs b/crates/multisig/src/views.rs index c8f3771..eaf533b 100644 --- a/crates/multisig/src/views.rs +++ b/crates/multisig/src/views.rs @@ -41,7 +41,7 @@ pub trait ThresholdAttrView { /// get the limit value for this multisig share fn limit(&self) -> Result; /// get the identifier value for this multisig share - fn identifier(&self) -> Result; + fn identifier(&self) -> Result<&[u8], Error>; /// get the threshold data associated with the signature fn threshold_data(&self) -> Result<&[u8], Error>; } diff --git a/crates/multisig/src/views/bls12381.rs b/crates/multisig/src/views/bls12381.rs index f476402..e6534db 100644 --- a/crates/multisig/src/views/bls12381.rs +++ b/crates/multisig/src/views/bls12381.rs @@ -5,7 +5,9 @@ use crate::{ ThresholdView, Views, }; use blsful::{ - vsss_rs::Share, Bls12381G1Impl, Bls12381G2Impl, Signature, SignatureSchemes, SignatureShare, + inner_types::{G1Projective, G2Projective, Scalar}, + vsss_rs::{IdentifierPrimeField, Share, ValueGroup}, + Bls12381G1Impl, Bls12381G2Impl, Signature, SignatureSchemes, SignatureShare, }; use multicodec::Codec; use multitrait::{EncodeInto, TryDecodeFrom}; @@ -203,7 +205,7 @@ impl<'a> TryDecodeFrom<'a> for SigCombined { #[derive(Clone)] pub struct SigShare( /// identifier - pub u8, + pub IdentifierPrimeField, /// threshold pub usize, /// limit @@ -218,7 +220,7 @@ impl From for Vec { fn from(val: SigShare) -> Self { let mut v = Vec::default(); // add in the share identifier - v.append(&mut Varuint(val.0).into()); + v.append(&mut val.0 .0.to_be_bytes().into()); // add in the share threshold v.append(&mut Varuint(val.1).into()); // add in the share limit @@ -245,7 +247,10 @@ impl<'a> TryDecodeFrom<'a> for SigShare { fn try_decode_from(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), Self::Error> { // try to decode the identifier - let (id, ptr) = Varuint::::try_decode_from(bytes)?; + let (id_bytes, ptr) = Varuint::<[u8; 32]>::try_decode_from(bytes)?; + let id = Option::::from(Scalar::from_be_bytes(&id_bytes)).ok_or( + Error::FailedConversion("Can't convert identifier to scalar".to_string()), + )?; // try to decode the threshold let (threshold, ptr) = Varuint::::try_decode_from(ptr)?; // try to decode the limit @@ -256,7 +261,7 @@ impl<'a> TryDecodeFrom<'a> for SigShare { let (share_data, ptr) = Varbytes::try_decode_from(ptr)?; Ok(( Self( - id.to_inner(), + IdentifierPrimeField(id), threshold.to_inner(), limit.to_inner(), share_type, @@ -268,7 +273,7 @@ impl<'a> TryDecodeFrom<'a> for SigShare { } #[derive(Clone, Default)] -pub(crate) struct ThresholdData(pub(crate) BTreeMap); +pub(crate) struct ThresholdData(pub(crate) BTreeMap, SigShare>); impl From for Vec { fn from(val: ThresholdData) -> Self { @@ -410,11 +415,28 @@ impl ConvView for View<'_> { let av = self.ms.threshold_attr_view()?; let threshold = av.threshold()?; let limit = av.limit()?; - let identifier = av.identifier()?; + let identifier_bytes = av.identifier()?; + if identifier_bytes.len() != 32 { + return Err(Error::FailedConversion( + "Insufficient identifier bytes".to_string(), + )); + } + let identifier_array = <[u8; 32]>::try_from(identifier_bytes) + .map_err(|_| Error::FailedConversion("Invalid bytes".to_string()))?; + let id_scalar = Option::::from(Scalar::from_be_bytes(&identifier_array)) + .ok_or(Error::FailedConversion( + "Invalid share identifier bytes".to_string(), + ))?; // create the sig share tuple - let sig_data: Vec = - SigShare(identifier, threshold, limit, scheme_type, sig_bytes).into(); + let sig_data: Vec = SigShare( + IdentifierPrimeField(id_scalar), + threshold, + limit, + scheme_type, + sig_bytes, + ) + .into(); Ok(ssh_key::Signature::new( ssh_key::Algorithm::Other( @@ -430,11 +452,28 @@ impl ConvView for View<'_> { let av = self.ms.threshold_attr_view()?; let threshold = av.threshold()?; let limit = av.limit()?; - let identifier = av.identifier()?; + let identifier_bytes = av.identifier()?; + if identifier_bytes.len() != 32 { + return Err(Error::FailedConversion( + "Insufficient identifier bytes".to_string(), + )); + } + let identifier_array = <[u8; 32]>::try_from(identifier_bytes) + .map_err(|_| Error::FailedConversion("Invalid bytes".to_string()))?; + let id_scalar = Option::::from(Scalar::from_be_bytes(&identifier_array)) + .ok_or(Error::FailedConversion( + "Invalid share identifier bytes".to_string(), + ))?; // create the sig share tuple - let sig_data: Vec = - SigShare(identifier, threshold, limit, scheme_type, sig_bytes).into(); + let sig_data: Vec = SigShare( + IdentifierPrimeField(id_scalar), + threshold, + limit, + scheme_type, + sig_bytes, + ) + .into(); Ok(ssh_key::Signature::new( ssh_key::Algorithm::Other( @@ -470,7 +509,7 @@ impl ThresholdAttrView for View<'_> { Ok(Varuint::::try_from(limit.as_slice())?.to_inner()) } /// get the share identifier - fn identifier(&self) -> Result { + fn identifier(&self) -> Result<&[u8], Error> { match self.ms.codec { Codec::Bls12381G1ShareMsig | Codec::Bls12381G2ShareMsig => { let identifier = self @@ -478,7 +517,7 @@ impl ThresholdAttrView for View<'_> { .attributes .get(&AttrId::ShareIdentifier) .ok_or(AttributesError::MissingIdentifier)?; - Ok(Varuint::::try_from(identifier.as_slice())?.to_inner()) + Ok(identifier.as_slice()) } _ => Err(SharesError::NotASignatureShare.into()), } @@ -533,7 +572,7 @@ impl ThresholdView for View<'_> { // and the payload encoding value let share = Builder::new(codec) .with_message_bytes(&self.ms.message.as_slice()) - .with_identifier(share.0) + .with_identifier(&share.0 .0.to_be_bytes()) .with_threshold(share.1) .with_limit(share.2) .with_signature_bytes(&share.4) @@ -566,7 +605,19 @@ impl ThresholdView for View<'_> { let av = share.threshold_attr_view()?; let threshold = av.threshold()?; let limit = av.limit()?; - let identifier = av.identifier()?; + let identifier_bytes = av.identifier()?; + if identifier_bytes.len() != 32 { + return Err(Error::FailedConversion( + "Insufficient number of identifier bytes".to_string(), + )); + } + let identifier_array = <[u8; 32]>::try_from(identifier_bytes) + .map_err(|_| Error::FailedConversion("Incorrect identifier bytes".to_string()))?; + let identifier = IdentifierPrimeField( + Option::::from(Scalar::from_be_bytes(&identifier_array)).ok_or( + Error::FailedConversion("Incorrect identifier bytes".to_string()), + )?, + ); // get the share's signature data let dv = share.data_view()?; @@ -654,8 +705,11 @@ impl ThresholdView for View<'_> { .0 .iter() .try_for_each(|(id, share)| -> Result<(), Error> { - let vsss = Share::with_identifier_and_value(*id, share.4.as_slice()); - // check to make sure all of the shares are of the same type + let inner = G1Projective::try_from(&share.4).map_err(|_| { + Error::FailedConversion("Invalid signature share bytes".to_string()) + })?; + let vsss = Share::with_identifier_and_value(*id, ValueGroup(inner)); + // check to make sure all shares are of the same type if let Some(sti) = share_type_id { if sti != share.3 { return Err(SharesError::ShareTypeMismatch.into()); @@ -694,8 +748,11 @@ impl ThresholdView for View<'_> { .0 .iter() .try_for_each(|(id, share)| -> Result<(), Error> { - let vsss = Share::with_identifier_and_value(*id, share.4.as_slice()); - // check to make sure all of the shares are of the same type + let inner = G2Projective::try_from(&share.4).map_err(|_| { + Error::FailedConversion("Invalid signature share bytes".to_string()) + })?; + let vsss = Share::with_identifier_and_value(*id, ValueGroup(inner)); + // check to make sure all shares are of the same type if let Some(sti) = share_type_id { if sti != share.3 { return Err(SharesError::ShareTypeMismatch.into()); diff --git a/crates/multitrait/src/try_decode_from.rs b/crates/multitrait/src/try_decode_from.rs index 343fb9f..58c9268 100644 --- a/crates/multitrait/src/try_decode_from.rs +++ b/crates/multitrait/src/try_decode_from.rs @@ -76,3 +76,16 @@ impl<'a> TryDecodeFrom<'a> for usize { decode::usize(bytes).map_err(Self::Error::UnsignedVarintDecode) } } + +impl TryDecodeFrom<'_> for [u8; N] { + type Error = Error; + + fn try_decode_from(bytes: &'_ [u8]) -> Result<([u8; N], &'_ [u8]), Self::Error> { + if bytes.len() < 32 { + return Err(Error::UnsignedVarintDecode(decode::Error::Overflow)); + } + let a = <[u8; N]>::try_from(bytes) + .map_err(|_| Self::Error::UnsignedVarintDecode(decode::Error::Insufficient))?; + Ok((a, &bytes[32..])) + } +}