|  | 
|  | 1 | +extern crate secp256k1; | 
|  | 2 | + | 
|  | 3 | +use secp256k1::musig::{ | 
|  | 4 | +    new_musig_nonce_pair, MusigAggNonce, MusigKeyAggCache, MusigPartialSignature, MusigPubNonce, | 
|  | 5 | +    MusigSession, MusigSecRand, | 
|  | 6 | +}; | 
|  | 7 | +use secp256k1::{Keypair, Message, PublicKey, Scalar, Secp256k1, SecretKey}; | 
|  | 8 | + | 
|  | 9 | +fn main() { | 
|  | 10 | +    let secp = Secp256k1::new(); | 
|  | 11 | +    let mut rng = rand::thread_rng(); | 
|  | 12 | + | 
|  | 13 | +    let (seckey1, pubkey1) = secp.generate_keypair(&mut rng); | 
|  | 14 | + | 
|  | 15 | +    let seckey2 = SecretKey::new(&mut rng); | 
|  | 16 | +    let pubkey2 = PublicKey::from_secret_key(&secp, &seckey2); | 
|  | 17 | + | 
|  | 18 | +    let pubkeys = [pubkey1, pubkey2]; | 
|  | 19 | +    let pubkeys_ref: Vec<&PublicKey> = pubkeys.iter().collect(); | 
|  | 20 | +    let pubkeys_ref = pubkeys_ref.as_slice(); | 
|  | 21 | + | 
|  | 22 | +    let mut musig_key_agg_cache = MusigKeyAggCache::new(&secp, pubkeys_ref); | 
|  | 23 | + | 
|  | 24 | +    let plain_tweak: [u8; 32] = *b"this could be a BIP32 tweak....\0"; | 
|  | 25 | +    let xonly_tweak: [u8; 32] = *b"this could be a Taproot tweak..\0"; | 
|  | 26 | + | 
|  | 27 | +    let plain_tweak = Scalar::from_be_bytes(plain_tweak).unwrap(); | 
|  | 28 | +    musig_key_agg_cache.pubkey_ec_tweak_add(&secp, &plain_tweak).unwrap(); | 
|  | 29 | + | 
|  | 30 | +    let xonly_tweak = Scalar::from_be_bytes(xonly_tweak).unwrap(); | 
|  | 31 | +    let tweaked_agg_pk = musig_key_agg_cache.pubkey_xonly_tweak_add(&secp, &xonly_tweak).unwrap(); | 
|  | 32 | + | 
|  | 33 | +    let agg_pk = musig_key_agg_cache.agg_pk(); | 
|  | 34 | + | 
|  | 35 | +    assert_eq!(agg_pk, tweaked_agg_pk.x_only_public_key().0); | 
|  | 36 | + | 
|  | 37 | +    let msg_bytes: [u8; 32] = *b"this_could_be_the_hash_of_a_msg!"; | 
|  | 38 | +    let msg = Message::from_digest_slice(&msg_bytes).unwrap(); | 
|  | 39 | + | 
|  | 40 | +    let musig_session_sec_rand1 = MusigSecRand::from_rng(&mut rng); | 
|  | 41 | + | 
|  | 42 | +    let nonce_pair1 = new_musig_nonce_pair( | 
|  | 43 | +        &secp, | 
|  | 44 | +        musig_session_sec_rand1, | 
|  | 45 | +        Some(&musig_key_agg_cache), | 
|  | 46 | +        Some(seckey1), | 
|  | 47 | +        pubkey1, | 
|  | 48 | +        Some(msg), | 
|  | 49 | +        None, | 
|  | 50 | +    ); | 
|  | 51 | + | 
|  | 52 | +    let musig_session_sec_rand2 = MusigSecRand::from_rng(&mut rng); | 
|  | 53 | + | 
|  | 54 | +    let nonce_pair2 = new_musig_nonce_pair( | 
|  | 55 | +        &secp, | 
|  | 56 | +        musig_session_sec_rand2, | 
|  | 57 | +        Some(&musig_key_agg_cache), | 
|  | 58 | +        Some(seckey2), | 
|  | 59 | +        pubkey2, | 
|  | 60 | +        Some(msg), | 
|  | 61 | +        None, | 
|  | 62 | +    ); | 
|  | 63 | + | 
|  | 64 | +    let sec_nonce1 = nonce_pair1.0; | 
|  | 65 | +    let pub_nonce1 = nonce_pair1.1; | 
|  | 66 | + | 
|  | 67 | +    let sec_nonce2 = nonce_pair2.0; | 
|  | 68 | +    let pub_nonce2 = nonce_pair2.1; | 
|  | 69 | + | 
|  | 70 | +    let nonces = [pub_nonce1, pub_nonce2]; | 
|  | 71 | +    let nonces_ref: Vec<&MusigPubNonce> = nonces.iter().collect(); | 
|  | 72 | +    let nonces_ref = nonces_ref.as_slice(); | 
|  | 73 | + | 
|  | 74 | +    let agg_nonce = MusigAggNonce::new(&secp, nonces_ref); | 
|  | 75 | + | 
|  | 76 | +    let session = MusigSession::new(&secp, &musig_key_agg_cache, agg_nonce, msg); | 
|  | 77 | + | 
|  | 78 | +    let keypair1 = Keypair::from_secret_key(&secp, &seckey1); | 
|  | 79 | +    let partial_sign1 = | 
|  | 80 | +        session.partial_sign(&secp, sec_nonce1, &keypair1, &musig_key_agg_cache).unwrap(); | 
|  | 81 | + | 
|  | 82 | +    let keypair2 = Keypair::from_secret_key(&secp, &seckey2); | 
|  | 83 | +    let partial_sign2 = | 
|  | 84 | +        session.partial_sign(&secp, sec_nonce2, &keypair2, &musig_key_agg_cache).unwrap(); | 
|  | 85 | + | 
|  | 86 | +    let is_partial_signature_valid = | 
|  | 87 | +        session.partial_verify(&secp, &musig_key_agg_cache, partial_sign1, pub_nonce1, pubkey1); | 
|  | 88 | +    assert!(is_partial_signature_valid); | 
|  | 89 | + | 
|  | 90 | +    let is_partial_signature_valid = | 
|  | 91 | +        session.partial_verify(&secp, &musig_key_agg_cache, partial_sign2, pub_nonce2, pubkey2); | 
|  | 92 | +    assert!(is_partial_signature_valid); | 
|  | 93 | + | 
|  | 94 | +    let partial_sigs = [partial_sign1, partial_sign2]; | 
|  | 95 | +    let partial_sigs_ref: Vec<&MusigPartialSignature> = partial_sigs.iter().collect(); | 
|  | 96 | +    let partial_sigs_ref = partial_sigs_ref.as_slice(); | 
|  | 97 | + | 
|  | 98 | +    let sig64 = session.partial_sig_agg(partial_sigs_ref); | 
|  | 99 | + | 
|  | 100 | +    assert!(secp.verify_schnorr(&sig64, &msg_bytes, &agg_pk).is_ok()); | 
|  | 101 | +} | 
0 commit comments