@@ -354,6 +354,18 @@ impl Signature {
354
354
. ok ( )
355
355
. map ( |recovered| Public ( recovered. serialize_compressed ( ) ) )
356
356
}
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
+ }
357
369
}
358
370
359
371
#[ cfg( feature = "full_crypto" ) ]
@@ -537,6 +549,22 @@ impl Pair {
537
549
let message = secp256k1:: Message :: parse ( message) ;
538
550
secp256k1:: sign ( & message, & self . secret ) . into ( )
539
551
}
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
+ }
540
568
}
541
569
542
570
impl CryptoType for Public {
@@ -791,4 +819,37 @@ mod test {
791
819
792
820
assert_eq ! ( sig1, sig2) ;
793
821
}
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
+ }
794
855
}
0 commit comments