TeachMeBitcoin

Conceptual MuSig2 key aggregation (not production code):

From TeachMeBitcoin, the free encyclopedia Reading time: 4 min

12. Key Aggregation with MuSig2 in Tapscript

MuSig2 is a multi-signature protocol that allows multiple signers to produce a single Schnorr signature that is indistinguishable from a single-party signature. When used with Taproot's key path spending, a 10-of-10 multisig looks identical on-chain to a single-person spend.

Why Key Aggregation Matters

In legacy Bitcoin, multisig outputs reveal the number of participants and their public keys on-chain. A 3-of-5 multisig transaction is obviously a 3-of-5 multisig to any blockchain observer. This has implications for:

MuSig2 + Taproot key path solving eliminates all three problems when all signers agree.

How MuSig2 Works (Simplified)

MuSig2 is a two-round interactive protocol:

Setup phase (done once per key combination):

1. Each signer i has private key x_i and public key P_i = x_i × G

2. Compute the aggregate key: P_agg = H(P_1, P_2, ..., P_n) × (a_1×P_1 + a_2×P_2 + ... + a_n×P_n)
   where a_i = H_agg(L, P_i) and L = {P_1, ..., P_n}

3. The Taproot output uses P_agg as its internal key (potentially tweaked with scripts)

Signing phase (done for each transaction):
Round 1:

- Each signer i generates two random nonces r_i1, r_i2

- Computes R_i1 = r_i1 × G, R_i2 = r_i2 × G

- Broadcasts (R_i1, R_i2) to all other signers

Round 2 (after all nonces collected):

- Compute b = H(R_11||R_12, R_21||R_22, ..., message)

- Each signer computes combined nonce: R_i = R_i1 + b × R_i2

- Compute aggregate nonce: R = R_1 + R_2 + ... + R_n

- Each signer computes partial sig: s_i = r_i1 + b×r_i2 + H(R, P_agg, message) × a_i × x_i

- Aggregate: s = s_1 + s_2 + ... + s_n

Final signature: (R, s)
This is a valid Schnorr signature under P_agg

MuSig2 in Practice with Python (Conceptual)

# Conceptual MuSig2 key aggregation (not production code):

def musig2_aggregate_keys(pubkeys):
    """
    Aggregate multiple public keys into a single MuSig2 key.
    pubkeys: list of 32-byte x-only public keys
    returns: 32-byte x-only aggregate public key
    """
    # Compute the key list hash
    L = b''.join(sorted(pubkeys))  # Sorted for determinism
    L_hash = sha256(L)

    # Compute per-key coefficients
    coefficients = []
    for pk in pubkeys:
        a_i = int.from_bytes(tagged_hash("KeyAgg coefficient", L_hash + pk), 'big')
        coefficients.append(a_i)

    # Weighted sum of public keys
    agg_point = None
    for pk, a_i in zip(pubkeys, coefficients):
        pk_point = lift_x(int.from_bytes(pk, 'big'))  # Convert to curve point
        weighted = point_mul(pk_point, a_i)
        agg_point = point_add(agg_point, weighted) if agg_point else weighted

    return x_only(agg_point)  # Return x-only representation

# Using the aggregate key in a Taproot output:
agg_key = musig2_aggregate_keys([pk_alice, pk_bob, pk_carol])
# This 32-byte key is used directly as the Taproot internal key
# The output looks EXACTLY like a single-signer Taproot output
taproot_output = bytes([0x51, 0x20]) + agg_key  # OP_1 <32-byte key>

MuSig2 vs Tapscript OP_CHECKSIGADD

These two approaches serve different multisig use cases:

MuSig2 (key path):
✓ Maximum privacy — looks like single signer
✓ Minimum fees — single 64-byte signature
✓ Requires all N signers to participate interactively
✗ Requires 2 rounds of communication
✗ If any signer is offline, must fall back to script path
✗ No on-chain accountability (can't prove who signed)

OP_CHECKSIGADD (script path):
✓ Non-interactive — signers can sign independently
✓ Threshold (M-of-N) without all signers present
✓ On-chain accountability if needed
✗ Reveals script structure when spending
✗ More bytes — one signature per signer
✗ Higher fees

The optimal Taproot design often combines both: MuSig2 aggregate key in the key path for the cooperative case, OP_CHECKSIGADD threshold in a script path for the non-cooperative case.

Technical Insight

This topic covers essential mechanics for Chapter 11. Understanding these details is key to mastering advanced Bitcoin script constructions like Taproot and specialized covenants.

☕ Help support TeachMeBitcoin

TeachMeBitcoin is an ad-free, open-source educational repository curated by a passionate team of Bitcoin researchers and educators for public benefit. If you found our articles helpful, please consider supporting our hosting and ongoing content updates with a clean donation:

Ethereum: 0x578417C51783663D8A6A811B3544E1f779D39A85
Bitcoin: bc1q77k9e95rn669kpzyjr8ke9w95zhk7pa5s63qzz
Solana: 4ycT2ayqeMucixj3wS8Ay8Tq9NRDYRPKYbj3UGESyQ4J
Address copied to clipboard!