Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f86cc10c1 | ||
|
|
8ec8ffe58b | ||
|
|
3aff8f4515 | ||
|
|
6663aec38c | ||
|
|
a74ece28cd |
6
.github/workflows/nodejs.yml
vendored
6
.github/workflows/nodejs.yml
vendored
@@ -15,8 +15,7 @@ jobs:
|
||||
with:
|
||||
node-version: 14.7.0
|
||||
- run: npm ci
|
||||
- name: Running tests
|
||||
run: npm run test
|
||||
- run: npm run test
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -26,8 +25,7 @@ jobs:
|
||||
with:
|
||||
node-version: 14.7.0
|
||||
- run: npm ci
|
||||
- name: Linting
|
||||
run: npm run lint
|
||||
- run: npm run lint
|
||||
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
This is a fixed depth merkle tree implementation with sequential inserts
|
||||
|
||||
Requires Node.js >= 14
|
||||
|
||||
## Usage
|
||||
|
||||
```javascript
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "fixed-merkle-tree",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.1",
|
||||
"description": "Fixed depth merkle tree implementation with sequential inserts",
|
||||
"main": "src/merkleTree.js",
|
||||
"scripts": {
|
||||
@@ -10,6 +10,7 @@
|
||||
"keywords": ["merkle", "tree", "merkleTree"],
|
||||
"author": "Roman Semenov <semenov.roma@gmail.com>",
|
||||
"license": "ISC",
|
||||
"files": ["src/*"],
|
||||
"dependencies": {
|
||||
"snarkjs": "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5",
|
||||
"circomlib": "git+https://github.com/tornadocash/circomlib.git#c372f14d324d57339c88451834bf2824e73bbdbc"
|
||||
|
||||
@@ -18,14 +18,15 @@ class MerkleTree {
|
||||
* Constructor
|
||||
* @param {number} levels Number of levels in the tree
|
||||
* @param {Array} [elements] Initial elements
|
||||
* @param [zeroElement] Value for non-existent leaves
|
||||
* @param {hashFunction} [hashFunction] Function used to hash 2 leaves
|
||||
* @param {Object} options
|
||||
* @param {hashFunction} [options.hashFunction] Function used to hash 2 leaves
|
||||
* @param [options.zeroElement] Value for non-existent leaves
|
||||
*/
|
||||
constructor(levels, elements = [], zeroElement = DEFAULT_ZERO, hashFunction) {
|
||||
constructor(levels, elements = [], { hashFunction, zeroElement = DEFAULT_ZERO } = {}) {
|
||||
this.levels = levels
|
||||
this.capacity = 2 << levels
|
||||
this.zeroElement = zeroElement
|
||||
this._hash = hashFunction ?? defaultHash
|
||||
this._hash = hashFunction || defaultHash
|
||||
|
||||
this._zeros = []
|
||||
this._layers = []
|
||||
@@ -43,7 +44,9 @@ class MerkleTree {
|
||||
for (let i = 0; i < Math.ceil(this._layers[level - 1].length / 2); i++) {
|
||||
this._layers[level][i] = this._hash(
|
||||
this._layers[level - 1][i * 2],
|
||||
this._layers[level - 1]?.[i * 2 + 1] ?? this._zeros[level - 1],
|
||||
i * 2 + 1 < this._layers[level - 1].length ?
|
||||
this._layers[level - 1][i * 2 + 1] :
|
||||
this._zeros[level - 1],
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -54,7 +57,7 @@ class MerkleTree {
|
||||
* @returns {*}
|
||||
*/
|
||||
root() {
|
||||
return this._layers[this.levels]?.[0] ?? this._zeros[this.levels]
|
||||
return this._layers[this.levels].length > 0 ? this._layers[this.levels][0] : this._zeros[this.levels]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,7 +97,9 @@ class MerkleTree {
|
||||
index >>= 1
|
||||
this._layers[level][index] = this._hash(
|
||||
this._layers[level - 1][index * 2],
|
||||
this._layers[level - 1]?.[index * 2 + 1] ?? this._zeros[level - 1],
|
||||
index * 2 + 1 < this._layers[level - 1].length ?
|
||||
this._layers[level - 1][index * 2 + 1] :
|
||||
this._zeros[level - 1],
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -109,15 +114,17 @@ class MerkleTree {
|
||||
throw new Error('Index out of bounds: ' + index)
|
||||
}
|
||||
const pathElements = []
|
||||
const pathIndex = []
|
||||
const pathIndices = []
|
||||
for (let level = 0; level < this.levels; level++) {
|
||||
pathIndex[level] = index % 2
|
||||
pathElements[level] = this._layers[level]?.[index ^ 1] ?? this._zeros[level]
|
||||
pathIndices[level] = index % 2
|
||||
pathElements[level] = (index ^ 1) < this._layers[level].length ?
|
||||
this._layers[level][index ^ 1] :
|
||||
this._zeros[level]
|
||||
index >>= 1
|
||||
}
|
||||
return {
|
||||
pathElements,
|
||||
pathIndex,
|
||||
pathIndices,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +136,14 @@ class MerkleTree {
|
||||
indexOf(element) {
|
||||
return this._layers[0].indexOf(element)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of non-zero tree elements
|
||||
* @returns {Object[]}
|
||||
*/
|
||||
elements() {
|
||||
return this._layers[0].slice()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MerkleTree
|
||||
|
||||
@@ -89,7 +89,7 @@ describe('MerkleTree', () => {
|
||||
it('should work for even index', () => {
|
||||
const tree = new MerkleTree(10, [1, 2, 3, 4, 5])
|
||||
const proof = tree.proof(2)
|
||||
proof.pathIndex.should.be.deep.equal([0, 1, 0, 0, 0, 0, 0, 0, 0, 0])
|
||||
proof.pathIndices.should.be.deep.equal([0, 1, 0, 0, 0, 0, 0, 0, 0, 0])
|
||||
proof.pathElements.should.be.deep.equal([
|
||||
4,
|
||||
'19814528709687996974327303300007262407299502847885145507292406548098437687919',
|
||||
@@ -107,7 +107,7 @@ describe('MerkleTree', () => {
|
||||
it('should work for odd index', () => {
|
||||
const tree = new MerkleTree(10, [1, 2, 3, 4, 5])
|
||||
const proof = tree.proof(3)
|
||||
proof.pathIndex.should.be.deep.equal([1, 1, 0, 0, 0, 0, 0, 0, 0, 0])
|
||||
proof.pathIndices.should.be.deep.equal([1, 1, 0, 0, 0, 0, 0, 0, 0, 0])
|
||||
proof.pathElements.should.be.deep.equal([
|
||||
3,
|
||||
'19814528709687996974327303300007262407299502847885145507292406548098437687919',
|
||||
|
||||
Reference in New Issue
Block a user