@@ -14,48 +14,117 @@ use crate::{
1414#[ cfg( feature = "global-context" ) ]
1515use crate :: { ecdsa, Message , SECP256K1 } ;
1616
17- /// Secret key - a 256-bit key used to create ECDSA and Taproot signatures.
18- ///
19- /// This value should be generated using a [cryptographically secure pseudorandom number generator].
20- ///
21- /// # Side channel attacks
22- ///
23- /// We have attempted to reduce the side channel attack surface by implementing a constant time `eq`
24- /// method. For similar reasons we explicitly do not implement `PartialOrd`, `Ord`, or `Hash` on
25- /// `SecretKey`. If you really want to order secret keys then you can use `AsRef` to get at the
26- /// underlying bytes and compare them - however this is almost certainly a bad idea.
27- ///
28- /// # Serde support
29- ///
30- /// Implements de/serialization with the `serde` feature enabled. We treat the byte value as a tuple
31- /// of 32 `u8`s for non-human-readable formats. This representation is optimal for some formats
32- /// (e.g. [`bincode`]) however other formats may be less optimal (e.g. [`cbor`]).
33- ///
34- /// # Examples
35- ///
36- /// Basic usage:
37- ///
38- /// ```
39- /// # #[cfg(all(feature = "rand", feature = "std"))] {
40- /// use secp256k1::{rand, Secp256k1, SecretKey};
41- ///
42- /// let secp = Secp256k1::new();
43- /// let secret_key = SecretKey::new(&mut rand::rng());
44- /// # }
45- /// ```
46- /// [`bincode`]: https://docs.rs/bincode
47- /// [`cbor`]: https://docs.rs/cbor
48- /// [cryptographically secure pseudorandom number generator]: https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator
49- #[ derive( Copy , Clone ) ]
50- pub struct SecretKey ( [ u8 ; constants:: SECRET_KEY_SIZE ] ) ;
51- impl_display_secret ! ( SecretKey ) ;
52- impl_non_secure_erase ! ( SecretKey , 0 , [ 1u8 ; constants:: SECRET_KEY_SIZE ] ) ;
17+ mod encapsulate {
18+ use crate :: constants:: SECRET_KEY_SIZE ;
19+ use crate :: ffi:: { self , CPtr } ;
20+ use crate :: Error ;
21+
22+ /// Secret key - a 256-bit key used to create ECDSA and Taproot signatures.
23+ ///
24+ /// This value should be generated using a [cryptographically secure pseudorandom number generator].
25+ ///
26+ /// # Side channel attacks
27+ ///
28+ /// We have attempted to reduce the side channel attack surface by implementing a constant time `eq`
29+ /// method. For similar reasons we explicitly do not implement `PartialOrd`, `Ord`, or `Hash` on
30+ /// `SecretKey`. If you really want to order secret keys then you can use `AsRef` to get at the
31+ /// underlying bytes and compare them - however this is almost certainly a bad idea.
32+ ///
33+ /// # Serde support
34+ ///
35+ /// Implements de/serialization with the `serde` feature enabled. We treat the byte value as a tuple
36+ /// of 32 `u8`s for non-human-readable formats. This representation is optimal for some formats
37+ /// (e.g. [`bincode`]) however other formats may be less optimal (e.g. [`cbor`]).
38+ ///
39+ /// # Examples
40+ ///
41+ /// Basic usage:
42+ ///
43+ /// ```
44+ /// # #[cfg(all(feature = "rand", feature = "std"))] {
45+ /// use secp256k1::{rand, Secp256k1, SecretKey};
46+ ///
47+ /// let secp = Secp256k1::new();
48+ /// let secret_key = SecretKey::new(&mut rand::rng());
49+ /// # }
50+ /// ```
51+ /// [`bincode`]: https://docs.rs/bincode
52+ /// [`cbor`]: https://docs.rs/cbor
53+ /// [cryptographically secure pseudorandom number generator]: https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator
54+ #[ derive( Copy , Clone ) ]
55+ pub struct SecretKey ( [ u8 ; SECRET_KEY_SIZE ] ) ;
56+ // FIXME these two macro call should be moved outside of the encapsulate module
57+ impl_display_secret ! ( SecretKey ) ;
58+ impl_non_secure_erase ! ( SecretKey , 0 , [ 1u8 ; SECRET_KEY_SIZE ] ) ;
59+
60+ impl SecretKey {
61+ /// Returns the secret key as a byte value.
62+ ///
63+ /// # Side channel attacks
64+ ///
65+ /// Using ordering functions (`PartialOrd`/`Ord`) on a reference to secret keys leaks data
66+ /// because the implementations are not constant time. Doing so will make your code vulnerable
67+ /// to side channel attacks. [`SecretKey::eq`] is implemented using a constant time algorithm,
68+ /// please consider using it to do comparisons of secret keys.
69+ #[ inline]
70+ pub fn to_secret_bytes ( & self ) -> [ u8 ; SECRET_KEY_SIZE ] { self . 0 }
71+
72+ /// Returns a reference to the secret key as a byte array.
73+ ///
74+ /// See note on [`Self::to_secret_bytes`].
75+ #[ inline]
76+ pub fn as_secret_bytes ( & self ) -> & [ u8 ; SECRET_KEY_SIZE ] { & self . 0 }
77+
78+ /// Converts a 32-byte array to a secret key.
79+ ///
80+ /// See note on [`Self::to_secret_bytes`].
81+ ///
82+ /// # Errors
83+ ///
84+ /// Returns an error when the secret key is invalid: when it is all-zeros or would exceed
85+ /// the curve order when interpreted as a big-endian unsigned integer.
86+ ///
87+ /// # Examples
88+ ///
89+ /// ```
90+ /// use secp256k1::SecretKey;
91+ /// let sk = SecretKey::from_byte_array([0xcd; 32]).expect("32 bytes, within curve order");
92+ /// ```
93+ #[ inline]
94+ pub fn from_secret_bytes ( data : [ u8 ; SECRET_KEY_SIZE ] ) -> Result < SecretKey , Error > {
95+ crate :: with_raw_global_context (
96+ |ctx| unsafe {
97+ if ffi:: secp256k1_ec_seckey_verify ( ctx. as_ptr ( ) , data. as_c_ptr ( ) ) == 0 {
98+ return Err ( Error :: InvalidSecretKey ) ;
99+ }
100+ Ok ( SecretKey ( data) )
101+ } ,
102+ None ,
103+ )
104+ }
105+ }
106+
107+ // Must be inside the `encapsulate` module since there is no way to obtain mutable
108+ // access to the internal array outside of the module.
109+ impl CPtr for SecretKey {
110+ type Target = u8 ;
111+
112+ fn as_c_ptr ( & self ) -> * const Self :: Target { self . as_secret_bytes ( ) . as_ptr ( ) }
113+
114+ fn as_mut_c_ptr ( & mut self ) -> * mut Self :: Target { self . 0 . as_mut_ptr ( ) }
115+ }
116+ }
117+ pub use encapsulate:: SecretKey ;
53118
54119impl PartialEq for SecretKey {
55120 /// This implementation is designed to be constant time to help prevent side channel attacks.
56121 #[ inline]
57122 fn eq ( & self , other : & Self ) -> bool {
58- let accum = self . 0 . iter ( ) . zip ( & other. 0 ) . fold ( 0 , |accum, ( a, b) | accum | a ^ b) ;
123+ let accum = self
124+ . as_secret_bytes ( )
125+ . iter ( )
126+ . zip ( other. as_secret_bytes ( ) )
127+ . fold ( 0 , |accum, ( a, b) | accum | a ^ b) ;
59128 unsafe { core:: ptr:: read_volatile ( & accum) == 0 }
60129 }
61130}
@@ -65,17 +134,9 @@ impl Eq for SecretKey {}
65134impl AsRef < [ u8 ; constants:: SECRET_KEY_SIZE ] > for SecretKey {
66135 /// Gets a reference to the underlying array.
67136 ///
68- /// # Side channel attacks
69- ///
70- /// Using ordering functions (`PartialOrd`/`Ord`) on a reference to secret keys leaks data
71- /// because the implementations are not constant time. Doing so will make your code vulnerable
72- /// to side channel attacks. [`SecretKey::eq`] is implemented using a constant time algorithm,
73- /// please consider using it to do comparisons of secret keys.
137+ /// See note on [`Self::to_secret_bytes`].
74138 #[ inline]
75- fn as_ref ( & self ) -> & [ u8 ; constants:: SECRET_KEY_SIZE ] {
76- let SecretKey ( dat) = self ;
77- dat
78- }
139+ fn as_ref ( & self ) -> & [ u8 ; constants:: SECRET_KEY_SIZE ] { self . as_secret_bytes ( ) }
79140}
80141
81142impl < I > ops:: Index < I > for SecretKey
@@ -85,26 +146,12 @@ where
85146 type Output = <[ u8 ] as ops:: Index < I > >:: Output ;
86147
87148 #[ inline]
88- fn index ( & self , index : I ) -> & Self :: Output { & self . 0 [ index] }
89- }
90-
91- impl ffi:: CPtr for SecretKey {
92- type Target = u8 ;
93-
94- fn as_c_ptr ( & self ) -> * const Self :: Target {
95- let SecretKey ( dat) = self ;
96- dat. as_ptr ( )
97- }
98-
99- fn as_mut_c_ptr ( & mut self ) -> * mut Self :: Target {
100- let & mut SecretKey ( ref mut dat) = self ;
101- dat. as_mut_ptr ( )
102- }
149+ fn index ( & self , index : I ) -> & Self :: Output { & self . as_secret_bytes ( ) [ index] }
103150}
104151
105152impl str:: FromStr for SecretKey {
106153 type Err = Error ;
107- fn from_str ( s : & str ) -> Result < SecretKey , Error > {
154+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
108155 let mut res = [ 0u8 ; constants:: SECRET_KEY_SIZE ] ;
109156 match from_hex ( s, & mut res) {
110157 Ok ( constants:: SECRET_KEY_SIZE ) => SecretKey :: from_secret_bytes ( res) ,
@@ -126,18 +173,13 @@ impl SecretKey {
126173 /// ```
127174 #[ inline]
128175 #[ cfg( feature = "rand" ) ]
129- pub fn new < R : rand:: Rng + ?Sized > ( rng : & mut R ) -> SecretKey {
130- let mut data = crate :: random_32_bytes ( rng) ;
131- unsafe {
132- while ffi:: secp256k1_ec_seckey_verify (
133- ffi:: secp256k1_context_no_precomp,
134- data. as_c_ptr ( ) ,
135- ) == 0
136- {
137- data = crate :: random_32_bytes ( rng) ;
176+ pub fn new < R : rand:: Rng + ?Sized > ( rng : & mut R ) -> Self {
177+ loop {
178+ let data = crate :: random_32_bytes ( rng) ;
179+ if let Ok ( key) = Self :: from_secret_bytes ( data) {
180+ return key;
138181 }
139182 }
140- SecretKey ( data)
141183 }
142184
143185 /// Converts a 32-byte array to a secret key.
@@ -146,26 +188,6 @@ impl SecretKey {
146188 Self :: from_secret_bytes ( data)
147189 }
148190
149- /// Converts a 32-byte array to a secret key.
150- ///
151- /// # Examples
152- ///
153- /// ```
154- /// use secp256k1::SecretKey;
155- /// let sk = SecretKey::from_secret_bytes([0xcd; 32]).expect("32 bytes, within curve order");
156- /// ```
157- #[ inline]
158- pub fn from_secret_bytes ( data : [ u8 ; constants:: SECRET_KEY_SIZE ] ) -> Result < SecretKey , Error > {
159- unsafe {
160- if ffi:: secp256k1_ec_seckey_verify ( ffi:: secp256k1_context_no_precomp, data. as_c_ptr ( ) )
161- == 0
162- {
163- return Err ( Error :: InvalidSecretKey ) ;
164- }
165- }
166- Ok ( SecretKey ( data) )
167- }
168-
169191 /// Creates a new secret key using data from BIP-340 [`Keypair`].
170192 ///
171193 /// # Examples
@@ -190,21 +212,13 @@ impl SecretKey {
190212 ) ;
191213 debug_assert_eq ! ( ret, 1 ) ;
192214 }
193- SecretKey ( sk)
215+ Self :: from_secret_bytes ( sk) . expect ( "a valid Keypair has a valid SecretKey" )
194216 }
195217
196- /// Returns a reference to the secret key as a byte value.
197- #[ inline]
198- pub fn as_secret_bytes ( & self ) -> & [ u8 ; constants:: SECRET_KEY_SIZE ] { & self . 0 }
199-
200- /// Returns the secret key as a byte value.
201- #[ inline]
202- pub fn to_secret_bytes ( & self ) -> [ u8 ; constants:: SECRET_KEY_SIZE ] { self . 0 }
203-
204218 /// Returns the secret key as a byte value.
205219 #[ inline]
206220 #[ deprecated( since = "0.32.0" , note = "use to_secret_bytes instead" ) ]
207- pub fn secret_bytes ( & self ) -> [ u8 ; constants:: SECRET_KEY_SIZE ] { self . 0 }
221+ pub fn secret_bytes ( & self ) -> [ u8 ; constants:: SECRET_KEY_SIZE ] { self . to_secret_bytes ( ) }
208222
209223 /// Negates the secret key.
210224 #[ inline]
@@ -316,10 +330,13 @@ impl serde::Serialize for SecretKey {
316330 fn serialize < S : serde:: Serializer > ( & self , s : S ) -> Result < S :: Ok , S :: Error > {
317331 if s. is_human_readable ( ) {
318332 let mut buf = [ 0u8 ; constants:: SECRET_KEY_SIZE * 2 ] ;
319- s. serialize_str ( crate :: to_hex ( & self . 0 , & mut buf) . expect ( "fixed-size hex serialization" ) )
333+ s. serialize_str (
334+ crate :: to_hex ( self . as_secret_bytes ( ) , & mut buf)
335+ . expect ( "fixed-size hex serialization" ) ,
336+ )
320337 } else {
321338 let mut tuple = s. serialize_tuple ( constants:: SECRET_KEY_SIZE ) ?;
322- for byte in self . 0 . iter ( ) {
339+ for byte in self . as_secret_bytes ( ) . iter ( ) {
323340 tuple. serialize_element ( byte) ?;
324341 }
325342 tuple. end ( )
0 commit comments