Skip to content

Commit

Permalink
fixup try fix mediawiki rendering without an online renderer tool
Browse files Browse the repository at this point in the history
  • Loading branch information
stevenroose committed Dec 13, 2023
1 parent 8da98a1 commit 6943941
Showing 1 changed file with 132 additions and 131 deletions.
263 changes: 132 additions & 131 deletions bip-txhash.mediawiki
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ 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.
bytes specify the TxFieldSelector.
* If the TxFieldSelector is invalid, 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.
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.
Expand All @@ -49,113 +49,114 @@ OP_TXHASH does the following:
* The element is interpreted as the TxFieldSelector and is popped off the stack.
* If the TxFieldSelector is invalid, fail.
* The 32-byte TxHash of the transaction at the current input index,
calculated using the given TxFieldSelector is pushed onto the stack.
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.

* There are two special cases for the TxFieldSelector:
- the empty value, zero bytes long: it is set equal to TXFS_SPECIAL_TEMPLATE,
the de-facto default value which means everything except the prevouts and
the prevout scriptPubkeys.
TXFS_SPECIAL_TEMPLATE is 4 bytes long, as follows:
1. TXFS_ALL
2. TXFS_INPUTS_TEMPLATE | TXFS_OUTPUTS_ALL
3. TXFS_INOUT_NUMBER | TXFS_INOUT_SELECTION_ALL
4. TXFS_INOUT_NUMBER | TXFS_INOUT_SELECTION_ALL
- the 0x00 byte: it is set equal to TXFS_SPECIAL_ALL, which means "ALL"
and is primarily useful to emulate SIGHASH_ALL when OP_TXHASH is used in
combination with OP_CHECKSIGFROMSTACK.
TXFS_SPECIAL_TEMPLATE is 4 bytes long, as follows:
1. TXFS_ALL
2. TXFS_INPUTS_ALL | TXFS_OUTPUTS_ALL
3. TXFS_INOUT_NUMBER | TXFS_INOUT_SELECTION_ALL
4. TXFS_INOUT_NUMBER | TXFS_INOUT_SELECTION_ALL
** the empty value, zero bytes long: it is set equal to TXFS_SPECIAL_TEMPLATE,
the de-facto default value which means everything except the prevouts and
the prevout scriptPubkeys.
TXFS_SPECIAL_TEMPLATE is 4 bytes long, as follows:
# TXFS_ALL
# TXFS_INPUTS_TEMPLATE | TXFS_OUTPUTS_ALL
# TXFS_INOUT_NUMBER | TXFS_INOUT_SELECTION_ALL
# TXFS_INOUT_NUMBER | TXFS_INOUT_SELECTION_ALL
** the 0x00 byte: it is set equal to TXFS_SPECIAL_ALL, which means "ALL"
and is primarily useful to emulate SIGHASH_ALL when OP_TXHASH is used in
combination with OP_CHECKSIGFROMSTACK.
TXFS_SPECIAL_TEMPLATE is 4 bytes long, as follows:
# TXFS_ALL
# TXFS_INPUTS_ALL | TXFS_OUTPUTS_ALL
# TXFS_INOUT_NUMBER | TXFS_INOUT_SELECTION_ALL
# TXFS_INOUT_NUMBER | TXFS_INOUT_SELECTION_ALL
* The first byte of the TxFieldSelector has its 8 bits assigned as follows,
from lowest to highest:
1. version (TXFS_VERSION)
2. locktime (TXFS_LOCKTIME)
3. current input index (TXFS_CURRENT_INPUT_IDX)
4. current input control block (or empty) (TXFS_CURRENT_INPUT_CONTROL_BLOCK)
5. current script last OP_CODESEPARATOR position (or 0xffffffff)
(TXFS_CURRENT_INPUT_LAST_CODESEPARATOR_POS)
6. inputs (TXFS_INPUTS)
7. outputs (TXFS_OUTPUTS)
from lowest to highest:
# version (TXFS_VERSION)
# locktime (TXFS_LOCKTIME)
# current input index (TXFS_CURRENT_INPUT_IDX)
# current input control block (or empty) (TXFS_CURRENT_INPUT_CONTROL_BLOCK)
# current script last OP_CODESEPARATOR position (or 0xffffffff) (TXFS_CURRENT_INPUT_LAST_CODESEPARATOR_POS)
# inputs (TXFS_INPUTS)
# outputs (TXFS_OUTPUTS)
* The last (highest) bit of the first byte (TXFS_CONTROL), we will call the
"control bit", and it can be used to control the behavior of the opcode. For
OP_TXHASH and OP_CHECKTXHASHVERIFY, the control bit is used to determine
whether the TxFieldSelector itself has to be included in the resulting hash.
(For potential other uses of the TxFieldSelector (like a hypothetical OP_TX),
this bit can be repurposed.)
"control bit", and it can be used to control the behavior of the opcode. For
OP_TXHASH and OP_CHECKTXHASHVERIFY, the control bit is used to determine
whether the TxFieldSelector itself has to be included in the resulting hash.
(For potential other uses of the TxFieldSelector (like a hypothetical OP_TX),
this bit can be repurposed.)

