107 lines
2.7 KiB
Plaintext
107 lines
2.7 KiB
Plaintext
pragma circom 2.0.0;
|
|
|
|
include "../circomlib/circuits/smt/smtprocessor.circom";
|
|
include "../circomlib/circuits/smt/smtverifier.circom";
|
|
include "../circomlib/circuits/comparators.circom";
|
|
|
|
|
|
// input:
|
|
// oldRoot
|
|
// from
|
|
// amount
|
|
// to
|
|
// signature
|
|
// extra input:
|
|
// fromBalance
|
|
// toBalance
|
|
// fromSiblings
|
|
// toSiblings
|
|
// output:
|
|
// newRoot
|
|
//
|
|
// proves:
|
|
// signature is verified
|
|
// from balance >= amount
|
|
// oldRoot calculated
|
|
//
|
|
// limited by sparse merkle tree implementation,
|
|
// we can't directly change the tree at once
|
|
// we can only update the tree with each leaf changes
|
|
// so we have an intermediate root showing from balance is reduced
|
|
//
|
|
// for each merkle tree proof, a list of siblings is required
|
|
// and provided as inputs
|
|
//
|
|
// original balance must be provided to calculate the new balance
|
|
//
|
|
// assumptions:
|
|
// - from and to is in tree
|
|
template AccountChange(nlevels) {
|
|
signal input from;
|
|
signal input amount;
|
|
signal input to;
|
|
|
|
signal input oldRoot;
|
|
|
|
signal input signature;
|
|
|
|
signal input fromBalance;
|
|
signal input fromSiblings[nlevels];
|
|
signal input toBalance;
|
|
signal input toSiblings[nlevels];
|
|
|
|
signal output newRoot;
|
|
|
|
// verify signature
|
|
|
|
// verify user's balance
|
|
component BalanceCheck = SMTVerifier(nlevels);
|
|
BalanceCheck.enabled <== 1;
|
|
BalanceCheck.root <== oldRoot;
|
|
for (var i = 0; i < nlevels; i++)
|
|
BalanceCheck.siblings[i] <== fromSiblings[i];
|
|
BalanceCheck.oldKey <== from;
|
|
BalanceCheck.oldValue <== fromBalance;
|
|
BalanceCheck.isOld0 <== 0;
|
|
BalanceCheck.key <== from;
|
|
BalanceCheck.value <== fromBalance;
|
|
BalanceCheck.fnc <== 0;
|
|
|
|
// abort if balance is not enough
|
|
component EnoughMoney = GreaterThan(252);
|
|
EnoughMoney.in[0] <== fromBalance;
|
|
EnoughMoney.in[1] <== amount;
|
|
EnoughMoney.out === 1;
|
|
|
|
// update from's balance
|
|
component ReduceFrom = SMTProcessor(nlevels);
|
|
ReduceFrom.oldRoot <== oldRoot;
|
|
for (var i = 0; i < nlevels; i++)
|
|
ReduceFrom.siblings[i] <== fromSiblings[i];
|
|
ReduceFrom.oldKey <== from;
|
|
ReduceFrom.oldValue <== fromBalance;
|
|
ReduceFrom.isOld0 <== 0;
|
|
ReduceFrom.newKey <== from;
|
|
ReduceFrom.newValue <== fromBalance - amount;
|
|
ReduceFrom.fnc[0] <== 0;
|
|
ReduceFrom.fnc[1] <== 1;
|
|
|
|
// update to's balance
|
|
component IncreaseTo = SMTProcessor(nlevels);
|
|
IncreaseTo.oldRoot <== ReduceFrom.newRoot;
|
|
for (var i = 0; i < nlevels; i++)
|
|
IncreaseTo.siblings[i] <== toSiblings[i];
|
|
IncreaseTo.oldKey <== to;
|
|
IncreaseTo.oldValue <== toBalance;
|
|
IncreaseTo.isOld0 <== 0;
|
|
IncreaseTo.newKey <== to;
|
|
IncreaseTo.newValue <== toBalance + amount;
|
|
IncreaseTo.fnc[0] <== 0;
|
|
IncreaseTo.fnc[1] <== 1;
|
|
|
|
// output the new root
|
|
newRoot <== IncreaseTo.newRoot;
|
|
}
|
|
|
|
component main {public [oldRoot]} = AccountChange(10);
|