Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve swap-in protocol with taproot and musig2 #563

Merged
merged 29 commits into from
Feb 15, 2024

Conversation

sstone
Copy link
Member

@sstone sstone commented Dec 5, 2023

This PR implements an evolution of our p2swh-based swap-in that uses Musig2 and taproot for better privacy and lower on-chain fees.

Our swap-in protocol becomes user key + server key OR user refund key + delay, and is implemented with taproot which provides a clean separation between the mutual use case (handled by the internal key, which is a Musig2 aggregation of the user's and server's key) and the refund case (handled by a taproot script with a single leaf: the refund script).

Musig2 requires both parties to generate secret nonces and exchange public nonces before they can compute partial Musig2 signatures, which can then be combined into a single Schnorr signature:

  • A new optional TLV is added to TxComplete, which includes public nonces for all swap-in inputs
  • A new optional TLV is added to TxSignatures, which includes partial Musig2 signatures for all swap-in inputs

Nonces are never persisted and their lifecycle is tied to the interactive tx session lifecycle: while the session is alive, it remembers nonces that it sent before i.e if TxComplete is sent several times, nonces for the same input id will be re-used. I believe that it is safe since they will be used only once for signing.

A specific user refund key is used in the refund script: this allows us to easily rotate swap-in addresses (each time we change th user refund key) and generate a single taproot descriptor that will allow bitcoin core to find and spend (after the refund delay) all swap-in transactions for a given user (i.e for a given phoenix wallet).

This is a first step towards fixing ACINQ/phoenix#403: this new scheme makes swap-in address rotation easy to implement but this is out of the scope of this PR.

Swap-in addresses are now regular p2tr addresses, and swap-in transactions become indistinguishable from other p2tr transactions.
And since spending swap-in inputs requires a single 64 bytes Schnorr transaction (instead of 2 73 bytes DER transaction + a 77 bytes redeem script), the weight of a swap-in input is reduced by 40% for cheaper on-chain fees.

This PR is built on top of #565 because of ACINQ/secp256k1-kmp#93 but if needed changes to secp256k1-kmp and bitcoin-kmp could be back-ported to work with kotlin 1.8.

@sstone sstone force-pushed the snapshot/swap-in-potentiam-taproot branch from cf0c81b to 294b474 Compare December 6, 2023 13:41
@sstone sstone force-pushed the snapshot/swap-in-potentiam-taproot branch 3 times, most recently from 6c784da to b159915 Compare December 21, 2023 18:22
@sstone sstone force-pushed the snapshot/swap-in-potentiam-taproot branch from b159915 to 4a14bf8 Compare January 2, 2024 10:49
RECOVERY.md Outdated Show resolved Hide resolved
RECOVERY.md Outdated Show resolved Hide resolved
RECOVERY.md Outdated Show resolved Hide resolved
RECOVERY.md Outdated Show resolved Hide resolved
@sstone sstone force-pushed the snapshot/swap-in-potentiam-taproot branch from 4237120 to 3b231d8 Compare January 8, 2024 16:48
@sstone sstone force-pushed the snapshot/swap-in-potentiam-taproot branch from 49bec2e to bae7be8 Compare January 17, 2024 09:46
@sstone sstone force-pushed the snapshot/swap-in-potentiam-taproot branch 4 times, most recently from 2f2b29c to d22dfd1 Compare January 24, 2024 15:23
@sstone sstone force-pushed the snapshot/swap-in-potentiam-taproot branch 3 times, most recently from 91ea457 to 361faa9 Compare January 30, 2024 17:02
@sstone sstone force-pushed the snapshot/swap-in-potentiam-taproot branch from 4ca344d to bd7644c Compare February 1, 2024 15:28
@sstone sstone marked this pull request as ready for review February 1, 2024 15:31
Copy link
Member

