← Back to team overview

mimblewimble team mailing list archive

Fwd: Relative Locktimes in Grin


dear Mimblewimblers,

Let me go into a more detailed explanation of the intended use of NRD kernels,
which is in payment channels.

Suppose that Alice and Bob have funded a channel with a total of v
Grin that's sitting in the 2-of-2 channel output C_0 = r_0^A * G + v*H
+ r_0^B * G, and they want to update the state to a new one where
Alice is entitled to v_i^A Grin and Bob to v_i^B Grin (which must
necessarily sum to v Grin.)

They pick new blinding factors for their default individual settlement
outputs, which are
S_i^A = r_i^A * G + v_i^A * H and S_i^B = r_i^B * G + v_i^B * H. They
also construct and share rangeproofs of these outputs. Let S_i = r_i^A
* G + v*H + r_i^B * G denote the sum of the outputs.

I call them "default" because in any actual settlement transaction,
say by Alice, she is free to change her blinding factor to any other
while also changing the transaction's kernel offset by the same
amount, and redoing the rangeproof on her output (she'll have to keep
Bob's default output as is).

These blinding factors determine excesses x_i^A = r_i^A - r_0^A and
x_i^B = r_i^B - r_0^B between C_0 and S_i. Setting x_i = x_i^A +
x_i^B, we have S_i - C_0 = x_i * G.

We now define a midway output as being halfway between C_0 and S_i:
M_i = (C_0 + S_i) / 2 = C_0 + (x_i / 2) * G = S_i - (x_i / 2) * G. The
parties also construct and share the rangeproof for midstate output

We can think of settlement as being done in two equal halves, with 2
equal half-kernels, which is where the NRD kernels come in. In order
to allow for revoking an attempted old settlement, there is a required
delay between 2 instances of the same NRD kernel.

To make everything work, Alice and Bob now pick their own secret
kernel offset o_i^A and o_i^B, and they construct NRD kernels K_i^A =
(x_i/2 - o_i^A) * G and K_i^B = (x_i/2 - o_i^B) * G. Note that Alice
can get Bob's partial signature on K_i^A without Bob learning o_i^A
(he only learns o_i^A * G), and vice-versa.

At this point, if i is the final channel state, Alice could publish a
half-settle transaction, and once on-chain, wait for the requisite
delay before publishing the 2nd half (with possible change in Alice's
output as noted earlier). Or Bob could publish the 2nd half without
delay using his different NRD kernel.

Now we come to the most interesting part. What if the state is updated to i+1?
In that case Alice and Bob will construct a revoke kernel for excess -x_i.
Note that this is a full negative excess, corresponding to a
transition from S_i back to C_0.

Should Alice in future, say in state j, ever attempt to close with
transaction C_0 -> M_i using NRD kernel K_i^A, then Bob can construct
the cut-through of transactions
M_i -> S_i using NRD kernel K_i^B with offset o_i^B,
S_i -> C_0 using revoke kernel -x_i * G with 0 offset,
C_0 -> M_j using NRD kernel K_j^B with offset o_j^B
which is
M_i -> M_j with 3 valid kernels and offset o_i^B+o_j^B.
Even if Alice sees the publication of this transaction, she should be
unable to de-aggregate it and override it to stop at S_i.

(an initial version of this revoke mechanism also featured separate
revoke kernels with private offsets, but having two offsets added
rather than three in the final revoke seems sufficient).

This design also prevents looping games, where Alice attempts to close
an old state, and then quickly self-revokes to keep the game going,
and stop Bob from extracting his channel funds.

We welcome feedback on this use of NRD kernels in a payment channel
revoke mechanism.


‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
> I'd like to propose a modification to NSKR locks that may eliminate the need to explicitly reference a prior kernel.
> Assumptions -
> * Grin/MW allows duplicate kernels to exist on-chain.
> * A duplicate kernel can be reused across different transactions, with compensating adjustments to the kernel excess via the kernel offset.
> Instead of kernel B referencing kernel A with a relative lockheight between them, we can instead have two instances of the same kernel A and A' with a relative lockheight between them.
> A sort of self-referential negative trigger.
> Each instance of the kernel would delay the next instance for at least the specified lockheight number of blocks.
> John Tromp wasted no time in naming this "No Recent Duplicate" or NRD locks.
> An NSKR kernel explicitly references a prior kernel and this reference would need to be stored on-chain.
> An NRD kernel would simply not be valid within n blocks (say 1440 blocks for 1 day) of any prior instance of itself.
> Note the first instance of an NRD kernel would trivially meet the conditions of the lock, with no prior instance existing to lock it.
> The same "moving window" concept of recent history would still apply, allowing kernel history to be efficiently verified.
> For a relative lock height of 1440 we need only look back over 1440 blocks of history as the lock "fails open" beyond that.
> One downside to this is the later referencing kernel and the prior referenced kernel would both be flagged as NRD.
> In the case of NSKR only the later referencing kernel need be flagged as such.
> This would make lookups easier and cheaper though as we would not need to maintain a full index of recent kernel history.
> We would only care about recent NRD kernels.
> NRD locks may solve the problem of how to reference a prior kernel without requiring any additional on-chain data beyond the relative lockheight itself.
> Feedback appreciated.
> - Antioch