From 3c4d0d0a77ad7eaefe5cfcbead93ee2a5bcfadbb Mon Sep 17 00:00:00 2001 From: Yondon Fu Date: Wed, 14 Jun 2017 16:34:46 -0400 Subject: [PATCH 1/6] MerkleProof library and initial stubbed out tests --- contracts/MerkleProof.sol | 38 ++++++++++++++++++++++ test/MerkleProof.js | 54 ++++++++++++++++++++++++++++++++ test/helpers/MerkleProofMock.sol | 12 +++++++ 3 files changed, 104 insertions(+) create mode 100644 contracts/MerkleProof.sol create mode 100644 test/MerkleProof.js create mode 100644 test/helpers/MerkleProofMock.sol diff --git a/contracts/MerkleProof.sol b/contracts/MerkleProof.sol new file mode 100644 index 000000000..89f9256c1 --- /dev/null +++ b/contracts/MerkleProof.sol @@ -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; + } +} diff --git a/test/MerkleProof.js b/test/MerkleProof.js new file mode 100644 index 000000000..8ff58ec34 --- /dev/null +++ b/test/MerkleProof.js @@ -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"); + }); + }); +}); diff --git a/test/helpers/MerkleProofMock.sol b/test/helpers/MerkleProofMock.sol new file mode 100644 index 000000000..84ccc1be3 --- /dev/null +++ b/test/helpers/MerkleProofMock.sol @@ -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); + } +} From 2e0bd06da2bc10bf88d1952b211a4b3a7e06d78d Mon Sep 17 00:00:00 2001 From: Yondon Fu Date: Thu, 15 Jun 2017 11:07:22 -0400 Subject: [PATCH 2/6] Add tests, docs and MerkleTree helper --- docs/source/merkleproof.rst | 9 +++ package.json | 1 + test/MerkleProof.js | 75 +++++++++----------- test/helpers/merkleTree.js | 135 ++++++++++++++++++++++++++++++++++++ 4 files changed, 177 insertions(+), 43 deletions(-) create mode 100644 docs/source/merkleproof.rst create mode 100644 test/helpers/merkleTree.js diff --git a/docs/source/merkleproof.rst b/docs/source/merkleproof.rst new file mode 100644 index 000000000..4dcc94e47 --- /dev/null +++ b/docs/source/merkleproof.rst @@ -0,0 +1,9 @@ +MerkleProof +============================================= + +Merkle proof verification for leaves of a Merkle tree. + +verifyProof(bytes _proof, bytes32 _root, bytes32 _leaf) internal constant returns (bool) +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +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. diff --git a/package.json b/package.json index 3f03eeb18..28c21f386 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "babel-register": "^6.23.0", "coveralls": "^2.13.1", "ethereumjs-testrpc": "^3.0.2", + "ethereumjs-util": "^5.1.2", "mocha-lcov-reporter": "^1.3.0", "solidity-coverage": "^0.1.0", "truffle": "3.2.2" diff --git a/test/MerkleProof.js b/test/MerkleProof.js index 8ff58ec34..f2e096e09 100644 --- a/test/MerkleProof.js +++ b/test/MerkleProof.js @@ -1,54 +1,43 @@ -var MerkleProofMock = artifacts.require("./helpers/MerkleProofMock.sol"); +var MerkleProof = artifacts.require("./MerkleProof.sol"); + +import { sha3 } from "ethereumjs-util"; +import MerkleTree from "./helpers/merkleTree.js"; contract('MerkleProof', function(accounts) { - let merkleProof; + let merkleProof; - before(async function() { - merkleProof = await MerkleProofMock.new(); + before(async function() { + merkleProof = await MerkleProof.new(); + }); + + describe("verifyProof", function() { + it("should return true for a valid Merkle proof", 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 result = await merkleProof.verifyProof(proof, root, leaf); + assert.isOk(result, "verifyProof did not return true for a valid proof"); }); - 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); + 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 root = merkleTree.getHexRoot(); - // const proof = merkleTree.getHexProof(elements[0]); + const proof = merkleTree.getHexProof(elements[0]); + const badProof = proof.slice(0, proof.length - 32); - // const leaf = merkleTree.bufToHex(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"); - }); + const result = await merkleProof.verifyProof(badProof, root, leaf); + assert.isNotOk(result, "verifyProof did not return false for an invalid proof"); }); + }); }); diff --git a/test/helpers/merkleTree.js b/test/helpers/merkleTree.js new file mode 100644 index 000000000..dc00eb12f --- /dev/null +++ b/test/helpers/merkleTree.js @@ -0,0 +1,135 @@ +import { sha3 } from "ethereumjs-util"; + +export default class MerkleTree { + constructor(elements) { + // Filter empty strings + this.elements = elements.filter(el => el); + + // Check if elements are 32 byte buffers + if (this.elements.some(el => el.length !== 32 || !Buffer.isBuffer(el))) { + throw new Error("Elements must be 32 byte buffers"); + } + + // Deduplicate elements + this.elements = this.bufDedup(this.elements); + // Sort elements + this.elements.sort(Buffer.compare); + + // Create layers + this.layers = this.getLayers(this.elements); + } + + getLayers(elements) { + if (elements.length == 0) { + return [[""]]; + } + + const layers = []; + layers.push(elements); + + // Get next layer until we reach the root + while (layers[layers.length - 1].length > 1) { + layers.push(this.getNextLayer(layers[layers.length - 1])); + } + + return layers; + } + + getNextLayer(elements) { + return elements.reduce((layer, el, idx, arr) => { + if (idx % 2 === 0) { + // Hash the current element with its pair element + layer.push(this.combinedHash(el, arr[idx + 1])); + } + + return layer; + }, []); + } + + combinedHash(first, second) { + if (!first) { return second; } + if (!second) { return first; } + + return sha3(this.sortAndConcat(first, second)); + } + + getRoot() { + return this.layers[this.layers.length - 1][0]; + } + + getHexRoot() { + return this.bufToHex(this.getRoot()); + } + + getProof(el) { + let idx = this.bufIndexOf(el, this.elements); + + if (idx === -1) { + throw new Error("Element does not exist in Merkle tree"); + } + + return this.layers.reduce((proof, layer) => { + const pairElement = this.getPairElement(idx, layer); + + if (pairElement) { + proof.push(pairElement); + } + + idx = Math.floor(idx / 2); + + return proof; + }, []); + } + + getHexProof(el) { + const proof = this.getProof(el); + + return this.bufArrToHex(proof); + } + + getPairElement(idx, layer) { + const pairIdx = idx % 2 === 0 ? idx + 1 : idx - 1; + + if (pairIdx < layer.length) { + return layer[pairIdx]; + } else { + return null; + } + } + + bufIndexOf(el, arr) { + for (let i = 0; i < arr.length; i++) { + if (el.equals(arr[i])) { + return i; + } + } + + return -1; + } + + bufDedup(elements) { + return elements.filter((el, idx) => { + return this.bufIndexOf(el, elements) === idx; + }); + } + + bufToHex(el) { + if (!Buffer.isBuffer(el)) { + throw new Error("Element is not a buffer"); + } + + return "0x" + el.toString("hex"); + } + + bufArrToHex(arr) { + if (arr.some(el => !Buffer.isBuffer(el))) { + throw new Error("Array is not an array of buffers"); + } + + return "0x" + arr.map(el => el.toString("hex")).join(""); + } + + sortAndConcat(...args) { + return Buffer.concat([...args].sort(Buffer.compare)); + } +} From 30e202313d9c4f6bacac64b5a634f312424a7be7 Mon Sep 17 00:00:00 2001 From: Yondon Fu Date: Thu, 15 Jun 2017 11:10:37 -0400 Subject: [PATCH 3/6] Fix indentation in MerkleProof.sol and remove mock contract --- contracts/MerkleProof.sol | 52 ++++++++++++++++---------------- test/helpers/MerkleProofMock.sol | 12 -------- 2 files changed, 26 insertions(+), 38 deletions(-) delete mode 100644 test/helpers/MerkleProofMock.sol diff --git a/contracts/MerkleProof.sol b/contracts/MerkleProof.sol index 89f9256c1..ca751a2a9 100644 --- a/contracts/MerkleProof.sol +++ b/contracts/MerkleProof.sol @@ -6,33 +6,33 @@ pragma solidity ^0.4.11; * @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; + /* + * @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)) - } + 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; + 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; + } } diff --git a/test/helpers/MerkleProofMock.sol b/test/helpers/MerkleProofMock.sol deleted file mode 100644 index 84ccc1be3..000000000 --- a/test/helpers/MerkleProofMock.sol +++ /dev/null @@ -1,12 +0,0 @@ -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); - } -} From bc3db5d4c11991b103899fc1fa266a2939c02135 Mon Sep 17 00:00:00 2001 From: Yondon Fu Date: Thu, 15 Jun 2017 11:13:37 -0400 Subject: [PATCH 4/6] Fix weird indent issue for inline assembly --- contracts/MerkleProof.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/MerkleProof.sol b/contracts/MerkleProof.sol index ca751a2a9..695ec4b2b 100644 --- a/contracts/MerkleProof.sol +++ b/contracts/MerkleProof.sol @@ -20,8 +20,8 @@ library MerkleProof { for (uint256 i = 32; i <= _proof.length; i += 32) { assembly { // Load the current element of the proof - proofElement := mload(add(_proof, i)) - } + proofElement := mload(add(_proof, i)) + } if (computedHash < proofElement) { // Hash(current computed hash + current element of the proof) From 863ad48a81fd8ff981bca11bbc5eefe99794d376 Mon Sep 17 00:00:00 2001 From: Yondon Fu Date: Fri, 28 Jul 2017 10:38:32 -0400 Subject: [PATCH 5/6] Check proof length multiple of 32. Use keccak256 instead of sha3 --- contracts/MerkleProof.sol | 7 +++++-- test/MerkleProof.js | 23 ++++++++++++++++++++--- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/contracts/MerkleProof.sol b/contracts/MerkleProof.sol index 695ec4b2b..1703ee4ea 100644 --- a/contracts/MerkleProof.sol +++ b/contracts/MerkleProof.sol @@ -14,6 +14,9 @@ library MerkleProof { * @param _leaf Leaf of Merkle tree */ function verifyProof(bytes _proof, bytes32 _root, bytes32 _leaf) constant returns (bool) { + // Check if proof length is a multiple of 32 + if (_proof.length % 32 != 0) return false; + bytes32 proofElement; bytes32 computedHash = _leaf; @@ -25,10 +28,10 @@ library MerkleProof { if (computedHash < proofElement) { // Hash(current computed hash + current element of the proof) - computedHash = sha3(computedHash, proofElement); + computedHash = keccak256(computedHash, proofElement); } else { // Hash(current element of the proof + current computed hash) - computedHash = sha3(proofElement, computedHash); + computedHash = keccak256(proofElement, computedHash); } } diff --git a/test/MerkleProof.js b/test/MerkleProof.js index f2e096e09..eef07b2de 100644 --- a/test/MerkleProof.js +++ b/test/MerkleProof.js @@ -26,18 +26,35 @@ contract('MerkleProof', function(accounts) { }); it("should return false for an invalid Merkle proof", async function() { + const correctElements = ["a", "b", "c"].map(el => sha3(el)); + const correctMerkleTree = new MerkleTree(correctElements); + + const correctRoot = correctMerkleTree.getHexRoot(); + + const correctLeaf = correctMerkleTree.bufToHex(correctElements[0]); + + const badElements = ["d", "e", "f"].map(el => sha3(el)) + const badMerkleTree = new MerkleTree(badElements) + + const badProof = badMerkleTree.getHexProof(badElements[0]) + + const result = await merkleProof.verifyProof(badProof, correctRoot, correctLeaf); + assert.isNotOk(result, "verifyProof did not return false for an invalid proof"); + }); + + it("should return false for a Merkle proof of invalid length", 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 badProof = proof.slice(0, proof.length - 5); const leaf = merkleTree.bufToHex(elements[0]); const result = await merkleProof.verifyProof(badProof, root, leaf); - assert.isNotOk(result, "verifyProof did not return false for an invalid proof"); - }); + assert.isNotOk(result, "verifyProof did not return false for proof of invalid length"); + }) }); }); From 24323d3ce305f13580d5baa88ac623f0bc3c6bc0 Mon Sep 17 00:00:00 2001 From: Yondon Fu Date: Mon, 7 Aug 2017 11:23:52 -0400 Subject: [PATCH 6/6] MerkleTree util class hashes elements --- test/MerkleProof.js | 16 ++++++++-------- test/helpers/merkleTree.js | 32 ++++++++++++++------------------ 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/test/MerkleProof.js b/test/MerkleProof.js index eef07b2de..7f449b431 100644 --- a/test/MerkleProof.js +++ b/test/MerkleProof.js @@ -1,7 +1,7 @@ var MerkleProof = artifacts.require("./MerkleProof.sol"); -import { sha3 } from "ethereumjs-util"; import MerkleTree from "./helpers/merkleTree.js"; +import { sha3, bufferToHex } from "ethereumjs-util"; contract('MerkleProof', function(accounts) { let merkleProof; @@ -12,28 +12,28 @@ contract('MerkleProof', function(accounts) { describe("verifyProof", function() { it("should return true for a valid Merkle proof", async function() { - const elements = ["a", "b", "c", "d"].map(el => sha3(el)); + const elements = ["a", "b", "c", "d"]; const merkleTree = new MerkleTree(elements); const root = merkleTree.getHexRoot(); const proof = merkleTree.getHexProof(elements[0]); - const leaf = merkleTree.bufToHex(elements[0]); + const leaf = bufferToHex(sha3(elements[0])); const result = await merkleProof.verifyProof(proof, root, leaf); assert.isOk(result, "verifyProof did not return true for a valid proof"); }); it("should return false for an invalid Merkle proof", async function() { - const correctElements = ["a", "b", "c"].map(el => sha3(el)); + const correctElements = ["a", "b", "c"] const correctMerkleTree = new MerkleTree(correctElements); const correctRoot = correctMerkleTree.getHexRoot(); - const correctLeaf = correctMerkleTree.bufToHex(correctElements[0]); + const correctLeaf = bufferToHex(sha3(correctElements[0])); - const badElements = ["d", "e", "f"].map(el => sha3(el)) + const badElements = ["d", "e", "f"] const badMerkleTree = new MerkleTree(badElements) const badProof = badMerkleTree.getHexProof(badElements[0]) @@ -43,7 +43,7 @@ contract('MerkleProof', function(accounts) { }); it("should return false for a Merkle proof of invalid length", async function() { - const elements = ["a", "b", "c"].map(el => sha3(el)); + const elements = ["a", "b", "c"] const merkleTree = new MerkleTree(elements); const root = merkleTree.getHexRoot(); @@ -51,7 +51,7 @@ contract('MerkleProof', function(accounts) { const proof = merkleTree.getHexProof(elements[0]); const badProof = proof.slice(0, proof.length - 5); - const leaf = merkleTree.bufToHex(elements[0]); + const leaf = bufferToHex(sha3(elements[0])); const result = await merkleProof.verifyProof(badProof, root, leaf); assert.isNotOk(result, "verifyProof did not return false for proof of invalid length"); diff --git a/test/helpers/merkleTree.js b/test/helpers/merkleTree.js index dc00eb12f..0de95eb15 100644 --- a/test/helpers/merkleTree.js +++ b/test/helpers/merkleTree.js @@ -1,14 +1,9 @@ -import { sha3 } from "ethereumjs-util"; +import { sha3, bufferToHex } from "ethereumjs-util"; export default class MerkleTree { constructor(elements) { - // Filter empty strings - this.elements = elements.filter(el => el); - - // Check if elements are 32 byte buffers - if (this.elements.some(el => el.length !== 32 || !Buffer.isBuffer(el))) { - throw new Error("Elements must be 32 byte buffers"); - } + // Filter empty strings and hash elements + this.elements = elements.filter(el => el).map(el => sha3(el)); // Deduplicate elements this.elements = this.bufDedup(this.elements); @@ -58,7 +53,7 @@ export default class MerkleTree { } getHexRoot() { - return this.bufToHex(this.getRoot()); + return bufferToHex(this.getRoot()); } getProof(el) { @@ -98,8 +93,17 @@ export default class MerkleTree { } bufIndexOf(el, arr) { + let hash; + + // Convert element to 32 byte hash if it is not one already + if (el.length !== 32 || !Buffer.isBuffer(el)) { + hash = sha3(el); + } else { + hash = el; + } + for (let i = 0; i < arr.length; i++) { - if (el.equals(arr[i])) { + if (hash.equals(arr[i])) { return i; } } @@ -113,14 +117,6 @@ export default class MerkleTree { }); } - bufToHex(el) { - if (!Buffer.isBuffer(el)) { - throw new Error("Element is not a buffer"); - } - - return "0x" + el.toString("hex"); - } - bufArrToHex(arr) { if (arr.some(el => !Buffer.isBuffer(el))) { throw new Error("Array is not an array of buffers");