use crate::Hash;
use p256::elliptic_curve::point::AffineCoordinates;
use p256::elliptic_curve::Group;
use serde::{Deserialize, Serialize};
use std::ops::{Mul, Neg};
#[derive(Default, Clone, Serialize, Deserialize)]
pub struct SignatureScheme<H: Hash> {
g: p256::AffinePoint,
_phantom: std::marker::PhantomData<H>,
}
impl<H: Hash> SignatureScheme<H> {
pub fn new() -> Self {
let g = p256::ProjectivePoint::generator().to_affine();
Self {
g,
_phantom: std::marker::PhantomData,
}
}
pub fn generate_key<R: rand::CryptoRng + rand::RngCore>(
&self,
rng: &mut R,
) -> (SigningKey, PublicKey) {
let d = p256::NonZeroScalar::random(rng);
let p = self.g.mul(d.neg().as_ref()).to_affine();
(SigningKey { d }, PublicKey { p })
}
pub fn sign<R: rand::CryptoRng + rand::RngCore, M: AsRef<[u8]>>(
&self,
rng: &mut R,
key: &SigningKey,
pub_key: &PublicKey,
message: M,
) -> Signature {
let k = p256::NonZeroScalar::random(rng);
let r = self.g.mul(k.as_ref());
let r_x = r.to_affine().x().to_vec();
let p_x = pub_key.p.x().to_vec();
let e = p256::elliptic_curve::ScalarPrimitive::<p256::NistP256>::from_slice(&H::hash(
[r_x, p_x, message.as_ref().to_vec()].concat(),
))
.unwrap();
let e = p256::Scalar::from(e);
let s = k.add(&e.multiply(&key.d));
Signature { e, s }
}
pub fn verify(&self, key: &PublicKey, message: &[u8], signature: &Signature) -> bool {
let r_v = self
.g
.mul(signature.s.as_ref())
.add(&key.p.mul(signature.e.as_ref()));
let r_x = r_v.to_affine().x().to_vec();
let p_x = key.p.x().to_vec();
let e_v = p256::elliptic_curve::ScalarPrimitive::<p256::NistP256>::from_slice(&H::hash(
[r_x, p_x, message.to_vec()].concat(),
));
e_v.map(p256::Scalar::from)
.map(|e_v| e_v == signature.e)
.unwrap_or(false)
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct PublicKey {
p: p256::AffinePoint,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct SigningKey {
d: p256::NonZeroScalar,
}
#[derive(Clone, Serialize, Deserialize)]
pub struct Signature {
e: p256::Scalar,
s: p256::Scalar,
}