From c3f91f762042debf7c516c21ad9b9a2a9f4ef3b8 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Mon, 14 Jul 2025 16:41:20 +0200 Subject: [PATCH] ed25519: implement `MultipartSigner/Verifier` (#764) --- ed25519-dalek/src/hazmat.rs | 4 ++-- ed25519-dalek/src/signing.rs | 22 +++++++++++++++++++--- ed25519-dalek/src/verifying.rs | 24 +++++++++++++++++------- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/ed25519-dalek/src/hazmat.rs b/ed25519-dalek/src/hazmat.rs index ce53f43..39167ce 100644 --- a/ed25519-dalek/src/hazmat.rs +++ b/ed25519-dalek/src/hazmat.rs @@ -142,7 +142,7 @@ pub fn raw_sign( where CtxDigest: Digest, { - esk.raw_sign::(message, verifying_key) + esk.raw_sign::(&[message], verifying_key) } /// Compute a signature over the given prehashed message, the Ed25519ph algorithm defined in @@ -230,7 +230,7 @@ pub fn raw_verify( where CtxDigest: Digest, { - vk.raw_verify::(message, signature) + vk.raw_verify::(&[message], signature) } /// The batched Ed25519 verification check, rejecting non-canonical R values. `MsgDigest` is the diff --git a/ed25519-dalek/src/signing.rs b/ed25519-dalek/src/signing.rs index d5ff0fd..de68dac 100644 --- a/ed25519-dalek/src/signing.rs +++ b/ed25519-dalek/src/signing.rs @@ -29,7 +29,7 @@ use curve25519_dalek::{ scalar::Scalar, }; -use ed25519::signature::{KeypairRef, Signer, Verifier}; +use ed25519::signature::{KeypairRef, MultipartSigner, MultipartVerifier, Signer, Verifier}; #[cfg(feature = "digest")] use crate::context::Context; @@ -568,6 +568,12 @@ impl KeypairRef for SigningKey { impl Signer for SigningKey { /// Sign a message with this signing key's secret key. fn try_sign(&self, message: &[u8]) -> Result { + self.try_multipart_sign(&[message]) + } +} + +impl MultipartSigner for SigningKey { + fn try_multipart_sign(&self, message: &[&[u8]]) -> Result { let expanded: ExpandedSecretKey = (&self.secret_key).into(); Ok(expanded.raw_sign::(message, &self.verifying_key)) } @@ -615,6 +621,16 @@ impl Verifier for SigningKey { } } +impl MultipartVerifier for SigningKey { + fn multipart_verify( + &self, + message: &[&[u8]], + signature: &Signature, + ) -> Result<(), SignatureError> { + self.verifying_key.multipart_verify(message, signature) + } +} + impl From for SigningKey { #[inline] fn from(secret: SecretKey) -> Self { @@ -829,7 +845,7 @@ impl ExpandedSecretKey { #[inline(always)] pub(crate) fn raw_sign( &self, - message: &[u8], + message: &[&[u8]], verifying_key: &VerifyingKey, ) -> Signature where @@ -838,7 +854,7 @@ impl ExpandedSecretKey { // OK unwrap, update can't fail. self.raw_sign_byupdate( |h: &mut CtxDigest| { - h.update(message); + message.iter().for_each(|slice| h.update(slice)); Ok(()) }, verifying_key, diff --git a/ed25519-dalek/src/verifying.rs b/ed25519-dalek/src/verifying.rs index d9946a5..fd2a6e9 100644 --- a/ed25519-dalek/src/verifying.rs +++ b/ed25519-dalek/src/verifying.rs @@ -19,7 +19,7 @@ use curve25519_dalek::{ scalar::Scalar, }; -use ed25519::signature::Verifier; +use ed25519::signature::{MultipartVerifier, Verifier}; use sha2::Sha512; @@ -200,7 +200,7 @@ impl VerifyingKey { #[allow(non_snake_case)] pub(crate) fn raw_verify( &self, - message: &[u8], + message: &[&[u8]], signature: &ed25519::Signature, ) -> Result<(), SignatureError> where @@ -245,7 +245,7 @@ impl VerifyingKey { let message = prehashed_message.finalize(); - let expected_R = RCompute::::compute(self, signature, Some(ctx), &message); + let expected_R = RCompute::::compute(self, signature, Some(ctx), &[&message]); if expected_R == signature.R { Ok(()) @@ -371,7 +371,7 @@ impl VerifyingKey { return Err(InternalError::Verify.into()); } - let expected_R = RCompute::::compute(self, signature, None, message); + let expected_R = RCompute::::compute(self, signature, None, &[message]); if expected_R == signature.R { Ok(()) } else { @@ -447,7 +447,7 @@ impl VerifyingKey { } let message = prehashed_message.finalize(); - let expected_R = RCompute::::compute(self, signature, Some(ctx), &message); + let expected_R = RCompute::::compute(self, signature, Some(ctx), &[&message]); if expected_R == signature.R { Ok(()) @@ -508,10 +508,10 @@ where key: &VerifyingKey, signature: InternalSignature, prehash_ctx: Option<&[u8]>, - message: &[u8], + message: &[&[u8]], ) -> CompressedEdwardsY { let mut c = Self::new(key, signature, prehash_ctx); - c.update(message); + message.iter().for_each(|slice| c.update(slice)); c.finish() } @@ -561,6 +561,16 @@ impl Verifier for VerifyingKey { /// /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> { + self.multipart_verify(&[message], signature) + } +} + +impl MultipartVerifier for VerifyingKey { + fn multipart_verify( + &self, + message: &[&[u8]], + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> { self.raw_verify::(message, signature) } }