@@ -22,7 +22,6 @@ use core::ops::{FnMut, Deref};
22
22
use key:: { SecretKey , PublicKey } ;
23
23
use ffi:: { self , CPtr } ;
24
24
use secp256k1_sys:: types:: { c_int, c_uchar, c_void} ;
25
- use Error ;
26
25
27
26
/// A tag used for recovering the public key from a compact signature
28
27
#[ derive( Copy , Clone ) ]
@@ -89,39 +88,12 @@ impl Deref for SharedSecret {
89
88
}
90
89
91
90
92
- unsafe fn callback_logic < F > ( output : * mut c_uchar , x : * const c_uchar , y : * const c_uchar , data : * mut c_void ) -> c_int
93
- where F : FnMut ( [ u8 ; 32 ] , [ u8 ; 32 ] ) -> SharedSecret {
94
- let callback: & mut F = & mut * ( data as * mut F ) ;
95
-
96
- let mut x_arr = [ 0 ; 32 ] ;
97
- let mut y_arr = [ 0 ; 32 ] ;
98
- ptr:: copy_nonoverlapping ( x, x_arr. as_mut_ptr ( ) , 32 ) ;
99
- ptr:: copy_nonoverlapping ( y, y_arr. as_mut_ptr ( ) , 32 ) ;
100
-
101
- let secret = callback ( x_arr, y_arr) ;
102
- ptr:: copy_nonoverlapping ( secret. as_ptr ( ) , output as * mut u8 , secret. len ( ) ) ;
103
-
104
- secret. len ( ) as c_int
105
- }
106
-
107
- #[ cfg( feature = "std" ) ]
108
- unsafe extern "C" fn hash_callback_catch_unwind < F > ( output : * mut c_uchar , x : * const c_uchar , y : * const c_uchar , data : * mut c_void ) -> c_int
109
- where F : FnMut ( [ u8 ; 32 ] , [ u8 ; 32 ] ) -> SharedSecret {
110
-
111
- let res = :: std:: panic:: catch_unwind ( ||callback_logic :: < F > ( output, x, y, data) ) ;
112
- if let Ok ( len) = res {
113
- len
114
- } else {
115
- -1
116
- }
91
+ unsafe extern "C" fn c_callback ( output : * mut c_uchar , x : * const c_uchar , y : * const c_uchar , _data : * mut c_void ) -> c_int {
92
+ ptr:: copy_nonoverlapping ( x, output, 32 ) ;
93
+ ptr:: copy_nonoverlapping ( y, output. offset ( 32 ) , 32 ) ;
94
+ 1
117
95
}
118
96
119
- unsafe extern "C" fn hash_callback_unsafe < F > ( output : * mut c_uchar , x : * const c_uchar , y : * const c_uchar , data : * mut c_void ) -> c_int
120
- where F : FnMut ( [ u8 ; 32 ] , [ u8 ; 32 ] ) -> SharedSecret {
121
- callback_logic :: < F > ( output, x, y, data)
122
- }
123
-
124
-
125
97
impl SharedSecret {
126
98
/// Creates a new shared secret from a pubkey and secret key
127
99
#[ inline]
@@ -137,35 +109,17 @@ impl SharedSecret {
137
109
ptr:: null_mut ( ) ,
138
110
)
139
111
} ;
140
- debug_assert_eq ! ( res, 1 ) ; // The default `secp256k1_ecdh_hash_function_default` should always return 1.
112
+ // The default `secp256k1_ecdh_hash_function_default` should always return 1.
113
+ // and the scalar was verified to be valid(0 > scalar > group_order) via the type system
114
+ debug_assert_eq ! ( res, 1 ) ;
141
115
ss. set_len ( 32 ) ; // The default hash function is SHA256, which is 32 bytes long.
142
116
ss
143
117
}
144
118
145
- fn new_with_callback_internal < F > ( point : & PublicKey , scalar : & SecretKey , mut closure : F , callback : ffi:: EcdhHashFn ) -> Result < SharedSecret , Error >
146
- where F : FnMut ( [ u8 ; 32 ] , [ u8 ; 32 ] ) -> SharedSecret {
147
- let mut ss = SharedSecret :: empty ( ) ;
148
-
149
- let res = unsafe {
150
- ffi:: secp256k1_ecdh (
151
- ffi:: secp256k1_context_no_precomp,
152
- ss. get_data_mut_ptr ( ) ,
153
- point. as_ptr ( ) ,
154
- scalar. as_ptr ( ) ,
155
- callback,
156
- & mut closure as * mut F as * mut c_void ,
157
- )
158
- } ;
159
- if res == -1 {
160
- return Err ( Error :: CallbackPanicked ) ;
161
- }
162
- debug_assert ! ( res >= 16 ) ; // 128 bit is the minimum for a secure hash function and the minimum we let users.
163
- ss. set_len ( res as usize ) ;
164
- Ok ( ss)
165
-
166
- }
167
119
168
120
/// Creates a new shared secret from a pubkey and secret key with applied custom hash function
121
+ /// The custom hash function must be in the form of `fn(x: [u8;32], y: [u8;32]) -> SharedSecret`
122
+ /// `SharedSecret` can be easily created via the `From` impl from arrays.
169
123
/// # Examples
170
124
/// ```
171
125
/// # use secp256k1::ecdh::SharedSecret;
@@ -182,43 +136,29 @@ impl SharedSecret {
182
136
/// });
183
137
///
184
138
/// ```
185
- #[ cfg( feature = "std" ) ]
186
- pub fn new_with_hash < F > ( point : & PublicKey , scalar : & SecretKey , hash_function : F ) -> Result < SharedSecret , Error >
139
+ pub fn new_with_hash < F > ( point : & PublicKey , scalar : & SecretKey , mut hash_function : F ) -> SharedSecret
187
140
where F : FnMut ( [ u8 ; 32 ] , [ u8 ; 32 ] ) -> SharedSecret {
188
- Self :: new_with_callback_internal ( point, scalar, hash_function, hash_callback_catch_unwind :: < F > )
189
- }
141
+ let mut xy = [ 0u8 ; 64 ] ;
190
142
191
- /// Creates a new shared secret from a pubkey and secret key with applied custom hash function
192
- /// Note that this function is the same as [`new_with_hash`]
193
- ///
194
- /// # Safety
195
- /// The function doesn't wrap the callback with [`catch_unwind`]
196
- /// so if the callback panics it will panic through an FFI boundray which is [`Undefined Behavior`]
197
- /// If possible you should use [`new_with_hash`] which does wrap the callback with [`catch_unwind`] so is safe to use.
198
- ///
199
- /// [`catch_unwind`]: https://doc.rust-lang.org/std/panic/fn.catch_unwind.html
200
- /// [`Undefined Behavior`]: https://doc.rust-lang.org/nomicon/ffi.html#ffi-and-panics
201
- /// [`new_with_hash`]: #method.new_with_hash
202
- /// # Examples
203
- /// ```
204
- /// # use secp256k1::ecdh::SharedSecret;
205
- /// # use secp256k1::{Secp256k1, PublicKey, SecretKey};
206
- /// # fn sha2(_a: &[u8], _b: &[u8]) -> [u8; 32] {[0u8; 32]}
207
- /// # let secp = Secp256k1::signing_only();
208
- /// # let secret_key = SecretKey::from_slice(&[3u8; 32]).unwrap();
209
- /// # let secret_key2 = SecretKey::from_slice(&[7u8; 32]).unwrap();
210
- /// # let public_key = PublicKey::from_secret_key(&secp, &secret_key2);
211
- //
212
- /// let secret = unsafe { SharedSecret::new_with_hash_no_panic(&public_key, &secret_key, |x,y| {
213
- /// let hash: [u8; 32] = sha2(&x,&y);
214
- /// hash.into()
215
- /// })};
216
- ///
217
- ///
218
- /// ```
219
- pub unsafe fn new_with_hash_no_panic < F > ( point : & PublicKey , scalar : & SecretKey , hash_function : F ) -> Result < SharedSecret , Error >
220
- where F : FnMut ( [ u8 ; 32 ] , [ u8 ; 32 ] ) -> SharedSecret {
221
- Self :: new_with_callback_internal ( point, scalar, hash_function, hash_callback_unsafe :: < F > )
143
+ let res = unsafe {
144
+ ffi:: secp256k1_ecdh (
145
+ ffi:: secp256k1_context_no_precomp,
146
+ xy. as_mut_ptr ( ) ,
147
+ point. as_ptr ( ) ,
148
+ scalar. as_ptr ( ) ,
149
+ c_callback,
150
+ ptr:: null_mut ( ) ,
151
+ )
152
+ } ;
153
+ // Our callback *always* returns 1.
154
+ // and the scalar was verified to be valid(0 > scalar > group_order) via the type system
155
+ debug_assert_eq ! ( res, 1 ) ;
156
+
157
+ let mut x = [ 0u8 ; 32 ] ;
158
+ let mut y = [ 0u8 ; 32 ] ;
159
+ x. copy_from_slice ( & xy[ ..32 ] ) ;
160
+ y. copy_from_slice ( & xy[ 32 ..] ) ;
161
+ hash_function ( x, y)
222
162
}
223
163
}
224
164
@@ -248,9 +188,9 @@ mod tests {
248
188
let ( sk1, pk1) = s. generate_keypair ( & mut thread_rng ( ) ) ;
249
189
let ( sk2, pk2) = s. generate_keypair ( & mut thread_rng ( ) ) ;
250
190
251
- let sec1 = SharedSecret :: new_with_hash ( & pk1, & sk2, |x, _| x. into ( ) ) . unwrap ( ) ;
252
- let sec2 = SharedSecret :: new_with_hash ( & pk2, & sk1, |x, _| x. into ( ) ) . unwrap ( ) ;
253
- let sec_odd = SharedSecret :: new_with_hash ( & pk1, & sk1, |x, _| x. into ( ) ) . unwrap ( ) ;
191
+ let sec1 = SharedSecret :: new_with_hash ( & pk1, & sk2, |x, _| x. into ( ) ) ;
192
+ let sec2 = SharedSecret :: new_with_hash ( & pk2, & sk1, |x, _| x. into ( ) ) ;
193
+ let sec_odd = SharedSecret :: new_with_hash ( & pk1, & sk1, |x, _| x. into ( ) ) ;
254
194
assert_eq ! ( sec1, sec2) ;
255
195
assert_ne ! ( sec_odd, sec2) ;
256
196
}
@@ -262,32 +202,29 @@ mod tests {
262
202
let expect_result: [ u8 ; 64 ] = [ 123 ; 64 ] ;
263
203
let mut x_out = [ 0u8 ; 32 ] ;
264
204
let mut y_out = [ 0u8 ; 32 ] ;
265
- let result = SharedSecret :: new_with_hash ( & pk1, & sk1, | x, y | {
205
+ let result = SharedSecret :: new_with_hash ( & pk1, & sk1, |x, y| {
266
206
x_out = x;
267
207
y_out = y;
268
208
expect_result. into ( )
269
- } ) . unwrap ( ) ;
270
- let result_unsafe = unsafe { SharedSecret :: new_with_hash_no_panic ( & pk1, & sk1, | x, y | {
271
- x_out = x;
272
- y_out = y;
273
- expect_result. into ( )
274
- } ) . unwrap ( ) } ;
209
+ } ) ;
275
210
assert_eq ! ( & expect_result[ ..] , & result[ ..] ) ;
276
- assert_eq ! ( result, result_unsafe) ;
277
211
assert_ne ! ( x_out, [ 0u8 ; 32 ] ) ;
278
212
assert_ne ! ( y_out, [ 0u8 ; 32 ] ) ;
279
213
}
280
214
281
215
#[ test]
282
- fn ecdh_with_hash_callback_panic ( ) {
283
- let s = Secp256k1 :: signing_only ( ) ;
284
- let ( sk1, pk1) = s. generate_keypair ( & mut thread_rng ( ) ) ;
285
- let mut res = [ 0u8 ; 48 ] ;
286
- let result = SharedSecret :: new_with_hash ( & pk1, & sk1, | x, _ | {
287
- res. copy_from_slice ( & x) ; // res.len() != x.len(). this will panic.
288
- res. into ( )
289
- } ) ;
290
- assert_eq ! ( result, Err ( Error :: CallbackPanicked ) ) ;
216
+ fn test_c_callback ( ) {
217
+ let x = [ 5u8 ; 32 ] ;
218
+ let y = [ 7u8 ; 32 ] ;
219
+ let mut output = [ 0u8 ; 64 ] ;
220
+ let res = unsafe { super :: c_callback ( output. as_mut_ptr ( ) , x. as_ptr ( ) , y. as_ptr ( ) , :: ptr:: null_mut ( ) ) } ;
221
+ assert_eq ! ( res, 1 ) ;
222
+ let mut new_x = [ 0u8 ; 32 ] ;
223
+ let mut new_y = [ 0u8 ; 32 ] ;
224
+ new_x. copy_from_slice ( & output[ ..32 ] ) ;
225
+ new_y. copy_from_slice ( & output[ 32 ..] ) ;
226
+ assert_eq ! ( x, new_x) ;
227
+ assert_eq ! ( y, new_y) ;
291
228
}
292
229
}
293
230
0 commit comments