def insert(self, index: str, data: str) -> bool: # Do the first level hash of data and insert into index-th leaf node_id = util.bitarray(index) self.cache[node_id] = self._hash(data) # Do a normal update up the tree curr_id = node_id.copy() while (curr_id.length() > 0): # Get both the parent and sibling ids s_id, is_left = self._sibling(curr_id) p_id = self._parent(curr_id) # Get the digest of the current node and sibling curr_digest = self.cache[curr_id] s_digest = None if s_id in self.cache: s_digest = self.cache[s_id] else: s_digest = self._empty_cache(s_id.length()) # Hash the digests of the left and right children if is_left: p_digest = self._hash(s_digest + curr_digest) else: p_digest = self._hash(curr_digest + s_digest) self.cache[p_id] = p_digest # Traverse up the tree by making the current node the parent node curr_id = p_id # Update root self.root_digest = self.cache[curr_id] return True
def generate_proof(self, index: str) -> list: copath = list() curr_id = util.bitarray(index) proof = Proof(index=curr_id) proof.proof_type = curr_id in self.cache if not proof.proof_type: curr_id = self._get_empty_ancestor(curr_id) proof.proof_id = curr_id # Our stopping condition is length > 0 so we don't add the root to the copath while (curr_id.length() > 0): # Append the sibling to the copath and advance current node s_id, is_left = self._sibling(curr_id) s_digest = None # Check to see if sibling is cache otherwise set to empty value of appropriate length if s_id in self.cache: s_digest = self.cache[s_id] else: s_digest = self._empty_cache(len(s_id)) copath.append((s_id, s_digest)) curr_id = self._parent(curr_id) proof.copath = copath return proof
def _percolate(self, leaf_id: str, leaf_data: str) -> None: node_id = util.bitarray(leaf_id) node_digest = self._hash(leaf_data) self.cache[node_id] = node_digest sibling_id, is_left = self._sibling(node_id) if sibling_id in self.cache: sibling_digest = self.cache[sibling_id] else: sibling_digest = self._empty_cache(sibling_id.length()) done = False while not done: parent_id = self._parent(node_id) parent_conflict = self._is_conflict(parent_id) if not parent_conflict: if is_left: parent_digest = self._hash(sibling_digest + node_digest) else: parent_digest = self._hash(node_digest + sibling_digest) self.cache[parent_id] = parent_digest node_id = parent_id node_digest = parent_digest sibling_id, is_left = self._sibling(node_id) if sibling_id in self.cache: sibling_digest = self.cache[sibling_id] else: sibling_digest = self._empty_cache(sibling_id.length()) else: done = True return
def batch_insert(self, transactions: dict) -> bool: leaves = sorted(transactions.items(), key=lambda leaf: leaf[0]) self.conflicts = util.find_conflicts(list(transactions.keys())) for i in range(len(leaves)): self._percolate(leaves[i][0], leaves[i][1]) self.root_digest = self.cache[util.bitarray()] return True
def test_membership_small(self): index = bitarray('101').to01() self.T.insert(index, b"angela") proof = self.T.generate_proof(index) self.assertTrue(self.T.verify_proof(proof))