Skip to content

Proposed Taproot implementation of onchain HTLC #12

@ZmnSCPxj-jr

Description

@ZmnSCPxj-jr

As requested by @nepet here: #4 (comment)

Here is a concrete implementation of the onchain HTLC using Taproot. IMPORTANT: This proposal does NOT require a MuSig2 signing ritual implementation; it only requires an implementation of the MuSig public key aggregation scheme. This has the advantage that the peerswap impl state machine requires practically no change, as there are no extra messages needed to implement the two-round MuSig2 signing ritual. In particular, this should neatly sidestep potential issues with protocol design that could render MuSig2 signing insecure such as this or this.

  • Parameters:
    • S, an ephemeral pubkey generated by the node that instantiates the HTLC and should have control of the timelock branch to recover funds in case of timeout.
      • The node should generate the ephemeral privkey s first, then compute S = s * G. s should be safe for the node to reveal without compromising its other keypairs, thus recommended to be an ephemeral privkey. In case derivation from a root privkey is needed, it could be derived using a hardened derivation at the final path element in an HD.
    • R, an ephemeral pubkey generated by the node that accepts the HTLC and should have control of the hashlock branch.
      • Similarly, the ephemeral privkey r should be safe for the node to reveal without compromising its other keypairs.
    • H, the SHA256 hash of the preimage P.
    • T, the relative timeout agreed upon.
  • Taproot output:
  • Internal pubkey is MuSig(S, R).
  • Two Tapscripts:
    • OP_HASH160 <ripemd160(H)> OP_EQUALVERIFY <R> OP_CHECKSIG - the hashlock branch controlled by R.
    • <T> OP_CHECKSEQUENCEVERIFY OP_DROP <S> OP_CHECKSIG - the timelock branch controlled by S.

We also add a new message coop_success which the sender of the onchain HTLC sends to contain s. This message SHOULD be sent any time after the sender of the onchain HTLC claims the corresponding in-Lightning HTLC, i.e. after it sends update_fulfill_htlc for the corresponding in-Lightning HTLC.

In all cases, there is no need for a MuSig2 or MuSig signing ritual in order to utilize the keypath spend path. It is enough to send the r privkey with coop_close in case of an abort (which a receiver MUST NOT send after it has offerred the corresponding in-channel HTLC and it has not been update_fail_htlced), or the s privkey with coop_success in case of protocol completion. Once one node is in possession of both privkeys, it can derive the privkey corresponding to MuSig(S, R), and use a standard single-signing Schnorr algorithm using its own compute resources.

We expect single-signing Schnorr algorithms to be simpler to implement, test, and prove secure, so we expect that we can deploy this earlier compared to relying on MuSig2 signing algorithms (and also removing protocol-related bugs when doing MuSig2 signing).

Both coop_close and coop_success would benefit from an ACK as in #6. In case of a disconnection of the TCP tunnel between the nodes, if no ack has been received, the sender of coop_close / coop_success SHOULD re-send the message on reestablishment of connection. This is not absolutely necessary for security since the hashlock and timelock branches remain valid even if delivery of the r or s privkey fails, but are important for convenience and to avoid having to reveal Tapscript branches, which degrade privacy.

This technique of "private key handover" is generally only utilizable by onchain swap / HTLC protocols, where possession of the entire UTXO is taken by one or the other participant in a 2-participant protocol. The technique does not easily generalize to other protocols and is potentially insecure outside of swap protocols. As peerswap is a swap protocol it is safe to use "private key handover", and simplifies implementation and state machines involved.

Corresponding cases for aborting via the timelock branch, or force-claiming via the hashlock branch, use the obvious approach and will not be described in further detail.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions