I was asked by Kruw to analyze and respond to Yuval “nothingmuch” Kogman’s post1 on centralized, coordinator-based, deanonymization attacks. In particular2, attacks on the WabiSabi protocol used by Wasabi wallet; Kogman was involved in the design of WabiSabi, but “left in protest before its release”1.

Kogman claims that the “this software is not fit for purpose and should not be used unless users trust the coordinators with their privacy”. However, Kogman hasn’t articulated a clear engineering basis for this statement. So I thought it would be worthwhile to do a proper security analysis of what coinjoin is, what kinds of attacks it prevents, and how well the two leading coinjoin implementations - Joinmarket and Wasabi - prevent real world deanonymization attacks.

Disclaimer: Kruw is paying me for my time at my usual open-source consulting rate; he runs the most popular Wasabi coordinator. I personally use Wasabi, and indeed, received my payment for this article from Kruw’s Wasabi wallet, to mine.

Contents

  1. Background
    1. K-Anonymity Sets
    2. Tor
  2. Notable Coinjoin Schemes
    1. Payjoin
    2. JoinMarket
    3. WabiSabi and Wasabi Wallet
      1. Round Structure and Cryptography
  3. Attacks On Multi-Party Coinjoins
    1. Sybil Attack
    2. Targeted Sybil Attack
    3. Address Reuse After Failed Coinjoins
      1. Leaking Commonly Owned Input Sets
      2. Information Extraction via Invalid Rounds
    4. Attacking Round Consistency
    5. The K-Anonymity Set of Communication Characteristics
  4. Final Thoughts
  5. Footnotes

Background

Coinjoin was first popularized3 by Gregory Maxwell in 2013. The basic principle is simple: if two or more parties collaboratively create a Bitcoin transaction, the common input ownership heuristic can be defeated, by the fact that not all inputs to the transaction are owned by the same entity. The simplest possible way to coinjoin is for two or more parties who were already intending to do a transaction to simply concatenate the inputs and outputs of their respective transactions together. Even this simple technique has a small cost savings: the multiple parties get to share the bytes in the transaction header, resulting in a smaller overall transaction.

However, this simplicity is lacking in privacy for two main reasons:

  1. An external observer can usually link inputs and outputs based on unique values.
  2. Parties within the coinjoin know which inputs and outputs belong to other coinjoin members.

For example, consider the following transaction:

Inputs Outputs
61,836 53,467
98,902 61,736
45,235

If you suspect this were a very simple two party coinjoin, it’s a reasonable guess that the first input and second output are owned by the same person, with the second input going to the first and third.

That leads us to our two main threat models:

  1. Passive chainalysis4: An attacker who uses publicly available blockchain data, possibly in conjunction with other data, to attempt to deanonymize transactions through passive analysis.
  2. Active (sybil) attack: An attacker who actively participates in coinjoins to gather data that is not publicly available. We can assume active attackers also use passive chainalysis.

Interestingly, based on my off-the-record discussions with current and former employees of Chainalysis and competing companies, real world chainalysis adversaries don’t actually bother to do the proper statistical analysis required to actually deanonymize even the simplest of coinjoins. Indeed, they don’t bother to do proper statistical analysis of anything at all: their products are highly unscientific, and based on “labeling” outputs on what is essentially hunches and primitive heuristics rather than actually figuring out the probability that a given output is associated with a given activity.5 I’ve even had a founder of a Chainalysis competitor drunkenly brag to me over dinner that his product was a total scam that didn’t do any real chainalysis at all: the real purpose of his product was to give police cover to throw people in jail, as well as allow exchanges to meet “AML/KYC” checkbox requirements. Chainalysis themselves has gone to great lengths to hide how their product actually works, e.g. in court cases; it’s highly likely that Chainalysis’s product does not in fact work reliably.

Conversely, recent court documents have revealed that Chainalysis ran a Tornado Cash Relayer, presumably in an attempt to gather data on Tornado Cash users. While Tornado Cash is a very different type of technology than coinjoin, if Chainalysis is taking active measures to deanonymize Tornado Cash usage they may also be taking active measures to deanonymize coinjoin implementations.

Regardless, whether or not our adversaries are presently scams or not, we should assume competence.

K-Anonymity Sets

