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