Skip to content

Commit f73c1a2

Browse files
authored
signature: add MultipartSigner and MultipartVerifier (#1880)
This PR adds new traits for multipart messages: `MultipartSigner`, `RandomizedMultipartSigner`, `RandomizedMultipartSignerMut` and `MultipartVerifier`. The idea here is to allow non-contiguous bytes to be passed, which is necessary when the message has to be constructed from multiple sources without wanting to allocate memory for a contiguous message. E.g. for `no_std` environments or when the message is rather big but pre-hashing is not applicable, e.g. PureEdDSA, ML-DSA or SLH-DSA. I know this is a rather big breaking change, so let me know what you think! These new traits can be implemented by a bunch of crates: - [x] `ecdsa`: RustCrypto/signatures#982 - [x] `ml-dsa`: RustCrypto/signatures#982 - [x] `slh-dsa`: RustCrypto/signatures#982 - [x] `bign256`: RustCrypto/elliptic-curves#1221 - [x] `sm2`: RustCrypto/elliptic-curves#1221 - [x] `k256`: RustCrypto/elliptic-curves#1221 - [x] `dsa`: RustCrypto/signatures#982 - [x] `lms`: RustCrypto/signatures#982 - [x] `rsa`: RustCrypto/RSA#525 - [ ] `ed25519-dalek` Resolves RustCrypto/signatures#959.
1 parent 57c9e79 commit f73c1a2

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

signature/src/signer.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,20 @@ pub trait Signer<S> {
2424
fn try_sign(&self, msg: &[u8]) -> Result<S, Error>;
2525
}
2626

27+
/// Equivalent of [`Signer`] but the message is provided in non-contiguous byte slices.
28+
pub trait MultipartSigner<S> {
29+
/// Equivalent of [`Signer::sign()`] but the message
30+
/// is provided in non-contiguous byte slices.
31+
fn multipart_sign(&self, msg: &[&[u8]]) -> S {
32+
self.try_multipart_sign(msg)
33+
.expect("signature operation failed")
34+
}
35+
36+
/// Equivalent of [`Signer::try_sign()`] but the
37+
/// message is provided in non-contiguous byte slices.
38+
fn try_multipart_sign(&self, msg: &[&[u8]]) -> Result<S, Error>;
39+
}
40+
2741
/// Sign the provided message bytestring using `&mut Self` (e.g. an evolving
2842
/// cryptographic key such as a stateful hash-based signature), returning a
2943
/// digital signature.
@@ -103,6 +117,25 @@ pub trait RandomizedSigner<S> {
103117
) -> Result<S, Error>;
104118
}
105119

120+
/// Equivalent of [`RandomizedSigner`] but the message is provided in non-contiguous byte slices.
121+
#[cfg(feature = "rand_core")]
122+
pub trait RandomizedMultipartSigner<S> {
123+
/// Equivalent of [`RandomizedSigner::sign_with_rng()`] but
124+
/// the message is provided in non-contiguous byte slices.
125+
fn multipart_sign_with_rng<R: CryptoRng + ?Sized>(&self, rng: &mut R, msg: &[&[u8]]) -> S {
126+
self.try_multipart_sign_with_rng(rng, msg)
127+
.expect("signature operation failed")
128+
}
129+
130+
/// Equivalent of [`RandomizedSigner::try_sign_with_rng()`] but
131+
/// the message is provided in non-contiguous byte slices.
132+
fn try_multipart_sign_with_rng<R: TryCryptoRng + ?Sized>(
133+
&self,
134+
rng: &mut R,
135+
msg: &[&[u8]],
136+
) -> Result<S, Error>;
137+
}
138+
106139
/// Combination of [`DigestSigner`] and [`RandomizedSigner`] with support for
107140
/// computing a signature over a digest which requires entropy from an RNG.
108141
#[cfg(all(feature = "digest", feature = "rand_core"))]
@@ -147,6 +180,25 @@ pub trait RandomizedSignerMut<S> {
147180
) -> Result<S, Error>;
148181
}
149182

183+
/// Equivalent of [`RandomizedSignerMut`] but the message is provided in non-contiguous byte slices.
184+
#[cfg(feature = "rand_core")]
185+
pub trait RandomizedMultipartSignerMut<S> {
186+
/// Equivalent of [`RandomizedSignerMut::sign_with_rng()`] but
187+
/// the message is provided in non-contiguous byte slices.
188+
fn multipart_sign_with_rng<R: CryptoRng + ?Sized>(&mut self, rng: &mut R, msg: &[&[u8]]) -> S {
189+
self.try_multipart_sign_with_rng(rng, msg)
190+
.expect("signature operation failed")
191+
}
192+
193+
/// Equivalent of [`RandomizedSignerMut::try_sign_with_rng()`]
194+
/// but the message is provided in non-contiguous byte slices.
195+
fn try_multipart_sign_with_rng<R: TryCryptoRng + ?Sized>(
196+
&mut self,
197+
rng: &mut R,
198+
msg: &[&[u8]],
199+
) -> Result<S, Error>;
200+
}
201+
150202
/// Blanket impl of [`RandomizedSignerMut`] for all [`RandomizedSigner`] types.
151203
#[cfg(feature = "rand_core")]
152204
impl<S, T: RandomizedSigner<S>> RandomizedSignerMut<S> for T {

signature/src/verifier.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ pub trait Verifier<S> {
1414
fn verify(&self, msg: &[u8], signature: &S) -> Result<(), Error>;
1515
}
1616

17+
/// Equivalent of [`Verifier`] but the message is provided in non-contiguous byte slices.
18+
pub trait MultipartVerifier<S> {
19+
/// Equivalent of [`Verifier::verify()`] but the
20+
/// message is provided in non-contiguous byte slices.
21+
fn multipart_verify(&self, msg: &[&[u8]], signature: &S) -> Result<(), Error>;
22+
}
23+
1724
/// Verify the provided signature for the given prehashed message [`Digest`]
1825
/// is authentic.
1926
///

0 commit comments

Comments
 (0)