38
38
//!
39
39
//! ```rust
40
40
//! extern crate secp256k1;
41
+ //! # #[cfg(feature="bitcoin_hashes")]
42
+ //! extern crate bitcoin_hashes;
41
43
//! # #[cfg(feature="rand")]
42
44
//! extern crate rand;
43
45
//!
44
46
//! #
45
47
//! # fn main() {
46
- //! # #[cfg(feature="rand")] {
47
- //! use rand::OsRng;
48
+ //! # #[cfg(all( feature="rand", feature="bitcoin_hashes") )] {
49
+ //! use rand::rngs:: OsRng;
48
50
//! use secp256k1::{Secp256k1, Message};
51
+ //! use bitcoin_hashes::sha256;
49
52
//!
50
53
//! let secp = Secp256k1::new();
51
54
//! let mut rng = OsRng::new().expect("OsRng");
52
55
//! 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() );
54
57
//!
55
58
//! let sig = secp.sign(&message, &secret_key);
56
59
//! assert!(secp.verify(&message, &sig, &public_key).is_ok());
57
60
//! # } }
58
61
//! ```
59
62
//!
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`
61
64
//! 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
63
66
//!
64
67
//! ```rust
65
68
//! # fn main() {
68
71
//! let secp = Secp256k1::new();
69
72
//! let secret_key = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order");
70
73
//! 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.
71
76
//! let message = Message::from_slice(&[0xab; 32]).expect("32 bytes");
72
77
//!
73
78
//! let sig = secp.sign(&message, &secret_key);
147
152
pub extern crate secp256k1_sys;
148
153
pub use secp256k1_sys as ffi;
149
154
155
+ #[ cfg( feature = "bitcoin_hashes" ) ] extern crate bitcoin_hashes;
150
156
#[ cfg( all( test, feature = "unstable" ) ) ] extern crate test;
151
157
#[ cfg( any( test, feature = "rand" ) ) ] pub extern crate rand;
152
158
#[ cfg( any( test) ) ] extern crate rand_core;
@@ -173,6 +179,9 @@ use core::marker::PhantomData;
173
179
use core:: ops:: Deref ;
174
180
use ffi:: CPtr ;
175
181
182
+ #[ cfg( feature = "bitcoin_hashes" ) ]
183
+ use bitcoin_hashes:: Hash ;
184
+
176
185
/// An ECDSA signature
177
186
#[ derive( Copy , Clone , PartialEq , Eq ) ]
178
187
pub struct Signature ( ffi:: Signature ) ;
@@ -219,6 +228,27 @@ pub trait ThirtyTwoByteHash {
219
228
fn into_32 ( self ) -> [ u8 ; 32 ] ;
220
229
}
221
230
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
+
222
252
impl SerializedSignature {
223
253
/// Get a pointer to the underlying data with the specified capacity.
224
254
pub ( crate ) fn get_data_mut_ptr ( & mut self ) -> * mut u8 {
@@ -451,7 +481,12 @@ impl_array_newtype!(Message, u8, constants::MESSAGE_SIZE);
451
481
impl_pretty_debug ! ( Message ) ;
452
482
453
483
impl 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).
455
490
#[ inline]
456
491
pub fn from_slice ( data : & [ u8 ] ) -> Result < Message , Error > {
457
492
if data == [ 0 ; constants:: MESSAGE_SIZE ] {
@@ -467,6 +502,25 @@ impl Message {
467
502
_ => Err ( Error :: InvalidMessage )
468
503
}
469
504
}
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
+ }
470
524
}
471
525
472
526
impl < T : ThirtyTwoByteHash > From < T > for Message {
@@ -1110,6 +1164,31 @@ mod tests {
1110
1164
test_bad_slice ( ) ;
1111
1165
test_low_s ( ) ;
1112
1166
}
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
+ }
1113
1192
}
1114
1193
1115
1194
#[ cfg( all( test, feature = "unstable" ) ) ]
0 commit comments