secp256k1/key/secret.rs
1// SPDX-License-Identifier: CC0-1.0
2//! Secret signing keys.
3
4use core::{ops, str};
5
6#[cfg(feature = "serde")]
7use serde::ser::SerializeTuple;
8
9use crate::ffi::CPtr as _;
10use crate::{
11 constants, ecdsa, ffi, from_hex, Error, Keypair, Message, Parity, PublicKey, Scalar,
12 XOnlyPublicKey,
13};
14
15mod encapsulate {
16 use crate::constants::SECRET_KEY_SIZE;
17 use crate::ffi::{self, CPtr};
18 use crate::Error;
19
20 /// Secret key - a 256-bit key used to create ECDSA and Taproot signatures.
21 ///
22 /// This value should be generated using a [cryptographically secure pseudorandom number generator].
23 ///
24 /// # Side channel attacks
25 ///
26 /// We have attempted to reduce the side channel attack surface by implementing a constant time `eq`
27 /// method. For similar reasons we explicitly do not implement `PartialOrd`, `Ord`, or `Hash` on
28 /// `SecretKey`. If you really want to order secret keys then you can use `AsRef` to get at the
29 /// underlying bytes and compare them - however this is almost certainly a bad idea.
30 ///
31 /// # Serde support
32 ///
33 /// Implements de/serialization with the `serde` feature enabled. We treat the byte value as a tuple
34 /// of 32 `u8`s for non-human-readable formats. This representation is optimal for some formats
35 /// (e.g. [`bincode`]) however other formats may be less optimal (e.g. [`cbor`]).
36 ///
37 /// # Examples
38 ///
39 /// Basic usage:
40 ///
41 /// ```
42 /// # #[cfg(all(feature = "rand", feature = "std"))] {
43 /// use secp256k1::{rand, SecretKey};
44 ///
45 /// let secret_key = SecretKey::new(&mut rand::rng());
46 /// # }
47 /// ```
48 /// [`bincode`]: https://docs.rs/bincode
49 /// [`cbor`]: https://docs.rs/cbor
50 /// [cryptographically secure pseudorandom number generator]: https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator
51 #[derive(Copy, Clone)]
52 pub struct SecretKey([u8; SECRET_KEY_SIZE]);
53 // FIXME these two macro call should be moved outside of the encapsulate module
54 impl_display_secret!(SecretKey);
55 impl_non_secure_erase!(SecretKey, 0, [1u8; SECRET_KEY_SIZE]);
56
57 impl SecretKey {
58 /// Returns the secret key as a byte value.
59 ///
60 /// # Side channel attacks
61 ///
62 /// Using ordering functions (`PartialOrd`/`Ord`) on a reference to secret keys leaks data
63 /// because the implementations are not constant time. Doing so will make your code vulnerable
64 /// to side channel attacks. [`SecretKey::eq`] is implemented using a constant time algorithm,
65 /// please consider using it to do comparisons of secret keys.
66 #[inline]
67 pub fn to_secret_bytes(&self) -> [u8; SECRET_KEY_SIZE] { self.0 }
68
69 /// Returns a reference to the secret key as a byte array.
70 ///
71 /// See note on [`Self::to_secret_bytes`].
72 #[inline]
73 pub fn as_secret_bytes(&self) -> &[u8; SECRET_KEY_SIZE] { &self.0 }
74
75 /// Converts a 32-byte array to a secret key.
76 ///
77 /// See note on [`Self::to_secret_bytes`].
78 ///
79 /// # Errors
80 ///
81 /// Returns an error when the secret key is invalid: when it is all-zeros or would exceed
82 /// the curve order when interpreted as a big-endian unsigned integer.
83 ///
84 /// # Examples
85 ///
86 /// ```
87 /// use secp256k1::SecretKey;
88 /// let sk = SecretKey::from_byte_array([0xcd; 32]).expect("32 bytes, within curve order");
89 /// ```
90 #[inline]
91 pub fn from_secret_bytes(data: [u8; SECRET_KEY_SIZE]) -> Result<SecretKey, Error> {
92 crate::with_raw_global_context(
93 |ctx| unsafe {
94 if ffi::secp256k1_ec_seckey_verify(ctx.as_ptr(), data.as_c_ptr()) == 0 {
95 return Err(Error::InvalidSecretKey);
96 }
97 Ok(SecretKey(data))
98 },
99 None,
100 )
101 }
102 }
103
104 // Must be inside the `encapsulate` module since there is no way to obtain mutable
105 // access to the internal array outside of the module.
106 impl CPtr for SecretKey {
107 type Target = u8;
108
109 fn as_c_ptr(&self) -> *const Self::Target { self.as_secret_bytes().as_ptr() }
110
111 fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.0.as_mut_ptr() }
112 }
113}
114pub use encapsulate::SecretKey;
115
116impl PartialEq for SecretKey {
117 /// This implementation is designed to be constant time to help prevent side channel attacks.
118 #[inline]
119 fn eq(&self, other: &Self) -> bool {
120 let accum = self
121 .as_secret_bytes()
122 .iter()
123 .zip(other.as_secret_bytes())
124 .fold(0, |accum, (a, b)| accum | a ^ b);
125 unsafe { core::ptr::read_volatile(&accum) == 0 }
126 }
127}
128
129impl Eq for SecretKey {}
130
131impl AsRef<[u8; constants::SECRET_KEY_SIZE]> for SecretKey {
132 /// Gets a reference to the underlying array.
133 ///
134 /// See note on [`Self::to_secret_bytes`].
135 #[inline]
136 fn as_ref(&self) -> &[u8; constants::SECRET_KEY_SIZE] { self.as_secret_bytes() }
137}
138
139impl<I> ops::Index<I> for SecretKey
140where
141 [u8]: ops::Index<I>,
142{
143 type Output = <[u8] as ops::Index<I>>::Output;
144
145 #[inline]
146 fn index(&self, index: I) -> &Self::Output { &self.as_secret_bytes()[index] }
147}
148
149impl str::FromStr for SecretKey {
150 type Err = Error;
151 fn from_str(s: &str) -> Result<Self, Self::Err> {
152 let mut res = [0u8; constants::SECRET_KEY_SIZE];
153 match from_hex(s, &mut res) {
154 Ok(constants::SECRET_KEY_SIZE) => SecretKey::from_secret_bytes(res),
155 _ => Err(Error::InvalidSecretKey),
156 }
157 }
158}
159
160impl SecretKey {
161 /// Generates a new random secret key.
162 ///
163 /// # Examples
164 ///
165 /// ```
166 /// # #[cfg(all(feature = "std", feature = "rand"))] {
167 /// use secp256k1::{rand, SecretKey};
168 /// let secret_key = SecretKey::new(&mut rand::rng());
169 /// # }
170 /// ```
171 #[inline]
172 #[cfg(feature = "rand")]
173 pub fn new<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
174 loop {
175 let data = crate::random_32_bytes(rng);
176 if let Ok(key) = Self::from_secret_bytes(data) {
177 return key;
178 }
179 }
180 }
181
182 /// Converts a 32-byte array to a secret key.
183 #[deprecated(since = "0.32.0", note = "use from_secret_bytes instead")]
184 pub fn from_byte_array(data: [u8; constants::SECRET_KEY_SIZE]) -> Result<SecretKey, Error> {
185 Self::from_secret_bytes(data)
186 }
187
188 /// Creates a new secret key using data from BIP-340 [`Keypair`].
189 ///
190 /// # Examples
191 ///
192 /// ```
193 /// # #[cfg(all(feature = "rand", feature = "std"))] {
194 /// use secp256k1::{rand, SecretKey, Keypair};
195 ///
196 /// let keypair = Keypair::new(&mut rand::rng());
197 /// let secret_key = SecretKey::from_keypair(&keypair);
198 /// # }
199 /// ```
200 #[inline]
201 pub fn from_keypair(keypair: &Keypair) -> Self {
202 let mut sk = [0u8; constants::SECRET_KEY_SIZE];
203 unsafe {
204 let ret = ffi::secp256k1_keypair_sec(
205 ffi::secp256k1_context_no_precomp,
206 sk.as_mut_c_ptr(),
207 keypair.as_c_ptr(),
208 );
209 debug_assert_eq!(ret, 1);
210 }
211 Self::from_secret_bytes(sk).expect("a valid Keypair has a valid SecretKey")
212 }
213
214 /// Returns the secret key as a byte value.
215 #[inline]
216 #[deprecated(since = "0.32.0", note = "use to_secret_bytes instead")]
217 pub fn secret_bytes(&self) -> [u8; constants::SECRET_KEY_SIZE] { self.to_secret_bytes() }
218
219 /// Negates the secret key.
220 #[inline]
221 #[must_use = "you forgot to use the negated secret key"]
222 pub fn negate(mut self) -> SecretKey {
223 unsafe {
224 let res = ffi::secp256k1_ec_seckey_negate(
225 ffi::secp256k1_context_no_precomp,
226 self.as_mut_c_ptr(),
227 );
228 debug_assert_eq!(res, 1);
229 }
230 self
231 }
232
233 /// Tweaks a [`SecretKey`] by adding `tweak` modulo the curve order.
234 ///
235 /// # Errors
236 ///
237 /// Returns an error if the resulting key would be invalid.
238 #[inline]
239 pub fn add_tweak(mut self, tweak: &Scalar) -> Result<SecretKey, Error> {
240 unsafe {
241 if ffi::secp256k1_ec_seckey_tweak_add(
242 ffi::secp256k1_context_no_precomp,
243 self.as_mut_c_ptr(),
244 tweak.as_c_ptr(),
245 ) != 1
246 {
247 Err(Error::InvalidTweak)
248 } else {
249 Ok(self)
250 }
251 }
252 }
253
254 /// Tweaks a [`SecretKey`] by multiplying by `tweak` modulo the curve order.
255 ///
256 /// # Errors
257 ///
258 /// Returns an error if the resulting key would be invalid.
259 #[inline]
260 pub fn mul_tweak(mut self, tweak: &Scalar) -> Result<SecretKey, Error> {
261 unsafe {
262 if ffi::secp256k1_ec_seckey_tweak_mul(
263 ffi::secp256k1_context_no_precomp,
264 self.as_mut_c_ptr(),
265 tweak.as_c_ptr(),
266 ) != 1
267 {
268 Err(Error::InvalidTweak)
269 } else {
270 Ok(self)
271 }
272 }
273 }
274
275 /// Constructs an ECDSA signature for `msg`.
276 #[inline]
277 pub fn sign_ecdsa(&self, msg: impl Into<Message>) -> ecdsa::Signature { ecdsa::sign(msg, self) }
278
279 /// Returns the [`Keypair`] for this [`SecretKey`].
280 ///
281 /// This is equivalent to using [`Keypair::from_secret_key`].
282 #[inline]
283 pub fn keypair(&self) -> Keypair { Keypair::from_secret_key(self) }
284
285 /// Returns the [`PublicKey`] for this [`SecretKey`].
286 ///
287 /// This is equivalent to using [`PublicKey::from_secret_key`].
288 #[inline]
289 pub fn public_key(&self) -> PublicKey { PublicKey::from_secret_key(self) }
290
291 /// Returns the [`XOnlyPublicKey`] (and its [`Parity`]) for this [`SecretKey`].
292 ///
293 /// This is equivalent to `XOnlyPublicKey::from_keypair(self.keypair(secp))`.
294 #[inline]
295 pub fn x_only_public_key(&self) -> (XOnlyPublicKey, Parity) {
296 let kp = self.keypair();
297 XOnlyPublicKey::from_keypair(&kp)
298 }
299
300 /// Constructor for unit testing.
301 #[cfg(test)]
302 #[cfg(all(feature = "rand", feature = "std"))]
303 pub fn test_random() -> Self { Self::new(&mut rand::rng()) }
304
305 /// Constructor for unit testing.
306 #[cfg(test)]
307 #[cfg(not(all(feature = "rand", feature = "std")))]
308 pub fn test_random() -> Self {
309 loop {
310 if let Ok(ret) = Self::from_secret_bytes(crate::test_random_32_bytes()) {
311 return ret;
312 }
313 }
314 }
315}
316
317#[cfg(feature = "serde")]
318impl serde::Serialize for SecretKey {
319 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
320 if s.is_human_readable() {
321 let mut buf = [0u8; constants::SECRET_KEY_SIZE * 2];
322 s.serialize_str(
323 crate::to_hex(self.as_secret_bytes(), &mut buf)
324 .expect("fixed-size hex serialization"),
325 )
326 } else {
327 let mut tuple = s.serialize_tuple(constants::SECRET_KEY_SIZE)?;
328 for byte in self.as_secret_bytes().iter() {
329 tuple.serialize_element(byte)?;
330 }
331 tuple.end()
332 }
333 }
334}
335
336#[cfg(feature = "serde")]
337impl<'de> serde::Deserialize<'de> for SecretKey {
338 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
339 if d.is_human_readable() {
340 d.deserialize_str(crate::serde_util::FromStrVisitor::new(
341 "a hex string representing 32 byte SecretKey",
342 ))
343 } else {
344 let visitor =
345 crate::serde_util::Tuple32Visitor::new("raw 32 bytes SecretKey", |bytes| {
346 SecretKey::from_secret_bytes(bytes)
347 });
348 d.deserialize_tuple(constants::SECRET_KEY_SIZE, visitor)
349 }
350 }
351}