#[cfg(feature = "async")]
use darkfi_serial::async_trait;
use darkfi_serial::{SerialDecodable, SerialEncodable};
use halo2_gadgets::ecc::chip::FixedPoint;
use pasta_curves::{
group::{ff::PrimeField, Group, GroupEncoding},
pallas,
};
use super::{
constants::{NullifierK, DRK_SCHNORR_DOMAIN},
util::{fp_mod_fv, hash_to_scalar},
PublicKey, SecretKey,
};
#[derive(Debug, Clone, Copy, Eq, PartialEq, SerialEncodable, SerialDecodable)]
pub struct Signature {
commit: pallas::Point,
response: pallas::Scalar,
}
impl Signature {
pub fn dummy() -> Self {
Self { commit: pallas::Point::identity(), response: pallas::Scalar::zero() }
}
}
pub trait SchnorrSecret {
fn sign(&self, message: &[u8]) -> Signature;
}
pub trait SchnorrPublic {
fn verify(&self, message: &[u8], signature: &Signature) -> bool;
}
impl SchnorrSecret for SecretKey {
fn sign(&self, message: &[u8]) -> Signature {
let mask = hash_to_scalar(DRK_SCHNORR_DOMAIN, &[&self.inner().to_repr(), message]);
let commit = NullifierK.generator() * mask;
let commit_bytes = commit.to_bytes();
let pubkey_bytes = PublicKey::from_secret(*self).to_bytes();
let transcript = &[&commit_bytes, &pubkey_bytes, message];
let challenge = hash_to_scalar(DRK_SCHNORR_DOMAIN, transcript);
let response = mask + challenge * fp_mod_fv(self.inner());
Signature { commit, response }
}
}
impl SchnorrPublic for PublicKey {
fn verify(&self, message: &[u8], signature: &Signature) -> bool {
let commit_bytes = signature.commit.to_bytes();
let pubkey_bytes = self.to_bytes();
let transcript = &[&commit_bytes, &pubkey_bytes, message];
let challenge = hash_to_scalar(DRK_SCHNORR_DOMAIN, transcript);
NullifierK.generator() * signature.response - self.inner() * challenge == signature.commit
}
}
#[cfg(test)]
mod tests {
use super::*;
use darkfi_serial::{deserialize, serialize};
use rand::rngs::OsRng;
#[test]
fn test_schnorr_signature() {
let secret = SecretKey::random(&mut OsRng);
let message: &[u8] = b"aaaahhhh i'm signiiinngg";
let signature = secret.sign(message);
let public = PublicKey::from_secret(secret);
assert!(public.verify(message, &signature));
let ser = serialize(&signature);
let de = deserialize(&ser).unwrap();
assert!(public.verify(message, &de));
}
}