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

Reduce trade protocol to 1 single transaction #279

Closed
sqrrm opened this issue Nov 7, 2020 · 19 comments
Closed

Reduce trade protocol to 1 single transaction #279

sqrrm opened this issue Nov 7, 2020 · 19 comments
Labels
an:idea https://github.com/bisq-network/proposals/issues/182#issuecomment-596599174 re:features re:protocol was:approved

Comments

@sqrrm
Copy link
Member

sqrrm commented Nov 7, 2020

This is a Bisq Network proposal. Please familiarize yourself with the submission and review process.

This idea relates to the efforts to reduce the number of transactions in a trade as suggested in #265. This is not a suggestion to implement this scheme, merely describing the possibilities available.

Core of current scheme

With the removal of taker and maker fee transactions as suggested in #265 there are still two transactions left as part of the happy path of the trade protocol, the deposit transaction where traders lock up funds in a 2of2 output, and the subsequent spending of that output to the traders payout addresses. In the unhappy path there are more transactions, where the 2of2 output is spent to the donation address and further actions are needed to recover the funds. An idea to improve on the recovery scheme is described in #275.

Single tx scheme

The core of the idea is to lock up funds with a deposit tx with two outputs, one that can be spent by Alice and one that can be spent by Bob, but Bob holds a secret needed to spend Alice's output and Alice holds a secret needed to spend Bob's output. There is also an optional spending path, with a 2of2 by Alice and Bob. All other outputs from the the deposit tx, such as fees and change do not affect this scheme and are not considered in this description.

Trade steps

  1. Alice and Bob generate a secret nonce each, N_a, N_b respectively. They share a hash of their nonce with each other, ie, Alice sends hash160(N_a) = H_a to Bob and Bob sends hash160(N_b) = H_b to Alice.
  2. The deposit tx is created taking inputs from Alice covering her part of the trade amount and deposit and from Bob covering his part. Two outputs are created, the first, D_a, that can be spent either by knowing N_a, N_b and Alice's privKey, or by a 2of2 of Alice and Bob. The second, D_b, can be spent by knowing N_a, N_b and Bob's privKey, or by a 2of2 of Alice and Bob. The scripts would look like this (my best attempt at Bitcoin scripts)
OP_HASH160 H_a OP_EQUALVERIFY OP_HASH160 H_b OP_EQUAL
OP_IF
   OP_DUP OP_HASH160 <AlicePubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
OP_ELSE
   2 <AlicePubKey> <BobPubKey> 2 OP_CHECKMULTISIG
OP_ENDIF
OP_HASH160 H_a OP_EQUALVERIFY OP_HASH160 H_b OP_EQUAL
OP_IF
    OP_DUP OP_HASH160 <BobPubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
OP_ELSE
    2 <AlicePubKey> <BobPubKey> 2 OP_CHECKMULTISIG
OP_ENDIF
  1. Alice and Bob sign a delayed payout tx that spends both of the outputs D_a and D_b in one transaction, using the multisig criterion, to the donation address.
  2. When the trade is completed, Alice sends N_a to Bob and Bob sends N_b to Alice. If Bob refuses to share his nonce, there are two ways to proceed. If he spends his output, D_b using the nonce path, his nonce will be visible onchain. If he doesn't spend his output, the delayed payout tx can be published. The delayed payout tx cannot be spent after either output is spent since they're both required as inputs to the delayed payout tx.

Considerations

This scheme allows for a single transaction to perform the full trade, with some caveats. If neither trader wants to move their coins after completing the trade there is a risk that the delayed payout tx could be published. There is however no incentive to do so, except to cause trouble, and it could only be done after the delay timeout. Once one trader has moved their coins, the other can safely leave their coins as they can only be spent using the nonce option.

Another point is that the deposit tx is now larger. If traders were to feel the need to spend their output immediately to protect against the delayed payouttx attack there would be no benefit in the number of transactions.

@stejbac
Copy link

stejbac commented Nov 8, 2020

