summaryrefslogtreecommitdiffstats
path: root/vendor/ecdsa/src/recovery.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:42 +0000
commit837b550238aa671a591ccf282dddeab29cadb206 (patch)
tree914b6b8862bace72bd3245ca184d374b08d8a672 /vendor/ecdsa/src/recovery.rs
parentAdding debian version 1.70.0+dfsg2-1. (diff)
downloadrustc-837b550238aa671a591ccf282dddeab29cadb206.tar.xz
rustc-837b550238aa671a591ccf282dddeab29cadb206.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/ecdsa/src/recovery.rs')
-rw-r--r--vendor/ecdsa/src/recovery.rs247
1 files changed, 247 insertions, 0 deletions
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;