예제 #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 __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()
예제 #3
0
    def test_absorb_offset(self):
        """
    Passing an ``offset`` argument to :py:meth:`Curl.absorb`.
    """
        # noinspection SpellCheckingInspection
        input_ = ('G9JYBOMPUXHYHKSNRNMMSSZCSHOFYOYNZRSZMAAYWDYEIMVVOGKPJB'
                  'VBM9TDPULSFUNMTVXRKFIDOHUXXVYDLFSZYZTWQYTE9SPYYWYTXJYQ'
                  '9IFGYOLZXWZBKWZN9QOOTBQMWMUBLEWUEEASRHRTNIQWJQNDWRYLCA')

        trits = TryteString(input_).as_trits()

        curl = Curl()
        curl.absorb(trits, offset=243, length=486)
        curl.absorb(trits, offset=0, length=243)
        trits_out = []
        curl.squeeze(trits_out)

        trits_out = TryteString.from_trits(trits_out)

        # noinspection SpellCheckingInspection
        self.assertEqual(
            trits_out,
            'ZWNF9YOCAKC9CXQFYZDKXSSAZOCAZLEVEB9OZDJQ'
            'GWEULHUDY9RAWAT9GIUXTTUSYJEGNGQDVJCGTQLN9',
        )
예제 #4
0
    def __init__(self):
        super(MultisigAddressBuilder, self).__init__()

        self._digests = []  # type: List[Digest]
        """
    Keeps track of digests that were added, so that we can attach them
    to the final :py:class:`MultisigAddress` object.
    """

        self._address = None  # type: Optional[MultisigAddress]
        """
    Caches the generated address.

    Generating the address modifies the internal state of the curl
    sponge, so each :py:class:`MultisigAddressBuilder` instance can
    only generate a single address.
    """

        self._sponge = Curl()
예제 #5
0
  def from_tryte_string(cls, trytes, hash_=None):
    # type: (TrytesCompatible, Optional[TransactionHash]) -> Transaction
    """
    Creates a Transaction object from a sequence of trytes.

    :param trytes:
      Raw trytes.  Should be exactly 2673 trytes long.

    :param hash_:
      The transaction hash, if available.
      If not provided, it will be computed from the transaction trytes.
    """
    tryte_string = TransactionTrytes(trytes)

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

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

      hash_ = TransactionHash.from_trits(hash_trits)

    return cls(
      hash_ = 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()),
      legacy_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]),
      tag = Tag(tryte_string[2592:2619]),
      attachment_timestamp = int_from_trits(tryte_string[2619:2628].as_trits()),
      attachment_timestamp_lower_bound = int_from_trits(tryte_string[2628:2637].as_trits()),
      attachment_timestamp_upper_bound = int_from_trits(tryte_string[2637:2646].as_trits()),
      nonce = Nonce(tryte_string[2646:2673]),
    )
예제 #6
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]),
        )
예제 #7
0
    def test_squeeze_multiple_hashes(self):
        """
    Squeezing more than 1 hash from the sponge.
    """
        # noinspection SpellCheckingInspection
        input_ = ('EMIDYNHBWMBCXVDEFOFWINXTERALUKYYPPHKP9JJ'
                  'FGJEIUY9MUDVNFZHMMWZUYUSWAIOWEVTHNWMHANBH')

        trits = TryteString(input_).as_trits()

        curl = Curl()
        curl.absorb(trits)
        trits_out = []
        curl.squeeze(trits_out, length=486)

        trits_out = TryteString.from_trits(trits_out)

        # noinspection SpellCheckingInspection
        self.assertEqual(
            trits_out,
            'AQBOPUMJMGVHFOXSMUAGZNACKUTISDPBSILMRAGIG'
            'RXXS9JJTLIKZUW9BCJWKSTFBDSBLNVEEGVGAMSSMQ'
            'GSJWCCFQRHWKTSMVPWWCEGOMCNWFYWDZBEDBLXIFB'
            'HOTCKUMCANLSXXTNKSYNBMOSDDEYFTDOYIKDRJM',
        )
