secp256k1/
secret.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Helpers for displaying secret values
4
5use core::fmt;
6
7use crate::constants::SECRET_KEY_SIZE;
8use crate::ecdh::SharedSecret;
9use crate::key::{Keypair, SecretKey};
10use crate::to_hex;
11macro_rules! impl_display_secret {
12    // Default hasher exists only in standard library and not alloc
13    ($thing:ident) => {
14        impl ::core::fmt::Debug for $thing {
15            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
16                use core::fmt;
17
18                use secp256k1_sys::secp256k1_ecdh_hash_function_default;
19
20                struct Hex16Writer([u8; 32]);
21
22                let mut output = Hex16Writer([0u8; 32]);
23                unsafe {
24                    // SAFETY: this function pointer is an Option<fn> so we need to unwrap it, even
25                    // though we know that the FFI has provided a non-null value for us.
26                    let ecdh_hash = secp256k1_ecdh_hash_function_default.unwrap();
27                    // SAFETY: output points to >= 32 mutable bytes; both inputs are >= 32 bytes
28                    assert!(self.as_ref().len() >= 32);
29                    ecdh_hash(
30                        output.0.as_mut_ptr(),
31                        self.as_ref().as_ptr(),
32                        "a debug-only byte 'y coordinate'".as_ptr(),
33                        core::ptr::null_mut(),
34                    );
35                }
36
37                impl fmt::Debug for Hex16Writer {
38                    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39                        for byte in self.0.iter().copied().take(8) {
40                            write!(f, "{:02x}", byte)?;
41                        }
42                        Ok(())
43                    }
44                }
45
46                f.debug_tuple(stringify!($thing)).field(&output).finish()
47            }
48        }
49    };
50}
51
52/// Helper struct for safely printing secrets (like [`SecretKey`] value).
53/// Formats the explicit byte value of the secret kept inside the type as a
54/// little-endian hexadecimal string using the provided formatter.
55///
56/// Secrets should not implement neither [`Debug`] and [`Display`] traits directly,
57/// and instead provide `fn display_secret<'a>(&'a self) -> DisplaySecret<'a>`
58/// function to be used in different display contexts (see "examples" below).
59///
60/// [`Display`]: fmt::Display
61/// [`Debug`]: fmt::Debug
62#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
63pub struct DisplaySecret {
64    secret: [u8; SECRET_KEY_SIZE],
65}
66impl_non_secure_erase!(DisplaySecret, secret, [0u8; SECRET_KEY_SIZE]);
67
68impl fmt::Debug for DisplaySecret {
69    #[inline]
70    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71        let mut slice = [0u8; SECRET_KEY_SIZE * 2];
72        let hex = to_hex(&self.secret, &mut slice).expect("fixed-size hex serializer failed");
73        f.debug_tuple("DisplaySecret").field(&hex).finish()
74    }
75}
76
77impl fmt::Display for DisplaySecret {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        for byte in &self.secret {
80            write!(f, "{:02x}", byte)?;
81        }
82        Ok(())
83    }
84}
85
86impl SecretKey {
87    /// Formats the explicit byte value of the secret key kept inside the type as a
88    /// little-endian hexadecimal string using the provided formatter.
89    ///
90    /// This is the only method that outputs the actual secret key value, and, thus,
91    /// should be used with extreme caution.
92    ///
93    /// # Examples
94    ///
95    /// ```
96    /// # #[cfg(feature = "std")] {
97    /// # use std::str::FromStr;
98    /// use secp256k1::SecretKey;
99    /// let key = SecretKey::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap();
100    ///
101    /// // Normal debug hides value (`Display` is not implemented for `SecretKey`).
102    /// // E.g., `format!("{:?}", key)` prints "SecretKey(#2518682f7819fb2d)".
103    ///
104    /// // Here we explicitly display the secret value:
105    /// assert_eq!(
106    ///     "0000000000000000000000000000000000000000000000000000000000000001",
107    ///     format!("{}", key.display_secret())
108    /// );
109    /// // Also, we can explicitly display with `Debug`:
110    /// assert_eq!(
111    ///     format!("{:?}", key.display_secret()),
112    ///     format!("DisplaySecret(\"{}\")", key.display_secret())
113    /// );
114    /// # }
115    /// ```
116    #[inline]
117    pub fn display_secret(&self) -> DisplaySecret {
118        DisplaySecret { secret: self.to_secret_bytes() }
119    }
120}
121
122impl Keypair {
123    /// Formats the explicit byte value of the secret key kept inside the type as a
124    /// little-endian hexadecimal string using the provided formatter.
125    ///
126    /// This is the only method that outputs the actual secret key value, and, thus,
127    /// should be used with extreme precaution.
128    ///
129    /// # Example
130    ///
131    /// ```
132    /// # #[cfg(feature = "std")] {
133    /// # use std::str::FromStr;
134    /// use secp256k1::{Keypair, Secp256k1, SecretKey};
135    ///
136    /// let secp = Secp256k1::new();
137    /// let key = SecretKey::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap();
138    /// let key = Keypair::from_secret_key(&key);
139    /// // Here we explicitly display the secret value:
140    /// assert_eq!(
141    ///     "0000000000000000000000000000000000000000000000000000000000000001",
142    ///     format!("{}", key.display_secret())
143    /// );
144    /// // Also, we can explicitly display with `Debug`:
145    /// assert_eq!(
146    ///     format!("{:?}", key.display_secret()),
147    ///     format!("DisplaySecret(\"{}\")", key.display_secret())
148    /// );
149    /// # }
150    /// ```
151    #[inline]
152    pub fn display_secret(&self) -> DisplaySecret { DisplaySecret { secret: self.secret_bytes() } }
153}
154
155impl SharedSecret {
156    /// Formats the explicit byte value of the shared secret kept inside the type as a
157    /// little-endian hexadecimal string using the provided formatter.
158    ///
159    /// This is the only method that outputs the actual shared secret value, and, thus,
160    /// should be used with extreme caution.
161    ///
162    /// # Examples
163    ///
164    /// ```
165    /// # #[cfg(not(secp256k1_fuzz))]
166    /// # #[cfg(feature = "std")] {
167    /// # use std::str::FromStr;
168    /// use secp256k1::{SecretKey, PublicKey};
169    /// use secp256k1::ecdh::SharedSecret;
170    ///
171    /// # 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");
172    /// # let sk = SecretKey::from_str("57f0148f94d13095cfda539d0da0d1541304b678d8b36e243980aab4e1b7cead").unwrap();
173    ///
174    /// let secret = SharedSecret::new(&pk, &sk);
175    /// // Here we explicitly display the secret value:
176    /// assert_eq!(
177    ///     format!("{}", secret.display_secret()),
178    ///     "cf05ae7da039ddce6d56dd57d3000c6dd91c6f1695eae47e05389f11e2467043"
179    /// );
180    /// // Also, we can explicitly display with `Debug`:
181    /// assert_eq!(
182    ///     format!("{:?}", secret.display_secret()),
183    ///     format!("DisplaySecret(\"{}\")", secret.display_secret())
184    /// );
185    /// # }
186    /// ```
187    #[inline]
188    pub fn display_secret(&self) -> DisplaySecret { DisplaySecret { secret: self.secret_bytes() } }
189}