#![allow(non_snake_case)]
use super::{Signature, VerifyingKey};
use crate::{
DistId, FieldBytes, NonZeroScalar, ProjectivePoint, PublicKey, Scalar, SecretKey, Sm2,
};
use core::fmt::{self, Debug};
use elliptic_curve::{
Curve, FieldBytesEncoding, Group, PrimeField,
array::typenum::Unsigned,
ops::Reduce,
point::AffineCoordinates,
subtle::{Choice, ConstantTimeEq},
};
use signature::{
Error, KeypairRef, MultipartSigner, RandomizedMultipartSigner, RandomizedSigner, Result,
Signer,
hazmat::{PrehashSigner, RandomizedPrehashSigner},
rand_core::TryCryptoRng,
};
use sm3::Sm3;
#[cfg(feature = "pkcs8")]
use crate::pkcs8::{
der::AnyRef,
spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier},
};
#[derive(Clone)]
pub struct SigningKey {
secret_scalar: NonZeroScalar,
verifying_key: VerifyingKey,
}
impl SigningKey {
pub fn new(distid: &DistId, secret_key: &SecretKey) -> Result<Self> {
Self::from_nonzero_scalar(distid, secret_key.to_nonzero_scalar())
}
pub fn from_bytes(distid: &DistId, bytes: &FieldBytes) -> Result<Self> {
Self::from_slice(distid, bytes)
}
pub fn from_slice(distid: &DistId, slice: &[u8]) -> Result<Self> {
let secret_scalar = NonZeroScalar::try_from(slice).map_err(|_| Error::new())?;
Self::from_nonzero_scalar(distid, secret_scalar)
}
pub fn from_nonzero_scalar(distid: &DistId, secret_scalar: NonZeroScalar) -> Result<Self> {
let public_key = PublicKey::from_secret_scalar(&secret_scalar);
let verifying_key = VerifyingKey::new(distid, public_key)?;
Ok(Self {
secret_scalar,
verifying_key,
})
}
pub fn to_bytes(&self) -> FieldBytes {
self.secret_scalar.to_bytes()
}
pub fn as_nonzero_scalar(&self) -> &NonZeroScalar {
&self.secret_scalar
}
pub fn verifying_key(&self) -> &VerifyingKey {
&self.verifying_key
}
#[cfg(feature = "alloc")]
pub fn distid(&self) -> &DistId {
self.verifying_key.distid()
}
}
impl PrehashSigner<Signature> for SigningKey {
fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature> {
sign_prehash_rfc6979(&self.secret_scalar, prehash, &[])
}
}
impl RandomizedPrehashSigner<Signature> for SigningKey {
fn sign_prehash_with_rng<R: TryCryptoRng + ?Sized>(
&self,
rng: &mut R,
prehash: &[u8],
) -> Result<Signature> {
let mut data = FieldBytes::default();
rng.try_fill_bytes(&mut data).map_err(|_| Error::new())?;
sign_prehash_rfc6979(&self.secret_scalar, prehash, &data)
}
}
impl RandomizedSigner<Signature> for SigningKey {
fn try_sign_with_rng<R: TryCryptoRng + ?Sized>(
&self,
rng: &mut R,
msg: &[u8],
) -> Result<Signature> {
self.try_multipart_sign_with_rng(rng, &[msg])
}
}
impl RandomizedMultipartSigner<Signature> for SigningKey {
fn try_multipart_sign_with_rng<R: TryCryptoRng + ?Sized>(
&self,
rng: &mut R,
msg: &[&[u8]],
) -> Result<Signature> {
let hash = self.verifying_key.hash_msg(msg);
self.sign_prehash_with_rng(rng, &hash)
}
}
impl Signer<Signature> for SigningKey {
fn try_sign(&self, msg: &[u8]) -> Result<Signature> {
self.try_multipart_sign(&[msg])
}
}
impl MultipartSigner<Signature> for SigningKey {
fn try_multipart_sign(&self, msg: &[&[u8]]) -> Result<Signature> {
let hash = self.verifying_key.hash_msg(msg);
self.sign_prehash(&hash)
}
}
impl AsRef<VerifyingKey> for SigningKey {
fn as_ref(&self) -> &VerifyingKey {
&self.verifying_key
}
}
impl ConstantTimeEq for SigningKey {
fn ct_eq(&self, other: &Self) -> Choice {
self.secret_scalar.ct_eq(&other.secret_scalar)
}
}
impl Debug for SigningKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SigningKey")
.field("verifying_key", &self.verifying_key)
.finish_non_exhaustive()
}
}
impl Eq for SigningKey {}
impl PartialEq for SigningKey {
fn eq(&self, other: &SigningKey) -> bool {
self.ct_eq(other).into()
}
}
impl KeypairRef for SigningKey {
type VerifyingKey = VerifyingKey;
}
fn sign_prehash_rfc6979(secret_scalar: &Scalar, prehash: &[u8], data: &[u8]) -> Result<Signature> {
if prehash.len() != <Sm2 as Curve>::FieldBytesSize::USIZE {
return Err(Error::new());
}
#[allow(deprecated)] let e = Scalar::reduce(FieldBytes::from_slice(prehash));
let k = Scalar::from_repr(rfc6979::generate_k::<Sm3, _>(
&secret_scalar.to_repr(),
&FieldBytesEncoding::<Sm2>::encode_field_bytes(Sm2::ORDER.as_ref()),
&e.to_bytes(),
data,
))
.unwrap();
let R = ProjectivePoint::mul_by_generator(&k).to_affine();
let r = e + Scalar::reduce(&R.x());
if bool::from(r.is_zero() | (r + k).ct_eq(&Scalar::ZERO)) {
return Err(Error::new());
}
let d_plus_1_inv =
Option::<Scalar>::from((secret_scalar + &Scalar::ONE).invert()).ok_or_else(Error::new)?;
let s = d_plus_1_inv * (k - (r * secret_scalar));
Signature::from_scalars(r, s)
}
#[cfg(feature = "pkcs8")]
impl SignatureAlgorithmIdentifier for SigningKey {
type Params = AnyRef<'static>;
const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
Signature::ALGORITHM_IDENTIFIER;
}