P2SH-P2WPKH Nested SegWit - Full Execution
7. P2SH-P2WPKH Nested SegWit — Full Execution
Overview
P2SH-P2WPKH is a backward-compatible "nested SegWit" format that wraps a P2WPKH witness program inside a P2SH envelope. This allows legacy wallets (which don't understand native SegWit bc1q addresses) to send funds to a SegWit-capable receiver. The sender sees a regular 3... address; the receiver gets SegWit benefits.
This format, defined in BIP 141 (section on P2SH compatibility), was a transitional mechanism and is still widely used today.
Script Structure
The redeemScript for P2SH-P2WPKH is a P2WPKH scriptPubKey:
redeemScript = OP_0 <20-byte HASH160(pubkey)>
= 00 14 <20 bytes> (22 bytes total)
Locking script (scriptPubKey) — standard P2SH wrapping:
OP_HASH160 <HASH160(redeemScript)> OP_EQUAL
Unlocking script (scriptSig):
<serialized redeemScript>
Note: The scriptSig contains ONLY the serialized redeemScript — it is a single data push.
Witness field:
02
<signature>
<pubkey>
Full Three-Layer Execution
Layer 1: P2SH validation
scriptSig: PUSH(redeemScript)
scriptPubKey: OP_HASH160 <hash> OP_EQUAL
Execution:
HASH160(redeemScript) == stored hash? → TRUE
Stack: [1]
Layer 2: SegWit witness program detection
After P2SH validation, interpreter detects that the redeemScript
is a valid witness program: OP_0 <20-byte program>
This triggers SegWit execution rules.
scriptSig must contain only a single push of the redeemScript.
If scriptSig contains anything else → INVALID
Layer 3: Witness execution (P2WPKH)
Witness: [<sig>, <pubkey>]
Implicit script: OP_DUP OP_HASH160 <20-byte program> OP_EQUALVERIFY OP_CHECKSIG
Result: [1] → VALID
Address Derivation
def pubkey_to_p2sh_p2wpkh_address(pubkey_hex: str) -> str:
pubkey_bytes = bytes.fromhex(pubkey_hex)
# Step 1: Build inner witness program
keyhash = hash160(pubkey_bytes) # RIPEMD160(SHA256(pubkey))
redeem_script = bytes([0x00, 0x14]) + keyhash # OP_0 PUSH20 <keyhash>
# Step 2: P2SH-hash the redeemScript
script_hash = hash160(redeem_script) # RIPEMD160(SHA256(redeemScript))
# Step 3: Version byte 0x05 for P2SH mainnet
payload = bytes([0x05]) + script_hash
checksum = sha256d(payload)[:4]
return base58.b58encode(payload + checksum).decode()
Weight Analysis
P2SH-P2WPKH input breakdown:
Non-witness: outpoint(36) + scriptSig_len(1) + redeemScript_push(23) + sequence(4) = 64 bytes × 4 = 256 WU
Witness: sig(72) + pubkey(33) + overhead(3) = 108 bytes × 1 = 108 WU
vs native P2WPKH: ≈ 271 WU ≈ 67.75 vbytes
The nested format costs ~34% more than native SegWit, but remains ~40% cheaper than legacy P2PKH, making it a valuable transitional format.
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: