From d244b81972856f5b6ff785d25f58791a461bea1a Mon Sep 17 00:00:00 2001 From: Hadrien Croubois Date: Thu, 14 Oct 2021 11:50:35 +0200 Subject: [PATCH] Add a MerkleProof.processProof utility function (#2841) * Add a MerkleProof.processProof utility function * Add changelog entry * fix lint * return index when processingProof * fix lint * fix test * Apply suggestions from code review Co-authored-by: Francisco Giordano * improve documentation * Apply suggestions from code review Co-authored-by: Francisco Giordano * remove index - see discussion in the PR * update changelog Co-authored-by: Francisco Giordano --- CHANGELOG.md | 1 + contracts/mocks/MerkleProofWrapper.sol | 4 ++++ contracts/utils/cryptography/MerkleProof.sol | 18 +++++++++++++----- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ade78449982..9ac6332d9ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * `Governor`: shift vote start and end by one block to better match Compound's GovernorBravo and prevent voting at the Governor level if the voting snapshot is not ready. ([#2892](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/#2892)) * `PaymentSplitter`: now supports ERC20 assets in addition to Ether. ([#2858](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/#2858)) * `ECDSA`: add a variant of `toEthSignedMessageHash` for arbitrary length message hashing. ([#2865](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/#2865)) + * `MerkleProof`: add a `processProof` function that returns the rebuilt root hash given a leaf and a proof. ([#2841](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2841)) ## 4.3.2 (2021-09-14) diff --git a/contracts/mocks/MerkleProofWrapper.sol b/contracts/mocks/MerkleProofWrapper.sol index 6189eb4aef7..1e188df36ba 100644 --- a/contracts/mocks/MerkleProofWrapper.sol +++ b/contracts/mocks/MerkleProofWrapper.sol @@ -12,4 +12,8 @@ contract MerkleProofWrapper { ) public pure returns (bool) { return MerkleProof.verify(proof, root, leaf); } + + function processProof(bytes32[] memory proof, bytes32 leaf) public pure returns (bytes32) { + return MerkleProof.processProof(proof, leaf); + } } diff --git a/contracts/utils/cryptography/MerkleProof.sol b/contracts/utils/cryptography/MerkleProof.sol index b3b4871de6c..caf2dbe31db 100644 --- a/contracts/utils/cryptography/MerkleProof.sol +++ b/contracts/utils/cryptography/MerkleProof.sol @@ -23,11 +23,21 @@ library MerkleProof { bytes32 root, bytes32 leaf ) internal pure returns (bool) { - bytes32 computedHash = leaf; + return processProof(proof, leaf) == root; + } + /** + * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up + * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt + * hash matches the root of the tree. When processing the proof, the pairs + * of leafs & pre-images are assumed to be sorted. + * + * _Available since v4.4._ + */ + function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; for (uint256 i = 0; i < proof.length; i++) { bytes32 proofElement = proof[i]; - if (computedHash <= proofElement) { // Hash(current computed hash + current element of the proof) computedHash = keccak256(abi.encodePacked(computedHash, proofElement)); @@ -36,8 +46,6 @@ library MerkleProof { computedHash = keccak256(abi.encodePacked(proofElement, computedHash)); } } - - // Check if the computed hash (root) is equal to the provided root - return computedHash == root; + return computedHash; } }