Most explanations of “how Bitcoin signatures work” fuse three unrelated questions into one: which mathematical algorithm makes the signature, which conditions must be met to spend, and which parts of the transaction the signature vouches for. P2TR is not a signature algorithm; MuSig2 is not a script type. They belong to different layers. Once you pull them apart, the picture is much cleaner:

LayerQuestion it answersOptions
Signature algorithmHow is the signature computed?ECDSA (secp256k1) vs Schnorr (BIP340)
Locking scriptWhat conditions authorize spending?P2PK → P2PKH → P2SH → P2WPKH/P2WSH → P2TR
SIGHASHWhich parts of the transaction are committed to?ALL / NONE / SINGLE + ANYONECANPAY; DEFAULT

This division covers the usual arrangements on Bitcoin, but the layers are not perfectly orthogonal: SIGHASH_DEFAULT, for example, exists only under Taproot, and specific scripts accept only specific algorithms. What follows walks down each layer and ends with selection guidance.

Layer one: the signature algorithm

ECDSA: the only on-chain algorithm from 2009 to 2021

Bitcoin arrived just as the Schnorr patent was expiring (the commonly cited date is February 2008; counting 20 years from filing gives February 2010), while ECDSA already had standardized implementations and support in OpenSSL. So until Taproot activated, ECDSA over secp256k1 was the only signature algorithm Bitcoin had on chain. Signatures use DER encoding and typically run 70–72 bytes, before the trailing one-byte SIGHASH flag:

1
s = k⁻¹ · (H(m) + r·x) mod n

Three consequences follow from that equation:

  • The nonce k is the whole game. Sign two different messages with the same private key and the same k, and the private key falls out directly. A SecureRandom flaw in Android in 2013 leaked private keys from a batch of mobile wallets for exactly this reason. The eventual mitigation is RFC 6979: derive k deterministically from the private key and the message, and stop depending on the quality of a random number generator.
  • Malleability. ECDSA’s algebra lets anyone replace s with n−s and the signature still verifies; lax parsing of non-DER encodings and a mutable scriptSig offered further room for tweaking. On non-SegWit transactions, a third party could therefore change the txid. When Mt. Gox suspended withdrawals in 2014 it blamed transaction malleability, though the actual losses cannot be pinned on malleability alone. BIP66 enforced strict DER at consensus level, low-S and similar rules arrived mainly through standard transaction policy, and BIP62 proposed a fuller fix but never advanced and is now Closed. SegWit moved signatures out of txid computation, which eliminates txid malleability from third-party signature edits in SegWit inputs — but not all transaction malleability.
  • No Schnorr-style linear aggregation. This does not mean ECDSA can do neither batch verification nor multisignatures; it means you cannot get Schnorr’s clean, native key and signature aggregation. Threshold ECDSA generally requires considerably more elaborate protocols.

Schnorr (BIP340): live with Taproot

Activated in November 2021 (block 709,632) as part of the Taproot soft fork. The core relation looks like this (omitting the conditional negation that x-only encoding requires):

1
s = k + e·x mod n,   e = tagged_hash("BIP0340/challenge", R || P || m)

Signatures are exactly 64 bytes (32 for r, 32 for s) with strict encoding; public keys are 32 bytes in x-only form, with verification using the even-y point. Verification checks s·G = R + e·P, which involves no modular inversion as ECDSA verification does, and there is no equivalent signature obtained by swapping s for n−s.

ECDSASchnorr (BIP340)
Signature size~70–72 B (DER, excluding the SIGHASH byte)Fixed 64 B
Public key33 B (compressed)32 B (x-only)
MalleabilityAn equivalent high-S form exists; standard transaction rules can constrain itAvoided by strict encoding and signature construction
Single verificationVerification relation contains a modular inversionNo ECDSA-style inversion; real-world speed depends on the implementation
Batch verificationNo native efficient batch check like Schnorr’sSupported with random coefficients
Signature / key aggregationNo equally clean native protocol; more complex multiparty schemes requiredMuSig2 (BIP327), n-of-n

Linearity is the point — but you cannot simply add verification equations together. Batch verification needs random coefficients so that invalid signatures cannot cancel one another out, and multi-scalar multiplication to make it fast. Across parties, protocols such as MuSig2 aggregate keys so the output looks exactly like an ordinary single-signer BIP340 signature. ECDSA is not mathematically barred from batch verification or threshold signing; it just lacks this clean native path.

