use num_bigint::BigUint;
use serde::{Deserialize, Serialize};
use crate::{Hash, Rand, SchnorrGroup};
#[derive(Clone, Serialize, Deserialize)]
pub struct SignatureScheme<H: Hash> {
group: SchnorrGroup,
_phantom: std::marker::PhantomData<H>,
}
impl<H: Hash> SignatureScheme<H> {
pub fn from_str(p: &str, q: &str, a: &str) -> Option<Self> {
let group = SchnorrGroup::from_str(p, q, a)?;
Some(Self {
group,
_phantom: std::marker::PhantomData,
})
}
pub fn generate_key<R: Rand>(&self) -> (SigningKey, PublicKey) {
let d = R::random_number(&self.group.q);
let p = self
.group
.a
.modpow(&d, &self.group.p)
.modinv(&self.group.p)
.unwrap();
(SigningKey { d }, PublicKey { p })
}
pub fn sign<R: Rand, M: AsRef<[u8]>>(
&self,
key: &SigningKey,
pub_key: &PublicKey,
message: M,
) -> Signature {
let k = R::random_number(&self.group.q);
let r = self.group.a.modpow(&k, &self.group.p);
let e = BigUint::from_bytes_le(&H::hash(
[
r.to_bytes_le(),
pub_key.p.to_bytes_le(),
message.as_ref().to_vec(),
]
.concat(),
));
let s = &k + &e * &key.d % &self.group.q;
Signature { s, e }
}
pub fn verify(&self, key: &PublicKey, message: &[u8], signature: &Signature) -> bool {
let r_v = self.group.a.modpow(&signature.s, &self.group.p)
* key.p.modpow(&signature.e, &self.group.p)
% &self.group.p;
let e_v = BigUint::from_bytes_le(&H::hash(
[r_v.to_bytes_le(), key.p.to_bytes_le(), message.to_vec()].concat(),
));
e_v == signature.e
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct PublicKey {
p: BigUint,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct SigningKey {
d: BigUint,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct Signature {
s: BigUint,
e: BigUint,
}