secp256k1/
schnorr.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Support for schnorr signatures.
4//!
5
6use core::{fmt, ptr, str};
7
8#[cfg(feature = "rand")]
9use rand::{CryptoRng, Rng};
10
11use crate::ffi::{self, CPtr};
12use crate::key::{Keypair, XOnlyPublicKey};
13#[cfg(feature = "global-context")]
14use crate::SECP256K1;
15use crate::{constants, from_hex, Error, Message, Secp256k1, Signing, Verification};
16
17/// Represents a schnorr signature.
18#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub struct Signature([u8; constants::SCHNORR_SIGNATURE_SIZE]);
20impl_array_newtype!(Signature, u8, constants::SCHNORR_SIGNATURE_SIZE);
21impl_pretty_debug!(Signature);
22
23#[cfg(feature = "serde")]
24impl serde::Serialize for Signature {
25    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
26        if s.is_human_readable() {
27            s.collect_str(self)
28        } else {
29            s.serialize_bytes(&self[..])
30        }
31    }
32}
33
34#[cfg(feature = "serde")]
35impl<'de> serde::Deserialize<'de> for Signature {
36    fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
37        if d.is_human_readable() {
38            d.deserialize_str(super::serde_util::FromStrVisitor::new(
39                "a hex string representing 64 byte schnorr signature",
40            ))
41        } else {
42            d.deserialize_bytes(super::serde_util::BytesVisitor::new(
43                "raw 64 bytes schnorr signature",
44                Signature::from_slice,
45            ))
46        }
47    }
48}
49
50impl fmt::LowerHex for Signature {
51    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
52        for ch in &self.0[..] {
53            write!(f, "{:02x}", ch)?;
54        }
55        Ok(())
56    }
57}
58
59impl fmt::Display for Signature {
60    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
61}
62
63impl str::FromStr for Signature {
64    type Err = Error;
65    fn from_str(s: &str) -> Result<Signature, Error> {
66        let mut res = [0u8; constants::SCHNORR_SIGNATURE_SIZE];
67        match from_hex(s, &mut res) {
68            Ok(constants::SCHNORR_SIGNATURE_SIZE) =>
69                Signature::from_slice(&res[0..constants::SCHNORR_SIGNATURE_SIZE]),
70            _ => Err(Error::InvalidSignature),
71        }
72    }
73}
74
75impl Signature {
76    /// Creates a `Signature` directly from a slice.
77    #[inline]
78    pub fn from_slice(data: &[u8]) -> Result<Signature, Error> {
79        match data.len() {
80            constants::SCHNORR_SIGNATURE_SIZE => {
81                let mut ret = [0u8; constants::SCHNORR_SIGNATURE_SIZE];
82                ret[..].copy_from_slice(data);
83                Ok(Signature(ret))
84            }
85            _ => Err(Error::InvalidSignature),
86        }
87    }
88
89    /// Returns a signature as a byte array.
90    #[inline]
91    pub fn serialize(&self) -> [u8; constants::SCHNORR_SIGNATURE_SIZE] { self.0 }
92
93    /// Verifies a schnorr signature for `msg` using `pk` and the global [`SECP256K1`] context.
94    #[inline]
95    #[cfg(feature = "global-context")]
96    pub fn verify(&self, msg: &Message, pk: &XOnlyPublicKey) -> Result<(), Error> {
97        SECP256K1.verify_schnorr(self, msg, pk)
98    }
99}
100
101impl<C: Signing> Secp256k1<C> {
102    fn sign_schnorr_helper(
103        &self,
104        msg: &Message,
105        keypair: &Keypair,
106        nonce_data: *const ffi::types::c_uchar,
107    ) -> Signature {
108        unsafe {
109            let mut sig = [0u8; constants::SCHNORR_SIGNATURE_SIZE];
110            assert_eq!(
111                1,
112                ffi::secp256k1_schnorrsig_sign(
113                    self.ctx.as_ptr(),
114                    sig.as_mut_c_ptr(),
115                    msg.as_c_ptr(),
116                    keypair.as_c_ptr(),
117                    nonce_data,
118                )
119            );
120
121            Signature(sig)
122        }
123    }
124
125    /// Creates a schnorr signature internally using the [`rand::rngs::ThreadRng`] random number
126    /// generator to generate the auxiliary random data.
127    #[cfg(feature = "rand-std")]
128    pub fn sign_schnorr(&self, msg: &Message, keypair: &Keypair) -> Signature {
129        self.sign_schnorr_with_rng(msg, keypair, &mut rand::thread_rng())
130    }
131
132    /// Creates a schnorr signature without using any auxiliary random data.
133    pub fn sign_schnorr_no_aux_rand(&self, msg: &Message, keypair: &Keypair) -> Signature {
134        self.sign_schnorr_helper(msg, keypair, ptr::null())
135    }
136
137    /// Creates a schnorr signature using the given auxiliary random data.
138    pub fn sign_schnorr_with_aux_rand(
139        &self,
140        msg: &Message,
141        keypair: &Keypair,
142        aux_rand: &[u8; 32],
143    ) -> Signature {
144        self.sign_schnorr_helper(msg, keypair, aux_rand.as_c_ptr() as *const ffi::types::c_uchar)
145    }
146
147    /// Creates a schnorr signature using the given random number generator to
148    /// generate the auxiliary random data.
149    #[cfg(feature = "rand")]
150    pub fn sign_schnorr_with_rng<R: Rng + CryptoRng>(
151        &self,
152        msg: &Message,
153        keypair: &Keypair,
154        rng: &mut R,
155    ) -> Signature {
156        let mut aux = [0u8; 32];
157        rng.fill_bytes(&mut aux);
158        self.sign_schnorr_helper(msg, keypair, aux.as_c_ptr() as *const ffi::types::c_uchar)
159    }
160}
161
162impl<C: Verification> Secp256k1<C> {
163    /// Verifies a schnorr signature.
164    pub fn verify_schnorr(
165        &self,
166        sig: &Signature,
167        msg: &Message,
168        pubkey: &XOnlyPublicKey,
169    ) -> Result<(), Error> {
170        unsafe {
171            let ret = ffi::secp256k1_schnorrsig_verify(
172                self.ctx.as_ptr(),
173                sig.as_c_ptr(),
174                msg.as_c_ptr(),
175                32,
176                pubkey.as_c_ptr(),
177            );
178
179            if ret == 1 {
180                Ok(())
181            } else {
182                Err(Error::IncorrectSignature)
183            }
184        }
185    }
186}
187
188#[cfg(test)]
189#[allow(unused_imports)]
190mod tests {
191    use core::str::FromStr;
192
193    #[cfg(feature = "rand-std")]
194    use rand::rngs::ThreadRng;
195    #[cfg(target_arch = "wasm32")]
196    use wasm_bindgen_test::wasm_bindgen_test as test;
197
198    use super::*;
199    use crate::schnorr::{Keypair, Signature, XOnlyPublicKey};
200    use crate::Error::InvalidPublicKey;
201    use crate::{constants, from_hex, Message, Secp256k1, SecretKey};
202
203    #[cfg(all(not(secp256k1_fuzz), feature = "alloc"))]
204    macro_rules! hex_32 {
205        ($hex:expr) => {{
206            let mut result = [0u8; 32];
207            from_hex($hex, &mut result).expect("valid hex string");
208            result
209        }};
210    }
211
212    #[test]
213    #[cfg(feature = "rand-std")]
214    fn schnorr_sign_with_aux_rand_verify() {
215        sign_helper(|secp, msg, seckey, rng| {
216            let aux_rand = crate::random_32_bytes(rng);
217            secp.sign_schnorr_with_aux_rand(msg, seckey, &aux_rand)
218        })
219    }
220
221    #[test]
222    #[cfg(feature = "rand-std")]
223    fn schnor_sign_with_rng_verify() {
224        sign_helper(|secp, msg, seckey, rng| secp.sign_schnorr_with_rng(msg, seckey, rng))
225    }
226
227    #[test]
228    #[cfg(feature = "rand-std")]
229    fn schnorr_sign_verify() { sign_helper(|secp, msg, seckey, _| secp.sign_schnorr(msg, seckey)) }
230
231    #[test]
232    #[cfg(feature = "rand-std")]
233    fn schnorr_sign_no_aux_rand_verify() {
234        sign_helper(|secp, msg, seckey, _| secp.sign_schnorr_no_aux_rand(msg, seckey))
235    }
236
237    #[cfg(feature = "rand-std")]
238    fn sign_helper(
239        sign: fn(&Secp256k1<crate::All>, &Message, &Keypair, &mut ThreadRng) -> Signature,
240    ) {
241        let secp = Secp256k1::new();
242
243        let mut rng = rand::thread_rng();
244        let kp = Keypair::new(&secp, &mut rng);
245        let (pk, _parity) = kp.x_only_public_key();
246
247        for _ in 0..100 {
248            let msg = crate::random_32_bytes(&mut rand::thread_rng());
249            let msg = Message::from_digest_slice(&msg).unwrap();
250
251            let sig = sign(&secp, &msg, &kp, &mut rng);
252
253            assert!(secp.verify_schnorr(&sig, &msg, &pk).is_ok());
254        }
255    }
256
257    #[test]
258    #[cfg(feature = "alloc")]
259    #[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs
260    fn schnorr_sign() {
261        let secp = Secp256k1::new();
262
263        let hex_msg = hex_32!("E48441762FB75010B2AA31A512B62B4148AA3FB08EB0765D76B252559064A614");
264        let msg = Message::from_digest_slice(&hex_msg).unwrap();
265        let sk = Keypair::from_seckey_str(
266            &secp,
267            "688C77BC2D5AAFF5491CF309D4753B732135470D05B7B2CD21ADD0744FE97BEF",
268        )
269        .unwrap();
270        let aux_rand: [u8; 32] =
271            hex_32!("02CCE08E913F22A36C5648D6405A2C7C50106E7AA2F1649E381C7F09D16B80AB");
272        let expected_sig = Signature::from_str("6470FD1303DDA4FDA717B9837153C24A6EAB377183FC438F939E0ED2B620E9EE5077C4A8B8DCA28963D772A94F5F0DDF598E1C47C137F91933274C7C3EDADCE8").unwrap();
273
274        let sig = secp.sign_schnorr_with_aux_rand(&msg, &sk, &aux_rand);
275
276        assert_eq!(expected_sig, sig);
277    }
278
279    #[test]
280    #[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs
281    #[cfg(feature = "alloc")]
282    fn schnorr_verify() {
283        let secp = Secp256k1::new();
284
285        let hex_msg = hex_32!("E48441762FB75010B2AA31A512B62B4148AA3FB08EB0765D76B252559064A614");
286        let msg = Message::from_digest_slice(&hex_msg).unwrap();
287        let sig = Signature::from_str("6470FD1303DDA4FDA717B9837153C24A6EAB377183FC438F939E0ED2B620E9EE5077C4A8B8DCA28963D772A94F5F0DDF598E1C47C137F91933274C7C3EDADCE8").unwrap();
288        let pubkey = XOnlyPublicKey::from_str(
289            "B33CC9EDC096D0A83416964BD3C6247B8FECD256E4EFA7870D2C854BDEB33390",
290        )
291        .unwrap();
292
293        assert!(secp.verify_schnorr(&sig, &msg, &pubkey).is_ok());
294    }
295
296    #[test]
297    fn test_serialize() {
298        let sig = Signature::from_str("6470FD1303DDA4FDA717B9837153C24A6EAB377183FC438F939E0ED2B620E9EE5077C4A8B8DCA28963D772A94F5F0DDF598E1C47C137F91933274C7C3EDADCE8").unwrap();
299        let sig_bytes = sig.serialize();
300        let bytes = [
301            100, 112, 253, 19, 3, 221, 164, 253, 167, 23, 185, 131, 113, 83, 194, 74, 110, 171, 55,
302            113, 131, 252, 67, 143, 147, 158, 14, 210, 182, 32, 233, 238, 80, 119, 196, 168, 184,
303            220, 162, 137, 99, 215, 114, 169, 79, 95, 13, 223, 89, 142, 28, 71, 193, 55, 249, 25,
304            51, 39, 76, 124, 62, 218, 220, 232,
305        ];
306        assert_eq!(sig_bytes, bytes);
307    }
308
309    #[test]
310    fn test_pubkey_from_slice() {
311        assert_eq!(XOnlyPublicKey::from_slice(&[]), Err(InvalidPublicKey));
312        assert_eq!(XOnlyPublicKey::from_slice(&[1, 2, 3]), Err(InvalidPublicKey));
313        let pk = XOnlyPublicKey::from_slice(&[
314            0xB3, 0x3C, 0xC9, 0xED, 0xC0, 0x96, 0xD0, 0xA8, 0x34, 0x16, 0x96, 0x4B, 0xD3, 0xC6,
315            0x24, 0x7B, 0x8F, 0xEC, 0xD2, 0x56, 0xE4, 0xEF, 0xA7, 0x87, 0x0D, 0x2C, 0x85, 0x4B,
316            0xDE, 0xB3, 0x33, 0x90,
317        ]);
318        assert!(pk.is_ok());
319    }
320
321    #[test]
322    #[cfg(feature = "rand-std")]
323    fn test_pubkey_serialize_roundtrip() {
324        let secp = Secp256k1::new();
325        let kp = Keypair::new(&secp, &mut rand::thread_rng());
326        let (pk, _parity) = kp.x_only_public_key();
327
328        let ser = pk.serialize();
329        let pubkey2 = XOnlyPublicKey::from_slice(&ser).unwrap();
330        assert_eq!(pk, pubkey2);
331    }
332
333    #[test]
334    #[cfg(feature = "alloc")]
335    fn test_xonly_key_extraction() {
336        let secp = Secp256k1::new();
337        let sk_str = "688C77BC2D5AAFF5491CF309D4753B732135470D05B7B2CD21ADD0744FE97BEF";
338        let keypair = Keypair::from_seckey_str(&secp, sk_str).unwrap();
339        let sk = SecretKey::from_keypair(&keypair);
340        assert_eq!(SecretKey::from_str(sk_str).unwrap(), sk);
341        let pk = crate::key::PublicKey::from_keypair(&keypair);
342        assert_eq!(crate::key::PublicKey::from_secret_key(&secp, &sk), pk);
343        let (xpk, _parity) = keypair.x_only_public_key();
344        assert_eq!(XOnlyPublicKey::from(pk), xpk);
345    }
346
347    #[test]
348    fn test_pubkey_from_bad_slice() {
349        // Bad sizes
350        assert_eq!(
351            XOnlyPublicKey::from_slice(&[0; constants::SCHNORR_PUBLIC_KEY_SIZE - 1]),
352            Err(InvalidPublicKey)
353        );
354        assert_eq!(
355            XOnlyPublicKey::from_slice(&[0; constants::SCHNORR_PUBLIC_KEY_SIZE + 1]),
356            Err(InvalidPublicKey)
357        );
358
359        // Bad parse
360        assert_eq!(
361            XOnlyPublicKey::from_slice(&[0xff; constants::SCHNORR_PUBLIC_KEY_SIZE]),
362            Err(InvalidPublicKey)
363        );
364        // In fuzzing mode restrictions on public key validity are much more
365        // relaxed, thus the invalid check below is expected to fail.
366        #[cfg(not(secp256k1_fuzz))]
367        assert_eq!(
368            XOnlyPublicKey::from_slice(&[0x55; constants::SCHNORR_PUBLIC_KEY_SIZE]),
369            Err(InvalidPublicKey)
370        );
371        assert_eq!(XOnlyPublicKey::from_slice(&[]), Err(InvalidPublicKey));
372    }
373
374    #[test]
375    #[cfg(feature = "std")]
376    fn test_pubkey_display_output() {
377        #[cfg(not(secp256k1_fuzz))]
378        let pk = {
379            let secp = Secp256k1::new();
380            static SK_BYTES: [u8; 32] = [
381                0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
382                0x06, 0x07, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x63, 0x63, 0x63, 0x63,
383                0x63, 0x63, 0x63, 0x63,
384            ];
385
386            let kp = Keypair::from_seckey_slice(&secp, &SK_BYTES).expect("sk");
387
388            // In fuzzing mode secret->public key derivation is different, so
389            // hard-code the expected result.
390            let (pk, _parity) = kp.x_only_public_key();
391            pk
392        };
393        #[cfg(secp256k1_fuzz)]
394        let pk = XOnlyPublicKey::from_slice(&[
395            0x18, 0x84, 0x57, 0x81, 0xf6, 0x31, 0xc4, 0x8f, 0x1c, 0x97, 0x09, 0xe2, 0x30, 0x92,
396            0x06, 0x7d, 0x06, 0x83, 0x7f, 0x30, 0xaa, 0x0c, 0xd0, 0x54, 0x4a, 0xc8, 0x87, 0xfe,
397            0x91, 0xdd, 0xd1, 0x66,
398        ])
399        .expect("pk");
400
401        assert_eq!(
402            pk.to_string(),
403            "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166"
404        );
405        assert_eq!(
406            XOnlyPublicKey::from_str(
407                "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166"
408            )
409            .unwrap(),
410            pk
411        );
412
413        assert!(XOnlyPublicKey::from_str(
414            "00000000000000000000000000000000000000000000000000000000000000000"
415        )
416        .is_err());
417        assert!(XOnlyPublicKey::from_str(
418            "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16601"
419        )
420        .is_err());
421        assert!(XOnlyPublicKey::from_str(
422            "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd16"
423        )
424        .is_err());
425        assert!(XOnlyPublicKey::from_str(
426            "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1"
427        )
428        .is_err());
429        assert!(XOnlyPublicKey::from_str(
430            "xx18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd1"
431        )
432        .is_err());
433
434        let long_str: String = "a".repeat(1024 * 1024);
435        assert!(XOnlyPublicKey::from_str(&long_str).is_err());
436    }
437
438    #[test]
439    // In fuzzing mode secret->public key derivation is different, so
440    // this test will never correctly derive the static pubkey.
441    #[cfg(not(secp256k1_fuzz))]
442    #[cfg(all(feature = "rand", feature = "alloc"))]
443    fn test_pubkey_serialize() {
444        use rand::rngs::mock::StepRng;
445        let secp = Secp256k1::new();
446        let kp = Keypair::new(&secp, &mut StepRng::new(1, 1));
447        let (pk, _parity) = kp.x_only_public_key();
448        assert_eq!(
449            &pk.serialize()[..],
450            &[
451                124, 121, 49, 14, 253, 63, 197, 50, 39, 194, 107, 17, 193, 219, 108, 154, 126, 9,
452                181, 248, 2, 12, 149, 233, 198, 71, 149, 134, 250, 184, 154, 229
453            ][..]
454        );
455    }
456
457    #[cfg(not(secp256k1_fuzz))] // fixed sig vectors can't work with fuzz-sigs
458    #[test]
459    #[cfg(all(feature = "serde", feature = "alloc"))]
460    fn test_serde() {
461        use serde_test::{assert_tokens, Configure, Token};
462
463        let s = Secp256k1::new();
464
465        let msg = Message::from_digest_slice(&[1; 32]).unwrap();
466        let keypair = Keypair::from_seckey_slice(&s, &[2; 32]).unwrap();
467        let aux = [3u8; 32];
468        let sig = s.sign_schnorr_with_aux_rand(&msg, &keypair, &aux);
469        static SIG_BYTES: [u8; constants::SCHNORR_SIGNATURE_SIZE] = [
470            0x14, 0xd0, 0xbf, 0x1a, 0x89, 0x53, 0x50, 0x6f, 0xb4, 0x60, 0xf5, 0x8b, 0xe1, 0x41,
471            0xaf, 0x76, 0x7f, 0xd1, 0x12, 0x53, 0x5f, 0xb3, 0x92, 0x2e, 0xf2, 0x17, 0x30, 0x8e,
472            0x2c, 0x26, 0x70, 0x6f, 0x1e, 0xeb, 0x43, 0x2b, 0x3d, 0xba, 0x9a, 0x01, 0x08, 0x2f,
473            0x9e, 0x4d, 0x4e, 0xf5, 0x67, 0x8a, 0xd0, 0xd9, 0xd5, 0x32, 0xc0, 0xdf, 0xa9, 0x07,
474            0xb5, 0x68, 0x72, 0x2d, 0x0b, 0x01, 0x19, 0xba,
475        ];
476        static SIG_STR: &str = "\
477            14d0bf1a8953506fb460f58be141af767fd112535fb3922ef217308e2c26706f1eeb432b3dba9a01082f9e4d4ef5678ad0d9d532c0dfa907b568722d0b0119ba\
478        ";
479
480        static PK_BYTES: [u8; 32] = [
481            24, 132, 87, 129, 246, 49, 196, 143, 28, 151, 9, 226, 48, 146, 6, 125, 6, 131, 127, 48,
482            170, 12, 208, 84, 74, 200, 135, 254, 145, 221, 209, 102,
483        ];
484        static PK_STR: &str = "18845781f631c48f1c9709e23092067d06837f30aa0cd0544ac887fe91ddd166";
485        let pk = XOnlyPublicKey::from_slice(&PK_BYTES).unwrap();
486
487        assert_tokens(&sig.compact(), &[Token::BorrowedBytes(&SIG_BYTES[..])]);
488        assert_tokens(&sig.compact(), &[Token::Bytes(&SIG_BYTES[..])]);
489        assert_tokens(&sig.compact(), &[Token::ByteBuf(&SIG_BYTES[..])]);
490
491        assert_tokens(&sig.readable(), &[Token::BorrowedStr(SIG_STR)]);
492        assert_tokens(&sig.readable(), &[Token::Str(SIG_STR)]);
493        assert_tokens(&sig.readable(), &[Token::String(SIG_STR)]);
494
495        #[rustfmt::skip]
496        assert_tokens(&pk.compact(), &[
497            Token::Tuple{ len: 32 },
498            Token::U8(24), Token::U8(132), Token::U8(87), Token::U8(129), Token::U8(246), Token::U8(49), Token::U8(196), Token::U8(143),
499            Token::U8(28), Token::U8(151), Token::U8(9), Token::U8(226), Token::U8(48), Token::U8(146), Token::U8(6), Token::U8(125),
500            Token::U8(6), Token::U8(131), Token::U8(127), Token::U8(48), Token::U8(170), Token::U8(12), Token::U8(208), Token::U8(84),
501            Token::U8(74), Token::U8(200), Token::U8(135), Token::U8(254), Token::U8(145), Token::U8(221), Token::U8(209), Token::U8(102),
502            Token::TupleEnd
503        ]);
504
505        assert_tokens(&pk.readable(), &[Token::BorrowedStr(PK_STR)]);
506        assert_tokens(&pk.readable(), &[Token::Str(PK_STR)]);
507        assert_tokens(&pk.readable(), &[Token::String(PK_STR)]);
508    }
509}