use super::{Signature, BELT_OID};
use crate::{
AffinePoint, BignP256, EncodedPoint, FieldBytes, Hash, ProjectivePoint, PublicKey, Scalar,
};
use belt_hash::{
digest::{Digest, FixedOutput},
BeltHash,
};
use crypto_bigint::{consts::U32, generic_array::GenericArray};
use elliptic_curve::{
generic_array::typenum::Unsigned,
group::GroupEncoding,
ops::{LinearCombination, Reduce},
sec1::ToEncodedPoint,
Curve, Field, Group,
};
use signature::{hazmat::PrehashVerifier, Error, Result, Verifier};
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[derive(Clone, Debug)]
pub struct VerifyingKey {
public_key: PublicKey,
}
impl VerifyingKey {
pub fn new(public_key: PublicKey) -> Result<Self> {
Ok(Self { public_key })
}
pub fn from_affine(affine: AffinePoint) -> Result<Self> {
let public_key = PublicKey::from_affine(affine).map_err(|_| Error::new())?;
Self::new(public_key)
}
pub fn as_affine(&self) -> &AffinePoint {
self.public_key.as_affine()
}
pub(crate) fn hash_msg(&self, msg: &[u8]) -> Hash {
let mut hasher = BeltHash::new();
hasher.update(msg);
hasher.finalize_fixed()
}
pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> {
let public_key = PublicKey::from_sec1_bytes(bytes).map_err(|_| Error::new())?;
Self::new(public_key)
}
#[cfg(feature = "alloc")]
pub fn to_sec1_bytes(&self) -> Box<[u8]> {
self.public_key.to_sec1_bytes()
}
}
impl PrehashVerifier<Signature> for VerifyingKey {
fn verify_prehash(&self, prehash: &[u8], signature: &Signature) -> Result<()> {
if prehash.len() != <BignP256 as Curve>::FieldBytesSize::USIZE {
return Err(Error::new());
}
let s0 = signature.s0();
let s1 = signature.s1();
let mut hash: GenericArray<u8, U32> = GenericArray::clone_from_slice(prehash);
hash.reverse();
let hw = Scalar::reduce_bytes(FieldBytes::from_slice(&hash));
let left = s1.add(&hw);
let right = s0.add(&Scalar::from_u64(2).pow([128, 0, 0, 0]));
let r = ProjectivePoint::lincomb(
&ProjectivePoint::generator(),
&left,
&self.public_key.to_projective(),
&right,
);
if r.is_identity().into() {
return Err(Error::new());
}
let mut r_bytes = r.to_bytes();
r_bytes.reverse();
let mut hasher = BeltHash::new();
hasher.update(BELT_OID);
hasher.update(&r_bytes[0..32]);
hasher.update(prehash);
let t = hasher.finalize();
let s0 = &mut s0.to_bytes()[16..];
s0.reverse();
if s0 == &t.as_slice()[..16] {
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<BignP256> for VerifyingKey {
fn to_encoded_point(&self, compress: bool) -> EncodedPoint {
self.as_affine().to_encoded_point(compress)
}
}