[Lightning-dev] Eltoo, anyprevout and chaperone signatures

Anthony Towns aj at erisian.com.au
Thu May 16 15:37:48 UTC 2019


On Thu, May 16, 2019 at 09:55:57AM +0200, Bastien TEINTURIER wrote:
> Thanks for your answers and links, the previous discussions probably happened
> before I joined this list so I'll go dig into the archive ;)

The discussion was on a different list anyway, I think, this might be
the middle of the thread:

https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-March/016777.html

> > Specifically we can't make make use of the collaborative path where
> > we override an `update_tx` with a newer one in taproot as far as I can
> > see, since the `update_tx` needs to be signed with noinput (for
> > rebindability) but there is no way for us to specify the chaperone key
> > since we're not revealing the committed script.
> Can you expand on that? Why do we need to "make use of the collaborative path"
> (maybe it's unclear to me what you mean by collaborative path here)?

I think Christian means the "key path" per the terminology in the
taproot bip. That's the path that just provides a signature, rather than
providing an internal key, a script, and signatures etc for the script.

> I feel like there will be a few other optimizations that are unlocked by
> taproot/tapscript, it will be interesting to dig into that.

I had a go at drafting up scripts, and passed them around privately to
some of the people on this list already. They're more "thought bubble"
than even "draft" yet, but for the sake of discussion:

---
FWIW, the eltoo scripts I'm imaginging with this spec are roughly:

UPDATE TX n:
  nlocktime: 500e6+n
  nsequence: 0
  output 0:
    P = muSig(A,B)
    scripts = [
      "OP_1 CHECKSIGVERIFY X CHECKSIGVERIFY 500e6+n+1 CLTV"
    ]
 witness:
    sig(P,hash_type=SINGLE|ANYPREVOUTANYSCRIPT=0xc3)
    sig(X,hash_type=0)

SETTLEMENT TX n:
  nlocktime: 500e6+n+1
  nsequence: [delay]
  output 0: A
  output 1: B
  output n: (HTLC)
    P = muSig(A,B)
    scripts = [
      "OP_1 CHECKSIGVERIFY X CHECKSIG"
      "A CHECKSIGVERIFY <t> CLTV"
    ]
  witness:
    sig(P,hash_type=ALL|ANYPREVOUT=0x41)
    sig(X,hash_type=0)

HTLC CLAIM (reveal secp256k1 preimage R):
  witness:
    hash-of-alternative-script
    sig(P,hash_type=SINGLE|ANYPREVOUT,reveal R)
    sig(X,hash_type=0)

HTLC REFUND (timeout):
  witness:
    hash-of-alternative-script
    sig(A,hash_type=ALL)

Because "n" changes for each UPDATE tx, each ANYPREVOUT signature
(for the SETTLEMENT tx) commits to a specific UPDATE tx via both the
scriptPubKey commitment and the tapleaf_hash commitment.

So the witness data for both txs involve revealing:

    33 byte control block
    43 byte redeem script
    65 byte anyprevout sig
    64 byte sighash all sig

Compared to a 65 byte key path spend (if ANYPREVOUT worked for key paths),
that's an extra 143 WU or 35.75 vbytes, so about 217% more expensive. The
update tx script proposed in eltoo.pdf is (roughly):

"IF 2 Asi Bsi ELSE <500e6+n+1> CLTV DROP 2 Au Bu ENDIF 2 OP_CHECKMULTISIG"

    148 byte redeem script
    65 byte anyprevout sig by them
    64 byte sighash all sig by us
    "1" or "0" to control the IF

which I think would be about 282 WU total, or an extra 216 WU/54 vbytes
over a 65 byte key path spend, so about 327% more expensive. So at least
we're a lot better than where we were with BIP 118, ECDSA and p2wsh.

Depending on if you can afford generating a bunch more signatures you
could also have a SIGHASH_ALL key path spend for the common unilateral
case where only a single UPDATE TX is published.

UPDATE TX n (alt):
  input: FUNDING TX
  witness: sig(P,hash_type=0)
  output 0:
    P = muSig(A,B)
    scripts = [
      "OP_1 CHECKSIGVERIFY X CHECKSIGVERIFY 500e6+n+1 CLTV"
    ]

SETTLEMENT TX n (alt):
  nsequence: [delay]
  input: UPDATE TX n (alt)
  witness: sig(P+H(P||scripts)*G,hash_type=0)
  outputs: [as above]

(This approach can either use the same ANYPREVOUT sigs for the HTLC
claims, or could include an additional sig for each active HTLC for each
channel update to allow HTLC claims via SIGHASH_ALL scriptless scripts...)

Despite using SIGHASH_SINGLE, I don't think you can combine two UPDATE txs
generally, because the nlocktime won't match (this could possibly be fixed
in a future soft-fork by using the annex to support per-input absolute
locktimes). You can't combine SETTLEMENT tx, because the ANYPREVOUT
signature needs to commit to multiple outputs (one for my balance, one
for yours, one for each active HTLC). Combining HTLC refunds is kind-of
easy, but only possible in the first place if you've got a bunch expiring
at the same time, which might not be that likely. Combining HTLC claims
should be easy enough since they just need scriptless-script signatures.

For fees, because of ALL|ANYPREVOUT, you can add a new input and new
change output to bring-your-own-fees for the UPDATE tx; and while you
can't do that for the SETTLEMENT tx, you can immediately spend your
channel-balance output to add fees via CPFP.

As far as "X" goes, calculating the private key as a HD key using ECDH
between the peers to generate the seed, and including the update id "n"
in the path, to vary it between each update tx might work well. You'd
need to give this key to watchtowers, but you'll probably have to pay
watchtowers to monitor your txs (so that they can add fees to the UPDATE
tx's), so only giving this key to the watchtowers you pay should maintain
the security assumptions.

Cheers,
aj




More information about the Lightning-dev mailing list