Skip to content

Commit

Permalink
remove index - see discussion in the PR
Browse files Browse the repository at this point in the history
  • Loading branch information
Amxx committed Oct 13, 2021
1 parent 272c3ba commit 3fe8e4f
Show file tree
Hide file tree
Showing 3 changed files with 7 additions and 38 deletions.
2 changes: 1 addition & 1 deletion contracts/mocks/MerkleProofWrapper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ contract MerkleProofWrapper {
return MerkleProof.verify(proof, root, leaf);
}

function processProof(bytes32[] memory proof, bytes32 leaf) public pure returns (bytes32, uint256) {
function processProof(bytes32[] memory proof, bytes32 leaf) public pure returns (bytes32) {
return MerkleProof.processProof(proof, leaf);
}
}
23 changes: 6 additions & 17 deletions contracts/utils/cryptography/MerkleProof.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,40 +23,29 @@ library MerkleProof {
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
// Check if the computed hash (root) is equal to the provided root
(bytes32 computedHash, ) = processProof(proof, leaf);
return computedHash == root;
return processProof(proof, leaf) == root;
}

/**
* @dev Returns the rebuilt hash obtained by traversing a Merklee tree up
* from `leaf` using `proof`, and an index uniquelly identifying the leaf
* location in the tree. 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.
* The produced index is unique in the sens that processing two valid proofs
* will return the same indices if and only if the leaf at the same location
* in the tree. This helps distinguishing two leaves that have the same
* bytes32 identifier but are present in different locations in the merkle
* tree.
* 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, uint256) {
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
uint256 index = 0;
for (uint256 i = 0; i < proof.length; i++) {
bytes32 proofElement = proof[i];
index <<= 1;
if (computedHash <= proofElement) {
// Hash(current computed hash + current element of the proof)
computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
} else {
// Hash(current element of the proof + current computed hash)
computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
index |= 1;
}
}
return (computedHash, index);
return computedHash;
}
}
20 changes: 0 additions & 20 deletions test/utils/cryptography/MerkleProof.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,24 +56,4 @@ contract('MerkleProof', function (accounts) {
expect(await this.merkleProof.verify(badProof, root, leaf)).to.equal(false);
});
});

describe('processProof', function () {
it('create unique indices', async function () {
const elements = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split('');
const merkleTree = new MerkleTree(elements, keccak256, { hashLeaves: true, sortPairs: true });

const root = merkleTree.getHexRoot();

const results = await Promise.all(elements
.map(element => keccak256(element))
.map(leaf => this.merkleProof.processProof(merkleTree.getHexProof(leaf), leaf)),
);

// All reconstructed roots are correct
expect(results.map(result => result[0])).to.have.members(Array(elements.length).fill(root));

// Indices are unique
expect(results.map(result => result[1].toNumber()).every((index, i, indices) => indices.indexOf(i) === index));
});
});
});

0 comments on commit 3fe8e4f

Please sign in to comment.