コード例 #1
0
    def _create_sponge(self, index):
        # type: (int) -> Curl
        """
    Prepares the Curl sponge for the generator.
    """
        seed = self.seed.as_trits()  # type: MutableSequence[int]

        for i in range(index):
            # Treat ``seed`` like a really big number and add ``index``.
            # Note that addition works a little bit differently in balanced
            # ternary.
            for j in range(len(seed)):
                seed[j] += 1

                if seed[j] > 1:
                    seed[j] = -1
                else:
                    break

        sponge = Curl()
        sponge.absorb(seed)

        # Squeeze all of the trits out of the sponge and re-absorb them.
        # Note that Curl transforms several times per operation, so this
        # sequence is not as redundant as it looks at first glance.
        sponge.squeeze(seed)
        sponge.reset()
        sponge.absorb(seed)

        return sponge
コード例 #2
0
    def from_tryte_string(cls, trytes):
        # type: (TrytesCompatible) -> Transaction
        """
    Creates a Transaction object from a sequence of trytes.
    """
        tryte_string = TransactionTrytes(trytes)

        hash_ = [0] * HASH_LENGTH  # type: MutableSequence[int]

        sponge = Curl()
        sponge.absorb(tryte_string.as_trits())
        sponge.squeeze(hash_)

        return cls(
            hash_=TransactionHash.from_trits(hash_),
            signature_message_fragment=Fragment(tryte_string[0:2187]),
            address=Address(tryte_string[2187:2268]),
            value=int_from_trits(tryte_string[2268:2295].as_trits()),
            tag=Tag(tryte_string[2295:2322]),
            timestamp=int_from_trits(tryte_string[2322:2331].as_trits()),
            current_index=int_from_trits(tryte_string[2331:2340].as_trits()),
            last_index=int_from_trits(tryte_string[2340:2349].as_trits()),
            bundle_hash=BundleHash(tryte_string[2349:2430]),
            trunk_transaction_hash=TransactionHash(tryte_string[2430:2511]),
            branch_transaction_hash=TransactionHash(tryte_string[2511:2592]),
            nonce=Hash(tryte_string[2592:2673]),
        )
コード例 #3
0
    def finalize(self):
        # type: () -> None
        """
    Finalizes the bundle, preparing it to be attached to the Tangle.
    """
        if self.hash:
            raise RuntimeError('Bundle is already finalized.')

        if not self:
            raise ValueError('Bundle has no transactions.')

        # Quick validation.
        balance = self.balance

        if balance < 0:
            if self.change_address:
                self.add_transaction(
                    ProposedTransaction(
                        address=self.change_address,
                        value=-balance,
                        tag=self.tag,
                    ))
            else:
                raise ValueError(
                    'Bundle has unspent inputs (balance: {balance}); '
                    'use ``send_unspent_inputs_to`` to create '
                    'change transaction.'.format(balance=balance, ), )
        elif balance > 0:
            raise ValueError(
                'Inputs are insufficient to cover bundle spend '
                '(balance: {balance}).'.format(balance=balance, ), )

        # Generate bundle hash.
        sponge = Curl()
        last_index = len(self) - 1

        for (i,
             txn) in enumerate(self):  # type: Tuple[int, ProposedTransaction]
            txn.current_index = i
            txn.last_index = last_index

            sponge.absorb(txn.get_signature_validation_trytes().as_trits())

        bundle_hash = [0] * HASH_LENGTH  # type: MutableSequence[int]
        sponge.squeeze(bundle_hash)
        self.hash = Hash.from_trits(bundle_hash)

        # Copy bundle hash to individual transactions.
        for txn in self:
            txn.bundle_hash = self.hash

            # Initialize signature/message fragment.
            txn.signature_message_fragment = Fragment(txn.message or b'')
コード例 #4
0
  def _generate_checksum(self):
    # type: () -> TryteString
    """
    Generates the correct checksum for this address.
    """
    checksum_trits = [] # type: MutableSequence[int]

    sponge = Curl()
    sponge.absorb(self.address.as_trits())
    sponge.squeeze(checksum_trits)

    checksum_length = AddressChecksum.LEN * TRITS_PER_TRYTE

    return TryteString.from_trits(checksum_trits[:checksum_length])
コード例 #5
0
    def get_digest(self):
        # type: () -> Digest
        """
    Generates the digest used to do the actual signing.

    Signing keys can have variable length and tend to be quite long,
    which makes them not-well-suited for use in crypto algorithms.

    The digest is essentially the result of running the signing key
    through a PBKDF, yielding a constant-length hash that can be used
    for crypto.
    """
        hashes_per_fragment = FRAGMENT_LENGTH // Hash.LEN

        key_fragments = self.iter_chunks(FRAGMENT_LENGTH)

        # The digest will contain one hash per key fragment.
        digest = [0] * HASH_LENGTH * len(key_fragments)

        for (i, fragment
             ) in enumerate(key_fragments):  # type: Tuple[int, TryteString]
            fragment_trits = fragment.as_trits()

            key_fragment = [0] * FRAGMENT_LENGTH
            hash_trits = []

            for j in range(hashes_per_fragment):
                hash_start = j * HASH_LENGTH
                hash_end = hash_start + HASH_LENGTH
                hash_trits = fragment_trits[
                    hash_start:hash_end]  # type: MutableSequence[int]

                for k in range(26):
                    sponge = Curl()
                    sponge.absorb(hash_trits)
                    sponge.squeeze(hash_trits)

                key_fragment[hash_start:hash_end] = hash_trits

            sponge = Curl()
            sponge.absorb(key_fragment)
            sponge.squeeze(hash_trits)

            fragment_start = i * FRAGMENT_LENGTH
            fragment_end = fragment_start + FRAGMENT_LENGTH

            digest[fragment_start:fragment_end] = hash_trits

        return Digest(TryteString.from_trits(digest), self.key_index)
