This commit is contained in:
Miguel Mota 2021-04-01 20:34:24 -07:00
commit af698a92ae
No known key found for this signature in database
GPG Key ID: 67EC1161588A00F9
4 changed files with 132 additions and 91 deletions

View File

@ -1,6 +1,6 @@
{
"name": "merkletreejs",
"version": "0.2.13",
"version": "0.2.16",
"description": "Construct Merkle Trees and verify proofs",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@ -52,7 +52,7 @@
"babelify": "^10.0.0",
"browserify": "^16.5.1",
"crypto": "0.0.3",
"ethereumjs-util": "6.1.0",
"ethereumjs-util": "^7.0.9",
"sha1": "^1.1.1",
"standard": "^14.3.4",
"standardx": "^5.0.0",

View File

@ -3,6 +3,13 @@ import SHA256 from 'crypto-js/sha256'
import Base from './Base'
import treeify from 'treeify'
type TValue = Buffer | string | number | null | undefined
type THashAlgoResult = Buffer | string
type THashAlgo = (value: TValue) => Buffer
type TLeaf = Buffer
type TLayer = any
type TFillDefaultHash = (idx?: number, hashFn?: THashAlgo) => THashAlgoResult
export interface Options {
/** If set to `true`, an odd node will be duplicated and combined to make a pair to generate the layer hash. */
duplicateOdd?: boolean
@ -16,34 +23,32 @@ export interface Options {
sortPairs?: boolean
/** If set to `true`, the leaves and hashing pairs will be sorted. */
sort?: boolean
/** If defined, the resulting hash of this function will be used to fill in odd numbered layers. */
fillDefaultHash?: TFillDefaultHash
}
type THashAlgo = any
type TValue = any
type TLeaf = any
type TLayer = any
/**
* Class reprensenting a Merkle Tree
* @namespace MerkleTree
*/
export class MerkleTree extends Base {
private duplicateOdd: boolean
private hashAlgo: (value: TValue) => THashAlgo
private hashLeaves: boolean
private isBitcoinTree: boolean
private leaves: TLeaf[]
private layers: TLayer[]
private sortLeaves: boolean
private sortPairs: boolean
private sort: boolean
private duplicateOdd: boolean = false
private hashFn: THashAlgo
private hashLeaves: boolean = false
private isBitcoinTree: boolean = false
private leaves: TLeaf[] = []
private layers: TLayer[] = []
private sortLeaves: boolean = false
private sortPairs: boolean = false
private sort: boolean = false
private fillDefaultHash: TFillDefaultHash | null = null
/**
* @desc Constructs a Merkle Tree.
* All nodes and leaves are stored as Buffers.
* Lonely leaf nodes are promoted to the next level up without being hashed again.
* @param {Buffer[]} leaves - Array of hashed leaves. Each leaf must be a Buffer.
* @param {Function} hashAlgorithm - Algorithm used for hashing leaves and nodes
* @param {Function} hashFunction - Algorithm used for hashing leaves and nodes
* @param {Object} options - Additional options
* @example
*```js
@ -60,13 +65,21 @@ export class MerkleTree extends Base {
*const tree = new MerkleTree(leaves, sha256)
*```
*/
constructor (leaves: any[], hashAlgorithm = SHA256, options: Options = {}) {
constructor (leaves: any[], hashFn = SHA256, options: Options = {}) {
super()
this.isBitcoinTree = !!options.isBitcoinTree
this.hashLeaves = !!options.hashLeaves
this.sortLeaves = !!options.sortLeaves
this.sortPairs = !!options.sortPairs
if (options.fillDefaultHash) {
if (typeof options.fillDefaultHash === 'function') {
this.fillDefaultHash = options.fillDefaultHash
} else {
throw new Error('method "fillDefaultHash" must be a function')
}
}
this.sort = !!options.sort
if (this.sort) {
this.sortLeaves = true
@ -75,9 +88,9 @@ export class MerkleTree extends Base {
this.duplicateOdd = !!options.duplicateOdd
this.hashAlgo = this._bufferifyFn(hashAlgorithm)
this.hashFn = this._bufferifyFn(hashFn)
if (this.hashLeaves) {
leaves = leaves.map(this.hashAlgo)
leaves = leaves.map(this.hashFn)
}
this.leaves = leaves.map(this.bufferify)
@ -85,6 +98,14 @@ export class MerkleTree extends Base {
this.leaves = this.leaves.sort(Buffer.compare)
}
if (this.fillDefaultHash) {
for (let i = 0; i < Math.pow(2, Math.ceil(Math.log2(this.leaves.length))); i++) {
if (i >= this.leaves.length) {
this.leaves.push(this.bufferify(this.fillDefaultHash(i, this.hashFn)))
}
}
}
this.layers = [this.leaves]
this._createHashes(this.leaves)
}
@ -105,13 +126,16 @@ export class MerkleTree extends Base {
if (this.isBitcoinTree) {
// Bitcoin method of duplicating the odd ending nodes
data = Buffer.concat([reverse(data), reverse(data)])
hash = this.hashAlgo(data)
hash = reverse(this.hashAlgo(hash))
hash = this.hashFn(data)
hash = reverse(this.hashFn(hash))
this.layers[layerIndex].push(hash)
continue
} else {
if (!this.duplicateOdd) {
if (this.duplicateOdd) {
// continue with creating layer
} else {
// push copy of hash and continue iteration
this.layers[layerIndex].push(nodes[i])
continue
}
@ -135,12 +159,11 @@ export class MerkleTree extends Base {
}
data = Buffer.concat(combined)
let hash = this.hashAlgo(data)
let hash = this.hashFn(data)
// double hash if bitcoin tree
if (this.isBitcoinTree) {
hash = reverse(this.hashAlgo(hash))
hash = reverse(this.hashFn(hash))
}
this.layers[layerIndex].push(hash)
@ -162,7 +185,7 @@ export class MerkleTree extends Base {
getLeaves (values?: any[]):Buffer[] {
if (Array.isArray(values)) {
if (this.hashLeaves) {
values = values.map(this.hashAlgo)
values = values.map(this.hashFn)
if (this.sortLeaves) {
values = values.sort(Buffer.compare)
}
@ -350,7 +373,7 @@ export class MerkleTree extends Base {
*const proof = tree.getProof(leaves[2], 2)
*```
*/
getProof (leaf: Buffer, index?: number):any[] {
getProof (leaf: Buffer | string, index?: number):any[] {
leaf = this.bufferify(leaf)
const proof = []
@ -422,7 +445,7 @@ export class MerkleTree extends Base {
*const proof = tree.getHexProof(leaves[2])
*```
*/
getHexProof (leaf: Buffer, index?: number):string[] {
getHexProof (leaf: Buffer | string, index?: number):string[] {
return this.getProof(leaf, index).map(x => this.bufferToHex(x.data))
}
@ -438,7 +461,7 @@ export class MerkleTree extends Base {
*const proof = tree.getPositionalHexProof(leaves[2])
*```
*/
getPositionalHexProof (leaf: Buffer, index?: number): (string | number)[][] {
getPositionalHexProof (leaf: Buffer | string, index?: number): (string | number)[][] {
return this.getProof(leaf, index).map(x => {
return [
x.position === 'left' ? 0 : 1,
@ -631,7 +654,7 @@ export class MerkleTree extends Base {
*const proof = tree.getHexMultiProof(indices)
*```
*/
getHexMultiProof (tree: Buffer[], indices: number[]):string[] {
getHexMultiProof (tree: Buffer[] | string[], indices: number[]):string[] {
return this.getMultiProof(tree, indices).map((x) => this.bufferToHex(x))
}
@ -649,7 +672,7 @@ export class MerkleTree extends Base {
*const proofFlags = tree.getProofFlags(leaves, proof)
*```
*/
getProofFlags (leaves: any[], proofs: Buffer[]):boolean[] {
getProofFlags (leaves: any[], proofs: Buffer[] | string[]):boolean[] {
if (!Array.isArray(leaves) || leaves.length <= 0) {
throw new Error('Invalid Inputs!')
}
@ -665,6 +688,8 @@ export class MerkleTree extends Base {
throw new Error('Element does not exist in Merkle tree')
}
const _proofs: Buffer[] = (proofs as any[]).map(this.bufferify)
const tested = []
const flags = []
for (let index = 0; index < this.layers.length; index++) {
@ -673,7 +698,7 @@ export class MerkleTree extends Base {
const skipped = tested.includes(layer[idx])
if (!skipped) {
const pairElement = this._getPairNode(layer, idx)
const proofUsed = proofs.includes(layer[idx]) || proofs.includes(pairElement)
const proofUsed = _proofs.includes(layer[idx]) || _proofs.includes(pairElement)
pairElement && flags.push(!proofUsed)
tested.push(layer[idx])
tested.push(pairElement)
@ -702,7 +727,7 @@ export class MerkleTree extends Base {
*const verified = tree.verify(proof, leaves[2], root)
*```
*/
verify (proof: any[], targetNode: Buffer, root: Buffer):boolean {
verify (proof: any[], targetNode: Buffer | string, root: Buffer | string):boolean {
let hash = this.bufferify(targetNode)
root = this.bufferify(root)
@ -726,6 +751,9 @@ export class MerkleTree extends Base {
} else if (Array.isArray(node)) {
isLeftNode = (node[0] === 0)
data = this.bufferify(node[1])
} else if (Buffer.isBuffer(node)) {
data = node
isLeftNode = true
} else if (node instanceof Object) {
data = this.bufferify(node.data)
isLeftNode = (node.position === 'left')
@ -740,21 +768,21 @@ export class MerkleTree extends Base {
buffers[isLeftNode ? 'unshift' : 'push'](reverse(data))
hash = this.hashAlgo(Buffer.concat(buffers))
hash = reverse(this.hashAlgo(hash))
hash = this.hashFn(Buffer.concat(buffers))
hash = reverse(this.hashFn(hash))
} else {
if (this.sortPairs) {
if (Buffer.compare(hash, data) === -1) {
buffers.push(hash, data)
hash = this.hashAlgo(Buffer.concat(buffers))
hash = this.hashFn(Buffer.concat(buffers))
} else {
buffers.push(data, hash)
hash = this.hashAlgo(Buffer.concat(buffers))
hash = this.hashFn(Buffer.concat(buffers))
}
} else {
buffers.push(hash)
buffers[isLeftNode ? 'unshift' : 'push'](data)
hash = this.hashAlgo(Buffer.concat(buffers))
hash = this.hashFn(Buffer.concat(buffers))
}
}
}
@ -782,10 +810,10 @@ export class MerkleTree extends Base {
*const verified = tree.verifyMultiProof(root, indices, proofLeaves, depth, proof)
*```
*/
verifyMultiProof (root: Buffer, indices: number[], leaves: Buffer[], depth: number, proof: Buffer[]):boolean {
verifyMultiProof (root: Buffer | string, indices: number[], leaves: Buffer[] | string[], depth: number, proof: Buffer[] | string[]):boolean {
root = this.bufferify(root)
leaves = leaves.map(this.bufferify)
proof = proof.map(this.bufferify)
leaves = (leaves as any[]).map(this.bufferify)
proof = (proof as any[]).map(this.bufferify)
const tree = {}
for (const [index, leaf] of this._zip(indices, leaves)) {
@ -805,7 +833,7 @@ export class MerkleTree extends Base {
pair = pair.sort(Buffer.compare)
}
tree[(index / 2) | 0] = this.hashAlgo(Buffer.concat(pair))
tree[(index / 2) | 0] = this.hashFn(Buffer.concat(pair))
indexqueue.push((index / 2) | 0)
}
i += 1
@ -876,7 +904,7 @@ export class MerkleTree extends Base {
*const proof = MerkleTree.getMultiProof(flatTree, indices)
*```
*/
static getMultiProof (tree: Buffer[], indices: number[]):Buffer[] {
static getMultiProof (tree: Buffer[] | string[], indices: number[]):Buffer[] {
const t = new MerkleTree([])
return t.getMultiProof(tree, indices)
}

View File

@ -37,14 +37,11 @@ test('merkle mountain range', t => {
}
const peakBagging = (size, peaks) => {
// keccak256(abi.encodePacked(size, keccak256(abi.encodePacked(size, peaks))));
const a = [{ t: 'uint256', v: size }, ...peaks.map(x => ({ t: 'bytes32', v: x.toString('hex') }))]
const x = soliditySha3(...a)
const b = [{ t: 'uint256', v: size }, { t: 'bytes32', v: x.toString('hex') }]
const res = soliditySha3(...b)
return res
// return keccak256(abi.encodePacked(size, keccak256(abi.encodePacked(size, peaks))));
}
const hashBranch = (index, left, right) => {

View File

@ -1,7 +1,7 @@
/* eslint camelcase: 0 */
const test = require('tape')
const { keccak } = require('ethereumjs-util')
const { keccak256 } = require('ethereumjs-util')
const crypto = require('crypto')
const CryptoJS = require('crypto-js')
const SHA256 = require('crypto-js/sha256')
@ -12,10 +12,10 @@ const { MerkleTree } = require('../')
const sha256 = (data) => crypto.createHash('sha256').update(data).digest()
test('sha256 with keccak leaves', t => {
test('sha256 with keccak256 leaves', t => {
t.plan(3)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const tree = new MerkleTree(leaves, sha256)
t.equal(tree.getHexRoot(), '0x311d2e46f49b15fff8b746b74ad57f2cc9e0d9939fda94387141a2d3fdf187ae')
@ -40,10 +40,10 @@ test('sha256 with keccak leaves', t => {
])
})
test('sha256 with keccak leaves with duplicate odd option', t => {
test('sha256 with keccak256 leaves with duplicate odd option', t => {
t.plan(3)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const tree = new MerkleTree(leaves, sha256, { duplicateOdd: true })
t.equal(tree.getHexRoot(), '0xbcdd0f60308db788712205115fe4273bfda49fa0925611fee765a63df9ab96a1')
@ -71,7 +71,7 @@ test('sha256 with keccak leaves with duplicate odd option', t => {
test('crypto-js - sha256', t => {
t.plan(1)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const tree = new MerkleTree(leaves, SHA256)
const root = '311d2e46f49b15fff8b746b74ad57f2cc9e0d9939fda94387141a2d3fdf187ae'
@ -115,21 +115,21 @@ test('sha256 verify with hex proof and pairSort', t => {
t.true(tree.verify(tree.getHexProof(leaves[1], 1), leaves[1], tree.getHexRoot()))
})
test('keccak with sort leaves and sort pairs option', t => {
test('keccak256 with sort leaves and sort pairs option', t => {
t.plan(1)
const leaves = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'].map(x => keccak(x))
const tree = new MerkleTree(leaves, keccak, { sortLeaves: true, sortPairs: true })
const leaves = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'].map(x => keccak256(Buffer.from(x)))
const tree = new MerkleTree(leaves, keccak256, { sortLeaves: true, sortPairs: true })
const root = '60219f87561939610b484575e45c6e81156a53b86d7cd16640d930d14f21758e'
t.equal(tree.getRoot().toString('hex'), root)
})
test('keccak with sort option', t => {
test('keccak256 with sort option', t => {
t.plan(1)
const leaves = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'].map(x => keccak(x))
const tree = new MerkleTree(leaves, keccak, { sort: true })
const leaves = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'].map(x => keccak256(Buffer.from(x)))
const tree = new MerkleTree(leaves, keccak256, { sort: true })
const root = '60219f87561939610b484575e45c6e81156a53b86d7cd16640d930d14f21758e'
t.equal(tree.getRoot().toString('hex'), root)
@ -165,7 +165,7 @@ test('sha256 with hash leaves option and duplicate odd option', t => {
t.equal(tree.getRoot().toString('hex'), root)
})
test('crypto-js - sha256 with keccak leaves', t => {
test('crypto-js - sha256 with keccak256 leaves', t => {
t.plan(1)
const leaves = ['a', 'b', 'c'].map(SHA256)
@ -175,10 +175,10 @@ test('crypto-js - sha256 with keccak leaves', t => {
t.equal(tree.getRoot().toString('hex'), root)
})
test('crypto-js - sha256 with keccak leaves and duplicate odd option', t => {
test('crypto-js - sha256 with keccak256 leaves and duplicate odd option', t => {
t.plan(1)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const tree = new MerkleTree(leaves, SHA256, { duplicateOdd: true })
const root = 'bcdd0f60308db788712205115fe4273bfda49fa0925611fee765a63df9ab96a1'
@ -206,20 +206,20 @@ test('crypto-js - SHA256 with SHA3 leaves', t => {
t.equal(tree.getRoot().toString('hex'), root)
})
test('crypto-js - SHA256 with keccak leaves and duplicate odd option', t => {
test('crypto-js - SHA256 with keccak256 leaves and duplicate odd option', t => {
t.plan(1)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const tree = new MerkleTree(leaves, SHA256, { duplicateOdd: true })
const root = 'bcdd0f60308db788712205115fe4273bfda49fa0925611fee765a63df9ab96a1'
t.equal(tree.getRoot().toString('hex'), root)
})
test('solidity keccak [keccak-256]', t => {
test('solidity keccak256', t => {
t.plan(20)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const a_hash = '3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb'
const b_hash = 'b5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510'
@ -227,11 +227,11 @@ test('solidity keccak [keccak-256]', t => {
t.deepEqual(leaves.map(x => x.toString('hex')), [a_hash, b_hash, c_hash])
const tree = new MerkleTree(leaves, keccak)
const tree = new MerkleTree(leaves, keccak256)
const layers = tree.getLayers().slice(1) // no leaves
const layer_1 = keccak(Buffer.concat([leaves[0], leaves[1]])).toString('hex')
const layer_1 = keccak256(Buffer.concat([leaves[0], leaves[1]])).toString('hex')
t.equal(layers[0][0].toString('hex'), layer_1)
t.equal(layers[0][1].toString('hex'), c_hash)
@ -265,10 +265,10 @@ test('solidity keccak [keccak-256]', t => {
t.true(tree.verify(proof_2, leaves[2], root))
})
test('solidity keccak [keccak-256] with duplicate odd option', t => {
test('solidity keccak256 with duplicate odd option', t => {
t.plan(20)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const a_hash = '3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb'
const b_hash = 'b5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510'
@ -276,10 +276,10 @@ test('solidity keccak [keccak-256] with duplicate odd option', t => {
t.deepEqual(leaves.map(x => x.toString('hex')), [a_hash, b_hash, c_hash])
const tree = new MerkleTree(leaves, keccak, { duplicateOdd: true })
const tree = new MerkleTree(leaves, keccak256, { duplicateOdd: true })
const layers = tree.getLayers().slice(1) // no leaves
const layer_1 = keccak(Buffer.concat([leaves[0], leaves[1]])).toString('hex')
const layer_2 = keccak(Buffer.concat([leaves[2], leaves[2]])).toString('hex')
const layer_1 = keccak256(Buffer.concat([leaves[0], leaves[1]])).toString('hex')
const layer_2 = keccak256(Buffer.concat([leaves[2], leaves[2]])).toString('hex')
t.equal(layers[0][0].toString('hex'), layer_1)
t.equal(layers[0][1].toString('hex'), layer_2)
@ -312,22 +312,22 @@ test('solidity keccak [keccak-256] with duplicate odd option', t => {
t.true(tree.verify(proof_2, layer_2, root))
})
test('solidity keccak [keccak-256] with duplicate leaves', t => {
test('solidity keccak256 with duplicate leaves', t => {
t.plan(5)
const leaves = ['a', 'b', 'a'].map(x => keccak(x))
const leaves = ['a', 'b', 'a'].map(x => keccak256(Buffer.from(x)))
const a_hash = '3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb'
const b_hash = 'b5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510'
const tree = new MerkleTree(leaves, keccak)
const tree = new MerkleTree(leaves, keccak256)
t.deepEqual(leaves.map(x => x.toString('hex')), [a_hash, b_hash, a_hash])
const root = Buffer.from('b8912f7269068901f231a965adfefbc10f0eedcfa61852b103efd54dac7db3d7', 'hex')
t.equal(tree.getRoot().toString('hex'), root.toString('hex'))
const layer_1 = keccak(Buffer.concat([leaves[0], leaves[1]])).toString('hex')
const layer_1 = keccak256(Buffer.concat([leaves[0], leaves[1]])).toString('hex')
const proof_0 = tree.getProof(leaves[2], 2)
t.equal(proof_0.length, 1)
@ -454,9 +454,9 @@ test('sha-256 with option.isBitcoinTree', t => {
t.true(tree.verify(proof_0, leaves[0], root))
})
test('keccak - hex strings', t => {
test('keccak256 - hex strings', t => {
t.plan(1)
const leaves = ['a', 'b', 'c'].map(x => keccak(x).toString('hex'))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)).toString('hex'))
const tree = new MerkleTree(leaves, SHA256)
const root = '311d2e46f49b15fff8b746b74ad57f2cc9e0d9939fda94387141a2d3fdf187ae'
t.equal(tree.getRoot().toString('hex'), root)
@ -490,7 +490,7 @@ test.skip('sha256 - 1,000,000 leaves', t => {
test('sha256 getHexLeaves', t => {
t.plan(1)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const tree = new MerkleTree(leaves, sha256)
t.deepEqual(tree.getHexLeaves(), [
'0x3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb',
@ -582,7 +582,7 @@ test('sha1', t => {
test('sha56 getHexLayers', t => {
t.plan(1)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const tree = new MerkleTree(leaves, sha256)
const layers = tree.getHexLayers()
@ -605,7 +605,7 @@ test('sha56 getHexLayers', t => {
test('getLayersAsObject', t => {
t.plan(1)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const tree = new MerkleTree(leaves, sha256)
const obj = tree.getLayersAsObject()
@ -625,7 +625,7 @@ test('getLayersAsObject', t => {
test('getLayersAsObject with duplicate odd option', t => {
t.plan(1)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const tree = new MerkleTree(leaves, sha256, { duplicateOdd: true })
const obj = tree.getLayersAsObject()
@ -645,7 +645,7 @@ test('getLayersAsObject with duplicate odd option', t => {
test.skip('sha256 getHexLayersFlat', t => {
t.plan(1)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const tree = new MerkleTree(leaves, sha256)
const layers = tree.getLayersFlat()
t.deepEqual(layers, [
@ -661,7 +661,7 @@ test.skip('sha256 getHexLayersFlat', t => {
test('print', t => {
t.plan(1)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const tree = new MerkleTree(leaves, sha256)
t.equal(tree.toString(),
@ -677,7 +677,7 @@ test('print', t => {
test('print with duplicate odd option', t => {
t.plan(1)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const tree = new MerkleTree(leaves, sha256, { duplicateOdd: true })
t.equal(tree.toString(),
@ -873,9 +873,9 @@ test('sha256 getProofFlag with indices', t => {
test('sha256 getMultiProof - statusim', t => {
t.plan(5)
const elements = ['a', 'b', 'c', 'd', 'e', 'f']
const elements = ['a', 'b', 'c', 'd', 'e', 'f'].map(x => Buffer.from(x))
const tree = new MerkleTree(elements, keccak, {
const tree = new MerkleTree(elements, keccak256, {
hashLeaves: true,
sortLeaves: true,
sortPairs: true
@ -891,7 +891,7 @@ test('sha256 getMultiProof - statusim', t => {
'0xf1918e8562236eb17adc8502332f4c9c82bc14e19bfc0aa10ab674ff75b3d2f3'
])
const leaves = tree.getLeaves(['d', 'a'])
const leaves = tree.getLeaves(['d', 'a'].map(x => Buffer.from(x)))
const proof = tree.getMultiProof(leaves)
const proofFlags = tree.getProofFlags(leaves, proof)
@ -910,7 +910,7 @@ test('sha256 getMultiProof - statusim', t => {
test('marshal leaves', t => {
t.plan(5)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const jsonLeaves = MerkleTree.marshalLeaves(leaves)
t.equal(typeof jsonLeaves, 'string')
@ -940,7 +940,7 @@ test('unmarshal leaves', t => {
test('marshal proof', t => {
t.plan(5)
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
const leaves = ['a', 'b', 'c'].map(x => keccak256(Buffer.from(x)))
const tree = new MerkleTree(leaves, sha256, { duplicateOdd: true })
const proof = tree.getProof(leaves[0])
@ -975,3 +975,19 @@ test('unmarshal proof', t => {
t.equal(proof[0].data.toString('hex'), 'b5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510')
t.equal(proof[1].data.toString('hex'), '43e061172b1177f25d0f156b2d2ed11728006fade8e167ff3d1b9dbc979a3358')
})
test('fillDefaultHashes', t => {
t.plan(1)
const leaves = [...Array(9)].map((x, i) => {
return keccak256(Buffer.from([i]))
})
const tree = new MerkleTree(leaves, keccak256, {
fillDefaultHash: (idx, hashFn) => {
return keccak256(Buffer.alloc(32))
}
})
t.equal(tree.getHexRoot(), '0x11f470d712bb3a84f0b01cb7c73493ec7d06eda480f567c99b9a6dc773679a72')
})