use crate::{
error::{AttributesError, ConversionsError, SharesError},
views::threshold_meta::{self, ThresholdDisclosure},
AttrId, AttrView, Builder, ConvView, DataView, Error, Multisig, ThresholdAttrView,
ThresholdView, Views,
};
use blsful::{
inner_types::{G1Projective, G2Projective, Scalar},
vsss_rs::{IdentifierPrimeField, Share, ValueGroup},
Bls12381G1Impl, Bls12381G2Impl, Signature, SignatureSchemes, SignatureShare,
};
use multi_codec::Codec;
use multi_trait::{EncodeInto, TryDecodeFrom};
use multi_util::{Varbytes, Varuint};
use std::{collections::BTreeMap, fmt};
pub const ALGORITHM_NAME_G1: &str = "bls12_381-g1@multisig";
pub const ALGORITHM_NAME_G1_SHARE: &str = "bls12_381-g1-share@multisig";
pub const ALGORITHM_NAME_G2: &str = "bls12_381-g2@multisig";
pub const ALGORITHM_NAME_G2_SHARE: &str = "bls12_381-g2-share@multisig";
#[repr(u8)]
#[derive(Clone, Copy, Default, Hash, Ord, PartialOrd, PartialEq, Eq)]
pub enum SchemeTypeId {
Basic,
MessageAugmentation,
#[default]
ProofOfPossession,
}
impl SchemeTypeId {
pub fn code(&self) -> u8 {
(*self).into()
}
pub fn as_str(&self) -> &str {
match self {
Self::Basic => "basic",
Self::MessageAugmentation => "message-augmentation",
Self::ProofOfPossession => "proof-of-possession",
}
}
}
impl From<SchemeTypeId> for u8 {
fn from(val: SchemeTypeId) -> Self {
val as u8
}
}
impl TryFrom<u8> for SchemeTypeId {
type Error = Error;
fn try_from(c: u8) -> Result<Self, Self::Error> {
match c {
0 => Ok(Self::Basic),
1 => Ok(Self::MessageAugmentation),
2 => Ok(Self::ProofOfPossession),
_ => Err(SharesError::InvalidSchemeTypeId(c).into()),
}
}
}
impl From<SchemeTypeId> for SignatureSchemes {
fn from(val: SchemeTypeId) -> Self {
match val {
SchemeTypeId::Basic => SignatureSchemes::Basic,
SchemeTypeId::MessageAugmentation => SignatureSchemes::MessageAugmentation,
SchemeTypeId::ProofOfPossession => SignatureSchemes::ProofOfPossession,
}
}
}
impl From<&SignatureSchemes> for SchemeTypeId {
fn from(s: &SignatureSchemes) -> Self {
match s {
SignatureSchemes::Basic => SchemeTypeId::Basic,
SignatureSchemes::MessageAugmentation => SchemeTypeId::MessageAugmentation,
SignatureSchemes::ProofOfPossession => SchemeTypeId::ProofOfPossession,
}
}
}
impl<C> From<&Signature<C>> for SchemeTypeId
where
C: blsful::BlsSignatureImpl,
{
fn from(s: &Signature<C>) -> Self {
match s {
Signature::Basic(_) => SchemeTypeId::Basic,
Signature::MessageAugmentation(_) => SchemeTypeId::MessageAugmentation,
Signature::ProofOfPossession(_) => SchemeTypeId::ProofOfPossession,
}
}
}
impl<C> From<&SignatureShare<C>> for SchemeTypeId
where
C: blsful::BlsSignatureImpl,
{
fn from(s: &SignatureShare<C>) -> Self {
match s {
SignatureShare::Basic(_) => SchemeTypeId::Basic,
SignatureShare::MessageAugmentation(_) => SchemeTypeId::MessageAugmentation,
SignatureShare::ProofOfPossession(_) => SchemeTypeId::ProofOfPossession,
}
}
}
impl From<SchemeTypeId> for Vec<u8> {
fn from(val: SchemeTypeId) -> Self {
val.code().encode_into()
}
}
impl<'a> TryFrom<&'a [u8]> for SchemeTypeId {
type Error = Error;
fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
let (id, _) = Self::try_decode_from(bytes)?;
Ok(id)
}
}
impl<'a> TryDecodeFrom<'a> for SchemeTypeId {
type Error = Error;
fn try_decode_from(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), Self::Error> {
let (code, ptr) = u8::try_decode_from(bytes)?;
Ok((Self::try_from(code)?, ptr))
}
}
impl TryFrom<&str> for SchemeTypeId {
type Error = Error;
fn try_from(s: &str) -> Result<Self, Self::Error> {
match s.to_ascii_lowercase().as_str() {
"basic" => Ok(Self::Basic),
"message-augmentation" => Ok(Self::MessageAugmentation),
"proof-of-possession" => Ok(Self::ProofOfPossession),
_ => Err(SharesError::InvalidShareTypeName(s.to_string()).into()),
}
}
}
impl fmt::Display for SchemeTypeId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[derive(Clone)]
pub struct SigCombined(
pub SchemeTypeId,
pub Vec<u8>,
);
impl From<SigCombined> for Vec<u8> {
fn from(val: SigCombined) -> Self {
let mut v = Vec::default();
v.append(&mut val.0.into());
v.append(&mut Varbytes::new(val.1.clone()).into());
v
}
}
impl<'a> TryFrom<&'a [u8]> for SigCombined {
type Error = Error;
fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
let (sig, _) = Self::try_decode_from(bytes)?;
Ok(sig)
}
}
impl<'a> TryDecodeFrom<'a> for SigCombined {
type Error = Error;
fn try_decode_from(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), Self::Error> {
let (sig_type, ptr) = SchemeTypeId::try_decode_from(bytes)?;
let (sig_data, ptr) = Varbytes::try_decode_from(ptr)?;
Ok((Self(sig_type, sig_data.to_inner()), ptr))
}
}
#[derive(Clone)]
pub struct SigShare(
pub IdentifierPrimeField<Scalar>,
pub usize,
pub usize,
pub SchemeTypeId,
pub Vec<u8>,
);
impl From<SigShare> for Vec<u8> {
fn from(val: SigShare) -> Self {
let mut v = Vec::default();
v.append(&mut val.0 .0.to_be_bytes().into());
v.append(&mut Varuint(val.1).into());
v.append(&mut Varuint(val.2).into());
v.append(&mut val.3.into());
v.append(&mut Varbytes::new(val.4.clone()).into());
v
}
}
impl<'a> TryFrom<&'a [u8]> for SigShare {
type Error = Error;
fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
let (share, _) = Self::try_decode_from(bytes)?;
Ok(share)
}
}
impl<'a> TryDecodeFrom<'a> for SigShare {
type Error = Error;
fn try_decode_from(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), Self::Error> {
let (id_bytes, ptr) = Varuint::<[u8; 32]>::try_decode_from(bytes)?;
let id = Option::<Scalar>::from(Scalar::from_be_bytes(&id_bytes)).ok_or(
Error::FailedConversion("Can't convert identifier to scalar".to_string()),
)?;
let (threshold, ptr) = Varuint::<usize>::try_decode_from(ptr)?;
let (limit, ptr) = Varuint::<usize>::try_decode_from(ptr)?;
let (share_type, ptr) = SchemeTypeId::try_decode_from(ptr)?;
let (share_data, ptr) = Varbytes::try_decode_from(ptr)?;
Ok((
Self(
IdentifierPrimeField(id),
threshold.to_inner(),
limit.to_inner(),
share_type,
share_data.to_inner(),
),
ptr,
))
}
}
#[derive(Clone, Default)]
pub(crate) struct ThresholdData(pub(crate) BTreeMap<IdentifierPrimeField<Scalar>, SigShare>);
impl From<ThresholdData> for Vec<u8> {
fn from(val: ThresholdData) -> Self {
let mut v = Vec::default();
v.append(&mut Varuint(val.0.len()).into());
val.0.iter().for_each(|(_, share)| {
v.append(&mut share.clone().into());
});
v
}
}
impl<'a> TryFrom<&'a [u8]> for ThresholdData {
type Error = Error;
fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
let (tdata, _) = Self::try_decode_from(bytes)?;
Ok(tdata)
}
}
impl<'a> TryDecodeFrom<'a> for ThresholdData {
type Error = Error;
fn try_decode_from(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), Self::Error> {
let (num_shares, ptr) = Varuint::<usize>::try_decode_from(bytes)?;
let (shares, ptr) = match *num_shares {
0 => (BTreeMap::default(), ptr),
_ => {
let mut shares = BTreeMap::new();
let mut p = ptr;
for _ in 0..*num_shares {
let (share, ptr) = SigShare::try_decode_from(p)?;
if shares.insert(share.0, share).is_some() {
return Err(SharesError::DuplicateShare.into());
}
p = ptr;
}
(shares, p)
}
};
Ok((Self(shares), ptr))
}
}
pub(crate) struct View<'a> {
ms: &'a Multisig,
}
impl<'a> TryFrom<&'a Multisig> for View<'a> {
type Error = Error;
fn try_from(ms: &'a Multisig) -> Result<Self, Self::Error> {
Ok(Self { ms })
}
}
impl<'a> AttrView for View<'a> {
fn payload_encoding(&self) -> Result<Codec, Error> {
let v = self
.ms
.attributes
.get(&AttrId::PayloadEncoding)
.ok_or(AttributesError::MissingPayloadEncoding)?;
let encoding = Codec::try_from(v.as_slice())?;
Ok(encoding)
}
fn scheme(&self) -> Result<u8, Error> {
let v = self
.ms
.attributes
.get(&AttrId::Scheme)
.ok_or(AttributesError::MissingScheme)?;
let scheme = Varuint::<u8>::try_from(v.as_slice())?;
Ok(*scheme)
}
}
impl<'a> DataView for View<'a> {
fn sig_bytes(&self) -> Result<Vec<u8>, Error> {
let sig = self
.ms
.attributes
.get(&AttrId::SigData)
.ok_or(AttributesError::MissingSignature)?;
Ok(sig.clone())
}
}
impl<'a> ConvView for View<'a> {
fn to_ssh_signature(&self) -> Result<ssh_key::Signature, Error> {
let dv = self.ms.data_view()?;
let sig_bytes = dv.sig_bytes()?;
let av = self.ms.attr_view()?;
let scheme_type = SchemeTypeId::try_from(av.scheme()?)?;
match self.ms.codec {
Codec::Bls12381G1Msig => {
let sig_data: Vec<u8> = SigCombined(scheme_type, sig_bytes).into();
Ok(ssh_key::Signature::new(
ssh_key::Algorithm::Other(
ssh_key::AlgorithmName::new(ALGORITHM_NAME_G1)
.map_err(|e| ConversionsError::Ssh(e.into()))?,
),
sig_data,
)
.map_err(|e| ConversionsError::Ssh(e.into()))?)
}
Codec::Bls12381G2Msig => {
let sig_data: Vec<u8> = SigCombined(scheme_type, sig_bytes).into();
Ok(ssh_key::Signature::new(
ssh_key::Algorithm::Other(
ssh_key::AlgorithmName::new(ALGORITHM_NAME_G2)
.map_err(|e| ConversionsError::Ssh(e.into()))?,
),
sig_data,
)
.map_err(|e| ConversionsError::Ssh(e.into()))?)
}
Codec::Bls12381G1ShareMsig => {
let av = self.ms.threshold_attr_view()?;
let threshold = av.threshold()?;
let limit = av.limit()?;
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::<Scalar>::from(Scalar::from_be_bytes(&identifier_array))
.ok_or(Error::FailedConversion(
"Invalid share identifier bytes".to_string(),
))?;
let sig_data: Vec<u8> = SigShare(
IdentifierPrimeField(id_scalar),
threshold,
limit,
scheme_type,
sig_bytes,
)
.into();
Ok(ssh_key::Signature::new(
ssh_key::Algorithm::Other(
ssh_key::AlgorithmName::new(ALGORITHM_NAME_G1_SHARE)
.map_err(|e| ConversionsError::Ssh(e.into()))?,
),
sig_data,
)
.map_err(|e| ConversionsError::Ssh(e.into()))?)
}
Codec::Bls12381G2ShareMsig => {
let av = self.ms.threshold_attr_view()?;
let threshold = av.threshold()?;
let limit = av.limit()?;
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::<Scalar>::from(Scalar::from_be_bytes(&identifier_array))
.ok_or(Error::FailedConversion(
"Invalid share identifier bytes".to_string(),
))?;
let sig_data: Vec<u8> = SigShare(
IdentifierPrimeField(id_scalar),
threshold,
limit,
scheme_type,
sig_bytes,
)
.into();
Ok(ssh_key::Signature::new(
ssh_key::Algorithm::Other(
ssh_key::AlgorithmName::new(ALGORITHM_NAME_G2_SHARE)
.map_err(|e| ConversionsError::Ssh(e.into()))?,
),
sig_data,
)
.map_err(|e| ConversionsError::Ssh(e.into()))?)
}
_ => Err(Error::UnsupportedAlgorithm(self.ms.codec.to_string())),
}
}
}
impl<'a> ThresholdAttrView for View<'a> {
fn threshold(&self) -> Result<usize, Error> {
let threshold = self
.ms
.attributes
.get(&AttrId::Threshold)
.ok_or(AttributesError::MissingThreshold)?;
Ok(Varuint::<usize>::try_from(threshold.as_slice())?.to_inner())
}
fn limit(&self) -> Result<usize, Error> {
let limit = self
.ms
.attributes
.get(&AttrId::Limit)
.ok_or(AttributesError::MissingLimit)?;
Ok(Varuint::<usize>::try_from(limit.as_slice())?.to_inner())
}
fn identifier(&self) -> Result<&[u8], Error> {
match self.ms.codec {
Codec::Bls12381G1ShareMsig | Codec::Bls12381G2ShareMsig => {
let identifier = self
.ms
.attributes
.get(&AttrId::ShareIdentifier)
.ok_or(AttributesError::MissingIdentifier)?;
Ok(identifier.as_slice())
}
_ => Err(SharesError::NotASignatureShare.into()),
}
}
fn threshold_data(&self) -> Result<&[u8], Error> {
let v = self
.ms
.attributes
.get(&AttrId::ThresholdData)
.ok_or(AttributesError::MissingThresholdData)?;
Ok(v.as_slice())
}
}
impl<'a> ThresholdView for View<'a> {
fn shares(&self) -> Result<Vec<Multisig>, Error> {
let codec = match self.ms.codec {
Codec::Bls12381G1Msig => Codec::Bls12381G1ShareMsig,
Codec::Bls12381G2Msig => Codec::Bls12381G2ShareMsig,
Codec::Bls12381G1ShareMsig | Codec::Bls12381G2ShareMsig => {
return Err(SharesError::IsASignatureShare.into())
}
_ => return Err(Error::UnsupportedAlgorithm(self.ms.codec.to_string())),
};
let threshold_data = {
let av = self.ms.threshold_attr_view()?;
match av.threshold_data() {
Ok(b) => ThresholdData::try_from(b)
.map_err(|e| SharesError::InvalidThresholdData(e.to_string()))?,
Err(_) => ThresholdData::default(),
}
};
let mut shares = Vec::with_capacity(threshold_data.0.len());
threshold_data
.0
.values()
.try_for_each(|share| -> Result<(), Error> {
let encoding = {
let av = self.ms.attr_view()?;
av.payload_encoding()?
};
let share = Builder::new(codec)
.with_message_bytes(&self.ms.message.as_slice())
.with_identifier(&share.0 .0.to_be_bytes())
.with_threshold(share.1)
.with_limit(share.2)
.with_signature_bytes(&share.4)
.with_payload_encoding(encoding)
.with_scheme(share.3.into())
.try_build()?;
shares.push(share);
Ok(())
})?;
Ok(shares)
}
fn add_share(&self, share: &Multisig) -> Result<Multisig, Error> {
match self.ms.codec {
Codec::Bls12381G1Msig | Codec::Bls12381G2Msig => {}
Codec::Bls12381G1ShareMsig | Codec::Bls12381G2ShareMsig => {
return Err(SharesError::IsASignatureShare.into())
}
_ => return Err(Error::UnsupportedAlgorithm(self.ms.codec.to_string())),
};
let (sdata, identifier, threshold, limit, encoding) = {
let av = share.attr_view()?;
let scheme_type = SchemeTypeId::try_from(av.scheme()?)?;
let av = share.threshold_attr_view()?;
let threshold = av.threshold()?;
let limit = av.limit()?;
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::<Scalar>::from(Scalar::from_be_bytes(&identifier_array)).ok_or(
Error::FailedConversion("Incorrect identifier bytes".to_string()),
)?,
);
let dv = share.data_view()?;
let sig_bytes = dv.sig_bytes()?;
let encoding = {
let av = self.ms.attr_view()?;
av.payload_encoding().ok()
};
(
SigShare(identifier, threshold, limit, scheme_type, sig_bytes),
identifier,
threshold,
limit,
encoding,
)
};
let threshold_data: Vec<u8> = {
let av = self.ms.threshold_attr_view()?;
let mut tdata = match av.threshold_data() {
Ok(b) => ThresholdData::try_from(b)
.map_err(|e| SharesError::InvalidThresholdData(e.to_string()))?,
Err(_) => ThresholdData::default(),
};
if tdata.0.contains_key(&identifier) {
return Err(SharesError::DuplicateShare.into());
}
tdata.0.insert(identifier, sdata);
tdata.into()
};
let encoding = {
let av = self.ms.attr_view()?;
match av.payload_encoding() {
Ok(encoding) => Some(encoding),
Err(_) => encoding,
}
};
let av = share.threshold_attr_view()?;
let threshold = av.threshold().unwrap_or(threshold);
let limit = av.limit().unwrap_or(limit);
let builder = Builder::new(self.ms.codec)
.with_message_bytes(&self.ms.message.as_slice())
.with_threshold(threshold)
.with_limit(limit)
.with_threshold_data(&threshold_data);
if let Some(encoding) = encoding {
builder.with_payload_encoding(encoding).try_build()
} else {
builder.try_build()
}
}
fn combine(&self) -> Result<Multisig, Error> {
let threshold_data = {
let av = self.ms.threshold_attr_view()?;
match av.threshold_data() {
Ok(b) => ThresholdData::try_from(b)
.map_err(|e| SharesError::InvalidThresholdData(e.to_string()))?,
Err(_) => ThresholdData::default(),
}
};
let num_shares = threshold_data.0.len();
let av = self.ms.threshold_attr_view()?;
if num_shares < av.threshold()? {
return Err(SharesError::NotEnoughShares.into());
}
match self.ms.codec {
Codec::Bls12381G1Msig => {
let mut share_type_id: Option<SchemeTypeId> = None;
let mut shares = Vec::default();
threshold_data
.0
.iter()
.try_for_each(|(id, share)| -> Result<(), Error> {
let bytes: [u8; 48] = share.4.as_slice().try_into().map_err(|_| {
Error::FailedConversion("Invalid signature share bytes".to_string())
})?;
let inner = Option::from(G1Projective::from_compressed(&bytes)).ok_or(
Error::FailedConversion("Invalid signature share bytes".to_string()),
)?;
let vsss = Share::with_identifier_and_value(*id, ValueGroup(inner));
if let Some(sti) = share_type_id {
if sti != share.3 {
return Err(SharesError::ShareTypeMismatch.into());
}
} else {
share_type_id = Some(share.3);
}
let s = match share.3 {
SchemeTypeId::Basic => SignatureShare::<Bls12381G1Impl>::Basic(vsss),
SchemeTypeId::MessageAugmentation => {
SignatureShare::<Bls12381G1Impl>::MessageAugmentation(vsss)
}
SchemeTypeId::ProofOfPossession => {
SignatureShare::<Bls12381G1Impl>::ProofOfPossession(vsss)
}
};
shares.push(s);
Ok(())
})?;
let sig = Signature::from_shares(shares.as_slice())
.map_err(|e| SharesError::ShareCombineFailed(e.to_string()))?;
let encoding = {
let av = self.ms.attr_view()?;
av.payload_encoding()?
};
Builder::new_from_bls_signature(&sig)?
.with_message_bytes(&self.ms.message.as_slice())
.with_payload_encoding(encoding)
.try_build()
}
Codec::Bls12381G2Msig => {
let mut share_type_id: Option<SchemeTypeId> = None;
let mut shares = Vec::default();
threshold_data
.0
.iter()
.try_for_each(|(id, share)| -> Result<(), Error> {
let bytes: [u8; 96] = share.4.as_slice().try_into().map_err(|_| {
Error::FailedConversion("Invalid signature share bytes".to_string())
})?;
let inner = Option::from(G2Projective::from_compressed(&bytes)).ok_or(
Error::FailedConversion("Invalid signature share bytes".to_string()),
)?;
let vsss = Share::with_identifier_and_value(*id, ValueGroup(inner));
if let Some(sti) = share_type_id {
if sti != share.3 {
return Err(SharesError::ShareTypeMismatch.into());
}
} else {
share_type_id = Some(share.3);
}
let s = match share.3 {
SchemeTypeId::Basic => SignatureShare::<Bls12381G2Impl>::Basic(vsss),
SchemeTypeId::MessageAugmentation => {
SignatureShare::<Bls12381G2Impl>::MessageAugmentation(vsss)
}
SchemeTypeId::ProofOfPossession => {
SignatureShare::<Bls12381G2Impl>::ProofOfPossession(vsss)
}
};
shares.push(s);
Ok(())
})?;
let sig = Signature::from_shares(shares.as_slice())
.map_err(|e| SharesError::ShareCombineFailed(e.to_string()))?;
let encoding = {
let av = self.ms.attr_view()?;
av.payload_encoding()?
};
Builder::new_from_bls_signature(&sig)?
.with_message_bytes(&self.ms.message.as_slice())
.with_payload_encoding(encoding)
.try_build()
}
_ => Err(Error::UnsupportedAlgorithm(self.ms.codec.to_string())),
}
}
fn shares_with_disclosure(
&self,
mode: ThresholdDisclosure,
meta_key: Option<&[u8]>,
) -> Result<Vec<Multisig>, Error> {
let shares = self.shares()?;
shares
.iter()
.map(|s| s.disclosure_view()?.to_disclosure(mode, meta_key, None))
.collect()
}
fn add_share_with_meta(
&self,
share: &Multisig,
meta_key: Option<&[u8]>,
) -> Result<Multisig, Error> {
let (share_t, share_n) = threshold_meta::read_threshold_params(share, meta_key)?;
let (sdata, identifier, encoding) = {
let av = share.attr_view()?;
let scheme_type = SchemeTypeId::try_from(av.scheme()?)?;
let tav = share.threshold_attr_view()?;
let identifier_bytes = tav.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::<Scalar>::from(Scalar::from_be_bytes(&identifier_array)).ok_or(
Error::FailedConversion("Incorrect identifier bytes".to_string()),
)?,
);
let dv = share.data_view()?;
let sig_bytes = dv.sig_bytes()?;
let encoding = {
let av = self.ms.attr_view()?;
av.payload_encoding().ok()
};
(
SigShare(identifier, share_t, share_n, scheme_type, sig_bytes),
identifier,
encoding,
)
};
let threshold_data: Vec<u8> = {
let av = self.ms.threshold_attr_view()?;
let mut tdata = match av.threshold_data() {
Ok(b) => ThresholdData::try_from(b)
.map_err(|e| SharesError::InvalidThresholdData(e.to_string()))?,
Err(_) => ThresholdData::default(),
};
if tdata.0.contains_key(&identifier) {
return Err(SharesError::DuplicateShare.into());
}
tdata.0.insert(identifier, sdata);
tdata.into()
};
let encoding = {
let av = self.ms.attr_view()?;
match av.payload_encoding() {
Ok(encoding) => Some(encoding),
Err(_) => encoding,
}
};
let builder = Builder::new(self.ms.codec)
.with_message_bytes(&self.ms.message.as_slice())
.with_threshold(share_t)
.with_limit(share_n)
.with_threshold_data(&threshold_data);
if let Some(encoding) = encoding {
builder.with_payload_encoding(encoding).try_build()
} else {
builder.try_build()
}
}
fn combine_with_meta(&self, meta_key: Option<&[u8]>) -> Result<Multisig, Error> {
let (threshold, _limit) = threshold_meta::read_threshold_params(self.ms, meta_key)?;
let threshold_data = {
let av = self.ms.threshold_attr_view()?;
match av.threshold_data() {
Ok(b) => ThresholdData::try_from(b)
.map_err(|e| SharesError::InvalidThresholdData(e.to_string()))?,
Err(_) => ThresholdData::default(),
}
};
let num_shares = threshold_data.0.len();
if num_shares < threshold {
return Err(SharesError::NotEnoughShares.into());
}
match self.ms.codec {
Codec::Bls12381G1Msig => {
let mut share_type_id: Option<SchemeTypeId> = None;
let mut shares = Vec::default();
threshold_data
.0
.iter()
.try_for_each(|(id, share)| -> Result<(), Error> {
let bytes: [u8; 48] = share.4.as_slice().try_into().map_err(|_| {
Error::FailedConversion("Invalid signature share bytes".to_string())
})?;
let inner = Option::from(G1Projective::from_compressed(&bytes)).ok_or(
Error::FailedConversion("Invalid signature share bytes".to_string()),
)?;
let vsss = Share::with_identifier_and_value(*id, ValueGroup(inner));
if let Some(sti) = share_type_id {
if sti != share.3 {
return Err(SharesError::ShareTypeMismatch.into());
}
} else {
share_type_id = Some(share.3);
}
let s = match share.3 {
SchemeTypeId::Basic => SignatureShare::<Bls12381G1Impl>::Basic(vsss),
SchemeTypeId::MessageAugmentation => {
SignatureShare::<Bls12381G1Impl>::MessageAugmentation(vsss)
}
SchemeTypeId::ProofOfPossession => {
SignatureShare::<Bls12381G1Impl>::ProofOfPossession(vsss)
}
};
shares.push(s);
Ok(())
})?;
let sig = Signature::from_shares(shares.as_slice())
.map_err(|e| SharesError::ShareCombineFailed(e.to_string()))?;
let encoding = {
let av = self.ms.attr_view()?;
av.payload_encoding()?
};
Builder::new_from_bls_signature(&sig)?
.with_message_bytes(&self.ms.message.as_slice())
.with_payload_encoding(encoding)
.try_build()
}
Codec::Bls12381G2Msig => {
let mut share_type_id: Option<SchemeTypeId> = None;
let mut shares = Vec::default();
threshold_data
.0
.iter()
.try_for_each(|(id, share)| -> Result<(), Error> {
let bytes: [u8; 96] = share.4.as_slice().try_into().map_err(|_| {
Error::FailedConversion("Invalid signature share bytes".to_string())
})?;
let inner = Option::from(G2Projective::from_compressed(&bytes)).ok_or(
Error::FailedConversion("Invalid signature share bytes".to_string()),
)?;
let vsss = Share::with_identifier_and_value(*id, ValueGroup(inner));
if let Some(sti) = share_type_id {
if sti != share.3 {
return Err(SharesError::ShareTypeMismatch.into());
}
} else {
share_type_id = Some(share.3);
}
let s = match share.3 {
SchemeTypeId::Basic => SignatureShare::<Bls12381G2Impl>::Basic(vsss),
SchemeTypeId::MessageAugmentation => {
SignatureShare::<Bls12381G2Impl>::MessageAugmentation(vsss)
}
SchemeTypeId::ProofOfPossession => {
SignatureShare::<Bls12381G2Impl>::ProofOfPossession(vsss)
}
};
shares.push(s);
Ok(())
})?;
let sig = Signature::from_shares(shares.as_slice())
.map_err(|e| SharesError::ShareCombineFailed(e.to_string()))?;
let encoding = {
let av = self.ms.attr_view()?;
av.payload_encoding()?
};
Builder::new_from_bls_signature(&sig)?
.with_message_bytes(&self.ms.message.as_slice())
.with_payload_encoding(encoding)
.try_build()
}
_ => Err(Error::UnsupportedAlgorithm(self.ms.codec.to_string())),
}
}
}