Shuffle input order on bitcoin sends (#3379)
What changed, and why it matters
This change makes Bitcoin transactions shuffle the order of their inputs (the coins being spent). Shuffling input order is a common privacy improvement because it makes it harder for outside observers to guess which inputs belong to the same wallet or link transactions together. It does not fix a crash, theft bug, or direct exploit.
Treat as a routine privacy improvement. Review whether `BitcoinOrdering.shuffle` is implemented deterministically per transaction to avoid re-shuffling on every re-build, and verify it does not interfere with hardware-wallet signing or PSBT input matching.
Security signals we found
Privacy hardening: shuffling transaction inputs to reduce deterministic wallet fingerprinting
No input validation, parsing, or cryptographic change
No memory safety or authorization change
Change is limited to Bitcoin transaction construction ordering
Evidence from the diff
The commit adds inputOrdering: BitcoinOrdering.shuffle to two transaction-building paths in cw_bitcoin/lib/electrum_wallet.dart: the normal Bitcoin send flow and the fee-bump/RBF flow. Previously input ordering was left at its default, which likely produced deterministic ordering. By shuffling inputs, the wallet reduces deterministic fingerprints that chain-analysis can use to cluster addresses or infer wallet software.
Changed components
cw_bitcoin/lib/electrum_wallet.dartBitcoin transaction building (send and RBF/fee-bump flows)Inspect captured patch +2 / −0
diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart
index 3dbecad9..ccd41d01 100644
--- a/cw_bitcoin/lib/electrum_wallet.dart
+++ b/cw_bitcoin/lib/electrum_wallet.dart
@@ -1537,6 +1537,7 @@ abstract class ElectrumWalletBase
fee: estimatedTx.fee.amount,
network: network,
memo: estimatedTx.memo,
+ inputOrdering: BitcoinOrdering.shuffle,
outputOrdering: BitcoinOrdering.none,
enableRBF: !estimatedTx.spendsUnconfirmedTX,
);
@@ -2302,6 +2303,7 @@ abstract class ElectrumWalletBase
fee: BigInt.from(newFee),
network: network,
memo: memo,
+ inputOrdering: BitcoinOrdering.shuffle,
outputOrdering: BitcoinOrdering.none,
enableRBF: true,
);
Why this scored 32/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.