Beispiel #1
0
  def _get_group_signature_error(group, sponge_type):
    # type: (List[Transaction], type) -> Optional[Text]
    """
    Validates the signature fragments for a group of transactions using
    the specified sponge type.

    Note: this method assumes that the transactions in the group have
    already passed basic validation (see :py:meth:`_create_validator`).

    :return:
      - ``None``:  Indicates that the signature fragments are valid.
      - ``Text``:  Error message indicating the fragments are invalid.
    """
    validate_group_signature =\
      validate_signature_fragments(
        fragments   = [txn.signature_message_fragment for txn in group],
        hash_       = group[0].bundle_hash,
        public_key  = group[0].address,
        sponge_type = sponge_type,
      )

    if validate_group_signature:
      return None

    return (
      'Transaction {i} has invalid signature '
      '(using {fragments} fragments).'.format(
        fragments   = len(group),
        i           = group[0].current_index,
      )
    )
Beispiel #2
0
    def _create_validator(self):
        # type: () -> Generator[Text]
        """
    Creates a generator that does all the work.
    """
        bundle_hash = self.bundle.hash
        last_index = len(self.bundle) - 1

        balance = 0
        for (i,
             txn) in enumerate(self.bundle):  # type: Tuple[int, Transaction]
            balance += txn.value

            if txn.bundle_hash != bundle_hash:
                yield 'Transaction {i} has invalid bundle hash.'.format(i=i, )

            if txn.current_index != i:
                yield ('Transaction {i} has invalid current index value '
                       '(expected {i}, actual {actual}).'.format(
                           actual=txn.current_index,
                           i=i,
                       ))

            if txn.last_index != last_index:
                yield ('Transaction {i} has invalid last index value '
                       '(expected {expected}, actual {actual}).'.format(
                           actual=txn.last_index,
                           expected=last_index,
                           i=i,
                       ))

        if balance != 0:
            yield ('Bundle has invalid balance (expected 0, actual {actual}).'.
                   format(actual=balance, ))

        # Signature validation is only meaningful if the transactions are
        # otherwise valid.
        if not self._errors:
            i = 0
            while i <= last_index:
                txn = self.bundle[i]

                if txn.value < 0:
                    signature_fragments = [txn.signature_message_fragment]

                    # The following transaction(s) should contain additional
                    # fragments.
                    fragments_valid = True
                    j = 0
                    for j in range(1, AddressGenerator.DIGEST_ITERATIONS):
                        i += 1
                        try:
                            next_txn = self.bundle[i]
                        except IndexError:
                            yield (
                                'Reached end of bundle while looking for '
                                'signature fragment {j} for transaction {i}.'.
                                format(
                                    i=txn.current_index,
                                    j=j + 1,
                                ))
                            fragments_valid = False
                            break

                        if next_txn.address != txn.address:
                            yield ('Unable to find signature fragment {j} '
                                   'for transaction {i}.'.format(
                                       i=txn.current_index,
                                       j=j + 1,
                                   ))
                            fragments_valid = False
                            break

                        if next_txn.value != 0:
                            yield ('Transaction {i} has invalid amount '
                                   '(expected 0, actual {actual}).'.format(
                                       actual=next_txn.value,
                                       i=next_txn.current_index,
                                   ))
                            fragments_valid = False
                            # Keep going, just in case there's another signature
                            # fragment next (so that we skip it in the next iteration
                            # of the outer loop).
                            continue

                        signature_fragments.append(
                            next_txn.signature_message_fragment)

                    if fragments_valid:
                        signature_valid = validate_signature_fragments(
                            fragments=signature_fragments,
                            hash_=txn.bundle_hash,
                            public_key=txn.address,
                        )

                        if not signature_valid:
                            yield ('Transaction {i} has invalid signature '
                                   '(using {fragments} fragments).'.format(
                                       fragments=len(signature_fragments),
                                       i=txn.current_index,
                                   ))

                    # Skip signature fragments in the next iteration.
                    # Note that it's possible to have
                    # ``j < AddressGenerator.DIGEST_ITERATIONS`` if the bundle is
                    # badly malformed.
                    i += j

                else:
                    # No signature to validate; skip this transaction.
                    i += 1
Beispiel #3
0
    def _create_validator(self):
        # type: () -> Generator[Text]
        """
    Creates a generator that does all the work.
    """
        # Group transactions by address to make it easier to iterate over
        # inputs.
        grouped_transactions = self.bundle.group_transactions()

        # Define a few expected values.
        bundle_hash = self.bundle.hash
        last_index = len(self.bundle) - 1

        # Track a few others as we go along.
        balance = 0

        # Check indices and balance first.
        # Note that we use a counter to keep track of the current index,
        # since at this point we can't trust that the transactions have
        # correct ``current_index`` values.
        counter = 0
        for group in grouped_transactions:
            for txn in group:
                balance += txn.value

                if txn.bundle_hash != bundle_hash:
                    yield 'Transaction {i} has invalid bundle hash.'.format(
                        i=counter, )

                if txn.current_index != counter:
                    yield ('Transaction {i} has invalid current index value '
                           '(expected {i}, actual {actual}).'.format(
                               actual=txn.current_index,
                               i=counter,
                           ))

                if txn.last_index != last_index:
                    yield ('Transaction {i} has invalid last index value '
                           '(expected {expected}, actual {actual}).'.format(
                               actual=txn.last_index,
                               expected=last_index,
                               i=counter,
                           ))

                counter += 1

        # Bundle must be balanced (spends must match inputs).
        if balance != 0:
            yield ('Bundle has invalid balance (expected 0, actual {actual}).'.
                   format(actual=balance, ))

        # Signature validation is only meaningful if the transactions are
        # otherwise valid.
        if not self._errors:
            for group in grouped_transactions:
                # Signature validation only applies to inputs.
                if group[0].value >= 0:
                    continue

                signature_valid = True
                signature_fragments = []
                for j, txn in enumerate(
                        group):  # type: Tuple[int, Transaction]
                    if (j > 0) and (txn.value != 0):
                        # Input is malformed; signature fragments after the first
                        # should have zero value.
                        yield (
                            'Transaction {i} has invalid amount '
                            '(expected 0, actual {actual}).'.format(
                                actual=txn.value,

                                # If we get to this point, we know that the
                                # ``current_index`` value for each transaction can be
                                # trusted.
                                i=txn.current_index,
                            ))

                        # We won't be able to validate the signature, but continue
                        # anyway, so that we can check that the other transactions
                        # in the group have the correct ``value``.
                        signature_valid = False
                        continue

                    signature_fragments.append(txn.signature_message_fragment)

                # After collecting the signature fragment from each transaction
                # in the group, run it through the validator.
                if signature_valid:
                    signature_valid = validate_signature_fragments(
                        fragments=signature_fragments,
                        hash_=txn.bundle_hash,
                        public_key=txn.address,
                    )

                    if not signature_valid:
                        yield (
                            'Transaction {i} has invalid signature '
                            '(using {fragments} fragments).'.format(
                                fragments=len(signature_fragments),

                                # If we get to this point, we know that the
                                # ``current_index`` value for each transaction can be
                                # trusted.
                                i=group[0].current_index,
                            ))