Skip to content

Commit 71073ff

Browse files
committed
Add BIP for OP_TXHASH and OP_CHECKTXHASHVERIFY
1 parent e918b50 commit 71073ff

File tree

4 files changed

+2430
-0
lines changed

4 files changed

+2430
-0
lines changed

bip-txhash.mediawiki

+230
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
<pre>
2+
BIP: tbd
3+
Layer: Consensus (soft fork)
4+
Title: OP_TXHASH and OP_CHECKTXHASHVERIFY
5+
Author: Steven Roose <[email protected]>
6+
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-tbd
7+
Status: Draft
8+
Type: Standards Track
9+
Created: 2023-09-03
10+
License: BSD-3-Clause
11+
</pre>
12+
13+
==Abstract==
14+
15+
This BIP proposes two new opcodes, OP_CHECKTXHASHVERIFY, to be activated
16+
as a change to the semantics of OP_NOP4 in legacy script, segwit and tapscript;
17+
and OP_TXHASH, to be activated as a change to the semantics of OP_SUCCESS189
18+
in tapscript only.
19+
20+
These opcodes provide a generalized method for introspecting certain details of
21+
the spending transaction, which enables non-interactive enforcement of certain
22+
properties of the transaction spending a certain UTXO.
23+
24+
The constructions specified in this BIP also open up the way for other
25+
potential updates; see Motivation section for more details.
26+
27+
28+
==Summary==
29+
30+
OP_CHECKTXHASHVERIFY uses opcode OP_NOP4 (0xb3) as a soft fork upgrade.
31+
32+
OP_CHECKTXHASHVERIFY does the following:
33+
34+
* There is at least one element on the stack, fail otherwise.
35+
* The element on the stack is at least 32 bytes long, fail otherwise.
36+
* The first 32 bytes are interpreted as the TxHash and the remaining suffix
37+
bytes specify the TxFieldSelector.
38+
* If the TxFieldSelector is invalid, fail.
39+
* The actual TxHash of the transaction at the current input index, calculated
40+
using the given TxFieldSelector must be equal to the first 32 bytes of the
41+
element on the stack, fail otherwise.
42+
43+
44+
OP_TXHASH uses tapscript opcode OP_SUCCESS189 (0xbd) as a soft fork upgrade.
45+
46+
OP_TXHASH does the following:
47+
48+
* There is at least one element on the stack, fail otherwise.
49+
* The element is interpreted as the TxFieldSelector and is popped off the stack.
50+
* If the TxFieldSelector is invalid, fail.
51+
* The 32-byte TxHash of the transaction at the current input index,
52+
calculated using the given TxFieldSelector is pushed onto the stack.
53+
54+
55+
The TxFieldSelector has the following semantics. We will give a brief conceptual
56+
summary, followed by a reference implementation of the CalculateTxHash function.
57+
58+
* There are two special cases for the TxFieldSelector:
59+
- the empty value, zero bytes long: it is set equal to 0xff|0xf6|0xbf|0xbf,
60+
the de-facto default value which means everything except the prevouts and
61+
the prevout scriptPubkeys.
62+
- the 0x00 byte: it is set equal to 0xff|0xff|0xbf|0xbf, which means "ALL"
63+
and is primarily useful to emulate SIGHASH_ALL when OP_TXHASH is used in
64+
combination with OP_CHECKSIGFROMSTACK.
65+
66+
* The first byte of the TxFieldSelector has its 8 bits assigned as follows,
67+
from lowest to highest:
68+
1. version
69+
2. locktime
70+
3. current input index
71+
4. current input control block (or empty)
72+
5. current script last OP_CODESEPARATOR position (or 0xffffffff)
73+
6. inputs
74+
7. outputs
75+
76+
* The last (highest) bit of the first byte, we will call the "control bit", and
77+
it can be used to control the behavior of the opcode. For OP_TXHASH and
78+
OP_CHECKTXHASHVERIFY, the control bit is used to determine whether the
79+
TxFieldSelector itself has to be included in the resulting hash. (For
80+
potential other uses of the TxFieldSelector (like a hypothetical OP_TX), this
81+
bit can be repurposed.)
82+
83+
* If either "inputs" or "outputs" is set to 1, expect another byte with its 8
84+
bits assigning the following variables, from lowest to highest:
85+
* Specifying which fields of the inputs will be selected:
86+
1. prevouts
87+
2. sequences
88+
3. scriptSigs
89+
4. prevout scriptPubkeys
90+
5. prevout values
91+
6. taproot annexes
92+
* Specifying which fields of the outputs will be selected:
93+
7. scriptPubkeys
94+
8. values
95+
96+
For both inputs and then outputs, do the following:
97+
98+
* If the "in/outputs" field is set to 1, another additional byte is expected:
99+
* The highest bit indicates whether the "number of in-/outputs" should be
100+
committed to.
101+
* For the remaining bits, there are three exceptional values:
102+
- 0x00 means "no in/outputs" (hence only the number of them as 0x80).
103+
- 0x40 means "select only the in/output of the current input index"
104+
(it is invalid when current index exceeds number of outputs).
105+
- 0x3f means "select all in/outputs".
106+
* The second highest bit is the "specification mode":
107+
- Set to 0 it means "leading mode".
108+
- Set to 1 it means "individual mode".
109+
* The third highest bit is used to indicate the "index size", i.e. the number
110+
of bytes will be used to represent in/output indices.
111+
* In "leading mode",
112+
- With "index size" set to 0, the remaining lowest 5 bits of the first byte
113+
will be interpreted as the number of leading in/outputs to select.
114+
- With "index size" set to 1, the remaining lowest 5 bits of the first byte
115+
together with the 8 bits of the next byte will be interpreted as the
116+
number of leading in/outputs to select.
117+
* In "individual mode", the remaining lowest 5 bits of the first byte will be
118+
interpreted as `n`, the number of individual in/outputs to select.
119+
- With "index size" set to 0, interpret the following `n` individual bytes
120+
as the indices of an individual in/outputs to select.
121+
- With "index size" set to 1, interpret the next `n` pairs of two bytes as
122+
the indices of individual in/outputs to select.
123+
124+
Effectively, this allows a user to select
125+
- all in/outputs
126+
- the current input index
127+
- the leading in/outputs up to 8192
128+
- up to 32 individually selected in/outputs
129+
130+
The TxFieldSelector is invalid when
131+
- a byte is expected but missing
132+
- additional unexpected bytes are present
133+
- index size is set to 1 while not being necessary
134+
- a leading number of individual index is selected out of bounds of the in/outputs
135+
- individual indices are duplicated or not in increasing order
136+
137+
These limitations are to avoid potential TxFieldSelector malleability. It is
138+
however allowed to use leading mode where it could be "all". This
139+
is important to allow for optional addition of extra inputs or outputs.
140+
//TODO(stevenroose) should we disallow individual that could be leading?
141+
142+
143+
===Resource limits===
144+
145+
* For legacy scripts and segwit, we don't add any extra resource limitations,
146+
with the argumentation that OP_CHECKTXHASHVERIFY already requires the user to
147+
provide at least 32 bytes of extra transaction size, either in the input
148+
scriptSig, or the witness. Additional more complex hashes require additional
149+
witness bytes. Given that OP_CAT is not available in this context, if a
150+
malicious user tries to increase the number of TransactionHashes being
151+
calculated by using opcodes like OP_DUP, the TxFieldSelector for all these
152+
calculations is identical, so the calculation can be cached within the same
153+
transaction.
154+
155+
* For tapscript, primarily motivated by the cheaper opcode OP_TXHASH (it
156+
doesn't require an additional 32 witness bytes be provided) and the potential
157+
future addition of byte manipulation opcodes like OP_CAT, an additional cost
158+
is specified per TransactionHash execution.
159+
Using the same validation budget ("sigops budget") introduced in BIP-0342,
160+
each TransactionHash decreases the validation budget by 10.
161+
If this brings the budget below zero, the script fails immediately.
162+
163+
The following considerations should be made:
164+
165+
* All fields that can be of arbitrary size are cachable as TransactionHash
166+
always hashes their hashed values.
167+
* In "individual mode", a user can at most commit 32 inputs or outputs, which we
168+
don't consider excessive for potential repeated use.
169+
* In "prefix mode", a caching strategy can be used where the SHA256 context is
170+
stored every N in/outputs so that multiple executions of the TransactionHash
171+
function can use the caches and only have to hash an additional N-1 items at
172+
most.
173+
174+
175+
==Motivation==
176+
177+
This BIP specifies a basic transaction introspection primitive that is useful
178+
to either reduce interactivity in multi-user protocols or to enforce some basic
179+
constraints on transactions.
180+
181+
Additionally, the constructions specified in this BIP can lay the groundwork for
182+
some potential future upgrades:
183+
* The TxFieldSelector construction would work well with a hypothetical opcode
184+
OP_TX that allows for directly introspecting the transaction by putting the
185+
fields selected on the stack instead of hashing them together.
186+
* The TransactionHash obtained by OP_TXHASH can be combined with a hypothetical
187+
opcode OP_CHECKSIGFROMSTACK to effectively create an incredibly flexible
188+
signature hash, which would enable constructions like SIGHASH_ANYPREVOUT.
189+
190+
===Comparing with some alternative proposals===
191+
192+
* This proposal strictly generalizes BIP-119's OP_CHECKTEMPLATEVERIFY, as the
193+
default mode of our TxFieldSelector is effectively the same (though not
194+
byte-for-byte identical) as what OP_CTV acomplishes, without costing any
195+
additional bytes. Additionally, using OP_CHECKTXHASHVERIFY allows for more
196+
flexibility which can help in the case for
197+
* enabling adding fees to a transaction without breaking a multi-tx protocol;
198+
* multi-user protocols where users are only concerned about their own inputs
199+
and outputs.
200+
201+
* Constructions like OP_IN_OUT_VALUE used with OP_EQUALVERIFY can be emulated by
202+
two OP_TXHASH instances by using the TxFieldSelector to select a single input
203+
value first and a single output value second and enforcing equality on the
204+
hashes. Neither of these alternatives can be used to enforce small value
205+
differencials without the use of 64-bit arithmetic.
206+
207+
* Like mentioned above, SIGHASH_ANYPREVOUT can be emulated using OP_TXHASH when
208+
combined with OP_CHECKSIGFROMSTACK:
209+
`<txfs> OP_TXHASH <pubkey> OP_CHECKSIGFROMSTACK` effectively emulates
210+
SIGHASH_ANYPREVOUT.
211+
212+
213+
214+
215+
==Detailed Specification==
216+
217+
A reference implementation in Rust is provided attached as part of this BIP
218+
together with a JSON file of test vectors generated using the reference
219+
implementation.
220+
221+
222+
==Acknowledgement==
223+
224+
Credit for this proposal mostly goes to Jeremy Rubin for his work on BIP-119's
225+
OP_CHECKTEMPLATEVERIFY and to Russell O'Connor for the original idea of
226+
generalizing CTV into OP_TXHASH.
227+
228+
Additional thanks to Andrew Poelstra, Greg Sanders, Rearden Code, Rusty Russell
229+
and others for their feedback on the specification.
230+

bip-txhash/ref-impl/Cargo.toml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "txhash-ref"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
bitcoin = { version = "0.31.0", features = [ "serde" ] }
10+
serde_json = "1.0.108"
11+
12+
[patch.crates-io]
13+
bitcoin = { path = "/home/steven/code/rust/bitcoin/bitcoin" }
14+
bitcoin-io = { path = "/home/steven/code/rust/bitcoin/io" }

0 commit comments

Comments
 (0)