diff --git a/md/images/multi-hop-locks.png b/md/images/multi-hop-locks.png index 9dd1841..d55b3e4 100644 Binary files a/md/images/multi-hop-locks.png and b/md/images/multi-hop-locks.png differ diff --git a/md/images/multi-hop-locks.txt b/md/images/multi-hop-locks.txt index cf97521..824e19d 100644 --- a/md/images/multi-hop-locks.txt +++ b/md/images/multi-hop-locks.txt @@ -22,21 +22,21 @@ participant Dave == Update == -Alice->Bob : add 2-of-2 MuSig(A,B) output with timelocked refund to A,\ncreate txB spending this to B, nonce(A,txB) -Bob->Alice : nonce(B,txB), psig(B,txB,(z+y0)*G) +Alice->Bob : add 2-of-2 MuSig(A,B) output with timelocked refund to A,\ncreate txB spending this to B +Bob->Alice : psig(B,txB,(z+y0)*G) Alice->Bob : psig(A,txB,(z+y0)*G) -Bob->Carol : add 2-of-2 MuSig(B,C) output with timelocked refund to B,\ncreate txC spending this to C, nonce(B,txC) -Carol->Bob : nonce(C,txC), psig(C,txC,(z+y0+y1)*G) +Bob->Carol : add 2-of-2 MuSig(B,C) output with timelocked refund to B,\ncreate txC spending this to C +Carol->Bob : psig(C,txC,(z+y0+y1)*G) Bob->Carol : psig(B,txC,(z+y0+y1)*G) -Carol->Dave : add 2-of-2 MuSig(C,D) output with timelocked refund to C,\ncreate txD spending this to D, nonce(C,txD) -Dave->Carol : nonce(D,txD), psig(D,txD,(z+y0+y1+y2)*G) +Carol->Dave : add 2-of-2 MuSig(C,D) output with timelocked refund to C,\ncreate txD spending this to D +Dave->Carol : psig(D,txD,(z+y0+y1+y2)*G) Carol->Dave : psig(C,txD,(z+y0+y1+y2)*G) == Settlement == -Dave->Dave : create adaptor_sig(D,txD,(z+y0+y1+y2)*G),\nMuSig combine with psig(C,txD,(z+y0+y1+y2)*G),\nbroadcast txD with combined sig -Carol->Carol : compute z+y0+y1 = adaptor_sig(D,txD,(z+y0+y1+y2)*G) - psig(D,txD,(z+y0+y1+y2)*G) - y2\nto create adaptor_sig(C,txC,(z+y0+y1)*G),\nMuSig combine with psig(B,txC,(z+y0+y1)*G),\nbroadcast txC with combined sig -Bob->Bob : compute z+y0 = adaptor_sig(C,txC,(z+y0+y1)*G) - psig(C,txC,(z+y0+y1)*G) - y1\nto create adaptor_sig(B,txB,(z+y0)*G),\nMuSig combine with psig(A,txB,(z+y0)*G),\nbroadcast txB with combined sig -Alice->Alice : compute z = adaptor_sig(B,txB,(z+y0)*G) - psig(B,txB,(z+y0)*G) - y0 +Dave->Dave : Create psig(D,txD,(z+y0+y1+y2)*G),\nsum with psig(C,txD,(z+y0+y1+y2)*G) and z+y0+y1+y2\nto create complete sig of txD and broadcast. +Carol->Carol : Compute z+y0+y1 =\n sig(D,txD,(z+y0+y1+y2)*G)\n - psig(D,txD,(z+y0+y1+y2)*G)\n - psig(C,txD,(z+y0+y1+y2)*G) \n - y2,\nsum with psig(C,txC,(z+y0+y1)*G) and psig(B,txC,(z+y0+y1)*G)\nto create complete sig of txC and broadcast. +Bob->Bob : Compute z+y0 =\n sig(C,txC,(z+y0+y1)*G)\n - psig(C,txC,(z+y0+y1)*G)\n - psig(B,txC,(z+y0+y1)*G)\n - y1,\nsum with psig(B,txB,(z+y0)*G) and psig(A,txB,(z+y0)*G)\nto create complete sig of txB and broadcast. +Alice->Alice : Compute z =\n sig(B,txB,(z+y0)*G)\n - psig(A,txB,(z+y0)*G)\n - psig(B,txB,(z+y0)*G)\n - y0. @enduml diff --git a/md/multi-hop-locks.md b/md/multi-hop-locks.md index 8de236c..7d325eb 100644 --- a/md/multi-hop-locks.md +++ b/md/multi-hop-locks.md @@ -2,24 +2,24 @@ Multi-Hop Locks from Scriptless Scripts =========================== Multi-hop locks are protocols that allow two parties to exchange coins and proof of payment without requiring a mutual funding multisig output. -Instead, they are connected through intermediate hops such that every hop has a shared funding multisig output with the next hop. -Multi-hop locks based on cryptographic hashes instead of scriptless scripts are used in the [Lightning Network protocol version 1.0](https://github.com/lightningnetwork/lightning-rfc) to route payments. +Instead, they are connected by hopping through intermediate nodes who are connected by having a shared funding multisig output. +Multi-hop locks based on cryptographic hashes instead of scriptless scripts are used in the [Lightning Network protocol](https://github.com/lightningnetwork/lightning-rfc) to route payments. Scriptless script multi-hop locks were introduced in a [post to the mimblewimble mailing list](https://lists.launchpad.net/mimblewimble/msg00086.html) and formally defined in the paper [Privacy-preserving Multi-hop Locks for Blockchain Scalability and Interoperability](https://eprint.iacr.org/2018/472.pdf). By using scriptless scripts they result in smaller transactions which look like regular transactions and therefore improve privacy. -More importantly, they allow [payment decorrelation](https://medium.com/@rusty_lightning/decorrelation-of-lightning-payments-7b6579db96b0) which means that hops in a multi-hop lock can not determine (absent timing and coin amount analysis) if they are on the same path, i.e. they don't know if they are forwarding the same payment. -Correlation attacks are especially problematic if the first and last intermediate hops are colluding because they would learn source and destination of a payment. +More importantly, they allow [payment decorrelation](https://medium.com/@rusty_lightning/decorrelation-of-lightning-payments-7b6579db96b0) which means that nodes in a multi-hop lock can not determine (absent timing and coin amount analysis) if they are on the same path, i.e. they don't know if they are forwarding the same payment. +Correlation attacks are especially problematic if the first and last intermediate nodes are colluding because they would learn source and destination of a payment. In addition, scriptless script multi-hop locks enable improved proof of payment and atomic multi path payments (see below). Notation --- -- `Xij := (xi + xj)*G` is the MuSig-combined public key of users `i` and `j`. Note that `xi` and `xj` are MuSig-tweaked secret keys (not the secret keys of users `i` and `j`). See the [MuSig paper](https://eprint.iacr.org/2018/068.pdf) for more details. -- `nonce(i,m) := ki*G` is the public nonce of user `i` for a MuSig signature on `m` (note that we don't call nonces `R` here to avoid confusion with the right lock `R`). -- `T := t*G` is an arbitrary tweak applied to the shared nonce. -- `psig(i,m,T) := ki + H(nonce(i,m)+nonce(j,m)+T,Xij,m)*xi` is a partial 2-of-2 MuSig from user `i` with user `j` for `m`. -- `adaptor_sig(i,m,T) := psig(i,m,T) + t` -- `sig(m,T) := psig(i,m,T) + adaptor_sig(j,m,T)` is the completed 2-of-2 MuSig from user `i` and `j` (public key `Xij`). It can be computed from a partial signature and an adaptor signature. +- `Pij` is the MuSig2 aggregated public key of users `i` and `j`. See the [MuSig2 paper](https://eprint.iacr.org/2020/1261) for more details. +- `T := t*G` for a randomly chosen `t` is called the adaptor with adaptor secret `t`. +- `psig(i,m,T)` is a partial 2-of-2 MuSig2 signature from signer `i` for `m` and adaptor `T`. For simplicity the other signer isn't included in the notation; usually it's the node the signer has a channel with and clear from context. + This signature is called _partial_ because it needs to be summed with the other party's partial signature in order to become a valid Schnorr signature. + Additionally, one may call this a _pre_ partial signature because the adaptor secret `t` needs to be added before this verifies as a regular partial signature. +- `sig(m,T) := psig(i,m,T) + psig(j,m,T) + t` is the complete Schnorr signature from user `i` and `j`. Protocol --- @@ -28,62 +28,61 @@ Protocol In the setup phase the recipient chooses `z` at random and sends the sender `z*G`. The sender will set up the multi-hop locks such that a successful payment reveals `z` to her and only her. -Knowledge of `z` can be a proof of payment which is similar in concept to payment preimages in the Lightning v1.0 (see section below for details). +Knowledge of `z` can be a proof of payment which is similar in concept to payment preimages in Lightning (see section below for details). -We picture the payment starting from the sender on the left side through intermediate hops to the recipient on the right side. -The setup phase continues with the sender setting up a tuple `(Li,yi,Ri)` consisting of the *left lock* `Li` and *right lock* `Ri` for every hop `i` in the following way: +We picture the payment starting from the sender on the left side through intermediate nodes to the recipient on the right side. +The setup phase continues with the sender setting up a tuple `(Li,yi,Ri)` consisting of the *left lock* `Li` and *right lock* `Ri` for every node `i` in the following way: - Every `yi` is a scalar uniformly chosen at random. - The sender's own left lock `L0` is set to `z*G` which was previously received from the recipient. -- For every lock `Ri` for hop `0<=i Bob -> Dave). -2. Bob receives the HTLC but does not forward anything to Dave. +1. Alice sends a 10mBTC PTLC to Bob, who should forward to Dave (Alice -> Bob -> Dave). +2. Bob receives the PTLC but does not forward anything to Dave. 3. After a few blocks, Alice gets impatient and retries the payment via Carol instead of Bob (Alice -> Carol -> Dave). 4. This payment succeeds: Alice has correctly paid 10mBTC to Dave and receives a proof-of-payment. -5. However, Bob wakes up before his HTLC-timeout and forwards the first 10mBTC to Dave. -6. It's free money for Dave, so Dave accepts it and the HTLC correctly fulfills. +5. However, Bob wakes up before his PTLC-timeout and forwards the first 10mBTC to Dave. +6. It's free money for Dave, so Dave accepts it and the PTLC correctly fulfills. 7. Alice has received her proof-of-payment, but she paid 20mBTC instead of 10mBTC. This can be avoided if the payment needs a secret from the sender to be fulfilled. @@ -146,9 +131,9 @@ This solution was originally introduced as [stuckless payments](https://lists.li The sender secret is `y0+y1+y2`. Alice MUST NOT send it to Dave during the setup phase. Alice does send `(z+y0+y1+y2)*G` to Dave as his left lock, which lets Dave discover `(y0+y1+y2)*G`. -At the end of the update phase, Dave cannot create the adaptor signature because he is missing `y0+y1+y2`. -Dave can request `y0+y1+y2` from Alice (and present `(y0+y1+y2)*G` to prove that he received the HTLC). -When Alice receives that request, she knows that the HTLC was correctly forwarded all the way to Dave. +At the end of the update phase, Dave cannot create the signature because he is missing `y0+y1+y2`. +Dave can request `y0+y1+y2` from Alice (and present `(y0+y1+y2)*G` to prove that he received the PTLC). +When Alice receives that request, she knows that the PTLC was correctly forwarded all the way to Dave. She can now safely send `y0+y1+y2` to Dave which allows the settlement phase to begin. In case Dave does not reply and the payment seems to be stuck, Alice can now retry with another secret `y0'+y1'+y2'` (and potentially another route). @@ -164,8 +149,8 @@ However intermediate nodes have a much bigger incentive to be online and forward Resources --- -* [MuSig](https://eprint.iacr.org/2018/068.pdf) -* [Lightning Network protocol version 1.0](https://github.com/lightningnetwork/lightning-rfc) +* [MuSig2](https://eprint.iacr.org/2020/1261) +* [Lightning Network protocol](https://github.com/lightningnetwork/lightning-rfc) * [Scripless Scripts in Lightning](https://lists.launchpad.net/mimblewimble/msg00086.html) * [Privacy-preserving Multi-hop Locks for Blockchain Scalability and Interoperability](https://eprint.iacr.org/2018/472.pdf) * [Payment Decorrelation](https://medium.com/@rusty_lightning/decorrelation-of-lightning-payments-7b6579db96b0)