UNPKG

@iden3/js-merkletree

Version:

javascript sparse merkle tree library

153 lines (152 loc) 5.61 kB
"use strict"; 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;