We start with:
An empty processing stack
A
txin-script (scriptSig) provided by the person spending the value to prove that they have the necessary private key. While anyone could provide the public key, only a person with the private key can provide a signature that will match that public key.
A
txout-script (scriptPubKey) obtained from the previous transaction (when the spender previously received the value that they are now spending).
- OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG
The
txin-script and the
txout-script are concatenated together resulting in a verification script of:
- OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG
Then processing of the script begins (left to right)
The
two constants are pushed onto the stack resulting in a processing stack of:
Leaving behind a verification script of:
- OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG
OP_DUP is performed (popping the top element,
, off the stack, duplicating it, and pushing both values back onto the stack), leaving behind a verification script of:
- OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG
The processing stack is now:
OP_HASH160 is performed (popping the the top element,
, off the stack, hashing that value with
RIPEMD160, and pushing the result back onto the stack), leaving behind a verification script of:
- OP_EQUALVERIFY OP_CHECKSIG
The processing stack is now:
The next constant is pushed onto the stack, leaving behind a verification script of:
- OP_EQUALVERIFY OP_CHECKSIG
The processing stack is now:
OP_EQUALVERIFY is performed (popping the top two elements off the stack and verifying that they are equal). This verifies that the
provided by the spender hashes to the same value as
that is
stored in the transaction where that spender previously received what they are now spending.
If we didn’t have
OP_EQUALVERIFY here, and instead performed
OP_CHECKSIG now, then we would be popping off the two copies of the public key hash,
and
, and treating one as a public key and the other as a signature. We’d then try and verify that
was a signature that is verifiable by using the
as a public key. Clearly this wouldn’t work at all.
Instead, what we want to do is verify that the
provided by the spender
in the txin-script is the correct public key (verify that it hashes to
the same value as was stored in the txout-script of the transaction where the spender received what they are now spending).
After this step is done
OP_CHECKSIG can be performed (popping off the remaining two elements on the stack,
and
, and verifying that the
signature provided was computed with the private key that matches the provided public key.
Notice that the public key is not stored in the
txout-script, only the
RIPEMD160 hash of the public key. An attacker could try to sign a transaction with any private key at all. Verifying the signature requires a public key to make sure that the signature was generated with the CORRECT private key. This verification can’t be performed with the RIPEMD160 hash of the public key.
In order to prevent an attacker from providing the wrong public key (one that works with their own private key instead of the intended private key), the provided
is hashed, and then compared (by way of
OP_EQUALVERIFY) to the
that is stored in the
txout-script. This forces the spender to provide the CORRECT
, and then
OP_CHECKSIG is used to force the spender to provide a
that can be verified with the
that they provided.