diff --git a/ecdsa/src/der.rs b/ecdsa/src/der.rs index 1d13c5b0..5103b081 100644 --- a/ecdsa/src/der.rs +++ b/ecdsa/src/der.rs @@ -159,6 +159,17 @@ where } } +impl From> for Signature +where + C: PrimeCurve, + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn from(sig: crate::Signature) -> Signature { + sig.to_der() + } +} + impl TryFrom<&[u8]> for Signature where C: PrimeCurve, @@ -192,7 +203,7 @@ where } } -impl TryFrom> for super::Signature +impl TryFrom> for crate::Signature where C: PrimeCurve, MaxSize: ArrayLength, diff --git a/ecdsa/src/sign.rs b/ecdsa/src/sign.rs index 546f1415..6386b894 100644 --- a/ecdsa/src/sign.rs +++ b/ecdsa/src/sign.rs @@ -22,6 +22,9 @@ use signature::{ DigestSigner, RandomizedDigestSigner, RandomizedSigner, Signer, }; +#[cfg(feature = "der")] +use {crate::der, core::ops::Add}; + #[cfg(feature = "pem")] use { crate::elliptic_curve::pkcs8::{EncodePrivateKey, SecretDocument}, @@ -100,239 +103,303 @@ where } } -#[cfg(feature = "verify")] -#[cfg_attr(docsrs, doc(cfg(feature = "verify")))] -impl AsRef> for SigningKey +// +// `*Signer` trait impls +// + +impl DigestSigner> for SigningKey where C: PrimeCurve + ProjectiveArithmetic, + C::UInt: for<'a> From<&'a Scalar>, + D: Digest + BlockSizeUser + FixedOutput> + FixedOutputReset, Scalar: Invert>> + Reduce + SignPrimitive, + SignatureSize: ArrayLength, { - fn as_ref(&self) -> &VerifyingKey { - &self.verifying_key + /// 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> { + Ok(self + .secret_scalar + .try_sign_digest_rfc6979::(msg_digest, &[])? + .0) } } -impl ConstantTimeEq for SigningKey +impl PrehashSigner> for SigningKey where - C: PrimeCurve + ProjectiveArithmetic, + C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, + C::Digest: FixedOutput>, + C::UInt: for<'a> From<&'a Scalar>, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, { - fn ct_eq(&self, other: &Self) -> Choice { - self.secret_scalar.ct_eq(&other.secret_scalar) + fn sign_prehash(&self, prehash: &[u8]) -> Result> { + let prehash = C::prehash_to_field_bytes(prehash)?; + + Ok(self + .secret_scalar + .try_sign_prehashed_rfc6979::(prehash, &[])? + .0) } } -impl Debug for SigningKey +impl Signer> for SigningKey where - C: PrimeCurve + ProjectiveArithmetic, + Self: DigestSigner>, + C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SigningKey").finish_non_exhaustive() + fn try_sign(&self, msg: &[u8]) -> Result> { + self.try_sign_digest(C::Digest::new_with_prefix(msg)) } } -impl Drop for SigningKey +impl RandomizedDigestSigner> for SigningKey where C: PrimeCurve + ProjectiveArithmetic, + C::UInt: for<'a> From<&'a Scalar>, + D: Digest + BlockSizeUser + FixedOutput> + FixedOutputReset, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, { - fn drop(&mut self) { - self.secret_scalar.zeroize(); + /// 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> { + let mut ad = FieldBytes::::default(); + rng.fill_bytes(&mut ad); + Ok(self + .secret_scalar + .try_sign_digest_rfc6979::(msg_digest, &ad)? + .0) } } -impl ZeroizeOnDrop for SigningKey +impl RandomizedSigner> for SigningKey where - C: PrimeCurve + ProjectiveArithmetic, + Self: RandomizedDigestSigner>, + C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, { + fn try_sign_with_rng(&self, rng: impl CryptoRng + RngCore, msg: &[u8]) -> Result> { + self.try_sign_digest_with_rng(rng, C::Digest::new_with_prefix(msg)) + } } -/// Constant-time comparison -impl Eq for SigningKey +#[cfg(feature = "der")] +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl PrehashSigner> for SigningKey where - C: PrimeCurve + ProjectiveArithmetic, + C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, + C::Digest: BlockSizeUser + FixedOutput> + FixedOutputReset, + C::UInt: for<'a> From<&'a Scalar>, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, { + fn sign_prehash(&self, prehash: &[u8]) -> Result> { + PrehashSigner::>::sign_prehash(self, prehash).map(Into::into) + } } -/// Constant-time comparison -impl PartialEq for SigningKey +#[cfg(feature = "der")] +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl Signer> for SigningKey where - C: PrimeCurve + ProjectiveArithmetic, + Self: DigestSigner>, + C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, { - fn eq(&self, other: &SigningKey) -> bool { - self.ct_eq(other).into() + fn try_sign(&self, msg: &[u8]) -> Result> { + Signer::>::try_sign(self, msg).map(Into::into) } } -impl From> for SigningKey +#[cfg(feature = "der")] +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl RandomizedDigestSigner> for SigningKey where C: PrimeCurve + ProjectiveArithmetic, + C::UInt: for<'a> From<&'a Scalar>, + D: Digest + BlockSizeUser + FixedOutput> + FixedOutputReset, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, { - fn from(secret_key: SecretKey) -> Self { - Self::from(&secret_key) + fn try_sign_digest_with_rng( + &self, + rng: impl CryptoRng + RngCore, + msg_digest: D, + ) -> Result> { + RandomizedDigestSigner::>::try_sign_digest_with_rng(self, rng, msg_digest) + .map(Into::into) } } -impl From<&SecretKey> for SigningKey +#[cfg(feature = "der")] +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl RandomizedSigner> for SigningKey where - C: PrimeCurve + ProjectiveArithmetic, + Self: RandomizedDigestSigner>, + C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, { - fn from(secret_key: &SecretKey) -> Self { - secret_key.to_nonzero_scalar().into() + fn try_sign_with_rng( + &self, + rng: impl CryptoRng + RngCore, + msg: &[u8], + ) -> Result> { + RandomizedSigner::>::try_sign_with_rng(self, rng, msg).map(Into::into) } } -impl From> for SecretKey +// +// Other trait impls +// + +#[cfg(feature = "verify")] +#[cfg_attr(docsrs, doc(cfg(feature = "verify")))] +impl AsRef> for SigningKey where C: PrimeCurve + ProjectiveArithmetic, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, { - fn from(key: SigningKey) -> Self { - key.secret_scalar.into() + fn as_ref(&self) -> &VerifyingKey { + &self.verifying_key } } -impl From<&SigningKey> for SecretKey +impl ConstantTimeEq for SigningKey where C: PrimeCurve + ProjectiveArithmetic, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, { - fn from(secret_key: &SigningKey) -> Self { - secret_key.secret_scalar.into() + fn ct_eq(&self, other: &Self) -> Choice { + self.secret_scalar.ct_eq(&other.secret_scalar) } } -impl DigestSigner> for SigningKey +impl Debug for SigningKey where C: PrimeCurve + ProjectiveArithmetic, - C::UInt: for<'a> From<&'a Scalar>, - D: Digest + BlockSizeUser + FixedOutput> + FixedOutputReset, Scalar: Invert>> + Reduce + SignPrimitive, - SignatureSize: ArrayLength, { - /// 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> { - Ok(self - .secret_scalar - .try_sign_digest_rfc6979::(msg_digest, &[])? - .0) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SigningKey").finish_non_exhaustive() } } -#[cfg(feature = "verify")] -#[cfg_attr(docsrs, doc(cfg(feature = "verify")))] -impl KeypairRef for SigningKey +impl Drop for SigningKey where C: PrimeCurve + ProjectiveArithmetic, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, { - type VerifyingKey = VerifyingKey; + fn drop(&mut self) { + self.secret_scalar.zeroize(); + } } -impl PrehashSigner> for SigningKey +/// Constant-time comparison +impl Eq for SigningKey where - C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, - C::Digest: FixedOutput>, - C::UInt: for<'a> From<&'a Scalar>, + C: PrimeCurve + ProjectiveArithmetic, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, { - fn sign_prehash(&self, prehash: &[u8]) -> Result> { - let prehash = C::prehash_to_field_bytes(prehash)?; +} - Ok(self - .secret_scalar - .try_sign_prehashed_rfc6979::(prehash, &[])? - .0) +/// Constant-time comparison +impl PartialEq for SigningKey +where + C: PrimeCurve + ProjectiveArithmetic, + Scalar: Invert>> + Reduce + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn eq(&self, other: &SigningKey) -> bool { + self.ct_eq(other).into() } } -impl Signer> for SigningKey +impl From> for SigningKey where - Self: DigestSigner>, - C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, + C: PrimeCurve + ProjectiveArithmetic, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, { - fn try_sign(&self, msg: &[u8]) -> Result> { - self.try_sign_digest(C::Digest::new_with_prefix(msg)) + fn from(secret_scalar: NonZeroScalar) -> 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 RandomizedDigestSigner> for SigningKey +impl From> for SigningKey where C: PrimeCurve + ProjectiveArithmetic, - C::UInt: for<'a> From<&'a Scalar>, - D: Digest + BlockSizeUser + FixedOutput> + FixedOutputReset, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, { - /// 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> { - let mut ad = FieldBytes::::default(); - rng.fill_bytes(&mut ad); - Ok(self - .secret_scalar - .try_sign_digest_rfc6979::(msg_digest, &ad)? - .0) + fn from(secret_key: SecretKey) -> Self { + Self::from(&secret_key) } } -impl RandomizedSigner> for SigningKey +impl From<&SecretKey> for SigningKey where - Self: RandomizedDigestSigner>, - C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, + C: PrimeCurve + ProjectiveArithmetic, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, { - fn try_sign_with_rng(&self, rng: impl CryptoRng + RngCore, msg: &[u8]) -> Result> { - self.try_sign_digest_with_rng(rng, C::Digest::new_with_prefix(msg)) + fn from(secret_key: &SecretKey) -> Self { + secret_key.to_nonzero_scalar().into() } } -impl From> for SigningKey +impl From> for SecretKey where C: PrimeCurve + ProjectiveArithmetic, Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, { - fn from(secret_scalar: NonZeroScalar) -> Self { - #[cfg(feature = "verify")] - let public_key = PublicKey::from_secret_scalar(&secret_scalar); + fn from(key: SigningKey) -> Self { + key.secret_scalar.into() + } +} - Self { - secret_scalar, - #[cfg(feature = "verify")] - verifying_key: public_key.into(), - } +impl From<&SigningKey> for SecretKey +where + C: PrimeCurve + ProjectiveArithmetic, + Scalar: Invert>> + Reduce + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn from(secret_key: &SigningKey) -> Self { + secret_key.secret_scalar.into() } } @@ -349,6 +416,14 @@ where } } +impl ZeroizeOnDrop for SigningKey +where + C: PrimeCurve + ProjectiveArithmetic, + Scalar: Invert>> + Reduce + SignPrimitive, + SignatureSize: ArrayLength, +{ +} + #[cfg(feature = "verify")] impl From> for VerifyingKey where @@ -373,6 +448,17 @@ where } } +#[cfg(feature = "verify")] +#[cfg_attr(docsrs, doc(cfg(feature = "verify")))] +impl KeypairRef for SigningKey +where + C: PrimeCurve + ProjectiveArithmetic, + Scalar: Invert>> + Reduce + SignPrimitive, + SignatureSize: ArrayLength, +{ + type VerifyingKey = VerifyingKey; +} + #[cfg(feature = "pkcs8")] #[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] impl TryFrom> for SigningKey @@ -405,9 +491,9 @@ where } } -#[cfg(feature = "pkcs8")] -#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] -impl DecodePrivateKey for SigningKey +#[cfg(feature = "pem")] +#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] +impl FromStr for SigningKey where C: PrimeCurve + AssociatedOid + ProjectiveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, @@ -415,11 +501,16 @@ where Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, { + type Err = Error; + + fn from_str(s: &str) -> Result { + Self::from_pkcs8_pem(s).map_err(|_| Error::new()) + } } -#[cfg(feature = "pem")] -#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] -impl FromStr for SigningKey +#[cfg(feature = "pkcs8")] +#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))] +impl DecodePrivateKey for SigningKey where C: PrimeCurve + AssociatedOid + ProjectiveArithmetic, AffinePoint: FromEncodedPoint + ToEncodedPoint, @@ -427,9 +518,4 @@ where Scalar: Invert>> + Reduce + SignPrimitive, SignatureSize: ArrayLength, { - type Err = Error; - - fn from_str(s: &str) -> Result { - Self::from_pkcs8_pem(s).map_err(|_| Error::new()) - } } diff --git a/ecdsa/src/verify.rs b/ecdsa/src/verify.rs index 5aa8bcb8..a3f4015e 100644 --- a/ecdsa/src/verify.rs +++ b/ecdsa/src/verify.rs @@ -17,6 +17,9 @@ use signature::{ DigestVerifier, Verifier, }; +#[cfg(feature = "der")] +use {crate::der, core::ops::Add}; + #[cfg(feature = "pkcs8")] use elliptic_curve::pkcs8::{self, AssociatedOid, DecodePublicKey}; @@ -94,18 +97,9 @@ where } } -impl AsRef> for VerifyingKey -where - C: PrimeCurve + ProjectiveArithmetic, - AffinePoint: FromEncodedPoint + ToEncodedPoint, - FieldSize: sec1::ModulusSize, -{ - fn as_ref(&self) -> &AffinePoint { - self.as_affine() - } -} - -impl Copy for VerifyingKey where C: PrimeCurve + ProjectiveArithmetic {} +// +// `*Verifier` trait impls +// impl DigestVerifier> for VerifyingKey where @@ -146,6 +140,76 @@ where } } +#[cfg(feature = "der")] +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl DigestVerifier> for VerifyingKey +where + C: PrimeCurve + ProjectiveArithmetic, + D: Digest + FixedOutput>, + AffinePoint: VerifyPrimitive, + Scalar: Reduce, + SignatureSize: ArrayLength, + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn verify_digest(&self, msg_digest: D, signature: &der::Signature) -> Result<()> { + let signature = Signature::::try_from(signature.clone())?; + DigestVerifier::>::verify_digest(self, msg_digest, &signature) + } +} + +#[cfg(feature = "der")] +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl PrehashVerifier> for VerifyingKey +where + C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, + AffinePoint: VerifyPrimitive, + Scalar: Reduce, + SignatureSize: ArrayLength, + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn verify_prehash(&self, prehash: &[u8], signature: &der::Signature) -> Result<()> { + let signature = Signature::::try_from(signature.clone())?; + PrehashVerifier::>::verify_prehash(self, prehash, &signature) + } +} + +#[cfg(feature = "der")] +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl Verifier> for VerifyingKey +where + C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive, + C::Digest: FixedOutput>, + AffinePoint: VerifyPrimitive, + Scalar: Reduce, + SignatureSize: ArrayLength, + der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn verify(&self, msg: &[u8], signature: &der::Signature) -> Result<()> { + let signature = Signature::::try_from(signature.clone())?; + Verifier::>::verify(self, msg, &signature) + } +} + +// +// Other trait impls +// + +impl AsRef> for VerifyingKey +where + C: PrimeCurve + ProjectiveArithmetic, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldSize: sec1::ModulusSize, +{ + fn as_ref(&self) -> &AffinePoint { + self.as_affine() + } +} + +impl Copy for VerifyingKey where C: PrimeCurve + ProjectiveArithmetic {} + impl From<&VerifyingKey> for EncodedPoint where C: PrimeCurve + ProjectiveArithmetic + PointCompression, @@ -157,6 +221,17 @@ where } } +impl Eq for VerifyingKey where C: PrimeCurve + ProjectiveArithmetic {} + +impl PartialEq for VerifyingKey +where + C: PrimeCurve + ProjectiveArithmetic, +{ + fn eq(&self, other: &Self) -> bool { + self.inner.eq(&other.inner) + } +} + impl From> for VerifyingKey where C: PrimeCurve + ProjectiveArithmetic, @@ -193,17 +268,6 @@ where } } -impl Eq for VerifyingKey where C: PrimeCurve + ProjectiveArithmetic {} - -impl PartialEq for VerifyingKey -where - C: PrimeCurve + ProjectiveArithmetic, -{ - fn eq(&self, other: &Self) -> bool { - self.inner.eq(&other.inner) - } -} - impl PartialOrd for VerifyingKey where C: PrimeCurve + ProjectiveArithmetic,