def hash_atoms(cls, atoms: List['Atom'], output: str = 'base17') -> Union[str, None, List]:
        """
        :param atoms: List[Atom]
        :param output: str default base17
        :return: Union[str, None, List]
        """
        atom_list = Atom.sort_atoms(atoms)
        molecular_sponge = shake()
        number_of_atoms = strings.encode(str(len(atom_list)))

        for atom in atom_list:
            molecular_sponge.update(number_of_atoms)

            for prop, value in atom.__dict__.items():

                if value is None and prop in ['batchId', 'characters', 'pubkey']:
                    continue

                if prop in ['otsFragment', 'index']:
                    continue

                if prop in ['meta']:
                    atom.meta = Meta.normalize_meta(value)
                    for index, meta in enumerate(atom.meta):
                        if meta['value'] is not None:
                            atom.meta[index]['value'] = str(meta['value'])

                            for key in ['key', 'value']:
                                molecular_sponge.update(strings.encode(meta[key]))
                    continue

                if prop in ['position', 'walletAddress', 'isotope']:
                    molecular_sponge.update(strings.encode('' if value is None else value))
                    continue

                if value is not None:
                    molecular_sponge.update(strings.encode(value))

        target = None

        if output in ['hex']:
            target = molecular_sponge.hexdigest(32)
        elif output in ['array']:
            target = list(molecular_sponge.hexdigest(32))
        elif output in ['base17']:
            target = strings.charset_base_convert(
                molecular_sponge.hexdigest(32), 16, 17, '0123456789abcdef', '0123456789abcdefg'
            )

            target = target.rjust(64, '0') if isinstance(target, str) else None

        return target
Esempio n. 2
0
def ots(molecule: 'Molecule') -> bool:
    """
    This section describes the function DecodeOtsFragments(Om, Hm), which is used to transform a collection
    of signature fragments Om and a molecular hash Hm into a single-use wallet address to be matched against
    the sender’s address.

    :param molecule: Molecule
    :return: bool
    :raises [MolecularHashMissingException, AtomsMissingException, SignatureMalformedException, SignatureMismatchException]:
    """
    missing(molecule)

    # Determine first atom
    first_atom = molecule.atoms[0]
    # Rebuilding OTS out of all the atoms
    key = ''.join([atom.otsFragment for atom in molecule.atoms])

    # Wrong size? Maybe it's compressed
    if 2048 != len(key):
        # Attempt decompression
        key = strings.base64_to_hex(key)
        # Still wrong? That's a failure
        if 2048 != len(key):
            raise SignatureMalformedException()

    key_fragments = molecule.signature_fragments(key, False)

    # Absorb the hashed Kk into the sponge to receive the digest Dk
    sponge = shake()
    sponge.update(strings.encode(key_fragments))
    digest = sponge.hexdigest(1024)

    # Squeeze the sponge to retrieve a 128 byte (64 character) string that should match the sender’s
    # wallet address
    sponge = shake()
    sponge.update(strings.encode(digest))
    address = sponge.hexdigest(32)

    if address != first_atom.walletAddress:
        raise SignatureMismatchException()

    return True
    def generate_public_key(cls, key: str) -> str:
        """
        :param key: str
        :return: str
        """
        digest_sponge = shake()

        for fragment in strings.chunk_substr(key, 128):
            working_fragment = fragment

            for _ in range(16):
                working_sponge = shake()
                working_sponge.update(strings.encode(working_fragment))
                working_fragment = working_sponge.hexdigest(64)

            digest_sponge.update(strings.encode(working_fragment))

        sponge = shake()
        sponge.update(strings.encode(digest_sponge.hexdigest(1024)))

        return sponge.hexdigest(32)
    def signature_fragments(self, key, encode: bool = True):

        key_fragments = ''
        normalized_hash = self.normalized_hash()

        # Subdivide Kk into 16 segments of 256 bytes (128 characters) each
        for index, ots_chunk in enumerate(map(''.join, zip(*[iter(key)] * 128))):
            working_chunk = ots_chunk

            for _ in range(8 + normalized_hash[index] * (-1 if encode else 1)):
                sponge = shake()
                sponge.update(strings.encode(working_chunk))
                working_chunk = sponge.hexdigest(64)

            key_fragments = '%s%s' % (key_fragments, working_chunk)
        return key_fragments
    def generate_private_key(cls, secret: str, token: str, position: str) -> str:
        """
        :param secret: str
        :param token: str
        :param position: str
        :return: str
        """
        # Converting secret to bigInt
        # Adding new position to the user secret to produce the indexed key
        indexed_key = '%x' % add(array([int(secret, 16)], dtype='object'),
                                 array([int(position, 16)], dtype='object'))[0]
        # Hashing the indexed key to produce the intermediate key
        intermediate_key_sponge = shake()
        intermediate_key_sponge.update(indexed_key.encode('utf-8'))

        if token not in ['']:
            intermediate_key_sponge.update(token.encode('utf-8'))

        # Hashing the intermediate key to produce the private key
        sponge = shake()
        sponge.update(strings.encode(intermediate_key_sponge.hexdigest(1024)))

        return sponge.hexdigest(1024)