コード例 #6
0
    def address_from_digest(digest):
        # type: (Digest) -> Address
        """
    Generates an address from a private key digest.
    """
        address_trits = [0] * (Address.LEN * TRITS_PER_TRYTE
                               )  # type: MutableSequence[int]

        sponge = Curl()
        sponge.absorb(digest.as_trits())
        sponge.squeeze(address_trits)

        address = Address.from_trits(address_trits)
        address.key_index = digest.key_index

        return address
コード例 #7
0
def validate_signature_fragments(fragments, hash_, public_key):
    # type: (Sequence[TryteString], Hash, TryteString) -> bool
    """
  Returns whether a sequence of signature fragments is valid.

  :param fragments:
    Sequence of signature fragments (usually
    :py:class:`cornode.transaction.Fragment` instances).

  :param hash_:
    Hash used to generate the signature fragments (usually a
    :py:class:`cornode.transaction.BundleHash` instance).

  :param public_key:
    The public key value used to verify the signature digest (usually a
    :py:class:`cornode.types.Address` instance).
  """
    checksum = [0] * (HASH_LENGTH * len(fragments))
    normalized_hash = normalize(hash_)

    for (i, fragment) in enumerate(fragments):  # type: Tuple[int, TryteString]
        outer_sponge = Curl()

        # If there are more than 3 iterations, loop back around to the
        # start.
        normalized_chunk = normalized_hash[i % len(normalized_hash)]

        buffer = []
        for (j, hash_trytes) in enumerate(fragment.iter_chunks(
                Hash.LEN)):  # type: Tuple[int, TryteString]
            buffer = hash_trytes.as_trits()  # type: MutableSequence[int]
            inner_sponge = Curl()

            # Note the sign flip compared to ``SignatureFragmentGenerator``.
            for _ in range(13 + normalized_chunk[j]):
                inner_sponge.reset()
                inner_sponge.absorb(buffer)
                inner_sponge.squeeze(buffer)

            outer_sponge.absorb(buffer)

        outer_sponge.squeeze(buffer)
        checksum[i * HASH_LENGTH:(i + 1) * HASH_LENGTH] = buffer

    actual_public_key = [0] * HASH_LENGTH  # type: MutableSequence[int]
    addy_sponge = Curl()
    addy_sponge.absorb(checksum)
    addy_sponge.squeeze(actual_public_key)

    return actual_public_key == public_key.as_trits()
コード例 #8
0
class SignatureFragmentGenerator(Iterator[TryteString]):
    """
  Used to generate signature fragments progressively.

  Each instance can generate 1 signature per fragment in the private
  key.
  """
    def __init__(self, private_key, hash_):
        # type: (PrivateKey, TryteString) -> None
        super(SignatureFragmentGenerator, self).__init__()

        self._key_chunks = private_key.iter_chunks(FRAGMENT_LENGTH)
        self._iteration = -1
        self._normalized_hash = normalize(hash_)
        self._sponge = Curl()

    def __iter__(self):
        # type: () -> SignatureFragmentGenerator
        return self

    def __len__(self):
        # type: () -> int
        """
    Returns the number of fragments this generator can create.

    Note: This method always returns the same result, no matter how
    many iterations have been completed.
    """
        return len(self._key_chunks)

    def __next__(self):
        # type: () -> TryteString
        """
    Returns the next signature fragment.
    """
        key_trytes = next(self._key_chunks)  # type: TryteString
        self._iteration += 1

        # If the key is long enough, loop back around to the start.
        normalized_chunk =\
          self._normalized_hash[self._iteration % len(self._normalized_hash)]

        signature_fragment = key_trytes.as_trits()

        # Build the signature, one hash at a time.
        for i in range(key_trytes.count_chunks(Hash.LEN)):
            hash_start = i * HASH_LENGTH
            hash_end = hash_start + HASH_LENGTH

            buffer = signature_fragment[hash_start:
                                        hash_end]  # type: MutableSequence[int]

            for _ in range(13 - normalized_chunk[i]):
                self._sponge.reset()
                self._sponge.absorb(buffer)
                self._sponge.squeeze(buffer)

            signature_fragment[hash_start:hash_end] = buffer

        return TryteString.from_trits(signature_fragment)

    if PY2:
        next = __next__