16
16
//! Support for shared secret computations
17
17
//!
18
18
19
- use core:: ptr;
19
+ use core:: { fmt , ptr} ;
20
20
use core:: ops:: { FnMut , Deref } ;
21
21
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 to_hex;
25
26
26
27
/// The buffer size (in bytes) used by `SharedSecret`.
27
28
const BUF_SIZE : usize = 256 ;
@@ -48,7 +49,7 @@ pub struct SharedSecret {
48
49
data : [ u8 ; BUF_SIZE ] ,
49
50
len : usize ,
50
51
}
51
- impl_raw_debug ! ( SharedSecret ) ;
52
+ impl_display_secret ! ( SharedSecret ) ;
52
53
53
54
// This implements `From<N>` for all `[u8; N]` arrays from 128bits(16 byte) to 2048bits allowing known hash lengths.
54
55
// Lower than 128 bits isn't resistant to collisions any more.
@@ -88,6 +89,11 @@ impl SharedSecret {
88
89
debug_assert ! ( len <= self . data. len( ) ) ;
89
90
self . len = len;
90
91
}
92
+
93
+ /// Serializes the whole shared secret buffer as byte value.
94
+ pub ( crate ) fn serialize_secret ( & self ) -> [ u8 ; BUF_SIZE ] {
95
+ self . data
96
+ }
91
97
}
92
98
93
99
impl PartialEq for SharedSecret {
@@ -183,6 +189,68 @@ impl SharedSecret {
183
189
y. copy_from_slice ( & xy[ 32 ..] ) ;
184
190
hash_function ( x, y)
185
191
}
192
+
193
+ /// Formats the explicit byte value of the shared secret kept inside the type as a
194
+ /// little-endian hexadecimal string using the provided formatter.
195
+ ///
196
+ /// This is the only method that outputs the actual shared secret value, and, thus,
197
+ /// should be used with extreme precaution.
198
+ ///
199
+ /// # Example
200
+ ///
201
+ /// ```
202
+ /// # #[cfg(all(feature = "std", not(feature = "bitcoin_hashes")))] {
203
+ /// # use std::str::FromStr;
204
+ /// # use secp256k1::{SecretKey, PublicKey};
205
+ /// use secp256k1::ecdh::SharedSecret;
206
+ /// # let pk = PublicKey::from_slice(&[3, 23, 183, 225, 206, 31, 159, 148, 195, 42, 67, 115, 146, 41, 248, 140, 11, 3, 51, 41, 111, 180, 110, 143, 114, 134, 88, 73, 198, 174, 52, 184, 78]).expect("hard coded slice should parse correctly");
207
+ /// # let sk = SecretKey::from_str("57f0148f94d13095cfda539d0da0d1541304b678d8b36e243980aab4e1b7cead").unwrap();
208
+ /// let secret = SharedSecret::new(&pk, &sk);
209
+ /// // Normal display hides the value.
210
+ /// assert_eq!(format!("{:?}", secret), "SharedSecret(#6b778f6da1cd7d46)");
211
+ /// // Here we explicitly display the secret value:
212
+ /// assert_eq!(
213
+ /// format!("{}", secret.display_secret()),
214
+ /// "cf05ae7da039ddce6d56dd57d3000c6dd91c6f1695eae47e05389f11e24670430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
215
+ /// // Can explicitly display with `{}` and `{:?}`.
216
+ /// assert_eq!(
217
+ /// format!("{:?}", secret.display_secret()),
218
+ /// format!("DisplaySecret(\"{}\")", secret.display_secret()));
219
+ /// # }
220
+ /// ```
221
+ #[ inline]
222
+ pub fn display_secret ( & self ) -> DisplaySecret {
223
+ DisplaySecret { secret : self . serialize_secret ( ) }
224
+ }
225
+ }
226
+
227
+ /// Helper struct for safely printing a shared secret.
228
+ ///
229
+ /// Formats the explicit byte value of the secret as a little-endian hexadecimal string using the
230
+ /// provided formatter.
231
+ #[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
232
+ pub struct DisplaySecret {
233
+ secret : [ u8 ; BUF_SIZE ]
234
+ }
235
+
236
+ impl fmt:: Debug for DisplaySecret {
237
+ #[ inline]
238
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
239
+ let mut slice = [ 0u8 ; BUF_SIZE * 2 ] ;
240
+ let hex = to_hex ( & self . secret , & mut slice) . expect ( "fixed-size hex serializer failed" ) ;
241
+ f. debug_tuple ( "DisplaySecret" )
242
+ . field ( & hex)
243
+ . finish ( )
244
+ }
245
+ }
246
+
247
+ impl fmt:: Display for DisplaySecret {
248
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
249
+ for byte in self . secret . iter ( ) {
250
+ write ! ( f, "{:02x}" , byte) ?;
251
+ }
252
+ Ok ( ( ) )
253
+ }
186
254
}
187
255
188
256
#[ cfg( test) ]
0 commit comments