merkletreets
Version:
merkletree for freeserver
209 lines (196 loc) • 5.54 kB
text/typescript
/**
* 默克尔树
* Copyright(C) 2018 liumurong
*/
import * as crypto from 'crypto';
/**
* 选项参数
*/
export interface MerkleOptions {
/**
* 叶子节点的个数
*/
leafcount: number;
hashTree?: MerkleTreeOption;
}
/**
* 树的选项参数
*/
export interface MerkleTreeOption {
leaves: string[];
_depth: number;
rows: string[][];
}
/**
* 树节点
*/
export interface MerkleNode {
hash: string,
left: MerkleNode | null,
right: MerkleNode | null,
depth: number,
index: number
}
/**
* MerkleTree
*/
export class MerkleTree {
/**
* 叶节点数组
*/
private leaves: string[];
/**
* 树高度
*/
private _depth: number;
/**
* 树节点
*/
private rows: string[][];
/**
* MerkleTree
* @param opts 选项
*/
constructor(opts: MerkleOptions = { leafcount: 0 }) {
this.leaves = opts.hashTree ? opts.hashTree.leaves : new Array(opts.leafcount).fill(this.hashFunc("0x")); // 默认填充0x字符
this._depth = opts.hashTree ? opts.hashTree._depth : 0;
this.rows = opts.hashTree ? opts.hashTree.rows : [];
}
/**
* 添加节点
* @param data 叶子节点数据
* @param hashed 是否是Hash值
*/
addLeaf(data: Buffer | string, hashed: boolean = false) {
if (hashed === true) {
this.leaves.push(data.toString());
return;
}
this.leaves.push(this.hashFunc(data))
}
/**
* 更新叶子节点
* @param index 叶子节点索引
* @param data 数据
* @param hashed 数据是否直接是Hash值
*/
updateLeaf(index: number, data: Buffer | string, hashed: boolean = false) {
let leafLength = this.leaves.length;
if (leafLength <= index) { // 索引超范围
return;
}
this.leaves[index] = hashed === true ? data.toString() : this.hashFunc(data);
}
/**
* 重新计算整棵树
* 当更新过叶子节点或者添加新节点之后需要重新更新整棵树
* 使用leafcount初始化的树也需要调用此方法
*/
update() {
let depth = this.depth(true);
this.rows = new Array(depth);
this.rows[depth] = this.leaves;
for (let i = depth - 1; i >= 0; i--) {
this.rows[i] = this.getNodes(this.rows[i + 1])
}
}
/**
* 据叶子节点获取上一级节点
* @param leaves 叶子节点
*/
private getNodes(leaves: string[]) {
let remainder = leaves.length % 2;
let nodes: string[] = [];
for (let i = 0; i < leaves.length - 1; i = i + 2) {
nodes[i / 2] = this.hashFunc(leaves[i] + leaves[i + 1]);
}
if (remainder === 1) {
// 将最后一个节点提升等级,并未复制一个新的
nodes[((leaves.length - remainder) / 2)] = leaves[leaves.length - 1];
}
return nodes;
}
/**
* 获取Root节点
*/
root(): MerkleNode {
return <MerkleNode>this.getTreeNode(0, 0);
}
/**
* 获取树节点
* @param depth 深度
* @param index 索引(本层)
*/
getTreeNode(depth: number, index: number): MerkleNode | null {
if (depth < 0 || depth > this.depth()) {
return null;
}
let levelNodes = this.getLevelNodes(depth);
if (index < 0 || index >= levelNodes.length) {
return null;
}
let nextLevelNodes = this.getLevelNodes(depth + 1);
let nextLevelIndex = index * 2;
return {
hash: levelNodes[index],
depth: depth,
index: index,
left: {
hash: nextLevelNodes[nextLevelIndex],
depth: depth + 1,
index: nextLevelIndex,
left: null,
right: null
},
right: nextLevelIndex + 1 >= nextLevelNodes.length ? null : {
hash: nextLevelNodes[nextLevelIndex + 1],
depth: depth + 1,
index: nextLevelIndex + 1,
left: null,
right: null
}
}
}
/**
* 树高
* @param force 强制刷新树高
*/
depth(force: boolean = false): number {
if (!this._depth || force === true) {
let pow = 0;
while (Math.pow(2, pow) < this.leaves.length) {
pow++;
}
this._depth = pow;
}
return this._depth;
}
/**
* 获取此级别的所有节点
* @param level 级别
*/
getLevelNodes(level: number): string[] {
if (level >= this.rows.length) {
return [];
}
return this.rows[level];
}
/**
* 获取叶子节点的hash值
* @param index 叶子节点的索引
*/
getLeafHash(index: number) {
return this.leaves[index];
}
/**
* 计算数据的Hash值,采用sha256算法
* @param data 数据
*/
hashFunc(data: Buffer | string): string {
let hash = crypto.createHash("sha256");
if (Buffer.isBuffer(data)) {
return hash.update(data).digest("hex");
}
return hash.update(Buffer.from(data)).digest("hex");
}
}