1use crate::{
4 checked::CheckedSum, decode::Decode, encode::Encode, public::EcdsaPublicKey, reader::Reader,
5 writer::Writer, Algorithm, EcdsaCurve, Error, Result,
6};
7use core::fmt;
8use sec1::consts::{U32, U48, U66};
9use zeroize::Zeroize;
10
11#[cfg(feature = "rand_core")]
12use rand_core::{CryptoRng, RngCore};
13
14#[cfg(feature = "subtle")]
15use subtle::{Choice, ConstantTimeEq};
16
17#[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
19#[derive(Clone)]
20pub struct EcdsaPrivateKey<const SIZE: usize> {
21 bytes: [u8; SIZE],
23}
24
25impl<const SIZE: usize> EcdsaPrivateKey<SIZE> {
26 pub fn as_slice(&self) -> &[u8] {
28 self.bytes.as_ref()
29 }
30
31 pub fn into_bytes(self) -> [u8; SIZE] {
33 self.bytes
34 }
35
36 fn decode(reader: &mut impl Reader) -> Result<Self> {
38 reader.read_nested(|reader| {
39 if reader.remaining_len() == SIZE.checked_add(1).ok_or(Error::Length)? {
40 if u8::decode(reader)? != 0 {
43 return Err(Error::FormatEncoding);
44 }
45 }
46
47 let mut bytes = [0u8; SIZE];
48 reader.read(&mut bytes)?;
49 Ok(Self { bytes })
50 })
51 }
52
53 fn needs_leading_zero(&self) -> bool {
55 self.bytes[0] >= 0x80
56 }
57}
58
59impl<const SIZE: usize> Encode for EcdsaPrivateKey<SIZE> {
60 fn encoded_len(&self) -> Result<usize> {
61 [4, self.needs_leading_zero().into(), SIZE].checked_sum()
62 }
63
64 fn encode(&self, writer: &mut impl Writer) -> Result<()> {
65 [self.needs_leading_zero().into(), SIZE]
66 .checked_sum()?
67 .encode(writer)?;
68
69 if self.needs_leading_zero() {
70 writer.write(&[0])?;
71 }
72
73 writer.write(&self.bytes)
74 }
75}
76
77impl<const SIZE: usize> AsRef<[u8; SIZE]> for EcdsaPrivateKey<SIZE> {
78 fn as_ref(&self) -> &[u8; SIZE] {
79 &self.bytes
80 }
81}
82
83impl<const SIZE: usize> fmt::Debug for EcdsaPrivateKey<SIZE> {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 f.debug_struct("Ed25519PrivateKey").finish_non_exhaustive()
86 }
87}
88
89impl<const SIZE: usize> fmt::LowerHex for EcdsaPrivateKey<SIZE> {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 for byte in self.as_ref() {
92 write!(f, "{:02x}", byte)?;
93 }
94 Ok(())
95 }
96}
97
98impl<const SIZE: usize> fmt::UpperHex for EcdsaPrivateKey<SIZE> {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 for byte in self.as_ref() {
101 write!(f, "{:02X}", byte)?;
102 }
103 Ok(())
104 }
105}
106
107impl<const SIZE: usize> Drop for EcdsaPrivateKey<SIZE> {
108 fn drop(&mut self) {
109 self.bytes.zeroize();
110 }
111}
112
113#[cfg(feature = "p256")]
114#[cfg_attr(docsrs, doc(cfg(feature = "p256")))]
115impl From<p256::SecretKey> for EcdsaPrivateKey<32> {
116 fn from(sk: p256::SecretKey) -> EcdsaPrivateKey<32> {
117 EcdsaPrivateKey {
118 bytes: sk.to_be_bytes().into(),
119 }
120 }
121}
122
123#[cfg(feature = "subtle")]
124#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))]
125impl<const SIZE: usize> ConstantTimeEq for EcdsaPrivateKey<SIZE> {
126 fn ct_eq(&self, other: &Self) -> Choice {
127 self.as_ref().ct_eq(other.as_ref())
128 }
129}
130
131#[cfg(feature = "subtle")]
132#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))]
133impl<const SIZE: usize> PartialEq for EcdsaPrivateKey<SIZE> {
134 fn eq(&self, other: &Self) -> bool {
135 self.ct_eq(other).into()
136 }
137}
138
139#[cfg(feature = "subtle")]
140#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))]
141impl<const SIZE: usize> Eq for EcdsaPrivateKey<SIZE> {}
142
143#[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
145#[derive(Clone, Debug)]
146pub enum EcdsaKeypair {
147 NistP256 {
149 public: sec1::EncodedPoint<U32>,
151
152 private: EcdsaPrivateKey<32>,
154 },
155
156 NistP384 {
158 public: sec1::EncodedPoint<U48>,
160
161 private: EcdsaPrivateKey<48>,
163 },
164
165 NistP521 {
167 public: sec1::EncodedPoint<U66>,
169
170 private: EcdsaPrivateKey<66>,
172 },
173}
174
175impl EcdsaKeypair {
176 #[cfg(feature = "rand_core")]
178 #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
179 #[allow(unused_variables)]
180 pub fn random(rng: impl CryptoRng + RngCore, curve: EcdsaCurve) -> Result<Self> {
181 match curve {
182 #[cfg(feature = "p256")]
183 EcdsaCurve::NistP256 => {
184 let private = p256::SecretKey::random(rng);
185 let public = private.public_key();
186 Ok(EcdsaKeypair::NistP256 {
187 private: private.into(),
188 public: public.into(),
189 })
190 }
191 _ => Err(Error::Algorithm),
192 }
193 }
194
195 pub fn algorithm(&self) -> Algorithm {
197 Algorithm::Ecdsa {
198 curve: self.curve(),
199 }
200 }
201
202 pub fn curve(&self) -> EcdsaCurve {
204 match self {
205 Self::NistP256 { .. } => EcdsaCurve::NistP256,
206 Self::NistP384 { .. } => EcdsaCurve::NistP384,
207 Self::NistP521 { .. } => EcdsaCurve::NistP521,
208 }
209 }
210
211 pub fn public_key_bytes(&self) -> &[u8] {
213 match self {
214 Self::NistP256 { public, .. } => public.as_ref(),
215 Self::NistP384 { public, .. } => public.as_ref(),
216 Self::NistP521 { public, .. } => public.as_ref(),
217 }
218 }
219
220 pub fn private_key_bytes(&self) -> &[u8] {
222 match self {
223 Self::NistP256 { private, .. } => private.as_ref(),
224 Self::NistP384 { private, .. } => private.as_ref(),
225 Self::NistP521 { private, .. } => private.as_ref(),
226 }
227 }
228}
229
230impl Decode for EcdsaKeypair {
231 fn decode(reader: &mut impl Reader) -> Result<Self> {
232 match EcdsaPublicKey::decode(reader)? {
233 EcdsaPublicKey::NistP256(public) => {
234 let private = EcdsaPrivateKey::<32>::decode(reader)?;
235 Ok(Self::NistP256 { public, private })
236 }
237 EcdsaPublicKey::NistP384(public) => {
238 let private = EcdsaPrivateKey::<48>::decode(reader)?;
239 Ok(Self::NistP384 { public, private })
240 }
241 EcdsaPublicKey::NistP521(public) => {
242 let private = EcdsaPrivateKey::<66>::decode(reader)?;
243 Ok(Self::NistP521 { public, private })
244 }
245 }
246 }
247}
248
249impl Encode for EcdsaKeypair {
250 fn encoded_len(&self) -> Result<usize> {
251 let public_len = EcdsaPublicKey::from(self).encoded_len()?;
252
253 let private_len = match self {
254 Self::NistP256 { private, .. } => private.encoded_len()?,
255 Self::NistP384 { private, .. } => private.encoded_len()?,
256 Self::NistP521 { private, .. } => private.encoded_len()?,
257 };
258
259 [public_len, private_len].checked_sum()
260 }
261
262 fn encode(&self, writer: &mut impl Writer) -> Result<()> {
263 EcdsaPublicKey::from(self).encode(writer)?;
264
265 match self {
266 Self::NistP256 { private, .. } => private.encode(writer)?,
267 Self::NistP384 { private, .. } => private.encode(writer)?,
268 Self::NistP521 { private, .. } => private.encode(writer)?,
269 }
270
271 Ok(())
272 }
273}
274
275impl From<EcdsaKeypair> for EcdsaPublicKey {
276 fn from(keypair: EcdsaKeypair) -> EcdsaPublicKey {
277 EcdsaPublicKey::from(&keypair)
278 }
279}
280
281impl From<&EcdsaKeypair> for EcdsaPublicKey {
282 fn from(keypair: &EcdsaKeypair) -> EcdsaPublicKey {
283 match keypair {
284 EcdsaKeypair::NistP256 { public, .. } => EcdsaPublicKey::NistP256(*public),
285 EcdsaKeypair::NistP384 { public, .. } => EcdsaPublicKey::NistP384(*public),
286 EcdsaKeypair::NistP521 { public, .. } => EcdsaPublicKey::NistP521(*public),
287 }
288 }
289}
290
291#[cfg(feature = "subtle")]
292#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))]
293impl ConstantTimeEq for EcdsaKeypair {
294 fn ct_eq(&self, other: &Self) -> Choice {
295 let public_eq =
296 Choice::from((EcdsaPublicKey::from(self) == EcdsaPublicKey::from(other)) as u8);
297
298 let private_key_a = match self {
299 Self::NistP256 { private, .. } => private.as_slice(),
300 Self::NistP384 { private, .. } => private.as_slice(),
301 Self::NistP521 { private, .. } => private.as_slice(),
302 };
303
304 let private_key_b = match other {
305 Self::NistP256 { private, .. } => private.as_slice(),
306 Self::NistP384 { private, .. } => private.as_slice(),
307 Self::NistP521 { private, .. } => private.as_slice(),
308 };
309
310 public_eq & private_key_a.ct_eq(private_key_b)
311 }
312}
313
314#[cfg(feature = "subtle")]
315#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))]
316impl PartialEq for EcdsaKeypair {
317 fn eq(&self, other: &Self) -> bool {
318 self.ct_eq(other).into()
319 }
320}
321
322#[cfg(feature = "subtle")]
323#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))]
324impl Eq for EcdsaKeypair {}