diff --git a/substrate/primitives/core/src/ecdsa.rs b/substrate/primitives/core/src/ecdsa.rs
index 1fb80f24eaf3ba054641e649028046f6cbacea11..c567b3c44f6cea9a00a23b81c3972d01e576152c 100644
--- a/substrate/primitives/core/src/ecdsa.rs
+++ b/substrate/primitives/core/src/ecdsa.rs
@@ -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")]
@@ -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 {
@@ -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);
+	}
 }