Privacy tools are typically analyzed in terms of k-anonymity sets: the set of \(k\) individuals from which an anonymized individual can’t be distinguished from. Monetary applications like coinjoin add an additional element: the amount of value that your value could have come from. This is especially relevant if you are trying to coinjoin larger amounts: the k-anonymity set for larger amounts is smaller, because fewer other k’s had sufficient funds to be a potential source of the funds.

Tor

The Tor network is an onion routing network. Coinjoin schemes make use of Tor for its anonymity: if Tor nodes fulfil their promise not to keep logs, in most threat models Tor allows coinjoin clients to communicate anonymously. Which is important to the security model of JoinMarket, and critical to the security model of Wasabi.

Tor is not decentralized. While a large number of volunteers run individual Tor nodes, the Tor consensus itself — the list of Tor nodes — is run by a centralized set directory authorities, who solely decide who is and is not a Tor node.

Notable Coinjoin Schemes

There’s only three notable, coinjoin schemes that have actually been implemented, and are currently in operation. Each of these schemes uses a fundamentally different approach, with advantages and disadvantages.

Payjoin

This is a two party protocol, allowing a payor (sender) to create a coinjoin transaction with the payee (recipient) that they were already intending to pay. This transaction defeats the common input ownership heuristic by combining the coins of payee and payor. Since Payjoin is a protocol, many wallets already support it, including our other two coinjoin implementations, JoinMarket and Wasabi.

The Bull Bitcoin Mobile Wallet (Play Store) is a good example of when and why Payjoin is advantageous. Developed by the Bull Bitcoin Exchange, it aims to solve two key problems:

  1. When buying Bitcoin, exchange customers tend to accumulate one UTXO per purchase. Payjoin allows previously purchased UTXOs to be combined with the BTC purchased right now, resulting in less fees spent consolidating UTXOs, without impacting privacy.
  2. When selling Bitcoin, the coinjoin transaction saves the exchange fees by combining one or more existing UTXOs with the amount sold. Additionally, in the future payjoin will make it possible to implement cut-through payments, further saving money on fees. And obviously, both parties potentially benefit from an improved k-anonymity set.

Since payjoin is a two party protocol, active attacks are irrelevant: the other party you are payjoining with inherently knows what inputs and outputs are yours. Furthermore, sybil attacks are not relevant: you are payjoining with a known entity you were already planning on transacting with anyway.

In practice, payjoins are often distinguishable by the Unnecessary Input Heuristic, allowing sender and receiver to be guessed based on the assumption that wallets only add the bare minimum number of inputs necessary to perform a payment. This assumption is not always correct, as some wallets do in fact add unnecessary inputs for UTXO management and privacy reasons. Secondly, not all payjoins meet this heuristic. Differences in transaction patterns, e.g. between a Bitcoin exchange and a typical Bitcoin holder, may also be different enough to distinguish the inputs and outputs of both parties. Regardless, the fee savings of payjoin are reason enough to implement it in any on-chain wallet.

We won’t discuss payjoin further, as it provides a clear fee-reduction benefit to any on-chain wallet — including coinjoin wallets — with no significant downsides other than implementation complexity. If the entity you are intending to pay on-chain offers payjoin, there is no reason not to use payjoin to pay them.

JoinMarket

This is meant to be a taker-maker protocol, in which the taker pays one or more makers to improve the privacy of their transaction by paying the makers to also contribute their inputs and outputs to the transaction; the taker also pays the transaction fees.

If makers contributed arbitrary inputs and outputs, of arbitrary value, this wouldn’t usually provide any privacy improvement as maker and taker inputs could usually be distinguished by simply matching them by value. So instead, makers contribute outputs equal in value to the taker’s payment output. The idea is that by having multiple payment outputs of the same value, we’ve achieved a k-anonymity set comprising these multiple outputs.

Here’s a very simple example of a JoinMarket transaction that I made for this article, with one taker, and one maker, txid 4f11…8b7d:

Inputs Outputs
148,798 46,981
1,448,113 100,420
1,347,800
100,420

At first glance, the 100,420 sat outputs appear to have a \(k=2\) anonymity set: there are two of them. But suppose you were the recipient of the first 100,420 sat output. The question for you is where did the money come from? Due to how JoinMarket works, it’s reasonable to assume that I paid you as a taker, and the other party in the transaction is the maker. Since I must be a taker, I must have paid for the transaction, as well as the maker fee.

