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
P2WPKHwitness program, thescriptCodeis0x1976a914{20-byte-pubkey-hash}88ac.- For
P2WSHwitness program,
- if the
witnessScriptdoes not contain anyOP_CODESEPARATOR, thescriptCodeis thewitnessScriptserialized as scripts insideCTxOut.- if the
witnessScriptcontains anyOP_CODESEPARATOR, thescriptCodeis thewitnessScriptbut removing everything up to and including the last executedOP_CODESEPARATORbefore 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.