@@ -22,7 +22,6 @@ use core::ops::{FnMut, Deref};
2222use key:: { SecretKey , PublicKey } ;
2323use ffi:: { self , CPtr } ;
2424use secp256k1_sys:: types:: { c_int, c_uchar, c_void} ;
25- use Error ;
2625
2726/// A tag used for recovering the public key from a compact signature
2827#[ derive( Copy , Clone ) ]
@@ -89,39 +88,12 @@ impl Deref for SharedSecret {
8988}
9089
9190
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
11795}
11896
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-
12597impl SharedSecret {
12698 /// Creates a new shared secret from a pubkey and secret key
12799 #[ inline]
@@ -137,35 +109,17 @@ impl SharedSecret {
137109 ptr:: null_mut ( ) ,
138110 )
139111 } ;
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 ) ;
141115 ss. set_len ( 32 ) ; // The default hash function is SHA256, which is 32 bytes long.
142116 ss
143117 }
144118
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- }
167119
168120 /// 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.
169123 /// # Examples
170124 /// ```
171125 /// # use secp256k1::ecdh::SharedSecret;
@@ -182,43 +136,29 @@ impl SharedSecret {
182136 /// });
183137 ///
184138 /// ```
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
187140 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 ] ;
190142
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)
222162 }
223163}
224164
@@ -248,9 +188,9 @@ mod tests {
248188 let ( sk1, pk1) = s. generate_keypair ( & mut thread_rng ( ) ) ;
249189 let ( sk2, pk2) = s. generate_keypair ( & mut thread_rng ( ) ) ;
250190
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 ( ) ) ;
254194 assert_eq ! ( sec1, sec2) ;
255195 assert_ne ! ( sec_odd, sec2) ;
256196 }
@@ -262,32 +202,29 @@ mod tests {
262202 let expect_result: [ u8 ; 64 ] = [ 123 ; 64 ] ;
263203 let mut x_out = [ 0u8 ; 32 ] ;
264204 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| {
266206 x_out = x;
267207 y_out = y;
268208 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+ } ) ;
275210 assert_eq ! ( & expect_result[ ..] , & result[ ..] ) ;
276- assert_eq ! ( result, result_unsafe) ;
277211 assert_ne ! ( x_out, [ 0u8 ; 32 ] ) ;
278212 assert_ne ! ( y_out, [ 0u8 ; 32 ] ) ;
279213 }
280214
281215 #[ 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) ;
291228 }
292229}
293230
0 commit comments