Why hash witness script instead of pubkey script in signature? 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, the scriptCode is 0x1976a914{20-byte-pubkey-hash}88ac.
  For P2WSH witness program,
  
  
  if the witnessScript does not contain any OP_CODESEPARATOR, the scriptCode is the witnessScript serialized as scripts inside CTxOut.
  if the witnessScript contains any OP_CODESEPARATOR, the scriptCode is the witnessScript but removing everything up to and including the last executed OP_CODESEPARATOR before the signature checking opcode being executed, serialized as scripts inside CTxOut. (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.
I'm just guessing, but by having the transaction commit to the scriptCode, we ensure that the signer knows what script they're signing for.  A hardware wallet, for example, can only be certain that outpoint 1234...cdef:0 pays a particular script if we give it the transaction that created that outpoint (so that it can hash that transaction, verify the txid, extract the scriptPubKey, and compare that to a provided witnessScript).  Because a transaction (without witness data) can be up to almost a megabyte in size and a spending transaction can refer to thousands of previous transactions, we create a situation where low-resource devices such as hardware wallets have a hard time verifying what they're signing.

By contrast, with BIP143, we need only tell the wallet each of the scriptCodes it's supposed to sign for.  BIP141 allows these to be up to 10,000 bytes, which is just 1/100th the maximum size of a transaction.  The wallet can examine these scriptCodes, ensure they agree with what the wallet expects, and commit to them in its signature knowing that if the person sending them the scriptCode lied about the actual scriptCode, the signature will be invalid.

This is the same reason the BIP143 signature format commits to the value of each input.  Before it had to process previous transactions in order to get their output amounts; now it just accepts whatever data it receives and signs it knowing that, if someone lied to it about the amount, the signature will be invalid.