use crate::{
bls12381, bls12381::DST_BLS_SIG_IN_G2_WITH_POP, hash::CryptoHash, signing_message, traits,
CryptoMaterialError, Genesis, Length, Uniform, ValidCryptoMaterial,
ValidCryptoMaterialStringExt, VerifyingKey,
};
use anyhow::{anyhow, Result};
use aptos_crypto_derive::{DeserializeKey, SerializeKey, SilentDebug, SilentDisplay};
use serde::Serialize;
use std::{convert::TryFrom, fmt};
#[derive(Clone, Debug, Eq, SerializeKey, DeserializeKey)]
pub struct PublicKey {
pub(crate) pubkey: blst::min_pk::PublicKey,
}
#[derive(SerializeKey, DeserializeKey, SilentDebug, SilentDisplay)]
pub struct PrivateKey {
pub(crate) privkey: blst::min_pk::SecretKey,
}
impl PublicKey {
pub const LENGTH: usize = 48;
pub fn to_bytes(&self) -> [u8; Self::LENGTH] {
self.pubkey.to_bytes()
}
pub fn group_check(&self) -> Result<()> {
self.pubkey.validate().map_err(|e| anyhow!("{:?}", e))
}
pub fn aggregate(pubkeys: Vec<&Self>) -> Result<PublicKey> {
let blst_pubkeys: Vec<_> = pubkeys.iter().map(|pk| &pk.pubkey).collect();
let aggpk = blst::min_pk::AggregatePublicKey::aggregate(&blst_pubkeys[..], false)
.map_err(|e| anyhow!("{:?}", e))?;
Ok(PublicKey {
pubkey: aggpk.to_public_key(),
})
}
}
impl PrivateKey {
pub const LENGTH: usize = 32;
pub fn to_bytes(&self) -> [u8; Self::LENGTH] {
self.privkey.to_bytes()
}
}
impl traits::PrivateKey for PrivateKey {
type PublicKeyMaterial = PublicKey;
}
impl traits::SigningKey for PrivateKey {
type VerifyingKeyMaterial = PublicKey;
type SignatureMaterial = bls12381::Signature;
fn sign<T: CryptoHash + Serialize>(&self, message: &T) -> bls12381::Signature {
bls12381::Signature {
sig: self
.privkey
.sign(&signing_message(message), DST_BLS_SIG_IN_G2_WITH_POP, &[]),
}
}
#[cfg(any(test, feature = "fuzzing"))]
fn sign_arbitrary_message(&self, message: &[u8]) -> bls12381::Signature {
bls12381::Signature {
sig: self.privkey.sign(message, DST_BLS_SIG_IN_G2_WITH_POP, &[]),
}
}
}
impl traits::ValidCryptoMaterial for PrivateKey {
fn to_bytes(&self) -> Vec<u8> {
self.to_bytes().to_vec()
}
}
impl Length for PrivateKey {
fn length(&self) -> usize {
Self::LENGTH
}
}
impl TryFrom<&[u8]> for PrivateKey {
type Error = CryptoMaterialError;
fn try_from(bytes: &[u8]) -> std::result::Result<Self, CryptoMaterialError> {
Ok(Self {
privkey: blst::min_pk::SecretKey::from_bytes(bytes)
.map_err(|_| CryptoMaterialError::DeserializationError)?,
})
}
}
impl Uniform for PrivateKey {
fn generate<R>(rng: &mut R) -> Self
where
R: ::rand::RngCore + ::rand::CryptoRng,
{
let mut ikm = [0u8; 32];
rng.fill_bytes(&mut ikm);
let privkey =
blst::min_pk::SecretKey::key_gen(&ikm, &[]).expect("ikm length should be higher");
Self { privkey }
}
}
impl Genesis for PrivateKey {
fn genesis() -> Self {
let mut buf = [0u8; Self::LENGTH];
buf[Self::LENGTH - 1] = 1;
Self::try_from(buf.as_ref()).unwrap()
}
}
#[cfg(feature = "assert-private-keys-not-cloneable")]
static_assertions::assert_not_impl_any!(PrivateKey: Clone);
#[cfg(any(test, feature = "cloneable-private-keys"))]
impl Clone for PrivateKey {
fn clone(&self) -> Self {
let serialized: &[u8] = &(self.to_bytes());
PrivateKey::try_from(serialized).unwrap()
}
}
impl From<&PrivateKey> for PublicKey {
fn from(private_key: &PrivateKey) -> Self {
Self {
pubkey: private_key.privkey.sk_to_pk(),
}
}
}
impl traits::PublicKey for PublicKey {
type PrivateKeyMaterial = PrivateKey;
}
impl VerifyingKey for PublicKey {
type SigningKeyMaterial = PrivateKey;
type SignatureMaterial = bls12381::Signature;
}
impl ValidCryptoMaterial for PublicKey {
fn to_bytes(&self) -> Vec<u8> {
self.to_bytes().to_vec()
}
}
impl Length for PublicKey {
fn length(&self) -> usize {
Self::LENGTH
}
}
impl TryFrom<&[u8]> for PublicKey {
type Error = CryptoMaterialError;
fn try_from(bytes: &[u8]) -> std::result::Result<Self, CryptoMaterialError> {
Ok(Self {
pubkey: blst::min_pk::PublicKey::from_bytes(bytes)
.map_err(|_| CryptoMaterialError::DeserializationError)?,
})
}
}
impl std::hash::Hash for PublicKey {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let encoded_pubkey = self.to_bytes();
state.write(&encoded_pubkey);
}
}
impl PartialEq for PublicKey {
fn eq(&self, other: &Self) -> bool {
self.to_bytes()[..] == other.to_bytes()[..]
}
}
impl fmt::Display for PublicKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", hex::encode(&self.to_bytes()))
}
}
#[cfg(any(test, feature = "fuzzing"))]
use crate::test_utils::KeyPair;
#[cfg(any(test, feature = "fuzzing"))]
use proptest::prelude::*;
#[cfg(any(test, feature = "fuzzing"))]
pub fn keypair_strategy() -> impl Strategy<Value = KeyPair<PrivateKey, PublicKey>> {
crate::test_utils::uniform_keypair_strategy::<PrivateKey, PublicKey>()
}
#[cfg(any(test, feature = "fuzzing"))]
impl proptest::arbitrary::Arbitrary for PublicKey {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
crate::test_utils::uniform_keypair_strategy::<PrivateKey, PublicKey>()
.prop_map(|v| v.public_key)
.boxed()
}
}