Beispiel #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
Beispiel #2
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()
Beispiel #3
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',
    )
Beispiel #4
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__