p256/
ecdsa.rs

1//! Elliptic Curve Digital Signature Algorithm (ECDSA)
2//!
3//! This module contains support for computing and verifying ECDSA signatures.
4//! To use it, you will need to enable one of the two following Cargo features:
5//!
6//! - `ecdsa-core`: provides only the [`Signature`] type (which represents an
7//!   ECDSA/P-256 signature). Does not require the `arithmetic` feature.
8//!   This is useful for 3rd-party crates which wish to use the `Signature`
9//!   type for interoperability purposes (particularly in conjunction with the
10//!   [`signature::Signer`] trait. Example use cases for this include other
11//!   software implementations of ECDSA/P-256 and wrappers for cloud KMS
12//!   services or hardware devices (HSM or crypto hardware wallet).
13//! - `ecdsa`: provides `ecdsa-core` features plus the [`SigningKey`] and
14//!   [`VerifyingKey`] types which natively implement ECDSA/P-256 signing and
15//!   verification.
16//!
17//! ## Signing/Verification Example
18//!
19//! This example requires the `ecdsa` Cargo feature is enabled:
20//!
21//! ```
22//! # #[cfg(feature = "ecdsa")]
23//! # {
24//! use p256::{
25//!     ecdsa::{SigningKey, Signature, signature::Signer},
26//! };
27//! use rand_core::OsRng; // requires 'getrandom' feature
28//!
29//! // Signing
30//! let signing_key = SigningKey::random(&mut OsRng); // Serialize with `::to_bytes()`
31//! let message = b"ECDSA proves knowledge of a secret number in the context of a single message";
32//! let signature = signing_key.sign(message);
33//!
34//! // Verification
35//! use p256::ecdsa::{VerifyingKey, signature::Verifier};
36//!
37//! let verifying_key = VerifyingKey::from(&signing_key); // Serialize with `::to_encoded_point()`
38//! assert!(verifying_key.verify(message, &signature).is_ok());
39//! # }
40//! ```
41
42pub use ecdsa_core::signature::{self, Error};
43
44use super::NistP256;
45
46#[cfg(feature = "ecdsa")]
47use {
48    crate::{AffinePoint, Scalar},
49    ecdsa_core::hazmat::{SignPrimitive, VerifyPrimitive},
50};
51
52/// ECDSA/P-256 signature (fixed-size)
53pub type Signature = ecdsa_core::Signature<NistP256>;
54
55/// ECDSA/P-256 signature (ASN.1 DER encoded)
56pub type DerSignature = ecdsa_core::der::Signature<NistP256>;
57
58/// ECDSA/P-256 signing key
59#[cfg(feature = "ecdsa")]
60#[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
61pub type SigningKey = ecdsa_core::SigningKey<NistP256>;
62
63/// ECDSA/P-256 verification key (i.e. public key)
64#[cfg(feature = "ecdsa")]
65#[cfg_attr(docsrs, doc(cfg(feature = "ecdsa")))]
66pub type VerifyingKey = ecdsa_core::VerifyingKey<NistP256>;
67
68#[cfg(feature = "sha256")]
69#[cfg_attr(docsrs, doc(cfg(feature = "sha256")))]
70impl ecdsa_core::hazmat::DigestPrimitive for NistP256 {
71    type Digest = sha2::Sha256;
72}
73
74#[cfg(feature = "ecdsa")]
75impl SignPrimitive<NistP256> for Scalar {}
76
77#[cfg(feature = "ecdsa")]
78impl VerifyPrimitive<NistP256> for AffinePoint {}
79
80#[cfg(all(test, feature = "ecdsa"))]
81mod tests {
82    use crate::{
83        ecdsa::{signature::Signer, SigningKey},
84        test_vectors::ecdsa::ECDSA_TEST_VECTORS,
85        BlindedScalar, Scalar,
86    };
87    use ecdsa_core::hazmat::SignPrimitive;
88    use elliptic_curve::{generic_array::GenericArray, group::ff::PrimeField, rand_core::OsRng};
89    use hex_literal::hex;
90
91    // Test vector from RFC 6979 Appendix 2.5 (NIST P-256 + SHA-256)
92    // <https://tools.ietf.org/html/rfc6979#appendix-A.2.5>
93    #[test]
94    fn rfc6979() {
95        let x = &hex!("c9afa9d845ba75166b5c215767b1d6934e50c3db36e89b127b8a622b120f6721");
96        let signer = SigningKey::from_bytes(x).unwrap();
97        let signature = signer.sign(b"sample");
98        assert_eq!(
99            signature.as_ref(),
100            &hex!(
101                "efd48b2aacb6a8fd1140dd9cd45e81d69d2c877b56aaf991c34d0ea84eaf3716
102                     f7cb1c942d657c41d436c7a1b6e29f65f3e900dbb9aff4064dc4ab2f843acda8"
103            )[..]
104        );
105        let signature = signer.sign(b"test");
106        assert_eq!(
107            signature.as_ref(),
108            &hex!(
109                "f1abb023518351cd71d881567b1ea663ed3efcf6c5132b354f28d3b0b7d38367
110                019f4113742a2b14bd25926b49c649155f267e60d3814b4c0cc84250e46f0083"
111            )[..]
112        );
113    }
114
115    #[test]
116    fn scalar_blinding() {
117        let vector = &ECDSA_TEST_VECTORS[0];
118        let d = Scalar::from_repr(GenericArray::clone_from_slice(vector.d)).unwrap();
119        let k = Scalar::from_repr(GenericArray::clone_from_slice(vector.k)).unwrap();
120        let k_blinded = BlindedScalar::new(k, &mut OsRng);
121        let z = GenericArray::clone_from_slice(vector.m);
122        let sig = d.try_sign_prehashed(k_blinded, z).unwrap().0;
123
124        assert_eq!(vector.r, sig.r().to_bytes().as_slice());
125        assert_eq!(vector.s, sig.s().to_bytes().as_slice());
126    }
127
128    mod sign {
129        use crate::{test_vectors::ecdsa::ECDSA_TEST_VECTORS, NistP256};
130        ecdsa_core::new_signing_test!(NistP256, ECDSA_TEST_VECTORS);
131    }
132
133    mod verify {
134        use crate::{test_vectors::ecdsa::ECDSA_TEST_VECTORS, NistP256};
135        ecdsa_core::new_verification_test!(NistP256, ECDSA_TEST_VECTORS);
136    }
137
138    mod wycheproof {
139        use crate::NistP256;
140        ecdsa_core::new_wycheproof_test!(wycheproof, "wycheproof", NistP256);
141    }
142}