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:
proofwhich is an inclusion proof showing a spending condition for
inputwhich 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.
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.