use ed25519_dalek::{Signature as DalekSignature, Verifier, VerifyingKey};
use serde::{Deserialize, Serialize};
use std::fmt;
use crate::error::{CryptoError, CryptoResult};
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Signature([u8; 64]);
impl Signature {
#[must_use]
pub const fn from_bytes(bytes: [u8; 64]) -> Self {
Self(bytes)
}
pub fn try_from_slice(slice: &[u8]) -> CryptoResult<Self> {
if slice.len() != 64 {
return Err(CryptoError::InvalidSignatureLength {
expected: 64,
actual: slice.len(),
});
}
let mut bytes = [0u8; 64];
bytes.copy_from_slice(slice);
Ok(Self(bytes))
}
#[must_use]
pub const fn as_bytes(&self) -> &[u8; 64] {
&self.0
}
#[must_use]
pub fn to_hex(&self) -> String {
hex::encode(self.0)
}
pub fn from_hex(s: &str) -> CryptoResult<Self> {
let bytes = hex::decode(s).map_err(|_| CryptoError::InvalidHexEncoding)?;
Self::try_from_slice(&bytes)
}
#[must_use]
pub fn to_base64(&self) -> String {
use base64::Engine;
base64::engine::general_purpose::STANDARD.encode(self.0)
}
pub fn from_base64(s: &str) -> CryptoResult<Self> {
use base64::Engine;
let bytes = base64::engine::general_purpose::STANDARD
.decode(s)
.map_err(|_| CryptoError::InvalidBase64Encoding)?;
Self::try_from_slice(&bytes)
}
pub fn verify(&self, message: &[u8], public_key: &[u8; 32]) -> CryptoResult<()> {
let verifying_key = VerifyingKey::from_bytes(public_key)
.map_err(|e| CryptoError::InvalidPublicKey(e.to_string()))?;
let sig = DalekSignature::from_bytes(&self.0);
verifying_key
.verify(message, &sig)
.map_err(|_| CryptoError::SignatureVerificationFailed)
}
#[must_use]
pub fn to_dalek(&self) -> DalekSignature {
DalekSignature::from_bytes(&self.0)
}
}
impl fmt::Debug for Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Signature({}...)", &self.to_hex()[..16])
}
}
impl fmt::Display for Signature {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_hex())
}
}
impl Serialize for Signature {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_base64())
}
}
impl<'de> Deserialize<'de> for Signature {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Self::from_base64(&s).map_err(serde::de::Error::custom)
}
}
impl From<DalekSignature> for Signature {
fn from(sig: DalekSignature) -> Self {
Self(sig.to_bytes())
}
}
impl From<Signature> for DalekSignature {
fn from(sig: Signature) -> Self {
DalekSignature::from_bytes(&sig.0)
}
}
impl From<[u8; 64]> for Signature {
fn from(bytes: [u8; 64]) -> Self {
Self(bytes)
}
}
impl From<Signature> for [u8; 64] {
fn from(sig: Signature) -> Self {
sig.0
}
}
impl AsRef<[u8]> for Signature {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::KeyPair;
#[test]
fn test_signature_encoding() {
let keypair = KeyPair::generate();
let message = b"test message";
let sig = keypair.sign(message);
let hex = sig.to_hex();
let decoded = Signature::from_hex(&hex).unwrap();
assert_eq!(sig, decoded);
let b64 = sig.to_base64();
let decoded = Signature::from_base64(&b64).unwrap();
assert_eq!(sig, decoded);
}
#[test]
fn test_signature_verification() {
let keypair = KeyPair::generate();
let message = b"test message";
let sig = keypair.sign(message);
assert!(sig.verify(message, keypair.public_key_bytes()).is_ok());
assert!(
sig.verify(b"wrong message", keypair.public_key_bytes())
.is_err()
);
let other_keypair = KeyPair::generate();
assert!(
sig.verify(message, other_keypair.public_key_bytes())
.is_err()
);
}
#[test]
fn test_invalid_signature_length() {
let result = Signature::try_from_slice(&[0u8; 63]);
assert!(matches!(
result,
Err(CryptoError::InvalidSignatureLength { .. })
));
}
}