Skip to content

Commit

Permalink
Add ecdsa::Pair::verify_prehashed() (paritytech#8996)
Browse files Browse the repository at this point in the history
* Add ecdsa::Pair::verify_prehashed()

* turn verify_prehashed() into an associated function

* add Signature::recover_prehashed()
  • Loading branch information
adoerr authored and jordy25519 committed Sep 17, 2021
1 parent 1b9e8e1 commit 5735b76
Showing 1 changed file with 61 additions and 0 deletions.
61 changes: 61 additions & 0 deletions primitives/core/src/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,18 @@ impl Signature {
.ok()
.map(|recovered| Public(recovered.serialize_compressed()))
}

/// Recover the public key from this signature and a pre-hashed message.
#[cfg(feature = "full_crypto")]
pub fn recover_prehashed(&self, message: &[u8; 32]) -> Option<Public> {
let message = secp256k1::Message::parse(message);

let sig: (_, _) = self.try_into().ok()?;

secp256k1::recover(&message, &sig.0, &sig.1)
.ok()
.map(|key| Public(key.serialize_compressed()))
}
}

#[cfg(feature = "full_crypto")]
Expand Down Expand Up @@ -537,6 +549,22 @@ impl Pair {
let message = secp256k1::Message::parse(message);
secp256k1::sign(&message, &self.secret).into()
}

/// Verify a signature on a pre-hashed message. Return `true` if the signature is valid
/// and thus matches the given `public` key.
pub fn verify_prehashed(sig: &Signature, message: &[u8; 32], public: &Public) -> bool {
let message = secp256k1::Message::parse(message);

let sig: (_, _) = match sig.try_into() {
Ok(x) => x,
_ => return false,
};

match secp256k1::recover(&message, &sig.0, &sig.1) {
Ok(actual) => public.0[..] == actual.serialize_compressed()[..],
_ => false,
}
}
}

impl CryptoType for Public {
Expand Down Expand Up @@ -791,4 +819,37 @@ mod test {

assert_eq!(sig1, sig2);
}

#[test]
fn verify_prehashed_works() {
let (pair, _, _) = Pair::generate_with_phrase(Some("password"));

// `msg` and `sig` match
let msg = keccak_256(b"this should be hashed");
let sig = pair.sign_prehashed(&msg);
assert!(Pair::verify_prehashed(&sig, &msg, &pair.public()));

// `msg` and `sig` don't match
let msg = keccak_256(b"this is a different message");
assert!(!Pair::verify_prehashed(&sig, &msg, &pair.public()));
}

#[test]
fn recover_prehashed_works() {
let (pair, _, _) = Pair::generate_with_phrase(Some("password"));

// recovered key matches signing key
let msg = keccak_256(b"this should be hashed");
let sig = pair.sign_prehashed(&msg);
let key = sig.recover_prehashed(&msg).unwrap();
assert_eq!(pair.public(), key);

// recovered key is useable
assert!(Pair::verify_prehashed(&sig, &msg, &key));

// recovered key and signing key don't match
let msg = keccak_256(b"this is a different message");
let key = sig.recover_prehashed(&msg).unwrap();
assert_ne!(pair.public(), key);
}
}

0 comments on commit 5735b76

Please sign in to comment.