Introduction

With the Taproot soft fork scheduled to be activated before the end of 2021, now is the time to look at other BIPs that have been waiting on it’s activation. One in particular that was discussed during the review of Taproot is a new set of sighash flags described by BIP-118 known as SIGHASH_ANYPREVOUT (APO) and SIGHASH_ANYPREVOUTANYSCRIPT (APOAS) - previously known as SIGHASH_NOINPUT. This soft fork enables a powerful new mechanism for replacing presigned transactions in off-chain protocols. The eltoo protocol in particular describes a protocol for the Lightning network that relies on APO and APOAS.

I summarize below the basic mechanisms and motivations of anyprevout and eltoo and describe my tests of the Bitcoin transactions needed for the eltoo protocol and how to run them. These tests use a fork of Bitcoin with an initial implementation of BIP-118.

The target audience for this write-up is anyone who wants to understand BIP-118 and eltoo better at the transaction and script level. You should also be capable of building Bitcoin Core from source and understand Python scripts. Following the steps below you will be able to see eltoo transactions confirmed on a local regtest network as a concrete example of both how eltoo and BIP-118 works. My hope is that this will allow both proposals to be better understood and increase the number of people capable of reviewing and offering suggestions. We need more people to run these tests, and create their own tests, to help find problems and improvements before BIP-118 can be adopted by the Bitcoin network and eltoo by the Lightning network

Anyprevout

BIP-118 proposes a soft fork that allows transactions to not just spend a specific previous transaction output, but instead any transactions output that uses the same signing key, in the case of SIGHASH_ANYPREVOUTANYSCRIPT, or that spends the same amount and uses the exact same script in the case of SIGHASH_ANYPREVOUT. Use of these two sighashes are enabled only for taproot script path spends of taproot transactions that reference a public key prepended with a new public key type. Some key features of BIP-118 are summarized below.

Taproot Internal Key

To spend an output using a signature signed with APO or APOAS the tapscript must include a 32-byte schnorr public key prepended with the new ANYPREVOUT public key type or alternately the single public key type byte without a schnorr public key. If only the key type byte is used, then it will be substituted with the taproot internal public key. This removes the largest piece of data from the tapscript for the most common spending condition and yields a significant transaction fee saving.

Transaction Hash

The core changes of BIP-118 are to how transaction hashes are generated in the SignatureHashSchnorr method of bitcoin/src/interpreter.cpp . This table summarizes which fields are hashed differently for the two new sighashes:

| | ANYPREVOUT (APO) | ANYPREVOUTANYSCRIPT (APOAS) | | — |:—:|:—:| | Prevout | Excluded | Excluded | | Amount | Included | Excluded | | ScriptPubkey | Included | Excluded | | Sequence | Included | Included | | Tapleaf Hash | Included | Excluded |

Sighash Anyonecanpay

If either sighash APO or APOAS are used, then the signature behaves as if SIGHASH_ANYONECANPAY was used because additional inputs can be added to the transaction without invalidating the signature used for the input signed with these new sighashes.

Sighash Single or All

Sighash APO or APOAS must be combined with either SIGHASH_SINGLE or ALL to indicate whether the signature commits to only a single output at the same index as the input, or all outputs in the transaction.

Prevout

Both APO and APOAS ignore the prevout field of the output being spent. This enables the creation of pre-signed transactions that do not spend only a specific transaction that has already been confirmed on the blockchain.

Amount

