1use crate::ct::ct_eq_32;
62use blake3::Hasher;
63use curve25519_dalek::constants::RISTRETTO_BASEPOINT_POINT;
64use curve25519_dalek::ristretto::RistrettoPoint;
65use curve25519_dalek::scalar::Scalar;
66use rand::RngCore;
67use serde::{Deserialize, Serialize};
68use thiserror::Error;
69
70#[derive(Debug, Error)]
71pub enum MuSig2Error {
72 #[error("Invalid public key")]
73 InvalidPublicKey,
74 #[error("Invalid nonce commitment")]
75 InvalidNonceCommitment,
76 #[error("Empty signer list")]
77 EmptySigners,
78 #[error("Mismatched lengths")]
79 MismatchedLengths,
80 #[error("Invalid signature")]
81 InvalidSignature,
82 #[error("Serialization error: {0}")]
83 Serialization(String),
84}
85
86pub type MuSig2Result<T> = Result<T, MuSig2Error>;
87
88fn random_scalar() -> Scalar {
90 let mut bytes = [0u8; 32];
91 rand::thread_rng().fill_bytes(&mut bytes);
92 Scalar::from_bytes_mod_order(bytes)
93}
94
95#[derive(Clone, Serialize, Deserialize)]
97pub struct MuSig2SecretKey(Scalar);
98
99#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
101pub struct MuSig2PublicKey(RistrettoPoint);
102
103#[derive(Clone)]
105pub struct MuSig2Signer {
106 secret_key: MuSig2SecretKey,
107 public_key: MuSig2PublicKey,
108}
109
110#[derive(Clone)]
112pub struct SigningNonce {
113 secret: Scalar,
114 public: MuSig2Nonce,
115}
116
117#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
119pub struct MuSig2Nonce(RistrettoPoint);
120
121#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
123pub struct NonceCommitment([u8; 32]);
124
125#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
127pub struct PartialSignature(Scalar);
128
129#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
131pub struct MuSig2Signature {
132 r: RistrettoPoint,
133 s: Scalar,
134}
135
136impl MuSig2Signer {
137 pub fn new() -> Self {
139 let secret = random_scalar();
140 let public = RISTRETTO_BASEPOINT_POINT * secret;
141
142 Self {
143 secret_key: MuSig2SecretKey(secret),
144 public_key: MuSig2PublicKey(public),
145 }
146 }
147
148 pub fn from_bytes(bytes: &[u8; 32]) -> MuSig2Result<Self> {
150 let secret = Scalar::from_bytes_mod_order(*bytes);
151 let public = RISTRETTO_BASEPOINT_POINT * secret;
152
153 Ok(Self {
154 secret_key: MuSig2SecretKey(secret),
155 public_key: MuSig2PublicKey(public),
156 })
157 }
158
159 pub fn public_key(&self) -> MuSig2PublicKey {
161 self.public_key
162 }
163
164 pub fn to_bytes(&self) -> [u8; 32] {
166 self.secret_key.0.to_bytes()
167 }
168
169 pub fn nonce_commitment(&self) -> (SigningNonce, NonceCommitment) {
171 let secret = random_scalar();
172 let public = RISTRETTO_BASEPOINT_POINT * secret;
173 let nonce = MuSig2Nonce(public);
174
175 let commitment = NonceCommitment(blake3::hash(&public.compress().to_bytes()).into());
177
178 (
179 SigningNonce {
180 secret,
181 public: nonce,
182 },
183 commitment,
184 )
185 }
186
187 pub fn partial_sign(
189 &self,
190 message: &[u8],
191 nonce: &SigningNonce,
192 public_keys: &[MuSig2PublicKey],
193 aggregated_nonce: &MuSig2Nonce,
194 ) -> MuSig2Result<PartialSignature> {
195 if public_keys.is_empty() {
196 return Err(MuSig2Error::EmptySigners);
197 }
198
199 let coeff = key_aggregation_coefficient(&self.public_key, public_keys);
201
202 let challenge = compute_challenge(
204 aggregated_nonce,
205 &aggregate_public_keys(public_keys)?,
206 message,
207 );
208
209 let s = nonce.secret + challenge * coeff * self.secret_key.0;
211
212 Ok(PartialSignature(s))
213 }
214}
215
216impl Default for MuSig2Signer {
217 fn default() -> Self {
218 Self::new()
219 }
220}
221
222impl SigningNonce {
223 pub fn public_nonce(&self) -> MuSig2Nonce {
225 self.public
226 }
227
228 pub fn verify_commitment(&self, commitment: &NonceCommitment) -> bool {
230 let computed = NonceCommitment(blake3::hash(&self.public.0.compress().to_bytes()).into());
231 ct_eq_32(&computed.0, &commitment.0)
232 }
233}
234
235impl MuSig2PublicKey {
236 pub fn from_bytes(bytes: &[u8; 32]) -> MuSig2Result<Self> {
238 let point = curve25519_dalek::ristretto::CompressedRistretto(*bytes)
239 .decompress()
240 .ok_or(MuSig2Error::InvalidPublicKey)?;
241 Ok(Self(point))
242 }
243
244 pub fn to_bytes(&self) -> [u8; 32] {
246 self.0.compress().to_bytes()
247 }
248}
249
250fn key_aggregation_coefficient(
252 pubkey: &MuSig2PublicKey,
253 all_pubkeys: &[MuSig2PublicKey],
254) -> Scalar {
255 let mut hasher = Hasher::new();
256
257 for pk in all_pubkeys {
259 hasher.update(&pk.0.compress().to_bytes());
260 }
261 hasher.update(&pubkey.0.compress().to_bytes());
262
263 let hash = hasher.finalize();
264 Scalar::from_bytes_mod_order(*hash.as_bytes())
265}
266
267pub fn aggregate_public_keys(public_keys: &[MuSig2PublicKey]) -> MuSig2Result<MuSig2PublicKey> {
269 if public_keys.is_empty() {
270 return Err(MuSig2Error::EmptySigners);
271 }
272
273 let mut aggregated = RistrettoPoint::default();
274
275 for pk in public_keys {
276 let coeff = key_aggregation_coefficient(pk, public_keys);
277 aggregated += coeff * pk.0;
278 }
279
280 Ok(MuSig2PublicKey(aggregated))
281}
282
283pub fn aggregate_nonces(
285 nonces: &[MuSig2Nonce],
286 commitments: &[NonceCommitment],
287) -> MuSig2Result<MuSig2Nonce> {
288 if nonces.is_empty() {
289 return Err(MuSig2Error::EmptySigners);
290 }
291
292 if nonces.len() != commitments.len() {
293 return Err(MuSig2Error::MismatchedLengths);
294 }
295
296 for (nonce, commitment) in nonces.iter().zip(commitments.iter()) {
298 let computed = NonceCommitment(blake3::hash(&nonce.0.compress().to_bytes()).into());
299 if !ct_eq_32(&computed.0, &commitment.0) {
300 return Err(MuSig2Error::InvalidNonceCommitment);
301 }
302 }
303
304 let mut aggregated = RistrettoPoint::default();
306 for nonce in nonces {
307 aggregated += nonce.0;
308 }
309
310 Ok(MuSig2Nonce(aggregated))
311}
312
313pub fn aggregate_partial_signatures(
315 partials: &[PartialSignature],
316) -> MuSig2Result<MuSig2Signature> {
317 if partials.is_empty() {
318 return Err(MuSig2Error::EmptySigners);
319 }
320
321 let mut s = Scalar::ZERO;
322 for partial in partials {
323 s += partial.0;
324 }
325
326 Ok(MuSig2Signature {
330 r: RistrettoPoint::default(),
331 s,
332 })
333}
334
335pub fn aggregate_partial_signatures_with_nonce(
337 partials: &[PartialSignature],
338 aggregated_nonce: &MuSig2Nonce,
339) -> MuSig2Result<MuSig2Signature> {
340 if partials.is_empty() {
341 return Err(MuSig2Error::EmptySigners);
342 }
343
344 let mut s = Scalar::ZERO;
345 for partial in partials {
346 s += partial.0;
347 }
348
349 Ok(MuSig2Signature {
350 r: aggregated_nonce.0,
351 s,
352 })
353}
354
355fn compute_challenge(nonce: &MuSig2Nonce, pubkey: &MuSig2PublicKey, message: &[u8]) -> Scalar {
357 let mut hasher = Hasher::new();
358 hasher.update(&nonce.0.compress().to_bytes());
359 hasher.update(&pubkey.0.compress().to_bytes());
360 hasher.update(message);
361
362 let hash = hasher.finalize();
363 Scalar::from_bytes_mod_order(*hash.as_bytes())
364}
365
366pub fn verify_musig2(
368 pubkey: &MuSig2PublicKey,
369 message: &[u8],
370 signature: &MuSig2Signature,
371) -> bool {
372 let challenge = compute_challenge(&MuSig2Nonce(signature.r), pubkey, message);
374
375 let lhs = RISTRETTO_BASEPOINT_POINT * signature.s;
377 let rhs = signature.r + challenge * pubkey.0;
378
379 lhs == rhs
380}
381
382impl MuSig2Signature {
383 pub fn to_bytes(&self) -> [u8; 64] {
385 let mut bytes = [0u8; 64];
386 bytes[..32].copy_from_slice(&self.r.compress().to_bytes());
387 bytes[32..].copy_from_slice(&self.s.to_bytes());
388 bytes
389 }
390
391 pub fn from_bytes(bytes: &[u8; 64]) -> MuSig2Result<Self> {
393 let r = curve25519_dalek::ristretto::CompressedRistretto(bytes[..32].try_into().unwrap())
394 .decompress()
395 .ok_or(MuSig2Error::InvalidSignature)?;
396 let s = Scalar::from_bytes_mod_order(bytes[32..].try_into().unwrap());
397
398 Ok(Self { r, s })
399 }
400}
401
402#[cfg(test)]
403mod tests {
404 use super::*;
405
406 #[test]
407 fn test_musig2_single_signer() {
408 let signer = MuSig2Signer::new();
409 let pubkeys = vec![signer.public_key()];
410 let agg_key = aggregate_public_keys(&pubkeys).unwrap();
411
412 let message = b"Single signer test";
413
414 let (nonce, commitment) = signer.nonce_commitment();
415 let commitments = vec![commitment];
416 let nonces = vec![nonce.public_nonce()];
417 let agg_nonce = aggregate_nonces(&nonces, &commitments).unwrap();
418
419 let partial = signer
420 .partial_sign(message, &nonce, &pubkeys, &agg_nonce)
421 .unwrap();
422 let signature = aggregate_partial_signatures_with_nonce(&[partial], &agg_nonce).unwrap();
423
424 assert!(verify_musig2(&agg_key, message, &signature));
425 }
426
427 #[test]
428 fn test_musig2_three_signers() {
429 let signer1 = MuSig2Signer::new();
430 let signer2 = MuSig2Signer::new();
431 let signer3 = MuSig2Signer::new();
432
433 let pubkeys = vec![
434 signer1.public_key(),
435 signer2.public_key(),
436 signer3.public_key(),
437 ];
438 let agg_key = aggregate_public_keys(&pubkeys).unwrap();
439
440 let message = b"Three signer test";
441
442 let (nonce1, commit1) = signer1.nonce_commitment();
443 let (nonce2, commit2) = signer2.nonce_commitment();
444 let (nonce3, commit3) = signer3.nonce_commitment();
445
446 let commitments = vec![commit1, commit2, commit3];
447 let nonces = vec![
448 nonce1.public_nonce(),
449 nonce2.public_nonce(),
450 nonce3.public_nonce(),
451 ];
452
453 let agg_nonce = aggregate_nonces(&nonces, &commitments).unwrap();
454
455 let partial1 = signer1
456 .partial_sign(message, &nonce1, &pubkeys, &agg_nonce)
457 .unwrap();
458 let partial2 = signer2
459 .partial_sign(message, &nonce2, &pubkeys, &agg_nonce)
460 .unwrap();
461 let partial3 = signer3
462 .partial_sign(message, &nonce3, &pubkeys, &agg_nonce)
463 .unwrap();
464
465 let signature =
466 aggregate_partial_signatures_with_nonce(&[partial1, partial2, partial3], &agg_nonce)
467 .unwrap();
468
469 assert!(verify_musig2(&agg_key, message, &signature));
470 }
471
472 #[test]
473 fn test_musig2_wrong_message() {
474 let signer1 = MuSig2Signer::new();
475 let signer2 = MuSig2Signer::new();
476
477 let pubkeys = vec![signer1.public_key(), signer2.public_key()];
478 let agg_key = aggregate_public_keys(&pubkeys).unwrap();
479
480 let message = b"Original message";
481
482 let (nonce1, commit1) = signer1.nonce_commitment();
483 let (nonce2, commit2) = signer2.nonce_commitment();
484
485 let commitments = vec![commit1, commit2];
486 let nonces = vec![nonce1.public_nonce(), nonce2.public_nonce()];
487 let agg_nonce = aggregate_nonces(&nonces, &commitments).unwrap();
488
489 let partial1 = signer1
490 .partial_sign(message, &nonce1, &pubkeys, &agg_nonce)
491 .unwrap();
492 let partial2 = signer2
493 .partial_sign(message, &nonce2, &pubkeys, &agg_nonce)
494 .unwrap();
495
496 let signature =
497 aggregate_partial_signatures_with_nonce(&[partial1, partial2], &agg_nonce).unwrap();
498
499 assert!(!verify_musig2(&agg_key, b"Different message", &signature));
500 }
501
502 #[test]
503 fn test_nonce_commitment_verification() {
504 let signer = MuSig2Signer::new();
505 let (nonce, commitment) = signer.nonce_commitment();
506
507 assert!(nonce.verify_commitment(&commitment));
508 }
509
510 #[test]
511 fn test_invalid_nonce_commitment() {
512 let signer = MuSig2Signer::new();
513 let (nonce1, _) = signer.nonce_commitment();
514 let (_, commitment2) = signer.nonce_commitment();
515
516 assert!(!nonce1.verify_commitment(&commitment2));
517 }
518
519 #[test]
520 fn test_aggregate_nonces_mismatch() {
521 let signer1 = MuSig2Signer::new();
522 let signer2 = MuSig2Signer::new();
523
524 let (nonce1, _) = signer1.nonce_commitment();
525 let (_, commit2) = signer2.nonce_commitment();
526
527 let result = aggregate_nonces(&[nonce1.public_nonce()], &[commit2]);
528 assert!(result.is_err());
529 }
530
531 #[test]
532 fn test_empty_signers() {
533 let result = aggregate_public_keys(&[]);
534 assert!(result.is_err());
535
536 let result = aggregate_nonces(&[], &[]);
537 assert!(result.is_err());
538
539 let result = aggregate_partial_signatures(&[]);
540 assert!(result.is_err());
541 }
542
543 #[test]
544 fn test_signature_serialization() {
545 let signer = MuSig2Signer::new();
546 let pubkeys = vec![signer.public_key()];
547 let agg_key = aggregate_public_keys(&pubkeys).unwrap();
548
549 let message = b"Serialization test";
550
551 let (nonce, commitment) = signer.nonce_commitment();
552 let commitments = vec![commitment];
553 let nonces = vec![nonce.public_nonce()];
554 let agg_nonce = aggregate_nonces(&nonces, &commitments).unwrap();
555
556 let partial = signer
557 .partial_sign(message, &nonce, &pubkeys, &agg_nonce)
558 .unwrap();
559 let signature = aggregate_partial_signatures_with_nonce(&[partial], &agg_nonce).unwrap();
560
561 let bytes = signature.to_bytes();
562 let recovered = MuSig2Signature::from_bytes(&bytes).unwrap();
563
564 assert!(verify_musig2(&agg_key, message, &recovered));
565 }
566
567 #[test]
568 fn test_signer_serialization() {
569 let signer = MuSig2Signer::new();
570 let bytes = signer.to_bytes();
571 let recovered = MuSig2Signer::from_bytes(&bytes).unwrap();
572
573 assert_eq!(
574 signer.public_key().to_bytes(),
575 recovered.public_key().to_bytes()
576 );
577 }
578
579 #[test]
580 fn test_deterministic_key_aggregation() {
581 let signer1 = MuSig2Signer::new();
582 let signer2 = MuSig2Signer::new();
583
584 let pubkeys = vec![signer1.public_key(), signer2.public_key()];
585 let agg1 = aggregate_public_keys(&pubkeys).unwrap();
586 let agg2 = aggregate_public_keys(&pubkeys).unwrap();
587
588 assert_eq!(agg1.to_bytes(), agg2.to_bytes());
589 }
590
591 #[test]
592 fn test_musig2_ten_signers() {
593 let signers: Vec<MuSig2Signer> = (0..10).map(|_| MuSig2Signer::new()).collect();
594 let pubkeys: Vec<MuSig2PublicKey> = signers.iter().map(|s| s.public_key()).collect();
595 let agg_key = aggregate_public_keys(&pubkeys).unwrap();
596
597 let message = b"Ten signer test";
598
599 let nonces_and_commits: Vec<(SigningNonce, NonceCommitment)> =
600 signers.iter().map(|s| s.nonce_commitment()).collect();
601
602 let nonces: Vec<MuSig2Nonce> = nonces_and_commits
603 .iter()
604 .map(|(n, _)| n.public_nonce())
605 .collect();
606 let commitments: Vec<NonceCommitment> =
607 nonces_and_commits.iter().map(|(_, c)| *c).collect();
608
609 let agg_nonce = aggregate_nonces(&nonces, &commitments).unwrap();
610
611 let partials: Vec<PartialSignature> = signers
612 .iter()
613 .zip(nonces_and_commits.iter())
614 .map(|(signer, (nonce, _))| {
615 signer
616 .partial_sign(message, nonce, &pubkeys, &agg_nonce)
617 .unwrap()
618 })
619 .collect();
620
621 let signature = aggregate_partial_signatures_with_nonce(&partials, &agg_nonce).unwrap();
622
623 assert!(verify_musig2(&agg_key, message, &signature));
624 }
625
626 #[test]
627 fn test_partial_signature_subset_fails() {
628 let signer1 = MuSig2Signer::new();
629 let signer2 = MuSig2Signer::new();
630 let signer3 = MuSig2Signer::new();
631
632 let (nonce1, commit1) = signer1.nonce_commitment();
633 let (nonce2, commit2) = signer2.nonce_commitment();
634 let (_, commit3) = signer3.nonce_commitment();
635
636 let commitments = vec![commit1, commit2, commit3];
637 let nonces = vec![nonce1.public_nonce(), nonce2.public_nonce()];
638
639 let result = aggregate_nonces(&nonces, &commitments);
641 assert!(result.is_err());
642 }
643}