Beispiel #1
0
    def principal_subroots(self, sublength):
        """Detects in corresponding order the roots of the successive, leftmost,
        full binary subtrees of maximum (and thus decreasing) length, whose
        lengths sum up to the provided argument. Detected nodes are prepended
        with a sign (+1 or -1), carrying information for subsequent generation
        of consistency proofs.

        :param sublength: non negative integer smaller than or equal to the
                tree's current length, such that the corresponding sequence
                of subroots exists
        :returns: Signed roots of the detected subtrees, whose hashes to be
                    utilized in generation of consistency proofs
        :rtype: list of signed nodes

        :raises NoPrincipalSubroots: if the provided number does not fulfill
            the prescribed conditions
        """
        if sublength < 0:
            # Mask negative input as incompatiblitity
            raise NoPrincipalSubroots

        principal_subroots = []
        append = principal_subroots.append
        powers = decompose(sublength)
        start = 0
        for power in powers:
            try:
                subroot = self.subroot(start, power)
            except NoSubtreeException:
                # Incompatibility issue detected
                raise NoPrincipalSubroots

            try:
                child = subroot.child
                grandchild = child.child
            except NoChildException:
                if subroot.is_left_parent():
                    append((+1, subroot))
                else:
                    append((-1, subroot))
            else:
                if child.is_left_parent():
                    append((+1, subroot))
                else:
                    append((-1, subroot))
            finally:
                start += 2**power

        if len(principal_subroots) > 0:
            # Modify last sign
            principal_subroots[-1] = (+1, principal_subroots[-1][1])

        return principal_subroots
Beispiel #2
0
def test_decompose(num, powers):
    """Tests decompose for all possible combination of powers from 0 to 10
    """

    assert utils.decompose(num) == reverseTupleFromList(powers)
Beispiel #3
0
def test_decompose_negative_convention():
    """Tests that decompose returns the nonsensical empty tuple for arguments smaller than zero
    """

    assert utils.decompose(-1) == ()
Beispiel #4
0
def test_decompose_zero_convention():
    """Tests that decompose returns the nonsensical empty tuple for arguments equal to zero
    """

    assert utils.decompose(0) == ()
Beispiel #5
0
    def update(self, record=None, digest=None):
        """
        Updates the Merkle-tree by storing the digest of the inserted record
        into a newly-created leaf. Restructures the tree appropriately and
        recalculates appropriate interior hashes

        :param record: [optional] The record whose digest is to be stored into
                    a new leaf
        :type record:  str or bytes
        :param digest: [optional] The digest to be stored into the new leaf
        :type digest:  str

        .. warning:: Exactly one of either record or digest
            should be provided

        :raises LeafConstructionError: if both record and digest
                                    were provided
        :raises UndecodableRecord: if the Merkle-tree is not in raw-bytes mode
            and the provided record does not fall under its configured type
        """
        encoding = self.encoding
        hash = self.hash

        if self:
            leaves = self.leaves
            append = leaves.append
            add = self.nodes.add

            # ~ Height and root of the *full* binary subtree with maximum
            # ~ possible length containing the rightmost leaf
            last_power = decompose(len(leaves))[-1]
            last_subroot = leaves[-1].descendant(degree=last_power)

            # Encrypt new record into new leaf
            try:
                new_leaf = Leaf(hash, encoding, record, digest)
            except (LeafConstructionError, UndecodableRecord):
                raise

            # Assimilate new leaf
            append(new_leaf)
            add(new_leaf)
            try:
                old_child = last_subroot.child  # Save child info before bifurcation
            except NoChildException:  # last_subroot was previously root
                self.__root = Node(hash, encoding, last_subroot, new_leaf)
                add(self.__root)
            else:
                # Create bifurcation node
                new_child = Node(hash, encoding, last_subroot, new_leaf)
                add(new_child)

                # Interject bifurcation node
                old_child.set_right(new_child)
                new_child.set_child(old_child)

                # Recalculate hashes only at the rightmost branch of the tree
                current_node = old_child
                while 1:
                    current_node.recalculate_hash(hash_func=hash)
                    try:
                        current_node = current_node.child
                    except NoChildException:
                        break
        else:  # Empty tree case
            try:
                new_leaf = Leaf(hash, encoding, record, digest)
            except (LeafConstructionError, UndecodableRecord):
                raise
            self.leaves = [new_leaf]
            self.nodes = set([new_leaf])
            self.__root = new_leaf