예제 #8
0
    def test_length(self):
        """
    Specifying different values for the ``length`` argument.
    """
        # noinspection SpellCheckingInspection
        input_ = ('G9JYBOMPUXHYHKSNRNMMSSZCSHOFYOYNZRSZMAAYWDYEIMVVOGKPJB'
                  'VBM9TDPULSFUNMTVXRKFIDOHUXXVYDLFSZYZTWQYTE9SPYYWYTXJYQ'
                  '9IFGYOLZXWZBKWZN9QOOTBQMWMUBLEWUEEASRHRTNIQWJQNDWRYLCA')

        trits = TryteString(input_).as_trits()

        curl = Curl()
        curl.absorb(trits, offset=0, length=486)
        curl.absorb(trits, offset=0, length=243)
        trits_out = []
        curl.squeeze(trits_out)

        trits_out = TryteString.from_trits(trits_out)

        # noinspection SpellCheckingInspection
        self.assertEqual(
            trits_out,
            'OTYHXEXJLCSMEY9LYCC9ASJXMORTLAYQEHRS9DAH'
            '9NR9DXLXYDGOVOBEL9LWRITLWPHPYPZDKXVPAPKUA',
        )
예제 #9
0
  def test_length_greater_than_243(self):
    """
    The input is longer than 1 hash.
    """
    # noinspection SpellCheckingInspection
    input_ = (
      'G9JYBOMPUXHYHKSNRNMMSSZCSHOFYOYNZRSZMAAYWDYEIMVVOGKPJB'
      'VBM9TDPULSFUNMTVXRKFIDOHUXXVYDLFSZYZTWQYTE9SPYYWYTXJYQ'
      '9IFGYOLZXWZBKWZN9QOOTBQMWMUBLEWUEEASRHRTNIQWJQNDWRYLCA'
    )

    trits = TryteString(input_).as_trits()

    curl = Curl()
    curl.absorb(trits)
    trits_out = []
    curl.squeeze(trits_out)

    trits_out = TryteString.from_trits(trits_out)

    # noinspection SpellCheckingInspection
    self.assertEqual(
      trits_out,

      'RWCBOLRFANOAYQWXXTFQJYQFAUTEEBSZWTIRSSDR'
      'EYGCNFRLHQVDZXYXSJKCQFQLJMMRHYAZKRRLQZDKR',
    )
예제 #10
0
  def test_happy_path(self):
    """
    Typical use case.
    """
    # noinspection SpellCheckingInspection
    input_ = (
      'EMIDYNHBWMBCXVDEFOFWINXTERALUKYYPPHKP9JJ'
      'FGJEIUY9MUDVNFZHMMWZUYUSWAIOWEVTHNWMHANBH'
    )

    trits = TryteString(input_).as_trits()
    

    curl = Curl()
    curl.absorb(trits)
    trits_out = []
    curl.squeeze(trits_out)

    trits_out = TryteString.from_trits(trits_out)
    # print('trits_out: ', trits_out)
    # # AQBOPUMJMGVHFOXSMUAGZNACKUTISDPBSILMRAGIGRXXS9JJTLIKZUW9BCJWKSTFBDSBLNVEEGVGAMSSM

    # noinspection SpellCheckingInspection
    self.assertEqual(
      trits_out,

      'AQBOPUMJMGVHFOXSMUAGZNACKUTISDPBSILMRAGI'
      'GRXXS9JJTLIKZUW9BCJWKSTFBDSBLNVEEGVGAMSSM',
    )
예제 #11
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'')
예제 #12
0
  def address_from_digest(digest_trits, key_index):
    # type: (Iterable[int], int) -> 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_trits)
    sponge.squeeze(address_trits)

    address = Address.from_trits(address_trits)
    address.key_index = key_index
    return address
예제 #13
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])
예제 #14
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)

        return Address.from_trits(
            trits=address_trits,
            key_index=digest.key_index,
            security_level=digest.security_level,
        )
예제 #15
0
파일: base.py 프로젝트: wusyong/iota.lib.py
    def from_tryte_string(cls, trytes, hash_=None):
        # type: (TrytesCompatible, Optional[TransactionHash]) -> Transaction
        """
        Creates a Transaction object from a sequence of trytes.

        :param trytes:
            Raw trytes.  Should be exactly 2673 trytes long.

        :param hash_:
            The transaction hash, if available.

            If not provided, it will be computed from the transaction
            trytes.
        """
        tryte_string = TransactionTrytes(trytes)

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

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

            hash_ = TransactionHash.from_trits(hash_trits)

        return cls(
            hash_=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()),
            legacy_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]),
            tag=Tag(tryte_string[2592:2619]),
            attachment_timestamp=int_from_trits(
                tryte_string[2619:2628].as_trits()),
            attachment_timestamp_lower_bound=int_from_trits(
                tryte_string[2628:2637].as_trits()),
            attachment_timestamp_upper_bound=int_from_trits(
                tryte_string[2637:2646].as_trits()),
            nonce=Nonce(tryte_string[2646:2673]),
        )
