darkfi_sdk/crypto/
schnorr.rs1#[cfg(feature = "async")]
20use darkfi_serial::async_trait;
21use darkfi_serial::{SerialDecodable, SerialEncodable};
22use halo2_gadgets::ecc::chip::FixedPoint;
23use pasta_curves::{
24 group::{ff::PrimeField, Group, GroupEncoding},
25 pallas,
26};
27
28use super::{
29 constants::{NullifierK, DRK_SCHNORR_DOMAIN},
30 util::{fp_mod_fv, hash_to_scalar},
31 PublicKey, SecretKey,
32};
33
34#[derive(Debug, Clone, Copy, Eq, PartialEq, SerialEncodable, SerialDecodable)]
36pub struct Signature {
37 commit: pallas::Point,
38 response: pallas::Scalar,
39}
40
41impl Signature {
42 pub fn dummy() -> Self {
44 Self { commit: pallas::Point::identity(), response: pallas::Scalar::zero() }
45 }
46}
47
48pub trait SchnorrSecret {
50 fn sign(&self, message: &[u8]) -> Signature;
52}
53
54pub trait SchnorrPublic {
56 fn verify(&self, message: &[u8], signature: &Signature) -> bool;
58}
59
60impl SchnorrSecret for SecretKey {
62 fn sign(&self, message: &[u8]) -> Signature {
63 let mask = hash_to_scalar(DRK_SCHNORR_DOMAIN, &[&self.inner().to_repr(), message]);
65
66 let commit = NullifierK.generator() * mask;
67
68 let commit_bytes = commit.to_bytes();
69 let pubkey_bytes = PublicKey::from_secret(*self).to_bytes();
70 let transcript = &[&commit_bytes, &pubkey_bytes, message];
71
72 let challenge = hash_to_scalar(DRK_SCHNORR_DOMAIN, transcript);
73 let response = mask + challenge * fp_mod_fv(self.inner());
74
75 Signature { commit, response }
76 }
77}
78
79impl SchnorrPublic for PublicKey {
80 fn verify(&self, message: &[u8], signature: &Signature) -> bool {
81 let commit_bytes = signature.commit.to_bytes();
82 let pubkey_bytes = self.to_bytes();
83 let transcript = &[&commit_bytes, &pubkey_bytes, message];
84
85 let challenge = hash_to_scalar(DRK_SCHNORR_DOMAIN, transcript);
86 NullifierK.generator() * signature.response - self.inner() * challenge == signature.commit
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 use darkfi_serial::{deserialize, serialize};
94 use rand::rngs::OsRng;
95
96 #[test]
97 fn test_schnorr_signature() {
98 let secret = SecretKey::random(&mut OsRng);
99 let message: &[u8] = b"aaaahhhh i'm signiiinngg";
100 let signature = secret.sign(message);
101 let public = PublicKey::from_secret(secret);
102 assert!(public.verify(message, &signature));
103
104 let ser = serialize(&signature);
106 let de = deserialize(&ser).unwrap();
107 assert!(public.verify(message, &de));
108 }
109}