From 0c2faa2f17fee8a404918eb744ca698dfa81d816 Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Tue, 12 Aug 2025 12:18:24 -0400 Subject: [PATCH 1/2] perf: optimize `MerkleTreeLib` pow2 padding --- src/utils/MerkleTreeLib.sol | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/utils/MerkleTreeLib.sol b/src/utils/MerkleTreeLib.sol index 6d12bec529..a1975c5523 100644 --- a/src/utils/MerkleTreeLib.sol +++ b/src/utils/MerkleTreeLib.sol @@ -254,6 +254,7 @@ library MerkleTreeLib { pure returns (bytes32[] memory result) { + uint256 p = roundUpPow2(leaves.length); /// @solidity memory-safe-assembly assembly { result := mload(0x40) @@ -262,8 +263,6 @@ library MerkleTreeLib { mstore(0x00, 0xe7171dc4) // `MerkleTreeLeavesEmpty()`. revert(0x1c, 0x04) } - let p := 1 // Padded length. - for {} lt(p, l) {} { p := add(p, p) } mstore(result, p) // Store length. mstore(0x40, add(result, add(0x20, shl(5, p)))) // Allocate memory. let d := sub(result, leaves) @@ -282,4 +281,22 @@ library MerkleTreeLib { function pad(bytes32[] memory leaves) internal pure returns (bytes32[] memory result) { result = pad(leaves, bytes32(0)); } + + /// @dev Returns the smallest power of 2 greater than or equal to `x`. + /// Defaults to zero if `x == 0`. + function roundUpPow2(uint256 x) internal pure returns (uint256 y) { + /// @solidity memory-safe-assembly + assembly { + y := sub(x, 1) + y := or(y, shr(1, y)) + y := or(y, shr(2, y)) + y := or(y, shr(4, y)) + y := or(y, shr(8, y)) + y := or(y, shr(16, y)) + y := or(y, shr(32, y)) + y := or(y, shr(64, y)) + y := or(y, shr(128, y)) + y := add(y, 1) + } + } } From 58c73775e4a6fabffc2f5a636cc366bce6d9a8ba Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Tue, 12 Aug 2025 17:13:54 -0400 Subject: [PATCH 2/2] improve bytecode size --- src/utils/MerkleTreeLib.sol | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/utils/MerkleTreeLib.sol b/src/utils/MerkleTreeLib.sol index a1975c5523..46f352de1b 100644 --- a/src/utils/MerkleTreeLib.sol +++ b/src/utils/MerkleTreeLib.sol @@ -254,7 +254,6 @@ library MerkleTreeLib { pure returns (bytes32[] memory result) { - uint256 p = roundUpPow2(leaves.length); /// @solidity memory-safe-assembly assembly { result := mload(0x40) @@ -263,6 +262,9 @@ library MerkleTreeLib { mstore(0x00, 0xe7171dc4) // `MerkleTreeLeavesEmpty()`. revert(0x1c, 0x04) } + let p := sub(mload(leaves), 1) + for { let i := 1 } lt(i, 0x80) { i := add(i, i) } { p := or(p, shr(i, p)) } + p := add(p, 1) mstore(result, p) // Store length. mstore(0x40, add(result, add(0x20, shl(5, p)))) // Allocate memory. let d := sub(result, leaves) @@ -281,22 +283,4 @@ library MerkleTreeLib { function pad(bytes32[] memory leaves) internal pure returns (bytes32[] memory result) { result = pad(leaves, bytes32(0)); } - - /// @dev Returns the smallest power of 2 greater than or equal to `x`. - /// Defaults to zero if `x == 0`. - function roundUpPow2(uint256 x) internal pure returns (uint256 y) { - /// @solidity memory-safe-assembly - assembly { - y := sub(x, 1) - y := or(y, shr(1, y)) - y := or(y, shr(2, y)) - y := or(y, shr(4, y)) - y := or(y, shr(8, y)) - y := or(y, shr(16, y)) - y := or(y, shr(32, y)) - y := or(y, shr(64, y)) - y := or(y, shr(128, y)) - y := add(y, 1) - } - } }