예제 #16
0
class MultisigAddressBuilder(object):
    """
  Creates multisig addresses.

  Note that this class generates a single address from multiple inputs,
  (digests) unlike :py:class:`iota.crypto.addresses.AddressGenerator`
  which generates multiple addresses from a single input (seed).
  """
    def __init__(self):
        super(MultisigAddressBuilder, self).__init__()

        self._digests = []  # type: List[Digest]
        """
    Keeps track of digests that were added, so that we can attach them
    to the final :py:class:`MultisigAddress` object.
    """

        self._address = None  # type: Optional[MultisigAddress]
        """
    Caches the generated address.

    Generating the address modifies the internal state of the curl
    sponge, so each :py:class:`MultisigAddressBuilder` instance can
    only generate a single address.
    """

        self._sponge = Curl()

    def add_digest(self, digest):
        # type: (Digest) -> None
        """
    Absorbs a digest into the sponge.

    IMPORTANT: Keep track of the order that digests are added!
    To spend inputs from a multisig address, you must provide the
    private keys in the same order!

    References:
      - https://github.com/iotaledger/wiki/blob/master/multisigs.md#spending-inputs
    """
        if self._address:
            raise ValueError(
                'Cannot add digests once an address is extracted.')

        self._sponge.absorb(digest.as_trits())
        self._digests.append(digest)

    def get_address(self):
        # type: () -> MultisigAddress
        """
    Returns the new multisig address.

    Note that you can continue to add digests after extracting an
    address; the next address will use *all* of the digests that have
    been added so far.
    """
        if not self._digests:
            raise ValueError(
                'Must call ``add_digest`` at least once '
                'before calling ``get_address``.', )

        if not self._address:
            address_trits = [0] * HASH_LENGTH
            self._sponge.squeeze(address_trits)

            self._address =\
              MultisigAddress.from_trits(address_trits, digests=self._digests[:])

        return self._address