With that assumption, you can easily deanonymize my input by making a reasonable guess at what inputs map to what change outputs, and doing some arithmetic:

\[\begin{align} 148798 - 100420 - 46981 &= 1397 \\ 1448113 - 100420 - 1347800 &= -107 \end{align}\]

Obviously, the first input is from the taker, as it contributed a net 1397 sats to the transaction, while the second input received a 107 sats maker fee. Which, having made the transaction myself, I can confirm is correct.

Even though I paid a 107 sat maker fee, and an extra 698 sats in transaction fees, I got no additional privacy!

This issue isn’t limited to simple test transactions either. In most cases, even when multiple makers are used, the taker can be identified by this analysis. The root cause of the problem is that JoinMarket is a market: takers and makers have fundamentally different roles, and thus their inputs and outputs can be distinguished by the fact that the taker is paying the makers.

In a sense, the economics of JoinMarket are entirely backwards: in a typical case — where the taker is paying multiple makers — the makers probably receive a privacy improvement by the fact that the decoy outputs have a k-anonymity set of all makers6. Yet the taker — who paid a non-trivial amount of money for this service — usually doesn’t receive the benefit of improved privacy.

I personally was unaware of this issue when I started writing this article. As it turns out, it was first concretely discussed on bitcointalk almost a decade ago, soon after JoinMarket was first released. However, the significance doesn’t seem to have been fully appreciated.

While there could be interesting things to say about other aspects of JoinMarket — like its use of fidelity bonds for sybil protection – it’s main functionality doesn’t work as intended. So we won’t cover it further in this article; I do not recommend using JoinMarket until it is redesigned.

WabiSabi and Wasabi Wallet

The WabiSabi protocol is a multi-step coinjoin protocol, implemented by the Wasabi Wallet7. There was also a BTCPay Server Plugin that used the WabiSabi protocol. But it is no longer maintained. I’m unaware of any WabiSabi implementation other than Wasabi Wallet. So for this article I’ll refer to “Wasabi” for both the protocol and Wasabi Wallet implementation. Finally, while there existed a previous 1.x version of the Wasabi wallet, as it is now obsolete we will be solely referring to the current 2.x release.

Wasabi relies on amount decomposition to achieve a k-anonymity set across multiple users. The privacy of funds deposited into Wasabi is protected by one or more coinjoin rounds, where a (user-configurable) central coordinator brings multiple users together to coinjoin their funds.

For this article I created a fresh Wasabi wallet and deposited 516,237sats into it. I then allowed Wasabi to coinjoin those funds using the https://coinjoin.kruw.io/ coordinator using the “Maximize Speed” coinjoin strategy. Here’s my input and outputs from the first coinjoin round, txid 7a27…47ad:

My Inputs and Outputs for txid 7a27c793440396fd0090792e40bf0f9c981900697367391bb566725c179647ad

To achieve a k-anonymity set, my Wasabi wallet has decomposed that deposit amount into multiple UTXOs of standard denominations8, shared by other participants in that coinjoin round. For example, my 59,049sat output was one of 5 different 59,059sat outputs in that transaction, a k-anonymity set of approximately 5; my 100,000sat output was one of 14 different 100,000sat outputs, a k-anonymity set of approximately 14.

You’ve probably noticed the numbers next to the shield icon. Wasabi keeps track of the anonymity score of each UTXO. This measurement is approximately — but not exactly — the k-anonymity set that Wasabi believes each coinjoin round provided. You can configure Wasabi with the desired anonymity score target for your coins, and Wasabi will continue to do coinjoin rounds until all (economically spendable) coins have reached your desired target. In the case of this test wallet, Wasabi did three coinjoin rounds in total before all outputs reached the desired target:

Wasabi Coinjoins

Importantly, the anonymity score tries to take into account the total value and composition of the outputs of other participants. For example, for txid ef4a…62d3, I intentionally used an unpopular coordinator with very few participants. Wasabi has calculated an anonymity score of 1 for my outputs due to the lack of other participants:

