From 49446c9a12d2384a8ccdf862dca2aad3e33708ad Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Thu, 23 Apr 2026 10:14:22 -0600 Subject: [PATCH] [WIP] signature: fallible signer traits Replaces the previous strategy of each of the signer traits providing two methods: 1. a fallible method named `try_*` that returns `signature::Result` with `signature::Error` in the `E` position. 2. an infallible equivalent method that panics if the `try_*` method returns an error. In its place, each of the signing traits has been split into an infallible trait and a `Try*`-prefixed fallible trait, e.g. `Signer`/`TrySigner`, `RandomizedSigner`/`TryRandomizedSigner`. The fallible traits now each have an associated `Error` type. The previous support for sneaking an inner error type through `signature::Error` has been removed, and it's now a simple unit struct. Where it makes sense, the infallible traits bound on the respective `Try*` traits with `Error = Infallible`, and a blanket impl is provided, e.g. for `TrySigner` and `TryMultipartSigner`. This isn't always possible though, e.g. `RandomizedSigner` uses `CryptoRng` for `sign_with_rng`, whereas `TryRandomizedSigner` uses `TryCryptoRng`. Likewise, `DigestSigner` uses a callback which returns `()`, whereas `TryDigestSigner` returns `Result<(), Error>`. The main advantages of this approach are that signing operations are for most common use cases infallible, and this approach eliminates the panic condition for such cases, and avoids people who don't want to think about handling signing errors from having to. However, for the people using e.g. external/remote signers that can have I/O errors, this gives them a concrete error type to work with instead of trying to smuggle one through `signature::Error`. The main disadvantage is a doubling of the number of traits, where we already have a combinatorial explosition of possibilities. --- signature/src/error.rs | 82 ++-------- signature/src/hazmat.rs | 33 +++- signature/src/signer.rs | 335 +++++++++++++++++++++++----------------- 3 files changed, 234 insertions(+), 216 deletions(-) diff --git a/signature/src/error.rs b/signature/src/error.rs index 846456575..0413bba6c 100644 --- a/signature/src/error.rs +++ b/signature/src/error.rs @@ -1,10 +1,8 @@ //! Signature error types +use core::convert::Infallible; use core::fmt::{self, Debug, Display}; -#[cfg(feature = "alloc")] -use alloc::boxed::Box; - /// Result type. /// /// A result with the `signature` crate's [`Error`] type. @@ -12,62 +10,26 @@ pub type Result = core::result::Result; /// Signature errors. /// -/// This type is deliberately opaque as to avoid sidechannel leakage which -/// could potentially be used recover signing private keys or forge signatures -/// (e.g. [BB'06]). -/// -/// When the `alloc` feature is enabled, it supports an optional [`core::error::Error::source`], -/// which can be used by things like remote signers (e.g. HSM, KMS) to report I/O or auth errors. +/// This type is deliberately opaque as to avoid sidechannel leakage which could potentially be used +/// recover signing private keys or forge signatures (e.g. [BB'06]). /// /// [BB'06]: https://en.wikipedia.org/wiki/Daniel_Bleichenbacher -#[derive(Default)] -#[non_exhaustive] -pub struct Error { - /// Source of the error (if applicable). - #[cfg(feature = "alloc")] - source: Option>, -} +#[derive(Clone, Copy, Default)] +pub struct Error; impl Error { - /// Create a new error with no associated source + /// DEPRECATED: create a new error. You can now just use `Error` instead because it's now a unit + /// struct which requires no constructor. + #[deprecated(since = "3.0.0", note = "use `Error` instead (no constructor needed)")] #[must_use] pub fn new() -> Self { - Self::default() - } - - /// Create a new error with an associated source. - /// - /// **NOTE:** The "source" should **NOT** be used to propagate cryptographic - /// errors e.g. signature parsing or verification errors. The intended use - /// cases are for propagating errors related to external signers, e.g. - /// communication/authentication errors with HSMs, KMS, etc. - #[cfg(feature = "alloc")] - pub fn from_source( - source: impl Into>, - ) -> Self { - Self { - source: Some(source.into()), - } + Error } } impl Debug for Error { - #[cfg(not(feature = "alloc"))] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("signature::Error {}") - } - - #[cfg(feature = "alloc")] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("signature::Error { source: ")?; - - if let Some(source) = &self.source { - write!(f, "Some({source})")?; - } else { - f.write_str("None")?; - } - - f.write_str(" }") + f.debug_struct("signature::Error").finish() } } @@ -77,25 +39,11 @@ impl Display for Error { } } -#[cfg(feature = "alloc")] -impl From> for Error { - fn from(source: Box) -> Error { - Self::from_source(source) - } -} +impl core::error::Error for Error {} -impl core::error::Error for Error { - fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { - #[cfg(not(feature = "alloc"))] - { - None - } - #[cfg(feature = "alloc")] - #[allow(trivial_casts)] - { - self.source - .as_ref() - .map(|source| source.as_ref() as &(dyn core::error::Error + 'static)) - } +// Needed to make error bounds work +impl From for Error { + fn from(_: Infallible) -> Self { + Error } } diff --git a/signature/src/hazmat.rs b/signature/src/hazmat.rs index eeb84ed83..40f9bf9e2 100644 --- a/signature/src/hazmat.rs +++ b/signature/src/hazmat.rs @@ -17,6 +17,9 @@ use crate::rand_core::TryCryptoRng; /// Sign the provided message prehash, returning a digital signature. pub trait PrehashSigner { + /// Error type. + type Error: core::error::Error + Into; + /// Attempt to sign the given message digest, returning a digital signature on success, or an /// error if something went wrong. /// @@ -28,14 +31,17 @@ pub trait PrehashSigner { /// Allowed lengths are algorithm-dependent and up to a particular implementation to decide. /// /// # Errors - /// Returns [`Error`] in the event `prehash` is an invalid length. - fn sign_prehash(&self, prehash: &[u8]) -> Result; + /// Returns `Self::Error` in the event `prehash` is an invalid length. + fn sign_prehash(&self, prehash: &[u8]) -> Result; } /// Sign the provided message prehash using the provided external randomness source, returning a /// digital signature. #[cfg(feature = "rand_core")] pub trait RandomizedPrehashSigner { + /// Error type. + type Error: core::error::Error + Into; + /// Attempt to sign the given message digest, returning a digital signature on success, or an /// error if something went wrong. /// @@ -47,13 +53,13 @@ pub trait RandomizedPrehashSigner { /// Allowed lengths are algorithm-dependent and up to a particular implementation to decide. /// /// # Errors - /// Returns [`Error`] in the event `prehash` is an invalid length, or if an internal error + /// Returns `Self::Error` in the event `prehash` is an invalid length, or if an internal error /// in the provided `rng` occurs. fn sign_prehash_with_rng( &self, rng: &mut R, prehash: &[u8], - ) -> Result; + ) -> Result; } /// Verify the provided message prehash using `Self` (e.g. a public key) @@ -78,8 +84,10 @@ pub trait PrehashVerifier { } /// Asynchronously sign the provided message prehash, returning a digital signature. -#[allow(async_fn_in_trait)] pub trait AsyncPrehashSigner { + /// Error type. + type Error: core::error::Error + Into; + /// Attempt to sign the given message digest, returning a digital signature on success, or an /// error if something went wrong. /// @@ -89,14 +97,19 @@ pub trait AsyncPrehashSigner { /// for the message digest for a given concrete signature algorithm. /// /// Allowed lengths are algorithm-dependent and up to a particular implementation to decide. - async fn sign_prehash_async(&self, prehash: &[u8]) -> Result; + /// + /// # Errors + /// Returns `Self::Error` in the event `prehash` is an invalid length. + async fn sign_prehash_async(&self, prehash: &[u8]) -> Result; } /// Asynchronously sign the provided message prehash using the provided external randomness source, /// returning a digital signature. #[cfg(feature = "rand_core")] -#[allow(async_fn_in_trait)] pub trait AsyncRandomizedPrehashSigner { + /// Error type. + type Error: core::error::Error + Into; + /// Attempt to sign the given message digest, returning a digital signature on success, or an /// error if something went wrong. /// @@ -106,9 +119,13 @@ pub trait AsyncRandomizedPrehashSigner { /// for the message digest for a given concrete signature algorithm. /// /// Allowed lengths are algorithm-dependent and up to a particular implementation to decide. + /// + /// # Errors + /// Returns `Self::Error` in the event `prehash` is an invalid length, or if `rng` experiences + /// an internal failure. async fn sign_prehash_with_rng_async( &self, rng: &mut R, prehash: &[u8], - ) -> Result; + ) -> Result; } diff --git a/signature/src/signer.rs b/signature/src/signer.rs index 1057b6b07..0909f5b54 100644 --- a/signature/src/signer.rs +++ b/signature/src/signer.rs @@ -1,6 +1,7 @@ //! Traits for generating digital signatures. use crate::error::Error; +use core::convert::Infallible; #[cfg(feature = "digest")] use crate::digest::Update; @@ -8,13 +9,20 @@ use crate::digest::Update; #[cfg(feature = "rand_core")] use crate::rand_core::{CryptoRng, TryCryptoRng}; -/// Sign the provided message bytestring using `Self` (e.g. a cryptographic key or connection to an -/// HSM), returning a digital signature. -pub trait Signer { +/// Sign the provided message bytestring using `Self` (e.g. a cryptographic key), returning a +/// digital signature. +pub trait Signer: TrySigner { /// Sign the given message and return a digital signature. - fn sign(&self, msg: &[u8]) -> S { - self.try_sign(msg).expect("signature operation failed") - } + fn sign(&self, msg: &[u8]) -> S; +} + +/// Sign the provided message bytestring using `Self` (e.g. a cryptographic key), returning a +/// digital signature on success, or the provided error type on failure. +/// +/// This is a fallible equivalent of the [`Signer`] trait. +pub trait TrySigner { + /// Error type. + type Error: core::error::Error + Into; /// Attempt to sign the given message, returning a digital signature on success, or an error if /// something went wrong. @@ -25,60 +33,106 @@ pub trait Signer { /// # Errors /// Returns implementation-specific errors in the event signing failed (e.g. KMS or HSM /// communication error). - fn try_sign(&self, msg: &[u8]) -> Result; + fn try_sign(&self, msg: &[u8]) -> Result; +} + +impl TrySigner for K +where + K: Signer, +{ + type Error = Infallible; + + fn try_sign(&self, msg: &[u8]) -> Result { + Ok(self.sign(msg)) + } } /// Equivalent of [`Signer`] but the message is provided in non-contiguous byte slices. -pub trait MultipartSigner { +pub trait MultipartSigner: TryMultipartSigner { /// Equivalent of [`Signer::sign()`] but the message is provided in non-contiguous byte slices. - fn multipart_sign(&self, msg: &[&[u8]]) -> S { - self.try_multipart_sign(msg) - .expect("signature operation failed") - } + fn multipart_sign(&self, msg: &[&[u8]]) -> S; +} + +/// Equivalent of [`Signer`] but the message is provided in non-contiguous byte slices. +/// +/// This is a fallible equivalent of the [`MultipartSigner`] trait. +pub trait TryMultipartSigner { + /// Error type. + type Error: core::error::Error + Into; - /// Equivalent of [`Signer::try_sign()`] but the message is provided in non-contiguous byte + /// Equivalent of [`TrySigner::try_sign()`] but the message is provided in non-contiguous byte /// slices. /// /// # Errors /// Returns implementation-specific errors in the event signing failed (e.g. KMS or HSM /// communication error). - fn try_multipart_sign(&self, msg: &[&[u8]]) -> Result; + fn try_multipart_sign(&self, msg: &[&[u8]]) -> Result; +} + +impl TryMultipartSigner for K +where + K: MultipartSigner, +{ + type Error = Infallible; + + fn try_multipart_sign(&self, msg: &[&[u8]]) -> Result { + Ok(self.multipart_sign(msg)) + } } /// Sign the provided message bytestring using `&mut Self` (e.g. an evolving cryptographic key such /// as a stateful hash-based signature), returning a digital signature. -pub trait SignerMut { +pub trait SignerMut: TrySignerMut { /// Sign the given message, update the state, and return a digital signature. - /// - /// # Panics - /// In the event of a signing error. - fn sign(&mut self, msg: &[u8]) -> S { - self.try_sign(msg).expect("signature operation failed") - } + fn sign(&mut self, msg: &[u8]) -> S; +} + +/// Sign the provided message bytestring using `&mut Self` (e.g. an evolving cryptographic key such +/// as a stateful hash-based signature), returning a digital signature on success, or the provided +/// error type on failure. +pub trait TrySignerMut { + /// Error type. + type Error: core::error::Error + Into; /// Attempt to sign the given message, updating the state, and returning a digital signature on /// success, or an error if something went wrong. /// - /// # Errors /// Signing can fail, e.g. if the number of time periods allowed by the current key is exceeded. - fn try_sign(&mut self, msg: &[u8]) -> Result; + /// + /// # Errors + /// Returns implementation-specific errors in the event signing failed (e.g. KMS or HSM + /// communication error). + fn try_sign(&mut self, msg: &[u8]) -> Result; +} + +impl TrySignerMut for K +where + K: SignerMut, +{ + type Error = Infallible; + + fn try_sign(&mut self, msg: &[u8]) -> Result { + Ok(self.sign(msg)) + } } /// Sign the given prehashed message `Digest` using `Self`. /// /// ## Notes /// -/// This trait is primarily intended for signature algorithms based on the [Fiat-Shamir heuristic], -/// a method for converting an interactive challenge/response-based proof-of-knowledge protocol into -/// an offline digital signature through the use of a random oracle, i.e. a digest function. +/// This trait is primarily intended for signature algorithms based on the +/// [Fiat-Shamir heuristic], a method for converting an interactive +/// challenge/response-based proof-of-knowledge protocol into an offline +/// digital signature through the use of a random oracle, i.e. a digest +/// function. /// -/// The security of such protocols critically rests upon the inability of an attacker to solve for -/// the output of the random oracle, as generally otherwise such signature algorithms are a system -/// of linear equations and therefore doing so would allow the attacker to trivially forge -/// signatures. +/// The security of such protocols critically rests upon the inability of +/// an attacker to solve for the output of the random oracle, as generally +/// otherwise such signature algorithms are a system of linear equations and +/// therefore doing so would allow the attacker to trivially forge signatures. /// -/// To prevent misuse which would potentially allow this to be possible, this API accepts a `Digest` -/// instance, rather than a raw digest value. +/// To prevent misuse which would potentially allow this to be possible, this +/// API accepts a `Digest` instance, rather than a raw digest value. /// /// [Fiat-Shamir heuristic]: https://en.wikipedia.org/wiki/Fiat%E2%80%93Shamir_heuristic #[cfg(feature = "digest")] @@ -87,16 +141,16 @@ pub trait DigestSigner { /// /// The given function can be invoked multiple times. It is expected that in each invocation the /// `Digest` is updated with the entire equal message. - /// - /// # Panics - /// In the event of a signing error. - fn sign_digest(&self, f: F) -> S { - self.try_sign_digest(|digest| { - f(digest); - Ok(()) - }) - .expect("signature operation failed") - } + fn sign_digest(&self, f: F) -> S; +} + +/// Sign the given prehashed message `Digest` using `Self`. +/// +/// This is a fallible equivalent of the [`DigestSigner`] trait. +#[cfg(feature = "digest")] +pub trait TryDigestSigner { + /// Error type. + type Error: core::error::Error + Into; /// Attempt to sign a message by updating the received `Digest` with it, returning a digital /// signature on success, or an error if something went wrong. @@ -107,17 +161,21 @@ pub trait DigestSigner { /// # Errors /// Returns implementation-specific errors in the event signing failed (e.g. KMS or HSM /// communication error). - fn try_sign_digest Result<(), Error>>(&self, f: F) -> Result; + fn try_sign_digest Result<(), Error>>(&self, f: F) -> Result; } /// Sign the given message using the provided external randomness source. #[cfg(feature = "rand_core")] pub trait RandomizedSigner { /// Sign the given message and return a digital signature - fn sign_with_rng(&self, rng: &mut R, msg: &[u8]) -> S { - self.try_sign_with_rng(rng, msg) - .expect("signature operation failed") - } + fn sign_with_rng(&self, rng: &mut R, msg: &[u8]) -> S; +} + +/// This is a fallible equivalent of the [`RandomizedSigner`] trait. +#[cfg(feature = "rand_core")] +pub trait TryRandomizedSigner { + /// Error type. + type Error: core::error::Error + Into; /// Attempt to sign the given message, returning a digital signature on success, or an error if /// something went wrong. @@ -132,20 +190,24 @@ pub trait RandomizedSigner { &self, rng: &mut R, msg: &[u8], - ) -> Result; + ) -> Result; } /// Equivalent of [`RandomizedSigner`] but the message is provided in non-contiguous byte slices. #[cfg(feature = "rand_core")] pub trait RandomizedMultipartSigner { - /// Equivalent of [`RandomizedSigner::sign_with_rng()`] but the message is provided in + /// Equivalent of [`RandomizedSigner::sign_with_rng`] but the message is provided in /// non-contiguous byte slices. - fn multipart_sign_with_rng(&self, rng: &mut R, msg: &[&[u8]]) -> S { - self.try_multipart_sign_with_rng(rng, msg) - .expect("signature operation failed") - } + fn multipart_sign_with_rng(&self, rng: &mut R, msg: &[&[u8]]) -> S; +} + +/// This is a fallible equivalent of the [`RandomizedMultipartSigner`] trait. +#[cfg(feature = "rand_core")] +pub trait TryRandomizedMultipartSigner { + /// Error type. + type Error: core::error::Error + Into; - /// Equivalent of [`RandomizedSigner::try_sign_with_rng()`] but the message is provided in + /// Equivalent of [`TryRandomizedSigner::try_sign_with_rng`] but the message is provided in /// non-contiguous byte slices. /// /// # Errors @@ -155,27 +217,25 @@ pub trait RandomizedMultipartSigner { &self, rng: &mut R, msg: &[&[u8]], - ) -> Result; + ) -> Result; } -/// Combination of [`DigestSigner`] and [`RandomizedSigner`] with support for computing a signature -/// over a digest which requires entropy from an RNG. +/// Combination of [`DigestSigner`] and [`RandomizedSigner`] with support for +/// computing a signature over a digest which requires entropy from an RNG. #[cfg(all(feature = "digest", feature = "rand_core"))] pub trait RandomizedDigestSigner { /// Sign a message by updating the received `Digest` with it, returning a signature. /// /// The given function can be invoked multiple times. It is expected that in each invocation the /// `Digest` is updated with the entire equal message. - /// - /// # Panics - /// In the event of a signing error. - fn sign_digest_with_rng(&self, rng: &mut R, f: F) -> S { - self.try_sign_digest_with_rng(rng, |digest| { - f(digest); - Ok(()) - }) - .expect("signature operation failed") - } + fn sign_digest_with_rng(&self, rng: &mut R, f: F) -> S; +} + +/// This is a fallible equivalent of the [`RandomizedDigestSigner`] trait. +#[cfg(all(feature = "digest", feature = "rand_core"))] +pub trait TryRandomizedDigestSigner { + /// Error type. + type Error: core::error::Error + Into; /// Attempt to sign a message by updating the received `Digest` with it, returning a digital /// signature on success, or an error if something went wrong. @@ -186,11 +246,14 @@ pub trait RandomizedDigestSigner { /// # Errors /// Returns implementation-specific errors in the event signing failed (e.g. KMS or HSM /// communication error), or if the provided `rng` experiences an internal failure. - fn try_sign_digest_with_rng Result<(), Error>>( + fn try_sign_digest_with_rng< + R: TryCryptoRng + ?Sized, + F: Fn(&mut D) -> Result<(), Self::Error>, + >( &self, rng: &mut R, f: F, - ) -> Result; + ) -> Result; } /// Sign the provided message bytestring using `&mut Self` (e.g. an evolving cryptographic key such @@ -199,70 +262,69 @@ pub trait RandomizedDigestSigner { #[cfg(feature = "rand_core")] pub trait RandomizedSignerMut { /// Sign the given message, update the state, and return a digital signature. - /// - /// # Panics - /// In the event of a signing error. - fn sign_with_rng(&mut self, rng: &mut R, msg: &[u8]) -> S { - self.try_sign_with_rng(rng, msg) - .expect("signature operation failed") - } + fn sign_with_rng(&mut self, rng: &mut R, msg: &[u8]) -> S; +} + +/// This is a fallible equivalent of the [`RandomizedSignerMut`] trait. +#[cfg(feature = "rand_core")] +pub trait TryRandomizedSignerMut { + /// Error type. + type Error: core::error::Error + Into; /// Attempt to sign the given message, updating the state, and returning a digital signature on /// success, or an error if something went wrong. /// /// # Errors - /// Signing can fail, e.g. if the number of time periods allowed by the current key is exceeded, + /// Signing can fail, e.g. if the number of time periods allowed by the current key is exceeded /// or if the provided `rng` experiences an internal failure. fn try_sign_with_rng( &mut self, rng: &mut R, msg: &[u8], - ) -> Result; + ) -> Result; } /// Equivalent of [`RandomizedSignerMut`] but the message is provided in non-contiguous byte slices. #[cfg(feature = "rand_core")] pub trait RandomizedMultipartSignerMut { - /// Equivalent of [`RandomizedSignerMut::sign_with_rng()`] but the message is provided in - /// non-contiguous byte slices. - /// - /// # Panics - /// In the event of a signing error. - fn multipart_sign_with_rng(&mut self, rng: &mut R, msg: &[&[u8]]) -> S { - self.try_multipart_sign_with_rng(rng, msg) - .expect("signature operation failed") - } + /// Equivalent of [`RandomizedSignerMut::sign_with_rng()`] but + /// the message is provided in non-contiguous byte slices. + fn multipart_sign_with_rng(&mut self, rng: &mut R, msg: &[&[u8]]) -> S; +} - /// Equivalent of [`RandomizedSignerMut::try_sign_with_rng()`] but the message is provided in +/// This is a fallible equivalent of the [`RandomizedMultipartSignerMut`] trait. +#[cfg(feature = "rand_core")] +pub trait TryRandomizedMultipartSignerMut { + /// Error type. + type Error: core::error::Error + Into; + + /// Equivalent of [`TryRandomizedSignerMut::try_sign_with_rng()`] but the message is provided in /// non-contiguous byte slices. /// /// # Errors - /// Signing can fail, e.g. if the number of time periods allowed by the current key is exceeded, - /// or if the provided `rng` experiences an internal failure. + /// Returns implementation-specific errors in the event signing failed (e.g. KMS or HSM + /// communication error), or if the provided `rng` experiences an internal failure. fn try_multipart_sign_with_rng( &mut self, rng: &mut R, msg: &[&[u8]], - ) -> Result; -} - -/// Blanket impl of [`RandomizedSignerMut`] for all [`RandomizedSigner`] types. -#[cfg(feature = "rand_core")] -impl> RandomizedSignerMut for T { - fn try_sign_with_rng( - &mut self, - rng: &mut R, - msg: &[u8], - ) -> Result { - T::try_sign_with_rng(self, rng, msg) - } + ) -> Result; } /// 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 [`Signer`] trait. -pub trait AsyncSigner { +pub trait AsyncSigner: TryAsyncSigner { + /// Sign the given message, returning a digital signature. + async fn sign_async(&self, msg: &[u8]) -> S; +} + +/// This is a fallible equivalent of the [`AsyncSigner`] trait. +pub trait TryAsyncSigner { + /// Error type. + type Error: core::error::Error + Into; + /// Attempt to sign the given message, returning a digital signature on success, or an error if /// something went wrong. /// @@ -272,16 +334,7 @@ pub trait AsyncSigner { /// # Errors /// Returns implementation-specific errors in the event signing failed (e.g. KMS or HSM /// communication error). - async fn sign_async(&self, msg: &[u8]) -> Result; -} - -impl AsyncSigner for T -where - T: Signer, -{ - async fn sign_async(&self, msg: &[u8]) -> Result { - self.try_sign(msg) - } + async fn try_sign_async(&self, msg: &[u8]) -> Result; } /// Asynchronously sign the given prehashed message `Digest` using `Self`. @@ -292,6 +345,21 @@ pub trait AsyncDigestSigner where D: Update, { + /// Sign a message by updating the received `Digest` with it, returning a digital signature. + async fn try_sign_digest_async(&self, f: F) -> S + where + F: AsyncFn(&mut D); +} + +/// This is a fallible equivalent of the [`RandomizedSignerMut`] trait. +#[cfg(feature = "digest")] +pub trait TryAsyncDigestSigner +where + D: Update, +{ + /// Error type. + type Error: core::error::Error + Into; + /// Attempt to sign a message by updating the received `Digest` with it, returning a digital /// signature on success, or an error if something went wrong. /// @@ -301,24 +369,23 @@ where /// # Errors /// Returns implementation-specific errors in the event signing failed (e.g. KMS or HSM /// communication error). - async fn sign_digest_async Result<(), Error>>( - &self, - f: F, - ) -> Result; + async fn try_sign_digest_async(&self, f: F) -> Result + where + F: AsyncFn(&mut D) -> Result<(), Self::Error>; } /// Sign the given message using the provided external randomness source. #[cfg(feature = "rand_core")] pub trait AsyncRandomizedSigner { /// Sign the given message and return a digital signature. - /// - /// # Panics - /// In the event of a signing error. - async fn sign_with_rng_async(&self, rng: &mut R, msg: &[u8]) -> S { - self.try_sign_with_rng_async(rng, msg) - .await - .expect("signature operation failed") - } + async fn sign_with_rng_async(&self, rng: &mut R, msg: &[u8]) -> S; +} + +/// This is a fallible equivalent of the [`AsyncRandomizedSigner`] trait. +#[cfg(feature = "rand_core")] +pub trait TryAsyncRandomizedSigner { + /// Error type. + type Error: core::error::Error + Into; /// Attempt to sign the given message, returning a digital signature on success, or an error if /// something went wrong. @@ -333,19 +400,5 @@ pub trait AsyncRandomizedSigner { &self, rng: &mut R, msg: &[u8], - ) -> Result; -} - -#[cfg(feature = "rand_core")] -impl AsyncRandomizedSigner for T -where - T: RandomizedSigner, -{ - async fn try_sign_with_rng_async( - &self, - rng: &mut R, - msg: &[u8], - ) -> Result { - self.try_sign_with_rng(rng, msg) - } + ) -> Result; }