* 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 (TXFS_INPUTS_PREVOUTS)
2. sequences (TXFS_INPUTS_SEQUENCES)
3. scriptSigs (TXFS_INPUTS_SCRIPTSIGS)
4. prevout scriptPubkeys (TXFS_INPUTS_PREV_SCRIPTPUBKEYS)
5. prevout values (TXFS_INPUTS_PREV_VALUED)
6. taproot annexes (TXFS_INPUTS_TAPROOT_ANNEXES)
* Specifying which fields of the outputs will be selected:
7. scriptPubkeys (TXFS_OUTPUTS_SCRIPTPUBKEYS)
8. values (TXFS_OUTPUTS_VALUES)
bits assigning the following variables, from lowest to highest:
** Specifying which fields of the inputs will be selected:
# prevouts (TXFS_INPUTS_PREVOUTS)
# sequences (TXFS_INPUTS_SEQUENCES)
# scriptSigs (TXFS_INPUTS_SCRIPTSIGS)
# prevout scriptPubkeys (TXFS_INPUTS_PREV_SCRIPTPUBKEYS)
# prevout values (TXFS_INPUTS_PREV_VALUED)
# taproot annexes (TXFS_INPUTS_TAPROOT_ANNEXES)
** Specifying which fields of the outputs will be selected:
# scriptPubkeys (TXFS_OUTPUTS_SCRIPTPUBKEYS)
# values (TXFS_OUTPUTS_VALUES)
//TODO(stevenroose) check that the 7 and 8 render correctly

* We define as follows:
- TXFS_ALL = TXFS_VERSION | TXFS_LOCKTIME | TXFS_CURRENT_INPUT_IDX | TXFS_CURRENT_INPUT_CONTROL_BLOCK
| TXFS_CURRENT_INPUT_LAST_CODESEPARATOR_POS | TXFS_INPUTS | TXFS_OUTPUTS | TXFS_CONTROL
- TXFS_INPUTS_ALL = TXFS_INPUTS_PREVOUTS | TXFS_INPUTS_SEQUENCES | TXFS_INPUTS_SCRIPTSIGS
| TXFS_INPUTS_PREV_SCRIPTPUBKEYS | TXFS_INPUTS_PREV_VALUES | TXFS_INPUTS_TAPROOT_ANNEXES
- TXFS_INPUTS_TEMPLATE = TXFS_INPUTS_SEQUENCES | TXFS_INPUTS_SCRIPTSIGS | TXFS_INPUTS_PREV_VALUES
| TXFS_INPUTS_TAPROOT_ANNEXES
- TXFS_OUTPUTS_ALL = TXFS_OUTPUTS_SCRIPTPUBKEYS | TXFS_OUTPUTS_VALUES
** TXFS_ALL = TXFS_VERSION | TXFS_LOCKTIME | TXFS_CURRENT_INPUT_IDX | TXFS_CURRENT_INPUT_CONTROL_BLOCK
| TXFS_CURRENT_INPUT_LAST_CODESEPARATOR_POS | TXFS_INPUTS | TXFS_OUTPUTS | TXFS_CONTROL
** TXFS_INPUTS_ALL = TXFS_INPUTS_PREVOUTS | TXFS_INPUTS_SEQUENCES | TXFS_INPUTS_SCRIPTSIGS
| TXFS_INPUTS_PREV_SCRIPTPUBKEYS | TXFS_INPUTS_PREV_VALUES | TXFS_INPUTS_TAPROOT_ANNEXES
** TXFS_INPUTS_TEMPLATE = TXFS_INPUTS_SEQUENCES | TXFS_INPUTS_SCRIPTSIGS | TXFS_INPUTS_PREV_VALUES
| TXFS_INPUTS_TAPROOT_ANNEXES
** TXFS_OUTPUTS_ALL = TXFS_OUTPUTS_SCRIPTPUBKEYS | TXFS_OUTPUTS_VALUES
For both inputs and then outputs, do the following:

