sort leaves option

This commit is contained in:
Miguel Mota 2019-06-07 15:15:16 -07:00
parent d84aa0e8a9
commit 882236e603
No known key found for this signature in database
GPG Key ID: 67EC1161588A00F9
6 changed files with 95 additions and 46 deletions

View File

@ -91,7 +91,7 @@ Output
## Documentation
<!-- :%s// -->
<!-- :%s/// -->
<!-- :%s/\[Options\]()/\[Options\](#options) -->
## Class
@ -116,7 +116,8 @@ Class reprensenting a Merkle Tree
* [isBitcoinTree](#isbitcointree)
* [layers](#layers)
* [leaves](#leaves)
* [sort](#sort)
* [sortLeaves](#sortleaves)
* [sortPairs](#sortpairs)
### Methods
@ -133,13 +134,15 @@ Class reprensenting a Merkle Tree
* [bufferify](#bufferify)
* [print](#print-1)
---
## Constructors
<a id="constructor"></a>
### constructor
**new MerkleTree**(leaves: *`any`*, hashAlgorithm: *`any`*, options?: *[Options](#options)
**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.
@ -164,10 +167,12 @@ const tree = new MerkleTree(leaves, sha256)
| ------ | ------ | ------ | ------ |
| 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](#options) | {} as any | Additional options |
| `Default value` options | [Options]() | {} as any | Additional options |
**Returns:** [MerkleTree]()
___
## Properties
<a id="duplicateodd"></a>
@ -223,11 +228,18 @@ ___
**● leaves**: *`any`[]*
___
<a id="sort"></a>
<a id="sortleaves"></a>
### sort
### sortLeaves
**● sort**: *`boolean`*
**● sortLeaves**: *`boolean`*
___
<a id="sortpairs"></a>
### sortPairs
**● sortPairs**: *`boolean`*
___
@ -432,6 +444,16 @@ ___
## Options
### Properties
* [duplicateOdd](#duplicateodd)
* [hashLeaves](#hashleaves)
* [isBitcoinTree](#isbitcointree)
* [sortLeaves](#sortleaves)
* [sortPairs](#sortpairs)
---
## Properties
<a id="duplicateodd"></a>
@ -461,14 +483,22 @@ ___
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="sort"></a>
<a id="sortleaves"></a>
### sort
### sortLeaves
**● sort**: *`boolean`*
**● sortLeaves**: *`boolean`*
If set to `true`, the leaves and hashing pairs will be sorted.
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

9
dist/index.d.ts vendored
View File

@ -5,8 +5,10 @@ interface Options {
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 and hashing pairs will be sorted. */
sort: boolean;
/** If set to `true`, the leaves will be sorted. */
sortLeaves: boolean;
/** If set to `true`, the hashing pairs will be sorted. */
sortPairs: boolean;
}
/**
* Class reprensenting a Merkle Tree
@ -19,7 +21,8 @@ export declare class MerkleTree {
isBitcoinTree: boolean;
leaves: any[];
layers: any[];
sort: boolean;
sortLeaves: boolean;
sortPairs: boolean;
/**
* @desc Constructs a Merkle Tree.
* All nodes and leaves are stored as Buffers.

19
dist/index.js vendored
View File

@ -34,13 +34,17 @@ var MerkleTree = /** @class */ (function () {
if (options === void 0) { options = {}; }
this.isBitcoinTree = !!options.isBitcoinTree;
this.hashLeaves = !!options.hashLeaves;
this.sort = !!options.sort;
this.sortLeaves = !!options.sortLeaves;
this.sortPairs = !!options.sortPairs;
this.duplicateOdd = !!options.duplicateOdd;
this.hashAlgo = bufferifyFn(hashAlgorithm);
if (this.hashLeaves) {
leaves = leaves.map(this.hashAlgo);
}
this.leaves = leaves.map(bufferify);
if (this.sortLeaves) {
this.leaves = this.leaves.sort(Buffer.compare);
}
this.layers = [this.leaves];
this.createHashes(this.leaves);
}
@ -74,20 +78,17 @@ var MerkleTree = /** @class */ (function () {
var left = nodes[i];
var right = i + 1 == nodes.length ? left : nodes[i + 1];
var data = null;
var combined = null;
if (this.isBitcoinTree) {
var combined = [reverse(left), reverse(right)];
if (this.sort) {
combined.sort(Buffer.compare);
}
data = Buffer.concat(combined);
combined = [reverse(left), reverse(right)];
}
else {
var combined = [left, right];
if (this.sort) {
combined = [left, right];
}
if (this.sortPairs) {
combined.sort(Buffer.compare);
}
data = Buffer.concat(combined);
}
var hash = this.hashAlgo(data);
// double hash if bitcoin tree
if (this.isBitcoinTree) {

View File

@ -9,8 +9,10 @@ interface Options {
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 and hashing pairs will be sorted. */
sort: boolean
/** If set to `true`, the leaves will be sorted. */
sortLeaves: boolean
/** If set to `true`, the hashing pairs will be sorted. */
sortPairs: boolean
}
@ -25,7 +27,8 @@ export class MerkleTree {
isBitcoinTree: boolean
leaves: any[]
layers: any[]
sort: boolean
sortLeaves: boolean
sortPairs: boolean
/**
* @desc Constructs a Merkle Tree.
@ -52,7 +55,8 @@ export class MerkleTree {
constructor(leaves, hashAlgorithm, options:Options={} as any) {
this.isBitcoinTree = !!options.isBitcoinTree
this.hashLeaves = !!options.hashLeaves
this.sort = !!options.sort
this.sortLeaves = !!options.sortLeaves
this.sortPairs = !!options.sortPairs
this.duplicateOdd = !!options.duplicateOdd
this.hashAlgo = bufferifyFn(hashAlgorithm)
if (this.hashLeaves) {
@ -60,6 +64,10 @@ export class MerkleTree {
}
this.leaves = leaves.map(bufferify)
if (this.sortLeaves) {
this.leaves = this.leaves.sort(Buffer.compare)
}
this.layers = [this.leaves]
this.createHashes(this.leaves)
}
@ -101,22 +109,19 @@ export class MerkleTree {
const left = nodes[i]
const right = i + 1 == nodes.length ? left : nodes[i + 1];
let data = null
let combined = null
if (this.isBitcoinTree) {
let combined = [reverse(left), reverse(right)]
if (this.sort) {
combined.sort(Buffer.compare)
}
data = Buffer.concat(combined)
combined = [reverse(left), reverse(right)]
} else {
let combined = [left, right]
if (this.sort) {
combined = [left, right]
}
if (this.sortPairs) {
combined.sort(Buffer.compare)
}
data = Buffer.concat(combined)
}
let hash = this.hashAlgo(data)

View File

@ -1,6 +1,6 @@
{
"name": "merkletreejs",
"version": "0.1.0",
"version": "0.1.1",
"description": "Construct Merkle Trees and verify proofs",
"main": "dist/index.js",
"types": "typings/merkletreejs/*",

View File

@ -39,21 +39,31 @@ test('crypto-js - sha256', t => {
t.equal(tree.getRoot().toString('hex'), root)
})
test('sha256 with sort option', t => {
test('sha256 with sort pairs option', t => {
t.plan(1)
const leaves = ['a', 'b', 'c', 'd', 'e', 'f'].map(x => sha256(x))
const tree = new MerkleTree(leaves, sha256, {sort: true})
const tree = new MerkleTree(leaves, sha256, {sortPairs: true})
const root = 'a30ba95a1a5dc397fe45ea20105363b08d682b864a28f4940419a29349a28325'
t.equal(tree.getRoot().toString('hex'), root)
})
test('sha256 with sha256 leaves and sort option and duplicate odd option', t => {
test('sha3 with sort leaves and sort pairs option', t => {
t.plan(1)
const leaves = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'].map(x => sha3(x))
const tree = new MerkleTree(leaves, sha3, {sortLeaves: true, sortPairs: true})
const root = '60219f87561939610b484575e45c6e81156a53b86d7cd16640d930d14f21758e'
t.equal(tree.getRoot().toString('hex'), root)
})
test('sha256 with sha256 leaves and sort pairs option and duplicate odd option', t => {
t.plan(1)
const leaves = ['a', 'b', 'c', 'd', 'e', 'f'].map(x => sha256(x))
const tree = new MerkleTree(leaves, sha256, {sort: true, duplicateOdd: true})
const tree = new MerkleTree(leaves, sha256, {sortPairs: true, duplicateOdd: true})
const root = 'a5260b2a7ec31584e5d5689a5628c2b3d949e2397334fd71c107478e5f887eaf'
t.equal(tree.getRoot().toString('hex'), root)