diff --git a/.gitignore b/.gitignore index 973ce80b6..371305122 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ node_modules/ proving-files/ zapps/ test-zapps/ +test-contracts/ \ No newline at end of file diff --git a/contracts/merkle-tree/MerkleTree.sol b/contracts/merkle-tree/MerkleTree.sol index de3c300f0..44a9a5aeb 100644 --- a/contracts/merkle-tree/MerkleTree.sol +++ b/contracts/merkle-tree/MerkleTree.sol @@ -46,14 +46,14 @@ contract MerkleTree is MiMC { /** These events are what the merkle-tree microservice's filters will listen for. */ - event NewLeaf(uint leafIndex, uint leafValue, uint root); - event NewLeaves(uint minLeafIndex, uint[] leafValues, uint root); + event NewLeaf(uint indexed leafIndex, uint indexed leafValue, uint indexed root); + event NewLeaves(uint indexed minLeafIndex, uint[] leafValues, uint indexed root); // event Output(uint[] input, uint[] output, uint prevNodeIndex, uint nodeIndex); // for debugging only - uint public zero = 0; - uint public treeHeight = 32; // - uint public treeWidth = 2 ** treeHeight; + uint public constant zero = 0; + uint public constant treeHeight = 32; + uint public constant treeWidth = uint64(2 ** treeHeight); uint public leafCount; // the number of leaves currently in the tree /** @@ -85,7 +85,7 @@ contract MerkleTree is MiMC { } else { pow1 = pow2; pow2 = pow2 << 1; - exp1++; + ++exp1; } } } @@ -97,19 +97,20 @@ contract MerkleTree is MiMC { @return root - the root of the merkle tree, after the insert. */ function insertLeaf(uint leafValue) public returns (uint root) { - + // Cache variables so they aren't continually read from storage + (uint treeHeight_, uint treeWidth_, uint leafCount_) = (treeHeight, treeWidth, leafCount); // check that space exists in the tree: - require(treeWidth > leafCount, "There is no space left in the tree."); + require(treeWidth_ > leafCount_, "There is no space left in the tree."); - uint slot = getFrontierSlot(leafCount); - uint nodeIndex = leafCount + treeWidth - 1; + uint slot = getFrontierSlot(leafCount_); + uint nodeIndex = leafCount_ + treeWidth_ - 1; uint prevNodeIndex; uint nodeValue = leafValue; // nodeValue is the hash, which iteratively gets overridden to the top of the tree until it becomes the root. uint[] memory input = new uint[](2); //input of the hash fuction uint[] memory output = new uint[](1); // output of the hash function - for (uint level = 0; level < treeHeight; level++) { + for (uint level = 0; level < treeHeight_;) { if (level == slot) frontier[slot] = nodeValue; @@ -134,14 +135,17 @@ contract MerkleTree is MiMC { nodeIndex = nodeIndex / 2; // move one row up the tree // emit Output(input, output, prevNodeIndex, nodeIndex); // for debugging only } + unchecked { + ++level; // GAS OPT: we know this won't overflow + } } root = nodeValue; root = uint(bytes32(root)); - emit NewLeaf(leafCount, leafValue, root); // this event is what the merkle-tree microservice's filter will listen for. + emit NewLeaf(leafCount_, leafValue, root); // this event is what the merkle-tree microservice's filter will listen for. - leafCount++; // the incrememnting of leafCount costs us 20k for the first leaf, and 5k thereafter + ++leafCount; // the incrememnting of leafCount costs us 20k for the first leaf, and 5k thereafter return root; //the root of the tree } @@ -152,15 +156,17 @@ contract MerkleTree is MiMC { @return root - the root of the merkle tree, after all the inserts. */ function insertLeaves(uint[] memory leafValues) public returns (uint root) { + // read pertinent vars into memory from storage in one operation + (uint treeHeight_, uint treeWidth_, uint leafCount_) = (treeHeight, treeWidth, leafCount); uint numberOfLeaves = leafValues.length; // check that space exists in the tree: - require(treeWidth > leafCount, "There is no space left in the tree."); - if (numberOfLeaves > treeWidth - leafCount) { - uint numberOfExcessLeaves = numberOfLeaves - (treeWidth - leafCount); + require(treeWidth_ > leafCount_, "There is no space left in the tree."); + if (numberOfLeaves > treeWidth_ - leafCount_) { + uint numberOfExcessLeaves = numberOfLeaves - (treeWidth_ - leafCount_); // remove the excess leaves, because we only want to emit those we've added as an event: - for (uint xs = 0; xs < numberOfExcessLeaves; xs++) { + for (uint xs = 0; xs < numberOfExcessLeaves; ++xs) { /* CAUTION!!! This attempts to succinctly achieve leafValues.pop() on a **memory** dynamic array. Not thoroughly tested! Credit: https://ethereum.stackexchange.com/a/51897/45916 @@ -170,7 +176,7 @@ contract MerkleTree is MiMC { mstore(leafValues, sub(mload(leafValues), 1)) } } - numberOfLeaves = treeWidth - leafCount; + numberOfLeaves = treeWidth_ - leafCount_; } uint slot; @@ -182,9 +188,9 @@ contract MerkleTree is MiMC { uint[] memory output = new uint[](1); // the output of the hash // consider each new leaf in turn, from left to right: - for (uint leafIndex = leafCount; leafIndex < leafCount + numberOfLeaves; leafIndex++) { - nodeValue = leafValues[leafIndex - leafCount]; - nodeIndex = leafIndex + treeWidth - 1; // convert the leafIndex to a nodeIndex + for (uint leafIndex = leafCount_; leafIndex < leafCount_ + numberOfLeaves; ++leafIndex) { + nodeValue = leafValues[leafIndex - leafCount_]; + nodeIndex = leafIndex + treeWidth_ - 1; // convert the leafIndex to a nodeIndex slot = getFrontierSlot(leafIndex); // determine at which level we will next need to store a nodeValue @@ -194,7 +200,7 @@ contract MerkleTree is MiMC { } // hash up to the level whose nodeValue we'll store in the frontier slot: - for (uint level = 1; level <= slot; level++) { + for (uint level = 1; level <= slot; ++level) { if (nodeIndex % 2 == 0) { // even nodeIndex input[0] = frontier[level - 1]; //replace with push? @@ -221,7 +227,7 @@ contract MerkleTree is MiMC { } // So far we've added all leaves, and hashed up to a particular level of the tree. We now need to continue hashing from that level until the root: - for (uint level = slot + 1; level <= treeHeight; level++) { + for (uint level = slot + 1; level <= treeHeight_;) { if (nodeIndex % 2 == 0) { // even nodeIndex @@ -244,15 +250,18 @@ contract MerkleTree is MiMC { nodeIndex = nodeIndex / 2; // the parentIndex, but will become the nodeIndex of the next level // emit Output(input, output, prevNodeIndex, nodeIndex); // for debugging only } - + + unchecked { + ++level; + } } root = nodeValue; root = uint(bytes32(root)); - emit NewLeaves(leafCount, leafValues, root); // this event is what the merkle-tree microservice's filter will listen for. + emit NewLeaves(leafCount_, leafValues, root); // this event is what the merkle-tree microservice's filter will listen for. - leafCount += numberOfLeaves; // the incrememnting of leafCount costs us 20k for the first leaf, and 5k thereafter + leafCount += numberOfLeaves; // the incrementing of leafCount costs us 20k for the first leaf, and 5k thereafter return root; //the root of the tree } diff --git a/contracts/merkle-tree/MiMC.sol b/contracts/merkle-tree/MiMC.sol index a58d3f46f..d4f44f849 100644 --- a/contracts/merkle-tree/MiMC.sol +++ b/contracts/merkle-tree/MiMC.sol @@ -67,8 +67,8 @@ contract MiMC { uint256 r = in_k; uint256 localQ = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001; - uint256 i; - for( i = 0; i < in_x.length; i++ ) + + for(uint256 i = 0; i < in_x.length; ++i ) { r = (r + (in_x[i] % localQ) + MiMCp(in_x[i], r, in_seed, round_count)) % localQ; } diff --git a/contracts/verify/Pairing.sol b/contracts/verify/Pairing.sol index d652b75a8..93f03e790 100644 --- a/contracts/verify/Pairing.sol +++ b/contracts/verify/Pairing.sol @@ -90,7 +90,7 @@ library Pairing { uint elements = p1.length; uint inputSize = elements * 6; uint[] memory input = new uint[](inputSize); - for (uint i = 0; i < elements; i++) + for (uint i = 0; i < elements; ++i) { input[i * 6 + 0] = p1[i].X; input[i * 6 + 1] = p1[i].Y; diff --git a/contracts/verify/Verifier.sol b/contracts/verify/Verifier.sol index 52d3e434a..3ea375c52 100644 --- a/contracts/verify/Verifier.sol +++ b/contracts/verify/Verifier.sol @@ -48,8 +48,8 @@ contract Verifier is Ownable { uint256 private r = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - function validateInputs(uint256[] memory _inputs) public view { - for (uint i = 0; i < _inputs.length; i++) { + function validateInputs(uint256[] calldata _inputs) public view { + for (uint i = 0; i < _inputs.length; ++i) { require(_inputs[i] < r, "Inputs must be less than r."); } } @@ -63,7 +63,7 @@ contract Verifier is Ownable { } } - function verificationCalculation(uint256[] memory _proof, uint256[] memory _publicInputs, uint256[] memory _vk) public returns (uint) { + function verificationCalculation(uint256[] calldata _proof, uint256[] calldata _publicInputs, uint256[] calldata _vk) public returns (uint) { Proof_G16 memory proof; Pairing.G1Point memory vk_dot_inputs; @@ -92,7 +92,7 @@ contract Verifier is Ownable { require(vk.gamma_abc.length == _publicInputs.length + 1, "Length of inputs[] or vk.query is incorrect!"); Pairing.G1Point memory sm_qpih; - for (uint i = 0; i < _publicInputs.length; i++) { + for (uint i = 0; i < _publicInputs.length; ++i) { sm_qpih = Pairing.scalar_mul(vk.gamma_abc[i+1], _publicInputs[i]); vk_dot_inputs = Pairing.addition( vk_dot_inputs, diff --git a/package-lock.json b/package-lock.json index c64eb62b5..77b90286c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "prettier": "^2.2.1", "shelljs": "^0.8.5", "solc": "^0.8.0", - "typescript": "4.9.5", + "typescript": "^4.9.5", "winston": "^3.3.3", "yargs": "^15.4.1", "zkp-utils": "^1.0.8" @@ -47,7 +47,7 @@ "@types/json-diff": "^0.7.0", "@types/lodash.clonedeep": "^4.5.6", "@types/mocha": "^9.1.0", - "@types/node": "^17.0.19", + "@types/node": "^17.0.45", "@types/prettier": "^2.4.4", "chai-as-promised": "^7.1.1", "chai-http": "^4.3.0", @@ -2272,9 +2272,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "17.0.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.19.tgz", - "integrity": "sha512-PfeQhvcMR4cPFVuYfBN4ifG7p9c+Dlh3yUZR6k+5yQK7wX3gDgVxBly4/WkBRs9x4dmcy1TVl08SY67wwtEvmA==", + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", "dev": true }, "node_modules/@types/normalize-package-data": { @@ -14094,9 +14094,9 @@ "dev": true }, "@types/node": { - "version": "17.0.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.19.tgz", - "integrity": "sha512-PfeQhvcMR4cPFVuYfBN4ifG7p9c+Dlh3yUZR6k+5yQK7wX3gDgVxBly4/WkBRs9x4dmcy1TVl08SY67wwtEvmA==", + "version": "17.0.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", + "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", "dev": true }, "@types/normalize-package-data": { diff --git a/package.json b/package.json index 65e7f899b..569381f13 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "@types/json-diff": "^0.7.0", "@types/lodash.clonedeep": "^4.5.6", "@types/mocha": "^9.1.0", - "@types/node": "^17.0.19", + "@types/node": "^17.0.45", "@types/prettier": "^2.4.4", "chai-as-promised": "^7.1.1", "chai-http": "^4.3.0",