UNPKG

@zk-kit/sparse-merkle-tree

Version:
125 lines (124 loc) 5.47 kB
import { HashFunction, Key, Value, Node, MerkleProof } from "./types"; /** * SparseMerkleTree class provides all the functions to create a sparse Merkle tree * and to take advantage of its features: {@linkcode SparseMerkleTree.add}, {@linkcode SparseMerkleTree.get}, * {@linkcode SparseMerkleTree.update}, {@linkcode SparseMerkleTree.delete}, {@linkcode SparseMerkleTree.createProof}, * {@linkcode SparseMerkleTree.verifyProof}. * To better understand the code below it may be useful to describe the terminology used: * * **nodes**: every node in the tree is the hash of the two child nodes (`H(x, y)`); * * **root node**: the root node is the top hash and since it represents the whole data * structure it can be used to certify its integrity; * * **leaf nodes**: every leaf node is the hash of a key/value pair and an additional * value to mark the node as leaf node (`H(x, y, 1)`); * * **entry**: a tree entry is a key/value pair used to create the leaf nodes; * * **zero nodes**: a zero node is an hash of zeros and in this implementation `H(0,0) = 0`; * * **siblings**: the children of a parent node are siblings; * * **path**: every entry key is a number < 2^256 that can be converted in a binary number, * and this binary number is the path used to place the entry in the tree (1 or 0 define the * child node to choose); * * **matching node**: when an entry is not found and the path leads to another existing entry, * this entry is a matching entry and it has some of the first bits in common with the entry not found; * * **depth**: the depth of a node is the length of the path to its root. */ export default class SparseMerkleTree { private hash; private zeroNode; private entryMark; private bigNumbers; private nodes; root: Node; /** * Initializes the SparseMerkleTree attributes. * @param hash Hash function used to hash the child nodes. * @param bigNumbers BigInt type enabling. */ constructor(hash: HashFunction, bigNumbers?: boolean); /** * Gets a key and if the key exists in the tree the function returns the * value, otherwise it returns 'undefined'. * @param key A key of a tree entry. * @returns A value of a tree entry or 'undefined'. */ get(key: Key): Value | undefined; /** * Adds a new entry in the tree. It retrieves a matching entry * or a zero node with a top-down approach and then it updates all the * hashes of the nodes in the path of the new entry with a bottom-up approach. * @param key The key of the new entry. * @param value The value of the new entry. */ add(key: Key, value: Value): void; /** * Updates a value of an entry in the tree. Also in this case * all the hashes of the nodes in the path of the entry are updated * with a bottom-up approach. * @param key The key of the entry. * @param value The value of the entry. */ update(key: Key, value: Value): void; /** * Deletes an entry in the tree. Also in this case all the hashes of * the nodes in the path of the entry are updated with a bottom-up approach. * @param key The key of the entry. */ delete(key: Key): void; /** * Creates a proof to prove the membership or the non-membership * of a tree entry. * @param key A key of an existing or a non-existing entry. * @returns The membership or the non-membership proof. */ createProof(key: Key): MerkleProof; /** * Verifies a membership or a non-membership proof. * @param merkleProof The proof to verify. * @returns True if the proof is valid, false otherwise. */ verifyProof(merkleProof: MerkleProof): boolean; /** * Searches for an entry in the tree. If the key passed as parameter exists in * the tree, the function returns the entry, otherwise it returns the entry * with only the key, and when there is another existing entry * in the same path it returns also this entry as 'matching entry'. * In any case the function returns the siblings of the path. * @param key The key of the entry to search for. * @returns The entry response. */ private retrieveEntry; /** * Calculates nodes with a bottom-up approach until it reaches the root node. * @param node The node to start from. * @param path The path of the key. * @param siblings The siblings of the path. * @returns The root node. */ private calculateRoot; /** * Adds new nodes in the tree with a bottom-up approach until it reaches the root node. * @param node The node to start from. * @param path The path of the key. * @param siblings The siblings of the path. * @param i The index to start from. * @returns The root node. */ private addNewNodes; /** * Deletes nodes in the tree with a bottom-up approach until it reaches the root node. * @param node The node to start from. * @param path The path of the key. * @param siblings The siblings of the path. * @param i The index to start from. */ private deleteOldNodes; /** * Checks if a node is a leaf node. * @param node A node of the tree. * @returns True if the node is a leaf, false otherwise. */ private isLeaf; /** * Checks the parameter type. * @param parameter The parameter to check. */ private checkParameterType; }