Monero-BCH Atomic Swaps

BTC-XMR atomic swaps are now live on their mainnets. I have been talking with some Monero developers about how BCH-XMR atomic swaps could be implemented. They say they do not think it is possible without SegWit.

Is this true? If it isn’t true, then it could be good to demonstrate that BCH can do XMR-BCH atomic swaps without SegWit. However, I am not in a position to implement an atomic swap capability nor even really understand the technical details of how it might be done. I can provide the Monero developer’s discussion contact upon request if there is interest in this.

1 Like

I’m not sure why there’s any fundamental reason it cannot be done without segwit, my best guess is that they might have built their swap implementation for segwit and are unwilling to adapt it for BCH.

A multisig spend is used in the middle of a TX chain, after which a pre-signed TX must be used to recover funds. If the counterparty malleates the multisig spend using an alternative signature, the pre-signed TX will be rendered invalid, making one party unable to claim their funds. After they don’t claim their funds for a long enough period of time, the counterparty is allowed to. This means any attempt at the atomic swap protocol when signatures contribute to the TX ID allows one party to unilaterally steal funds.

1 Like

I just reread the intended use of Schnorr signatures in regards to BCH and have to say I initially misunderstood it. That is on me. While I have to double check the specifics of Schnorr-usage from Script, a modified set of scripts should theoretically exist enabling this.

Then yes, all third party vectors should no longer exist. I also reviewed PMv3 (relevant thread immediately available), whose detached signatures do still contribute to the TX ID, and noted that despite a brief moment otherwise, they are not intending to introduce further malleability. I also noted the following thread discussing malleability as a whole Transaction malleability: MalFix, SegWit, SIGHASH_NOINPUT, SIGHASH_SPENDANYOUTPUT, etc. It was created a while after the relevant fixes, and is generally ignorable, but I do want to mention it to emphasize why a lack of malleability is so important.

Sorry for initially saying otherwise, and I’ll try to review the exact details of Schnorr-utilizing Scripts later.

I have created a bounty for BCH<>XMR atomic swaps. Right now the bounty is sitting at 1 XMR. You can contribute XMR to the bounty pot here:

3 Likes

Would be cool if it was possible to also contribute using BCH.

1 Like

We could have a parallel BCH bounties system, but there is no central hub for that now, I think. There are a few BCH-based Fiverr-like systems, I believe, although these types of bounties probably aren’t a good fit for it.

Copying from my comment on the bounty website:

I have established a BCH address for donations for this bounty. I will personally custody the funds and release them to whoever completes the bounty requirements. The address is:

bitcoincash:qrm0snx7l9kakt6lmzdpyupwryjktr47au6004uwyp

You can check the total donation amount in this BCH block explorer. The corresponding QR code is also available at this link:

https://blockchair.com/bitcoin-cash/address/qrm0snx7l9kakt6lmzdpyupwryjktr47au6004uwyp

A test transaction to the address is available here (check the OP_RETURN) : https://blockchair.com/bitcoin-cash/transaction/ec1598e29938836825477425dba43e654492adff8e8a6942f9febfa306f26ca5

Statement:

++++++++++++++++++

I, Rucknium, solemnly swear to release these funds to the person or persons who fulfills the requirements for the BCH<>XMR Atomic Swaps bounty at https://bounties.monero.social/posts/37/bch-xmr-atomic-swaps The Times 23/Nov/2021 Hong Kong student Tony Chung jailed for wanting independence

++++++++++++++++++

Signature of the above statement with the private key of bitcoincash:qrm0snx7l9kakt6lmzdpyupwryjktr47au6004uwyp

++++++++++++++++++

H9weHELZUa7rpGQFbUF8YYcU39ojN72GxJnGC3Hy5GqvAq1AcXEgGD4CZIIuLSKlwnX2WFHEliUKSTeu1710kcw=

++++++++++++++++++

2 Likes

Is the REFUND spend described in the paper the problem?

The descendant TX is pre-signed and so if the same party malleates the parent then it invalidates its own signature in the descendant?

