summaryrefslogtreecommitdiffstats
path: root/vendor/ecdsa
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/ecdsa
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/ecdsa')
-rw-r--r--vendor/ecdsa/.cargo-checksum.json2
-rw-r--r--vendor/ecdsa/CHANGELOG.md97
-rw-r--r--vendor/ecdsa/Cargo.toml50
-rw-r--r--vendor/ecdsa/README.md4
-rw-r--r--vendor/ecdsa/src/der.rs240
-rw-r--r--vendor/ecdsa/src/dev.rs33
-rw-r--r--vendor/ecdsa/src/hazmat.rs235
-rw-r--r--vendor/ecdsa/src/lib.rs467
-rw-r--r--vendor/ecdsa/src/recovery.rs247
-rw-r--r--vendor/ecdsa/src/sign.rs424
-rw-r--r--vendor/ecdsa/src/signing.rs598
-rw-r--r--vendor/ecdsa/src/verify.rs325
-rw-r--r--vendor/ecdsa/src/verifying.rs482
13 files changed, 2149 insertions, 1055 deletions
diff --git a/vendor/ecdsa/.cargo-checksum.json b/vendor/ecdsa/.cargo-checksum.json
index 3f233a5f2..10d399ee2 100644
--- a/vendor/ecdsa/.cargo-checksum.json
+++ b/vendor/ecdsa/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"CHANGELOG.md":"3ce4bb9d644207d6be3015fb14fb8b21b5a5b1726d6e23e518069c09b72c3c6d","Cargo.toml":"8251cd573e1cccd72cc28d182555834efeced8c9b9b9d8b6f66dc45e66d7c88c","LICENSE-APACHE":"78779d420019e6b4630376af8e86b6b335ee8a2f89ede6e0411e0469a326aaa4","LICENSE-MIT":"bdebaf9156a298f8fdab56dd26cb5144673de522d80f4c0d88e0039145f147f9","README.md":"5b6363fc1dc18b5ea22dcb4e11481abd2c9fff9a5bce268296e119dc23cdc3d6","src/der.rs":"496d7b6047b4d346fa76c00b07db2cec06d935e552ced3abb939ea2a84a38c38","src/dev.rs":"2403e76837802f1587ea9b7da7ce62f6ae65b431691977f31bce71ae36639a05","src/hazmat.rs":"7baab4647e5e9fb2d918c69a8df557aef41e4b5cc92fc964592f315798603e40","src/lib.rs":"8a9f7e22c1ffe206eaaf0844ca4eaea29910f7cfd6dd61e3c95b1297c01931b0","src/recovery.rs":"7dd92127de3b33883ca1bf1eaadd4ce8176febe9b5c1353dc31fbee0c092a611","src/sign.rs":"6c360d0292e23c21dc5274a08ab98c5005df4b83a8d22871cfc91d4c413b0511","src/verify.rs":"19a759a7a8db7e0b17cbf6ba69a8fe2634089546b31a6423d86f8b693a6f1d7d","tests/lib.rs":"68922b3fb793f7f64a6fdf8aa59b6fb9432d4706d7ad1d82129a8337c5cf6568"},"package":"413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c"} \ No newline at end of file
+{"files":{"CHANGELOG.md":"3b692c15478b5aa15df17a094b84b03e0cfb6c56dbe8a5ec6d40b53ef1dcea2f","Cargo.toml":"09391aecb7abdf0ec8a55d81dad7f5df355562b286d2aca24b764243a8e06453","LICENSE-APACHE":"78779d420019e6b4630376af8e86b6b335ee8a2f89ede6e0411e0469a326aaa4","LICENSE-MIT":"bdebaf9156a298f8fdab56dd26cb5144673de522d80f4c0d88e0039145f147f9","README.md":"f99485065d3d5541ef1814ea8d3f75718f08cb78eb5626f9d34941799655b4b9","src/der.rs":"d3320fc6c6c3e5f08c8323c07bdf774a2f4cfc97d8951751c7e89232572167a7","src/dev.rs":"75d56ac79f04efc018b37eca752c7861579772a758cac94874ccf85aa880602a","src/hazmat.rs":"6d888d3389ac9d0431beed24b865260f0554271cdbb9aa24a6ca9341717fdfc7","src/lib.rs":"63f4d7ead0024b1fba3083c413a21e168d435d0917208be61c9fad868c84acdc","src/recovery.rs":"41141f9f4ffbd155c5167fbe749299496077c55e6b64ed83f65ced1372205623","src/signing.rs":"11842af046b43fe53add72a7fdc78a9555a1dbc37fe6bb0d1139e8b25491538f","src/verifying.rs":"c7441025d4ddcfce2c7701813d84c032364da4bd38bd28895a75d09eaca53ee3","tests/lib.rs":"68922b3fb793f7f64a6fdf8aa59b6fb9432d4706d7ad1d82129a8337c5cf6568"},"package":"a48e5d537b8a30c0b023116d981b16334be1485af7ca68db3a2b7024cbc957fd"} \ No newline at end of file
diff --git a/vendor/ecdsa/CHANGELOG.md b/vendor/ecdsa/CHANGELOG.md
index ba65d59cf..c551aaa8d 100644
--- a/vendor/ecdsa/CHANGELOG.md
+++ b/vendor/ecdsa/CHANGELOG.md
@@ -4,6 +4,103 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## 0.16.6 (2023-04-09)
+### Fixed
+- Test macro handling of serialized field size ([#707])
+
+[#707]: https://github.com/RustCrypto/signatures/pull/707
+
+## 0.16.5 (2023-04-08)
+### Fixed
+- Use `C::FieldBytesSize` instead of `C::Uint::BYTES` ([#705])
+
+[#705]: https://github.com/RustCrypto/signatures/pull/705
+
+## 0.16.4 (2023-04-05)
+### Fixed
+- `RecoveryId` computation in `SignPrimitive` ([#702])
+
+[#702]: https://github.com/RustCrypto/signatures/pull/702
+
+## 0.16.3 (2023-04-04)
+### Added
+- RFC5758 OID support ([#686])
+- `SignatureAlgorithmIdentifier` impls for `SigningKey`/`VerifyingKey` ([#688])
+- `SignatureWithOid` ([#689], [#690])
+- `AssociatedAlgorithmIdentifier` impls for `SigningKey`/`VerifyingKey` ([#698])
+
+### Changed
+- Loosen `signature` bound to `2.0, <2.2` ([#697])
+
+[#686]: https://github.com/RustCrypto/signatures/pull/686
+[#688]: https://github.com/RustCrypto/signatures/pull/688
+[#689]: https://github.com/RustCrypto/signatures/pull/689
+[#690]: https://github.com/RustCrypto/signatures/pull/690
+[#697]: https://github.com/RustCrypto/signatures/pull/697
+[#698]: https://github.com/RustCrypto/signatures/pull/698
+
+## 0.16.2 (2023-03-28)
+### Added
+- Handle the reduced R.x case in public key recovery ([#680])
+- `Signature::{from_bytes, from_slice}` methods ([#684])
+
+[#680]: https://github.com/RustCrypto/signatures/pull/680
+[#684]: https://github.com/RustCrypto/signatures/pull/684
+
+## 0.16.1 (2023-03-09)
+### Added
+- `VerifyingKey::to_sec1_bytes` + more conversions ([#675])
+
+[#675]: https://github.com/RustCrypto/signatures/pull/675
+
+## 0.16.0 (2023-03-01)
+### Added
+- `Decode` and `Encode` impls for `der::Signature` ([#666])
+
+### Changed
+- Use `Scalar::invert_vartime` for faster verification ([#651])
+- Bump `serdect` dependency to 0.2 ([#657])
+- Bump `elliptic-curve` dependency to v0.13; MSRV 1.65 ([#660], [#663])
+- Bump `rfc6979` dependency to v0.4 ([#662])
+
+[#651]: https://github.com/RustCrypto/signatures/pull/651
+[#657]: https://github.com/RustCrypto/signatures/pull/657
+[#660]: https://github.com/RustCrypto/signatures/pull/660
+[#662]: https://github.com/RustCrypto/signatures/pull/662
+[#666]: https://github.com/RustCrypto/signatures/pull/666
+
+## 0.15.1 (2023-01-23)
+### Added
+- `SigningKey::*_recoverable` methods ([#635])
+
+[#635]: https://github.com/RustCrypto/signatures/pull/635
+
+## 0.15.0 (2023-01-15)
+### Added
+- `DigestPrimitive::Digest` now has bounds that work with RFC6979 ([#568])
+- `*Signer`/`*Verifier` impls for `der::Signature` ([#569])
+- `VerifyingKey` recovery support ([#576])
+- Trial recovery support ([#580])
+
+### Changed
+- Signature now internally structured with `r` and `s` components ([#565])
+- `SigningKey::verifying_key` now returns a reference ([#567])
+- Refactor `prehash_to_field_bytes` to `bits2field` free function ([#574])
+- Rename `sign` feature to `signing` ([#610])
+- Rename `verify` feature to `verifying` features ([#610])
+- Bump `signature` crate dependency to v2.0 ([#614])
+
+[#565]: https://github.com/RustCrypto/signatures/pull/565
+[#567]: https://github.com/RustCrypto/signatures/pull/567
+[#574]: https://github.com/RustCrypto/signatures/pull/574
+[#580]: https://github.com/RustCrypto/signatures/pull/580
+[#568]: https://github.com/RustCrypto/signatures/pull/568
+[#569]: https://github.com/RustCrypto/signatures/pull/569
+[#576]: https://github.com/RustCrypto/signatures/pull/576
+[#580]: https://github.com/RustCrypto/signatures/pull/580
+[#610]: https://github.com/RustCrypto/signatures/pull/610
+[#614]: https://github.com/RustCrypto/signatures/pull/614
+
## 0.14.8 (2022-09-27)
### Added
- Impl `From<SigningKey>` for `SecretKey` ([#548])
diff --git a/vendor/ecdsa/Cargo.toml b/vendor/ecdsa/Cargo.toml
index 62a5410a5..5f0e94d97 100644
--- a/vendor/ecdsa/Cargo.toml
+++ b/vendor/ecdsa/Cargo.toml
@@ -11,9 +11,9 @@
[package]
edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
name = "ecdsa"
-version = "0.14.8"
+version = "0.16.6"
authors = ["RustCrypto Developers"]
description = """
Pure Rust implementation of the Elliptic Curve Digital Signature Algorithm
@@ -43,11 +43,17 @@ rustdoc-args = [
]
[dependencies.der]
-version = "0.6"
+version = "0.7"
optional = true
+[dependencies.digest]
+version = "0.10.6"
+features = ["oid"]
+optional = true
+default-features = false
+
[dependencies.elliptic-curve]
-version = "0.12"
+version = "0.13.3"
features = [
"digest",
"sec1",
@@ -55,37 +61,43 @@ features = [
default-features = false
[dependencies.rfc6979]
-version = "0.3"
+version = "0.4"
optional = true
[dependencies.serdect]
-version = "0.1"
+version = "0.2"
features = ["alloc"]
optional = true
default-features = false
+[dependencies.sha2]
+version = "0.10"
+features = ["oid"]
+optional = true
+default-features = false
+
[dependencies.signature]
-version = ">=1.6.2, <1.7"
-features = [
- "hazmat-preview",
- "rand-preview",
-]
+version = "2.0, <2.2"
+features = ["rand_core"]
default-features = false
[dev-dependencies.elliptic-curve]
-version = "0.12"
+version = "0.13"
features = ["dev"]
default-features = false
[dev-dependencies.hex-literal]
-version = "0.3"
+version = "0.4"
[dev-dependencies.sha2]
version = "0.10"
default-features = false
[features]
-alloc = []
+alloc = [
+ "elliptic-curve/alloc",
+ "signature/alloc",
+]
arithmetic = ["elliptic-curve/arithmetic"]
default = ["digest"]
dev = [
@@ -94,13 +106,17 @@ dev = [
"elliptic-curve/dev",
"hazmat",
]
-digest = ["signature/digest-preview"]
+digest = [
+ "dep:digest",
+ "signature/digest",
+]
hazmat = []
pem = [
"elliptic-curve/pem",
"pkcs8",
]
pkcs8 = [
+ "digest",
"elliptic-curve/pkcs8",
"der",
]
@@ -108,7 +124,7 @@ serde = [
"elliptic-curve/serde",
"serdect",
]
-sign = [
+signing = [
"arithmetic",
"digest",
"hazmat",
@@ -119,7 +135,7 @@ std = [
"elliptic-curve/std",
"signature/std",
]
-verify = [
+verifying = [
"arithmetic",
"digest",
"hazmat",
diff --git a/vendor/ecdsa/README.md b/vendor/ecdsa/README.md
index 6da609998..06ed0dc37 100644
--- a/vendor/ecdsa/README.md
+++ b/vendor/ecdsa/README.md
@@ -41,7 +41,7 @@ USE AT YOUR OWN RISK!
## Minimum Supported Rust Version
-This crate requires **Rust 1.57** at a minimum.
+This crate requires **Rust 1.65** at a minimum.
We may change the MSRV in the future, but it will be accompanied by a minor
version bump.
@@ -70,7 +70,7 @@ dual licensed as above, without any additional terms or conditions.
[build-image]: https://github.com/RustCrypto/signatures/actions/workflows/ecdsa.yml/badge.svg
[build-link]: https://github.com/RustCrypto/signatures/actions/workflows/ecdsa.yml
[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
-[rustc-image]: https://img.shields.io/badge/rustc-1.57+-blue.svg
+[rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg
[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260048-signatures
diff --git a/vendor/ecdsa/src/der.rs b/vendor/ecdsa/src/der.rs
index 5925df443..cb774232e 100644
--- a/vendor/ecdsa/src/der.rs
+++ b/vendor/ecdsa/src/der.rs
@@ -2,19 +2,21 @@
use crate::{Error, Result};
use core::{
- fmt,
+ fmt::{self, Debug},
ops::{Add, Range},
};
-use der::{asn1::UIntRef, Decode, Encode, Reader};
+use der::{asn1::UintRef, Decode, Encode, FixedTag, Length, Reader, Tag, Writer};
use elliptic_curve::{
- bigint::Encoding as _,
consts::U9,
- generic_array::{ArrayLength, GenericArray},
- FieldSize, PrimeCurve,
+ generic_array::{typenum::Unsigned, ArrayLength, GenericArray},
+ FieldBytesSize, PrimeCurve,
};
#[cfg(feature = "alloc")]
-use alloc::boxed::Box;
+use {
+ alloc::{boxed::Box, vec::Vec},
+ signature::SignatureEncoding,
+};
#[cfg(feature = "serde")]
use serdect::serde::{de, ser, Deserialize, Serialize};
@@ -36,7 +38,7 @@ use serdect::serde::{de, ser, Deserialize, Serialize};
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;
+pub type MaxSize<C> = <<FieldBytesSize<C> as Add>::Output as Add<MaxOverhead>>::Output;
/// Byte array containing a serialized ASN.1 signature
type SignatureBytes<C> = GenericArray<u8, MaxSize<C>>;
@@ -48,7 +50,7 @@ pub struct Signature<C>
where
C: PrimeCurve,
MaxSize<C>: ArrayLength<u8>,
- <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
{
/// ASN.1 DER-encoded signature data
bytes: SignatureBytes<C>,
@@ -60,45 +62,45 @@ where
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>,
+ <FieldBytesSize<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
- }
+ /// Parse signature from DER-encoded bytes.
+ pub fn from_bytes(input: &[u8]) -> Result<Self> {
+ let (r, s) = decode_der(input).map_err(|_| Error::new())?;
- /// Borrow this signature as a byte slice
- pub fn as_bytes(&self) -> &[u8] {
- &self.bytes.as_slice()[..self.len()]
- }
+ if r.as_bytes().len() > C::FieldBytesSize::USIZE
+ || s.as_bytes().len() > C::FieldBytesSize::USIZE
+ {
+ return Err(Error::new());
+ }
- /// 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()
+ 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,
+ })
}
- /// 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)?;
+ /// Create an ASN.1 DER encoded signature from big endian `r` and `s` scalar
+ /// components.
+ pub(crate) fn from_components(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);
@@ -114,6 +116,22 @@ where
.map_err(|_| der::Tag::Sequence.value_error())
}
+ /// 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()
+ }
+
+ /// Get the length of the signature in bytes
+ pub fn len(&self) -> usize {
+ self.s_range.end
+ }
+
/// Get the `r` component of the signature (leading zeros removed)
pub(crate) fn r(&self) -> &[u8] {
&self.bytes[self.r_range.clone()]
@@ -129,18 +147,33 @@ impl<C> AsRef<[u8]> for Signature<C>
where
C: PrimeCurve,
MaxSize<C>: ArrayLength<u8>,
- <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
{
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
-impl<C> fmt::Debug for Signature<C>
+impl<C> Clone for Signature<C>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ fn clone(&self) -> Self {
+ Self {
+ bytes: self.bytes.clone(),
+ r_range: self.r_range.clone(),
+ s_range: self.s_range.clone(),
+ }
+ }
+}
+
+impl<C> Debug for Signature<C>
where
C: PrimeCurve,
MaxSize<C>: ArrayLength<u8>,
- <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ecdsa::der::Signature<{:?}>(", C::default())?;
@@ -153,64 +186,125 @@ where
}
}
-impl<C> TryFrom<&[u8]> for Signature<C>
+impl<'a, C> Decode<'a> for Signature<C>
where
C: PrimeCurve,
MaxSize<C>: ArrayLength<u8>,
- <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
{
- type Error = Error;
+ fn decode<R: Reader<'a>>(reader: &mut R) -> der::Result<Self> {
+ let header = reader.peek_header()?;
+ header.tag.assert_eq(Tag::Sequence)?;
- fn try_from(input: &[u8]) -> Result<Self> {
- let (r, s) = decode_der(input).map_err(|_| Error::new())?;
+ let mut buf = SignatureBytes::<C>::default();
+ let len = (header.encoded_len()? + header.length)?;
+ let slice = buf
+ .get_mut(..usize::try_from(len)?)
+ .ok_or_else(|| reader.error(Tag::Sequence.length_error().kind()))?;
- if r.as_bytes().len() > C::UInt::BYTE_SIZE || s.as_bytes().len() > C::UInt::BYTE_SIZE {
- return Err(Error::new());
- }
+ reader.read_into(slice)?;
+ Self::from_bytes(slice).map_err(|_| Tag::Integer.value_error())
+ }
+}
- let r_range = find_scalar_range(input, r.as_bytes())?;
- let s_range = find_scalar_range(input, s.as_bytes())?;
+impl<C> Encode for Signature<C>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ fn encoded_len(&self) -> der::Result<Length> {
+ Length::try_from(self.len())
+ }
- if s_range.end != input.len() {
- return Err(Error::new());
- }
+ fn encode(&self, writer: &mut impl Writer) -> der::Result<()> {
+ writer.write(self.as_bytes())
+ }
+}
- let mut bytes = SignatureBytes::<C>::default();
- bytes[..s_range.end].copy_from_slice(input);
+impl<C> FixedTag for Signature<C>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ const TAG: Tag = Tag::Sequence;
+}
- Ok(Signature {
- bytes,
- r_range,
- s_range,
- })
+impl<C> From<crate::Signature<C>> for Signature<C>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ fn from(sig: crate::Signature<C>) -> Signature<C> {
+ sig.to_der()
+ }
+}
+
+impl<C> TryFrom<&[u8]> for Signature<C>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ type Error = Error;
+
+ fn try_from(input: &[u8]) -> Result<Self> {
+ Self::from_bytes(input)
}
}
-impl<C> TryFrom<Signature<C>> for super::Signature<C>
+impl<C> TryFrom<Signature<C>> for crate::Signature<C>
where
C: PrimeCurve,
MaxSize<C>: ArrayLength<u8>,
- <FieldSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+ <FieldBytesSize<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 r_begin = C::FieldBytesSize::USIZE.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[r_begin..C::FieldBytesSize::USIZE].copy_from_slice(sig.r());
bytes[s_begin..].copy_from_slice(sig.s());
Self::try_from(bytes.as_slice())
}
}
+#[cfg(feature = "alloc")]
+impl<C> From<Signature<C>> for Box<[u8]>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ fn from(signature: Signature<C>) -> Box<[u8]> {
+ signature.to_vec().into_boxed_slice()
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<C> SignatureEncoding for Signature<C>
+where
+ C: PrimeCurve,
+ MaxSize<C>: ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
+{
+ type Repr = Box<[u8]>;
+
+ fn to_vec(&self) -> Vec<u8> {
+ self.as_bytes().into()
+ }
+}
+
#[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>,
+ <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
{
fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
where
@@ -221,12 +315,11 @@ where
}
#[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>,
+ <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
{
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
where
@@ -239,14 +332,14 @@ where
}
/// Decode the `r` and `s` components of a DER-encoded ECDSA signature.
-fn decode_der(der_bytes: &[u8]) -> der::Result<(UIntRef<'_>, UIntRef<'_>)> {
+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)?;
+ let r = UintRef::decode(reader)?;
+ let s = UintRef::decode(reader)?;
Ok((r, s))
})?;
@@ -269,7 +362,7 @@ 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>,
+ <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
{
type Digest = C::Digest;
}
@@ -277,7 +370,6 @@ where
#[cfg(all(test, feature = "arithmetic"))]
mod tests {
use elliptic_curve::dev::MockCurve;
- use signature::Signature as _;
type Signature = crate::Signature<MockCurve>;
@@ -291,7 +383,7 @@ mod tests {
#[test]
fn test_fixed_to_asn1_signature_roundtrip() {
- let signature1 = Signature::from_bytes(&EXAMPLE_SIGNATURE).unwrap();
+ let signature1 = Signature::try_from(EXAMPLE_SIGNATURE.as_ref()).unwrap();
// Convert to ASN.1 DER and back
let asn1_signature = signature1.to_der();
diff --git a/vendor/ecdsa/src/dev.rs b/vendor/ecdsa/src/dev.rs
index ce00c7fbf..8c1b7c876 100644
--- a/vendor/ecdsa/src/dev.rs
+++ b/vendor/ecdsa/src/dev.rs
@@ -29,19 +29,20 @@ pub struct TestVector {
/// 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,
+ bigint::Encoding,
+ generic_array::{typenum::Unsigned, GenericArray},
+ group::ff::PrimeField,
+ Curve, CurveArithmetic, Scalar,
},
hazmat::SignPrimitive,
};
fn decode_scalar(bytes: &[u8]) -> Option<Scalar<$curve>> {
- if bytes.len() == <$curve as Curve>::UInt::BYTE_SIZE {
+ if bytes.len() == <$curve as Curve>::FieldBytesSize::USIZE {
Scalar::<$curve>::from_repr(GenericArray::clone_from_slice(bytes)).into()
} else {
None
@@ -53,8 +54,14 @@ macro_rules! new_signing_test {
for vector in $vectors {
let d = decode_scalar(vector.d).expect("invalid vector.d");
let k = decode_scalar(vector.k).expect("invalid vector.m");
+
+ assert_eq!(
+ <$curve as Curve>::FieldBytesSize::USIZE,
+ vector.m.len(),
+ "invalid vector.m (must be field-sized digest)"
+ );
let z = GenericArray::clone_from_slice(vector.m);
- let sig = d.try_sign_prehashed(k, z).expect("ECDSA sign failed").0;
+ 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());
@@ -65,7 +72,6 @@ macro_rules! new_signing_test {
/// Define ECDSA verification test.
#[macro_export]
-#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
macro_rules! new_verification_test {
($curve:path, $vectors:expr) => {
use $crate::{
@@ -73,7 +79,7 @@ macro_rules! new_verification_test {
generic_array::GenericArray,
group::ff::PrimeField,
sec1::{EncodedPoint, FromEncodedPoint},
- AffinePoint, ProjectiveArithmetic, Scalar,
+ AffinePoint, CurveArithmetic, Scalar,
},
hazmat::VerifyPrimitive,
Signature,
@@ -97,7 +103,7 @@ macro_rules! new_verification_test {
)
.unwrap();
- let result = q.verify_prehashed(z, &sig);
+ let result = q.verify_prehashed(&z, &sig);
assert!(result.is_ok());
}
}
@@ -122,7 +128,7 @@ macro_rules! new_verification_test {
Signature::from_scalars(GenericArray::clone_from_slice(vector.r), s_tweaked)
.unwrap();
- let result = q.verify_prehashed(z, &sig);
+ let result = q.verify_prehashed(&z, &sig);
assert!(result.is_err());
}
}
@@ -133,10 +139,13 @@ macro_rules! new_verification_test {
/// 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};
+ use $crate::{
+ elliptic_curve::{bigint::Integer, sec1::EncodedPoint},
+ signature::Verifier,
+ Signature,
+ };
#[test]
fn $name() {
@@ -148,7 +157,7 @@ macro_rules! new_wycheproof_test {
fn element_from_padded_slice<C: elliptic_curve::Curve>(
data: &[u8],
) -> elliptic_curve::FieldBytes<C> {
- let point_len = C::UInt::BYTE_SIZE;
+ let point_len = C::FieldBytesSize::USIZE;
if data.len() >= point_len {
let offset = data.len() - point_len;
for v in data.iter().take(offset) {
diff --git a/vendor/ecdsa/src/hazmat.rs b/vendor/ecdsa/src/hazmat.rs
index 3ca3fc4ce..6e59f2e2e 100644
--- a/vendor/ecdsa/src/hazmat.rs
+++ b/vendor/ecdsa/src/hazmat.rs
@@ -10,50 +10,53 @@
//! Failure to use them correctly can lead to catastrophic failures including
//! FULL PRIVATE KEY RECOVERY!
+use crate::{Error, Result};
+use core::cmp;
+use elliptic_curve::{generic_array::typenum::Unsigned, FieldBytes, PrimeCurve};
+
#[cfg(feature = "arithmetic")]
use {
crate::{RecoveryId, SignatureSize},
- core::borrow::Borrow,
elliptic_curve::{
- group::Curve as _,
- ops::{Invert, LinearCombination, Reduce},
+ ff::PrimeField,
+ group::{Curve as _, Group},
+ ops::{Invert, LinearCombination, MulByGenerator, Reduce},
+ point::AffineCoordinates,
+ scalar::IsHigh,
subtle::CtOption,
- AffineArithmetic, AffineXCoordinate, Field, Group, ProjectiveArithmetic, ProjectivePoint,
- Scalar, ScalarArithmetic,
+ CurveArithmetic, ProjectivePoint, Scalar,
},
};
#[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,
+ elliptic_curve::FieldBytesSize,
+ signature::{
+ digest::{core_api::BlockSizeUser, Digest, FixedOutput, FixedOutputReset},
+ PrehashSignature,
+ },
};
-#[cfg(all(feature = "arithmetic", feature = "digest"))]
-use signature::digest::FixedOutput;
+#[cfg(feature = "rfc6979")]
+use elliptic_curve::{FieldBytesEncoding, ScalarPrimitive};
-#[cfg(all(feature = "rfc6979"))]
-use {
- elliptic_curve::ScalarCore,
- signature::digest::{core_api::BlockSizeUser, FixedOutputReset},
-};
+#[cfg(any(feature = "arithmetic", feature = "digest"))]
+use crate::{elliptic_curve::generic_array::ArrayLength, Signature};
/// 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
+pub trait SignPrimitive<C>:
+ AsRef<Self>
+ + Into<FieldBytes<C>>
+ + IsHigh
+ + PrimeField<Repr = FieldBytes<C>>
+ + Reduce<C::Uint, Bytes = FieldBytes<C>>
+ + Sized
where
- C: PrimeCurve + ProjectiveArithmetic + ScalarArithmetic<Scalar = Self>,
+ C: PrimeCurve + CurveArithmetic + CurveArithmetic<Scalar = Self>,
SignatureSize<C>: ArrayLength<u8>,
{
/// Try to sign the prehashed message.
@@ -72,26 +75,27 @@ where
fn try_sign_prehashed<K>(
&self,
k: K,
- z: FieldBytes<C>,
+ z: &FieldBytes<C>,
) -> Result<(Signature<C>, Option<RecoveryId>)>
where
- K: Borrow<Self> + Invert<Output = CtOption<Self>>,
+ K: AsRef<Self> + Invert<Output = CtOption<Self>>,
{
- if k.borrow().is_zero().into() {
+ if k.as_ref().is_zero().into() {
return Err(Error::new());
}
- let z = Self::from_be_bytes_reduced(z);
+ let z = <Self as Reduce<C::Uint>>::reduce_bytes(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();
+ let R = ProjectivePoint::<C>::mul_by_generator(k.as_ref()).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());
+ let r = Self::reduce_bytes(&R.x());
+ let x_is_reduced = r.to_repr() != R.x();
// Compute 𝒔 as a signature over 𝒓 and 𝒛.
let s = k_inv * (z + (r * self));
@@ -100,8 +104,9 @@ where
return Err(Error::new());
}
- // TODO(tarcieri): support for computing recovery ID
- Ok((Signature::from_scalars(r, s)?, None))
+ let signature = Signature::from_scalars(r, s)?;
+ let recovery_id = RecoveryId::new(R.y_is_odd().into(), x_is_reduced);
+ Ok((signature, Some(recovery_id)))
}
/// Try to sign the given message digest deterministically using the method
@@ -113,40 +118,24 @@ where
///
/// [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>,
+ 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,
+ Self: From<ScalarPrimitive<C>> + Invert<Output = CtOption<Self>>,
+ D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldBytesSize<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)
- }
+ let k = Scalar::<C>::from_repr(rfc6979::generate_k::<D, _>(
+ &self.to_repr(),
+ &C::ORDER.encode_field_bytes(),
+ z,
+ ad,
+ ))
+ .unwrap();
- /// 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)
+ self.try_sign_prehashed::<Self>(k, z)
}
}
@@ -156,11 +145,9 @@ where
/// 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
+pub trait VerifyPrimitive<C>: AffineCoordinates<FieldRepr = FieldBytes<C>> + Copy + Sized
where
- C: PrimeCurve + AffineArithmetic<AffinePoint = Self> + ProjectiveArithmetic,
- Scalar<C>: Reduce<C::UInt>,
+ C: PrimeCurve + CurveArithmetic<AffinePoint = Self> + CurveArithmetic,
SignatureSize<C>: ArrayLength<u8>,
{
/// Verify the prehashed message against the provided signature
@@ -170,10 +157,10 @@ where
/// - `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);
+ fn verify_prehashed(&self, z: &FieldBytes<C>, sig: &Signature<C>) -> Result<()> {
+ let z = Scalar::<C>::reduce_bytes(z);
let (r, s) = sig.split_scalars();
- let s_inv = *s.invert();
+ let s_inv = *s.invert_vartime();
let u1 = z * s_inv;
let u2 = *r * s_inv;
let x = ProjectivePoint::<C>::lincomb(
@@ -185,7 +172,7 @@ where
.to_affine()
.x();
- if Scalar::<C>::from_be_bytes_reduced(x) == *r {
+ if *r == Scalar::<C>::reduce_bytes(&x) {
Ok(())
} else {
Err(Error::new())
@@ -194,12 +181,11 @@ where
/// 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>>,
+ D: FixedOutput<OutputSize = FieldBytesSize<C>>,
{
- self.verify_prehashed(msg_digest.finalize_fixed(), sig)
+ self.verify_prehashed(&msg_digest.finalize_fixed(), sig)
}
}
@@ -214,48 +200,91 @@ where
///
/// [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)
- }
+ type Digest: BlockSizeUser
+ + Digest
+ + FixedOutput<OutputSize = FieldBytesSize<Self>>
+ + FixedOutputReset;
}
#[cfg(feature = "digest")]
impl<C> PrehashSignature for Signature<C>
where
C: DigestPrimitive,
- <FieldSize<C> as core::ops::Add>::Output: ArrayLength<u8>,
+ <FieldBytesSize<C> as core::ops::Add>::Output: ArrayLength<u8>,
{
type Digest = C::Digest;
}
+
+/// Partial implementation of the `bits2int` function as defined in
+/// [RFC6979 § 2.3.2] as well as [SEC1] § 2.3.8.
+///
+/// This is used to convert a message digest whose size may be smaller or
+/// larger than the size of the curve's scalar field into a serialized
+/// (unreduced) field element.
+///
+/// [RFC6979 § 2.3.2]: https://datatracker.ietf.org/doc/html/rfc6979#section-2.3.2
+/// [SEC1]: https://www.secg.org/sec1-v2.pdf
+pub fn bits2field<C: PrimeCurve>(bits: &[u8]) -> Result<FieldBytes<C>> {
+ // Minimum allowed bits size is half the field size
+ if bits.len() < C::FieldBytesSize::USIZE / 2 {
+ return Err(Error::new());
+ }
+
+ let mut field_bytes = FieldBytes::<C>::default();
+
+ match bits.len().cmp(&C::FieldBytesSize::USIZE) {
+ cmp::Ordering::Equal => field_bytes.copy_from_slice(bits),
+ cmp::Ordering::Less => {
+ // If bits is smaller than the field size, pad with zeroes on the left
+ field_bytes[(C::FieldBytesSize::USIZE - bits.len())..].copy_from_slice(bits);
+ }
+ cmp::Ordering::Greater => {
+ // If bits is larger than the field size, truncate
+ field_bytes.copy_from_slice(&bits[..C::FieldBytesSize::USIZE]);
+ }
+ }
+
+ Ok(field_bytes)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::bits2field;
+ use elliptic_curve::dev::MockCurve;
+ use hex_literal::hex;
+
+ #[test]
+ fn bits2field_too_small() {
+ assert!(bits2field::<MockCurve>(b"").is_err());
+ }
+
+ #[test]
+ fn bits2field_size_less() {
+ let prehash = hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+ let field_bytes = bits2field::<MockCurve>(&prehash).unwrap();
+ assert_eq!(
+ field_bytes.as_slice(),
+ &hex!("00000000000000000000000000000000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
+ );
+ }
+
+ #[test]
+ fn bits2field_size_eq() {
+ let prehash = hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+ let field_bytes = bits2field::<MockCurve>(&prehash).unwrap();
+ assert_eq!(field_bytes.as_slice(), &prehash);
+ }
+
+ #[test]
+ fn bits2field_size_greater() {
+ let prehash = hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
+ let field_bytes = bits2field::<MockCurve>(&prehash).unwrap();
+ assert_eq!(
+ field_bytes.as_slice(),
+ &hex!("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
+ );
+ }
+}
diff --git a/vendor/ecdsa/src/lib.rs b/vendor/ecdsa/src/lib.rs
index 9e339ba8f..4842d507f 100644
--- a/vendor/ecdsa/src/lib.rs
+++ b/vendor/ecdsa/src/lib.rs
@@ -1,5 +1,5 @@
#![no_std]
-#![cfg_attr(docsrs, feature(doc_cfg))]
+#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/8f1a9894/logo.svg",
@@ -60,22 +60,15 @@ 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;
+#[cfg(feature = "signing")]
+mod signing;
+#[cfg(feature = "verifying")]
+mod verifying;
pub use crate::recovery::RecoveryId;
@@ -83,24 +76,20 @@ pub use crate::recovery::RecoveryId;
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;
+pub use signature::{self, Error, Result, SignatureEncoding};
-#[cfg(feature = "verify")]
-#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
-pub use crate::verify::VerifyingKey;
+#[cfg(feature = "signing")]
+pub use crate::signing::SigningKey;
+#[cfg(feature = "verifying")]
+pub use crate::verifying::VerifyingKey;
use core::{
fmt::{self, Debug},
ops::Add,
};
use elliptic_curve::{
- bigint::Encoding as _,
- generic_array::{sequence::Concat, ArrayLength, GenericArray},
- FieldBytes, FieldSize, ScalarCore,
+ generic_array::{sequence::Concat, typenum::Unsigned, ArrayLength, GenericArray},
+ FieldBytes, FieldBytesSize, ScalarPrimitive,
};
#[cfg(feature = "alloc")]
@@ -109,14 +98,76 @@ use alloc::vec::Vec;
#[cfg(feature = "arithmetic")]
use {
core::str,
- elliptic_curve::{ff::PrimeField, IsHigh, NonZeroScalar, ScalarArithmetic},
+ elliptic_curve::{scalar::IsHigh, CurveArithmetic, NonZeroScalar},
+};
+
+#[cfg(feature = "digest")]
+use digest::{
+ const_oid::{AssociatedOid, ObjectIdentifier},
+ Digest,
+};
+
+#[cfg(feature = "pkcs8")]
+use elliptic_curve::pkcs8::spki::{
+ der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier,
};
#[cfg(feature = "serde")]
use serdect::serde::{de, ser, Deserialize, Serialize};
+#[cfg(all(feature = "alloc", feature = "pkcs8"))]
+use elliptic_curve::pkcs8::spki::{
+ self, AlgorithmIdentifierOwned, DynAssociatedAlgorithmIdentifier,
+};
+
+/// OID for ECDSA with SHA-224 digests.
+///
+/// ```text
+/// ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+/// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 1 }
+/// ```
+// TODO(tarcieri): use `ObjectIdentifier::push_arc` when const unwrap is stable
+#[cfg(feature = "digest")]
+pub const ECDSA_SHA224_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.1");
+
+/// OID for ECDSA with SHA-256 digests.
+///
+/// ```text
+/// ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+/// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
+/// ```
+#[cfg(feature = "digest")]
+pub const ECDSA_SHA256_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.2");
+
+/// OID for ECDSA with SHA-384 digests.
+///
+/// ```text
+/// ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+/// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 }
+/// ```
+#[cfg(feature = "digest")]
+pub const ECDSA_SHA384_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.3");
+
+/// OID for ECDSA with SHA-512 digests.
+///
+/// ```text
+/// ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+/// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 }
+/// ```
+#[cfg(feature = "digest")]
+pub const ECDSA_SHA512_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.4");
+
+#[cfg(feature = "digest")]
+const SHA224_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.4");
+#[cfg(feature = "digest")]
+const SHA256_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.1");
+#[cfg(feature = "digest")]
+const SHA384_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.2");
+#[cfg(feature = "digest")]
+const SHA512_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.3");
+
/// Size of a fixed sized signature for the given elliptic curve.
-pub type SignatureSize<C> = <FieldSize<C> as Add>::Output;
+pub type SignatureSize<C> = <FieldBytesSize<C> as Add>::Output;
/// Fixed-size byte array containing an ECDSA signature
pub type SignatureBytes<C> = GenericArray<u8, SignatureSize<C>>;
@@ -144,11 +195,9 @@ pub type SignatureBytes<C> = GenericArray<u8, SignatureSize<C>>;
/// 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>,
+pub struct Signature<C: PrimeCurve> {
+ r: ScalarPrimitive<C>,
+ s: ScalarPrimitive<C>,
}
impl<C> Signature<C>
@@ -156,13 +205,34 @@ where
C: PrimeCurve,
SignatureSize<C>: ArrayLength<u8>,
{
- /// Parse a signature from ASN.1 DER
+ /// Parse a signature from fixed-with bytes.
+ pub fn from_bytes(bytes: &SignatureBytes<C>) -> Result<Self> {
+ let (r_bytes, s_bytes) = bytes.split_at(C::FieldBytesSize::USIZE);
+ let r = ScalarPrimitive::from_slice(r_bytes).map_err(|_| Error::new())?;
+ let s = ScalarPrimitive::from_slice(s_bytes).map_err(|_| Error::new())?;
+
+ if r.is_zero().into() || s.is_zero().into() {
+ return Err(Error::new());
+ }
+
+ Ok(Self { r, s })
+ }
+
+ /// Parse a signature from a byte slice.
+ pub fn from_slice(slice: &[u8]) -> Result<Self> {
+ if slice.len() == SignatureSize::<C>::USIZE {
+ Self::from_bytes(SignatureBytes::<C>::from_slice(slice))
+ } else {
+ Err(Error::new())
+ }
+ }
+
+ /// 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>,
+ <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
{
der::Signature::<C>::try_from(bytes).and_then(Self::try_from)
}
@@ -175,51 +245,50 @@ where
/// 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);
+ (self.r.to_bytes(), self.s.to_bytes())
+ }
- (
- GenericArray::clone_from_slice(r_bytes),
- GenericArray::clone_from_slice(s_bytes),
- )
+ /// Serialize this signature as bytes.
+ pub fn to_bytes(&self) -> SignatureBytes<C> {
+ let mut bytes = SignatureBytes::<C>::default();
+ let (r_bytes, s_bytes) = bytes.split_at_mut(C::FieldBytesSize::USIZE);
+ r_bytes.copy_from_slice(&self.r.to_bytes());
+ s_bytes.copy_from_slice(&self.s.to_bytes());
+ bytes
}
- /// Serialize this signature as ASN.1 DER
+ /// 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>,
+ <FieldBytesSize<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")
+ let (r, s) = self.split_bytes();
+ der::Signature::from_components(&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()
+ self.to_bytes().to_vec()
}
}
#[cfg(feature = "arithmetic")]
-#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
impl<C> Signature<C>
where
- C: PrimeCurve + ScalarArithmetic,
+ C: PrimeCurve + CurveArithmetic,
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")
+ NonZeroScalar::new(self.r.into()).unwrap()
}
/// 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")
+ NonZeroScalar::new(self.s.into()).unwrap()
}
/// Split the signature into its `r` and `s` scalars.
@@ -235,9 +304,8 @@ where
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());
+ result.s = ScalarPrimitive::from(-s);
Some(result)
} else {
None
@@ -245,48 +313,46 @@ where
}
}
-impl<C> signature::Signature for Signature<C>
+impl<C> Copy for Signature<C>
where
C: PrimeCurve,
SignatureSize<C>: ArrayLength<u8>,
+ <SignatureSize<C> as ArrayLength<u8>>::ArrayType: Copy,
{
- fn from_bytes(bytes: &[u8]) -> Result<Self> {
- Self::try_from(bytes)
- }
}
-impl<C> AsRef<[u8]> for Signature<C>
+impl<C> Debug for Signature<C>
where
C: PrimeCurve,
SignatureSize<C>: ArrayLength<u8>,
{
- fn as_ref(&self) -> &[u8] {
- self.bytes.as_slice()
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ecdsa::Signature<{:?}>(", C::default())?;
+
+ for byte in self.to_bytes() {
+ write!(f, "{:02X}", byte)?;
+ }
+
+ write!(f, ")")
}
}
-impl<C> Copy for Signature<C>
+impl<C> From<Signature<C>> for SignatureBytes<C>
where
C: PrimeCurve,
SignatureSize<C>: ArrayLength<u8>,
- <SignatureSize<C> as ArrayLength<u8>>::ArrayType: Copy,
{
+ fn from(signature: Signature<C>) -> SignatureBytes<C> {
+ signature.to_bytes()
+ }
}
-impl<C> Debug for Signature<C>
+impl<C> SignatureEncoding 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, ")")
- }
+ type Repr = SignatureBytes<C>;
}
impl<C> TryFrom<&[u8]> for Signature<C>
@@ -296,22 +362,8 @@ where
{
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),
- })
+ fn try_from(slice: &[u8]) -> Result<Self> {
+ Self::from_slice(slice)
}
}
@@ -331,7 +383,7 @@ where
SignatureSize<C>: ArrayLength<u8>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- for byte in &self.bytes {
+ for byte in self.to_bytes() {
write!(f, "{:02x}", byte)?;
}
Ok(())
@@ -344,7 +396,7 @@ where
SignatureSize<C>: ArrayLength<u8>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- for byte in &self.bytes {
+ for byte in self.to_bytes() {
write!(f, "{:02X}", byte)?;
}
Ok(())
@@ -352,16 +404,15 @@ where
}
#[cfg(feature = "arithmetic")]
-#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
impl<C> str::FromStr for Signature<C>
where
- C: PrimeCurve + ScalarArithmetic,
+ C: PrimeCurve + CurveArithmetic,
SignatureSize<C>: ArrayLength<u8>,
{
type Err = Error;
fn from_str(hex: &str) -> Result<Self> {
- if hex.as_bytes().len() != C::UInt::BYTE_SIZE * 4 {
+ if hex.as_bytes().len() != C::FieldBytesSize::USIZE * 4 {
return Err(Error::new());
}
@@ -374,7 +425,7 @@ where
return Err(Error::new());
}
- let (r_hex, s_hex) = hex.split_at(C::UInt::BYTE_SIZE * 2);
+ let (r_hex, s_hex) = hex.split_at(C::FieldBytesSize::USIZE * 2);
let r = r_hex
.parse::<NonZeroScalar<C>>()
@@ -388,8 +439,40 @@ where
}
}
+/// ECDSA [`ObjectIdentifier`] which identifies the digest used by default
+/// with the `Signer` and `Verifier` traits.
+///
+/// To support non-default digest algorithms, use the [`SignatureWithOid`]
+/// type instead.
+#[cfg(all(feature = "digest", feature = "hazmat"))]
+impl<C> AssociatedOid for Signature<C>
+where
+ C: hazmat::DigestPrimitive,
+ C::Digest: AssociatedOid,
+{
+ const OID: ObjectIdentifier = match ecdsa_oid_for_digest(C::Digest::OID) {
+ Some(oid) => oid,
+ None => panic!("no RFC5758 ECDSA OID defined for DigestPrimitive::Digest"),
+ };
+}
+
+/// ECDSA `AlgorithmIdentifier` which identifies the digest used by default
+/// with the `Signer` and `Verifier` traits.
+#[cfg(feature = "pkcs8")]
+impl<C> AssociatedAlgorithmIdentifier for Signature<C>
+where
+ C: PrimeCurve,
+ Self: AssociatedOid,
+{
+ type Params = AnyRef<'static>;
+
+ const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = AlgorithmIdentifierRef {
+ oid: Self::OID,
+ parameters: None,
+ };
+}
+
#[cfg(feature = "serde")]
-#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl<C> Serialize for Signature<C>
where
C: PrimeCurve,
@@ -399,12 +482,11 @@ where
where
S: ser::Serializer,
{
- serdect::array::serialize_hex_upper_or_bin(&self.bytes, serializer)
+ serdect::array::serialize_hex_upper_or_bin(&self.to_bytes(), serializer)
}
}
#[cfg(feature = "serde")]
-#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
impl<'de, C> Deserialize<'de> for Signature<C>
where
C: PrimeCurve,
@@ -419,3 +501,194 @@ where
Self::try_from(bytes.as_slice()).map_err(de::Error::custom)
}
}
+
+/// An extended [`Signature`] type which is parameterized by an
+/// `ObjectIdentifier` which identifies the ECDSA variant used by a
+/// particular signature.
+///
+/// Valid `ObjectIdentifiers` are defined in [RFC5758 § 3.2]:
+///
+/// - SHA-224: [`ECDSA_SHA224_OID`] (1.2.840.10045.4.3.1)
+/// - SHA-256: [`ECDSA_SHA256_OID`] (1.2.840.10045.4.3.2)
+/// - SHA-384: [`ECDSA_SHA384_OID`] (1.2.840.10045.4.3.3)
+/// - SHA-512: [`ECDSA_SHA512_OID`] (1.2.840.10045.4.3.4)
+///
+/// [RFC5758 § 3.2]: https://www.rfc-editor.org/rfc/rfc5758#section-3.2
+#[cfg(feature = "digest")]
+#[derive(Clone, Eq, PartialEq)]
+pub struct SignatureWithOid<C: PrimeCurve> {
+ /// Inner signature type.
+ signature: Signature<C>,
+
+ /// OID which identifies the ECDSA variant used.
+ ///
+ /// MUST be one of the ECDSA algorithm variants as defined in RFC5758.
+ ///
+ /// These OIDs begin with `1.2.840.10045.4`.
+ oid: ObjectIdentifier,
+}
+
+#[cfg(feature = "digest")]
+impl<C> SignatureWithOid<C>
+where
+ C: PrimeCurve,
+{
+ /// Create a new signature with an explicitly provided OID.
+ ///
+ /// OID must begin with `1.2.840.10045.4`, the [RFC5758] OID prefix for
+ /// ECDSA variants.
+ ///
+ /// [RFC5758]: https://www.rfc-editor.org/rfc/rfc5758#section-3.2
+ pub fn new(signature: Signature<C>, oid: ObjectIdentifier) -> Result<Self> {
+ // TODO(tarcieri): use `ObjectIdentifier::starts_with`
+ for (arc1, arc2) in ObjectIdentifier::new_unwrap("1.2.840.10045.4.3")
+ .arcs()
+ .zip(oid.arcs())
+ {
+ if arc1 != arc2 {
+ return Err(Error::new());
+ }
+ }
+
+ Ok(Self { signature, oid })
+ }
+
+ /// Create a new signature, determining the OID from the given digest.
+ ///
+ /// Supports SHA-2 family digests as enumerated in [RFC5758 § 3.2], i.e.
+ /// SHA-224, SHA-256, SHA-384, or SHA-512.
+ ///
+ /// [RFC5758 § 3.2]: https://www.rfc-editor.org/rfc/rfc5758#section-3.2
+ pub fn new_with_digest<D>(signature: Signature<C>) -> Result<Self>
+ where
+ D: AssociatedOid + Digest,
+ {
+ let oid = ecdsa_oid_for_digest(D::OID).ok_or_else(Error::new)?;
+ Ok(Self { signature, oid })
+ }
+
+ /// Parse a signature from fixed-with bytes.
+ pub fn from_bytes_with_digest<D>(bytes: &SignatureBytes<C>) -> Result<Self>
+ where
+ D: AssociatedOid + Digest,
+ SignatureSize<C>: ArrayLength<u8>,
+ {
+ Self::new_with_digest::<D>(Signature::<C>::from_bytes(bytes)?)
+ }
+
+ /// Parse a signature from a byte slice.
+ pub fn from_slice_with_digest<D>(slice: &[u8]) -> Result<Self>
+ where
+ D: AssociatedOid + Digest,
+ SignatureSize<C>: ArrayLength<u8>,
+ {
+ Self::new_with_digest::<D>(Signature::<C>::from_slice(slice)?)
+ }
+
+ /// Get the fixed-width ECDSA signature.
+ pub fn signature(&self) -> &Signature<C> {
+ &self.signature
+ }
+
+ /// Get the ECDSA OID for this signature.
+ pub fn oid(&self) -> ObjectIdentifier {
+ self.oid
+ }
+
+ /// Serialize this signature as bytes.
+ pub fn to_bytes(&self) -> SignatureBytes<C>
+ where
+ SignatureSize<C>: ArrayLength<u8>,
+ {
+ self.signature.to_bytes()
+ }
+}
+
+#[cfg(feature = "digest")]
+impl<C> Copy for SignatureWithOid<C>
+where
+ C: PrimeCurve,
+ SignatureSize<C>: ArrayLength<u8>,
+ <SignatureSize<C> as ArrayLength<u8>>::ArrayType: Copy,
+{
+}
+
+#[cfg(feature = "digest")]
+impl<C> From<SignatureWithOid<C>> for Signature<C>
+where
+ C: PrimeCurve,
+{
+ fn from(sig: SignatureWithOid<C>) -> Signature<C> {
+ sig.signature
+ }
+}
+
+#[cfg(feature = "digest")]
+impl<C> From<SignatureWithOid<C>> for SignatureBytes<C>
+where
+ C: PrimeCurve,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(signature: SignatureWithOid<C>) -> SignatureBytes<C> {
+ signature.to_bytes()
+ }
+}
+
+/// NOTE: this implementation assumes the default digest for the given elliptic
+/// curve as defined by [`hazmat::DigestPrimitive`].
+///
+/// When working with alternative digests, you will need to use e.g.
+/// [`SignatureWithOid::new_with_digest`].
+#[cfg(all(feature = "digest", feature = "hazmat"))]
+impl<C> SignatureEncoding for SignatureWithOid<C>
+where
+ C: hazmat::DigestPrimitive,
+ C::Digest: AssociatedOid,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ type Repr = SignatureBytes<C>;
+}
+
+/// NOTE: this implementation assumes the default digest for the given elliptic
+/// curve as defined by [`hazmat::DigestPrimitive`].
+///
+/// When working with alternative digests, you will need to use e.g.
+/// [`SignatureWithOid::new_with_digest`].
+#[cfg(all(feature = "digest", feature = "hazmat"))]
+impl<C> TryFrom<&[u8]> for SignatureWithOid<C>
+where
+ C: hazmat::DigestPrimitive,
+ C::Digest: AssociatedOid,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ type Error = Error;
+
+ fn try_from(slice: &[u8]) -> Result<Self> {
+ Self::new(Signature::<C>::from_slice(slice)?, C::Digest::OID)
+ }
+}
+
+#[cfg(all(feature = "alloc", feature = "pkcs8"))]
+impl<C> DynAssociatedAlgorithmIdentifier for SignatureWithOid<C>
+where
+ C: PrimeCurve,
+{
+ fn algorithm_identifier(&self) -> spki::Result<AlgorithmIdentifierOwned> {
+ Ok(AlgorithmIdentifierOwned {
+ oid: self.oid,
+ parameters: None,
+ })
+ }
+}
+
+/// Get the ECDSA OID for a given digest OID.
+#[cfg(feature = "digest")]
+const fn ecdsa_oid_for_digest(digest_oid: ObjectIdentifier) -> Option<ObjectIdentifier> {
+ match digest_oid {
+ SHA224_OID => Some(ECDSA_SHA224_OID),
+ SHA256_OID => Some(ECDSA_SHA256_OID),
+ SHA384_OID => Some(ECDSA_SHA384_OID),
+ SHA512_OID => Some(ECDSA_SHA512_OID),
+ _ => None,
+ }
+}
diff --git a/vendor/ecdsa/src/recovery.rs b/vendor/ecdsa/src/recovery.rs
index c923bbad7..dd1b6aed5 100644
--- a/vendor/ecdsa/src/recovery.rs
+++ b/vendor/ecdsa/src/recovery.rs
@@ -2,6 +2,38 @@
use crate::{Error, Result};
+#[cfg(feature = "signing")]
+use {
+ crate::{hazmat::SignPrimitive, SigningKey},
+ elliptic_curve::subtle::CtOption,
+ signature::{hazmat::PrehashSigner, DigestSigner, Signer},
+};
+
+#[cfg(feature = "verifying")]
+use {
+ crate::{hazmat::VerifyPrimitive, VerifyingKey},
+ elliptic_curve::{
+ bigint::CheckedAdd,
+ ops::{LinearCombination, Reduce},
+ point::DecompressPoint,
+ sec1::{self, FromEncodedPoint, ToEncodedPoint},
+ AffinePoint, FieldBytesEncoding, FieldBytesSize, Group, PrimeField, ProjectivePoint,
+ },
+ signature::hazmat::PrehashVerifier,
+};
+
+#[cfg(any(feature = "signing", feature = "verifying"))]
+use {
+ crate::{
+ hazmat::{bits2field, DigestPrimitive},
+ Signature, SignatureSize,
+ },
+ elliptic_curve::{
+ generic_array::ArrayLength, ops::Invert, CurveArithmetic, PrimeCurve, Scalar,
+ },
+ signature::digest::Digest,
+};
+
/// Recovery IDs, a.k.a. "recid".
///
/// This is an integer value `0`, `1`, `2`, or `3` included along with a
@@ -55,6 +87,74 @@ impl RecoveryId {
}
}
+#[cfg(feature = "verifying")]
+impl RecoveryId {
+ /// Given a public key, message, and signature, use trial recovery
+ /// to determine if a suitable recovery ID exists, or return an error
+ /// otherwise.
+ pub fn trial_recovery_from_msg<C>(
+ verifying_key: &VerifyingKey<C>,
+ msg: &[u8],
+ signature: &Signature<C>,
+ ) -> Result<Self>
+ where
+ C: DigestPrimitive + PrimeCurve + CurveArithmetic,
+ AffinePoint<C>:
+ DecompressPoint<C> + FromEncodedPoint<C> + ToEncodedPoint<C> + VerifyPrimitive<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+ SignatureSize<C>: ArrayLength<u8>,
+ {
+ Self::trial_recovery_from_digest(verifying_key, C::Digest::new_with_prefix(msg), signature)
+ }
+
+ /// Given a public key, message digest, and signature, use trial recovery
+ /// to determine if a suitable recovery ID exists, or return an error
+ /// otherwise.
+ pub fn trial_recovery_from_digest<C, D>(
+ verifying_key: &VerifyingKey<C>,
+ digest: D,
+ signature: &Signature<C>,
+ ) -> Result<Self>
+ where
+ C: PrimeCurve + CurveArithmetic,
+ D: Digest,
+ AffinePoint<C>:
+ DecompressPoint<C> + FromEncodedPoint<C> + ToEncodedPoint<C> + VerifyPrimitive<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+ SignatureSize<C>: ArrayLength<u8>,
+ {
+ Self::trial_recovery_from_prehash(verifying_key, &digest.finalize(), signature)
+ }
+
+ /// Given a public key, message digest, and signature, use trial recovery
+ /// to determine if a suitable recovery ID exists, or return an error
+ /// otherwise.
+ pub fn trial_recovery_from_prehash<C>(
+ verifying_key: &VerifyingKey<C>,
+ prehash: &[u8],
+ signature: &Signature<C>,
+ ) -> Result<Self>
+ where
+ C: PrimeCurve + CurveArithmetic,
+ AffinePoint<C>:
+ DecompressPoint<C> + FromEncodedPoint<C> + ToEncodedPoint<C> + VerifyPrimitive<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+ SignatureSize<C>: ArrayLength<u8>,
+ {
+ for id in 0..=Self::MAX {
+ let recovery_id = RecoveryId(id);
+
+ if let Ok(vk) = VerifyingKey::recover_from_prehash(prehash, signature, recovery_id) {
+ if verifying_key == &vk {
+ return Ok(recovery_id);
+ }
+ }
+ }
+
+ Err(Error::new())
+ }
+}
+
impl TryFrom<u8> for RecoveryId {
type Error = Error;
@@ -69,6 +169,153 @@ impl From<RecoveryId> for u8 {
}
}
+#[cfg(feature = "signing")]
+impl<C> SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// Sign the given message prehash, returning a signature and recovery ID.
+ pub fn sign_prehash_recoverable(&self, prehash: &[u8]) -> Result<(Signature<C>, RecoveryId)> {
+ let z = bits2field::<C>(prehash)?;
+ let (sig, recid) = self
+ .as_nonzero_scalar()
+ .try_sign_prehashed_rfc6979::<C::Digest>(&z, &[])?;
+
+ Ok((sig, recid.ok_or_else(Error::new)?))
+ }
+
+ /// Sign the given message digest, returning a signature and recovery ID.
+ pub fn sign_digest_recoverable<D>(&self, msg_digest: D) -> Result<(Signature<C>, RecoveryId)>
+ where
+ D: Digest,
+ {
+ self.sign_prehash_recoverable(&msg_digest.finalize())
+ }
+
+ /// Sign the given message, hashing it with the curve's default digest
+ /// function, and returning a signature and recovery ID.
+ pub fn sign_recoverable(&self, msg: &[u8]) -> Result<(Signature<C>, RecoveryId)> {
+ self.sign_digest_recoverable(C::Digest::new_with_prefix(msg))
+ }
+}
+
+#[cfg(feature = "signing")]
+impl<C, D> DigestSigner<D, (Signature<C>, RecoveryId)> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ D: Digest,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn try_sign_digest(&self, msg_digest: D) -> Result<(Signature<C>, RecoveryId)> {
+ self.sign_digest_recoverable(msg_digest)
+ }
+}
+
+#[cfg(feature = "signing")]
+impl<C> PrehashSigner<(Signature<C>, RecoveryId)> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn sign_prehash(&self, prehash: &[u8]) -> Result<(Signature<C>, RecoveryId)> {
+ self.sign_prehash_recoverable(prehash)
+ }
+}
+
+#[cfg(feature = "signing")]
+impl<C> Signer<(Signature<C>, RecoveryId)> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn try_sign(&self, msg: &[u8]) -> Result<(Signature<C>, RecoveryId)> {
+ self.sign_recoverable(msg)
+ }
+}
+
+#[cfg(feature = "verifying")]
+impl<C> VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ AffinePoint<C>:
+ DecompressPoint<C> + FromEncodedPoint<C> + ToEncodedPoint<C> + VerifyPrimitive<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// Recover a [`VerifyingKey`] from the given message, signature, and
+ /// [`RecoveryId`].
+ ///
+ /// The message is first hashed using this curve's [`DigestPrimitive`].
+ pub fn recover_from_msg(
+ msg: &[u8],
+ signature: &Signature<C>,
+ recovery_id: RecoveryId,
+ ) -> Result<Self>
+ where
+ C: DigestPrimitive,
+ {
+ Self::recover_from_digest(C::Digest::new_with_prefix(msg), signature, recovery_id)
+ }
+
+ /// Recover a [`VerifyingKey`] from the given message [`Digest`],
+ /// signature, and [`RecoveryId`].
+ pub fn recover_from_digest<D>(
+ msg_digest: D,
+ signature: &Signature<C>,
+ recovery_id: RecoveryId,
+ ) -> Result<Self>
+ where
+ D: Digest,
+ {
+ Self::recover_from_prehash(&msg_digest.finalize(), signature, recovery_id)
+ }
+
+ /// Recover a [`VerifyingKey`] from the given `prehash` of a message, the
+ /// signature over that prehashed message, and a [`RecoveryId`].
+ #[allow(non_snake_case)]
+ pub fn recover_from_prehash(
+ prehash: &[u8],
+ signature: &Signature<C>,
+ recovery_id: RecoveryId,
+ ) -> Result<Self> {
+ let (r, s) = signature.split_scalars();
+ let z = <Scalar<C> as Reduce<C::Uint>>::reduce_bytes(&bits2field::<C>(prehash)?);
+
+ let mut r_bytes = r.to_repr();
+ if recovery_id.is_x_reduced() {
+ match Option::<C::Uint>::from(
+ C::Uint::decode_field_bytes(&r_bytes).checked_add(&C::ORDER),
+ ) {
+ Some(restored) => r_bytes = restored.encode_field_bytes(),
+ // No reduction should happen here if r was reduced
+ None => return Err(Error::new()),
+ };
+ }
+ let R = AffinePoint::<C>::decompress(&r_bytes, u8::from(recovery_id.is_y_odd()).into());
+
+ if R.is_none().into() {
+ return Err(Error::new());
+ }
+
+ let R = ProjectivePoint::<C>::from(R.unwrap());
+ let r_inv = *r.invert();
+ let u1 = -(r_inv * z);
+ let u2 = r_inv * *s;
+ let pk = ProjectivePoint::<C>::lincomb(&ProjectivePoint::<C>::generator(), &u1, &R, &u2);
+ let vk = Self::from_affine(pk.into())?;
+
+ // Ensure signature verifies with the recovered key
+ vk.verify_prehash(prehash, signature)?;
+
+ Ok(vk)
+ }
+}
+
#[cfg(test)]
mod tests {
use super::RecoveryId;
diff --git a/vendor/ecdsa/src/sign.rs b/vendor/ecdsa/src/sign.rs
deleted file mode 100644
index 12d00edb2..000000000
--- a/vendor/ecdsa/src/sign.rs
+++ /dev/null
@@ -1,424 +0,0 @@
-//! 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/signing.rs b/vendor/ecdsa/src/signing.rs
new file mode 100644
index 000000000..3a40c6db3
--- /dev/null
+++ b/vendor/ecdsa/src/signing.rs
@@ -0,0 +1,598 @@
+//! ECDSA signing: producing signatures using a [`SigningKey`].
+
+use crate::{
+ ecdsa_oid_for_digest,
+ hazmat::{bits2field, DigestPrimitive, SignPrimitive},
+ Error, Result, Signature, SignatureSize, SignatureWithOid,
+};
+use core::fmt::{self, Debug};
+use digest::{const_oid::AssociatedOid, Digest, FixedOutput};
+use elliptic_curve::{
+ generic_array::ArrayLength,
+ group::ff::PrimeField,
+ ops::Invert,
+ subtle::{Choice, ConstantTimeEq, CtOption},
+ zeroize::{Zeroize, ZeroizeOnDrop},
+ CurveArithmetic, FieldBytes, FieldBytesSize, NonZeroScalar, PrimeCurve, Scalar, SecretKey,
+};
+use signature::{
+ hazmat::{PrehashSigner, RandomizedPrehashSigner},
+ rand_core::CryptoRngCore,
+ DigestSigner, RandomizedDigestSigner, RandomizedSigner, Signer,
+};
+
+#[cfg(feature = "der")]
+use {crate::der, core::ops::Add};
+
+#[cfg(feature = "pem")]
+use {
+ crate::elliptic_curve::pkcs8::{DecodePrivateKey, EncodePrivateKey, SecretDocument},
+ core::str::FromStr,
+};
+
+#[cfg(feature = "pkcs8")]
+use crate::elliptic_curve::{
+ pkcs8::{
+ self,
+ der::AnyRef,
+ spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier},
+ ObjectIdentifier,
+ },
+ sec1::{self, FromEncodedPoint, ToEncodedPoint},
+ AffinePoint,
+};
+
+#[cfg(feature = "verifying")]
+use {crate::VerifyingKey, elliptic_curve::PublicKey, signature::KeypairRef};
+
+/// ECDSA secret key used for signing. Generic over prime order elliptic curves
+/// (e.g. NIST P-curves)
+///
+/// Requires an [`elliptic_curve::CurveArithmetic`] impl on the curve, and a
+/// [`SignPrimitive`] impl on its associated `Scalar` type.
+///
+/// ## Usage
+///
+/// The [`signature`] crate defines the following traits which are the
+/// primary API for signing:
+///
+/// - [`Signer`]: sign a message using this key
+/// - [`DigestSigner`]: sign the output of a [`Digest`] using this key
+/// - [`PrehashSigner`]: sign the low-level raw output bytes of a message digest
+///
+/// See the [`p256` crate](https://docs.rs/p256/latest/p256/ecdsa/index.html)
+/// for examples of using this type with a concrete elliptic curve.
+#[derive(Clone)]
+pub struct SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + 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 = "verifying")]
+ verifying_key: VerifyingKey<C>,
+}
+
+impl<C> SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// Generate a cryptographically random [`SigningKey`].
+ pub fn random(rng: &mut impl CryptoRngCore) -> Self {
+ NonZeroScalar::<C>::random(rng).into()
+ }
+
+ /// Initialize signing key from a raw scalar serialized as a byte array.
+ pub fn from_bytes(bytes: &FieldBytes<C>) -> Result<Self> {
+ SecretKey::<C>::from_bytes(bytes)
+ .map(Into::into)
+ .map_err(|_| Error::new())
+ }
+
+ /// Initialize signing key from a raw scalar serialized as a byte slice.
+ pub fn from_slice(bytes: &[u8]) -> Result<Self> {
+ SecretKey::<C>::from_slice(bytes)
+ .map(Into::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`].
+ #[cfg(feature = "verifying")]
+ pub fn verifying_key(&self) -> &VerifyingKey<C> {
+ &self.verifying_key
+ }
+}
+
+//
+// `*Signer` trait impls
+//
+
+/// 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
+impl<C, D> DigestSigner<D, Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn try_sign_digest(&self, msg_digest: D) -> Result<Signature<C>> {
+ self.sign_prehash(&msg_digest.finalize_fixed())
+ }
+}
+
+/// Sign message prehash 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
+impl<C> PrehashSigner<Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature<C>> {
+ let z = bits2field::<C>(prehash)?;
+ Ok(self
+ .secret_scalar
+ .try_sign_prehashed_rfc6979::<C::Digest>(&z, &[])?
+ .0)
+ }
+}
+
+/// Sign message 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
+impl<C> Signer<Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + 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 + CurveArithmetic + DigestPrimitive,
+ D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn try_sign_digest_with_rng(
+ &self,
+ rng: &mut impl CryptoRngCore,
+ msg_digest: D,
+ ) -> Result<Signature<C>> {
+ self.sign_prehash_with_rng(rng, &msg_digest.finalize_fixed())
+ }
+}
+
+impl<C> RandomizedPrehashSigner<Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn sign_prehash_with_rng(
+ &self,
+ rng: &mut impl CryptoRngCore,
+ prehash: &[u8],
+ ) -> Result<Signature<C>> {
+ let z = bits2field::<C>(prehash)?;
+ let mut ad = FieldBytes::<C>::default();
+ rng.fill_bytes(&mut ad);
+ Ok(self
+ .secret_scalar
+ .try_sign_prehashed_rfc6979::<C::Digest>(&z, &ad)?
+ .0)
+ }
+}
+
+impl<C> RandomizedSigner<Signature<C>> for SigningKey<C>
+where
+ Self: RandomizedDigestSigner<C::Digest, Signature<C>>,
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn try_sign_with_rng(&self, rng: &mut impl CryptoRngCore, msg: &[u8]) -> Result<Signature<C>> {
+ self.try_sign_digest_with_rng(rng, C::Digest::new_with_prefix(msg))
+ }
+}
+
+impl<C, D> DigestSigner<D, SignatureWithOid<C>> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ D: AssociatedOid + Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn try_sign_digest(&self, msg_digest: D) -> Result<SignatureWithOid<C>> {
+ let signature: Signature<C> = self.try_sign_digest(msg_digest)?;
+ let oid = ecdsa_oid_for_digest(D::OID).ok_or_else(Error::new)?;
+ SignatureWithOid::new(signature, oid)
+ }
+}
+
+impl<C> Signer<SignatureWithOid<C>> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ C::Digest: AssociatedOid,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn try_sign(&self, msg: &[u8]) -> Result<SignatureWithOid<C>> {
+ self.try_sign_digest(C::Digest::new_with_prefix(msg))
+ }
+}
+
+#[cfg(feature = "der")]
+impl<C> PrehashSigner<der::Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+ der::MaxSize<C>: ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
+{
+ fn sign_prehash(&self, prehash: &[u8]) -> Result<der::Signature<C>> {
+ PrehashSigner::<Signature<C>>::sign_prehash(self, prehash).map(Into::into)
+ }
+}
+
+#[cfg(feature = "der")]
+impl<C> Signer<der::Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+ der::MaxSize<C>: ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
+{
+ fn try_sign(&self, msg: &[u8]) -> Result<der::Signature<C>> {
+ Signer::<Signature<C>>::try_sign(self, msg).map(Into::into)
+ }
+}
+
+#[cfg(feature = "der")]
+impl<C, D> RandomizedDigestSigner<D, der::Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+ der::MaxSize<C>: ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
+{
+ fn try_sign_digest_with_rng(
+ &self,
+ rng: &mut impl CryptoRngCore,
+ msg_digest: D,
+ ) -> Result<der::Signature<C>> {
+ RandomizedDigestSigner::<D, Signature<C>>::try_sign_digest_with_rng(self, rng, msg_digest)
+ .map(Into::into)
+ }
+}
+
+#[cfg(feature = "der")]
+impl<C> RandomizedPrehashSigner<der::Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+ der::MaxSize<C>: ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
+{
+ fn sign_prehash_with_rng(
+ &self,
+ rng: &mut impl CryptoRngCore,
+ prehash: &[u8],
+ ) -> Result<der::Signature<C>> {
+ RandomizedPrehashSigner::<Signature<C>>::sign_prehash_with_rng(self, rng, prehash)
+ .map(Into::into)
+ }
+}
+
+#[cfg(feature = "der")]
+impl<C> RandomizedSigner<der::Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+ der::MaxSize<C>: ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
+{
+ fn try_sign_with_rng(
+ &self,
+ rng: &mut impl CryptoRngCore,
+ msg: &[u8],
+ ) -> Result<der::Signature<C>> {
+ RandomizedSigner::<Signature<C>>::try_sign_with_rng(self, rng, msg).map(Into::into)
+ }
+}
+
+//
+// Other trait impls
+//
+
+#[cfg(feature = "verifying")]
+impl<C> AsRef<VerifyingKey<C>> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn as_ref(&self) -> &VerifyingKey<C> {
+ &self.verifying_key
+ }
+}
+
+impl<C> ConstantTimeEq for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + 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 + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + 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 + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn drop(&mut self) {
+ self.secret_scalar.zeroize();
+ }
+}
+
+/// Constant-time comparison
+impl<C> Eq for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+}
+impl<C> PartialEq for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn eq(&self, other: &SigningKey<C>) -> bool {
+ self.ct_eq(other).into()
+ }
+}
+
+impl<C> From<NonZeroScalar<C>> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(secret_scalar: NonZeroScalar<C>) -> Self {
+ #[cfg(feature = "verifying")]
+ let public_key = PublicKey::from_secret_scalar(&secret_scalar);
+
+ Self {
+ secret_scalar,
+ #[cfg(feature = "verifying")]
+ verifying_key: public_key.into(),
+ }
+ }
+}
+
+impl<C> From<SecretKey<C>> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + 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 + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + 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 + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + 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 + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(secret_key: &SigningKey<C>) -> Self {
+ secret_key.secret_scalar.into()
+ }
+}
+
+impl<C> TryFrom<&[u8]> for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ type Error = Error;
+
+ fn try_from(bytes: &[u8]) -> Result<Self> {
+ Self::from_slice(bytes)
+ }
+}
+
+impl<C> ZeroizeOnDrop for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+}
+
+#[cfg(feature = "verifying")]
+impl<C> From<SigningKey<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(signing_key: SigningKey<C>) -> VerifyingKey<C> {
+ signing_key.verifying_key
+ }
+}
+
+#[cfg(feature = "verifying")]
+impl<C> From<&SigningKey<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(signing_key: &SigningKey<C>) -> VerifyingKey<C> {
+ signing_key.verifying_key
+ }
+}
+
+#[cfg(feature = "verifying")]
+impl<C> KeypairRef for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ type VerifyingKey = VerifyingKey<C>;
+}
+
+#[cfg(feature = "pkcs8")]
+impl<C> AssociatedAlgorithmIdentifier for SigningKey<C>
+where
+ C: AssociatedOid + CurveArithmetic + PrimeCurve,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ type Params = ObjectIdentifier;
+
+ const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> =
+ SecretKey::<C>::ALGORITHM_IDENTIFIER;
+}
+
+#[cfg(feature = "pkcs8")]
+impl<C> SignatureAlgorithmIdentifier for SigningKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+ Signature<C>: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
+{
+ type Params = AnyRef<'static>;
+
+ const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
+ Signature::<C>::ALGORITHM_IDENTIFIER;
+}
+
+#[cfg(feature = "pkcs8")]
+impl<C> TryFrom<pkcs8::PrivateKeyInfo<'_>> for SigningKey<C>
+where
+ C: PrimeCurve + AssociatedOid + CurveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + 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")]
+impl<C> EncodePrivateKey for SigningKey<C>
+where
+ C: AssociatedOid + PrimeCurve + CurveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
+ SecretKey::from(self.secret_scalar).to_pkcs8_der()
+ }
+}
+
+#[cfg(feature = "pem")]
+impl<C> FromStr for SigningKey<C>
+where
+ C: PrimeCurve + AssociatedOid + CurveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + 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
deleted file mode 100644
index 5aa8bcb8d..000000000
--- a/vendor/ecdsa/src/verify.rs
+++ /dev/null
@@ -1,325 +0,0 @@
-//! 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)
- }
-}
diff --git a/vendor/ecdsa/src/verifying.rs b/vendor/ecdsa/src/verifying.rs
new file mode 100644
index 000000000..4ac0570ca
--- /dev/null
+++ b/vendor/ecdsa/src/verifying.rs
@@ -0,0 +1,482 @@
+//! ECDSA verifying: checking signatures are authentic using a [`VerifyingKey`].
+
+use crate::{
+ hazmat::{bits2field, DigestPrimitive, VerifyPrimitive},
+ Error, Result, Signature, SignatureSize,
+};
+use core::{cmp::Ordering, fmt::Debug};
+use elliptic_curve::{
+ generic_array::ArrayLength,
+ point::PointCompression,
+ sec1::{self, CompressedPoint, EncodedPoint, FromEncodedPoint, ToEncodedPoint},
+ AffinePoint, CurveArithmetic, FieldBytesSize, PrimeCurve, PublicKey,
+};
+use signature::{
+ digest::{Digest, FixedOutput},
+ hazmat::PrehashVerifier,
+ DigestVerifier, Verifier,
+};
+
+#[cfg(feature = "alloc")]
+use alloc::boxed::Box;
+
+#[cfg(feature = "der")]
+use {crate::der, core::ops::Add};
+
+#[cfg(feature = "pem")]
+use {
+ core::str::FromStr,
+ elliptic_curve::pkcs8::{DecodePublicKey, EncodePublicKey},
+};
+
+#[cfg(feature = "pkcs8")]
+use elliptic_curve::pkcs8::{
+ self,
+ der::AnyRef,
+ spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier},
+ AssociatedOid, ObjectIdentifier,
+};
+
+#[cfg(feature = "sha2")]
+use {
+ crate::{
+ SignatureWithOid, ECDSA_SHA224_OID, ECDSA_SHA256_OID, ECDSA_SHA384_OID, ECDSA_SHA512_OID,
+ },
+ sha2::{Sha224, Sha256, Sha384, Sha512},
+};
+
+#[cfg(all(feature = "pem", feature = "serde"))]
+use serdect::serde::{de, ser, Deserialize, Serialize};
+
+/// ECDSA public key used for verifying signatures. Generic over prime order
+/// elliptic curves (e.g. NIST P-curves)
+///
+/// Requires an [`elliptic_curve::CurveArithmetic`] impl on the curve, and a
+/// [`VerifyPrimitive`] impl on its associated `AffinePoint` type.
+///
+/// ## Usage
+///
+/// The [`signature`] crate defines the following traits which are the
+/// primary API for verifying:
+///
+/// - [`Verifier`]: verify a message against a provided key and signature
+/// - [`DigestVerifier`]: verify a message [`Digest`] against a provided key and signature
+/// - [`PrehashVerifier`]: verify the low-level raw output bytes of a message digest
+///
+/// See the [`p256` crate](https://docs.rs/p256/latest/p256/ecdsa/index.html)
+/// for examples of using this type with a concrete elliptic curve.
+///
+/// # `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.
+#[derive(Clone, Debug)]
+pub struct VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+{
+ pub(crate) inner: PublicKey<C>,
+}
+
+impl<C> VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<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)
+ }
+
+ /// Convert this [`VerifyingKey`] into the
+ /// `Elliptic-Curve-Point-to-Octet-String` encoding described in
+ /// SEC 1: Elliptic Curve Cryptography (Version 2.0) section 2.3.3
+ /// (page 10).
+ ///
+ /// <http://www.secg.org/sec1-v2.pdf>
+ #[cfg(feature = "alloc")]
+ pub fn to_sec1_bytes(&self) -> Box<[u8]>
+ where
+ C: PointCompression,
+ {
+ self.inner.to_sec1_bytes()
+ }
+
+ /// Borrow the inner [`AffinePoint`] for this public key.
+ pub fn as_affine(&self) -> &AffinePoint<C> {
+ self.inner.as_affine()
+ }
+}
+
+//
+// `*Verifier` trait impls
+//
+
+impl<C, D> DigestVerifier<D, Signature<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
+ AffinePoint<C>: VerifyPrimitive<C>,
+ 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 + CurveArithmetic,
+ AffinePoint<C>: VerifyPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn verify_prehash(&self, prehash: &[u8], signature: &Signature<C>) -> Result<()> {
+ let field = bits2field::<C>(prehash)?;
+ self.inner.as_affine().verify_prehashed(&field, signature)
+ }
+}
+
+impl<C> Verifier<Signature<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ AffinePoint<C>: VerifyPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn verify(&self, msg: &[u8], signature: &Signature<C>) -> Result<()> {
+ self.verify_digest(C::Digest::new_with_prefix(msg), signature)
+ }
+}
+
+#[cfg(feature = "sha2")]
+impl<C> Verifier<SignatureWithOid<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ AffinePoint<C>: VerifyPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn verify(&self, msg: &[u8], sig: &SignatureWithOid<C>) -> Result<()> {
+ match sig.oid() {
+ ECDSA_SHA224_OID => self.verify_prehash(&Sha224::digest(msg), sig.signature()),
+ ECDSA_SHA256_OID => self.verify_prehash(&Sha256::digest(msg), sig.signature()),
+ ECDSA_SHA384_OID => self.verify_prehash(&Sha384::digest(msg), sig.signature()),
+ ECDSA_SHA512_OID => self.verify_prehash(&Sha512::digest(msg), sig.signature()),
+ _ => Err(Error::new()),
+ }
+ }
+}
+
+#[cfg(feature = "der")]
+impl<C, D> DigestVerifier<D, der::Signature<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
+ AffinePoint<C>: VerifyPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+ der::MaxSize<C>: ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
+{
+ fn verify_digest(&self, msg_digest: D, signature: &der::Signature<C>) -> Result<()> {
+ let signature = Signature::<C>::try_from(signature.clone())?;
+ DigestVerifier::<D, Signature<C>>::verify_digest(self, msg_digest, &signature)
+ }
+}
+
+#[cfg(feature = "der")]
+impl<C> PrehashVerifier<der::Signature<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ AffinePoint<C>: VerifyPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+ der::MaxSize<C>: ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
+{
+ fn verify_prehash(&self, prehash: &[u8], signature: &der::Signature<C>) -> Result<()> {
+ let signature = Signature::<C>::try_from(signature.clone())?;
+ PrehashVerifier::<Signature<C>>::verify_prehash(self, prehash, &signature)
+ }
+}
+
+#[cfg(feature = "der")]
+impl<C> Verifier<der::Signature<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic + DigestPrimitive,
+ AffinePoint<C>: VerifyPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+ der::MaxSize<C>: ArrayLength<u8>,
+ <FieldBytesSize<C> as Add>::Output: Add<der::MaxOverhead> + ArrayLength<u8>,
+{
+ fn verify(&self, msg: &[u8], signature: &der::Signature<C>) -> Result<()> {
+ let signature = Signature::<C>::try_from(signature.clone())?;
+ Verifier::<Signature<C>>::verify(self, msg, &signature)
+ }
+}
+
+//
+// Other trait impls
+//
+
+impl<C> AsRef<AffinePoint<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+{
+ fn as_ref(&self) -> &AffinePoint<C> {
+ self.as_affine()
+ }
+}
+
+impl<C> Copy for VerifyingKey<C> where C: PrimeCurve + CurveArithmetic {}
+
+impl<C> From<VerifyingKey<C>> for CompressedPoint<C>
+where
+ C: PrimeCurve + CurveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+{
+ fn from(verifying_key: VerifyingKey<C>) -> CompressedPoint<C> {
+ verifying_key.inner.into()
+ }
+}
+
+impl<C> From<&VerifyingKey<C>> for CompressedPoint<C>
+where
+ C: PrimeCurve + CurveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+{
+ fn from(verifying_key: &VerifyingKey<C>) -> CompressedPoint<C> {
+ verifying_key.inner.into()
+ }
+}
+
+impl<C> From<VerifyingKey<C>> for EncodedPoint<C>
+where
+ C: PrimeCurve + CurveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+{
+ fn from(verifying_key: VerifyingKey<C>) -> EncodedPoint<C> {
+ verifying_key.inner.into()
+ }
+}
+
+impl<C> From<&VerifyingKey<C>> for EncodedPoint<C>
+where
+ C: PrimeCurve + CurveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+{
+ fn from(verifying_key: &VerifyingKey<C>) -> EncodedPoint<C> {
+ verifying_key.inner.into()
+ }
+}
+
+impl<C> Eq for VerifyingKey<C> where C: PrimeCurve + CurveArithmetic {}
+
+impl<C> PartialEq for VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+{
+ fn eq(&self, other: &Self) -> bool {
+ self.inner.eq(&other.inner)
+ }
+}
+
+impl<C> From<PublicKey<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+{
+ fn from(public_key: PublicKey<C>) -> VerifyingKey<C> {
+ VerifyingKey { inner: public_key }
+ }
+}
+
+impl<C> From<&PublicKey<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+{
+ fn from(public_key: &PublicKey<C>) -> VerifyingKey<C> {
+ (*public_key).into()
+ }
+}
+
+impl<C> From<VerifyingKey<C>> for PublicKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+{
+ fn from(verifying_key: VerifyingKey<C>) -> PublicKey<C> {
+ verifying_key.inner
+ }
+}
+
+impl<C> From<&VerifyingKey<C>> for PublicKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+{
+ fn from(verifying_key: &VerifyingKey<C>) -> PublicKey<C> {
+ (*verifying_key).into()
+ }
+}
+
+impl<C> PartialOrd for VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<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 + CurveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+{
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.inner.cmp(&other.inner)
+ }
+}
+
+impl<C> TryFrom<&[u8]> for VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+{
+ type Error = Error;
+
+ fn try_from(bytes: &[u8]) -> Result<Self> {
+ Self::from_sec1_bytes(bytes)
+ }
+}
+
+#[cfg(feature = "pkcs8")]
+impl<C> AssociatedAlgorithmIdentifier for VerifyingKey<C>
+where
+ C: AssociatedOid + CurveArithmetic + PrimeCurve,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+{
+ type Params = ObjectIdentifier;
+
+ const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<ObjectIdentifier> =
+ PublicKey::<C>::ALGORITHM_IDENTIFIER;
+}
+
+#[cfg(feature = "pkcs8")]
+impl<C> SignatureAlgorithmIdentifier for VerifyingKey<C>
+where
+ C: PrimeCurve + CurveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+ Signature<C>: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
+{
+ type Params = AnyRef<'static>;
+
+ const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
+ Signature::<C>::ALGORITHM_IDENTIFIER;
+}
+
+#[cfg(feature = "pkcs8")]
+impl<C> TryFrom<pkcs8::SubjectPublicKeyInfoRef<'_>> for VerifyingKey<C>
+where
+ C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+{
+ type Error = pkcs8::spki::Error;
+
+ fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> {
+ PublicKey::try_from(spki).map(|inner| Self { inner })
+ }
+}
+
+#[cfg(feature = "pem")]
+impl<C> EncodePublicKey for VerifyingKey<C>
+where
+ C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<C>: sec1::ModulusSize,
+{
+ fn to_public_key_der(&self) -> pkcs8::spki::Result<pkcs8::Document> {
+ self.inner.to_public_key_der()
+ }
+}
+
+#[cfg(feature = "pem")]
+impl<C> FromStr for VerifyingKey<C>
+where
+ C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<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"))]
+impl<C> Serialize for VerifyingKey<C>
+where
+ C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<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"))]
+impl<'de, C> Deserialize<'de> for VerifyingKey<C>
+where
+ C: PrimeCurve + AssociatedOid + CurveArithmetic + PointCompression,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldBytesSize<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)
+ }
+}