Skip to content

Commit 9b84072

Browse files
committed
move SecretKey into its own module
Move-only, except for a couple import paths.
1 parent e86555a commit 9b84072

File tree

2 files changed

+352
-334
lines changed

2 files changed

+352
-334
lines changed

src/key/mod.rs

Lines changed: 5 additions & 334 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
//! Public and secret keys.
44
//!
55
6-
use core::ops::{self, BitXor};
6+
mod secret;
7+
8+
use core::ops::BitXor;
79
use core::{fmt, ptr, str};
810

911
#[cfg(feature = "arbitrary")]
@@ -12,115 +14,17 @@ use secp256k1_sys::secp256k1_ec_pubkey_sort;
1214
#[cfg(feature = "serde")]
1315
use serde::ser::SerializeTuple;
1416

17+
pub use self::secret::SecretKey;
1518
use crate::ellswift::ElligatorSwift;
1619
use crate::ffi::types::c_uint;
1720
use crate::ffi::{self, CPtr};
18-
use crate::Error::{self, InvalidPublicKey, InvalidPublicKeySum, InvalidSecretKey};
21+
use crate::Error::{self, InvalidPublicKey, InvalidPublicKeySum};
1922
#[cfg(feature = "global-context")]
2023
use crate::SECP256K1;
2124
use crate::{
2225
constants, ecdsa, from_hex, schnorr, Message, Scalar, Secp256k1, Signing, Verification,
2326
};
2427

25-
/// Secret key - a 256-bit key used to create ECDSA and Taproot signatures.
26-
///
27-
/// This value should be generated using a [cryptographically secure pseudorandom number generator].
28-
///
29-
/// # Side channel attacks
30-
///
31-
/// We have attempted to reduce the side channel attack surface by implementing a constant time `eq`
32-
/// method. For similar reasons we explicitly do not implement `PartialOrd`, `Ord`, or `Hash` on
33-
/// `SecretKey`. If you really want to order secret keys then you can use `AsRef` to get at the
34-
/// underlying bytes and compare them - however this is almost certainly a bad idea.
35-
///
36-
/// # Serde support
37-
///
38-
/// Implements de/serialization with the `serde` feature enabled. We treat the byte value as a tuple
39-
/// of 32 `u8`s for non-human-readable formats. This representation is optimal for some formats
40-
/// (e.g. [`bincode`]) however other formats may be less optimal (e.g. [`cbor`]).
41-
///
42-
/// # Examples
43-
///
44-
/// Basic usage:
45-
///
46-
/// ```
47-
/// # #[cfg(all(feature = "rand", feature = "std"))] {
48-
/// use secp256k1::{rand, Secp256k1, SecretKey};
49-
///
50-
/// let secp = Secp256k1::new();
51-
/// let secret_key = SecretKey::new(&mut rand::rng());
52-
/// # }
53-
/// ```
54-
/// [`bincode`]: https://docs.rs/bincode
55-
/// [`cbor`]: https://docs.rs/cbor
56-
/// [cryptographically secure pseudorandom number generator]: https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator
57-
#[derive(Copy, Clone)]
58-
pub struct SecretKey([u8; constants::SECRET_KEY_SIZE]);
59-
impl_display_secret!(SecretKey);
60-
impl_non_secure_erase!(SecretKey, 0, [1u8; constants::SECRET_KEY_SIZE]);
61-
62-
impl PartialEq for SecretKey {
63-
/// This implementation is designed to be constant time to help prevent side channel attacks.
64-
#[inline]
65-
fn eq(&self, other: &Self) -> bool {
66-
let accum = self.0.iter().zip(&other.0).fold(0, |accum, (a, b)| accum | a ^ b);
67-
unsafe { core::ptr::read_volatile(&accum) == 0 }
68-
}
69-
}
70-
71-
impl Eq for SecretKey {}
72-
73-
impl AsRef<[u8; constants::SECRET_KEY_SIZE]> for SecretKey {
74-
/// Gets a reference to the underlying array.
75-
///
76-
/// # Side channel attacks
77-
///
78-
/// Using ordering functions (`PartialOrd`/`Ord`) on a reference to secret keys leaks data
79-
/// because the implementations are not constant time. Doing so will make your code vulnerable
80-
/// to side channel attacks. [`SecretKey::eq`] is implemented using a constant time algorithm,
81-
/// please consider using it to do comparisons of secret keys.
82-
#[inline]
83-
fn as_ref(&self) -> &[u8; constants::SECRET_KEY_SIZE] {
84-
let SecretKey(dat) = self;
85-
dat
86-
}
87-
}
88-
89-
impl<I> ops::Index<I> for SecretKey
90-
where
91-
[u8]: ops::Index<I>,
92-
{
93-
type Output = <[u8] as ops::Index<I>>::Output;
94-
95-
#[inline]
96-
fn index(&self, index: I) -> &Self::Output { &self.0[index] }
97-
}
98-
99-
impl ffi::CPtr for SecretKey {
100-
type Target = u8;
101-
102-
fn as_c_ptr(&self) -> *const Self::Target {
103-
let SecretKey(dat) = self;
104-
dat.as_ptr()
105-
}
106-
107-
fn as_mut_c_ptr(&mut self) -> *mut Self::Target {
108-
let &mut SecretKey(ref mut dat) = self;
109-
dat.as_mut_ptr()
110-
}
111-
}
112-
113-
impl str::FromStr for SecretKey {
114-
type Err = Error;
115-
fn from_str(s: &str) -> Result<SecretKey, Error> {
116-
let mut res = [0u8; constants::SECRET_KEY_SIZE];
117-
match from_hex(s, &mut res) {
118-
Ok(constants::SECRET_KEY_SIZE) => SecretKey::from_byte_array(res),
119-
_ => Err(Error::InvalidSecretKey),
120-
}
121-
}
122-
}
123-
12428
/// Public key - used to verify ECDSA signatures and to do Taproot tweaks.
12529
///
12630
/// # Serde support
@@ -184,239 +88,6 @@ impl str::FromStr for PublicKey {
18488
}
18589
}
18690

