Skip to content

Commit

Permalink
async-signature: move to AFIT; MSRV 1.75 (#1428)
Browse files Browse the repository at this point in the history
`AFIT` was stabilized in Rust 1.75.

`#[allow(async_fn_in_trait)]` is required until a solution to RPITIT is
merged in rust.

This put responsability on the implementor of `async_signature::AsyncSigner`
to make sure their future is `Send`able.
see rust-lang/rust#115822 (comment)
for more context.

Also introduces an `AsyncRandomizedSigner` trait.

Co-authored-by: Arthur Gautier <arthur.gautier@arista.com>
  • Loading branch information
tarcieri and baloo committed Dec 29, 2023
1 parent 05a23aa commit 9224b6b
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 22 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/async-signature.yml
Expand Up @@ -23,7 +23,7 @@ jobs:
strategy:
matrix:
rust:
- 1.60.0 # MSRV
- 1.75.0 # MSRV
- stable
steps:
- uses: actions/checkout@v4
Expand Down
12 changes: 0 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions async-signature/Cargo.toml
Expand Up @@ -10,14 +10,14 @@ 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"
signature = ">= 2.0, <2.3"

[features]
digest = ["signature/digest"]
rand_core = ["signature/rand_core"]

[package.metadata.docs.rs]
all-features = true
Expand Down
4 changes: 2 additions & 2 deletions async-signature/README.md
Expand Up @@ -9,7 +9,7 @@

## Minimum Supported Rust Version

Rust **1.60** or higher.
Rust **1.75** or higher.

Minimum supported Rust version can be changed in the future, but it will be
done with a minor version bump.
Expand All @@ -36,7 +36,7 @@ dual licensed as above, without any additional terms or conditions.
[docs-image]: https://docs.rs/async-signature/badge.svg
[docs-link]: https://docs.rs/async-signature/
[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
[rustc-image]: https://img.shields.io/badge/rustc-1.60+-blue.svg
[rustc-image]: https://img.shields.io/badge/rustc-1.75+-blue.svg
[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260048-signatures
[build-image]: https://github.com/RustCrypto/traits/workflows/async-signature/badge.svg?branch=master&event=push
Expand Down
47 changes: 42 additions & 5 deletions async-signature/src/lib.rs
Expand Up @@ -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<S: 'static> {
/// Attempt to sign the given message, returning a digital signature on
/// success, or an error if something went wrong.
Expand All @@ -33,7 +34,6 @@ pub trait AsyncSigner<S: 'static> {
async fn sign_async(&self, msg: &[u8]) -> Result<S, Error>;
}

#[async_trait(?Send)]
impl<S, T> AsyncSigner<S> for T
where
S: 'static,
Expand All @@ -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<D, S>
where
D: Digest + 'static,
Expand All @@ -60,7 +60,6 @@ where
}

#[cfg(feature = "digest")]
#[async_trait(?Send)]
impl<D, S, T> AsyncDigestSigner<D, S> for T
where
D: Digest + 'static,
Expand All @@ -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<S> {
/// 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<S, Error>;
}

#[cfg(feature = "rand_core")]
impl<S, T> AsyncRandomizedSigner<S> for T
where
S: 'static,
T: signature::RandomizedSigner<S>,
{
async fn try_sign_with_rng_async(
&self,
rng: &mut impl CryptoRngCore,
msg: &[u8],
) -> Result<S, Error> {
self.try_sign_with_rng(rng, msg)
}
}

0 comments on commit 9224b6b

Please sign in to comment.