* If the "in/outputs" field is set to 1, another additional byte is expected:
* The highest bit (TXFS_INOUT_NUMBER) indicates whether the "number of
in-/outputs" should be committed to.
* For the remaining bits, there are three exceptional values:
- 0x00 (TXFS_INOUT_SELECTION_NONE) means "no in/outputs"
(hence only the number of them as 0x80 (TXFS_INOUT_NUMBER)).
- 0x40 (TXFS_INOUT_SELECTION_CURRENT) means "select only the in/output of
the current input index" (it is invalid when current index exceeds number
of outputs).
- 0x3f (TXFS_INOUT_SELECTION_ALL) means "select all in/outputs".
* The second highest bit (TXFS_INOUT_SELECTION_MODE) is the "specification mode":
- Set to 0 it means "leading mode".
- Set to 1 it means "individual mode".
* The third highest bit (TXFS_INOUT_SELECTION_SIZE) is used to indicate the
"index size", i.e. the number of bytes will be used to represent in/output
indices.
* In "leading mode",
- With "index size" set to 0, the remaining lowest 5 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 5 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 5 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 highest bit (TXFS_INOUT_NUMBER) indicates whether the "number of
in-/outputs" should be committed to.
** For the remaining bits, there are three exceptional values:
*** 0x00 (TXFS_INOUT_SELECTION_NONE) means "no in/outputs"
(hence only the number of them as 0x80 (TXFS_INOUT_NUMBER)).
*** 0x40 (TXFS_INOUT_SELECTION_CURRENT) means "select only the in/output of
the current input index" (it is invalid when current index exceeds number
of outputs).
*** 0x3f (TXFS_INOUT_SELECTION_ALL) means "select all in/outputs".
** The second highest bit (TXFS_INOUT_SELECTION_MODE) is the "specification mode":
*** Set to 0 it means "leading mode".
*** Set to 1 it means "individual mode".
** The third highest bit (TXFS_INOUT_SELECTION_SIZE) is used to indicate the
"index size", i.e. the number of bytes will be used to represent in/output
indices.
** In "leading mode",
*** With "index size" set to 0, the remaining lowest 5 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 5 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 5 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.

Effectively, this allows a user to select
- all in/outputs
- the current input index
- the leading in/outputs up to 8192
- up to 32 individually selected in/outputs
* all in/outputs
* the current input index
* the leading in/outputs up to 8192
* up to 32 individually selected in/outputs
The TxFieldSelector is invalid when
- a byte is expected but missing
- additional unexpected bytes are present
- index size is set to 1 while not being necessary
- a leading number of individual index is selected out of bounds of the in/outputs
- individual indices are duplicated or not in increasing order
* a byte is expected but missing
* additional unexpected bytes are present
* index size is set to 1 while not being necessary
* a leading number of individual index is selected out of bounds of the in/outputs
* individual indices are duplicated or not in increasing order
These limitations are to avoid potential TxFieldSelector malleability. It is
however allowed to use leading mode where it could be "all". This
Expand All @@ -166,33 +167,33 @@ is important to allow for optional addition of extra inputs or outputs.
===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.
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 (it
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.
If this brings the budget below zero, the script fails immediately.
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.
If this brings the budget below zero, the script fails immediately.

The following considerations should be made:
The following considerations should be made:

* All fields that can be of arbitrary size are cachable as TransactionHash
always hashes their hashed values.
* In "individual mode", a user can at most commit 32 inputs or outputs, 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.
** All fields that can be of arbitrary size are cachable as TransactionHash
always hashes their hashed values.
** In "individual mode", a user can at most commit 32 inputs or outputs, 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.


==Motivation==
Expand All @@ -204,33 +205,33 @@ 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.
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.
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 generalizes BIP-119's OP_CHECKTEMPLATEVERIFY, as the
default mode of our TxFieldSelector is effectively the same (though not
byte-for-byte identical) 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.
default mode of our TxFieldSelector is effectively the same (though not
byte-for-byte identical) 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.
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:
`<txfs> OP_TXHASH <pubkey> OP_CHECKSIGFROMSTACK` effectively emulates
SIGHASH_ANYPREVOUT.
combined with OP_CHECKSIGFROMSTACK:
`<txfs> OP_TXHASH <pubkey> OP_CHECKSIGFROMSTACK` effectively emulates
SIGHASH_ANYPREVOUT.



Expand All @@ -245,9 +246,9 @@ implementation.
==Implementation==

* A proposed implementation for Bitcoin Core is available here:
https://github.com/bitcoin/bitcoin/pull/29050
https://github.com/bitcoin/bitcoin/pull/29050
* A proposed implementation for rust-bitcoin is available here:
https://github.com/rust-bitcoin/rust-bitcoin/pull/2275
https://github.com/rust-bitcoin/rust-bitcoin/pull/2275


==Acknowledgement==
Expand Down

0 comments on commit 6943941

Please sign in to comment.