Skip to content

Commit f198b6b

Browse files
committed
docs(paper): tighten TL;DR, drop self-references, reframe positively
Shrink the abstract block from ~50 lines to 16, removing the extended protocol-explanation parenthetical and the in-line corpus methodology that already lives in section 4. Drop all references to 'earlier versions of this paper' / 'previous version of this paper' (sections 0 and 11); the paper has not been published, so its own version history is not part of the narrative. Reframe the headline as 'robust today and concretely improvable by a client-default change': lead with the 60.4% of CJs that lose no candidate at all, present 'uniform_fee' as a clean deployable fix rather than as a privacy-budget shortfall. No numerical claim changes; only framing.
1 parent e78669c commit f198b6b

2 files changed

Lines changed: 52 additions & 87 deletions

File tree

docs/mainnet-deanon.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ <h1>JoinMarket Maker Clustering and Taker Anonymity-Set Reduction</h1>
106106
<div class="kpi safe"><b>0 / 35</b><span>Cross-nick collisions / probed nicks with v7.3 matches (of 72 probed)</span></div>
107107
</div>
108108
<h1 id="joinmarket-maker-wallet-clustering-and-taker-anonymity-set-reduction">JoinMarket Maker Wallet Clustering and Taker Anonymity-Set Reduction</h1>
109-
<blockquote><p><strong>TL;DR.</strong> JoinMarket is a Bitcoin CoinJoin protocol where a <em>taker</em> pays a small fee to one or more <em>makers</em> to mix coins into a single transaction with several equal-value outputs; every equal output is supposed to be indistinguishable from every other equal output in the same round (makers want anonymity from each other and from the taker, just as the taker wants anonymity from the makers). We ran a passive on-chain experiment on exactly one year of mainnet JoinMarket activity (heights 894,697 to 947,358, 2025-05-01 to 2026-05-01, 10,581 JoinMarket CoinJoins, of which 7,400 are fully ILP-decoded and 3,158 yield partial maker slots via greedy preprocessing, <span class="math inline">$\S 7.4$</span>) and clustered maker wallets using only protocol-forced signals: the JoinMarket mixdepth state machine (a maker's change stays in the source mixdepth and its equal output advances to the next, and the maker chooses the mixdepth with the highest balance to re-advertise), the integer-linear-program (ILP) recovery of slot membership (which inputs and change output belong to the same participant) inside each CoinJoin so that the Common Input Ownership Heuristic (CIOH) can be applied across the on-CJ and off-CJ sides of a maker wallet, and the maker's published fee schedule used as a per-CoinJoin disambiguator. A simple example of that last signal: if a maker charges 0.1% in one CJ and an equal output of that CJ then participates in a later CJ whose ILP-recovered slot also charges 0.1% (and no other maker in the producer CJ charges 0.1% at that amount), the equal output is uniquely bound to that producer slot. This <em>fee-fingerprint</em> attribution is the only chain edge in this attack that ties a specific equal output to a specific maker slot; the change-chain and the auxiliary edges (CIOH, FB-funding) cluster <em>slots across CoinJoins</em> but cannot label which of the indistinguishable equal outputs of a producer CJ belongs to which maker. The result is more measured than earlier versions of this paper suggested. The mean published anonymity set is 8.06 equal outputs per CJ; the mean <em>residual</em> anonymity set after removing makers whose equal outputs are univocally attributed by the fee fingerprint (or co-spent with a cluster-mate's attributed output in a later CJ) is 7.55. On 39.6% of CJs at least one maker's equal output is certified; on 3 CJs (0.03%) the round collapses fully to the taker. The fee fingerprint is therefore a measurable but bounded leak. None of the edges in this attack are probabilistic: every merge is a hard same-wallet conclusion or no merge at all. The single largest remediation is <em>fee-policy homogenization</em>: in the simulator, when every maker runs the reference client's default policy the fingerprint cannot disambiguate and the residual rises to its theoretical ceiling <span class="math inline">$n_{eq}$</span> (<span class="math inline">$\S 9.4$</span>). Practical mitigations and their trade-offs are discussed in <span class="math inline">$\S 9$</span>.</p></blockquote>
109+
<blockquote><p><strong>TL;DR.</strong> JoinMarket holds up well in practice. On one year of mainnet activity (10,464 CoinJoins), a passive on-chain adversary using only protocol-forced signals trims the mean anonymity set from 8.06 to 7.55 equal outputs per CJ at precision = 1.0, a 6.3% reduction. 60.4% of CJs leak no maker at all; only 0.03% collapse to the taker alone. The single dominant edge is the <em>fee fingerprint</em>: when a maker's published fee policy uniquely matches the realized fee of a producer slot at a later consumer CJ's amount, the equal output is hard-bound to that slot. Because that leak has one identifiable cause, it also has one deployable fix: <em>fee-policy homogenization</em>. When every maker runs the reference client's default policy, the fingerprint stops disambiguating and the residual returns to the <span class="math inline">$n_{eq}$</span> ceiling (<span class="math inline">$\S 9.4$</span>). The protocol is therefore both robust today and concretely improvable by a client-default change.</p></blockquote>
110110
<h2 id="scope-and-motivation">1. Scope and motivation</h2>
111111
<p>A JoinMarket CoinJoin (CJ) is an atomic transaction in which one <em>taker</em> and <span class="math inline">$M$</span> <em>makers</em> contribute inputs and produce <span class="math inline">$n_{eq} = M + 1$</span> equal-amount outputs (the <em>equal outputs</em>) plus up to <span class="math inline">$n_{eq}$</span> change outputs (one per participant who needs change; typically all <span class="math inline">$M$</span> makers and usually the taker too). Each participant contributes one <em>slot</em>: a bundle of one or more inputs they own, exactly one equal-amount output, and at most one change output. The published anonymity property is that the taker's equal output is indistinguishable from the makers' equal outputs: the taker hides in a set of <span class="math inline">$n_{eq}$</span> candidates per round.</p>
112112
<p>JoinMarket defends this set in several layered ways:</p>
@@ -307,9 +307,9 @@ <h2 id="appendix-a-forensic-slot-sample-v7-3-1y-merged-corpus">Appendix A. Foren
307307
<p>The two `<code>cert_a</code><code> rows are slots whose published equal output later appears as an input to another CJ where the fee fingerprint of the producer slot is corpus-univocal (no other producer slot in any decoded CJ in the window would have charged the same absolute and relative coordinator fee at the consumer amount). The </code><code>cert_b</code><code> rows are slots that are <em>not</em> fingerprint-attributed at the consumer CJ, but whose producer cluster appears exactly once in the consumer's equal-input candidate set and at least once in its change-input cluster set, so the cluster-co-spend rule of <span class="math inline">$\S 7$</span> Path B disambiguates them deterministically. The </code><code>large_cluster</code><code> rows sit in clusters of <span class="math inline">$\geq 28$</span> slots (the top 1% of the 23,562-cluster distribution) yet remain uncertified: their cluster is large enough to participate in CIOH and round-trip edges but no consumer CJ in the window happens to anchor a same-cluster change at the same time as an equal-input from this producer. The </code><code>partial_only</code>` rows are recovered by the greedy preprocessing pass of <span class="math inline">$\S 7.4$</span> and would have been silently dropped in a full-ILP-only pipeline; both remain uncertified here because no consumer CJ links back to them in the 1y window, but they enlarge the denominator of the published <span class="math inline">$n_{eq}$</span> figures by contributing real maker slots whose existence the analyst can establish without the full ILP.</p>
308308
<p>A reader can replay any row by piping the producer txid into `<code>joinmarket_analyzer.solver.solve_all_solutions</code><code> (for </code><code>partial=no</code><code> slots) or </code><code>greedy_preprocessing</code><code> (for </code><code>partial=yes</code><code> slots) at </code><code>max_fee_rel = 0.05</code>`, intersecting the result with the consumer txid's input set, and checking the Path A or Path B rule of <span class="math inline">$\S 7$</span>. The full per-slot trace contains 73,981 rows (one per merged maker slot, including provenance, cluster id, and the FB-anchored / large-cluster flags) and is included in the corpus release for full auditability.</p>
309309
<h2 id="conclusion">11. Conclusion</h2>
310-
<p>The JoinMarket equal-output anonymity set as published per round (<span class="math inline">$n_{eq}$</span>) overstates the protocol's privacy budget against a passive on-chain adversary, but the overstatement is bounded. A protocol-correct chain-following clusterer at precision = 1.0 reduces the published anonymity set from a mean of 8.06 to 7.55 on the 1y mainnet corpus (a 6.3% reduction across 10,464 CJs, combining 7,400 full-ILP decompositions with 3,158 partial-ILP recoveries per <span class="math inline">$\S 7.4$</span>), with 39.6% of CJs losing at least one candidate to certified-maker removal and 3 CJs (0.03%) collapsing fully to the taker. The structural channel the attack exploits, namely JoinMarket's fee-fingerprint signal (<span class="math inline">$\S 5.2$</span>) that ties a specific equal output of producer CJ <span class="math inline">$T$</span> to a specific producer slot of <span class="math inline">$T$</span>, is intrinsic to the protocol and to the typical maker fee-advertisement workflow; it is not a fixable implementation bug.</p>
310+
<p>JoinMarket's equal-output anonymity set as published per round (<span class="math inline">$n_{eq}$</span>) is largely realized in practice. Against a passive on-chain adversary running a protocol-correct chain-following clusterer at precision = 1.0, the published mean of 8.06 contracts only to 7.55 on the 1y mainnet corpus (a 6.3% reduction across 10,464 CJs, combining 7,400 full-ILP decompositions with 3,158 partial-ILP recoveries per <span class="math inline">$\S 7.4$</span>). 60.4% of CJs lose no candidate at all; 3 CJs (0.03%) collapse fully to the taker. The structural channel the attack exploits, namely JoinMarket's fee-fingerprint signal (<span class="math inline">$\S 5.2$</span>) that ties a specific equal output of producer CJ <span class="math inline">$T$</span> to a specific producer slot of <span class="math inline">$T$</span>, is intrinsic to the protocol and to the typical maker fee-advertisement workflow, and it has a clean deployable fix.</p>
311311
<p>The precision = 1.0 guarantee is what makes the result actionable: under the per-CJ loose gate the clusterer never merges two distinct maker wallets on this corpus, validated by three independent ground-truth sources. Each certified maker the analyst extracts is a <em>deterministic</em> hide-set reduction, not a probabilistic one. The precision guarantee is gate-and-corpus dependent: the scaled simulator (<span class="math inline">$\S 6.1$</span>) shows that under adversarial fee jitter the per-CJ gate breaks at <span class="math inline">$\sim 3\%$</span> of edges and only the corpus-unique gate restores precision = 1.0 by construction. On the present mainnet snapshot the gates are empirically indistinguishable; on a future snapshot in which an adversary deliberately concentrates many makers near similar fee policies the analyst should switch to the corpus-unique gate at a recall cost of about 5%.</p>
312-
<p>The practical implication for JoinMarket users is that the relevant privacy figure for a round is not its published <span class="math inline">$n_{eq}$</span> but the v7.3 residual: today, around 94% of <span class="math inline">$n_{eq}$</span>. The simulator (<span class="math inline">$\S 9.4$</span>) identifies the deployable mitigation: <strong>fee-policy homogenization</strong> (<code>uniform_fee</code>, every maker on the reference client's default policy) drives the residual to the full <span class="math inline">$n_{eq}$</span> ceiling and produces zero Path A attributions. The behavioral knobs that the previous version of this paper proposed (<code>no_change_as_input</code>, <code>maker_only_cj</code>) are at best neutral and at worst <em>counterproductive</em>: by suppressing the v6 change-chain cluster-merging edge without touching the fee fingerprint, they force makers to recycle equal outputs more aggressively and <em>increase</em> the Path A attribution surface. The protocol is therefore hardenable today, by a coordinated client default change, without any protocol-level cryptographic addition; a future JMP-0005-class equal-output permutation commitment would close the residual leak in depth against an adaptive adversary. Until a JoinMarket client release ships the <code>uniform_fee</code> default, the v7.3 residual is the privacy budget the protocol gives its users.</p>
312+
<p>The practical implication for JoinMarket users is that the relevant privacy figure for a round is its v7.3 residual, today around 94% of <span class="math inline">$n_{eq}$</span>, and that this figure is <em>improvable</em> by a single client-default change. The simulator (<span class="math inline">$\S 9.4$</span>) identifies the mitigation: <strong>fee-policy homogenization</strong> (<code>uniform_fee</code>, every maker on the reference client's default policy) drives the residual to the full <span class="math inline">$n_{eq}$</span> ceiling and produces zero Path A attributions. Alternative behavioral knobs (<code>no_change_as_input</code>, <code>maker_only_cj</code>) are at best neutral and at worst <em>counterproductive</em>: by suppressing the v6 change-chain cluster-merging edge without touching the fee fingerprint, they force makers to recycle equal outputs more aggressively and <em>increase</em> the Path A attribution surface. The headline result is therefore that JoinMarket is robust today and straightforwardly hardenable, by a coordinated client default change, without any protocol-level cryptographic addition; a future JMP-0005-class equal-output permutation commitment would close the residual leak in depth against an adaptive adversary.</p>
313313
</main>
314314
<footer>
315315
Generated by <code>publish_site.py</code> from

0 commit comments

Comments
 (0)