Skip to main content

acta_maker_sdk/
signing.rs

1use std::future::Future;
2use std::pin::Pin;
3
4use ed25519_dalek::{Signature, VerifyingKey};
5use thiserror::Error;
6
7pub type SigningFuture<'a> =
8    Pin<Box<dyn Future<Output = Result<[u8; 64], SigningError>> + Send + 'a>>;
9
10#[derive(Debug, Clone, PartialEq, Eq, Error)]
11#[error("{message}")]
12pub struct SigningError {
13    message: String,
14}
15
16impl SigningError {
17    #[must_use]
18    pub fn new(message: impl Into<String>) -> Self {
19        Self {
20            message: message.into(),
21        }
22    }
23}
24
25/// Asynchronous Ed25519 signer capability.
26///
27/// Implementations must not block the async executor while waiting for I/O.
28pub trait AsyncSignerLike: Send + Sync {
29    fn pubkey_bytes(&self) -> [u8; 32];
30
31    fn sign_message<'a>(&'a self, message: &'a [u8]) -> SigningFuture<'a>;
32}
33
34pub(crate) async fn sign_verified<S: AsyncSignerLike + ?Sized>(
35    signer: &S,
36    message: &[u8],
37) -> Result<[u8; 64], SigningError> {
38    let signature = signer.sign_message(message).await?;
39    let verifying_key = VerifyingKey::from_bytes(&signer.pubkey_bytes())
40        .map_err(|_| SigningError::new("async signer returned an invalid Ed25519 public key"))?;
41    verifying_key
42        .verify_strict(message, &Signature::from_bytes(&signature))
43        .map_err(|_| {
44            SigningError::new("async signer returned a signature for a different key or message")
45        })?;
46    Ok(signature)
47}