summaryrefslogtreecommitdiffstats
path: root/vendor/ecdsa/src/hazmat.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:41:41 +0000
commit10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch)
treebdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/ecdsa/src/hazmat.rs
parentReleasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff)
downloadrustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz
rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/ecdsa/src/hazmat.rs')
-rw-r--r--vendor/ecdsa/src/hazmat.rs261
1 files changed, 261 insertions, 0 deletions
diff --git a/vendor/ecdsa/src/hazmat.rs b/vendor/ecdsa/src/hazmat.rs
new file mode 100644
index 000000000..3ca3fc4ce
--- /dev/null
+++ b/vendor/ecdsa/src/hazmat.rs
@@ -0,0 +1,261 @@
+//! Low-level ECDSA primitives.
+//!
+//! # ⚠️ Warning: Hazmat!
+//!
+//! YOU PROBABLY DON'T WANT TO USE THESE!
+//!
+//! These primitives are easy-to-misuse low-level interfaces.
+//!
+//! If you are an end user / non-expert in cryptography, do not use these!
+//! Failure to use them correctly can lead to catastrophic failures including
+//! FULL PRIVATE KEY RECOVERY!
+
+#[cfg(feature = "arithmetic")]
+use {
+ crate::{RecoveryId, SignatureSize},
+ core::borrow::Borrow,
+ elliptic_curve::{
+ group::Curve as _,
+ ops::{Invert, LinearCombination, Reduce},
+ subtle::CtOption,
+ AffineArithmetic, AffineXCoordinate, Field, Group, ProjectiveArithmetic, ProjectivePoint,
+ Scalar, ScalarArithmetic,
+ },
+};
+
+#[cfg(feature = "digest")]
+use {
+ core::cmp,
+ elliptic_curve::{bigint::Encoding, FieldSize},
+ signature::{digest::Digest, PrehashSignature},
+};
+
+#[cfg(any(feature = "arithmetic", feature = "digest"))]
+use crate::{
+ elliptic_curve::{generic_array::ArrayLength, FieldBytes, PrimeCurve},
+ Error, Result, Signature,
+};
+
+#[cfg(all(feature = "arithmetic", feature = "digest"))]
+use signature::digest::FixedOutput;
+
+#[cfg(all(feature = "rfc6979"))]
+use {
+ elliptic_curve::ScalarCore,
+ signature::digest::{core_api::BlockSizeUser, FixedOutputReset},
+};
+
+/// Try to sign the given prehashed message using ECDSA.
+///
+/// This trait is intended to be implemented on a type with access to the
+/// secret scalar via `&self`, such as particular curve's `Scalar` type.
+#[cfg(feature = "arithmetic")]
+#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
+pub trait SignPrimitive<C>: Field + Into<FieldBytes<C>> + Reduce<C::UInt> + Sized
+where
+ C: PrimeCurve + ProjectiveArithmetic + ScalarArithmetic<Scalar = Self>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// Try to sign the prehashed message.
+ ///
+ /// Accepts the following arguments:
+ ///
+ /// - `k`: ephemeral scalar value. MUST BE UNIFORMLY RANDOM!!!
+ /// - `z`: message digest to be signed. MUST BE OUTPUT OF A CRYPTOGRAPHICALLY
+ /// SECURE DIGEST ALGORITHM!!!
+ ///
+ /// # Returns
+ ///
+ /// ECDSA [`Signature`] and, when possible/desired, a [`RecoveryId`]
+ /// which can be used to recover the verifying key for a given signature.
+ #[allow(non_snake_case)]
+ fn try_sign_prehashed<K>(
+ &self,
+ k: K,
+ z: FieldBytes<C>,
+ ) -> Result<(Signature<C>, Option<RecoveryId>)>
+ where
+ K: Borrow<Self> + Invert<Output = CtOption<Self>>,
+ {
+ if k.borrow().is_zero().into() {
+ return Err(Error::new());
+ }
+
+ let z = Self::from_be_bytes_reduced(z);
+
+ // Compute scalar inversion of 𝑘
+ let k_inv = Option::<Scalar<C>>::from(k.invert()).ok_or_else(Error::new)?;
+
+ // Compute 𝑹 = 𝑘×𝑮
+ let R = (C::ProjectivePoint::generator() * k.borrow()).to_affine();
+
+ // Lift x-coordinate of 𝑹 (element of base field) into a serialized big
+ // integer, then reduce it into an element of the scalar field
+ let r = Self::from_be_bytes_reduced(R.x());
+
+ // Compute 𝒔 as a signature over 𝒓 and 𝒛.
+ let s = k_inv * (z + (r * self));
+
+ if s.is_zero().into() {
+ return Err(Error::new());
+ }
+
+ // TODO(tarcieri): support for computing recovery ID
+ Ok((Signature::from_scalars(r, s)?, None))
+ }
+
+ /// Try to sign the given message digest deterministically using the method
+ /// described in [RFC6979] for computing ECDSA ephemeral scalar `k`.
+ ///
+ /// Accepts the following parameters:
+ /// - `z`: message digest to be signed.
+ /// - `ad`: optional additional data, e.g. added entropy from an RNG
+ ///
+ /// [RFC6979]: https://datatracker.ietf.org/doc/html/rfc6979
+ #[cfg(all(feature = "rfc6979"))]
+ #[cfg_attr(docsrs, doc(cfg(feature = "rfc6979")))]
+ fn try_sign_prehashed_rfc6979<D>(
+ &self,
+ z: FieldBytes<C>,
+ ad: &[u8],
+ ) -> Result<(Signature<C>, Option<RecoveryId>)>
+ where
+ Self: From<ScalarCore<C>>,
+ C::UInt: for<'a> From<&'a Self>,
+ D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
+ {
+ let x = C::UInt::from(self);
+ let k = rfc6979::generate_k::<D, C::UInt>(&x, &C::ORDER, &z, ad);
+ let k = Self::from(ScalarCore::<C>::new(*k).unwrap());
+ self.try_sign_prehashed(k, z)
+ }
+
+ /// Try to sign the given digest instance using the method described in
+ /// [RFC6979].
+ ///
+ /// [RFC6979]: https://datatracker.ietf.org/doc/html/rfc6979
+ #[cfg(all(feature = "rfc6979"))]
+ #[cfg_attr(docsrs, doc(cfg(feature = "rfc6979")))]
+ fn try_sign_digest_rfc6979<D>(
+ &self,
+ msg_digest: D,
+ ad: &[u8],
+ ) -> Result<(Signature<C>, Option<RecoveryId>)>
+ where
+ Self: From<ScalarCore<C>>,
+ C::UInt: for<'a> From<&'a Self>,
+ D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
+ {
+ self.try_sign_prehashed_rfc6979::<D>(msg_digest.finalize_fixed(), ad)
+ }
+}
+
+/// Verify the given prehashed message using ECDSA.
+///
+/// This trait is intended to be implemented on type which can access
+/// the affine point represeting the public key via `&self`, such as a
+/// particular curve's `AffinePoint` type.
+#[cfg(feature = "arithmetic")]
+#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
+pub trait VerifyPrimitive<C>: AffineXCoordinate<C> + Copy + Sized
+where
+ C: PrimeCurve + AffineArithmetic<AffinePoint = Self> + ProjectiveArithmetic,
+ Scalar<C>: Reduce<C::UInt>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// Verify the prehashed message against the provided signature
+ ///
+ /// Accepts the following arguments:
+ ///
+ /// - `z`: message digest to be verified. MUST BE OUTPUT OF A
+ /// CRYPTOGRAPHICALLY SECURE DIGEST ALGORITHM!!!
+ /// - `sig`: signature to be verified against the key and message
+ fn verify_prehashed(&self, z: FieldBytes<C>, sig: &Signature<C>) -> Result<()> {
+ let z = Scalar::<C>::from_be_bytes_reduced(z);
+ let (r, s) = sig.split_scalars();
+ let s_inv = *s.invert();
+ let u1 = z * s_inv;
+ let u2 = *r * s_inv;
+ let x = ProjectivePoint::<C>::lincomb(
+ &ProjectivePoint::<C>::generator(),
+ &u1,
+ &ProjectivePoint::<C>::from(*self),
+ &u2,
+ )
+ .to_affine()
+ .x();
+
+ if Scalar::<C>::from_be_bytes_reduced(x) == *r {
+ Ok(())
+ } else {
+ Err(Error::new())
+ }
+ }
+
+ /// Verify message digest against the provided signature.
+ #[cfg(feature = "digest")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "digest")))]
+ fn verify_digest<D>(&self, msg_digest: D, sig: &Signature<C>) -> Result<()>
+ where
+ D: FixedOutput<OutputSize = FieldSize<C>>,
+ {
+ self.verify_prehashed(msg_digest.finalize_fixed(), sig)
+ }
+}
+
+/// Bind a preferred [`Digest`] algorithm to an elliptic curve type.
+///
+/// Generally there is a preferred variety of the SHA-2 family used with ECDSA
+/// for a particular elliptic curve.
+///
+/// This trait can be used to specify it, and with it receive a blanket impl of
+/// [`PrehashSignature`], used by [`signature_derive`][1]) for the [`Signature`]
+/// type for a particular elliptic curve.
+///
+/// [1]: https://github.com/RustCrypto/traits/tree/master/signature/derive
+#[cfg(feature = "digest")]
+#[cfg_attr(docsrs, doc(cfg(feature = "digest")))]
+pub trait DigestPrimitive: PrimeCurve {
+ /// Preferred digest to use when computing ECDSA signatures for this
+ /// elliptic curve. This is typically a member of the SHA-2 family.
+ // TODO(tarcieri): add BlockSizeUser + FixedOutput(Reset) bounds in next breaking release
+ // These bounds ensure the digest algorithm can be used for HMAC-DRBG for RFC6979
+ type Digest: Digest;
+
+ /// Compute field bytes for a prehash (message digest), either zero-padding
+ /// or truncating if the prehash size does not match the field size.
+ fn prehash_to_field_bytes(prehash: &[u8]) -> Result<FieldBytes<Self>> {
+ // Minimum allowed prehash size is half the field size
+ if prehash.len() < Self::UInt::BYTE_SIZE / 2 {
+ return Err(Error::new());
+ }
+
+ let mut field_bytes = FieldBytes::<Self>::default();
+
+ // This is a operation according to RFC6979 Section 2.3.2. and SEC1 Section 2.3.8.
+ // https://datatracker.ietf.org/doc/html/rfc6979#section-2.3.2
+ // https://www.secg.org/sec1-v2.pdf
+ match prehash.len().cmp(&Self::UInt::BYTE_SIZE) {
+ cmp::Ordering::Equal => field_bytes.copy_from_slice(prehash),
+ cmp::Ordering::Less => {
+ // If prehash is smaller than the field size, pad with zeroes on the left
+ field_bytes[(Self::UInt::BYTE_SIZE - prehash.len())..].copy_from_slice(prehash);
+ }
+ cmp::Ordering::Greater => {
+ // If prehash is larger than the field size, truncate
+ field_bytes.copy_from_slice(&prehash[..Self::UInt::BYTE_SIZE]);
+ }
+ }
+
+ Ok(field_bytes)
+ }
+}
+
+#[cfg(feature = "digest")]
+impl<C> PrehashSignature for Signature<C>
+where
+ C: DigestPrimitive,
+ <FieldSize<C> as core::ops::Add>::Output: ArrayLength<u8>,
+{
+ type Digest = C::Digest;
+}