From 4d185d3390458e9a53b83282431c293c7916a041 Mon Sep 17 00:00:00 2001 From: Pascal Marco Caversaccio Date: Mon, 30 Jan 2023 22:30:14 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=A6=B9=20further=20merkleproofverificatio?= =?UTF-8?q?n=20fuzz=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pascal Marco Caversaccio --- .eslintignore | 4 +- .gitmodules | 2 +- .prettierignore | 1 + .solhintignore | 1 + remappings.txt | 1 + test/utils/MerkleProofVerification.t.sol | 146 ++++++++++++++++++++++- 6 files changed, 150 insertions(+), 5 deletions(-) diff --git a/.eslintignore b/.eslintignore index 32e01dfa..2439e745 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,6 +1,8 @@ node_modules -lib/create-util +lib/murky +lib/prb-test lib/forge-std +lib/create-util lib/solidity-bytes-utils lib/openzeppelin-contracts bin diff --git a/.gitmodules b/.gitmodules index 248b5c62..2cd296e6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -15,4 +15,4 @@ url = https://github.com/paulrberg/prb-test.git [submodule "lib/murky"] path = lib/murky - url = https://github.com/dmfxyz/murky + url = https://github.com/dmfxyz/murky.git diff --git a/.prettierignore b/.prettierignore index 84eeb5e2..2439e745 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,5 @@ node_modules +lib/murky lib/prb-test lib/forge-std lib/create-util diff --git a/.solhintignore b/.solhintignore index 0d01aed5..34eb1f1a 100644 --- a/.solhintignore +++ b/.solhintignore @@ -1,4 +1,5 @@ node_modules +lib/murky lib/prb-test lib/forge-std lib/create-util diff --git a/remappings.txt b/remappings.txt index 0466ab64..ee96e929 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,4 +1,5 @@ utils/=lib/utils/ +murky/=lib/murky/src/ prb/test/=lib/prb-test/src/ forge-std/=lib/forge-std/src/ create-util/=lib/create-util/contracts/ diff --git a/test/utils/MerkleProofVerification.t.sol b/test/utils/MerkleProofVerification.t.sol index 126e631c..6de5fd9b 100644 --- a/test/utils/MerkleProofVerification.t.sol +++ b/test/utils/MerkleProofVerification.t.sol @@ -4,12 +4,15 @@ pragma solidity ^0.8.17; import {Test} from "forge-std/Test.sol"; import {VyperDeployer} from "utils/VyperDeployer.sol"; +import {Merkle} from "murky/Merkle.sol"; + import {IMerkleProofVerification} from "./interfaces/IMerkleProofVerification.sol"; contract MerkleProofVerificationTest is Test { VyperDeployer private vyperDeployer = new VyperDeployer(); IMerkleProofVerification private merkleProofVerification; + Merkle private merkleGenerator; /** * @dev An `internal` helper function that converts the JavaScript-based @@ -278,6 +281,7 @@ contract MerkleProofVerificationTest is Test { "MerkleProofVerification" ) ); + merkleGenerator = new Merkle(); } function testVerify() public { @@ -541,11 +545,147 @@ contract MerkleProofVerificationTest is Test { ); } + /** + * @notice Forked and adjusted accordingly from here: + * https://github.com/Vectorized/solady/blob/main/test/MerkleProofLib.t.sol. + */ function testFuzzVerify( - bytes32[] calldata proof, - bytes32 root, - bytes32 leaf + bytes32[] calldata data, + uint256 randomness ) public { + vm.assume(data.length > 1); + uint256 nodeIndex = randomness % data.length; + bytes32 root = merkleGenerator.getRoot(data); + bytes32[] memory proof = merkleGenerator.getProof(data, nodeIndex); + bytes32 leaf = data[nodeIndex]; + assertTrue(merkleProofVerification.verify(proof, root, leaf)); + assertTrue( + !merkleProofVerification.verify( + proof, + bytes32(uint256(root) ^ 1), + leaf + ) + ); + + proof[0] = bytes32(uint256(proof[0]) ^ 1); assertTrue(!merkleProofVerification.verify(proof, root, leaf)); + assertTrue( + !merkleProofVerification.verify( + proof, + bytes32(uint256(root) ^ 1), + leaf + ) + ); + } + + /** + * @notice Forked and adjusted accordingly from here: + * https://github.com/Vectorized/solady/blob/main/test/MerkleProofLib.t.sol. + */ + function testFuzzMultiProofVerifySingleLeaf( + bytes32[] calldata data, + uint256 randomness + ) public { + vm.assume(data.length > 1); + uint256 nodeIndex = randomness % data.length; + bytes32 root = merkleGenerator.getRoot(data); + bytes32[] memory proof = merkleGenerator.getProof(data, nodeIndex); + bytes32[] memory leaves = new bytes32[](1); + leaves[0] = data[nodeIndex]; + bool[] memory proofFlags = new bool[](proof.length); + assertTrue( + merkleProofVerification.multi_proof_verify( + proof, + proofFlags, + root, + leaves + ) + ); + assertTrue( + !merkleProofVerification.multi_proof_verify( + proof, + proofFlags, + bytes32(uint256(root) ^ 1), + leaves + ) + ); + + proof[0] = bytes32(uint256(proof[0]) ^ 1); + assertTrue( + !merkleProofVerification.multi_proof_verify( + proof, + proofFlags, + root, + leaves + ) + ); + assertTrue( + !merkleProofVerification.multi_proof_verify( + proof, + proofFlags, + bytes32(uint256(root) ^ 1), + leaves + ) + ); + } + + /** + * @notice Forked and adjusted accordingly from here: + * https://github.com/Vectorized/solady/blob/main/test/MerkleProofLib.t.sol. + */ + function testFuzzVerifyMultiProofMultipleLeaves( + bool damageProof, + bool damageRoot, + bool damageLeaves + ) public { + bool noDamage = true; + + bytes32 root = merkleGenerator.hashLeafPairs( + merkleGenerator.hashLeafPairs( + merkleGenerator.hashLeafPairs(bytes32("a"), bytes32("b")), + merkleGenerator.hashLeafPairs(bytes32("c"), bytes32("d")) + ), + merkleGenerator.hashLeafPairs(bytes32("e"), bytes32("f")) + ); + + bytes32[] memory leaves = new bytes32[](3); + leaves[0] = bytes32("d"); + leaves[1] = bytes32("e"); + leaves[2] = bytes32("f"); + + bytes32[] memory proof = new bytes32[](2); + proof[0] = bytes32("c"); + proof[1] = merkleGenerator.hashLeafPairs(bytes32("b"), bytes32("a")); + + bool[] memory flags = new bool[](4); + flags[0] = false; + flags[1] = true; + flags[2] = false; + flags[3] = true; + + if (damageRoot) { + noDamage = false; + root = bytes32(uint256(root) ^ 1); + } + + if (damageLeaves) { + noDamage = false; + leaves[0] = bytes32(uint256(leaves[0]) ^ 1); + } + + if (damageProof && proof.length != 0) { + noDamage = false; + proof[0] = bytes32(uint256(proof[0]) ^ 1); + } + + assertEq( + merkleProofVerification.multi_proof_verify( + proof, + flags, + root, + leaves + ), + noDamage + ); } }