diff --git a/.github/workflows/async-signature.yml b/.github/workflows/async-signature.yml index 41aba9707..60bfab329 100644 --- a/.github/workflows/async-signature.yml +++ b/.github/workflows/async-signature.yml @@ -23,8 +23,7 @@ jobs: strategy: matrix: rust: - - 1.60.0 # MSRV - - stable + - beta steps: - uses: actions/checkout@v4 - uses: RustCrypto/actions/cargo-cache@master diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 30a0da8f8..67667fb50 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -26,7 +26,7 @@ jobs: - uses: RustCrypto/actions/cargo-cache@master - uses: dtolnay/rust-toolchain@master with: - toolchain: 1.73.0 + toolchain: beta components: clippy - run: cargo clippy --all --all-features --tests -- -D warnings @@ -36,6 +36,6 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: - toolchain: stable + toolchain: beta components: rustfmt - run: cargo fmt --all -- --check diff --git a/async-signature/Cargo.toml b/async-signature/Cargo.toml index 753f62944..7028483ce 100644 --- a/async-signature/Cargo.toml +++ b/async-signature/Cargo.toml @@ -10,7 +10,7 @@ readme = "README.md" keywords = ["crypto", "ecdsa", "ed25519", "signature", "signing"] categories = ["cryptography", "no-std"] edition = "2021" -rust-version = "1.60" +rust-version = "1.75" [dependencies] async-trait = "0.1.9" @@ -18,6 +18,7 @@ signature = ">= 2.0, <2.3" [features] digest = ["signature/digest"] +rand_core = ["signature/rand_core"] [package.metadata.docs.rs] all-features = true diff --git a/async-signature/src/lib.rs b/async-signature/src/lib.rs index 8c59952ca..1dcd2b199 100644 --- a/async-signature/src/lib.rs +++ b/async-signature/src/lib.rs @@ -17,13 +17,14 @@ pub use signature::{self, Error}; #[cfg(feature = "digest")] pub use signature::digest::{self, Digest}; -use async_trait::async_trait; +#[cfg(feature = "rand_core")] +use signature::rand_core::CryptoRngCore; /// Asynchronously sign the provided message bytestring using `Self` /// (e.g. client for a Cloud KMS or HSM), returning a digital signature. /// /// This trait is an async equivalent of the [`signature::Signer`] trait. -#[async_trait(?Send)] +#[allow(async_fn_in_trait)] pub trait AsyncSigner { /// Attempt to sign the given message, returning a digital signature on /// success, or an error if something went wrong. @@ -33,7 +34,6 @@ pub trait AsyncSigner { async fn sign_async(&self, msg: &[u8]) -> Result; } -#[async_trait(?Send)] impl AsyncSigner for T where S: 'static, @@ -48,7 +48,7 @@ where /// /// This trait is an async equivalent of the [`signature::DigestSigner`] trait. #[cfg(feature = "digest")] -#[async_trait(?Send)] +#[allow(async_fn_in_trait)] pub trait AsyncDigestSigner where D: Digest + 'static, @@ -60,7 +60,6 @@ where } #[cfg(feature = "digest")] -#[async_trait(?Send)] impl AsyncDigestSigner for T where D: Digest + 'static, @@ -71,3 +70,41 @@ where self.try_sign_digest(digest) } } + +/// Sign the given message using the provided external randomness source. +#[cfg(feature = "rand_core")] +#[allow(async_fn_in_trait)] +pub trait AsyncRandomizedSigner { + /// Sign the given message and return a digital signature + async fn sign_with_rng_async(&self, rng: &mut impl CryptoRngCore, msg: &[u8]) -> S { + self.try_sign_with_rng_async(rng, msg) + .await + .expect("signature operation failed") + } + + /// Attempt to sign the given message, returning a digital signature on + /// success, or an error if something went wrong. + /// + /// The main intended use case for signing errors is when communicating + /// with external signers, e.g. cloud KMS, HSMs, or other hardware tokens. + async fn try_sign_with_rng_async( + &self, + rng: &mut impl CryptoRngCore, + msg: &[u8], + ) -> Result; +} + +#[cfg(feature = "rand_core")] +impl AsyncRandomizedSigner for T +where + S: 'static, + T: signature::RandomizedSigner, +{ + async fn try_sign_with_rng_async( + &self, + rng: &mut impl CryptoRngCore, + msg: &[u8], + ) -> Result { + self.try_sign_with_rng(rng, msg) + } +}