use crate::{
error::{
AttributesError, CipherError, ConversionsError, KdfError, SealError, SignError,
ThresholdError, VerifyError,
},
views::threshold_meta::{self, ThresholdDisclosure},
AttrId, AttrView, Builder, CipherAttrView, ConvView, DataView, Error, FingerprintView,
KdfAttrView, Multikey, OpenView, SealView, SignView, ThresholdAttrView, ThresholdView,
VerifyView, Views,
};
use blsful::{
inner_types::{G1Projective, G2Projective, Scalar},
vsss_rs::{IdentifierPrimeField, Share, ValueGroup},
Bls12381G1Impl, Bls12381G2Impl, PublicKey, PublicKeyShare, SecretKey, SecretKeyShare,
Signature, SignatureSchemes, SignatureShare, TimeCryptCiphertext, SECRET_KEY_BYTES,
};
use elliptic_curve::group::GroupEncoding;
use multi_codec::Codec;
use multi_hash::{mh, Multihash};
use multi_sig::{ms, views::bls12381::SchemeTypeId, Multisig, Views as SigViews};
use multi_trait::TryDecodeFrom;
use multi_util::{Varbytes, Varuint};
use rand_core::Rng;
use ssh_encoding::{Decode, Encode};
use std::{array::TryFromSliceError, collections::BTreeMap};
use zeroize::Zeroizing;
pub const ALGORITHM_NAME_G1: &str = "bls12_381-g1@multikey";
pub const ALGORITHM_NAME_G1_SHARE: &str = "bls12_381-g1-share@multikey";
pub const ALGORITHM_NAME_G2: &str = "bls12_381-g2@multikey";
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;
fn bytes_to_identifier(bytes: &[u8]) -> Result<IdentifierPrimeField<Scalar>, 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()),
))?,
))
}
fn bytes_to_value(bytes: &[u8]) -> Result<IdentifierPrimeField<Scalar>, 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()),
))?,
))
}
#[derive(Clone)]
pub struct KeyShare(
pub IdentifierPrimeField<Scalar>,
pub usize,
pub usize,
pub Vec<u8>,
);
impl From<KeyShare> for Vec<u8> {
fn from(val: KeyShare) -> Self {
let mut v = Vec::default();
v.extend_from_slice(&val.0 .0.to_be_bytes());
v.append(&mut Varuint(val.1).into());
v.append(&mut Varuint(val.2).into());
v.append(&mut Varbytes::new(val.3.clone()).into());
v
}
}
impl<'a> TryFrom<&'a [u8]> for KeyShare {
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 KeyShare {
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 identifier = bytes_to_identifier(id_bytes.0.as_slice())?;
let (threshold, ptr) = Varuint::<usize>::try_decode_from(ptr)?;
let (limit, ptr) = Varuint::<usize>::try_decode_from(ptr)?;
let (key_data, ptr) = Varbytes::try_decode_from(ptr)?;
Ok((
Self(
identifier,
threshold.to_inner(),
limit.to_inner(),
key_data.to_inner(),
),
ptr,
))
}
}
#[derive(Clone, Default)]
pub(crate) struct ThresholdData(pub(crate) BTreeMap<IdentifierPrimeField<Scalar>, KeyShare>);
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) = KeyShare::try_decode_from(p)?;
shares.insert(share.0, share);
p = ptr;
}
(shares, p)
}
};
Ok((Self(shares), ptr))
}
}
pub(crate) struct View<'a> {
mk: &'a Multikey,
}
impl<'a> TryFrom<&'a Multikey> for View<'a> {
type Error = Error;
fn try_from(mk: &'a Multikey) -> Result<Self, Self::Error> {
Ok(Self { mk })
}
}
impl<'a> AttrView for View<'a> {
fn is_encrypted(&self) -> bool {
if let Some(v) = self.mk.attributes.get(&AttrId::KeyIsEncrypted) {
if let Ok(b) = Varuint::<bool>::try_from(v.as_slice()) {
return b.to_inner();
}
}
false
}
fn is_secret_key(&self) -> bool {
matches!(
self.mk.codec,
Codec::Bls12381G1Priv
| Codec::Bls12381G2Priv
| Codec::Bls12381G1PrivShare
| Codec::Bls12381G2PrivShare
)
}
fn is_public_key(&self) -> bool {
matches!(self.mk.codec, Codec::Bls12381G1Pub | Codec::Bls12381G2Pub)
}
fn is_secret_key_share(&self) -> bool {
matches!(
self.mk.codec,
Codec::Bls12381G1PrivShare | Codec::Bls12381G2PrivShare
)
}
}
impl<'a> ThresholdAttrView for View<'a> {
fn threshold(&self) -> Result<usize, Error> {
let v = self
.mk
.attributes
.get(&AttrId::Threshold)
.ok_or(AttributesError::MissingThreshold)?;
Ok(*Varuint::<usize>::try_from(v.as_slice())?)
}
fn limit(&self) -> Result<usize, Error> {
let v = self
.mk
.attributes
.get(&AttrId::Limit)
.ok_or(AttributesError::MissingLimit)?;
Ok(*Varuint::<usize>::try_from(v.as_slice())?)
}
fn identifier(&self) -> Result<&[u8], Error> {
let v = self
.mk
.attributes
.get(&AttrId::ShareIdentifier)
.ok_or(AttributesError::MissingShareIdentifier)?;
Ok(v.as_slice())
}
fn threshold_data(&self) -> Result<&[u8], Error> {
let v = self
.mk
.attributes
.get(&AttrId::ThresholdData)
.ok_or(AttributesError::MissingThresholdData)?;
Ok(v.as_slice())
}
}
impl<'a> DataView for View<'a> {
fn key_bytes(&self) -> Result<Zeroizing<Vec<u8>>, Error> {
let key = self
.mk
.attributes
.get(&AttrId::KeyData)
.ok_or(AttributesError::MissingKey)?;
Ok(key.clone())
}
fn secret_bytes(&self) -> Result<Zeroizing<Vec<u8>>, Error> {
if !self.is_secret_key() {
return Err(AttributesError::NotSecretKey(self.mk.codec).into());
}
if self.is_encrypted() {
return Err(AttributesError::EncryptedKey.into());
}
self.key_bytes()
}
}
impl<'a> CipherAttrView for View<'a> {
fn cipher_codec(&self) -> Result<Codec, Error> {
let codec = self
.mk
.attributes
.get(&AttrId::CipherCodec)
.ok_or(CipherError::MissingCodec)?;
Ok(Codec::try_from(codec.as_slice())?)
}
fn nonce_bytes(&self) -> Result<Zeroizing<Vec<u8>>, Error> {
self.mk
.attributes
.get(&AttrId::CipherNonce)
.ok_or(CipherError::MissingNonce.into())
.cloned()
}
fn key_length(&self) -> Result<usize, Error> {
let key_length = self
.mk
.attributes
.get(&AttrId::CipherKeyLen)
.ok_or(CipherError::MissingKeyLen)?;
Ok(Varuint::<usize>::try_from(key_length.as_slice())?.to_inner())
}
}
impl<'a> KdfAttrView for View<'a> {
fn kdf_codec(&self) -> Result<Codec, Error> {
let codec = self
.mk
.attributes
.get(&AttrId::KdfCodec)
.ok_or(KdfError::MissingCodec)?;
Ok(Codec::try_from(codec.as_slice())?)
}
fn salt_bytes(&self) -> Result<Zeroizing<Vec<u8>>, Error> {
self.mk
.attributes
.get(&AttrId::KdfSalt)
.ok_or(KdfError::MissingSalt.into())
.cloned()
}
fn rounds(&self) -> Result<usize, Error> {
let rounds = self
.mk
.attributes
.get(&AttrId::KdfRounds)
.ok_or(KdfError::MissingRounds)?;
Ok(Varuint::<usize>::try_from(rounds.as_slice())?.to_inner())
}
}
impl<'a> FingerprintView for View<'a> {
fn fingerprint(&self, codec: Codec) -> Result<Multihash, Error> {
let attr = self.mk.attr_view()?;
if attr.is_secret_key() {
let pk = self.to_public_key()?;
let fp = pk.fingerprint_view()?;
let f = fp.fingerprint(codec)?;
Ok(f)
} else {
let bytes = {
let kd = self.mk.data_view()?;
kd.key_bytes()?
};
Ok(mh::Builder::new_from_bytes(codec, bytes)?.try_build()?)
}
}
}
impl<'a> ConvView for View<'a> {
fn to_public_key(&self) -> Result<Multikey, Error> {
let secret_bytes = {
let kd = self.mk.data_view()?;
kd.secret_bytes()?
};
match self.mk.codec {
Codec::Bls12381G1Priv => {
let bytes: [u8; SECRET_KEY_BYTES] = secret_bytes.as_slice()[..SECRET_KEY_BYTES]
.try_into()
.map_err(|_| {
ConversionsError::SecretKeyFailure(
"failed to get secret key bytes".to_string(),
)
})?;
let secret_key: SecretKey<Bls12381G1Impl> = {
let sk = Option::from(SecretKey::from_be_bytes(&bytes));
sk.ok_or(ConversionsError::SecretKeyFailure(
"failed to create secret key".to_string(),
))?
};
let public_key = secret_key.public_key();
let key_bytes = public_key.0.to_bytes();
Builder::new(Codec::Bls12381G1Pub)
.with_comment(&self.mk.comment)
.with_key_bytes(&key_bytes)
.try_build()
}
Codec::Bls12381G1PrivShare => {
let av = self.mk.threshold_attr_view()?;
let threshold = av.threshold()?;
let limit = av.limit()?;
let identifier = bytes_to_identifier(av.identifier()?)?;
let value = bytes_to_value(secret_bytes.as_slice())?;
let secret_key: SecretKeyShare<Bls12381G1Impl> =
SecretKeyShare(Share::with_identifier_and_value(identifier, value));
let public_key = secret_key
.public_key()
.map_err(|e| ConversionsError::PublicKeyFailure(e.to_string()))?;
let key_bytes = public_key.0 .0.value().0.to_bytes().as_ref().to_vec();
Builder::new(Codec::Bls12381G1PubShare)
.with_comment(&self.mk.comment)
.with_key_bytes(&key_bytes)
.with_threshold(threshold)
.with_limit(limit)
.with_identifier(&public_key.0 .0.identifier().0.to_be_bytes())
.try_build()
}
Codec::Bls12381G2Priv => {
let bytes: [u8; SECRET_KEY_BYTES] = secret_bytes.as_slice()[..SECRET_KEY_BYTES]
.try_into()
.map_err(|_| {
ConversionsError::SecretKeyFailure(
"failed to get secret key bytes".to_string(),
)
})?;
let secret_key: SecretKey<Bls12381G2Impl> = {
let sk = Option::from(SecretKey::from_be_bytes(&bytes));
sk.ok_or(ConversionsError::SecretKeyFailure(
"failed to create secret key".to_string(),
))?
};
let public_key = secret_key.public_key();
let key_bytes = public_key.0.to_bytes();
Builder::new(Codec::Bls12381G2Pub)
.with_comment(&self.mk.comment)
.with_key_bytes(&key_bytes)
.try_build()
}
Codec::Bls12381G2PrivShare => {
let av = self.mk.threshold_attr_view()?;
let threshold = av.threshold()?;
let limit = av.limit()?;
let identifier = bytes_to_identifier(av.identifier()?)?;
let value = bytes_to_value(secret_bytes.as_slice())?;
let secret_key: SecretKeyShare<Bls12381G2Impl> =
SecretKeyShare(Share::with_identifier_and_value(identifier, value));
let public_key = secret_key
.public_key()
.map_err(|e| ConversionsError::PublicKeyFailure(e.to_string()))?;
let key_bytes = public_key.0 .0.value().0.to_bytes().as_ref().to_vec();
Builder::new(Codec::Bls12381G2PubShare)
.with_comment(&self.mk.comment)
.with_key_bytes(&key_bytes)
.with_threshold(threshold)
.with_limit(limit)
.with_identifier(&public_key.0 .0.identifier().0.to_be_bytes())
.try_build()
}
_ => Err(ConversionsError::UnsupportedCodec(self.mk.codec).into()),
}
}
fn to_ssh_public_key(&self) -> Result<ssh_key::PublicKey, Error> {
let mut pk = self.mk.clone();
if self.is_secret_key() {
pk = self.to_public_key()?;
}
let key_bytes = {
let kd = pk.data_view()?;
kd.key_bytes()?
};
let mut buf: Vec<u8> = Vec::new();
let name = match pk.codec {
Codec::Bls12381G1Pub => {
key_bytes
.encode(&mut buf)
.map_err(|e| ConversionsError::Ssh(e.into()))?;
ALGORITHM_NAME_G1
}
Codec::Bls12381G1PubShare => {
let tav = pk.threshold_attr_view()?;
let key_share: Vec<u8> = KeyShare(
bytes_to_identifier(tav.identifier()?)?,
tav.threshold()?,
tav.limit()?,
key_bytes.to_vec(),
)
.into();
key_share
.encode(&mut buf)
.map_err(|e| ConversionsError::Ssh(e.into()))?;
ALGORITHM_NAME_G1_SHARE
}
Codec::Bls12381G2Pub => {
key_bytes
.encode(&mut buf)
.map_err(|e| ConversionsError::Ssh(e.into()))?;
ALGORITHM_NAME_G2
}
Codec::Bls12381G2PubShare => {
let tav = pk.threshold_attr_view()?;
let key_share: Vec<u8> = KeyShare(
bytes_to_identifier(tav.identifier()?)?,
tav.threshold()?,
tav.limit()?,
key_bytes.to_vec(),
)
.into();
key_share
.encode(&mut buf)
.map_err(|e| ConversionsError::Ssh(e.into()))?;
ALGORITHM_NAME_G2_SHARE
}
_ => return Err(ConversionsError::UnsupportedCodec(self.mk.codec).into()),
};
let opaque_key_bytes = ssh_key::public::OpaquePublicKeyBytes::decode(&mut buf.as_slice())
.map_err(|e| ConversionsError::Ssh(e.into()))?;
Ok(ssh_key::PublicKey::new(
ssh_key::public::KeyData::Other(ssh_key::public::OpaquePublicKey {
algorithm: ssh_key::Algorithm::Other(
ssh_key::AlgorithmName::new(name)
.map_err(|e| ConversionsError::Ssh(e.into()))?,
),
key: opaque_key_bytes,
}),
pk.comment,
))
}
fn to_ssh_private_key(&self) -> Result<ssh_key::PrivateKey, Error> {
let secret_bytes = {
let kd = self.mk.data_view()?;
kd.secret_bytes()?
};
let pk = self.to_public_key()?;
let key_bytes = {
let kd = pk.data_view()?;
kd.key_bytes()?
};
let mut secret_buf: Vec<u8> = Vec::new();
let mut public_buf: Vec<u8> = Vec::new();
let name = match self.mk.codec {
Codec::Bls12381G1Priv => {
secret_bytes
.encode(&mut secret_buf)
.map_err(|e| ConversionsError::Ssh(e.into()))?;
key_bytes
.encode(&mut public_buf)
.map_err(|e| ConversionsError::Ssh(e.into()))?;
ALGORITHM_NAME_G1
}
Codec::Bls12381G1PrivShare => {
let sav = self.mk.threshold_attr_view()?;
let secret_key_share: Vec<u8> = KeyShare(
bytes_to_identifier(sav.identifier()?)?,
sav.threshold()?,
sav.limit()?,
secret_bytes.to_vec(),
)
.into();
let pav = pk.threshold_attr_view()?;
let public_key_share: Vec<u8> = KeyShare(
bytes_to_identifier(pav.identifier()?)?,
pav.threshold()?,
pav.limit()?,
key_bytes.to_vec(),
)
.into();
secret_key_share
.encode(&mut secret_buf)
.map_err(|e| ConversionsError::Ssh(e.into()))?;
public_key_share
.encode(&mut public_buf)
.map_err(|e| ConversionsError::Ssh(e.into()))?;
ALGORITHM_NAME_G1_SHARE
}
Codec::Bls12381G2Priv => {
secret_bytes
.encode(&mut secret_buf)
.map_err(|e| ConversionsError::Ssh(e.into()))?;
key_bytes
.encode(&mut public_buf)
.map_err(|e| ConversionsError::Ssh(e.into()))?;
ALGORITHM_NAME_G2
}
Codec::Bls12381G2PrivShare => {
let sav = self.mk.threshold_attr_view()?;
let secret_key_share: Vec<u8> = KeyShare(
bytes_to_identifier(sav.identifier()?)?,
sav.threshold()?,
sav.limit()?,
secret_bytes.to_vec(),
)
.into();
let pav = pk.threshold_attr_view()?;
let public_key_share: Vec<u8> = KeyShare(
bytes_to_identifier(pav.identifier()?)?,
pav.threshold()?,
pav.limit()?,
key_bytes.to_vec(),
)
.into();
secret_key_share
.encode(&mut secret_buf)
.map_err(|e| ConversionsError::Ssh(e.into()))?;
public_key_share
.encode(&mut public_buf)
.map_err(|e| ConversionsError::Ssh(e.into()))?;
ALGORITHM_NAME_G2_SHARE
}
_ => return Err(ConversionsError::UnsupportedCodec(self.mk.codec).into()),
};
let opaque_private_key_bytes =
ssh_key::private::OpaquePrivateKeyBytes::decode(&mut secret_buf.as_slice())
.map_err(|e| ConversionsError::Ssh(e.into()))?;
let opaque_public_key_bytes =
ssh_key::public::OpaquePublicKeyBytes::decode(&mut public_buf.as_slice())
.map_err(|e| ConversionsError::Ssh(e.into()))?;
Ok(ssh_key::PrivateKey::new(
ssh_key::private::KeypairData::Other(ssh_key::private::OpaqueKeypair {
public: ssh_key::public::OpaquePublicKey {
algorithm: ssh_key::Algorithm::Other(
ssh_key::AlgorithmName::new(name)
.map_err(|e| ConversionsError::Ssh(e.into()))?,
),
key: opaque_public_key_bytes,
},
private: opaque_private_key_bytes,
}),
self.mk.comment.clone(),
)
.map_err(|e| ConversionsError::Ssh(e.into()))?)
}
}
impl<'a> SignView for View<'a> {
fn sign(&self, msg: &[u8], combined: bool, scheme: Option<u8>) -> Result<Multisig, Error> {
let scheme = scheme.ok_or(SignError::MissingScheme)?;
let attr = self.mk.attr_view()?;
if !attr.is_secret_key() {
return Err(SignError::NotSigningKey.into());
}
let secret_bytes = {
let kd = self.mk.data_view()?;
kd.secret_bytes()?
};
let sig_scheme: SignatureSchemes = SchemeTypeId::try_from(scheme)?.into();
match self.mk.codec {
Codec::Bls12381G1Priv => {
let bytes: [u8; SECRET_KEY_BYTES] = secret_bytes.as_slice()[..SECRET_KEY_BYTES]
.try_into()
.map_err(|_| {
ConversionsError::SecretKeyFailure(
"failed to get secret key bytes".to_string(),
)
})?;
let secret_key: SecretKey<Bls12381G1Impl> = {
let sk = Option::from(SecretKey::from_be_bytes(&bytes));
sk.ok_or(ConversionsError::SecretKeyFailure(
"failed to create secret key".to_string(),
))?
};
let signature = secret_key
.sign(sig_scheme, msg)
.map_err(|e| SignError::SigningFailed(e.to_string()))?;
let mut ms = ms::Builder::new_from_bls_signature(&signature)?;
if combined {
ms = ms.with_message_bytes(&msg);
}
Ok(ms.try_build()?)
}
Codec::Bls12381G1PrivShare => {
let av = self.mk.threshold_attr_view()?;
let threshold = av.threshold()?;
let limit = av.limit()?;
let identifier = bytes_to_identifier(av.identifier()?)?;
let value = bytes_to_value(secret_bytes.as_slice())?;
let secret_key: SecretKeyShare<Bls12381G1Impl> =
SecretKeyShare(Share::with_identifier_and_value(identifier, value));
let signature = secret_key
.sign(sig_scheme, msg)
.map_err(|e| SignError::SigningFailed(e.to_string()))?;
let mut ms =
ms::Builder::new_from_bls_signature_share(threshold, limit, &signature)?;
if combined {
ms = ms.with_message_bytes(&msg);
}
Ok(ms.try_build()?)
}
Codec::Bls12381G2Priv => {
let bytes: [u8; SECRET_KEY_BYTES] = secret_bytes.as_slice()[..SECRET_KEY_BYTES]
.try_into()
.map_err(|_| {
ConversionsError::SecretKeyFailure(
"failed to get secret key bytes".to_string(),
)
})?;
let secret_key: SecretKey<Bls12381G2Impl> = {
let sk = Option::from(SecretKey::from_be_bytes(&bytes));
sk.ok_or(ConversionsError::SecretKeyFailure(
"failed to create secret key".to_string(),
))?
};
let signature = secret_key
.sign(sig_scheme, msg)
.map_err(|e| SignError::SigningFailed(e.to_string()))?;
let mut ms = ms::Builder::new_from_bls_signature(&signature)?;
if combined {
ms = ms.with_message_bytes(&msg);
}
Ok(ms.try_build()?)
}
Codec::Bls12381G2PrivShare => {
let av = self.mk.threshold_attr_view()?;
let threshold = av.threshold()?;
let limit = av.limit()?;
let identifier = bytes_to_identifier(av.identifier()?)?;
let value = bytes_to_value(secret_bytes.as_slice())?;
let secret_key: SecretKeyShare<Bls12381G2Impl> =
SecretKeyShare(Share::with_identifier_and_value(identifier, value));
let signature = secret_key
.sign(sig_scheme, msg)
.map_err(|e| SignError::SigningFailed(e.to_string()))?;
let mut ms =
ms::Builder::new_from_bls_signature_share(threshold, limit, &signature)?;
if combined {
ms = ms.with_message_bytes(&msg);
}
Ok(ms.try_build()?)
}
_ => Err(ConversionsError::UnsupportedCodec(self.mk.codec).into()),
}
}
}
impl<'a> ThresholdView for View<'a> {
fn split(&self, threshold: usize, limit: usize) -> Result<Vec<Multikey>, Error> {
if threshold > limit {
return Err(ThresholdError::InvalidThresholdLimit(threshold, limit).into());
}
let attr = self.mk.attr_view()?;
if !attr.is_secret_key() {
return Err(ThresholdError::NotASecretKey.into());
}
let secret_bytes = {
let kd = self.mk.data_view()?;
kd.secret_bytes()?
};
match self.mk.codec {
Codec::Bls12381G1Priv => {
let bytes: [u8; SECRET_KEY_BYTES] = secret_bytes.as_slice()[..SECRET_KEY_BYTES]
.try_into()
.map_err(|_| {
ConversionsError::SecretKeyFailure(
"failed to get secret key bytes".to_string(),
)
})?;
let secret_key: SecretKey<Bls12381G1Impl> = {
let sk = Option::from(SecretKey::from_be_bytes(&bytes));
sk.ok_or(ConversionsError::SecretKeyFailure(
"failed to create secret key".to_string(),
))?
};
let key_shares = secret_key
.split(threshold, limit)
.map_err(ThresholdError::Bls)?;
let mut shares = Vec::with_capacity(key_shares.len());
key_shares
.iter()
.try_for_each(|share| -> Result<(), Error> {
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)
.with_key_bytes(&key_bytes)
.with_threshold(threshold)
.with_limit(limit)
.with_identifier(&identifier)
.try_build()?;
shares.push(mk);
Ok(())
})?;
Ok(shares)
}
Codec::Bls12381G2Priv => {
let bytes: [u8; SECRET_KEY_BYTES] = secret_bytes.as_slice()[..SECRET_KEY_BYTES]
.try_into()
.map_err(|_| {
ConversionsError::SecretKeyFailure(
"failed to get secret key bytes".to_string(),
)
})?;
let secret_key: SecretKey<Bls12381G2Impl> = {
let sk = Option::from(SecretKey::from_be_bytes(&bytes));
sk.ok_or(ConversionsError::SecretKeyFailure(
"failed to create secret key".to_string(),
))?
};
let key_shares = secret_key
.split(threshold, limit)
.map_err(ThresholdError::Bls)?;
let mut shares = Vec::with_capacity(key_shares.len());
key_shares
.iter()
.try_for_each(|share| -> Result<(), Error> {
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)
.with_key_bytes(&key_bytes)
.with_threshold(threshold)
.with_limit(limit)
.with_identifier(&identifier)
.try_build()?;
shares.push(mk);
Ok(())
})?;
Ok(shares)
}
_ => Err(ConversionsError::UnsupportedCodec(self.mk.codec).into()),
}
}
fn add_share(&self, share: &Multikey) -> Result<Multikey, Error> {
match self.mk.codec {
Codec::Bls12381G1Priv | Codec::Bls12381G2Priv => {}
Codec::Bls12381G1Pub | Codec::Bls12381G2Pub => {
return Err(ThresholdError::NotASecretKey.into())
}
Codec::Bls12381G1PubShare
| Codec::Bls12381G1PrivShare
| Codec::Bls12381G2PubShare
| Codec::Bls12381G2PrivShare => return Err(ThresholdError::IsAKeyShare.into()),
_ => return Err(Error::UnsupportedAlgorithm(self.mk.codec.to_string())),
}
let (key_share, identifier, threshold, limit) = {
let av = share.threshold_attr_view()?;
let identifier = bytes_to_identifier(av.identifier()?)?;
let threshold = av.threshold()?;
let limit = av.limit()?;
let dv = share.data_view()?;
let key_bytes = dv.key_bytes()?;
(
KeyShare(identifier, threshold, limit, key_bytes.to_vec()),
identifier,
threshold,
limit,
)
};
let threshold_data: Vec<u8> = {
let av = self.mk.threshold_attr_view()?;
let mut tdata = match av.threshold_data() {
Ok(b) => ThresholdData::try_from(b).unwrap_or_default(),
Err(_) => ThresholdData::default(),
};
tdata.0.insert(identifier, key_share);
tdata.into()
};
let av = share.threshold_attr_view()?;
let threshold = av.threshold().unwrap_or(threshold);
let limit = av.limit().unwrap_or(limit);
let comment = if self.mk.comment.is_empty() {
share.comment.clone()
} else {
String::default()
};
Builder::new(self.mk.codec)
.with_comment(&comment)
.with_threshold(threshold)
.with_limit(limit)
.with_threshold_data(&threshold_data)
.try_build()
}
fn combine(&self) -> Result<Multikey, Error> {
let (threshold_data, threshold) = {
let av = self.mk.threshold_attr_view()?;
(
match av.threshold_data() {
Ok(b) => ThresholdData::try_from(b).unwrap_or_default(),
Err(_) => ThresholdData::default(),
},
av.threshold()?,
)
};
let num_shares = threshold_data.0.len();
if num_shares < threshold {
return Err(ThresholdError::NotEnoughShares.into());
}
match self.mk.codec {
Codec::Bls12381G1Priv => {
let mut shares = Vec::with_capacity(threshold_data.0.len());
threshold_data
.0
.iter()
.try_for_each(|(id, share)| -> Result<(), Error> {
let value = bytes_to_value(share.3.as_slice())?;
let vsss = Share::with_identifier_and_value(*id, value);
shares.push(SecretKeyShare::<Bls12381G1Impl>(vsss));
Ok(())
})?;
let key = SecretKey::combine(shares.as_slice())
.map_err(|e| ThresholdError::ShareCombineFailed(e.to_string()))?;
let key_bytes = key.to_be_bytes().to_vec();
Builder::new(Codec::Bls12381G1Priv)
.with_comment(&self.mk.comment)
.with_key_bytes(&key_bytes)
.try_build()
}
Codec::Bls12381G2Priv => {
let mut shares = Vec::with_capacity(threshold_data.0.len());
threshold_data
.0
.iter()
.try_for_each(|(id, share)| -> Result<(), Error> {
let value = bytes_to_value(share.3.as_slice())?;
let vsss = Share::with_identifier_and_value(*id, value);
shares.push(SecretKeyShare::<Bls12381G2Impl>(vsss));
Ok(())
})?;
let key = SecretKey::combine(shares.as_slice())
.map_err(|e| ThresholdError::ShareCombineFailed(e.to_string()))?;
let key_bytes = key.to_be_bytes().to_vec();
Builder::new(Codec::Bls12381G2Priv)
.with_comment(&self.mk.comment)
.with_key_bytes(&key_bytes)
.try_build()
}
_ => Err(Error::UnsupportedAlgorithm(self.mk.codec.to_string())),
}
}
fn split_with_disclosure(
&self,
threshold: usize,
limit: usize,
mode: ThresholdDisclosure,
meta_key: Option<&Multikey>,
) -> Result<Vec<Multikey>, Error> {
let shares = self.split(threshold, limit)?;
shares
.iter()
.map(|s| s.disclosure_view()?.to_disclosure(mode, meta_key, None))
.collect()
}
fn add_share_with_meta(
&self,
share: &Multikey,
meta_key: Option<&Multikey>,
) -> Result<Multikey, Error> {
let (share_t, share_n) = threshold_meta::read_threshold_params(share, meta_key)?;
let (key_share, identifier) = {
let av = share.threshold_attr_view()?;
let identifier = bytes_to_identifier(av.identifier()?)?;
let dv = share.data_view()?;
let key_bytes = dv.key_bytes()?;
(
KeyShare(identifier, share_t, share_n, key_bytes.to_vec()),
identifier,
)
};
let threshold_data: Vec<u8> = {
let av = self.mk.threshold_attr_view()?;
let mut tdata = match av.threshold_data() {
Ok(b) => ThresholdData::try_from(b)
.map_err(|e| ThresholdError::ShareCombineFailed(e.to_string()))?,
Err(_) => ThresholdData::default(),
};
if tdata.0.contains_key(&identifier) {
return Err(ThresholdError::DuplicateShare.into());
}
tdata.0.insert(identifier, key_share);
tdata.into()
};
let comment = if self.mk.comment.is_empty() {
share.comment.clone()
} else {
self.mk.comment.clone()
};
let builder = Builder::new(self.mk.codec)
.with_comment(&comment)
.with_threshold(share_t)
.with_limit(share_n)
.with_threshold_data(&threshold_data);
builder.try_build()
}
fn combine_with_meta(&self, meta_key: Option<&Multikey>) -> Result<Multikey, Error> {
let (threshold, _limit) = threshold_meta::read_threshold_params(self.mk, meta_key)?;
let threshold_data = {
let av = self.mk.threshold_attr_view()?;
match av.threshold_data() {
Ok(b) => ThresholdData::try_from(b)
.map_err(|e| ThresholdError::ShareCombineFailed(e.to_string()))?,
Err(_) => ThresholdData::default(),
}
};
let num_shares = threshold_data.0.len();
if num_shares < threshold {
return Err(ThresholdError::NotEnoughShares.into());
}
match self.mk.codec {
Codec::Bls12381G1Priv => {
let mut shares = Vec::with_capacity(threshold_data.0.len());
threshold_data
.0
.iter()
.try_for_each(|(id, share)| -> Result<(), Error> {
let value = bytes_to_value(share.3.as_slice())?;
let vsss = Share::with_identifier_and_value(*id, value);
shares.push(SecretKeyShare::<Bls12381G1Impl>(vsss));
Ok(())
})?;
let key = SecretKey::combine(shares.as_slice())
.map_err(|e| ThresholdError::ShareCombineFailed(e.to_string()))?;
let key_bytes = key.to_be_bytes().to_vec();
Builder::new(Codec::Bls12381G1Priv)
.with_comment(&self.mk.comment)
.with_key_bytes(&key_bytes)
.try_build()
}
Codec::Bls12381G2Priv => {
let mut shares = Vec::with_capacity(threshold_data.0.len());
threshold_data
.0
.iter()
.try_for_each(|(id, share)| -> Result<(), Error> {
let value = bytes_to_value(share.3.as_slice())?;
let vsss = Share::with_identifier_and_value(*id, value);
shares.push(SecretKeyShare::<Bls12381G2Impl>(vsss));
Ok(())
})?;
let key = SecretKey::combine(shares.as_slice())
.map_err(|e| ThresholdError::ShareCombineFailed(e.to_string()))?;
let key_bytes = key.to_be_bytes().to_vec();
Builder::new(Codec::Bls12381G2Priv)
.with_comment(&self.mk.comment)
.with_key_bytes(&key_bytes)
.try_build()
}
_ => Err(Error::UnsupportedAlgorithm(self.mk.codec.to_string())),
}
}
}
impl<'a> VerifyView for View<'a> {
fn verify(&self, multisig: &Multisig, msg: Option<&[u8]>) -> Result<(), Error> {
let attr = self.mk.attr_view()?;
let pubmk = if attr.is_secret_key() {
let kc = self.mk.conv_view()?;
kc.to_public_key()?
} else {
self.mk.clone()
};
let key_bytes = {
let kd = pubmk.data_view()?;
let key_bytes = kd.key_bytes()?;
key_bytes.to_vec()
};
let av = multisig.attr_view()?;
let sig_scheme = SchemeTypeId::try_from(av.scheme()?)?;
match pubmk.codec {
Codec::Bls12381G1Pub => {
let public_key = PublicKey::try_from(&key_bytes)
.map_err(|e| ConversionsError::PublicKeyFailure(e.to_string()))?;
let sv = multisig.data_view()?;
let sig = sv.sig_bytes().map_err(|_| VerifyError::MissingSignature)?;
let group_encoding: G1Projective = {
let bytes: [u8; G1_PUBLIC_KEY_BYTES] = sig.as_slice()[..G1_PUBLIC_KEY_BYTES]
.try_into()
.map_err(|e: TryFromSliceError| VerifyError::BadSignature(e.to_string()))?;
let res = Option::from(G1Projective::from_compressed(&bytes));
res.ok_or(VerifyError::BadSignature(
"failed to deserialize group encoding".to_string(),
))?
};
let sig = match sig_scheme {
SchemeTypeId::Basic => Signature::<Bls12381G1Impl>::Basic(group_encoding),
SchemeTypeId::MessageAugmentation => {
Signature::<Bls12381G1Impl>::MessageAugmentation(group_encoding)
}
SchemeTypeId::ProofOfPossession => {
Signature::<Bls12381G1Impl>::ProofOfPossession(group_encoding)
}
};
let msg = if let Some(msg) = msg {
msg
} else if !multisig.message.is_empty() {
multisig.message.as_slice()
} else {
return Err(VerifyError::MissingMessage.into());
};
Ok(sig
.verify(&public_key, msg)
.map_err(|e| VerifyError::BadSignature(e.to_string()))?)
}
Codec::Bls12381G1PubShare => {
let pk_bytes: [u8; 96] = key_bytes.as_slice().try_into().map_err(|_| {
ConversionsError::PublicKeyFailure("Invalid public key share bytes".to_string())
})?;
let pk_point: G2Projective = Option::from(G2Projective::from_compressed(&pk_bytes))
.ok_or(ConversionsError::PublicKeyFailure(
"Invalid public key share point".to_string(),
))?;
let pk_identifier = {
let pav = pubmk.threshold_attr_view()?;
bytes_to_identifier(pav.identifier()?)?
};
let public_key: PublicKeyShare<Bls12381G1Impl> = PublicKeyShare(
Share::with_identifier_and_value(pk_identifier, ValueGroup(pk_point)),
);
let av = multisig.threshold_attr_view()?;
let identifier = bytes_to_identifier(av.identifier()?)?;
let sv = multisig.data_view()?;
let value = sv.sig_bytes().map_err(|_| VerifyError::MissingSignature)?;
let bytes: [u8; 48] = value.as_slice().try_into().map_err(|_| {
VerifyError::BadSignature("Invalid signature share bytes".to_string())
})?;
let point = Option::from(G1Projective::from_compressed(&bytes)).ok_or(
VerifyError::BadSignature("Invalid signature share bytes".to_string()),
)?;
let share = Share::with_identifier_and_value(identifier, ValueGroup(point));
let sig = match sig_scheme {
SchemeTypeId::Basic => SignatureShare::<Bls12381G1Impl>::Basic(share),
SchemeTypeId::MessageAugmentation => {
SignatureShare::<Bls12381G1Impl>::MessageAugmentation(share)
}
SchemeTypeId::ProofOfPossession => {
SignatureShare::<Bls12381G1Impl>::ProofOfPossession(share)
}
};
let msg = if let Some(msg) = msg {
msg
} else if !multisig.message.is_empty() {
multisig.message.as_slice()
} else {
return Err(VerifyError::MissingMessage.into());
};
Ok(sig
.verify(&public_key, msg)
.map_err(|e| VerifyError::BadSignature(e.to_string()))?)
}
Codec::Bls12381G2Pub => {
let public_key = PublicKey::try_from(&key_bytes)
.map_err(|e| ConversionsError::PublicKeyFailure(e.to_string()))?;
let sv = multisig.data_view()?;
let sig = sv.sig_bytes().map_err(|_| VerifyError::MissingSignature)?;
let group_encoding: G2Projective = {
let bytes: [u8; G2_PUBLIC_KEY_BYTES] = sig.as_slice()[..G2_PUBLIC_KEY_BYTES]
.try_into()
.map_err(|e: TryFromSliceError| VerifyError::BadSignature(e.to_string()))?;
let res = Option::from(G2Projective::from_compressed(&bytes));
res.ok_or(VerifyError::BadSignature(
"failed to deserialize group encoding".to_string(),
))?
};
let sig = match sig_scheme {
SchemeTypeId::Basic => Signature::<Bls12381G2Impl>::Basic(group_encoding),
SchemeTypeId::MessageAugmentation => {
Signature::<Bls12381G2Impl>::MessageAugmentation(group_encoding)
}
SchemeTypeId::ProofOfPossession => {
Signature::<Bls12381G2Impl>::ProofOfPossession(group_encoding)
}
};
let msg = if let Some(msg) = msg {
msg
} else if !multisig.message.is_empty() {
multisig.message.as_slice()
} else {
return Err(VerifyError::MissingMessage.into());
};
Ok(sig
.verify(&public_key, msg)
.map_err(|e| VerifyError::BadSignature(e.to_string()))?)
}
Codec::Bls12381G2PubShare => {
let pk_bytes: [u8; 48] = key_bytes.as_slice().try_into().map_err(|_| {
ConversionsError::PublicKeyFailure("Invalid public key share bytes".to_string())
})?;
let pk_point: G1Projective = Option::from(G1Projective::from_compressed(&pk_bytes))
.ok_or(ConversionsError::PublicKeyFailure(
"Invalid public key share point".to_string(),
))?;
let pk_identifier = {
let pav = pubmk.threshold_attr_view()?;
bytes_to_identifier(pav.identifier()?)?
};
let public_key: PublicKeyShare<Bls12381G2Impl> = PublicKeyShare(
Share::with_identifier_and_value(pk_identifier, ValueGroup(pk_point)),
);
let av = multisig.threshold_attr_view()?;
let identifier = bytes_to_identifier(av.identifier()?)?;
let sv = multisig.data_view()?;
let value = sv.sig_bytes().map_err(|_| VerifyError::MissingSignature)?;
let bytes: [u8; 96] = value.as_slice().try_into().map_err(|_| {
VerifyError::BadSignature("Invalid signature share bytes".to_string())
})?;
let point: G2Projective = Option::from(G2Projective::from_compressed(&bytes))
.ok_or(VerifyError::BadSignature(
"Invalid signature share bytes".to_string(),
))?;
let share = Share::with_identifier_and_value(identifier, ValueGroup(point));
let sig = match sig_scheme {
SchemeTypeId::Basic => SignatureShare::<Bls12381G2Impl>::Basic(share),
SchemeTypeId::MessageAugmentation => {
SignatureShare::<Bls12381G2Impl>::MessageAugmentation(share)
}
SchemeTypeId::ProofOfPossession => {
SignatureShare::<Bls12381G2Impl>::ProofOfPossession(share)
}
};
let msg = if let Some(msg) = msg {
msg
} else if !multisig.message.is_empty() {
multisig.message.as_slice()
} else {
return Err(VerifyError::MissingMessage.into());
};
Ok(sig
.verify(&public_key, msg)
.map_err(|e| VerifyError::BadSignature(e.to_string()))?)
}
_ => Err(ConversionsError::UnsupportedCodec(self.mk.codec).into()),
}
}
}
impl<'a> SealView for View<'a> {
fn seal(
&self,
plaintext: &[u8],
_aead_codec: Codec,
_aad: &[u8],
) -> Result<(Vec<u8>, Option<Multikey>), Error> {
let attr = self.mk.attr_view()?;
if !attr.is_public_key() {
return Err(SealError::NotEncapsulationKey.into());
}
let key_bytes = self.mk.data_view()?.key_bytes()?;
let mut id = [0u8; 32];
rand::rng().fill_bytes(&mut id);
match self.mk.codec {
Codec::Bls12381G1Pub => {
let pub_key = PublicKey::<Bls12381G1Impl>::try_from(key_bytes.as_slice())
.map_err(|e| SealError::EncapsulationFailed(e.to_string()))?;
let ct = pub_key
.encrypt_time_lock(SignatureSchemes::ProofOfPossession, plaintext, &id)
.map_err(|e| SealError::EncapsulationFailed(e.to_string()))?;
let mut out = Vec::new();
out.append(&mut Varbytes::new(id.to_vec()).into());
out.extend_from_slice(&Vec::from(&ct));
Ok((out, None))
}
Codec::Bls12381G2Pub => {
let pub_key = PublicKey::<Bls12381G2Impl>::try_from(key_bytes.as_slice())
.map_err(|e| SealError::EncapsulationFailed(e.to_string()))?;
let ct = pub_key
.encrypt_time_lock(SignatureSchemes::ProofOfPossession, plaintext, &id)
.map_err(|e| SealError::EncapsulationFailed(e.to_string()))?;
let mut out = Vec::new();
out.append(&mut Varbytes::new(id.to_vec()).into());
out.extend_from_slice(&Vec::from(&ct));
Ok((out, None))
}
_ => Err(SealError::NotEncapsulationKey.into()),
}
}
}
impl<'a> OpenView for View<'a> {
fn open(
&self,
sealed_msg: &[u8],
_ephemeral: Option<&Multikey>,
_aad: &[u8],
) -> Result<Zeroizing<Vec<u8>>, Error> {
let attr = self.mk.attr_view()?;
if !attr.is_secret_key() {
return Err(SealError::NotDecapsulationKey.into());
}
let secret_bytes = self.mk.data_view()?.secret_bytes()?;
let (id_vb, ct_bytes) = Varbytes::try_decode_from(sealed_msg)
.map_err(|_| SealError::InvalidFormat("missing TimeCrypt id".into()))?;
let id = id_vb.to_inner();
match self.mk.codec {
Codec::Bls12381G1Priv => {
let bytes: [u8; SECRET_KEY_BYTES] = secret_bytes.as_slice()[..SECRET_KEY_BYTES]
.try_into()
.map_err(|_| {
SealError::DecapsulationFailed("invalid BLS G1 secret key length".into())
})?;
let secret_key: SecretKey<Bls12381G1Impl> =
Option::from(SecretKey::from_be_bytes(&bytes)).ok_or_else(|| {
SealError::DecapsulationFailed("invalid BLS G1 secret key bytes".into())
})?;
let ct = TimeCryptCiphertext::<Bls12381G1Impl>::try_from(ct_bytes)
.map_err(|e| SealError::DecapsulationFailed(e.to_string()))?;
let sig = secret_key
.sign(ct.scheme, &id)
.map_err(|e| SealError::DecapsulationFailed(e.to_string()))?;
ct.decrypt(&sig)
.into_option()
.map(Zeroizing::new)
.ok_or_else(|| {
SealError::DecapsulationFailed("BLS TimeCrypt decryption failed".into())
.into()
})
}
Codec::Bls12381G2Priv => {
let bytes: [u8; SECRET_KEY_BYTES] = secret_bytes.as_slice()[..SECRET_KEY_BYTES]
.try_into()
.map_err(|_| {
SealError::DecapsulationFailed("invalid BLS G2 secret key length".into())
})?;
let secret_key: SecretKey<Bls12381G2Impl> =
Option::from(SecretKey::from_be_bytes(&bytes)).ok_or_else(|| {
SealError::DecapsulationFailed("invalid BLS G2 secret key bytes".into())
})?;
let ct = TimeCryptCiphertext::<Bls12381G2Impl>::try_from(ct_bytes)
.map_err(|e| SealError::DecapsulationFailed(e.to_string()))?;
let sig = secret_key
.sign(ct.scheme, &id)
.map_err(|e| SealError::DecapsulationFailed(e.to_string()))?;
ct.decrypt(&sig)
.into_option()
.map(Zeroizing::new)
.ok_or_else(|| {
SealError::DecapsulationFailed("BLS TimeCrypt decryption failed".into())
.into()
})
}
_ => Err(SealError::NotDecapsulationKey.into()),
}
}
}