My Inputs and Outputs for txid ef4a4964f9e1e2cdc5f5daae90c1a08b31247094f69fb774684c8dade5ee62d3

Since Wasabi uses a central coordinator, as long as you’re using a popular coordinator it is relatively straightforward to achieve very large coinjoin transactions with hundreds of inputs and outputs, with most standard values having a dozen identical outputs. In this circumstance, it takes relatively little fees to achieve relatively large anonymity sets, making Wasabi fairly cost effective. Unlike JoinMarket, since all participants (modulo the coordinator themselves) are participating in an equal way, there is no (known) way for a passive chainalysis attacker to map outputs to inputs better than the probabilities inherent to the k-anonymity set.

Round Structure and Cryptography

With a central coordinator, one way to implement all this would be to simply have each participant tell the coordinator what inputs and outputs they wanted to use in the coinjoin, and the coordinator could construct a transaction containing all the requested inputs and outputs for participants to sign. If Wasabi worked this way, the resulting coinjoins would be resistant to passive chainalysis. Secondly — assuming that a large number of participants were present in each round — it would be difficult for participants to learn what inputs and outputs belonged to other participants by process of elimination.

But you would have to trust the coordinator to keep the link between inputs and outputs a secret. That’s a problem. Both for the obvious reason that we’d rather the coordinator not know that. But also, because honest coordinators would rather not have that information themselves.

Wasabi mitigates this problem with a multi-phase protocol, with participants using multiple identities via an anonymous communication mechanism such as Tor. For a full description, you should read the docs. But in summary, the protocol consists of the following phases:

  1. Input Registration: Participants tell the coordinator which inputs they want to use, and receive what is essentially a per-round chaumian e-cash token for each input. The identities the participants use in this phase are known as the “Alices”; typically Tor is used here for anonymity.
  2. Output Registration: Using a new identity, e.g. via a new Tor connection, participants spend their input tokens to register outputs they want to exist in the coinjoin round.
  3. Signing: Now that the full transaction is built by the coordinator, every participant signs the transaction, re-using their Alice identities from the Input Registration phase.
  4. Blame Round: If not all participants signed, the coinjoin is attempted again with the successful participants. Coins from unsuccessful participants are temporarily blacklisted to make DoS attacks expensive.

The key to the privacy guarantee is the combination of using two different sets of identities for input and output registration, and the use of a per-round e-cash-like token. The privacy guarantee against active chainalysis by the coordinator does depend heavily on Tor: if Tor connections can be deanonymized by the coordinator, the coordinator could link inputs to outputs.

Attacks On Multi-Party Coinjoins

For the purposes of this article, we’re going to assume that the underlying e-cash-like cryptography that Wasabi uses works as advertised and is implemented correctly; I’m not aware of anyone claiming that it doesn’t. Instead, we’re going to look in more detail at the security model of coordinator-blinded multi-party coinjoins, and Kogman’s criticisms of Wasabi.

Sybil Attack

If the coordinator can’t link inputs and outputs, can the coinjoin still be deanonymized? Yes! With a Sybil Attack: if an active attacker manages to “flood” the coinjoin round with participants, so they are every participant except the target, they can deanonymize the coinjoin through a simple process of elimination.

This attack is fundamental to any type of multi-party open-access coinjoin system where anyone can choose to be a participant and can participate anonymously9. Indeed, this attack even applies — in theory — to systems such as Monero and Zcash. The only question is how expensive is the attack?

A typical Wasabi round transaction10 Kruw’s coordinator is about 25,000vB in size, spending about 50,000sats in transaction fees. At current prices, that’s about $50 USD. Additionally, dozens of Wasabi coinjoins happen every day.

An adversary who tried to do a straightforward sybil attack, flooding every coinjoin round with so many inputs and outputs that victims were isolated, would probably have to spend thousands or tens of thousands of dollars in fees per day. On top of that, since it’s typical for millions of dollars worth of BTC to be coinjoined every round, a convincing attack would also need access to tens of millions of dollars worth of BTC to simulate that.

There is no evidence such an attack is happening. Certainly, no government or other entity has publicly claimed to be doing such an attack, and in my private discussions with people involved in the chainalysis industry, I certainly haven’t heard any claims of such an attack.

