use crate::{
hazmat::{DigestPrimitive, FromDigest, SignPrimitive},
rfc6979, Error, Signature, SignatureSize,
};
use elliptic_curve::{
ff::PrimeField, generic_array::ArrayLength, ops::Invert, subtle::ConstantTimeEq,
weierstrass::Curve, zeroize::Zeroize, FieldBytes, NonZeroScalar, ProjectiveArithmetic, Scalar,
SecretKey,
};
use signature::{
digest::{BlockInput, Digest, FixedOutput, Reset, Update},
rand_core::{CryptoRng, RngCore},
DigestSigner, RandomizedDigestSigner, RandomizedSigner,
};
#[cfg(feature = "verify")]
use {
crate::verify::VerifyingKey,
core::fmt::Debug,
elliptic_curve::{AffinePoint, ProjectivePoint},
};
#[cfg(feature = "pkcs8")]
use crate::elliptic_curve::{
consts::U1,
ops::Add,
pkcs8::{self, FromPrivateKey},
sec1::{FromEncodedPoint, ToEncodedPoint, UncompressedPointSize, UntaggedPointSize},
AlgorithmParameters,
};
#[cfg(feature = "pem")]
use core::str::FromStr;
#[cfg_attr(docsrs, doc(cfg(feature = "sign")))]
pub struct SigningKey<C>
where
C: Curve + ProjectiveArithmetic,
Scalar<C>: PrimeField<Repr = FieldBytes<C>>
+ FromDigest<C>
+ Invert<Output = Scalar<C>>
+ SignPrimitive<C>
+ Zeroize,
SignatureSize<C>: ArrayLength<u8>,
{
inner: SecretKey<C>,
}
impl<C> SigningKey<C>
where
C: Curve + ProjectiveArithmetic,
Scalar<C>: PrimeField<Repr = FieldBytes<C>>
+ FromDigest<C>
+ Invert<Output = Scalar<C>>
+ SignPrimitive<C>
+ Zeroize,
SignatureSize<C>: ArrayLength<u8>,
{
pub fn random(rng: impl CryptoRng + RngCore) -> Self {
Self {
inner: SecretKey::random(rng),
}
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
SecretKey::from_bytes(bytes)
.map(|sk| Self { inner: sk })
.map_err(|_| Error::new())
}
#[cfg(feature = "verify")]
#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
pub fn verify_key(&self) -> VerifyingKey<C>
where
AffinePoint<C>: Copy + Clone + Debug + Default,
ProjectivePoint<C>: From<AffinePoint<C>>,
{
VerifyingKey {
inner: self.inner.public_key(),
}
}
pub fn to_bytes(&self) -> FieldBytes<C> {
self.inner.to_bytes()
}
}
impl<C> From<SecretKey<C>> for SigningKey<C>
where
C: Curve + ProjectiveArithmetic,
Scalar<C>: PrimeField<Repr = FieldBytes<C>>
+ ConstantTimeEq
+ FromDigest<C>
+ Invert<Output = Scalar<C>>
+ SignPrimitive<C>
+ Zeroize,
SignatureSize<C>: ArrayLength<u8>,
{
fn from(secret_key: SecretKey<C>) -> Self {
Self { inner: secret_key }
}
}
impl<C, D> DigestSigner<D, Signature<C>> for SigningKey<C>
where
C: Curve + ProjectiveArithmetic,
D: FixedOutput<OutputSize = C::FieldSize> + BlockInput + Clone + Default + Reset + Update,
Scalar<C>: PrimeField<Repr = FieldBytes<C>>
+ FromDigest<C>
+ Invert<Output = Scalar<C>>
+ SignPrimitive<C>
+ Zeroize,
SignatureSize<C>: ArrayLength<u8>,
{
fn try_sign_digest(&self, digest: D) -> Result<Signature<C>, Error> {
let k = rfc6979::generate_k(self.inner.secret_scalar(), digest.clone(), &[]);
let msg_scalar = Scalar::<C>::from_digest(digest);
self.inner
.secret_scalar()
.try_sign_prehashed(&**k, &msg_scalar)
}
}
impl<C> signature::Signer<Signature<C>> for SigningKey<C>
where
Self: DigestSigner<C::Digest, Signature<C>>,
C: Curve + ProjectiveArithmetic + DigestPrimitive,
Scalar<C>: PrimeField<Repr = FieldBytes<C>>
+ FromDigest<C>
+ Invert<Output = Scalar<C>>
+ SignPrimitive<C>
+ Zeroize,
SignatureSize<C>: ArrayLength<u8>,
{
fn try_sign(&self, msg: &[u8]) -> Result<Signature<C>, signature::Error> {
self.try_sign_digest(C::Digest::new().chain(msg))
}
}
impl<C, D> RandomizedDigestSigner<D, Signature<C>> for SigningKey<C>
where
C: Curve + ProjectiveArithmetic,
D: FixedOutput<OutputSize = C::FieldSize> + BlockInput + Clone + Default + Reset + Update,
Scalar<C>: PrimeField<Repr = FieldBytes<C>>
+ FromDigest<C>
+ Invert<Output = Scalar<C>>
+ SignPrimitive<C>
+ Zeroize,
SignatureSize<C>: ArrayLength<u8>,
{
fn try_sign_digest_with_rng(
&self,
mut rng: impl CryptoRng + RngCore,
digest: D,
) -> Result<Signature<C>, Error> {
let mut added_entropy = FieldBytes::<C>::default();
rng.fill_bytes(&mut added_entropy);
let k = rfc6979::generate_k(self.inner.secret_scalar(), digest.clone(), &added_entropy);
let msg_scalar = Scalar::<C>::from_digest(digest);
self.inner
.secret_scalar()
.try_sign_prehashed(&**k, &msg_scalar)
}
}
impl<C> RandomizedSigner<Signature<C>> for SigningKey<C>
where
Self: RandomizedDigestSigner<C::Digest, Signature<C>>,
C: Curve + ProjectiveArithmetic + DigestPrimitive,
Scalar<C>: PrimeField<Repr = FieldBytes<C>>
+ FromDigest<C>
+ Invert<Output = Scalar<C>>
+ SignPrimitive<C>
+ Zeroize,
SignatureSize<C>: ArrayLength<u8>,
{
fn try_sign_with_rng(
&self,
rng: impl CryptoRng + RngCore,
msg: &[u8],
) -> Result<Signature<C>, Error> {
self.try_sign_digest_with_rng(rng, C::Digest::new().chain(msg))
}
}
impl<C> From<NonZeroScalar<C>> for SigningKey<C>
where
C: Curve + ProjectiveArithmetic,
Scalar<C>: PrimeField<Repr = FieldBytes<C>>
+ FromDigest<C>
+ Invert<Output = Scalar<C>>
+ SignPrimitive<C>
+ Zeroize,
SignatureSize<C>: ArrayLength<u8>,
{
fn from(secret_scalar: NonZeroScalar<C>) -> Self {
Self {
inner: SecretKey::new(secret_scalar),
}
}
}
#[cfg(feature = "verify")]
impl<C> From<&SigningKey<C>> for VerifyingKey<C>
where
C: Curve + ProjectiveArithmetic,
AffinePoint<C>: Copy + Clone + Debug + Default,
ProjectivePoint<C>: From<AffinePoint<C>>,
Scalar<C>: PrimeField<Repr = FieldBytes<C>>
+ FromDigest<C>
+ Invert<Output = Scalar<C>>
+ SignPrimitive<C>
+ Zeroize,
SignatureSize<C>: ArrayLength<u8>,
{
fn from(signing_key: &SigningKey<C>) -> VerifyingKey<C> {
signing_key.verify_key()
}
}
#[cfg(feature = "pkcs8")]
#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
impl<C> FromPrivateKey for SigningKey<C>
where
C: Curve + AlgorithmParameters + ProjectiveArithmetic,
AffinePoint<C>: Copy + Clone + Debug + Default + FromEncodedPoint<C> + ToEncodedPoint<C>,
ProjectivePoint<C>: From<AffinePoint<C>>,
Scalar<C>: PrimeField<Repr = FieldBytes<C>>
+ FromDigest<C>
+ Invert<Output = Scalar<C>>
+ SignPrimitive<C>
+ Zeroize,
SignatureSize<C>: ArrayLength<u8>,
UntaggedPointSize<C>: Add<U1> + ArrayLength<u8>,
UncompressedPointSize<C>: ArrayLength<u8>,
{
fn from_pkcs8_private_key_info(
private_key_info: pkcs8::PrivateKeyInfo<'_>,
) -> pkcs8::Result<Self> {
SecretKey::from_pkcs8_private_key_info(private_key_info).map(|inner| Self { inner })
}
}
#[cfg(feature = "pem")]
#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
impl<C> FromStr for SigningKey<C>
where
C: Curve + AlgorithmParameters + ProjectiveArithmetic,
AffinePoint<C>: Copy + Clone + Debug + Default + FromEncodedPoint<C> + ToEncodedPoint<C>,
ProjectivePoint<C>: From<AffinePoint<C>>,
Scalar<C>: PrimeField<Repr = FieldBytes<C>>
+ FromDigest<C>
+ Invert<Output = Scalar<C>>
+ SignPrimitive<C>
+ Zeroize,
SignatureSize<C>: ArrayLength<u8>,
UntaggedPointSize<C>: Add<U1> + ArrayLength<u8>,
UncompressedPointSize<C>: ArrayLength<u8>,
{
type Err = Error;
fn from_str(s: &str) -> Result<Self, Error> {
Self::from_pkcs8_pem(s).map_err(|_| Error::new())
}
}