Merge
This commit is contained in:
commit
af698a92ae
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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')
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue