Edit: I’ve tried to capture the whole idea here https://gist.github.com/phyro/ef42ce95cfbad05964f8be2f5d8f9466
Say we have a transaction
T and we want to prove it was added in block
B. We can do that by either:
- Checking the
utxo_mmr_rootof the block
Band then have a merkle proof for inclusion of the outputs of
T. (Edit: I’ve been corrected that this does not prove inclusion of
- Checking the position of the transaction kernel and computing from
kernel_mmr_sizein to get the block in which it was added (a bit weaker because it does not commit to utxos)
There’s another simple way to prove it which is basically the standard “global excess validation” where you subtract the transaction and check that the block is still valid (it should be if outputs were
0*H and if they were not, you can adjust them by adding
v*H + 0*G outputs and check it then).
Let’s assume we take part in a PayJoin transaction that adds one input and one output to it
I1->O1 but we don’t know the rest of the transaction. If
O1 was generated from
I1 AND both had a form
0*H + r*G we could, given
O1, compute also
I1 which means that we would know
O1.r - I1.r. This means that if this ‘subset transaction’ was included in a block
B, then if we have:
the sum of kernels at block
we can compute the sum based on the
the total kernel offset
blocks have a header
the total UTXO set sum
we don’t have this, but imagine a block header commits to the
We could check if
I1->O1 was a part of block
B by adjusting the total_kernel_offset and the total_utxo_set at that block. If it can be validated as “a valid chain” after the change, then we know that the difference of these blinding factors was a part of the transaction (I think).
This could seem useless because why would you keep the subset of a transaction instead of keeping it all, but you might not need to keep even the subset if
O1 is derived from
I1. Suppose you have a chain of PayJoin txs to which you added pairs
X -> A, O1 # + O1.r O1 -> O2 # - O1.r + O2.r O2 -> O3 # - O2.r + O3.r O3 -> O4 # - O3.r + O4.r O4 -> O5 # - O4.r + O5.r
If we restore a wallet and see
O5, then we can compute
O4 which means that we know
O5.r - O4.r and can thus check every block from head towards genesis which block would be valid if this ‘subset transaction’ would be removed. Note that if it was included in a block, such a block MUST exist because the block would need to be valid without this 1-1 part as well because they had
Once we have found
O4 we can again figure out
O3 and then repeat the check for blocks prior to the block where
O4 was included.
This way, we can prove a subgraph (chain) from
O1->O2->O3->O4->O5 exists on the blockchain without the need to actually keep the transaction data around.
Whether this is useful or not is still not clear to me, but I thought I’d still share. I guess the outcome here is that if we had the
total_utxo_set commitment on the header, some new options might be possible. I’m also sharing this in case someone else sees anything usefull that could come from this.
Note: A 2-2 PayJoin can be broken down into 2 transactions, 1 that is known to the sender (sender’s input and output) and 1 to receiver (receiver’s input and output), so we have a transaction a transaction we want. If input and output are generated deterministically, we can generate them and don’t really need to save them anywhere. We’ve shown above (hopefully) that only a transaction is needed to compute in which block it was added.