@iden3/js-merkletree
Version:
javascript sparse merkle tree library
153 lines (152 loc) • 5.61 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.rootFromProof = exports.verifyProof = exports.siblignsFroomProof = exports.Proof = void 0;
const constants_1 = require("../../constants");
const utils_1 = require("../utils");
const hash_1 = require("../hash/hash");
const node_1 = require("../node/node");
const node_2 = require("../utils/node");
const proof_1 = require("../errors/proof");
class Proof {
constructor(obj) {
this.existence = obj?.existence ?? false;
this.depth = 0;
this.nodeAux = obj?.nodeAux;
const { siblings, notEmpties } = this.reduceSiblings(obj?.siblings);
this.siblings = siblings;
this.notEmpties = notEmpties;
}
bytes() {
let bsLen = constants_1.PROOF_FLAG_LEN + this.notEmpties.length + constants_1.ELEM_BYTES_LEN * this.siblings.length;
if (typeof this.nodeAux !== 'undefined') {
bsLen += 2 * constants_1.ELEM_BYTES_LEN;
}
const arrBuff = new ArrayBuffer(bsLen);
const bs = new Uint8Array(arrBuff);
if (!this.existence) {
bs[0] |= 1;
}
bs[1] = this.depth;
bs.set(this.notEmpties, constants_1.PROOF_FLAG_LEN);
const siblingBytes = (0, utils_1.siblings2Bytes)(this.siblings);
bs.set(siblingBytes, this.notEmpties.length + constants_1.PROOF_FLAG_LEN);
if (typeof this.nodeAux !== 'undefined') {
bs[0] |= 2;
bs.set(this.nodeAux.key.value, bs.length - 2 * constants_1.ELEM_BYTES_LEN);
bs.set(this.nodeAux.value.value, bs.length - 1 * constants_1.ELEM_BYTES_LEN);
}
return bs;
}
toJSON() {
return {
existence: this.existence,
siblings: this.allSiblings().map((s) => s.toJSON()),
node_aux: this.nodeAux
? {
key: this.nodeAux.key.toJSON(),
value: this.nodeAux.value.toJSON()
}
: undefined
};
}
reduceSiblings(siblings) {
const reducedSiblings = [];
const notEmpties = new Uint8Array(constants_1.NOT_EMPTIES_LEN);
if (!siblings) {
return { siblings: reducedSiblings, notEmpties };
}
for (let i = 0; i < siblings.length; i++) {
const sibling = siblings[i];
if (JSON.stringify(siblings[i]) !== JSON.stringify(hash_1.ZERO_HASH)) {
(0, utils_1.setBitBigEndian)(notEmpties, i);
reducedSiblings.push(sibling);
this.depth = i + 1;
}
}
return { notEmpties, siblings: reducedSiblings };
}
static fromJSON(obj) {
let nodeAux = undefined;
const nodeAuxJson = obj.node_aux ?? obj.nodeAux; // we keep backward compatibility and support both representations
if (nodeAuxJson) {
nodeAux = {
key: hash_1.Hash.fromString(nodeAuxJson.key),
value: hash_1.Hash.fromString(nodeAuxJson.value)
};
}
const existence = obj.existence ?? false;
const siblings = obj.siblings.map((s) => hash_1.Hash.fromString(s));
return new Proof({ existence, nodeAux, siblings });
}
allSiblings() {
return Proof.buildAllSiblings(this.depth, this.notEmpties, this.siblings);
}
static buildAllSiblings(depth, notEmpties, siblings) {
let sibIdx = 0;
const allSiblings = [];
for (let i = 0; i < depth; i += 1) {
if ((0, utils_1.testBitBigEndian)(notEmpties, i)) {
allSiblings.push(siblings[sibIdx]);
sibIdx += 1;
}
else {
allSiblings.push(hash_1.ZERO_HASH);
}
}
return allSiblings;
}
}
exports.Proof = Proof;
/**
* @deprecated The method should not be used and will be removed in the next major version,
* please use proof.allSiblings instead
*/
const siblignsFroomProof = (proof) => {
return proof.allSiblings();
};
exports.siblignsFroomProof = siblignsFroomProof;
const verifyProof = async (rootKey, proof, k, v) => {
try {
const rFromProof = await (0, exports.rootFromProof)(proof, k, v);
return (0, utils_1.bytesEqual)(rootKey.value, rFromProof.value);
}
catch (err) {
if (err === proof_1.ErrNodeAuxNonExistAgainstHIndex) {
return false;
}
throw err;
}
};
exports.verifyProof = verifyProof;
const rootFromProof = async (proof, k, v) => {
const kHash = hash_1.Hash.fromBigInt(k);
const vHash = hash_1.Hash.fromBigInt(v);
let midKey;
if (proof.existence) {
midKey = await (0, node_2.leafKey)(kHash, vHash);
}
else {
if (typeof proof.nodeAux === 'undefined') {
midKey = hash_1.ZERO_HASH;
}
else {
const nodeAux = proof.nodeAux;
if ((0, utils_1.bytesEqual)(kHash.value, nodeAux.key.value)) {
throw proof_1.ErrNodeAuxNonExistAgainstHIndex;
}
midKey = await (0, node_2.leafKey)(nodeAux.key, nodeAux.value);
}
}
const siblings = proof.allSiblings();
const path = (0, utils_1.getPath)(siblings.length, kHash.value);
for (let i = siblings.length - 1; i >= 0; i -= 1) {
if (path[i]) {
midKey = await new node_1.NodeMiddle(siblings[i], midKey).getKey();
}
else {
midKey = await new node_1.NodeMiddle(midKey, siblings[i]).getKey();
}
}
return midKey;
};
exports.rootFromProof = rootFromProof;