Repository navigation
Conversation
The receiver always contributed its smallest confirmed UTXO. A fixed smallest-first order systematically reproduces the Unnecessary Input Heuristic 2 fingerprint (the smallest input falling below the smallest output), which reveals that the transaction is a payjoin. rust-payjoin's TryPreservingPrivacy would avoid this, but the FFI returns an opaque InputPair that cannot be mapped back to the coin we need for reservation and signing, so selection cannot be delegated to it yet. Pick a candidate at random using a cryptographically secure shuffle instead, which removes the worst-case deterministic bias while keeping the coin identity we rely on. Also collapse the post-signing PSBT cleanup (finalize the contributed inputs, strip finalized scriptSig/witness from every other input, clear all partial signatures and key paths) into a single NormalizeContributedProposalSignatures method, so the invariant that only the receiver's contributed inputs carry signature material is enforced in one place rather than as four loose calls.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Selection always contributed the smallest confirmed UTXO, and doing that on every payjoin systematically reproduces the Unnecessary Input Heuristic 2 fingerprint — the smallest input sitting below the smallest output — which advertises that the transaction is a payjoin, the opposite of the point. I replace the deterministic smallest-first order with a cryptographically secure random shuffle of the candidates, keeping the coin identity we need for reservation and signing, which removes the worst-case deterministic bias.
Separately, the guarantee that no signature leaks onto a non-contributed input was implicit: the signer signed every wallet-owned input and then leaned on four separate cleanup calls to strip signatures off everything except the contributed inputs. I collapse that cleanup — finalizing the contributed inputs, stripping finalized scriptSig/witness from every other input, and clearing all partial signatures and key paths — into a single
NormalizeContributedProposalSignaturesmethod, so the invariant is enforced in one place; this also resolves an existing TODO.note — partial mitigation, blocked upstream
rust-payjoin's
try_preserving_privacywould do proper UIH2 avoidance, but the FFI hands back an opaqueInputPairwith no outpoint accessor andWantsInputsexposes no PSBT, so the selected input can't be mapped back to theReceivedCoinwe need for reservation and signing. Random selection is the best standalone mitigation available; full UIH2 avoidance needs an upstream payjoin-ffi change that exposes the chosen coin or accepts an index, which is worth filing.