use core::{
convert::{TryFrom, TryInto},
fmt,
hash::Hash,
marker::PhantomData,
};
use group::{cofactor::CofactorGroup, ff::PrimeField, GroupEncoding};
use crate::{hex_if_possible, Error, Randomizer, SigType, Signature, SpendAuth};
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VerificationKeyBytes<T: SigType> {
pub(crate) bytes: [u8; 32],
pub(crate) _marker: PhantomData<T>,
}
impl<T: SigType> fmt::Debug for VerificationKeyBytes<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("VerificationKeyBytes")
.field("bytes", &hex_if_possible(&self.bytes))
.finish()
}
}
impl<T: SigType> From<[u8; 32]> for VerificationKeyBytes<T> {
fn from(bytes: [u8; 32]) -> VerificationKeyBytes<T> {
VerificationKeyBytes {
bytes,
_marker: PhantomData,
}
}
}
impl<T: SigType> From<VerificationKeyBytes<T>> for [u8; 32] {
fn from(refined: VerificationKeyBytes<T>) -> [u8; 32] {
refined.bytes
}
}
#[derive(PartialEq, Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(try_from = "VerificationKeyBytes<T>"))]
#[cfg_attr(feature = "serde", serde(into = "VerificationKeyBytes<T>"))]
#[cfg_attr(feature = "serde", serde(bound = "T: SigType"))]
pub struct VerificationKey<T: SigType> {
pub(crate) point: T::Point,
pub(crate) bytes: VerificationKeyBytes<T>,
}
impl<T: SigType> From<VerificationKey<T>> for VerificationKeyBytes<T> {
fn from(pk: VerificationKey<T>) -> VerificationKeyBytes<T> {
pk.bytes
}
}
impl<T: SigType> From<VerificationKey<T>> for [u8; 32] {
fn from(pk: VerificationKey<T>) -> [u8; 32] {
pk.bytes.bytes
}
}
impl<T: SigType> TryFrom<VerificationKeyBytes<T>> for VerificationKey<T> {
type Error = Error;
fn try_from(bytes: VerificationKeyBytes<T>) -> Result<Self, Self::Error> {
let mut repr = <T::Point as GroupEncoding>::Repr::default();
repr.as_mut().copy_from_slice(&bytes.bytes);
let maybe_point = T::Point::from_bytes(&repr);
if maybe_point.is_some().into() {
let point = maybe_point.unwrap();
Ok(VerificationKey { point, bytes })
} else {
Err(Error::MalformedVerificationKey)
}
}
}
impl<T: SigType> TryFrom<[u8; 32]> for VerificationKey<T> {
type Error = Error;
fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
VerificationKeyBytes::from(bytes).try_into()
}
}
impl<T: SpendAuth> VerificationKey<T> {
pub fn randomize(&self, randomizer: &Randomizer<T>) -> VerificationKey<T> {
let point = self.point + (T::basepoint() * randomizer);
let bytes = VerificationKeyBytes {
bytes: point.to_bytes().as_ref().try_into().unwrap(),
_marker: PhantomData,
};
VerificationKey { bytes, point }
}
}
impl<T: SigType> VerificationKey<T> {
pub(crate) fn from(s: &T::Scalar) -> VerificationKey<T> {
let point = T::basepoint() * s;
let bytes = VerificationKeyBytes {
bytes: point.to_bytes().as_ref().try_into().unwrap(),
_marker: PhantomData,
};
VerificationKey { bytes, point }
}
pub fn verify(&self, msg: &[u8], signature: &Signature<T>) -> Result<(), Error> {
use crate::HStar;
let c = HStar::<T>::default()
.update(&signature.r_bytes[..])
.update(&self.bytes.bytes[..]) .update(msg)
.finalize();
self.verify_prehashed(signature, c)
}
#[allow(non_snake_case)]
pub(crate) fn verify_prehashed(
&self,
signature: &Signature<T>,
c: T::Scalar,
) -> Result<(), Error> {
let r = {
let mut repr = <T::Point as GroupEncoding>::Repr::default();
repr.as_mut().copy_from_slice(&signature.r_bytes);
let maybe_point = T::Point::from_bytes(&repr);
if maybe_point.is_some().into() {
maybe_point.unwrap()
} else {
return Err(Error::InvalidSignature);
}
};
let s = {
let mut repr = <T::Scalar as PrimeField>::Repr::default();
repr.as_mut().copy_from_slice(&signature.s_bytes);
let maybe_scalar = T::Scalar::from_repr(repr);
if maybe_scalar.is_some().into() {
maybe_scalar.unwrap()
} else {
return Err(Error::InvalidSignature);
}
};
let sB = T::basepoint() * s;
let cA = self.point * c;
let check = sB - cA - r;
if check.is_small_order().into() {
Ok(())
} else {
Err(Error::InvalidSignature)
}
}
}