grinvestigation

Grinvestigation

View on GitHub

Bidirectional payment proofs for Mimblewimble

NOTE: The cryptography below has not been verified and it could be INSECURE! It needs to be proven correct before being used.

The existing payment proofs only work for the SRS flow and additionally, only allow the sender to show the payment proof.

An improvement over this is early payment proofs RFC which allows us to create payment proofs also for the invoice (RSR) flow.

I think both of them only allow the sender to show the payment proof. So if we think of payment proofs as:

            sent to
sender ----------------> receiver

         received from 
sender <---------------- receiver

We see that we only get the payment proofs from the sender to the receiver. There’s no way for the receiver to prove they received something from the sender. They only work in one direction.

Every payment in store comes with an invoice. The invoice serves as a proof for both the payer and the payee which allows them to prove the payer paid payee for some specific goods. It would be nice to have a payment proof that is simple and works in both ways.

Bidirectional payment proofs

In order for both parties to end up with a payment proof, we likely want to produce the payment proof at step 2 so that when a party produces a signature, they already have the payment proof information. Regardless of the flow, at step 2 we have both the sender’s public nonce Rs and the receiver’s public nonce Rr. This allows us to do the following.

Commitment

A transaction commits to a message which is publicly verified as part of a signature verification. Anyone can compute the Schnorr challenge e which is used to scale P in R + e*P = s*G. In order to commit to a payment proof, we commit to another (secret) message by scaling R part as well, but in a way that is invisible to the signature verifiers. This way, we don’t change the Schnorr verification formula which means we don’t add a scalar multiplication operation for the verifiers while still being able to prove the commitment.

Suppose our payment proof has the following fields:

type
amount
timestamp
memo

To commit to this payment proof, we can compute a challenge for the nonces as f = H(M' | Rs | Rr) where M' is our new hidden message commitment which is our payment proof.

Instead of using Rs as the sender nonce, we use Rs' = f * Rs. Similarly, instead of using Rr, we use Rr' = f * Rr and sign for the final kernel nonce Rs' + Rr'.

We also need a proof that Rs is owned by the sender_addr and Rr by receiver_addr. This can be done by providing a simple signature with their addresses with nonce as the message. This is why we don’t need the sender_addr and receiver_addr in the payment proof as these will have to be our witnesses.

Verification

Given (M', X, Rs, sig(Rs, sender_addr), Rr, sig(Rr, receiver_addr)) where M' is the payment proof, X is the kernel commitment of some kernel on chain and the rest is the original nonces with signatures as proofs of nonce ownership, any party can prove this kernel committed to payment proof M' by computing f = H(M' | Rs | Rr) and showing that f * Rs + f * Rr = R where R is a part of the signature (s, R) for that kernel.