[Lightning-dev] Lightning in a Taproot future

ZmnSCPxj ZmnSCPxj at protonmail.com
Sun Dec 15 15:43:07 UTC 2019

Good morning list,

I would like to initiate some discussion on how Lightning could be updated to take advantage of the upcoming taproot update to the base layer.

For now, I am assuming the continued use of the existing Poon-Dryja update mechanism.
Decker-Russell-Osuntokun requires `SIGHASH_NOINPUT`/`SIGHASH_ANYPREVOUT`, and its details seem less settled for now than taproot details.

* [ ] We could update the current Poon-Dryja mechanism to use Schnorr signatures.
* [ ] Or we could just keep the current Poon-Dryja mechanism with SegWit v0 only, and only update to Schnorr / SegWit v1 when we can implement Decker-Russell-Osuntokun.
  * This brings up the question as to whether we will allow Poon-Dryja to host pointlocked-timelocked contracts (i.e. the Scriptless Script replacement of HTLCs that uses payment points+scalars).
    * [ ] We could constrain Poon-Dryja channels to only HTLCs.
      * This might be simpler for implementations: implementations could have a completely new module that implements Decker-Russell-Osuntokun with HTLCs and PTLCs, and not touch existing modules for Poon-Dryja with HTLCs only.
      * We could "retire" Poon-Dryja constructions at some point and only add new features to Decker-Russell-Osuntokun channels.
    * [ ] We could allow hosting PTLCs as well on Poon-Dryja channels, as nothing in the base layer prevents a transaction from providing both SegWit v0 and SegWit v1 outputs anyway.

Poon-Dryja with Schnorr

If we decide to update the current Poon-Dryja mechanism to use Schnorr, there are some wrinkles:

* [ ] We could just drop-in replace the signing algorithm with Schnorr.
  * We would define a NUMS point to be used as Taproot internal key, and use a single tapscript that is simply the current script template.
  * This is arguably not really taking advantage of the Schnorr and Taproot features, however.
* [ ] Or we could use some sort of MuSig between the two channel participants.

The latter option is probably what we want to use, as it potentially allows a channel close to be indistinguishable from an ordinary SegWit v1 spend of a UTXO.
Even for channels that have been published via gossip, it moves the onus of storing historical data about historically-published channels from base layer fullnodes to nodes that want to surveill the network.

### Digression: 2-of-2 is Obviously Lightning

Existing 2-of-2 outputs have a very high probability of being Lightning Network channels.
Thus, someone who wishes to surveill the Lightning Network can simply query any archive fullnode for historical 2-of-2 outputs and have a good chance that those are Lightning Network channels.

Consider the adage: Never go to sea with two chronometers; take one or three.
This implies that ordinary HODL usage of transaction outputs will either use 1-of-1, or 2-of-3.

Offchain techniques, on the other hand, are only safe (trustless) if they are n-of-n, and are only usefully multi-participant if n > 1.
Thus any n-of-n is likely to be an offchain protocol, with the most likely being the most widespread offchain protocol, Lightning Network.

Thus, the hyperbole "2-of-2 is Obviously Lightning".

However, we can "hide" 2-of-2 in a 2-of-3, which can be done by generating a third point from a NUMS point plus a random tweak generated by both participants.
Better yet, MuSig allows hiding any n-of-n among 1-of-1; we expect 1-of-1 use to dominate in the foreseeable future, thus MuSig usage maximizes our anonymity set.

### End Digression

A potential issue with MuSig is the increased number of communication rounds needed to generate signatures.

In the current Poon-Dryja setup we have, in order to completely sign the commitment transaction held by one participant, we only require sending a completed signature from the remote participant via `commitment_signed`.
Then the local participant issues a `revoke_and_ack` to reassure the remote side that the previous commitment it held is now revoked.
Thus, the signing itself requires only 0.5 round trips.

MuSig requires three rounds to complete the signing protocol.
Since Poon-Dryja only require the complete set of signatures for any particular commitment transaction to be owned by only one participant (i.e. Poon-Dryja commitment transactions are asymmetrical), MuSig only requires 2.5 round trips to sign a Poon-Dryja commitment.

Reducing the round trips is desirable when considering latency, which affects the experienced speed of forwarding, as well as the backwards propagation of failures (but not of successful payments).
Currently, latency on the network is known to be very low, but I observe that most Lightning Network participants today have excellent Internet connectivity, which might not be true in the foreseeable future.

We can reduce the round trips to 1.5 per commitment, except for the initial commitment transaction, by sending the `R` precommitments (the first phase of MuSig) of the *next* signing session while sending the `s` for the *current* signing session.