That's very interesting - I was vaguely thinking of a scheme along similar lines recently, but exchanging 2-of-2 private keys instead of nonces, plus attempting to use some kind of cryptographic technique to reveal Alice/Bob's nonce/private key from the leaking of their public key (in witness data) when they unilaterally spend, rather than using a custom script. But thinking further, that idea probably wouldn't work because the payout public keys are always part of the delayed payout tx signature anyway (so would be known to both parties). I believe there are nevertheless cryptographic techniques to cut down the tx sizes further, if one is determined enough to do so.

One way to help deter nuisance publishing of the delayed payout tx, after the trade, may be to use two alternative (say custom p2wsh) half-way addresses to temporarily hold the disputed funds (so creating staged delayed payouts, a little similar to the ideas in #275). Then after a further mandatory delay, the funds could be unilaterally sent to the donation address. The parties would produce two punishment tx's that would pay the entire deposit from each respective half-way address to the other party, in the event that a party's nonce was revealed, as there would never be any reason to do that while the trade is still open.

One might want 3 nonces for that, in alternating requests starting with the buyer, such that the first two unlock the respective payout UXTOs for normal spending and the last two unlock the punishment tx's. The last message would just be a "courtesy" nonce sent by the buyer, with no real way of ensuring it's receipt. (Also, the buyer's first nonce could I think be sent as soon as he starts the payment, which has the advantage of not requiring him to be online when the seller releases.)

The purpose of the half-way addresses would be to provide a hard guarantee that the funds are really yours after the trade closes, even in the unlikely event of the refund agent being corrupt/uncooperative after a nuisance delayed payout, plus avoiding the need to go through the refund agent in the first place.

@MwithM MwithM added an:idea https://github.com/bisq-network/proposals/issues/182#issuecomment-596599174 re:features labels Nov 8, 2020
@stejbac
Copy link

stejbac commented Nov 9, 2020

I was thinking further about the above problem of exchanging 2-of-2 private keys directly in place of nonces (caused by the delayed payout tx signature containing Alice's and Bob's payout public key(s), and therefore being unable to use any of the latter as effective keys to unlock the other party's funds). There may be a solution whereby the traders create and sign a delayed payout tx that moves just the buyer's (say Alice's) UXTO to an intermediate 2-of-2 address, together with a second, non-timelocked tx that moves both funds onward to the donation address. The latter is created in such a way that Alice doesn't learn Bob's public key when signing it (and thus only Bob holds the fully signed tx) - some special cryptographic techniques involving zero-knowledge proofs might be needed there. That way the seller (say Bob) can first move Alice's UXTO to the intermediate address in the case of a dispute and wait for it confirm. Then sending both funds onward won't have the side effect of releasing Alice's payout.

If Alice wants to raise a dispute, she would first move her funds to the intermediate address. At that point it becomes a little tricky - Alice would need to hold Bob's public key for his UXTO (which was redacted from the signature of the payment to the donation address) in an encrypted form. This would need to be decrypted by a third party, say the donation address holder himself, who would refuse to do so until at least 10 days had passed or the movement of her funds to the intermediate address had confirmed. Without that protection, she could run off with her payout before starting fiat payment to Bob. So unfortunately this weakens the security a bit, back towards that of the old arbitration scheme, as collusion between the buyer and the third party (arbitrator / donation address holder / etc.) would allow immediate theft of most of the funds.

In the happy path, when Alice starts payment, she would just send her private key to Bob's UXTO straight to him. (It would need to be a hardened private key if it had a BIP32 derivation path.) He would release either by spending his UXTO or sending Alice his public key to his UXTO (which is revealed by any spend of the UXTO). From this, Bob's private key to Alice's UXTO could be calculated, say by having provided him with the private key (at the start of the trade) AES encrypted with the public key. For this to work, i.e. that Bob won't just get gibberish upon decryption, a zero knowledge proof is required.

So using zero knowledge proofs (which would be exchanged at the start of the trade), it should be possible to use standard 2-of-2 multisig p2wsh payout addresses for Alice and Bob, in place of custom payout scripts. In fact, using the secure two-party ECDSA signing algorithm described in #275 or the papers mentioned therein, I believe it would be even be possible to use a deposit tx with just two ordinary p2wpkh payout addresses for Alice and Bob. This would result in further tx size reductions and hopefully enhanced resistance to chain analysis. (There may be further elaborate techniques one could use to hide entropy in the payout outputs to avoid having to use an OP_RETURN output for the contract hash.)

If the aforementioned security weakening towards that of the old arbitration scheme is unacceptable, I think the best you could probably do is one p2wpkh output for the buyer and one 1-of-2 multisig p2wsh output for the seller. There might be a way round using time-lock puzzles (e.g. repeated RSA modular exponentiation) that the buyer needs to take days to complete in order to send the funds to the donation address. But I'm not sure that's practical, due to there possibly being a large speed variation between an ordinary CPU and dedicated hardware for solving the puzzle.

@chimp1984
Copy link

If neither trader wants to move their coins after completing the trade there is a risk that the delayed payout tx could be published. There is however no incentive to do so, except to cause trouble, and it could only be done after the delay timeout.
Another point is that the deposit tx is now larger. If traders were to feel the need to spend their output immediately to protect against the delayed payouttx attack there would be no benefit in the number of transactions.

Yes thats unfortunately probably an issue. The larger deposit tx + at least one transfer tx might be same or even bigger than deposit tx +payout tx (if we can get rid of maker and taker fee tx).

@chimp1984
Copy link

chimp1984 commented Nov 9, 2020

In fact, using the secure two-party ECDSA signing algorithm described in #275

I think you wanted to reference #278

avoid having to use an OP_RETURN output for the contract hash

I think we could drop that as well. I guess that was a bit of "overengineering" and never practically used... Though it is cool to have the hashed contract signed by both on the blockchain. Kind of blockchain-legal construct.

@sqrrm
Copy link
Member Author

sqrrm commented Nov 9, 2020

@stejbac Thanks for your thoughts on this. I don't think it's good to introduce further reliance on a trusted third party so I wouldn't go down that route. It also would make the scheme less reliable since this third party would have to be reachable.

I do like the idea of the intermediate step for the delayed payout. There could be an option to spend your own output from this intermediate step if the nonces have already been exchanged. @chimp1984 That way it's safe to leave outputs unspent once you have the nonce. If the delayed payout tx is spent, either party could spend their respective output before the next, time delayed step of the delayed payout sequence can continue. Still requires watching the chain though.

On exchanging private keys, I don't get how it is supposed to work. If you can't share them in an atomic swap somehow, then it would be possible for one party to abscond with the funds. Perhaps that's part of #278 that I didn't really understand.

@sqrrm
Copy link
Member Author

sqrrm commented Nov 15, 2020

After answering some questions about how easy it is to trace the funds onchain with the current trade protocol I thought how that could be improved. Just having one transaction for the trade would be good, but using any kind of specialized script would obviously make it stand out. Then there would be the fees, either as BTC to a specific address, or as BSQ. Feels hard to avoid creating transactions with a very specific signature if the fees are to be included in the same transaction.

@chimp1984
Copy link

Maybe Taproot could become useful once activated?

@sqrrm
Copy link
Member Author

sqrrm commented Nov 18, 2020

If we move to some alternative way of paying fees, perhaps in a batch with some proof of payment as discussed a while back or anything that doesn't publicly link the trade tx to the fees, then there might be something we can do.

The problem is that the one tx trade relies on revealing the nonce as part of spending. That is rather specific. If we could get around that with some atomic information swap with some zero knowledge magic, then I think it's possible to embed that into a tweaked pubkey to make a normal spend, with the alternative merkle tree spending path having the 2of2 spend to prepare the delayed payout transaction.

I don't know enough crypto to devise such a scheme, but perhaps @stejbac does.

As long as the fees are part of the trade tx there would still be space savings in using taproot for the less likely script paths so it's not pointless to think about it. Step one would be to get taproot activated though, let's see how long that takes. With segwit in memory I don't think there is any need to rush this.

@chimp1984
Copy link

chimp1984 commented Nov 19, 2020

The main problem with privacy will still be the coin merge and connecting the output to the next trade input. I think CoinJoin is the only real help to get rid of that in Bitcoin. The additional attributes that the tx is easier detectable and that there are fee inputs which also help to connect trades if coines where merged and further spent just adds up to the base problem. Motivated users have always the option to separate the trades at costs of convenience and miner fees in the current protocol and this new proposed one (with or without Taproot and with or without trade fees).

Excluding the trade fee might be a new challenge similar to off chain trade protocol idea and the recently proposed idea in #281 seem to come with too many downsides conceptually.

So maybe better to focus on solving one hard problem at a time and reducing 4 txs to 1 tx is already a big achievement if we can get there. Once Taproot is activated and provides futher improvement capabilities I think a protocol update to Taproot will be not that disruptive.

@Conza88
Copy link

Conza88 commented Mar 3, 2021

Really supportive of this, just a ton of how is way over my head. So anything I can do to help (cheer from the sidelines?) let me now.

@chimp1984
Copy link

chimp1984 commented Apr 24, 2021

@sqrrm @stejbac
I tried to recap the whole concept. Please let me know if my conclusion is correct and if it represents the latest state of the discussion.
There has been some discussion to use private keys instead of the nonces but I am not sure if a solution has been found with that approach.

Preparation:

Alice:
Creates nonce: N_a
Sends hash h(N_a) = h_a to Bob

Bob:
Creates nonce: N_b
Sends hash h(N_b) = h_b to Alice

Deposit tx:

We want to keep the utxos for both traders separate so that they can spend it independently anytime later, thus not requireing a payout tx. The utxo can be used for funding the next deposit tx.
If one has spent their utxo they reveal their nonce so the peer can spend as well their utxo even if they failed to exchange the nonce.
The second path (the 'else' in bitcoin script) is being used to get spent by the staged delayed payout transactions.

We let Alice selling 1 BTC and use 0.1 BTC security deposit for both sides.

Deposit tx:
Input 1: Alice 1.1 BTC
Input 2: Bob 0.1 BTC
Output 1: 0.1 BTC Path 1: both nonces are known and funds go to address of Alice
Path 2: 2of2 Multisig
Output 2: 1.1 BTC Path 1: both nonces are known and funds go to address of Bob
Path 2: 2of2 Multisig

Trade protocol:

  1. After deposit tx is confirmed Bob sends fiat/altcoin to Alice. She also sends her nonce to Alice. If Alice would use the nonce he would learn her nonce as well.
  2. After Alice has received fiat/altcoin she sends her nonce to Bob.

If anyone does not send the nonce to the peer they can either wait until the peer spends the utxo and reveal the nonce or publish the staged delayed payout txs, thus putting pressure on the peer to react or bringing it to arbitration.

If both have revealed their nonce they can leave their output unspent until needed, but they have to observe the blockchain that the peer is not starting to publish the staged delayed payout txs.

Staged delayed payout tx:

To avoid that one triggers a delayed payout tx to the burningman while both have exchanged the nonce and are just keeping the output unspent we can use a staged chain of txs.
The first is to signal the peer that they need to act. They have to observe the blockchain to get notified and if they spot an announcement tx they can either spend the utxo with the nonces, thus rendering all follow up txs invalid by consuming the utxo, or use the burn tx to send the funds to the burningman if they don't have the nonces.
This protects against getting the funds burned after a completed trade at the cost of needing to publish the tx earlier as intented.
If any party does not respond the active peer can avoid the need to go through arbitration and DAO refund by publishing the refund tx to themself.

Staged txs for avoiding burningman/arbitration

Alice's announce tx: Txa1
Input 1: depositTx:0 path 2
Input 2: depositTx:1 path 2
Output 1: 0.1 BTC Path 1: both nonces are known and funds go to address of Alice
Path 2: 2of2 Multisig
Output 2: 1.1 BTC Path 1: both nonces are known and funds go to address of Bob
Path 2: 2of2 Multisig
Timelock: 10 days

Bobs announce tx: Txb1
Input 1: depositTx:0 path 2
Input 2: depositTx:1 path 2
Output 1: 0.1 BTC Path 1: both nonces are known and funds go to address of Alice
Path 2: 2of2 Multisig
Output 2: 1.1 BTC Path 1: both nonces are known and funds go to address of Bob
Path 2: 2of2 Multisig
Timelock: 10 days

Trader takes all if other does not react in time

Alice takes all tx: Txa2
Input 1: Txa1:0 path 2
Input 2: Txa1:1 path 2
Output: Alice address
Timelock: relative 5 days after Txa1

Bob takes all tx: Txb2
Input 1: Txb1:0 path 2
Input 2: Txb1:1 path 2
Output: Bobs address
Timelock: relative 5 days after Txb1

Avoid the peer takes all and got to arbitration

Bobs intercept tx: Txb3
Input 1: Txa1:0 path 2
Input 2: Txa1:1 path 2
Output: donation address
No timelock

Alice intercept tx: Txa3
Input 1: Txb1:0 path 2
Input 2: Txb1:1 path 2
Output: donation address
No timelock

Conclusion

If we do not find a way to construct the deposit tx so that it is significantly smaller I fear the size will be maybe even bigger or at least not much smaller like using a payout tx. The added complexity would be only justified if the reduction in miner fees is big enough.

The staged delayed payout transactions adds also quite a bit of complexity and the sequence of the signature exchange in the protocol is a critical element to consider as well (to mitigate risk if one peer stops cooperating in the process of constructing the full tx chain). If the txs need to be created in sequence it would add several roundtrip messages to the protocol increasing risks and slowing the process down.

The requirement to observe the blockchain also adds a serious risk and complexity. In fact there is an incentive to try to steal the funds by going the announcement path and if the peer fails to react in time to consume all funds. Removing the option to send to one self would make it more safe. But even then it could be problematic if the user is offline for an extended time as they would miss communication with the arbitrator which might lead that the malicious peer gets reimbursed and the honest user finds out too late that his unpublished utxo got burned.

Avoiding arbitration cases from non-responders would be still a good feature but the cost/benefit should be checked by getting data from arbitrators about the number of such cases.

@sqrrm
Copy link
Member Author

sqrrm commented Apr 24, 2021

I think this is a fair recap.

The size of the deposit tx would be larger than the current deposit tx but I think smaller than the two txs needed if we were to just remove the trade fee txs in the current protocol. Once taproot is available it would be possible to hide the branches of the script and only the default payout option shown which would reduce the size further and also make the txs more generic and not as easy to distinguish as Bisq txs.

I'm not quite clear on the cryptography but I have a feeling it might be possible to use @stejbac's suggestions with Schnorr signatures and make this protocol indistinguishable from a normal 2 input 3 output tx, except that the trade fee output would be recognized as the donation address.

I see a clear benefit for frequent Bisq users that could use the output from one trade as the input to the next and thus finalize the previous trade by initiating a new one. I would describe the unspent outputs from a completed trade as unsafe until one of them are spent. Perhaps suggesting that infrequent Bisq users spend the output to secure their funds if the counterparty hasn't spent their side. If an infrequent user trades with a frequent user the benefit of the single tx protocol is there for both of them as soon as one party has spent their output, which is likely to happen quickly since one of them is a frequent trader.

@hodlwave
Copy link

This is a great idea @sqrrm.

I'm not a cryptography expert, but I think the protocol would benefit from a combination of Taproot and MuSig2 to greatly reduce the cost of either party spending their Deposit Tx output in the happy path.

Extending the example @chimp1984 provided above where Alice is selling 1 BTC to Bob and we use a 0.1 BTC security deposit.

Deposit tx:

Input 1: Alice 1.1 BTC
Input 2: Bob 0.1 BTC

Output 1: 0.1 BTC

  • Taproot key path: a public key <MuSigPubKey1a> derived from <AlicePubKey1a> and <BobPubKey1a> using MuSig2
  • Taproot script:
    • Path 1 (spendable by Alice if she learns N_b): OP_HASH160 H_a OP_EQUALVERIFY OP_HASH160 H_b OP_EQUAL OP_DUP OP_HASH160 <AlicePubKey2Hash> OP_EQUALVERIFY OP_CHECKSIG
    • Path 2: 2of2 multisig with <AlicePubKey3a> <BobPubKey3a> used for staged refund Tx

Output 2: 1.1 BTC

  • Taproot key path: a public key <MuSigPubKey1b> derived from <AlicePubKey1b> and <BobPubKey1b> using MuSig2
  • Taproot script:
    • Path 1 (spendable by Bob if he learns N_a): OP_HASH160 H_a OP_EQUALVERIFY OP_HASH160 H_b OP_EQUAL OP_DUP OP_HASH160 <BobPubKey2Hash> OP_EQUALVERIFY OP_CHECKSIG
    • Path 2: 2of2 multisig with <AlicePubKey3b> <BobPubKey3b> used for staged refund Tx

With this scheme, once Alice and Bob have exchanged nonces, Alice can spend Output 1 and Bob can spend Output 2 via the first Taproot script path. At this point, Alice can give Bob <AlicePrivKey1b> while Bob can give Alice <BobPrivKey1a> so each of them can use the cheaper key path to spend the output they effectively already control.

@Conza88
Copy link

Conza88 commented Apr 24, 2021

From a branding/marketing perspective—hazing Taproot & Schorr is massive 👍👌🏆 . Being one of the first to implement that would be novel in of itself for new users to check out. Combined with single transaction, new UX design, and multi payment method 🌚🚀

@dmp1ce
Copy link

dmp1ce commented May 3, 2021

@hodlwave I like the idea but how can the nonce which is exchanged be guaranteed to be correct? If alice decides to send a bad nonce for example, does it resort to arbitration and multisig for bob then.

@chris-belcher
Copy link

chris-belcher commented May 4, 2021

A couple of thoughts:

  1. If I understand correctly, the big scripts (involving OP_EQUALVERIFY, OP_IF, etc) have to be recorded into the blockchain for each bisq trade. This costs miner fees and degrades privacy. But there should be a way to avoid this using a coinswap transform, which is when the coins are held in a 2-of-2 multisig with a pre-signed transaction that pays to the big script. In the unhappy non-cooperative case either Alice or Bob can get this pre-signed transaction mined, but in the happy case Alice and Bob would just sign each other's transaction because they are confident that they'll get their money anyway and signing each other's transactions saves miner fees. This would mean in the happy case the blockchain only ever sees a 2-of-2 multisig (or taproot single-sig with musig). This is exactly the same way Lightning channels work, remember that when lightning channels are closed cooperatively the blockchain only sees a 2-of-2 multisig, and those big HTLC scripts are only visible for uncooperative channel closes.
  2. When writing the big script, it's a good idea to avoid the oversized preimage attack by adding something like OP_SIZE 32 OP_EQUALVERIFY.
  3. Check if you can make use of private key handover. This is when there are coins in a 2-of-2 multisig, with Alice and Bob each holding one key. When Bob is satisfied that Alice legitimately should possess the coins then Bob will send his private key over to Alice. Alice now controls both keys in the 2of2 multisig and therefore she now possesses the coins (although she'll still need to watch the bitcoin network and be ready to react to another pre-signed transaction being broadcast). This has a benefit that Alice can leave her coins unspent indefinitely.
  4. All these protocols at some points have a requirement that the user be constantly watching the bitcoin network and be ready to react. How about creating some kind of watchtowers? These would be computers running out there that watch the blockchain on behalf of the user and can broadcast a justice transaction. It should be possible to encrypt the justice transactions and send them so that watchtowers can work without privacy loss. Lightning is intended to work this way so why not Bisq as well.

@pazza83
Copy link

pazza83 commented May 10, 2021

Hi @sqrrm thanks for the proposal. I am doing some housekeeping on the proposals.

I will close this as approved.

I understand you are working on this already and am excited about it's implementation. Please consider if it would be beneficial to make a project for this work.

Many thanks.

@pazza83
Copy link

pazza83 commented Nov 18, 2023

@sqrrm Just following up on this proposal. Is this proposal planned to be implemented?

@Conza88
Copy link

Conza88 commented Nov 18, 2023

Needs to happen to reduce the impact of the nft bs ordinal 🤡 spam (checkers players crashing the chess club).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
an:idea https://github.com/bisq-network/proposals/issues/182#issuecomment-596599174 re:features re:protocol was:approved
Projects
None yet
Development

No branches or pull requests

9 participants