If yes, then this is solvable - we can use introspection opcodes (activated in May '22) to emulate SIGHASH_ANYPREVOUT (APO) so descendant TX’s signature would be valid even if prevout TXID changes - the spender would simply have to update the prevout TXID in the TX, and the signature would still be valid.

1 Like

I think these should work. If anyone tries to rug any child transaction, the other party can simply update the child with new prevout reference, because the signatures for the custom sighash will still be valid.

Here’s a link to BitauthIDE template using the scripts below.

SWAPLOCK

// Alice has XMR, wants BCH
// Bob has BCH, wants XMR

// Build custom sighash
OP_INPUTINDEX OP_UTXOVALUE
OP_INPUTINDEX OP_UTXOBYTECODE OP_CAT
OP_INPUTINDEX OP_OUTPUTVALUE OP_CAT
OP_INPUTINDEX OP_OUTPUTBYTECODE OP_CAT
OP_SHA256

OP_SWAP
OP_IFDUP
OP_IF
    // Verify Bob's hashlock
    OP_SHA256
    <$(<secret_hashlock> OP_SHA256)> OP_EQUALVERIFY

    // Verify signatures
    <key_alice_revealing.public_key> OP_OVER
    <4> OP_ROLL OP_SWAP OP_ROT OP_CHECKDATASIGVERIFY
    <key_bob_revealing.public_key> OP_CHECKDATASIG
OP_ELSE
    // Verify refund timelock
    <timelock_0> OP_CHECKSEQUENCEVERIFY OP_DROP

    // Verify refund signatures
    <key_alice.public_key> OP_OVER
    <4> OP_ROLL OP_SWAP OP_ROT OP_CHECKDATASIGVERIFY
    <key_bob.public_key> OP_CHECKDATASIG
OP_ENDIF

Buy SWAPLOCK

<key_alice_revealing.data_signature.swaplock_swap_sighash>
<key_bob_revealing.data_signature.swaplock_swap_sighash>
<secret_hashlock>

Refund SWAPLOCK

<key_alice.data_signature.swaplock_swap_sighash>
<key_bob.data_signature.swaplock_swap_sighash>
<0>

REFUND

OP_IFDUP
OP_IF
    // Build custom sighash
    OP_INPUTINDEX OP_UTXOVALUE
    OP_INPUTINDEX OP_UTXOBYTECODE OP_CAT
    OP_INPUTINDEX OP_OUTPUTVALUE OP_CAT
    OP_INPUTINDEX OP_OUTPUTBYTECODE OP_CAT
    OP_SHA256

    // Verify signatures
    OP_DUP OP_ROT
    <key_bob_revealing.public_key>
    <2> OP_ROLL OP_SWAP
    OP_CHECKDATASIGVERIFY
    <key_alice_revealing.public_key>
    OP_CHECKDATASIG
OP_ELSE
    // Verify grace period timelock
    <timelock_1> OP_CHECKSEQUENCEVERIFY OP_DROP

    // Verify Alice's signature
    <key_alice.public_key> OP_CHECKSIG
OP_ENDIF

Spend REFUND

<key_alice_revealing.data_signature.refund_complete_sighash>
<key_bob_revealing.data_signature.refund_complete_sighash>

Claim REFUND

<key_alice.schnorr_signature.all_outputs>
<0>
1 Like

Sounds reasonable. Would like much more documentation in the contract itself to understand the primary intent, all the exploits and edge cases it is avoiding and how they are being covered.

2 Likes

The mechanics are basically the same as the contract described in the paper: https://raw.githubusercontent.com/h4sh3d/xmr-btc-atomic-swap/master/whitepaper/xmr-btc.pdf

It would be cool if paper’s author (h4sh3d) would review this contract here.

Thing is, child TX-es get signed before the parent. Parties only sign the parent once they verified children are signed correctly, and then the parent gets mined. With SegWit, it’s not vulnerable to 2nd party malleability, but on BCH it would be. So, I make the child TX-es signatures malleable too, so that link to parent can be updated without breaking the signature.

1 Like

Also, I should have added a disclaimer: this is not intended as a production version, but as proof-of-concept to get the ball rolling.

One edge-case is malleability of fees (which could be closed with few more opcodes to tighten the TX). Bob could malleate the funding TX, and post his version of children to the mempool first and add 1 more input and output to ensure the fee will be minimum. Shouldn’t be an issue on BCH, but the possibility is there - and we can close this option, or use it as a feature, we could have these custom preimage signatures sign for the exact amount going from the input to output, and then either party could fund the TX with an extra input to pay for the fees - something not possible with BTC version :smiley:

Because of malleability, it’s extra work on the app stack too, because they have to monitor for the possibility of parent’s TXID being changed and update the children accordingly.

1 Like

I have improved the contracts to make full use of covenants, code is available at the link.

Significant bytecode size savings are achieved!

bytecode v1 size v2 size difference
SWAPLOCK 206 140 -66
Buy SWAPLOCK 177 74 -103
Refund SWAPLOCK 144 0 -144
REFUND 130 113 -27
Spend REFUND 143 72 -71
Claim REFUND 67 66 -1

Cross-chain Atomic Swap With Bitcoin Cash Using One-Time Verifiably Encrypted Signatures

v2.0.0

Based on:

License

MIT No Attribution

Transaction malleability breaking the chain is. I believe 2-party Schnorr has no malleability and would be sufficient. Introspection may be another path forward.

Regarding your scripts, I don’t want to sign off on them due to their complexity, sorry. I can, immediately, note that since adaptor signature swaps leak a private key, they can’t reuse public keys. Accordingly, building a custom sighash should only require committing to bytecodes, not to values, if you want to micro-optimize this.

2 Likes

Hey, thanks for the prompt feedback!

Yup, wrapped my head around it in the meantime. On BCH, signatures are 1st/2nd party malleable but, as demonstrated above, we can mitigate that by excluding parent TXID(s) from descendant signatures, so e.g. Bob posting a malleated funding TX can’t invalidate the pre-signed Refund path - because Alice can just update the pre-signed TX prevout ref. and Bob’s signature will continue to be valid.

2nd party maleability is still the problem - the 2nd party can roll another signature with a different random value, and post that TX instead of the agreed one, and with that invalidate any pre-signed children which would block the refund path, since, without SegWit, the signature is included in the TXID calculation.

Yes, see v2 of the contract (didn’t want to clutter by posting the code here).
Introspection enforces forwarding BCH to the correct recipient (either P2PKH constructed from either party’s key, or forwarding to Refund contract) + require a data signature to reveal the XMR share.
The covenant / introspection approach not only has significant size savings but also makes the TX chain more tight, I use it to enforce 1in-1out TX form, and commit to the fee while at it.

Yup, that’s why in the refund contract’s recovery path (if Bob diappears) we have to use another key for Alice, a non-leaking one.
Also note that in my contracts the signatures are replayable, so swap & refund keys must be considered one-time for that reason, too.

See the v2, we don’t really need to sign anything since we can enforce BCH balance flow with covenant / introspection opcodes, in which case the purpose of the data signature is just to unlock the spending path & force the party to reveal their XMR share.
The revealing signatures could really be signing whatever message, but the message needs to be known in advance for the VES to work, right? So I just make the output bytecode immutable (covenant) & require a signature of just the output’s bytecode as the message.

I have created a repo for these, here:

And I have coded a version (referred to as v3) in CashScript, too. It is slightly bigger when compiled, but the advantage is possibility of using CashScript tooling for application development.

Swaplock: contracts/v3/swaplock.cash · master · ac-0353f40e / cross-chain-swap-ves · GitLab

Refund: contracts/v3/refund.cash · master · ac-0353f40e / cross-chain-swap-ves · GitLab

1 Like

I’ve noticed you talk about various malleability concepts online and I have yet to figure out what it is you are talking about.

Maybe I can start with what my position / understanding is.

You use “1st person malleability” sometimes, which is a term that feels acadamic or technical, but not really useful. Like you can’t call “breaking and entering” when you use your own key on your own front door.
1st person would be the owner of the private key re-signing the input. Not really malleability.

2nd person, as quoted above, as I understand the quoted part, is about an unconfirmed input being double spend, with the intention to make your transaction invalid and you need to re-sign to follow that change.
Similar to the above, this is not malleability. This is double spending.

Malleability is defined as a valid (signed) transaction being modified in a way that changes its TXID, but does NOT invalidate its signatures and thus allowing it to be mined in its new form, with the new TXID.

I am not aware of any way to malleate a normal p2sh or p2pkh transaction. Multisig is a bit tricky, but malleating without any of the signers being in on it is also as far as I know not possible.

Malleability for all the important cases has been solved years ago on BCH, no?

1 Like

Yup, and on BCH we closed off 3rd party malleability.

If you and me sign a 2/2 then you’re my “2nd party” and from my PoV I’m the “1st party”. Our signatures are independent, meaning any party can reroll their own signature to change the TXID without having to get a new signature from the other party.

This means I can double-spend a 2/2 all by myself and invalidate the whole graph of descendant transactions, and that would be a problem for the original swap scheme outlined in the paper, for the same reason it would be a problem for Lightning Network: they use multisig to emulate covenants.

We can work around the issue of invalidating descendant transactions by using proper covenants - which can be coded such that they allow updating the prevout refs without breaking any signature, meaning the descendant transactions graph could be reconstructed if the parent gets double-spent, without needing updated signature from the other party.

Any other type of “malleability” you described in this thread doesn’t fall under the definition of malleability. Any TXID change that requires access to private key is not malleability.

It typically is just scamming / double spending / updating-the-tx. Whatever is appropriate.

Re-using a known term that is still active in the crypto space to mean something different doesn’t feel right. It certainly confused me, and I expect it to cause confusion in others too.

1 Like