예제 #17
0
    def from_tryte_string(cls: Type[T],
                          trytes: TrytesCompatible,
                          hash_: Optional[TransactionHash] = None) -> T:
        """
        Creates a Transaction object from a sequence of trytes.

        :param TrytesCompatible trytes:
            Raw trytes.  Should be exactly 2673 trytes long.

        :param Optional[TransactionHash] hash_:
            The transaction hash, if available.

            If not provided, it will be computed from the transaction
            trytes.

        :return:
            :py:class:`Transaction` object.

        Example usage::

            from iota import Transaction

            txn =\\
              Transaction.from_tryte_string(
                b'GYPRVHBEZOOFXSHQBLCYW9ICTCISLHDBNMMVYD9JJHQMPQCTIQAQTJNNNJ9IDXLRCC'
                b'OYOXYPCLR9PBEY9ORZIEPPDNTI9CQWYZUOTAVBXPSBOFEQAPFLWXSWUIUSJMSJIIIZ'
                b'WIKIRH9GCOEVZFKNXEVCUCIIWZQCQEUVRZOCMEL9AMGXJNMLJCIA9UWGRPPHCEOPTS'
                b'VPKPPPCMQXYBHMSODTWUOABPKWFFFQJHCBVYXLHEWPD9YUDFTGNCYAKQKVEZYRBQRB'
                b'XIAUX9SVEDUKGMTWQIYXRGSWYRK9SRONVGTW9YGHSZRIXWGPCCUCDRMAXBPDFVHSRY'
                b'WHGB9DQSQFQKSNICGPIPTRZINYRXQAFSWSEWIFRMSBMGTNYPRWFSOIIWWT9IDSELM9'
                b'JUOOWFNCCSHUSMGNROBFJX9JQ9XT9PKEGQYQAWAFPRVRRVQPUQBHLSNTEFCDKBWRCD'
                b'X9EYOBB9KPMTLNNQLADBDLZPRVBCKVCYQEOLARJYAGTBFR9QLPKZBOYWZQOVKCVYRG'
                b'YI9ZEFIQRKYXLJBZJDBJDJVQZCGYQMROVHNDBLGNLQODPUXFNTADDVYNZJUVPGB9LV'
                b'PJIYLAPBOEHPMRWUIAJXVQOEM9ROEYUOTNLXVVQEYRQWDTQGDLEYFIYNDPRAIXOZEB'
                b'CS9P99AZTQQLKEILEVXMSHBIDHLXKUOMMNFKPYHONKEYDCHMUNTTNRYVMMEYHPGASP'
                b'ZXASKRUPWQSHDMU9VPS99ZZ9SJJYFUJFFMFORBYDILBXCAVJDPDFHTTTIYOVGLRDYR'
                b'TKHXJORJVYRPTDH9ZCPZ9ZADXZFRSFPIQKWLBRNTWJHXTOAUOL9FVGTUMMPYGYICJD'
                b'XMOESEVDJWLMCVTJLPIEKBE9JTHDQWV9MRMEWFLPWGJFLUXI9BXPSVWCMUWLZSEWHB'
                b'DZKXOLYNOZAPOYLQVZAQMOHGTTQEUAOVKVRRGAHNGPUEKHFVPVCOYSJAWHZU9DRROH'
                b'BETBAFTATVAUGOEGCAYUXACLSSHHVYDHMDGJP9AUCLWLNTFEVGQGHQXSKEMVOVSKQE'
                b'EWHWZUDTYOBGCURRZSJZLFVQQAAYQO9TRLFFN9HTDQXBSPPJYXMNGLLBHOMNVXNOWE'
                b'IDMJVCLLDFHBDONQJCJVLBLCSMDOUQCKKCQJMGTSTHBXPXAMLMSXRIPUBMBAWBFNLH'
                b'LUJTRJLDERLZFUBUSMF999XNHLEEXEENQJNOFFPNPQ9PQICHSATPLZVMVIWLRTKYPI'
                b'XNFGYWOJSQDAXGFHKZPFLPXQEHCYEAGTIWIJEZTAVLNUMAFWGGLXMBNUQTOFCNLJTC'
                b'DMWVVZGVBSEBCPFSM99FLOIDTCLUGPSEDLOKZUAEVBLWNMODGZBWOVQT9DPFOTSKRA'
                b'BQAVOQ9RXWBMAKFYNDCZOJGTCIDMQSQQSODKDXTPFLNOKSIZEOY9HFUTLQRXQMEPGO'
                b'XQGLLPNSXAUCYPGZMNWMQWSWCKAQYKXJTWINSGPPZG9HLDLEAWUWEVCTVRCBDFOXKU'
                b'ROXH9HXXAXVPEJFRSLOGRVGYZASTEBAQNXJJROCYRTDPYFUIQJVDHAKEG9YACV9HCP'
                b'JUEUKOYFNWDXCCJBIFQKYOXGRDHVTHEQUMHO999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999999999999999999999999999999999999'
                b'999999999999RKWEEVD99A99999999A99999999NFDPEEZCWVYLKZGSLCQNOFUSENI'
                b'XRHWWTZFBXMPSQHEDFWZULBZFEOMNLRNIDQKDNNIELAOXOVMYEI9PGTKORV9IKTJZQ'
                b'UBQAWTKBKZ9NEZHBFIMCLV9TTNJNQZUIJDFPTTCTKBJRHAITVSKUCUEMD9M9SQJ999'
                b'999TKORV9IKTJZQUBQAWTKBKZ9NEZHBFIMCLV9TTNJNQZUIJDFPTTCTKBJRHAITVSK'
                b'UCUEMD9M9SQJ999999999999999999999999999999999999999999999999999999'
                b'999999999999999999999999999999999'
              )

        """
        tryte_string = TransactionTrytes(trytes)

        if not hash_:
            hash_trits: MutableSequence[int] = [0] * HASH_LENGTH

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

            hash_ = TransactionHash.from_trits(hash_trits)

        return cls(
            hash_=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()),
            legacy_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]),
            tag=Tag(tryte_string[2592:2619]),
            attachment_timestamp=int_from_trits(
                tryte_string[2619:2628].as_trits()),
            attachment_timestamp_lower_bound=int_from_trits(
                tryte_string[2628:2637].as_trits()),
            attachment_timestamp_upper_bound=int_from_trits(
                tryte_string[2637:2646].as_trits()),
            nonce=Nonce(tryte_string[2646:2673]),
        )
