secp256k1/musig.rs
1//! This module implements high-level Rust bindings for a Schnorr-based
2//! multi-signature scheme called MuSig2 [paper](https://eprint.iacr.org/2020/1261).
3//! It is compatible with bip-schnorr.
4//!
5//! The documentation in this module is for reference and may not be sufficient
6//! for advanced use-cases. A full description of the C API usage along with security considerations
7//! can be found in [C-musig.md](secp256k1-sys/depend/secp256k1/src/modules/musig/musig.md).
8use core;
9use core::fmt;
10use core::mem::MaybeUninit;
11#[cfg(feature = "std")]
12use std;
13
14use crate::ffi::{self, CPtr};
15#[cfg(doc)]
16use crate::key;
17use crate::{
18 from_hex, schnorr, Error, Keypair, PublicKey, Scalar, Secp256k1, SecretKey, XOnlyPublicKey,
19};
20
21/// Serialized size (in bytes) of the aggregated nonce.
22/// The serialized form is used for transmitting or storing the aggregated nonce.
23pub const AGGNONCE_SERIALIZED_SIZE: usize = 66;
24
25/// Serialized size (in bytes) of an individual public nonce.
26/// The serialized form is used for transmission between signers.
27pub const PUBNONCE_SERIALIZED_SIZE: usize = 66;
28
29/// Serialized size (in bytes) of a partial signature.
30/// The serialized form is used for transmitting partial signatures to be
31/// aggregated into the final signature.
32pub const PART_SIG_SERIALIZED_SIZE: usize = 32;
33
34/// Musig parsing errors
35#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
36pub enum ParseError {
37 /// Parse Argument is malformed. This might occur if the point is on the secp order,
38 /// or if the secp scalar is outside of group order
39 MalformedArg,
40}
41
42#[cfg(feature = "std")]
43impl std::error::Error for ParseError {}
44
45impl fmt::Display for ParseError {
46 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
47 match *self {
48 ParseError::MalformedArg => write!(f, "Malformed parse argument"),
49 }
50 }
51}
52
53/// Session Id for a MuSig session.
54#[allow(missing_copy_implementations)]
55#[derive(Debug, Eq, PartialEq)]
56pub struct SessionSecretRand([u8; 32]);
57
58impl SessionSecretRand {
59 /// Creates a new [`SessionSecretRand`] with random bytes from the given rng
60 #[cfg(feature = "rand")]
61 pub fn from_rng<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
62 let session_secrand = crate::random_32_bytes(rng);
63 SessionSecretRand(session_secrand)
64 }
65
66 /// Creates a new [`SessionSecretRand`] with the given bytes.
67 ///
68 /// Special care must be taken that the bytes are unique for each call to
69 /// [`KeyAggCache::nonce_gen`] or [`new_nonce_pair`]. The simplest
70 /// recommendation is to use a cryptographicaly random 32-byte value.
71 ///
72 /// If the **rand** feature is enabled, [`SessionSecretRand::from_rng`] can be used to generate a
73 /// random session id.
74 ///
75 /// # Panics
76 ///
77 /// Panics if passed the all-zeros string. This is disallowed by the upstream
78 /// library. The input to this function should either be the whitened output of
79 /// a random number generator, or if that is not available, the output of a
80 /// stable monotonic counter.
81 pub fn assume_unique_per_nonce_gen(inner: [u8; 32]) -> Self {
82 // See SecretKey::eq for this "constant-time" algorithm for comparison against zero.
83 let inner_or = inner.iter().fold(0, |accum, x| accum | *x);
84 assert!(
85 unsafe { core::ptr::read_volatile(&inner_or) != 0 },
86 "session secrets may not be all zero",
87 );
88
89 SessionSecretRand(inner)
90 }
91
92 /// Obtains the inner bytes of the [`SessionSecretRand`].
93 pub fn to_byte_array(&self) -> [u8; 32] { self.0 }
94
95 /// Obtains a reference to the inner bytes of the [`SessionSecretRand`].
96 pub fn as_byte_array(&self) -> &[u8; 32] { &self.0 }
97
98 /// Obtains a mutable raw pointer to the beginning of the underlying storage.
99 ///
100 /// This is a low-level function and not exposed in the public API.
101 fn as_mut_ptr(&mut self) -> *mut u8 { self.0.as_mut_ptr() }
102}
103
104/// Cached data related to a key aggregation.
105#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
106pub struct KeyAggCache {
107 data: ffi::MusigKeyAggCache,
108 aggregated_xonly_public_key: XOnlyPublicKey,
109}
110
111impl CPtr for KeyAggCache {
112 type Target = ffi::MusigKeyAggCache;
113
114 fn as_c_ptr(&self) -> *const Self::Target { self.as_ptr() }
115
116 fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() }
117}
118
119/// Musig tweaking related error.
120#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
121pub struct InvalidTweakErr;
122
123#[cfg(feature = "std")]
124impl std::error::Error for InvalidTweakErr {}
125
126impl fmt::Display for InvalidTweakErr {
127 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
128 write!(f, "The tweak is negation of secret key")
129 }
130}
131
132/// Low level API for starting a signing session by generating a nonce.
133///
134/// Use [`KeyAggCache::nonce_gen`] whenever
135/// possible. This API provides full flexibility in providing custom nonce generation,
136/// but should be use with care.
137///
138/// This function outputs a secret nonce that will be required for signing and a
139/// corresponding public nonce that is intended to be sent to other signers.
140///
141/// MuSig differs from regular Schnorr signing in that implementers _must_ take
142/// special care to not reuse a nonce. If you cannot provide a `sec_key`, `session_secrand`
143/// UNIFORMLY RANDOM AND KEPT SECRET (even from other signers). Refer to libsecp256k1
144/// documentation for additional considerations.
145///
146/// MuSig2 nonces can be precomputed without knowing the aggregate public key, the message to sign.
147/// Refer to libsecp256k1 documentation for additional considerations.
148///
149/// # Arguments:
150///
151/// * `session_secrand`: [`SessionSecretRand`] Uniform random identifier for this session. Each call to this
152/// function must have a UNIQUE `session_secrand`.
153/// * `sec_key`: Optional [`SecretKey`] that we will use to sign to a create partial signature. Provide this
154/// for maximal mis-use resistance.
155/// * `pub_key`: [`PublicKey`] that we will use to create partial signature. The secnonce
156/// output of this function cannot be used to sign for any other public key.
157/// * `msg`: Optional message that will be signed later on. Provide this for maximal misuse resistance.
158/// * `extra_rand`: Additional randomness for mis-use resistance. Provide this for maximal misuse resistance
159///
160/// Remember that nonce reuse will immediately leak the secret key!
161///
162/// Example:
163///
164/// ```rust
165/// # #[cfg(feature = "std")]
166/// # #[cfg(feature = "rand")] {
167/// # use secp256k1::{PublicKey, SecretKey};
168/// # use secp256k1::musig::{new_nonce_pair, SessionSecretRand};
169/// // The session id must be sampled at random. Read documentation for more details.
170/// let session_secrand = SessionSecretRand::from_rng(&mut rand::rng());
171/// let sk = SecretKey::new(&mut rand::rng());
172/// let pk = PublicKey::from_secret_key(&sk);
173///
174/// // Supply extra auxiliary randomness to prevent misuse(for example, time of day)
175/// let extra_rand : Option<[u8; 32]> = None;
176///
177/// let (_sec_nonce, _pub_nonce) = new_nonce_pair(session_secrand, None, Some(sk), pk, None, None);
178/// # }
179/// ```
180pub fn new_nonce_pair(
181 mut session_secrand: SessionSecretRand,
182 key_agg_cache: Option<&KeyAggCache>,
183 sec_key: Option<SecretKey>,
184 pub_key: PublicKey,
185 msg: Option<&[u8; 32]>,
186 extra_rand: Option<[u8; 32]>,
187) -> (SecretNonce, PublicNonce) {
188 let extra_ptr = extra_rand.as_ref().map(|e| e.as_ptr()).unwrap_or(core::ptr::null());
189 let sk_ptr = sec_key.as_ref().map(|e| e.as_c_ptr()).unwrap_or(core::ptr::null());
190 let msg_ptr = msg.as_ref().map(|e| e.as_c_ptr()).unwrap_or(core::ptr::null());
191 let cache_ptr = key_agg_cache.map(|e| e.as_ptr()).unwrap_or(core::ptr::null());
192
193 let mut seed = session_secrand.to_byte_array();
194 if let Some(bytes) = sec_key {
195 for (this, that) in seed.iter_mut().zip(bytes.to_secret_bytes().iter()) {
196 *this ^= *that;
197 }
198 }
199 if let Some(bytes) = extra_rand {
200 for (this, that) in seed.iter_mut().zip(bytes.iter()) {
201 *this ^= *that;
202 }
203 }
204
205 unsafe {
206 // The use of a mutable pointer to `session_secrand`, which is a local variable,
207 // may seem concerning/wrong. It is ok: this pointer is only mutable because the
208 // behavior of `secp256k1_musig_nonce_gen` on error is to zero out the secret
209 // nonce. We guarantee this won't happen, but also if it does, it's harmless
210 // to zero out a local variable without propagating that change back to the
211 // caller or anything.
212 let mut sec_nonce = MaybeUninit::<ffi::MusigSecNonce>::uninit();
213 let mut pub_nonce = MaybeUninit::<ffi::MusigPubNonce>::uninit();
214
215 let ret = crate::with_global_context(
216 |secp: &Secp256k1<crate::AllPreallocated>| {
217 ffi::secp256k1_musig_nonce_gen(
218 secp.ctx.as_ptr(),
219 sec_nonce.as_mut_ptr(),
220 pub_nonce.as_mut_ptr(),
221 session_secrand.as_mut_ptr(),
222 sk_ptr,
223 pub_key.as_c_ptr(),
224 msg_ptr,
225 cache_ptr,
226 extra_ptr,
227 )
228 },
229 Some(&seed),
230 );
231
232 if ret == 0 {
233 // Rust type system guarantees that
234 // - input secret key is valid
235 // - msg is 32 bytes
236 // - Key agg cache is valid
237 // - extra input is 32 bytes
238 // This can only happen when the session id is all zeros
239 panic!("A zero session id was supplied")
240 } else {
241 let pub_nonce = PublicNonce(pub_nonce.assume_init());
242 let sec_nonce = SecretNonce(sec_nonce.assume_init());
243 (sec_nonce, pub_nonce)
244 }
245 }
246}
247
248/// A Musig partial signature.
249#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
250#[repr(transparent)]
251pub struct PartialSignature(ffi::MusigPartialSignature);
252
253impl CPtr for PartialSignature {
254 type Target = ffi::MusigPartialSignature;
255
256 fn as_c_ptr(&self) -> *const Self::Target { self.as_ptr() }
257
258 fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() }
259}
260
261impl fmt::LowerHex for PartialSignature {
262 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
263 for b in self.serialize() {
264 write!(f, "{:02x}", b)?;
265 }
266 Ok(())
267 }
268}
269
270impl fmt::Display for PartialSignature {
271 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
272}
273
274impl core::str::FromStr for PartialSignature {
275 type Err = ParseError;
276 fn from_str(s: &str) -> Result<Self, Self::Err> {
277 let mut res = [0u8; PART_SIG_SERIALIZED_SIZE];
278 match from_hex(s, &mut res) {
279 Ok(PART_SIG_SERIALIZED_SIZE) => PartialSignature::from_byte_array(&res),
280 _ => Err(ParseError::MalformedArg),
281 }
282 }
283}
284
285#[cfg(feature = "serde")]
286impl serde::Serialize for PartialSignature {
287 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
288 if s.is_human_readable() {
289 s.collect_str(self)
290 } else {
291 s.serialize_bytes(&self.serialize()[..])
292 }
293 }
294}
295
296#[cfg(feature = "serde")]
297impl<'de> serde::Deserialize<'de> for PartialSignature {
298 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
299 if d.is_human_readable() {
300 d.deserialize_str(super::serde_util::FromStrVisitor::new(
301 "a hex string representing a MuSig2 partial signature",
302 ))
303 } else {
304 d.deserialize_bytes(super::serde_util::BytesVisitor::new(
305 "a raw MuSig2 partial signature",
306 |slice| {
307 let bytes: &[u8; PART_SIG_SERIALIZED_SIZE] =
308 slice.try_into().map_err(|_| ParseError::MalformedArg)?;
309
310 Self::from_byte_array(bytes)
311 },
312 ))
313 }
314 }
315}
316
317impl PartialSignature {
318 /// Serialize a PartialSignature as a byte array.
319 pub fn serialize(&self) -> [u8; PART_SIG_SERIALIZED_SIZE] {
320 let mut data = MaybeUninit::<[u8; PART_SIG_SERIALIZED_SIZE]>::uninit();
321 unsafe {
322 if ffi::secp256k1_musig_partial_sig_serialize(
323 ffi::secp256k1_context_no_precomp,
324 data.as_mut_ptr() as *mut u8,
325 self.as_ptr(),
326 ) == 0
327 {
328 // Only fails if args are null pointer which is possible in safe rust
329 unreachable!("Serialization cannot fail")
330 } else {
331 data.assume_init()
332 }
333 }
334 }
335
336 /// Deserialize a PartialSignature from bytes.
337 ///
338 /// # Errors:
339 ///
340 /// - MalformedArg: If the signature [`PartialSignature`] is out of curve order
341 pub fn from_byte_array(data: &[u8; PART_SIG_SERIALIZED_SIZE]) -> Result<Self, ParseError> {
342 let mut partial_sig = MaybeUninit::<ffi::MusigPartialSignature>::uninit();
343 unsafe {
344 if ffi::secp256k1_musig_partial_sig_parse(
345 ffi::secp256k1_context_no_precomp,
346 partial_sig.as_mut_ptr(),
347 data.as_ptr(),
348 ) == 0
349 {
350 Err(ParseError::MalformedArg)
351 } else {
352 Ok(PartialSignature(partial_sig.assume_init()))
353 }
354 }
355 }
356
357 /// Get a const pointer to the inner PartialSignature
358 pub fn as_ptr(&self) -> *const ffi::MusigPartialSignature { &self.0 }
359
360 /// Get a mut pointer to the inner PartialSignature
361 pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigPartialSignature { &mut self.0 }
362}
363
364impl KeyAggCache {
365 /// Creates a new [`KeyAggCache`] by supplying a list of PublicKeys used in the session.
366 ///
367 /// Computes a combined public key and the hash of the given public keys.
368 ///
369 /// Different orders of `pubkeys` result in different `agg_pk`s.
370 /// The pubkeys can be sorted lexicographically before combining with which
371 /// ensures the same resulting `agg_pk` for the same multiset of pubkeys.
372 /// This is useful to do before aggregating pubkeys, such that the order of pubkeys
373 /// does not affect the combined public key.
374 /// To do this, call [`key::sort_pubkeys`].
375 ///
376 /// # Returns
377 ///
378 /// A [`KeyAggCache`] the can be used [`KeyAggCache::nonce_gen`] and [`Session::new`].
379 ///
380 /// # Args:
381 ///
382 /// * `secp` - Secp256k1 context object initialized for verification
383 /// * `pubkeys` - Input array of public keys to combine. The order is important; a
384 /// different order will result in a different combined public key
385 ///
386 /// Example:
387 ///
388 /// ```rust
389 /// # #[cfg(feature = "std")]
390 /// # #[cfg(feature = "rand")] {
391 /// # use secp256k1::{SecretKey, Keypair, PublicKey};
392 /// # use secp256k1::musig::KeyAggCache;
393 /// # let sk1 = SecretKey::new(&mut rand::rng());
394 /// # let pub_key1 = PublicKey::from_secret_key(&sk1);
395 /// # let sk2 = SecretKey::new(&mut rand::rng());
396 /// # let pub_key2 = PublicKey::from_secret_key(&sk2);
397 /// #
398 /// let key_agg_cache = KeyAggCache::new(&[&pub_key1, &pub_key2]);
399 /// let _agg_pk = key_agg_cache.agg_pk();
400 /// # }
401 /// ```
402 ///
403 /// # Panics
404 ///
405 /// Panics if an empty slice of pubkeys is provided.
406 pub fn new(pubkeys: &[&PublicKey]) -> Self {
407 if pubkeys.is_empty() {
408 panic!("Cannot aggregate an empty slice of pubkeys");
409 }
410
411 let mut key_agg_cache = MaybeUninit::<ffi::MusigKeyAggCache>::uninit();
412 let mut agg_pk = MaybeUninit::<ffi::XOnlyPublicKey>::uninit();
413
414 unsafe {
415 let pubkeys_ref = core::slice::from_raw_parts(
416 pubkeys.as_c_ptr() as *const *const ffi::PublicKey,
417 pubkeys.len(),
418 );
419
420 let ret = crate::with_global_context(
421 |secp: &Secp256k1<crate::AllPreallocated>| {
422 ffi::secp256k1_musig_pubkey_agg(
423 secp.ctx.as_ptr(),
424 agg_pk.as_mut_ptr(),
425 key_agg_cache.as_mut_ptr(),
426 pubkeys_ref.as_ptr(),
427 pubkeys_ref.len(),
428 )
429 },
430 None,
431 );
432 if ret == 0 {
433 // Returns 0 only if the keys are malformed that never happens in safe rust type system.
434 unreachable!("Invalid XOnlyPublicKey in input pubkeys")
435 } else {
436 // secp256k1_musig_pubkey_agg overwrites the cache and the key so this is sound.
437 let key_agg_cache = key_agg_cache.assume_init();
438 let agg_pk = XOnlyPublicKey::from(agg_pk.assume_init());
439 KeyAggCache { data: key_agg_cache, aggregated_xonly_public_key: agg_pk }
440 }
441 }
442 }
443
444 /// Obtains the aggregate public key for this [`KeyAggCache`]
445 pub fn agg_pk(&self) -> XOnlyPublicKey { self.aggregated_xonly_public_key }
446
447 /// Obtains the aggregate public key for this [`KeyAggCache`] as a full [`PublicKey`].
448 ///
449 /// This is only useful if you need the non-xonly public key, in particular for
450 /// plain (non-xonly) tweaking or batch-verifying multiple key aggregations
451 /// (not supported yet).
452 pub fn agg_pk_full(&self) -> PublicKey {
453 unsafe {
454 let mut pk = PublicKey::from(ffi::PublicKey::new());
455 if ffi::secp256k1_musig_pubkey_get(
456 ffi::secp256k1_context_no_precomp,
457 pk.as_mut_c_ptr(),
458 self.as_ptr(),
459 ) == 0
460 {
461 // Returns 0 only if the keys are malformed that never happens in safe rust type system.
462 unreachable!("All the arguments are valid")
463 } else {
464 pk
465 }
466 }
467 }
468
469 /// Apply ordinary "EC" tweaking to a public key in a [`KeyAggCache`].
470 ///
471 /// This is done by adding the generator multiplied with `tweak32` to it. Returns the tweaked [`PublicKey`].
472 /// This is useful for deriving child keys from an aggregate public key via BIP32.
473 /// This function is required if you want to _sign_ for a tweaked aggregate key.
474 ///
475 /// # Arguments:
476 ///
477 /// * `secp` : [`Secp256k1`] context object initialized for verification
478 /// * `tweak`: tweak of type [`Scalar`] with which to tweak the aggregated key
479 ///
480 /// # Errors:
481 ///
482 /// If resulting public key would be invalid (only when the tweak is the negation of the corresponding
483 /// secret key). For uniformly random 32-byte arrays(for example, in BIP 32 derivation) the chance of
484 /// being invalid is negligible (around 1 in 2^128).
485 ///
486 /// Example:
487 ///
488 /// ```rust
489 /// # #[cfg(not(secp256k1_fuzz))]
490 /// # #[cfg(feature = "std")]
491 /// # #[cfg(feature = "rand")] {
492 /// # use secp256k1::{Scalar, SecretKey, Keypair, PublicKey};
493 /// # use secp256k1::musig::KeyAggCache;
494 /// # let sk1 = SecretKey::new(&mut rand::rng());
495 /// # let pub_key1 = PublicKey::from_secret_key(&sk1);
496 /// # let sk2 = SecretKey::new(&mut rand::rng());
497 /// # let pub_key2 = PublicKey::from_secret_key(&sk2);
498 /// #
499 /// let mut key_agg_cache = KeyAggCache::new(&[&pub_key1, &pub_key2]);
500 ///
501 /// let tweak: [u8; 32] = *b"this could be a BIP32 tweak....\0";
502 /// let tweak = Scalar::from_be_bytes(tweak).unwrap();
503 /// let tweaked_key = key_agg_cache.pubkey_ec_tweak_add(&tweak).unwrap();
504 /// # }
505 /// ```
506 pub fn pubkey_ec_tweak_add(&mut self, tweak: &Scalar) -> Result<PublicKey, InvalidTweakErr> {
507 unsafe {
508 let mut out = PublicKey::from(ffi::PublicKey::new());
509
510 let ret = crate::with_global_context(
511 |secp: &Secp256k1<crate::AllPreallocated>| {
512 ffi::secp256k1_musig_pubkey_ec_tweak_add(
513 secp.ctx.as_ptr(),
514 out.as_mut_c_ptr(),
515 self.as_mut_ptr(),
516 tweak.as_c_ptr(),
517 )
518 },
519 None,
520 );
521 if ret == 0 {
522 Err(InvalidTweakErr)
523 } else {
524 self.aggregated_xonly_public_key = out.x_only_public_key().0;
525 Ok(out)
526 }
527 }
528 }
529
530 /// Apply "x-only" tweaking to a public key in a [`KeyAggCache`].
531 ///
532 /// This is done by adding the generator multiplied with `tweak32` to it. Returns the tweaked [`XOnlyPublicKey`].
533 /// This is useful in creating taproot outputs.
534 /// This function is required if you want to _sign_ for a tweaked aggregate key.
535 ///
536 /// # Arguments:
537 ///
538 /// * `secp` : [`Secp256k1`] context object initialized for verification
539 /// * `tweak`: tweak of type [`SecretKey`] with which to tweak the aggregated key
540 ///
541 /// # Errors:
542 ///
543 /// If resulting public key would be invalid (only when the tweak is the negation of the corresponding
544 /// secret key). For uniformly random 32-byte arrays(for example, in BIP341 taproot tweaks) the chance of
545 /// being invalid is negligible (around 1 in 2^128)
546 ///
547 /// Example:
548 ///
549 /// ```rust
550 /// # #[cfg(not(secp256k1_fuzz))]
551 /// # #[cfg(feature = "std")]
552 /// # #[cfg(feature = "rand")] {
553 /// # use secp256k1::{Scalar, SecretKey, Keypair, PublicKey};
554 /// # use secp256k1::musig::KeyAggCache;
555 /// # let sk1 = SecretKey::new(&mut rand::rng());
556 /// # let pub_key1 = PublicKey::from_secret_key(&sk1);
557 /// # let sk2 = SecretKey::new(&mut rand::rng());
558 /// # let pub_key2 = PublicKey::from_secret_key(&sk2);
559 ///
560 /// let mut key_agg_cache = KeyAggCache::new(&[&pub_key1, &pub_key2]);
561 ///
562 /// let tweak = Scalar::from_be_bytes(*b"Insecure tweak, Don't use this!!").unwrap(); // tweak could be from tap
563 /// let _x_only_key_tweaked = key_agg_cache.pubkey_xonly_tweak_add(&tweak).unwrap();
564 /// # }
565 /// ```
566 pub fn pubkey_xonly_tweak_add(&mut self, tweak: &Scalar) -> Result<PublicKey, InvalidTweakErr> {
567 unsafe {
568 let mut out = PublicKey::from(ffi::PublicKey::new());
569
570 let ret = crate::with_global_context(
571 |secp: &Secp256k1<crate::AllPreallocated>| {
572 ffi::secp256k1_musig_pubkey_xonly_tweak_add(
573 secp.ctx.as_ptr(),
574 out.as_mut_c_ptr(),
575 self.as_mut_ptr(),
576 tweak.as_c_ptr(),
577 )
578 },
579 None,
580 );
581 if ret == 0 {
582 Err(InvalidTweakErr)
583 } else {
584 self.aggregated_xonly_public_key = out.x_only_public_key().0;
585 Ok(out)
586 }
587 }
588 }
589
590 /// Starts a signing session by generating a nonce
591 ///
592 /// This function outputs a secret nonce that will be required for signing and a
593 /// corresponding public nonce that is intended to be sent to other signers.
594 ///
595 /// MuSig differs from regular Schnorr signing in that implementers _must_ take
596 /// special care to not reuse a nonce. If you cannot provide a `sec_key`, `session_secrand`
597 /// UNIFORMLY RANDOM AND KEPT SECRET (even from other signers).
598 /// Refer to libsecp256k1 documentation for additional considerations.
599 ///
600 /// MuSig2 nonces can be precomputed without knowing the aggregate public key, the message to sign.
601 /// See the `new_nonce_pair` method that allows generating [`SecretNonce`] and [`PublicNonce`]
602 /// with only the `session_secrand` field.
603 ///
604 /// If the aggregator lies, the resulting signature will simply be invalid.
605 ///
606 /// Remember that nonce reuse will immediately leak the secret key!
607 ///
608 /// # Returns:
609 ///
610 /// A pair of ([`SecretNonce`], [`PublicNonce`]) that can be later used signing and aggregation
611 ///
612 /// # Arguments:
613 ///
614 /// * `secp` : [`Secp256k1`] context object initialized for signing
615 /// * `session_secrand`: [`SessionSecretRand`] Uniform random identifier for this session. Each call to this
616 /// function must have a UNIQUE `session_secrand`.
617 /// * `pub_key`: [`PublicKey`] of the signer creating the nonce.
618 /// * `msg`: message that will be signed later on.
619 /// * `extra_rand`: Additional randomness for mis-use resistance
620 ///
621 /// Example:
622 ///
623 /// ```rust
624 /// # #[cfg(feature = "std")]
625 /// # #[cfg(feature = "rand")] {
626 /// # use secp256k1::{SecretKey, Keypair, PublicKey};
627 /// # use secp256k1::musig::{KeyAggCache, SessionSecretRand};
628 /// # let sk1 = SecretKey::new(&mut rand::rng());
629 /// # let pub_key1 = PublicKey::from_secret_key(&sk1);
630 /// # let sk2 = SecretKey::new(&mut rand::rng());
631 /// # let pub_key2 = PublicKey::from_secret_key(&sk2);
632 /// #
633 /// let key_agg_cache = KeyAggCache::new(&[&pub_key1, &pub_key2]);
634 /// // The session id must be sampled at random. Read documentation for more details.
635 /// let session_secrand = SessionSecretRand::from_rng(&mut rand::rng());
636 ///
637 /// // Provide the current time for mis-use resistance
638 /// let msg = b"Public message we want to sign!!";
639 /// let extra_rand : Option<[u8; 32]> = None;
640 /// let (_sec_nonce, _pub_nonce) = key_agg_cache.nonce_gen(session_secrand, pub_key1, msg, extra_rand);
641 /// # }
642 /// ```
643 pub fn nonce_gen(
644 &self,
645 session_secrand: SessionSecretRand,
646 pub_key: PublicKey,
647 msg: &[u8; 32],
648 extra_rand: Option<[u8; 32]>,
649 ) -> (SecretNonce, PublicNonce) {
650 // The secret key here is supplied as NULL. This is okay because we supply the
651 // public key and the message.
652 // This makes a simple API for the user because it does not require them to pass here.
653 new_nonce_pair(session_secrand, Some(self), None, pub_key, Some(msg), extra_rand)
654 }
655
656 /// Get a const pointer to the inner KeyAggCache
657 pub fn as_ptr(&self) -> *const ffi::MusigKeyAggCache { &self.data }
658
659 /// Get a mut pointer to the inner KeyAggCache
660 pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigKeyAggCache { &mut self.data }
661}
662
663/// Musig Secret Nonce.
664///
665/// A signer who is online throughout the whole process and can keep this structure
666/// in memory can use the provided API functions for a safe standard workflow.
667///
668/// This structure does not implement `Copy` or `Clone`; after construction the only
669/// thing that can or should be done with this nonce is to call [`Session::partial_sign`],
670/// which will take ownership. This is to prevent accidental reuse of the nonce.
671///
672/// See the warnings on [`Self::dangerous_into_bytes`] for more information about
673/// the risks of non-standard workflows.
674#[allow(missing_copy_implementations)]
675#[derive(Debug)]
676pub struct SecretNonce(ffi::MusigSecNonce);
677
678impl CPtr for SecretNonce {
679 type Target = ffi::MusigSecNonce;
680
681 fn as_c_ptr(&self) -> *const Self::Target { self.as_ptr() }
682
683 fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() }
684}
685
686impl SecretNonce {
687 /// Get a const pointer to the inner KeyAggCache
688 pub fn as_ptr(&self) -> *const ffi::MusigSecNonce { &self.0 }
689
690 /// Get a mut pointer to the inner KeyAggCache
691 pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigSecNonce { &mut self.0 }
692
693 /// Function to return a copy of the internal array. See WARNING before using this function.
694 ///
695 /// # Warning:
696 ///
697 /// Storing and re-creating this structure may lead to nonce reuse, which will leak
698 /// your secret key in two signing sessions, even if neither session is completed.
699 /// These functions should be avoided if possible and used with care.
700 ///
701 /// See <https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/>
702 /// for more details about these risks.
703 ///
704 /// # Warning:
705 ///
706 /// The underlying library, libsecp256k1, does not guarantee the byte format will be consistent
707 /// across versions or platforms. Special care should be taken to ensure the returned bytes are
708 /// only ever passed to `dangerous_from_bytes` from the same libsecp256k1 version, and the same
709 /// platform.
710 pub fn dangerous_into_bytes(self) -> [u8; secp256k1_sys::MUSIG_SECNONCE_SIZE] {
711 self.0.dangerous_into_bytes()
712 }
713
714 /// Function to create a new [`SecretNonce`] from a 32 byte array.
715 ///
716 /// Refer to the warnings on [`SecretNonce::dangerous_into_bytes`] for more details.
717 pub fn dangerous_from_bytes(array: [u8; secp256k1_sys::MUSIG_SECNONCE_SIZE]) -> Self {
718 SecretNonce(ffi::MusigSecNonce::dangerous_from_bytes(array))
719 }
720}
721
722/// An individual MuSig public nonce. Not to be confused with [`AggregatedNonce`].
723#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
724#[repr(transparent)]
725pub struct PublicNonce(ffi::MusigPubNonce);
726
727impl CPtr for PublicNonce {
728 type Target = ffi::MusigPubNonce;
729
730 fn as_c_ptr(&self) -> *const Self::Target { self.as_ptr() }
731
732 fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() }
733}
734
735impl fmt::LowerHex for PublicNonce {
736 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
737 for b in self.serialize() {
738 write!(f, "{:02x}", b)?;
739 }
740 Ok(())
741 }
742}
743
744impl fmt::Display for PublicNonce {
745 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
746}
747
748impl core::str::FromStr for PublicNonce {
749 type Err = ParseError;
750 fn from_str(s: &str) -> Result<Self, Self::Err> {
751 let mut res = [0u8; PUBNONCE_SERIALIZED_SIZE];
752 match from_hex(s, &mut res) {
753 Ok(PUBNONCE_SERIALIZED_SIZE) => PublicNonce::from_byte_array(&res),
754 _ => Err(ParseError::MalformedArg),
755 }
756 }
757}
758
759#[cfg(feature = "serde")]
760impl serde::Serialize for PublicNonce {
761 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
762 if s.is_human_readable() {
763 s.collect_str(self)
764 } else {
765 s.serialize_bytes(&self.serialize()[..])
766 }
767 }
768}
769
770#[cfg(feature = "serde")]
771impl<'de> serde::Deserialize<'de> for PublicNonce {
772 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
773 if d.is_human_readable() {
774 d.deserialize_str(super::serde_util::FromStrVisitor::new(
775 "a hex string representing a MuSig2 public nonce",
776 ))
777 } else {
778 d.deserialize_bytes(super::serde_util::BytesVisitor::new(
779 "a raw MuSig2 public nonce",
780 |slice| {
781 let bytes: &[u8; PUBNONCE_SERIALIZED_SIZE] =
782 slice.try_into().map_err(|_| ParseError::MalformedArg)?;
783
784 Self::from_byte_array(bytes)
785 },
786 ))
787 }
788 }
789}
790
791impl PublicNonce {
792 /// Serialize a PublicNonce
793 pub fn serialize(&self) -> [u8; PUBNONCE_SERIALIZED_SIZE] {
794 let mut data = [0; PUBNONCE_SERIALIZED_SIZE];
795 unsafe {
796 if ffi::secp256k1_musig_pubnonce_serialize(
797 ffi::secp256k1_context_no_precomp,
798 data.as_mut_ptr(),
799 self.as_ptr(),
800 ) == 0
801 {
802 // Only fails when the arguments are invalid which is not possible in safe rust
803 unreachable!("Arguments must be valid and well-typed")
804 } else {
805 data
806 }
807 }
808 }
809
810 /// Deserialize a PublicNonce from a portable byte representation
811 ///
812 /// # Errors:
813 ///
814 /// - MalformedArg: If the [`PublicNonce`] is 132 bytes, but out of curve order
815 pub fn from_byte_array(data: &[u8; PUBNONCE_SERIALIZED_SIZE]) -> Result<Self, ParseError> {
816 let mut pub_nonce = MaybeUninit::<ffi::MusigPubNonce>::uninit();
817 unsafe {
818 if ffi::secp256k1_musig_pubnonce_parse(
819 ffi::secp256k1_context_no_precomp,
820 pub_nonce.as_mut_ptr(),
821 data.as_ptr(),
822 ) == 0
823 {
824 Err(ParseError::MalformedArg)
825 } else {
826 Ok(PublicNonce(pub_nonce.assume_init()))
827 }
828 }
829 }
830
831 /// Get a const pointer to the inner PublicNonce
832 pub fn as_ptr(&self) -> *const ffi::MusigPubNonce { &self.0 }
833
834 /// Get a mut pointer to the inner PublicNonce
835 pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigPubNonce { &mut self.0 }
836}
837
838/// Musig aggregated nonce computed by aggregating all individual public nonces
839#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
840pub struct AggregatedNonce(ffi::MusigAggNonce);
841
842impl CPtr for AggregatedNonce {
843 type Target = ffi::MusigAggNonce;
844
845 fn as_c_ptr(&self) -> *const Self::Target { self.as_ptr() }
846
847 fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.as_mut_ptr() }
848}
849
850impl fmt::LowerHex for AggregatedNonce {
851 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
852 for b in self.serialize() {
853 write!(f, "{:02x}", b)?;
854 }
855 Ok(())
856 }
857}
858
859impl fmt::Display for AggregatedNonce {
860 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
861}
862
863impl core::str::FromStr for AggregatedNonce {
864 type Err = ParseError;
865 fn from_str(s: &str) -> Result<Self, Self::Err> {
866 let mut res = [0u8; AGGNONCE_SERIALIZED_SIZE];
867 match from_hex(s, &mut res) {
868 Ok(AGGNONCE_SERIALIZED_SIZE) => AggregatedNonce::from_byte_array(&res),
869 _ => Err(ParseError::MalformedArg),
870 }
871 }
872}
873
874#[cfg(feature = "serde")]
875impl serde::Serialize for AggregatedNonce {
876 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
877 if s.is_human_readable() {
878 s.collect_str(self)
879 } else {
880 s.serialize_bytes(&self.serialize()[..])
881 }
882 }
883}
884
885#[cfg(feature = "serde")]
886impl<'de> serde::Deserialize<'de> for AggregatedNonce {
887 fn deserialize<D: serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
888 if d.is_human_readable() {
889 d.deserialize_str(super::serde_util::FromStrVisitor::new(
890 "a hex string representing a MuSig2 aggregated nonce",
891 ))
892 } else {
893 d.deserialize_bytes(super::serde_util::BytesVisitor::new(
894 "a raw MuSig2 aggregated nonce",
895 |slice| {
896 let bytes: &[u8; AGGNONCE_SERIALIZED_SIZE] =
897 slice.try_into().map_err(|_| ParseError::MalformedArg)?;
898
899 Self::from_byte_array(bytes)
900 },
901 ))
902 }
903 }
904}
905
906impl AggregatedNonce {
907 /// Combine received public nonces into a single aggregated nonce
908 ///
909 /// This is useful to reduce the communication between signers, because instead
910 /// of everyone sending nonces to everyone else, there can be one party
911 /// receiving all nonces, combining the nonces with this function and then
912 /// sending only the combined nonce back to the signers.
913 ///
914 /// Example:
915 ///
916 /// ```rust
917 /// # #[cfg(feature = "std")]
918 /// # #[cfg(feature = "rand")] {
919 /// # use secp256k1::{SecretKey, Keypair, PublicKey};
920 /// # use secp256k1::musig::{AggregatedNonce, KeyAggCache, SessionSecretRand};
921 /// # let sk1 = SecretKey::new(&mut rand::rng());
922 /// # let pub_key1 = PublicKey::from_secret_key(&sk1);
923 /// # let sk2 = SecretKey::new(&mut rand::rng());
924 /// # let pub_key2 = PublicKey::from_secret_key(&sk2);
925 ///
926 /// # let key_agg_cache = KeyAggCache::new(&[&pub_key1, &pub_key2]);
927 /// // The session id must be sampled at random. Read documentation for more details.
928 ///
929 /// let msg = b"Public message we want to sign!!";
930 ///
931 /// let session_secrand1 = SessionSecretRand::from_rng(&mut rand::rng());
932 /// let (_sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(session_secrand1, pub_key1, msg, None);
933 ///
934 /// // Signer two does the same: Possibly on a different device
935 /// let session_secrand2 = SessionSecretRand::from_rng(&mut rand::rng());
936 /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(session_secrand2, pub_key2, msg, None);
937 ///
938 /// let aggnonce = AggregatedNonce::new(&[&pub_nonce1, &pub_nonce2]);
939 /// # }
940 /// ```
941 /// # Panics
942 ///
943 /// Panics if an empty slice of nonces is provided.
944 ///
945 pub fn new(nonces: &[&PublicNonce]) -> Self {
946 if nonces.is_empty() {
947 panic!("Cannot aggregate an empty slice of nonces");
948 }
949
950 let mut aggnonce = MaybeUninit::<ffi::MusigAggNonce>::uninit();
951
952 unsafe {
953 let pubnonces = core::slice::from_raw_parts(
954 nonces.as_c_ptr() as *const *const ffi::MusigPubNonce,
955 nonces.len(),
956 );
957
958 let ret = crate::with_global_context(
959 |secp: &Secp256k1<crate::AllPreallocated>| {
960 ffi::secp256k1_musig_nonce_agg(
961 secp.ctx().as_ptr(),
962 aggnonce.as_mut_ptr(),
963 pubnonces.as_ptr(),
964 pubnonces.len(),
965 )
966 },
967 None,
968 );
969 if ret == 0 {
970 // This can only crash if the individual nonces are invalid which is not possible is rust.
971 // Note that even if aggregate nonce is point at infinity, the musig spec sets it as `G`
972 unreachable!("Public key nonces are well-formed and valid in rust typesystem")
973 } else {
974 AggregatedNonce(aggnonce.assume_init())
975 }
976 }
977 }
978
979 /// Serialize a AggregatedNonce into a 66 bytes array.
980 pub fn serialize(&self) -> [u8; AGGNONCE_SERIALIZED_SIZE] {
981 let mut data = [0; AGGNONCE_SERIALIZED_SIZE];
982 unsafe {
983 if ffi::secp256k1_musig_aggnonce_serialize(
984 ffi::secp256k1_context_no_precomp,
985 data.as_mut_ptr(),
986 self.as_ptr(),
987 ) == 0
988 {
989 // Only fails when the arguments are invalid which is not possible in safe rust
990 unreachable!("Arguments must be valid and well-typed")
991 } else {
992 data
993 }
994 }
995 }
996
997 /// Deserialize a AggregatedNonce from byte slice
998 ///
999 /// # Errors:
1000 ///
1001 /// - MalformedArg: If the byte slice is 66 bytes, but the [`AggregatedNonce`] is invalid
1002 pub fn from_byte_array(data: &[u8; AGGNONCE_SERIALIZED_SIZE]) -> Result<Self, ParseError> {
1003 let mut aggnonce = MaybeUninit::<ffi::MusigAggNonce>::uninit();
1004 unsafe {
1005 if ffi::secp256k1_musig_aggnonce_parse(
1006 ffi::secp256k1_context_no_precomp,
1007 aggnonce.as_mut_ptr(),
1008 data.as_ptr(),
1009 ) == 0
1010 {
1011 Err(ParseError::MalformedArg)
1012 } else {
1013 Ok(AggregatedNonce(aggnonce.assume_init()))
1014 }
1015 }
1016 }
1017
1018 /// Get a const pointer to the inner AggregatedNonce
1019 pub fn as_ptr(&self) -> *const ffi::MusigAggNonce { &self.0 }
1020
1021 /// Get a mut pointer to the inner AggregatedNonce
1022 pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigAggNonce { &mut self.0 }
1023}
1024
1025/// The aggregated signature of all partial signatures.
1026#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1027pub struct AggregatedSignature([u8; 64]);
1028
1029impl AggregatedSignature {
1030 /// Returns the aggregated signature [`schnorr::Signature`] assuming it is valid.
1031 ///
1032 /// The `partial_sig_agg` function cannot guarantee that the produced signature is valid because participants
1033 /// may send invalid signatures. In some applications this doesn't matter because the invalid message is simply
1034 /// dropped with no consequences. These can simply call this function to obtain the resulting signature. However
1035 /// in applications that require having valid signatures before continuing (e.g. presigned transactions in Bitcoin Lightning Network) this would be exploitable. Such applications MUST verify the resulting signature using the
1036 /// [`verify`](Self::verify) method.
1037 ///
1038 /// Note that while an alternative approach of verifying partial signatures is valid, verifying the aggregated
1039 /// signature is more performant. Thus it should be generally better to verify the signature using this function first
1040 /// and fall back to detection of violators if it fails.
1041 pub fn assume_valid(self) -> schnorr::Signature { schnorr::Signature::from_byte_array(self.0) }
1042
1043 /// Verify the aggregated signature against the aggregate public key and message
1044 /// before returning the signature.
1045 pub fn verify(
1046 self,
1047 aggregate_key: &XOnlyPublicKey,
1048 message: &[u8],
1049 ) -> Result<schnorr::Signature, Error> {
1050 let sig = schnorr::Signature::from_byte_array(self.0);
1051 schnorr::verify(&sig, message, aggregate_key)
1052 .map(|_| sig)
1053 .map_err(|_| Error::IncorrectSignature)
1054 }
1055}
1056
1057/// A musig Signing session.
1058#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1059pub struct Session(ffi::MusigSession);
1060
1061impl Session {
1062 /// Creates a new musig signing session.
1063 ///
1064 /// Takes the public nonces of all signers and computes a session that is
1065 /// required for signing and verification of partial signatures.
1066 ///
1067 /// # Returns:
1068 ///
1069 /// A [`Session`] that can be later used for signing.
1070 ///
1071 /// # Arguments:
1072 ///
1073 /// * `secp` : [`Secp256k1`] context object initialized for signing
1074 /// * `key_agg_cache`: [`KeyAggCache`] to be used for this session
1075 /// * `agg_nonce`: [`AggregatedNonce`], the aggregate nonce
1076 /// * `msg`: message that will be signed later on.
1077 ///
1078 /// Example:
1079 ///
1080 /// ```rust
1081 /// # #[cfg(feature = "std")]
1082 /// # #[cfg(feature = "rand")] {
1083 /// # use secp256k1::{SecretKey, Keypair, PublicKey};
1084 /// # use secp256k1::musig::{AggregatedNonce, KeyAggCache, Session, SessionSecretRand};
1085 /// # let sk1 = SecretKey::new(&mut rand::rng());
1086 /// # let pub_key1 = PublicKey::from_secret_key(&sk1);
1087 /// # let sk2 = SecretKey::new(&mut rand::rng());
1088 /// # let pub_key2 = PublicKey::from_secret_key(&sk2);
1089 ///
1090 /// # let key_agg_cache = KeyAggCache::new(&[&pub_key1, &pub_key2]);
1091 /// // The session id must be sampled at random. Read documentation for more details.
1092 ///
1093 /// let msg = b"Public message we want to sign!!";
1094 ///
1095 /// // Provide the current time for mis-use resistance
1096 /// let session_secrand1 = SessionSecretRand::from_rng(&mut rand::rng());
1097 /// let extra_rand1 : Option<[u8; 32]> = None;
1098 /// let (_sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(session_secrand1, pub_key1, msg, extra_rand1);
1099 ///
1100 /// // Signer two does the same. Possibly on a different device
1101 /// let session_secrand2 = SessionSecretRand::from_rng(&mut rand::rng());
1102 /// let extra_rand2 : Option<[u8; 32]> = None;
1103 /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(session_secrand2, pub_key2, msg, extra_rand2);
1104 ///
1105 /// let aggnonce = AggregatedNonce::new(&[&pub_nonce1, &pub_nonce2]);
1106 ///
1107 /// let session = Session::new(
1108 /// &key_agg_cache,
1109 /// aggnonce,
1110 /// msg,
1111 /// );
1112 /// # }
1113 /// ```
1114 pub fn new(key_agg_cache: &KeyAggCache, agg_nonce: AggregatedNonce, msg: &[u8; 32]) -> Self {
1115 let mut session = MaybeUninit::<ffi::MusigSession>::uninit();
1116
1117 unsafe {
1118 let ret = crate::with_global_context(
1119 |secp: &Secp256k1<crate::AllPreallocated>| {
1120 ffi::secp256k1_musig_nonce_process(
1121 secp.ctx().as_ptr(),
1122 session.as_mut_ptr(),
1123 agg_nonce.as_ptr(),
1124 msg.as_c_ptr(),
1125 key_agg_cache.as_ptr(),
1126 )
1127 },
1128 None,
1129 );
1130 if ret == 0 {
1131 // Only fails on cryptographically unreachable codes or if the args are invalid.
1132 // None of which can occur in safe rust.
1133 unreachable!("Impossible to construct invalid arguments in safe rust.
1134 Also reaches here if R1 + R2*b == point at infinity, but only occurs with 2^128 probability")
1135 } else {
1136 Session(session.assume_init())
1137 }
1138 }
1139 }
1140
1141 /// Produces a partial signature for a given key pair and secret nonce.
1142 ///
1143 /// Remember that nonce reuse will immediately leak the secret key!
1144 ///
1145 /// # Returns:
1146 ///
1147 /// A [`PartialSignature`] that can be later be aggregated into a [`schnorr::Signature`]
1148 ///
1149 /// # Arguments:
1150 ///
1151 /// * `secp` : [`Secp256k1`] context object initialized for signing
1152 /// * `sec_nonce`: [`SecretNonce`] to be used for this session that has never
1153 /// been used before. For mis-use resistance, this API takes a mutable reference
1154 /// to `sec_nonce` and sets it to zero even if the partial signing fails.
1155 /// * `key_pair`: The [`Keypair`] to sign the message
1156 /// * `key_agg_cache`: [`KeyAggCache`] containing the aggregate pubkey used in
1157 /// the creation of this session
1158 ///
1159 /// # Errors:
1160 ///
1161 /// - If the provided [`SecretNonce`] has already been used for signing
1162 ///
1163 pub fn partial_sign(
1164 &self,
1165 mut secnonce: SecretNonce,
1166 keypair: &Keypair,
1167 key_agg_cache: &KeyAggCache,
1168 ) -> PartialSignature {
1169 unsafe {
1170 let mut partial_sig = MaybeUninit::<ffi::MusigPartialSignature>::uninit();
1171
1172 let res = crate::with_global_context(
1173 |secp: &Secp256k1<crate::AllPreallocated>| {
1174 ffi::secp256k1_musig_partial_sign(
1175 secp.ctx().as_ptr(),
1176 partial_sig.as_mut_ptr(),
1177 secnonce.as_mut_ptr(),
1178 keypair.as_c_ptr(),
1179 key_agg_cache.as_ptr(),
1180 self.as_ptr(),
1181 )
1182 },
1183 Some(&keypair.secret_bytes()),
1184 );
1185
1186 assert_eq!(res, 1);
1187 PartialSignature(partial_sig.assume_init())
1188 }
1189 }
1190
1191 /// Checks that an individual partial signature verifies
1192 ///
1193 /// This function is essential when using protocols with adaptor signatures.
1194 /// However, it is not essential for regular MuSig's, in the sense that if any
1195 /// partial signatures does not verify, the full signature will also not verify, so the
1196 /// problem will be caught. But this function allows determining the specific party
1197 /// who produced an invalid signature, so that signing can be restarted without them.
1198 ///
1199 /// # Returns:
1200 ///
1201 /// true if the partial signature successfully verifies, otherwise returns false
1202 ///
1203 /// # Arguments:
1204 ///
1205 /// * `secp` : [`Secp256k1`] context object initialized for signing
1206 /// * `key_agg_cache`: [`KeyAggCache`] containing the aggregate pubkey used in
1207 /// the creation of this session
1208 /// * `partial_sig`: [`PartialSignature`] sent by the signer associated with
1209 /// the given `pub_nonce` and `pubkey`
1210 /// * `pub_nonce`: The [`PublicNonce`] of the signer associated with the `partial_sig`
1211 /// and `pub_key`
1212 /// * `pub_key`: The [`XOnlyPublicKey`] of the signer associated with the given
1213 /// `partial_sig` and `pub_nonce`
1214 ///
1215 /// Example:
1216 ///
1217 /// ```rust
1218 /// # #[cfg(not(secp256k1_fuzz))]
1219 /// # #[cfg(feature = "std")]
1220 /// # #[cfg(feature = "rand")] {
1221 /// # use secp256k1::{SecretKey, Keypair, PublicKey};
1222 /// # use secp256k1::musig::{AggregatedNonce, KeyAggCache, SessionSecretRand, Session};
1223 /// # let sk1 = SecretKey::new(&mut rand::rng());
1224 /// # let pub_key1 = PublicKey::from_secret_key(&sk1);
1225 /// # let sk2 = SecretKey::new(&mut rand::rng());
1226 /// # let pub_key2 = PublicKey::from_secret_key(&sk2);
1227 ///
1228 /// # let key_agg_cache = KeyAggCache::new(&[&pub_key1, &pub_key2]);
1229 /// // The session id must be sampled at random. Read documentation for more details.
1230 ///
1231 /// let msg = b"Public message we want to sign!!";
1232 ///
1233 /// // Provide the current time for mis-use resistance
1234 /// let session_secrand1 = SessionSecretRand::from_rng(&mut rand::rng());
1235 /// let (mut sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(session_secrand1, pub_key1, msg, None);
1236 ///
1237 /// // Signer two does the same. Possibly on a different device
1238 /// let session_secrand2 = SessionSecretRand::from_rng(&mut rand::rng());
1239 /// let (_sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(session_secrand2, pub_key2, msg, None);
1240 ///
1241 /// let aggnonce = AggregatedNonce::new(&[&pub_nonce1, &pub_nonce2]);
1242 ///
1243 /// let session = Session::new(
1244 /// &key_agg_cache,
1245 /// aggnonce,
1246 /// msg,
1247 /// );
1248 ///
1249 /// let keypair = Keypair::from_secret_key(&sk1);
1250 /// let partial_sig1 = session.partial_sign(
1251 /// sec_nonce1,
1252 /// &keypair,
1253 /// &key_agg_cache,
1254 /// );
1255 ///
1256 /// assert!(session.partial_verify(
1257 /// &key_agg_cache,
1258 /// &partial_sig1,
1259 /// &pub_nonce1,
1260 /// pub_key1,
1261 /// ));
1262 /// # }
1263 /// ```
1264 pub fn partial_verify(
1265 &self,
1266 key_agg_cache: &KeyAggCache,
1267 partial_sig: &PartialSignature,
1268 pub_nonce: &PublicNonce,
1269 pub_key: PublicKey,
1270 ) -> bool {
1271 unsafe {
1272 let ret = crate::with_global_context(
1273 |secp: &Secp256k1<crate::AllPreallocated>| {
1274 ffi::secp256k1_musig_partial_sig_verify(
1275 secp.ctx.as_ptr(),
1276 partial_sig.as_ptr(),
1277 pub_nonce.as_ptr(),
1278 pub_key.as_c_ptr(),
1279 key_agg_cache.as_ptr(),
1280 self.as_ptr(),
1281 )
1282 },
1283 None,
1284 );
1285 ret == 1
1286 }
1287 }
1288
1289 /// Aggregate partial signatures for this session into a single [`schnorr::Signature`]
1290 ///
1291 /// # Returns:
1292 ///
1293 /// A single [`schnorr::Signature`]. Note that this does *NOT* mean that the signature verifies with respect to the
1294 /// aggregate public key.
1295 ///
1296 /// # Arguments:
1297 ///
1298 /// * `partial_sigs`: Array of [`PartialSignature`] to be aggregated
1299 ///
1300 /// ```rust
1301 /// # #[cfg(feature = "rand-std")] {
1302 /// # use secp256k1::{KeyAggCache, SecretKey, Keypair, PublicKey, SessionSecretRand, AggregatedNonce, Session};
1303 /// # let sk1 = SecretKey::new(&mut rand::rng());
1304 /// # let pub_key1 = PublicKey::from_secret_key(&sk1);
1305 /// # let sk2 = SecretKey::new(&mut rand::rng());
1306 /// # let pub_key2 = PublicKey::from_secret_key(&sk2);
1307 ///
1308 /// let key_agg_cache = KeyAggCache::new(&[pub_key1, pub_key2]);
1309 /// // The session id must be sampled at random. Read documentation for more details.
1310 ///
1311 /// let msg = b"Public message we want to sign!!";
1312 ///
1313 /// // Provide the current time for mis-use resistance
1314 /// let session_secrand1 = SessionSecretRand::from_rng(&mut rand::rng());
1315 /// let (mut sec_nonce1, pub_nonce1) = key_agg_cache.nonce_gen(session_secrand1, pub_key1, msg, None)
1316 /// .expect("non zero session id");
1317 ///
1318 /// // Signer two does the same. Possibly on a different device
1319 /// let session_secrand2 = SessionSecretRand::from_rng(&mut rand::rng());
1320 /// let (mut sec_nonce2, pub_nonce2) = key_agg_cache.nonce_gen(session_secrand2, pub_key2, msg, None)
1321 /// .expect("non zero session id");
1322 ///
1323 /// let aggnonce = AggregatedNonce::new(&[pub_nonce1, pub_nonce2]);
1324 ///
1325 /// let session = Session::new(
1326 /// &key_agg_cache,
1327 /// aggnonce,
1328 /// msg,
1329 /// );
1330 ///
1331 /// let partial_sig1 = session.partial_sign(
1332 /// sec_nonce1,
1333 /// &Keypair::from_secret_key(&sk1),
1334 /// &key_agg_cache,
1335 /// ).unwrap();
1336 ///
1337 /// // Other party creates the other partial signature
1338 /// let partial_sig2 = session.partial_sign(
1339 /// sec_nonce2,
1340 /// &Keypair::from_secret_key(&sk2),
1341 /// &key_agg_cache,
1342 /// ).unwrap();
1343 ///
1344 /// let partial_sigs = [partial_sign1, partial_sign2];
1345 /// let partial_sigs_ref: Vec<&PartialSignature> = partial_sigs.iter().collect();
1346 /// let partial_sigs_ref = partial_sigs_ref.as_slice();
1347 ///
1348 /// let aggregated_signature = session.partial_sig_agg(partial_sigs_ref);
1349 ///
1350 /// // Get the final schnorr signature
1351 /// assert!(aggregated_signature.verify(&agg_pk, &msg_bytes).is_ok());
1352 /// # }
1353 /// ```
1354 ///
1355 /// # Panics
1356 ///
1357 /// Panics if an empty slice of partial signatures is provided.
1358 pub fn partial_sig_agg(&self, partial_sigs: &[&PartialSignature]) -> AggregatedSignature {
1359 if partial_sigs.is_empty() {
1360 panic!("Cannot aggregate an empty slice of partial signatures");
1361 }
1362
1363 let mut sig = [0u8; 64];
1364 unsafe {
1365 let partial_sigs_ref = core::slice::from_raw_parts(
1366 partial_sigs.as_ptr() as *const *const ffi::MusigPartialSignature,
1367 partial_sigs.len(),
1368 );
1369
1370 if ffi::secp256k1_musig_partial_sig_agg(
1371 ffi::secp256k1_context_no_precomp,
1372 sig.as_mut_ptr(),
1373 self.as_ptr(),
1374 partial_sigs_ref.as_ptr(),
1375 partial_sigs_ref.len(),
1376 ) == 0
1377 {
1378 // All arguments are well-typed partial signatures
1379 unreachable!("Impossible to construct invalid(not well-typed) partial signatures")
1380 } else {
1381 // Resulting signature must be well-typed. Does not mean that will be succeed verification
1382 AggregatedSignature(sig)
1383 }
1384 }
1385 }
1386
1387 /// Get a const pointer to the inner Session
1388 pub fn as_ptr(&self) -> *const ffi::MusigSession { &self.0 }
1389
1390 /// Get a mut pointer to the inner Session
1391 pub fn as_mut_ptr(&mut self) -> *mut ffi::MusigSession { &mut self.0 }
1392}
1393
1394#[cfg(test)]
1395mod tests {
1396 use super::*;
1397 #[cfg(feature = "std")]
1398 #[cfg(feature = "rand")]
1399 use crate::PublicKey;
1400
1401 #[test]
1402 #[cfg(feature = "std")]
1403 #[cfg(feature = "rand")]
1404 fn session_secret_rand() {
1405 let mut rng = rand::rng();
1406 let session_secrand = SessionSecretRand::from_rng(&mut rng);
1407 let session_secrand1 = SessionSecretRand::from_rng(&mut rng);
1408 assert_ne!(session_secrand.to_byte_array(), [0; 32]); // with overwhelming probability
1409 assert_ne!(session_secrand, session_secrand1); // with overwhelming probability
1410 }
1411
1412 #[test]
1413 fn session_secret_no_rand() {
1414 let custom_bytes = [42u8; 32];
1415 let session_secrand = SessionSecretRand::assume_unique_per_nonce_gen(custom_bytes);
1416 assert_eq!(session_secrand.to_byte_array(), custom_bytes);
1417 assert_eq!(session_secrand.as_byte_array(), &custom_bytes);
1418 }
1419
1420 #[test]
1421 #[should_panic(expected = "session secrets may not be all zero")]
1422 fn session_secret_rand_zero_panic() {
1423 let zero_bytes = [0u8; 32];
1424 let _session_secrand = SessionSecretRand::assume_unique_per_nonce_gen(zero_bytes);
1425 }
1426
1427 #[test]
1428 #[cfg(not(secp256k1_fuzz))]
1429 #[cfg(feature = "std")]
1430 fn key_agg_cache() {
1431 let (_seckey1, pubkey1) = crate::test_random_keypair();
1432 let (_seckey2, pubkey2) = crate::test_random_keypair();
1433
1434 let pubkeys = [&pubkey1, &pubkey2];
1435 let key_agg_cache = KeyAggCache::new(&pubkeys);
1436 let agg_pk = key_agg_cache.agg_pk();
1437
1438 // Test agg_pk_full
1439 let agg_pk_full = key_agg_cache.agg_pk_full();
1440 assert_eq!(agg_pk_full.x_only_public_key().0, agg_pk);
1441 }
1442
1443 #[test]
1444 #[cfg(not(secp256k1_fuzz))]
1445 #[cfg(feature = "std")]
1446 fn key_agg_cache_tweaking() {
1447 let (_seckey1, pubkey1) = crate::test_random_keypair();
1448 let (_seckey2, pubkey2) = crate::test_random_keypair();
1449
1450 let mut key_agg_cache = KeyAggCache::new(&[&pubkey1, &pubkey2]);
1451 let key_agg_cache1 = KeyAggCache::new(&[&pubkey2, &pubkey1]);
1452 let key_agg_cache2 = KeyAggCache::new(&[&pubkey1, &pubkey1]);
1453 let key_agg_cache3 = KeyAggCache::new(&[&pubkey1, &pubkey1, &pubkey2]);
1454 assert_ne!(key_agg_cache, key_agg_cache1); // swapped keys DOES mean not equal
1455 assert_ne!(key_agg_cache, key_agg_cache2); // missing keys
1456 assert_ne!(key_agg_cache, key_agg_cache3); // repeated key
1457 let original_agg_pk = key_agg_cache.agg_pk();
1458 assert_ne!(key_agg_cache.agg_pk(), key_agg_cache1.agg_pk()); // swapped keys DOES mean not equal
1459 assert_ne!(key_agg_cache.agg_pk(), key_agg_cache2.agg_pk()); // missing keys
1460 assert_ne!(key_agg_cache.agg_pk(), key_agg_cache3.agg_pk()); // repeated key
1461
1462 // Test EC tweaking
1463 let plain_tweak: [u8; 32] = *b"this could be a BIP32 tweak....\0";
1464 let plain_tweak = Scalar::from_be_bytes(plain_tweak).unwrap();
1465 let tweaked_key = key_agg_cache.pubkey_ec_tweak_add(&plain_tweak).unwrap();
1466 assert_ne!(key_agg_cache.agg_pk(), original_agg_pk);
1467 assert_eq!(key_agg_cache.agg_pk(), tweaked_key.x_only_public_key().0);
1468
1469 // Test xonly tweaking
1470 let xonly_tweak: [u8; 32] = *b"this could be a Taproot tweak..\0";
1471 let xonly_tweak = Scalar::from_be_bytes(xonly_tweak).unwrap();
1472 let tweaked_agg_pk = key_agg_cache.pubkey_xonly_tweak_add(&xonly_tweak).unwrap();
1473 assert_eq!(key_agg_cache.agg_pk(), tweaked_agg_pk.x_only_public_key().0);
1474 }
1475
1476 #[test]
1477 #[cfg(feature = "std")]
1478 #[should_panic(expected = "Cannot aggregate an empty slice of pubkeys")]
1479 fn key_agg_cache_empty_panic() { let _ = KeyAggCache::new(&[]); }
1480
1481 #[test]
1482 #[cfg(feature = "std")]
1483 #[cfg(feature = "rand")]
1484 fn nonce_generation() {
1485 let mut rng = rand::rng();
1486
1487 let (_seckey1, pubkey1) = crate::test_random_keypair();
1488 let (seckey2, pubkey2) = crate::test_random_keypair();
1489
1490 let key_agg_cache = KeyAggCache::new(&[&pubkey1, &pubkey2]);
1491
1492 let msg: &[u8; 32] = b"This message is exactly 32 bytes";
1493
1494 // Test nonce generation with KeyAggCache
1495 let session_secrand1 = SessionSecretRand::from_rng(&mut rng);
1496 let (_sec_nonce1, pub_nonce1) =
1497 key_agg_cache.nonce_gen(session_secrand1, pubkey1, msg, None);
1498
1499 // Test direct nonce generation
1500 let session_secrand2 = SessionSecretRand::from_rng(&mut rng);
1501 let extra_rand = Some([42u8; 32]);
1502 let (_sec_nonce2, _pub_nonce2) = new_nonce_pair(
1503 session_secrand2,
1504 Some(&key_agg_cache),
1505 Some(seckey2),
1506 pubkey2,
1507 Some(msg),
1508 extra_rand,
1509 );
1510
1511 // Test PublicNonce serialization/deserialization
1512 let serialized_nonce = pub_nonce1.serialize();
1513 let deserialized_nonce = PublicNonce::from_byte_array(&serialized_nonce).unwrap();
1514 assert_eq!(pub_nonce1.serialize(), deserialized_nonce.serialize());
1515 }
1516
1517 #[test]
1518 #[cfg(feature = "std")]
1519 #[cfg(feature = "rand")]
1520 fn aggregated_nonce() {
1521 let mut rng = rand::rng();
1522
1523 let (_seckey1, pubkey1) = crate::test_random_keypair();
1524 let (_seckey2, pubkey2) = crate::test_random_keypair();
1525
1526 let key_agg_cache = KeyAggCache::new(&[&pubkey1, &pubkey2]);
1527
1528 let msg: &[u8; 32] = b"This message is exactly 32 bytes";
1529
1530 let session_secrand1 = SessionSecretRand::from_rng(&mut rng);
1531 let (_, pub_nonce1) = key_agg_cache.nonce_gen(session_secrand1, pubkey1, msg, None);
1532
1533 let session_secrand2 = SessionSecretRand::from_rng(&mut rng);
1534 let (_, pub_nonce2) = key_agg_cache.nonce_gen(session_secrand2, pubkey2, msg, None);
1535
1536 // Test AggregatedNonce creation
1537 let agg_nonce = AggregatedNonce::new(&[&pub_nonce1, &pub_nonce2]);
1538 let agg_nonce1 = AggregatedNonce::new(&[&pub_nonce2, &pub_nonce1]);
1539 let agg_nonce2 = AggregatedNonce::new(&[&pub_nonce2, &pub_nonce2]);
1540 let agg_nonce3 = AggregatedNonce::new(&[&pub_nonce2, &pub_nonce2]);
1541 assert_eq!(agg_nonce, agg_nonce1); // swapped nonces
1542 assert_ne!(agg_nonce, agg_nonce2); // repeated/different nonces
1543 assert_ne!(agg_nonce, agg_nonce3); // repeated nonce but still both nonces present
1544
1545 // Test AggregatedNonce serialization/deserialization
1546 let serialized_agg_nonce = agg_nonce.serialize();
1547 let deserialized_agg_nonce =
1548 AggregatedNonce::from_byte_array(&serialized_agg_nonce).unwrap();
1549 assert_eq!(agg_nonce.serialize(), deserialized_agg_nonce.serialize());
1550 }
1551
1552 #[test]
1553 #[cfg(feature = "std")]
1554 #[should_panic(expected = "Cannot aggregate an empty slice of nonces")]
1555 fn aggregated_nonce_empty_panic() {
1556 let empty_nonces: Vec<&PublicNonce> = vec![];
1557 let _agg_nonce = AggregatedNonce::new(&empty_nonces);
1558 }
1559
1560 #[test]
1561 #[cfg(not(secp256k1_fuzz))]
1562 #[cfg(feature = "std")]
1563 #[cfg(feature = "rand")]
1564 fn session_and_partial_signing() {
1565 let mut rng = rand::rng();
1566
1567 let (seckey1, pubkey1) = crate::test_random_keypair();
1568 let (seckey2, pubkey2) = crate::test_random_keypair();
1569
1570 let pubkeys = [&pubkey1, &pubkey2];
1571 let key_agg_cache = KeyAggCache::new(&pubkeys);
1572
1573 let msg: &[u8; 32] = b"This message is exactly 32 bytes";
1574
1575 let session_secrand1 = SessionSecretRand::from_rng(&mut rng);
1576 let (sec_nonce1, pub_nonce1) =
1577 key_agg_cache.nonce_gen(session_secrand1, pubkey1, msg, None);
1578
1579 let session_secrand2 = SessionSecretRand::from_rng(&mut rng);
1580 let (sec_nonce2, pub_nonce2) =
1581 key_agg_cache.nonce_gen(session_secrand2, pubkey2, msg, None);
1582
1583 let nonces = [&pub_nonce1, &pub_nonce2];
1584 let agg_nonce = AggregatedNonce::new(&nonces);
1585
1586 // Test Session creation
1587 let session = Session::new(&key_agg_cache, agg_nonce, msg);
1588
1589 // Test partial signing
1590 let keypair1 = Keypair::from_secret_key(&seckey1);
1591 let partial_sign1 = session.partial_sign(sec_nonce1, &keypair1, &key_agg_cache);
1592
1593 let keypair2 = Keypair::from_secret_key(&seckey2);
1594 let partial_sign2 = session.partial_sign(sec_nonce2, &keypair2, &key_agg_cache);
1595
1596 // Test partial signature verification
1597 assert!(session.partial_verify(&key_agg_cache, &partial_sign1, &pub_nonce1, pubkey1));
1598 assert!(session.partial_verify(&key_agg_cache, &partial_sign2, &pub_nonce2, pubkey2));
1599 // Test that they are invalid if you switch keys
1600 assert!(!session.partial_verify(&key_agg_cache, &partial_sign2, &pub_nonce2, pubkey1));
1601 assert!(!session.partial_verify(&key_agg_cache, &partial_sign2, &pub_nonce1, pubkey2));
1602 assert!(!session.partial_verify(&key_agg_cache, &partial_sign2, &pub_nonce1, pubkey1));
1603
1604 // Test PartialSignature serialization/deserialization
1605 let serialized_partial_sig = partial_sign1.serialize();
1606 let deserialized_partial_sig =
1607 PartialSignature::from_byte_array(&serialized_partial_sig).unwrap();
1608 assert_eq!(partial_sign1.serialize(), deserialized_partial_sig.serialize());
1609 }
1610
1611 #[test]
1612 #[cfg(not(secp256k1_fuzz))]
1613 #[cfg(feature = "std")]
1614 #[cfg(feature = "rand")]
1615 fn signature_aggregation_and_verification() {
1616 let mut rng = rand::rng();
1617
1618 let (seckey1, pubkey1) = crate::test_random_keypair();
1619 let (seckey2, pubkey2) = crate::test_random_keypair();
1620
1621 let pubkeys = [&pubkey1, &pubkey2];
1622 let key_agg_cache = KeyAggCache::new(&pubkeys);
1623
1624 let msg: &[u8; 32] = b"This message is exactly 32 bytes";
1625
1626 let session_secrand1 = SessionSecretRand::from_rng(&mut rng);
1627 let (sec_nonce1, pub_nonce1) =
1628 key_agg_cache.nonce_gen(session_secrand1, pubkey1, msg, None);
1629
1630 let session_secrand2 = SessionSecretRand::from_rng(&mut rng);
1631 let (sec_nonce2, pub_nonce2) =
1632 key_agg_cache.nonce_gen(session_secrand2, pubkey2, msg, None);
1633
1634 let nonces = [&pub_nonce1, &pub_nonce2];
1635 let agg_nonce = AggregatedNonce::new(&nonces);
1636 let session = Session::new(&key_agg_cache, agg_nonce, msg);
1637
1638 let keypair1 = Keypair::from_secret_key(&seckey1);
1639 let partial_sign1 = session.partial_sign(sec_nonce1, &keypair1, &key_agg_cache);
1640
1641 let keypair2 = Keypair::from_secret_key(&seckey2);
1642 let partial_sign2 = session.partial_sign(sec_nonce2, &keypair2, &key_agg_cache);
1643
1644 // Test signature verification
1645 let aggregated_signature = session.partial_sig_agg(&[&partial_sign1, &partial_sign2]);
1646 let agg_pk = key_agg_cache.agg_pk();
1647 aggregated_signature.verify(&agg_pk, msg).unwrap();
1648
1649 // Test assume_valid
1650 let schnorr_sig = aggregated_signature.assume_valid();
1651 schnorr::verify(&schnorr_sig, msg, &agg_pk).unwrap();
1652
1653 // Test with wrong aggregate (repeated sigs)
1654 let aggregated_signature = session.partial_sig_agg(&[&partial_sign1, &partial_sign1]);
1655 aggregated_signature.verify(&agg_pk, msg).unwrap_err();
1656 let schnorr_sig = aggregated_signature.assume_valid();
1657 schnorr::verify(&schnorr_sig, msg, &agg_pk).unwrap_err();
1658
1659 // Test with swapped sigs -- this will work. Unlike keys, sigs are not ordered.
1660 let aggregated_signature = session.partial_sig_agg(&[&partial_sign2, &partial_sign1]);
1661 aggregated_signature.verify(&agg_pk, msg).unwrap();
1662 let schnorr_sig = aggregated_signature.assume_valid();
1663 schnorr::verify(&schnorr_sig, msg, &agg_pk).unwrap();
1664 }
1665
1666 #[test]
1667 #[cfg(feature = "std")]
1668 #[cfg(feature = "rand")]
1669 #[should_panic(expected = "Cannot aggregate an empty slice of partial signatures")]
1670 fn partial_sig_agg_empty_panic() {
1671 let mut rng = rand::rng();
1672
1673 let (_seckey1, pubkey1) = crate::test_random_keypair();
1674 let (_seckey2, pubkey2) = crate::test_random_keypair();
1675
1676 let pubkeys = [pubkey1, pubkey2];
1677 let mut pubkeys_ref: Vec<&PublicKey> = pubkeys.iter().collect();
1678 let pubkeys_ref = pubkeys_ref.as_mut_slice();
1679
1680 let key_agg_cache = KeyAggCache::new(pubkeys_ref);
1681 let msg: &[u8; 32] = b"This message is exactly 32 bytes";
1682
1683 let session_secrand1 = SessionSecretRand::from_rng(&mut rng);
1684 let (_, pub_nonce1) = key_agg_cache.nonce_gen(session_secrand1, pubkey1, msg, None);
1685 let session_secrand2 = SessionSecretRand::from_rng(&mut rng);
1686 let (_, pub_nonce2) = key_agg_cache.nonce_gen(session_secrand2, pubkey2, msg, None);
1687
1688 let nonces = [pub_nonce1, pub_nonce2];
1689 let nonces_ref: Vec<&PublicNonce> = nonces.iter().collect();
1690 let agg_nonce = AggregatedNonce::new(&nonces_ref);
1691 let session = Session::new(&key_agg_cache, agg_nonce, msg);
1692
1693 let _agg_sig = session.partial_sig_agg(&[]);
1694 }
1695
1696 #[test]
1697 fn de_serialization() {
1698 const MUSIG_PUBLIC_NONCE_HEX: &str = "03f4a361abd3d50535be08421dbc73b0a8f595654ae3238afcaf2599f94e25204c036ba174214433e21f5cd0fcb14b038eb40b05b7e7c820dd21aa568fdb0a9de4d7";
1699 let pubnonce: PublicNonce = MUSIG_PUBLIC_NONCE_HEX.parse().unwrap();
1700
1701 assert_eq!(pubnonce.to_string(), MUSIG_PUBLIC_NONCE_HEX);
1702
1703 const MUSIG_AGGREGATED_NONCE_HEX: &str = "0218c30fe0f567a4a9c05eb4835e2735419cf30f834c9ce2fe3430f021ba4eacd503112e97bcf6a022d236d71a9357824a2b19515f980131b3970b087cadf94cc4a7";
1704 let aggregated_nonce: AggregatedNonce = MUSIG_AGGREGATED_NONCE_HEX.parse().unwrap();
1705 assert_eq!(aggregated_nonce.to_string(), MUSIG_AGGREGATED_NONCE_HEX);
1706
1707 const MUSIG_PARTIAL_SIGNATURE_HEX: &str =
1708 "289eeb2f5efc314aa6d87bf58125043c96d15a007db4b6aaaac7d18086f49a99";
1709 let partial_signature: PartialSignature = MUSIG_PARTIAL_SIGNATURE_HEX.parse().unwrap();
1710 assert_eq!(partial_signature.to_string(), MUSIG_PARTIAL_SIGNATURE_HEX);
1711 }
1712}