use crate::errors::{CrabError, CrabResult};
use ed25519_dalek::{
Signature, Signer, SigningKey, Verifier, VerifyingKey, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH,
SIGNATURE_LENGTH,
};
use rand_core::OsRng;
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(
feature = "serde-support",
derive(serde::Serialize, serde::Deserialize)
)]
#[cfg_attr(feature = "serde-support", serde(transparent))]
pub struct Ed25519Signature(
#[cfg_attr(feature = "serde-support", serde(with = "serde_sig_bytes"))]
pub [u8; SIGNATURE_LENGTH],
);
#[cfg(feature = "serde-support")]
mod serde_sig_bytes {
use super::SIGNATURE_LENGTH;
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S>(bytes: &[u8; SIGNATURE_LENGTH], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&crate::encoding::base64_encode(bytes))
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; SIGNATURE_LENGTH], D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
let bytes = crate::encoding::base64_decode(&s).map_err(serde::de::Error::custom)?;
if bytes.len() != SIGNATURE_LENGTH {
return Err(serde::de::Error::custom(format!(
"Expected {} bytes, got {}",
SIGNATURE_LENGTH,
bytes.len()
)));
}
let mut arr = [0u8; SIGNATURE_LENGTH];
arr.copy_from_slice(&bytes);
Ok(arr)
}
}
impl Ed25519Signature {
pub fn from_bytes(bytes: &[u8]) -> CrabResult<Self> {
if bytes.len() != SIGNATURE_LENGTH {
return Err(CrabError::invalid_input(format!(
"Ed25519 signature must be {} bytes, got {}",
SIGNATURE_LENGTH,
bytes.len()
)));
}
let mut sig = [0u8; SIGNATURE_LENGTH];
sig.copy_from_slice(bytes);
Ok(Self(sig))
}
pub fn as_bytes(&self) -> &[u8; SIGNATURE_LENGTH] {
&self.0
}
pub fn to_base64(&self) -> String {
crate::encoding::base64_encode(&self.0)
}
pub fn from_base64(data: &str) -> CrabResult<Self> {
let bytes = crate::encoding::base64_decode(data)?;
Self::from_bytes(&bytes)
}
pub fn to_hex(&self) -> String {
hex::encode(self.0)
}
pub fn from_hex(data: &str) -> CrabResult<Self> {
let bytes = hex::decode(data)?;
Self::from_bytes(&bytes)
}
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(
feature = "serde-support",
derive(serde::Serialize, serde::Deserialize)
)]
pub struct Ed25519PublicKey(
#[cfg_attr(feature = "serde-support", serde(with = "serde_pub_key"))] VerifyingKey,
);
#[cfg(feature = "serde-support")]
mod serde_pub_key {
use super::{VerifyingKey, PUBLIC_KEY_LENGTH};
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S>(key: &VerifyingKey, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&crate::encoding::base64_encode(key.as_bytes()))
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<VerifyingKey, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
let bytes = crate::encoding::base64_decode(&s).map_err(serde::de::Error::custom)?;
if bytes.len() != PUBLIC_KEY_LENGTH {
return Err(serde::de::Error::custom(format!(
"Expected {} bytes, got {}",
PUBLIC_KEY_LENGTH,
bytes.len()
)));
}
VerifyingKey::from_bytes(bytes[..PUBLIC_KEY_LENGTH].try_into().unwrap())
.map_err(serde::de::Error::custom)
}
}
impl Ed25519PublicKey {
pub fn from_bytes(bytes: &[u8]) -> CrabResult<Self> {
if bytes.len() != PUBLIC_KEY_LENGTH {
return Err(CrabError::invalid_input(format!(
"Ed25519 public key must be {} bytes, got {}",
PUBLIC_KEY_LENGTH,
bytes.len()
)));
}
let key = VerifyingKey::from_bytes(bytes.try_into().expect("length already checked"))
.map_err(|e| CrabError::key_error(format!("Invalid Ed25519 public key: {}", e)))?;
Ok(Self(key))
}
pub fn as_bytes(&self) -> &[u8; PUBLIC_KEY_LENGTH] {
self.0.as_bytes()
}
pub fn verify(&self, message: &[u8], signature: &Ed25519Signature) -> CrabResult<bool> {
let sig = Signature::from_bytes(&signature.0);
Ok(self.0.verify(message, &sig).is_ok())
}
pub fn to_base64(&self) -> String {
crate::encoding::base64_encode(self.0.as_bytes())
}
pub fn from_base64(data: &str) -> CrabResult<Self> {
let bytes = crate::encoding::base64_decode(data)?;
Self::from_bytes(&bytes)
}
pub fn to_hex(&self) -> String {
hex::encode(self.0.as_bytes())
}
pub fn from_hex(data: &str) -> CrabResult<Self> {
let bytes = hex::decode(data)?;
Self::from_bytes(&bytes)
}
}
pub struct Ed25519KeyPair {
signing_key: SigningKey,
}
impl Ed25519KeyPair {
pub fn generate() -> CrabResult<Self> {
let signing_key = SigningKey::generate(&mut OsRng);
Ok(Self { signing_key })
}
pub fn from_secret_bytes(secret: &[u8]) -> CrabResult<Self> {
if secret.len() != SECRET_KEY_LENGTH {
return Err(CrabError::invalid_input(format!(
"Ed25519 secret key must be {} bytes, got {}",
SECRET_KEY_LENGTH,
secret.len()
)));
}
let signing_key =
SigningKey::from_bytes(secret.try_into().expect("length already checked"));
Ok(Self { signing_key })
}
pub fn secret_bytes(&self) -> &[u8; SECRET_KEY_LENGTH] {
self.signing_key.as_bytes()
}
pub fn public_key(&self) -> Ed25519PublicKey {
Ed25519PublicKey(self.signing_key.verifying_key())
}
pub fn sign(&self, message: &[u8]) -> Ed25519Signature {
let sig = self.signing_key.sign(message);
Ed25519Signature(sig.to_bytes())
}
pub fn sign_with_verification(&self, message: &[u8]) -> CrabResult<Ed25519Signature> {
let signature = self.sign(message);
if !self.verify(message, &signature)? {
return Err(CrabError::Internal("Signature verification failed after signing".into()));
}
Ok(signature)
}
pub fn verify(&self, message: &[u8], signature: &Ed25519Signature) -> CrabResult<bool> {
self.public_key().verify(message, signature)
}
pub fn to_pkcs8_der(&self) -> CrabResult<Vec<u8>> {
use ed25519_dalek::pkcs8::EncodePrivateKey;
self.signing_key
.to_pkcs8_der()
.map(|doc| doc.as_bytes().to_vec())
.map_err(|e| CrabError::key_error(format!("Failed to encode PKCS#8 DER: {}", e)))
}
pub fn from_pkcs8_der(der: &[u8]) -> CrabResult<Self> {
use ed25519_dalek::pkcs8::DecodePrivateKey;
let signing_key = SigningKey::from_pkcs8_der(der)
.map_err(|e| CrabError::key_error(format!("Failed to decode PKCS#8 DER: {}", e)))?;
Ok(Self { signing_key })
}
pub fn to_pkcs8_pem(&self) -> CrabResult<String> {
use ed25519_dalek::pkcs8::EncodePrivateKey;
self.signing_key
.to_pkcs8_pem(Default::default())
.map(|s| s.to_string())
.map_err(|e| CrabError::key_error(format!("Failed to encode PKCS#8 PEM: {}", e)))
}
pub fn from_pkcs8_pem(pem: &str) -> CrabResult<Self> {
use ed25519_dalek::pkcs8::DecodePrivateKey;
let signing_key = SigningKey::from_pkcs8_pem(pem)
.map_err(|e| CrabError::key_error(format!("Failed to decode PKCS#8 PEM: {}", e)))?;
Ok(Self { signing_key })
}
}
impl Ed25519PublicKey {
pub fn to_public_key_der(&self) -> CrabResult<Vec<u8>> {
use ed25519_dalek::pkcs8::EncodePublicKey;
self.0
.to_public_key_der()
.map(|doc| doc.as_bytes().to_vec())
.map_err(|e| CrabError::key_error(format!("Failed to encode public key DER: {}", e)))
}
pub fn from_public_key_der(der: &[u8]) -> CrabResult<Self> {
use ed25519_dalek::pkcs8::DecodePublicKey;
let key = VerifyingKey::from_public_key_der(der)
.map_err(|e| CrabError::key_error(format!("Failed to decode public key DER: {}", e)))?;
Ok(Self(key))
}
pub fn to_public_key_pem(&self) -> CrabResult<String> {
use ed25519_dalek::pkcs8::EncodePublicKey;
self.0
.to_public_key_pem(Default::default())
.map_err(|e| CrabError::key_error(format!("Failed to encode public key PEM: {}", e)))
}
pub fn from_public_key_pem(pem: &str) -> CrabResult<Self> {
use ed25519_dalek::pkcs8::DecodePublicKey;
let key = VerifyingKey::from_public_key_pem(pem)
.map_err(|e| CrabError::key_error(format!("Failed to decode public key PEM: {}", e)))?;
Ok(Self(key))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ed25519_generate_and_sign() {
let keypair = Ed25519KeyPair::generate().unwrap();
let message = b"Test message";
let signature = keypair.sign(message);
assert!(keypair.verify(message, &signature).unwrap());
}
#[test]
fn test_ed25519_verify_wrong_message() {
let keypair = Ed25519KeyPair::generate().unwrap();
let message = b"Test message";
let signature = keypair.sign(message);
assert!(!keypair.verify(b"Wrong message", &signature).unwrap());
}
#[test]
fn test_ed25519_public_key_verify() {
let keypair = Ed25519KeyPair::generate().unwrap();
let public_key = keypair.public_key();
let message = b"Test message";
let signature = keypair.sign(message);
assert!(public_key.verify(message, &signature).unwrap());
assert!(!public_key.verify(b"Wrong", &signature).unwrap());
}
#[test]
fn test_ed25519_from_secret_bytes() {
let keypair1 = Ed25519KeyPair::generate().unwrap();
let secret = keypair1.secret_bytes();
let keypair2 = Ed25519KeyPair::from_secret_bytes(secret).unwrap();
assert_eq!(keypair1.public_key().as_bytes(), keypair2.public_key().as_bytes());
}
#[test]
fn test_ed25519_signature_serialization() {
let keypair = Ed25519KeyPair::generate().unwrap();
let message = b"Test";
let signature = keypair.sign(message);
let b64 = signature.to_base64();
let recovered = Ed25519Signature::from_base64(&b64).unwrap();
assert_eq!(signature, recovered);
let hex = signature.to_hex();
let recovered = Ed25519Signature::from_hex(&hex).unwrap();
assert_eq!(signature, recovered);
}
#[test]
fn test_ed25519_public_key_serialization() {
let keypair = Ed25519KeyPair::generate().unwrap();
let public_key = keypair.public_key();
let b64 = public_key.to_base64();
let recovered = Ed25519PublicKey::from_base64(&b64).unwrap();
assert_eq!(public_key.as_bytes(), recovered.as_bytes());
let hex = public_key.to_hex();
let recovered = Ed25519PublicKey::from_hex(&hex).unwrap();
assert_eq!(public_key.as_bytes(), recovered.as_bytes());
}
#[test]
fn test_ed25519_sign_with_verification() {
let keypair = Ed25519KeyPair::generate().unwrap();
let message = b"Test message";
let signature = keypair.sign_with_verification(message).unwrap();
assert!(keypair.verify(message, &signature).unwrap());
}
}