187-
impl SecretKey {
188-
/// Generates a new random secret key.
189-
///
190-
/// # Examples
191-
///
192-
/// ```
193-
/// # #[cfg(all(feature = "std", feature = "rand"))] {
194-
/// use secp256k1::{rand, SecretKey};
195-
/// let secret_key = SecretKey::new(&mut rand::rng());
196-
/// # }
197-
/// ```
198-
#[inline]
199-
#[cfg(feature = "rand")]
200-
pub fn new<R: rand::Rng + ?Sized>(rng: &mut R) -> SecretKey {
201-
let mut data = crate::random_32_bytes(rng);
202-
unsafe {
203-
while ffi::secp256k1_ec_seckey_verify(
204-
ffi::secp256k1_context_no_precomp,
205-
data.as_c_ptr(),
206-
) == 0
207-
{
208-
data = crate::random_32_bytes(rng);
209-
}
210-
}
211-
SecretKey(data)
212-
}
213-
214-
/// Converts a 32-byte slice to a secret key.
215-
///
216-
/// # Examples
217-
///
218-
/// ```
219-
/// use secp256k1::SecretKey;
220-
/// let sk = SecretKey::from_slice(&[0xcd; 32]).expect("32 bytes, within curve order");
221-
/// ```
222-
#[deprecated(since = "0.31.0", note = "Use `from_byte_array` instead.")]
223-
#[inline]
224-
pub fn from_slice(data: &[u8]) -> Result<SecretKey, Error> {
225-
match <[u8; constants::SECRET_KEY_SIZE]>::try_from(data) {
226-
Ok(data) => Self::from_byte_array(data),
227-
Err(_) => Err(InvalidSecretKey),
228-
}
229-
}
230-
231-
/// Converts a 32-byte array to a secret key.
232-
///
233-
/// # Examples
234-
///
235-
/// ```
236-
/// use secp256k1::SecretKey;
237-
/// let sk = SecretKey::from_byte_array([0xcd; 32]).expect("32 bytes, within curve order");
238-
/// ```
239-
#[inline]
240-
pub fn from_byte_array(data: [u8; constants::SECRET_KEY_SIZE]) -> Result<SecretKey, Error> {
241-
unsafe {
242-
if ffi::secp256k1_ec_seckey_verify(ffi::secp256k1_context_no_precomp, data.as_c_ptr())
243-
== 0
244-
{
245-
return Err(InvalidSecretKey);
246-
}
247-
}
248-
Ok(SecretKey(data))
249-
}
250-
251-
/// Creates a new secret key using data from BIP-340 [`Keypair`].
252-
///
253-
/// # Examples
254-
///
255-
/// ```
256-
/// # #[cfg(all(feature = "rand", feature = "std"))] {
257-
/// use secp256k1::{rand, Secp256k1, SecretKey, Keypair};
258-
///
259-
/// let secp = Secp256k1::new();
260-
/// let keypair = Keypair::new(&secp, &mut rand::rng());
261-
/// let secret_key = SecretKey::from_keypair(&keypair);
262-
/// # }
263-
/// ```
264-
#[inline]
265-
pub fn from_keypair(keypair: &Keypair) -> Self {
266-
let mut sk = [0u8; constants::SECRET_KEY_SIZE];
267-
unsafe {
268-
let ret = ffi::secp256k1_keypair_sec(
269-
ffi::secp256k1_context_no_precomp,
270-
sk.as_mut_c_ptr(),
271-
keypair.as_c_ptr(),
272-
);
273-
debug_assert_eq!(ret, 1);
274-
}
275-
SecretKey(sk)
276-
}
277-
278-
/// Returns the secret key as a byte value.
279-
#[inline]
280-
pub fn secret_bytes(&self) -> [u8; constants::SECRET_KEY_SIZE] { self.0 }
281-
282-
/// Negates the secret key.
283-
#[inline]
284-
#[must_use = "you forgot to use the negated secret key"]
285-
pub fn negate(mut self) -> SecretKey {
286-
unsafe {
287-
let res = ffi::secp256k1_ec_seckey_negate(
288-
ffi::secp256k1_context_no_precomp,
289-
self.as_mut_c_ptr(),
290-
);
291-
debug_assert_eq!(res, 1);
292-
}
293-
self
294-
}
295-
296-
/// Tweaks a [`SecretKey`] by adding `tweak` modulo the curve order.
297-
///
298-
/// # Errors
299-
///
300-
/// Returns an error if the resulting key would be invalid.
301-
#[inline]
302-
pub fn add_tweak(mut self, tweak: &Scalar) -> Result<SecretKey, Error> {
303-
unsafe {
304-
if ffi::secp256k1_ec_seckey_tweak_add(
305-
ffi::secp256k1_context_no_precomp,
306-
self.as_mut_c_ptr(),
307-
tweak.as_c_ptr(),
308-
) != 1
309-
{
310-
Err(Error::InvalidTweak)
311-
} else {
312-
Ok(self)
313-
}
314-
}
315-
}
316-
317-
/// Tweaks a [`SecretKey`] by multiplying by `tweak` modulo the curve order.
318-
///
319-
/// # Errors
320-
///
321-
/// Returns an error if the resulting key would be invalid.
322-
#[inline]
323-
pub fn mul_tweak(mut self, tweak: &Scalar) -> Result<SecretKey, Error> {
324-
unsafe {
325-
if ffi::secp256k1_ec_seckey_tweak_mul(
326-
ffi::secp256k1_context_no_precomp,
327-
self.as_mut_c_ptr(),
328-
tweak.as_c_ptr(),
329-
) != 1
330-
{
331-
Err(Error::InvalidTweak)
332-
} else {
333-
Ok(self)
334-
}
335-
}
336-
}
337-
338-
/// Constructs an ECDSA signature for `msg` using the global [`SECP256K1`] context.
339-
#[inline]
340-
#[cfg(feature = "global-context")]
341-
pub fn sign_ecdsa(&self, msg: impl Into<Message>) -> ecdsa::Signature {
342-
SECP256K1.sign_ecdsa(msg, self)
343-
}
344-
345-
/// Returns the [`Keypair`] for this [`SecretKey`].
346-
///
347-
/// This is equivalent to using [`Keypair::from_secret_key`].
348-
#[inline]
349-
pub fn keypair<C: Signing>(&self, secp: &Secp256k1<C>) -> Keypair {
350-
Keypair::from_secret_key(secp, self)
351-
}
352-
353-
/// Returns the [`PublicKey`] for this [`SecretKey`].
354-
///
355-
/// This is equivalent to using [`PublicKey::from_secret_key`].
356-
#[inline]
357-
pub fn public_key<C: Signing>(&self, secp: &Secp256k1<C>) -> PublicKey {
358-
PublicKey::from_secret_key(secp, self)
359-
}
360-
361-
/// Returns the [`XOnlyPublicKey`] (and its [`Parity`]) for this [`SecretKey`].
362-
///
363-
/// This is equivalent to `XOnlyPublicKey::from_keypair(self.keypair(secp))`.
364-
#[inline]
365-
pub fn x_only_public_key<C: Signing>(&self, secp: &Secp256k1<C>) -> (XOnlyPublicKey, Parity) {
366-
let kp = self.keypair(secp);
367-
XOnlyPublicKey::from_keypair(&kp)
368-
}
369-
370-
/// Constructor for unit testing.
371-
#[cfg(test)]
372-
#[cfg(all(feature = "rand", feature = "std"))]
373-
pub fn test_random() -> Self { Self::new(&mut rand::rng()) }
374-
375-
/// Constructor for unit testing.
376-
#[cfg(test)]
377-
#[cfg(not(all(feature = "rand", feature = "std")))]
378-
pub fn test_random() -> Self {
379-
loop {
380-
if let Ok(ret) = Self::from_byte_array(crate::test_random_32_bytes()) {
381-
return ret;
382-
}
383-
}
384-
}
385-
}
386-
387-
#[cfg(feature = "serde")]
388-
impl serde::Serialize for SecretKey {
389-
fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
390-
if s.is_human_readable() {
391-
let mut buf = [0u8; constants::SECRET_KEY_SIZE * 2];
392-
s.serialize_str(crate::to_hex(&self.0, &mut buf).expect("fixed-size hex serialization"))
393-
} else {
394-
let mut tuple = s.serialize_tuple(constants::SECRET_KEY_SIZE)?;
395-
for byte in self.0.iter() {
396-
tuple.serialize_element(byte)?;
397-
}
398-
tuple.end()
399-
}
400-
}
401-
}
402-
403-
#[cfg(feature = "serde")]
404-
impl<'de> serde::Deserialize<'de> for SecretKey {
405-
fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
406-
if d.is_human_readable() {
407-
d.deserialize_str(super::serde_util::FromStrVisitor::new(
408-
"a hex string representing 32 byte SecretKey",
409-
))
410-
} else {
411-
let visitor = super::serde_util::Tuple32Visitor::new(
412-
"raw 32 bytes SecretKey",
413-
SecretKey::from_byte_array,
414-
);
415-
d.deserialize_tuple(constants::SECRET_KEY_SIZE, visitor)
416-
}
417-
}
418-
}
419-
42091
impl PublicKey {
42192
/// Obtains a raw const pointer suitable for use with FFI functions.
42293
#[inline]

0 commit comments

Comments
 (0)