1use crate::{
4 ecdsa_oid_for_digest,
5 hazmat::{bits2field, DigestPrimitive, SignPrimitive},
6 Error, Result, Signature, SignatureSize, SignatureWithOid,
7};
8use core::fmt::{self, Debug};
9use digest::{const_oid::AssociatedOid, Digest, FixedOutput};
10use elliptic_curve::{
11 generic_array::ArrayLength,
12 group::ff::PrimeField,
13 ops::Invert,
14 subtle::{Choice, ConstantTimeEq, CtOption},
15 zeroize::{Zeroize, ZeroizeOnDrop},
16 CurveArithmetic, FieldBytes, FieldBytesSize, NonZeroScalar, PrimeCurve, Scalar, SecretKey,
17};
18use signature::{
19 hazmat::{PrehashSigner, RandomizedPrehashSigner},
20 rand_core::CryptoRngCore,
21 DigestSigner, RandomizedDigestSigner, RandomizedSigner, Signer,
22};
23
24#[cfg(feature = "der")]
25use {crate::der, core::ops::Add};
26
27#[cfg(feature = "pem")]
28use {
29 crate::elliptic_curve::pkcs8::{DecodePrivateKey, EncodePrivateKey, SecretDocument},
30 core::str::FromStr,
31};
32
33#[cfg(feature = "pkcs8")]
34use crate::elliptic_curve::{
35 pkcs8::{
36 self,
37 der::AnyRef,
38 spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier},
39 ObjectIdentifier,
40 },
41 sec1::{self, FromEncodedPoint, ToEncodedPoint},
42 AffinePoint,
43};
44
45#[cfg(feature = "verifying")]
46use {crate::VerifyingKey, elliptic_curve::PublicKey, signature::KeypairRef};
47
48#[derive(Clone)]
66pub struct SigningKey<C>
67where
68 C: PrimeCurve + CurveArithmetic,
69 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
70 SignatureSize<C>: ArrayLength<u8>,
71{
72 secret_scalar: NonZeroScalar<C>,
74
75 #[cfg(feature = "verifying")]
77 verifying_key: VerifyingKey<C>,
78}
79
80impl<C> SigningKey<C>
81where
82 C: PrimeCurve + CurveArithmetic,
83 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
84 SignatureSize<C>: ArrayLength<u8>,
85{
86 pub fn random(rng: &mut impl CryptoRngCore) -> Self {
88 NonZeroScalar::<C>::random(rng).into()
89 }
90
91 pub fn from_bytes(bytes: &FieldBytes<C>) -> Result<Self> {
93 SecretKey::<C>::from_bytes(bytes)
94 .map(Into::into)
95 .map_err(|_| Error::new())
96 }
97
98 pub fn from_slice(bytes: &[u8]) -> Result<Self> {
100 SecretKey::<C>::from_slice(bytes)
101 .map(Into::into)
102 .map_err(|_| Error::new())
103 }
104
105 pub fn to_bytes(&self) -> FieldBytes<C> {
107 self.secret_scalar.to_repr()
108 }
109
110 pub fn as_nonzero_scalar(&self) -> &NonZeroScalar<C> {
118 &self.secret_scalar
119 }
120
121 #[cfg(feature = "verifying")]
123 pub fn verifying_key(&self) -> &VerifyingKey<C> {
124 &self.verifying_key
125 }
126}
127
128impl<C, D> DigestSigner<D, Signature<C>> for SigningKey<C>
137where
138 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
139 D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
140 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
141 SignatureSize<C>: ArrayLength<u8>,
142{
143 fn try_sign_digest(&self, msg_digest: D) -> Result<Signature<C>> {
144 self.sign_prehash(&msg_digest.finalize_fixed())
145 }
146}
147
148impl<C> PrehashSigner<Signature<C>> for SigningKey<C>
153where
154 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
155 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
156 SignatureSize<C>: ArrayLength<u8>,
157{
158 fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature<C>> {
159 let z = bits2field::<C>(prehash)?;
160 Ok(self
161 .secret_scalar
162 .try_sign_prehashed_rfc6979::<C::Digest>(&z, &[])?
163 .0)
164 }
165}
166
167impl<C> Signer<Signature<C>> for SigningKey<C>
172where
173 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
174 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
175 SignatureSize<C>: ArrayLength<u8>,
176{
177 fn try_sign(&self, msg: &[u8]) -> Result<Signature<C>> {
178 self.try_sign_digest(C::Digest::new_with_prefix(msg))
179 }
180}
181
182impl<C, D> RandomizedDigestSigner<D, Signature<C>> for SigningKey<C>
183where
184 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
185 D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
186 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
187 SignatureSize<C>: ArrayLength<u8>,
188{
189 fn try_sign_digest_with_rng(
190 &self,
191 rng: &mut impl CryptoRngCore,
192 msg_digest: D,
193 ) -> Result<Signature<C>> {
194 self.sign_prehash_with_rng(rng, &msg_digest.finalize_fixed())
195 }
196}
197
198impl<C> RandomizedPrehashSigner<Signature<C>> for SigningKey<C>
199where
200 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
201 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
202 SignatureSize<C>: ArrayLength<u8>,
203{
204 fn sign_prehash_with_rng(
205 &self,
206 rng: &mut impl CryptoRngCore,
207 prehash: &[u8],
208 ) -> Result<Signature<C>> {
209 let z = bits2field::<C>(prehash)?;
210 let mut ad = FieldBytes::<C>::default();
211 rng.fill_bytes(&mut ad);
212 Ok(self
213 .secret_scalar
214 .try_sign_prehashed_rfc6979::<C::Digest>(&z, &ad)?
215 .0)
216 }
217}
218
219impl<C> RandomizedSigner<Signature<C>> for SigningKey<C>
220where
221 Self: RandomizedDigestSigner<C::Digest, Signature<C>>,
222 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
223 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
224 SignatureSize<C>: ArrayLength<u8>,
225{
226 fn try_sign_with_rng(&self, rng: &mut impl CryptoRngCore, msg: &[u8]) -> Result<Signature<C>> {
227 self.try_sign_digest_with_rng(rng, C::Digest::new_with_prefix(msg))
228 }
229}
230
231impl<C, D> DigestSigner<D, SignatureWithOid<C>> for SigningKey<C>
232where
233 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
234 D: AssociatedOid + Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
235 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
236 SignatureSize<C>: ArrayLength<u8>,
237{
238 fn try_sign_digest(&self, msg_digest: D) -> Result<SignatureWithOid<C>> {
239 let signature: Signature<C> = self.try_sign_digest(msg_digest)?;
240 let oid = ecdsa_oid_for_digest(D::OID).ok_or_else(Error::new)?;
241 SignatureWithOid::new(signature, oid)
242 }
243}
244
245impl<C> Signer<SignatureWithOid<C>> for SigningKey<C>
246where
247 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
248 C::Digest: AssociatedOid,
249 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
250 SignatureSize<C>: ArrayLength<u8>,
251{
252 fn try_sign(&self, msg: &[u8]) -> Result<SignatureWithOid<C>> {
253 self.try_sign_digest(C::Digest::new_with_prefix(msg))
254 }
255}
256
257#[cfg(feature = "der")]
258impl<C> PrehashSigner<der::Signature<C>> for SigningKey<C>
259where
260 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
261 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
262 SignatureSize<C>: ArrayLength<u8>,
263 der::MaxSize<C>: ArrayLength<u8>,
264 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
265{
266 fn sign_prehash(&self, prehash: &[u8]) -> Result<der::Signature<C>> {
267 PrehashSigner::<Signature<C>>::sign_prehash(self, prehash).map(Into::into)
268 }
269}
270
271#[cfg(feature = "der")]
272impl<C> Signer<der::Signature<C>> for SigningKey<C>
273where
274 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
275 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
276 SignatureSize<C>: ArrayLength<u8>,
277 der::MaxSize<C>: ArrayLength<u8>,
278 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
279{
280 fn try_sign(&self, msg: &[u8]) -> Result<der::Signature<C>> {
281 Signer::<Signature<C>>::try_sign(self, msg).map(Into::into)
282 }
283}
284
285#[cfg(feature = "der")]
286impl<C, D> RandomizedDigestSigner<D, der::Signature<C>> for SigningKey<C>
287where
288 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
289 D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
290 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
291 SignatureSize<C>: ArrayLength<u8>,
292 der::MaxSize<C>: ArrayLength<u8>,
293 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
294{
295 fn try_sign_digest_with_rng(
296 &self,
297 rng: &mut impl CryptoRngCore,
298 msg_digest: D,
299 ) -> Result<der::Signature<C>> {
300 RandomizedDigestSigner::<D, Signature<C>>::try_sign_digest_with_rng(self, rng, msg_digest)
301 .map(Into::into)
302 }
303}
304
305#[cfg(feature = "der")]
306impl<C> RandomizedPrehashSigner<der::Signature<C>> for SigningKey<C>
307where
308 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
309 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
310 SignatureSize<C>: ArrayLength<u8>,
311 der::MaxSize<C>: ArrayLength<u8>,
312 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
313{
314 fn sign_prehash_with_rng(
315 &self,
316 rng: &mut impl CryptoRngCore,
317 prehash: &[u8],
318 ) -> Result<der::Signature<C>> {
319 RandomizedPrehashSigner::<Signature<C>>::sign_prehash_with_rng(self, rng, prehash)
320 .map(Into::into)
321 }
322}
323
324#[cfg(feature = "der")]
325impl<C> RandomizedSigner<der::Signature<C>> for SigningKey<C>
326where
327 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
328 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
329 SignatureSize<C>: ArrayLength<u8>,
330 der::MaxSize<C>: ArrayLength<u8>,
331 <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
332{
333 fn try_sign_with_rng(
334 &self,
335 rng: &mut impl CryptoRngCore,
336 msg: &[u8],
337 ) -> Result<der::Signature<C>> {
338 RandomizedSigner::<Signature<C>>::try_sign_with_rng(self, rng, msg).map(Into::into)
339 }
340}
341
342#[cfg(feature = "verifying")]
347impl<C> AsRef<VerifyingKey<C>> for SigningKey<C>
348where
349 C: PrimeCurve + CurveArithmetic,
350 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
351 SignatureSize<C>: ArrayLength<u8>,
352{
353 fn as_ref(&self) -> &VerifyingKey<C> {
354 &self.verifying_key
355 }
356}
357
358impl<C> ConstantTimeEq for SigningKey<C>
359where
360 C: PrimeCurve + CurveArithmetic,
361 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
362 SignatureSize<C>: ArrayLength<u8>,
363{
364 fn ct_eq(&self, other: &Self) -> Choice {
365 self.secret_scalar.ct_eq(&other.secret_scalar)
366 }
367}
368
369impl<C> Debug for SigningKey<C>
370where
371 C: PrimeCurve + CurveArithmetic,
372 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
373 SignatureSize<C>: ArrayLength<u8>,
374{
375 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
376 f.debug_struct("SigningKey").finish_non_exhaustive()
377 }
378}
379
380impl<C> Drop for SigningKey<C>
381where
382 C: PrimeCurve + CurveArithmetic,
383 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
384 SignatureSize<C>: ArrayLength<u8>,
385{
386 fn drop(&mut self) {
387 self.secret_scalar.zeroize();
388 }
389}
390
391impl<C> Eq for SigningKey<C>
393where
394 C: PrimeCurve + CurveArithmetic,
395 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
396 SignatureSize<C>: ArrayLength<u8>,
397{
398}
399impl<C> PartialEq for SigningKey<C>
400where
401 C: PrimeCurve + CurveArithmetic,
402 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
403 SignatureSize<C>: ArrayLength<u8>,
404{
405 fn eq(&self, other: &SigningKey<C>) -> bool {
406 self.ct_eq(other).into()
407 }
408}
409
410impl<C> From<NonZeroScalar<C>> for SigningKey<C>
411where
412 C: PrimeCurve + CurveArithmetic,
413 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
414 SignatureSize<C>: ArrayLength<u8>,
415{
416 fn from(secret_scalar: NonZeroScalar<C>) -> Self {
417 #[cfg(feature = "verifying")]
418 let public_key = PublicKey::from_secret_scalar(&secret_scalar);
419
420 Self {
421 secret_scalar,
422 #[cfg(feature = "verifying")]
423 verifying_key: public_key.into(),
424 }
425 }
426}
427
428impl<C> From<SecretKey<C>> for SigningKey<C>
429where
430 C: PrimeCurve + CurveArithmetic,
431 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
432 SignatureSize<C>: ArrayLength<u8>,
433{
434 fn from(secret_key: SecretKey<C>) -> Self {
435 Self::from(&secret_key)
436 }
437}
438
439impl<C> From<&SecretKey<C>> for SigningKey<C>
440where
441 C: PrimeCurve + CurveArithmetic,
442 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
443 SignatureSize<C>: ArrayLength<u8>,
444{
445 fn from(secret_key: &SecretKey<C>) -> Self {
446 secret_key.to_nonzero_scalar().into()
447 }
448}
449
450impl<C> From<SigningKey<C>> for SecretKey<C>
451where
452 C: PrimeCurve + CurveArithmetic,
453 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
454 SignatureSize<C>: ArrayLength<u8>,
455{
456 fn from(key: SigningKey<C>) -> Self {
457 key.secret_scalar.into()
458 }
459}
460
461impl<C> From<&SigningKey<C>> for SecretKey<C>
462where
463 C: PrimeCurve + CurveArithmetic,
464 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
465 SignatureSize<C>: ArrayLength<u8>,
466{
467 fn from(secret_key: &SigningKey<C>) -> Self {
468 secret_key.secret_scalar.into()
469 }
470}
471
472impl<C> TryFrom<&[u8]> for SigningKey<C>
473where
474 C: PrimeCurve + CurveArithmetic,
475 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
476 SignatureSize<C>: ArrayLength<u8>,
477{
478 type Error = Error;
479
480 fn try_from(bytes: &[u8]) -> Result<Self> {
481 Self::from_slice(bytes)
482 }
483}
484
485impl<C> ZeroizeOnDrop for SigningKey<C>
486where
487 C: PrimeCurve + CurveArithmetic,
488 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
489 SignatureSize<C>: ArrayLength<u8>,
490{
491}
492
493#[cfg(feature = "verifying")]
494impl<C> From<SigningKey<C>> for VerifyingKey<C>
495where
496 C: PrimeCurve + CurveArithmetic,
497 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
498 SignatureSize<C>: ArrayLength<u8>,
499{
500 fn from(signing_key: SigningKey<C>) -> VerifyingKey<C> {
501 signing_key.verifying_key
502 }
503}
504
505#[cfg(feature = "verifying")]
506impl<C> From<&SigningKey<C>> for VerifyingKey<C>
507where
508 C: PrimeCurve + CurveArithmetic,
509 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
510 SignatureSize<C>: ArrayLength<u8>,
511{
512 fn from(signing_key: &SigningKey<C>) -> VerifyingKey<C> {
513 signing_key.verifying_key
514 }
515}
516
517#[cfg(feature = "verifying")]
518impl<C> KeypairRef for SigningKey<C>
519where
520 C: PrimeCurve + CurveArithmetic,
521 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
522 SignatureSize<C>: ArrayLength<u8>,
523{
524 type VerifyingKey = VerifyingKey<C>;
525}
526
527#[cfg(feature = "pkcs8")]
528impl<C> AssociatedAlgorithmIdentifier for SigningKey<C>
529where
530 C: AssociatedOid + CurveArithmetic + PrimeCurve,
531 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
532 SignatureSize<C>: ArrayLength<u8>,
533{
534 type Params = ObjectIdentifier;
535
536 const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> =
537 SecretKey::<C>::ALGORITHM_IDENTIFIER;
538}
539
540#[cfg(feature = "pkcs8")]
541impl<C> SignatureAlgorithmIdentifier for SigningKey<C>
542where
543 C: PrimeCurve + CurveArithmetic,
544 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
545 SignatureSize<C>: ArrayLength<u8>,
546 Signature<C>: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
547{
548 type Params = AnyRef<'static>;
549
550 const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
551 Signature::<C>::ALGORITHM_IDENTIFIER;
552}
553
554#[cfg(feature = "pkcs8")]
555impl<C> TryFrom<pkcs8::PrivateKeyInfo<'_>> for SigningKey<C>
556where
557 C: PrimeCurve + AssociatedOid + CurveArithmetic,
558 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
559 FieldBytesSize<C>: sec1::ModulusSize,
560 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
561 SignatureSize<C>: ArrayLength<u8>,
562{
563 type Error = pkcs8::Error;
564
565 fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> {
566 SecretKey::try_from(private_key_info).map(Into::into)
567 }
568}
569
570#[cfg(feature = "pem")]
571impl<C> EncodePrivateKey for SigningKey<C>
572where
573 C: AssociatedOid + PrimeCurve + CurveArithmetic,
574 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
575 FieldBytesSize<C>: sec1::ModulusSize,
576 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
577 SignatureSize<C>: ArrayLength<u8>,
578{
579 fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
580 SecretKey::from(self.secret_scalar).to_pkcs8_der()
581 }
582}
583
584#[cfg(feature = "pem")]
585impl<C> FromStr for SigningKey<C>
586where
587 C: PrimeCurve + AssociatedOid + CurveArithmetic,
588 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
589 FieldBytesSize<C>: sec1::ModulusSize,
590 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
591 SignatureSize<C>: ArrayLength<u8>,
592{
593 type Err = Error;
594
595 fn from_str(s: &str) -> Result<Self> {
596 Self::from_pkcs8_pem(s).map_err(|_| Error::new())
597 }
598}