3838//!
3939//! ```rust
4040//! extern crate secp256k1;
41+ //! # #[cfg(feature="bitcoin_hashes")]
42+ //! extern crate bitcoin_hashes;
4143//! # #[cfg(feature="rand")]
4244//! extern crate rand;
4345//!
4446//! #
4547//! # fn main() {
46- //! # #[cfg(feature="rand")] {
47- //! use rand::OsRng;
48+ //! # #[cfg(all( feature="rand", feature="bitcoin_hashes") )] {
49+ //! use rand::rngs:: OsRng;
4850//! use secp256k1::{Secp256k1, Message};
51+ //! use bitcoin_hashes::sha256;
4952//!
5053//! let secp = Secp256k1::new();
5154//! let mut rng = OsRng::new().expect("OsRng");
5255//! let (secret_key, public_key) = secp.generate_keypair(&mut rng);
53- //! let message = Message::from_slice(&[0xab; 32]).expect("32 bytes" );
56+ //! let message = Message::from_hashed_data::<sha256::Hash>("Hello World!".as_bytes() );
5457//!
5558//! let sig = secp.sign(&message, &secret_key);
5659//! assert!(secp.verify(&message, &sig, &public_key).is_ok());
5760//! # } }
5861//! ```
5962//!
60- //! The above code requires `rust-secp256k1` to be compiled with the `rand`
63+ //! The above code requires `rust-secp256k1` to be compiled with the `rand` and `bitcoin_hashes`
6164//! feature enabled, to get access to [`generate_keypair`](struct.Secp256k1.html#method.generate_keypair)
62- //! Alternately, keys can be parsed from slices, like
65+ //! Alternately, keys and messages can be parsed from slices, like
6366//!
6467//! ```rust
6568//! # fn main() {
6871//! let secp = Secp256k1::new();
6972//! let secret_key = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order");
7073//! let public_key = PublicKey::from_secret_key(&secp, &secret_key);
74+ //! // This is unsafe unless the supplied byte slice is the output of a cryptographic hash function.
75+ //! // See the above example for how to use this library together with bitcoin_hashes.
7176//! let message = Message::from_slice(&[0xab; 32]).expect("32 bytes");
7277//!
7378//! let sig = secp.sign(&message, &secret_key);
147152pub extern crate secp256k1_sys;
148153pub use secp256k1_sys as ffi;
149154
155+ #[ cfg( feature = "bitcoin_hashes" ) ] extern crate bitcoin_hashes;
150156#[ cfg( all( test, feature = "unstable" ) ) ] extern crate test;
151157#[ cfg( any( test, feature = "rand" ) ) ] pub extern crate rand;
152158#[ cfg( any( test) ) ] extern crate rand_core;
@@ -173,6 +179,9 @@ use core::marker::PhantomData;
173179use core:: ops:: Deref ;
174180use ffi:: CPtr ;
175181
182+ #[ cfg( feature = "bitcoin_hashes" ) ]
183+ use bitcoin_hashes:: Hash ;
184+
176185/// An ECDSA signature
177186#[ derive( Copy , Clone , PartialEq , Eq ) ]
178187pub struct Signature ( ffi:: Signature ) ;
@@ -219,6 +228,27 @@ pub trait ThirtyTwoByteHash {
219228 fn into_32 ( self ) -> [ u8 ; 32 ] ;
220229}
221230
231+ #[ cfg( feature = "bitcoin_hashes" ) ]
232+ impl ThirtyTwoByteHash for bitcoin_hashes:: sha256:: Hash {
233+ fn into_32 ( self ) -> [ u8 ; 32 ] {
234+ self . into_inner ( )
235+ }
236+ }
237+
238+ #[ cfg( feature = "bitcoin_hashes" ) ]
239+ impl ThirtyTwoByteHash for bitcoin_hashes:: sha256d:: Hash {
240+ fn into_32 ( self ) -> [ u8 ; 32 ] {
241+ self . into_inner ( )
242+ }
243+ }
244+
245+ #[ cfg( feature = "bitcoin_hashes" ) ]
246+ impl < T : bitcoin_hashes:: sha256t:: Tag > ThirtyTwoByteHash for bitcoin_hashes:: sha256t:: Hash < T > {
247+ fn into_32 ( self ) -> [ u8 ; 32 ] {
248+ self . into_inner ( )
249+ }
250+ }
251+
222252impl SerializedSignature {
223253 /// Get a pointer to the underlying data with the specified capacity.
224254 pub ( crate ) fn get_data_mut_ptr ( & mut self ) -> * mut u8 {
@@ -451,7 +481,12 @@ impl_array_newtype!(Message, u8, constants::MESSAGE_SIZE);
451481impl_pretty_debug ! ( Message ) ;
452482
453483impl Message {
454- /// Converts a `MESSAGE_SIZE`-byte slice to a message object
484+ /// **If you just want to sign an arbitrary message use `Message::from_hashed_data` instead.**
485+ ///
486+ /// Converts a `MESSAGE_SIZE`-byte slice to a message object. **WARNING:** the slice has to be a
487+ /// cryptographically secure hash of the actual message that's going to be signed. Otherwise
488+ /// the result of signing isn't a
489+ /// [secure signature](https://twitter.com/pwuille/status/1063582706288586752).
455490 #[ inline]
456491 pub fn from_slice ( data : & [ u8 ] ) -> Result < Message , Error > {
457492 if data == [ 0 ; constants:: MESSAGE_SIZE ] {
@@ -467,6 +502,25 @@ impl Message {
467502 _ => Err ( Error :: InvalidMessage )
468503 }
469504 }
505+
506+ /// Constructs a `Message` by hashing `data` with hash algorithm `H`. This requires the feature
507+ /// `bitcoin_hashes` to be enabled.
508+ /// ```rust
509+ /// extern crate bitcoin_hashes;
510+ /// use secp256k1::Message;
511+ /// use bitcoin_hashes::sha256;
512+ /// use bitcoin_hashes::Hash;
513+ ///
514+ /// let m1 = Message::from_hashed_data::<sha256::Hash>("Hello world!".as_bytes());
515+ /// // is equivalent to
516+ /// let m2 = Message::from(sha256::Hash::hash("Hello world!".as_bytes()));
517+ ///
518+ /// assert_eq!(m1, m2);
519+ /// ```
520+ #[ cfg( feature = "bitcoin_hashes" ) ]
521+ pub fn from_hashed_data < H : ThirtyTwoByteHash + bitcoin_hashes:: Hash > ( data : & [ u8 ] ) -> Self {
522+ <H as bitcoin_hashes:: Hash >:: hash ( data) . into ( )
523+ }
470524}
471525
472526impl < T : ThirtyTwoByteHash > From < T > for Message {
@@ -1110,6 +1164,31 @@ mod tests {
11101164 test_bad_slice ( ) ;
11111165 test_low_s ( ) ;
11121166 }
1167+
1168+ #[ cfg( feature = "bitcoin_hashes" ) ]
1169+ #[ test]
1170+ fn test_from_hash ( ) {
1171+ use bitcoin_hashes;
1172+ use bitcoin_hashes:: Hash ;
1173+
1174+ let test_bytes = "Hello world!" . as_bytes ( ) ;
1175+
1176+ let hash = bitcoin_hashes:: sha256:: Hash :: hash ( test_bytes) ;
1177+ let msg = Message :: from ( hash) ;
1178+ assert_eq ! ( msg. 0 , hash. into_inner( ) ) ;
1179+ assert_eq ! (
1180+ msg,
1181+ Message :: from_hashed_data:: <bitcoin_hashes:: sha256:: Hash >( test_bytes)
1182+ ) ;
1183+
1184+ let hash = bitcoin_hashes:: sha256d:: Hash :: hash ( test_bytes) ;
1185+ let msg = Message :: from ( hash) ;
1186+ assert_eq ! ( msg. 0 , hash. into_inner( ) ) ;
1187+ assert_eq ! (
1188+ msg,
1189+ Message :: from_hashed_data:: <bitcoin_hashes:: sha256d:: Hash >( test_bytes)
1190+ ) ;
1191+ }
11131192}
11141193
11151194#[ cfg( all( test, feature = "unstable" ) ) ]
0 commit comments