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
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()
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', )
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__