59 lines
2.3 KiB
Solidity
59 lines
2.3 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity >=0.8.4;
|
|
|
|
/// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree.
|
|
/// @author Solady
|
|
/// (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol)
|
|
/// @author Modified from Solmate
|
|
/// (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol)
|
|
/// @author Modified from OpenZeppelin
|
|
/// (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol)
|
|
library MerkleProofLib {
|
|
/// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`.
|
|
function verify(
|
|
bytes32[] calldata proof,
|
|
bytes32 root,
|
|
bytes32 leaf
|
|
) internal pure returns (bool isValid) {
|
|
/// @solidity memory-safe-assembly
|
|
assembly {
|
|
if proof.length {
|
|
// Left shift by 5 is equivalent to multiplying by 0x20.
|
|
let end := add(
|
|
proof.offset,
|
|
shl(5, proof.length)
|
|
)
|
|
// Initialize `offset` to the offset of `proof` in the calldata.
|
|
let offset := proof.offset
|
|
// Iterate over proof elements to compute root hash.
|
|
for {
|
|
|
|
} 1 {
|
|
|
|
} {
|
|
// Slot of `leaf` in scratch space.
|
|
// If the condition is true: 0x20, otherwise: 0x00.
|
|
let scratch := shl(
|
|
5,
|
|
gt(leaf, calldataload(offset))
|
|
)
|
|
// Store elements to hash contiguously in scratch space.
|
|
// Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes.
|
|
mstore(scratch, leaf)
|
|
mstore(
|
|
xor(scratch, 0x20),
|
|
calldataload(offset)
|
|
)
|
|
// Reuse `leaf` to store the hash to reduce stack operations.
|
|
leaf := keccak256(0x00, 0x40)
|
|
offset := add(offset, 0x20)
|
|
if iszero(lt(offset, end)) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
isValid := eq(leaf, root)
|
|
}
|
|
}
|
|
}
|