I am proud to announce…
The first publicly-available and Bitcoin-compatible Rust implementation of the MuSig2 protocol!
(at least, the first judging by what I could find)
Detailed API documentation is available here.
What?
The MuSig2 protocol allows a group of people who don’t trust each other to cooperatively sign a message, and then aggregate their signatures into a single signature which is indistinguishable from a signature made by a single private key.
The group collectively controls an aggregated public key which can only create signatures if everyone in the group cooperates (AKA an N-of-N multisignature scheme).
In a previous article several months ago, I described the older MuSig1 protocol, diving into the algebra behind it and dissecting why it works. MuSig2 is an upgrade to MuSig1, optimized to support secure signature aggregation with only two round-trips of network communication instead of three.
My implementation is fully compatible with the BIP-0327 and BIP-0340 specifications.
Usage
A collection of public keys can be aggregated together into a KeyAggContext
like so:
1 | use secp256k1::{SecretKey, PublicKey}; |
The KeyAggContext
can optionally be tweaked with additional commitments, such as a BIP341 taproot script commitment, allowing the group to provably commit their aggregated public key to a specific value.
1 | let tweak: [u8; 32] = sha256(/* ... */); |
The musig2
crate provides an idiot-proof stateful signing API suitable for use by application developers or downstream protocol implementors. Rust’s lifetime system ensures at compile time that secret nonces cannot be reused (which would suck).
Start by creating a FirstRound
, in which you exchange nonces with your co-signers.
1 | use musig2::{FirstRound, PubNonce, SecNonceSpices}; |
Once the first round is complete, you can finalize it into a SecondRound
. This is the only time the signer’s secret key is needed.
1 | use musig2::{PartialSignature, SecondRound}; |
If all signatures were received successfully, finalizing the second round should succeed with overwhelming probability. The result is an aggregated Schnorr signature, indistinguishable from a single-signer context.
1 | use musig2::CompactSignature; |
Ecosystem Compatibility
I made this crate with the aim of maximizing compatibility with other popular Bitcoin-related packages in the Rust ecosystem, such as the bitcoin
crate and its cryptographic backbone, the secp256k1
crate.
By default, the musig2
crate relies on the secp256k1
crate for elliptic curve cryptography, which is just a binding to libsecp256k1
. This is the same library which powers Bitcoin Core.
For those interested in a pure-rust build, you can alternatively configure musig2
to use the k256
crate for elliptic curve math instead. k256
is maintained by the RustCrypto team.
1 | cargo add musig2 --no-default-features --features k256 |
Contributing
Pull requests, feature suggestions, and bug reports are all welcome!
Links
For full details on the musig2
crate, check out:
Disclaimer
The musig2
crate is beta software, not covered by warranty and has not been independently audited.