When a segwit input is signed, the signature will commit to the witness script (or a p2pkh-like script in case of p2wpkh). This is specified in BIP143:
- For
P2WPKH
witness program, thescriptCode
is0x1976a914{20-byte-pubkey-hash}88ac
.- For
P2WSH
witness program,
- if the
witnessScript
does not contain anyOP_CODESEPARATOR
, thescriptCode
is thewitnessScript
serialized as scripts insideCTxOut
.- if the
witnessScript
contains anyOP_CODESEPARATOR
, thescriptCode
is thewitnessScript
but removing everything up to and including the last executedOP_CODESEPARATOR
before the signature checking opcode being executed, serialized as scripts insideCTxOut
. (The exact semantics is demonstrated in the examples below)
What's the rationale behind this? Why doesn't the hash commit to the pubkey script as in legacy (p2pkh and p2sh) payments? This difference complicates signing/verification code a bit, so I suppose there must be some good reason for it.
Maybe my question should be: Why does the hash commit to any script at all for segwit inputs? In legacy signatures, putting scriptPubkey in scriptSig for the current input is a (complicated, see below) way to avoid signature reuse between inputs. But in segwit, this is accomplished with the outpoint
part of the hashing algorithm. So couldn't we just skip the scriptCode
part?
It seems to me that there is another reason for why we hash the scriptPubkey for legacy signatures and the witness script for segwit signatures, since there are simpler ways to avoid signature reuse:
- Legacy: We could just have added a dummy byte somewhere in the current input
- Segwit: Current input's outpoint already solves the problem.