use digest::Digest;
use rand_core::{CryptoRng, RngCore};
use serde::{Deserialize, Serialize};
use crate::{Group, PublicKey, Signature, SigningKey};
#[derive(Clone, Serialize, Deserialize)]
pub struct SignatureScheme<G: Group, H: Digest> {
pub(crate) group: G,
pub(crate) _phantom: std::marker::PhantomData<H>,
}
impl<G, H> SignatureScheme<G, H>
where
G: Group,
H: Digest,
{
pub fn generate_key<R: RngCore + CryptoRng>(
&self,
rng: &mut R,
) -> (SigningKey<G>, PublicKey<G>) {
let d = self.group.random_scalar(rng);
let neg_d = self.group.neg(&d);
let p = self.group.mul_by_generator(&neg_d);
(SigningKey { d }, PublicKey { p })
}
pub fn sign<R: RngCore + CryptoRng, M: AsRef<[u8]>>(
&self,
rng: &mut R,
key: &SigningKey<G>,
pub_key: &PublicKey<G>,
message: M,
) -> Signature<G> {
let k = self.group.random_scalar(rng);
let r = self.group.mul_by_generator(&k);
let e = G::map_to_scalar(
H::new()
.chain_update(
[
G::map_point(&r),
G::map_point(&pub_key.p),
message.as_ref().to_vec(),
]
.concat(),
)
.finalize()
.as_ref(),
);
let s = self.group.add_mul_scalar(&k, &e, &key.d);
Signature { s, e }
}
pub fn verify(&self, key: &PublicKey<G>, message: &[u8], signature: &Signature<G>) -> bool {
let r_v = {
let a_s = self.group.mul_by_generator(&signature.s);
let p_e = self.group.mul(&key.p, &signature.e);
self.group.dot(&a_s, &p_e)
};
let e_v = G::map_to_scalar(
H::new()
.chain_update([G::map_point(&r_v), G::map_point(&key.p), message.to_vec()].concat())
.finalize()
.as_ref(),
);
G::is_equivalent_scalars(&e_v, &signature.e)
}
}