Update docs
This commit is contained in:
parent
9957ac545e
commit
a69a927e8e
624
README.md
624
README.md
|
@ -1,6 +1,6 @@
|
|||
<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 />
|
||||
<br />
|
||||
<br />
|
||||
|
@ -18,9 +18,9 @@
|
|||
|
||||
## Contents
|
||||
|
||||
- [Diagrams](#diagrams)
|
||||
- [Install](#install)
|
||||
- [Getting started](#Getting-started)
|
||||
- [Diagrams](#diagrams)
|
||||
- [Documentation](#documentation)
|
||||
- [Test](#test)
|
||||
- [FAQ](#faq)
|
||||
|
@ -29,24 +29,6 @@
|
|||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
|
||||
## 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
|
||||
|
||||
```bash
|
||||
|
@ -93,6 +75,24 @@ Output
|
|||
└─ 0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
<!-- :%s/// -->
|
||||
|
@ -100,44 +100,62 @@ Output
|
|||
|
||||
## Class
|
||||
|
||||
Class reprensenting a Merkle Tree
|
||||
|
||||
*__namespace__*: MerkleTree
|
||||
|
||||
## Hierarchy
|
||||
|
||||
**MerkleTree**
|
||||
|
||||
### Constructors
|
||||
|
||||
* [constructor](#constructor)
|
||||
* [constructor](api-classes-index-merkletree.md#constructor)
|
||||
|
||||
### Properties
|
||||
|
||||
* [duplicateOdd](#duplicateodd)
|
||||
* [hashAlgo](#hashalgo)
|
||||
* [hashLeaves](#hashleaves)
|
||||
* [isBitcoinTree](#isbitcointree)
|
||||
* [layers](#layers)
|
||||
* [leaves](#leaves)
|
||||
* [sort](#sort)
|
||||
* [sortLeaves](#sortleaves)
|
||||
* [sortPairs](#sortpairs)
|
||||
* [duplicateOdd](api-classes-index-merkletree.md#duplicateodd)
|
||||
* [hashAlgo](api-classes-index-merkletree.md#hashalgo)
|
||||
* [hashLeaves](api-classes-index-merkletree.md#hashleaves)
|
||||
* [isBitcoinTree](api-classes-index-merkletree.md#isbitcointree)
|
||||
* [layers](api-classes-index-merkletree.md#layers)
|
||||
* [leaves](api-classes-index-merkletree.md#leaves)
|
||||
* [sort](api-classes-index-merkletree.md#sort)
|
||||
* [sortLeaves](api-classes-index-merkletree.md#sortleaves)
|
||||
* [sortPairs](api-classes-index-merkletree.md#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)
|
||||
* [_bufferIndexOf](api-classes-index-merkletree.md#_bufferindexof)
|
||||
* [_bufferToHex](api-classes-index-merkletree.md#_buffertohex)
|
||||
* [_bufferify](api-classes-index-merkletree.md#_bufferify)
|
||||
* [_bufferifyFn](api-classes-index-merkletree.md#_bufferifyfn)
|
||||
* [_createHashes](api-classes-index-merkletree.md#_createhashes)
|
||||
* [_getPairNode](api-classes-index-merkletree.md#_getpairnode)
|
||||
* [_isHexString](api-classes-index-merkletree.md#_ishexstring)
|
||||
* [_log2](api-classes-index-merkletree.md#_log2)
|
||||
* [_toTreeString](api-classes-index-merkletree.md#_totreestring)
|
||||
* [_zip](api-classes-index-merkletree.md#_zip)
|
||||
* [getDepth](api-classes-index-merkletree.md#getdepth)
|
||||
* [getHexLayers](api-classes-index-merkletree.md#gethexlayers)
|
||||
* [getHexLayersFlat](api-classes-index-merkletree.md#gethexlayersflat)
|
||||
* [getHexLeaves](api-classes-index-merkletree.md#gethexleaves)
|
||||
* [getHexMultiProof](api-classes-index-merkletree.md#gethexmultiproof)
|
||||
* [getHexProof](api-classes-index-merkletree.md#gethexproof)
|
||||
* [getHexRoot](api-classes-index-merkletree.md#gethexroot)
|
||||
* [getLayers](api-classes-index-merkletree.md#getlayers)
|
||||
* [getLayersAsObject](api-classes-index-merkletree.md#getlayersasobject)
|
||||
* [getLayersFlat](api-classes-index-merkletree.md#getlayersflat)
|
||||
* [getLeaves](api-classes-index-merkletree.md#getleaves)
|
||||
* [getMultiProof](api-classes-index-merkletree.md#getmultiproof)
|
||||
* [getProof](api-classes-index-merkletree.md#getproof)
|
||||
* [getProofFlags](api-classes-index-merkletree.md#getproofflags)
|
||||
* [getProofIndices](api-classes-index-merkletree.md#getproofindices)
|
||||
* [getRoot](api-classes-index-merkletree.md#getroot)
|
||||
* [print](api-classes-index-merkletree.md#print)
|
||||
* [toString](api-classes-index-merkletree.md#tostring)
|
||||
* [verify](api-classes-index-merkletree.md#verify)
|
||||
* [verifyMultiProof](api-classes-index-merkletree.md#verifymultiproof)
|
||||
* [bufferify](api-classes-index-merkletree.md#bufferify)
|
||||
* [getMultiProof](api-classes-index-merkletree.md#getmultiproof-1)
|
||||
* [isHexString](api-classes-index-merkletree.md#ishexstring)
|
||||
* [print](api-classes-index-merkletree.md#print-1)
|
||||
|
||||
---
|
||||
|
||||
|
@ -147,34 +165,17 @@ Class reprensenting a Merkle Tree
|
|||
|
||||
### constructor
|
||||
|
||||
⊕ **new MerkleTree**(leaves: *`any`*, hashAlgorithm: *`any`*, options?: *[Options]()
|
||||
|
||||
*__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
|
||||
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(x => keccak(x))
|
||||
|
||||
const tree = new MerkleTree(leaves, sha256)
|
||||
```
|
||||
⊕ **new MerkleTree**(leaves: *`any`*, hashAlgorithm?: *`any`*, options?: *[Options](api-interfaces-index-options.md)*): [MerkleTree](api-classes-index-merkletree.md)
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| 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 |
|
||||
| `Default value` hashAlgorithm | `any` | SHA256 | Algorithm used for hashing leaves and nodes |
|
||||
| `Default value` options | [Options](api-interfaces-index-options.md) | {} | Additional options |
|
||||
|
||||
**Returns:** [MerkleTree]()
|
||||
**Returns:** [MerkleTree](api-classes-index-merkletree.md)
|
||||
|
||||
___
|
||||
|
||||
|
@ -194,15 +195,15 @@ ___
|
|||
**● hashAlgo**: *`function`*
|
||||
|
||||
#### Type declaration
|
||||
▸(value: *`any`*): `any`
|
||||
▸(value: *[TValue](api-modules-index-module.md#tvalue)*): [THashAlgo](api-modules-index-module.md#thashalgo)
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type |
|
||||
| ------ | ------ |
|
||||
| value | `any` |
|
||||
| value | [TValue](api-modules-index-module.md#tvalue) |
|
||||
|
||||
**Returns:** `any`
|
||||
**Returns:** [THashAlgo](api-modules-index-module.md#thashalgo)
|
||||
|
||||
___
|
||||
<a id="hashleaves"></a>
|
||||
|
@ -223,14 +224,21 @@ ___
|
|||
|
||||
### layers
|
||||
|
||||
**● layers**: *`any`[]*
|
||||
**● layers**: *[TLayer](api-modules-index-module.md#tlayer)[]*
|
||||
|
||||
___
|
||||
<a id="leaves"></a>
|
||||
|
||||
### leaves
|
||||
|
||||
**● leaves**: *`any`[]*
|
||||
**● leaves**: *[TLeaf](api-modules-index-module.md#tleaf)[]*
|
||||
|
||||
___
|
||||
<a id="sort"></a>
|
||||
|
||||
### sort
|
||||
|
||||
**● sort**: *`boolean`*
|
||||
|
||||
___
|
||||
<a id="sortleaves"></a>
|
||||
|
@ -250,11 +258,73 @@ ___
|
|||
|
||||
## Methods
|
||||
|
||||
<a id="createhashes"></a>
|
||||
<a id="_bufferindexof"></a>
|
||||
|
||||
### createHashes
|
||||
### `<Private>` _bufferIndexOf
|
||||
|
||||
▸ **createHashes**(nodes: *`any`*): `void`
|
||||
▸ **_bufferIndexOf**(arr: *`any`*, el: *`any`*): `number`
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type |
|
||||
| ------ | ------ |
|
||||
| arr | `any` |
|
||||
| el | `any` |
|
||||
|
||||
**Returns:** `number`
|
||||
* Index number
|
||||
|
||||
___
|
||||
<a id="_buffertohex"></a>
|
||||
|
||||
### `<Private>` _bufferToHex
|
||||
|
||||
▸ **_bufferToHex**(value: *`Buffer`*): `string`
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ------ |
|
||||
| value | `Buffer` | \- |
|
||||
|
||||
**Returns:** `string`
|
||||
|
||||
___
|
||||
<a id="_bufferify"></a>
|
||||
|
||||
### `<Private>` _bufferify
|
||||
|
||||
▸ **_bufferify**(x: *`any`*): `any`
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type |
|
||||
| ------ | ------ |
|
||||
| x | `any` |
|
||||
|
||||
**Returns:** `any`
|
||||
|
||||
___
|
||||
<a id="_bufferifyfn"></a>
|
||||
|
||||
### `<Private>` _bufferifyFn
|
||||
|
||||
▸ **_bufferifyFn**(f: *`any`*): `(Anonymous function)`
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type |
|
||||
| ------ | ------ |
|
||||
| f | `any` |
|
||||
|
||||
**Returns:** `(Anonymous function)`
|
||||
|
||||
___
|
||||
<a id="_createhashes"></a>
|
||||
|
||||
### `<Private>` _createHashes
|
||||
|
||||
▸ **_createHashes**(nodes: *`any`*): `void`
|
||||
|
||||
**Parameters:**
|
||||
|
||||
|
@ -264,6 +334,157 @@ ___
|
|||
|
||||
**Returns:** `void`
|
||||
|
||||
___
|
||||
<a id="_getpairnode"></a>
|
||||
|
||||
### `<Private>` _getPairNode
|
||||
|
||||
▸ **_getPairNode**(layer: *`any`*, idx: *`any`*): `any`
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ------ |
|
||||
| layer | `any` | Tree layer |
|
||||
| idx | `any` |
|
||||
|
||||
**Returns:** `any`
|
||||
* Node
|
||||
|
||||
___
|
||||
<a id="_ishexstring"></a>
|
||||
|
||||
### `<Private>` _isHexString
|
||||
|
||||
▸ **_isHexString**(v: *`any`*): `boolean`
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type |
|
||||
| ------ | ------ |
|
||||
| v | `any` |
|
||||
|
||||
**Returns:** `boolean`
|
||||
|
||||
___
|
||||
<a id="_log2"></a>
|
||||
|
||||
### `<Private>` _log2
|
||||
|
||||
▸ **_log2**(x: *`any`*): `any`
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type |
|
||||
| ------ | ------ |
|
||||
| x | `any` |
|
||||
|
||||
**Returns:** `any`
|
||||
|
||||
___
|
||||
<a id="_totreestring"></a>
|
||||
|
||||
### `<Private>` _toTreeString
|
||||
|
||||
▸ **_toTreeString**(): `any`
|
||||
|
||||
**Returns:** `any`
|
||||
|
||||
___
|
||||
<a id="_zip"></a>
|
||||
|
||||
### `<Private>` _zip
|
||||
|
||||
▸ **_zip**(a: *`any`*, b: *`any`*): `any`
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ------ |
|
||||
| a | `any` | first array |
|
||||
| b | `any` | second array |
|
||||
|
||||
**Returns:** `any`
|
||||
|
||||
___
|
||||
<a id="getdepth"></a>
|
||||
|
||||
### getDepth
|
||||
|
||||
▸ **getDepth**(): `number`
|
||||
|
||||
**Returns:** `number`
|
||||
|
||||
___
|
||||
<a id="gethexlayers"></a>
|
||||
|
||||
### getHexLayers
|
||||
|
||||
▸ **getHexLayers**(): `any`
|
||||
|
||||
**Returns:** `any`
|
||||
|
||||
___
|
||||
<a id="gethexlayersflat"></a>
|
||||
|
||||
### getHexLayersFlat
|
||||
|
||||
▸ **getHexLayersFlat**(): `any`
|
||||
|
||||
**Returns:** `any`
|
||||
|
||||
___
|
||||
<a id="gethexleaves"></a>
|
||||
|
||||
### getHexLeaves
|
||||
|
||||
▸ **getHexLeaves**(): `string`[]
|
||||
|
||||
**Returns:** `string`[]
|
||||
|
||||
___
|
||||
<a id="gethexmultiproof"></a>
|
||||
|
||||
### getHexMultiProof
|
||||
|
||||
▸ **getHexMultiProof**(tree: *`any`*, indices: *`any`*): `string`[]
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ------ |
|
||||
| tree | `any` |
|
||||
| indices | `any` | Tree indices. |
|
||||
|
||||
**Returns:** `string`[]
|
||||
* Multiproofs as hex strings.
|
||||
|
||||
___
|
||||
<a id="gethexproof"></a>
|
||||
|
||||
### getHexProof
|
||||
|
||||
▸ **getHexProof**(leaf: *`any`*, index: *`any`*): `string`[]
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ------ |
|
||||
| leaf | `any` | Target leaf |
|
||||
| `Optional` index | `any` |
|
||||
|
||||
**Returns:** `string`[]
|
||||
* Proof array as hex strings.
|
||||
|
||||
___
|
||||
<a id="gethexroot"></a>
|
||||
|
||||
### getHexRoot
|
||||
|
||||
▸ **getHexRoot**(): `string`
|
||||
|
||||
**Returns:** `string`
|
||||
|
||||
___
|
||||
<a id="getlayers"></a>
|
||||
|
||||
|
@ -271,15 +492,6 @@ ___
|
|||
|
||||
▸ **getLayers**(): `any`[]
|
||||
|
||||
getLayers
|
||||
|
||||
*__desc__*: Returns array of all layers of Merkle Tree, including leaves and root.
|
||||
|
||||
*__example__*:
|
||||
```js
|
||||
const layers = tree.getLayers()
|
||||
```
|
||||
|
||||
**Returns:** `any`[]
|
||||
|
||||
___
|
||||
|
@ -291,46 +503,53 @@ ___
|
|||
|
||||
**Returns:** `any`
|
||||
|
||||
___
|
||||
<a id="getlayersflat"></a>
|
||||
|
||||
### getLayersFlat
|
||||
|
||||
▸ **getLayersFlat**(): `any`
|
||||
|
||||
**Returns:** `any`
|
||||
|
||||
___
|
||||
<a id="getleaves"></a>
|
||||
|
||||
### getLeaves
|
||||
|
||||
▸ **getLeaves**(): `any`[]
|
||||
▸ **getLeaves**(data: *`any`[]*): `any`[]
|
||||
|
||||
getLeaves
|
||||
**Parameters:**
|
||||
|
||||
*__desc__*: Returns array of leaves of Merkle Tree.
|
||||
|
||||
*__example__*:
|
||||
```js
|
||||
const leaves = tree.getLeaves()
|
||||
```
|
||||
| Name | Type |
|
||||
| ------ | ------ |
|
||||
| `Optional` data | `any`[] |
|
||||
|
||||
**Returns:** `any`[]
|
||||
|
||||
___
|
||||
<a id="getmultiproof"></a>
|
||||
|
||||
### getMultiProof
|
||||
|
||||
▸ **getMultiProof**(tree: *`any`*, indices: *`any`*): `any`[]
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ------ |
|
||||
| tree | `any` |
|
||||
| indices | `any` | Tree indices. |
|
||||
|
||||
**Returns:** `any`[]
|
||||
* Multiproofs
|
||||
|
||||
___
|
||||
<a id="getproof"></a>
|
||||
|
||||
### getProof
|
||||
|
||||
▸ **getProof**(leaf: *`any`*, index?: *`any`*): `any`[]
|
||||
|
||||
getProof
|
||||
|
||||
*__desc__*: Returns the proof for a target leaf.
|
||||
|
||||
*__example__*:
|
||||
```js
|
||||
const proof = tree.getProof(leaves[2])
|
||||
```
|
||||
|
||||
*__example__*:
|
||||
```js
|
||||
const leaves = ['a', 'b', 'a'].map(x => keccak(x))
|
||||
const tree = new MerkleTree(leaves, keccak)
|
||||
const proof = tree.getProof(leaves[2], 2)
|
||||
```
|
||||
▸ **getProof**(leaf: *`any`*, index: *`any`*): `any`[]
|
||||
|
||||
**Parameters:**
|
||||
|
||||
|
@ -342,6 +561,40 @@ const proof = tree.getProof(leaves[2], 2)
|
|||
**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="getproofflags"></a>
|
||||
|
||||
### getProofFlags
|
||||
|
||||
▸ **getProofFlags**(els: *`any`*, proofs: *`any`*): `any`[]
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type |
|
||||
| ------ | ------ |
|
||||
| els | `any` |
|
||||
| proofs | `any` |
|
||||
|
||||
**Returns:** `any`[]
|
||||
* Boolean flags
|
||||
|
||||
___
|
||||
<a id="getproofindices"></a>
|
||||
|
||||
### getProofIndices
|
||||
|
||||
▸ **getProofIndices**(treeIndices: *`any`*, depth: *`any`*): `any`[]
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ------ |
|
||||
| treeIndices | `any` | Tree indices |
|
||||
| depth | `any` | Tree depth; number of layers. |
|
||||
|
||||
**Returns:** `any`[]
|
||||
* Proof indices
|
||||
|
||||
___
|
||||
<a id="getroot"></a>
|
||||
|
||||
|
@ -349,15 +602,6 @@ ___
|
|||
|
||||
▸ **getRoot**(): `any`
|
||||
|
||||
getRoot
|
||||
|
||||
*__desc__*: Returns the Merkle root hash as a Buffer.
|
||||
|
||||
*__example__*:
|
||||
```js
|
||||
const root = tree.getRoot()
|
||||
```
|
||||
|
||||
**Returns:** `any`
|
||||
|
||||
___
|
||||
|
@ -378,15 +622,6 @@ ___
|
|||
|
||||
**Returns:** `any`
|
||||
|
||||
___
|
||||
<a id="totreestring"></a>
|
||||
|
||||
### toTreeString
|
||||
|
||||
▸ **toTreeString**(): `any`
|
||||
|
||||
**Returns:** `any`
|
||||
|
||||
___
|
||||
<a id="verify"></a>
|
||||
|
||||
|
@ -394,17 +629,6 @@ ___
|
|||
|
||||
▸ **verify**(proof: *`any`*, targetNode: *`any`*, root: *`any`*): `boolean`
|
||||
|
||||
verify
|
||||
|
||||
*__desc__*: Returns true if the proof path (array of hashes) can connect the target node to the Merkle root.
|
||||
|
||||
*__example__*:
|
||||
```js
|
||||
const root = tree.getRoot()
|
||||
const proof = tree.getProof(leaves[2])
|
||||
const verified = tree.verify(proof, leaves[2], root)
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type | Description |
|
||||
|
@ -415,6 +639,25 @@ const verified = tree.verify(proof, leaves[2], root)
|
|||
|
||||
**Returns:** `boolean`
|
||||
|
||||
___
|
||||
<a id="verifymultiproof"></a>
|
||||
|
||||
### verifyMultiProof
|
||||
|
||||
▸ **verifyMultiProof**(root: *`any`*, indices: *`any`*, leaves: *`any`*, depth: *`any`*, proof: *`any`*): `any`
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ------ |
|
||||
| root | `any` | Merkle tree root |
|
||||
| indices | `any` | Leave indices |
|
||||
| leaves | `any` | Leaf values at indices. |
|
||||
| depth | `any` | Tree depth |
|
||||
| proof | `any` | Multiproofs given indices |
|
||||
|
||||
**Returns:** `any`
|
||||
|
||||
___
|
||||
<a id="bufferify"></a>
|
||||
|
||||
|
@ -430,6 +673,38 @@ ___
|
|||
|
||||
**Returns:** `any`
|
||||
|
||||
___
|
||||
<a id="getmultiproof-1"></a>
|
||||
|
||||
### `<Static>` getMultiProof
|
||||
|
||||
▸ **getMultiProof**(tree: *`any`*, indices: *`any`*): `any`[]
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ------ |
|
||||
| tree | `any` | Tree as a flat array. |
|
||||
| indices | `any` | Tree indices. |
|
||||
|
||||
**Returns:** `any`[]
|
||||
* Multiproofs
|
||||
|
||||
___
|
||||
<a id="ishexstring"></a>
|
||||
|
||||
### `<Static>` isHexString
|
||||
|
||||
▸ **isHexString**(v: *`any`*): `boolean`
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type |
|
||||
| ------ | ------ |
|
||||
| v | `any` |
|
||||
|
||||
**Returns:** `boolean`
|
||||
|
||||
___
|
||||
<a id="print-1"></a>
|
||||
|
||||
|
@ -439,79 +714,12 @@ ___
|
|||
|
||||
**Parameters:**
|
||||
|
||||
| Name | Type |
|
||||
| ------ | ------ |
|
||||
| tree | `any` |
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ------ |
|
||||
| tree | `any` | Merkle tree instance. |
|
||||
|
||||
**Returns:** `void`
|
||||
|
||||
## Interface
|
||||
|
||||
## Options
|
||||
|
||||
### Properties
|
||||
|
||||
* [duplicateOdd](#duplicateodd)
|
||||
* [hashLeaves](#hashleaves)
|
||||
* [isBitcoinTree](#isbitcointree)
|
||||
* [sort](#sort)
|
||||
* [sortLeaves](#sortleaves)
|
||||
* [sortPairs](#sortpairs)
|
||||
|
||||
---
|
||||
|
||||
## Properties
|
||||
|
||||
<a id="duplicateodd"></a>
|
||||
|
||||
### duplicateOdd
|
||||
|
||||
**● 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
|
||||
|
||||
**● hashLeaves**: *`boolean`*
|
||||
|
||||
If set to `true`, the leaves will hashed using the set hashing algorithms.
|
||||
|
||||
___
|
||||
<a id="isbitcointree"></a>
|
||||
|
||||
### isBitcoinTree
|
||||
|
||||
**● isBitcoinTree**: *`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.
|
||||
|
||||
___
|
||||
<a id="sortleaves"></a>
|
||||
|
||||
### sort
|
||||
|
||||
**● sort**: *`boolean`*
|
||||
|
||||
If set to `true`, the leaves and hashing pairs will be sorted.
|
||||
|
||||
### sortLeaves
|
||||
|
||||
**● sortLeaves**: *`boolean`*
|
||||
|
||||
If set to `true`, the leaves will be sorted.
|
||||
|
||||
___
|
||||
<a id="sortpairs"></a>
|
||||
|
||||
### sortPairs
|
||||
|
||||
**● sortPairs**: *`boolean`*
|
||||
|
||||
If set to `true`, the hashing pairs will be sorted.
|
||||
|
||||
## Test
|
||||
|
||||
```bash
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mxfile host="app.diagrams.net" modified="2020-06-06T17:56:54.181Z" agent="5.0 (X11)" etag="EqUJNqwkYz94jIl3aqxT" version="13.1.14" type="google"><diagram id="_fycCV10ZWOh--qWWdVK" name="Page-1">7Z1bc6M2FIB/TR7TQRcuftxcNp1p0+kkO233kcSKTccxXkI2zv76ykYCcyCLTDE6NjwZCRBwzocu54LP2OXz+iYJV/PbeCoWZ9SZrs/Y1RmlxPEm8mdT857V+NzPKmZJNFUHFRX30Q+hz1S1r9FUvJQOTON4kUarcuVjvFyKx7RUFyZJ/FY+7ClelK+6CmeiUnH/GC6qtX9H03Se1QauU9T/KqLZXF+ZOGrPc6gPVhUv83Aav+1UseszdpnEcZptPa8vxWIjPC2X7LzPH+zNbywRy9TkhLu724dvN1c/blcp/eOv89XNv7Pr84BmzXwPF6/qidXdpu9aBLIZKW1ZuHibR6m4X4WPmz1vUuGybp4+L2SJyM3wZZWp4ClaC3nVC9W2SFKx/vCuSS4LCZGIn0WavMtD1AkTJT2FD3NZVn4rlKEFPN/Rg64LlfpnecOFhOSGEtI+AmPIBUZcikxiHLnEKMEmMRe7xHxsb6WHXGKMYWPMxy4xdD1/gFxi3MUmsQlyibkEmcQ083gl5iPrxyYEucQ8ho0x7FN+QgFjekllTWLY5/yUY5MY9jk/8xxkEsM+5+cBNolhn/N7Dra3EvucnwRliVHXtsTQz/mpg0xi6Of8YJVEuWWJ5Rbjn4psOf20sWbLUrwSyy/zaFkWlVhH6T9y2/nFVaWvm5LavlrvFt51YSnvf+ekTfGrbm9TKE7blorzpp+jzUNuS9m9imnFjg40Ip8nfk0exU9EoV//NExmIm2cw1Z1vKNDt0aHui4RizCNvpdvuE6x6gp/xpF8lOKl42Ao9AAb2YOqswo8qg1BGwcBDWWCqDS05Sx/7P+DnsnqaRjosaNAj1QsFi3RI5Bh1jd6JsvQYaDHTdFjNtGjYODMO6990cvnwboh3jd6Juv5YaDnHgd6FRtaS/QoXPb33uuZGEYa0WuLUStkD4SeNkM2o+dbHXDBOMlbD7hgrsedvtEzsTANAz3juR4q9GjbAZc6DQ0dHD0TU90g0NOBCs3ocZvouayjuZ4b2J7rmdg8h4GefxToUWDR5H7bXg8EKXFowTs4eibG42GgF5ii56JCr/WAC9HrvdczscIPA73JUaAHTcqt0YMm5d7R0wbK0biiNdGMnmcTPR+sDipOCFP0fOhZg26Rg6M3ejNAVBxy9Dzo/4JTNGP04FIZThoPjh4dB9xy6FczeoFN9GBiUWV1YOzNgI603tHrxJtxEugZezOsose9juZ6MHy9/7neft6MZbwUZtg5rbAje2D3ImWT1rwT2/oD4Wm8FLE6KFNosmvr8WDQiNi3x4Ngj6mFgxC1HSFKCPagWhiGjEBkdRZmbyGve/EUb9+HQnbet9dY7zh/2Sa7f5IHEL5aFzvl1kz9blt50BW3ukbe6AM8StZll9PVmLQGY8d17PaO0niN0uB41qHS6myzubgNNbYVPlDadb2OOlPG5j7UVxLk6NtN1DXMHrGvnTrzZRfauTs+7VCYRWBdO7or7Vw7vx2hdmBAkX3t1BnButDO78enHUbRvTt1dqKBjjsM3ayA1plSutDOl+PTTiXJwb52qtaGu65lqBoih5GpC10t9mVat0QeaH/keuhGi7rV+EC141F07w72dFqY5E5sJ4cS2klI1Cl4aHOzUaM1OEuKtOaiBW+dx8otmBqDodmOg3YObQumnUREnQZ5ptF4gdWkH5jqyLW3ae/MC5gzGfTMHqszmAyUPVMfWGA1CJmAz1y1Zw9+KbF39saYKGi3bGbPbhQy64g92FD/7NGRPWCVbWbPru9/0hV7MLKvd/bGHG9oc25mz2q6I3M7Yg821D97nSR5nwJ7E9NFrorVscUejMOBnwVo+1UVEoCGDo5eJ0neJ4Ge6UpDxTxZG3KBf5+2DrcDy1zSd5Y36yTL+xTYyyMPm+Gjdsdc+PlAaC03hs+3Dd+Y5w1jONHD99GXGPfOeXRswzdmesMQiubFhtUcDJg64ZKWfg0XJnNAB8nB2RtTvWGASDN7E5vswfwfd9KWPQhx30413WGP7OWBNM3JPY7Vfg8m90DbiCl78G8tOOubvdGxAcOEmtn7IF6kp1ACyB5tyZ4PPwfp980eHfu98gfysRv4cta6tvDxzr4gKovFn4Fmhxd/qcqu/wM=</diagram></mxfile>
|
|
@ -1,9 +1,6 @@
|
|||
/// <reference types="node" />
|
||||
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`, 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. */
|
||||
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. */
|
||||
|
@ -25,7 +22,6 @@ declare type TLayer = any;
|
|||
*/
|
||||
export declare class MerkleTree {
|
||||
duplicateOdd: boolean;
|
||||
singleOdd: boolean;
|
||||
hashAlgo: (value: TValue) => THashAlgo;
|
||||
hashLeaves: boolean;
|
||||
isBitcoinTree: boolean;
|
||||
|
@ -56,8 +52,8 @@ export declare class MerkleTree {
|
|||
*const tree = new MerkleTree(leaves, sha256)
|
||||
*```
|
||||
*/
|
||||
constructor(leaves: any, hashAlgorithm: any, options?: Options);
|
||||
createHashes(nodes: any): void;
|
||||
constructor(leaves: any, hashAlgorithm?: any, options?: Options);
|
||||
private _createHashes;
|
||||
/**
|
||||
* getLeaves
|
||||
* @desc Returns array of leaves of Merkle Tree.
|
||||
|
@ -146,7 +142,7 @@ export declare class MerkleTree {
|
|||
* 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
|
||||
* @example
|
||||
* ```js
|
||||
*const proof = tree.getProof(leaves[2])
|
||||
*```
|
||||
|
@ -159,13 +155,70 @@ export declare class MerkleTree {
|
|||
*```
|
||||
*/
|
||||
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
|
||||
* @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: any, index?: any): 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: any, depth: any): any[];
|
||||
/**
|
||||
* 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): any[];
|
||||
/**
|
||||
* 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: any, indices: any): 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[]} indices - Tree indices.
|
||||
* @return {Boolean[]} - Boolean flags
|
||||
* @example
|
||||
* ```js
|
||||
*const indices = [2, 5, 6]
|
||||
*const proof = tree.getMultiProof(indices)
|
||||
*const proofFlags = tree.getProofFlags(leaves, proof)
|
||||
*```
|
||||
*/
|
||||
getProofFlags(els: any, proofs: any): any[];
|
||||
/**
|
||||
* verify
|
||||
* @desc Returns true if the proof path (array of hashes) can connect the target node
|
||||
|
@ -183,20 +236,217 @@ export declare class MerkleTree {
|
|||
*```
|
||||
*/
|
||||
verify(proof: any, targetNode: any, root: any): 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: any, indices: any, leaves: any, depth: any, proof: any): any;
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* print
|
||||
* @desc Prints out a visual representation of the merkle tree.
|
||||
* @example
|
||||
*```js
|
||||
*tree.print()
|
||||
*```
|
||||
*/
|
||||
print(): void;
|
||||
toTreeString(): any;
|
||||
/**
|
||||
* 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(): any;
|
||||
/**
|
||||
* 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: any, indices: any): any[];
|
||||
/**
|
||||
* 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(x: any): any;
|
||||
static isHexStr(v: any): boolean;
|
||||
/**
|
||||
* 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: any): boolean;
|
||||
/**
|
||||
* print
|
||||
* @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;
|
||||
|
|
|
@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
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"));
|
||||
/**
|
||||
* Class reprensenting a Merkle Tree
|
||||
|
@ -33,7 +34,7 @@ class MerkleTree {
|
|||
*const tree = new MerkleTree(leaves, sha256)
|
||||
*```
|
||||
*/
|
||||
constructor(leaves, hashAlgorithm, options = {}) {
|
||||
constructor(leaves, hashAlgorithm = sha256_1.default, options = {}) {
|
||||
this.isBitcoinTree = !!options.isBitcoinTree;
|
||||
this.hashLeaves = !!options.hashLeaves;
|
||||
this.sortLeaves = !!options.sortLeaves;
|
||||
|
@ -44,7 +45,6 @@ class MerkleTree {
|
|||
this.sortPairs = true;
|
||||
}
|
||||
this.duplicateOdd = !!options.duplicateOdd;
|
||||
this.singleOdd = !!options.singleOdd;
|
||||
this.hashAlgo = this._bufferifyFn(hashAlgorithm);
|
||||
if (this.hashLeaves) {
|
||||
leaves = leaves.map(this.hashAlgo);
|
||||
|
@ -54,10 +54,9 @@ class MerkleTree {
|
|||
this.leaves = this.leaves.sort(Buffer.compare);
|
||||
}
|
||||
this.layers = [this.leaves];
|
||||
this.createHashes(this.leaves);
|
||||
this._createHashes(this.leaves);
|
||||
}
|
||||
// TODO: documentation
|
||||
createHashes(nodes) {
|
||||
_createHashes(nodes) {
|
||||
while (nodes.length > 1) {
|
||||
const layerIndex = this.layers.length;
|
||||
this.layers.push([]);
|
||||
|
@ -76,7 +75,7 @@ class MerkleTree {
|
|||
continue;
|
||||
}
|
||||
else {
|
||||
if (!this.duplicateOdd && !this.singleOdd) {
|
||||
if (!this.duplicateOdd) {
|
||||
this.layers[layerIndex].push(nodes[i]);
|
||||
continue;
|
||||
}
|
||||
|
@ -91,21 +90,7 @@ class MerkleTree {
|
|||
combined = [buffer_reverse_1.default(left), buffer_reverse_1.default(right)];
|
||||
}
|
||||
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];
|
||||
}
|
||||
if (this.sortPairs) {
|
||||
combined.sort(Buffer.compare);
|
||||
|
@ -138,7 +123,7 @@ class MerkleTree {
|
|||
data = data.sort(Buffer.compare);
|
||||
}
|
||||
}
|
||||
return this.leaves.filter(x => this.bufIndexOf(data, x) !== -1);
|
||||
return this.leaves.filter(x => this._bufferIndexOf(data, x) !== -1);
|
||||
}
|
||||
return this.leaves;
|
||||
}
|
||||
|
@ -252,7 +237,7 @@ class MerkleTree {
|
|||
* 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
|
||||
* @example
|
||||
* ```js
|
||||
*const proof = tree.getProof(leaves[2])
|
||||
*```
|
||||
|
@ -312,7 +297,33 @@ class MerkleTree {
|
|||
return proof;
|
||||
}
|
||||
}
|
||||
// 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) {
|
||||
const leafCount = Math.pow(2, depth);
|
||||
let maximalIndices = new Set();
|
||||
|
@ -343,7 +354,17 @@ class MerkleTree {
|
|||
return !treeIndices.includes(index - leafCount);
|
||||
});
|
||||
}
|
||||
// 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) {
|
||||
if (!indices) {
|
||||
indices = tree;
|
||||
|
@ -353,7 +374,7 @@ class MerkleTree {
|
|||
if (this.sortPairs) {
|
||||
els = els.sort(Buffer.compare);
|
||||
}
|
||||
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)) {
|
||||
throw new Error('Element does not exist in Merkle tree');
|
||||
}
|
||||
|
@ -364,7 +385,7 @@ class MerkleTree {
|
|||
const layer = this.layers[i];
|
||||
for (let j = 0; j < ids.length; j++) {
|
||||
const idx = ids[j];
|
||||
const pairElement = this.getPairElement(idx, layer);
|
||||
const pairElement = this._getPairNode(layer, idx);
|
||||
hashes.push(layer[idx]);
|
||||
if (pairElement) {
|
||||
proof.push(pairElement);
|
||||
|
@ -379,22 +400,35 @@ class MerkleTree {
|
|||
}
|
||||
return this.getProofIndices(indices, this._log2((tree.length / 2) | 0)).map(index => tree[index]);
|
||||
}
|
||||
// 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
|
||||
* @desc Returns list of booleans where proofs should be used instead of hashing.
|
||||
* Proof flags are used in the Solidity multiproof verifiers.
|
||||
* @param {Number[]} indices - Tree indices.
|
||||
* @return {Boolean[]} - Boolean flags
|
||||
* @example
|
||||
* ```js
|
||||
*const indices = [2, 5, 6]
|
||||
*const proof = tree.getMultiProof(indices)
|
||||
*const proofFlags = tree.getProofFlags(leaves, proof)
|
||||
*```
|
||||
*/
|
||||
getProofFlags(els, proofs) {
|
||||
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)) {
|
||||
throw new Error('Element does not exist in Merkle tree');
|
||||
}
|
||||
|
@ -405,7 +439,7 @@ class MerkleTree {
|
|||
ids = ids.reduce((ids, idx) => {
|
||||
const skipped = tested.includes(layer[idx]);
|
||||
if (!skipped) {
|
||||
const pairElement = this.getPairElement(idx, layer);
|
||||
const pairElement = this._getPairNode(layer, idx);
|
||||
const proofUsed = proofs.includes(layer[idx]) || proofs.includes(pairElement);
|
||||
pairElement && flags.push(!proofUsed);
|
||||
tested.push(layer[idx]);
|
||||
|
@ -417,19 +451,6 @@ class MerkleTree {
|
|||
}
|
||||
return flags;
|
||||
}
|
||||
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));
|
||||
}
|
||||
/**
|
||||
* verify
|
||||
* @desc Returns true if the proof path (array of hashes) can connect the target node
|
||||
|
@ -495,7 +516,26 @@ class MerkleTree {
|
|||
}
|
||||
return Buffer.compare(hash, root) === 0;
|
||||
}
|
||||
// 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) {
|
||||
root = this._bufferify(root);
|
||||
leaves = leaves.map(this._bufferify);
|
||||
|
@ -520,11 +560,26 @@ class MerkleTree {
|
|||
}
|
||||
return !indices.length || (({}).hasOwnProperty.call(tree, 1) && tree[1].equals(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 objs = [];
|
||||
|
@ -549,27 +604,118 @@ class MerkleTree {
|
|||
}
|
||||
return objs[0];
|
||||
}
|
||||
// TODO: documentation
|
||||
/**
|
||||
* print
|
||||
* @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
|
||||
/**
|
||||
* 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.getLayersFlat(), 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(arr, el) {
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
if (el.equals(arr[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(x) {
|
||||
if (!Buffer.isBuffer(x)) {
|
||||
// crypto-js support
|
||||
if (typeof x === 'object' && x.words) {
|
||||
return Buffer.from(x.toString(crypto_js_1.default.enc.Hex), 'hex');
|
||||
}
|
||||
else if (MerkleTree.isHexStr(x)) {
|
||||
else if (MerkleTree.isHexString(x)) {
|
||||
return Buffer.from(x.replace(/^0x/, ''), 'hex');
|
||||
}
|
||||
else if (typeof x === 'string') {
|
||||
|
@ -578,38 +724,120 @@ class MerkleTree {
|
|||
}
|
||||
return x;
|
||||
}
|
||||
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
|
||||
/**
|
||||
* print
|
||||
* @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
|
||||
* @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(x) {
|
||||
return MerkleTree.bufferify(x);
|
||||
}
|
||||
/**
|
||||
* 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);
|
||||
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');
|
||||
};
|
||||
}
|
||||
_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(v) {
|
||||
return MerkleTree.isHexString(v);
|
||||
}
|
||||
/**
|
||||
* log2
|
||||
* @desc Returns the log2 of number.
|
||||
* @param {Number} value
|
||||
* @return {Number}
|
||||
*/
|
||||
_log2(x) {
|
||||
return x === 1 ? 0 : 1 + this._log2((x / 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) {
|
||||
return a.map((e, i) => [e, b[i]]);
|
||||
}
|
||||
|
|
383
index.ts
383
index.ts
|
@ -1,12 +1,11 @@
|
|||
import reverse from 'buffer-reverse'
|
||||
import CryptoJS from 'crypto-js'
|
||||
import SHA256 from 'crypto-js/sha256'
|
||||
import treeify from 'treeify'
|
||||
|
||||
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`, 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. */
|
||||
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. */
|
||||
|
@ -30,7 +29,6 @@ type TLayer = any
|
|||
*/
|
||||
export class MerkleTree {
|
||||
duplicateOdd: boolean
|
||||
singleOdd: boolean
|
||||
hashAlgo: (value: TValue) => THashAlgo
|
||||
hashLeaves: boolean
|
||||
isBitcoinTree: boolean
|
||||
|
@ -62,7 +60,7 @@ export class MerkleTree {
|
|||
*const tree = new MerkleTree(leaves, sha256)
|
||||
*```
|
||||
*/
|
||||
constructor (leaves, hashAlgorithm, options: Options = {}) {
|
||||
constructor (leaves, hashAlgorithm=SHA256, options: Options = {}) {
|
||||
this.isBitcoinTree = !!options.isBitcoinTree
|
||||
this.hashLeaves = !!options.hashLeaves
|
||||
this.sortLeaves = !!options.sortLeaves
|
||||
|
@ -75,7 +73,6 @@ export class MerkleTree {
|
|||
}
|
||||
|
||||
this.duplicateOdd = !!options.duplicateOdd
|
||||
this.singleOdd = !!options.singleOdd
|
||||
|
||||
this.hashAlgo = this._bufferifyFn(hashAlgorithm)
|
||||
if (this.hashLeaves) {
|
||||
|
@ -88,11 +85,10 @@ export class MerkleTree {
|
|||
}
|
||||
|
||||
this.layers = [this.leaves]
|
||||
this.createHashes(this.leaves)
|
||||
this._createHashes(this.leaves)
|
||||
}
|
||||
|
||||
// TODO: documentation
|
||||
createHashes (nodes) {
|
||||
private _createHashes (nodes) {
|
||||
while (nodes.length > 1) {
|
||||
const layerIndex = this.layers.length
|
||||
|
||||
|
@ -114,7 +110,7 @@ export class MerkleTree {
|
|||
this.layers[layerIndex].push(hash)
|
||||
continue
|
||||
} else {
|
||||
if (!this.duplicateOdd && !this.singleOdd) {
|
||||
if (!this.duplicateOdd) {
|
||||
this.layers[layerIndex].push(nodes[i])
|
||||
continue
|
||||
}
|
||||
|
@ -130,18 +126,7 @@ export class MerkleTree {
|
|||
if (this.isBitcoinTree) {
|
||||
combined = [reverse(left), reverse(right)]
|
||||
} 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]
|
||||
}
|
||||
|
||||
if (this.sortPairs) {
|
||||
|
@ -182,7 +167,7 @@ export class MerkleTree {
|
|||
}
|
||||
}
|
||||
|
||||
return this.leaves.filter(x => this.bufIndexOf(data, x) !== -1)
|
||||
return this.leaves.filter(x => this._bufferIndexOf(data, x) !== -1)
|
||||
}
|
||||
|
||||
return this.leaves
|
||||
|
@ -307,7 +292,7 @@ export class MerkleTree {
|
|||
* 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
|
||||
* @example
|
||||
* ```js
|
||||
*const proof = tree.getProof(leaves[2])
|
||||
*```
|
||||
|
@ -379,7 +364,34 @@ export class MerkleTree {
|
|||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
const leafCount = 2 ** depth
|
||||
let maximalIndices :any = new Set()
|
||||
|
@ -414,7 +426,17 @@ export class MerkleTree {
|
|||
})
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if (!indices) {
|
||||
indices = tree
|
||||
|
@ -426,7 +448,7 @@ export class MerkleTree {
|
|||
els = els.sort(Buffer.compare)
|
||||
}
|
||||
|
||||
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)) {
|
||||
throw new Error('Element does not exist in Merkle tree')
|
||||
}
|
||||
|
@ -439,7 +461,7 @@ export class MerkleTree {
|
|||
const layer = this.layers[i]
|
||||
for (let j = 0; j < ids.length; j++) {
|
||||
const idx = ids[j]
|
||||
const pairElement = this.getPairElement(idx, layer)
|
||||
const pairElement = this._getPairNode(layer, idx)
|
||||
|
||||
hashes.push(layer[idx])
|
||||
if (pairElement) {
|
||||
|
@ -460,25 +482,36 @@ export class MerkleTree {
|
|||
return this.getProofIndices(indices, this._log2((tree.length / 2) | 0)).map(index => tree[index])
|
||||
}
|
||||
|
||||
// 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
|
||||
* @desc Returns list of booleans where proofs should be used instead of hashing.
|
||||
* Proof flags are used in the Solidity multiproof verifiers.
|
||||
* @param {Number[]} indices - Tree indices.
|
||||
* @return {Boolean[]} - Boolean flags
|
||||
* @example
|
||||
* ```js
|
||||
*const indices = [2, 5, 6]
|
||||
*const proof = tree.getMultiProof(indices)
|
||||
*const proofFlags = tree.getProofFlags(leaves, proof)
|
||||
*```
|
||||
*/
|
||||
getProofFlags (els, proofs) {
|
||||
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)) {
|
||||
throw new Error('Element does not exist in Merkle tree')
|
||||
}
|
||||
|
@ -490,7 +523,7 @@ export class MerkleTree {
|
|||
ids = ids.reduce((ids, idx) => {
|
||||
const skipped = tested.includes(layer[idx])
|
||||
if (!skipped) {
|
||||
const pairElement = this.getPairElement(idx, layer)
|
||||
const pairElement = this._getPairNode(layer, idx)
|
||||
const proofUsed = proofs.includes(layer[idx]) || proofs.includes(pairElement)
|
||||
pairElement && flags.push(!proofUsed)
|
||||
tested.push(layer[idx])
|
||||
|
@ -504,21 +537,6 @@ export class MerkleTree {
|
|||
return flags
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
/**
|
||||
* verify
|
||||
* @desc Returns true if the proof path (array of hashes) can connect the target node
|
||||
|
@ -589,7 +607,26 @@ export class MerkleTree {
|
|||
return Buffer.compare(hash, root) === 0
|
||||
}
|
||||
|
||||
// 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) {
|
||||
root = this._bufferify(root)
|
||||
leaves = leaves.map(this._bufferify)
|
||||
|
@ -616,12 +653,27 @@ export class MerkleTree {
|
|||
return !indices.length || (({}).hasOwnProperty.call(tree, 1) && tree[1].equals(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 objs = []
|
||||
|
@ -650,29 +702,124 @@ export class MerkleTree {
|
|||
return objs[0]
|
||||
}
|
||||
|
||||
// TODO: documentation
|
||||
/**
|
||||
* print
|
||||
* @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())
|
||||
*```
|
||||
*/
|
||||
private _toTreeString () {
|
||||
const obj = this.getLayersAsObject()
|
||||
return treeify.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
|
||||
/**
|
||||
* 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.getLayersFlat(), 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)
|
||||
*```
|
||||
*/
|
||||
private _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)
|
||||
*```
|
||||
*/
|
||||
private _bufferIndexOf (arr, el) {
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
if (el.equals(arr[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 (x) {
|
||||
if (!Buffer.isBuffer(x)) {
|
||||
// crypto-js support
|
||||
if (typeof x === 'object' && x.words) {
|
||||
return Buffer.from(x.toString(CryptoJS.enc.Hex), 'hex')
|
||||
} else if (MerkleTree.isHexStr(x)) {
|
||||
} else if (MerkleTree.isHexString(x)) {
|
||||
return Buffer.from(x.replace(/^0x/, ''), 'hex')
|
||||
} else if (typeof x === 'string') {
|
||||
return Buffer.from(x)
|
||||
|
@ -682,31 +829,83 @@ export class MerkleTree {
|
|||
return x
|
||||
}
|
||||
|
||||
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
|
||||
/**
|
||||
* print
|
||||
* @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 (value: Buffer) {
|
||||
/**
|
||||
* 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 (value: Buffer) {
|
||||
return '0x' + value.toString('hex')
|
||||
}
|
||||
|
||||
_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')
|
||||
*```
|
||||
*/
|
||||
private _bufferify (x) {
|
||||
return MerkleTree.bufferify(x)
|
||||
}
|
||||
|
||||
_bufferifyFn (f) {
|
||||
/**
|
||||
* 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 (f) {
|
||||
return function (x) {
|
||||
const v = f(x)
|
||||
if (Buffer.isBuffer(v)) {
|
||||
return v
|
||||
}
|
||||
|
||||
if (this._isHexStr(v)) {
|
||||
if (this._isHexString(v)) {
|
||||
return Buffer.from(v, 'hex')
|
||||
}
|
||||
|
||||
|
@ -715,15 +914,45 @@ export class MerkleTree {
|
|||
}
|
||||
}
|
||||
|
||||
_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'))
|
||||
*```
|
||||
*/
|
||||
private _isHexString (v) {
|
||||
return MerkleTree.isHexString(v)
|
||||
}
|
||||
|
||||
_log2 (x) {
|
||||
/**
|
||||
* log2
|
||||
* @desc Returns the log2 of number.
|
||||
* @param {Number} value
|
||||
* @return {Number}
|
||||
*/
|
||||
private _log2 (x) {
|
||||
return x === 1 ? 0 : 1 + this._log2((x / 2) | 0)
|
||||
}
|
||||
|
||||
_zip (a, b) {
|
||||
/**
|
||||
* 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 (a, b) {
|
||||
return a.map((e, i) => [e, b[i]])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "merkletreejs",
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.2",
|
||||
"description": "Construct Merkle Trees and verify proofs",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
|
@ -11,7 +11,7 @@
|
|||
"test": "tape test/*.js",
|
||||
"build": "rm -rf dist/ && tsc",
|
||||
"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 --theme markdown index.ts --out docs --mdEngine github --mdDocusaurus --mdHideSources"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -13,23 +13,59 @@ const { MerkleTree } = require('../')
|
|||
const sha256 = (data) => crypto.createHash('sha256').update(data).digest()
|
||||
|
||||
test('sha256 with keccak leaves', t => {
|
||||
t.plan(1)
|
||||
t.plan(3)
|
||||
|
||||
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
|
||||
const tree = new MerkleTree(leaves, sha256)
|
||||
const root = '311d2e46f49b15fff8b746b74ad57f2cc9e0d9939fda94387141a2d3fdf187ae'
|
||||
|
||||
t.equal(tree.getRoot().toString('hex'), root)
|
||||
t.equal(tree.getHexRoot(), '0x311d2e46f49b15fff8b746b74ad57f2cc9e0d9939fda94387141a2d3fdf187ae')
|
||||
t.deepEqual(tree.getHexLeaves(), [
|
||||
'0x3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb',
|
||||
'0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510',
|
||||
'0x0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2'
|
||||
])
|
||||
t.deepEqual(tree.getHexLayers(), [
|
||||
[
|
||||
'0x3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb',
|
||||
'0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510',
|
||||
'0x0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2'
|
||||
],
|
||||
[
|
||||
'0x176f0f307632fdd5831875eb709e2f68d770b102262998b214ddeb3f04164ae1',
|
||||
'0x0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2'
|
||||
],
|
||||
[
|
||||
'0x311d2e46f49b15fff8b746b74ad57f2cc9e0d9939fda94387141a2d3fdf187ae'
|
||||
]
|
||||
])
|
||||
})
|
||||
|
||||
test('sha256 with keccak leaves with duplicate odd option', t => {
|
||||
t.plan(1)
|
||||
t.plan(3)
|
||||
|
||||
const leaves = ['a', 'b', 'c'].map(x => keccak(x))
|
||||
const tree = new MerkleTree(leaves, sha256, { duplicateOdd: true })
|
||||
const root = 'bcdd0f60308db788712205115fe4273bfda49fa0925611fee765a63df9ab96a1'
|
||||
|
||||
t.equal(tree.getRoot().toString('hex'), root)
|
||||
t.equal(tree.getHexRoot(), '0xbcdd0f60308db788712205115fe4273bfda49fa0925611fee765a63df9ab96a1')
|
||||
t.deepEqual(tree.getHexLeaves(), [
|
||||
'0x3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb',
|
||||
'0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510',
|
||||
'0x0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2'
|
||||
])
|
||||
t.deepEqual(tree.getHexLayers(), [
|
||||
[
|
||||
'0x3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb',
|
||||
'0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510',
|
||||
'0x0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2'
|
||||
],
|
||||
[
|
||||
'0x176f0f307632fdd5831875eb709e2f68d770b102262998b214ddeb3f04164ae1',
|
||||
'0x43e061172b1177f25d0f156b2d2ed11728006fade8e167ff3d1b9dbc979a3358'
|
||||
],
|
||||
[
|
||||
'0xbcdd0f60308db788712205115fe4273bfda49fa0925611fee765a63df9ab96a1'
|
||||
]
|
||||
])
|
||||
})
|
||||
|
||||
test('crypto-js - sha256', t => {
|
||||
|
@ -462,9 +498,21 @@ test('crypto-js bufferify', t => {
|
|||
t.deepEqual(leaves.map(MerkleTree.bufferify), leaves.map(bufferifyCryptoJS))
|
||||
})
|
||||
|
||||
test('sha1', t => {
|
||||
test('bufferify', t => {
|
||||
t.plan(1)
|
||||
|
||||
t.deepEqual(MerkleTree.bufferify('0x1234'), Buffer.from('1234', 'hex'))
|
||||
})
|
||||
|
||||
test('isHexString', t => {
|
||||
t.plan(1)
|
||||
|
||||
t.deepEqual(MerkleTree.isHexString('0x1234'), true)
|
||||
})
|
||||
|
||||
test('sha1', t => {
|
||||
t.plan(2)
|
||||
|
||||
const leaves = [
|
||||
'd89f84d948796605a413e196f40bce1d6294175d',
|
||||
'32f04c7f572bf75a266268c6f4d8c92731dc3b7f',
|
||||
|
@ -481,6 +529,11 @@ test('sha1', t => {
|
|||
const leaf = 'd89f84d948796605a413e196f40bce1d6294175d'
|
||||
const proof = tree.getHexProof(leaf)
|
||||
|
||||
t.deepEqual(proof, [
|
||||
'0xb80b52d80f5fe940ac2c987044bc439e4218ac94',
|
||||
'0x59f544ee5de8d761b124ccd4e1285d3b02a2a539'
|
||||
])
|
||||
|
||||
t.equal(tree.verify(proof, leaf, root), true)
|
||||
})
|
||||
|
||||
|
@ -691,7 +744,7 @@ test('sha256 getMultiProof using tree array', t => {
|
|||
])
|
||||
|
||||
const depth = tree.getDepth()
|
||||
t.equal(depth, Math.log2((treeFlat.length/2)|0))
|
||||
t.equal(depth, Math.log2((treeFlat.length / 2) | 0))
|
||||
|
||||
const tRoot = treeFlat[1]
|
||||
const tLeaves = indices.map(i => leaves[i])
|
||||
|
|
Loading…
Reference in New Issue