Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.mediawiki
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,20 @@ users (see also: [https://en.bitcoin.it/wiki/Economic_majority economic majority
| Salvatore Ingala
| Specification
| Draft
|-
| [[bip-0446.md|446]]
| Consensus (soft fork)
| OP_TEMPLATEHASH
| Gregory Sanders, Antoine Poinsot, Steven Roose
| Specification
| Draft
|-
| [[bip-0448.md|448]]
| Consensus (soft fork)
| Taproot-native (Re)bindable Transactions
| Gregory Sanders, Antoine Poinsot, Steven Roose
| Specification
| Draft
|}

<!-- IMPORTANT! See the instructions at the top of this page, do NOT JUST add BIPs here! -->
172 changes: 172 additions & 0 deletions bip-0446.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
```
BIP: 446
Layer: Consensus (soft fork)
Title: OP_TEMPLATEHASH
Authors: Gregory Sanders <gsanders87@gmail.com>
Antoine Poinsot <mail@antoinep.com>
Steven Roose <steven@stevenroose.org>
Status: Draft
Type: Specification
Assigned: 2026-02-06
License: CC0-1.0
```

## Abstract

This document proposes a new operation for [Tapscript][tapscript-bip]: `OP_TEMPLATEHASH`. It introduces the ability to
push on the stack a hash of the transaction spending an output.

## Motivation

`OP_TEMPLATEHASH` can be used to commit to the transaction spending an output[^commit-exact-tx]. This capability
can replace the use of pre-signed transactions in second-layer protocols. By reducing interactivity it makes such
protocols simpler, safer, and sometimes notably more efficient. For instance it can remove the need to share HTLC
signatures in the Lightning Network protocol's [`commitment_signed` message][ln-commit-signed][^ln-second-stage], make
receiving an Ark "VTXO" [non-interactive][ark-case-ctv], and [reduces roundtrips][symmetric-greg] in the implementation
of LN-Symmetry. It is also a [significant optimisation][fournier-ctv-dlcs] for [Discreet Log Contracts][optech-dlcs].

## Specification

`OP_TEMPLATEHASH` redefines `OP_SUCCESS206` (0xce) in the Tapscript execution context with further restrictions.

Upon execution of the opcode, the template hash of the transaction in context is pushed onto the stack as defined below,
and script execution continues.

The template hash uses a tagged hash as introduced by [BIP340][schnorr-bip] and [BIP341][taproot-bip]. We use a new tag
for this purpose: *TemplateHash*.

The template hash re-uses the *sha_sequences*, *sha_outputs* and *sha_annex* pre-computed transaction data introduced in
BIP341. Numerical values in 4-byte are encoded in little-endian.

The template hash is the *hash<sub>TemplateHash</sub>* of the following transaction fields concatenated:

- Transaction data:
- *nVersion* (4): the version of the transaction.
- *nLockTime* (4): the locktime of the transaction.
- *sha_sequences* (32): the SHA256 of the serialization of all input sequence, as per BIP341.
- *sha_outputs* (32): the SHA256 of the serialization of all outputs in `CTxOut` format, as per BIP341.
- Data about this input:
- *annex_present* (1): as defined in BIP341 (0 if no annex is present, or 1 otherwise).
- *input_index* (4): index of this input in the transaction input vector. Index of the first input is 0.
- If an annex is present:
- *sha_annex* (32): the SHA256 of the annex, as per BIP341.

## Rationale

The template hash follows BIP341's signature message format, with minimal necessary deviations. This reuses a
tried-and-proven approach to hashed messages, and importantly makes it possible to reuse the pre-computed subfields
introduced by BIP341 to prevent quadratic hashing. Besides the hash tags, this results in at most 109 bytes being hashed
upon execution of the operation[^hashed-msg-max-size]. This is strictly less hashing than is necessary for other
existing operations.

The specific fields from the BIP341 signature message that are ommitted when computing the template hash are the
following:
- *hash_type*: refers to the sighash type identifier in the context of BIP341 signatures. The input for `OP_TEMPLATEHASH` is fixed, so there
is no need for a mechanism to modify the hash composition.
- *spend_type*: this value is defined by BIP341 as *2\*ext_flag + annex_present*. Since no extension is appended to the
signature message, *ext_flag* is set to 0. Therefore we commit directly to *annex_present*.
- *sha_prevouts* / *sha_scriptpubkeys*: committing to these fields as is would introduce a hash cycle when the hash is
committed in the output itself. Committing to all other prevouts or scriptpubkeys would introduce hashing a quantity
of data quadratic in the number of inputs. It would also prevent spending two coins encumbered by a template hash
check in the same transaction. Finally, the flexibility of not committing to the specific coins spent is also
desirable to recover from mistakes[^no-commit-other-coins].
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn’t the commitment to all of the inputs’ sequence fields, sha_sequences, indirectly commit to the count of inputs, and therefore prevent adding another input?

(Or maybe I’m misconstruing what sha_sequences exactly is, feel free to correct me in that case.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

commit to the count of inputs, and therefore prevent adding another input?

Yes, it commits to the total number of inputs. Typically this would be 1, but you can certainly have more for batching scenarios.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but when your OP_TEMPLATEHASH commits to the spending transaction having a single input, you would not have the flexibility to add a second output to provide more funds, i.e., doesn’t that contradict your flexibility point?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's an included footnote for a (weak) example with respect to value, though it doesn't apply to prevouts per se. If the other coin gets swept, you can "contribute" a new utxo to make it whole and rescue the locked funds.

It's not the primary motivation for the design decision compared to the others.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second reading, I do see what you mean. It seems to me that this could be discussed more explicitly than such a subtle footnote.

- *sha_amounts*: the BIP341 rationale for committing to the amounts of all spent coins is to be able to prove to an offline
signer the fees of a transaction. Although `OP_TEMPLATEHASH` can be used as a building block for rebindable
signatures, the utility of committing to spent amounts but not spent scriptpubkeys [is
limited][greg-attack-input-ownership]. Still for rebindable signatures, committing to spent amounts can be justified
as defense-in-depth against implementation mistakes[^commit-spent-amounts]. However, the lack of flexibility this
introduces also makes it harder to recover from a mistake in committing to the next
transaction[^no-commit-other-coins]. Furthermore, committing to all spent amounts also makes overcommitting funds to
such a script result in the output being forever unspendable instead of the excess just going to fees at spend time.

The design of `OP_TEMPLATEHASH` was inspired by the design of [BIP119][ctv-bip] `OP_CHECKTEMPLATEVERIFY` but differs in
several important ways.

First of all, `OP_TEMPLATEHASH` is only defined for Tapscript, as modifying legacy Script comes with an unnecessarily
increased risk surface. In addition, sticking to Tapscript allows leveraging more powerful upgrade hooks (`OP_SUCCESS`s
instead of `OP_NOP`s) which make it possible to push the template hash on the stack instead of being constrained to
strict assertions with no stack modification. Pushing the template hash on the stack substantially improves the
efficiency of using `OP_TEMPLATEHASH` as a building block for rebindable signatures.

Unlike `OP_TEMPLATEHASH`, `OP_CHECKTEMPLATEVERIFY` also commits to the scriptSig of all inputs of the spending
transaction. `OP_CHECKTEMPLATEVERIFY` gives txid stability when the committed spending transaction has a single input,
and when the scriptSig of this single input has been committed by the hash.
Taproot scriptSigs must be empty and therefore under the single input case `OP_TEMPLATEHASH` has no requirement
to commit to scriptSigs to achieve txid stability.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

everytime I read through this always my biggest question is "why not commit to all script sigs being empty" or "what are the potential downsides to having multi input malleability"

would be nice to have an explanation in this to explain why this trade off is okay

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. the input is segwit, so it already explicitly commits to its own scriptSig being blank
  2. the purported benefit to committing to other scriptSigs in addition was to ensure txid stability, but without fixing the other inputs' prevout ahead of time, this cannot be achieved in general. (The "BitVM Trick" was to ensure this was actually possible, but I consider this not an intentional design decision; I'd rather the "sibling input commitment" be done properly if that's what we want!)

Given that it doesn't ensure the "next transaction" commitment we are aiming for which includes additional hashing on top of taproot hashes already existing, it was not added to the proposal.


Finally, BIP119 `OP_CHECKTEMPLATEVERIFY` does not commit to the Taproot annex (or its absence). `OP_TEMPLATEHASH` does.
Deviating from other operations which do commit to the annex would be unnecessary and surprising. Committing to the
annex also makes usage of `OP_TEMPLATEHASH` forward compatible with potential future meaning that it could be given. Not
committing to it would also prevent using `OP_TEMPLATEHASH` in conjunction with annex-based proof of publication
techniques unless additional signatures are included, as used for instance [in the LN-Symmetry demo][symmetry-annex-publication].

Programmable transaction introspection capabilities have been proposed as an alternative to a primitive which only
allows committing to the exact next transaction. It remains to be shown that these more flexible capabilities do
enable important use cases which justify each proposed change's specific semantics and implementation complexity. It
has been suggested that the new primitive should have its own upgrade hook from which to softfork in additional
consensus meaning for more flexible introspection at some future point. We have not done so due to the fact that Taproot
and Tapscript already presents plentiful upgrade hooks for the future.

## Backward compatibility

This document proposes to give meaning to a Tapscript `OP_SUCCESS` operation. The presence of an `OP_SUCCESS` in a
Tapscript would previously make it unconditionally succeed. This proposal therefore only tightens the block validation
rules: there is no block that is valid under the rules proposed in this BIP but not under the existing Bitcoin consensus
rules. As a consequence these changes are backward-compatible with non-upgraded node software. That said, the authors
strongly encourage node operators to upgrade in order to fully validate all consensus rules.

## Implementation

* https://github.com/instagibbs/bitcoin/tree/2025-07-op_templatehash

## Test Vectors

For development and testing purposes, we provide a [collection of test vectors](bip-0446/). The test
vectors are separated into two JSON files. The [first one](bip-0446/basics.json) is a short list of
simple test cases exercising the various fields of a transaction committed to when using `OP_TEMPLATEHASH`. The [second
one](bip-0446/script_assets_test.json) is a more exhaustive suite of tests exercising `OP_TEMPLATEHASH`
under a large number of different conditions. It reuses the [Bitcoin Core Taproot test framework][feature_taproot.py]
introduced with the implementation of BIP341. Format details and usage demonstration are available
[here](bip-0446/README.md).

## Acknowledgements

Credit to Jeremy Rubin for his leadership and perseverance in defending how a simple primitive which
allows committing to the entire spending transaction is useful for reducing
interactivity in second layer protocols. This BIP draws on the design of BIP119 and is
heavily inspired by his exploration of the potential uses for such a primitive.

## Copyright

This document is licensed under the Creative Commons CC0 1.0 Universal license.


[^ln-second-stage]: Second-stage HTLC transactions are currently enforced through a 2-of-2 multisig between the channel
partners. Committing to the HTLC transaction directly in the commitment transaction's HTLC output is a drop-in
replacement for the multisig, which has the advantage of not requiring Lightning nodes to transmit and store signatures
for every HTLC at every state it is still active for.
[^commit-exact-tx]: All the transaction's fields are committed to except the inputs' prevout. This means the output must
be spent by this exact transaction, although the other spent outputs may vary.
[^no-commit-other-coins]: It is possible to commit to an underfunded transaction to spend a coin. If the transaction
commits to more than one input, it is possible to recover from the mistake by creating a separate coin of an appropriate
value and spending it along with the encumbered coin. Committing to other inputs this transaction must spend or their
input removes the ability to recover from such a mistake.
[^commit-spent-amounts]: Adding commitments to the spent amounts may offer extra protection when reusing a public key
previously associate with a rebindable signature. See [BIP118's rationale][apo-bip-spent-amounts] for more about this.
[^hashed-msg-max-size]: If no annex is committed, 77 bytes are hashed: 72 bytes of transaction data + 5 bytes of data
about this input. Committing to an annex adds 32 additional bytes of data about this input, bringing the total to 109.


[schnorr-bip]: bip-0340.mediawiki
[taproot-bip]: bip-0341.mediawiki
[tapscript-bip]: bip-0342.mediawiki
[ctv-bip]: bip-0119.mediawiki
[apo-bip-spent-amounts]: https://github.com/bitcoin/bips/blob/master/bip-0118.mediawiki#cite_note-3
[ark-case-ctv]: https://delvingbitcoin.org/t/the-ark-case-for-ctv/1528
[symmetric-greg]: https://delvingbitcoin.org/t/ln-symmetry-project-recap/359
[greg-attack-input-ownership]: https://gnusha.org/pi/bitcoindev/CAB3F3Dv1kuJdu8veNUHa4b58TvWy=BT6zfxdhqEPBQ8rjDfWtA@mail.gmail.com
[symmetry-annex-publication]: https://github.com/instagibbs/bolts/blob/eltoo_draft/XX-eltoo-transactions.md#update-transaction
[ln-commit-signed]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#committing-updates-so-far-commitment_signed
[fournier-ctv-dlcs]: https://gnusha.org/pi/bitcoindev/CAH5Bsr2vxL3FWXnJTszMQj83jTVdRvvuVpimEfY7JpFCyP1AZA@mail.gmail.com
[optech-dlcs]: https://bitcoinops.org/en/topics/discreet-log-contracts
[feature_taproot.py]: https://github.com/bitcoin/bitcoin/blob/v29.0/test/functional/feature_taproot.py
32 changes: 32 additions & 0 deletions bip-0446/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# `OP_TEMPLATEHASH` test vectors

The test vectors are split into basic sanity checks and more extensive coverage. Both are JSON files containing a JSON
array of JSON objects. Each JSON object in the array represents a Script validation test case.

For [`basics.json`](basics.json), each object contains the following fields:
- `spending_tx`: a hexadecimal string representing a serialized Bitcoin transaction. This is the transaction to be
validated.
- `input_index`: a JSON integer representing the index of the transaction input for which to perform Script validation.
- `spent_outputs`: a JSON array of hexadecimal strings representing serialized Bitcoin transaction outputs. This is the
list of outputs pointed to by the inputs of the transaction to be validated.
- `valid`: a JSON boolean. Whether script validation should succeed.
- `comment`: a JSON string. Reason why script validation should succeed or fail.

For [`script_assets_test.json`](script_assets_test.json), each object contains the following fields:
- `tx`: a hexadecimal string representing a serialized Bitcoin transaction. This is the transaction to be validated.
- `index`: a JSON integer representing the index of the transaction input for which to perform Script validation.
- `prevouts`: a JSON array of hexadecimal strings representing serialized Bitcoin transaction outputs. This is the list
of outputs pointed to by the inputs of the transaction to be validated.
- `flags`: a JSON array of strings representing the script validation flags to enable for this test case.
- `success`: an optional JSON object representing the transaction input fields to set such as script validation
succeeds. The subfields are the following:
- `scriptSig`: a JSON hexadecimal string representing the serialized input script.
- `witness`: a JSON array of hexadecimal strings representing the witness stack for this input.
- `final`: an optional JSON boolean which, if true, indicates script validation should always succeed with more
validation flags than specified in `flags`.
- `failure`: an optional JSON object representing the transaction input fields to set such as script validation
fails. The subfields are the following:
- `scriptSig`: a JSON hexadecimal string representing the serialized input script.
- `witness`: a JSON array of hexadecimal strings representing the witness stack for this input.

Location of code that generated the test [`basics.json`](basics.json) [here](https://github.com/instagibbs/bitcoin/blob/2025-07-op_templatehash/src/test/script_tests.cpp#L1820). Example usage of [`script_assets_test.json`](script_assets_test.json) [here](https://github.com/bitcoin/bitcoin/blob/f490f5562d4b20857ef8d042c050763795fd43da/src/test/script_tests.cpp#L1558).
Loading