Skip to content

Instantly share code, notes, and snippets.

@phyro
Last active May 19, 2022 20:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save phyro/694d809931c83eaa15941367afe46249 to your computer and use it in GitHub Desktop.
Save phyro/694d809931c83eaa15941367afe46249 to your computer and use it in GitHub Desktop.

About Payjoins

Let's take a simple example of a UTXO transaction

5 -> 4 (change)
  -> 1 (receiver)

We'll be ignoring fees for simplicity. We have a single input with 5 coins and two outputs 4 and 1. The transaction above is an equation 5 = 4 + 1. The left-hand side of the equation has input amounts while the right-hand side has the output amounts. Since the transaction is an equation, we can flip these around 4 + 1 = 5 to obtain a valid transaction, but this time we have

4 (change)   -> 5
1 (receiver)

This is considered a payjoin because two parties contributed inputs. A regular transaction with 1 input and 2 outputs already does "payjoin" on the right-hand side of the transaction. It is done by the sender by contributing the change output.

Note: We had two arrows in the first transaction and only a single arrow in the "flipped" transaction. This is because an arrow represents an output in the above diagram.

Cash

When we're paying with cash, we never make a payjoin. Payjoining when paying in store with cash would only bring confusion and complexity without any benefits. Public ledgers are slightly different because we could get benefits that we don't with cash. Because of its public nature, banknotes can be tracked even if they can't be distinguished. Let's consider the following two transactions

# Alice pays Bob
5 -> 3 (change)
  -> 2 (Bob)

# Bob pays Charlie
2 -> 1 (change)
  -> 1 (Charlie)

which makes the following transaction graph

5 -> 3
  -> 2 -> 1
       -> 1 (Charlie)

The direction of the arrows is to the right and we can see that for every transaction, we have two arrows/outputs to the right side. This makes it quite hard to answer the question "To which output Bob sent money?" or "To which output Alice sent money?". In both cases, you have ambiguity because it can be either of the two arrows/outputs on the right. But let's turn the question around and ask "From which input Charlie received money?" and we have no ambiguity. It's 2 in the transaction graph. We can then ask again "From which input did the owner of 2 receive money?" and we can again trace this to 5. This is because the double arrow is only on the right side and as soon as we "flip the transaction" around we go from having two arrows to a single arrow because the flipped transaction has a single output. Answering questions about the right side of the equation (outputs) is exponentially hard with the number of transactions while answering questions about the left side (inputs) is linear and predictable. This leaves us with the following tracing:

  • To which output Alice sent money? - exponential (hard)
  • From which input Bob received money? - linear (easy)

It would be better if both questions were hard to answer to make it hard to analyze any direction with certainty which would significantly improve fungibility in my opinion. Having no payjoins present on the network also leaks information about the input ownership known as common-input-ownership heuristic.

Why payjoins

In order to ensure answering both questions is hard, we have to be able to flip the transaction around and keep at least two arrows/outputs. Let's first see what happens with a non-payjoin transaction

# Non-payjoin tx
5 (sender) -> 4 (sender)
           -> 1 (receiver)
  
# Flipped nonpayjoin tx
4 (sender)   -> 5 (sender)  
1 (receiver)

We have not preserved two arrows when we flipped a non-payjoin transaction which means that answering a question about inputs in the original transaction is easy. Let's take a look now what happens with a payjoin transaction

# Payjoin tx
5 (sender)   -> 4 (sender)
2 (receiver) -> 3 (receiver)

# Flipped payjoin tx
4 (sender)   -> 5 (sender)
3 (receiver) -> 2 (receiver)

We have preserved two arrows which makes answering questions in both directions exponential. This, in my opinion, is one of the big benefits of payjoins which I'd say outweighs the fact that the receiver shows an input to the sender. It may be better to optimize for both parties than just for the receiver.

Benefits of payjoins

Payjoin solves a couple of issues:

  1. they make answering questions from right-to-left equally hard
  2. they break the common-input-ownership heuristic
  3. they remove the sense of direction
  4. they improve the UTXO set scalability by keeping the set smaller
  5. they are more fair

I have not touched on points 3., 4. and 5. yet so let's do this now. First, 3. claims that payjoins remove the sense of a direction in the transaction. This is because it's impossible to know whether an input was from the sender or the receiver. While it's true that one party is the sender and one is the receiver, this information gets obfuscated for an outside observer and it looks like both are the sender and the receiver which makes the direction of the money flow unclear. Second, 4. claims we may improve UTXO set scalability. The more inputs we use across the chain history, the smaller the UTXO set will be. A regular 2-2 payjoin transaction uses two inputs and creates two outputs. This can be seen as an "update" of existing outputs rather than creation of something new. A transaction that is turned into a payjoin will always use more inputs than the non-payjoin equivalent which will result in a smaller network's UTXO set in the long run. Regarding the claim in 5., I claim this because transacting parties contributing to the right side of the transaction makes it mutually beneficial - both get some privacy regarding their created output. We already "payjoin" on the right side while leaving the party on the left side without any benefits. I think it's not fair that there is an asymmetry in what the parties learn about each other, specifically, the receiver learns two outputs about the sender, but the sender learns only one about the receiver. It would be nicer and more fair to not leave the sender without their benefits on the left side and provide the same benefits for both there as well. In general, information symmetry is more fair than asymmetry.

Downsides of payjoin

  1. receiver leaks an input to the sender
  2. receiver probabilistically leaks an input to an outside observer
  3. this leak forms a chain of receiver outputs, similar to the chain of change outputs the sender has

The first is obvious, the sender will know one of your inputs. This, in my opinion, is not as bad as it seems at first. They already know one of our inputs which is the output we created as a receiver (it will be an input in the future). In a payjoin, the sender finds out about another input of ours. The second is also obvious. An outside observer will learn that one of the inputs is from the receiver (with certain probability), but they won't be able to tell which one or the probability. The downsides are only for the receiver, while the sender benefits from the obfuscation. The third one is perhaps the most interesting. People learn another transaction of the receiver with probability (as they do today for the sender). The actual consequence of this would need a deeper analysis.

Defaulting to payjoins

This may sound controversial, but I think payjoin transactions make a better default than non-payjoin transactions. It seems to me that the more payjoins we have on the network, the more we make the transaction graph of the network probabilistic because payjoins make certain information (direction, sender inputs) probabilistic. We can no longer answer this with certainty unless the sender leaks these out, but that's a local problem of transacting with people you don't trust and this too can be combated through coinswap/coinjoin. The probabilistic nature is also true if we have some payjoins on the network, but the problem is that if we have too few payjoins (which is a likely outcome), the probabilies are so small that a tracing company can simply assume nonpayjoin transactions and find patterns that confirm this. Both options have their downsides regarding tracing, but my guess is that going towards inherently probabilistic information is a good step towards better fungibility. For fungibility of outputs in the network, it might be better to optimize for the privacy of all the parties rather than for the receiver. This way, the history of the outputs may end up being more obfuscated than when optimizing for a single party. The last sentence is my intuition (at the moment) and not something I have empirical evidence for. It would also be good to have some analysis for the "receiver change output" chain that happens when the receiver makes payjoins.

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