Skip to content

Instantly share code, notes, and snippets.

Last active June 15, 2022 22:08
Show Gist options
  • Save sanket1729/4b525c6049f4d9e034d27368c49f28a6 to your computer and use it in GitHub Desktop.
Save sanket1729/4b525c6049f4d9e034d27368c49f28a6 to your computer and use it in GitHub Desktop.
Psbt musig2 signing

Musig2 signing in Psbt

New fields required:

  • PSBT_IN_MUSIG_PARTICIPANT_PUBLIC_KEYS: (<x_only_pk(agg_pk_to_sign)><x_only_pk(agg_pk)>) -> <[x_only_pk]*>: For example, (a, b) -> [c] where b = Musig2_KeyAgg([c]) and a is a tweaked(BIP32 tweak or x-only tweak or both) key derived from b where the tweaking information is present in PSBT_IN_TAP_BIP32_DERIVATION in case of BIP32 tweak. In case, a is the output key, an additional BIP341 tweak is applied. The tweak information is provided in PSBT_IN_TAP_INTERNAL_KEY or PSBT_IN_TAP_MERKLE_ROOT. The full xpub for the aggregated agg_pk can be provided in PBST_GLOBAL_XPUB field

  • PSBT_IN_TAP_MUSIG2_PUB_NONCE: (<x_only_pk(participant_key), x_only_pk(agg_pk_to_sign), leaf_hash>) -> <pub_nonce> (serialized pub_nonce including R1 and R2).

  • PSBT_IN_TAP_PARTIAL_SIGNATURE: (<x_only_pk(participant_key), x_only_pk(agg_pk_to_sign), leaf_hash>) -> <partial_sig> (serialized partial_sig)

Aggregating pubkeys and tweaking:

Q: How to compute the final tweak from the aggregated pubkey that is required for signing?

Note that the the key agg_xpk_tweaked maybe different from the musig agg_pk = KeyAgg(pki). In most cases, this would be obtained from applying a bip32 tweak to agg_pk and another BIP341 taproot tweak. The signers and finalizers need to know this tweak to sign for agg_xkp_tweaked. The BIP32 and x-only taproot tweaks can be computed recomputing agg_pk = KeyAgg(pki) and looking at the PSBT_IN_TAP_BIP32_DERIVATION for the agg_xkp_tweaked. The derivation path, in this case, would be the non-hardened path agg_pk. If the aggregated key being signed is the internal key, the additional taproot BIP341 tweak information is available in PSBT_IN_TAP_INTERNAL_KEY or PSBT_IN_TAP_MERKLE_ROOT.

Figuring out if wallet needs to participate in musig2 signing session

  • Wallet/users lookup psbt for all x-only public keys PSBT_IN_TAP_INTERNAL_KEY and in leaf (mini)scripts from PSBT_IN_TAP_LEAF_SCRIPT and lookup corresponding the PSBT_IN_TAP_BIP32_DERIVATION for each key.
    • Non-aggregated pubkey case: If the derivation path is known to the wallet, sign with the corresponding key.
    • Aggregated pubkey case: Lookup the key in PSBT_IN_MUSIG_PARTICIPANT_PUBLIC_KEYS (Map from <x_only_pk><x_only_pk> -> List[x_only_pks]) and see we can sign for any of the constituent keys. To do this, we check the PSBT_IN_TAP_BIP32_DERIVATION for each constituent key and check we have the key corresponding to the master fingerprint. If yes, we initiate in musig2 signing procedure for each of the keys that we can sign for.

Musig2 signing round1:

  • After figuring out which keys signers can sign for, each signer fills in PSBT_IN_TAP_MUSIG2_PUB_NONCE with key data as a tuple (partipant_pk, agg_xpk_tweaked, leaf_hash) and value data as musig pub nonces (R1, R2). participant_pk represents the public key of a participant in musig2 signing while agg_xpk_tweaked represents the final possibly multiple times tweaked public that the signers together want to sign. agg_xpk_tweaked is included to indicate which key the signer is willing to sign for as the same participant_pk can be used multiple times in the different public keys in the same leaf script. (eg musig2(A, B, C) and musig2(A, D, E)). leaf_hash is also included for the signer to select which leaves they are willing to sign for. This nonce is not unique per signer, and the signer can add nonces to all keys that it is willing to sign for. If the key is an internal key, use [0u8; 32] as leaf hash.
  • The signer should ensure that never even uses the same nonces again for any signing session regardless of the outcome of the session.

Remark: Musig2 has the benefit that we can proceed with round1 of signing without knowing the messages or keys! However a psbt workflow starts with an unsigned transaction, so it seems unlikely(?) that we can leverage this property to any use while signing bitcoin transactions. It may be possible to share these nonces out of the band before we engage in the psbt sign workflow, but that is outside of the scope of psbt.

Musig round 2:

  • If all the participants have added nonces corresponding for key, leaf_hash pair, add a partial signature to PSBT_IN_TAP_PARTIAL_SIGNATURE with key data (partipicant_pk, agg_pk_tweaked, leaf_hash) and value as partial-sig which only contains the s part of signature as per Musig partial sign spec.

Psbt Finalizing

  • If there are enough signatures to produce a final signature, the finalizer can aggregate the partial signatures and add tweak*G and uses this as a final signature while satisfying the psbt.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment