BitcoinMachine

Module 07

P2PKH

Pay-to-Public-Key-Hash is the most common script template on the Bitcoin network. Every address starting with '1' encodes a P2PKH. Let's dissect it opcode by opcode.

0 / 4 sections

What you'll learn

  • Identify the scriptSig and scriptPubKey halves of a P2PKH transaction
  • Trace every opcode step in a P2PKH execution
  • Explain why Bitcoin hashes public keys before embedding them in addresses
  • Connect a Base58Check address to the 20-byte hash inside it

01

Two scripts, one validation

A Bitcoin transaction input carries a scriptSig (the unlocking script). The output being spent carries a scriptPubKey (the locking script). To validate, nodes concatenate them and run the combined script. This is the P2PKH pattern.

For P2PKH the split is:

scriptSig (unlocking)

<sig> <pubkey>

Provided by the spender. Proves ownership.

scriptPubKey (locking)

OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

Embedded in the output. Defines the conditions.

The pubkey hash in the scriptPubKey is the 20-byte HASH160 of the public key. This is exactly what a Bitcoin address encodes (with a checksum and version byte added).
Real Bitcoin

Address reuse risk

P2PKH hides your public key until you spend. Once spent, the pubkey is on-chain permanently. If ECDSA were ever broken, funds in already-spent P2PKH outputs would be at risk — which is why modern wallets generate a new address for every transaction.

02

Step by step

Let's trace what each opcode does when P2PKH runs.

<sig> <pubkey>

The spender pushes their signature and public key onto the stack.

OP_DUP

Duplicates the pubkey. Now the stack has two copies — one for hashing, one for signature verification.

OP_HASH160

Hashes the top copy of the pubkey with RIPEMD160(SHA256). Produces the 20-byte pubkey hash.

<pubKeyHash>

The expected hash from the scriptPubKey is pushed. This is what the address was derived from.

OP_EQUALVERIFY

Pops both hashes and checks they match. If they differ, the script fails immediately — wrong pubkey.

OP_CHECKSIG

Uses the original pubkey (still on the stack) to verify the signature against the transaction hash. Pushes 1 if valid.

Now watch it run. The pubkey hash below is the live HASH160 of the test-vector pubkey:0x751e76e8199196d454941c45d1b3a323f1433bd6

Script
<sig>71B
<pubkey>33B
OP_DUP
OP_HASH160
<hash160>20B
OP_EQUALVERIFY
OP_CHECKSIG
Stack0 items

↑ top of stack

nothing here yet

press Step or Run to push an item

bottom
0x304402200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2002202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f4001Push 71 bytes onto the stack.
0 stepsReady

03

Why hash the pubkey?

Publishing a raw public key reveals it to the world. Bitcoin's designers added a second layer of hashing so that even if ECDSA were broken, the owner's public key would remain hidden until the coin is spent.

Additionally, a 20-byte hash is smaller than a 33-byte compressed public key — fewer bytes on-chain means lower fees.

The tradeoff: once you spend a P2PKH output, the pubkey is revealed. That's why address reuse is discouraged — each spend exposes your key.

04

Your turn

Assemble the full P2PKH script from scratch using the test vectors. The pubkey hash is 0x751e76e8199196d454941c45d1b3a323f1433bd6.

Challenge

Run a full P2PKH

Write the complete combined script — scriptSig followed by scriptPubKey — using the test-vector sig, pubkey, and the pubkey hash shown above. The script must succeed (status = success).

Ctrl+Enter to check

← Home