Finally, we can consider to reduce the use of MuSig via various techniques.
One technique is the use of fast forwards: https://lists.linuxfoundation.org/pipermail/lightning-dev/2019-April/001986.html

The other involves using Taproot.
The taproot internal pubkey is the MuSig of both participants, but we also add an explicit 2-of-2 as a tapscript (or hide the 2-of-2 in a 2-of-3), i.e. `<A> OP_CHECKSIGVERIFY <B> OP_CHECKSIG` in a tapscript.
This allows commitment transactions to use the tapscript path and have separate signatures for both participants.
Then, mutual close uses the MuSig keypath spend.
This reduces the changes relative to the current Poon-Dryja implementation: we can continue to use `commitment_signed` messages (or equivalent new ones for Taproot-based Poon-Dryja channels), and only the mutual close ritual needs to be modified to use MuSig.

Thus the options are below, but ***please do not select an option yet***, because further sections greatly affect the tradeoffs of the options below.

* [ ] Latency is not an issue (even in the foreseeable future), just use the 2.5 round trips for MuSig and MuSig-sign every commitment.
* [ ] Pre-send the `R` commitments with the previous `s`.
  * This increases the needed storage requirements of both nodes, and possibly complexity of node software, but reduces the round trips to 1.5.
  * This usage may need to have larger bounds than what may be naively expected, if we decide to use Multi-`R` composable MuSig (see later section).
  * Even *without* this option, at the minimum we still need to store `R` commitments and `R`, at least in memory, until we complete the MuSig ritual.
* [ ] Use fast-forwards.
  * This removes the latency of commitment transaction signing from the forwarding and failure-reporting paths.
    * *Improved* forwarding and failure-reporting latency compared to today (revocation and signature not needed for forwarding/failure-reporting).
  * Latency is still high for commitment transaction signing, but this is less of an issue as it is no longer in the forwarding/failure-reporting path.
* [ ] Explicit 2-of-2 for commitment, MuSig for mutual close.
  * No degradation in latency compared to today (0.5 round trips for signature, additional 1 round trip for signalling and revocation).
  * No improvement (or degradation) of privacy for unilateral closes compared to today, but improved privacy for mutual closes.
    * An argument *for* this option is that unilateral closes (commitment transactions) have special scripts on their outputs anyway, thus still leak their privacy, but see later sections for how Taproot may help reduce the uniqueness of those outputs, thus *not* taking this option may still improve privacy for unilateral closes.

Composable MuSig

As I describe here: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-November/017493.html

In that write-up, I mention the use-case of nodelets.
Another use-case is for redundant hardware signers: https://lists.ozlabs.org/pipermail/c-lightning/2019-December/000172.html

We have the option of allowing for a composable MuSig, probably my multi-`R` proposal, where each participant may send one or more `R` commitments and subsequent `R`s.

* [ ] Not use composable MuSig of any kind, at least for now.
  * Possibly we could defer the use of a composable MuSig when a better composable MuSig (with security proofs) has been derived.
* [ ] Use Multi-`R` composable MuSig.
  * We need to probably impose some limit on the number of `R` commitments that can be sent: _____ `R`s maximum.

The latter option above affects the previous choice regarding whether to pre-send `R` commitments with the previous `s` sending, as this increases the maximal storage requirement for the pre-sent `R` commitment(s).

Pointlocked Timelocked Contracts

I would have preferred to keep this in a separate discussion thread, however the exact details of PTLCs may affect our decision on how to sign commitment transactions.

PTLCs are necessary to switch the Lightning Network to payment point+scalar, and indeed one can argue that the entire point of enabling Schnorr and Taproot at the base layer is to allow us to use payment point+scalar at the Lightning layer.

First, I will discuss how to create a certain kind of PTLCs, which I call "purely scriptless" PTLCs.
In particular, I would like to point out that we *actually* use in current Poon-Dryja Lightning Network channels is *revocable* HTLCs, thus we need to have *revocable* PTLCs to replace them.

* First, we must have a sender A, who is buying a secret scalar, and knows the point equivalent to that scalar.
* Second, we have a receiver B, who knows this secret scalar (or can somehow learn this secret scalar).
* A and B agree on the specifications of the PTLC: the point, the future absolute timelock, the value.
* A creates (but *does not* sign or broadcast) a transaction that pays to a MuSig of A and B and shares the txid and output number with the relevant MuSig output.
* A and B create a backout transaction.
  * This backout has an `nLockTime` equal to the agreed absolute timelock.
  * It spends the above MuSig output (this input must enable `nLockTime`, e.g. by setting `nSequence` to `0xFFFFFFFE`).
  * It creates an output that is solely controlled by A.
