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.
https://en.wikipedia.org/wiki/Dual_modular_redundancy
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.
https://zmnscpxj.github.io/offchain/safety.html
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.
Thus:
* 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.
Conclusion
----------
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.
Regards,
ZmnSCPxj
_______________________________________________
Lightning-dev mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/lightning-dev