Skip to content

Instantly share code, notes, and snippets.


phyro/ Secret

Last active Jan 23, 2021
What would you like to do?
Replays and Aggregators

Replay resistance through aggregators

One of the previous protections against replay attacks required the attacker to replay a sequence of payjoin transactions until the attacker was met with an impossible requirement of replaying a transaction that was impossible to replay due to a duplicate output (anchor solution) consensus rule violation.

This is an attempt to not introduce an absolute protection as the anchor solution does, but perhaps something that is for most practical concerns a good enough solution.

Main idea

Let's assume we have a daily aggregator A. Every transaction that gets published on the chain also sends a coinswap for each created output to A.

Let's reuse the idea of making every transaction a payjoin. We now have the same first step part of the attack protected in the same way which is that the attacker would need to replay a sequence of payjoin transactions. But we lack the initial condition which would make it impossible to replay the first transaction.

Let's assume we get an output from a daily aggregator O1. If a significant aggregation took place in A when O1 was created, then we can assume that it is extremely hard to replay the aggregated transaction that created O1. This is because all the outputs in the aggregated transactions need to be spent and the attacker would also need to know how to generate all the inputs of the aggregated transaction which seems almost impossible to do. The output O1 can thus play a similar role as an anchor, but can be spent.

All we have to do is know which outputs were 'coinswapped' and then use these as inputs for our payjoin transactions.

In order to be able to do simultaneous transactions, the wallet makes sure it has N "safe" outputs available. We could label a coinswapped output as "safe" by using one of the zero bits in the bulletproof and setting it to 1.

Note: When doing a payjoin with a safe input B_I', then the output we create B_O is also safe.

Wallet algorithm


Alice (sender) has an input A_I and a change output A_O. After the transaction has been broadcasted, A_O' is created with a bulletproof coinswap bit set to 1 and A_O -> A_O' is sent to the daily aggregator.


Bob (receiver) contributes an input B_I' (coinswapped) to the transaction, making a payjoin. Bob also has an output B_O and similarly as in the case of Alice, after the transaction has been broadcasted, B_O' is created with a bulletproof coinswap bit set to 1 and B_O -> B_O' is sent to the daily aggregator.

First receive

It is impossible to contribute a coinswapped input when you don't own any output. The first receive can be made safe if the received output is coinswapped in the aggregator before doing any other transaction.


This is hard enough to replay as is, but can be made basically impossible if the daily aggregator contributes aggri-1 -> aggri to the daily aggregated transaction i and then in i+1 adds aggri -> aggri+1 and so on. This would require the attacker to replay everything from all the daily aggregators which is practically impossible.

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