* A and B perform a MuSig ritual to sign the backout transaction.
* A now signs and broadcast the first transaction, the one that has an output that represents the PTLC.
* A and B wait for the above transaction to confirm deeply.
  This completes the setup phase for the PTLC.
* After this point, if the agreed-upon locktime is reached, A broadcasts the backout transaction and aborts the ritual.
* A and B create a claim transaction.
  * This has an `nLockTime` of 0, or a present or past blockheight, or disabled `nLockTime`.
  * This spends the above MuSig output.
  * This creates an output that is solely controlled by B.
* A and B generate an adaptor signature for the claim transaction, which reveals the agreed scalar.
  * This is almost entirely a MuSig ritual, except at `s` exchange, B provides `t + r + h(R | MuSig(A,B) | m) * MuSigTweak(A, B, B) * b` first, then demands `r + h(R | MuSig(A,B) | m) * MuSigTweak(A, B, A) * a` from A, then reveals `r + h(R | MuSig(A,B) | m) * MuSigTweak(A, B, B) * b` (or the completed signature, by publishing onchain), revealing the secret scalar `t` to A.
* A is able to learn the secret scalar from the above adaptor signature followed by the full signature, completing the ritual.

Note that the above ritual is "purely scriptless".
It is possible to take advantage of taproot to create a tapscript equivalent to `<agreed locktime> OP_CHECKLOCKTIMEVERIFY OP_DROP <A> OP_CHECKSIG`.
This removes the need to perform a MuSig ritual to sign a backout transaction: A can generate the backout transaction all by itself.
This use is not purely scriptless, as the timelocked branch is controlled by a tapscript that is hidden in the pointlocked branch, meaning that taking the timelocked branch reveals the contract.

The tradeoff is that if we use "purely scriptless" PTLCs:

* If we have purely scriptless PTLCs, then even the timelock branch is potentially indistinguishable from ordinary spends.
  * We should note that Bitcoin Core itself already uses the current blockheight plus 1 for `nLockTime` when spending, instead of a 0 or disabled `nLockTime`.
  * If the above habit were more widespread (i.e. if all wallets implemented the use of a current `nLockTime` for ordinary onchain spends) then the timelock branch has an anonymity set equal to all Schnorr keypath spends, as the `nLockTime` is always used anyway.
  * Other kinds of offchain protocols may also utilize this technique, slightly increasing the anonymity set as well.
    Thus, the use of the current blockheight plus 1 for `nLockTime` should be recommended for improved privacy in Bitcoin anyway.
* However, purely scriptless PTLCs require a complete MuSig ritual (2.5 to 3 round trips!) to sign the timelocked branch (the initial backout transaction); this increases the latency of adding new PTLCs.
  * Of note is that in the case of Lightning, we may need to add a new PTLC while another PTLC is *still* in-flight; on the new commitment transaction, we need to redo the MuSig rituals to create new backouts and new adaptor signtures for each PTLC.
    * This can be amortized such that we redo all the rituals for all existing PTLCs in parallel.
      * The use of multi-`R` composable MuSig greatly increases the storage requirements as well!
  * Further, the privacy gained in the timelock path is degraded or lost when we consider revocable PTLCs and revocable outputs.
  * It is not clear to me as fo now if the MuSig ritual for the backout transaction must complete in full before the MuSig ritual for the claim transaction (the pointlocked branch, which includes sharing an adaptor signature during `s` exchange).
    * If we can do these two rituals in parallel, this reduces the latency disadvantage of the purely scriptless PTLC to just 1 round trip compared to the tapscripted timelock branch PTLC.
    * Possibly the adaptor signature ritual could stop until B provides the adaptor signature, then full `s` exchange is deferred to after the PTLC 2-of-2 is instantiated onchain/reified in a commitment transaction.

Thus our options are the below, but again, you should defer deciding on the best option until you understand about revocable PTLCs.

* [ ] We can use a purely scriptless PTLC construction.
  * Better privacy, but increased latency.
* [ ] We can use a tapscripted timelock branch and a keypath pointlocked branch for the PTLC.
  * Lower latency, but possibly reduced privacy advantage in the timelock branch (privacy advantage still exists in the pointlocked branch, which we hope is more common anyway).

Revocable Outputs and PTLCs

Poon-Dryja mechanism is based on revocation of contracts instantiated from previous states.
Thus, all outputs of Poon-Dryja must be made revocable.

