From c6013c54aafbf51e1a3468bd232357e9811d0532 Mon Sep 17 00:00:00 2001 From: jlest01 <174762002+jlest01@users.noreply.github.com> Date: Mon, 11 Nov 2024 23:14:34 -0300 Subject: [PATCH] Add Musig2 example file --- Cargo.toml | 4 ++ examples/musig.rs | 103 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 examples/musig.rs diff --git a/Cargo.toml b/Cargo.toml index 639da069c..c2a5e58ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,6 +66,10 @@ required-features = ["hashes", "std"] name = "generate_keys" required-features = ["rand", "std"] +[[example]] +name = "musig" +required-features = ["rand", "std"] + [workspace] members = ["secp256k1-sys"] exclude = ["no_std_test"] diff --git a/examples/musig.rs b/examples/musig.rs new file mode 100644 index 000000000..c6c8c970a --- /dev/null +++ b/examples/musig.rs @@ -0,0 +1,103 @@ +extern crate secp256k1; + +use secp256k1::musig::{ + new_musig_nonce_pair, MusigAggNonce, MusigKeyAggCache, MusigPartialSignature, MusigPubNonce, + MusigSession, MusigSessionId, +}; +use secp256k1::{Keypair, Message, PublicKey, Scalar, Secp256k1, SecretKey}; + +fn main() { + let secp = Secp256k1::new(); + let mut rng = rand::thread_rng(); + + let (seckey1, pubkey1) = secp.generate_keypair(&mut rng); + + let seckey2 = SecretKey::new(&mut rng); + let pubkey2 = PublicKey::from_secret_key(&secp, &seckey2); + + let pubkeys = [pubkey1, pubkey2]; + let pubkeys_ref: Vec<&PublicKey> = pubkeys.iter().collect(); + let pubkeys_ref = pubkeys_ref.as_slice(); + + let mut musig_key_agg_cache = MusigKeyAggCache::new(&secp, pubkeys_ref); + + let plain_tweak: [u8; 32] = *b"this could be a BIP32 tweak....\0"; + let xonly_tweak: [u8; 32] = *b"this could be a Taproot tweak..\0"; + + let plain_tweak = Scalar::from_be_bytes(plain_tweak).unwrap(); + musig_key_agg_cache.pubkey_ec_tweak_add(&secp, &plain_tweak).unwrap(); + + let xonly_tweak = Scalar::from_be_bytes(xonly_tweak).unwrap(); + let tweaked_agg_pk = musig_key_agg_cache.pubkey_xonly_tweak_add(&secp, &xonly_tweak).unwrap(); + + let agg_pk = musig_key_agg_cache.agg_pk(); + + assert_eq!(agg_pk, tweaked_agg_pk.x_only_public_key().0); + + let msg_bytes: [u8; 32] = *b"this_could_be_the_hash_of_a_msg!"; + let msg = Message::from_digest_slice(&msg_bytes).unwrap(); + + let musig_session_id1 = MusigSessionId::new(&mut rng); + + let nonce_pair1 = new_musig_nonce_pair( + &secp, + musig_session_id1, + Some(&musig_key_agg_cache), + Some(seckey1), + pubkey1, + Some(msg), + None, + ) + .unwrap(); + + let musig_session_id2 = MusigSessionId::new(&mut rng); + + let nonce_pair2 = new_musig_nonce_pair( + &secp, + musig_session_id2, + Some(&musig_key_agg_cache), + Some(seckey2), + pubkey2, + Some(msg), + None, + ) + .unwrap(); + + let sec_nonce1 = nonce_pair1.0; + let pub_nonce1 = nonce_pair1.1; + + let sec_nonce2 = nonce_pair2.0; + let pub_nonce2 = nonce_pair2.1; + + let nonces = [pub_nonce1, pub_nonce2]; + let nonces_ref: Vec<&MusigPubNonce> = nonces.iter().collect(); + let nonces_ref = nonces_ref.as_slice(); + + let agg_nonce = MusigAggNonce::new(&secp, nonces_ref); + + let session = MusigSession::new(&secp, &musig_key_agg_cache, agg_nonce, msg); + + let keypair1 = Keypair::from_secret_key(&secp, &seckey1); + let partial_sign1 = + session.partial_sign(&secp, sec_nonce1, &keypair1, &musig_key_agg_cache).unwrap(); + + let keypair2 = Keypair::from_secret_key(&secp, &seckey2); + let partial_sign2 = + session.partial_sign(&secp, sec_nonce2, &keypair2, &musig_key_agg_cache).unwrap(); + + let is_partial_signature_valid = + session.partial_verify(&secp, &musig_key_agg_cache, partial_sign1, pub_nonce1, pubkey1); + assert!(is_partial_signature_valid); + + let is_partial_signature_valid = + session.partial_verify(&secp, &musig_key_agg_cache, partial_sign2, pub_nonce2, pubkey2); + assert!(is_partial_signature_valid); + + let partial_sigs = [partial_sign1, partial_sign2]; + let partial_sigs_ref: Vec<&MusigPartialSignature> = partial_sigs.iter().collect(); + let partial_sigs_ref = partial_sigs_ref.as_slice(); + + let sig64 = session.partial_sig_agg(partial_sigs_ref); + + assert!(secp.verify_schnorr(&sig64, &msg_bytes, &agg_pk).is_ok()); +}