Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion docs/utils/merkletreelib.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,17 @@
Library for generating Merkle trees.


<b>Note:</b>

- 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
- 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.
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.



Expand Down Expand Up @@ -132,4 +142,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.
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))`.
15 changes: 15 additions & 0 deletions src/utils/MerkleTreeLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ 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:
/// - 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
/// - 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.
/// 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 */
Expand Down Expand Up @@ -244,4 +254,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));
}
}
15 changes: 14 additions & 1 deletion test/MerkleTreeLib.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down