use crate::common::CryptoError;
use ed25519_dalek::{
Signature as DalekSignature, SigningKey as DalekSigningKey, VerifyingKey as DalekVerifyingKey,
};
use ed25519_dalek::{Signer, Verifier};
const SEED_SIZE: usize = 32;
const VERIFICATION_KEY_SIZE: usize = 32;
const SIGNATURE_SIZE: usize = 64;
const SECRET_COMPOUND_SIZE: usize = 64;
#[derive(Clone, PartialEq, Eq)]
pub struct Ed25519VerificationKey([u8; VERIFICATION_KEY_SIZE]);
impl core::fmt::Debug for Ed25519VerificationKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Ed25519VerificationKey(<{} bytes>)", self.0.len())
}
}
impl Ed25519VerificationKey {
#[inline]
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
if bytes.len() != VERIFICATION_KEY_SIZE {
return None;
}
let mut array = [0u8; VERIFICATION_KEY_SIZE];
array.copy_from_slice(bytes);
DalekVerifyingKey::from_bytes(&array).ok()?;
Some(Self(array))
}
#[inline]
#[must_use]
pub fn as_bytes(&self) -> &[u8; VERIFICATION_KEY_SIZE] {
&self.0
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct Ed25519SigningKey([u8; SECRET_COMPOUND_SIZE]);
impl core::fmt::Debug for Ed25519SigningKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Ed25519SigningKey([REDACTED])")
}
}
impl Ed25519SigningKey {
#[inline]
pub fn from_seed_bytes(seed: &[u8]) -> Self {
let mut seed_array = [0u8; SEED_SIZE];
seed_array.copy_from_slice(seed);
let signing_key = DalekSigningKey::from_bytes(&seed_array);
let verifying_key = signing_key.verifying_key();
let mut compound = [0u8; SECRET_COMPOUND_SIZE];
compound[..SEED_SIZE].copy_from_slice(&seed_array);
compound[SEED_SIZE..].copy_from_slice(&verifying_key.to_bytes());
Self(compound)
}
#[inline]
#[must_use]
pub fn seed_bytes(&self) -> [u8; SEED_SIZE] {
let mut seed = [0u8; SEED_SIZE];
seed.copy_from_slice(&self.0[..SEED_SIZE]);
seed
}
#[inline]
#[must_use]
pub fn verifying_bytes(&self) -> [u8; VERIFICATION_KEY_SIZE] {
let mut vk = [0u8; VERIFICATION_KEY_SIZE];
vk.copy_from_slice(&self.0[SEED_SIZE..]);
vk
}
#[inline]
fn signing_key(&self) -> DalekSigningKey {
let seed = self.seed_bytes();
DalekSigningKey::from_bytes(&seed)
}
#[inline]
#[must_use]
pub fn compound_bytes(&self) -> &[u8; SECRET_COMPOUND_SIZE] {
&self.0
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct Ed25519Signature([u8; SIGNATURE_SIZE]);
impl core::fmt::Debug for Ed25519Signature {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Ed25519Signature(<{} bytes>)", self.0.len())
}
}
impl Ed25519Signature {
#[inline]
#[must_use]
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
if bytes.len() != SIGNATURE_SIZE {
return None;
}
let mut arr = [0u8; SIGNATURE_SIZE];
arr.copy_from_slice(bytes);
Some(Self(arr))
}
#[inline]
#[must_use]
pub fn from_dalek(signature: &DalekSignature) -> Self {
Self(signature.to_bytes())
}
#[inline]
#[must_use]
pub fn as_bytes(&self) -> &[u8; SIGNATURE_SIZE] {
&self.0
}
}
#[derive(Clone, Debug)]
pub struct Ed25519;
impl super::DsignAlgorithm for Ed25519 {
type SigningKey = Ed25519SigningKey;
type VerificationKey = Ed25519VerificationKey;
type Signature = Ed25519Signature;
const ALGORITHM_NAME: &'static str = "Ed25519";
const SIGNING_KEY_SIZE: usize = SECRET_COMPOUND_SIZE;
const VERIFICATION_KEY_SIZE: usize = VERIFICATION_KEY_SIZE;
const SIGNATURE_SIZE: usize = SIGNATURE_SIZE;
fn derive_verification_key(signing_key: &Self::SigningKey) -> Self::VerificationKey {
let mut bytes = [0u8; VERIFICATION_KEY_SIZE];
bytes.copy_from_slice(&signing_key.verifying_bytes());
Ed25519VerificationKey(bytes)
}
fn sign(signing_key: &Self::SigningKey, message: &[u8]) -> Self::Signature {
let signing_key = signing_key.signing_key();
let signature = signing_key.sign(message);
Ed25519Signature::from_dalek(&signature)
}
fn verify(
verification_key: &Self::VerificationKey,
message: &[u8],
signature: &Self::Signature,
) -> Result<()> {
let verifying_key = DalekVerifyingKey::from_bytes(verification_key.as_bytes())
.map_err(|_| CryptoError::InvalidPublicKey)?;
let signature = DalekSignature::try_from(signature.as_bytes().as_ref())
.map_err(|_| CryptoError::InvalidSignature)?;
verifying_key
.verify(message, &signature)
.map_err(|_| CryptoError::VerificationFailed)
}
fn gen_key(seed: &[u8]) -> Self::SigningKey {
assert_eq!(
seed.len(),
SEED_SIZE,
"Ed25519 seed must be exactly 32 bytes"
);
Ed25519SigningKey::from_seed_bytes(seed)
}
fn raw_serialize_verification_key(key: &Self::VerificationKey) -> &[u8] {
key.as_bytes()
}
fn raw_deserialize_verification_key(bytes: &[u8]) -> Option<Self::VerificationKey> {
Ed25519VerificationKey::from_bytes(bytes)
}
fn raw_serialize_signature(sig: &Self::Signature) -> &[u8] {
sig.as_bytes()
}
fn raw_deserialize_signature(bytes: &[u8]) -> Option<Self::Signature> {
if bytes.len() != SIGNATURE_SIZE {
return None;
}
let mut array = [0u8; SIGNATURE_SIZE];
array.copy_from_slice(bytes);
Some(Ed25519Signature(array))
}
}
use crate::common::error::{CryptoError as CommonCryptoError, Result};
use crate::common::traits::DsignAlgorithm as CommonDsignAlgorithm;
impl CommonDsignAlgorithm for Ed25519 {
type SigningKey = Ed25519SigningKey;
type VerificationKey = Ed25519VerificationKey;
type Signature = Ed25519Signature;
type Context = ();
const ALGORITHM_NAME: &'static str = "Ed25519";
const SEED_SIZE: usize = SEED_SIZE;
const SIGNING_KEY_SIZE: usize = SECRET_COMPOUND_SIZE;
const VERIFICATION_KEY_SIZE: usize = VERIFICATION_KEY_SIZE;
const SIGNATURE_SIZE: usize = SIGNATURE_SIZE;
fn gen_key_from_seed(seed: &[u8]) -> Result<Self::SigningKey> {
if seed.len() != SEED_SIZE {
return Err(CommonCryptoError::InvalidKeyLength);
}
Ok(Ed25519SigningKey::from_seed_bytes(seed))
}
fn derive_verification_key(signing_key: &Self::SigningKey) -> Result<Self::VerificationKey> {
let mut bytes = [0u8; VERIFICATION_KEY_SIZE];
bytes.copy_from_slice(&signing_key.verifying_bytes());
Ok(Ed25519VerificationKey(bytes))
}
fn sign(message: &[u8], signing_key: &Self::SigningKey) -> Result<Self::Signature> {
let signing_key_dalek = signing_key.signing_key();
let signature = signing_key_dalek.sign(message);
Ok(Ed25519Signature::from_dalek(&signature))
}
fn verify(
message: &[u8],
signature: &Self::Signature,
verification_key: &Self::VerificationKey,
) -> Result<()> {
let verifying_key = DalekVerifyingKey::from_bytes(verification_key.as_bytes())
.map_err(|_| CommonCryptoError::InvalidPublicKey)?;
let sig = DalekSignature::try_from(signature.as_bytes().as_ref())
.map_err(|_| CommonCryptoError::InvalidSignature)?;
verifying_key
.verify(message, &sig)
.map_err(|_| CommonCryptoError::VerificationFailed)
}
#[cfg(feature = "alloc")]
fn serialize_verification_key(key: &Self::VerificationKey) -> alloc::vec::Vec<u8> {
key.as_bytes().to_vec()
}
fn deserialize_verification_key(bytes: &[u8]) -> Result<Self::VerificationKey> {
Ed25519VerificationKey::from_bytes(bytes).ok_or(CommonCryptoError::InvalidPublicKey)
}
#[cfg(feature = "alloc")]
fn serialize_signature(signature: &Self::Signature) -> alloc::vec::Vec<u8> {
signature.as_bytes().to_vec()
}
fn deserialize_signature(bytes: &[u8]) -> Result<Self::Signature> {
if bytes.len() != SIGNATURE_SIZE {
return Err(CommonCryptoError::InvalidSignature);
}
let mut array = [0u8; SIGNATURE_SIZE];
array.copy_from_slice(bytes);
Ok(Ed25519Signature(array))
}
fn forget_signing_key(mut signing_key: Self::SigningKey) {
use zeroize::Zeroize;
signing_key.0.zeroize();
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dsign::DsignAlgorithm;
#[test]
fn test_key_generation_deterministic() {
let seed = [7u8; 32];
let signing1 = Ed25519::gen_key(&seed);
let signing2 = Ed25519::gen_key(&seed);
assert_eq!(signing1.compound_bytes(), signing2.compound_bytes());
}
#[test]
fn test_sign_and_verify_roundtrip() {
let seed = [42u8; 32];
let signing_key = Ed25519::gen_key(&seed);
let verification_key =
<Ed25519 as crate::dsign::DsignAlgorithm>::derive_verification_key(&signing_key);
let message = b"cardano";
let signature = <Ed25519 as crate::dsign::DsignAlgorithm>::sign(&signing_key, message);
let result = <Ed25519 as crate::dsign::DsignAlgorithm>::verify(
&verification_key,
message,
&signature,
);
assert!(result.is_ok());
}
#[test]
fn test_verify_fails_wrong_message() {
let seed = [9u8; 32];
let signing_key = Ed25519::gen_key(&seed);
let verification_key =
<Ed25519 as crate::dsign::DsignAlgorithm>::derive_verification_key(&signing_key);
let signature = <Ed25519 as crate::dsign::DsignAlgorithm>::sign(&signing_key, b"hello");
let result = <Ed25519 as crate::dsign::DsignAlgorithm>::verify(
&verification_key,
b"world",
&signature,
);
assert!(result.is_err());
assert_eq!(result.unwrap_err(), CryptoError::VerificationFailed);
}
#[test]
fn test_verify_fails_wrong_key() {
let seed1 = [1u8; 32];
let seed2 = [2u8; 32];
let signing_key1 = Ed25519::gen_key(&seed1);
let signing_key2 = Ed25519::gen_key(&seed2);
let verification_key2 =
<Ed25519 as crate::dsign::DsignAlgorithm>::derive_verification_key(&signing_key2);
let message = b"test";
let signature1 = <Ed25519 as crate::dsign::DsignAlgorithm>::sign(&signing_key1, message);
let result = <Ed25519 as crate::dsign::DsignAlgorithm>::verify(
&verification_key2,
message,
&signature1,
);
assert!(result.is_err());
}
#[test]
fn test_empty_message() {
let seed = [42u8; 32];
let signing_key = Ed25519::gen_key(&seed);
let verification_key =
<Ed25519 as crate::dsign::DsignAlgorithm>::derive_verification_key(&signing_key);
let signature = <Ed25519 as crate::dsign::DsignAlgorithm>::sign(&signing_key, b"");
let result =
<Ed25519 as crate::dsign::DsignAlgorithm>::verify(&verification_key, b"", &signature);
assert!(result.is_ok());
}
#[test]
fn test_large_message() {
let seed = [99u8; 32];
let signing_key = Ed25519::gen_key(&seed);
let verification_key =
<Ed25519 as crate::dsign::DsignAlgorithm>::derive_verification_key(&signing_key);
let large_message = vec![0xAB; 10_000];
let signature =
<Ed25519 as crate::dsign::DsignAlgorithm>::sign(&signing_key, &large_message);
let result = <Ed25519 as crate::dsign::DsignAlgorithm>::verify(
&verification_key,
&large_message,
&signature,
);
assert!(result.is_ok());
}
#[test]
fn test_hash_verification_key() {
use crate::dsign::DsignAlgorithm;
use crate::hash::{Blake2b224, Blake2b256};
let seed = [42u8; 32];
let signing_key = Ed25519::gen_key(&seed);
let vk = <Ed25519 as DsignAlgorithm>::derive_verification_key(&signing_key);
let hash_256 = Ed25519::hash_verification_key::<Blake2b256>(&vk);
assert_eq!(hash_256.len(), 32);
let hash_224 = Ed25519::hash_verification_key::<Blake2b224>(&vk);
assert_eq!(hash_224.len(), 28);
let seed2 = [43u8; 32];
let signing_key2 = Ed25519::gen_key(&seed2);
let vk2 = <Ed25519 as DsignAlgorithm>::derive_verification_key(&signing_key2);
let hash2_256 = Ed25519::hash_verification_key::<Blake2b256>(&vk2);
assert_ne!(hash_256, hash2_256);
let hash_256_again = Ed25519::hash_verification_key::<Blake2b256>(&vk);
assert_eq!(hash_256, hash_256_again);
}
}
#[cfg(test)]
mod hex {
#[allow(dead_code)]
pub(crate) fn encode(bytes: &[u8]) -> String {
bytes.iter().map(|b| format!("{:02x}", b)).collect()
}
}