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}