merkletreejs
Advanced tools
Comparing version 0.2.1 to 0.2.2
@@ -5,4 +5,2 @@ /// <reference types="node" /> | ||
duplicateOdd?: boolean; | ||
/** If set to `true`, an odd node will not have a pair generating the layer hash. */ | ||
singleOdd?: boolean; | ||
/** If set to `true`, the leaves will hashed using the set hashing algorithms. */ | ||
@@ -19,6 +17,2 @@ hashLeaves?: boolean; | ||
} | ||
declare type THashAlgo = any; | ||
declare type TValue = any; | ||
declare type TLeaf = any; | ||
declare type TLayer = any; | ||
/** | ||
@@ -29,12 +23,11 @@ * Class reprensenting a Merkle Tree | ||
export declare class MerkleTree { | ||
duplicateOdd: boolean; | ||
singleOdd: boolean; | ||
hashAlgo: (value: TValue) => THashAlgo; | ||
hashLeaves: boolean; | ||
isBitcoinTree: boolean; | ||
leaves: TLeaf[]; | ||
layers: TLayer[]; | ||
sortLeaves: boolean; | ||
sortPairs: boolean; | ||
sort: boolean; | ||
private duplicateOdd; | ||
private hashAlgo; | ||
private hashLeaves; | ||
private isBitcoinTree; | ||
private leaves; | ||
private layers; | ||
private sortLeaves; | ||
private sortPairs; | ||
private sort; | ||
/** | ||
@@ -62,4 +55,4 @@ * @desc Constructs a Merkle Tree. | ||
*/ | ||
constructor(leaves: any, hashAlgorithm: any, options?: Options); | ||
createHashes(nodes: any): void; | ||
constructor(leaves: any[], hashAlgorithm?: any, options?: Options); | ||
private _createHashes; | ||
/** | ||
@@ -74,3 +67,3 @@ * getLeaves | ||
*/ | ||
getLeaves(data?: any[]): any[]; | ||
getLeaves(values?: any[]): Buffer[]; | ||
/** | ||
@@ -95,3 +88,3 @@ * getHexLeaves | ||
*/ | ||
getLayers(): any[]; | ||
getLayers(): Buffer[]; | ||
/** | ||
@@ -106,3 +99,3 @@ * getHexLayers | ||
*/ | ||
getHexLayers(): any; | ||
getHexLayers(): string[]; | ||
/** | ||
@@ -117,3 +110,3 @@ * getLayersFlat | ||
*/ | ||
getLayersFlat(): any; | ||
getLayersFlat(): Buffer[]; | ||
/** | ||
@@ -128,3 +121,3 @@ * getHexLayersFlat | ||
*/ | ||
getHexLayersFlat(): any; | ||
getHexLayersFlat(): string[]; | ||
/** | ||
@@ -139,3 +132,3 @@ * getRoot | ||
*/ | ||
getRoot(): any; | ||
getRoot(): Buffer; | ||
/** | ||
@@ -159,3 +152,3 @@ * getHexRoot | ||
* with values of 'left' or 'right' and a data property of type Buffer. | ||
*@example | ||
* @example | ||
* ```js | ||
@@ -172,11 +165,69 @@ *const proof = tree.getProof(leaves[2]) | ||
*/ | ||
getProof(leaf: any, index?: any): any[]; | ||
getProofIndices(treeIndices: any, depth: any): any[]; | ||
getMultiProof(tree: any, indices: any): any[]; | ||
getHexMultiProof(tree: any, indices: any): string[]; | ||
bufIndexOf(arr: any, el: any): number; | ||
getProofFlags(els: any, proofs: any): any[]; | ||
getPairElement(idx: any, layer: any): any; | ||
getHexProof(leaf: any, index?: any): string[]; | ||
getProof(leaf: Buffer, index?: number): any[]; | ||
/** | ||
* getHexProof | ||
* @desc Returns the proof for a target leaf as hex strings. | ||
* @param {Buffer} leaf - Target leaf | ||
* @param {Number} [index] - Target leaf index in leaves array. | ||
* Use if there are leaves containing duplicate data in order to distinguish it. | ||
* @return {String[]} - Proof array as hex strings. | ||
* @example | ||
* ```js | ||
*const proof = tree.getHexProof(leaves[2]) | ||
*``` | ||
*/ | ||
getHexProof(leaf: Buffer, index?: number): string[]; | ||
/** | ||
* getProofIndices | ||
* @desc Returns the proof indices for given tree indices. | ||
* @param {Number[]} treeIndices - Tree indices | ||
* @param {Number} depth - Tree depth; number of layers. | ||
* @return {Number[]} - Proof indices | ||
* @example | ||
* ```js | ||
*const proofIndices = tree.getProofIndices([2,5,6], 4) | ||
*console.log(proofIndices) // [ 23, 20, 19, 8, 3 ] | ||
*``` | ||
*/ | ||
getProofIndices(treeIndices: number[], depth: number): number[]; | ||
/** | ||
* getMultiProof | ||
* @desc Returns the multiproof for given tree indices. | ||
* @param {Number[]} indices - Tree indices. | ||
* @return {Buffer[]} - Multiproofs | ||
* @example | ||
* ```js | ||
*const indices = [2, 5, 6] | ||
*const proof = tree.getMultiProof(indices) | ||
*``` | ||
*/ | ||
getMultiProof(tree?: any[], indices?: any[]): Buffer[]; | ||
/** | ||
* getHexMultiProof | ||
* @desc Returns the multiproof for given tree indices as hex strings. | ||
* @param {Number[]} indices - Tree indices. | ||
* @return {String[]} - Multiproofs as hex strings. | ||
* @example | ||
* ```js | ||
*const indices = [2, 5, 6] | ||
*const proof = tree.getHexMultiProof(indices) | ||
*``` | ||
*/ | ||
getHexMultiProof(tree: Buffer[], indices: number[]): string[]; | ||
/** | ||
* getProofFlags | ||
* @desc Returns list of booleans where proofs should be used instead of hashing. | ||
* Proof flags are used in the Solidity multiproof verifiers. | ||
* @param {Buffer[]} leaves | ||
* @param {Buffer[]} proofs | ||
* @return {Boolean[]} - Boolean flags | ||
* @example | ||
* ```js | ||
*const indices = [2, 5, 6] | ||
*const proof = tree.getMultiProof(indices) | ||
*const proofFlags = tree.getProofFlags(leaves, proof) | ||
*``` | ||
*/ | ||
getProofFlags(leaves: Buffer[], proofs: Buffer[]): boolean[]; | ||
/** | ||
* verify | ||
@@ -197,19 +248,216 @@ * @desc Returns true if the proof path (array of hashes) can connect the target node | ||
*/ | ||
verify(proof: any, targetNode: any, root: any): boolean; | ||
verifyMultiProof(root: any, indices: any, leaves: any, depth: any, proof: any): any; | ||
verify(proof: any[], targetNode: Buffer, root: Buffer): boolean; | ||
/** | ||
* verifyMultiProof | ||
* @desc Returns true if the multiproofs can connect the leaves to the Merkle root. | ||
* @param {Buffer} root - Merkle tree root | ||
* @param {Number[]} indices - Leave indices | ||
* @param {Buffer[]} leaves - Leaf values at indices. | ||
* @param {Number} depth - Tree depth | ||
* @param {Buffer[]} proof - Multiproofs given indices | ||
* @return {Boolean} | ||
* @example | ||
*```js | ||
*const root = tree.getRoot() | ||
*const treeFlat = tree.getLayersFlat() | ||
*const depth = tree.getDepth() | ||
*const indices = [2, 5, 6] | ||
*const proofLeaves = indices.map(i => leaves[i]) | ||
*const proof = tree.getMultiProof(treeFlat, indices) | ||
*const verified = tree.verifyMultiProof(root, indices, proofLeaves, depth, proof) | ||
*``` | ||
*/ | ||
verifyMultiProof(root: Buffer, indices: number[], leaves: Buffer[], depth: number, proof: Buffer[]): boolean; | ||
/** | ||
* getDepth | ||
* @desc Returns the tree depth (number of layers) | ||
* @return {Number} | ||
* @example | ||
*```js | ||
*const depth = tree.getDepth() | ||
*``` | ||
*/ | ||
getDepth(): number; | ||
/** | ||
* getLayersAsObject | ||
* @desc Returns the layers as nested objects instead of an array. | ||
* @example | ||
*```js | ||
*const layersObj = tree.getLayersAsObject() | ||
*``` | ||
*/ | ||
getLayersAsObject(): any; | ||
/** | ||
* @desc Prints out a visual representation of the merkle tree. | ||
* @example | ||
*```js | ||
*tree.print() | ||
*``` | ||
*/ | ||
print(): void; | ||
toTreeString(): any; | ||
toString(): any; | ||
static bufferify(x: any): any; | ||
static isHexStr(v: any): boolean; | ||
/** | ||
* toTreeString | ||
* @desc Returns a visual representation of the merkle tree as a string. | ||
* @return {String} | ||
* @example | ||
*```js | ||
*console.log(tree.toTreeString()) | ||
*``` | ||
*/ | ||
private _toTreeString; | ||
/** | ||
* toString | ||
* @desc Returns a visual representation of the merkle tree as a string. | ||
* @example | ||
*```js | ||
*console.log(tree.toString()) | ||
*``` | ||
*/ | ||
toString(): string; | ||
/** | ||
* getMultiProof | ||
* @desc Returns the multiproof for given tree indices. | ||
* @param {Buffer[]} tree - Tree as a flat array. | ||
* @param {Number[]} indices - Tree indices. | ||
* @return {Buffer[]} - Multiproofs | ||
* | ||
*@example | ||
* ```js | ||
*const flatTree = tree.getLayersFlat() | ||
*const indices = [2, 5, 6] | ||
*const proof = MerkleTree.getMultiProof(flatTree, indices) | ||
*``` | ||
*/ | ||
static getMultiProof(tree: Buffer[], indices: number[]): Buffer[]; | ||
/** | ||
* getPairNode | ||
* @desc Returns the node at the index for given layer. | ||
* @param {Buffer[]} layer - Tree layer | ||
* @param {Number} index - Index at layer. | ||
* @return {Buffer} - Node | ||
* | ||
*@example | ||
* ```js | ||
*const node = tree.getPairNode(layer, index) | ||
*``` | ||
*/ | ||
private _getPairNode; | ||
/** | ||
* bufferIndexOf | ||
* @desc Returns the first index of which given buffer is found in array. | ||
* @param {Buffer[]} haystack - Array of buffers. | ||
* @param {Buffer} needle - Buffer to find. | ||
* @return {Number} - Index number | ||
* | ||
* @example | ||
* ```js | ||
*const index = tree.bufferIndexOf(haystack, needle) | ||
*``` | ||
*/ | ||
private _bufferIndexOf; | ||
/** | ||
* bufferify | ||
* @desc Returns a buffer type for the given value. | ||
* @param {String|Number|Object|Buffer} value | ||
* @return {Buffer} | ||
* | ||
* @example | ||
* ```js | ||
*const buf = MerkleTree.bufferify('0x1234') | ||
*``` | ||
*/ | ||
static bufferify(value: any): Buffer; | ||
/** | ||
* isHexString | ||
* @desc Returns true if value is a hex string. | ||
* @param {String} value | ||
* @return {Boolean} | ||
* | ||
* @example | ||
* ```js | ||
*console.log(MerkleTree.isHexString('0x1234')) | ||
*``` | ||
*/ | ||
static isHexString(v: string): boolean; | ||
/** | ||
* @desc Prints out a visual representation of the given merkle tree. | ||
* @param {Object} tree - Merkle tree instance. | ||
* @return {String} | ||
* @example | ||
*```js | ||
*MerkleTree.print(tree) | ||
*``` | ||
*/ | ||
static print(tree: any): void; | ||
_bufferToHex(value: Buffer): string; | ||
_bufferify(x: any): any; | ||
_bufferifyFn(f: any): (x: any) => Buffer; | ||
_isHexStr(v: any): boolean; | ||
_log2(x: any): any; | ||
_zip(a: any, b: any): any; | ||
/** | ||
* bufferToHex | ||
* @desc Returns a hex string with 0x prefix for given buffer. | ||
* @param {Buffer} value | ||
* @return {String} | ||
* @example | ||
*```js | ||
*const hexStr = tree.bufferToHex(Buffer.from('A')) | ||
*``` | ||
*/ | ||
private _bufferToHex; | ||
/** | ||
* bufferify | ||
* @desc Returns a buffer type for the given value. | ||
* @param {String|Number|Object|Buffer} value | ||
* @return {Buffer} | ||
* | ||
* @example | ||
* ```js | ||
*const buf = MerkleTree.bufferify('0x1234') | ||
*``` | ||
*/ | ||
private _bufferify; | ||
/** | ||
* bufferifyFn | ||
* @desc Returns a function that will bufferify the return value. | ||
* @param {Function} | ||
* @return {Function} | ||
* | ||
* @example | ||
* ```js | ||
*const fn = tree.bufferifyFn((value) => sha256(value)) | ||
*``` | ||
*/ | ||
private _bufferifyFn; | ||
/** | ||
* isHexString | ||
* @desc Returns true if value is a hex string. | ||
* @param {String} value | ||
* @return {Boolean} | ||
* | ||
* @example | ||
* ```js | ||
*console.log(MerkleTree.isHexString('0x1234')) | ||
*``` | ||
*/ | ||
private _isHexString; | ||
/** | ||
* log2 | ||
* @desc Returns the log2 of number. | ||
* @param {Number} value | ||
* @return {Number} | ||
*/ | ||
private _log2; | ||
/** | ||
* zip | ||
* @desc Returns true if value is a hex string. | ||
* @param {String[]|Number[]|Buffer[]} a - first array | ||
* @param {String[]|Number[]|Buffer[]} b - second array | ||
* @return {String[][]|Number[][]|Buffer[][]} | ||
* | ||
* @example | ||
* ```js | ||
*const zipped = tree.zip(['a', 'b'],['A', 'B']) | ||
*console.log(zipped) // [ [ 'a', 'A' ], [ 'b', 'B' ] ] | ||
*``` | ||
*/ | ||
private _zip; | ||
} | ||
export default MerkleTree; |
@@ -6,4 +6,6 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.MerkleTree = void 0; | ||
const buffer_reverse_1 = __importDefault(require("buffer-reverse")); | ||
const crypto_js_1 = __importDefault(require("crypto-js")); | ||
const sha256_1 = __importDefault(require("crypto-js/sha256")); | ||
const treeify_1 = __importDefault(require("treeify")); | ||
@@ -37,3 +39,3 @@ /** | ||
*/ | ||
constructor(leaves, hashAlgorithm, options = {}) { | ||
constructor(leaves, hashAlgorithm = sha256_1.default, options = {}) { | ||
this.isBitcoinTree = !!options.isBitcoinTree; | ||
@@ -49,3 +51,2 @@ this.hashLeaves = !!options.hashLeaves; | ||
this.duplicateOdd = !!options.duplicateOdd; | ||
this.singleOdd = !!options.singleOdd; | ||
this.hashAlgo = this._bufferifyFn(hashAlgorithm); | ||
@@ -60,6 +61,5 @@ if (this.hashLeaves) { | ||
this.layers = [this.leaves]; | ||
this.createHashes(this.leaves); | ||
this._createHashes(this.leaves); | ||
} | ||
// TODO: documentation | ||
createHashes(nodes) { | ||
_createHashes(nodes) { | ||
while (nodes.length > 1) { | ||
@@ -83,3 +83,3 @@ const layerIndex = this.layers.length; | ||
else { | ||
if (!this.duplicateOdd && !this.singleOdd) { | ||
if (!this.duplicateOdd) { | ||
this.layers[layerIndex].push(nodes[i]); | ||
@@ -99,17 +99,3 @@ continue; | ||
else { | ||
if (this.singleOdd) { | ||
right = nodes[i + 1]; | ||
if (!left) { | ||
combined = [right]; | ||
} | ||
else if (!right) { | ||
combined = [left]; | ||
} | ||
else { | ||
combined = [left, right]; | ||
} | ||
} | ||
else { | ||
combined = [left, right]; | ||
} | ||
combined = [left, right]; | ||
} | ||
@@ -139,11 +125,11 @@ if (this.sortPairs) { | ||
*/ | ||
getLeaves(data) { | ||
if (Array.isArray(data)) { | ||
getLeaves(values) { | ||
if (Array.isArray(values)) { | ||
if (this.hashLeaves) { | ||
data = data.map(this.hashAlgo); | ||
values = values.map(this.hashAlgo); | ||
if (this.sortLeaves) { | ||
data = data.sort(Buffer.compare); | ||
values = values.sort(Buffer.compare); | ||
} | ||
} | ||
return this.leaves.filter(x => this.bufIndexOf(data, x) !== -1); | ||
return this.leaves.filter(x => this._bufferIndexOf(values, x) !== -1); | ||
} | ||
@@ -262,3 +248,3 @@ return this.leaves; | ||
* with values of 'left' or 'right' and a data property of type Buffer. | ||
*@example | ||
* @example | ||
* ```js | ||
@@ -323,3 +309,29 @@ *const proof = tree.getProof(leaves[2]) | ||
} | ||
// TODO: documentation | ||
/** | ||
* getHexProof | ||
* @desc Returns the proof for a target leaf as hex strings. | ||
* @param {Buffer} leaf - Target leaf | ||
* @param {Number} [index] - Target leaf index in leaves array. | ||
* Use if there are leaves containing duplicate data in order to distinguish it. | ||
* @return {String[]} - Proof array as hex strings. | ||
* @example | ||
* ```js | ||
*const proof = tree.getHexProof(leaves[2]) | ||
*``` | ||
*/ | ||
getHexProof(leaf, index) { | ||
return this.getProof(leaf, index).map(x => this._bufferToHex(x.data)); | ||
} | ||
/** | ||
* getProofIndices | ||
* @desc Returns the proof indices for given tree indices. | ||
* @param {Number[]} treeIndices - Tree indices | ||
* @param {Number} depth - Tree depth; number of layers. | ||
* @return {Number[]} - Proof indices | ||
* @example | ||
* ```js | ||
*const proofIndices = tree.getProofIndices([2,5,6], 4) | ||
*console.log(proofIndices) // [ 23, 20, 19, 8, 3 ] | ||
*``` | ||
*/ | ||
getProofIndices(treeIndices, depth) { | ||
@@ -355,3 +367,13 @@ const leafCount = Math.pow(2, depth); | ||
} | ||
// TODO: documentation | ||
/** | ||
* getMultiProof | ||
* @desc Returns the multiproof for given tree indices. | ||
* @param {Number[]} indices - Tree indices. | ||
* @return {Buffer[]} - Multiproofs | ||
* @example | ||
* ```js | ||
*const indices = [2, 5, 6] | ||
*const proof = tree.getMultiProof(indices) | ||
*``` | ||
*/ | ||
getMultiProof(tree, indices) { | ||
@@ -366,3 +388,3 @@ if (!indices) { | ||
} | ||
let ids = els.map((el) => this.bufIndexOf(this.leaves, el)).sort((a, b) => a === b ? 0 : a > b ? 1 : -1); | ||
let ids = els.map((el) => this._bufferIndexOf(this.leaves, el)).sort((a, b) => a === b ? 0 : a > b ? 1 : -1); | ||
if (!ids.every((idx) => idx !== -1)) { | ||
@@ -378,3 +400,3 @@ throw new Error('Element does not exist in Merkle tree'); | ||
const idx = ids[j]; | ||
const pairElement = this.getPairElement(idx, layer); | ||
const pairElement = this._getPairNode(layer, idx); | ||
hashes.push(layer[idx]); | ||
@@ -394,18 +416,32 @@ if (pairElement) { | ||
} | ||
// TODO: documentation | ||
/** | ||
* getHexMultiProof | ||
* @desc Returns the multiproof for given tree indices as hex strings. | ||
* @param {Number[]} indices - Tree indices. | ||
* @return {String[]} - Multiproofs as hex strings. | ||
* @example | ||
* ```js | ||
*const indices = [2, 5, 6] | ||
*const proof = tree.getHexMultiProof(indices) | ||
*``` | ||
*/ | ||
getHexMultiProof(tree, indices) { | ||
return this.getMultiProof(tree, indices).map(this._bufferToHex); | ||
} | ||
// TODO: documentation | ||
bufIndexOf(arr, el) { | ||
for (let i = 0; i < arr.length; i++) { | ||
if (el.equals(arr[i])) { | ||
return i; | ||
} | ||
} | ||
return -1; | ||
} | ||
// TODO: documentation | ||
getProofFlags(els, proofs) { | ||
let ids = els.map((el) => this.bufIndexOf(this.leaves, el)).sort((a, b) => a === b ? 0 : a > b ? 1 : -1); | ||
/** | ||
* getProofFlags | ||
* @desc Returns list of booleans where proofs should be used instead of hashing. | ||
* Proof flags are used in the Solidity multiproof verifiers. | ||
* @param {Buffer[]} leaves | ||
* @param {Buffer[]} proofs | ||
* @return {Boolean[]} - Boolean flags | ||
* @example | ||
* ```js | ||
*const indices = [2, 5, 6] | ||
*const proof = tree.getMultiProof(indices) | ||
*const proofFlags = tree.getProofFlags(leaves, proof) | ||
*``` | ||
*/ | ||
getProofFlags(leaves, proofs) { | ||
let ids = leaves.map((el) => this._bufferIndexOf(this.leaves, el)).sort((a, b) => a === b ? 0 : a > b ? 1 : -1); | ||
if (!ids.every((idx) => idx !== -1)) { | ||
@@ -421,3 +457,3 @@ throw new Error('Element does not exist in Merkle tree'); | ||
if (!skipped) { | ||
const pairElement = this.getPairElement(idx, layer); | ||
const pairElement = this._getPairNode(layer, idx); | ||
const proofUsed = proofs.includes(layer[idx]) || proofs.includes(pairElement); | ||
@@ -434,15 +470,2 @@ pairElement && flags.push(!proofUsed); | ||
} | ||
getPairElement(idx, layer) { | ||
const pairIdx = idx % 2 === 0 ? idx + 1 : idx - 1; | ||
if (pairIdx < layer.length) { | ||
return layer[pairIdx]; | ||
} | ||
else { | ||
return null; | ||
} | ||
} | ||
// TODO: documentation | ||
getHexProof(leaf, index) { | ||
return this.getProof(leaf, index).map(x => this._bufferToHex(x.data)); | ||
} | ||
/** | ||
@@ -513,3 +536,22 @@ * verify | ||
} | ||
// TODO: documentation | ||
/** | ||
* verifyMultiProof | ||
* @desc Returns true if the multiproofs can connect the leaves to the Merkle root. | ||
* @param {Buffer} root - Merkle tree root | ||
* @param {Number[]} indices - Leave indices | ||
* @param {Buffer[]} leaves - Leaf values at indices. | ||
* @param {Number} depth - Tree depth | ||
* @param {Buffer[]} proof - Multiproofs given indices | ||
* @return {Boolean} | ||
* @example | ||
*```js | ||
*const root = tree.getRoot() | ||
*const treeFlat = tree.getLayersFlat() | ||
*const depth = tree.getDepth() | ||
*const indices = [2, 5, 6] | ||
*const proofLeaves = indices.map(i => leaves[i]) | ||
*const proof = tree.getMultiProof(treeFlat, indices) | ||
*const verified = tree.verifyMultiProof(root, indices, proofLeaves, depth, proof) | ||
*``` | ||
*/ | ||
verifyMultiProof(root, indices, leaves, depth, proof) { | ||
@@ -539,9 +581,24 @@ root = this._bufferify(root); | ||
} | ||
// TODO: documentation | ||
/** | ||
* getDepth | ||
* @desc Returns the tree depth (number of layers) | ||
* @return {Number} | ||
* @example | ||
*```js | ||
*const depth = tree.getDepth() | ||
*``` | ||
*/ | ||
getDepth() { | ||
return this.getLayers().length - 1; | ||
} | ||
// TODO: documentation | ||
/** | ||
* getLayersAsObject | ||
* @desc Returns the layers as nested objects instead of an array. | ||
* @example | ||
*```js | ||
*const layersObj = tree.getLayersAsObject() | ||
*``` | ||
*/ | ||
getLayersAsObject() { | ||
const layers = this.getLayers().map(x => x.map(x => x.toString('hex'))); | ||
const layers = this.getLayers().map((layer) => layer.map((value) => value.toString('hex'))); | ||
const objs = []; | ||
@@ -569,63 +626,236 @@ for (let i = 0; i < layers.length; i++) { | ||
} | ||
// TODO: documentation | ||
/** | ||
* @desc Prints out a visual representation of the merkle tree. | ||
* @example | ||
*```js | ||
*tree.print() | ||
*``` | ||
*/ | ||
print() { | ||
MerkleTree.print(this); | ||
} | ||
// TODO: documentation | ||
toTreeString() { | ||
/** | ||
* toTreeString | ||
* @desc Returns a visual representation of the merkle tree as a string. | ||
* @return {String} | ||
* @example | ||
*```js | ||
*console.log(tree.toTreeString()) | ||
*``` | ||
*/ | ||
_toTreeString() { | ||
const obj = this.getLayersAsObject(); | ||
return treeify_1.default.asTree(obj, true); | ||
} | ||
// TODO: documentation | ||
/** | ||
* toString | ||
* @desc Returns a visual representation of the merkle tree as a string. | ||
* @example | ||
*```js | ||
*console.log(tree.toString()) | ||
*``` | ||
*/ | ||
toString() { | ||
return this.toTreeString(); | ||
return this._toTreeString(); | ||
} | ||
// TODO: documentation | ||
static bufferify(x) { | ||
if (!Buffer.isBuffer(x)) { | ||
/** | ||
* getMultiProof | ||
* @desc Returns the multiproof for given tree indices. | ||
* @param {Buffer[]} tree - Tree as a flat array. | ||
* @param {Number[]} indices - Tree indices. | ||
* @return {Buffer[]} - Multiproofs | ||
* | ||
*@example | ||
* ```js | ||
*const flatTree = tree.getLayersFlat() | ||
*const indices = [2, 5, 6] | ||
*const proof = MerkleTree.getMultiProof(flatTree, indices) | ||
*``` | ||
*/ | ||
static getMultiProof(tree, indices) { | ||
const t = new MerkleTree([]); | ||
return t.getMultiProof(tree, indices); | ||
} | ||
/** | ||
* getPairNode | ||
* @desc Returns the node at the index for given layer. | ||
* @param {Buffer[]} layer - Tree layer | ||
* @param {Number} index - Index at layer. | ||
* @return {Buffer} - Node | ||
* | ||
*@example | ||
* ```js | ||
*const node = tree.getPairNode(layer, index) | ||
*``` | ||
*/ | ||
_getPairNode(layer, idx) { | ||
const pairIdx = idx % 2 === 0 ? idx + 1 : idx - 1; | ||
if (pairIdx < layer.length) { | ||
return layer[pairIdx]; | ||
} | ||
else { | ||
return null; | ||
} | ||
} | ||
/** | ||
* bufferIndexOf | ||
* @desc Returns the first index of which given buffer is found in array. | ||
* @param {Buffer[]} haystack - Array of buffers. | ||
* @param {Buffer} needle - Buffer to find. | ||
* @return {Number} - Index number | ||
* | ||
* @example | ||
* ```js | ||
*const index = tree.bufferIndexOf(haystack, needle) | ||
*``` | ||
*/ | ||
_bufferIndexOf(array, element) { | ||
for (let i = 0; i < array.length; i++) { | ||
if (element.equals(array[i])) { | ||
return i; | ||
} | ||
} | ||
return -1; | ||
} | ||
/** | ||
* bufferify | ||
* @desc Returns a buffer type for the given value. | ||
* @param {String|Number|Object|Buffer} value | ||
* @return {Buffer} | ||
* | ||
* @example | ||
* ```js | ||
*const buf = MerkleTree.bufferify('0x1234') | ||
*``` | ||
*/ | ||
static bufferify(value) { | ||
if (!Buffer.isBuffer(value)) { | ||
// crypto-js support | ||
if (typeof x === 'object' && x.words) { | ||
return Buffer.from(x.toString(crypto_js_1.default.enc.Hex), 'hex'); | ||
if (typeof value === 'object' && value.words) { | ||
return Buffer.from(value.toString(crypto_js_1.default.enc.Hex), 'hex'); | ||
} | ||
else if (MerkleTree.isHexStr(x)) { | ||
return Buffer.from(x.replace(/^0x/, ''), 'hex'); | ||
else if (MerkleTree.isHexString(value)) { | ||
return Buffer.from(value.replace(/^0x/, ''), 'hex'); | ||
} | ||
else if (typeof x === 'string') { | ||
return Buffer.from(x); | ||
else if (typeof value === 'string') { | ||
return Buffer.from(value); | ||
} | ||
} | ||
return x; | ||
return value; | ||
} | ||
static isHexStr(v) { | ||
/** | ||
* isHexString | ||
* @desc Returns true if value is a hex string. | ||
* @param {String} value | ||
* @return {Boolean} | ||
* | ||
* @example | ||
* ```js | ||
*console.log(MerkleTree.isHexString('0x1234')) | ||
*``` | ||
*/ | ||
static isHexString(v) { | ||
return (typeof v === 'string' && /^(0x)?[0-9A-Fa-f]*$/.test(v)); | ||
} | ||
// TODO: documentation | ||
/** | ||
* @desc Prints out a visual representation of the given merkle tree. | ||
* @param {Object} tree - Merkle tree instance. | ||
* @return {String} | ||
* @example | ||
*```js | ||
*MerkleTree.print(tree) | ||
*``` | ||
*/ | ||
static print(tree) { | ||
console.log(tree.toString()); | ||
} | ||
/** | ||
* bufferToHex | ||
* @desc Returns a hex string with 0x prefix for given buffer. | ||
* @param {Buffer} value | ||
* @return {String} | ||
* @example | ||
*```js | ||
*const hexStr = tree.bufferToHex(Buffer.from('A')) | ||
*``` | ||
*/ | ||
_bufferToHex(value) { | ||
return '0x' + value.toString('hex'); | ||
} | ||
_bufferify(x) { | ||
return MerkleTree.bufferify(x); | ||
/** | ||
* bufferify | ||
* @desc Returns a buffer type for the given value. | ||
* @param {String|Number|Object|Buffer} value | ||
* @return {Buffer} | ||
* | ||
* @example | ||
* ```js | ||
*const buf = MerkleTree.bufferify('0x1234') | ||
*``` | ||
*/ | ||
_bufferify(value) { | ||
return MerkleTree.bufferify(value); | ||
} | ||
/** | ||
* bufferifyFn | ||
* @desc Returns a function that will bufferify the return value. | ||
* @param {Function} | ||
* @return {Function} | ||
* | ||
* @example | ||
* ```js | ||
*const fn = tree.bufferifyFn((value) => sha256(value)) | ||
*``` | ||
*/ | ||
_bufferifyFn(f) { | ||
return function (x) { | ||
const v = f(x); | ||
return function (value) { | ||
const v = f(value); | ||
if (Buffer.isBuffer(v)) { | ||
return v; | ||
} | ||
if (this._isHexStr(v)) { | ||
if (this._isHexString(v)) { | ||
return Buffer.from(v, 'hex'); | ||
} | ||
// crypto-js support | ||
return Buffer.from(f(crypto_js_1.default.enc.Hex.parse(x.toString('hex'))).toString(crypto_js_1.default.enc.Hex), 'hex'); | ||
return Buffer.from(f(crypto_js_1.default.enc.Hex.parse(value.toString('hex'))).toString(crypto_js_1.default.enc.Hex), 'hex'); | ||
}; | ||
} | ||
_isHexStr(v) { | ||
return MerkleTree.isHexStr(v); | ||
/** | ||
* isHexString | ||
* @desc Returns true if value is a hex string. | ||
* @param {String} value | ||
* @return {Boolean} | ||
* | ||
* @example | ||
* ```js | ||
*console.log(MerkleTree.isHexString('0x1234')) | ||
*``` | ||
*/ | ||
_isHexString(value) { | ||
return MerkleTree.isHexString(value); | ||
} | ||
_log2(x) { | ||
return x === 1 ? 0 : 1 + this._log2((x / 2) | 0); | ||
/** | ||
* log2 | ||
* @desc Returns the log2 of number. | ||
* @param {Number} value | ||
* @return {Number} | ||
*/ | ||
_log2(n) { | ||
return n === 1 ? 0 : 1 + this._log2((n / 2) | 0); | ||
} | ||
/** | ||
* zip | ||
* @desc Returns true if value is a hex string. | ||
* @param {String[]|Number[]|Buffer[]} a - first array | ||
* @param {String[]|Number[]|Buffer[]} b - second array | ||
* @return {String[][]|Number[][]|Buffer[][]} | ||
* | ||
* @example | ||
* ```js | ||
*const zipped = tree.zip(['a', 'b'],['A', 'B']) | ||
*console.log(zipped) // [ [ 'a', 'A' ], [ 'b', 'B' ] ] | ||
*``` | ||
*/ | ||
_zip(a, b) { | ||
@@ -632,0 +862,0 @@ return a.map((e, i) => [e, b[i]]); |
{ | ||
"name": "merkletreejs", | ||
"version": "0.2.1", | ||
"version": "0.2.2", | ||
"description": "Construct Merkle Trees and verify proofs", | ||
@@ -14,3 +14,3 @@ "main": "dist/index.js", | ||
"lint": "standardx --fix index.ts test/*.js", | ||
"docs:md": "rm -rf docs/ && typedoc --theme markdown index.ts --out docs --mdEngine github --mdDocusaurus --mdHideSources" | ||
"docs": "rm -rf docs/ && typedoc --plugin typedoc-plugin-markdown -hideSources --theme markdown --hideGenerator --excludeExternals --excludePrivate --out docs index.ts" | ||
}, | ||
@@ -54,4 +54,4 @@ "repository": { | ||
"tape": "^4.9.2", | ||
"typedoc": "^0.14.2", | ||
"typedoc-plugin-markdown": "^1.2.1", | ||
"typedoc": "^0.17.7", | ||
"typedoc-plugin-markdown": "^2.3.1", | ||
"typescript": "^3.4.1" | ||
@@ -77,4 +77,6 @@ }, | ||
"parser": "@typescript-eslint/parser", | ||
"plugins": [ "@typescript-eslint/eslint-plugin" ] | ||
"plugins": [ | ||
"@typescript-eslint/eslint-plugin" | ||
] | ||
} | ||
} |
685
README.md
<h3 align="center"> | ||
<br /> | ||
<img src="https://user-images.githubusercontent.com/168240/39508295-ceeb1576-4d96-11e8-90aa-b2a56825567d.png" alt="logo" width="600" /> | ||
<img src="https://user-images.githubusercontent.com/168240/83951171-85f48c80-a7e4-11ea-896e-529c28ffa18e.png" alt="merkletree.js logo" width="600" /> | ||
<br /> | ||
@@ -21,5 +21,5 @@ <br /> | ||
- [Diagrams](#diagrams) | ||
- [Install](#install) | ||
- [Getting started](#Getting-started) | ||
- [Diagrams](#diagrams) | ||
- [Documentation](#documentation) | ||
@@ -33,20 +33,2 @@ - [Test](#test) | ||
## Diagrams | ||
Diagram of Merkle Tree | ||
<img src="https://user-images.githubusercontent.com/168240/43616375-15330c32-9671-11e8-9057-6e61c312c856.png" alt="Merkle Tree" width="500"> | ||
Diagram of Merkle Tree Proof | ||
<img src="https://user-images.githubusercontent.com/168240/43616387-27ec860a-9671-11e8-9f3f-0b871a6581a6.png" alt="Merkle Tree Proof" width="420"> | ||
Diagram of Invalid Merkle Tree Proofs | ||
<img src="https://user-images.githubusercontent.com/168240/43616398-33e20584-9671-11e8-9f62-9f48ce412898.png" alt="Merkle Tree Proof" width="420"> | ||
Diagram of Bitcoin Merkle Tree | ||
<img src="https://user-images.githubusercontent.com/168240/43616417-46d3293e-9671-11e8-81c3-8cdf7f8ddd77.png" alt="Merkle Tree Proof" width="420"> | ||
## Install | ||
@@ -98,2 +80,20 @@ | ||
## Diagrams | ||
▾ Visualization of Merkle Tree | ||
<img src="https://user-images.githubusercontent.com/168240/43616375-15330c32-9671-11e8-9057-6e61c312c856.png" alt="Merkle Tree" width="500"> | ||
▾ Visualization of Merkle Tree Proof | ||
<img src="https://user-images.githubusercontent.com/168240/43616387-27ec860a-9671-11e8-9f3f-0b871a6581a6.png" alt="Merkle Tree Proof" width="420"> | ||
▾ Visualization of Invalid Merkle Tree Proofs | ||
<img src="https://user-images.githubusercontent.com/168240/43616398-33e20584-9671-11e8-9f62-9f48ce412898.png" alt="Merkle Tree Proof" width="420"> | ||
▾ Visualization of Bitcoin Merkle Tree | ||
<img src="https://user-images.githubusercontent.com/168240/43616417-46d3293e-9671-11e8-81c3-8cdf7f8ddd77.png" alt="Merkle Tree Proof" width="420"> | ||
## Documentation | ||
@@ -104,57 +104,59 @@ | ||
## Class | ||
<!-- BEGIN DOCUMENTATION --> | ||
# Class: MerkleTree | ||
Class reprensenting a Merkle Tree | ||
*__namespace__*: MerkleTree | ||
**`namespace`** MerkleTree | ||
## Hierarchy | ||
**MerkleTree** | ||
* **MerkleTree** | ||
## Index | ||
### Constructors | ||
* [constructor](#constructor) | ||
* [constructor](_index_.merkletree.md#constructor) | ||
### Properties | ||
* [duplicateOdd](#duplicateodd) | ||
* [hashAlgo](#hashalgo) | ||
* [hashLeaves](#hashleaves) | ||
* [isBitcoinTree](#isbitcointree) | ||
* [layers](#layers) | ||
* [leaves](#leaves) | ||
* [sort](#sort) | ||
* [sortLeaves](#sortleaves) | ||
* [sortPairs](#sortpairs) | ||
### Methods | ||
* [createHashes](#createhashes) | ||
* [getLayers](#getlayers) | ||
* [getLayersAsObject](#getlayersasobject) | ||
* [getLeaves](#getleaves) | ||
* [getProof](#getproof) | ||
* [getRoot](#getroot) | ||
* [print](#print) | ||
* [toString](#tostring) | ||
* [toTreeString](#totreestring) | ||
* [verify](#verify) | ||
* [bufferify](#bufferify) | ||
* [print](#print-1) | ||
* [getDepth](_index_.merkletree.md#getdepth) | ||
* [getHexLayers](_index_.merkletree.md#gethexlayers) | ||
* [getHexLayersFlat](_index_.merkletree.md#gethexlayersflat) | ||
* [getHexLeaves](_index_.merkletree.md#gethexleaves) | ||
* [getHexMultiProof](_index_.merkletree.md#gethexmultiproof) | ||
* [getHexProof](_index_.merkletree.md#gethexproof) | ||
* [getHexRoot](_index_.merkletree.md#gethexroot) | ||
* [getLayers](_index_.merkletree.md#getlayers) | ||
* [getLayersAsObject](_index_.merkletree.md#getlayersasobject) | ||
* [getLayersFlat](_index_.merkletree.md#getlayersflat) | ||
* [getLeaves](_index_.merkletree.md#getleaves) | ||
* [getMultiProof](_index_.merkletree.md#getmultiproof) | ||
* [getProof](_index_.merkletree.md#getproof) | ||
* [getProofFlags](_index_.merkletree.md#getproofflags) | ||
* [getProofIndices](_index_.merkletree.md#getproofindices) | ||
* [getRoot](_index_.merkletree.md#getroot) | ||
* [print](_index_.merkletree.md#print) | ||
* [toString](_index_.merkletree.md#tostring) | ||
* [verify](_index_.merkletree.md#verify) | ||
* [verifyMultiProof](_index_.merkletree.md#verifymultiproof) | ||
* [bufferify](_index_.merkletree.md#static-bufferify) | ||
* [getMultiProof](_index_.merkletree.md#static-getmultiproof) | ||
* [isHexString](_index_.merkletree.md#static-ishexstring) | ||
* [print](_index_.merkletree.md#static-print) | ||
--- | ||
## Constructors | ||
<a id="constructor"></a> | ||
### constructor | ||
⊕ **new MerkleTree**(leaves: *`any`*, hashAlgorithm: *`any`*, options?: *[Options]() | ||
\+ **new MerkleTree**(`leaves`: any[], `hashAlgorithm`: any, `options`: [Options](#options)): *[MerkleTree](_index_.merkletree.md)* | ||
*__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. | ||
**`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. | ||
*__example__*: | ||
```js | ||
**`example`** | ||
```js | ||
const MerkleTree = require('merkletreejs') | ||
@@ -175,161 +177,266 @@ const crypto = require('crypto') | ||
| Name | Type | Default value | Description | | ||
| ------ | ------ | ------ | ------ | | ||
| leaves | `any` | - | Array of hashed leaves. Each leaf must be a Buffer. | | ||
| hashAlgorithm | `any` | - | Algorithm used for hashing leaves and nodes | | ||
| `Default value` options | [Options]() | {} as any | Additional options | | ||
Name | Type | Default | Description | | ||
------ | ------ | ------ | ------ | | ||
`leaves` | any[] | - | Array of hashed leaves. Each leaf must be a Buffer. | | ||
`hashAlgorithm` | any | SHA256 | Algorithm used for hashing leaves and nodes | | ||
`options` | [Options](../interfaces/_index_.options.md) | {} | Additional options | | ||
**Returns:** [MerkleTree]() | ||
**Returns:** *[MerkleTree](_index_.merkletree.md)* | ||
___ | ||
## Methods | ||
## Properties | ||
### getDepth | ||
<a id="duplicateodd"></a> | ||
▸ **getDepth**(): *number* | ||
### duplicateOdd | ||
getDepth | ||
**● duplicateOdd**: *`boolean`* | ||
**`desc`** Returns the tree depth (number of layers) | ||
**`example`** | ||
```js | ||
const depth = tree.getDepth() | ||
``` | ||
**Returns:** *number* | ||
___ | ||
<a id="hashalgo"></a> | ||
### hashAlgo | ||
### getHexLayers | ||
**● hashAlgo**: *`function`* | ||
▸ **getHexLayers**(): *string[]* | ||
#### Type declaration | ||
▸(value: *`any`*): `any` | ||
getHexLayers | ||
**Parameters:** | ||
**`desc`** Returns multi-dimensional array of all layers of Merkle Tree, including leaves and root as hex strings. | ||
| Name | Type | | ||
| ------ | ------ | | ||
| value | `any` | | ||
**`example`** | ||
```js | ||
const layers = tree.getHexLayers() | ||
``` | ||
**Returns:** `any` | ||
**Returns:** *string[]* | ||
___ | ||
<a id="hashleaves"></a> | ||
### hashLeaves | ||
### getHexLayersFlat | ||
**● hashLeaves**: *`boolean`* | ||
▸ **getHexLayersFlat**(): *string[]* | ||
___ | ||
<a id="isbitcointree"></a> | ||
getHexLayersFlat | ||
### isBitcoinTree | ||
**`desc`** Returns single flat array of all layers of Merkle Tree, including leaves and root as hex string. | ||
**● isBitcoinTree**: *`boolean`* | ||
**`example`** | ||
```js | ||
const layers = tree.getHexLayersFlat() | ||
``` | ||
**Returns:** *string[]* | ||
___ | ||
<a id="layers"></a> | ||
### layers | ||
### getHexLeaves | ||
**● layers**: *`any`[]* | ||
▸ **getHexLeaves**(): *string[]* | ||
___ | ||
<a id="leaves"></a> | ||
getHexLeaves | ||
### leaves | ||
**`desc`** Returns array of leaves of Merkle Tree as hex strings. | ||
**● leaves**: *`any`[]* | ||
**`example`** | ||
```js | ||
const leaves = tree.getHexLeaves() | ||
``` | ||
**Returns:** *string[]* | ||
___ | ||
<a id="sortleaves"></a> | ||
### sortLeaves | ||
### getHexMultiProof | ||
**● sortLeaves**: *`boolean`* | ||
▸ **getHexMultiProof**(`tree`: Buffer[], `indices`: number[]): *string[]* | ||
___ | ||
<a id="sortpairs"></a> | ||
getHexMultiProof | ||
### sortPairs | ||
**`desc`** Returns the multiproof for given tree indices as hex strings. | ||
**● sortPairs**: *`boolean`* | ||
**`example`** | ||
```js | ||
const indices = [2, 5, 6] | ||
const proof = tree.getHexMultiProof(indices) | ||
``` | ||
**Parameters:** | ||
Name | Type | Description | | ||
------ | ------ | ------ | | ||
`tree` | Buffer[] | - | | ||
`indices` | number[] | Tree indices. | | ||
**Returns:** *string[]* | ||
- Multiproofs as hex strings. | ||
___ | ||
## Methods | ||
### getHexProof | ||
<a id="createhashes"></a> | ||
▸ **getHexProof**(`leaf`: Buffer, `index?`: number): *string[]* | ||
### createHashes | ||
getHexProof | ||
▸ **createHashes**(nodes: *`any`*): `void` | ||
**`desc`** Returns the proof for a target leaf as hex strings. | ||
**`example`** | ||
```js | ||
const proof = tree.getHexProof(leaves[2]) | ||
``` | ||
**Parameters:** | ||
| Name | Type | | ||
| ------ | ------ | | ||
| nodes | `any` | | ||
Name | Type | Description | | ||
------ | ------ | ------ | | ||
`leaf` | Buffer | Target leaf | | ||
`index?` | number | - | | ||
**Returns:** `void` | ||
**Returns:** *string[]* | ||
- Proof array as hex strings. | ||
___ | ||
<a id="getlayers"></a> | ||
### getHexRoot | ||
▸ **getHexRoot**(): *string* | ||
getHexRoot | ||
**`desc`** Returns the Merkle root hash as a hex string. | ||
**`example`** | ||
```js | ||
const root = tree.getHexRoot() | ||
``` | ||
**Returns:** *string* | ||
___ | ||
### getLayers | ||
▸ **getLayers**(): `any`[] | ||
▸ **getLayers**(): *Buffer[]* | ||
getLayers | ||
*__desc__*: Returns array of all layers of Merkle Tree, including leaves and root. | ||
**`desc`** Returns multi-dimensional array of all layers of Merkle Tree, including leaves and root. | ||
*__example__*: | ||
```js | ||
**`example`** | ||
```js | ||
const layers = tree.getLayers() | ||
``` | ||
**Returns:** `any`[] | ||
**Returns:** *Buffer[]* | ||
___ | ||
<a id="getlayersasobject"></a> | ||
### getLayersAsObject | ||
▸ **getLayersAsObject**(): `any` | ||
▸ **getLayersAsObject**(): *any* | ||
**Returns:** `any` | ||
getLayersAsObject | ||
**`desc`** Returns the layers as nested objects instead of an array. | ||
**`example`** | ||
```js | ||
const layersObj = tree.getLayersAsObject() | ||
``` | ||
**Returns:** *any* | ||
___ | ||
<a id="getleaves"></a> | ||
### getLayersFlat | ||
▸ **getLayersFlat**(): *Buffer[]* | ||
getLayersFlat | ||
**`desc`** Returns single flat array of all layers of Merkle Tree, including leaves and root. | ||
**`example`** | ||
```js | ||
const layers = tree.getLayersFlat() | ||
``` | ||
**Returns:** *Buffer[]* | ||
___ | ||
### getLeaves | ||
▸ **getLeaves**(): `any`[] | ||
▸ **getLeaves**(`values?`: any[]): *Buffer[]* | ||
getLeaves | ||
*__desc__*: Returns array of leaves of Merkle Tree. | ||
**`desc`** Returns array of leaves of Merkle Tree. | ||
*__example__*: | ||
```js | ||
**`example`** | ||
```js | ||
const leaves = tree.getLeaves() | ||
``` | ||
**Returns:** `any`[] | ||
**Parameters:** | ||
Name | Type | | ||
------ | ------ | | ||
`values?` | any[] | | ||
**Returns:** *Buffer[]* | ||
___ | ||
<a id="getproof"></a> | ||
### getMultiProof | ||
▸ **getMultiProof**(`tree?`: any[], `indices?`: any[]): *Buffer[]* | ||
getMultiProof | ||
**`desc`** Returns the multiproof for given tree indices. | ||
**`example`** | ||
```js | ||
const indices = [2, 5, 6] | ||
const proof = tree.getMultiProof(indices) | ||
``` | ||
**Parameters:** | ||
Name | Type | Description | | ||
------ | ------ | ------ | | ||
`tree?` | any[] | - | | ||
`indices?` | any[] | Tree indices. | | ||
**Returns:** *Buffer[]* | ||
- Multiproofs | ||
___ | ||
### getProof | ||
▸ **getProof**(leaf: *`any`*, index?: *`any`*): `any`[] | ||
▸ **getProof**(`leaf`: Buffer, `index?`: number): *any[]* | ||
getProof | ||
*__desc__*: Returns the proof for a target leaf. | ||
**`desc`** Returns the proof for a target leaf. | ||
*__example__*: | ||
```js | ||
**`example`** | ||
```js | ||
const proof = tree.getProof(leaves[2]) | ||
``` | ||
*__example__*: | ||
```js | ||
**`example`** | ||
```js | ||
const leaves = ['a', 'b', 'a'].map(x => keccak(x)) | ||
@@ -342,68 +449,132 @@ const tree = new MerkleTree(leaves, keccak) | ||
| Name | Type | Description | | ||
| ------ | ------ | ------ | | ||
| leaf | `any` | Target leaf | | ||
| `Optional` index | `any` | | ||
Name | Type | Description | | ||
------ | ------ | ------ | | ||
`leaf` | Buffer | Target leaf | | ||
`index?` | number | - | | ||
**Returns:** `any`[] | ||
* Array of objects containing a position property of type string with values of 'left' or 'right' and a data property of type Buffer. | ||
**Returns:** *any[]* | ||
- Array of objects containing a position property of type string | ||
with values of 'left' or 'right' and a data property of type Buffer. | ||
___ | ||
<a id="getroot"></a> | ||
### getProofFlags | ||
▸ **getProofFlags**(`leaves`: Buffer[], `proofs`: Buffer[]): *boolean[]* | ||
getProofFlags | ||
**`desc`** Returns list of booleans where proofs should be used instead of hashing. | ||
Proof flags are used in the Solidity multiproof verifiers. | ||
**`example`** | ||
```js | ||
const indices = [2, 5, 6] | ||
const proof = tree.getMultiProof(indices) | ||
const proofFlags = tree.getProofFlags(leaves, proof) | ||
``` | ||
**Parameters:** | ||
Name | Type | | ||
------ | ------ | | ||
`leaves` | Buffer[] | | ||
`proofs` | Buffer[] | | ||
**Returns:** *boolean[]* | ||
- Boolean flags | ||
___ | ||
### getProofIndices | ||
▸ **getProofIndices**(`treeIndices`: number[], `depth`: number): *number[]* | ||
getProofIndices | ||
**`desc`** Returns the proof indices for given tree indices. | ||
**`example`** | ||
```js | ||
const proofIndices = tree.getProofIndices([2,5,6], 4) | ||
console.log(proofIndices) // [ 23, 20, 19, 8, 3 ] | ||
``` | ||
**Parameters:** | ||
Name | Type | Description | | ||
------ | ------ | ------ | | ||
`treeIndices` | number[] | Tree indices | | ||
`depth` | number | Tree depth; number of layers. | | ||
**Returns:** *number[]* | ||
- Proof indices | ||
___ | ||
### getRoot | ||
▸ **getRoot**(): `any` | ||
▸ **getRoot**(): *Buffer* | ||
getRoot | ||
*__desc__*: Returns the Merkle root hash as a Buffer. | ||
**`desc`** Returns the Merkle root hash as a Buffer. | ||
*__example__*: | ||
```js | ||
**`example`** | ||
```js | ||
const root = tree.getRoot() | ||
``` | ||
**Returns:** `any` | ||
**Returns:** *Buffer* | ||
___ | ||
<a id="print"></a> | ||
▸ **print**(): `void` | ||
▸ **print**(): *void* | ||
**Returns:** `void` | ||
**`desc`** Prints out a visual representation of the merkle tree. | ||
**`example`** | ||
```js | ||
tree.print() | ||
``` | ||
**Returns:** *void* | ||
___ | ||
<a id="tostring"></a> | ||
### toString | ||
▸ **toString**(): `any` | ||
▸ **toString**(): *string* | ||
**Returns:** `any` | ||
toString | ||
___ | ||
<a id="totreestring"></a> | ||
**`desc`** Returns a visual representation of the merkle tree as a string. | ||
### toTreeString | ||
**`example`** | ||
```js | ||
console.log(tree.toString()) | ||
``` | ||
▸ **toTreeString**(): `any` | ||
**Returns:** *string* | ||
**Returns:** `any` | ||
___ | ||
<a id="verify"></a> | ||
### verify | ||
▸ **verify**(proof: *`any`*, targetNode: *`any`*, root: *`any`*): `boolean` | ||
▸ **verify**(`proof`: any[], `targetNode`: Buffer, `root`: Buffer): *boolean* | ||
verify | ||
*__desc__*: Returns true if the proof path (array of hashes) can connect the target node to the Merkle root. | ||
**`desc`** Returns true if the proof path (array of hashes) can connect the target node | ||
to the Merkle root. | ||
*__example__*: | ||
```js | ||
**`example`** | ||
```js | ||
const root = tree.getRoot() | ||
@@ -416,71 +587,170 @@ const proof = tree.getProof(leaves[2]) | ||
| Name | Type | Description | | ||
| ------ | ------ | ------ | | ||
| proof | `any` | Array of proof objects that should connect target node to Merkle root. | | ||
| targetNode | `any` | Target node Buffer | | ||
| root | `any` | Merkle root Buffer | | ||
Name | Type | Description | | ||
------ | ------ | ------ | | ||
`proof` | any[] | Array of proof objects that should connect target node to Merkle root. | | ||
`targetNode` | Buffer | Target node Buffer | | ||
`root` | Buffer | Merkle root Buffer | | ||
**Returns:** `boolean` | ||
**Returns:** *boolean* | ||
___ | ||
<a id="bufferify"></a> | ||
### `<Static>` bufferify | ||
### verifyMultiProof | ||
▸ **bufferify**(x: *`any`*): `any` | ||
▸ **verifyMultiProof**(`root`: Buffer, `indices`: number[], `leaves`: Buffer[], `depth`: number, `proof`: Buffer[]): *boolean* | ||
verifyMultiProof | ||
**`desc`** Returns true if the multiproofs can connect the leaves to the Merkle root. | ||
**`example`** | ||
```js | ||
const root = tree.getRoot() | ||
const treeFlat = tree.getLayersFlat() | ||
const depth = tree.getDepth() | ||
const indices = [2, 5, 6] | ||
const proofLeaves = indices.map(i => leaves[i]) | ||
const proof = tree.getMultiProof(treeFlat, indices) | ||
const verified = tree.verifyMultiProof(root, indices, proofLeaves, depth, proof) | ||
``` | ||
**Parameters:** | ||
| Name | Type | | ||
| ------ | ------ | | ||
| x | `any` | | ||
Name | Type | Description | | ||
------ | ------ | ------ | | ||
`root` | Buffer | Merkle tree root | | ||
`indices` | number[] | Leave indices | | ||
`leaves` | Buffer[] | Leaf values at indices. | | ||
`depth` | number | Tree depth | | ||
`proof` | Buffer[] | Multiproofs given indices | | ||
**Returns:** `any` | ||
**Returns:** *boolean* | ||
___ | ||
<a id="print-1"></a> | ||
### `<Static>` print | ||
### `Static` bufferify | ||
▸ **print**(tree: *`any`*): `void` | ||
▸ **bufferify**(`value`: any): *Buffer* | ||
bufferify | ||
**`desc`** Returns a buffer type for the given value. | ||
**`example`** | ||
```js | ||
const buf = MerkleTree.bufferify('0x1234') | ||
``` | ||
**Parameters:** | ||
| Name | Type | | ||
| ------ | ------ | | ||
| tree | `any` | | ||
Name | Type | | ||
------ | ------ | | ||
`value` | any | | ||
**Returns:** `void` | ||
**Returns:** *Buffer* | ||
## Interface | ||
___ | ||
## Options | ||
### `Static` getMultiProof | ||
▸ **getMultiProof**(`tree`: Buffer[], `indices`: number[]): *Buffer[]* | ||
getMultiProof | ||
**`desc`** Returns the multiproof for given tree indices. | ||
**`example`** | ||
```js | ||
const flatTree = tree.getLayersFlat() | ||
const indices = [2, 5, 6] | ||
const proof = MerkleTree.getMultiProof(flatTree, indices) | ||
``` | ||
**Parameters:** | ||
Name | Type | Description | | ||
------ | ------ | ------ | | ||
`tree` | Buffer[] | Tree as a flat array. | | ||
`indices` | number[] | Tree indices. | | ||
**Returns:** *Buffer[]* | ||
- Multiproofs | ||
___ | ||
### `Static` isHexString | ||
▸ **isHexString**(`v`: string): *boolean* | ||
isHexString | ||
**`desc`** Returns true if value is a hex string. | ||
**`example`** | ||
```js | ||
console.log(MerkleTree.isHexString('0x1234')) | ||
``` | ||
**Parameters:** | ||
Name | Type | | ||
------ | ------ | | ||
`v` | string | | ||
**Returns:** *boolean* | ||
___ | ||
### `Static` print | ||
▸ **print**(`tree`: any): *void* | ||
**`desc`** Prints out a visual representation of the given merkle tree. | ||
**`example`** | ||
```js | ||
MerkleTree.print(tree) | ||
``` | ||
**Parameters:** | ||
Name | Type | Description | | ||
------ | ------ | ------ | | ||
`tree` | any | Merkle tree instance. | | ||
**Returns:** *void* | ||
# Interface: Options | ||
## Hierarchy | ||
* **Options** | ||
## Index | ||
### Properties | ||
* [duplicateOdd](#duplicateodd) | ||
* [hashLeaves](#hashleaves) | ||
* [isBitcoinTree](#isbitcointree) | ||
* [sort](#sort) | ||
* [sortLeaves](#sortleaves) | ||
* [sortPairs](#sortpairs) | ||
* [duplicateOdd](_index_.options.md#optional-duplicateodd) | ||
* [hashLeaves](_index_.options.md#optional-hashleaves) | ||
* [isBitcoinTree](_index_.options.md#optional-isbitcointree) | ||
* [sort](_index_.options.md#optional-sort) | ||
* [sortLeaves](_index_.options.md#optional-sortleaves) | ||
* [sortPairs](_index_.options.md#optional-sortpairs) | ||
--- | ||
## Properties | ||
<a id="duplicateodd"></a> | ||
### `Optional` duplicateOdd | ||
### duplicateOdd | ||
• **duplicateOdd**? : *boolean* | ||
**● duplicateOdd**: *`boolean`* | ||
If set to `true`, an odd node will be duplicated and combined to make a pair to generate the layer hash. | ||
___ | ||
<a id="hashleaves"></a> | ||
### hashLeaves | ||
### `Optional` hashLeaves | ||
**● hashLeaves**: *`boolean`* | ||
• **hashLeaves**? : *boolean* | ||
@@ -490,7 +760,6 @@ If set to `true`, the leaves will hashed using the set hashing algorithms. | ||
___ | ||
<a id="isbitcointree"></a> | ||
### isBitcoinTree | ||
### `Optional` isBitcoinTree | ||
**● isBitcoinTree**: *`boolean`* | ||
• **isBitcoinTree**? : *boolean* | ||
@@ -500,25 +769,27 @@ If set to `true`, constructs the Merkle Tree using the [Bitcoin Merkle Tree implementation](http://www.righto.com/2014/02/bitcoin-mining-hard-way-algorithms.html). Enable it when you need to replicate Bitcoin constructed Merkle Trees. In Bitcoin Merkle Trees, single nodes are combined with themselves, and each output hash is hashed again. | ||
___ | ||
<a id="sortleaves"></a> | ||
### sort | ||
### `Optional` sort | ||
**● sort**: *`boolean`* | ||
• **sort**? : *boolean* | ||
If set to `true`, the leaves and hashing pairs will be sorted. | ||
### sortLeaves | ||
___ | ||
**● sortLeaves**: *`boolean`* | ||
### `Optional` sortLeaves | ||
• **sortLeaves**? : *boolean* | ||
If set to `true`, the leaves will be sorted. | ||
___ | ||
<a id="sortpairs"></a> | ||
### sortPairs | ||
### `Optional` sortPairs | ||
**● sortPairs**: *`boolean`* | ||
• **sortPairs**? : *boolean* | ||
If set to `true`, the hashing pairs will be sorted. | ||
<!-- END DOCUMENTATION --> | ||
## Test | ||
@@ -564,2 +835,6 @@ | ||
- [Compact Merkle Multiproofs](https://arxiv.org/pdf/2002.07648.pdf) | ||
- [Eth 2.0 specs - Merkle Multiproofs](https://github.com/ethereum/eth2.0-specs/blob/dev/ssz/merkle-proofs.md#merkle-multiproofs) | ||
## Contributing | ||
@@ -566,0 +841,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
63726
1299
839