Skip to main content

ecdsa/
signing.rs

1//! ECDSA signing: producing signatures using a [`SigningKey`].
2
3use crate::{
4    EcdsaCurve, Error, Result, Signature, SignatureSize, SignatureWithOid, ecdsa_oid_for_digest,
5    hazmat::{DigestAlgorithm, bits2field, sign_prehashed_rfc6979},
6};
7use core::fmt::{self, Debug};
8use digest::{Update, block_api::EagerHash, const_oid::AssociatedOid};
9use elliptic_curve::{
10    CurveArithmetic, FieldBytes, Generate, NonZeroScalar, Scalar, SecretKey,
11    array::ArraySize,
12    group::ff::PrimeField,
13    ops::Invert,
14    rand_core::CryptoRng,
15    subtle::{Choice, ConstantTimeEq, CtOption},
16    zeroize::{Zeroize, ZeroizeOnDrop},
17};
18use signature::{
19    DigestSigner, MultipartSigner, RandomizedDigestSigner, RandomizedMultipartSigner,
20    RandomizedSigner, Signer,
21    hazmat::{PrehashSigner, RandomizedPrehashSigner},
22    rand_core::TryCryptoRng,
23};
24
25#[cfg(feature = "der")]
26use {crate::der, core::ops::Add};
27
28#[cfg(feature = "pem")]
29use {core::str::FromStr, elliptic_curve::pkcs8::DecodePrivateKey};
30
31#[cfg(any(feature = "der", feature = "pem"))]
32use elliptic_curve::FieldBytesSize;
33
34#[cfg(feature = "pkcs8")]
35use crate::elliptic_curve::{
36    AffinePoint,
37    pkcs8::{
38        self, ObjectIdentifier,
39        der::AnyRef,
40        spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier},
41    },
42    sec1::{self, FromSec1Point, ToSec1Point},
43};
44
45#[cfg(feature = "algorithm")]
46use {crate::VerifyingKey, elliptic_curve::PublicKey, signature::KeypairRef};
47
48#[cfg(all(feature = "alloc", feature = "pkcs8"))]
49use elliptic_curve::pkcs8::{EncodePrivateKey, SecretDocument};
50
51/// ECDSA secret key used for signing. Generic over prime order elliptic curves
52/// (e.g. NIST P-curves).
53///
54/// Requires an [`elliptic_curve::CurveArithmetic`] impl on the curve.
55///
56/// ## Usage
57///
58/// The [`signature`] crate defines the following traits which are the
59/// primary API for signing:
60///
61/// - [`Signer`]: sign a message using this key
62/// - [`DigestSigner`]: sign the output of a [`Digest`] using this key
63/// - [`PrehashSigner`]: sign the low-level raw output bytes of a message digest
64///
65/// See the [`p256` crate](https://docs.rs/p256/latest/p256/ecdsa/index.html)
66/// for examples of using this type with a concrete elliptic curve.
67#[derive(Clone)]
68pub struct SigningKey<C>
69where
70    C: EcdsaCurve + CurveArithmetic,
71{
72    /// ECDSA signing keys are non-zero elements of a given curve's scalar field.
73    secret_scalar: NonZeroScalar<C>,
74
75    /// Verifying key which corresponds to this signing key.
76    #[cfg(feature = "algorithm")]
77    verifying_key: VerifyingKey<C>,
78}
79
80impl<C> SigningKey<C>
81where
82    C: EcdsaCurve + CurveArithmetic,
83{
84    /// Initialize signing key from a raw scalar serialized as a byte array.
85    pub fn from_bytes(bytes: &FieldBytes<C>) -> Result<Self> {
86        SecretKey::<C>::from_bytes(bytes)
87            .map(Into::into)
88            .map_err(|_| Error::new())
89    }
90
91    /// Initialize signing key from a raw scalar serialized as a byte slice.
92    pub fn from_slice(bytes: &[u8]) -> Result<Self> {
93        SecretKey::<C>::from_slice(bytes)
94            .map(Into::into)
95            .map_err(|_| Error::new())
96    }
97
98    /// Serialize this [`SigningKey`] as bytes
99    pub fn to_bytes(&self) -> FieldBytes<C> {
100        self.secret_scalar.to_repr()
101    }
102
103    /// Borrow the secret [`NonZeroScalar`] value for this key.
104    ///
105    /// # ⚠️ Warning
106    ///
107    /// This value is key material.
108    ///
109    /// Please treat it with the care it deserves!
110    pub fn as_nonzero_scalar(&self) -> &NonZeroScalar<C> {
111        &self.secret_scalar
112    }
113
114    /// Get the [`VerifyingKey`] which corresponds to this [`SigningKey`].
115    #[cfg(feature = "algorithm")]
116    pub fn verifying_key(&self) -> &VerifyingKey<C> {
117        &self.verifying_key
118    }
119
120    /// DEPRECATED: Generate a cryptographically random [`SigningKey`].
121    #[deprecated(since = "0.17.0", note = "use the `Generate` trait instead")]
122    pub fn random<R: CryptoRng + ?Sized>(rng: &mut R) -> Self {
123        Self::generate_from_rng(rng)
124    }
125}
126
127impl<C> Generate for SigningKey<C>
128where
129    C: EcdsaCurve + CurveArithmetic,
130{
131    fn try_generate_from_rng<R: TryCryptoRng + ?Sized>(
132        rng: &mut R,
133    ) -> core::result::Result<Self, R::Error> {
134        NonZeroScalar::<C>::try_generate_from_rng(rng).map(Into::into)
135    }
136}
137
138//
139// `*Signer` trait impls
140//
141
142/// Sign message digest using a deterministic ephemeral scalar (`k`)
143/// computed using the algorithm described in [RFC6979 § 3.2].
144///
145/// [RFC6979 § 3.2]: https://tools.ietf.org/html/rfc6979#section-3
146impl<C, D> DigestSigner<D, Signature<C>> for SigningKey<C>
147where
148    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
149    D: EagerHash + Update,
150    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
151    SignatureSize<C>: ArraySize,
152{
153    fn try_sign_digest<F: Fn(&mut D) -> Result<()>>(&self, f: F) -> Result<Signature<C>> {
154        let mut digest = D::new();
155        f(&mut digest)?;
156        self.sign_prehash(&digest.finalize())
157    }
158}
159
160/// Sign message prehash using a deterministic ephemeral scalar (`k`)
161/// computed using the algorithm described in [RFC6979 § 3.2].
162///
163/// [RFC6979 § 3.2]: https://tools.ietf.org/html/rfc6979#section-3
164impl<C> PrehashSigner<Signature<C>> for SigningKey<C>
165where
166    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
167    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
168    SignatureSize<C>: ArraySize,
169{
170    fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature<C>> {
171        let z = bits2field::<C>(prehash)?;
172        Ok(sign_prehashed_rfc6979::<C, C::Digest>(&self.secret_scalar, &z, &[])?.0)
173    }
174}
175
176/// Sign message using a deterministic ephemeral scalar (`k`)
177/// computed using the algorithm described in [RFC6979 § 3.2].
178///
179/// [RFC6979 § 3.2]: https://tools.ietf.org/html/rfc6979#section-3
180impl<C> Signer<Signature<C>> for SigningKey<C>
181where
182    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
183    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
184    SignatureSize<C>: ArraySize,
185{
186    fn try_sign(&self, msg: &[u8]) -> Result<Signature<C>> {
187        self.try_multipart_sign(&[msg])
188    }
189}
190
191impl<C> MultipartSigner<Signature<C>> for SigningKey<C>
192where
193    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
194    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
195    SignatureSize<C>: ArraySize,
196{
197    fn try_multipart_sign(&self, msg: &[&[u8]]) -> core::result::Result<Signature<C>, Error> {
198        self.try_sign_digest(|digest: &mut C::Digest| {
199            msg.iter().for_each(|slice| digest.update(slice));
200            Ok(())
201        })
202    }
203}
204
205impl<C, D> RandomizedDigestSigner<D, Signature<C>> for SigningKey<C>
206where
207    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
208    D: EagerHash + Update,
209    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
210    SignatureSize<C>: ArraySize,
211{
212    fn try_sign_digest_with_rng<R: TryCryptoRng + ?Sized, F: Fn(&mut D) -> Result<()>>(
213        &self,
214        rng: &mut R,
215        f: F,
216    ) -> Result<Signature<C>> {
217        let mut digest = D::new();
218        f(&mut digest)?;
219        self.sign_prehash_with_rng(rng, &digest.finalize())
220    }
221}
222
223impl<C> RandomizedPrehashSigner<Signature<C>> for SigningKey<C>
224where
225    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
226    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
227    SignatureSize<C>: ArraySize,
228{
229    fn sign_prehash_with_rng<R: TryCryptoRng + ?Sized>(
230        &self,
231        rng: &mut R,
232        prehash: &[u8],
233    ) -> Result<Signature<C>> {
234        let z = bits2field::<C>(prehash)?;
235
236        loop {
237            let mut ad = FieldBytes::<C>::default();
238            rng.try_fill_bytes(&mut ad).map_err(|_| Error::new())?;
239
240            if let Ok((signature, _)) =
241                sign_prehashed_rfc6979::<C, C::Digest>(&self.secret_scalar, &z, &ad)
242            {
243                break Ok(signature);
244            }
245        }
246    }
247}
248
249impl<C> RandomizedSigner<Signature<C>> for SigningKey<C>
250where
251    Self: RandomizedDigestSigner<C::Digest, Signature<C>>,
252    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
253    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
254    SignatureSize<C>: ArraySize,
255{
256    fn try_sign_with_rng<R: TryCryptoRng + ?Sized>(
257        &self,
258        rng: &mut R,
259        msg: &[u8],
260    ) -> Result<Signature<C>> {
261        self.try_multipart_sign_with_rng(rng, &[msg])
262    }
263}
264
265impl<C> RandomizedMultipartSigner<Signature<C>> for SigningKey<C>
266where
267    Self: RandomizedDigestSigner<C::Digest, Signature<C>>,
268    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
269    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
270    SignatureSize<C>: ArraySize,
271{
272    fn try_multipart_sign_with_rng<R: TryCryptoRng + ?Sized>(
273        &self,
274        rng: &mut R,
275        msg: &[&[u8]],
276    ) -> Result<Signature<C>> {
277        self.try_sign_digest_with_rng(rng, |digest: &mut C::Digest| {
278            msg.iter().for_each(|slice| digest.update(slice));
279            Ok(())
280        })
281    }
282}
283
284impl<C, D> DigestSigner<D, SignatureWithOid<C>> for SigningKey<C>
285where
286    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
287    D: AssociatedOid + EagerHash + Update,
288    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
289    SignatureSize<C>: ArraySize,
290{
291    fn try_sign_digest<F: Fn(&mut D) -> Result<()>>(&self, f: F) -> Result<SignatureWithOid<C>> {
292        let signature: Signature<C> = self.try_sign_digest(f)?;
293        let oid = ecdsa_oid_for_digest(D::OID).ok_or_else(Error::new)?;
294        SignatureWithOid::new(signature, oid)
295    }
296}
297
298impl<C> Signer<SignatureWithOid<C>> for SigningKey<C>
299where
300    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
301    C::Digest: AssociatedOid,
302    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
303    SignatureSize<C>: ArraySize,
304{
305    fn try_sign(&self, msg: &[u8]) -> Result<SignatureWithOid<C>> {
306        self.try_multipart_sign(&[msg])
307    }
308}
309
310impl<C> MultipartSigner<SignatureWithOid<C>> for SigningKey<C>
311where
312    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
313    C::Digest: AssociatedOid,
314    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
315    SignatureSize<C>: ArraySize,
316{
317    fn try_multipart_sign(&self, msg: &[&[u8]]) -> Result<SignatureWithOid<C>> {
318        self.try_sign_digest(|digest: &mut C::Digest| {
319            msg.iter().for_each(|slice| digest.update(slice));
320            Ok(())
321        })
322    }
323}
324
325#[cfg(feature = "der")]
326impl<C> PrehashSigner<der::Signature<C>> for SigningKey<C>
327where
328    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
329    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
330    SignatureSize<C>: ArraySize,
331    der::MaxSize<C>: ArraySize,
332    <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
333{
334    fn sign_prehash(&self, prehash: &[u8]) -> Result<der::Signature<C>> {
335        PrehashSigner::<Signature<C>>::sign_prehash(self, prehash).map(Into::into)
336    }
337}
338
339#[cfg(feature = "der")]
340impl<C> Signer<der::Signature<C>> for SigningKey<C>
341where
342    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
343    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
344    SignatureSize<C>: ArraySize,
345    der::MaxSize<C>: ArraySize,
346    <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
347{
348    fn try_sign(&self, msg: &[u8]) -> Result<der::Signature<C>> {
349        Signer::<Signature<C>>::try_sign(self, msg).map(Into::into)
350    }
351}
352
353#[cfg(feature = "der")]
354impl<C, D> RandomizedDigestSigner<D, der::Signature<C>> for SigningKey<C>
355where
356    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
357    D: EagerHash + Update,
358    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
359    SignatureSize<C>: ArraySize,
360    der::MaxSize<C>: ArraySize,
361    <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
362{
363    fn try_sign_digest_with_rng<R: TryCryptoRng + ?Sized, F: Fn(&mut D) -> Result<()>>(
364        &self,
365        rng: &mut R,
366        f: F,
367    ) -> Result<der::Signature<C>> {
368        RandomizedDigestSigner::<D, Signature<C>>::try_sign_digest_with_rng(self, rng, f)
369            .map(Into::into)
370    }
371}
372
373#[cfg(feature = "der")]
374impl<C> RandomizedPrehashSigner<der::Signature<C>> for SigningKey<C>
375where
376    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
377    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
378    SignatureSize<C>: ArraySize,
379    der::MaxSize<C>: ArraySize,
380    <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
381{
382    fn sign_prehash_with_rng<R: TryCryptoRng + ?Sized>(
383        &self,
384        rng: &mut R,
385        prehash: &[u8],
386    ) -> Result<der::Signature<C>> {
387        RandomizedPrehashSigner::<Signature<C>>::sign_prehash_with_rng(self, rng, prehash)
388            .map(Into::into)
389    }
390}
391
392#[cfg(feature = "der")]
393impl<D, C> DigestSigner<D, der::Signature<C>> for SigningKey<C>
394where
395    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
396    D: EagerHash + Update,
397    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
398    SignatureSize<C>: ArraySize,
399    der::MaxSize<C>: ArraySize,
400    <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
401{
402    fn try_sign_digest<F: Fn(&mut D) -> Result<()>>(&self, f: F) -> Result<der::Signature<C>> {
403        DigestSigner::<D, Signature<C>>::try_sign_digest(self, f).map(Into::into)
404    }
405}
406
407#[cfg(feature = "der")]
408impl<C> RandomizedSigner<der::Signature<C>> for SigningKey<C>
409where
410    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
411    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
412    SignatureSize<C>: ArraySize,
413    der::MaxSize<C>: ArraySize,
414    <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
415{
416    fn try_sign_with_rng<R: TryCryptoRng + ?Sized>(
417        &self,
418        rng: &mut R,
419        msg: &[u8],
420    ) -> Result<der::Signature<C>> {
421        RandomizedSigner::<Signature<C>>::try_sign_with_rng(self, rng, msg).map(Into::into)
422    }
423}
424
425#[cfg(feature = "der")]
426impl<C> RandomizedMultipartSigner<der::Signature<C>> for SigningKey<C>
427where
428    C: EcdsaCurve + CurveArithmetic + DigestAlgorithm,
429    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
430    SignatureSize<C>: ArraySize,
431    der::MaxSize<C>: ArraySize,
432    <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArraySize,
433{
434    fn try_multipart_sign_with_rng<R: TryCryptoRng + ?Sized>(
435        &self,
436        rng: &mut R,
437        msg: &[&[u8]],
438    ) -> Result<der::Signature<C>> {
439        RandomizedMultipartSigner::<Signature<C>>::try_multipart_sign_with_rng(self, rng, msg)
440            .map(Into::into)
441    }
442}
443
444//
445// Other trait impls
446//
447
448#[cfg(feature = "algorithm")]
449impl<C> AsRef<VerifyingKey<C>> for SigningKey<C>
450where
451    C: EcdsaCurve + CurveArithmetic,
452    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
453    SignatureSize<C>: ArraySize,
454{
455    fn as_ref(&self) -> &VerifyingKey<C> {
456        &self.verifying_key
457    }
458}
459
460impl<C> ConstantTimeEq for SigningKey<C>
461where
462    C: EcdsaCurve + CurveArithmetic,
463    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
464    SignatureSize<C>: ArraySize,
465{
466    fn ct_eq(&self, other: &Self) -> Choice {
467        self.secret_scalar.ct_eq(&other.secret_scalar)
468    }
469}
470
471impl<C> Debug for SigningKey<C>
472where
473    C: EcdsaCurve + CurveArithmetic,
474{
475    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
476        f.debug_struct("SigningKey").finish_non_exhaustive()
477    }
478}
479
480impl<C> Drop for SigningKey<C>
481where
482    C: EcdsaCurve + CurveArithmetic,
483{
484    fn drop(&mut self) {
485        self.secret_scalar.zeroize();
486    }
487}
488
489/// Constant-time comparison
490impl<C> Eq for SigningKey<C>
491where
492    C: EcdsaCurve + CurveArithmetic,
493    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
494    SignatureSize<C>: ArraySize,
495{
496}
497impl<C> PartialEq for SigningKey<C>
498where
499    C: EcdsaCurve + CurveArithmetic,
500    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
501    SignatureSize<C>: ArraySize,
502{
503    fn eq(&self, other: &SigningKey<C>) -> bool {
504        self.ct_eq(other).into()
505    }
506}
507
508impl<C> From<NonZeroScalar<C>> for SigningKey<C>
509where
510    C: EcdsaCurve + CurveArithmetic,
511{
512    fn from(secret_scalar: NonZeroScalar<C>) -> Self {
513        #[cfg(feature = "algorithm")]
514        let public_key = PublicKey::from_secret_scalar(&secret_scalar);
515
516        Self {
517            secret_scalar,
518            #[cfg(feature = "algorithm")]
519            verifying_key: public_key.into(),
520        }
521    }
522}
523
524impl<C> From<SecretKey<C>> for SigningKey<C>
525where
526    C: EcdsaCurve + CurveArithmetic,
527{
528    fn from(secret_key: SecretKey<C>) -> Self {
529        Self::from(&secret_key)
530    }
531}
532
533impl<C> From<&SecretKey<C>> for SigningKey<C>
534where
535    C: EcdsaCurve + CurveArithmetic,
536{
537    fn from(secret_key: &SecretKey<C>) -> Self {
538        secret_key.to_nonzero_scalar().into()
539    }
540}
541
542impl<C> From<SigningKey<C>> for SecretKey<C>
543where
544    C: EcdsaCurve + CurveArithmetic,
545    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
546    SignatureSize<C>: ArraySize,
547{
548    fn from(key: SigningKey<C>) -> Self {
549        key.secret_scalar.into()
550    }
551}
552
553impl<C> From<&SigningKey<C>> for SecretKey<C>
554where
555    C: EcdsaCurve + CurveArithmetic,
556{
557    fn from(secret_key: &SigningKey<C>) -> Self {
558        secret_key.secret_scalar.into()
559    }
560}
561
562impl<C> TryFrom<&[u8]> for SigningKey<C>
563where
564    C: EcdsaCurve + CurveArithmetic,
565{
566    type Error = Error;
567
568    fn try_from(bytes: &[u8]) -> Result<Self> {
569        Self::from_slice(bytes)
570    }
571}
572
573impl<C> ZeroizeOnDrop for SigningKey<C> where C: EcdsaCurve + CurveArithmetic {}
574
575#[cfg(feature = "algorithm")]
576impl<C> From<SigningKey<C>> for VerifyingKey<C>
577where
578    C: EcdsaCurve + CurveArithmetic,
579    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
580    SignatureSize<C>: ArraySize,
581{
582    fn from(signing_key: SigningKey<C>) -> VerifyingKey<C> {
583        signing_key.verifying_key
584    }
585}
586
587#[cfg(feature = "algorithm")]
588impl<C> From<&SigningKey<C>> for VerifyingKey<C>
589where
590    C: EcdsaCurve + CurveArithmetic,
591    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
592    SignatureSize<C>: ArraySize,
593{
594    fn from(signing_key: &SigningKey<C>) -> VerifyingKey<C> {
595        signing_key.verifying_key
596    }
597}
598
599#[cfg(feature = "algorithm")]
600impl<C> KeypairRef for SigningKey<C>
601where
602    C: EcdsaCurve + CurveArithmetic,
603    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
604    SignatureSize<C>: ArraySize,
605{
606    type VerifyingKey = VerifyingKey<C>;
607}
608
609#[cfg(feature = "pkcs8")]
610impl<C> AssociatedAlgorithmIdentifier for SigningKey<C>
611where
612    C: EcdsaCurve + AssociatedOid + CurveArithmetic,
613    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
614    SignatureSize<C>: ArraySize,
615{
616    type Params = ObjectIdentifier;
617
618    const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> =
619        SecretKey::<C>::ALGORITHM_IDENTIFIER;
620}
621
622#[cfg(feature = "pkcs8")]
623impl<C> SignatureAlgorithmIdentifier for SigningKey<C>
624where
625    C: EcdsaCurve + CurveArithmetic,
626    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
627    SignatureSize<C>: ArraySize,
628    Signature<C>: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
629{
630    type Params = AnyRef<'static>;
631
632    const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
633        Signature::<C>::ALGORITHM_IDENTIFIER;
634}
635
636#[cfg(feature = "pkcs8")]
637impl<C> TryFrom<pkcs8::PrivateKeyInfoRef<'_>> for SigningKey<C>
638where
639    C: EcdsaCurve + AssociatedOid + CurveArithmetic,
640    AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
641    FieldBytesSize<C>: sec1::ModulusSize,
642    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
643    SignatureSize<C>: ArraySize,
644{
645    type Error = pkcs8::Error;
646
647    fn try_from(private_key_info: pkcs8::PrivateKeyInfoRef<'_>) -> pkcs8::Result<Self> {
648        SecretKey::try_from(private_key_info).map(Into::into)
649    }
650}
651
652#[cfg(all(feature = "alloc", feature = "pkcs8"))]
653impl<C> EncodePrivateKey for SigningKey<C>
654where
655    C: EcdsaCurve + AssociatedOid + CurveArithmetic,
656    AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
657    FieldBytesSize<C>: sec1::ModulusSize,
658    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
659    SignatureSize<C>: ArraySize,
660{
661    fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
662        SecretKey::from(self.secret_scalar).to_pkcs8_der()
663    }
664}
665
666#[cfg(feature = "pem")]
667impl<C> FromStr for SigningKey<C>
668where
669    C: EcdsaCurve + AssociatedOid + CurveArithmetic,
670    AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
671    FieldBytesSize<C>: sec1::ModulusSize,
672    Scalar<C>: Invert<Output = CtOption<Scalar<C>>>,
673    SignatureSize<C>: ArraySize,
674{
675    type Err = Error;
676
677    fn from_str(s: &str) -> Result<Self> {
678        Self::from_pkcs8_pem(s).map_err(|_| Error::new())
679    }
680}