Ironically, if such an attack is being done, it would arguably be (at least temporarily) improving the privacy of coinjoin participants who weren’t targets of the attack. That would mean some entity is spending enormous resources doing coinjoins and keeping the data to themselves (at least for now).

Targeted Sybil Attack

Can a sybil attack be made cheaper? With the involvement of the coordinator, maybe. For this section we’ll assume that round consistency holds; we’ll discuss in a further section the analysis if round consistency does not hold.

Any multi-party coinjoin scheme will have some type of input registration mechanism, and some notion of “rounds”. If an attacker — including the coordinator itself — can direct different users to different rounds, the attacker could then perform a sybil attack more cheaply. For example, suppose that an attacker was trying to trace where a particular set of one or more coins went after coinjoining: rather than sybil attacking all coinjoin rounds, they could instead only attack coinjoin rounds spending those coins.

In Wasabi, without the cooperation of the coordinator, the attacker could only do this by repeatedly trying to join coinjoin rounds and then disconnecting when those rounds do not contain the target inputs. This attack would require access to a significant amount of money due to the blacklisting mechanism, as each round would result in coins being blacklisted and unusable for subsequent rounds.

Since individual transactions in Wasabi are fairly expensive, the cost of successful attacks is high: in my example above, a sybil attacker who managed to isolate me would still have had to spend $140 USD in transaction fees to deanonymize me, and they would have had to have access to many multiples of the $10 million USD worth of BTC mixed in that transaction.

Additionally, this attack has an inherent trade-off between information gained and disruptiveness/ease-of-detection: if the attacker consistently manages to sybil attack rounds to the point where only one other real user is in the round, the attacker will disrupt all coinjoin activity at the coordinator. Highly suspicious! Conversely, if rounds spending non-target coins succeed, that also means that rounds spending target coins will have non-target coins in them, reducing the information gained by the deanonymization.

With the cooperation of the coordinator this attack requires much less capital, and can be more successful. First, let’s assume that the attacker knows all coins that the target wants to coinjoin11.

The attacker participates in every coinjoin, registering their sybil coins as inputs. If other participants register non-target coins, the attacker drops out, leading to a blame round without the sybil coins. Since the attacker is cooperating with the coordinator, the sybil coins are not blacklisted and can be reused later.

If other participants register target coins, the coordinator prevents non-target coins (other than the sybil coins) from participating. From the point of view of non-target participants, this would just look like a temporary failure of the coordinator. Either the target coins were registered first, which would result in a “successful” round, or after a blame round the coinjoin would complete. Either way the resulting transaction would only have the sybil attacker and target, allowing for easy deanonymization.

For a convincing coinjoin this attack is still expensive: the attack still has to pay the transaction fees of their inputs and outputs. But it can be done with access to much less capital as blacklisting is not a concern; if blacklisting can be made visible to other participants, detecting this kind of attack by a malicious coordinator may be more feasible.

Address Reuse After Failed Coinjoins

Ideally addresses would never be reused. However, like almost all wallet software, Wasabi uses a deterministic wallet where addresses are generated deterministically from a seed. The problem is the gap limit: the maximum number of unused addresses in a row that the wallet will generate and look for when recovering from a seed.

Currently, if a coinjoin attempt totally fails — with the blame rounds failing to generate a valid transaction — Wasabi reuses the output addresses used in that round in subsequent coinjoin attempts.

What can the attacker learn from this? Suppose we have a failed round with two or more (genuine) participants. Both the coordinator, and all participants, learn the desired mapping of inputs and outputs during the round for all participants collectively. The desired mapping of inputs and outputs for any individual participant is protected by the k-anonymity set of having multiple participants.

Now suppose that the round fails, and one or more participants join a subsequent coinjoin round. Unless the same set of participants tries to coinjoin again in a subsequent round, address re-use breaks the k-anonymity set: the intersection of inputs and outputs from a previous failed round, with the set of inputs and outputs from the current round, is likely to be a unique participant. Thus deanonymizing that participant.

The fix is to simply not re-use addresses after a failed round. As of writing there is an open pull-req that would mark addresses as used in the event of a round failure. But it’s unclear how this should interact with the gap limit.