At a high-enough level, this only requires the addition of a `(revocation_secret && remote_secret) || (CSV && L)` to the top-level logic (`L`) of a contract.
Of course, the details have the devil.

Now, in Poon-Dryja, each side of the channel has its own commitment transaction.
Thus, contracts on the commitment transaction refer to a "local side" and a "remote side".
The "local side" is whoever is holding the completely-signed commitment transaction, while the "remote side" is the other side.

Revocable outputs always have a CSV-requirement before the output can be spent by whoever "should" own the output, according to the contract details.
The revocation secret is known by the local side, and then when a *new* commitment transaction has been signed, the revocation secret is given by the local side to the remote side, allowing all outputs to be spent directly by the remote side if an old, revoked commitment transaction is published onchain.

There are many ways to implement revocable outputs.
The core idea of revocable outputs, however, is that there must exist some relative-locktime branch on each output that goes to the local side.
This relative-locktime branch can be implemented as "purely scriptless" by using a 2-of-2 of both the local and remote sides, with a relative-locktime `nSequence`, using the same technique as described in the previous section.

However, unlike the absolute-locktime `nLockTime` for the timelock branches of PTLCs, ***there is no current wallet software that uses activated-relative-locktime `nSequence` for ordinary spends***.
Thus, any use of the relative-locktime branch does *not* have a privacy advantage under purely scriptless.

Thus the tradeoffs here are different, and definitely in favor of the tapscripted-relative-locktime technique.

* There is no current wallet software that uses relative locktimes.
  * Bitcoin Core uses absolute locktimes with the current blockheight plus 1, and we can hide the use of absolute locktimes by imitating this Bitcoin Core behavior.
  * Any use of relative locktimes is a strong signal of some kind of complicated offchain updateable mechanism.
    We can note as well that Decker-Russell-Osuntokun also uses relative locktimes.
* The relative-locktime branch in revocable outputs is the **desirable** case, because taking the relative locktime means that the commitment transaction published *was not* a revoked transaction (i.e. it was the latest transaction version).
  * Thus, it would be nice if this had good privacy.
  * However, this *cannot* have good privacy since there is no current common use of activated relative locktimes for ordinary spends.

The latter point above also biases us towards rejecting purely-scriptless in the *previous* section, in particular:

* The absolute-locktime branch in the PTLC is the **undesirable** case, where the payee B somehow stops responding to A.
  * In particular, propagating failure backwards is done by simply deleting PTLCs, thus the absolute-locktime branch does not come into play during payment failure.
  * Thus, the privacy increase of hiding absolute-locktime branches is minor, and the privacy breach of revocable outputs (i.e. it leaks the use of relative-locktime, and nearly all uses of relative locktime will be offchain updateable cryptocurrency mechanisms, such as Poon-Dryja or Decker-Russell-Osuntokun) is arguably much larger than the privacy increase of purely-scriptless absolute-locktime.

Of particular not is that if a PTLC is instantiated on the commitment transaction of the payer A, then the absolute-locktime backout transaction must *not* pay to A only, but instead pays to a *revocable output* that will eventually pay to A after the relative locktime.
Thus, the privacy boost of the purely-scriptless backout transaction would be lost by the later revelation of the use of a relative locktime after the revocable output is reclaimed by A.
Again, that use of relative locktime (whether enforced by script, or by scriptless use of a 2-of-2 that is spent with an activated relative-locktime `nSequence`) is a strong indicator of the use of Poon-Dryja or Decker-Russell-Osuntokun or even Decker-Wattenhofer mechanisms, and the logic is that since Lightning Network is the most widespread offchain mechanism, it probably indicates the use of LN.

Thus the decision in the previous section is affected by this reality that we in fact need *revocable* PTLCs, not plain PTLCs, thus the advantage of purely-scriptless backout transactions in the previous section is reduced by the need to make outputs revocable.


* Revocable outputs require a relative-timelock branch.
* That branch is the **desirable** branch, i.e. the latest commitment transaction is the one that got published and thus is *not* revoked.
  * We thus expect this relative-timelock branch to be the *common* branch.
* No wallet uses relative-timelock for ordinary spends, unlike abolute-locktime where Bitcoin Core always uses absolute-locktime `nLockTime` for ordinary spends.
  * Thus, using purely scriptless for the relative-timelock branch of revocable outputs does not in fact hide that we are doing something special.


Others may find further issues or alternative options for the above points.
Further discussion may be warranted before we actually select particular options to implement and evaluate in alpha software.


More information about the Lightning-dev mailing list