From c9b7c9b8aa60c3cd45d76f31d89d73f4a1823b60 Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 9 May 2024 15:09:28 -0700 Subject: [PATCH 1/6] fix gas loop optimization in MerkleProof.sol (#5028) --- contracts/utils/cryptography/MerkleProof.sol | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/contracts/utils/cryptography/MerkleProof.sol b/contracts/utils/cryptography/MerkleProof.sol index dce05a0dc05..7b9678e32ba 100644 --- a/contracts/utils/cryptography/MerkleProof.sol +++ b/contracts/utils/cryptography/MerkleProof.sol @@ -50,8 +50,11 @@ library MerkleProof { */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; - for (uint256 i = 0; i < proof.length; i++) { + for (uint256 i; i < proof.length; ) { computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]); + unchecked { + ++i; + } } return computedHash; } @@ -61,8 +64,11 @@ library MerkleProof { */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; - for (uint256 i = 0; i < proof.length; i++) { + for (uint256 i; i < proof.length; ) { computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]); + unchecked { + ++i; + } } return computedHash; } @@ -135,12 +141,15 @@ library MerkleProof { // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. - for (uint256 i = 0; i < totalHashes; i++) { + for (uint256 i; i < totalHashes; ) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = Hashes.commutativeKeccak256(a, b); + unchecked { + ++i; + } } if (totalHashes > 0) { @@ -191,12 +200,15 @@ library MerkleProof { // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. - for (uint256 i = 0; i < totalHashes; i++) { + for (uint256 i; i < totalHashes; ) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = Hashes.commutativeKeccak256(a, b); + unchecked { + ++i; + } } if (totalHashes > 0) { From 9e2ba99dfcf5f145fd68c5eea42d899836d9571b Mon Sep 17 00:00:00 2001 From: Carson Date: Thu, 9 May 2024 15:30:01 -0700 Subject: [PATCH 2/6] fix gas loop optimization in MerkleProof.sol | caching length (#5028) --- contracts/utils/cryptography/MerkleProof.sol | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/contracts/utils/cryptography/MerkleProof.sol b/contracts/utils/cryptography/MerkleProof.sol index 7b9678e32ba..a9f7f37f78e 100644 --- a/contracts/utils/cryptography/MerkleProof.sol +++ b/contracts/utils/cryptography/MerkleProof.sol @@ -50,7 +50,8 @@ library MerkleProof { */ function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; - for (uint256 i; i < proof.length; ) { + uint256 len = proof.length; + for (uint256 i; i < len; ) { computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]); unchecked { ++i; @@ -64,7 +65,8 @@ library MerkleProof { */ function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; - for (uint256 i; i < proof.length; ) { + uint256 len = proof.length; + for (uint256 i; i < len; ) { computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]); unchecked { ++i; From 6845307f3a939df5450f5b45459ea95248771569 Mon Sep 17 00:00:00 2001 From: cairo <101215230+cairoeth@users.noreply.github.com> Date: Fri, 31 May 2024 14:32:20 -0700 Subject: [PATCH 3/6] remove unchecked block and make variable explicit --- contracts/utils/cryptography/MerkleProof.sol | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/contracts/utils/cryptography/MerkleProof.sol b/contracts/utils/cryptography/MerkleProof.sol index a9f7f37f78e..b280614c846 100644 --- a/contracts/utils/cryptography/MerkleProof.sol +++ b/contracts/utils/cryptography/MerkleProof.sol @@ -51,11 +51,8 @@ library MerkleProof { function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; uint256 len = proof.length; - for (uint256 i; i < len; ) { + for (uint256 i = 0; i < len; i++) { computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]); - unchecked { - ++i; - } } return computedHash; } @@ -66,11 +63,8 @@ library MerkleProof { function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { bytes32 computedHash = leaf; uint256 len = proof.length; - for (uint256 i; i < len; ) { + for (uint256 i = 0; i < len; i++) { computedHash = Hashes.commutativeKeccak256(computedHash, proof[i]); - unchecked { - ++i; - } } return computedHash; } @@ -143,15 +137,12 @@ library MerkleProof { // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. - for (uint256 i; i < totalHashes; ) { + for (uint256 i = 0; i < totalHashes; ) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = Hashes.commutativeKeccak256(a, b); - unchecked { - ++i; - } } if (totalHashes > 0) { @@ -202,15 +193,12 @@ library MerkleProof { // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. - for (uint256 i; i < totalHashes; ) { + for (uint256 i = 0; i < totalHashes; ) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) : proof[proofPos++]; hashes[i] = Hashes.commutativeKeccak256(a, b); - unchecked { - ++i; - } } if (totalHashes > 0) { From ec869726994974d5628b5878493dd1ac43fc433a Mon Sep 17 00:00:00 2001 From: cairo <101215230+cairoeth@users.noreply.github.com> Date: Fri, 31 May 2024 14:33:47 -0700 Subject: [PATCH 4/6] add increase for loops --- contracts/utils/cryptography/MerkleProof.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/utils/cryptography/MerkleProof.sol b/contracts/utils/cryptography/MerkleProof.sol index b280614c846..0745746f61b 100644 --- a/contracts/utils/cryptography/MerkleProof.sol +++ b/contracts/utils/cryptography/MerkleProof.sol @@ -137,7 +137,7 @@ library MerkleProof { // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. - for (uint256 i = 0; i < totalHashes; ) { + for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) @@ -193,7 +193,7 @@ library MerkleProof { // get the next hash. // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the // `proof` array. - for (uint256 i = 0; i < totalHashes; ) { + for (uint256 i = 0; i < totalHashes; i++) { bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; bytes32 b = proofFlags[i] ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) From d58f5379a67649cfe7d4979280a644995db6eff7 Mon Sep 17 00:00:00 2001 From: cairo <101215230+cairoeth@users.noreply.github.com> Date: Fri, 31 May 2024 14:53:55 -0700 Subject: [PATCH 5/6] add changeset --- .changeset/funny-houses-thank.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/funny-houses-thank.md diff --git a/.changeset/funny-houses-thank.md b/.changeset/funny-houses-thank.md new file mode 100644 index 00000000000..6170614234d --- /dev/null +++ b/.changeset/funny-houses-thank.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`MerkleProof`: Optimize loops of proof processing functions From 27654f7d3e2843a73b731dc6a6365ee1b0003a18 Mon Sep 17 00:00:00 2001 From: cairo <101215230+cairoeth@users.noreply.github.com> Date: Fri, 31 May 2024 15:04:55 -0700 Subject: [PATCH 6/6] Delete funny-houses-thank.md --- .changeset/funny-houses-thank.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .changeset/funny-houses-thank.md diff --git a/.changeset/funny-houses-thank.md b/.changeset/funny-houses-thank.md deleted file mode 100644 index 6170614234d..00000000000 --- a/.changeset/funny-houses-thank.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'openzeppelin-solidity': minor ---- - -`MerkleProof`: Optimize loops of proof processing functions