use crate::{
bls12381::{
bls12381_keys::{PrivateKey, PublicKey},
DST_BLS_SIG_IN_G2_WITH_POP,
},
hash::CryptoHash,
signing_message, traits, CryptoMaterialError, Length, ValidCryptoMaterial,
ValidCryptoMaterialStringExt,
};
use anyhow::{anyhow, Result};
use aptos_crypto_derive::{DeserializeKey, SerializeKey};
use blst::BLST_ERROR;
use serde::Serialize;
use std::convert::TryFrom;
#[derive(Debug, Clone, Eq, SerializeKey, DeserializeKey)]
pub struct Signature {
pub(crate) sig: blst::min_pk::Signature,
}
impl Signature {
pub const LENGTH: usize = 96;
pub fn to_bytes(&self) -> [u8; Self::LENGTH] {
self.sig.to_bytes()
}
pub fn group_check(&self) -> Result<()> {
self.sig.validate(true).map_err(|e| anyhow!("{:?}", e))
}
pub fn aggregate(sigs: Vec<Self>) -> Result<Signature> {
let sigs: Vec<_> = sigs.iter().map(|s| &s.sig).collect();
let agg_sig = blst::min_pk::AggregateSignature::aggregate(&sigs[..], false)
.map_err(|e| anyhow!("{:?}", e))?;
Ok(Signature {
sig: agg_sig.to_signature(),
})
}
pub fn verify_aggregate_arbitrary_msg(&self, msgs: &[&[u8]], pks: &[&PublicKey]) -> Result<()> {
let pks = pks
.iter()
.map(|&pk| &pk.pubkey)
.collect::<Vec<&blst::min_pk::PublicKey>>();
let result = self
.sig
.aggregate_verify(true, msgs, DST_BLS_SIG_IN_G2_WITH_POP, &pks, false);
if result == BLST_ERROR::BLST_SUCCESS {
Ok(())
} else {
Err(anyhow!("{:?}", result))
}
}
pub fn verify_aggregate<T: CryptoHash + Serialize>(
&self,
msgs: &[&T],
pks: &[&PublicKey],
) -> Result<()> {
let msgs = msgs
.iter()
.map(|&m| signing_message(m))
.collect::<Vec<Vec<u8>>>();
let msgs_refs = msgs.iter().map(|m| m.as_slice()).collect::<Vec<&[u8]>>();
self.verify_aggregate_arbitrary_msg(&msgs_refs, pks)
}
#[cfg(any(test, feature = "fuzzing"))]
pub fn dummy_signature() -> Self {
use crate::{Genesis, SigningKey};
let private_key = PrivateKey::genesis();
let msg = b"hello foo";
private_key.sign_arbitrary_message(msg)
}
}
impl traits::Signature for Signature {
type VerifyingKeyMaterial = PublicKey;
type SigningKeyMaterial = PrivateKey;
fn verify<T: CryptoHash + Serialize>(&self, message: &T, public_key: &PublicKey) -> Result<()> {
self.verify_arbitrary_msg(&signing_message(message), public_key)
}
fn verify_arbitrary_msg(&self, message: &[u8], public_key: &PublicKey) -> Result<()> {
let result = self.sig.verify(
true,
message,
DST_BLS_SIG_IN_G2_WITH_POP,
&[],
&public_key.pubkey,
false,
);
if result == BLST_ERROR::BLST_SUCCESS {
Ok(())
} else {
Err(anyhow!("{:?}", result))
}
}
fn to_bytes(&self) -> Vec<u8> {
self.to_bytes().to_vec()
}
}
impl ValidCryptoMaterial for Signature {
fn to_bytes(&self) -> Vec<u8> {
self.to_bytes().to_vec()
}
}
impl Length for Signature {
fn length(&self) -> usize {
Self::LENGTH
}
}
impl TryFrom<&[u8]> for Signature {
type Error = CryptoMaterialError;
fn try_from(bytes: &[u8]) -> std::result::Result<Signature, CryptoMaterialError> {
Ok(Self {
sig: blst::min_pk::Signature::from_bytes(bytes)
.map_err(|_| CryptoMaterialError::DeserializationError)?,
})
}
}
impl std::hash::Hash for Signature {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let encoded_signature = self.to_bytes();
state.write(&encoded_signature);
}
}
impl PartialEq for Signature {
fn eq(&self, other: &Self) -> bool {
self.to_bytes()[..] == other.to_bytes()[..]
}
}