summaryrefslogtreecommitdiffstats
path: root/vendor/ecdsa/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
commit10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch)
treebdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/ecdsa/src
parentReleasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff)
downloadrustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz
rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/ecdsa/src')
-rw-r--r--vendor/ecdsa/src/der.rs349
-rw-r--r--vendor/ecdsa/src/dev.rs221
-rw-r--r--vendor/ecdsa/src/hazmat.rs261
-rw-r--r--vendor/ecdsa/src/lib.rs421
-rw-r--r--vendor/ecdsa/src/recovery.rs110
-rw-r--r--vendor/ecdsa/src/sign.rs424
-rw-r--r--vendor/ecdsa/src/verify.rs325
7 files changed, 2111 insertions, 0 deletions
diff --git a/vendor/ecdsa/src/der.rs b/vendor/ecdsa/src/der.rs
new file mode 100644
index 000000000..5925df443
--- /dev/null
+++ b/vendor/ecdsa/src/der.rs
@@ -0,0 +1,349 @@
+//! Support for ECDSA signatures encoded as ASN.1 DER.
+
+use crate::{Error, Result};
+use core::{
+ fmt,
+ ops::{Add, Range},
+};
+use der::{asn1::UIntRef, Decode, Encode, Reader};
+use elliptic_curve::{
+ bigint::Encoding as _,
+ consts::U9,
+ generic_array::{ArrayLength, GenericArray},
+ FieldSize, PrimeCurve,
+};
+
+#[cfg(feature = "alloc")]
+use alloc::boxed::Box;
+
+#[cfg(feature = "serde")]
+use serdect::serde::{de, ser, Deserialize, Serialize};
+
+/// Maximum overhead of an ASN.1 DER-encoded ECDSA signature for a given curve:
+/// 9-bytes.
+///
+/// Includes 3-byte ASN.1 DER header:
+///
+/// - 1-byte: ASN.1 `SEQUENCE` tag (0x30)
+/// - 2-byte: length
+///
+/// ...followed by two ASN.1 `INTEGER` values, which each have a header whose
+/// maximum length is the following:
+///
+/// - 1-byte: ASN.1 `INTEGER` tag (0x02)
+/// - 1-byte: length
+/// - 1-byte: zero to indicate value is positive (`INTEGER` is signed)
+pub type MaxOverhead = U9;
+
+/// Maximum size of an ASN.1 DER encoded signature for the given elliptic curve.
+pub type MaxSize<C> = <<FieldSize<C> as Add>::Output as Add<MaxOverhead>>::Output;
+
+/// Byte array containing a serialized ASN.1 signature
+type SignatureBytes<C> = GenericArray<u8, MaxSize<C>>;
+
+/// ASN.1 DER-encoded signature.
+///
+/// Generic over the scalar size of the elliptic curve.
+pub struct Signature<C>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ /// ASN.1 DER-encoded signature data
+ bytes: SignatureBytes<C>,
+
+ /// Range of the `r` value within the signature
+ r_range: Range<usize>,
+
+ /// Range of the `s` value within the signature
+ s_range: Range<usize>,
+}
+
+impl<C> signature::Signature for Signature<C>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ /// Parse an ASN.1 DER-encoded ECDSA signature from a byte slice
+ fn from_bytes(bytes: &[u8]) -> Result<Self> {
+ bytes.try_into()
+ }
+}
+
+#[allow(clippy::len_without_is_empty)]
+impl<C> Signature<C>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ /// Get the length of the signature in bytes
+ pub fn len(&self) -> usize {
+ self.s_range.end
+ }
+
+ /// Borrow this signature as a byte slice
+ pub fn as_bytes(&self) -> &[u8] {
+ &self.bytes.as_slice()[..self.len()]
+ }
+
+ /// Serialize this signature as a boxed byte slice
+ #[cfg(feature = "alloc")]
+ pub fn to_bytes(&self) -> Box<[u8]> {
+ self.as_bytes().to_vec().into_boxed_slice()
+ }
+
+ /// Create an ASN.1 DER encoded signature from big endian `r` and `s` scalars
+ pub(crate) fn from_scalar_bytes(r: &[u8], s: &[u8]) -> der::Result<Self> {
+ let r = UIntRef::new(r)?;
+ let s = UIntRef::new(s)?;
+
+ let mut bytes = SignatureBytes::<C>::default();
+ let mut writer = der::SliceWriter::new(&mut bytes);
+
+ writer.sequence((r.encoded_len()? + s.encoded_len()?)?, |seq| {
+ seq.encode(&r)?;
+ seq.encode(&s)
+ })?;
+
+ writer
+ .finish()?
+ .try_into()
+ .map_err(|_| der::Tag::Sequence.value_error())
+ }
+
+ /// Get the `r` component of the signature (leading zeros removed)
+ pub(crate) fn r(&self) -> &[u8] {
+ &self.bytes[self.r_range.clone()]
+ }
+
+ /// Get the `s` component of the signature (leading zeros removed)
+ pub(crate) fn s(&self) -> &[u8] {
+ &self.bytes[self.s_range.clone()]
+ }
+}
+
+impl<C> AsRef<[u8]> for Signature<C>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ fn as_ref(&self) -> &[u8] {
+ self.as_bytes()
+ }
+}
+
+impl<C> fmt::Debug for Signature<C>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ecdsa::der::Signature<{:?}>(", C::default())?;
+
+ for &byte in self.as_ref() {
+ write!(f, "{:02X}", byte)?;
+ }
+
+ write!(f, ")")
+ }
+}
+
+impl<C> TryFrom<&[u8]> for Signature<C>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ type Error = Error;
+
+ fn try_from(input: &[u8]) -> Result<Self> {
+ let (r, s) = decode_der(input).map_err(|_| Error::new())?;
+
+ if r.as_bytes().len() > C::UInt::BYTE_SIZE || s.as_bytes().len() > C::UInt::BYTE_SIZE {
+ return Err(Error::new());
+ }
+
+ let r_range = find_scalar_range(input, r.as_bytes())?;
+ let s_range = find_scalar_range(input, s.as_bytes())?;
+
+ if s_range.end != input.len() {
+ return Err(Error::new());
+ }
+
+ let mut bytes = SignatureBytes::<C>::default();
+ bytes[..s_range.end].copy_from_slice(input);
+
+ Ok(Signature {
+ bytes,
+ r_range,
+ s_range,
+ })
+ }
+}
+
+impl<C> TryFrom<Signature<C>> for super::Signature<C>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ type Error = Error;
+
+ fn try_from(sig: Signature<C>) -> Result<super::Signature<C>> {
+ let mut bytes = super::SignatureBytes::<C>::default();
+ let r_begin = C::UInt::BYTE_SIZE.saturating_sub(sig.r().len());
+ let s_begin = bytes.len().saturating_sub(sig.s().len());
+ bytes[r_begin..C::UInt::BYTE_SIZE].copy_from_slice(sig.r());
+ bytes[s_begin..].copy_from_slice(sig.s());
+ Self::try_from(bytes.as_slice())
+ }
+}
+
+#[cfg(feature = "serde")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
+impl<C> Serialize for Signature<C>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ serdect::slice::serialize_hex_upper_or_bin(&self.as_bytes(), serializer)
+ }
+}
+
+#[cfg(feature = "serde")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
+impl<'de, C> Deserialize<'de> for Signature<C>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ let mut buf = SignatureBytes::<C>::default();
+ let slice = serdect::slice::deserialize_hex_or_bin(&mut buf, deserializer)?;
+ Self::try_from(slice).map_err(de::Error::custom)
+ }
+}
+
+/// Decode the `r` and `s` components of a DER-encoded ECDSA signature.
+fn decode_der(der_bytes: &[u8]) -> der::Result<(UIntRef<'_>, UIntRef<'_>)> {
+ let mut reader = der::SliceReader::new(der_bytes)?;
+ let header = der::Header::decode(&mut reader)?;
+ header.tag.assert_eq(der::Tag::Sequence)?;
+
+ let ret = reader.read_nested(header.length, |reader| {
+ let r = UIntRef::decode(reader)?;
+ let s = UIntRef::decode(reader)?;
+ Ok((r, s))
+ })?;
+
+ reader.finish(ret)
+}
+
+/// Locate the range within a slice at which a particular subslice is located
+fn find_scalar_range(outer: &[u8], inner: &[u8]) -> Result<Range<usize>> {
+ let outer_start = outer.as_ptr() as usize;
+ let inner_start = inner.as_ptr() as usize;
+ let start = inner_start
+ .checked_sub(outer_start)
+ .ok_or_else(Error::new)?;
+ let end = start.checked_add(inner.len()).ok_or_else(Error::new)?;
+ Ok(Range { start, end })
+}
+
+#[cfg(all(feature = "digest", feature = "hazmat"))]
+impl<C> signature::PrehashSignature for Signature<C>
+where
+ C: PrimeCurve + crate::hazmat::DigestPrimitive,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ type Digest = C::Digest;
+}
+
+#[cfg(all(test, feature = "arithmetic"))]
+mod tests {
+ use elliptic_curve::dev::MockCurve;
+ use signature::Signature as _;
+
+ type Signature = crate::Signature<MockCurve>;
+
+ const EXAMPLE_SIGNATURE: [u8; 64] = [
+ 0xf3, 0xac, 0x80, 0x61, 0xb5, 0x14, 0x79, 0x5b, 0x88, 0x43, 0xe3, 0xd6, 0x62, 0x95, 0x27,
+ 0xed, 0x2a, 0xfd, 0x6b, 0x1f, 0x6a, 0x55, 0x5a, 0x7a, 0xca, 0xbb, 0x5e, 0x6f, 0x79, 0xc8,
+ 0xc2, 0xac, 0x8b, 0xf7, 0x78, 0x19, 0xca, 0x5, 0xa6, 0xb2, 0x78, 0x6c, 0x76, 0x26, 0x2b,
+ 0xf7, 0x37, 0x1c, 0xef, 0x97, 0xb2, 0x18, 0xe9, 0x6f, 0x17, 0x5a, 0x3c, 0xcd, 0xda, 0x2a,
+ 0xcc, 0x5, 0x89, 0x3,
+ ];
+
+ #[test]
+ fn test_fixed_to_asn1_signature_roundtrip() {
+ let signature1 = Signature::from_bytes(&EXAMPLE_SIGNATURE).unwrap();
+
+ // Convert to ASN.1 DER and back
+ let asn1_signature = signature1.to_der();
+ let signature2 = Signature::from_der(asn1_signature.as_ref()).unwrap();
+
+ assert_eq!(signature1, signature2);
+ }
+
+ #[test]
+ fn test_asn1_too_short_signature() {
+ assert!(Signature::from_der(&[]).is_err());
+ assert!(Signature::from_der(&[der::Tag::Sequence.into()]).is_err());
+ assert!(Signature::from_der(&[der::Tag::Sequence.into(), 0x00]).is_err());
+ assert!(Signature::from_der(&[
+ der::Tag::Sequence.into(),
+ 0x03,
+ der::Tag::Integer.into(),
+ 0x01,
+ 0x01
+ ])
+ .is_err());
+ }
+
+ #[test]
+ fn test_asn1_non_der_signature() {
+ // A minimal 8-byte ASN.1 signature parses OK.
+ assert!(Signature::from_der(&[
+ der::Tag::Sequence.into(),
+ 0x06, // length of below
+ der::Tag::Integer.into(),
+ 0x01, // length of value
+ 0x01, // value=1
+ der::Tag::Integer.into(),
+ 0x01, // length of value
+ 0x01, // value=1
+ ])
+ .is_ok());
+
+ // But length fields that are not minimally encoded should be rejected, as they are not
+ // valid DER, cf.
+ // https://github.com/google/wycheproof/blob/2196000605e4/testvectors/ecdsa_secp256k1_sha256_test.json#L57-L66
+ assert!(Signature::from_der(&[
+ der::Tag::Sequence.into(),
+ 0x81, // extended length: 1 length byte to come
+ 0x06, // length of below
+ der::Tag::Integer.into(),
+ 0x01, // length of value
+ 0x01, // value=1
+ der::Tag::Integer.into(),
+ 0x01, // length of value
+ 0x01, // value=1
+ ])
+ .is_err());
+ }
+}
diff --git a/vendor/ecdsa/src/dev.rs b/vendor/ecdsa/src/dev.rs
new file mode 100644
index 000000000..ce00c7fbf
--- /dev/null
+++ b/vendor/ecdsa/src/dev.rs
@@ -0,0 +1,221 @@
+//! Development-related functionality.
+
+// TODO(tarcieri): implement full set of tests from ECDSA2VS
+// <https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/dss2/ecdsa2vs.pdf>
+
+/// ECDSA test vector
+pub struct TestVector {
+ /// Private scalar
+ pub d: &'static [u8],
+
+ /// Public key x-coordinate (`Qx`)
+ pub q_x: &'static [u8],
+
+ /// Public key y-coordinate (`Qy`)
+ pub q_y: &'static [u8],
+
+ /// Ephemeral scalar (a.k.a. nonce)
+ pub k: &'static [u8],
+
+ /// Message digest (prehashed)
+ pub m: &'static [u8],
+
+ /// Signature `r` component
+ pub r: &'static [u8],
+
+ /// Signature `s` component
+ pub s: &'static [u8],
+}
+
+/// Define ECDSA signing test.
+#[macro_export]
+#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
+macro_rules! new_signing_test {
+ ($curve:path, $vectors:expr) => {
+ use $crate::{
+ elliptic_curve::{
+ bigint::Encoding, generic_array::GenericArray, group::ff::PrimeField, Curve,
+ ProjectiveArithmetic, Scalar,
+ },
+ hazmat::SignPrimitive,
+ };
+
+ fn decode_scalar(bytes: &[u8]) -> Option<Scalar<$curve>> {
+ if bytes.len() == <$curve as Curve>::UInt::BYTE_SIZE {
+ Scalar::<$curve>::from_repr(GenericArray::clone_from_slice(bytes)).into()
+ } else {
+ None
+ }
+ }
+
+ #[test]
+ fn ecdsa_signing() {
+ for vector in $vectors {
+ let d = decode_scalar(vector.d).expect("invalid vector.d");
+ let k = decode_scalar(vector.k).expect("invalid vector.m");
+ let z = GenericArray::clone_from_slice(vector.m);
+ let sig = d.try_sign_prehashed(k, z).expect("ECDSA sign failed").0;
+
+ assert_eq!(vector.r, sig.r().to_bytes().as_slice());
+ assert_eq!(vector.s, sig.s().to_bytes().as_slice());
+ }
+ }
+ };
+}
+
+/// Define ECDSA verification test.
+#[macro_export]
+#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
+macro_rules! new_verification_test {
+ ($curve:path, $vectors:expr) => {
+ use $crate::{
+ elliptic_curve::{
+ generic_array::GenericArray,
+ group::ff::PrimeField,
+ sec1::{EncodedPoint, FromEncodedPoint},
+ AffinePoint, ProjectiveArithmetic, Scalar,
+ },
+ hazmat::VerifyPrimitive,
+ Signature,
+ };
+
+ #[test]
+ fn ecdsa_verify_success() {
+ for vector in $vectors {
+ let q_encoded = EncodedPoint::<$curve>::from_affine_coordinates(
+ GenericArray::from_slice(vector.q_x),
+ GenericArray::from_slice(vector.q_y),
+ false,
+ );
+
+ let q = AffinePoint::<$curve>::from_encoded_point(&q_encoded).unwrap();
+ let z = GenericArray::clone_from_slice(vector.m);
+
+ let sig = Signature::from_scalars(
+ GenericArray::clone_from_slice(vector.r),
+ GenericArray::clone_from_slice(vector.s),
+ )
+ .unwrap();
+
+ let result = q.verify_prehashed(z, &sig);
+ assert!(result.is_ok());
+ }
+ }
+
+ #[test]
+ fn ecdsa_verify_invalid_s() {
+ for vector in $vectors {
+ let q_encoded = EncodedPoint::<$curve>::from_affine_coordinates(
+ GenericArray::from_slice(vector.q_x),
+ GenericArray::from_slice(vector.q_y),
+ false,
+ );
+
+ let q = AffinePoint::<$curve>::from_encoded_point(&q_encoded).unwrap();
+ let z = GenericArray::clone_from_slice(vector.m);
+
+ // Flip a bit in `s`
+ let mut s_tweaked = GenericArray::clone_from_slice(vector.s);
+ s_tweaked[0] ^= 1;
+
+ let sig =
+ Signature::from_scalars(GenericArray::clone_from_slice(vector.r), s_tweaked)
+ .unwrap();
+
+ let result = q.verify_prehashed(z, &sig);
+ assert!(result.is_err());
+ }
+ }
+
+ // TODO(tarcieri): test invalid Q, invalid r, invalid m
+ };
+}
+
+/// Define a Wycheproof verification test.
+#[macro_export]
+#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
+macro_rules! new_wycheproof_test {
+ ($name:ident, $test_name: expr, $curve:path) => {
+ use $crate::{elliptic_curve::sec1::EncodedPoint, signature::Verifier, Signature};
+
+ #[test]
+ fn $name() {
+ use blobby::Blob5Iterator;
+ use elliptic_curve::{bigint::Encoding as _, generic_array::typenum::Unsigned};
+
+ // Build a field element but allow for too-short input (left pad with zeros)
+ // or too-long input (check excess leftmost bytes are zeros).
+ fn element_from_padded_slice<C: elliptic_curve::Curve>(
+ data: &[u8],
+ ) -> elliptic_curve::FieldBytes<C> {
+ let point_len = C::UInt::BYTE_SIZE;
+ if data.len() >= point_len {
+ let offset = data.len() - point_len;
+ for v in data.iter().take(offset) {
+ assert_eq!(*v, 0, "EcdsaVerifier: point too large");
+ }
+ elliptic_curve::FieldBytes::<C>::clone_from_slice(&data[offset..])
+ } else {
+ // Provided slice is too short and needs to be padded with zeros
+ // on the left. Build a combined exact iterator to do this.
+ let iter = core::iter::repeat(0)
+ .take(point_len - data.len())
+ .chain(data.iter().cloned());
+ elliptic_curve::FieldBytes::<C>::from_exact_iter(iter).unwrap()
+ }
+ }
+
+ fn run_test(
+ wx: &[u8],
+ wy: &[u8],
+ msg: &[u8],
+ sig: &[u8],
+ pass: bool,
+ ) -> Option<&'static str> {
+ let x = element_from_padded_slice::<$curve>(wx);
+ let y = element_from_padded_slice::<$curve>(wy);
+ let q_encoded = EncodedPoint::<$curve>::from_affine_coordinates(
+ &x, &y, /* compress= */ false,
+ );
+ let verifying_key =
+ $crate::VerifyingKey::<$curve>::from_encoded_point(&q_encoded).unwrap();
+
+ let sig = match Signature::from_der(sig) {
+ Ok(s) => s,
+ Err(_) if !pass => return None,
+ Err(_) => return Some("failed to parse signature ASN.1"),
+ };
+
+ match verifying_key.verify(msg, &sig) {
+ Ok(_) if pass => None,
+ Ok(_) => Some("signature verify unexpectedly succeeded"),
+ Err(_) if !pass => None,
+ Err(_) => Some("signature verify failed"),
+ }
+ }
+
+ let data = include_bytes!(concat!("test_vectors/data/", $test_name, ".blb"));
+
+ for (i, row) in Blob5Iterator::new(data).unwrap().enumerate() {
+ let [wx, wy, msg, sig, status] = row.unwrap();
+ let pass = match status[0] {
+ 0 => false,
+ 1 => true,
+ _ => panic!("invalid value for pass flag"),
+ };
+ if let Some(desc) = run_test(wx, wy, msg, sig, pass) {
+ panic!(
+ "\n\
+ Failed test โ„–{}: {}\n\
+ wx:\t{:?}\n\
+ wy:\t{:?}\n\
+ msg:\t{:?}\n\
+ sig:\t{:?}\n\
+ pass:\t{}\n",
+ i, desc, wx, wy, msg, sig, pass,
+ );
+ }
+ }
+ }
+ };
+}
diff --git a/vendor/ecdsa/src/hazmat.rs b/vendor/ecdsa/src/hazmat.rs
new file mode 100644
index 000000000..3ca3fc4ce
--- /dev/null
+++ b/vendor/ecdsa/src/hazmat.rs
@@ -0,0 +1,261 @@
+//! Low-level ECDSA primitives.
+//!
+//! # โš ๏ธ Warning: Hazmat!
+//!
+//! YOU PROBABLY DON'T WANT TO USE THESE!
+//!
+//! These primitives are easy-to-misuse low-level interfaces.
+//!
+//! If you are an end user / non-expert in cryptography, do not use these!
+//! Failure to use them correctly can lead to catastrophic failures including
+//! FULL PRIVATE KEY RECOVERY!
+
+#[cfg(feature = "arithmetic")]
+use {
+ crate::{RecoveryId, SignatureSize},
+ core::borrow::Borrow,
+ elliptic_curve::{
+ group::Curve as _,
+ ops::{Invert, LinearCombination, Reduce},
+ subtle::CtOption,
+ AffineArithmetic, AffineXCoordinate, Field, Group, ProjectiveArithmetic, ProjectivePoint,
+ Scalar, ScalarArithmetic,
+ },
+};
+
+#[cfg(feature = "digest")]
+use {
+ core::cmp,
+ elliptic_curve::{bigint::Encoding, FieldSize},
+ signature::{digest::Digest, PrehashSignature},
+};
+
+#[cfg(any(feature = "arithmetic", feature = "digest"))]
+use crate::{
+ elliptic_curve::{generic_array::ArrayLength, FieldBytes, PrimeCurve},
+ Error, Result, Signature,
+};
+
+#[cfg(all(feature = "arithmetic", feature = "digest"))]
+use signature::digest::FixedOutput;
+
+#[cfg(all(feature = "rfc6979"))]
+use {
+ elliptic_curve::ScalarCore,
+ signature::digest::{core_api::BlockSizeUser, FixedOutputReset},
+};
+
+/// Try to sign the given prehashed message using ECDSA.
+///
+/// This trait is intended to be implemented on a type with access to the
+/// secret scalar via `&self`, such as particular curve's `Scalar` type.
+#[cfg(feature = "arithmetic")]
+#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
+pub trait SignPrimitive<C>: Field + Into<FieldBytes<C>> + Reduce<C::UInt> + Sized
+where
+ C: PrimeCurve + ProjectiveArithmetic + ScalarArithmetic<Scalar = Self>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// Try to sign the prehashed message.
+ ///
+ /// Accepts the following arguments:
+ ///
+ /// - `k`: ephemeral scalar value. MUST BE UNIFORMLY RANDOM!!!
+ /// - `z`: message digest to be signed. MUST BE OUTPUT OF A CRYPTOGRAPHICALLY
+ /// SECURE DIGEST ALGORITHM!!!
+ ///
+ /// # Returns
+ ///
+ /// ECDSA [`Signature`] and, when possible/desired, a [`RecoveryId`]
+ /// which can be used to recover the verifying key for a given signature.
+ #[allow(non_snake_case)]
+ fn try_sign_prehashed<K>(
+ &self,
+ k: K,
+ z: FieldBytes<C>,
+ ) -> Result<(Signature<C>, Option<RecoveryId>)>
+ where
+ K: Borrow<Self> + Invert<Output = CtOption<Self>>,
+ {
+ if k.borrow().is_zero().into() {
+ return Err(Error::new());
+ }
+
+ let z = Self::from_be_bytes_reduced(z);
+
+ // Compute scalar inversion of ๐‘˜
+ let k_inv = Option::<Scalar<C>>::from(k.invert()).ok_or_else(Error::new)?;
+
+ // Compute ๐‘น = ๐‘˜ร—๐‘ฎ
+ let R = (C::ProjectivePoint::generator() * k.borrow()).to_affine();
+
+ // Lift x-coordinate of ๐‘น (element of base field) into a serialized big
+ // integer, then reduce it into an element of the scalar field
+ let r = Self::from_be_bytes_reduced(R.x());
+
+ // Compute ๐’” as a signature over ๐’“ and ๐’›.
+ let s = k_inv * (z + (r * self));
+
+ if s.is_zero().into() {
+ return Err(Error::new());
+ }
+
+ // TODO(tarcieri): support for computing recovery ID
+ Ok((Signature::from_scalars(r, s)?, None))
+ }
+
+ /// Try to sign the given message digest deterministically using the method
+ /// described in [RFC6979] for computing ECDSA ephemeral scalar `k`.
+ ///
+ /// Accepts the following parameters:
+ /// - `z`: message digest to be signed.
+ /// - `ad`: optional additional data, e.g. added entropy from an RNG
+ ///
+ /// [RFC6979]: https://datatracker.ietf.org/doc/html/rfc6979
+ #[cfg(all(feature = "rfc6979"))]
+ #[cfg_attr(docsrs, doc(cfg(feature = "rfc6979")))]
+ fn try_sign_prehashed_rfc6979<D>(
+ &self,
+ z: FieldBytes<C>,
+ ad: &[u8],
+ ) -> Result<(Signature<C>, Option<RecoveryId>)>
+ where
+ Self: From<ScalarCore<C>>,
+ C::UInt: for<'a> From<&'a Self>,
+ D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
+ {
+ let x = C::UInt::from(self);
+ let k = rfc6979::generate_k::<D, C::UInt>(&x, &C::ORDER, &z, ad);
+ let k = Self::from(ScalarCore::<C>::new(*k).unwrap());
+ self.try_sign_prehashed(k, z)
+ }
+
+ /// Try to sign the given digest instance using the method described in
+ /// [RFC6979].
+ ///
+ /// [RFC6979]: https://datatracker.ietf.org/doc/html/rfc6979
+ #[cfg(all(feature = "rfc6979"))]
+ #[cfg_attr(docsrs, doc(cfg(feature = "rfc6979")))]
+ fn try_sign_digest_rfc6979<D>(
+ &self,
+ msg_digest: D,
+ ad: &[u8],
+ ) -> Result<(Signature<C>, Option<RecoveryId>)>
+ where
+ Self: From<ScalarCore<C>>,
+ C::UInt: for<'a> From<&'a Self>,
+ D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
+ {
+ self.try_sign_prehashed_rfc6979::<D>(msg_digest.finalize_fixed(), ad)
+ }
+}
+
+/// Verify the given prehashed message using ECDSA.
+///
+/// This trait is intended to be implemented on type which can access
+/// the affine point represeting the public key via `&self`, such as a
+/// particular curve's `AffinePoint` type.
+#[cfg(feature = "arithmetic")]
+#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
+pub trait VerifyPrimitive<C>: AffineXCoordinate<C> + Copy + Sized
+where
+ C: PrimeCurve + AffineArithmetic<AffinePoint = Self> + ProjectiveArithmetic,
+ Scalar<C>: Reduce<C::UInt>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// Verify the prehashed message against the provided signature
+ ///
+ /// Accepts the following arguments:
+ ///
+ /// - `z`: message digest to be verified. MUST BE OUTPUT OF A
+ /// CRYPTOGRAPHICALLY SECURE DIGEST ALGORITHM!!!
+ /// - `sig`: signature to be verified against the key and message
+ fn verify_prehashed(&self, z: FieldBytes<C>, sig: &Signature<C>) -> Result<()> {
+ let z = Scalar::<C>::from_be_bytes_reduced(z);
+ let (r, s) = sig.split_scalars();
+ let s_inv = *s.invert();
+ let u1 = z * s_inv;
+ let u2 = *r * s_inv;
+ let x = ProjectivePoint::<C>::lincomb(
+ &ProjectivePoint::<C>::generator(),
+ &u1,
+ &ProjectivePoint::<C>::from(*self),
+ &u2,
+ )
+ .to_affine()
+ .x();
+
+ if Scalar::<C>::from_be_bytes_reduced(x) == *r {
+ Ok(())
+ } else {
+ Err(Error::new())
+ }
+ }
+
+ /// Verify message digest against the provided signature.
+ #[cfg(feature = "digest")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "digest")))]
+ fn verify_digest<D>(&self, msg_digest: D, sig: &Signature<C>) -> Result<()>
+ where
+ D: FixedOutput<OutputSize = FieldSize<C>>,
+ {
+ self.verify_prehashed(msg_digest.finalize_fixed(), sig)
+ }
+}
+
+/// Bind a preferred [`Digest`] algorithm to an elliptic curve type.
+///
+/// Generally there is a preferred variety of the SHA-2 family used with ECDSA
+/// for a particular elliptic curve.
+///
+/// This trait can be used to specify it, and with it receive a blanket impl of
+/// [`PrehashSignature`], used by [`signature_derive`][1]) for the [`Signature`]
+/// type for a particular elliptic curve.
+///
+/// [1]: https://github.com/RustCrypto/traits/tree/master/signature/derive
+#[cfg(feature = "digest")]
+#[cfg_attr(docsrs, doc(cfg(feature = "digest")))]
+pub trait DigestPrimitive: PrimeCurve {
+ /// Preferred digest to use when computing ECDSA signatures for this
+ /// elliptic curve. This is typically a member of the SHA-2 family.
+ // TODO(tarcieri): add BlockSizeUser + FixedOutput(Reset) bounds in next breaking release
+ // These bounds ensure the digest algorithm can be used for HMAC-DRBG for RFC6979
+ type Digest: Digest;
+
+ /// Compute field bytes for a prehash (message digest), either zero-padding
+ /// or truncating if the prehash size does not match the field size.
+ fn prehash_to_field_bytes(prehash: &[u8]) -> Result<FieldBytes<Self>> {
+ // Minimum allowed prehash size is half the field size
+ if prehash.len() < Self::UInt::BYTE_SIZE / 2 {
+ return Err(Error::new());
+ }
+
+ let mut field_bytes = FieldBytes::<Self>::default();
+
+ // This is a operation according to RFC6979 Section 2.3.2. and SEC1 Section 2.3.8.
+ // https://datatracker.ietf.org/doc/html/rfc6979#section-2.3.2
+ // https://www.secg.org/sec1-v2.pdf
+ match prehash.len().cmp(&Self::UInt::BYTE_SIZE) {
+ cmp::Ordering::Equal => field_bytes.copy_from_slice(prehash),
+ cmp::Ordering::Less => {
+ // If prehash is smaller than the field size, pad with zeroes on the left
+ field_bytes[(Self::UInt::BYTE_SIZE - prehash.len())..].copy_from_slice(prehash);
+ }
+ cmp::Ordering::Greater => {
+ // If prehash is larger than the field size, truncate
+ field_bytes.copy_from_slice(&prehash[..Self::UInt::BYTE_SIZE]);
+ }
+ }
+
+ Ok(field_bytes)
+ }
+}
+
+#[cfg(feature = "digest")]
+impl<C> PrehashSignature for Signature<C>
+where
+ C: DigestPrimitive,
+ <FieldSize<C> as core::ops::Add>::Output: ArrayLength<u8>,
+{
+ type Digest = C::Digest;
+}
diff --git a/vendor/ecdsa/src/lib.rs b/vendor/ecdsa/src/lib.rs
new file mode 100644
index 000000000..9e339ba8f
--- /dev/null
+++ b/vendor/ecdsa/src/lib.rs
@@ -0,0 +1,421 @@
+#![no_std]
+#![cfg_attr(docsrs, feature(doc_cfg))]
+#![doc = include_str!("../README.md")]
+#![doc(
+ html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
+ html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg"
+)]
+#![forbid(unsafe_code)]
+#![warn(
+ clippy::cast_lossless,
+ clippy::cast_possible_truncation,
+ clippy::cast_possible_wrap,
+ clippy::cast_precision_loss,
+ clippy::cast_sign_loss,
+ clippy::checked_conversions,
+ clippy::implicit_saturating_sub,
+ clippy::panic,
+ clippy::panic_in_result_fn,
+ clippy::unwrap_used,
+ missing_docs,
+ rust_2018_idioms,
+ unused_lifetimes,
+ unused_qualifications
+)]
+
+//! ## `serde` support
+//!
+//! When the `serde` feature of this crate is enabled, `Serialize` and
+//! `Deserialize` impls are provided for the [`Signature`] and [`VerifyingKey`]
+//! types.
+//!
+//! Please see type-specific documentation for more information.
+//!
+//! ## Interop
+//!
+//! Any crates which provide an implementation of ECDSA for a particular
+//! elliptic curve can leverage the types from this crate, along with the
+//! [`k256`], [`p256`], and/or [`p384`] crates to expose ECDSA functionality in
+//! a generic, interoperable way by leveraging the [`Signature`] type with in
+//! conjunction with the [`signature::Signer`] and [`signature::Verifier`]
+//! traits.
+//!
+//! For example, the [`ring-compat`] crate implements the [`signature::Signer`]
+//! and [`signature::Verifier`] traits in conjunction with the
+//! [`p256::ecdsa::Signature`] and [`p384::ecdsa::Signature`] types to
+//! wrap the ECDSA implementations from [*ring*] in a generic, interoperable
+//! API.
+//!
+//! [`k256`]: https://docs.rs/k256
+//! [`p256`]: https://docs.rs/p256
+//! [`p256::ecdsa::Signature`]: https://docs.rs/p256/latest/p256/ecdsa/type.Signature.html
+//! [`p384`]: https://docs.rs/p384
+//! [`p384::ecdsa::Signature`]: https://docs.rs/p384/latest/p384/ecdsa/type.Signature.html
+//! [`ring-compat`]: https://docs.rs/ring-compat
+//! [*ring*]: https://docs.rs/ring
+
+#[cfg(feature = "alloc")]
+extern crate alloc;
+
+mod recovery;
+
+#[cfg(feature = "der")]
+#[cfg_attr(docsrs, doc(cfg(feature = "der")))]
+pub mod der;
+
+#[cfg(feature = "dev")]
+#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
+pub mod dev;
+
+#[cfg(feature = "hazmat")]
+#[cfg_attr(docsrs, doc(cfg(feature = "hazmat")))]
+pub mod hazmat;
+
+#[cfg(feature = "sign")]
+mod sign;
+
+#[cfg(feature = "verify")]
+mod verify;
+
+pub use crate::recovery::RecoveryId;
+
+// Re-export the `elliptic-curve` crate (and select types)
+pub use elliptic_curve::{self, sec1::EncodedPoint, PrimeCurve};
+
+// Re-export the `signature` crate (and select types)
+pub use signature::{self, Error, Result};
+
+#[cfg(feature = "sign")]
+#[cfg_attr(docsrs, doc(cfg(feature = "sign")))]
+pub use crate::sign::SigningKey;
+
+#[cfg(feature = "verify")]
+#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
+pub use crate::verify::VerifyingKey;
+
+use core::{
+ fmt::{self, Debug},
+ ops::Add,
+};
+use elliptic_curve::{
+ bigint::Encoding as _,
+ generic_array::{sequence::Concat, ArrayLength, GenericArray},
+ FieldBytes, FieldSize, ScalarCore,
+};
+
+#[cfg(feature = "alloc")]
+use alloc::vec::Vec;
+
+#[cfg(feature = "arithmetic")]
+use {
+ core::str,
+ elliptic_curve::{ff::PrimeField, IsHigh, NonZeroScalar, ScalarArithmetic},
+};
+
+#[cfg(feature = "serde")]
+use serdect::serde::{de, ser, Deserialize, Serialize};
+
+/// Size of a fixed sized signature for the given elliptic curve.
+pub type SignatureSize<C> = <FieldSize<C> as Add>::Output;
+
+/// Fixed-size byte array containing an ECDSA signature
+pub type SignatureBytes<C> = GenericArray<u8, SignatureSize<C>>;
+
+/// ECDSA signature (fixed-size). Generic over elliptic curve types.
+///
+/// Serialized as fixed-sized big endian scalar values with no added framing:
+///
+/// - `r`: field element size for the given curve, big-endian
+/// - `s`: field element size for the given curve, big-endian
+///
+/// For example, in a curve with a 256-bit modulus like NIST P-256 or
+/// secp256k1, `r` and `s` will both be 32-bytes, resulting in a signature
+/// with a total of 64-bytes.
+///
+/// ASN.1 DER-encoded signatures also supported via the
+/// [`Signature::from_der`] and [`Signature::to_der`] methods.
+///
+/// # `serde` support
+///
+/// When the `serde` feature of this crate is enabled, it provides support for
+/// serializing and deserializing ECDSA signatures using the `Serialize` and
+/// `Deserialize` traits.
+///
+/// The serialization uses a 64-byte fixed encoding when used with binary
+/// formats, and a hexadecimal encoding when used with text formats.
+#[derive(Clone, Eq, PartialEq)]
+pub struct Signature<C: PrimeCurve>
+where
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ bytes: SignatureBytes<C>,
+}
+
+impl<C> Signature<C>
+where
+ C: PrimeCurve,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// Parse a signature from ASN.1 DER
+ #[cfg(feature = "der")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "der")))]
+ pub fn from_der(bytes: &[u8]) -> Result<Self>
+ where
+ der::MaxSize<C>: ArrayLength<u8>,
+ <FieldSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
+ {
+ der::Signature::<C>::try_from(bytes).and_then(Self::try_from)
+ }
+
+ /// Create a [`Signature`] from the serialized `r` and `s` scalar values
+ /// which comprise the signature.
+ pub fn from_scalars(r: impl Into<FieldBytes<C>>, s: impl Into<FieldBytes<C>>) -> Result<Self> {
+ Self::try_from(r.into().concat(s.into()).as_slice())
+ }
+
+ /// Split the signature into its `r` and `s` components, represented as bytes.
+ pub fn split_bytes(&self) -> (FieldBytes<C>, FieldBytes<C>) {
+ let (r_bytes, s_bytes) = self.bytes.split_at(C::UInt::BYTE_SIZE);
+
+ (
+ GenericArray::clone_from_slice(r_bytes),
+ GenericArray::clone_from_slice(s_bytes),
+ )
+ }
+
+ /// Serialize this signature as ASN.1 DER
+ #[cfg(feature = "der")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "der")))]
+ pub fn to_der(&self) -> der::Signature<C>
+ where
+ der::MaxSize<C>: ArrayLength<u8>,
+ <FieldSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
+ {
+ let (r, s) = self.bytes.split_at(C::UInt::BYTE_SIZE);
+ der::Signature::from_scalar_bytes(r, s).expect("DER encoding error")
+ }
+
+ /// Convert this signature into a byte vector.
+ #[cfg(feature = "alloc")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
+ pub fn to_vec(&self) -> Vec<u8> {
+ self.bytes.to_vec()
+ }
+}
+
+#[cfg(feature = "arithmetic")]
+#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
+impl<C> Signature<C>
+where
+ C: PrimeCurve + ScalarArithmetic,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// Get the `r` component of this signature
+ pub fn r(&self) -> NonZeroScalar<C> {
+ NonZeroScalar::try_from(self.split_bytes().0.as_slice())
+ .expect("r-component ensured valid in constructor")
+ }
+
+ /// Get the `s` component of this signature
+ pub fn s(&self) -> NonZeroScalar<C> {
+ NonZeroScalar::try_from(self.split_bytes().1.as_slice())
+ .expect("s-component ensured valid in constructor")
+ }
+
+ /// Split the signature into its `r` and `s` scalars.
+ pub fn split_scalars(&self) -> (NonZeroScalar<C>, NonZeroScalar<C>) {
+ (self.r(), self.s())
+ }
+
+ /// Normalize signature into "low S" form as described in
+ /// [BIP 0062: Dealing with Malleability][1].
+ ///
+ /// [1]: https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki
+ pub fn normalize_s(&self) -> Option<Self> {
+ let s = self.s();
+
+ if s.is_high().into() {
+ let neg_s = -s;
+ let mut result = self.clone();
+ result.bytes[C::UInt::BYTE_SIZE..].copy_from_slice(&neg_s.to_repr());
+ Some(result)
+ } else {
+ None
+ }
+ }
+}
+
+impl<C> signature::Signature for Signature<C>
+where
+ C: PrimeCurve,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from_bytes(bytes: &[u8]) -> Result<Self> {
+ Self::try_from(bytes)
+ }
+}
+
+impl<C> AsRef<[u8]> for Signature<C>
+where
+ C: PrimeCurve,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn as_ref(&self) -> &[u8] {
+ self.bytes.as_slice()
+ }
+}
+
+impl<C> Copy for Signature<C>
+where
+ C: PrimeCurve,
+ SignatureSize<C>: ArrayLength<u8>,
+ <SignatureSize<C> as ArrayLength<u8>>::ArrayType: Copy,
+{
+}
+
+impl<C> Debug for Signature<C>
+where
+ C: PrimeCurve,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ecdsa::Signature<{:?}>(", C::default())?;
+
+ for &byte in self.as_ref() {
+ write!(f, "{:02X}", byte)?;
+ }
+
+ write!(f, ")")
+ }
+}
+
+impl<C> TryFrom<&[u8]> for Signature<C>
+where
+ C: PrimeCurve,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ type Error = Error;
+
+ fn try_from(bytes: &[u8]) -> Result<Self> {
+ if bytes.len() != C::UInt::BYTE_SIZE * 2 {
+ return Err(Error::new());
+ }
+
+ for scalar_bytes in bytes.chunks_exact(C::UInt::BYTE_SIZE) {
+ let scalar = ScalarCore::<C>::from_be_slice(scalar_bytes).map_err(|_| Error::new())?;
+
+ if scalar.is_zero().into() {
+ return Err(Error::new());
+ }
+ }
+
+ Ok(Self {
+ bytes: GenericArray::clone_from_slice(bytes),
+ })
+ }
+}
+
+impl<C> fmt::Display for Signature<C>
+where
+ C: PrimeCurve,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:X}", self)
+ }
+}
+
+impl<C> fmt::LowerHex for Signature<C>
+where
+ C: PrimeCurve,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ for byte in &self.bytes {
+ write!(f, "{:02x}", byte)?;
+ }
+ Ok(())
+ }
+}
+
+impl<C> fmt::UpperHex for Signature<C>
+where
+ C: PrimeCurve,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ for byte in &self.bytes {
+ write!(f, "{:02X}", byte)?;
+ }
+ Ok(())
+ }
+}
+
+#[cfg(feature = "arithmetic")]
+#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
+impl<C> str::FromStr for Signature<C>
+where
+ C: PrimeCurve + ScalarArithmetic,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ type Err = Error;
+
+ fn from_str(hex: &str) -> Result<Self> {
+ if hex.as_bytes().len() != C::UInt::BYTE_SIZE * 4 {
+ return Err(Error::new());
+ }
+
+ // This check is mainly to ensure `hex.split_at` below won't panic
+ if !hex
+ .as_bytes()
+ .iter()
+ .all(|&byte| matches!(byte, b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z'))
+ {
+ return Err(Error::new());
+ }
+
+ let (r_hex, s_hex) = hex.split_at(C::UInt::BYTE_SIZE * 2);
+
+ let r = r_hex
+ .parse::<NonZeroScalar<C>>()
+ .map_err(|_| Error::new())?;
+
+ let s = s_hex
+ .parse::<NonZeroScalar<C>>()
+ .map_err(|_| Error::new())?;
+
+ Self::from_scalars(r, s)
+ }
+}
+
+#[cfg(feature = "serde")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
+impl<C> Serialize for Signature<C>
+where
+ C: PrimeCurve,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ serdect::array::serialize_hex_upper_or_bin(&self.bytes, serializer)
+ }
+}
+
+#[cfg(feature = "serde")]
+#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
+impl<'de, C> Deserialize<'de> for Signature<C>
+where
+ C: PrimeCurve,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ let mut bytes = SignatureBytes::<C>::default();
+ serdect::array::deserialize_hex_or_bin(&mut bytes, deserializer)?;
+ Self::try_from(bytes.as_slice()).map_err(de::Error::custom)
+ }
+}
diff --git a/vendor/ecdsa/src/recovery.rs b/vendor/ecdsa/src/recovery.rs
new file mode 100644
index 000000000..c923bbad7
--- /dev/null
+++ b/vendor/ecdsa/src/recovery.rs
@@ -0,0 +1,110 @@
+//! Public key recovery support.
+
+use crate::{Error, Result};
+
+/// Recovery IDs, a.k.a. "recid".
+///
+/// This is an integer value `0`, `1`, `2`, or `3` included along with a
+/// signature which is used during the recovery process to select the correct
+/// public key from the signature.
+///
+/// It consists of two bits of information:
+///
+/// - low bit (0/1): was the y-coordinate of the affine point resulting from
+/// the fixed-base multiplication ๐‘˜ร—๐‘ฎ odd? This part of the algorithm
+/// functions similar to point decompression.
+/// - hi bit (3/4): did the affine x-coordinate of ๐‘˜ร—๐‘ฎ overflow the order of
+/// the scalar field, requiring a reduction when computing `r`?
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
+pub struct RecoveryId(u8);
+
+impl RecoveryId {
+ /// Maximum supported value for the recovery ID (inclusive).
+ pub const MAX: u8 = 3;
+
+ /// Create a new [`RecoveryId`] from the following 1-bit arguments:
+ ///
+ /// - `is_y_odd`: is the affine y-coordinate of ๐‘˜ร—๐‘ฎ odd?
+ /// - `is_x_reduced`: did the affine x-coordinate of ๐‘˜ร—๐‘ฎ overflow the curve order?
+ pub const fn new(is_y_odd: bool, is_x_reduced: bool) -> Self {
+ Self((is_x_reduced as u8) << 1 | (is_y_odd as u8))
+ }
+
+ /// Did the affine x-coordinate of ๐‘˜ร—๐‘ฎ overflow the curve order?
+ pub const fn is_x_reduced(self) -> bool {
+ (self.0 & 0b10) != 0
+ }
+
+ /// Is the affine y-coordinate of ๐‘˜ร—๐‘ฎ odd?
+ pub const fn is_y_odd(self) -> bool {
+ (self.0 & 1) != 0
+ }
+
+ /// Convert a `u8` into a [`RecoveryId`].
+ pub const fn from_byte(byte: u8) -> Option<Self> {
+ if byte <= Self::MAX {
+ Some(Self(byte))
+ } else {
+ None
+ }
+ }
+
+ /// Convert this [`RecoveryId`] into a `u8`.
+ pub const fn to_byte(self) -> u8 {
+ self.0
+ }
+}
+
+impl TryFrom<u8> for RecoveryId {
+ type Error = Error;
+
+ fn try_from(byte: u8) -> Result<Self> {
+ Self::from_byte(byte).ok_or_else(Error::new)
+ }
+}
+
+impl From<RecoveryId> for u8 {
+ fn from(id: RecoveryId) -> u8 {
+ id.0
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::RecoveryId;
+
+ #[test]
+ fn new() {
+ assert_eq!(RecoveryId::new(false, false).to_byte(), 0);
+ assert_eq!(RecoveryId::new(true, false).to_byte(), 1);
+ assert_eq!(RecoveryId::new(false, true).to_byte(), 2);
+ assert_eq!(RecoveryId::new(true, true).to_byte(), 3);
+ }
+
+ #[test]
+ fn try_from() {
+ for n in 0u8..=3 {
+ assert_eq!(RecoveryId::try_from(n).unwrap().to_byte(), n);
+ }
+
+ for n in 4u8..=255 {
+ assert!(RecoveryId::try_from(n).is_err());
+ }
+ }
+
+ #[test]
+ fn is_x_reduced() {
+ assert_eq!(RecoveryId::try_from(0).unwrap().is_x_reduced(), false);
+ assert_eq!(RecoveryId::try_from(1).unwrap().is_x_reduced(), false);
+ assert_eq!(RecoveryId::try_from(2).unwrap().is_x_reduced(), true);
+ assert_eq!(RecoveryId::try_from(3).unwrap().is_x_reduced(), true);
+ }
+
+ #[test]
+ fn is_y_odd() {
+ assert_eq!(RecoveryId::try_from(0).unwrap().is_y_odd(), false);
+ assert_eq!(RecoveryId::try_from(1).unwrap().is_y_odd(), true);
+ assert_eq!(RecoveryId::try_from(2).unwrap().is_y_odd(), false);
+ assert_eq!(RecoveryId::try_from(3).unwrap().is_y_odd(), true);
+ }
+}
diff --git a/vendor/ecdsa/src/sign.rs b/vendor/ecdsa/src/sign.rs
new file mode 100644
index 000000000..12d00edb2
--- /dev/null
+++ b/vendor/ecdsa/src/sign.rs
@@ -0,0 +1,424 @@
+//! ECDSA signing key.
+
+// TODO(tarcieri): support for hardware crypto accelerators
+
+use crate::{
+ hazmat::{DigestPrimitive, SignPrimitive},
+ Error, Result, Signature, SignatureSize,
+};
+use core::fmt::{self, Debug};
+use elliptic_curve::{
+ generic_array::ArrayLength,
+ group::ff::PrimeField,
+ ops::{Invert, Reduce},
+ subtle::{Choice, ConstantTimeEq, CtOption},
+ zeroize::{Zeroize, ZeroizeOnDrop},
+ FieldBytes, FieldSize, NonZeroScalar, PrimeCurve, ProjectiveArithmetic, Scalar, SecretKey,
+};
+use signature::{
+ digest::{core_api::BlockSizeUser, Digest, FixedOutput, FixedOutputReset},
+ hazmat::PrehashSigner,
+ rand_core::{CryptoRng, RngCore},
+ DigestSigner, RandomizedDigestSigner, RandomizedSigner, Signer,
+};
+
+#[cfg(feature = "pem")]
+use {
+ crate::elliptic_curve::pkcs8::{EncodePrivateKey, SecretDocument},
+ core::str::FromStr,
+};
+
+#[cfg(feature = "pkcs8")]
+use crate::elliptic_curve::{
+ pkcs8::{self, AssociatedOid, DecodePrivateKey},
+ sec1::{self, FromEncodedPoint, ToEncodedPoint},
+ AffinePoint,
+};
+
+#[cfg(feature = "verify")]
+use {crate::verify::VerifyingKey, elliptic_curve::PublicKey, signature::Keypair};
+
+/// ECDSA signing key. Generic over elliptic curves.
+///
+/// Requires an [`elliptic_curve::ProjectiveArithmetic`] impl on the curve, and a
+/// [`SignPrimitive`] impl on its associated `Scalar` type.
+#[derive(Clone)]
+#[cfg_attr(docsrs, doc(cfg(feature = "sign")))]
+pub struct SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// ECDSA signing keys are non-zero elements of a given curve's scalar field.
+ secret_scalar: NonZeroScalar<C>,
+
+ /// Verifying key which corresponds to this signing key.
+ #[cfg(feature = "verify")]
+ verifying_key: VerifyingKey<C>,
+}
+
+impl<C> SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// Generate a cryptographically random [`SigningKey`].
+ pub fn random(rng: impl CryptoRng + RngCore) -> Self {
+ NonZeroScalar::<C>::random(rng).into()
+ }
+
+ /// Initialize signing key from a raw scalar serialized as a byte slice.
+ pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
+ SecretKey::<C>::from_be_bytes(bytes)
+ .map(|sk| sk.to_nonzero_scalar().into())
+ .map_err(|_| Error::new())
+ }
+
+ /// Serialize this [`SigningKey`] as bytes
+ pub fn to_bytes(&self) -> FieldBytes<C> {
+ self.secret_scalar.to_repr()
+ }
+
+ /// Borrow the secret [`NonZeroScalar`] value for this key.
+ ///
+ /// # โš ๏ธ Warning
+ ///
+ /// This value is key material.
+ ///
+ /// Please treat it with the care it deserves!
+ pub fn as_nonzero_scalar(&self) -> &NonZeroScalar<C> {
+ &self.secret_scalar
+ }
+
+ /// Get the [`VerifyingKey`] which corresponds to this [`SigningKey`]
+ // TODO(tarcieri): make this return `&VerifyingKey<C>` in the next breaking release
+ #[cfg(feature = "verify")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
+ pub fn verifying_key(&self) -> VerifyingKey<C> {
+ self.verifying_key
+ }
+}
+
+#[cfg(feature = "verify")]
+#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
+impl<C> AsRef<VerifyingKey<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn as_ref(&self) -> &VerifyingKey<C> {
+ &self.verifying_key
+ }
+}
+
+impl<C> ConstantTimeEq for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn ct_eq(&self, other: &Self) -> Choice {
+ self.secret_scalar.ct_eq(&other.secret_scalar)
+ }
+}
+
+impl<C> Debug for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("SigningKey").finish_non_exhaustive()
+ }
+}
+
+impl<C> Drop for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn drop(&mut self) {
+ self.secret_scalar.zeroize();
+ }
+}
+
+impl<C> ZeroizeOnDrop for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+}
+
+/// Constant-time comparison
+impl<C> Eq for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+}
+
+/// Constant-time comparison
+impl<C> PartialEq for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn eq(&self, other: &SigningKey<C>) -> bool {
+ self.ct_eq(other).into()
+ }
+}
+
+impl<C> From<SecretKey<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(secret_key: SecretKey<C>) -> Self {
+ Self::from(&secret_key)
+ }
+}
+
+impl<C> From<&SecretKey<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(secret_key: &SecretKey<C>) -> Self {
+ secret_key.to_nonzero_scalar().into()
+ }
+}
+
+impl<C> From<SigningKey<C>> for SecretKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(key: SigningKey<C>) -> Self {
+ key.secret_scalar.into()
+ }
+}
+
+impl<C> From<&SigningKey<C>> for SecretKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(secret_key: &SigningKey<C>) -> Self {
+ secret_key.secret_scalar.into()
+ }
+}
+
+impl<C, D> DigestSigner<D, Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ C::UInt: for<'a> From<&'a Scalar<C>>,
+ D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// Sign message digest using a deterministic ephemeral scalar (`k`)
+ /// computed using the algorithm described in [RFC6979 ยง 3.2].
+ ///
+ /// [RFC6979 ยง 3.2]: https://tools.ietf.org/html/rfc6979#section-3
+ fn try_sign_digest(&self, msg_digest: D) -> Result<Signature<C>> {
+ Ok(self
+ .secret_scalar
+ .try_sign_digest_rfc6979::<D>(msg_digest, &[])?
+ .0)
+ }
+}
+
+#[cfg(feature = "verify")]
+#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
+impl<C> Keypair<Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ type VerifyingKey = VerifyingKey<C>;
+}
+
+impl<C> PrehashSigner<Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive,
+ C::Digest: BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
+ C::UInt: for<'a> From<&'a Scalar<C>>,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature<C>> {
+ let prehash = C::prehash_to_field_bytes(prehash)?;
+
+ Ok(self
+ .secret_scalar
+ .try_sign_prehashed_rfc6979::<C::Digest>(prehash, &[])?
+ .0)
+ }
+}
+
+impl<C> Signer<Signature<C>> for SigningKey<C>
+where
+ Self: DigestSigner<C::Digest, Signature<C>>,
+ C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn try_sign(&self, msg: &[u8]) -> Result<Signature<C>> {
+ self.try_sign_digest(C::Digest::new_with_prefix(msg))
+ }
+}
+
+impl<C, D> RandomizedDigestSigner<D, Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ C::UInt: for<'a> From<&'a Scalar<C>>,
+ D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// Sign message prehash using an ephemeral scalar (`k`) derived according
+ /// to a variant of RFC 6979 (Section 3.6) which supplies additional
+ /// entropy from an RNG.
+ fn try_sign_digest_with_rng(
+ &self,
+ mut rng: impl CryptoRng + RngCore,
+ msg_digest: D,
+ ) -> Result<Signature<C>> {
+ let mut ad = FieldBytes::<C>::default();
+ rng.fill_bytes(&mut ad);
+ Ok(self
+ .secret_scalar
+ .try_sign_digest_rfc6979::<D>(msg_digest, &ad)?
+ .0)
+ }
+}
+
+impl<C> RandomizedSigner<Signature<C>> for SigningKey<C>
+where
+ Self: RandomizedDigestSigner<C::Digest, Signature<C>>,
+ C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn try_sign_with_rng(&self, rng: impl CryptoRng + RngCore, msg: &[u8]) -> Result<Signature<C>> {
+ self.try_sign_digest_with_rng(rng, C::Digest::new_with_prefix(msg))
+ }
+}
+
+impl<C> From<NonZeroScalar<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(secret_scalar: NonZeroScalar<C>) -> Self {
+ #[cfg(feature = "verify")]
+ let public_key = PublicKey::from_secret_scalar(&secret_scalar);
+
+ Self {
+ secret_scalar,
+ #[cfg(feature = "verify")]
+ verifying_key: public_key.into(),
+ }
+ }
+}
+
+impl<C> TryFrom<&[u8]> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ type Error = Error;
+
+ fn try_from(bytes: &[u8]) -> Result<Self> {
+ Self::from_bytes(bytes)
+ }
+}
+
+#[cfg(feature = "verify")]
+impl<C> From<&SigningKey<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(signing_key: &SigningKey<C>) -> VerifyingKey<C> {
+ signing_key.verifying_key()
+ }
+}
+
+#[cfg(feature = "pkcs8")]
+#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
+impl<C> TryFrom<pkcs8::PrivateKeyInfo<'_>> for SigningKey<C>
+where
+ C: PrimeCurve + AssociatedOid + ProjectiveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ type Error = pkcs8::Error;
+
+ fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> {
+ SecretKey::try_from(private_key_info).map(Into::into)
+ }
+}
+
+#[cfg(feature = "pem")]
+#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
+impl<C> EncodePrivateKey for SigningKey<C>
+where
+ C: AssociatedOid + PrimeCurve + ProjectiveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
+ SecretKey::from(self.secret_scalar).to_pkcs8_der()
+ }
+}
+
+#[cfg(feature = "pkcs8")]
+#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
+impl<C> DecodePrivateKey for SigningKey<C>
+where
+ C: PrimeCurve + AssociatedOid + ProjectiveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+}
+
+#[cfg(feature = "pem")]
+#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
+impl<C> FromStr for SigningKey<C>
+where
+ C: PrimeCurve + AssociatedOid + ProjectiveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ type Err = Error;
+
+ fn from_str(s: &str) -> Result<Self> {
+ Self::from_pkcs8_pem(s).map_err(|_| Error::new())
+ }
+}
diff --git a/vendor/ecdsa/src/verify.rs b/vendor/ecdsa/src/verify.rs
new file mode 100644
index 000000000..5aa8bcb8d
--- /dev/null
+++ b/vendor/ecdsa/src/verify.rs
@@ -0,0 +1,325 @@
+//! ECDSA verification key.
+
+use crate::{
+ hazmat::{DigestPrimitive, VerifyPrimitive},
+ Error, Result, Signature, SignatureSize,
+};
+use core::{cmp::Ordering, fmt::Debug};
+use elliptic_curve::{
+ generic_array::ArrayLength,
+ ops::Reduce,
+ sec1::{self, EncodedPoint, FromEncodedPoint, ToEncodedPoint},
+ AffinePoint, FieldSize, PointCompression, PrimeCurve, ProjectiveArithmetic, PublicKey, Scalar,
+};
+use signature::{
+ digest::{Digest, FixedOutput},
+ hazmat::PrehashVerifier,
+ DigestVerifier, Verifier,
+};
+
+#[cfg(feature = "pkcs8")]
+use elliptic_curve::pkcs8::{self, AssociatedOid, DecodePublicKey};
+
+#[cfg(feature = "pem")]
+use elliptic_curve::pkcs8::EncodePublicKey;
+
+#[cfg(feature = "pem")]
+use core::str::FromStr;
+
+#[cfg(all(feature = "pem", feature = "serde"))]
+#[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "serde"))))]
+use serdect::serde::{de, ser, Deserialize, Serialize};
+
+/// ECDSA verification key (i.e. public key). Generic over elliptic curves.
+///
+/// Requires an [`elliptic_curve::ProjectiveArithmetic`] impl on the curve, and a
+/// [`VerifyPrimitive`] impl on its associated `AffinePoint` type.
+///
+/// # `serde` support
+///
+/// When the `serde` feature of this crate is enabled, it provides support for
+/// serializing and deserializing ECDSA signatures using the `Serialize` and
+/// `Deserialize` traits.
+///
+/// The serialization leverages the encoding used by the [`PublicKey`] type,
+/// which is a binary-oriented ASN.1 DER encoding.
+#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
+#[derive(Clone, Debug)]
+pub struct VerifyingKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+{
+ pub(crate) inner: PublicKey<C>,
+}
+
+impl<C> VerifyingKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+{
+ /// Initialize [`VerifyingKey`] from a SEC1-encoded public key.
+ pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> {
+ PublicKey::from_sec1_bytes(bytes)
+ .map(|pk| Self { inner: pk })
+ .map_err(|_| Error::new())
+ }
+
+ /// Initialize [`VerifyingKey`] from an affine point.
+ ///
+ /// Returns an [`Error`] if the given affine point is the additive identity
+ /// (a.k.a. point at infinity).
+ pub fn from_affine(affine: AffinePoint<C>) -> Result<Self> {
+ Ok(Self {
+ inner: PublicKey::from_affine(affine).map_err(|_| Error::new())?,
+ })
+ }
+
+ /// Initialize [`VerifyingKey`] from an [`EncodedPoint`].
+ pub fn from_encoded_point(public_key: &EncodedPoint<C>) -> Result<Self> {
+ Option::from(PublicKey::<C>::from_encoded_point(public_key))
+ .map(|public_key| Self { inner: public_key })
+ .ok_or_else(Error::new)
+ }
+
+ /// Serialize this [`VerifyingKey`] as a SEC1 [`EncodedPoint`], optionally
+ /// applying point compression.
+ pub fn to_encoded_point(&self, compress: bool) -> EncodedPoint<C> {
+ self.inner.to_encoded_point(compress)
+ }
+
+ /// Borrow the inner [`AffinePoint`] for this public key.
+ pub fn as_affine(&self) -> &AffinePoint<C> {
+ self.inner.as_affine()
+ }
+}
+
+impl<C> AsRef<AffinePoint<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+{
+ fn as_ref(&self) -> &AffinePoint<C> {
+ self.as_affine()
+ }
+}
+
+impl<C> Copy for VerifyingKey<C> where C: PrimeCurve + ProjectiveArithmetic {}
+
+impl<C, D> DigestVerifier<D, Signature<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ D: Digest + FixedOutput<OutputSize = FieldSize<C>>,
+ AffinePoint<C>: VerifyPrimitive<C>,
+ Scalar<C>: Reduce<C::UInt>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn verify_digest(&self, msg_digest: D, signature: &Signature<C>) -> Result<()> {
+ self.inner.as_affine().verify_digest(msg_digest, signature)
+ }
+}
+
+impl<C> PrehashVerifier<Signature<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive,
+ AffinePoint<C>: VerifyPrimitive<C>,
+ Scalar<C>: Reduce<C::UInt>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn verify_prehash(&self, prehash: &[u8], signature: &Signature<C>) -> Result<()> {
+ let prehash = C::prehash_to_field_bytes(prehash)?;
+ self.inner.as_affine().verify_prehashed(prehash, signature)
+ }
+}
+
+impl<C> Verifier<Signature<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive,
+ C::Digest: FixedOutput<OutputSize = FieldSize<C>>,
+ AffinePoint<C>: VerifyPrimitive<C>,
+ Scalar<C>: Reduce<C::UInt>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn verify(&self, msg: &[u8], signature: &Signature<C>) -> Result<()> {
+ self.verify_digest(C::Digest::new_with_prefix(msg), signature)
+ }
+}
+
+impl<C> From<&VerifyingKey<C>> for EncodedPoint<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+{
+ fn from(verifying_key: &VerifyingKey<C>) -> EncodedPoint<C> {
+ verifying_key.to_encoded_point(C::COMPRESS_POINTS)
+ }
+}
+
+impl<C> From<PublicKey<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+{
+ fn from(public_key: PublicKey<C>) -> VerifyingKey<C> {
+ VerifyingKey { inner: public_key }
+ }
+}
+
+impl<C> From<&PublicKey<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+{
+ fn from(public_key: &PublicKey<C>) -> VerifyingKey<C> {
+ (*public_key).into()
+ }
+}
+
+impl<C> From<VerifyingKey<C>> for PublicKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+{
+ fn from(verifying_key: VerifyingKey<C>) -> PublicKey<C> {
+ verifying_key.inner
+ }
+}
+
+impl<C> From<&VerifyingKey<C>> for PublicKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+{
+ fn from(verifying_key: &VerifyingKey<C>) -> PublicKey<C> {
+ (*verifying_key).into()
+ }
+}
+
+impl<C> Eq for VerifyingKey<C> where C: PrimeCurve + ProjectiveArithmetic {}
+
+impl<C> PartialEq for VerifyingKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+{
+ fn eq(&self, other: &Self) -> bool {
+ self.inner.eq(&other.inner)
+ }
+}
+
+impl<C> PartialOrd for VerifyingKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+{
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.inner.partial_cmp(&other.inner)
+ }
+}
+
+impl<C> Ord for VerifyingKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+{
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.inner.cmp(&other.inner)
+ }
+}
+
+impl<C> TryFrom<&[u8]> for VerifyingKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+{
+ type Error = Error;
+
+ fn try_from(bytes: &[u8]) -> Result<Self> {
+ Self::from_sec1_bytes(bytes)
+ }
+}
+
+#[cfg(feature = "pkcs8")]
+#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
+impl<C> TryFrom<pkcs8::SubjectPublicKeyInfo<'_>> for VerifyingKey<C>
+where
+ C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+{
+ type Error = pkcs8::spki::Error;
+
+ fn try_from(spki: pkcs8::SubjectPublicKeyInfo<'_>) -> pkcs8::spki::Result<Self> {
+ PublicKey::try_from(spki).map(|inner| Self { inner })
+ }
+}
+
+#[cfg(feature = "pkcs8")]
+#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
+impl<C> DecodePublicKey for VerifyingKey<C>
+where
+ C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+{
+}
+
+#[cfg(feature = "pem")]
+#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
+impl<C> EncodePublicKey for VerifyingKey<C>
+where
+ C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+{
+ fn to_public_key_der(&self) -> pkcs8::spki::Result<pkcs8::Document> {
+ self.inner.to_public_key_der()
+ }
+}
+
+#[cfg(feature = "pem")]
+#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
+impl<C> FromStr for VerifyingKey<C>
+where
+ C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+{
+ type Err = Error;
+
+ fn from_str(s: &str) -> Result<Self> {
+ Self::from_public_key_pem(s).map_err(|_| Error::new())
+ }
+}
+
+#[cfg(all(feature = "pem", feature = "serde"))]
+#[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "serde"))))]
+impl<C> Serialize for VerifyingKey<C>
+where
+ C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+{
+ fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ self.inner.serialize(serializer)
+ }
+}
+
+#[cfg(all(feature = "pem", feature = "serde"))]
+#[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "serde"))))]
+impl<'de, C> Deserialize<'de> for VerifyingKey<C>
+where
+ C: PrimeCurve + AssociatedOid + ProjectiveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+{
+ fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ PublicKey::<C>::deserialize(deserializer).map(Into::into)
+ }
+}