Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
MerkleProof library and initial stubbed out tests
  • Loading branch information
yondonfu committed Jun 14, 2017
commit 3c4d0d0a77ad7eaefe5cfcbead93ee2a5bcfadbb
38 changes: 38 additions & 0 deletions contracts/MerkleProof.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
pragma solidity ^0.4.11;

/*
* @title MerkleProof
* @dev Merkle proof verification
* @note Based on https://github.com/ameensol/merkle-tree-solidity/blob/master/src/MerkleProof.sol
*/
library MerkleProof {
/*
* @dev Verifies a Merkle proof proving the existence of a leaf in a Merkle tree. Assumes that each pair of leaves
* and each pair of pre-images is sorted.
* @param _proof Merkle proof containing sibling hashes on the branch from the leaf to the root of the Merkle tree
* @param _root Merkle root
* @param _leaf Leaf of Merkle tree
*/
function verifyProof(bytes _proof, bytes32 _root, bytes32 _leaf) constant returns (bool) {
bytes32 proofElement;
bytes32 computedHash = _leaf;

for (uint256 i = 32; i <= _proof.length; i += 32) {
assembly {
// Load the current element of the proof
proofElement := mload(add(_proof, i))
}

if (computedHash < proofElement) {
// Hash(current computed hash + current element of the proof)
computedHash = sha3(computedHash, proofElement);
} else {
// Hash(current element of the proof + current computed hash)
computedHash = sha3(proofElement, computedHash);
}
}

// Check if the computed hash (root) is equal to the provided root
return computedHash == _root;
}
}
54 changes: 54 additions & 0 deletions test/MerkleProof.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
var MerkleProofMock = artifacts.require("./helpers/MerkleProofMock.sol");

contract('MerkleProof', function(accounts) {
let merkleProof;

before(async function() {
merkleProof = await MerkleProofMock.new();
});

describe("verifyProof", function() {
it("should return true for a valid Merkle proof given even number of leaves", async function() {
// const elements = ["a", "b", "c", "d"].map(el => sha3(el));
// const merkleTree = new MerkleTree(elements);

// const root = merkleTree.getHexRoot();

// const proof = merkleTree.getHexProof(elements[0]);

// const leaf = merkleTree.bufToHex(elements[0]);

// const validProof = await merkleProof.verifyProof(proof, root, leaf);
// assert.isOk(validProof, "verifyProof did not return true for a valid proof given even number of leaves");
});

it("should return true for a valid Merkle proof given odd number of leaves", async function () {
// const elements = ["a", "b", "c"].map(el => sha3(el));
// const merkleTree = new MerkleTree(elements);

// const root = merkleTree.getHexRoot();

// const proof = merkleTree.getHexProof(elements[0]);

// const leaf = merkleTree.bufToHex(elements[0]);

// const validProof = await merkleProof.verifyProof(proof, root, leaf);
// assert.isOk(validProof, "verifyProof did not return true for a valid proof given odd number of leaves");
});

it("should return false for an invalid Merkle proof", async function() {
// const elements = ["a", "b", "c"].map(el => sha3(el));
// const merkleTree = new MerkleTree(elements);

// const root = merkleTree.getHexRoot();

// const proof = merkleTree.getHexProof(elements[0]);
// const badProof = proof.slice(0, proof.length - 32);

// const leaf = merkleTree.bufToHex(elements[0]);

// const validProof = await merkleProof.verifyProof(badProof, root, leaf);
// assert.isNotOk(validProof, "verifyProof did not return false for an invalid proof");
});
});
});
12 changes: 12 additions & 0 deletions test/helpers/MerkleProofMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
pragma solidity ^0.4.11;

import '../../contracts/MerkleProof.sol';

contract MerkleProofMock {

bool public result;

function verifyProof(bytes _proof, bytes32 _root, bytes32 _leaf) {
result = MerkleProof.verifyProof(_proof, _root, _leaf);
}
}