ed25519: implement MultipartSigner/Verifier (#764)

This commit is contained in:
daxpedda 2025-07-14 16:41:20 +02:00 committed by GitHub
parent fc8a8a5276
commit c3f91f7620
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 38 additions and 12 deletions

View file

@ -142,7 +142,7 @@ pub fn raw_sign<CtxDigest>(
where where
CtxDigest: Digest<OutputSize = U64>, CtxDigest: Digest<OutputSize = U64>,
{ {
esk.raw_sign::<CtxDigest>(message, verifying_key) esk.raw_sign::<CtxDigest>(&[message], verifying_key)
} }
/// Compute a signature over the given prehashed message, the Ed25519ph algorithm defined in /// Compute a signature over the given prehashed message, the Ed25519ph algorithm defined in
@ -230,7 +230,7 @@ pub fn raw_verify<CtxDigest>(
where where
CtxDigest: Digest<OutputSize = U64>, CtxDigest: Digest<OutputSize = U64>,
{ {
vk.raw_verify::<CtxDigest>(message, signature) vk.raw_verify::<CtxDigest>(&[message], signature)
} }
/// The batched Ed25519 verification check, rejecting non-canonical R values. `MsgDigest` is the /// The batched Ed25519 verification check, rejecting non-canonical R values. `MsgDigest` is the

View file

@ -29,7 +29,7 @@ use curve25519_dalek::{
scalar::Scalar, scalar::Scalar,
}; };
use ed25519::signature::{KeypairRef, Signer, Verifier}; use ed25519::signature::{KeypairRef, MultipartSigner, MultipartVerifier, Signer, Verifier};
#[cfg(feature = "digest")] #[cfg(feature = "digest")]
use crate::context::Context; use crate::context::Context;
@ -568,6 +568,12 @@ impl KeypairRef for SigningKey {
impl Signer<Signature> for SigningKey { impl Signer<Signature> for SigningKey {
/// Sign a message with this signing key's secret key. /// Sign a message with this signing key's secret key.
fn try_sign(&self, message: &[u8]) -> Result<Signature, SignatureError> { fn try_sign(&self, message: &[u8]) -> Result<Signature, SignatureError> {
self.try_multipart_sign(&[message])
}
}
impl MultipartSigner<Signature> for SigningKey {
fn try_multipart_sign(&self, message: &[&[u8]]) -> Result<Signature, SignatureError> {
let expanded: ExpandedSecretKey = (&self.secret_key).into(); let expanded: ExpandedSecretKey = (&self.secret_key).into();
Ok(expanded.raw_sign::<Sha512>(message, &self.verifying_key)) Ok(expanded.raw_sign::<Sha512>(message, &self.verifying_key))
} }
@ -615,6 +621,16 @@ impl Verifier<Signature> for SigningKey {
} }
} }
impl MultipartVerifier<Signature> for SigningKey {
fn multipart_verify(
&self,
message: &[&[u8]],
signature: &Signature,
) -> Result<(), SignatureError> {
self.verifying_key.multipart_verify(message, signature)
}
}
impl From<SecretKey> for SigningKey { impl From<SecretKey> for SigningKey {
#[inline] #[inline]
fn from(secret: SecretKey) -> Self { fn from(secret: SecretKey) -> Self {
@ -829,7 +845,7 @@ impl ExpandedSecretKey {
#[inline(always)] #[inline(always)]
pub(crate) fn raw_sign<CtxDigest>( pub(crate) fn raw_sign<CtxDigest>(
&self, &self,
message: &[u8], message: &[&[u8]],
verifying_key: &VerifyingKey, verifying_key: &VerifyingKey,
) -> Signature ) -> Signature
where where
@ -838,7 +854,7 @@ impl ExpandedSecretKey {
// OK unwrap, update can't fail. // OK unwrap, update can't fail.
self.raw_sign_byupdate( self.raw_sign_byupdate(
|h: &mut CtxDigest| { |h: &mut CtxDigest| {
h.update(message); message.iter().for_each(|slice| h.update(slice));
Ok(()) Ok(())
}, },
verifying_key, verifying_key,

View file

@ -19,7 +19,7 @@ use curve25519_dalek::{
scalar::Scalar, scalar::Scalar,
}; };
use ed25519::signature::Verifier; use ed25519::signature::{MultipartVerifier, Verifier};
use sha2::Sha512; use sha2::Sha512;
@ -200,7 +200,7 @@ impl VerifyingKey {
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub(crate) fn raw_verify<CtxDigest>( pub(crate) fn raw_verify<CtxDigest>(
&self, &self,
message: &[u8], message: &[&[u8]],
signature: &ed25519::Signature, signature: &ed25519::Signature,
) -> Result<(), SignatureError> ) -> Result<(), SignatureError>
where where
@ -245,7 +245,7 @@ impl VerifyingKey {
let message = prehashed_message.finalize(); let message = prehashed_message.finalize();
let expected_R = RCompute::<CtxDigest>::compute(self, signature, Some(ctx), &message); let expected_R = RCompute::<CtxDigest>::compute(self, signature, Some(ctx), &[&message]);
if expected_R == signature.R { if expected_R == signature.R {
Ok(()) Ok(())
@ -371,7 +371,7 @@ impl VerifyingKey {
return Err(InternalError::Verify.into()); return Err(InternalError::Verify.into());
} }
let expected_R = RCompute::<Sha512>::compute(self, signature, None, message); let expected_R = RCompute::<Sha512>::compute(self, signature, None, &[message]);
if expected_R == signature.R { if expected_R == signature.R {
Ok(()) Ok(())
} else { } else {
@ -447,7 +447,7 @@ impl VerifyingKey {
} }
let message = prehashed_message.finalize(); let message = prehashed_message.finalize();
let expected_R = RCompute::<Sha512>::compute(self, signature, Some(ctx), &message); let expected_R = RCompute::<Sha512>::compute(self, signature, Some(ctx), &[&message]);
if expected_R == signature.R { if expected_R == signature.R {
Ok(()) Ok(())
@ -508,10 +508,10 @@ where
key: &VerifyingKey, key: &VerifyingKey,
signature: InternalSignature, signature: InternalSignature,
prehash_ctx: Option<&[u8]>, prehash_ctx: Option<&[u8]>,
message: &[u8], message: &[&[u8]],
) -> CompressedEdwardsY { ) -> CompressedEdwardsY {
let mut c = Self::new(key, signature, prehash_ctx); let mut c = Self::new(key, signature, prehash_ctx);
c.update(message); message.iter().for_each(|slice| c.update(slice));
c.finish() c.finish()
} }
@ -561,6 +561,16 @@ impl Verifier<ed25519::Signature> for VerifyingKey {
/// ///
/// Returns `Ok(())` if the signature is valid, and `Err` otherwise. /// Returns `Ok(())` if the signature is valid, and `Err` otherwise.
fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> { fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> {
self.multipart_verify(&[message], signature)
}
}
impl MultipartVerifier<ed25519::Signature> for VerifyingKey {
fn multipart_verify(
&self,
message: &[&[u8]],
signature: &ed25519::Signature,
) -> Result<(), SignatureError> {
self.raw_verify::<Sha512>(message, signature) self.raw_verify::<Sha512>(message, signature)
} }
} }