summaryrefslogtreecommitdiffstats
path: root/vendor/ecdsa/src/sign.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/ecdsa/src/sign.rs')
-rw-r--r--vendor/ecdsa/src/sign.rs424
1 files changed, 424 insertions, 0 deletions
diff --git a/vendor/ecdsa/src/sign.rs b/vendor/ecdsa/src/sign.rs
new file mode 100644
index 000000000..12d00edb2
--- /dev/null
+++ b/vendor/ecdsa/src/sign.rs
@@ -0,0 +1,424 @@
+//! ECDSA signing key.
+
+// TODO(tarcieri): support for hardware crypto accelerators
+
+use crate::{
+ hazmat::{DigestPrimitive, SignPrimitive},
+ Error, Result, Signature, SignatureSize,
+};
+use core::fmt::{self, Debug};
+use elliptic_curve::{
+ generic_array::ArrayLength,
+ group::ff::PrimeField,
+ ops::{Invert, Reduce},
+ subtle::{Choice, ConstantTimeEq, CtOption},
+ zeroize::{Zeroize, ZeroizeOnDrop},
+ FieldBytes, FieldSize, NonZeroScalar, PrimeCurve, ProjectiveArithmetic, Scalar, SecretKey,
+};
+use signature::{
+ digest::{core_api::BlockSizeUser, Digest, FixedOutput, FixedOutputReset},
+ hazmat::PrehashSigner,
+ rand_core::{CryptoRng, RngCore},
+ DigestSigner, RandomizedDigestSigner, RandomizedSigner, Signer,
+};
+
+#[cfg(feature = "pem")]
+use {
+ crate::elliptic_curve::pkcs8::{EncodePrivateKey, SecretDocument},
+ core::str::FromStr,
+};
+
+#[cfg(feature = "pkcs8")]
+use crate::elliptic_curve::{
+ pkcs8::{self, AssociatedOid, DecodePrivateKey},
+ sec1::{self, FromEncodedPoint, ToEncodedPoint},
+ AffinePoint,
+};
+
+#[cfg(feature = "verify")]
+use {crate::verify::VerifyingKey, elliptic_curve::PublicKey, signature::Keypair};
+
+/// ECDSA signing key. Generic over elliptic curves.
+///
+/// Requires an [`elliptic_curve::ProjectiveArithmetic`] impl on the curve, and a
+/// [`SignPrimitive`] impl on its associated `Scalar` type.
+#[derive(Clone)]
+#[cfg_attr(docsrs, doc(cfg(feature = "sign")))]
+pub struct SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// ECDSA signing keys are non-zero elements of a given curve's scalar field.
+ secret_scalar: NonZeroScalar<C>,
+
+ /// Verifying key which corresponds to this signing key.
+ #[cfg(feature = "verify")]
+ verifying_key: VerifyingKey<C>,
+}
+
+impl<C> SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// Generate a cryptographically random [`SigningKey`].
+ pub fn random(rng: impl CryptoRng + RngCore) -> Self {
+ NonZeroScalar::<C>::random(rng).into()
+ }
+
+ /// Initialize signing key from a raw scalar serialized as a byte slice.
+ pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
+ SecretKey::<C>::from_be_bytes(bytes)
+ .map(|sk| sk.to_nonzero_scalar().into())
+ .map_err(|_| Error::new())
+ }
+
+ /// Serialize this [`SigningKey`] as bytes
+ pub fn to_bytes(&self) -> FieldBytes<C> {
+ self.secret_scalar.to_repr()
+ }
+
+ /// Borrow the secret [`NonZeroScalar`] value for this key.
+ ///
+ /// # ⚠️ Warning
+ ///
+ /// This value is key material.
+ ///
+ /// Please treat it with the care it deserves!
+ pub fn as_nonzero_scalar(&self) -> &NonZeroScalar<C> {
+ &self.secret_scalar
+ }
+
+ /// Get the [`VerifyingKey`] which corresponds to this [`SigningKey`]
+ // TODO(tarcieri): make this return `&VerifyingKey<C>` in the next breaking release
+ #[cfg(feature = "verify")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
+ pub fn verifying_key(&self) -> VerifyingKey<C> {
+ self.verifying_key
+ }
+}
+
+#[cfg(feature = "verify")]
+#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
+impl<C> AsRef<VerifyingKey<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn as_ref(&self) -> &VerifyingKey<C> {
+ &self.verifying_key
+ }
+}
+
+impl<C> ConstantTimeEq for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn ct_eq(&self, other: &Self) -> Choice {
+ self.secret_scalar.ct_eq(&other.secret_scalar)
+ }
+}
+
+impl<C> Debug for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("SigningKey").finish_non_exhaustive()
+ }
+}
+
+impl<C> Drop for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn drop(&mut self) {
+ self.secret_scalar.zeroize();
+ }
+}
+
+impl<C> ZeroizeOnDrop for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+}
+
+/// Constant-time comparison
+impl<C> Eq for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+}
+
+/// Constant-time comparison
+impl<C> PartialEq for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn eq(&self, other: &SigningKey<C>) -> bool {
+ self.ct_eq(other).into()
+ }
+}
+
+impl<C> From<SecretKey<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(secret_key: SecretKey<C>) -> Self {
+ Self::from(&secret_key)
+ }
+}
+
+impl<C> From<&SecretKey<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(secret_key: &SecretKey<C>) -> Self {
+ secret_key.to_nonzero_scalar().into()
+ }
+}
+
+impl<C> From<SigningKey<C>> for SecretKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(key: SigningKey<C>) -> Self {
+ key.secret_scalar.into()
+ }
+}
+
+impl<C> From<&SigningKey<C>> for SecretKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(secret_key: &SigningKey<C>) -> Self {
+ secret_key.secret_scalar.into()
+ }
+}
+
+impl<C, D> DigestSigner<D, Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ C::UInt: for<'a> From<&'a Scalar<C>>,
+ D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// Sign message digest using a deterministic ephemeral scalar (`k`)
+ /// computed using the algorithm described in [RFC6979 § 3.2].
+ ///
+ /// [RFC6979 § 3.2]: https://tools.ietf.org/html/rfc6979#section-3
+ fn try_sign_digest(&self, msg_digest: D) -> Result<Signature<C>> {
+ Ok(self
+ .secret_scalar
+ .try_sign_digest_rfc6979::<D>(msg_digest, &[])?
+ .0)
+ }
+}
+
+#[cfg(feature = "verify")]
+#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
+impl<C> Keypair<Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ type VerifyingKey = VerifyingKey<C>;
+}
+
+impl<C> PrehashSigner<Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive,
+ C::Digest: BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
+ C::UInt: for<'a> From<&'a Scalar<C>>,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature<C>> {
+ let prehash = C::prehash_to_field_bytes(prehash)?;
+
+ Ok(self
+ .secret_scalar
+ .try_sign_prehashed_rfc6979::<C::Digest>(prehash, &[])?
+ .0)
+ }
+}
+
+impl<C> Signer<Signature<C>> for SigningKey<C>
+where
+ Self: DigestSigner<C::Digest, Signature<C>>,
+ C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn try_sign(&self, msg: &[u8]) -> Result<Signature<C>> {
+ self.try_sign_digest(C::Digest::new_with_prefix(msg))
+ }
+}
+
+impl<C, D> RandomizedDigestSigner<D, Signature<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ C::UInt: for<'a> From<&'a Scalar<C>>,
+ D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ /// Sign message prehash using an ephemeral scalar (`k`) derived according
+ /// to a variant of RFC 6979 (Section 3.6) which supplies additional
+ /// entropy from an RNG.
+ fn try_sign_digest_with_rng(
+ &self,
+ mut rng: impl CryptoRng + RngCore,
+ msg_digest: D,
+ ) -> Result<Signature<C>> {
+ let mut ad = FieldBytes::<C>::default();
+ rng.fill_bytes(&mut ad);
+ Ok(self
+ .secret_scalar
+ .try_sign_digest_rfc6979::<D>(msg_digest, &ad)?
+ .0)
+ }
+}
+
+impl<C> RandomizedSigner<Signature<C>> for SigningKey<C>
+where
+ Self: RandomizedDigestSigner<C::Digest, Signature<C>>,
+ C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn try_sign_with_rng(&self, rng: impl CryptoRng + RngCore, msg: &[u8]) -> Result<Signature<C>> {
+ self.try_sign_digest_with_rng(rng, C::Digest::new_with_prefix(msg))
+ }
+}
+
+impl<C> From<NonZeroScalar<C>> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(secret_scalar: NonZeroScalar<C>) -> Self {
+ #[cfg(feature = "verify")]
+ let public_key = PublicKey::from_secret_scalar(&secret_scalar);
+
+ Self {
+ secret_scalar,
+ #[cfg(feature = "verify")]
+ verifying_key: public_key.into(),
+ }
+ }
+}
+
+impl<C> TryFrom<&[u8]> for SigningKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ type Error = Error;
+
+ fn try_from(bytes: &[u8]) -> Result<Self> {
+ Self::from_bytes(bytes)
+ }
+}
+
+#[cfg(feature = "verify")]
+impl<C> From<&SigningKey<C>> for VerifyingKey<C>
+where
+ C: PrimeCurve + ProjectiveArithmetic,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn from(signing_key: &SigningKey<C>) -> VerifyingKey<C> {
+ signing_key.verifying_key()
+ }
+}
+
+#[cfg(feature = "pkcs8")]
+#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
+impl<C> TryFrom<pkcs8::PrivateKeyInfo<'_>> for SigningKey<C>
+where
+ C: PrimeCurve + AssociatedOid + ProjectiveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ type Error = pkcs8::Error;
+
+ fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> {
+ SecretKey::try_from(private_key_info).map(Into::into)
+ }
+}
+
+#[cfg(feature = "pem")]
+#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
+impl<C> EncodePrivateKey for SigningKey<C>
+where
+ C: AssociatedOid + PrimeCurve + ProjectiveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
+ SecretKey::from(self.secret_scalar).to_pkcs8_der()
+ }
+}
+
+#[cfg(feature = "pkcs8")]
+#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
+impl<C> DecodePrivateKey for SigningKey<C>
+where
+ C: PrimeCurve + AssociatedOid + ProjectiveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+}
+
+#[cfg(feature = "pem")]
+#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
+impl<C> FromStr for SigningKey<C>
+where
+ C: PrimeCurve + AssociatedOid + ProjectiveArithmetic,
+ AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
+ FieldSize<C>: sec1::ModulusSize,
+ Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
+ SignatureSize<C>: ArrayLength<u8>,
+{
+ type Err = Error;
+
+ fn from_str(s: &str) -> Result<Self> {
+ Self::from_pkcs8_pem(s).map_err(|_| Error::new())
+ }
+}