From f6143b7f10a43c89b0c92d0314d962d5c6e6ecb6 Mon Sep 17 00:00:00 2001 From: Vectorized Date: Sun, 22 Jun 2025 21:02:55 +0000 Subject: [PATCH 1/5] pad --- src/utils/MerkleTreeLib.sol | 5 +++++ test/MerkleTreeLib.t.sol | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/utils/MerkleTreeLib.sol b/src/utils/MerkleTreeLib.sol index e898f93709..b128fc6b73 100644 --- a/src/utils/MerkleTreeLib.sol +++ b/src/utils/MerkleTreeLib.sol @@ -244,4 +244,9 @@ library MerkleTreeLib { } } } + + /// @dev Equivalent to `pad(leafs, bytes32(0))`. + function pad(bytes32[] memory leafs) internal pure returns (bytes32[] memory result) { + result = pad(leafs, bytes32(0)); + } } diff --git a/test/MerkleTreeLib.t.sol b/test/MerkleTreeLib.t.sol index 7006490efd..053a3a2334 100644 --- a/test/MerkleTreeLib.t.sol +++ b/test/MerkleTreeLib.t.sol @@ -90,8 +90,19 @@ contract MerkleTreeLibTest is SoladyTest { return MerkleTreeLib.build(leafs).leaf(leafIndex); } + function _maybePad(bytes32[] memory leafs) internal returns (bytes32[] memory) { + if (_randomChance(2)) { + if (_randomChance(2)) { + return leafs.pad(); + } + return leafs.pad(bytes32(_random())); + } + return leafs; + } + function testBuildAndGetLeafProof(bytes32[] memory leafs, uint256 leafIndex) public { if (leafs.length == 0) return _testBuildAndGetRoot(leafs); + leafs = _maybePad(leafs); bytes32[] memory t = MerkleTreeLib.build(leafs); if (leafIndex < leafs.length) { bytes32[] memory proof = this.buildAndGetLeafProof(leafs, leafIndex); @@ -161,12 +172,14 @@ contract MerkleTreeLibTest is SoladyTest { bool[] flags; } - function testBuildAndGetLeafsMultiProof(bytes32) public { + function testBuildAndGetLeafsMultiProof(bytes32 r) public { + _maybeBrutalizeMemory(r); TestMultiProofTemps memory t; t.leafs = new bytes32[](_bound(_random(), 1, 128)); for (uint256 i; i < t.leafs.length; ++i) { t.leafs[i] = bytes32(_random()); } + t.leafs = _maybePad(t.leafs); t.leafIndices = _generateUniqueLeafIndices(t.leafs); t.tree = MerkleTreeLib.build(t.leafs); (t.proof, t.flags) = t.tree.leafsMultiProof(t.leafIndices); From 69705d95ee1e67150974a328e55ab467942d1f19 Mon Sep 17 00:00:00 2001 From: Vectorized Date: Sun, 22 Jun 2025 21:10:52 +0000 Subject: [PATCH 2/5] T --- docs/utils/merkletreelib.md | 20 +++++++++++++++++++- src/utils/MerkleTreeLib.sol | 7 +++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/utils/merkletreelib.md b/docs/utils/merkletreelib.md index d8025e7b38..b3194ec9f1 100644 --- a/docs/utils/merkletreelib.md +++ b/docs/utils/merkletreelib.md @@ -3,7 +3,14 @@ Library for generating Merkle trees. +Note: +- This library does NOT hash the leafs and does NOT sort the leafs. +We leave it up to you to decide if this is needed. +If your leafs are 64 bytes long, do hash them first for safety. +See: https://www.rareskills.io/post/merkle-tree-second-preimage-attack +- This library use the pair sort keccak256 hash, which works +out-of-the-box with the accompanying `MerkleProofLib`. @@ -132,4 +139,15 @@ function pad(bytes32[] memory leafs, bytes32 defaultFill) returns (bytes32[] memory result) ``` -Returns a copy of leafs, with the length padded to a power of 2. \ No newline at end of file +Returns a copy of leafs, with the length padded to a power of 2. + +### pad(bytes32[]) + +```solidity +function pad(bytes32[] memory leafs) + internal + pure + returns (bytes32[] memory result) +``` + +Equivalent to `pad(leafs, bytes32(0))`. \ No newline at end of file diff --git a/src/utils/MerkleTreeLib.sol b/src/utils/MerkleTreeLib.sol index b128fc6b73..f928d62410 100644 --- a/src/utils/MerkleTreeLib.sol +++ b/src/utils/MerkleTreeLib.sol @@ -4,6 +4,13 @@ pragma solidity ^0.8.4; /// @notice Library for generating Merkle trees. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleTreeLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/merkle-tree/blob/master/src/core.ts) +/// @dev Note: +/// - This library does NOT hash the leafs and does NOT sort the leafs. +/// We leave it up to you to decide if this is needed. +/// If your leafs are 64 bytes long, do hash them first for safety. +/// See: https://www.rareskills.io/post/merkle-tree-second-preimage-attack +/// - This library use the pair sort keccak256 hash, which works +/// out-of-the-box with the accompanying `MerkleProofLib`. library MerkleTreeLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ From 704cd2de74503d915c1e91b118a41fc82f0088c8 Mon Sep 17 00:00:00 2001 From: Vectorized Date: Sun, 22 Jun 2025 21:21:41 +0000 Subject: [PATCH 3/5] T --- docs/utils/merkletreelib.md | 9 ++++++++- src/utils/MerkleTreeLib.sol | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/utils/merkletreelib.md b/docs/utils/merkletreelib.md index b3194ec9f1..53b5828593 100644 --- a/docs/utils/merkletreelib.md +++ b/docs/utils/merkletreelib.md @@ -5,12 +5,19 @@ Library for generating Merkle trees. Note: -- This library does NOT hash the leafs and does NOT sort the leafs. +- This library does NOT hash the leafs. Note that some libraries hash the leafs by default. We leave it up to you to decide if this is needed. If your leafs are 64 bytes long, do hash them first for safety. See: https://www.rareskills.io/post/merkle-tree-second-preimage-attack +- This library does NOT sort the leafs. Note that some libraries sort the leafs by default. - This library use the pair sort keccak256 hash, which works out-of-the-box with the accompanying `MerkleProofLib`. +- This library is NOT equivalent to OpenZeppelin's. +If you are only concerned with using this library in your Foundry tests (e.g. to check +that you have used MerkleProofLib correctly) you do NOT need to care about equivalence. +This library is designed to be drop-in equivalent to any other library. +This may be relevant if you want to test that generated proofs via Solidity vs +some external library are equal. diff --git a/src/utils/MerkleTreeLib.sol b/src/utils/MerkleTreeLib.sol index f928d62410..27135d5b41 100644 --- a/src/utils/MerkleTreeLib.sol +++ b/src/utils/MerkleTreeLib.sol @@ -5,12 +5,19 @@ pragma solidity ^0.8.4; /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleTreeLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/merkle-tree/blob/master/src/core.ts) /// @dev Note: -/// - This library does NOT hash the leafs and does NOT sort the leafs. +/// - This library does NOT hash the leafs. Note that some libraries hash the leafs by default. /// We leave it up to you to decide if this is needed. /// If your leafs are 64 bytes long, do hash them first for safety. /// See: https://www.rareskills.io/post/merkle-tree-second-preimage-attack +/// - This library does NOT sort the leafs. Note that some libraries sort the leafs by default. /// - This library use the pair sort keccak256 hash, which works /// out-of-the-box with the accompanying `MerkleProofLib`. +/// - This library is NOT equivalent to OpenZeppelin's. +/// If you are only concerned with using this library in your Foundry tests (e.g. to check +// that you have used MerkleProofLib correctly) you do NOT need to care about equivalence. +/// This library is designed to be drop-in equivalent to any other library. +/// This may be relevant if you want to test that generated proofs via Solidity vs +/// some external library are equal. library MerkleTreeLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ From 8a802d61f25753e144ebc1c3ef111bbe23e2149b Mon Sep 17 00:00:00 2001 From: Vectorized Date: Sun, 22 Jun 2025 21:22:41 +0000 Subject: [PATCH 4/5] T --- docs/utils/merkletreelib.md | 3 +-- src/utils/MerkleTreeLib.sol | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/utils/merkletreelib.md b/docs/utils/merkletreelib.md index 53b5828593..97561d5a96 100644 --- a/docs/utils/merkletreelib.md +++ b/docs/utils/merkletreelib.md @@ -12,10 +12,9 @@ See: https://www.rareskills.io/post/merkle-tree-second-preimage-attack - This library does NOT sort the leafs. Note that some libraries sort the leafs by default. - This library use the pair sort keccak256 hash, which works out-of-the-box with the accompanying `MerkleProofLib`. -- This library is NOT equivalent to OpenZeppelin's. +- This library is NOT equivalent to OpenZeppelin or Murky. If you are only concerned with using this library in your Foundry tests (e.g. to check that you have used MerkleProofLib correctly) you do NOT need to care about equivalence. -This library is designed to be drop-in equivalent to any other library. This may be relevant if you want to test that generated proofs via Solidity vs some external library are equal. diff --git a/src/utils/MerkleTreeLib.sol b/src/utils/MerkleTreeLib.sol index 27135d5b41..38bddf2f11 100644 --- a/src/utils/MerkleTreeLib.sol +++ b/src/utils/MerkleTreeLib.sol @@ -12,10 +12,9 @@ pragma solidity ^0.8.4; /// - This library does NOT sort the leafs. Note that some libraries sort the leafs by default. /// - This library use the pair sort keccak256 hash, which works /// out-of-the-box with the accompanying `MerkleProofLib`. -/// - This library is NOT equivalent to OpenZeppelin's. +/// - This library is NOT equivalent to OpenZeppelin or Murky. /// If you are only concerned with using this library in your Foundry tests (e.g. to check // that you have used MerkleProofLib correctly) you do NOT need to care about equivalence. -/// This library is designed to be drop-in equivalent to any other library. /// This may be relevant if you want to test that generated proofs via Solidity vs /// some external library are equal. library MerkleTreeLib { From 529e39bebe515614cf4e7fd7cbc18b16c1faba14 Mon Sep 17 00:00:00 2001 From: Vectorized Date: Sun, 22 Jun 2025 21:31:41 +0000 Subject: [PATCH 5/5] T --- docs/utils/merkletreelib.md | 13 +++++-------- src/utils/MerkleTreeLib.sol | 13 +++++-------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/docs/utils/merkletreelib.md b/docs/utils/merkletreelib.md index 97561d5a96..e04334cb01 100644 --- a/docs/utils/merkletreelib.md +++ b/docs/utils/merkletreelib.md @@ -5,18 +5,15 @@ Library for generating Merkle trees. Note: -- This library does NOT hash the leafs. Note that some libraries hash the leafs by default. +- Leafs are NOT auto hashed. Note that some libraries hash the leafs by default. We leave it up to you to decide if this is needed. If your leafs are 64 bytes long, do hash them first for safety. See: https://www.rareskills.io/post/merkle-tree-second-preimage-attack -- This library does NOT sort the leafs. Note that some libraries sort the leafs by default. -- This library use the pair sort keccak256 hash, which works -out-of-the-box with the accompanying `MerkleProofLib`. +- Leafs are NOT auto globally sorted. Note that some libraries sort the leafs by default. +- The pair hash is pair-sorted-keccak256, which works out-of-the-box with `MerkleProofLib`. - This library is NOT equivalent to OpenZeppelin or Murky. -If you are only concerned with using this library in your Foundry tests (e.g. to check -that you have used MerkleProofLib correctly) you do NOT need to care about equivalence. -This may be relevant if you want to test that generated proofs via Solidity vs -some external library are equal. +Equivalence is NOT required if you are just using this for pure Solidity testing. +May be relevant for differential testing between Solidity vs external libraries. diff --git a/src/utils/MerkleTreeLib.sol b/src/utils/MerkleTreeLib.sol index 38bddf2f11..8d673a691d 100644 --- a/src/utils/MerkleTreeLib.sol +++ b/src/utils/MerkleTreeLib.sol @@ -5,18 +5,15 @@ pragma solidity ^0.8.4; /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleTreeLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/merkle-tree/blob/master/src/core.ts) /// @dev Note: -/// - This library does NOT hash the leafs. Note that some libraries hash the leafs by default. +/// - Leafs are NOT auto hashed. Note that some libraries hash the leafs by default. /// We leave it up to you to decide if this is needed. /// If your leafs are 64 bytes long, do hash them first for safety. /// See: https://www.rareskills.io/post/merkle-tree-second-preimage-attack -/// - This library does NOT sort the leafs. Note that some libraries sort the leafs by default. -/// - This library use the pair sort keccak256 hash, which works -/// out-of-the-box with the accompanying `MerkleProofLib`. +/// - Leafs are NOT auto globally sorted. Note that some libraries sort the leafs by default. +/// - The pair hash is pair-sorted-keccak256, which works out-of-the-box with `MerkleProofLib`. /// - This library is NOT equivalent to OpenZeppelin or Murky. -/// If you are only concerned with using this library in your Foundry tests (e.g. to check -// that you have used MerkleProofLib correctly) you do NOT need to care about equivalence. -/// This may be relevant if you want to test that generated proofs via Solidity vs -/// some external library are equal. +/// Equivalence is NOT required if you are just using this for pure Solidity testing. +/// May be relevant for differential testing between Solidity vs external libraries. library MerkleTreeLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */