mirror of
https://github.com/tornadocash/fixed-merkle-tree.git
synced 2024-11-22 01:37:09 +01:00
upload lib files
This commit is contained in:
parent
1f34fa69fa
commit
2e65f7cac0
42
lib/BaseTree.d.ts
vendored
Normal file
42
lib/BaseTree.d.ts
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
import { Element, HashFunction, ProofPath } from './index';
|
||||
export declare class BaseTree {
|
||||
levels: number;
|
||||
protected _hashFn: HashFunction<Element>;
|
||||
protected zeroElement: Element;
|
||||
protected _zeros: Element[];
|
||||
protected _layers: Array<Element[]>;
|
||||
get capacity(): number;
|
||||
get layers(): Array<Element[]>;
|
||||
get zeros(): Element[];
|
||||
get elements(): Element[];
|
||||
get root(): Element;
|
||||
/**
|
||||
* Find an element in the tree
|
||||
* @param element An element to find
|
||||
* @param comparator A function that checks leaf value equality
|
||||
* @returns {number} Index if element is found, otherwise -1
|
||||
*/
|
||||
indexOf(element: Element, comparator?: <T>(arg0: T, arg1: T) => boolean): number;
|
||||
/**
|
||||
* Insert new element into the tree
|
||||
* @param element Element to insert
|
||||
*/
|
||||
insert(element: Element): void;
|
||||
bulkInsert(elements: Element[]): void;
|
||||
/**
|
||||
* Change an element in the tree
|
||||
* @param {number} index Index of element to change
|
||||
* @param element Updated element value
|
||||
*/
|
||||
update(index: number, element: Element): void;
|
||||
proof(element: Element): ProofPath;
|
||||
/**
|
||||
* Get merkle path to a leaf
|
||||
* @param {number} index Leaf index to generate path for
|
||||
* @returns {{pathElements: Object[], pathIndex: number[]}} An object containing adjacent elements and left-right index
|
||||
*/
|
||||
path(index: number): ProofPath;
|
||||
protected _buildZeros(): void;
|
||||
protected _processNodes(nodes: Element[], layerIndex: number): any[];
|
||||
protected _processUpdate(index: number): void;
|
||||
}
|
156
lib/BaseTree.js
Normal file
156
lib/BaseTree.js
Normal file
@ -0,0 +1,156 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.BaseTree = void 0;
|
||||
class BaseTree {
|
||||
get capacity() {
|
||||
return 2 ** this.levels;
|
||||
}
|
||||
get layers() {
|
||||
return this._layers.slice();
|
||||
}
|
||||
get zeros() {
|
||||
return this._zeros.slice();
|
||||
}
|
||||
get elements() {
|
||||
return this._layers[0].slice();
|
||||
}
|
||||
get root() {
|
||||
var _a;
|
||||
return (_a = this._layers[this.levels][0]) !== null && _a !== void 0 ? _a : this._zeros[this.levels];
|
||||
}
|
||||
/**
|
||||
* Find an element in the tree
|
||||
* @param element An element to find
|
||||
* @param comparator A function that checks leaf value equality
|
||||
* @returns {number} Index if element is found, otherwise -1
|
||||
*/
|
||||
indexOf(element, comparator) {
|
||||
if (comparator) {
|
||||
return this._layers[0].findIndex((el) => comparator(element, el));
|
||||
}
|
||||
else {
|
||||
return this._layers[0].indexOf(element);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Insert new element into the tree
|
||||
* @param element Element to insert
|
||||
*/
|
||||
insert(element) {
|
||||
if (this._layers[0].length >= this.capacity) {
|
||||
throw new Error('Tree is full');
|
||||
}
|
||||
this.update(this._layers[0].length, element);
|
||||
}
|
||||
/*
|
||||
* Insert multiple elements into the tree.
|
||||
* @param {Array} elements Elements to insert
|
||||
*/
|
||||
bulkInsert(elements) {
|
||||
if (!elements.length) {
|
||||
return;
|
||||
}
|
||||
if (this._layers[0].length + elements.length > this.capacity) {
|
||||
throw new Error('Tree is full');
|
||||
}
|
||||
// First we insert all elements except the last one
|
||||
// updating only full subtree hashes (all layers where inserted element has odd index)
|
||||
// the last element will update the full path to the root making the tree consistent again
|
||||
for (let i = 0; i < elements.length - 1; i++) {
|
||||
this._layers[0].push(elements[i]);
|
||||
let level = 0;
|
||||
let index = this._layers[0].length - 1;
|
||||
while (index % 2 === 1) {
|
||||
level++;
|
||||
index >>= 1;
|
||||
const left = this._layers[level - 1][index * 2];
|
||||
const right = this._layers[level - 1][index * 2 + 1];
|
||||
this._layers[level][index] = this._hashFn(left, right);
|
||||
}
|
||||
}
|
||||
this.insert(elements[elements.length - 1]);
|
||||
}
|
||||
/**
|
||||
* Change an element in the tree
|
||||
* @param {number} index Index of element to change
|
||||
* @param element Updated element value
|
||||
*/
|
||||
update(index, element) {
|
||||
if (isNaN(Number(index)) || index < 0 || index > this._layers[0].length || index >= this.capacity) {
|
||||
throw new Error('Insert index out of bounds: ' + index);
|
||||
}
|
||||
this._layers[0][index] = element;
|
||||
this._processUpdate(index);
|
||||
}
|
||||
proof(element) {
|
||||
const index = this.indexOf(element);
|
||||
return this.path(index);
|
||||
}
|
||||
/**
|
||||
* Get merkle path to a leaf
|
||||
* @param {number} index Leaf index to generate path for
|
||||
* @returns {{pathElements: Object[], pathIndex: number[]}} An object containing adjacent elements and left-right index
|
||||
*/
|
||||
path(index) {
|
||||
if (isNaN(Number(index)) || index < 0 || index >= this._layers[0].length) {
|
||||
throw new Error('Index out of bounds: ' + index);
|
||||
}
|
||||
let elIndex = +index;
|
||||
const pathElements = [];
|
||||
const pathIndices = [];
|
||||
const pathPositions = [];
|
||||
for (let level = 0; level < this.levels; level++) {
|
||||
pathIndices[level] = elIndex % 2;
|
||||
const leafIndex = elIndex ^ 1;
|
||||
if (leafIndex < this._layers[level].length) {
|
||||
pathElements[level] = this._layers[level][leafIndex];
|
||||
pathPositions[level] = leafIndex;
|
||||
}
|
||||
else {
|
||||
pathElements[level] = this._zeros[level];
|
||||
pathPositions[level] = 0;
|
||||
}
|
||||
elIndex >>= 1;
|
||||
}
|
||||
return {
|
||||
pathElements,
|
||||
pathIndices,
|
||||
pathPositions,
|
||||
pathRoot: this.root,
|
||||
};
|
||||
}
|
||||
_buildZeros() {
|
||||
this._zeros = [this.zeroElement];
|
||||
for (let i = 1; i <= this.levels; i++) {
|
||||
this._zeros[i] = this._hashFn(this._zeros[i - 1], this._zeros[i - 1]);
|
||||
}
|
||||
}
|
||||
_processNodes(nodes, layerIndex) {
|
||||
const length = nodes.length;
|
||||
let currentLength = Math.ceil(length / 2);
|
||||
const currentLayer = new Array(currentLength);
|
||||
currentLength--;
|
||||
const starFrom = length - ((length % 2) ^ 1);
|
||||
let j = 0;
|
||||
for (let i = starFrom; i >= 0; i -= 2) {
|
||||
if (nodes[i - 1] === undefined)
|
||||
break;
|
||||
const left = nodes[i - 1];
|
||||
const right = (i === starFrom && length % 2 === 1) ? this._zeros[layerIndex - 1] : nodes[i];
|
||||
currentLayer[currentLength - j] = this._hashFn(left, right);
|
||||
j++;
|
||||
}
|
||||
return currentLayer;
|
||||
}
|
||||
_processUpdate(index) {
|
||||
for (let level = 1; level <= this.levels; level++) {
|
||||
index >>= 1;
|
||||
const left = this._layers[level - 1][index * 2];
|
||||
const right = index * 2 + 1 < this._layers[level - 1].length
|
||||
? this._layers[level - 1][index * 2 + 1]
|
||||
: this._zeros[level - 1];
|
||||
this._layers[level][index] = this._hashFn(left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.BaseTree = BaseTree;
|
30
lib/FixedMerkleTree.d.ts
vendored
Normal file
30
lib/FixedMerkleTree.d.ts
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
import { Element, HashFunction, MerkleTreeOptions, SerializedTreeState, TreeEdge, TreeSlice } from './';
|
||||
import { BaseTree } from './BaseTree';
|
||||
export default class MerkleTree extends BaseTree {
|
||||
constructor(levels: number, elements?: Element[], { hashFunction, zeroElement, }?: MerkleTreeOptions);
|
||||
private _buildHashes;
|
||||
/**
|
||||
* Insert multiple elements into the tree.
|
||||
* @param {Array} elements Elements to insert
|
||||
*/
|
||||
bulkInsert(elements: Element[]): void;
|
||||
getTreeEdge(edgeIndex: number): TreeEdge;
|
||||
/**
|
||||
* 🪓
|
||||
* @param count
|
||||
*/
|
||||
getTreeSlices(count?: number): TreeSlice[];
|
||||
/**
|
||||
* Serialize entire tree state including intermediate layers into a plain object
|
||||
* Deserializing it back will not require to recompute any hashes
|
||||
* Elements are not converted to a plain type, this is responsibility of the caller
|
||||
*/
|
||||
serialize(): SerializedTreeState;
|
||||
/**
|
||||
* Deserialize data into a MerkleTree instance
|
||||
* Make sure to provide the same hashFunction as was used in the source tree,
|
||||
* otherwise the tree state will be invalid
|
||||
*/
|
||||
static deserialize(data: SerializedTreeState, hashFunction?: HashFunction<Element>): MerkleTree;
|
||||
toString(): string;
|
||||
}
|
104
lib/FixedMerkleTree.js
Normal file
104
lib/FixedMerkleTree.js
Normal file
@ -0,0 +1,104 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const simpleHash_1 = __importDefault(require("./simpleHash"));
|
||||
const BaseTree_1 = require("./BaseTree");
|
||||
class MerkleTree extends BaseTree_1.BaseTree {
|
||||
constructor(levels, elements = [], { hashFunction = simpleHash_1.default, zeroElement = 0, } = {}) {
|
||||
super();
|
||||
this.levels = levels;
|
||||
if (elements.length > this.capacity) {
|
||||
throw new Error('Tree is full');
|
||||
}
|
||||
this._hashFn = hashFunction;
|
||||
this.zeroElement = zeroElement;
|
||||
this._layers = [];
|
||||
const leaves = elements.slice();
|
||||
this._layers = [leaves];
|
||||
this._buildZeros();
|
||||
this._buildHashes();
|
||||
}
|
||||
_buildHashes() {
|
||||
for (let layerIndex = 1; layerIndex <= this.levels; layerIndex++) {
|
||||
const nodes = this._layers[layerIndex - 1];
|
||||
this._layers[layerIndex] = this._processNodes(nodes, layerIndex);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Insert multiple elements into the tree.
|
||||
* @param {Array} elements Elements to insert
|
||||
*/
|
||||
bulkInsert(elements) {
|
||||
if (!elements.length) {
|
||||
return;
|
||||
}
|
||||
if (this._layers[0].length + elements.length > this.capacity) {
|
||||
throw new Error('Tree is full');
|
||||
}
|
||||
// First we insert all elements except the last one
|
||||
// updating only full subtree hashes (all layers where inserted element has odd index)
|
||||
// the last element will update the full path to the root making the tree consistent again
|
||||
for (let i = 0; i < elements.length - 1; i++) {
|
||||
this._layers[0].push(elements[i]);
|
||||
let level = 0;
|
||||
let index = this._layers[0].length - 1;
|
||||
while (index % 2 === 1) {
|
||||
level++;
|
||||
index >>= 1;
|
||||
this._layers[level][index] = this._hashFn(this._layers[level - 1][index * 2], this._layers[level - 1][index * 2 + 1]);
|
||||
}
|
||||
}
|
||||
this.insert(elements[elements.length - 1]);
|
||||
}
|
||||
getTreeEdge(edgeIndex) {
|
||||
const edgeElement = this._layers[0][edgeIndex];
|
||||
if (edgeElement === undefined) {
|
||||
throw new Error('Element not found');
|
||||
}
|
||||
const edgePath = this.path(edgeIndex);
|
||||
return { edgePath, edgeElement, edgeIndex, edgeElementsCount: this._layers[0].length };
|
||||
}
|
||||
/**
|
||||
* 🪓
|
||||
* @param count
|
||||
*/
|
||||
getTreeSlices(count = 4) {
|
||||
const length = this._layers[0].length;
|
||||
let size = Math.ceil(length / count);
|
||||
if (size % 2)
|
||||
size++;
|
||||
const slices = [];
|
||||
for (let i = 0; i < length; i += size) {
|
||||
const edgeLeft = i;
|
||||
const edgeRight = i + size;
|
||||
slices.push({ edge: this.getTreeEdge(edgeLeft), elements: this.elements.slice(edgeLeft, edgeRight) });
|
||||
}
|
||||
return slices;
|
||||
}
|
||||
/**
|
||||
* Serialize entire tree state including intermediate layers into a plain object
|
||||
* Deserializing it back will not require to recompute any hashes
|
||||
* Elements are not converted to a plain type, this is responsibility of the caller
|
||||
*/
|
||||
serialize() {
|
||||
return {
|
||||
levels: this.levels,
|
||||
_zeros: this._zeros,
|
||||
_layers: this._layers,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Deserialize data into a MerkleTree instance
|
||||
* Make sure to provide the same hashFunction as was used in the source tree,
|
||||
* otherwise the tree state will be invalid
|
||||
*/
|
||||
static deserialize(data, hashFunction) {
|
||||
return new MerkleTree(data.levels, data._layers[0], { hashFunction, zeroElement: data._zeros[0] });
|
||||
}
|
||||
toString() {
|
||||
return JSON.stringify(this.serialize());
|
||||
}
|
||||
}
|
||||
exports.default = MerkleTree;
|
33
lib/PartialMerkleTree.d.ts
vendored
Normal file
33
lib/PartialMerkleTree.d.ts
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
import { Element, HashFunction, MerkleTreeOptions, ProofPath, SerializedPartialTreeState, TreeEdge } from './';
|
||||
import { BaseTree } from './BaseTree';
|
||||
export declare class PartialMerkleTree extends BaseTree {
|
||||
private _leaves;
|
||||
private _leavesAfterEdge;
|
||||
private _edgeLeaf;
|
||||
private _initialRoot;
|
||||
private _edgeLeafProof;
|
||||
private _proofMap;
|
||||
constructor(levels: number, { edgePath, edgeElement, edgeIndex, edgeElementsCount, }: TreeEdge, leaves: Element[], { hashFunction, zeroElement }?: MerkleTreeOptions);
|
||||
get edgeIndex(): number;
|
||||
get edgeElement(): Element;
|
||||
get edgeLeafProof(): ProofPath;
|
||||
private _createProofMap;
|
||||
private _buildTree;
|
||||
private _buildHashes;
|
||||
/**
|
||||
* Change an element in the tree
|
||||
* @param {number} index Index of element to change
|
||||
* @param element Updated element value
|
||||
*/
|
||||
update(index: number, element: Element): void;
|
||||
path(index: number): ProofPath;
|
||||
/**
|
||||
* Shifts edge of tree to left
|
||||
* @param edge new TreeEdge below current edge
|
||||
* @param elements leaves between old and new edge
|
||||
*/
|
||||
shiftEdge(edge: TreeEdge, elements: Element[]): void;
|
||||
serialize(): SerializedPartialTreeState;
|
||||
static deserialize(data: SerializedPartialTreeState, hashFunction?: HashFunction<Element>): PartialMerkleTree;
|
||||
toString(): string;
|
||||
}
|
155
lib/PartialMerkleTree.js
Normal file
155
lib/PartialMerkleTree.js
Normal file
@ -0,0 +1,155 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.PartialMerkleTree = void 0;
|
||||
const simpleHash_1 = __importDefault(require("./simpleHash"));
|
||||
const BaseTree_1 = require("./BaseTree");
|
||||
class PartialMerkleTree extends BaseTree_1.BaseTree {
|
||||
constructor(levels, { edgePath, edgeElement, edgeIndex, edgeElementsCount, }, leaves, { hashFunction, zeroElement } = {}) {
|
||||
super();
|
||||
if (edgeIndex + leaves.length !== edgeElementsCount)
|
||||
throw new Error('Invalid number of elements');
|
||||
this._edgeLeafProof = edgePath;
|
||||
this._initialRoot = edgePath.pathRoot;
|
||||
this.zeroElement = zeroElement !== null && zeroElement !== void 0 ? zeroElement : 0;
|
||||
this._edgeLeaf = { data: edgeElement, index: edgeIndex };
|
||||
this._leavesAfterEdge = leaves;
|
||||
this.levels = levels;
|
||||
this._hashFn = hashFunction || simpleHash_1.default;
|
||||
this._createProofMap();
|
||||
this._buildTree();
|
||||
}
|
||||
get edgeIndex() {
|
||||
return this._edgeLeaf.index;
|
||||
}
|
||||
get edgeElement() {
|
||||
return this._edgeLeaf.data;
|
||||
}
|
||||
get edgeLeafProof() {
|
||||
return this._edgeLeafProof;
|
||||
}
|
||||
_createProofMap() {
|
||||
this._proofMap = this.edgeLeafProof.pathPositions.reduce((p, c, i) => {
|
||||
p.set(i, [c, this.edgeLeafProof.pathElements[i]]);
|
||||
return p;
|
||||
}, new Map());
|
||||
this._proofMap.set(this.levels, [0, this.edgeLeafProof.pathRoot]);
|
||||
}
|
||||
_buildTree() {
|
||||
const edgeLeafIndex = this._edgeLeaf.index;
|
||||
this._leaves = Array(edgeLeafIndex).concat(this._leavesAfterEdge);
|
||||
if (this._proofMap.has(0)) {
|
||||
const [proofPos, proofEl] = this._proofMap.get(0);
|
||||
this._leaves[proofPos] = proofEl;
|
||||
}
|
||||
this._layers = [this._leaves];
|
||||
this._buildZeros();
|
||||
this._buildHashes();
|
||||
}
|
||||
_buildHashes() {
|
||||
for (let layerIndex = 1; layerIndex <= this.levels; layerIndex++) {
|
||||
const nodes = this._layers[layerIndex - 1];
|
||||
const currentLayer = this._processNodes(nodes, layerIndex);
|
||||
if (this._proofMap.has(layerIndex)) {
|
||||
const [proofPos, proofEl] = this._proofMap.get(layerIndex);
|
||||
if (!currentLayer[proofPos])
|
||||
currentLayer[proofPos] = proofEl;
|
||||
}
|
||||
this._layers[layerIndex] = currentLayer;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Change an element in the tree
|
||||
* @param {number} index Index of element to change
|
||||
* @param element Updated element value
|
||||
*/
|
||||
update(index, element) {
|
||||
if (isNaN(Number(index)) || index < 0 || index > this._layers[0].length || index >= this.capacity) {
|
||||
throw new Error('Insert index out of bounds: ' + index);
|
||||
}
|
||||
if (index < this._edgeLeaf.index) {
|
||||
throw new Error(`Index ${index} is below the edge: ${this._edgeLeaf.index}`);
|
||||
}
|
||||
this._layers[0][index] = element;
|
||||
this._processUpdate(index);
|
||||
}
|
||||
path(index) {
|
||||
if (isNaN(Number(index)) || index < 0 || index >= this._layers[0].length) {
|
||||
throw new Error('Index out of bounds: ' + index);
|
||||
}
|
||||
if (index < this._edgeLeaf.index) {
|
||||
throw new Error(`Index ${index} is below the edge: ${this._edgeLeaf.index}`);
|
||||
}
|
||||
let elIndex = Number(index);
|
||||
const pathElements = [];
|
||||
const pathIndices = [];
|
||||
const pathPositions = [];
|
||||
for (let level = 0; level < this.levels; level++) {
|
||||
pathIndices[level] = elIndex % 2;
|
||||
const leafIndex = elIndex ^ 1;
|
||||
if (leafIndex < this._layers[level].length) {
|
||||
const [proofPos, proofEl] = this._proofMap.get(level);
|
||||
pathElements[level] = proofPos === leafIndex ? proofEl : this._layers[level][leafIndex];
|
||||
pathPositions[level] = leafIndex;
|
||||
}
|
||||
else {
|
||||
pathElements[level] = this._zeros[level];
|
||||
pathPositions[level] = 0;
|
||||
}
|
||||
elIndex >>= 1;
|
||||
}
|
||||
return {
|
||||
pathElements,
|
||||
pathIndices,
|
||||
pathPositions,
|
||||
pathRoot: this.root,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Shifts edge of tree to left
|
||||
* @param edge new TreeEdge below current edge
|
||||
* @param elements leaves between old and new edge
|
||||
*/
|
||||
shiftEdge(edge, elements) {
|
||||
if (this._edgeLeaf.index <= edge.edgeIndex) {
|
||||
throw new Error(`New edgeIndex should be smaller then ${this._edgeLeaf.index}`);
|
||||
}
|
||||
if (elements.length !== (this._edgeLeaf.index - edge.edgeIndex)) {
|
||||
throw new Error(`Elements length should be ${this._edgeLeaf.index - edge.edgeIndex}`);
|
||||
}
|
||||
this._edgeLeafProof = edge.edgePath;
|
||||
this._edgeLeaf = { index: edge.edgeIndex, data: edge.edgeElement };
|
||||
this._leavesAfterEdge = [...elements, ...this._leavesAfterEdge];
|
||||
this._createProofMap();
|
||||
this._buildTree();
|
||||
}
|
||||
serialize() {
|
||||
const leaves = this.layers[0].slice(this._edgeLeaf.index);
|
||||
return {
|
||||
_edgeLeafProof: this._edgeLeafProof,
|
||||
_edgeLeaf: this._edgeLeaf,
|
||||
_edgeElementsCount: this._layers[0].length,
|
||||
levels: this.levels,
|
||||
leaves,
|
||||
_zeros: this._zeros,
|
||||
};
|
||||
}
|
||||
static deserialize(data, hashFunction) {
|
||||
const edge = {
|
||||
edgePath: data._edgeLeafProof,
|
||||
edgeElement: data._edgeLeaf.data,
|
||||
edgeIndex: data._edgeLeaf.index,
|
||||
edgeElementsCount: data._edgeElementsCount,
|
||||
};
|
||||
return new PartialMerkleTree(data.levels, edge, data.leaves, {
|
||||
hashFunction,
|
||||
zeroElement: data._zeros[0],
|
||||
});
|
||||
}
|
||||
toString() {
|
||||
return JSON.stringify(this.serialize());
|
||||
}
|
||||
}
|
||||
exports.PartialMerkleTree = PartialMerkleTree;
|
44
lib/index.d.ts
vendored
Normal file
44
lib/index.d.ts
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
export { default as MerkleTree } from './FixedMerkleTree';
|
||||
export { PartialMerkleTree } from './PartialMerkleTree';
|
||||
export { simpleHash } from './simpleHash';
|
||||
export declare type HashFunction<T> = {
|
||||
(left: T, right: T): string;
|
||||
};
|
||||
export declare type MerkleTreeOptions = {
|
||||
hashFunction?: HashFunction<Element>;
|
||||
zeroElement?: Element;
|
||||
};
|
||||
export declare type Element = string | number;
|
||||
export declare type SerializedTreeState = {
|
||||
levels: number;
|
||||
_zeros: Array<Element>;
|
||||
_layers: Array<Element[]>;
|
||||
};
|
||||
export declare type SerializedPartialTreeState = {
|
||||
levels: number;
|
||||
leaves: Element[];
|
||||
_edgeElementsCount: number;
|
||||
_zeros: Array<Element>;
|
||||
_edgeLeafProof: ProofPath;
|
||||
_edgeLeaf: LeafWithIndex;
|
||||
};
|
||||
export declare type ProofPath = {
|
||||
pathElements: Element[];
|
||||
pathIndices: number[];
|
||||
pathPositions: number[];
|
||||
pathRoot: Element;
|
||||
};
|
||||
export declare type TreeEdge = {
|
||||
edgeElement: Element;
|
||||
edgePath: ProofPath;
|
||||
edgeIndex: number;
|
||||
edgeElementsCount: number;
|
||||
};
|
||||
export declare type TreeSlice = {
|
||||
edge: TreeEdge;
|
||||
elements: Element[];
|
||||
};
|
||||
export declare type LeafWithIndex = {
|
||||
index: number;
|
||||
data: Element;
|
||||
};
|
12
lib/index.js
Normal file
12
lib/index.js
Normal file
@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.simpleHash = exports.PartialMerkleTree = exports.MerkleTree = void 0;
|
||||
var FixedMerkleTree_1 = require("./FixedMerkleTree");
|
||||
Object.defineProperty(exports, "MerkleTree", { enumerable: true, get: function () { return __importDefault(FixedMerkleTree_1).default; } });
|
||||
var PartialMerkleTree_1 = require("./PartialMerkleTree");
|
||||
Object.defineProperty(exports, "PartialMerkleTree", { enumerable: true, get: function () { return PartialMerkleTree_1.PartialMerkleTree; } });
|
||||
var simpleHash_1 = require("./simpleHash");
|
||||
Object.defineProperty(exports, "simpleHash", { enumerable: true, get: function () { return simpleHash_1.simpleHash; } });
|
10
lib/simpleHash.d.ts
vendored
Normal file
10
lib/simpleHash.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
import { Element } from './index';
|
||||
/***
|
||||
* This is insecure hash function, just for example only
|
||||
* @param data
|
||||
* @param seed
|
||||
* @param hashLength
|
||||
*/
|
||||
export declare function simpleHash<T>(data: T[], seed?: number, hashLength?: number): string;
|
||||
declare const _default: (left: Element, right: Element) => string;
|
||||
export default _default;
|
21
lib/simpleHash.js
Normal file
21
lib/simpleHash.js
Normal file
@ -0,0 +1,21 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.simpleHash = void 0;
|
||||
/***
|
||||
* This is insecure hash function, just for example only
|
||||
* @param data
|
||||
* @param seed
|
||||
* @param hashLength
|
||||
*/
|
||||
function simpleHash(data, seed, hashLength = 40) {
|
||||
const str = data.join('');
|
||||
let i, l, hval = seed !== null && seed !== void 0 ? seed : 0x811c9dcc5;
|
||||
for (i = 0, l = str.length; i < l; i++) {
|
||||
hval ^= str.charCodeAt(i);
|
||||
hval += (hval << 1) + (hval << 4) + (hval << 6) + (hval << 8) + (hval << 24);
|
||||
}
|
||||
const hash = (hval >>> 0).toString(16);
|
||||
return BigInt('0x' + hash.padEnd(hashLength - (hash.length - 1), '0')).toString(10);
|
||||
}
|
||||
exports.simpleHash = simpleHash;
|
||||
exports.default = (left, right) => simpleHash([left, right]);
|
Loading…
Reference in New Issue
Block a user