scriptPubKey is a P2SH script, and the BIP16 redeemScript pushed in the scriptSig is exactly a push of a version byte plus a push of a witness program."—BIP 141, Segregated WitnessSegWit activated on August 24, 2017. The protocol was ready. The wallets were not.
Native SegWit outputs use bech32 addresses (bc1q…), but in 2017 most wallets and exchanges could only send to legacy addresses—1… (P2PKH) or 3… (P2SH). A user who generated a bech32 address and asked Coinbase to withdraw to it would get an error: "invalid address."
The solution was elegant. Wrap the SegWit witness program inside a P2SH script. The output looks like any other P2SH output (a 3-address), but when spent, the P2SH redeem script turns out to be a witness program, triggering SegWit validation. Legacy wallets can send to it without knowing SegWit exists. Only the spender needs SegWit awareness.
This chapter covers both flavors:
SegWit's designers faced a deployment dilemma. Native SegWit required senders to understand bech32 addresses, but Bitcoin's ecosystem had hundreds of wallets, exchanges, and payment processors. Updating them all simultaneously was impossible. BIP 141† solved this with a two-pronged strategy:
bc1q…): optimal efficiency, but requires sender support.3…): slightly less efficient, but any wallet that supports P2SH (since 2012) can send to them.In practice, wrapped SegWit dominated from 2017 through 2019. Exchanges like Coinbase did not support sending to bech32 addresses until 2020. Even today, some services still generate 3-addresses for SegWit wallets to maximize compatibility.
Our Chapter 8 specimen—the first SegWit transaction ever confirmed (block 481,824)—is a P2SH-P2WPKH spend. Let us now examine exactly how the wrapping works.
When someone sends to a P2SH-P2WPKH address, they create a standard P2SH output:
| Hex | Opcode | Meaning |
|---|---|---|
a9 | OP_HASH160 | Hash the top stack item |
14 | OP_PUSHBYTES_20 | Push next 20 bytes |
(20 bytes) | (data) | HASH160 of the redeem script |
87 | OP_EQUAL | Check equality |
This is identical to any P2SH output. The sender does not know—and does not need to know—that the redeem script is a witness program.
The redeem script hidden inside this P2SH is simply a witness program:
| Hex | Opcode | Meaning |
|---|---|---|
00 | OP_0 | Witness version 0 |
14 | OP_PUSHBYTES_20 | Push next 20 bytes |
(20 bytes) | (data) | HASH160 of the public key |
This 22-byte script is the bridge: it satisfies P2SH (it is the preimage of the script hash) and it matches the pattern for a version-0, 20-byte witness program, triggering P2WPKH rules.
Unlike native P2WPKH (Chapter 9), the scriptSig is not empty. It contains exactly one item: a push of the 22-byte redeem script:
| Hex | Opcode | Meaning |
|---|---|---|
16 | OP_PUSHBYTES_22 | Push next 22 bytes |
0014… | (data) | The 22-byte witness program |
This 23-byte scriptSig is the only additional cost of wrapping. The witness data (signature + public key) is identical to native P2WPKH.
Validation proceeds in two stages:
OP_0 <20 bytes>—a version-0, 20-byte witness program. The node invokes P2WPKH rules: verify the witness signature against the public key whose HASH160 matches the witness program.BIP 141 defines that a witness program can appear in two places: directly in a scriptPubKey (native) or as a P2SH redeem script (wrapped). The node checks both locations. If the redeem script after P2SH evaluation matches the witness program pattern, SegWit kicks in automatically. This is why only one level of wrapping is allowed—BIP 141 explicitly forbids P2SH-P2SH-P2WPKH or any deeper nesting.
The same wrapping technique applies to P2WSH. For a 2-of-3 multisig:
| Hex | Opcode | Meaning |
|---|---|---|
00 | OP_0 | Witness version 0 |
20 | OP_PUSHBYTES_32 | Push next 32 bytes |
(32 bytes) | (data) | SHA-256 of the witnessScript |
The scriptSig is 35 bytes: OP_PUSHBYTES_34 (0x22) followed by the 34-byte witness program. The witness data is identical to native P2WSH.
BIP 141 notes that P2SH-P2WSH has reduced security compared to native P2WSH. The funding output commits to a 20-byte HASH160 of the redeem script (80 bits of collision resistance), not the 32-byte SHA-256 used in native P2WSH (128 bits). For high-value multisig, native P2WSH is strongly preferred.
Wrapping adds exactly one cost: the scriptSig bytes, which count as non-witness data at 4 WU each.
| Type | ScriptSig | Extra WU | Extra vbytes |
|---|---|---|---|
| P2SH-P2WPKH | 23 bytes | \(23 \times 4 = 92\) | 23 |
| P2SH-P2WSH | 35 bytes | \(35 \times 4 = 140\) | 35 |
The following table compares all output types for a single-key (P2PKH family) and a 2-of-3 multisig (P2SH family) transaction, each with 1 input and 2 outputs. Signatures are assumed to be 72 bytes (worst-case DER).
| Single-key (1-in-2-out) | Size | Weight | vsize | vs Legacy |
|---|---|---|---|---|
| P2PKH (legacy) | 226 | 904 | 226 | — |
| P2SH-P2WPKH (wrapped) | 248 | 662 | 166 | \(-27\%\) |
| P2WPKH (native) | 223 | 562 | 141 | \(-38\%\) |
Outputs are type-matched: P2PKH outputs (34 B) for legacy, P2SH (32 B) for wrapped, P2WPKH (31 B) for native. 72-byte worst-case DER signatures throughout.
| 2-of-3 multisig (1-in-2-out) | Size | Weight | vsize | vs Legacy |
|---|---|---|---|---|
| P2SH multisig (legacy) | 371 | 1,484 | 371 | — |
| P2SH-P2WSH (wrapped) | 406 | 856 | 214 | \(-42\%\) |
| P2WSH (native) | 393 | 804 | 201 | \(-46\%\) |
Legacy baseline from Ch. 6 specimen. Wrapped uses P2SH outputs (32 B); native uses P2WSH outputs (43 B).
The pattern is clear: wrapping captures most of SegWit's fee savings. The wrapper's cost is exactly its scriptSig size: 23 vbytes for P2SH-P2WPKH, 35 vbytes for P2SH-P2WSH (see exercise P1). Compared to the total savings over legacy, this overhead is modest.
The wrapped-vs-native gap (25 or 13 vbytes in the tables above) is small compared to the legacy-vs-wrapped gap (60 or 157 vbytes). This is because the dominant cost reduction comes from moving signatures to the witness at 1 WU per byte instead of 4. The scriptSig wrapper is a fixed overhead that becomes proportionally smaller as transactions grow more complex.
A P2SH-P2WPKH address is generated in three steps:
0x0014 \(\|\) \(h\) (22 bytes).The result is a standard 3-address. No external observer can distinguish it from a regular P2SH multisig address until the output is spent and the 22-byte redeem script is revealed.
For P2SH-P2WSH, step 2 uses 0x0020 \(\|\) \(\text{SHA-256}(\text{witnessScript})\) (34 bytes), and step 3 hashes this 34-byte witness program.
| Date | Milestone |
|---|---|
| Aug 2017 | SegWit activates (block 481,824). Wrapped SegWit is the only practical option. |
| Feb 2018 | Bitcoin Core 0.16.0† adds bech32 support. Major exchanges begin SegWit rollout. |
| Jun 2020 | Bitcoin Core 0.20.0† makes P2WPKH the default address type. |
| 2020-2021 | Major exchanges (Coinbase, Kraken, Gemini) add bech32 send support. |
| 2023-2024 | Native SegWit (bech32) dominates; wrapped SegWit usage declines. |
Wrapped SegWit served its purpose: it bridged the three-year gap between protocol readiness and ecosystem readiness. By 2024, it was largely superseded by native SegWit and Taproot.
This chapter concludes Part III. We have traced the complete SegWit story: the motivation (Chapter 8), native single-key (Chapter 9), native scripts (Chapter 10), and the backward-compatible bridge (this chapter). Part IV turns to Taproot—the next major upgrade, activated in November 2021—which unifies all output types under a single 34-byte scriptPubKey format using Schnorr signatures and Merklized Abstract Syntax Trees (MAST).
751e76e8199196d454941c45d1b3a323f1433bd6 (from BIP 141's test vector).bc1p…), not P2SH wrapping. Why was the P2SH bridge not repeated for Taproot?L1. 23 bytes. It contains a single push: OP_PUSHBYTES_22 (0x16) followed by the 22-byte witness program (0014 + 20-byte key hash).
L2. Legacy wallets understand P2SH addresses (3…), valid since BIP 16 activation in 2012. The sender constructs a standard P2SH output without knowing the redeem script's contents. Native SegWit uses bech32 addresses (bc1q…), which legacy wallets do not recognize as valid.
L3. After the P2SH hash check succeeds, the node deserializes the redeem script and checks whether it matches the witness program pattern: a 1-byte version push (OP_0 through OP_16) followed by a direct data push between 2 and 40 bytes. If it does, SegWit rules are triggered.
L4. BIP 141 explicitly defines only two locations where a witness program is recognized: (1) directly in a scriptPubKey, or (2) as a BIP 16 P2SH redeem script. Multiple levels of wrapping (P2SH-P2SH-P2WPKH) would create ambiguity and complexity without any benefit—one level of wrapping already provides full backward compatibility.
L5. P2SH-P2WSH: the funding output uses HASH160 (20 bytes, 80 bits of collision resistance) to commit to the 34-byte witness program. Native P2WSH: the funding output uses the 32-byte SHA-256 directly (128 bits of collision resistance). The 48-bit gap is significant—\(2^{80}\) operations are theoretically within reach, while \(2^{128}\) is not.
H1. From the Chapter 8 specimen, the scriptSig is at the input's scriptSig field. The payload after the 0x16 push opcode is the 22-byte witness program: 0014… (20-byte key hash). Computing HASH160 of this 22-byte value should yield the 20-byte hash in the prevout scriptPubKey (a914…87).
H2. 2-input, 3-output P2SH-P2WPKH:
H3.
0014751e76e8199196d454941c45d1b3a323f1433bd6 (22 bytes).bcfeb728b584253d5f3f70bcb780e9ef218a68f4.05bcfeb728b584253d5f3f70bcb780e9ef218a68f4 → 3JvL6Ymt8MVWiCNHC7oWU6nLeHNJKLZGLN.P1. Consider \(n\) inputs and \(k\) outputs. In native P2WPKH, each input has a 0-byte scriptSig (1-byte length varint). In P2SH-P2WPKH, each input has a 23-byte scriptSig (1-byte length varint, since \(23 < 253\)). The output data is identical. The witness data is identical. The only difference per input is \(+23\) non-witness bytes. Each non-witness byte costs exactly 4 WU (it appears in both the stripped size \(\times 3\) and total size \(\times 1\) terms). So the total weight increase is \(23n \times 4 = 92n\) WU, and the vsize increase is \(\lceil 92n/4 \rceil = 23n\) vbytes. For a single input, this is exactly 23 vbytes—the scriptSig length. The proof generalizes: the overhead per input is always the scriptSig byte count.
P2. In P2SH-P2WSH, the funding output contains OP_HASH160 <20> OP_EQUAL. An attacker performing a collision attack targets this 20-byte HASH160, which has only \(2^{80}\) collision resistance. If Alice and Bob create a 2-of-2 P2SH-P2WSH, Alice could search for a different 34-byte witness program (containing a different witnessScript) that produces the same HASH160. She needs \(2^{80}\) operations.
In native P2WSH, the funding output contains the 32-byte SHA-256 directly. A collision attack now targets the SHA-256 with \(2^{128}\) collision resistance. Even if the attacker finds a witness program collision, it must also be a valid witness program (starting with 0020), further constraining the search.
The key insight: the witness is verified against SHA-256 in both cases, but the funding commitment uses a weaker hash in the wrapped version. The attack occurs before spending, when the attacker substitutes a different script at the P2SH commitment layer.
C1. In 2017–2018, most counterparties (exchanges, wallets) could only send to P2SH addresses. Lightning implementations needed to accept channel funding from these counterparties, so P2SH-P2WSH was the practical choice. As bech32 support became widespread (2019–2020), implementations switched to native P2WSH for the improved collision resistance and slightly lower fees. The BOLT specifications now recommend native P2WSH for channel funding.
C2. From the blockchain alone, you cannot determine whether a P2SH output is P2SH-P2WSH, P2SH-P2WPKH, or plain P2SH multisig. All three have identical scriptPubKeys (a914…87). The redeem script is only revealed when the output is spent—at that point, the scriptSig reveals whether it is a 22-byte witness program (P2SH-P2WPKH), 34-byte witness program (P2SH-P2WSH), or a full multisig script (plain P2SH). Until spent, the output type is hidden. This is a privacy feature of P2SH.
B1. By November 2021 (Taproot activation), bech32/bech32m support was widespread. Major exchanges had added bech32 send support during 2020–2021, and Bitcoin Core had made P2WPKH the default address type since version 0.20.0 (June 2020). The ecosystem no longer needed a backward-compatible bridge. Additionally, wrapping Taproot in P2SH would negate some of its privacy benefits: Taproot aims to make all output types look identical, but a 3-address immediately identifies the output as P2SH.
B2. Migration is simple: the wallet generates a new native P2WPKH address (bech32) using the same key pair and sends funds from the old P2SH-P2WPKH address to the new one. The user needs only their private key—the public key hash is derived identically in both cases. On-chain, a transaction moves funds from a 3-address to a bc1q-address. The key pair does not change; only the address encoding and spending mechanism differ. Future receives should use the new bech32 address.