It is probably possible to use a technique based on silent payments to solve this issue as well. Here, fresh output addresses specific to the coinjoin round would be deterministically generated from the inputs, and perhaps the nLockTime field, in such a way that recovery would always be possible, regardless of how many rounds had failed. A disadvantage to doing this would be that Wasabi HD wallet seeds would not be compatible with any other wallet: you’d have to recover your funds with Wasabi.

Finally, the Wasabi client supports payments directly within coinjoin rounds via an RPC call. This saves on fees by avoiding a second transaction. But it is inherently vulnerable to this issue if a payment is retried without a fresh address after a coinjoin round failure. That said, in addition to this being an advanced, RPC-only, feature not exposed in the GUI, the GUI also doesn’t make any claims as to the anonymity level of payments made within coinjoins.

Leaking Commonly Owned Input Sets

Avoiding address re-use does not solve the second, lesser, information leak of an attacker learning sets of coins with a common owner. Wasabi will often spend more than one output at once in a coinjoin round for efficiency. An attacker could thus learn statistical evidence that different coins have the same owner. It’s not clear that this could be fully mitigated in any coinjoin scheme that wanted to have the ability to spend more than one output at once.

Information Extraction via Invalid Rounds

A more risky attack, potentially with better information gathering properties, would be for the coordinator to pretend that more Alice’s exist than actually do by using entirely invalid inputs. This is risky, because in the Wasabi protocol participants do learn the inputs to the round before output registration - this is needed for optimal coin amount selection. A participant with access to an up-to-date UTXO set can detect this fraud. However, at the moment the Wasabi client does not assume access to a UTXO set, and thus does not automatically detect this fraud.

The advantage over attacking via failed rounds is that a rogue coordinator could get better statistical information at less cost on the mapping of desired inputs to desired outputs. However, once the re-used address problem is fixed, this attack is no more powerful as learning that mapping becomes mostly useless.

Attacking Round Consistency

As discussed above, while it is always possible to sybil attack coinjoins, doing so is supposed to have a high cost because actual transaction fees must be paid for successful rounds that result in mined transactions.

But what if you didn’t have to pay that cost?

If the coordinator can fool different participants into signing a valid transaction, with different rounds, the coordinator could essentially sybil attack each participant by re-using the liquidity of other participants. Wasabi identifies rounds by a 256-bit Round ID, which is generated by hashing all round-related values together. Notably, the Input Registration start time, and the coordinator identity. Those two are sufficient to uniquely identify a round. Additionally, since all round settings are hashed into the Round ID, provided that Round ID consistency holds, the coordinator is unable to deanonymize different participants through differences in behavior due to different round settings.

While coinjoining, the Wasabi client requests the status of all rounds periodically. Then, after the client decides to participate in a particular round, it uses the Round ID in messages interacting with the coordinator. In certain cases, such as a full round, multiple rounds can happen in parallel; the coordinator can potentially advertise different Round IDs to different clients.

During the input registration phase all Alice’s send BIP-322 ownership proofs of their inputs to the coordinator. These ownership proofs commit to the round ID, preventing ownership proofs from being reused for any other round. Finally, the coordinator gives each client all ownership proofs for all inputs prior to signing. These ownership proofs are validated as they are received by the client.

The catch with this that Kogman pointed out is that simply validating the ownership proof itself is not enough: we also need to validate that the ownership proof actually corresponds to the scriptPubKey of the transaction input the ownership proof is supposed to be proving. The Wasabi client does not assume it has access to a valid UTXO set, and thus does not directly validate ownership.

If that were the whole of it, then the ownership proof mechanism could be fooled by “fake” ownership proofs: real pubkeys that don’t actually correspond to the scriptPubKey of the input they’re supposed to be proving ownership of.

However Kogman failed to consider how Taproot signing works: the signature commits to the scriptPubKey, meaning that any faked ownership proofs would ultimately result in an invalid transaction. This scenario is just another form of invalid input attack, which we’ve already dealt with above in the our discussion of invalid rounds.

At the moment, Wasabi still supports non-taproot inputs, because many services had historically been slow to support Bech32m (Taproot) addresses. Fortunately as long as there are any non-attacker taproot inputs in a Wasabi round, all inputs must have valid ownership proofs. Put another way: to sybil attack via attacking round consistency, the evil coordinator must have as much real liquidity (and spend proportionally as much fees) as all taproot inputs in the round, and they can only attack clients who are not contributing taproot inputs.

