ElementsProject / peerswap-spec

6 stars 3 forks source link

send a signature instead of a private key for cooperative closes #4

Open remyers opened 1 year ago

remyers commented 1 year ago

It seems odd at first that the coop_close message (sent by the swap taker) contains a private key.

This should be safe because the swap taker must create a random private key for each swap (not derived from an HD wallet). This simplifies the protocol because the swap maker can create the claim_by_coop transaction immediately without further communication with the swap taker.

An alternative approach would be for the swap taker to send a signature signed with SIGHASH_NONE | ANYONECANPAY. With this approach, the swap taker would not have to create a random private key for each swap, but could safely use an xpub scheme to derive their key. This could simplify backups because they do not need to synchronously backup a random private key for each swap; a derived key can be restored by iterating a predefined xpub branch. On the other hand, if the taker loses the <preimage> or <redeem_script> of a swap, it won't matter if they can recover their private key. The taker must always back up some information for each swap.

ZmnSCPxj-jr commented 1 year ago

Hardened derivation should allow revealing of the derived privkey without leaking the root privkey.

I think you should consider privkey handover in the success case, as that lets the taker arbitrarily decide a new destination for the funds later, until just before the onchain timelock expires. This is useful if a peerswap has to terminate at your node (e.g. not enough CLTV budget to forward further) and you want to continue the peerswap anyway, letting the onchain HTLC immediately fund a new onchain HTLC without an intervening singlesig address.

remyers commented 1 year ago

Good point about hardened HD paths.

Do you mean that the maker should send a new coop_success message (similar to coop_close from the taker) after the off-chain payment has been completed?

Why is it better for the taker to fund a new swap output by spending a previous swap output with two signatures instead of a signature and pre-image? I must be missing something.

Do you mean that the previous swap output would directly fund a second swap ? That doesn't seem possible because the CSV timeout would be sooner and there could be a race for the claim-by-csv path with the maker of the original swap.

ZmnSCPxj-jr commented 1 year ago

Why is it better for the taker to fund a new swap output by spending a previous swap output with two signatures instead of a signature and pre-image? I must be missing something.

It is not better now, but once we switch to Taproot we will want this. The obvious Taproot construction is that the 2-of-2 is the internal pubkey and we have a Tapscript with the hashlock branch, and pre-sign an nSequenced transaction for the timelock branch. With private key handover via coop_success, the receiver can generate a single keypath spend signature, vs a Tapscript revelation + signature + pre-image. This is at least a reason to not design our software to make private key handover risky, since once we switch to Taproot we want the privacy gain and reduced onchain footprint and using non-hardened derivation where we cannot safely hand over private key would need to be redesigned later.

Now of course the sender and receiver can still just MuSig to a particular address the receiver wants, but MuSig and MuSig2 is two-round, whereas handing over the private key is just a one-sided send. And handing over the private key allows the receiver to defer its decision until much later (at least before the timeout), e.g. it can now decide by itself where to send the funds even if the sender goes offline.

nepet commented 1 year ago

Taproot will be supported eventually, let’s gather tapscript related thoughts in a separate issue to not confuse with the current protocol maybe, or is this the issue that collects thoughts and tapscript proposals? In this case we may want to rename the issue to be more descriptive that the discussion here is taproot related.

ZmnSCPxj-jr commented 1 year ago

Not quite, but planning to use non-hardened derivation does conflict with the post-Taproot technique private key handover, so even if you make a new issue you still need to link it here.

ZmnSCPxj-jr commented 1 year ago

As I realized later in https://github.com/ElementsProject/peerswap-spec/issues/12#issuecomment-1280123443 it can actually be better now (pre-Taproot) to instead use private key handover in both coop_close and coop_success cases. Instead of using <2> <R> <S> <2> OP_CHECKMULTISIG just use <MuSig(R, S)> OP_CHECKSIG. MuSig(R, S) is just hash(R) * S + hash(S) * R and that can be computed just as well for ECDSA as for Schnorr (the fact that "MuSig" can refer to both a public key aggregation scheme, and a multi-participant signing algorithm for Schnorr sigs, is confusing, but blame it on the MuSig authors \^\^; I am using MuSig here to refer to the public key aggregation scheme). Once you know both corresponding privkeys r and s, you can compute hash(r * G) * s + hash(s * G) * r and then single-sign it, regardless of using ECDSA or Schnorr. This drops your 2-of-2 cooperative branch from 2-of-2 to 1-of-1 and saves one signature. This is a distinct advantage: just one signature vs signature+preimage.

So yeah "send the privkey for cooperative successes also".