use crate::{
ed25519::{Ed25519PrivateKey, Ed25519PublicKey, ED25519_SIGNATURE_LENGTH, L},
hash::CryptoHash,
traits::*,
};
use anyhow::{anyhow, Result};
use aptos_crypto_derive::{DeserializeKey, SerializeKey};
use core::convert::TryFrom;
use serde::Serialize;
use std::{cmp::Ordering, fmt};
#[derive(DeserializeKey, Clone, SerializeKey)]
pub struct Ed25519Signature(pub(crate) ed25519_dalek::Signature);
impl Ed25519Signature {
pub const LENGTH: usize = ed25519_dalek::SIGNATURE_LENGTH;
pub fn to_bytes(&self) -> [u8; ED25519_SIGNATURE_LENGTH] {
self.0.to_bytes()
}
pub(crate) fn from_bytes_unchecked(
bytes: &[u8],
) -> std::result::Result<Ed25519Signature, CryptoMaterialError> {
match ed25519_dalek::Signature::try_from(bytes) {
Ok(dalek_signature) => Ok(Ed25519Signature(dalek_signature)),
Err(_) => Err(CryptoMaterialError::DeserializationError),
}
}
#[cfg(any(test, feature = "fuzzing"))]
pub fn dummy_signature() -> Self {
Self::from_bytes_unchecked(&[0u8; Self::LENGTH]).unwrap()
}
pub fn check_s_malleability(bytes: &[u8]) -> std::result::Result<(), CryptoMaterialError> {
if bytes.len() != ED25519_SIGNATURE_LENGTH {
return Err(CryptoMaterialError::WrongLengthError);
}
if !Ed25519Signature::check_s_lt_l(&bytes[32..]) {
return Err(CryptoMaterialError::CanonicalRepresentationError);
}
Ok(())
}
fn check_s_lt_l(s: &[u8]) -> bool {
for i in (0..32).rev() {
match s[i].cmp(&L[i]) {
Ordering::Less => return true,
Ordering::Greater => return false,
_ => {}
}
}
false
}
}
impl Signature for Ed25519Signature {
type VerifyingKeyMaterial = Ed25519PublicKey;
type SigningKeyMaterial = Ed25519PrivateKey;
fn verify<T: CryptoHash + Serialize>(
&self,
message: &T,
public_key: &Ed25519PublicKey,
) -> Result<()> {
Self::verify_arbitrary_msg(self, &signing_message(message), public_key)
}
fn verify_arbitrary_msg(&self, message: &[u8], public_key: &Ed25519PublicKey) -> Result<()> {
Ed25519Signature::check_s_malleability(&self.to_bytes())?;
public_key
.0
.verify_strict(message, &self.0)
.map_err(|e| anyhow!("{}", e))
.and(Ok(()))
}
fn to_bytes(&self) -> Vec<u8> {
self.0.to_bytes().to_vec()
}
}
impl Length for Ed25519Signature {
fn length(&self) -> usize {
ED25519_SIGNATURE_LENGTH
}
}
impl ValidCryptoMaterial for Ed25519Signature {
fn to_bytes(&self) -> Vec<u8> {
self.to_bytes().to_vec()
}
}
impl std::hash::Hash for Ed25519Signature {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let encoded_signature = self.to_bytes();
state.write(&encoded_signature);
}
}
impl TryFrom<&[u8]> for Ed25519Signature {
type Error = CryptoMaterialError;
fn try_from(bytes: &[u8]) -> std::result::Result<Ed25519Signature, CryptoMaterialError> {
Ed25519Signature::check_s_malleability(bytes)?;
Ed25519Signature::from_bytes_unchecked(bytes)
}
}
impl PartialEq for Ed25519Signature {
fn eq(&self, other: &Ed25519Signature) -> bool {
self.to_bytes()[..] == other.to_bytes()[..]
}
}
impl Eq for Ed25519Signature {}
impl fmt::Display for Ed25519Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", hex::encode(&self.0.to_bytes()[..]))
}
}
impl fmt::Debug for Ed25519Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Ed25519Signature({})", self)
}
}