Layer two: the locking script

The algorithm decides how to sign; the script decides what has to be true for a signature to count. The evolutionary arc, roughly: put the conditions behind a hash, then hide the optional conditions inside a Merkle tree.

  • P2PK (2009): the public key sits directly in the output, common in early transactions; most of Satoshi’s early mining rewards are generally believed to use this form. The key is public on chain while unspent, which is why this type often gets singled out in quantum discussions. That said, under the classical security model a published public key is not the same as a leaked private key.
  • P2PKH (2009): only hash160(pubkey) is stored; the public key and signature are revealed at spend time. The output script is 25 bytes, a compressed-key input costs about 148 vB, and mainnet addresses begin with 1.
  • P2MS (bare multisig, BIP11): m-of-n is written straight into the output and all n public keys are exposed. OP_CHECKMULTISIG also has the historic off-by-one quirk of popping one extra element, so an extra placeholder is required.
  • P2SH (BIP16, 2012): the output commits only to a 20-byte script hash; multisig, timelocks, and other complex conditions move off chain until spend time, when the full script is revealed. Mainnet addresses begin with 3. Nested P2SH-P2WPKH was derived from this in 2017 for wallet compatibility (~91 vB per input) and now serves mainly as a transition path.
  • P2WPKH / P2WSH (SegWit, BIP141 / BIP143, 2017-08, block 481,824): signatures move into the witness, where each byte costs 1 weight unit against 4 for non-witness data, bringing a P2WPKH input down to about 68 vB. Because the txid no longer covers the witness, txid malleability from third-party signature edits disappears — a key foundation for the Lightning Network. BIP143 fixes two older problems as a side effect: the signed message now includes the amount of the input being spent, so a malicious host cannot misstate the value and still produce a valid signature; and reusable hashes bring the signature-hash computation down from O(n²) to O(n).
  • P2TR (BIP341 / BIP342, 2021-11): the output script is OP_1 <32-byte output key Q>, 34 bytes in total, and mainnet addresses begin with bc1p:
1
Q = P + t·G,   t = tagged_hash("TapTweak", P || merkle_root)

When there is no script tree, merkle_root is omitted rather than hashed in as zero. The two spending paths:

  • Key path: a single Schnorr signature. With SIGHASH_DEFAULT that is 64 bytes and a typical input of about 57.5 vB — the smallest among common standard single-sig inputs. While unspent, a P2TR output exposes neither an internal key nor a script tree; a key-path spend reveals neither either. So as far as the output script and witness structure go, a single-sig spend and a key-path spend with a hidden script tree are indistinguishable.
  • Script path: reveals the executed script branch and a control block (leaf version and output-key parity bit, internal key, Merkle path). Tapscript replaces OP_CHECKMULTISIG with OP_CHECKSIGADD, accumulating successful signatures, which removes the placeholder quirk and eases batch validation; the spend does not reveal the other script branches.

Output script and typical input sizes

TypeOutput script sizeInput (typical)AlgorithmNotes
P2PK35 B (compressed key) / 67 B (uncompressed key)~114 vBECDSAPublic key exposed indefinitely
P2PKH25 B~148 vBECDSAAssumes a compressed key
P2SH-P2WPKH23 B~91 vBECDSANested transition form
P2WPKH22 B~68 vBECDSACommon single-sig type
P2WSH 2-of-334 B~104.5–105 vB (varies slightly with DER length)ECDSA ×2Witness script fully revealed
P2TR key path34 B~57.5 vBSchnorrUses DEFAULT; script tree stays hidden

Output sizes above cover the scriptPubKey only and exclude the 8-byte amount field. Inputs are given in vB, with ECDSA rows assuming a low-R (71-byte DER) signature; real sizes shift with DER length, the SIGHASH flag, and script and witness structure.

Layer three: SIGHASH

The same algorithm with a different SIGHASH flag signs a completely different “contract” — the flag decides which inputs and which outputs the signature commits to:

