payjoin's privacy collapses when sender's and receiver's wallets produce divergent transaction-level fingerprints. a chain analyst then partitions the merged tx back into per-owner inputs. primarily through the backward channel, since the lib already coerces intra-tx uniformity for nSequence (see receive/common/mod.rs:280-317 and send/mod.rs:391,1295).
complements #1586 (network-level): this covers nSequence divergence in prior transactions feeding a payjoin, what any chain observer sees after broadcast.
verified across the same six integrations. each wallet's own nSequence policy (used in its non-payjoin transactions, which become payjoin inputs) splits into two groups (the second a bug):
group A - uniformly 0xFFFFFFFD (ENABLE_RBF_NO_LOCKTIME):
group C - mixed [0x01, 0xFFFFFFFF, …] (bug):
Cake Wallet transaction_builder.dart:402-406 applies replaceByFeeSequence only to inputs[0]; remaining inputs stay at defaultTxSequence. Combined with electrum_wallet.dart:1516, every multi-input cake tx with confirmed UTXOs has the deterministic pattern [0x01, MAX, …, MAX], propagating through the spending graph.
empirical confirmation in How Fingerprints Damage PayJoin Privacy @arminsabouri: a real Cake → BBM payjoin is intra-uniform (the lib coerces receiver to match sender's nSequence), but Cake's prior tx carries the [1, MAX] pattern from the group C bug, propagating Cake-ownership via the backward channel and recovering the partition.
the lib's intra-tx coerce (good!) doesn't reach into transactions that predate the payjoin. prior txs were built with each wallet's standard tx-construction code - the leak lives there.
should I open an issue on cake to fix group C (apply replaceByFeeSequence to all inputs, not just inputs[0])?
zooming out, same family as #1586: would an "integration conformance policy" make sense? lib defines required tx-construction behaviors (uniform nSequence, canonical sighash, etc.), enforced via sender-side validation or documented as protocol requirement, closing the divergence category at the source instead of patching wallet-by-wallet.
the target end-state is only one group. with group B dissolved, 5 of 6 already converge on 0xFFFFFFFD; only Cake's group-C bug diverges. fixing group C therefore closes the nSequence divergence entirely - there's no residual A↔B split (a payjoin-cli ↔ Boltz payjoin is already uniform). canonical convergence on 0xFFFFFFFD (Bitcoin Core default since v0.16, now used by 5 of 6) plus sender-side conformance validation is the remaining policy question.
EDIT: group B - uniformly 0xFFFFFFFF (Sequence::MAX) corrected, dissolves into group A. the old Boltz/BBM MAX was their payjoin-contributed input, which the lib overwrites with the sender's sequence at receive/common/mod.rs:285-317 it never reaches the chain. their own txs use 0xFFFFFFFD
payjoin's privacy collapses when sender's and receiver's wallets produce divergent transaction-level fingerprints. a chain analyst then partitions the merged tx back into per-owner inputs. primarily through the backward channel, since the lib already coerces intra-tx uniformity for
nSequence(seereceive/common/mod.rs:280-317andsend/mod.rs:391,1295).complements #1586 (network-level): this covers
nSequencedivergence inpriortransactions feeding a payjoin, what any chain observer sees after broadcast.verified across the same six integrations. each wallet's own
nSequence policy(used in its non-payjoin transactions, which become payjoin inputs) splits into two groups (the second a bug):group A - uniformly
0xFFFFFFFD(ENABLE_RBF_NO_LOCKTIME):payjoin-clivia Bitcoin Core'swalletcreatefundedpsbt(RBF default since v0.16)ldk-nodebdk_wallet 2.3.0Lianaspend.rs:773Boltzboltz-core/src/bitcoin/tx.rs:179Bull Bitcoin Mobilebdk_wallet_datasource.dart:202-204(bdk_dart default0xFFFFFFFD; set to0xFFFFFFFEonly whenreplaceByFee == false, which defaultstruesend_state.dart:82)group C - mixed
[0x01, 0xFFFFFFFF, …](bug):Cake Wallettransaction_builder.dart:402-406appliesreplaceByFeeSequenceonly toinputs[0]; remaining inputs stay atdefaultTxSequence. Combined withelectrum_wallet.dart:1516, every multi-input cake tx with confirmed UTXOs has the deterministic pattern[0x01, MAX, …, MAX], propagating through the spending graph.empirical confirmation in
How Fingerprints Damage PayJoin Privacy@arminsabouri: a real Cake → BBM payjoin is intra-uniform (the lib coerces receiver to match sender'snSequence), but Cake's prior tx carries the[1, MAX]pattern from the group C bug, propagating Cake-ownership via the backward channel and recovering the partition.the lib's intra-tx coerce (good!) doesn't reach into transactions that predate the payjoin. prior txs were built with each wallet's standard tx-construction code - the leak lives there.
should I open an issue on cake to fix group C (apply
replaceByFeeSequenceto all inputs, not justinputs[0])?zooming out, same family as #1586: would an "integration conformance policy" make sense? lib defines required tx-construction behaviors (uniform
nSequence, canonical sighash, etc.), enforced via sender-side validation or documented as protocol requirement, closing the divergence category at the source instead of patching wallet-by-wallet.the target end-state is only one group. with group B dissolved, 5 of 6 already converge on
0xFFFFFFFD; onlyCake's group-C bug diverges. fixing group C therefore closes thenSequencedivergence entirely - there's no residual A↔B split (apayjoin-cli↔Boltzpayjoin is already uniform). canonical convergence on0xFFFFFFFD(Bitcoin Core default since v0.16, now used by 5 of 6) plus sender-side conformance validation is the remaining policy question.EDIT:
group B - uniformlycorrected, dissolves into group A. the old0xFFFFFFFF(Sequence::MAX)Boltz/BBMMAX was their payjoin-contributed input, which the lib overwrites with the sender's sequence atreceive/common/mod.rs:285-317it never reaches the chain. their own txs use0xFFFFFFFD