1use crate::{
4 DigestAlgorithm, EcdsaCurve, Error, Result, Signature, SignatureWithOid, ecdsa_oid_for_digest,
5 hazmat::sign_prehashed_rfc6979,
6};
7use core::fmt::{self, Debug};
8use digest::{Digest, FixedOutput, const_oid::AssociatedOid};
9use elliptic_curve::{
10 CurveArithmetic, FieldBytes, Generate, NonZeroScalar, Scalar, SecretKey,
11 group::ff::PrimeField,
12 ops::Invert,
13 rand_core::CryptoRng,
14 subtle::{Choice, ConstantTimeEq, CtOption},
15 zeroize::{Zeroize, ZeroizeOnDrop},
16};
17use signature::{
18 DigestSigner, MultipartSigner, RandomizedDigestSigner, RandomizedMultipartSigner,
19 RandomizedSigner, Signer,
20 hazmat::{PrehashSigner, RandomizedPrehashSigner},
21 rand_core::TryCryptoRng,
22};
23
24#[cfg(feature = "pkcs8")]
25use crate::elliptic_curve::{
26 AffinePoint,
27 pkcs8::{
28 self, ObjectIdentifier,
29 der::AnyRef,
30 spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier},
31 },
32 sec1::{self, FromSec1Point, ToSec1Point},
33};
34#[cfg(any(feature = "der", feature = "pem"))]
35use elliptic_curve::FieldBytesSize;
36#[cfg(feature = "der")]
37use elliptic_curve::array::ArraySize;
38#[cfg(all(feature = "alloc", feature = "pkcs8"))]
39use elliptic_curve::pkcs8::{EncodePrivateKey, SecretDocument};
40#[cfg(feature = "algorithm")]
41use {crate::VerifyingKey, elliptic_curve::PublicKey, signature::KeypairRef};
42#[cfg(feature = "der")]
43use {crate::der, core::ops::Add};
44#[cfg(feature = "pem")]
45use {core::str::FromStr, elliptic_curve::pkcs8::DecodePrivateKey};
46
47#[derive(Clone)]
64pub struct SigningKey<C>
65where
66 C: EcdsaCurve + CurveArithmetic,
67{
68 secret_scalar: NonZeroScalar<C>,
70
71 #[cfg(feature = "algorithm")]
73 verifying_key: VerifyingKey<C>,
74}
75
76impl<C> SigningKey<C>
77where
78 C: EcdsaCurve + CurveArithmetic,
79{
80 pub fn from_bytes(bytes: &FieldBytes<C>) -> Result<Self> {
85 SecretKey::<C>::from_bytes(bytes)
86 .map(Into::into)
87 .map_err(|_| Error::new())
88 }
89
90 pub fn from_slice(bytes: &[u8]) -> Result<Self> {
96 SecretKey::<C>::from_slice(bytes)
97 .map(Into::into)
98 .map_err(|_| Error::new())
99 }
100
101 pub fn to_bytes(&self) -> FieldBytes<C> {
103 self.secret_scalar.to_repr()
104 }
105
106 pub fn as_nonzero_scalar(&self) -> &NonZeroScalar<C> {
114 &self.secret_scalar
115 }
116
117 #[cfg(feature = "algorithm")]
119 pub fn verifying_key(&self) -> &VerifyingKey<C> {
120 &self.verifying_key
121 }
122
123 #[deprecated(since = "0.17.0", note = "use the `Generate` trait instead")]
125 pub fn random<R: CryptoRng + ?Sized>(rng: &mut R) -> Self {
126 Self::generate_from_rng(rng)
127 }
128}
129
130impl<C> Generate for SigningKey<C>
131where
132 C: EcdsaCurve + CurveArithmetic,
133{
134 fn try_generate_from_rng<R: TryCryptoRng + ?Sized>(
135 rng: &mut R,
136 ) -> core::result::Result<Self, R::Error> {
137 NonZeroScalar::<C>::try_generate_from_rng(rng).map(Into::into)
138 }
139}
140
141impl<C, D> DigestSigner<D, Signature<C>> for SigningKey<C>
150where
151 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
152 D: Digest + FixedOutput,
153 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
154{
155 fn try_sign_digest<F: Fn(&mut D) -> Result<()>>(&self, f: F) -> Result<Signature<C>> {
156 let mut digest = D::new();
157 f(&mut digest)?;
158 self.sign_prehash(&digest.finalize_fixed())
159 }
160}
161
162impl<C> PrehashSigner<Signature<C>> for SigningKey<C>
167where
168 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
169 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
170{
171 fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature<C>> {
172 Ok(sign_prehashed_rfc6979::<C, C::Digest>(&self.secret_scalar, prehash, &[]).0)
173 }
174}
175
176impl<C> Signer<Signature<C>> for SigningKey<C>
181where
182 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
183 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
184{
185 fn try_sign(&self, msg: &[u8]) -> Result<Signature<C>> {
186 self.try_multipart_sign(&[msg])
187 }
188}
189
190impl<C> MultipartSigner<Signature<C>> for SigningKey<C>
191where
192 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
193 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
194{
195 fn try_multipart_sign(&self, msg: &[&[u8]]) -> core::result::Result<Signature<C>, Error> {
196 self.try_sign_digest(|digest: &mut C::Digest| {
197 msg.iter().for_each(|slice| digest.update(slice));
198 Ok(())
199 })
200 }
201}
202
203impl<C, D> RandomizedDigestSigner<D, Signature<C>> for SigningKey<C>
204where
205 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
206 D: Digest + FixedOutput,
207 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
208{
209 fn try_sign_digest_with_rng<R: TryCryptoRng + ?Sized, F: Fn(&mut D) -> Result<()>>(
210 &self,
211 rng: &mut R,
212 f: F,
213 ) -> Result<Signature<C>> {
214 let mut digest = D::new();
215 f(&mut digest)?;
216 self.sign_prehash_with_rng(rng, &digest.finalize_fixed())
217 }
218}
219
220impl<C> RandomizedPrehashSigner<Signature<C>> for SigningKey<C>
221where
222 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
223 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
224{
225 fn sign_prehash_with_rng<R: TryCryptoRng + ?Sized>(
226 &self,
227 rng: &mut R,
228 prehash: &[u8],
229 ) -> Result<Signature<C>> {
230 let mut ad = FieldBytes::<C>::default();
231 rng.try_fill_bytes(&mut ad).map_err(|_| Error::new())?;
232 Ok(sign_prehashed_rfc6979::<C, C::Digest>(&self.secret_scalar, prehash, &ad).0)
233 }
234}
235
236impl<C> RandomizedSigner<Signature<C>> for SigningKey<C>
237where
238 Self: RandomizedDigestSigner<C::Digest, Signature<C>>,
239 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
240 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
241{
242 fn try_sign_with_rng<R: TryCryptoRng + ?Sized>(
243 &self,
244 rng: &mut R,
245 msg: &[u8],
246 ) -> Result<Signature<C>> {
247 self.try_multipart_sign_with_rng(rng, &[msg])
248 }
249}
250
251impl<C> RandomizedMultipartSigner<Signature<C>> for SigningKey<C>
252where
253 Self: RandomizedDigestSigner<C::Digest, Signature<C>>,
254 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
255 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
256{
257 fn try_multipart_sign_with_rng<R: TryCryptoRng + ?Sized>(
258 &self,
259 rng: &mut R,
260 msg: &[&[u8]],
261 ) -> Result<Signature<C>> {
262 self.try_sign_digest_with_rng(rng, |digest: &mut C::Digest| {
263 msg.iter().for_each(|slice| digest.update(slice));
264 Ok(())
265 })
266 }
267}
268
269impl<C, D> DigestSigner<D, SignatureWithOid<C>> for SigningKey<C>
270where
271 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
272 D: AssociatedOid + Digest + FixedOutput,
273 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
274{
275 fn try_sign_digest<F: Fn(&mut D) -> Result<()>>(&self, f: F) -> Result<SignatureWithOid<C>> {
276 let signature: Signature<C> = self.try_sign_digest(f)?;
277 let oid = ecdsa_oid_for_digest(D::OID).ok_or_else(Error::new)?;
278 SignatureWithOid::new(signature, oid)
279 }
280}
281
282impl<C> Signer<SignatureWithOid<C>> for SigningKey<C>
283where
284 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
285 C::Digest: AssociatedOid,
286 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
287{
288 fn try_sign(&self, msg: &[u8]) -> Result<SignatureWithOid<C>> {
289 self.try_multipart_sign(&[msg])
290 }
291}
292
293impl<C> MultipartSigner<SignatureWithOid<C>> for SigningKey<C>
294where
295 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
296 C::Digest: AssociatedOid,
297 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
298{
299 fn try_multipart_sign(&self, msg: &[&[u8]]) -> Result<SignatureWithOid<C>> {
300 self.try_sign_digest(|digest: &mut C::Digest| {
301 msg.iter().for_each(|slice| digest.update(slice));
302 Ok(())
303 })
304 }
305}
306
307#[cfg(feature = "der")]
308impl<C> PrehashSigner<der::Signature<C>> for SigningKey<C>
309where
310 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
311 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
312 der::MaxSize<C>: ArraySize,
313 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
314{
315 fn sign_prehash(&self, prehash: &[u8]) -> Result<der::Signature<C>> {
316 PrehashSigner::<Signature<C>>::sign_prehash(self, prehash).map(Into::into)
317 }
318}
319
320#[cfg(feature = "der")]
321impl<C> Signer<der::Signature<C>> for SigningKey<C>
322where
323 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
324 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
325 der::MaxSize<C>: ArraySize,
326 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
327{
328 fn try_sign(&self, msg: &[u8]) -> Result<der::Signature<C>> {
329 Signer::<Signature<C>>::try_sign(self, msg).map(Into::into)
330 }
331}
332
333#[cfg(feature = "der")]
334impl<C, D> RandomizedDigestSigner<D, der::Signature<C>> for SigningKey<C>
335where
336 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
337 D: Digest + FixedOutput,
338 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
339 der::MaxSize<C>: ArraySize,
340 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
341{
342 fn try_sign_digest_with_rng<R: TryCryptoRng + ?Sized, F: Fn(&mut D) -> Result<()>>(
343 &self,
344 rng: &mut R,
345 f: F,
346 ) -> Result<der::Signature<C>> {
347 RandomizedDigestSigner::<D, Signature<C>>::try_sign_digest_with_rng(self, rng, f)
348 .map(Into::into)
349 }
350}
351
352#[cfg(feature = "der")]
353impl<C> RandomizedPrehashSigner<der::Signature<C>> for SigningKey<C>
354where
355 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
356 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
357 der::MaxSize<C>: ArraySize,
358 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
359{
360 fn sign_prehash_with_rng<R: TryCryptoRng + ?Sized>(
361 &self,
362 rng: &mut R,
363 prehash: &[u8],
364 ) -> Result<der::Signature<C>> {
365 RandomizedPrehashSigner::<Signature<C>>::sign_prehash_with_rng(self, rng, prehash)
366 .map(Into::into)
367 }
368}
369
370#[cfg(feature = "der")]
371impl<D, C> DigestSigner<D, der::Signature<C>> for SigningKey<C>
372where
373 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
374 D: Digest + FixedOutput,
375 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
376 der::MaxSize<C>: ArraySize,
377 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
378{
379 fn try_sign_digest<F: Fn(&mut D) -> Result<()>>(&self, f: F) -> Result<der::Signature<C>> {
380 DigestSigner::<D, Signature<C>>::try_sign_digest(self, f).map(Into::into)
381 }
382}
383
384#[cfg(feature = "der")]
385impl<C> RandomizedSigner<der::Signature<C>> for SigningKey<C>
386where
387 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
388 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
389 der::MaxSize<C>: ArraySize,
390 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
391{
392 fn try_sign_with_rng<R: TryCryptoRng + ?Sized>(
393 &self,
394 rng: &mut R,
395 msg: &[u8],
396 ) -> Result<der::Signature<C>> {
397 RandomizedSigner::<Signature<C>>::try_sign_with_rng(self, rng, msg).map(Into::into)
398 }
399}
400
401#[cfg(feature = "der")]
402impl<C> RandomizedMultipartSigner<der::Signature<C>> for SigningKey<C>
403where
404 C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
405 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
406 der::MaxSize<C>: ArraySize,
407 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
408{
409 fn try_multipart_sign_with_rng<R: TryCryptoRng + ?Sized>(
410 &self,
411 rng: &mut R,
412 msg: &[&[u8]],
413 ) -> Result<der::Signature<C>> {
414 RandomizedMultipartSigner::<Signature<C>>::try_multipart_sign_with_rng(self, rng, msg)
415 .map(Into::into)
416 }
417}
418
419#[cfg(feature = "algorithm")]
424impl<C> AsRef<VerifyingKey<C>> for SigningKey<C>
425where
426 C: EcdsaCurve + CurveArithmetic,
427 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
428{
429 fn as_ref(&self) -> &VerifyingKey<C> {
430 &self.verifying_key
431 }
432}
433
434impl<C> ConstantTimeEq for SigningKey<C>
435where
436 C: EcdsaCurve + CurveArithmetic,
437 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
438{
439 fn ct_eq(&self, other: &Self) -> Choice {
440 self.secret_scalar.ct_eq(&other.secret_scalar)
441 }
442}
443
444impl<C> Debug for SigningKey<C>
445where
446 C: EcdsaCurve + CurveArithmetic,
447{
448 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
449 f.debug_struct("SigningKey").finish_non_exhaustive()
450 }
451}
452
453impl<C> Drop for SigningKey<C>
454where
455 C: EcdsaCurve + CurveArithmetic,
456{
457 fn drop(&mut self) {
458 self.secret_scalar.zeroize();
459 }
460}
461
462impl<C> Eq for SigningKey<C>
464where
465 C: EcdsaCurve + CurveArithmetic,
466 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
467{
468}
469impl<C> PartialEq for SigningKey<C>
470where
471 C: EcdsaCurve + CurveArithmetic,
472 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
473{
474 fn eq(&self, other: &SigningKey<C>) -> bool {
475 self.ct_eq(other).into()
476 }
477}
478
479impl<C> From<NonZeroScalar<C>> for SigningKey<C>
480where
481 C: EcdsaCurve + CurveArithmetic,
482{
483 fn from(secret_scalar: NonZeroScalar<C>) -> Self {
484 #[cfg(feature = "algorithm")]
485 let public_key = PublicKey::from_secret_scalar(&secret_scalar);
486
487 Self {
488 secret_scalar,
489 #[cfg(feature = "algorithm")]
490 verifying_key: public_key.into(),
491 }
492 }
493}
494
495impl<C> From<SecretKey<C>> for SigningKey<C>
496where
497 C: EcdsaCurve + CurveArithmetic,
498{
499 fn from(secret_key: SecretKey<C>) -> Self {
500 Self::from(&secret_key)
501 }
502}
503
504impl<C> From<&SecretKey<C>> for SigningKey<C>
505where
506 C: EcdsaCurve + CurveArithmetic,
507{
508 fn from(secret_key: &SecretKey<C>) -> Self {
509 secret_key.to_nonzero_scalar().into()
510 }
511}
512
513impl<C> From<SigningKey<C>> for SecretKey<C>
514where
515 C: EcdsaCurve + CurveArithmetic,
516 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
517{
518 fn from(key: SigningKey<C>) -> Self {
519 key.secret_scalar.into()
520 }
521}
522
523impl<C> From<&SigningKey<C>> for SecretKey<C>
524where
525 C: EcdsaCurve + CurveArithmetic,
526{
527 fn from(secret_key: &SigningKey<C>) -> Self {
528 secret_key.secret_scalar.into()
529 }
530}
531
532impl<C> TryFrom<&[u8]> for SigningKey<C>
533where
534 C: EcdsaCurve + CurveArithmetic,
535{
536 type Error = Error;
537
538 fn try_from(bytes: &[u8]) -> Result<Self> {
539 Self::from_slice(bytes)
540 }
541}
542
543impl<C> ZeroizeOnDrop for SigningKey<C> where C: EcdsaCurve + CurveArithmetic {}
544
545#[cfg(feature = "algorithm")]
546impl<C> From<SigningKey<C>> for VerifyingKey<C>
547where
548 C: EcdsaCurve + CurveArithmetic,
549 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
550{
551 fn from(signing_key: SigningKey<C>) -> VerifyingKey<C> {
552 signing_key.verifying_key
553 }
554}
555
556#[cfg(feature = "algorithm")]
557impl<C> From<&SigningKey<C>> for VerifyingKey<C>
558where
559 C: EcdsaCurve + CurveArithmetic,
560 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
561{
562 fn from(signing_key: &SigningKey<C>) -> VerifyingKey<C> {
563 signing_key.verifying_key
564 }
565}
566
567#[cfg(feature = "algorithm")]
568impl<C> KeypairRef for SigningKey<C>
569where
570 C: EcdsaCurve + CurveArithmetic,
571 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
572{
573 type VerifyingKey = VerifyingKey<C>;
574}
575
576#[cfg(feature = "pkcs8")]
577impl<C> AssociatedAlgorithmIdentifier for SigningKey<C>
578where
579 C: EcdsaCurve + AssociatedOid + CurveArithmetic,
580 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
581{
582 type Params = ObjectIdentifier;
583
584 const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> =
585 SecretKey::<C>::ALGORITHM_IDENTIFIER;
586}
587
588#[cfg(feature = "pkcs8")]
589impl<C> SignatureAlgorithmIdentifier for SigningKey<C>
590where
591 C: EcdsaCurve + CurveArithmetic,
592 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
593 Signature<C>: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
594{
595 type Params = AnyRef<'static>;
596
597 const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
598 Signature::<C>::ALGORITHM_IDENTIFIER;
599}
600
601#[cfg(feature = "pkcs8")]
602impl<C> TryFrom<pkcs8::PrivateKeyInfoRef<'_>> for SigningKey<C>
603where
604 C: EcdsaCurve + AssociatedOid + CurveArithmetic,
605 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
606 FieldBytesSize<C>: sec1::ModulusSize,
607 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
608{
609 type Error = pkcs8::Error;
610
611 fn try_from(private_key_info: pkcs8::PrivateKeyInfoRef<'_>) -> pkcs8::Result<Self> {
612 SecretKey::try_from(private_key_info).map(Into::into)
613 }
614}
615
616#[cfg(all(feature = "alloc", feature = "pkcs8"))]
617impl<C> EncodePrivateKey for SigningKey<C>
618where
619 C: EcdsaCurve + AssociatedOid + CurveArithmetic,
620 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
621 FieldBytesSize<C>: sec1::ModulusSize,
622 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
623{
624 fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
625 SecretKey::from(self.secret_scalar).to_pkcs8_der()
626 }
627}
628
629#[cfg(feature = "pem")]
630impl<C> FromStr for SigningKey<C>
631where
632 C: EcdsaCurve + AssociatedOid + CurveArithmetic,
633 AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
634 FieldBytesSize<C>: sec1::ModulusSize,
635 Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
636{
637 type Err = Error;
638
639 fn from_str(s: &str) -> Result<Self> {
640 Self::from_pkcs8_pem(s).map_err(|_| Error::new())
641 }
642}