16
16
//!
17
17
18
18
use core:: ptr;
19
- use core:: ops :: Deref ;
19
+ use core:: borrow :: Borrow ;
20
20
21
21
use key:: { SecretKey , PublicKey } ;
22
22
use ffi:: { self , CPtr } ;
@@ -39,106 +39,46 @@ use secp256k1_sys::types::{c_int, c_uchar, c_void};
39
39
/// assert_eq!(sec1, sec2);
40
40
/// # }
41
41
// ```
42
- #[ derive( Copy , Clone ) ]
43
- pub struct SharedSecret {
44
- data : [ u8 ; 256 ] ,
45
- len : usize ,
46
- }
47
- impl_raw_debug ! ( SharedSecret ) ;
48
-
49
-
50
- // This implementes `From<N>` for all `[u8; N]` arrays from 128bits(16 byte) to 2048bits allowing known hash lengths.
51
- // Lower than 128 bits isn't resistant to collisions any more.
52
- impl_from_array_len ! ( SharedSecret , 256 , ( 16 20 28 32 48 64 96 128 256 ) ) ;
53
-
54
- impl SharedSecret {
55
-
56
- /// Creates an empty `SharedSecret`.
57
- pub ( crate ) fn empty ( ) -> SharedSecret {
58
- SharedSecret {
59
- data : [ 0u8 ; 256 ] ,
60
- len : 0 ,
61
- }
62
- }
63
-
64
- /// Gets a pointer to the underlying data with the specified capacity.
65
- pub ( crate ) fn get_data_mut_ptr ( & mut self ) -> * mut u8 {
66
- self . data . as_mut_ptr ( )
67
- }
68
-
69
- /// Gets the capacity of the underlying data buffer.
70
- pub fn capacity ( & self ) -> usize {
71
- self . data . len ( )
72
- }
73
-
74
- /// Gets the len of the used data.
75
- pub fn len ( & self ) -> usize {
76
- self . len
77
- }
78
-
79
- /// Returns true if the underlying data buffer is empty.
80
- pub fn is_empty ( & self ) -> bool {
81
- self . data . is_empty ( )
82
- }
83
-
84
- /// Sets the length of the object.
85
- pub ( crate ) fn set_len ( & mut self , len : usize ) {
86
- debug_assert ! ( len <= self . data. len( ) ) ;
87
- self . len = len;
88
- }
89
- }
90
-
91
- impl PartialEq for SharedSecret {
92
- fn eq ( & self , other : & SharedSecret ) -> bool {
93
- self . as_ref ( ) == other. as_ref ( )
94
- }
95
- }
96
-
97
- impl AsRef < [ u8 ] > for SharedSecret {
98
- fn as_ref ( & self ) -> & [ u8 ] {
99
- & self . data [ ..self . len ]
100
- }
101
- }
102
-
103
- impl Deref for SharedSecret {
104
- type Target = [ u8 ] ;
105
- fn deref ( & self ) -> & [ u8 ] {
106
- & self . data [ ..self . len ]
107
- }
108
- }
109
-
110
-
111
- unsafe extern "C" fn c_callback ( output : * mut c_uchar , x : * const c_uchar , y : * const c_uchar , _data : * mut c_void ) -> c_int {
112
- ptr:: copy_nonoverlapping ( x, output, 32 ) ;
113
- ptr:: copy_nonoverlapping ( y, output. offset ( 32 ) , 32 ) ;
114
- 1
115
- }
42
+ #[ derive( Copy , Clone , Debug , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
43
+ pub struct SharedSecret ( [ u8 ; 32 ] ) ;
116
44
117
45
impl SharedSecret {
118
46
/// Creates a new shared secret from a pubkey and secret key.
119
47
#[ inline]
120
48
pub fn new ( point : & PublicKey , scalar : & SecretKey ) -> SharedSecret {
121
- let mut ss = SharedSecret :: empty ( ) ;
49
+ let mut buf = [ 0u8 ; 32 ] ;
122
50
let res = unsafe {
123
51
ffi:: secp256k1_ecdh (
124
52
ffi:: secp256k1_context_no_precomp,
125
- ss . get_data_mut_ptr ( ) ,
53
+ buf . as_mut_ptr ( ) ,
126
54
point. as_c_ptr ( ) ,
127
55
scalar. as_c_ptr ( ) ,
128
56
ffi:: secp256k1_ecdh_hash_function_default,
129
57
ptr:: null_mut ( ) ,
130
58
)
131
59
} ;
132
- // The default `secp256k1_ecdh_hash_function_default` should always return 1.
133
- // and the scalar was verified to be valid(0 > scalar > group_order) via the type system
134
60
debug_assert_eq ! ( res, 1 ) ;
135
- ss. set_len ( 32 ) ; // The default hash function is SHA256, which is 32 bytes long.
136
- ss
61
+ SharedSecret ( buf)
62
+ }
63
+ }
64
+
65
+ impl Borrow < [ u8 ] > for SharedSecret {
66
+ fn borrow ( & self ) -> & [ u8 ] {
67
+ & self . 0
68
+ }
69
+ }
70
+
71
+ impl AsRef < [ u8 ] > for SharedSecret {
72
+ fn as_ref ( & self ) -> & [ u8 ] {
73
+ & self . 0
137
74
}
138
75
}
139
76
140
77
/// Creates a shared point from public key and secret key.
141
78
///
79
+ /// **Important: use of a strong cryptographic hash function may be critical to security! Do NOT use
80
+ /// unless you understand cryptographical implications.** If not, use SharedSecret instead.
81
+ ///
142
82
/// Can be used like `SharedSecret` but caller is responsible for then hashing the returned buffer.
143
83
/// This allows for the use of a custom hash function since `SharedSecret` uses SHA256.
144
84
///
@@ -183,6 +123,12 @@ pub fn shared_secret_point(point: &PublicKey, scalar: &SecretKey) -> [u8; 64] {
183
123
xy
184
124
}
185
125
126
+ unsafe extern "C" fn c_callback ( output : * mut c_uchar , x : * const c_uchar , y : * const c_uchar , _data : * mut c_void ) -> c_int {
127
+ ptr:: copy_nonoverlapping ( x, output, 32 ) ;
128
+ ptr:: copy_nonoverlapping ( y, output. offset ( 32 ) , 32 ) ;
129
+ 1
130
+ }
131
+
186
132
#[ cfg( test) ]
187
133
#[ allow( unused_imports) ]
188
134
mod tests {
@@ -221,6 +167,30 @@ mod tests {
221
167
assert_eq ! ( x, new_x) ;
222
168
assert_eq ! ( y, new_y) ;
223
169
}
170
+
171
+ #[ test]
172
+ #[ cfg( not( fuzzing) ) ]
173
+ #[ cfg( all( feature="rand-std" , feature = "std" , feature = "bitcoin_hashes" ) ) ]
174
+ fn bitcoin_hashes_and_sys_generate_same_secret ( ) {
175
+ use hashes:: { sha256, Hash , HashEngine } ;
176
+
177
+ let s = Secp256k1 :: signing_only ( ) ;
178
+ let ( sk1, _) = s. generate_keypair ( & mut thread_rng ( ) ) ;
179
+ let ( _, pk2) = s. generate_keypair ( & mut thread_rng ( ) ) ;
180
+
181
+ let secret_sys = SharedSecret :: new ( & pk2, & sk1) ;
182
+
183
+ let xy = shared_secret_point ( & pk2, & sk1) ;
184
+
185
+ // Mimics logic in `bitcoin-core/secp256k1/src/module/main_impl.h`
186
+ let version = ( xy[ 63 ] & 0x01 ) | 0x02 ;
187
+ let mut engine = sha256:: HashEngine :: default ( ) ;
188
+ engine. input ( & [ version] ) ;
189
+ engine. input ( & xy. as_ref ( ) [ ..32 ] ) ;
190
+ let secret_bh = sha256:: Hash :: from_engine ( engine) ;
191
+
192
+ assert_eq ! ( secret_bh. as_inner( ) , secret_sys. as_ref( ) ) ;
193
+ }
224
194
}
225
195
226
196
#[ cfg( all( test, feature = "unstable" ) ) ]
0 commit comments