From 4f8af2dceb0fbc36cb32eb2cc14f80c340b9022e Mon Sep 17 00:00:00 2001 From: Doug Hoyte Date: Mon, 31 Jan 2022 10:10:13 -0500 Subject: [PATCH] Add test and docs describing a misuse of MerkleProof (#3090) Co-authored-by: Francisco Giordano --- contracts/utils/cryptography/MerkleProof.sol | 7 ++++++- test/utils/cryptography/MerkleProof.test.js | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/contracts/utils/cryptography/MerkleProof.sol b/contracts/utils/cryptography/MerkleProof.sol index b0fe49416..c0621a73b 100644 --- a/contracts/utils/cryptography/MerkleProof.sol +++ b/contracts/utils/cryptography/MerkleProof.sol @@ -11,6 +11,11 @@ pragma solidity ^0.8.0; * Note: the hashing algorithm should be keccak256 and pair sorting should be enabled. * * See `test/utils/cryptography/MerkleProof.test.js` for some examples. + * + * WARNING: You should avoid using leaf values that are 64 bytes long prior to + * hashing, or use a hash function other than keccak256 for hashing leaves. + * This is because the concatenation of a sorted pair of internal nodes in + * the merkle tree could be reinterpreted as a leaf value. */ library MerkleProof { /** @@ -28,7 +33,7 @@ library MerkleProof { } /** - * @dev Returns the rebuilt hash obtained by traversing a Merklee tree up + * @dev Returns the rebuilt hash obtained by traversing a Merkle 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. diff --git a/test/utils/cryptography/MerkleProof.test.js b/test/utils/cryptography/MerkleProof.test.js index dab2062d4..61fa45c3e 100644 --- a/test/utils/cryptography/MerkleProof.test.js +++ b/test/utils/cryptography/MerkleProof.test.js @@ -24,6 +24,12 @@ contract('MerkleProof', function (accounts) { const proof = merkleTree.getHexProof(leaf); expect(await this.merkleProof.verify(proof, root, leaf)).to.equal(true); + + // For demonstration, it is also possible to create valid proofs for certain 64-byte values *not* in elements: + const noSuchLeaf = keccak256( + Buffer.concat([keccak256(elements[0]), keccak256(elements[1])].sort(Buffer.compare)), + ); + expect(await this.merkleProof.verify(proof.slice(1), root, noSuchLeaf)).to.equal(true); }); it('returns false for an invalid Merkle proof', async function () {