<oembed><type>rich</type><version>1.0</version><title>Anthony Towns [ARCHIVE] wrote</title><author_name>Anthony Towns [ARCHIVE] (npub17r…x9l2h)</author_name><author_url>https://yabu.me/npub17rld56k4365lfphyd8u8kwuejey5xcazdxptserx03wc4jc9g24stx9l2h</author_url><provider_name>njump</provider_name><provider_url>https://yabu.me</provider_url><html>📅 Original date posted:2021-10-08&#xA;📝 Original message:&#xA;Hi all,&#xA;&#xA;Here&#39;s my proposal for replacing BOLT#2 and BOLT#3 to take advantage of&#xA;taproot and implement PTLCs. &#xA;&#xA;It&#39;s particularly inspired by ZmnSCPxj&#39;s thoughts from Dec 2019 [0], and&#xA;some of his and Lloyd Fournier&#39;s posts since then (which are listed in&#xA;references) -- in particular, I think those allow us to drop the latency&#xA;for forwarding a payment *massively* (though refunding a payment still&#xA;requires roundtrips), and also support receiving via a mostly offline&#xA;lightning wallet, which seems kinda cool.&#xA;&#xA;I somehow hadn&#39;t realised it prior to a conversation with @brian_trollz&#xA;via twitter DM, but I think switching to PTLCs, even without eltoo,&#xA;means that there&#39;s no longer any need to permanently store old payment&#xA;info in order to recover the entirety of the channel&#39;s funds. (Some brute&#xA;force is required to recover the timeout info, but in my testing I think&#xA;that&#39;s about 0.05 seconds of work per ptlc output via python+libsecp256k1)&#xA;&#xA;This doesn&#39;t require any soft-forks, so I think we could start work on&#xA;it immediately, and the above benefits actually seem pretty worth it,&#xA;even ignoring any privacy/efficiency benefits from doing taproot key&#xA;path spends and forwarding PTLCs.&#xA;&#xA;I&#39;ve sketched up the musig/musig2 parts for the &#34;balance&#34; transactions&#xA;in python [1] and tested it a little on signet [2], which I think is&#xA;enough to convince me that this is implementable. There&#39;ll be a bit of&#xA;preliminary work needed in actually defining specs/BIPs for musig and&#xA;musig2 and adaptor signatures, I think.&#xA;&#xA;Anyway, details follow. They&#39;re also up on github as a gist [3] if that&#xA;floats your boat.&#xA;&#xA;[0] https://lists.linuxfoundation.org/pipermail/lightning-dev/2019-December/002375.html&#xA;&#xA;[1] https://github.com/ajtowns/bitcoin/blob/202109-ptlc-lnpenalty/test/functional/feature_ln_ptlc.py&#xA;&#xA;[2] The balance transaction (spending the funding tx and with outputs&#xA;    being Alice&#39;s and Bob&#39;s channel balance is at):&#xA;    https://explorer.bc-2.jp/tx/ba58d99dfaad83e105a0de1a9becfcf8eaf897aaaada54bd7b08134ff579997c?input:0&amp;expand&#xA;&#xA;[3] https://gist.github.com/ajtowns/12f58fa8a4dc9f136ed04ca2584816a2/&#xA;&#xA;Goals&#xA;=====&#xA;&#xA;1. Support HTLCs&#xA;2. Support PTLCs&#xA;3. Minimise long-term data storage requirements&#xA;4. Minimise latency when forwarding payments&#xA;5. Minimise latency when refunding payments&#xA;6. Support offline receiving&#xA;7. Minimise on-chain footprint&#xA;8. Minimise ability for third-parties to analyse&#xA;&#xA;Setup&#xA;=====&#xA;&#xA;We have two participants in the channel, Alice and Bob. They each have&#xA;bip32 private keys, a and b, and share the corresponding xpubs A and B&#xA;with each other.&#xA;&#xA;Musig&#xA;-----&#xA;&#xA;We will use musig to combine the keys, where P = musig(A,B) = H(A,B,1)*A&#xA;+ H(A,B,2)*B. We&#39;ll talk about subkeys of P, eg P/4/5/6, which are&#xA;calculated by taking subkeys of the input and then applying musig,&#xA;eg P/4/5/6 = musig(A/4/5/6, B/4/5/6). (Note that we don&#39;t use hardened&#xA;paths anywhere)&#xA;&#xA;Musig2&#xA;------&#xA;&#xA;We&#39;ll use musig2 to sign for these keys, that is both parties will&#xA;pre-share two nonce points each, NA1, NA2, NB1, NB2, and the nonce will be&#xA;calculated as: R=(NA1+NB1)+k(NA2+NB2), where k=Hash(P,NA1,NA2,NB1,NB2,m),&#xA;where P is the pubkey that will be signing and m is the message to be&#xA;signed. Note that NA1, NA2, NB1, NB2 can be calculated and shared prior&#xA;to knowing what message will be signed.&#xA;&#xA;The partial sig by A for a message m with nonce R as above is calculated as:&#xA;&#xA;    sa = (na1+k*na2) + H(R,A+B,m)*a&#xA;&#xA;where na1, na2, and a are the secrets generating NA1, NA2 and A respectively.&#xA;Calculating the corresponding partial signature for B,&#xA;&#xA;    sb = (nb1+k*nb2) + H(R,A+B,m)*b&#xA;&#xA;gives a valid signature (R,sa+sb) for (A+B):&#xA;&#xA;    (sa+sb)G = R + H(R,A+B,m)*(A+B)&#xA;&#xA;Note that BIP340 sepcifies x-only pubkeys, so A+B and R implicitly have&#xA;even y, however since those values are caluclated via musig and musig2&#xA;respectively, this cannot be ensured in advance. Instead, if we find:&#xA;&#xA;    H(A,B,1)*A + H(A,B,2)*B&#xA;&#xA;does not have even y, we calculate:&#xA;&#xA;    P = (-H(A,B,1))*A + (-H(A,B,2))*B&#xA;&#xA;instead, which will have even y. Similarly, if (NA1+NB1+k(NA2+NB2)) does&#xA;not have even y, when signing, we replace each partial nonce by its negation,&#xA;eg: sa = -(na1+k*na2) + H(R,A+B,m).&#xA;&#xA;Adaptor Sigs&#xA;------------&#xA;&#xA;An adaptor signature for P for secret X is calculated as:&#xA;&#xA;    s = r + H(R+X, P, m)*p&#xA;&#xA;which gives:&#xA;&#xA;    (s+x)G = (R+X) + H(R+X, P, m)*P&#xA;&#xA;so that (R+X,s+x) is a valid signature by P of m, and the preimage for&#xA;X can be calculated as the difference between the published sig and the&#xA;adaptor sig, x=(s+x)-(s).&#xA;&#xA;Note that if R+X does not have even Y, we will need to negate both R and X,&#xA;and the recovered secret preimage will be -x instead of x.&#xA;&#xA;Revocable Secrets&#xA;-----------------&#xA;&#xA;Alice and Bob have shachain secrets RA(n) and RB(n) respectively,&#xA;and second level shachain secrets RA2(n,i) and RB2(n,i), with n and i&#xA;counting up from 0 to a maximum.&#xA;&#xA;Summary&#xA;=======&#xA;&#xA;We&#39;ll introduce four layers of transactions:&#xA;&#xA; 1. The funding transaction - used to establish the channel, provides&#xA;    the utxo backing the channel while the channel is open.&#xA; 2. The balance transaction - tracks the funding transaction, contains&#xA;    a &#34;balance&#34; output for each of the participants.&#xA; 3. The inflight transactions - spends a balance output from the balance&#xA;    transaction and provides outputs for any inflight htlc/ptlc transactions.&#xA; 4. Layered transactions - spends inflight htlc/ptlc outputs by revealing&#xA;    the preimage, while still allowing for the penalty path.&#xA;&#xA;Funding transaction&#xA;===================&#xA;&#xA;The funding transaction simply pays to P/0/f via taproot, where f starts&#xA;at 0 and increases any time the funding transaction is updated onchain&#xA;(eg when splicing funds in or out).&#xA;&#xA;Balance transaction&#xA;===================&#xA;&#xA;The balance transaction spends the funding transaction, and has two&#xA;outputs, one for Alice&#39;s balance and one for Bob&#39;s balance (omitting a&#xA;zero/dust balance).&#xA;&#xA;We count the number of balance updates, starting at 0, and call it &#34;n&#34;.&#xA;&#34;n&#34; is encoded in the transaction locktime and the input nsequence, so&#xA;if a balance transaction appears on chain, &#34;n&#34; can be decoded from the&#xA;nsequence and locktime.&#xA;&#xA;Alice&#39;s balance is paid to an address with internal pubkey P/1/n/0&#xA;and a script path of &#34;&lt;A/1/n&gt; CHECKSIGVERIFY &lt;D&gt; CSV&#34; where D is&#xA;Alice&#39;s to_self_delay. Bob&#39;s balance is similar, with internal pubkey&#xA;P/1/n/1.&#xA;&#xA;In order to update to a new balance transaction, the process is as follows.&#xA;First, nonces are exchanged in advance:&#xA;&#xA;  Alice:&#xA;    Generates a nonce pair NA1, NA2 derived from RA(n). Shares this with&#xA;    Bob.&#xA;  Bob:&#xA;    Generates a nonce pair NB1, NB2 derived from RB(n). Shares this with&#xA;    Alice.&#xA;&#xA;Then, presuming Alice initiates the update:&#xA;&#xA;  Alice:&#xA;    Generates deterministic nonce pair, DA1, DA2. Combines this with&#xA;    Bob&#39;s NB1, NB2 nonce pair.  Generates partial signature for nonce&#xA;    (DA, NB) for the transaction. Sends DA1 and DA2 and the partial&#xA;    signature to Bob.&#xA;&#xA;  Bob:&#xA;    Checks the partial signature is valid. Updates to the new balance&#xA;    transaction. Generates a nonce pair, DB1, DB2, and gnerates a partial&#xA;    signature for the balance transaction for nonce (NA, DB). Sends DB1,&#xA;    DB2, and the partial signature to Alice. Generates a new revocable&#xA;    secret RB(n+1). Revokes the previous secret RB(n) and sends the&#xA;    details of both to Alice.&#xA;&#xA;  Alice:&#xA;    Checks the partial signature is valid. Updates to the new balance&#xA;    transaction. Checks the secret revocation info is correct and stores&#xA;    it. Generates a new revocable secret RA(n+1). Revokes the previous&#xA;    secret RA(n) and sends the details of both to Bob.&#xA;&#xA;  Bob:&#xA;    Checks the secret revocation info is correct an stores it.&#xA;&#xA;This means that both Alice and Bob have the same balance transaction here&#xA;(with the same txid) but have different signatures for it (and thus&#xA;differing wtxids).&#xA;&#xA;Because updating the balance transaction involves two round trips&#xA;before Bob can be sure Alice cannot use the old state, we move all the&#xA;transaction information to the inflight transactions, which we will be&#xA;able to update immediately, without requiring a round trip at all.&#xA;&#xA;Note that if Bob publishes the signature for an old state, then the&#xA;signature is:&#xA;&#xA;   s = ((DA1+NB1) + k(DA2+NB2)) + H(R,A+B,m)(a+b)&#xA;&#xA;but Alice can calculate the secrets for both DA1 and DA2 (she generated&#xA;those deterministically herself in the first place), and NB1 and NB2 (she&#xA;has the secret revocation information, and verified that it correctly&#xA;generated the nonces Bob was using), which allows her to calculate Bob&#39;s&#xA;private key using modular arithmetic:&#xA;&#xA;   b = H(R,P,m) / (s - (DA1+NB1) - b(DA2+NB2)) - a&#xA;&#xA;which means she can then directly sign without Bob&#39;s assistance, allowing&#xA;her to claim any funds.&#xA;&#xA;Inflight and Layered Transactions&#xA;=================================&#xA;&#xA;We construct two inflight transactions on top of the current balance&#xA;transaction, one spending Alice&#39;s balance, and one spending Bob&#39;s balance.&#xA;&#xA;We will use &#34;i&#34; to represent the number of times a given inflight&#xA;transaction has been updated for the nth update to the balance&#xA;transaction.&#xA;&#xA;At any time Alice can update the inflight transaction spending her balance&#xA;to transfer funds towards Bob, either by updating the balances directly,&#xA;or adding a htlc/ptlc entry to conditionally transfer funds to Bob. (And&#xA;conversely for Bob)&#xA;&#xA;We will define RP=musig(A/2/n/i, RB2(n,i)).&#xA;&#xA;The inflight transaction spending Alice&#39;s balance can have multiple&#xA;types of outputs:&#xA;&#xA; * Alice&#39;s remaining balance: pays directly to A/2/n/i&#xA;&#xA; * Bob&#39;s remaining balances: pays to RP/2 with script path&#xA;   &#34;&lt;B/2/n/i&gt; CHECKSIGVERIFY &lt;D&gt; CSV&#34;&#xA;&#xA; * An htlc paying to Bob: pays to RP/2/k with script paths:&#xA;   + &#34;LENGTH 32 EQUALVERIFY HASH160 &lt;X&gt; EQUALVERIFY &lt;B/2/n/i/k&gt; CHECKSIGVERIFY &lt;A/2/n/i/k&gt; CHECKSIG&#34;&#xA;   + &#34;&lt;A/2/n/i/k/1&gt; CHECKSIGVERIFY &lt;T&gt; CLTV&#34;&#xA;&#xA; * A ptlc paying to Bob: pays to RP/2/k with script paths:&#xA;   + &#34;&lt;B/2/n/i/k&gt; CHECKSIG NOTIF &lt;T&gt; CLTV DROP ENDIF &lt;A/2/n/i/k&gt; CHECKSIG&#34;&#xA;&#xA;Any outputs that would be zero or dust are not included.&#xA;&#xA;Note that we number each currently inflight transaction by &#34;k&#34;,&#xA;starting at 0. The same htlc/ptlc may have a different value for k&#xA;between different inflight transactions.&#xA;&#xA;The inflight transation&#39;s locktime is set to the current block&#xA;height. This enables brute force searching for the locktime of any&#xA;inflight ptlcs (so that in a penalty scenario when the other party posts&#xA;an out of date inflight transaction, you can search through a small&#xA;number of possible timeout values simply by not sending any ptlcs with&#xA;a timeout more that L blocks in the future).&#xA;&#xA;The balance input&#39;s nsequence is used to encode the value of the lower&#xA;24 bits of i in the same way the balance transaction&#39;s fund input&#39;s&#xA;nsequence encodes the upper 24 bits of n.&#xA;&#xA;The layered transaction will spend the htlc/ptlc outputs, with an&#xA;ANYONECANPAY|SINGLE signature by Alice using the A/2/n/i/k path.&#xA;The output committed to is:&#xA;&#xA; * pays to RP/3/k with script path:&#xA;   + &lt;B/3/n/i/k&gt; CHECKSIGVERIFY &lt;D&gt; CSV&#xA;&#xA;with no absolute or relative locktime.&#xA;&#xA;To update the inflight transaction spending Alice&#39;s balance as well as&#xA;any dependent layered transactions, the process is as follows:&#xA;&#xA;  Bob:&#xA;    Generates a second level revocable secret, RB2(n,i) and sends Alice&#xA;    the corresponding point, PB2. Calculates a nonce pair, NB1, NB2, and&#xA;    sends that to Alice. This is done in advance.&#xA;&#xA;  Alice:&#xA;    Calculates the new inflight transaction. Calculates new nonces NA1,&#xA;    NA2, and partially signs the spend of her balance via the key path,&#xA;    with musig2 nonces NA1, NB1, NA2, NB2. For each inflight htlc,&#xA;    Alice provides a signature via A/2/n/i/k. For each inflight ptlc,&#xA;    Alice provides an adaptor signature via the A/2/n/i/k/0 path that&#xA;    is conditional on the ptlc&#39;s point.&#xA;&#xA;  Bob:&#xA;    Bob verifies the new proposed inflight state and each of the&#xA;    signatures. Bob may now rely on the new state. Bob revokes their&#xA;    prior secret, RB2(n, i-1), and sends a new point/nonce pair (PB2&#39;,&#xA;    NB1&#39;, NB2&#39;) to Alice to prepare for the next round.&#xA;&#xA;Note that Bob could stream multiple point/nonce pairs in advance,&#xA;allowing Alice to do multiple inflight tx updates within the time taken&#xA;for a roundtrip.&#xA;&#xA;Alice can unilaterally do the following safely:&#xA;&#xA; 1. transfer from Alice&#39;s balance to Bob&#39;s balance&#xA; 2. accept that a htlc/ptlc succeeded, removing the corresponding output&#xA;    and allocating the funds associated with it directly to Bob&#39;s balance&#xA; 3. introduce a htlc/ptlc, spending funds from Alice&#39;s balance&#xA;&#xA;However refunding/cancelling a htlc/ptlc requires a two-phase commit&#xA;with 1.5 round trips:&#xA;&#xA; - Bob proposes refunding a htlc/ptlc&#xA; - Alice agrees and sends a partial signature for the new transaction&#xA;   with the htlc/ptlc funds transferred back to her balance,&#xA; - Bob records the new transaction, and revokes the earlier second&#xA;   level secret RB2(n, i-1).&#xA; - Alice verifies the revocation, and can safely treat the funds as&#xA;   refunded (and thus refund back to the original payer, eg).&#xA;&#xA;The advantage of doing this over negotiating a new balance transaction&#xA;is that only the second level revocation secrets need to be online,&#xA;allowing for operation by semi-offline lightning nodes (ie, having the&#xA;channel private key and first level revocation secrets offline). Such&#xA;semi-offline nodes risk losing funds in the &#34;inflight&#34; transaction&#xA;(either by revealing the second level revocation secrets or by simply&#xA;data loss of the current inflight/layered transactions) but do not risk&#xA;losing or spending funds in their own output of the balance transaction.&#xA;&#xA;This means the funds locked in Alice&#39;s balance can be spent in the&#xA;following ways:&#xA;&#xA; * Alice can claim them directly if Bob does not post the inflight&#xA;   transaction before the delay expires, via the script balance output&#39;s&#xA;   script path. Alice gets the entire balance in this case.&#xA;&#xA; * Bob can post a revoked inflight transaction, for which Alice knows the&#xA;   secret for RB(n,i). In this case Alice recovers the value of i from&#xA;   the nsequence (using brute force for the upper bits if she has&#xA;   provided more than 16M updates of the inflight tx for any given&#xA;   balance transaction), and then calculates the secret key for PB,&#xA;   and hence PB/2/k and PB/3/k, at which point she can claim every&#xA;   output via a key path spend, even if Bob posts some or all of the&#xA;   layered transactions. Alice gets the entire balance in this case&#xA;   (though spends more on fees).&#xA;&#xA; * Bob can post a current inflight transaction, along with layered&#xA;   transactions for any of the inflight htlc/ptlcs for which he knows the&#xA;   corresponding preimage, allowing Alice to recover the preimages from&#xA;   the on-chain spends immediately. Alice can claim her balance output and&#xA;   any timed out funds immediately as well. Bob can finish claiming his&#xA;   balance and any claimed htlc/ptlc funds after the delay has finished.&#xA;&#xA;Note that Bob never shares his signature to spend Alice&#39;s balance prior&#xA;to posting the inflight transaction, so Alice can never post an inflight&#xA;transaction that spends her own balance.&#xA;&#xA;The cases where Alice may have difficulty claiming funds is Bob posts&#xA;a revoked inflight transaction (possibly spending a revoked balance&#xA;transaction) are:&#xA;&#xA; * if the inflight transaction contains a htlc output, then if Alice&#xA;   has not retained the old htlc details (the hash160 and the timeout)&#xA;   she will not be able to reconstruct the script path, and thus will&#xA;   not be able to calculate the TapTweak to sign for the key path.&#xA;   However if Bob attempts to claim the output (via the pre-signed&#xA;   layered transaction), that will reveal the information she was missing,&#xA;   and she can immediately claim the funds via the layered transaction&#xA;   output, prior to Bob being able to spend that output.&#xA;&#xA; * if the inflight transaction contains a ptlc output, then if Alice&#xA;   has not retained the old ptlc details (the point and the timeout)&#xA;   she will not trivially be able to reconstruct the script path,&#xA;   which includes the timeout. However, presuming the timeout was&#xA;   within 5000 blocks, then the only possible timeouts are the inflight&#xA;   tx&#39;s nlocktime+i with 0&lt;i&lt;=5000, and she will only need to calculate&#xA;   5000*k cases and match the corresponding scriptPubKeys to exhaustively&#xA;   enumerate every possible ptlc output, which should take under a minute,&#xA;   and be easily achievable. In addition, if Bob attempts to claim the&#xA;   funds, he will reveal the script path, and Alice will be either able&#xA;   to claim the inflight output directly or the layered output.&#xA;&#xA;Misc&#xA;====&#xA;&#xA;In order to transition from BOLT#3 format to this proposal, an onchain&#xA;transaction is required, as the &#34;revocable signatures&#34; arrangement cannot&#xA;be mimicked via the existing 2-of-2 CHECKMULTISIG output.&#xA;&#xA;To allow splicing in/out, it may be important to maintain multiple&#xA;concurrent funding transactions (paying to P/0/f and P/0/f+1 eg),&#xA;which then requires maintaining multiple current balance transactions&#xA;(paying to P/1/n/* and P/1/n+1/x eg) and likewise multiple current&#xA;inflight/layered transactions. This will require ensuring the states&#xA;for all those transactions are synchoronised when verifying upates,&#xA;and requires sharing multiple nonces for signing (eg RA(n) and RA(n+1)&#xA;and RB2(n,i), and RB2(n+1,i)).&#xA;&#xA;Fees for the balance and inflight transactions must be considered upfront,&#xA;and paid for from the channel balance (or perhaps via additional anchor&#xA;outputs that allocate more than the dust threshold and are immediately&#xA;spendable). Fees for the layered transactions however can (and must)&#xA;be provided by whoever is attempting to claim the funds.&#xA;&#xA;Bob having a current inflight transaction spending Alice&#39;s balance is&#xA;advantageous to Alice as Bob posting the inflight transaction allows&#xA;her to immediately claim her balance, rather than having to wait for&#xA;the delay to complete.&#xA;&#xA;If two nodes agree to only forward ptlcs in future, then updating the&#xA;funding transaction (to P/0/f+1 eg) and ignoring any proposed inflight&#xA;transactions that include htlc outputs is enough to ensure that all htlc&#xA;records can be forgotten without risking any part of the channel balance&#xA;being unclaimable.&#xA;&#xA;This does not support option_static_remotekey, but compensates for that&#xA;by allowing balances to be recovered with only the channel setup data&#xA;even if all revocation data is lost.&#xA;&#xA;&#xA;References&#xA;==========&#xA;&#xA;Hopefully the above includes enough explanation to be understood on its own,&#xA;but here&#39;s references for a bunch of the concepts.&#xA;&#xA; * musig: https://blockstream.com/2018/01/23/en-musig-key-aggregation-schnorr-signatures/&#xA;&#xA; * musig2: https://medium.com/blockstream/musig2-simple-two-round-schnorr-multisignatures-bf9582e99295&#xA;&#xA; * adaptor sigs: https://github.com/ElementsProject/scriptless-scripts/blob/master/md/atomic-swap.md&#xA;&#xA; * fast forwards [ZmnSCPxj]&#xA;    https://lists.linuxfoundation.org/pipermail/lightning-dev/2019-April/001986.html&#xA;    https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-May/003043.html&#xA;    https://lists.linuxfoundation.org/pipermail/lightning-dev/2021-October/003265.html&#xA;&#xA; * revocable signatures [LLFourn]&#xA;    https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-August/002785.html</html></oembed>