Skip to content

Commit

Permalink
Add BIP for OP_TXHASH and OP_CHECKTXHASHVERIFY
Browse files Browse the repository at this point in the history
  • Loading branch information
stevenroose committed Sep 30, 2023
1 parent e643d24 commit 5b4092a
Showing 1 changed file with 235 additions and 0 deletions.
235 changes: 235 additions & 0 deletions bip-txhash.mediawiki
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
<pre>
BIP: tbd
Layer: Consensus (soft fork)
Title: OP_TXHASH and OP_CHECKTXHASHVERIFY
Author: Steven Roose <steven@roose.io>
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-tbd
Status: Draft
Type: Standards Track
Created: 2023-09-03
License: BSD-3-Clause
</pre>

==Abstract==

This BIP proposes two new opcodes, OP_CHECKTXHASHVERIFY, to be activated
as a change to the semantics of OP_NOP4 in legacy script, segwit and tapscript;
and OP_TXHASH, to be activated as a change to the semantics of OP_SUCCESS189
in tapscript only.

These new opcodes allow for non-interactive enforcement of certain properties
of transactions spending a certain UTXO. Together with something like
OP_CHECKSIGFROMSTACK (and maybe OP_CAT) it would also enable the emulation of
arbitrarily complex sighash types. More on the use cases in the Motivation
section of this BIP.


==Summary==

OP_CHECKTXHASHVERIFY uses opcode OP_NOP4 (0xb3) as a soft fork upgrade.

OP_CHECKTXHASHVERIFY does the following:

* There is at least one element on the stack, fail otherwise.
* The element on the stack is at least 32 bytes long, fail otherwise.
* The first 32 bytes are interpreted as the TxHash and the remaining suffix
bytes specify the TxFieldSelector.
* If ValidateTxFieldSelector fails for the provided TxFieldSelector, fail.
* The actual TxHash of the transaction at the current input index, calculated
using the given TxFieldSelector must be equal to the first 32 bytes of the
element on the stack, fail otherwise.

OP_TXHASH uses tapscript opcode OP_SUCCESS189 (0xbd) as a soft fork upgrade.

OP_TXHASH does the following:

* There is at least one element on the stack, fail otherwise.
* The element is interpreted as the TxFieldSelector and is popped off the stack.
* If ValidateTxFieldSelector fails for the provided TxFieldSelector, fail.
* The 32-byte TxHash of the transaction at the current input index,
calculated using the given TxFieldSelector is pushed onto the stack.

The TxFieldSelector has the following semantics. We will give a brief conceptual
summary, followed by a reference implementation of the CalculateTxHash function.

* If the TxFieldSelector is zero bytes long, it is set equal to
0xff|0xf6|0x3f|0x3f, the de-facto default value which means everything except
the prevouts and the prevout scriptPubkeys.
* The first byte of the TxFieldSelector has its 8 bits assigned as follows,
from lowest to highest:
1. version
2. locktime
3. nb_inputs
4. nb_outputs
5. current input index
6. current input control block (only in case of tapscript spend)
7. inputs
8. outputs
* If either "inputs" or "outputs" is set to 1, expect another byte with its 8
bits assigning the following variables, from lowest to highest:
* Specifying which fields of the inputs will be selected:
1. prevouts
2. sequences
3. scriptSigs
4. prevout scriptPubkeys
5. prevout values
6. taproot annexes (only in case of tapscript spend)
* Specifying which fields of the outputs will be selected:
7. scriptPubkeys
8. values
For both inputs and then outputs, do the following:

* If the "in/outputs" field is set to 1, another additional byte is expected:
* There are two exceptional values:
- 0x00 means "select only the in/output of the current input index".
- 0x3f means "select all in/outputs". //TODO(stevenroose) make this 0xff?
* The highest bit is the "specification mode":
- Set to 0 it means "prefix mode".
- Set to 1 it means "individual mode".
* The second highest bit is used to indicate the "index size", i.e. the number
of bytes will be used to represent in/output indices.
* In "prefix mode",
- With "index size" set to 0, the remaining lowest 6 bits of the first byte
will be interpreted as the number of leading in/outputs to select.
- With "index size" set to 1, the remaining lowest 6 bits of the first byte
together with the 8 bits of the next byte will be interpreted as the
number of leading in/outputs to select.
* In "individual mode", the remaining lowest 6 bits of the first byte will be
interpreted as `n`, the number of individual in/outputs to select.
- With "index size" set to 0, interpret the following `n` individual bytes
as the indices of an individual in/outputs to select.
- With "index size" set to 1, interpret the next `n` pairs of two bytes as
the indices of individual in/outputs to select.

The function ValidateTxFieldSelector has the following semantics, it
effectively checks that the TxFieldSelector value is valid according to
above rules:

