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        #[cfg(feature = "std")]
15        impl core::fmt::Debug for $thing {
16            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
17                use core::hash::Hasher;
18                const DEBUG_HASH_TAG: &[u8] = &[
19                    0x66, 0xa6, 0x77, 0x1b, 0x9b, 0x6d, 0xae, 0xa1, 0xb2, 0xee, 0x4e, 0x07, 0x49,
20                    0x4a, 0xac, 0x87, 0xa9, 0xb8, 0x5b, 0x4b, 0x35, 0x02, 0xaa, 0x6d, 0x0f, 0x79,
21                    0xcb, 0x63, 0xe6, 0xf8, 0x66, 0x22,
22                ]; // =SHA256(b"rust-secp256k1DEBUG");
23
24                let mut hasher = std::collections::hash_map::DefaultHasher::new();
25
26                hasher.write(DEBUG_HASH_TAG);
27                hasher.write(DEBUG_HASH_TAG);
28                hasher.write(&self.secret_bytes());
29                let hash = hasher.finish();
30
31                f.debug_tuple(stringify!($thing)).field(&format_args!("#{:016x}", hash)).finish()
32            }
33        }
34
35        #[cfg(all(not(feature = "std"), feature = "hashes"))]
36        impl ::core::fmt::Debug for $thing {
37            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
38                use hashes::{sha256, Hash, HashEngine};
39
40                let tag = "rust-secp256k1DEBUG";
41
42                let mut engine = sha256::Hash::engine();
43                let tag_hash = sha256::Hash::hash(tag.as_bytes());
44                engine.input(&tag_hash[..]);
45                engine.input(&tag_hash[..]);
46                engine.input(&self.secret_bytes());
47                let hash = sha256::Hash::from_engine(engine);
48
49                f.debug_tuple(stringify!($thing)).field(&format_args!("#{:016x}", hash)).finish()
50            }
51        }
52
53        #[cfg(all(not(feature = "std"), not(feature = "hashes")))]
54        impl ::core::fmt::Debug for $thing {
55            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
56                write!(f, "<secret requires std or hashes feature to display>")
57            }
58        }
59    };
60}
61
62/// Helper struct for safely printing secrets (like [`SecretKey`] value).
63/// Formats the explicit byte value of the secret kept inside the type as a
64/// little-endian hexadecimal string using the provided formatter.
65///
66/// Secrets should not implement neither [`Debug`] and [`Display`] traits directly,
67/// and instead provide `fn display_secret<'a>(&'a self) -> DisplaySecret<'a>`
68/// function to be used in different display contexts (see "examples" below).
69///
70/// [`Display`]: fmt::Display
71/// [`Debug`]: fmt::Debug
72#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
73pub struct DisplaySecret {
74    secret: [u8; SECRET_KEY_SIZE],
75}
76impl_non_secure_erase!(DisplaySecret, secret, [0u8; SECRET_KEY_SIZE]);
77
78impl fmt::Debug for DisplaySecret {
79    #[inline]
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        let mut slice = [0u8; SECRET_KEY_SIZE * 2];
82        let hex = to_hex(&self.secret, &mut slice).expect("fixed-size hex serializer failed");
83        f.debug_tuple("DisplaySecret").field(&hex).finish()
84    }
85}
86
87impl fmt::Display for DisplaySecret {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        for byte in &self.secret {
90            write!(f, "{:02x}", byte)?;
91        }
92        Ok(())
93    }
94}
95
96impl SecretKey {
97    /// Formats the explicit byte value of the secret key kept inside the type as a
98    /// little-endian hexadecimal string using the provided formatter.
99    ///
100    /// This is the only method that outputs the actual secret key value, and, thus,
101    /// should be used with extreme caution.
102    ///
103    /// # Examples
104    ///
105    /// ```
106    /// # #[cfg(feature = "std")] {
107    /// # use std::str::FromStr;
108    /// use secp256k1::SecretKey;
109    /// let key = SecretKey::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap();
110    ///
111    /// // Normal debug hides value (`Display` is not implemented for `SecretKey`).
112    /// // E.g., `format!("{:?}", key)` prints "SecretKey(#2518682f7819fb2d)".
113    ///
114    /// // Here we explicitly display the secret value:
115    /// assert_eq!(
116    ///     "0000000000000000000000000000000000000000000000000000000000000001",
117    ///     format!("{}", key.display_secret())
118    /// );
119    /// // Also, we can explicitly display with `Debug`:
120    /// assert_eq!(
121    ///     format!("{:?}", key.display_secret()),
122    ///     format!("DisplaySecret(\"{}\")", key.display_secret())
123    /// );
124    /// # }
125    /// ```
126    #[inline]
127    pub fn display_secret(&self) -> DisplaySecret { DisplaySecret { secret: self.secret_bytes() } }
128}
129
130impl Keypair {
131    /// Formats the explicit byte value of the secret key kept inside the type as a
132    /// little-endian hexadecimal string using the provided formatter.
133    ///
134    /// This is the only method that outputs the actual secret key value, and, thus,
135    /// should be used with extreme precaution.
136    ///
137    /// # Example
138    ///
139    /// ```
140    /// # #[cfg(feature = "std")] {
141    /// # use std::str::FromStr;
142    /// use secp256k1::{Keypair, Secp256k1, SecretKey};
143    ///
144    /// let secp = Secp256k1::new();
145    /// let key = SecretKey::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap();
146    /// let key = Keypair::from_secret_key(&secp, &key);
147    /// // Here we explicitly display the secret value:
148    /// assert_eq!(
149    ///     "0000000000000000000000000000000000000000000000000000000000000001",
150    ///     format!("{}", key.display_secret())
151    /// );
152    /// // Also, we can explicitly display with `Debug`:
153    /// assert_eq!(
154    ///     format!("{:?}", key.display_secret()),
155    ///     format!("DisplaySecret(\"{}\")", key.display_secret())
156    /// );
157    /// # }
158    /// ```
159    #[inline]
160    pub fn display_secret(&self) -> DisplaySecret { DisplaySecret { secret: self.secret_bytes() } }
161}
162
163impl SharedSecret {
164    /// Formats the explicit byte value of the shared secret kept inside the type as a
165    /// little-endian hexadecimal string using the provided formatter.
166    ///
167    /// This is the only method that outputs the actual shared secret value, and, thus,
168    /// should be used with extreme caution.
169    ///
170    /// # Examples
171    ///
172    /// ```
173    /// # #[cfg(not(secp256k1_fuzz))]
174    /// # #[cfg(feature = "std")] {
175    /// # use std::str::FromStr;
176    /// use secp256k1::{SecretKey, PublicKey};
177    /// use secp256k1::ecdh::SharedSecret;
178    ///
179    /// # 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");
180    /// # let sk = SecretKey::from_str("57f0148f94d13095cfda539d0da0d1541304b678d8b36e243980aab4e1b7cead").unwrap();
181    ///
182    /// let secret = SharedSecret::new(&pk, &sk);
183    /// // Here we explicitly display the secret value:
184    /// assert_eq!(
185    ///     format!("{}", secret.display_secret()),
186    ///     "cf05ae7da039ddce6d56dd57d3000c6dd91c6f1695eae47e05389f11e2467043"
187    /// );
188    /// // Also, we can explicitly display with `Debug`:
189    /// assert_eq!(
190    ///     format!("{:?}", secret.display_secret()),
191    ///     format!("DisplaySecret(\"{}\")", secret.display_secret())
192    /// );
193    /// # }
194    /// ```
195    #[inline]
196    pub fn display_secret(&self) -> DisplaySecret { DisplaySecret { secret: self.secret_bytes() } }
197}