TSP-0011 โ Native MuSig2
Proposal Number: TSP-0011
Proposal Number: TSP-0011
Proposal Name: Native MuSig2 Multi-Signatures
Category: Consensus (C) โ pre-Oct 2025 numbering retained as 000x
Status: Draft
Author: Tondi Foundation Development Team & Avato Labs
Created: 2025-09-05
Target: Tondi Frontier (v2026a)
Scope: Tapscript opcodes for MuSig2 key and nonce aggregation, partial signature operations, on-chain validation semantics, interoperability with TSP-0008 (CISA) and TSP-0007 (ANYPREVOUT), governance & activation
This document uses RFC 2119 keywords (MUST/SHOULD/MAYโฆ).
This proposal introduces native support for the MuSig2 multi-signature scheme, building on BIP-340 Schnorr signatures. It complements TSP-0008 by enabling MuSig2 for general multi-party scripts without cross-input restrictions, and TSP-0010 (PTLC) for adaptor-compatible multi-sigs. v1 focuses on n-of-n schemes, with future extensions for thresholds.
1. Abstract
Native MuSig2 integrates the MuSig2 protocol directly into Tondi tapscript, allowing multi-party key aggregation, nonce handling, and signature verification via new opcodes. This enables compact, private multi-signatures for Taproot outputs, where aggregated keys appear as single keys on-chain. MuSig2 supports two-round interactive signing, rogue-key resistance, and tweaking for BIP-32 derivations or Taproot scripts. The proposal ensures soft-fork compatibility, with on-chain verification matching BIP-340.
2. Background and Motivation
-
Efficiency and Privacy: MuSig2 aggregates multiple keys into one BIP-340 public key, producing a single 64B signature. This reduces on-chain size (e.g., 30-50% fee savings vs. OP_CHECKSIGADD) and hides multi-party nature, enhancing privacy over explicit multi-sig scripts.
-
Interactivity Reduction: Two-round protocol (nonce exchange + partial signs) is faster than three-round schemes, suitable for Tondi's DAG high-TPS environment.
-
Security: Proven under AOMDL assumption, resistant to rogue-key attacks via coefficients.
-
Composability: Integrates with PTLC adaptors (TSP-0010) for multi-party conditionals and CISA (TSP-0008) for aggregated settlements.
Design Goals:
- Soft fork (tapscript-only + OP_SUCCESSx tightening);
- BIP-340 compatible;
- Non-interactive aggregation where possible;
- v1: n-of-n only, no thresholds.
3. Terminology and Overall Design
-
MuSig2: Two-round Schnorr multi-signature scheme for n signers, producing a single signature under an aggregated key.
-
Key Aggregation: Computes aggregated public key X from individual X_i using coefficients a_i to prevent rogue-key attacks.
-
Nonce Aggregation: Each signer contributes two nonces; aggregated with a binding factor b.
-
Partial Signature: Each signer's contribution s_i, summed to final s.
-
Tweaking: Plain (BIP-32) or x-only (Taproot) adjustments to aggregated keys.
v1 Scope:
- Tapscript script-path only;
- SIGHASH_ALL default;
- Interoperable with APO/CISA but no mixing in v1 cohorts;
- On-chain ops for aggregation/verification.
4. Specification
4.1 New Opcodes
-
Via OP_SUCCESSx for soft fork:
- OP_MUSIGKEYAGG (0xBA): Aggregates public keys with coefficients.
- OP_MUSIGNONCEAGG (0xBB): Aggregates nonces with binding.
- OP_MUSIGPARTIALSIG (0xBC): Computes partial signature (off-chain hint, on-chain verify).
- OP_MUSIGVERIFY (0xBD): Verifies aggregated signature.
Specific values allocated from TSP-0001 reserved range 0xB2-0xBF.
-
Non-upgraded nodes: Unconditional success; upgraded: Tighten to MuSig2 logic.
4.2 Key Aggregation
Stack: <pubkey_n> ... <pubkey_1> n OP_MUSIGKEYAGG
- Sort pubkeys X_1..X_n (x-only, ascending).
- L = TaggedHash("KeyAgg list", X_1 || ... || X_n)
- For each X_i: a_i = TaggedHash("KeyAgg coeff", L || X_i) (a_i=1 if n=1 or X_i is second in sorted unique list).
- Agg key X = sum (a_i * X_i)
- Push X (x-only 32B) to stack.
- Fail if any X_i invalid or n>1024 (configurable).
Pseudocode:
fn musig_key_agg(pubkeys: Vec<XOnlyPubKey>) -> XOnlyPubKey {
let sorted = sort(pubkeys);
let L = tag_hash("KeyAgg list", concat(sorted));
let mut X = Point::infinity();
for (i, Xi) in sorted.iter().enumerate() {
let ai = if sorted.len() == 1 || (i > 0 && Xi == sorted[1]) { 1 } else { tag_hash("KeyAgg coeff", L || Xi) };
X += ai * Xi;
}
X.x_only()
}
4.3 Nonce Aggregation
Each signer generates two secret nonces k_{i,1}, k_{i,2}; computes R_{i,1} = k_{i,1}*G, R_{i,2} = k_{i,2}*G (off-chain).
Stack: <R_{n,2}> <R_{n,1}> ... <R_{1,2}> <R_{1,1}> n OP_MUSIGNONCEAGG
- Compute R1_sum = sum R_{i,1}, R2_sum = sum R_{i,2}
- b = TaggedHash("MuSig/noncecoeff", R1_sum.x || R2_sum.x || agg_X || m)
- Agg nonce R = R1_sum + b * R2_sum
- Push R (x-only 32B).
- Fail if R even (adjust as per BIP-340) or invalid points.
4.4 Partial Signature and Aggregation
Off-chain: Each signer computes s_i = k_{i,1} + b * k_{i,2} + e * a_i * x_i, where e = TaggedHash("BIP0340/challenge", R.x || agg_X || m)
On-chain (for verify): Sum s = sum s_i
4.5 Verification
Stack: <sig_s> <agg_R> <agg_X>
- e = TaggedHash("BIP0340/challenge", agg_R.x || agg_X || m)
- Verify: s * G == agg_R + e * agg_X
- Fail tx if false (VERIFY variant pops and fails script).
4.6 Tweaking
- Plain: agg_X' = agg_X + t * G, for BIP-32.
- X-only: agg_X' = agg_X + TaggedHash("TapTweak", agg_X || merkle_root).
- Use in scripts: <tweaked_X> OP_CHECKSIG (standard BIP-340).
4.7 Interoperability and Constraints
- v1: No APO mixing in MuSig2 sessions (future extension).
- With CISA (TSP-0008): Use MuSig2 coeffs in cohorts.
- Failure: Invalid points, overflow, mismatched n.
5. DAG / Mempool Policy
- Size/Fee: Aggregated sigs count as 64B; limit n=1024.
- Validation: Batch verify; relay only standard templates.
- RBF: Compatible.
6. Security Analysis
6.1 Rogue-Key Resistance: Coeffs a_i bind key set.
6.2 Nonce Security: Two nonces per signer; binding b prevents reuse.
6.3 Provable: EUF under AOMDL; no replay via tags.
7. Economic and Privacy Impacts
- Savings: ~47 vBytes/input vs. SegWit.
- Privacy: Indistinguishable from single-sig.
8. Compatibility and Deployment
8.1 Soft Fork: Tapscript-only.
8.2 Activation: Testnet 3 months; version bit.
9. Reference Implementation (Pseudocode)
fn musig_verify(s: Scalar, R: Point, X: Point, m: Bytes) -> bool {
let e = tag_hash("BIP0340/challenge", R.x_only() || X || m);
s * G == R + e * X
}
10. Test Vectors
- 2-signer agg key, nonce, sig.
- Negative: Rogue-key attempt, nonce reuse.
11. Interoperability and Evolution
- Thresholds via future TSP.
- Multi-session batching.
12. Deployment Checklist
- Test vectors, audits.
13. Conclusion
TSP-0011 enables native MuSig2 for efficient, private multi-sigs in Tondi.
Appendix A: Size Example
- n=3: Single 64B sig vs. 3x64B.
References
- BIP-327: MuSig2
- MuSig2 Paper (eprint.iacr.org/2020/1261)
- BIP-340/341/342