This is an idea I have had bouncing around for a little while that takes advantage of our concept “partial transactions” (discussed previously in the context of decoys and incremental aggregation during relay) and the “daily aggregator” currently being discussed.
This is far from a fully fleshed out idea and is still very rough but I wanted to see what people thought of this.
tl;dr We can non-interactively aggregate partial transactions, breaking linkability “at rest”. The partial transactions can collectively pay the fees for the final aggregated transaction. And we can potentially incentivize the aggregator for doing this work.
A “full transaction” consists of a set of input(s), a set of output(s), a kernel and an offset. For simplicity let’s assume transactions only contain a single kernel.
A -> [B, C], K, offset
We have previously discussed “self-spend” partial transactions (no kernel) as a way of adding decoy outputs or otherwise obfuscating existing transactions. It has been proposed that these could be aggregated or combined with an existing transaction given sufficient fee on the existing transaction.
A -> A’, excess
Alice, for example, could construct a “self-spend” partial transaction, moving funds from A to A’, by revealing the excess between the two commitments.
We believe partial transactions are safe to use in a “self-spend” scenario where Alice owns both A and A’. A partial transaction can be reversed given knowledge of the excess and is therefore unsafe for anything other than a “self-spend”.
In this scenario the original transaction sets the fee. Aggregation is only possible if the original tx had sufficient fee to cover the additional inputs and outputs from the partial transaction.
Partial Transaction Aggregation
Two partial transactions can be trivially aggregated -
A -> A’, excessA
B -> B’, excessB
[A, B] -> [A’, B’], (excessA + excessB)
Partial Transaction Fees
In the example above A and A’ have equal value. We are simply moving funds from one output to another.
But we could reduce
A' by a small amount and introduce an imbalance. Let’s call this imbalance the partial transaction “fee”.
A -> A’, fee, excess
The fee is the difference between the two committed values and the excess the difference between the two blinding factors.
(r1*G + v1*H) -> (r2*G + v2*H), (v1 - v2), (r1 - r2)
Note that the introduction of fees affects the reversibility of these partial transactions. It is no longer “free” to reverse a partial transaction and the fee must be “refunded”.
Partial Transaction Aggregation (2)
If each partial transaction includes a small “fee” then several can be aggregated together such that the sum of the fees is now sufficient to cover the cost of an additional kernel. We can now produce a full transaction from several partial transactions with the necessary kernel excess and offset.
A -> A’, feeA, excessA
B -> B’, feeB, excessB
[A, B] -> [A’, B’], KA+B, offset
Note that this aggregation is still non-interactive, similar to aggregation of full transactions. Alice, or Bob, or Charlie can take multiple partial transactions and construct the necessary kernel to produce a full transaction. The difference here is we only need a single kernel in the resulting aggregated transaction.
Aggregating full transaction on a delayed basis (daily, hourly, whatever) has the undesireable property of necessarily trading time for aggregation. Rather than a transaction confirming in ~60s we choose to wait 24 hours in an attempt to obfuscate linkability. This is maybe reasonable for some transactions but not others.
An alternative approach may be to aggregate “self-spend” partial transactions. We don’t attempt to break linkability within transactions, but between them.
Say we have two full transactions where one is dependent on the other. The concern is linkability across the shared output.
A -> B
B -> C
A -> B -> C
Aggregation of full transactions aims to obfuscate the linkability by increasing the number of possible links between inputs and outputs.
A -> B1
[B1, B2, …] -> [C1, C2, …]
A -> B1 -> C?
We can achieve similar obfuscation of linkability, not by aggregating full transactions, but instead by introducing aggregation between transactions.
A -> B
[B1, B2, …] -> [B’1, B’2, …]
B’ -> C
A -> B -?- B’ -> C
Here we are not attempting to obfuscate linkability of outputs “in transit” (within transactions) but instead “at rest” (between transactions). Introducing a 24 hour delay when funds are “at rest” may be a more acceptable user experience than delaying transactions themselves. A user could decide to aggregate overnight, for example. A user could receive a transaction quickly and then self-spend to obfuscate linkability with less concern over the cost of the delay.
This needs more thinking through of implications but given we can potentially include a small fee on each partial transaction sufficient for an aggregation kernel, it would be possible to include sufficient fee to cover an additional output, given a mechanism to reward the aggregator for their services. The fees from the partial transactions could pay for both the transaction fee and an additional aggregation fee claimed by the aggregator. This idea of incentivizing aggregation may be a bad idea, but it is worth thinking through.