Why? Because honest nodes will only sign for a single Round ID. Suppose that we have three Alice participants in a round, Alice Adams, Alice Brown, and Alice Turner. We’ll say that Turner has one or more Taproot inputs, and the other two Alice’s have only non-Taproot inputs.

If the round is to result in a valid transaction, the coordinator needs to provide Alice Adams and Alice Brown with the correct, valid, ownership proof from Alice Turner. Yet, if the coordinator does that, the coordinator is also forced to give all Alice’s the same Round ID, negating any attempt at a sybil attack as all Alice’s will register outputs with the same Round ID; the liquidity of all Alice’s contributes to the overall anonymity set.

Note that the Taproot input can be your input: provided you contribute at least one Taproot input to the coinjoin, you can be sure that all honest liquidity in the round is contributing under the same Round ID. Now that payments to Bech32m (Taproot) addresses are widely supported, it would be a good idea for Wasabi to generate Taproot deposit addresses by default; as of v2.6.0, it does not. That said, for output addresses Taproot address are generated randomly 50% of the time, which protects the vast majority of coinjoins as so much liquidity is trying to register at least one Taproot address.

The K-Anonymity Set of Communication Characteristics

Previously, Kogman had brought up the subject of registration delays in a GitHub issue. While Kogman doesn’t articulate a clear engineering basis for the criticism, we can: the k-anonymity set of communication characteristics is important in any multi-party coinjoin system which aims to anonymize via separate identities for difference phases.

Recall that Tor provides an anonymized equivalent to TCP stream functionality, routed over fixed length relay cells. Now imagine that you have the slowest internet connection of any participant in a coinjoin round by a significant margin. Put another way, you don’t have a k-anonymity set of internet speed. It’s possible that the coordinator could detect this unique characteristic via the exact timings of data exchanged with the coordinator, and thus deanonymize your inputs and outputs by observing that unique characteristic across both input registration, and output registration.

It would be ideal if Wasabi could eventually move to a purely packet-based data anonymity scheme, where all communications were done via exchange of atomic packets whose timing characteristics could be thoroughly randomized. Unfortunately, such a widely used scheme with trust characteristics similar to Tor simply doesn’t exist yet. It’s likely that Wasabi could improve on this situation somewhat with increased use of random delays. But without a purely packet-based communication scheme it’s probably best to try to use Wasabi on a relatively common type of internet connection to try to maximize your k-anonymity set. As always, this situation is improved in mixes with higher numbers of participants due to the large k-anonymity set.

A related version of this problem that Kogman also brought up1 is subtle differences in serialization and de-serialization. Wasabi makes use of JSON serialization, which is notorious for being underspecified and implemented slightly differently by different implementations. Again, your k-anonymity set is how many other participants use the exact same serialization scheme as you do. Slight differences could result in the coordinator being able to associate inputs and outputs.

Fortunately, Wasabi only has one commonly used implementation. So in practice this is unlikely to be an issue. But regardless, Wasabi should eventually move to a fully-specified, rigid, binary serialization protocol.

Final Thoughts

Even though there are ways that Wasabi could be improved, it clearly is the best option out there for coinjoining. PayJoin supporting wallets gets an honorable mention here, as it has clear benefits if both sender and receiver support it. Unfortunately, as much as I would like be able to recommend JoinMarket, the ugly fact is leaving on-chain clues as to where the coins actually came from is a much worse flaw than any hypothetical problem where maybe a coordinator could betray your trust at high cost and risk to themselves.

Think about it: would you rather risk one entity possibly being untrustworthy, and finding a way to bypass Wasabi’s cryptographic protections? Or would you rather knowingly broadcast on-chain metadata to the entire world that anyone, now or in the future, could use to deanonymize you?

While trusted coordinators are undesirable. Being able to trust your coordinator is a good belt-and-suspenders measure. Its good that Kruw shouldn’t be able to deanonymize my coinjoins even if he wanted to. But it’s also good that on top of that there’s good human-scale reasons to think he’s not going to anyway.

