Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit 48aea1b

Browse files
authored
Add ecdsa::Pair::verify_prehashed() (#8996)
* Add ecdsa::Pair::verify_prehashed() * turn verify_prehashed() into an associated function * add Signature::recover_prehashed()
1 parent 94679eb commit 48aea1b

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

primitives/core/src/ecdsa.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,18 @@ impl Signature {
354354
.ok()
355355
.map(|recovered| Public(recovered.serialize_compressed()))
356356
}
357+
358+
/// Recover the public key from this signature and a pre-hashed message.
359+
#[cfg(feature = "full_crypto")]
360+
pub fn recover_prehashed(&self, message: &[u8; 32]) -> Option<Public> {
361+
let message = secp256k1::Message::parse(message);
362+
363+
let sig: (_, _) = self.try_into().ok()?;
364+
365+
secp256k1::recover(&message, &sig.0, &sig.1)
366+
.ok()
367+
.map(|key| Public(key.serialize_compressed()))
368+
}
357369
}
358370

359371
#[cfg(feature = "full_crypto")]
@@ -537,6 +549,22 @@ impl Pair {
537549
let message = secp256k1::Message::parse(message);
538550
secp256k1::sign(&message, &self.secret).into()
539551
}
552+
553+
/// Verify a signature on a pre-hashed message. Return `true` if the signature is valid
554+
/// and thus matches the given `public` key.
555+
pub fn verify_prehashed(sig: &Signature, message: &[u8; 32], public: &Public) -> bool {
556+
let message = secp256k1::Message::parse(message);
557+
558+
let sig: (_, _) = match sig.try_into() {
559+
Ok(x) => x,
560+
_ => return false,
561+
};
562+
563+
match secp256k1::recover(&message, &sig.0, &sig.1) {
564+
Ok(actual) => public.0[..] == actual.serialize_compressed()[..],
565+
_ => false,
566+
}
567+
}
540568
}
541569

542570
impl CryptoType for Public {
@@ -791,4 +819,37 @@ mod test {
791819

792820
assert_eq!(sig1, sig2);
793821
}
822+
823+
#[test]
824+
fn verify_prehashed_works() {
825+
let (pair, _, _) = Pair::generate_with_phrase(Some("password"));
826+
827+
// `msg` and `sig` match
828+
let msg = keccak_256(b"this should be hashed");
829+
let sig = pair.sign_prehashed(&msg);
830+
assert!(Pair::verify_prehashed(&sig, &msg, &pair.public()));
831+
832+
// `msg` and `sig` don't match
833+
let msg = keccak_256(b"this is a different message");
834+
assert!(!Pair::verify_prehashed(&sig, &msg, &pair.public()));
835+
}
836+
837+
#[test]
838+
fn recover_prehashed_works() {
839+
let (pair, _, _) = Pair::generate_with_phrase(Some("password"));
840+
841+
// recovered key matches signing key
842+
let msg = keccak_256(b"this should be hashed");
843+
let sig = pair.sign_prehashed(&msg);
844+
let key = sig.recover_prehashed(&msg).unwrap();
845+
assert_eq!(pair.public(), key);
846+
847+
// recovered key is useable
848+
assert!(Pair::verify_prehashed(&sig, &msg, &key));
849+
850+
// recovered key and signing key don't match
851+
let msg = keccak_256(b"this is a different message");
852+
let key = sig.recover_prehashed(&msg).unwrap();
853+
assert_ne!(pair.public(), key);
854+
}
794855
}

0 commit comments

Comments
 (0)