* If there are 0 bytes, it becomes the default of 0xff|0xf6|0xff|0xff; succeed.
* If the first byte is exactly 0x00, the Script execution succeeds immediately.
//TODO(stevenroose) is this valuable? it's the only "exception case" that
could potentially be hooked for some future upgrade
* If in the first byte, "inputs" and "outputs" is 0, no additional bytes can be
present, otherwise fail.
* If the "inputs" bit is set to 1, one of the lowest 6 bits in the second byte
must be set to 1, otherwise fail.
* If the "outputs" bit is set to 1, one of the highest 2 bits in the second byte
must be set to 1, otherwise fail.
* If in the first byte, "inputs" or "outputs" is 1, do the following, once for
each:
* Expect an additional byte.
* If this byte is either 0x00 or 0x3f, no additional bytes are expected for
this section.
* Interpret the top 2 bits of this byte as per above, setting the
"specification" mode and "index size".
* In "prefix mode":
* with "index size" 0, no additional bytes are expected, otherwise fail;
* with "index size" 1, one additional byte are expected, otherwise fail.
* In "individual mode", interpret the lowest 6 bits of this byte as integer n,
so that
* with "index size" 0, n additional bytes are expected, otherwise fail;
* with "index size" 1, two times n additional bytes are expected, otherwise
fail.
* If any additional bytes are present after this, fail.

The recommended standardness rules additionally:

* Reject non-empty pushes starting with the 0 byte preceding OP_TXHASH as
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS.

===Resource limits===

* For legacy scripts and segwit, we don't add any extra resource limitations,
with the argumentation that OP_CHECKTXHASHVERIFY already requires the user to
provide at least 32 bytes of extra transaction size, either in the input
scriptSig, or the witness. Additional more complex hashes require additional
witness bytes. Given that OP_CAT is not available in this context, if a
malicious user tries to increase the number of TransactionHashes being
calculated by using opcodes like OP_DUP, the TxFieldSelector for all these
calculations is identical, so the calculation can be cached within the same
transaction.
* For tapscript, primarily motivated by the cheaper opcode OP_TXHASH (that
doesn't require an additional 32 witness bytes be provided) and the potential
future addition of byte manipulation opcodes like OP_CAT, an additional cost
is specified per TransactionHash execution.
Using the same validation budget ("sigops budget") introduced in BIP-0342,
each TransactionHash decreases the validation budget by 10.
The following considerations should be made:
* In "individual mode", a user can at most hash 64 items together, which we
don't consider excessive for potential repeated use.
* In "prefix mode", a caching strategy can be used where the SHA256 context is
stored every N in/outputs so that multiple executions of the TransactionHash
function can use the caches and only have to hash an additional N-1 items at
most.
If either budget requriement brings the budget below zero, the script fails
immediately.

==Motivation==

This BIP specifies a basic transaction introspection primitive that is useful
to either reduce interactivity in multi-user protocols or to enforce some basic
constraints on transactions.

Additionally, the constructions specified in this BIP can lay the groundwork for
some potential future upgrades:
* The TxFieldSelector construction would work well with a hypothetical opcode
OP_TX that allows for directly introspecting the transaction by putting the
fields selected on the stack instead of hashing them together.
* The TransactionHash obtained by OP_TXHASH can be combined with a hypothetical
opcode OP_CHECKSIGFROMSTACK to effectively create an incredibly flexible
signature hash, which would enable constructions like SIGHASH_ANYPREVOUT.
===Comparing with some alternative proposals===

* This proposal strictly supercedes BIP-119's OP_CHECKTEMPLATEVERIFY, as the
default mode of our TxFieldSelector is effectively (though not byte-for-byte
identical) the same as what OP_CTV acomplishes, without costing any additional
bytes. Additionally, using OP_CHECKTXHASHVERIFY allows for more flexibility
which can help in the case for
* enabling adding fees to a transaction without breaking a multi-tx protocol;
* multi-user protocols where users are only concerned about their own inputs
and outputs.
* Constructions like OP_IN_OUT_VALUE used with OP_EQUALVERIFY can be emulated by
two OP_TXHASH instances by using the TxFieldSelector to select a single input
value first and a single output value second and enforcing equality on the
hashes. Neither of these alternatives can be used to enforce small value
differencials without the use of 64-bit arithmetic.
* Like mentioned above, SIGHASH_ANYPREVOUT can be emulated using OP_TXHASH when
combined with OP_CHECKSIGFROMSTACK and OP_CAT.
`OP_DUP OP_TXHASH OP_CAT <"some_tag"> OP_SWAP OP_SHA256 <pubkey>
OP_CHECKSIGFROMSTACK` effectively emulates SIGHASH_ANYPREVOUT.



==Detailed Specification==

<source lang="rust">
wip
</source>




==Acknowledgement==

Credit for this proposal mostly goes to Jeremy Rubin for his work on BIP-119's
OP_CHECKTEMPLATEVERIFY and to Russell O'Connor for the original idea of
OP_TXHASH.

Additional thanks to Andrew Poelstra, Rearden Code, Rusty Russell and
others for their feedback on the specification.

0 comments on commit 5b4092a

Please sign in to comment.