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_bundle_hash(secret: str) -> str: """ Hashes the user secret to produce a bundle hash :param secret: str :return: str """ sponge = shake() sponge.update(strings.encode(secret)) return sponge.hexdigest(32)
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 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
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)
def __init__( self, key ): ###INITIALIZES CIPHER AND EVERYTHING NEEDED TO ENCRYPT AND DECRYPT #self.nums_key = list(map(lambda x: ord(chr(x)), shake(key.encode()).digest())) #64 nums long self.shooketh = shake(key.encode()).digest() self.nums_key = list( map(lambda x: ord(chr(x)), self.shooketh)) #_#change ord(chr(x)) to ord(x)#_# self.block_size = 64 #block_size is 64 cause key must be 64 characters long self.pad = lambda s: s + ( self.block_size - len(s) % self.block_size) * chr( self.block_size - len(s) % self.block_size ) ###pads the password to be 64 characters long self.unpad = lambda s: s[:-ord(s[len(s) - 1:]) ] ###unpads to its orginal character length
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 short_hash(self, key): sponge = shake() sponge.update(strings.encode(key)) return self.encode(sponge.digest(8))
def generate_private_key(self, key): sponge = shake() sponge.update(strings.encode(key)) return self.encode( hex_decode( SecretKey(sponge.digest(crypto_box_SECRETKEYBYTES)).hex_sk()))