use async_trait::async_trait;
use ed25519_dalek::{Signer as EdSigner, SigningKey};
use thiserror::Error;
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct SignedPayload {
pub signature: [u8; 64],
pub verifying_key: [u8; 32],
}
impl SignedPayload {
#[must_use]
pub fn new(signature: [u8; 64], verifying_key: [u8; 32]) -> Self {
Self {
signature,
verifying_key,
}
}
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum SignerError {
#[error("signer backend: {0}")]
Backend(String),
#[error("internal: {0}")]
Internal(String),
}
#[async_trait]
pub trait SignerProvider: Send + Sync {
async fn sign_handoff(&self, payload: &[u8]) -> Result<SignedPayload, SignerError>;
}
pub struct SoftwareSigner {
key: SigningKey,
}
impl SoftwareSigner {
#[must_use]
pub fn new(key: SigningKey) -> Self {
Self { key }
}
#[must_use]
pub fn from_bytes(seed: [u8; 32]) -> Self {
Self::new(SigningKey::from_bytes(&seed))
}
}
#[async_trait]
impl SignerProvider for SoftwareSigner {
async fn sign_handoff(&self, payload: &[u8]) -> Result<SignedPayload, SignerError> {
let sig = self.key.sign(payload);
Ok(SignedPayload {
signature: sig.to_bytes(),
verifying_key: self.key.verifying_key().to_bytes(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use ed25519_dalek::{Signature, Verifier, VerifyingKey};
#[tokio::test]
async fn software_signer_produces_verifiable_signature() {
let signer = SoftwareSigner::from_bytes([7u8; 32]);
let payload = b"hello";
let signed = signer.sign_handoff(payload).await.expect("sign");
let vk = VerifyingKey::from_bytes(&signed.verifying_key).expect("vk");
let sig = Signature::from_bytes(&signed.signature);
vk.verify(payload, &sig).expect("verify");
}
}