I read on bitcoin-dev that CHECKSIGFROMSTACKVERIFY (CHECKDATASIG in BCash) can be used to emulate new sighash flags. How would that work, concretely? As an example, please provide an example update transaction based on figure 4 of the Eltoo paper, or aj's simplified lightning (that doesn't work with watchtowers).

  • You also need OP_CAT or OP_SUBSTR. If you are still interested in this question, I can answer this in detail – sanket1729 Jan 28 at 18:14
  • @sanket1729, Yes, I am still interested! Thanks! Looking forward to reading your answer. – Janus Troelsen Jan 28 at 20:49
  • 1
    Sorry for the super long delay, I finally have an answer for you. This may be a lot to take in, so let me know if something needs more clarification. – sanket1729 Jul 22 at 8:46

Eltoo relies on a primitive SIGHASH_ANYPREVOUT or SIGHASH_NOINPUT (hereafter referred as APO) BPI118, constructing Eltoo from APO would be replacing the CHECKSIG figure 4 of Eltoo paper with a modified script.

Most of this answer is based on a blog post by Russell O'Connor from this link(which goes into other covenant constructions too). For completeness, let us look at the basics of transaction introspection and later hop into how to construct APO. The answer is for Segwit Signature Hash and the ECDSA signature algorithm. Unfortunately, extending this to taproot requires additional opcodes/other changes which I will explain at the end of the answer.

  1. OP_CHECKSIGFROMSTACK:(hereafter CSFS) There is no formal proposal for this opcode yet, but most likely this would work as follows: pop 1) a pubkey pk, 2) a message m, and a 3) digital signature sig. The operation would perform the verify the sig as ECSDA.Verify(pk, sha256(m), sig) and push the result onto the stack top.
  2. OP_CAT: Pop two items from stack top and next_top and push next_top || top onto the stack where || denotes the byte string concatenation. I will be assuming a SIGHASH_ALL for the below construction, but the construction can be used for sighash type.

First we will look at basic transaction introspection using OP_CAT and OP_CSFS: Consider the following script:

1. OP_OVER OP_SHA256 <pubKey>

with the witness stack


Where <fixed_pk> is public whose secret key is known to everyone. Say, the generator G whose secret key is 1. <sig_msg> denotes transition digest being signed.

At the end of Step 1, the stack is


At the end of step 2, the stack contents are


Note that 1 is translated as SIGHASH_ALL and catted to sig. This creates a regular bitcoin signature which we can verify using regular OP_CHECKSIG. After Step 3, the stack contents are


Which would call OP_CHECKSIGFROMSTACKVERIFY to leave only <sig_msg> onto the stack. The OP_CHECKSIGFROMSTACKVERIFY of step 4 uses the same pubKey and signature. This operation performs another SHA-256(double sha256 is required for segwit sighash algorithm) and does a digital signature validation on the doubly hashed <sig_msg>. Note that because we are using exactly the same <pubKey> and <sig> that we used for the previous OP_CHECKSIGVERIFY operation, the current OP_CHECKSIGFROMSTACKVERIFY can only succeed if <sig_msg> is identical to the message that was checked during step 3’s OP_CHECKSIGVERIFY operation. At this point, we are certain that the <sig_msg> on the stack top is the same as the signed transaction message.

Note that since the private key to <fixed_pk> is known, anyone can create this signature, but this script would only succeed if the <sig_msg> is correctly specified as mentioned above.


Anyprevout essentially is substituting some things from the regular signature hash messages and replacing those with 0's. In detail, we can now split our sig_msg into multiple parts as defined in BIP143 using OP_SUBSTR. It is also possible to use OP_CAT to initially supply the split up the message and then CAT it together.

Now that we have signature hash message as per BIP143 on the stack, we manipulate it to make certain fields 0's. In particular, we make items 2-4 0.

2. hashPrevouts (32-byte hash)
3. hashSequence (32-byte hash)
4. outpoint (32-byte hash + 4-byte little endian) 

We take a OP_DUP OP_SUSTR 0 <4> to get item 1, version. onto the stack. and similarly, obtain a concatenation of items 5-10 onto the stack. Finally, we CAT them together by <ver> <[0; (32+ 32 + (32 +4))]> <items 5.10>` to get a new sighash which we use for Eltoo update key.

Let introspect_script =


as we discussed above. And let manipulate_txdata_script be the script to modify the stack contents from BIP143 sighash message to get a new message which sets the respective items to 0s. Then our final substitute for OP_CHECKSIGANYPREVOUT would be the following script.

final_script(eltoo_pk) = <introspect_script> <manipulate_txdata_script> <eltoo_pk> OP_CSFS

Satisfying this would require the following onto the initial witness stack.


Lastly, the eltoo script would now look like:

    10 OP_CSV
    final_script(Au) final_script(Bu)

Note how the two of two multi-sig is split into two parts.

Taproot Signature Hash:

The same technique does not work for Taproot Signature Hash algorithm(see BIP341) and Schnorr signatures (see BIP340) because of tagged hashes. At a high level, because of tags, the size of these messages is more than 520 bytes which is currently the maximum supported by bitcoin network. It is possible to overcome this limitation by adding 1)streaming SHA256 opcodes, 2) by raising the per stack element limit, Or 3) adding support for tagged hashes by new opcodes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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