FlagValueCommits to inputsCommits to outputsTypical use and caveats
ALL0x01AllAllThe default for legacy / SegWit v0; by far the most common
NONE0x02AllNoneOutputs can be replaced; only for deliberate protocol designs
SINGLE0x03AllThe output at the same indexCoinJoin-style joint transactions; must handle a missing output at that index
+ANYONECANPAYCombined with the low flag, adding 0x80Only this inputDetermined by the low flagCrowdfunding, adding inputs, and similar
DEFAULT0x00AllAllTaproot only; same scope as ALL, saves one byte

The table simplifies commitment at the level of prevouts and outputs. More precisely: under legacy and BIP143, NONE and SINGLE zero out the nSequence of other inputs in the hash, so those fields are not committed at all. Taproot (BIP341) does the opposite and commits to nSequence on every input even under NONE and SINGLE (unless ANYONECANPAY is set). That is one of BIP341’s changes from BIP143.

Three historical footguns worth remembering:

  • The SINGLE out-of-range bug. In legacy, when the input index has no matching output, SignatureHash returns the 32-byte representation of the integer 1 instead of a normal transaction digest (internally, 0x01 followed by 31 zero bytes in little-endian). This does not make arbitrary signatures valid, but a signature produced against that constant commits to nothing about the actual transaction and may be reusable in other transactions meeting the same condition. BIP143’s v0 witness path avoids the degenerate branch, and Taproot (BIP341) simply declares SIGHASH_SINGLE invalid when the corresponding output is missing.
  • No amount commitment. The legacy signed message omits the input amount — the root of hardware-wallet amount-spoofing attacks. BIP143 fixes this by including the input’s amount.
  • Taproot’s signature message uses the TapSighash tagged hash instead of the double SHA256 of legacy / BIP143, and commits to the amount and scriptPubKey of the output being spent, among other context. The script path additionally commits to the tapleaf hash, key version, and OP_CODESEPARATOR position. Which fields are included still depends on the SIGHASH flag.

In practice: use ALL for legacy / SegWit v0 and DEFAULT for Taproot. Reach for NONE, SINGLE, or ANYONECANPAY only when a protocol explicitly requires it and you understand exactly what you are authorizing.

Multisig: three implementations side by side

Multisig is where signature choices diverge most sharply:

P2WSH m-of-nTaproot script path m-of-nMuSig2 (BIP327) key path
On-chain formOutput is a script hash; spending reveals n public keys and the thresholdOutput is a tweaked key; spending reveals the executed branchA single aggregate key, itself tweakable for Taproot
Signature countm ECDSA signaturesm Schnorr signatures1 aggregate Schnorr signature
Typical 2-of-3 input~104.5–105 vB~108–116.5 vB (including the control block)Not directly supported; only 3-of-3 key path at ~57.5 vB
Revealed at spendFull script plus every public keyExecuted branch plus control blockNo extra script information
ThresholdAny m-of-nAny (single script or per branch)n-of-n only
Visible while unspentOnly that it is a P2WSH, not the threshold or keysIdentical to any other P2TR outputIdentical to any other P2TR output

The ~108–116.5 vB Taproot figure corresponds to the common shapes — a single 2-of-3 OP_CHECKSIGADD leaf, or three 2-of-2 leaves — assuming SIGHASH_DEFAULT and the relevant tree depth; depth, script, and SIGHASH all move the number.

A few points matter more than the table:

  • Rogue-key attacks. Let the victim’s key be P₁; an attacker can pick P₂ = x₂·G − P₁ so that naive addition yields P₁ + P₂ = x₂·G, giving them sole control of the aggregate key. BIP327 first computes L over the list of public keys, then derives coefficients a_i = int(tagged_hash("KeyAgg coefficient", L || P_i)) mod n; by the MuSig2* optimization, the second distinct key and any duplicates of it take coefficient 1, and the specification defines how duplicate keys are handled.
  • MuSig1 required three rounds of interaction; MuSig2 cuts it to two. Each signer’s public nonce consists of two curve points, and implementations must store session state safely and never reuse a secnonce. BIP327 provides an interoperability standard, but before adopting it you still need to confirm end-to-end support in your wallets, coordinator, and hardware firmware.
  • MuSig2 is n-of-n only. For genuine t-of-n thresholds, use FROST, write the threshold as an OP_CHECKSIGADD script under Taproot, or split signer combinations into script branches.
  • A 2-of-3 Taproot script path is not necessarily cheaper than P2WSH; under the assumptions above it costs roughly 4–12 vB more. Its real payoff is that the routine cooperative path can use the key path, the emergency branches stay hidden in normal operation, and the output looks like any other P2TR while unspent.
  • The privacy boundary. When n parties spend via a MuSig2 key path, the output script and witness structure are indistinguishable from an ordinary single-sig P2TR spend. That is not the same as anonymity: amounts, address reuse, and wallet fingerprints still leak metadata.

