Skip to content

Try preserving privacy for transactions greater than 2 outputs #551

Open

Description

@arminsabouri

When the receiver selects optimal inputs, they use the try_preserving_privacy function to choose an input in a way that avoids triggering the Unnecessary Input Heuristic (UIH{1|2}). Currently, privacy-aware input selection is only supported for transactions with exactly two outputs. The motivation for this ticket is twofold:

  1. Increasing the Anonymity Set:
    As explained in Unnecessary Input Heuristics & PayJoin Transactions, limiting payjoin transactions to two outputs inadvertently reduces the anonymity set as n-input-m-output payments become more common.

In its current state, PayJoin is only described for transactions with more than
one input and two outputs. This leads to an anonymity set of 15.4% compared to
the total number of transactions according to our extracted data for September
2020 (Figure 2). Moreover, it appears that classical payment transactions have
been decreasing over the past years. Therefore, PayJoin should also be extended
to transactions with more than two outputs to increase the anonymity set. As one
of the main contributions of PayJoin is breaking the common input ownership
heuristic, it can also poison the heuristic for a larger set of transactions.

  1. Support for Multiparty payjoins / NSMR. Even when N is small the number of outputs are generally greater than 2. Currently Multiparty Senders: NS1R #434 just picked the first candidate input.

Relaxing the 2 output requirment is easy enough and we should still be able to overcome UIH2 heuritic. However, we will be sacrifising the somewhat stealthy tx structure of payjoin. Per the quote above this might be a worthwhile sacrifise. We could also consider relaxing this requirment only in the multi-party context.

Activity

  1. Jolah1 commented on Aug 11, 2026

    @Jolah1
    Contributor

    I'd like to take this one.
    Reading through avoid_uih, the outputs.len() != 2 guard doesn't appear to be protecting any 2-output-specific math — the body already takes a min over all outputs and all inputs. What does need attention is the minimum-output
    term: the doc comment says it considers post-contribution amounts, but the computation folds in the receiver's own output at its pre-contribution value. Correcting that term makes the comparison well-defined for any number of outputs, so the guard falls out as a consequence rather than being relaxed on its own. I'll write that up properly with a failing test in the PR.

    Scope I'm proposing:

    • correct the minimum-output computation and drop the 2-output restriction that depends on it
    • keep erroring below 2 outputs, since a transaction with no change output gives UIH2 nothing to identify
    • unit tests covering 3-output transactions and the case where the receiver's output is the smallest

    I'd leave the output-splitting and candidate-scoring ideas from #1413 out of this — they're larger design questions and this change stands on its own without them.

    One question before I start. #1722 discusses moving try_preserving_privacy out of core into a separate heuristics crate so it can iterate at 0.x, and there's a concept ACK on that shape. With the 1.0 bump in #1801 open, is it worth landing this in core now, or would you rather hold it until that split is decided?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedExtra attention is needed

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions