@chainsafe/eth2.0-utils
Version:
Utilities required across multiple lodestar packages
132 lines (98 loc) • 3.08 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.LightProgressiveMerkleTree = void 0;
var _crypto = require("../crypto");
var _math = require("../math");
var _assert = _interopRequireDefault(require("assert"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
/**
* Only usable if we need proof and root of adding single element.
* Element proof gets invalid if you add another element.
*/
class LightProgressiveMerkleTree {
constructor(depth) {
_defineProperty(this, "_depth", void 0);
_defineProperty(this, "_count", void 0);
_defineProperty(this, "_branch", void 0);
_defineProperty(this, "_zerohashes", void 0);
(0, _assert.default)(depth <= 52, "tree depth must be less than 53");
this._depth = depth;
this._count = 0;
this._branch = Array.from({
length: depth
}, () => Buffer.alloc(32));
this._zerohashes = Array.from({
length: depth
}, () => Buffer.alloc(32));
for (let i = 0; i < depth - 1; i++) {
this._zerohashes[i + 1] = this._branch[i + 1] = (0, _crypto.hash)(Buffer.concat([this._zerohashes[i], this._zerohashes[i]]));
}
}
count() {
return this._count;
}
depth() {
return this._depth;
}
push(item) {
const depth = this._depth;
const proof = this._proof();
this._count++;
let i = 0;
let powerOfTwo = 2;
for (let j = 0; j < depth; j++) {
if (this._count % powerOfTwo !== 0) {
break;
}
i++;
powerOfTwo *= 2;
}
let value = item;
for (let j = 0; j < depth; j++) {
if (j < i) {
value = (0, _crypto.hash)(Buffer.concat([this._branch[j], value]));
} else {
break;
}
}
this._branch[i] = value;
return proof;
}
clone() {
const cloned = Object.create(LightProgressiveMerkleTree.prototype);
cloned._depth = this._depth;
cloned._count = this._count;
cloned._branch = this._branch.slice();
cloned._zerohashes = this._zerohashes;
return cloned;
}
root() {
let root = Buffer.alloc(32);
let size = this._count;
for (let i = 0; i < this._depth; i++) {
if (size % 2 === 1) {
root = (0, _crypto.hash)(Buffer.concat([this._branch[i], root]));
} else {
root = (0, _crypto.hash)(Buffer.concat([root, this._zerohashes[i]]));
}
size = (0, _math.intDiv)(size, 2);
}
return root;
}
_proof() {
let size = this._count;
const proof = this._branch.slice();
for (let i = 0; i < this._depth; i++) {
if (size % 2 === 0) {
proof[i] = this._zerohashes[i];
}
size = (0, _math.intDiv)(size, 2);
}
return proof;
}
}
exports.LightProgressiveMerkleTree = LightProgressiveMerkleTree;
//# sourceMappingURL=lightMerkleTree.js.map