@t-bast t-bast left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've opened #592 to leverage the musig2 helpers and fix my remaining open comments. Once we converge on it and merge it into this PR, I think that the code will be in pretty good shape, the only thing that will remain will be to write unit tests that exercise the musig2 swaps and fix the SwapInManager tests!

Copy link
Member

@t-bast t-bast left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, we now just need to add tests for the interactive-tx signing part using musig2 and fix the swap-in manager tests, and I think we'll be ready 🚀

@sstone
Copy link
Member Author

sstone commented Feb 5, 2024

The swap-in manager tests were failing when we experimented with not sending the full tx (I was creating wallet UTXOs manually), they've been restored now.

@t-bast
Copy link
Member

t-bast commented Feb 5, 2024

Right, that was why! That makes sense, then we just need to add tests to InteractiveTxTestsCommon to use the musig2 path and we should have everything.

@sstone sstone force-pushed the snapshot/swap-in-potentiam-taproot branch from d69d4c0 to 02d89fb Compare February 6, 2024 09:42
sstone and others added 11 commits February 8, 2024 11:58
They use taproot v1, providing the tx output and not the entire tx is safe (see #579).
Here we add the swap-in input output and txout to the swap-in TLV, so this change does not interface with proposed changes to the LN spec.
We use the musig2 helpers exposed by ACINQ/bitcoin-kmp#114
to simplify the swap-in protocol and hide all of the musig2 internal
details (key aggregation cache, control block, internal taproot key,
opaque session object, nonce aggregation).

The code is simpler to reason about and signing is more similar to
signing normal single-sig inputs.
They were disabled when we experimented with not sending the full tx.
RECOVERY.md Outdated Show resolved Hide resolved
RECOVERY.md Outdated Show resolved Hide resolved
RECOVERY.md Outdated Show resolved Hide resolved
RECOVERY.md Outdated Show resolved Hide resolved
@sstone sstone force-pushed the snapshot/swap-in-potentiam-taproot branch 2 times, most recently from 48d7454 to be62fc5 Compare February 12, 2024 14:32
Copy link
Member

@t-bast t-bast left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of typos in that recovery file 😅, but apart from that it's looking all good, I tested all those steps and everything worked fine!

RECOVERY.md Outdated Show resolved Hide resolved
RECOVERY.md Outdated Show resolved Hide resolved
RECOVERY.md Outdated Show resolved Hide resolved
RECOVERY.md Outdated Show resolved Hide resolved
RECOVERY.md Outdated Show resolved Hide resolved
RECOVERY.md Outdated Show resolved Hide resolved
@sstone sstone force-pushed the snapshot/swap-in-potentiam-taproot branch from be62fc5 to 5e18d0b Compare February 13, 2024 12:35
RECOVERY.md Outdated Show resolved Hide resolved
The current recovery process needed to be updated to derive the correct master priv key from the seed by specifying our
custom BIP32 path (m/52h/0h/2h/0) when we create the wallet.

We also export 2 descriptor methods: one to get the private swap-in wallet descriptor, which can be used as-is, and the other to get the
public swap-in wallet descriptor, which can be used to create a watch-only wallet to monitor swap-in funds and to recovery funds using our recovery procedure.

Both descriptor use the refund master key, and not the master key itself because we use hardened paths to derive the refund key, which means that it is not
possible to compute the refund master public key from the master public: importing the descriptor would fail.
@sstone sstone force-pushed the snapshot/swap-in-potentiam-taproot branch from 5e18d0b to 7d17663 Compare February 13, 2024 14:00
Copy link
Member

@t-bast t-bast left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

build.gradle.kts Outdated Show resolved Hide resolved
Co-authored-by: Bastien Teinturier <31281497+t-bast@users.noreply.github.com>
@sstone sstone requested a review from pm47 February 15, 2024 08:54
@sstone sstone merged commit 9785182 into master Feb 15, 2024
4 checks passed
@sstone sstone deleted the snapshot/swap-in-potentiam-taproot branch February 15, 2024 09:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants