diff --git a/signature-crate/src/sign/digest.rs b/signature-crate/src/sign/digest.rs index e4f21c2b..504a852f 100644 --- a/signature-crate/src/sign/digest.rs +++ b/signature-crate/src/sign/digest.rs @@ -4,7 +4,11 @@ //! For use signature algorithms that support an Initialize-Update-Finalize //! (IUF) API, such as ECDSA or Ed25519ph. -use crate::{error::Error, Signature}; +use super::Sign; +use crate::{ + error::Error, + signature::{RawDigestSignature, Signature}, +}; use digest::Digest; /// Sign the given prehashed message `Digest` using `Self`. @@ -14,5 +18,47 @@ where S: Signature, { /// Sign the given prehashed message `Digest`, returning a signature. - fn sign(&self, digest: D) -> Result; + fn sign_digest(&self, digest: D) -> Result; +} + +/// Sign the given message using a "raw digest" signature algorithm, i.e. +/// any algorithm where signatures are always computed as `S(H(m)))` where: +/// +/// - `S`: signature algorithm +/// - `H`: hash (a.k.a. digest) function +/// - `m`: message +/// +/// This is the preferred trait to be `impl`'d for such algorithms, and when +/// used will take advantage of a blanket `impl` of `Sign` which will hash +/// the original message in advance using the relevant `Digest` algorithm +pub trait SignRawDigest: Send + Sync +where + S: Signature + RawDigestSignature, +{ + /// Digest algorithm to hash the input message with + type Digest: Digest; + + /// Sign the given prehashed message `Digest`, returning a signature. + fn sign_raw_digest(&self, digest: Self::Digest) -> Result; +} + +impl SignDigest for T +where + D: Digest, + S: Signature + RawDigestSignature, + T: SignRawDigest, +{ + fn sign_digest(&self, digest: D) -> Result { + self.sign_raw_digest(digest) + } +} + +impl Sign for T +where + S: Signature + RawDigestSignature, + T: SignRawDigest, +{ + fn sign(&self, msg: &[u8]) -> Result { + self.sign_digest(>::Digest::new().chain(msg)) + } } diff --git a/signature-crate/src/signature.rs b/signature-crate/src/signature.rs index 8376a5a4..db6acca1 100644 --- a/signature-crate/src/signature.rs +++ b/signature-crate/src/signature.rs @@ -22,3 +22,15 @@ pub trait Signature: AsRef<[u8]> + Debug + Sized { self.as_slice().into() } } + +/// Marker trait for "raw digest" signature algorithms, i.e. any algorithm +/// where signatures are exclusively computed as `S(H(m)))` where: +/// +/// - `S`: signature algorithm +/// - `H`: hash (a.k.a. digest) function +/// - `m`: message +/// +/// Notably this does not hold true for Ed25519, which hashes the input message +/// twice in an effort to remain secure even in the event of collisions in the +/// underlying hash function. +pub trait RawDigestSignature {} diff --git a/signature-crate/src/verify/digest.rs b/signature-crate/src/verify/digest.rs index c577e700..f2d12db6 100644 --- a/signature-crate/src/verify/digest.rs +++ b/signature-crate/src/verify/digest.rs @@ -4,7 +4,11 @@ //! For use signature algorithms that support an Initialize-Update-Finalize //! (IUF) API, such as ECDSA or Ed25519ph. -use crate::{error::Error, Signature}; +use super::Verify; +use crate::{ + error::Error, + signature::{RawDigestSignature, Signature}, +}; use digest::Digest; /// Verify the provided signature for the given prehashed message `Digest` @@ -15,5 +19,50 @@ where S: Signature, { /// Verify the signature against the given `Digest` - fn verify(&self, digest: D, signature: &S) -> Result<(), Error>; + fn verify_digest(&self, digest: D, signature: &S) -> Result<(), Error>; +} + +/// Verify the given message using a "raw digest" signature algorithm, i.e. +/// any algorithm where signatures are always computed as `S(H(m)))` where: +/// +/// - `S`: signature algorithm +/// - `H`: hash (a.k.a. digest) function +/// - `m`: message +/// +/// This is the preferred trait to be `impl`'d for such algorithms, and when +/// used will take advantage of a blanket `impl` of `Sign` which will hash +/// the original message in advance using the relevant `Digest` algorithm +pub trait VerifyRawDigest: Send + Sync +where + S: Signature + RawDigestSignature, +{ + /// Digest algorithm to hash the input message with + type Digest: Digest; + + /// Verify the signature against given prehashed message `Digest` + fn verify_raw_digest(&self, digest: Self::Digest, signature: &S) -> Result<(), Error>; +} + +impl VerifyDigest for T +where + D: Digest, + S: Signature + RawDigestSignature, + T: VerifyRawDigest, +{ + fn verify_digest(&self, digest: D, signature: &S) -> Result<(), Error> { + self.verify_raw_digest(digest, signature) + } +} + +impl Verify for T +where + S: Signature + RawDigestSignature, + T: VerifyRawDigest, +{ + fn verify(&self, msg: &[u8], signature: &S) -> Result<(), Error> { + self.verify_raw_digest( + >::Digest::new().chain(msg), + signature, + ) + } }