A transaction signed with APO, but not APOAS, commits to the specific amount of the output being spent. This creates a way to restrict which outputs can be spent from when the APO sighash is used. An input signed with APOAS has more flexibility to allow protocols that “consolidate a group of UTXOs with the same spending condition into a single UTXO” (see BIP-118 ref 3 and also enables the Layered Commitments protocol.

ScriptPubkey

Only an input signed with APO commits to the exact script of the output being spent. An input signed with APOAS can spend any input that has matching spending conditions, even if the hash of the exact script is not the same. For example, the script for an eltoo state update transaction includes the number of the state. This means that the hash of the script will be different for each state. Spending conditions, such as the key used to sign, can be used to constrain which output can be spent when APOAS is used to create the signature.

Sequence

Both APO and APOAS commit to the sequence number of the specific input being spent. This allows a way to restrict which transactions can be spent when these sighashes are used.

Tapleaf Hash

APOAS does not commit to the root script of a transaction, defined by the ScriptPubkey of the output it spends, or the leaf script defined by the tapleaf hash of the spending transaction. APO does commit to a specific leaf script so must commit to a matching tapleaf hash.

Unchanged Fields

These fields are committed to in the same way both with or without BIP-118:

  • hash type: bit field used to sign, eg. SIGHASH_ANYPREVOUT SIGHASH_ALL
  • version: of the spending transaction
  • locktime: of the spending transaction
  • spend type: bit field that indicates key vs. script spend and whether an annex is present
  • annex hash: hash of the annex, but only if an annex is present for the transaction
  • key type: indicates the transaction is signed with a normal Taproot, Anyprevout or undefined key type.
  • outputs hash: a hash of either all (SIGHASH_ALL) outputs in the spending transaction or just the output at the same index as the input of the spending transaction being signed (SIGHASH_SINGLE).
  • code separator position: included for all script path spends

See anyprevout.xyz for more discussion about the advantages and other uses of BIP-118.

Eltoo

The eltoo channel update protocol uses floating transactions that can spend from any older channel state, but not a newer one, using the anyprevout sighash. The eltoo protocol has three primary improvements over the current channel update mechanism used by Lightning:

  1. no penalty for publishing an old channel state
  2. no need to store old state information
  3. compatible with channel factories (aka multiparty channels)

It may also be possible to reduce the need to preselect transaction fees for uncooperative close transactions.

I have based my tests on the taproot eltoo sketch from AJ Towns, but without chaperone signatures (ie. the ‘X CHECKSIGVERIFY’ in his sketch).

Overview

The Taproot eltoo scripts and transactions are pre-signed but not broadcast to the network except in the case of a non-cooperative close of the channel. Everytime the payment channel is updated, two new transactions are generated and pre-signed by both parties: one to immediately update the state of the channel and another to settle the value after a delay that gives time for a newer state to override it. When an update transaction is confirmed by the Bitcoin network, it can be spent, and effectively replaced, by a newer update, but not an older one, within a window of time after it was broadcast. After the relative timelock of an update transaction has expired, the corresponding settlement transaction can then spend its value and create outputs for settled value spendable by each of the two parties and inflight value as HTLC outputs that can be claimed by one party if they have a hash preimage, or refunded to the other after a timeout.

An update transaction uses the APOAS sighash to allow it to spend from any previous update transaction. A settlement transaction uses the APO sighash to bind it to a specific update transaction based on its script, which contains the state number, but not a specific transaction because the update transaction’s id can not be known when signing. A transaction to claim or refund an HTLC and collect the settled value only requires one party to sign so these can be signed after the settlement transaction has been confirmed in a block and does not need the APO or APOAS sighash.

APO, APOAS eltoo transaction diagram

Scripts

Scripts for the update, settle, claim and refund transactions are described below. The update transaction is used to immediately spend an earlier update transaction with a lower state number. The settle transaction spends from a corresponding update transaction after a relative timelock has expired. A claim transaction immediately spends from the HTLC output of a specific settle transaction if presented with the correct hash preimage. A refund transaction can spend from the HTLC output of a specific settle transaction after a certain absolute clock time.

Update

The first two lines of this script check that the corresponding transaction has been signed by a Schnorr key used as the Taproot internal key. This internal key should be a 2 of 2 multisig (eg. using MuSig2) key and the signature should be generated by both channel parties. In these tests though we use a Schnorr key and signatures generated in the standard way for simplicity. OP_1 is used for a single byte anyprevout key that is replaced by the internal Taproot public key. The ctlv_start_time + state value represents the state number of the channel and is increased every time the channel is updated. As per BIP-65, OP_CHECKLOCKTIMEVERIFY fails if the spending transaction has a nLocktime field with a value from an older state.

OP_1	 
OP_CHECKSIGVERIFY
<cltv_start_time + state>
OP_CHECKLOCKTIMEVERIFY

Note that OP_CHECKLOCKTIMEVERIFY leaves the state constant on the stack, but because it is the last opcode there is no need to add an OP_DROP.

Settle

The first two lines of this script check that the corresponding transaction has been signed by both parties in the same way as the update script. The csv_delay constant represents a relative block delay before which this transaction will not be valid. As per BIP-112, OP_CHECKSEQUENCEVERIFY fails if the spending transaction has an nSequence field value not greater than the csv_delay and so can only be included in a block after that delay.

OP_1
OP_CHECKSIGVERIFY
<csv_delay>
OP_CHECKSEQUENCEVERIFY

Note that OP_CHECKSEQUENCEVERIFY leaves the delay constant on the stack, but because it is the last opcode there is no need to add an OP_DROP.

Claim

The input to this script is both a signature and a preimage value that when hashed matches the preimage_hash value encoded in the script. The OP_EQUALVERIFY opcode fails if they do not match. The pubkey constant is provided by the payee of the HTLC to ensure they can generate the signature to claim the HTLC output immediately if they learn the preimage by forwarding the payment successfully.

OP_HASH160
<preimage_hash>
OP_EQUALVERIFY
<pubkey>
OP_CHECKSIG

Refund

The pubkey constant is provided by the payer of the HTLC to ensure only they can generate the signature to claim the HTLC output if the payer has not forwarded the payment successfully. The expiry constant defines the time after which the payer can reclaim the HTLC balance. The OP_CHECKLOCKTIMEVERIFY opcode fails if the nLocktime value of the spending transaction does not exceed the expiry constant. The transaction can not be mined into a block until the median time past of the last 10 blocks exceeds the nLocktime of the transaction as per BIP-65 and BIP-113.

<pubkey>
OP_CHECKSIGVERIFY
<expiry>
OP_CHECKLOCKTIMEVERIFY

Transactions

Update

An Update transaction to a new state the transaction has the following field settings:

  nLocktime: <cltv_start_time + state>
  nVersion = 2
  Input nSequence: 0
  Output scriptPubkey: <state_address>

The nLocktime value is checked by the script and state_address is a Taproot address that encodes the Update script for a specific state and the Settle script with the constant expiry delay.

Only a signature must be provided to spend an Update transaction to the output of a newer Update transaction.

Settle

Claim

Refund

Taproot

Tests

Challenges

Future

Simulation

PTLCs

Layered Commitments

Channel Factories

Musig

Other applications of APO

Summary