ecdsa/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_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//! ## `serde` support
27//!
28//! When the `serde` feature of this crate is enabled, `Serialize` and
29//! `Deserialize` impls are provided for the [`Signature`] and [`VerifyingKey`]
30//! types.
31//!
32//! Please see type-specific documentation for more information.
33//!
34//! ## Interop
35//!
36//! Any crates which provide an implementation of ECDSA for a particular
37//! elliptic curve can leverage the types from this crate, along with the
38//! [`k256`], [`p256`], and/or [`p384`] crates to expose ECDSA functionality in
39//! a generic, interoperable way by leveraging the [`Signature`] type with in
40//! conjunction with the [`signature::Signer`] and [`signature::Verifier`]
41//! traits.
42//!
43//! For example, the [`ring-compat`] crate implements the [`signature::Signer`]
44//! and [`signature::Verifier`] traits in conjunction with the
45//! [`p256::ecdsa::Signature`] and [`p384::ecdsa::Signature`] types to
46//! wrap the ECDSA implementations from [*ring*] in a generic, interoperable
47//! API.
48//!
49//! [`k256`]: https://docs.rs/k256
50//! [`p256`]: https://docs.rs/p256
51//! [`p256::ecdsa::Signature`]: https://docs.rs/p256/latest/p256/ecdsa/type.Signature.html
52//! [`p384`]: https://docs.rs/p384
53//! [`p384::ecdsa::Signature`]: https://docs.rs/p384/latest/p384/ecdsa/type.Signature.html
54//! [`ring-compat`]: https://docs.rs/ring-compat
55//! [*ring*]: https://docs.rs/ring
56
57#[cfg(feature = "alloc")]
58extern crate alloc;
59
60mod recovery;
61
62#[cfg(feature = "der")]
63#[cfg_attr(docsrs, doc(cfg(feature = "der")))]
64pub mod der;
65
66#[cfg(feature = "dev")]
67#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
68pub mod dev;
69
70#[cfg(feature = "hazmat")]
71#[cfg_attr(docsrs, doc(cfg(feature = "hazmat")))]
72pub mod hazmat;
73
74#[cfg(feature = "sign")]
75mod sign;
76
77#[cfg(feature = "verify")]
78mod verify;
79
80pub use crate::recovery::RecoveryId;
81
82// Re-export the `elliptic-curve` crate (and select types)
83pub use elliptic_curve::{self, sec1::EncodedPoint, PrimeCurve};
84
85// Re-export the `signature` crate (and select types)
86pub use signature::{self, Error, Result};
87
88#[cfg(feature = "sign")]
89#[cfg_attr(docsrs, doc(cfg(feature = "sign")))]
90pub use crate::sign::SigningKey;
91
92#[cfg(feature = "verify")]
93#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
94pub use crate::verify::VerifyingKey;
95
96use core::{
97    fmt::{self, Debug},
98    ops::Add,
99};
100use elliptic_curve::{
101    bigint::Encoding as _,
102    generic_array::{sequence::Concat, ArrayLength, GenericArray},
103    FieldBytes, FieldSize, ScalarCore,
104};
105
106#[cfg(feature = "alloc")]
107use alloc::vec::Vec;
108
109#[cfg(feature = "arithmetic")]
110use {
111    core::str,
112    elliptic_curve::{ff::PrimeField, IsHigh, NonZeroScalar, ScalarArithmetic},
113};
114
115#[cfg(feature = "serde")]
116use serdect::serde::{de, ser, Deserialize, Serialize};
117
118/// Size of a fixed sized signature for the given elliptic curve.
119pub type SignatureSize<C> = <FieldSize<C> as Add>::Output;
120
121/// Fixed-size byte array containing an ECDSA signature
122pub type SignatureBytes<C> = GenericArray<u8, SignatureSize<C>>;
123
124/// ECDSA signature (fixed-size). Generic over elliptic curve types.
125///
126/// Serialized as fixed-sized big endian scalar values with no added framing:
127///
128/// - `r`: field element size for the given curve, big-endian
129/// - `s`: field element size for the given curve, big-endian
130///
131/// For example, in a curve with a 256-bit modulus like NIST P-256 or
132/// secp256k1, `r` and `s` will both be 32-bytes, resulting in a signature
133/// with a total of 64-bytes.
134///
135/// ASN.1 DER-encoded signatures also supported via the
136/// [`Signature::from_der`] and [`Signature::to_der`] methods.
137///
138/// # `serde` support
139///
140/// When the `serde` feature of this crate is enabled, it provides support for
141/// serializing and deserializing ECDSA signatures using the `Serialize` and
142/// `Deserialize` traits.
143///
144/// The serialization uses a 64-byte fixed encoding when used with binary
145/// formats, and a hexadecimal encoding when used with text formats.
146#[derive(Clone, Eq, PartialEq)]
147pub struct Signature<C: PrimeCurve>
148where
149    SignatureSize<C>: ArrayLength<u8>,
150{
151    bytes: SignatureBytes<C>,
152}
153
154impl<C> Signature<C>
155where
156    C: PrimeCurve,
157    SignatureSize<C>: ArrayLength<u8>,
158{
159    /// Parse a signature from ASN.1 DER
160    #[cfg(feature = "der")]
161    #[cfg_attr(docsrs, doc(cfg(feature = "der")))]
162    pub fn from_der(bytes: &[u8]) -> Result<Self>
163    where
164        der::MaxSize<C>: ArrayLength<u8>,
165        <FieldSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
166    {
167        der::Signature::<C>::try_from(bytes).and_then(Self::try_from)
168    }
169
170    /// Create a [`Signature`] from the serialized `r` and `s` scalar values
171    /// which comprise the signature.
172    pub fn from_scalars(r: impl Into<FieldBytes<C>>, s: impl Into<FieldBytes<C>>) -> Result<Self> {
173        Self::try_from(r.into().concat(s.into()).as_slice())
174    }
175
176    /// Split the signature into its `r` and `s` components, represented as bytes.
177    pub fn split_bytes(&self) -> (FieldBytes<C>, FieldBytes<C>) {
178        let (r_bytes, s_bytes) = self.bytes.split_at(C::UInt::BYTE_SIZE);
179
180        (
181            GenericArray::clone_from_slice(r_bytes),
182            GenericArray::clone_from_slice(s_bytes),
183        )
184    }
185
186    /// Serialize this signature as ASN.1 DER
187    #[cfg(feature = "der")]
188    #[cfg_attr(docsrs, doc(cfg(feature = "der")))]
189    pub fn to_der(&self) -> der::Signature<C>
190    where
191        der::MaxSize<C>: ArrayLength<u8>,
192        <FieldSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
193    {
194        let (r, s) = self.bytes.split_at(C::UInt::BYTE_SIZE);
195        der::Signature::from_scalar_bytes(r, s).expect("DER encoding error")
196    }
197
198    /// Convert this signature into a byte vector.
199    #[cfg(feature = "alloc")]
200    #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
201    pub fn to_vec(&self) -> Vec<u8> {
202        self.bytes.to_vec()
203    }
204}
205
206#[cfg(feature = "arithmetic")]
207#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
208impl<C> Signature<C>
209where
210    C: PrimeCurve + ScalarArithmetic,
211    SignatureSize<C>: ArrayLength<u8>,
212{
213    /// Get the `r` component of this signature
214    pub fn r(&self) -> NonZeroScalar<C> {
215        NonZeroScalar::try_from(self.split_bytes().0.as_slice())
216            .expect("r-component ensured valid in constructor")
217    }
218
219    /// Get the `s` component of this signature
220    pub fn s(&self) -> NonZeroScalar<C> {
221        NonZeroScalar::try_from(self.split_bytes().1.as_slice())
222            .expect("s-component ensured valid in constructor")
223    }
224
225    /// Split the signature into its `r` and `s` scalars.
226    pub fn split_scalars(&self) -> (NonZeroScalar<C>, NonZeroScalar<C>) {
227        (self.r(), self.s())
228    }
229
230    /// Normalize signature into "low S" form as described in
231    /// [BIP 0062: Dealing with Malleability][1].
232    ///
233    /// [1]: https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki
234    pub fn normalize_s(&self) -> Option<Self> {
235        let s = self.s();
236
237        if s.is_high().into() {
238            let neg_s = -s;
239            let mut result = self.clone();
240            result.bytes[C::UInt::BYTE_SIZE..].copy_from_slice(&neg_s.to_repr());
241            Some(result)
242        } else {
243            None
244        }
245    }
246}
247
248impl<C> signature::Signature for Signature<C>
249where
250    C: PrimeCurve,
251    SignatureSize<C>: ArrayLength<u8>,
252{
253    fn from_bytes(bytes: &[u8]) -> Result<Self> {
254        Self::try_from(bytes)
255    }
256}
257
258impl<C> AsRef<[u8]> for Signature<C>
259where
260    C: PrimeCurve,
261    SignatureSize<C>: ArrayLength<u8>,
262{
263    fn as_ref(&self) -> &[u8] {
264        self.bytes.as_slice()
265    }
266}
267
268impl<C> Copy for Signature<C>
269where
270    C: PrimeCurve,
271    SignatureSize<C>: ArrayLength<u8>,
272    <SignatureSize<C> as ArrayLength<u8>>::ArrayType: Copy,
273{
274}
275
276impl<C> Debug for Signature<C>
277where
278    C: PrimeCurve,
279    SignatureSize<C>: ArrayLength<u8>,
280{
281    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
282        write!(f, "ecdsa::Signature<{:?}>(", C::default())?;
283
284        for &byte in self.as_ref() {
285            write!(f, "{:02X}", byte)?;
286        }
287
288        write!(f, ")")
289    }
290}
291
292impl<C> TryFrom<&[u8]> for Signature<C>
293where
294    C: PrimeCurve,
295    SignatureSize<C>: ArrayLength<u8>,
296{
297    type Error = Error;
298
299    fn try_from(bytes: &[u8]) -> Result<Self> {
300        if bytes.len() != C::UInt::BYTE_SIZE * 2 {
301            return Err(Error::new());
302        }
303
304        for scalar_bytes in bytes.chunks_exact(C::UInt::BYTE_SIZE) {
305            let scalar = ScalarCore::<C>::from_be_slice(scalar_bytes).map_err(|_| Error::new())?;
306
307            if scalar.is_zero().into() {
308                return Err(Error::new());
309            }
310        }
311
312        Ok(Self {
313            bytes: GenericArray::clone_from_slice(bytes),
314        })
315    }
316}
317
318impl<C> fmt::Display for Signature<C>
319where
320    C: PrimeCurve,
321    SignatureSize<C>: ArrayLength<u8>,
322{
323    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
324        write!(f, "{:X}", self)
325    }
326}
327
328impl<C> fmt::LowerHex for Signature<C>
329where
330    C: PrimeCurve,
331    SignatureSize<C>: ArrayLength<u8>,
332{
333    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
334        for byte in &self.bytes {
335            write!(f, "{:02x}", byte)?;
336        }
337        Ok(())
338    }
339}
340
341impl<C> fmt::UpperHex for Signature<C>
342where
343    C: PrimeCurve,
344    SignatureSize<C>: ArrayLength<u8>,
345{
346    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347        for byte in &self.bytes {
348            write!(f, "{:02X}", byte)?;
349        }
350        Ok(())
351    }
352}
353
354#[cfg(feature = "arithmetic")]
355#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
356impl<C> str::FromStr for Signature<C>
357where
358    C: PrimeCurve + ScalarArithmetic,
359    SignatureSize<C>: ArrayLength<u8>,
360{
361    type Err = Error;
362
363    fn from_str(hex: &str) -> Result<Self> {
364        if hex.as_bytes().len() != C::UInt::BYTE_SIZE * 4 {
365            return Err(Error::new());
366        }
367
368        // This check is mainly to ensure `hex.split_at` below won't panic
369        if !hex
370            .as_bytes()
371            .iter()
372            .all(|&byte| matches!(byte, b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z'))
373        {
374            return Err(Error::new());
375        }
376
377        let (r_hex, s_hex) = hex.split_at(C::UInt::BYTE_SIZE * 2);
378
379        let r = r_hex
380            .parse::<NonZeroScalar<C>>()
381            .map_err(|_| Error::new())?;
382
383        let s = s_hex
384            .parse::<NonZeroScalar<C>>()
385            .map_err(|_| Error::new())?;
386
387        Self::from_scalars(r, s)
388    }
389}
390
391#[cfg(feature = "serde")]
392#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
393impl<C> Serialize for Signature<C>
394where
395    C: PrimeCurve,
396    SignatureSize<C>: ArrayLength<u8>,
397{
398    fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
399    where
400        S: ser::Serializer,
401    {
402        serdect::array::serialize_hex_upper_or_bin(&self.bytes, serializer)
403    }
404}
405
406#[cfg(feature = "serde")]
407#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
408impl<'de, C> Deserialize<'de> for Signature<C>
409where
410    C: PrimeCurve,
411    SignatureSize<C>: ArrayLength<u8>,
412{
413    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
414    where
415        D: de::Deserializer<'de>,
416    {
417        let mut bytes = SignatureBytes::<C>::default();
418        serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?;
419        Self::try_from(bytes.as_slice()).map_err(de::Error::custom)
420    }
421}