Skip to content

Instantly share code, notes, and snippets.

@instagibbs
Last active October 18, 2023 16:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save instagibbs/1d02d0251640c250ceea1c66665ec163 to your computer and use it in GitHub Desktop.
Save instagibbs/1d02d0251640c250ceea1c66665ec163 to your computer and use it in GitHub Desktop.
PTLCs for LN

Messaging Changes

I am assuming minimal changes to commitment transaction structure, essentially swapping out HTLC for PTLC, so no fast-forward schemes here.

Here are output labels because I get confused so often what things in BOLTs mean:

  • (a) a_o_atx_* Alice-offered "offered PTLC" in Alice's tx
  • (b) a_o_btx_* Alice-offered "received PTLC" in Bob's tx
  • (c) b_o_atx_* Bob-offered "received PTLC" in Alice's tx
  • (d) b_o_btx_* Bob-offered "offered PTLC" in Bob's tx

*_presign means single-signature adaptors for PTLC-Success transactions
*_psig means partial signature for MuSig2 for PTLC-Success transactions
*_nonce means nonce for _psig (TBD, didn't bother filling these out)
*_signed means BIP340 signature for PTLC-Timeout transactions

done is just a message to prompt a response before sending commitment_signed

Messages are maximally split up for understanding, and to analyze round-trips and complexity. This is not a concrete proposal for bits on the wire.

Single-sig adaptors, sync updates

    +-------+                                 +-------+
    |       |                                 |       | Alice's turn
    |       |--(1)---- update_offer_ptlc ---->|       | new amounts, lock info
    |       |--(2)---- update_offer_ptlc ---->|       | new amounts, lock info
    |       |--(3)---- done------------------>|       | Prompt Bob to send (d) adaptor sigs before Alice sends commit tx sig
    |       |                                 |       |
    |       |<-(4)--- b_o_btx_presign---------|       | Bob re-commits to all (d) PTLC-Success paths (must be before commit)
    |       |                                 |       | 
    |       |--(5)--- commitment_signed ----->|       | Alice's B_commit sig
    |       |--(6)--- b_o_btx_sign----------->|       | Alice's full sig for (d) PTLC-timeouts back to Bob
    |       |--(7)--- a_o_btx_presign-------->|       | Alice's adaptor sig for (b)
    |       |--(8)--- a_o_atx_presign-------->|       | Alice re-commits to all (a) PTLC-S paths with adaptor sigs
    |       |                                 |       |
    |   A   |<-(9)--- revoke_and_ack ---------|   B   | Bob can broadcast latest state safely, revoke older
    |       |<-(10)- commitment_signed -------|       | Bob's A_commit sig
    |       |<-(11)--b_o_atx_presign----------|       | Bob's adaptor signatures for (c)
    |       |<-(12)--a_o_atx_sign-------------|       | Bob's full sig for (a) PTLC-timeouts back to Alice
    |       |                                 |       |
    |       |--(13)-- revoke_and_ack -------->|       | Alice is now committed, Bob can now safely forward
    |       |                                 |       |
    +-------+                                 +-------+

Rationale

(3) is necessary to prompt sending of b_o_btx_presign at (4). If Alice sends commitment_signed (5) without (4) being received, then Bob can take his commitment transaction to chain, and retroactively "uncommit" PTLCs he has previously offered in prior updates, which Alice has forwarded.

(6)/(7) is the rest of the (adaptor) signatures to complete Bob's transaction.

Since we have synchronous updates, a_o_atx_presign (8) can be sent by Alice any time after done(3) since we already know the complete structure Alice's commitment transaction by (3), and therefore the sighashes for all PTLCs.

Alice must send a_o_atx_presign(8) before commitment_signed(10) can be sent anyways, for the same reason as (3).

This results in 2.5 RTT for a PTLC forward.

Single-sig adaptors, async updates

If we allow asynchronous updates(without ANYPREVOUT-like functionality), we can not predict the commitment transaction structure on "our side" until the other side signals they are done changing it.

    +-------+                                 +-------+
    |       |<-(0)---- update_offer_ptlc -----|       | new amounts, lock info
    |       |                                 |       |
    |       |--(1)---- update_offer_ptlc ---->|       | new amounts, lock info
    |       |--(2)---- update_offer_ptlc ---->|       | new amounts, lock info
    |       |--(3)---- done------------------>|       | Prompt Bob to send (d) adaptor sigs before Alice sends commit tx sig
    |       |                                 |       |
    |       |<-(4)--- b_o_btx_presign---------|       | Bob re-commits to all (d) PTLC-Success paths (must be before commit)
    |       |                                 |       |
    |       |--(5)--- commitment_signed ----->|       | Alice's B_commit sig
    |       |--(6)--- a_o_btx_presign-------->|       | Alice's presignatures for (b)
    |       |--(7)--- b_o_btx_sign----------->|       | Alice's full sig for (d)
    |       |                                 |       |
    |   A   |<-(8)--- revoke_and_ack ---------|   B   | Bob can broadcast local latest state safely, revoke older
    |       |<-(9)--- done--------------------|       | Bob prompts Alice to re-commit to (a)
    |       |                                 |       |
    |       |--(10)-- a_o_atx_presign-------->|       | Alice re-commits to all (a) PTLC-Success paths (must be before commit)
    |       |                                 |       |
    |       |<-(11)- commitment_signed -------|       | Bob's A_commit sig, Bob's presignatures for (c) and full sig for (a)
    |       |<-(12)-- b_o_atx_presign---------|       | Bob's presignatures for (c)
    |       |<-(13)-- a_o_atx_sign------------|       | Bob's full sig for (d)
    |       |                                 |       |
    |       |--(14)-- revoke_and_ack -------->|       | Alice is now committed, Bob can now safely forward
    |       |                                 |       |
    +-------+                                 +-------+

Rationale

a_o_atx_presign(10) must happen after done(9), in other words after all Bob-intitiated updates are done which adds another round-trip, resulting in 3.5 RTT per PTLC forward.

The rest of the protocol stays the same.

MuSig2-based adaptor signatures, sync updates

The key difference for this construction is that it necessitates additional round-trips since the receiving party must offer a partial signature first to maintain fairness in the exchange protocol.

Let's ignore all nonces for the sake of simplicity, assuming they can be preshared optimally.

    +-------+                                 +-------+ Alice's turn
    |       |                                 |       |
    |       |--(1)---- update_offer_ptlc ---->|       | new amounts, lock info
    |       |--(2)---- update_offer_ptlc ---->|       | new amounts, lock info
    |       |--(3)---- b_o_btx_psig---------->|       | Alice psigning Bob-offered PTLC in Bob tx (d) 
    |       |--(4)---- done------------------>|       | Prompt Bob to send (d) adaptor sigs before Alice sends commit tx sig
    |       |                                 |       |
    |       |<-(5)--- b_o_btx_psig------------|       | Bob re-commits to all (d) PTLC-Success paths (must be before commit)
    |       |                                 |       |
    |       |--(6)--- commitment_signed ----->|       | Bob knows full local commit tx sig for Alice (and Alice knows PTLC-S (d))
    |       |                                 |       |
    |       |<-(7)--- a_o_atx_psig------------|       | Bob psigning Alice-offered PTLC in Alice tx (a)
    |       |<-(8)--- a_o_btx_psig------------|       | Bob psigning Alice-offered PTLC in Bob tx (b)
    |       |                                 |       |
    |       |--(9)--- a_o_atx_psig----------->|       | Alice psigning Alice-offered PTLC in Alice tx (a)
    |       |--(10)-- a_o_btx_psig----------->|       | Alice psigning Alice-offered PTLC in Bob tx (b)
    |       |--(11)-- b_o_atx_psig----------->|       | Alice psigning Bob-offered PTLC in Alice tx (c) 
    |       |                                 |       |
    |       |<-(12)---b_o_atx_psig------------|       | Bob psigning Bob-offered PTLC in Alice tx (c)
    |   A   |<-(13)---revoke_and_ack ---------|   B   | All Alice-offered PTLCs locked in, new tx safe for Bob
    |       |<-(14)-- commitment_signed ------|       | Alice now knows Bob's sigs for Alice's commit tx
    |       |                                 |       | Bob wasn't allowed to add his own PTLCs so Alice can finish up
    |       |--(15)--- revoke_and_ack ------->|       | Alice is now committed, Bob can now safely forward
    |       |                                 |       |
    +-------+                                 +-------+

Rationale

b_o_*tx_psig(3) must be sent by Alice first, and conversely a_o_*tx_psig(3) must be sent by Bob first. This results in 3.5 RTT.

MuSig2-based adaptor signatures, async updates

With asynchronous updates, again, Bob will not be able to predict the structure of Alice's commitment transaction as early, resulting in an additional round-trip. Nonce message patterns are left as an exercise for the reader.

    +-------+                                 +-------+
    |       |<-(0)---- update_offer_ptlc -----|       | new amounts, lock info
    |       |                                 |       |
    |       |--(1)---- update_offer_ptlc ---->|       | new amounts, lock info
    |       |--(2)---- update_offer_ptlc ---->|       | new amounts, lock info
    |       |--(3)--- b_o_btx_psig----------->|       | Alice psigning Bob-offered PTLC in Bob tx (d) 
    |       |--(4)---- done------------------>|       | Prompt Bob to send (d) adaptor sigs before Alice sends commit tx sig
    |       |                                 |       |
    |       |<-(5)--- b_o_btx_psig------------|       | Bob re-commits to all (d) PTLC-Success paths (must be before commit)
    |       |                                 |       |
    |       |--(6)--- commitment_signed ----->|       | Bob knows full local commit tx sig for Alice and Alice knows (d)
    |       |                                 |       |
    |       |<-(7)--- a_o_btx_psig------------|       | Bob psigning Alice-offered PTLC in Bob tx (b)
    |       |                                 |       |
    |       |--(8)--- a_o_btx_psig----------->|       | Alice psigning Alice-offered PTLC in Bob tx (b)
    |       |                                 |       |
    |   A   |<-(9)---- revoke_and_ack --------|   B   | All Alice-offered PTLCs locked in, new tx safe for Bob
    |       |<-(10)--- done ------------------|       | Bob is done, atx is fixed, psig time
    |       |<-(11)-- a_o_atx_psig------------|       | Bob psigning Alice-offered PTLC in Alice tx (a)
    |       |                                 |       |
    |       |--(10)-- a_o_atx_psig----------->|       | Alice psigning Alice-offered PTLC in Alice tx (a)
    |       |--(11)-- b_o_atx_psig----------->|       | Alice psigning Bob-offered PTLC in Alice tx (c) 
    |       |                                 |       |
    |       |<-(12)--- b_o_atx_psig-----------|       | Bob psigning Bob-offered PTLC in Alice tx (c)
    |       |<-(13)-- commitment_signed ------|       | Alice now knows Bob's sigs for Alice's commit tx
    |       |                                 |       | Bob wasn't allowed to add his own PTLCs so Alice can finish up
    |       |--(14)--- revoke_and_ack ------->|       | Alice is now committed, Bob can now safely forward
    |       |                                 |       |
    +-------+                                 +-------+

Rationale

This pattern results in 4.5 RTT for a PTLC forward.

Single-sig adaptor, sync, with ANYPREVOUT

    +-------+                                 +-------+
    |       |                                 |       | Alice's turn
    |       |--(1)---- update_offer_ptlc ---->|       | new amounts, lock info, a_o_ptlc (unbound adaptor APO sig for {a,b}tx)
    |       |--(2)---- update_offer_ptlc ---->|       | new amounts, lock info, a_o_ptlc (unbound adaptor APO sig for {a,b}tx)
    |       |--(3)--- commitment_signed ----->|       | Alice's B_commit sig
    |       |--(4)--- b_o_btx_sign----------->|       | Alice's full sig for (d) PTLC-timeouts back to Bob
    |       |                                 |       |
    |   A   |<-(5)--- revoke_and_ack ---------|   B   | Bob can broadcast latest state safely, revoke older
    |       |<-(6)-- commitment_signed -------|       | Bob's A_commit sig
    |       |<-(7)---a_o_atx_sign-------------|       | Bob's full sig for (a) PTLC-timeouts back to Alice
    |       |                                 |       |
    |       |--(8)--- revoke_and_ack -------->|       | Alice is now committed, Bob can now safely forward
    |       |                                 |       |
    +-------+                                 +-------+

Rationale

Since we don't ever have to predict commitment transaction txids, we can send PTLC adaptor signatures inside the PTLC offers themselves, and never have to send them again. This results in a much closer message pattern to today's.

Asynchronous should be the same.

Single-sig adaptor, ln-symmetry

This one is just for fun.

    +-------+                                 +-------+
    |       |                                 |       | Alice's turn
    |       |--(1)---- update_offer_ptlc ---->|       | new amounts, lock info, a_o_ptlc (unbound adaptor APO sig for PTLC point)
    |   A   |--(2)---- update_offer_ptlc ---->|   B   | new amounts, lock info, a_o_ptlc (unbound adaptor APO sig for PTLC point)
    |       |--(3)--- update_signed --------->|       | Alice's psig for update tx. Bob can now forward
    |       |                                 |       |
    +-------+                                 +-------+

Rationale

Uses simplified updates. A single partial signature per state update, and a single adaptor signature per added PTLC.

T-bast reordering updates

Forgot about t-bast's ideas which details a reordering that can save round-trips.

Single-sig adaptor, sync updates

+-------+                                 +-------+
|       |                                 |       | Alice's turn
|       |--(1)---- update_offer_ptlc ---->|       | new amounts, lock info
|       |--(2)---- update_offer_ptlc ---->|       | new amounts, lock info
|       |--(3)--- a_o_atx_presign-------->|       | Alice re-commits to all (a) PTLC-S paths with adaptor sigs
|       |                                 |       |
|       |<-(4)-- commitment_signed -------|       | Bob's A_commit sig
|       |<-(5)---b_o_atx_presign----------|       | Bob's adaptor signatures for (c)
|       |<-(6)---a_o_atx_sign-------------|       | Bob's full sig for (a) PTLC-timeouts back to Alice
|       |<-(7)--- b_o_btx_presign---------|       | Bob re-commits to all (d) PTLC-Success paths (must be before commit)
|       |                                 |       | 
|       |--(8)--- revoke_and_ack -------->|       | Alice is now committed, Bob can now safely forward
|       |--(9)--- commitment_signed ----->|       | Alice's B_commit sig
|       |--(10)-- b_o_btx_sign----------->|       | Alice's full sig for (d) PTLC-timeouts back to Bob
|       |--(12)-- a_o_btx_presign-------->|       | Alice's adaptor sig for (b)
|       |                                 |       |
|   A   |<-(13)-- revoke_and_ack ---------|   B   | Bob can broadcast latest state safely, revoke older
|       |                                 |       |
|       |                                 |       |
+-------+                                 +-------+

Rationale:

If we have Bob commit first, this cuts out round-trips. Same effect below.

MuSig adaptor, sync updates

+-------+                                 +-------+ Alice's turn
|       |                                 |       |
|       |--(1)---- update_offer_ptlc ---->|       | new amounts, lock info
|       |--(2)---- update_offer_ptlc ---->|       | new amounts, lock info
|       |--(3)--- b_o_atx_psig----------->|       | Alice psigning Bob-offered PTLC in Alice tx (c)  (Bob can now safely send commitment_signed)
|       |--(4)---- b_o_btx_psig---------->|       | Alice psigning Bob-offered PTLC in Bob tx (d)        
|       |                                 |       |
|       |<-(5)----b_o_atx_psig------------|       | Bob psigning Bob-offered PTLC in Alice tx (c)   
|       |<-(6)--- b_o_btx_psig------------|       | Bob re-commits to all (d) PTLC-Success paths (must be before commit)
|       |<-(8)--- a_o_atx_psig------------|       | Bob psigning Alice-offered PTLC in Alice tx (a)
|       |<-(9)--- a_o_btx_psig------------|       | Bob psigning Alice-offered PTLC in Bob tx (b)         
|       |<-(7)--- commitment_signed ------|       | Alice now knows Bob's sigs for Alice's commit tx
|       |                                 |       |
|       |--(10)--- revoke_and_ack ------->|       | Alice still needs to commit to the new PTLCs before Bob can forward
|       |--(11)-- commitment_signed ----->|       | Bob knows full local commit tx sig for Alice (and Alice knows PTLC-S (d)) 
|       |--(12)-- a_o_atx_psig----------->|       | Alice psigning Alice-offered PTLC in Alice tx (a)
|       |--(13)-- a_o_btx_psig----------->|       | Alice psigning Alice-offered PTLC in Bob tx (b)
|       |                                 |       |   Alice is now committed, Bob can now safely forward
|   A   |<-(14)---revoke_and_ack ---------|   B   | All Alice-offered PTLCs locked in, new tx safe for Bob
|       |                                 |       |
+-------+                                 +-------+

Conclusions & Questions

  1. With a bit of message re-ordering and sync updates, we can keep 1.5RTT without too much pain
    1. async updates likely possible as well, but makes my head hurt more than it already does
  2. Otherwise, PTLCs, in the absense of deeper commitment transaction updates ala "fast-forward", add some forwarding latency
    1. Async updates paradoxically add PTLC forwarding latency. Is this the time to adopt a simplified update protocol? Would async updates make fast-forwarding impossible?
    2. MuSig2 adds a round-trip of latency in many cases, even with "fast-forwards", or ANYPREVOUT based constructs like ln-symmetry. It also adds nonce management per-commitment tx, per-PTLC.
  3. Absent total mempool re-writes, the cost of MuSig2 or single-signature adaptors will end up being the same due to bring-your-own-fee requirements. It seems to have no upsides currently, and introduces nonce management.
  4. ANYPREVOUT makes things a lot less convoluted, even for penalty based channels. One MuSig2(and pair of nonces) or adaptor signature per PTLC, lifetime.
  5. Would inversion of who sends commitment_signed first interfere with other updates on simplified update mechanism?
  6. Single-sig adaptors are not widely adopted compared to MuSig2 variant. There is a single unmereged implementation that needs review and standardization.

Some reasonable choices:

  1. single-sig adaptor, async updates, no message re-ordering. Highest number of round-trips to forward (3.5RTT)
  2. single-sig adaptor, sync updates, no message re-ordering. Slightly fewer round-trips than above to forward (2.5RTT)
  3. single-sig adaptor, sync updates, switch up commitment ordering. Same forwarding round-trips as today (1.5RTT)
    1. can be swapped out with MuSig2 upon future mempool architecture with replace-by-feerate?
  4. "fast-forward" commitment transaction rewrite, sync updates(?), which was deemed Future Work prior (0.5RTT)
@hieblmi
Copy link

hieblmi commented Oct 18, 2023

Shouldn't If Alice sends commitment_signed (5) without (3) being received, ... change to If Alice sends commitment_signed (5) without (4) being received, ...?

@instagibbs
Copy link
Author

@hieblmi thanks fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment