merkletreejs
Version:
Construct Merkle Trees and verify proofs
571 lines (570 loc) • 19.1 kB
TypeScript
/// <reference types="node" />
import Base from './Base';
declare type TValue = Buffer | BigInt | string | number | null | undefined;
declare type THashFnResult = Buffer | string;
declare type THashFn = (value: TValue) => Buffer;
declare type TLeaf = Buffer;
declare type TFillDefaultHash = (idx?: number, hashFn?: THashFn) => THashFnResult;
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;
/** If set to `true`, the leaves will hashed using the set hashing algorithms. */
hashLeaves?: boolean;
/** 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. */
isBitcoinTree?: boolean;
/** If set to `true`, the leaves will be sorted. Recommended for use of multiProofs. */
sortLeaves?: boolean;
/** If set to `true`, the hashing pairs will be sorted. */
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 | Buffer | string;
/** If set to `true`, the resulting tree will be a complete tree. Recommended for use of multiProofs. */
complete?: boolean;
concatenator?: (inputs: Buffer[]) => Buffer | Buffer[] | BigInt[];
}
/**
* Class reprensenting a Merkle Tree
* @namespace MerkleTree
*/
export declare class MerkleTree extends Base {
private duplicateOdd;
private hashFn;
private concatenator;
private hashLeaves;
private isBitcoinTree;
private leaves;
private layers;
private sortLeaves;
private sortPairs;
private sort;
private fillDefaultHash;
private complete;
/**
* @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} hashFunction - Hash function to use for hashing leaves and nodes
* @param {Object} options - Additional options
* @example
*```js
*const MerkleTree = require('merkletreejs')
*const crypto = require('crypto')
*
*function sha256(data) {
* // returns Buffer
* return crypto.createHash('sha256').update(data).digest()
*}
*
*const leaves = ['a', 'b', 'c'].map(value => keccak(value))
*
*const tree = new MerkleTree(leaves, sha256)
*```
*/
constructor(leaves: any[], hashFn?: any, options?: Options);
getOptions(): {
complete: boolean;
isBitcoinTree: boolean;
hashLeaves: boolean;
sortLeaves: boolean;
sortPairs: boolean;
sort: boolean;
fillDefaultHash: string;
duplicateOdd: boolean;
};
private processLeaves;
private createHashes;
/**
* addLeaf
* @desc Adds a leaf to the tree and re-calculates layers.
* @param {String|Buffer} - Leaf
* @param {Boolean} - Set to true if the leaf should be hashed before being added to tree.
* @example
*```js
*tree.addLeaf(newLeaf)
*```
*/
addLeaf(leaf: TLeaf, shouldHash?: boolean): void;
/**
* addLeaves
* @desc Adds multiple leaves to the tree and re-calculates layers.
* @param {String[]|Buffer[]} - Array of leaves
* @param {Boolean} - Set to true if the leaves should be hashed before being added to tree.
* @example
*```js
*tree.addLeaves(newLeaves)
*```
*/
addLeaves(leaves: TLeaf[], shouldHash?: boolean): void;
/**
* getLeaves
* @desc Returns array of leaves of Merkle Tree.
* @return {Buffer[]}
* @example
*```js
*const leaves = tree.getLeaves()
*```
*/
getLeaves(values?: any[]): Buffer[];
removeLeaf(index: number): Buffer;
updateLeaf(index: number, value: Buffer, shouldHash?: boolean): void;
/**
* getLeaf
* @desc Returns the leaf at the given index.
* @param {Number} - Index number
* @return {Buffer}
* @example
*```js
*const leaf = tree.getLeaf(1)
*```
*/
getLeaf(index: number): Buffer;
/**
* getHexLeaf
* @desc Returns the leaf at the given index as a hex string.
* @param {Number} - Index number
* @return {String}
* @example
*```js
*const leaf = tree.getHexLeaf(1)
*```
*/
getHexLeaf(index: number): string;
/**
* getLeafIndex
* @desc Returns the index of the given leaf, or -1 if the leaf is not found.
* @param {String|Buffer} - Target leaf
* @return {number}
* @example
*```js
*const leaf = Buffer.from('abc')
*const index = tree.getLeafIndex(leaf)
*```
*/
getLeafIndex(target: TLeaf): number;
/**
* getLeafCount
* @desc Returns the total number of leaves.
* @return {number}
* @example
*```js
*const count = tree.getLeafCount()
*```
*/
getLeafCount(): number;
/**
* getHexLeaves
* @desc Returns array of leaves of Merkle Tree as hex strings.
* @return {String[]}
* @example
*```js
*const leaves = tree.getHexLeaves()
*```
*/
getHexLeaves(): string[];
/**
* marshalLeaves
* @desc Returns array of leaves of Merkle Tree as a JSON string.
* @param {String[]|Buffer[]} - Merkle tree leaves
* @return {String} - List of leaves as JSON string
* @example
*```js
*const jsonStr = MerkleTree.marshalLeaves(leaves)
*```
*/
static marshalLeaves(leaves: any[]): string;
/**
* unmarshalLeaves
* @desc Returns array of leaves of Merkle Tree as a Buffers.
* @param {String|Object} - JSON stringified leaves
* @return {Buffer[]} - Unmarshalled list of leaves
* @example
*```js
*const leaves = MerkleTree.unmarshalLeaves(jsonStr)
*```
*/
static unmarshalLeaves(jsonStr: string | object): Buffer[];
/**
* getLayers
* @desc Returns multi-dimensional array of all layers of Merkle Tree, including leaves and root.
* @return {Buffer[][]}
* @example
*```js
*const layers = tree.getLayers()
*```
*/
getLayers(): Buffer[][];
/**
* getHexLayers
* @desc Returns multi-dimensional array of all layers of Merkle Tree, including leaves and root as hex strings.
* @return {String[][]}
* @example
*```js
*const layers = tree.getHexLayers()
*```
*/
getHexLayers(): string[][];
/**
* getLayersFlat
* @desc Returns single flat array of all layers of Merkle Tree, including leaves and root.
* @return {Buffer[]}
* @example
*```js
*const layers = tree.getLayersFlat()
*```
*/
getLayersFlat(): Buffer[];
/**
* getHexLayersFlat
* @desc Returns single flat array of all layers of Merkle Tree, including leaves and root as hex string.
* @return {String[]}
* @example
*```js
*const layers = tree.getHexLayersFlat()
*```
*/
getHexLayersFlat(): string[];
/**
* getLayerCount
* @desc Returns the total number of layers.
* @return {number}
* @example
*```js
*const count = tree.getLayerCount()
*```
*/
getLayerCount(): number;
/**
* getRoot
* @desc Returns the Merkle root hash as a Buffer.
* @return {Buffer}
* @example
*```js
*const root = tree.getRoot()
*```
*/
getRoot(): Buffer;
/**
* getHexRoot
* @desc Returns the Merkle root hash as a hex string.
* @return {String}
* @example
*```js
*const root = tree.getHexRoot()
*```
*/
getHexRoot(): string;
/**
* getProof
* @desc Returns the proof for a target leaf.
* @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 {Object[]} - Array of objects containing a position property of type string
* with values of 'left' or 'right' and a data property of type Buffer.
* @example
* ```js
*const proof = tree.getProof(leaves[2])
*```
*
* @example
*```js
*const leaves = ['a', 'b', 'a'].map(value => keccak(value))
*const tree = new MerkleTree(leaves, keccak)
*const proof = tree.getProof(leaves[2], 2)
*```
*/
getProof(leaf: Buffer | string, index?: number): {
position: 'left' | 'right';
data: Buffer;
}[];
/**
* 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 | string, index?: number): string[];
/**
* getProofs
* @desc Returns the proofs for all leaves.
* @return {Object[]} - Array of objects containing a position property of type string
* with values of 'left' or 'right' and a data property of type Buffer for all leaves.
* @example
* ```js
*const proofs = tree.getProofs()
*```
*
* @example
*```js
*const leaves = ['a', 'b', 'a'].map(value => keccak(value))
*const tree = new MerkleTree(leaves, keccak)
*const proofs = tree.getProofs()
*```
*/
getProofs(): any[];
/**
* getProofsDFS
* @desc Get all proofs through single traverse
* @param {Number} currentLayer - Current layer index in traverse.
* @param {Number} index - Current tarvese node index in traverse.
* @param {Object[]} proof - Proof chain for single leaf.
* @param {Object[]} proofs - Proofs for all leaves
* @example
* ```js
*const layers = tree.getLayers()
*const index = 0;
*let proof = [];
*let proofs = [];
*const proof = tree.getProofsDFS(layers, index, proof, proofs)
*```
*/
getProofsDFS(currentLayer: any, index: any, proof: any, proofs: any): any[];
/**
* getHexProofs
* @desc Returns the proofs for all leaves as hex strings.
* @return {String[]} - Proofs array as hex strings.
* @example
* ```js
*const proofs = tree.getHexProofs()
*```
*/
getHexProofs(): string[];
/**
* getPositionalHexProof
* @desc Returns the proof for a target leaf as hex strings and the position in binary (left == 0).
* @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 | number)[][]} - Proof array as hex strings. position at index 0
* @example
* ```js
*const proof = tree.getPositionalHexProof(leaves[2])
*```
*/
getPositionalHexProof(leaf: Buffer | string, index?: number): (string | number)[][];
/**
* marshalProof
* @desc Returns proof array as JSON string.
* @param {String[]|Object[]} proof - Merkle tree proof array
* @return {String} - Proof array as JSON string.
* @example
* ```js
*const jsonStr = MerkleTree.marshalProof(proof)
*```
*/
static marshalProof(proof: any[]): string;
/**
* unmarshalProof
* @desc Returns the proof for a target leaf as a list of Buffers.
* @param {String|Object} - Merkle tree leaves
* @return {String|Object} - Marshalled proof
* @example
* ```js
*const proof = MerkleTree.unmarshalProof(jsonStr)
*```
*/
static unmarshalProof(jsonStr: string | object): any[];
static marshalTree(tree: MerkleTree): string;
static unmarshalTree(jsonStr: string | object, hashFn?: any, options?: Options): MerkleTree;
/**
* 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[];
private getProofIndicesForUnevenTree;
/**
* 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[];
private getMultiProofForUnevenTree;
/**
* 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[] | string[], 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 {Number[]|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: any[], proofs: Buffer[] | string[]): boolean[];
/**
* verify
* @desc Returns true if the proof path (array of hashes) can connect the target node
* to the Merkle root.
* @param {Object[]} proof - Array of proof objects that should connect
* target node to Merkle root.
* @param {Buffer} targetNode - Target node Buffer
* @param {Buffer} root - Merkle root Buffer
* @return {Boolean}
* @example
*```js
*const root = tree.getRoot()
*const proof = tree.getProof(leaves[2])
*const verified = tree.verify(proof, leaves[2], root)
*```
*/
verify(proof: any[], targetNode: Buffer | string, root: Buffer | string): boolean;
/**
* verifyMultiProof
* @desc Returns true if the multiproofs can connect the leaves to the Merkle root.
* @param {Buffer} root - Merkle tree root
* @param {Number[]} proofIndices - Leave indices for proof
* @param {Buffer[]} proofLeaves - Leaf values at indices for proof
* @param {Number} leavesCount - Count of original leaves
* @param {Buffer[]} proof - Multiproofs given indices
* @return {Boolean}
* @example
*```js
*const leaves = tree.getLeaves()
*const root = tree.getRoot()
*const treeFlat = tree.getLayersFlat()
*const leavesCount = leaves.length
*const proofIndices = [2, 5, 6]
*const proofLeaves = proofIndices.map(i => leaves[i])
*const proof = tree.getMultiProof(treeFlat, indices)
*const verified = tree.verifyMultiProof(root, proofIndices, proofLeaves, leavesCount, proof)
*```
*/
verifyMultiProof(root: Buffer | string, proofIndices: number[], proofLeaves: Buffer[] | string[], leavesCount: number, proof: Buffer[] | string[]): boolean;
verifyMultiProofWithFlags(root: Buffer | string, leaves: TLeaf[], proofs: Buffer[] | string[], proofFlag: boolean[]): boolean;
private verifyMultiProofForUnevenTree;
/**
* 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;
/**
* verify
* @desc Returns true if the proof path (array of hashes) can connect the target node
* to the Merkle root.
* @param {Object[]} proof - Array of proof objects that should connect
* target node to Merkle root.
* @param {Buffer} targetNode - Target node Buffer
* @param {Buffer} root - Merkle root Buffer
* @param {Function} hashFunction - Hash function for hashing leaves and nodes
* @param {Object} options - Additional options
* @return {Boolean}
* @example
*```js
*const verified = MerkleTree.verify(proof, leaf, root, sha256, options)
*```
*/
static verify(proof: any[], targetNode: Buffer | string, root: Buffer | string, hashFn?: any, options?: Options): boolean;
/**
* 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[] | string[], indices: number[]): Buffer[];
/**
* resetTree
* @desc Resets the tree by clearing the leaves and layers.
* @example
*```js
*tree.resetTree()
*```
*/
resetTree(): void;
/**
* 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;
/**
* toTreeString
* @desc Returns a visual representation of the merkle tree as a string.
* @return {String}
* @example
*```js
*console.log(tree.toTreeString())
*```
*/
protected toTreeString(): string;
/**
* toString
* @desc Returns a visual representation of the merkle tree as a string.
* @example
*```js
*console.log(tree.toString())
*```
*/
toString(): string;
isUnevenTree(treeLayers?: any[]): boolean;
private isPowOf2;
isValidLeafIndex(idx: number): boolean;
private calculateRootForUnevenTree;
}
export default MerkleTree;