1616//! Support for shared secret computations
1717//!
1818
19- use core:: ptr;
19+ use core:: { fmt , ptr} ;
2020use core:: ops:: { FnMut , Deref } ;
2121
2222use key:: { SecretKey , PublicKey } ;
2323use ffi:: { self , CPtr } ;
2424use secp256k1_sys:: types:: { c_int, c_uchar, c_void} ;
25+ use to_hex;
2526
2627/// The buffer size (in bytes) used by `SharedSecret`.
2728const BUF_SIZE : usize = 256 ;
@@ -48,7 +49,7 @@ pub struct SharedSecret {
4849 data : [ u8 ; BUF_SIZE ] ,
4950 len : usize ,
5051}
51- impl_raw_debug ! ( SharedSecret ) ;
52+ impl_display_secret ! ( SharedSecret ) ;
5253
5354// This implements `From<N>` for all `[u8; N]` arrays from 128bits(16 byte) to 2048bits allowing known hash lengths.
5455// Lower than 128 bits isn't resistant to collisions any more.
@@ -88,6 +89,11 @@ impl SharedSecret {
8889 debug_assert ! ( len <= self . data. len( ) ) ;
8990 self . len = len;
9091 }
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+ }
9197}
9298
9399impl PartialEq for SharedSecret {
@@ -183,6 +189,68 @@ impl SharedSecret {
183189 y. copy_from_slice ( & xy[ 32 ..] ) ;
184190 hash_function ( x, y)
185191 }
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+ }
186254}
187255
188256#[ cfg( test) ]
0 commit comments