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