use crate::{
ed25519::{Ed25519Signature, ED25519_PRIVATE_KEY_LENGTH, ED25519_PUBLIC_KEY_LENGTH},
hash::CryptoHash,
traits::*,
};
use aptos_crypto_derive::{DeserializeKey, SerializeKey, SilentDebug, SilentDisplay};
use core::convert::TryFrom;
use serde::Serialize;
use std::fmt;
#[cfg(any(test, feature = "fuzzing"))]
use crate::test_utils::{self, KeyPair};
#[cfg(any(test, feature = "fuzzing"))]
use proptest::prelude::*;
#[derive(DeserializeKey, SerializeKey, SilentDebug, SilentDisplay)]
pub struct Ed25519PrivateKey(pub(crate) ed25519_dalek::SecretKey);
#[cfg(feature = "assert-private-keys-not-cloneable")]
static_assertions::assert_not_impl_any!(Ed25519PrivateKey: Clone);
#[cfg(any(test, feature = "cloneable-private-keys"))]
impl Clone for Ed25519PrivateKey {
fn clone(&self) -> Self {
let serialized: &[u8] = &(self.to_bytes());
Ed25519PrivateKey::try_from(serialized).unwrap()
}
}
#[derive(DeserializeKey, Clone, SerializeKey)]
pub struct Ed25519PublicKey(pub(crate) ed25519_dalek::PublicKey);
impl Ed25519PrivateKey {
pub const LENGTH: usize = ed25519_dalek::SECRET_KEY_LENGTH;
pub fn to_bytes(&self) -> [u8; ED25519_PRIVATE_KEY_LENGTH] {
self.0.to_bytes()
}
fn from_bytes_unchecked(
bytes: &[u8],
) -> std::result::Result<Ed25519PrivateKey, CryptoMaterialError> {
match ed25519_dalek::SecretKey::from_bytes(bytes) {
Ok(dalek_secret_key) => Ok(Ed25519PrivateKey(dalek_secret_key)),
Err(_) => Err(CryptoMaterialError::DeserializationError),
}
}
fn sign_arbitrary_message(&self, message: &[u8]) -> Ed25519Signature {
let secret_key: &ed25519_dalek::SecretKey = &self.0;
let public_key: Ed25519PublicKey = self.into();
let expanded_secret_key: ed25519_dalek::ExpandedSecretKey =
ed25519_dalek::ExpandedSecretKey::from(secret_key);
let sig = expanded_secret_key.sign(message.as_ref(), &public_key.0);
Ed25519Signature(sig)
}
}
impl Ed25519PublicKey {
pub fn to_bytes(&self) -> [u8; ED25519_PUBLIC_KEY_LENGTH] {
self.0.to_bytes()
}
pub(crate) fn from_bytes_unchecked(
bytes: &[u8],
) -> std::result::Result<Ed25519PublicKey, CryptoMaterialError> {
match ed25519_dalek::PublicKey::from_bytes(bytes) {
Ok(dalek_public_key) => Ok(Ed25519PublicKey(dalek_public_key)),
Err(_) => Err(CryptoMaterialError::DeserializationError),
}
}
#[cfg(test)]
pub(crate) fn from_x25519_public_bytes(
x25519_bytes: &[u8],
negative: bool,
) -> Result<Self, CryptoMaterialError> {
if x25519_bytes.len() != 32 {
return Err(CryptoMaterialError::DeserializationError);
}
let key_bits = {
let mut bits = [0u8; 32];
bits.copy_from_slice(x25519_bytes);
bits
};
let mtg_point = curve25519_dalek::montgomery::MontgomeryPoint(key_bits);
let sign = if negative { 1u8 } else { 0u8 };
let ed_point = mtg_point
.to_edwards(sign)
.ok_or(CryptoMaterialError::DeserializationError)?;
Ed25519PublicKey::try_from(&ed_point.compress().as_bytes()[..])
}
}
impl PrivateKey for Ed25519PrivateKey {
type PublicKeyMaterial = Ed25519PublicKey;
}
impl SigningKey for Ed25519PrivateKey {
type VerifyingKeyMaterial = Ed25519PublicKey;
type SignatureMaterial = Ed25519Signature;
fn sign<T: CryptoHash + Serialize>(&self, message: &T) -> Ed25519Signature {
Ed25519PrivateKey::sign_arbitrary_message(self, signing_message(message).as_ref())
}
#[cfg(any(test, feature = "fuzzing"))]
fn sign_arbitrary_message(&self, message: &[u8]) -> Ed25519Signature {
Ed25519PrivateKey::sign_arbitrary_message(self, message)
}
}
impl Uniform for Ed25519PrivateKey {
fn generate<R>(rng: &mut R) -> Self
where
R: ::rand::RngCore + ::rand::CryptoRng + ::rand_core::CryptoRng + ::rand_core::RngCore,
{
Ed25519PrivateKey(ed25519_dalek::SecretKey::generate(rng))
}
}
impl PartialEq<Self> for Ed25519PrivateKey {
fn eq(&self, other: &Self) -> bool {
self.to_bytes() == other.to_bytes()
}
}
impl Eq for Ed25519PrivateKey {}
impl TryFrom<&[u8]> for Ed25519PrivateKey {
type Error = CryptoMaterialError;
fn try_from(bytes: &[u8]) -> std::result::Result<Ed25519PrivateKey, CryptoMaterialError> {
Ed25519PrivateKey::from_bytes_unchecked(bytes)
}
}
impl Length for Ed25519PrivateKey {
fn length(&self) -> usize {
Self::LENGTH
}
}
impl ValidCryptoMaterial for Ed25519PrivateKey {
fn to_bytes(&self) -> Vec<u8> {
self.to_bytes().to_vec()
}
}
impl Genesis for Ed25519PrivateKey {
fn genesis() -> Self {
let mut buf = [0u8; ED25519_PRIVATE_KEY_LENGTH];
buf[ED25519_PRIVATE_KEY_LENGTH - 1] = 1;
Self::try_from(buf.as_ref()).unwrap()
}
}
impl From<&Ed25519PrivateKey> for Ed25519PublicKey {
fn from(private_key: &Ed25519PrivateKey) -> Self {
let secret: &ed25519_dalek::SecretKey = &private_key.0;
let public: ed25519_dalek::PublicKey = secret.into();
Ed25519PublicKey(public)
}
}
impl PublicKey for Ed25519PublicKey {
type PrivateKeyMaterial = Ed25519PrivateKey;
}
impl std::hash::Hash for Ed25519PublicKey {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let encoded_pubkey = self.to_bytes();
state.write(&encoded_pubkey);
}
}
impl PartialEq for Ed25519PublicKey {
fn eq(&self, other: &Ed25519PublicKey) -> bool {
self.to_bytes() == other.to_bytes()
}
}
impl Eq for Ed25519PublicKey {}
impl VerifyingKey for Ed25519PublicKey {
type SigningKeyMaterial = Ed25519PrivateKey;
type SignatureMaterial = Ed25519Signature;
}
impl fmt::Display for Ed25519PublicKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", hex::encode(&self.0.as_bytes()))
}
}
impl fmt::Debug for Ed25519PublicKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Ed25519PublicKey({})", self)
}
}
impl TryFrom<&[u8]> for Ed25519PublicKey {
type Error = CryptoMaterialError;
fn try_from(bytes: &[u8]) -> std::result::Result<Ed25519PublicKey, CryptoMaterialError> {
Ed25519PublicKey::from_bytes_unchecked(bytes)
}
}
impl Length for Ed25519PublicKey {
fn length(&self) -> usize {
ED25519_PUBLIC_KEY_LENGTH
}
}
impl ValidCryptoMaterial for Ed25519PublicKey {
fn to_bytes(&self) -> Vec<u8> {
self.0.to_bytes().to_vec()
}
}
#[cfg(any(test, feature = "fuzzing"))]
pub fn keypair_strategy() -> impl Strategy<Value = KeyPair<Ed25519PrivateKey, Ed25519PublicKey>> {
test_utils::uniform_keypair_strategy::<Ed25519PrivateKey, Ed25519PublicKey>()
}
#[cfg(any(test, feature = "fuzzing"))]
impl proptest::arbitrary::Arbitrary for Ed25519PublicKey {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
crate::test_utils::uniform_keypair_strategy::<Ed25519PrivateKey, Ed25519PublicKey>()
.prop_map(|v| v.public_key)
.boxed()
}
}