TeachMeBitcoin

P2WPKH Script - Full Witness Execution

From TeachMeBitcoin, the free encyclopedia Reading time: 3 min

5. P2WPKH Script — Full Witness Execution

Overview

Pay-to-Witness-Public-Key-Hash (P2WPKH) is the SegWit (Segregated Witness) equivalent of P2PKH, introduced in BIP 141 and activated in August 2017. SegWit separates signature data (the witness) from the transaction body, solving transaction malleability, enabling the Lightning Network, and reducing effective transaction weight.

P2WPKH native addresses use Bech32 encoding (prefix bc1q on mainnet).

Script Structure

Locking script (scriptPubKey) — 22 bytes:

OP_0 <20-byte witness program>

The 20-byte witness program is identical to the pubKeyHash in P2PKH: HASH160(pubkey).

scriptSig: Empty (zero bytes) — this is critical for SegWit.

Witness field (replaces scriptSig):

02            <- witness item count
<sig>         <- item 1: DER signature + SIGHASH byte
<pubkey>      <- item 2: compressed public key

Byte-Level Anatomy

scriptPubKey (22 bytes):
00            <- OP_0 (witness version 0)
14            <- push 20 bytes
<20-byte HASH160(pubkey)>

Witness (serialized):
02            <- 2 witness items
47            <- item 1 length (71 bytes)
<71-byte signature>
21            <- item 2 length (33 bytes)
<33-byte compressed pubkey>

SegWit Execution Rules

For SegWit inputs, the standard script interpreter is bypassed. Instead:

  1. The scriptPubKey is detected as a witness program (starts with OP_0 to OP_16).

  2. The scriptSig must be empty. If not, the transaction is invalid.

  3. The witness stack is used as input.

  4. For version 0 with 20-byte program (P2WPKH), a virtual P2PKH script is constructed:

Implicit script constructed by the interpreter:
OP_DUP OP_HASH160 <20-byte witness program> OP_EQUALVERIFY OP_CHECKSIG
  1. This implicit script is executed with the witness items as the stack.

Transaction Weight and Discount

SegWit introduces weight units (WU) with a discount for witness data:

Transaction weight formula:
weight = (non-witness bytes × 4) + (witness bytes × 1)

1 weight unit = 0.25 vbytes
Block limit = 4,000,000 WU = 1,000,000 vbytes

A P2WPKH input contributes:
  - 41 bytes non-witness (outpoint + sequence + empty scriptSig) × 4 = 164 WU
  - ~107 bytes witness × 1 = 107 WU
  - Total ≈ 271 WU ≈ 67.75 vbytes

vs P2PKH input:
  - 148 bytes × 4 = 592 WU ≈ 148 vbytes

This ~55% size reduction makes P2WPKH transactions significantly cheaper to send.

BIP 143 Signature Hash

SegWit v0 uses a new signature hashing algorithm (BIP 143) to prevent quadratic hashing attacks:

def bip143_sighash(tx, input_index, script_code, value, sighash_type=1):
    """
    BIP143 sighash for P2WPKH
    script_code = OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY OP_CHECKSIG
    value = satoshis locked in the UTXO being spent
    """
    hash_prevouts  = double_sha256(serialize_all_outpoints(tx))
    hash_sequence  = double_sha256(serialize_all_sequences(tx))
    hash_outputs   = double_sha256(serialize_all_outputs(tx))

    preimage = (
        tx.version.to_bytes(4, 'little') +
        hash_prevouts +
        hash_sequence +
        serialize_outpoint(tx.inputs[input_index]) +
        script_code +
        value.to_bytes(8, 'little') +
        tx.inputs[input_index].sequence.to_bytes(4, 'little') +
        hash_outputs +
        tx.locktime.to_bytes(4, 'little') +
        sighash_type.to_bytes(4, 'little')
    )
    return double_sha256(preimage)

The key difference from legacy sighash is that the value (amount) of the UTXO being spent is now committed to in the signature, closing the "hardware wallet attack" where a malicious host could misrepresent amounts.

☕ Help support TeachMeBitcoin

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:

Ethereum: 0x578417C51783663D8A6A811B3544E1f779D39A85
Bitcoin: bc1q77k9e95rn669kpzyjr8ke9w95zhk7pa5s63qzz
Solana: 4ycT2ayqeMucixj3wS8Ay8Tq9NRDYRPKYbj3UGESyQ4J
Address copied to clipboard!