Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gas Optimizations: PR #1 (closed #209 to include changes in this one) #213

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ node_modules/
proving-files/
zapps/
test-zapps/
test-contracts/
61 changes: 35 additions & 26 deletions contracts/merkle-tree/MerkleTree.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Author

@Antony-SS Antony-SS Jul 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reject the change to cast to a uint64. Accidentally left this in from when I was testing treeWidth as a uint64. Make sure to keep it as a constant though.

uint public leafCount; // the number of leaves currently in the tree

/**
Expand Down Expand Up @@ -85,7 +85,7 @@ contract MerkleTree is MiMC {
} else {
pow1 = pow2;
pow2 = pow2 << 1;
exp1++;
++exp1;
}
}
}
Expand All @@ -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;

Expand All @@ -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
}
Expand All @@ -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
Expand All @@ -170,7 +176,7 @@ contract MerkleTree is MiMC {
mstore(leafValues, sub(mload(leafValues), 1))
}
}
numberOfLeaves = treeWidth - leafCount;
numberOfLeaves = treeWidth_ - leafCount_;
}

uint slot;
Expand All @@ -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

Expand All @@ -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?
Expand All @@ -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
Expand All @@ -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
}

Expand Down
4 changes: 2 additions & 2 deletions contracts/merkle-tree/MiMC.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/verify/Pairing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 4 additions & 4 deletions contracts/verify/Verifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
}
}
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down