use crate::{
bls12381::bls12381_keys::{PrivateKey, PublicKey},
CryptoMaterialError, Length, ValidCryptoMaterial, ValidCryptoMaterialStringExt,
};
use anyhow::{anyhow, Result};
use aptos_crypto_derive::{DeserializeKey, SerializeKey};
use blst::BLST_ERROR;
use std::convert::TryFrom;
const DST_BLS_POP_IN_G2: &[u8] = b"BLS_POP_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_";
#[derive(Debug, Clone, SerializeKey, DeserializeKey)]
pub struct ProofOfPossession {
pub(crate) pop: blst::min_pk::Signature,
}
impl ProofOfPossession {
pub const LENGTH: usize = 96;
pub fn to_bytes(&self) -> [u8; Self::LENGTH] {
self.pop.to_bytes()
}
pub fn group_check(&self) -> Result<()> {
self.pop.validate(true).map_err(|e| anyhow!("{:?}", e))
}
pub fn verify(&self, pk: &PublicKey) -> Result<()> {
let result = self.pop.verify(
true,
&pk.to_bytes(),
DST_BLS_POP_IN_G2,
&[],
&pk.pubkey,
true,
);
if result == BLST_ERROR::BLST_SUCCESS {
Ok(())
} else {
Err(anyhow!(
"Proof-of-possession (PoP) did NOT verify: {:?}",
result
))
}
}
pub fn create(sk: &PrivateKey) -> ProofOfPossession {
let pk = PublicKey {
pubkey: sk.privkey.sk_to_pk(),
};
ProofOfPossession::create_with_pubkey(sk, &pk)
}
pub fn create_with_pubkey(sk: &PrivateKey, pk: &PublicKey) -> ProofOfPossession {
let pk_bytes = pk.to_bytes();
ProofOfPossession {
pop: sk.privkey.sign(&pk_bytes, DST_BLS_POP_IN_G2, &[]),
}
}
}
impl ValidCryptoMaterial for ProofOfPossession {
fn to_bytes(&self) -> Vec<u8> {
self.to_bytes().to_vec()
}
}
impl Length for ProofOfPossession {
fn length(&self) -> usize {
Self::LENGTH
}
}
impl TryFrom<&[u8]> for ProofOfPossession {
type Error = CryptoMaterialError;
fn try_from(bytes: &[u8]) -> std::result::Result<ProofOfPossession, CryptoMaterialError> {
Ok(Self {
pop: blst::min_pk::Signature::from_bytes(bytes)
.map_err(|_| CryptoMaterialError::DeserializationError)?,
})
}
}
impl std::hash::Hash for ProofOfPossession {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let encoded_signature = self.to_bytes();
state.write(&encoded_signature);
}
}