Skip to content

Instantly share code, notes, and snippets.

Last active May 30, 2022 17:00
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?

MW scripts

NOTE: Even if this holds any grounds, I don't believe it's a good fit for Grin for many reasons, but it may be something other projects could research further.

The grand MW formula that proves the spending history was valid and that there's no inflation is

Σutxo = Σkernel + offset*G + height*reward*H

The reason this proves the validity of all past transactions is because all relevant spending conditions are captured in the kernels which are ever growing. To remove an element from the left-hand side of the equation (a UTXO), you'd need to cancel out its blinding factor through a new kernel. I think this same strategy could be used for general spending conditions.

Below is a way to introduce a more powerful scripting variant whose correctness of spending history is verified by the grand MW formula. As mentioned above, the formula needs to capture all the outputs created and spent by valid spending scripts which preserves the security model.

Since the equation uses the ECC algebra, in order to do this, we have to map the scripts to curve points. We achieve this by mapping a script to a NUMS point which also helps us avoid any potential inflation vectors. The main idea is that when we create an output with a spending condition of a merkle tree root hash root_hash, we compute its corresponding NUMS mapping as P = to_nums(root_hash). To keep the formula balanced, we also create a new type of kernel KernelNUMSAdd that has a field hash which gets populated with root_hash and the verifier adds to_nums(hash) to the grand formula to keep the transaction and the grand equation balanced. We now have the grand equation balanced when we create a script output. Now we want to make sure that the output can't possibly be spent without a valid spending condition being met. To achieve this, when we spend an output, we also require a new type of kernel KernelNUMSSubtract that has two fields:

  1. proof which is an inclusion proof showing a spending condition for root_hash
  2. input which is an input parameter to the revealed spending condition

The verifier validates the spending condition and subtracts to_nums(root_hash). Essentially we have the following formula which prevents any manipulation and proves that all past spending scripts were valid without having to retain anything beyond kernels (which now include scripts as NUMS points as well as their valid spending proofs). We can think of the grand formula as being extended to

Σutxo + Σutxo_nums = Σkernel + Σkernel_nums + offset*G + height*reward*H

It is impossible to spend an output without showing a kernel with its spending condition even in the case of a long reorg. This is because, like output creation/spending, the script creation/spending is equally balanced on both sides of the equation. When we create an output with a blinding factor r1, we add r1 to both left and right side of the equation. When we spend an output we remove r1 from the left side and subtract it from the right side which cancels the previous r1 and thus keeps the equation balanced. Similarly with scripts, when we add a script output we add a specific NUMS to the left and right side of the equation and remove that NUMS from the left side and subtract it from the right side when that output is spent. This means that if someone wanted to spend a script output without revealing a script condition, the formula would not balance out because we would no longer have the NUMS point in the UTXO set, but we would have it cancelled out on the right side of the equation and thus the formula would not be balanced. A new verifier can check the whole history of spending conditions was valid.

This approach keeps the kernels "self-isolated" meaning that to validate a kernel, we don't need any additional data other than what is available on the kernel.

NITX example

Suppose we create an output whose one of the spending conditions is to reveal a signature with a specific pubkey A with the message being the kernel curve point. To spend this output, we create a new KernelNUMSSubtract kernel that reveals the inclusion proof for that spending condition script and we give the signature as the input param for that script. Since the script can include a public key of other parties, this allows noninteractive transactions given that the parties somehow communicate the blinding factor and the value of the output spent.

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