Skip to content
Back to skills

Musig2

ASecurity

MuSig2 (BIP327): two-round Schnorr key aggregation for n-of-n multisig. Aggregates n public keys into a single 32-byte x-only pubkey indistinguishable from a single-sig. Used in Taproot cooperative spends. Quick refs: protocol round-trip, key aggregation math, common attacks. USE WHEN: implementing n-of-n cooperative Taproot signing, designing Lightning Taproot channels, joint custody.

  • 31 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 8, 2026
ai-agentsrustgoexpressgitapisecurity

Works with

  • api

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned September 22, 2026

npx -y skills add claude-dev-suite/claude-dev-suite --skill musig2 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Musig2?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Musig2
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/claude-dev-suite-musig2/badge)](https://www.skillsdirectory.com/skills/claude-dev-suite-musig2)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: bitcoin-musig2
description: |
  MuSig2 (BIP327): two-round Schnorr key aggregation for n-of-n
  multisig. Aggregates n public keys into a single 32-byte x-only
  pubkey indistinguishable from a single-sig. Used in Taproot
  cooperative spends.
  Quick refs: protocol round-trip, key aggregation math, common attacks.
  USE WHEN: implementing n-of-n cooperative Taproot signing, designing
  Lightning Taproot channels, joint custody.
allowed-tools: Read, Grep, Glob
---

# MuSig2 (BIP327)

> **Quick refs**: [protocol.md](quick-ref/protocol.md), [key-agg.md](quick-ref/key-agg.md), [attacks.md](quick-ref/attacks.md)

MuSig2 is the **standard** Schnorr key-aggregation protocol for Bitcoin.
n parties hold separate private keys, jointly produce a single public
key `Q` and a single signature `(R, s)` indistinguishable from a
single-key Schnorr signature.

Replaces MuSig1 (3-round) and MuSig-DN with simpler 2-round + better
security proofs.

BIP327 is **Status: Deployed**, spec version 1.0.4 (as of September
2026).

## Properties

- **Indistinguishable** — observers cannot tell `Q` was aggregated.
- **Off-chain coordination** — n-of-n in 2 rounds with no on-chain
  multisig.
- **Provably secure** in the Algorithmic One-More-Discrete-Log (AOMDL)
  + Random Oracle Model.
- **Fits Taproot key-path** — cheapest spend; no script-path needed
  for cooperative case.

## Two-round protocol summary

### Round 1 — Nonce exchange

Each signer i:
1. Generates two ephemeral nonces `(k_{i,1}, k_{i,2})`.
2. Computes `(R_{i,1}, R_{i,2}) = (k_{i,1}*G, k_{i,2}*G)`.
3. Broadcasts `R_{i,1}, R_{i,2}` to all other signers (66 bytes total).

Aggregator computes:
- `R_1 = sum(R_{i,1})`, `R_2 = sum(R_{i,2})`.
- `b = TaggedHash("MuSig/noncecoef", R_1 || R_2 || agg_pubkey || msg)`.
- `R = R_1 + b*R_2`.

### Round 2 — Partial sig exchange

Each signer i:
1. Computes their partial sig `s_i` using `R`, message, key-agg
   coefficient `a_i`, etc.
2. Broadcasts `s_i`.

Aggregator: `s = sum(s_i) mod n`.

Final sig: `(R.x, s)` — 64 bytes, valid BIP340 sig under `Q`.

## Key aggregation

```
Inputs: pubkeys P_1, ..., P_n (in agreed-upon order)
1. L = sorted(P_i)   (canonical order, byte-lex)
2. a_i = TaggedHash("KeyAgg coefficient", L || P_i.x)
3. Q = sum(a_i * P_i)
```

If `Q.y` is odd, parity bit `g_q = -1`, otherwise `g_q = +1`. This
parity is tracked through signing.

The coefficients `a_i` defeat the **rogue-key attack** that MuSig1
patched but earlier schemes had: an attacker who could pick their
public key after seeing others' would otherwise control the sum.

## Tweaks (Taproot integration)

After key aggregation, Taproot tweak applies:
```
Q_tweaked = Q + t*G  where t = TaggedHash("TapTweak", Q.x || merkle_root)
```

Signing for `Q_tweaked` requires an extra adjustment in the partial
sig phase. BIP327 specifies "tweak context" maintaining the
accumulated tweak.

## Pre-shared nonces (NonceGen variants)

- `NonceGen` deterministic from secret + msg + extra_in.
- "MuSig2 with non-determinism" requires careful aux entropy.
- **Critical**: nonces must NOT be reused across different signing
  sessions, even with different messages. State must be persisted
  carefully (e.g., in encrypted nonce wallet).

## Use cases in Bitcoin

1. **Joint custody** — 2 partners co-spend with single-sig appearance.
2. **Lightning** — Taproot channels (BOLT update) replace OP_2 pubkey
   with MuSig2-aggregated key for channel funding output.
3. **DAO multisig with privacy** — n directors sign as one.
4. **Vault hot/cold cooperative spend** — cold key + hot key
   aggregated for everyday use.
5. **Coinjoin servers** with k-anonymity → users + service jointly
   sign.

## Descriptors, PSBTs and wallet integration

BIP327 covers only the signing math. Three companion BIPs (all by Ava
Chow) carry MuSig2 into wallet software — statuses as of September
2026:

- **BIP328** (Complete) — *Derivation Scheme for MuSig2 Aggregate
  Keys*. Wraps a plain aggregate pubkey in a **synthetic xpub**:
  depth 0, child number 0, fixed chaincode
  `868087ca02a6f974c4598924c36b57762d32cb45717167e300622c7167e38965`
  (SHA256 of the text `MuSig2MuSig2MuSig2`). Only unhardened
  derivation is possible — there is no aggregate private key. Each
  `CKDpub` step's `I_L` enters the session context as a **plain**
  tweak (`is_xonly_t = false`), so every signer must recompute the
  derivation tweaks for the child key being signed for.
- **BIP390** (Draft, v0.2.0) — the `musig(KEY,KEY,...,KEY)` descriptor
  key expression. Allowed only inside `tr()`, `rawtr()` or `sp()`,
  never nested in another `musig()`. Keys are sorted with `KeySort`
  after all derivation and before aggregation, so the order written
  in the descriptor does not matter. `musig(...)/NUM/.../*` derives
  from the aggregate key per BIP328, and is legal only when every
  participant is an xpub (or derived from one) and no participant
  itself uses `/*` or `/<NUM;NUM;...>`. No hardened steps after
  `musig()`.
- **BIP373** (Complete) — *MuSig2 PSBT Fields*, carrying both rounds
  through an otherwise ordinary PSBT workflow:
  `PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS` (`0x1a`),
  `PSBT_IN_MUSIG2_PUB_NONCE` (`0x1b`),
  `PSBT_IN_MUSIG2_PARTIAL_SIG` (`0x1c`) and
  `PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS` (`0x08`).

Bitcoin Core parses `musig()` descriptors and reads/writes the BIP373
PSBT fields from **v30.0 (October 2025)**; descriptor support merged
in PR #31244 (2025-07-31). Core accepts `musig()` only inside `tr()`
— not `rawtr()` or `sp()` — per `doc/descriptors.md` (v31.1, July
2026).

## Security caveats

- **Concurrent sessions** — naive per-signer parallel sessions enable
  "Wagner-style" forge attacks. Solution in BIP327: nonce binding to
  message (the `b` coefficient).
- **State persistence** — nonces must be wiped after one use. Power
  loss between round 1 and round 2 → must restart with fresh nonces.
- **Hardware wallet support** — still thin as of September 2026. The
  Ledger Bitcoin app has shipped `musig()` key expressions since
  v2.4.0 (CHANGELOG 2025-03-07; GitHub release 2025-03-17): at most
  5 keys per `musig()`, at most 8 parallel signing sessions
  (persistent state is scarce), `musig()` allowed in `multi_a` but
  not `sortedmulti_a`, and only `musig(...)/**` or
  `musig(...)/<M;N>/*` — participants must be aggregated without
  further per-key derivation. v2.5.1 (CHANGELOG 2026-09-09) fixed
  `musig()` inside `multi_a` fragments. Coldcard is the opposite
  case: the Mk4 and Q1 board configs both set `NGU_INCL_MUSIG = 0`
  ("Exclude unused optional libngu secp256k1 features to save
  firmware space"), so MuSig is compiled out of the firmware
  entirely (as of September 2026). Either way a coordinator that
  speaks BIP373 PSBTs is required.

## Implementations

- `libsecp256k1` (`secp256k1_musig_*` — no `2` in the prefix).
  Mainline since v0.6.0 (2024-11-04) and built by default
  (`--enable-module-musig` is `[default=yes]`); not experimental.
  `secp256k1_musig_keyagg_cache` and `secp256k1_musig_session` still
  have no serialization/parsing functions as of v0.8.0 (2026-08-03),
  so signing state cannot be persisted across a process restart
  between round 1 and round 2.
- `rust-secp256k1` — the module is `musig`, not `musig2`
  (`secp256k1::musig`: `KeyAggCache`, `SecretNonce`/`PublicNonce`,
  `AggregatedNonce`, `Session`, `PartialSignature`,
  `AggregatedSignature`). Support was added in the 0.32 development
  series (CHANGELOG entry "0.32.0 - 2025-10-02", which also removed
  the `Secp256k1` context from the public API), but **no stable
  0.32.0 was ever published** — the three `0.32.0-beta.*` crates are
  yanked. The first stable release carrying MuSig2 is 0.33.0
  (2026-08-28); current stable is 0.33.1 (2026-08-29).
- **BDK has no MuSig2 support** as of September 2026. The blocker is
  `rust-miniscript`: PR #954 (*Add BIP390 `musig()` descriptor key
  expressions*) is still open, so `bdk_wallet` 3.1.0 (2026-06-14)
  cannot even parse `tr(musig(...))` — bdk-ffi pins that behaviour in
  a test literally named `cannotCreateMusigDescriptor`.

## Common bugs

- Forgetting to apply parity flips during partial-sig phase
  (`g_q` and `g_b` must propagate).
- Reusing nonces across two attempts of the same session → key leak.
- Missing key-aggregation coefficient `a_i` → produces a sig under a
  different aggregated pubkey.

## See also

- [schnorr/SKILL.md](../schnorr/SKILL.md)
- [frost/SKILL.md](../frost/SKILL.md)
- [adaptor-sigs/SKILL.md](../adaptor-sigs/SKILL.md)
- [../../protocol/taproot/SKILL.md](../../protocol/taproot/SKILL.md)

Files in this skill

  • SKILL.md4.7 KB
  • quick-ref/attacks.md3.5 KB
  • quick-ref/key-agg.md3.1 KB
  • quick-ref/protocol.md3.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…