1use aztec_core::grumpkin;
10use aztec_core::types::{Fq, Fr, GrumpkinScalar, Point};
11use blake2::{Blake2s256, Digest};
12
13use crate::pedersen::pedersen_hash;
14
15#[derive(Clone, Debug, PartialEq, Eq)]
17pub struct SchnorrSignature {
18 pub s: [u8; 32],
20 pub e: [u8; 32],
22}
23
24impl SchnorrSignature {
25 pub fn to_bytes(&self) -> [u8; 64] {
27 let mut out = [0u8; 64];
28 out[..32].copy_from_slice(&self.s);
29 out[32..].copy_from_slice(&self.e);
30 out
31 }
32
33 pub fn from_bytes(bytes: &[u8; 64]) -> Self {
35 let mut s = [0u8; 32];
36 let mut e = [0u8; 32];
37 s.copy_from_slice(&bytes[..32]);
38 e.copy_from_slice(&bytes[32..]);
39 Self { s, e }
40 }
41
42 pub fn to_fields(&self) -> Vec<Fr> {
47 self.to_bytes()
48 .iter()
49 .map(|&b| Fr::from(b as u64))
50 .collect()
51 }
52}
53
54fn generate_nonce(private_key: &GrumpkinScalar, message: &Fr) -> GrumpkinScalar {
58 let mut hasher = Blake2s256::new();
59 hasher.update(private_key.to_be_bytes());
60 hasher.update(message.to_be_bytes());
61 let hash = hasher.finalize();
62
63 GrumpkinScalar::from_be_bytes_mod_order(&hash)
67}
68
69fn compute_challenge(r: &Point, public_key: &Point, message: &[u8]) -> [u8; 32] {
76 let pedersen_h = pedersen_hash(&[r.x, public_key.x, public_key.y]);
78
79 let mut hasher = Blake2s256::new();
80 hasher.update(pedersen_h.to_be_bytes());
81 hasher.update(message);
82 let hash = hasher.finalize();
83 let mut out = [0u8; 32];
84 out.copy_from_slice(&hash);
85 out
86}
87
88pub fn schnorr_sign(private_key: &GrumpkinScalar, message: &Fr) -> SchnorrSignature {
99 let g = grumpkin::generator();
100 let public_key = grumpkin::scalar_mul(private_key, &g);
101
102 let k = generate_nonce(private_key, message);
104
105 let r = grumpkin::scalar_mul(&k, &g);
107
108 let e_bytes = compute_challenge(&r, &public_key, &message.to_be_bytes());
110 let e_scalar = GrumpkinScalar::from_be_bytes_mod_order(&e_bytes);
111
112 let s_scalar = Fq(k.0 - private_key.0 * e_scalar.0);
114
115 SchnorrSignature {
116 s: s_scalar.to_be_bytes(),
117 e: e_bytes,
118 }
119}
120
121pub fn schnorr_verify(public_key: &Point, message: &Fr, signature: &SchnorrSignature) -> bool {
128 let g = grumpkin::generator();
129
130 let s_scalar = GrumpkinScalar::from_be_bytes_mod_order(&signature.s);
131 let e_scalar = GrumpkinScalar::from_be_bytes_mod_order(&signature.e);
132
133 let s_g = grumpkin::scalar_mul(&s_scalar, &g);
135 let e_pk = grumpkin::scalar_mul(&e_scalar, public_key);
136 let r_prime = grumpkin::point_add(&s_g, &e_pk);
137
138 let e_prime = compute_challenge(&r_prime, public_key, &message.to_be_bytes());
140
141 signature.e == e_prime
142}
143
144#[cfg(test)]
145#[allow(clippy::expect_used)]
146mod tests {
147 use super::*;
148 use crate::keys::{derive_public_key_from_secret_key, derive_signing_key};
149
150 #[test]
151 fn sign_and_verify_roundtrip() {
152 let secret = Fr::from(12345u64);
153 let signing_key = derive_signing_key(&secret);
154 let public_key = derive_public_key_from_secret_key(&signing_key);
155
156 let message = Fr::from(42u64);
157 let sig = schnorr_sign(&signing_key, &message);
158
159 assert!(schnorr_verify(&public_key, &message, &sig));
160 }
161
162 #[test]
163 fn wrong_message_fails_verification() {
164 let secret = Fr::from(12345u64);
165 let signing_key = derive_signing_key(&secret);
166 let public_key = derive_public_key_from_secret_key(&signing_key);
167
168 let message = Fr::from(42u64);
169 let sig = schnorr_sign(&signing_key, &message);
170
171 let wrong_message = Fr::from(43u64);
172 assert!(!schnorr_verify(&public_key, &wrong_message, &sig));
173 }
174
175 #[test]
176 fn wrong_key_fails_verification() {
177 let secret = Fr::from(12345u64);
178 let signing_key = derive_signing_key(&secret);
179
180 let other_secret = Fr::from(99999u64);
181 let other_signing_key = derive_signing_key(&other_secret);
182 let other_public_key = derive_public_key_from_secret_key(&other_signing_key);
183
184 let message = Fr::from(42u64);
185 let sig = schnorr_sign(&signing_key, &message);
186
187 assert!(!schnorr_verify(&other_public_key, &message, &sig));
188 }
189
190 #[test]
191 fn signing_is_deterministic() {
192 let secret = Fr::from(8923u64);
193 let signing_key = derive_signing_key(&secret);
194
195 let message = Fr::from(1000u64);
196 let sig1 = schnorr_sign(&signing_key, &message);
197 let sig2 = schnorr_sign(&signing_key, &message);
198
199 assert_eq!(sig1, sig2);
200 }
201
202 #[test]
203 fn different_messages_produce_different_signatures() {
204 let secret = Fr::from(8923u64);
205 let signing_key = derive_signing_key(&secret);
206
207 let sig1 = schnorr_sign(&signing_key, &Fr::from(1u64));
208 let sig2 = schnorr_sign(&signing_key, &Fr::from(2u64));
209
210 assert_ne!(sig1, sig2);
211 }
212
213 #[test]
214 fn signature_serialization_roundtrip() {
215 let secret = Fr::from(42u64);
216 let signing_key = derive_signing_key(&secret);
217
218 let sig = schnorr_sign(&signing_key, &Fr::from(100u64));
219 let bytes = sig.to_bytes();
220 let recovered = SchnorrSignature::from_bytes(&bytes);
221
222 assert_eq!(sig, recovered);
223 }
224
225 #[test]
226 fn to_fields_produces_64_elements() {
227 let secret = Fr::from(42u64);
228 let signing_key = derive_signing_key(&secret);
229
230 let sig = schnorr_sign(&signing_key, &Fr::from(100u64));
231 let fields = sig.to_fields();
232
233 assert_eq!(fields.len(), 64);
234 for field in &fields {
236 let val = field.to_usize();
237 assert!(val < 256);
238 }
239 }
240
241 #[test]
242 fn verify_with_realistic_key_derivation() {
243 let secret_key = Fr::from(8923u64);
245 let signing_key = derive_signing_key(&secret_key);
246 let public_key = derive_public_key_from_secret_key(&signing_key);
247
248 let message_hash =
250 Fr::from_hex("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")
251 .expect("valid hex");
252 let sig = schnorr_sign(&signing_key, &message_hash);
253
254 assert!(schnorr_verify(&public_key, &message_hash, &sig));
255 }
256}