@0xcert/merkle
Version:
Implementation of basic functions of binary Merkle tree.
97 lines • 4.72 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Merkle = exports.MerkleHasherPosition = void 0;
var MerkleHasherPosition;
(function (MerkleHasherPosition) {
MerkleHasherPosition[MerkleHasherPosition["VALUE"] = 0] = "VALUE";
MerkleHasherPosition[MerkleHasherPosition["LEAF"] = 1] = "LEAF";
MerkleHasherPosition[MerkleHasherPosition["NODE"] = 2] = "NODE";
})(MerkleHasherPosition = exports.MerkleHasherPosition || (exports.MerkleHasherPosition = {}));
class Merkle {
constructor(options) {
this._options = Object.assign({ hasher: (v) => v, noncer: () => '' }, options);
}
hash(value, path, position) {
return this._options.hasher(value, path, position);
}
nonce(path) {
return this._options.noncer(path);
}
notarize(data, prepend = []) {
return __awaiter(this, void 0, void 0, function* () {
const values = [...data];
const nonces = [];
const empty = yield this._options.noncer([...prepend, values.length]);
const nodes = [yield this._options.hasher(empty, [...prepend, values.length], MerkleHasherPosition.NODE)];
for (let i = values.length - 1; i >= 0; i--) {
const right = nodes[0];
nonces.unshift(yield this._options.noncer([...prepend, i]));
const value = yield this._options.hasher(values[i], [...prepend, i], MerkleHasherPosition.VALUE);
nodes.unshift(yield this._options.hasher(`${value}${nonces[0]}`, [...prepend, i], MerkleHasherPosition.LEAF));
const left = nodes[0];
nodes.unshift(yield this._options.hasher(`${left}${right}`, [...prepend, i], MerkleHasherPosition.NODE));
}
return {
values: values.map((value, index) => ({ index, value, nonce: nonces[index] })),
nodes: nodes.map((hash, index) => ({ index, hash })),
};
});
}
disclose(recipe, expose) {
return __awaiter(this, void 0, void 0, function* () {
const size = Math.max(...expose.map((i) => i + 1), 0);
const values = [];
const nodes = [
recipe.nodes.find((n) => n.index === size * 2),
];
for (let i = size - 1; i >= 0; i--) {
if (expose.indexOf(i) !== -1) {
values.unshift(recipe.values.find((n) => n.index === i));
}
else {
nodes.unshift(recipe.nodes.find((n) => n.index === i * 2 + 1));
}
}
return { values, nodes };
});
}
imprint(recipe) {
return __awaiter(this, void 0, void 0, function* () {
const nodes = [
...yield Promise.all(recipe.values.map((v, i) => __awaiter(this, void 0, void 0, function* () {
const value = yield this._options.hasher(v.value, [i], MerkleHasherPosition.VALUE);
return {
index: v.index * 2 + 1,
hash: yield this._options.hasher(`${value}${v.nonce}`, [i], MerkleHasherPosition.LEAF),
value: v.value,
};
}))),
...recipe.nodes,
];
const size = Math.max(...nodes.map((n) => n.index + 1), 0);
for (let i = size - 1; i >= 0; i -= 2) {
const right = nodes.find((n) => n.index === i);
const left = nodes.find((n) => n.index === i - 1);
if (right && left) {
nodes.unshift({
index: i - 2,
hash: yield this._options.hasher(`${left.hash}${right.hash}`, [i], MerkleHasherPosition.NODE),
});
}
}
const root = nodes.find((n) => n.index === 0);
return root ? root.hash : null;
});
}
}
exports.Merkle = Merkle;
//# sourceMappingURL=merkle.js.map