1#![no_std]
2#![cfg_attr(docsrs, feature(doc_auto_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
6    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
7)]
8#![forbid(unsafe_code)]
9#![warn(
10    clippy::cast_lossless,
11    clippy::cast_possible_truncation,
12    clippy::cast_possible_wrap,
13    clippy::cast_precision_loss,
14    clippy::cast_sign_loss,
15    clippy::checked_conversions,
16    clippy::implicit_saturating_sub,
17    clippy::panic,
18    clippy::panic_in_result_fn,
19    clippy::unwrap_used,
20    missing_docs,
21    rust_2018_idioms,
22    unused_lifetimes,
23    unused_qualifications
24)]
25
26#[cfg(feature = "alloc")]
58extern crate alloc;
59
60mod normalized;
61mod recovery;
62
63#[cfg(feature = "der")]
64pub mod der;
65#[cfg(feature = "dev")]
66pub mod dev;
67#[cfg(feature = "hazmat")]
68pub mod hazmat;
69#[cfg(feature = "signing")]
70mod signing;
71#[cfg(feature = "verifying")]
72mod verifying;
73
74pub use crate::{normalized::NormalizedSignature, recovery::RecoveryId};
75
76pub use elliptic_curve::{self, sec1::EncodedPoint, PrimeCurve};
78
79pub use signature::{self, Error, Result, SignatureEncoding};
81
82#[cfg(feature = "signing")]
83pub use crate::signing::SigningKey;
84#[cfg(feature = "verifying")]
85pub use crate::verifying::VerifyingKey;
86
87use core::{fmt, ops::Add};
88use elliptic_curve::{
89    generic_array::{typenum::Unsigned, ArrayLength, GenericArray},
90    FieldBytes, FieldBytesSize, ScalarPrimitive,
91};
92
93#[cfg(feature = "alloc")]
94use alloc::vec::Vec;
95
96#[cfg(feature = "arithmetic")]
97use {
98    core::str,
99    elliptic_curve::{scalar::IsHigh, CurveArithmetic, NonZeroScalar},
100};
101
102#[cfg(feature = "digest")]
103use digest::{
104    const_oid::{AssociatedOid, ObjectIdentifier},
105    Digest,
106};
107
108#[cfg(feature = "pkcs8")]
109use elliptic_curve::pkcs8::spki::{
110    der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier,
111};
112
113#[cfg(feature = "serde")]
114use serdect::serde::{de, ser, Deserialize, Serialize};
115
116#[cfg(all(feature = "alloc", feature = "pkcs8"))]
117use elliptic_curve::pkcs8::spki::{
118    self, AlgorithmIdentifierOwned, DynAssociatedAlgorithmIdentifier,
119};
120
121#[cfg(feature = "digest")]
129pub const ECDSA_SHA224_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.1");
130
131#[cfg(feature = "digest")]
138pub const ECDSA_SHA256_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.2");
139
140#[cfg(feature = "digest")]
147pub const ECDSA_SHA384_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.3");
148
149#[cfg(feature = "digest")]
156pub const ECDSA_SHA512_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.4");
157
158#[cfg(feature = "digest")]
159const SHA224_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.4");
160#[cfg(feature = "digest")]
161const SHA256_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.1");
162#[cfg(feature = "digest")]
163const SHA384_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.2");
164#[cfg(feature = "digest")]
165const SHA512_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.3");
166
167pub type SignatureSize<C> = <FieldBytesSize<C> as Add>::Output;
169
170pub type SignatureBytes<C> = GenericArray<u8, SignatureSize<C>>;
172
173#[derive(Clone, Eq, PartialEq)]
198pub struct Signature<C: PrimeCurve> {
199    r: ScalarPrimitive<C>,
200    s: ScalarPrimitive<C>,
201}
202
203impl<C> Signature<C>
204where
205    C: PrimeCurve,
206    SignatureSize<C>: ArrayLength<u8>,
207{
208    pub fn from_bytes(bytes: &SignatureBytes<C>) -> Result<Self> {
217        let (r_bytes, s_bytes) = bytes.split_at(C::FieldBytesSize::USIZE);
218        let r = FieldBytes::<C>::clone_from_slice(r_bytes);
219        let s = FieldBytes::<C>::clone_from_slice(s_bytes);
220        Self::from_scalars(r, s)
221    }
222
223    pub fn from_slice(slice: &[u8]) -> Result<Self> {
225        if slice.len() == SignatureSize::<C>::USIZE {
226            Self::from_bytes(SignatureBytes::<C>::from_slice(slice))
227        } else {
228            Err(Error::new())
229        }
230    }
231
232    #[cfg(feature = "der")]
234    pub fn from_der(bytes: &[u8]) -> Result<Self>
235    where
236        der::MaxSize<C>: ArrayLength<u8>,
237        <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
238    {
239        der::Signature::<C>::try_from(bytes).and_then(Self::try_from)
240    }
241
242    pub fn from_scalars(r: impl Into<FieldBytes<C>>, s: impl Into<FieldBytes<C>>) -> Result<Self> {
251        let r = ScalarPrimitive::from_slice(&r.into()).map_err(|_| Error::new())?;
252        let s = ScalarPrimitive::from_slice(&s.into()).map_err(|_| Error::new())?;
253
254        if r.is_zero().into() || s.is_zero().into() {
255            return Err(Error::new());
256        }
257
258        Ok(Self { r, s })
259    }
260
261    pub fn split_bytes(&self) -> (FieldBytes<C>, FieldBytes<C>) {
263        (self.r.to_bytes(), self.s.to_bytes())
264    }
265
266    pub fn to_bytes(&self) -> SignatureBytes<C> {
268        let mut bytes = SignatureBytes::<C>::default();
269        let (r_bytes, s_bytes) = bytes.split_at_mut(C::FieldBytesSize::USIZE);
270        r_bytes.copy_from_slice(&self.r.to_bytes());
271        s_bytes.copy_from_slice(&self.s.to_bytes());
272        bytes
273    }
274
275    #[cfg(feature = "der")]
277    pub fn to_der(&self) -> der::Signature<C>
278    where
279        der::MaxSize<C>: ArrayLength<u8>,
280        <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
281    {
282        let (r, s) = self.split_bytes();
283        der::Signature::from_components(&r, &s).expect("DER encoding error")
284    }
285
286    #[cfg(feature = "alloc")]
288    pub fn to_vec(&self) -> Vec<u8> {
289        self.to_bytes().to_vec()
290    }
291}
292
293#[cfg(feature = "arithmetic")]
294impl<C> Signature<C>
295where
296    C: PrimeCurve + CurveArithmetic,
297    SignatureSize<C>: ArrayLength<u8>,
298{
299    pub fn r(&self) -> NonZeroScalar<C> {
301        NonZeroScalar::new(self.r.into()).unwrap()
302    }
303
304    pub fn s(&self) -> NonZeroScalar<C> {
306        NonZeroScalar::new(self.s.into()).unwrap()
307    }
308
309    pub fn split_scalars(&self) -> (NonZeroScalar<C>, NonZeroScalar<C>) {
311        (self.r(), self.s())
312    }
313
314    pub fn normalize_s(&self) -> Option<Self> {
319        let s = self.s();
320
321        if s.is_high().into() {
322            let mut result = self.clone();
323            result.s = ScalarPrimitive::from(-s);
324            Some(result)
325        } else {
326            None
327        }
328    }
329}
330
331impl<C> Copy for Signature<C>
332where
333    C: PrimeCurve,
334    SignatureSize<C>: ArrayLength<u8>,
335    <SignatureSize<C> as ArrayLength<u8>>::ArrayType: Copy,
336{
337}
338
339impl<C> From<Signature<C>> for SignatureBytes<C>
340where
341    C: PrimeCurve,
342    SignatureSize<C>: ArrayLength<u8>,
343{
344    fn from(signature: Signature<C>) -> SignatureBytes<C> {
345        signature.to_bytes()
346    }
347}
348
349impl<C> SignatureEncoding for Signature<C>
350where
351    C: PrimeCurve,
352    SignatureSize<C>: ArrayLength<u8>,
353{
354    type Repr = SignatureBytes<C>;
355}
356
357impl<C> TryFrom<&[u8]> for Signature<C>
358where
359    C: PrimeCurve,
360    SignatureSize<C>: ArrayLength<u8>,
361{
362    type Error = Error;
363
364    fn try_from(slice: &[u8]) -> Result<Self> {
365        Self::from_slice(slice)
366    }
367}
368
369impl<C> fmt::Debug for Signature<C>
370where
371    C: PrimeCurve,
372    SignatureSize<C>: ArrayLength<u8>,
373{
374    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
375        write!(f, "ecdsa::Signature<{:?}>(", C::default())?;
376
377        for byte in self.to_bytes() {
378            write!(f, "{:02X}", byte)?;
379        }
380
381        write!(f, ")")
382    }
383}
384
385impl<C> fmt::Display for Signature<C>
386where
387    C: PrimeCurve,
388    SignatureSize<C>: ArrayLength<u8>,
389{
390    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391        write!(f, "{:X}", self)
392    }
393}
394
395impl<C> fmt::LowerHex for Signature<C>
396where
397    C: PrimeCurve,
398    SignatureSize<C>: ArrayLength<u8>,
399{
400    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
401        for byte in self.to_bytes() {
402            write!(f, "{:02x}", byte)?;
403        }
404        Ok(())
405    }
406}
407
408impl<C> fmt::UpperHex for Signature<C>
409where
410    C: PrimeCurve,
411    SignatureSize<C>: ArrayLength<u8>,
412{
413    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
414        for byte in self.to_bytes() {
415            write!(f, "{:02X}", byte)?;
416        }
417        Ok(())
418    }
419}
420
421#[cfg(feature = "arithmetic")]
422impl<C> str::FromStr for Signature<C>
423where
424    C: PrimeCurve + CurveArithmetic,
425    SignatureSize<C>: ArrayLength<u8>,
426{
427    type Err = Error;
428
429    fn from_str(hex: &str) -> Result<Self> {
430        if hex.as_bytes().len() != C::FieldBytesSize::USIZE * 4 {
431            return Err(Error::new());
432        }
433
434        if !hex
436            .as_bytes()
437            .iter()
438            .all(|&byte| matches!(byte, b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z'))
439        {
440            return Err(Error::new());
441        }
442
443        let (r_hex, s_hex) = hex.split_at(C::FieldBytesSize::USIZE * 2);
444
445        let r = r_hex
446            .parse::<NonZeroScalar<C>>()
447            .map_err(|_| Error::new())?;
448
449        let s = s_hex
450            .parse::<NonZeroScalar<C>>()
451            .map_err(|_| Error::new())?;
452
453        Self::from_scalars(r, s)
454    }
455}
456
457#[cfg(all(feature = "digest", feature = "hazmat"))]
463impl<C> AssociatedOid for Signature<C>
464where
465    C: hazmat::DigestPrimitive,
466    C::Digest: AssociatedOid,
467{
468    const OID: ObjectIdentifier = match ecdsa_oid_for_digest(C::Digest::OID) {
469        Some(oid) => oid,
470        None => panic!("no RFC5758 ECDSA OID defined for DigestPrimitive::Digest"),
471    };
472}
473
474#[cfg(feature = "pkcs8")]
477impl<C> AssociatedAlgorithmIdentifier for Signature<C>
478where
479    C: PrimeCurve,
480    Self: AssociatedOid,
481{
482    type Params = AnyRef<'static>;
483
484    const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = AlgorithmIdentifierRef {
485        oid: Self::OID,
486        parameters: None,
487    };
488}
489
490#[cfg(feature = "serde")]
491impl<C> Serialize for Signature<C>
492where
493    C: PrimeCurve,
494    SignatureSize<C>: ArrayLength<u8>,
495{
496    fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
497    where
498        S: ser::Serializer,
499    {
500        serdect::array::serialize_hex_upper_or_bin(&self.to_bytes(), serializer)
501    }
502}
503
504#[cfg(feature = "serde")]
505impl<'de, C> Deserialize<'de> for Signature<C>
506where
507    C: PrimeCurve,
508    SignatureSize<C>: ArrayLength<u8>,
509{
510    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
511    where
512        D: de::Deserializer<'de>,
513    {
514        let mut bytes = SignatureBytes::<C>::default();
515        serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?;
516        Self::try_from(bytes.as_slice()).map_err(de::Error::custom)
517    }
518}
519
520#[cfg(feature = "digest")]
533#[derive(Clone, Eq, PartialEq)]
534pub struct SignatureWithOid<C: PrimeCurve> {
535    signature: Signature<C>,
537
538    oid: ObjectIdentifier,
544}
545
546#[cfg(feature = "digest")]
547impl<C> SignatureWithOid<C>
548where
549    C: PrimeCurve,
550{
551    pub fn new(signature: Signature<C>, oid: ObjectIdentifier) -> Result<Self> {
558        for (arc1, arc2) in ObjectIdentifier::new_unwrap("1.2.840.10045.4.3")
560            .arcs()
561            .zip(oid.arcs())
562        {
563            if arc1 != arc2 {
564                return Err(Error::new());
565            }
566        }
567
568        Ok(Self { signature, oid })
569    }
570
571    pub fn new_with_digest<D>(signature: Signature<C>) -> Result<Self>
578    where
579        D: AssociatedOid + Digest,
580    {
581        let oid = ecdsa_oid_for_digest(D::OID).ok_or_else(Error::new)?;
582        Ok(Self { signature, oid })
583    }
584
585    pub fn from_bytes_with_digest<D>(bytes: &SignatureBytes<C>) -> Result<Self>
587    where
588        D: AssociatedOid + Digest,
589        SignatureSize<C>: ArrayLength<u8>,
590    {
591        Self::new_with_digest::<D>(Signature::<C>::from_bytes(bytes)?)
592    }
593
594    pub fn from_slice_with_digest<D>(slice: &[u8]) -> Result<Self>
596    where
597        D: AssociatedOid + Digest,
598        SignatureSize<C>: ArrayLength<u8>,
599    {
600        Self::new_with_digest::<D>(Signature::<C>::from_slice(slice)?)
601    }
602
603    pub fn signature(&self) -> &Signature<C> {
605        &self.signature
606    }
607
608    pub fn oid(&self) -> ObjectIdentifier {
610        self.oid
611    }
612
613    pub fn to_bytes(&self) -> SignatureBytes<C>
615    where
616        SignatureSize<C>: ArrayLength<u8>,
617    {
618        self.signature.to_bytes()
619    }
620}
621
622#[cfg(feature = "digest")]
623impl<C> Copy for SignatureWithOid<C>
624where
625    C: PrimeCurve,
626    SignatureSize<C>: ArrayLength<u8>,
627    <SignatureSize<C> as ArrayLength<u8>>::ArrayType: Copy,
628{
629}
630
631#[cfg(feature = "digest")]
632impl<C> From<SignatureWithOid<C>> for Signature<C>
633where
634    C: PrimeCurve,
635{
636    fn from(sig: SignatureWithOid<C>) -> Signature<C> {
637        sig.signature
638    }
639}
640
641#[cfg(feature = "digest")]
642impl<C> From<SignatureWithOid<C>> for SignatureBytes<C>
643where
644    C: PrimeCurve,
645    SignatureSize<C>: ArrayLength<u8>,
646{
647    fn from(signature: SignatureWithOid<C>) -> SignatureBytes<C> {
648        signature.to_bytes()
649    }
650}
651
652#[cfg(all(feature = "digest", feature = "hazmat"))]
658impl<C> SignatureEncoding for SignatureWithOid<C>
659where
660    C: hazmat::DigestPrimitive,
661    C::Digest: AssociatedOid,
662    SignatureSize<C>: ArrayLength<u8>,
663{
664    type Repr = SignatureBytes<C>;
665}
666
667#[cfg(all(feature = "digest", feature = "hazmat"))]
673impl<C> TryFrom<&[u8]> for SignatureWithOid<C>
674where
675    C: hazmat::DigestPrimitive,
676    C::Digest: AssociatedOid,
677    SignatureSize<C>: ArrayLength<u8>,
678{
679    type Error = Error;
680
681    fn try_from(slice: &[u8]) -> Result<Self> {
682        Self::new(Signature::<C>::from_slice(slice)?, C::Digest::OID)
683    }
684}
685
686#[cfg(all(feature = "alloc", feature = "pkcs8"))]
687impl<C> DynAssociatedAlgorithmIdentifier for SignatureWithOid<C>
688where
689    C: PrimeCurve,
690{
691    fn algorithm_identifier(&self) -> spki::Result<AlgorithmIdentifierOwned> {
692        Ok(AlgorithmIdentifierOwned {
693            oid: self.oid,
694            parameters: None,
695        })
696    }
697}
698
699#[cfg(feature = "digest")]
701const fn ecdsa_oid_for_digest(digest_oid: ObjectIdentifier) -> Option<ObjectIdentifier> {
702    match digest_oid {
703        SHA224_OID => Some(ECDSA_SHA224_OID),
704        SHA256_OID => Some(ECDSA_SHA256_OID),
705        SHA384_OID => Some(ECDSA_SHA384_OID),
706        SHA512_OID => Some(ECDSA_SHA512_OID),
707        _ => None,
708    }
709}