use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATURE_LENGTH, Signer};
use rand::rngs::OsRng;
use zeroize::ZeroizeOnDrop;
use crate::error::CryptoError;
pub const SIGNING_KEY_LENGTH: usize = SECRET_KEY_LENGTH;
pub const VERIFYING_KEY_LENGTH: usize = PUBLIC_KEY_LENGTH;
#[derive(Clone, ZeroizeOnDrop)]
pub struct SigningKey(ed25519_dalek::SigningKey);
impl SigningKey {
pub(crate) fn from_random_bytes(bytes: [u8; SIGNING_KEY_LENGTH]) -> Self {
assert!(
bytes.iter().any(|&b| b != 0),
"SigningKey random bytes are all zeros - RNG failure or bug"
);
Self(ed25519_dalek::SigningKey::from_bytes(&bytes))
}
pub fn from_bytes(bytes: &[u8; SIGNING_KEY_LENGTH]) -> Self {
Self(ed25519_dalek::SigningKey::from_bytes(bytes))
}
pub fn generate() -> Self {
let mut csprng = OsRng;
let key = ed25519_dalek::SigningKey::generate(&mut csprng);
Self::from_random_bytes(key.to_bytes())
}
pub fn verifying_key(&self) -> VerifyingKey {
VerifyingKey(self.0.verifying_key())
}
pub fn sign(&self, message: &[u8]) -> Signature {
debug_assert!(
message.len() <= 64 * 1024 * 1024,
"message exceeds 64MB sanity limit"
);
let signature = self.0.sign(message);
let sig_bytes = signature.to_bytes();
assert_eq!(
sig_bytes.len(),
SIGNATURE_LENGTH,
"signature length mismatch: expected {}, got {}",
SIGNATURE_LENGTH,
sig_bytes.len()
);
assert!(
sig_bytes.iter().any(|&b| b != 0),
"signature is all zeros - cryptographic library bug"
);
Signature(signature)
}
pub fn to_bytes(&self) -> [u8; SIGNING_KEY_LENGTH] {
self.0.to_bytes()
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct VerifyingKey(ed25519_dalek::VerifyingKey);
impl VerifyingKey {
pub fn from_bytes(bytes: &[u8; VERIFYING_KEY_LENGTH]) -> Result<Self, CryptoError> {
assert!(
bytes.iter().any(|&b| b != 0),
"verifying key bytes are all zeros - corrupted or uninitialized key"
);
let key = ed25519_dalek::VerifyingKey::from_bytes(bytes)?;
Ok(Self(key))
}
pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), CryptoError> {
debug_assert!(
message.len() <= 64 * 1024 * 1024,
"message exceeds 64MB sanity limit"
);
self.0.verify_strict(message, &signature.0)?;
Ok(())
}
pub fn to_bytes(&self) -> [u8; VERIFYING_KEY_LENGTH] {
self.0.to_bytes()
}
}
impl std::fmt::Debug for VerifyingKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let bytes = self.to_bytes();
write!(
f,
"VerifyingKey({:02x}{:02x}{:02x}{:02x}...)",
bytes[0], bytes[1], bytes[2], bytes[3]
)
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Signature(ed25519_dalek::Signature);
impl Signature {
pub fn from_bytes(bytes: &[u8; SIGNATURE_LENGTH]) -> Self {
assert!(
bytes.iter().any(|&b| b != 0),
"signature bytes are all zeros - corrupted or uninitialized signature"
);
Self(ed25519_dalek::Signature::from_bytes(bytes))
}
pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] {
self.0.to_bytes()
}
}
impl std::fmt::Debug for Signature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let bytes = self.to_bytes();
write!(
f,
"Signature({:02x}{:02x}{:02x}{:02x}...)",
bytes[0], bytes[1], bytes[2], bytes[3]
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sign_and_verify_roundtrip() {
let signing_key = SigningKey::generate();
let verifying_key = signing_key.verifying_key();
let message = b"test message for signing";
let signature = signing_key.sign(message);
assert!(verifying_key.verify(message, &signature).is_ok());
}
#[test]
fn tampered_message_fails_verification() {
let signing_key = SigningKey::generate();
let verifying_key = signing_key.verifying_key();
let message = b"original message";
let signature = signing_key.sign(message);
let tampered = b"tampered message";
assert!(verifying_key.verify(tampered, &signature).is_err());
}
#[test]
fn tampered_signature_fails_verification() {
let signing_key = SigningKey::generate();
let verifying_key = signing_key.verifying_key();
let message = b"test message";
let signature = signing_key.sign(message);
let mut bad_sig_bytes = signature.to_bytes();
bad_sig_bytes[0] ^= 0x01;
let bad_signature = Signature::from_bytes(&bad_sig_bytes);
assert!(verifying_key.verify(message, &bad_signature).is_err());
}
#[test]
fn wrong_key_fails_verification() {
let signing_key = SigningKey::generate();
let wrong_key = SigningKey::generate();
let message = b"test message";
let signature = signing_key.sign(message);
assert!(
wrong_key
.verifying_key()
.verify(message, &signature)
.is_err()
);
}
#[test]
fn signing_key_roundtrip() {
let original = SigningKey::generate();
let bytes = original.to_bytes();
let restored = SigningKey::from_bytes(&bytes);
assert_eq!(
original.verifying_key().to_bytes(),
restored.verifying_key().to_bytes()
);
let message = b"test";
let sig1 = original.sign(message);
let sig2 = restored.sign(message);
assert_eq!(sig1.to_bytes(), sig2.to_bytes());
}
#[test]
fn verifying_key_roundtrip() {
let signing_key = SigningKey::generate();
let original = signing_key.verifying_key();
let bytes = original.to_bytes();
let restored = VerifyingKey::from_bytes(&bytes).unwrap();
assert_eq!(original, restored);
}
#[test]
fn signature_roundtrip() {
let signing_key = SigningKey::generate();
let signature = signing_key.sign(b"test");
let bytes = signature.to_bytes();
let restored = Signature::from_bytes(&bytes);
assert_eq!(signature, restored);
}
#[test]
fn empty_message_can_be_signed() {
let signing_key = SigningKey::generate();
let verifying_key = signing_key.verifying_key();
let signature = signing_key.sign(b"");
assert!(verifying_key.verify(b"", &signature).is_ok());
}
#[test]
fn deterministic_signatures() {
let signing_key = SigningKey::generate();
let message = b"determinism test";
let sig1 = signing_key.sign(message);
let sig2 = signing_key.sign(message);
assert_eq!(sig1.to_bytes(), sig2.to_bytes());
}
}