10

When executing a Bitcoin Script, there are some "special cases" where the interpreter performs extra verification beyond just executing scriptSig and then scriptPubKey.

For example, if the scriptPubKey has the following specific format:

OP_HASH160 <20 byte hash> OP_EQUAL

then the interpreter will additionally apply the BIP 0016 "Pay to Script Hash" (P2SH) rules.

What's the full list of "special cases" that could be encountered during Script execution, and when is each encountered?

0

1 Answer 1

15

As of September 2023, "high-level" script validation with all active consensus rules on the network is approximately this:

Top level evaluation

  • Execute the scriptSig, and call the resulting stack stack. If execution aborts, fail.
  • Execute the scriptPubKey with stack as input, and call the resulting stack result. If execution aborts, fail.
  • If result is empty, or its top element has numerical value 0, fail.
  • [from BIP141] If scriptPubKey is exactly equal to an OP_n (with n between 0 and 16, inclusive) followed by a direct push of exactly 2 to 40 bytes inclusive:
    • If scriptSig not empty, fail.
    • Run segwit validation with the 2-to-40 byte push in scriptPubKey as program, the n value as version, and witness as input (see further). If this execution aborts, fail.
  • [From BIP16] If scriptPubKey is exactly equal to OP_HASH160 + a 20 byte push + OP_EQUAL, run P2SH validation:
    • If scriptSig does not consists of only pushes, fail.
    • If result is empty, fail.
    • Interpret the top element of result as a script, and execute it, with the rest of result as input. Call the resulting stack p2sh_result. If this execution aborts, fail.
    • If p2sh_result is empty, or its top element has numerical value 0, fail.
    • [From BIP141] If the top element of result is exactly OP_n (with n between 0 and 16 inclusive) followed by a direct push of 2 through 40 bytes inclusive:
      • If scriptSig is not exactly a direct push of the top element of result, fail.
      • Run segwit validation with the 2-to-40 byte push in the top element of result as program, the n value as version, and witness as input (see further). If this execution aborts, fail.
  • If segwit validation did not trigger, but a witness is provided in the transaction input, fail.
  • If no failure occurred before this point, the input is valid.

Segwit validation

Segwit validation for version version, with program program, and input input:

  • [From BIP141] If the version is 0:
    • If the program is not 20 or 32 bytes, fail.
    • If the program is 20 bytes hash:
      • If input is not exactly 2 elements, fail.
      • Execute the script OP_DUP OP_HASH160 hash OP_EQUALVERIFY OP_CHECKSIG, with initial stack input. If execution aborts, fail.
      • If the resulting stack is not exactly one element, or that element has numerical value 0, fail.
    • If the program is 32 bytes hash:
      • If input is empty, or its top element's SHA256 hash does not equal hash, fail.
      • Execute the top element of input as script, with the other elements as input. If execution aborts, fail.
      • If the resulting stack is not exactly one element, or that element has numerical value 0, fail.
  • [From BIP341] If the version is 1, the program length is 32, and this is not operating inside a P2SH wrapping:
    • If the input consists of 0 elements, fail.
    • If the last element of input starts with byte 0x50, call it the annex and remove it from the input.
    • If the (remainder of) input consists of a single element, evaluate it as a Taproot key path spend:
      • The element is interpreted as a single BIP340 (Schnorr) signature for the transaction, using a message hashing scheme described in BIP341. If the signature is invalid, fail.
    • If the (remainder of) input consists of two or more elements, evaluate it as a Taproot script path spend:
      • The last element of input is interpreted as a Taproot control block, encoding a leaf_version, an internal x-only public key, and a Merkle path, and the penultimate element of input is called the taproot_script. The control block and taproot_script are removed from input.
        • Recompute the Merkle root of the script tree, starting from the leaf (leaf_version and taproot_script), and then tweak the internal x-only key with that Merkle root. If the result does not match the 32-byte witness program, fail.
        • [From BIP342] If the leaf_version is 0xc0, taproot_script is evaluated according to the Tapscript validation rules, with the remaining of input as initial stack. See BIP342 for how this differs from normal script execution.
  • If no failure occurred up to this point, return success.

Source: https://github.com/bitcoin/bitcoin/blob/v25.0/src/script/interpreter.cpp, functions VerifyScript, VerifyWitnessProgram, ExecuteWitnessScript.

TL;DR: only the BIP16 P2SH pattern (OP_HASH160 <20 bytes> OP_EQUAL) and the BIP141 segwit pattern (OP_n <2 to 40 bytes>) are actual special cases that trigger additional rules. But the details are more complex.

23
  • 1
    In the P2SH wrapped case, should this be "Run segwit validation with the top element of result as program" (instead of scriptPubKey as program)?
    – Elliott
    Mar 26, 2021 at 17:38
  • 2
    Yes, the redeemscript is any script, it can contain any opcodes. It's just the scriptSig that must be push only for P2SH spends. Sep 1, 2023 at 16:26
  • 2
    @joke Correct, it's just adding a "if version is 1, witness program is 32 bytes, ..." branch. Sep 1, 2023 at 16:38
  • 1
    1) Yes, no other pushes are allowed (because inputs need to provided through witness, not through scriptSig). 2) The list of witness items is called a stack too, though admittedly that name isn't very accurate. But yes, last element. 3) Yes, for P2WSH the witness stack consists of the witness script's inputs, followed by the witness script itself. All but the last element become the initial stack for execution. 4) The witness stack is not a script, it's just a list of elements; it has no notion of opcodes or pushes - rather, it's the resulting script stack itself. Sep 2, 2023 at 0:41
  • 2
    All correct. The witness stack is just an array of byte arrays. For P2WSH the last one is interpreted as the witness script, the rest becomes the initial script execution stack. Sep 2, 2023 at 1:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.