How to choose

  1. Self-custody: use a P2TR key path when your toolchain supports it; fall back to P2WPKH if your wallet or the recipient does not.
  2. Shared control by every party (say, a team cold wallet with n-of-n): MuSig2, which has the smallest on-chain footprint and looks like an ordinary single-sig P2TR spend.
  3. Conditional spending (inheritance, timeouts, two-factor, escape hatches): a Taproot script tree, with the most common cooperative path on the key path and everything else in the tree.
  4. Compatibility first (exchange whitelists, older hardware wallets): P2WPKH / P2WSH multisig remains the safe choice; older environments may still need P2PKH.

PSBT (BIP174) and output descriptors let these designs work across devices and vendors — provided every link in the chain supports the same scripts and signing protocols. Confirm the full toolchain before you commit to a design.

The failure mode never changed

However the algorithm layer evolves, a leaked or reused nonce can expose the corresponding private key:

  • ECDSA uses RFC 6979 deterministic nonces; BIP340 derives nonces per its own specification; MuSig2 cannot simply copy purely deterministic session nonces and must follow BIP327’s rules for high-quality randomness and single-use secnonce values.
  • Hardware wallets with anti-klepto support let the host inject extra entropy and prove via DLEQ proofs and similar mechanisms that nonces were generated as agreed, reducing the risk of private-key exfiltration through nonce grinding. This is not something every wallet offers by default.
  • In MuSig2, one party reusing its own secnonce may expose that party’s key, not automatically everyone else’s. Every endpoint must still audit how nonces are generated, stored, used, and wiped, so that it does not become the weak link in the authorization chain.

Looking ahead: BIP118 (ANYPREVOUT) would let a signature avoid committing to a specific UTXO, paving the way for eltoo-style Lightning updates; cross-input signature aggregation (combining signatures across inputs into one) could cut the cost of transactions like CoinJoin. The first builds on Schnorr / Taproot’s extensible signing structure, the second exploits Schnorr’s linearity more directly. Neither is a consensus rule today: BIP118 remains a Draft, and cross-input aggregation is not deployed.

A quick checklist

Algorithm layer

  1. Does ECDSA use RFC 6979 or an equally sound nonce scheme? Do Schnorr and MuSig2 follow BIP340 and BIP327 respectively?
  2. Is nonce discipline auditable? Does the hardware wallet support anti-klepto? Is every MuSig2 secnonce used exactly once?

Script layer

  1. Is the public key exposed long-term? P2PK and P2TR outputs publish a key outright; P2PKH / P2WPKH reveal it on spend; address reuse further tightens transaction linkage.
  2. Do you need to hide spending conditions? A P2TR key path hides the internal key and script tree, but the output key Q is always on chain. Script privacy and public-key exposure are not the same concern.

Multiparty and SIGHASH

  1. Is the multisig really n-of-n or actually t-of-n? MuSig2 directly supports only the former. Are the interaction rounds and implementation audits clearly understood?
  2. Does SIGHASH need a non-default mode? Legacy / SegWit v0 default to ALL, Taproot to DEFAULT. Without a clear requirement, stay away from NONE / SINGLE / ANYONECANPAY.
  3. Does the multiparty contract verify the Taproot internal key, aggregation coefficients, Merkle root, and tweak? Naive key addition or trusting a coordinator invites rogue-key and substitution risks.

Bitcoin’s signature landscape evolves by accumulation, not replacement: new schemes lean on Schnorr, the script layer moves toward minimum disclosure per spending path, and SIGHASH keeps patching and extending its commitment scope. The real divergence is in multiparty coordination protocols — where both the fee and privacy leverage and the new attack surface live.