JoinMarket fails on the first measure: under normal usage many of your transactions can be deanonymized due to the fee payment flaw. Yet it also fails on the second measure: it picks counterparties purely based on economics and chance, such that any bad actor with funds to spare can easily become your counterparty and trivially deanonymize you. It’s kinda similar to how Tor would be less secure if it were decentralized, because we wouldn’t have any ability to use the human element to keep bad actors out; there’s no way to prove you aren’t keeping logs.

Kogman’s hyperbolic behavior here is a good example of what not to do. He failed to do a good engineering analysis of his criticisms (e.g. how Taproot signing made one fairly irrelevant), while turning off people by quickly jumping to accusations of impropriety for simply getting paid for their work (my landlord does not accept blog posts!). Meanwhile he himself has an obvious conflict of interest: a Spiral grant rumored to be worth hundreds of thousands a year, that obviously is only going to get renewed if he continues to find sufficiently important issues. Even that might be understandable. But then to also promote JoinMarket instead despite its long-known issues is not a good look:

In any case, technology is rarely perfect. I personally do not use Wasabi alone. I prefer to use coinjoined coins to open lightning channels, and actually spend my money with Lighting. That layers two very different privacy techniques, such that both would have to fail for my financial privacy to be affected.

Footnotes

  1. “[bitcoindev] Reiterating centralized coinjoin (Wasabi & Samourai) deanonymization attacks”, 2024-12-21 14:16, Yuval Kogman, also available locally (OTS)  2 3

  2. Kogman also critiques the Whirlpool protocol used by the now-defunct Samourai. We will not cover that protocol here as Samourai was always, and intentionally, horrendously insecure due to its leakage of xpubs by default. 

  3. Gregory Maxwell’s CoinJoin: Bitcoin privacy for the real world post popularized the concept, in addition to his earlier I taint rich! post. There were even earlier mentions of the idea of coinjoin, e.g. in 2011; Maxwell does not take credit for the idea itself. As for the name “coinjoin”, Maxwell asked me personally to come up with a good name for it — I’m happy with the result! 

  4. Chainalysis is an American blockchain analysis firm; the term “chainalysis” is used here as a generic term for that activity in general. 

  5. For example, I’ve been privately told that Sarah Meiklejohn’s 2013 A Fistful of Bitcoins: Characterizing Payments Among Men with No Name clustering methodology is often used by chainalysis companies. This methodology is just a heuristic, not a proper statistical probability analysis, and was not designed to be used for these purposes. 

  6. This may not be true in practice if makers have significantly different fee policies, as subsequent transactions may deanonymize them by different fees charged. But JoinMarket does randomize maker fees to an extent, which will often mitigate this issue. 

  7. GingerWallet also forked the Wasabi Wallet source code when the central Wasabi coordinator was shutdown. Since GingerWallet doesn’t appear to have gotten much development effort, or usage, we won’t discuss it further. 

  8. 5000, 6561, 8192, 10000, 13122, 16384, 19683, 20000, 32768, 39366, 50000, 59049, 65536, 100000, 118098, 131072, 177147, 200000, 262144, 354294, 500000, 524288, 531441, 1000000, 1048576, 1062882, 1594323, 2000000, 2097152, 3188646, 4194304, 4782969, 5000000, 8388608, 9565938, 10000000, 14348907, 16777216, 20000000, 28697814, 33554432, 43046721, 50000000, 67108864, 86093442, 100000000, 129140163, 134217728, 200000000, 258280326, 268435456, 387420489, 500000000, 536870912, 774840978, 1000000000, 1073741824, 1162261467, 2000000000, 2147483648, 2324522934, 3486784401, 4294967296, 5000000000, 6973568802, 8589934592, 10000000000, 10460353203, 17179869184, 20000000000, 20920706406, 31381059609, 34359738368, 50000000000, 62762119218, 68719476736, 94143178827, 100000000000, and 137438953472 sats, which were carefully chosen to minimize the average number of UTXOs needed to decompose typical amounts. 

  9. A closed coinjoin scheme could prevent sybil attack by limiting the coinjoin participants to a set of known entities. 

  10. Statistics on Wasabi rounds are collected and published by Wabisator and LiquiSabi, among others. 

  11. The worst-case scenario. If the attacker does not know all of the coins the target wishes to coinjoin, the attack will be visible as some coins will mysteriously fail to be registered in the input registration phase.