use super::Signature;
use crate::{
distid::hash_z, AffinePoint, DistId, EncodedPoint, FieldBytes, Hash, ProjectivePoint,
PublicKey, Scalar, Sm2,
};
use elliptic_curve::{
generic_array::typenum::Unsigned,
ops::{LinearCombination, Reduce},
point::AffineCoordinates,
sec1::ToEncodedPoint,
Curve, Group,
};
use signature::{hazmat::PrehashVerifier, Error, Result, Verifier};
use sm3::{digest::Digest, Sm3};
#[cfg(feature = "alloc")]
use alloc::{boxed::Box, string::String};
#[derive(Clone, Debug)]
pub struct VerifyingKey {
public_key: PublicKey,
identity_hash: Hash,
#[cfg(feature = "alloc")]
distid: String,
}
impl VerifyingKey {
pub fn new(distid: &DistId, public_key: PublicKey) -> Result<Self> {
let identity_hash = hash_z(distid, &public_key).map_err(|_| Error::new())?;
Ok(Self {
identity_hash,
public_key,
#[cfg(feature = "alloc")]
distid: distid.into(),
})
}
pub fn from_sec1_bytes(distid: &DistId, bytes: &[u8]) -> Result<Self> {
let public_key = PublicKey::from_sec1_bytes(bytes).map_err(|_| Error::new())?;
Self::new(distid, public_key)
}
pub fn from_affine(distid: &DistId, affine: AffinePoint) -> Result<Self> {
let public_key = PublicKey::from_affine(affine).map_err(|_| Error::new())?;
Self::new(distid, public_key)
}
pub fn as_affine(&self) -> &AffinePoint {
self.public_key.as_affine()
}
#[cfg(feature = "alloc")]
pub fn distid(&self) -> &DistId {
self.distid.as_str()
}
#[cfg(feature = "alloc")]
pub fn to_sec1_bytes(&self) -> Box<[u8]> {
self.public_key.to_sec1_bytes()
}
pub(crate) fn hash_msg(&self, msg: &[u8]) -> Hash {
Sm3::new_with_prefix(self.identity_hash)
.chain_update(msg)
.finalize()
}
}
impl PrehashVerifier<Signature> for VerifyingKey {
fn verify_prehash(&self, prehash: &[u8], signature: &Signature) -> Result<()> {
if prehash.len() != <Sm2 as Curve>::FieldBytesSize::USIZE {
return Err(Error::new());
}
let r = signature.r();
let s = signature.s();
let e = Scalar::reduce_bytes(FieldBytes::from_slice(prehash));
let t = *r + *s;
if t.is_zero().into() {
return Err(Error::new());
}
let x = ProjectivePoint::lincomb(
&ProjectivePoint::generator(),
&s,
&ProjectivePoint::from(&self.public_key),
&t,
)
.to_affine()
.x();
if *r == e + Scalar::reduce_bytes(&x) {
Ok(())
} else {
Err(Error::new())
}
}
}
impl Verifier<Signature> for VerifyingKey {
fn verify(&self, msg: &[u8], signature: &Signature) -> Result<()> {
let hash = self.hash_msg(msg);
self.verify_prehash(&hash, signature)
}
}
impl AsRef<AffinePoint> for VerifyingKey {
fn as_ref(&self) -> &AffinePoint {
self.as_affine()
}
}
impl From<VerifyingKey> for PublicKey {
fn from(verifying_key: VerifyingKey) -> PublicKey {
verifying_key.public_key
}
}
impl From<&VerifyingKey> for PublicKey {
fn from(verifying_key: &VerifyingKey) -> PublicKey {
verifying_key.public_key
}
}
impl ToEncodedPoint<Sm2> for VerifyingKey {
fn to_encoded_point(&self, compress: bool) -> EncodedPoint {
self.as_affine().to_encoded_point(compress)
}
}