예제 #18
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)
예제 #19
0
    def test_squeeze_offset(self):
        """
    Passing an ``offset`` argument to :py:meth:`Curl.squeeze`.

    Example use case:
    https://github.com/iotaledger/iri/blob/v1.4.1.6/src/main/java/com/iota/iri/hash/ISS.java#L83
    """
        # noinspection SpellCheckingInspection
        input_ = (
            'CDLFODMOGMQAWXDURDXTUAOO9BFESHYGZLBUWIIHPTLNZCUNHZAAXSUPUIBW'
            'IRLOVKCVWJSWEKRJQZUVRDZGZRNANUNCSGANCJWVHMZMVNJVUAZNFZKDAIVV'
            'LSMIM9SVGUHYECTGGIXTAMXXO9FIXUMQFZCGRQWAOWJPBTXNNQIRSTZEEAJV'
            'FSXWTHWBQJCWQNYYMHSPCYRA99ITVILYJPMFGOGOUOZUVABK9HMGABSORCVD'
            'FNGLMPJ9NFKBWCZMFPIWEAGRWPRNLLG9VYUUVLCTEWKGWQIRIJKERZWC9LVR'
            'XJEXNHBNUGEGGLMWGERKYFB9YEZCLXLKKMCGLRKQOGASDOUDYEDJLMV9BHPG'
            'GCXQIUVUOFFXKEIIINLVWLRYHHLKXPLSTWKIKNEJWEDFQQFXQVEHGRCIJC9T'
            'GVQNPPKGCFGPJNWSCPQZDDSIGAVZEIVYJDVPUOCTEMKTZFGXNGPQCOIBD9MX'
            'YTHJTX')

        trits = TryteString(input_).as_trits()
        curl = Curl()

        trits_out = [0] * 243
        for i in range(6):
            curl.reset()
            curl.absorb(trits, i * 243, (i + 1) * 243)
            curl.squeeze(trits, i * 243)

        curl.reset()
        curl.absorb(trits)
        curl.squeeze(trits_out)

        trits_out = TryteString.from_trits(trits_out)

        # noinspection SpellCheckingInspection
        self.assertEqual(
            trits_out,
            'TAWDGNSEAD9ZRGBBVRVEKQYYVDOKHYQ9KEIYJKFT'
            'BQEYZDWZVMRFJQQGTMPHBZOGPIJCCVWLZVDKLAQVI',
        )
예제 #20
0
    def conductPOW(self, bundle):
        HASH_LENGTH = 243
        mwm = 14  # minimum weight on mainnet tangle (expected 1 minute for iot device at this level)
        trailing_zeros = [0] * mwm  # For checking transaction hash
        previoustx = None
        max_iter = 5
        i = 0

        branch_transaction_hash = bundle.branchObj.bundle_hash
        trunk_transaction_hash = bundle.trunkObj.bundle_hash

        for trxn in reversed(bundle.trxns):
            startTime = time.time()
            trxn.attachment_timestamp = int(round(time.time() * 1000))

            while i != max_iter:
                if (not previoustx):
                    if trxn.current_index == trxn.last_index:
                        trxn.branch_transaction_hash = branch_transaction_hash
                        trxn.trunk_transaction_hash = trunk_transaction_hash
                    else:
                        raise ValueError(
                            'Head transaction is inconsistent in bundle')

                else:  # It is not the head transaction (For clarity, see bundle figure in report)
                    trxn.branch_transaction_hash = trunk_transaction_hash
                    trxn.trunk_transaction_hash = previoustx

                # Let's do the pow locally
                trxn_string = trxn.as_tryte_string().__str__()
                # returns a python unicode string
                powed_trytes = _libccurl.ccurl_pow(trxn_string.encode('utf-8'),
                                                   mwm)
                # construct trytestring from python string
                powed_trytes_bytes = powed_trytes[:2673]
                # Let's decode into unicode
                powed_txn_trytes = powed_trytes_bytes.decode('utf-8')
                powed_txn_trytes = TryteString(powed_txn_trytes)

                # Create powed txn hash
                hash_trits: MutableSequence[int] = [0] * HASH_LENGTH
                sponge = Curl()
                sponge.absorb(powed_txn_trytes.as_trits())
                sponge.squeeze(hash_trits)
                hash = TransactionHash.from_trits(hash_trits)
                trxn.hash = hash
                previoustx = hash

                if hash_trits[-mwm:] == trailing_zeros:
                    # We are good to go, exit from while loop
                    totalTime = time.time() - startTime
                    logger.info("Successfully conducted PoW for trxn " +
                                str(trxn.current_index) +
                                "! Time: {:.4g}".format(totalTime) + " sec")
                    break
                else:
                    i = i + 1
                    logger.info(
                        'Oops, wrong hash detected in try'
                        ' #{rounds}. Recalculating PoW... '.format(rounds=i))

        # Tail transactions represent bundles in the tangle
        return bundle.tail_transaction.hash
예제 #21
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:`iota.transaction.Fragment` instances).

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

  :param public_key:
    The public key value used to verify the signature digest (usually a
    :py:class:`iota.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()
예제 #22
0
def hash(trytes):
    curl = Curl()
    curl.absorb(trytes.as_trits())
    trits_out = []
    curl.squeeze(trits_out)
    return TryteString.from_trits(trits_out)
예제 #23
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__