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; }