@@ -14,48 +14,117 @@ use crate::{
14
14
#[ cfg( feature = "global-context" ) ]
15
15
use crate :: { ecdsa, Message , SECP256K1 } ;
16
16
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 ;
53
118
54
119
impl PartialEq for SecretKey {
55
120
/// This implementation is designed to be constant time to help prevent side channel attacks.
56
121
#[ inline]
57
122
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) ;
59
128
unsafe { core:: ptr:: read_volatile ( & accum) == 0 }
60
129
}
61
130
}
@@ -65,17 +134,9 @@ impl Eq for SecretKey {}
65
134
impl AsRef < [ u8 ; constants:: SECRET_KEY_SIZE ] > for SecretKey {
66
135
/// Gets a reference to the underlying array.
67
136
///
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`].
74
138
#[ 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 ( ) }
79
140
}
80
141
81
142
impl < I > ops:: Index < I > for SecretKey
@@ -85,26 +146,12 @@ where
85
146
type Output = <[ u8 ] as ops:: Index < I > >:: Output ;
86
147
87
148
#[ 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] }
103
150
}
104
151
105
152
impl str:: FromStr for SecretKey {
106
153
type Err = Error ;
107
- fn from_str ( s : & str ) -> Result < SecretKey , Error > {
154
+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
108
155
let mut res = [ 0u8 ; constants:: SECRET_KEY_SIZE ] ;
109
156
match from_hex ( s, & mut res) {
110
157
Ok ( constants:: SECRET_KEY_SIZE ) => SecretKey :: from_secret_bytes ( res) ,
@@ -126,18 +173,13 @@ impl SecretKey {
126
173
/// ```
127
174
#[ inline]
128
175
#[ 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;
138
181
}
139
182
}
140
- SecretKey ( data)
141
183
}
142
184
143
185
/// Converts a 32-byte array to a secret key.
@@ -146,26 +188,6 @@ impl SecretKey {
146
188
Self :: from_secret_bytes ( data)
147
189
}
148
190
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
-
169
191
/// Creates a new secret key using data from BIP-340 [`Keypair`].
170
192
///
171
193
/// # Examples
@@ -190,21 +212,13 @@ impl SecretKey {
190
212
) ;
191
213
debug_assert_eq ! ( ret, 1 ) ;
192
214
}
193
- SecretKey ( sk)
215
+ Self :: from_secret_bytes ( sk) . expect ( "a valid Keypair has a valid SecretKey" )
194
216
}
195
217
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
-
204
218
/// Returns the secret key as a byte value.
205
219
#[ inline]
206
220
#[ 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 ( ) }
208
222
209
223
/// Negates the secret key.
210
224
#[ inline]
@@ -316,10 +330,13 @@ impl serde::Serialize for SecretKey {
316
330
fn serialize < S : serde:: Serializer > ( & self , s : S ) -> Result < S :: Ok , S :: Error > {
317
331
if s. is_human_readable ( ) {
318
332
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
+ )
320
337
} else {
321
338
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 ( ) {
323
340
tuple. serialize_element ( byte) ?;
324
341
}
325
342
tuple. end ( )
0 commit comments