Tapscript sighash commits to (simplified):
2. How Tapscript Differs from Legacy Script
Tapscript is deliberately close to legacy Bitcoin Script. The goal was evolutionary improvement, not revolutionary replacement. Most opcodes work identically. The differences are targeted and purposeful.
Differences in Signature Opcodes
The most significant behavioral difference is in how signature-checking opcodes work.
Legacy Script uses ECDSA signatures. Tapscript uses Schnorr signatures.
In legacy Script, OP_CHECKSIG verifies a DER-encoded ECDSA signature. In Tapscript, OP_CHECKSIG verifies a 64-byte (or 65-byte with sighash type) Schnorr signature. The opcode byte is the same (0xac), but the signature format is entirely different.
Legacy OP_CHECKSIG input format:
Stack before: [<DER-encoded ECDSA sig + sighash_byte>, <33-byte compressed pubkey>]
Tapscript OP_CHECKSIG input format:
Stack before: [<64-byte Schnorr sig> or <65-byte Schnorr sig with sighash>, <32-byte x-only pubkey>]
Notice the public key format change: legacy Script uses 33-byte compressed public keys. Tapscript uses 32-byte x-only public keys — just the x-coordinate of the elliptic curve point. This is possible because for any x-coordinate, there are only two possible y-coordinates, and the convention is to always use the even one.
OP_CHECKMULTISIG is replaced by OP_CHECKSIGADD.
In legacy Script, OP_CHECKMULTISIG takes multiple signatures and public keys and checks M-of-N in a single opcode. In Tapscript, this opcode is disabled (causes immediate failure). Instead, Tapscript introduces OP_CHECKSIGADD which checks one signature at a time and accumulates a count:
Legacy 2-of-3 multisig:
OP_0 <sig1> <sig2> OP_2 <pk1> <pk2> <pk3> OP_3 OP_CHECKMULTISIG
Tapscript 2-of-3 equivalent:
<sig1> <sig2> <sig3>
<pk1> OP_CHECKSIGADD
<pk2> OP_CHECKSIGADD
<pk3> OP_CHECKSIGADD
OP_2 OP_GREATERTHANOREQUAL
Differences in Disabled Opcodes
Tapscript disables several opcodes that were previously available in legacy Script, and re-enables the semantics of some that were previously NOP-repurposed.
Opcodes disabled in Tapscript (cause immediate failure):
- OP_CHECKMULTISIG (0xae)
- OP_CHECKMULTISIGVERIFY (0xaf)
Opcodes that are OP_SUCCESS in Tapscript (cause immediate success):
- Many previously undefined/reserved opcodes
- See the OP_SUCCESS topic for the full list
Differences in Resource Limits
Legacy Script Tapscript
Script size limit: 10,000 bytes weight-limited (no fixed byte cap)
Non-push opcode limit: 201 NONE (removed entirely)
Stack item size: 520 bytes 520 bytes (unchanged)
Stack depth: 1,000 items 1,000 items (unchanged)
Numeric size: 4 bytes 4 bytes (unchanged)
Differences in Signature Hashing
The data that gets hashed to produce the signature hash (sighash) is structured differently in Tapscript. Legacy Script had several sighash hash algorithm variants (original, BIP 143 for SegWit v0). Tapscript uses the algorithm defined in BIP 341, which:
-
Commits to all input amounts (fixing the "unknown fee" attack on hardware wallets)
-
Commits to all input scriptPubKeys
-
Uses tagged hashes (domain-separated SHA256) throughout
-
Is not vulnerable to the quadratic hashing problem of legacy transactions
# Tapscript sighash commits to (simplified):
sighash_data = (
hash_type + # 1 byte
nVersion + # 4 bytes
nLockTime + # 4 bytes
sha_prevouts + # 32 bytes (hash of all outpoints)
sha_amounts + # 32 bytes (hash of all input amounts) ← NEW
sha_scriptpubkeys + # 32 bytes (hash of all input scripts) ← NEW
sha_sequences + # 32 bytes
sha_outputs + # 32 bytes
spend_type + # 1 byte
input_index # 4 bytes
)
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.
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: