def test_verify_proof(self): claim1_name = 97 # 'a' claim1_txid = 'bd9fa7ffd57d810d4ce14de76beea29d847b8ac34e8e536802534ecb1ca43b68' claim1_outpoint = 0 claim1_height = 10 claim1_node_hash = get_hash_for_outpoint( unhexlify(claim1_txid)[::-1], claim1_outpoint, claim1_height) claim2_name = 98 # 'b' claim2_txid = 'ad9fa7ffd57d810d4ce14de76beea29d847b8ac34e8e536802534ecb1ca43b68' claim2_outpoint = 1 claim2_height = 5 claim2_node_hash = get_hash_for_outpoint( unhexlify(claim2_txid)[::-1], claim2_outpoint, claim2_height) to_hash1 = claim1_node_hash hash1 = double_sha256(to_hash1) to_hash2 = bytes((claim1_name,)) + hash1 + bytes((claim2_name,)) + claim2_node_hash root_hash = double_sha256(to_hash2) proof = { 'last takeover height': claim1_height, 'txhash': claim1_txid, 'nOut': claim1_outpoint, 'nodes': [ {'children': [ {'character': 97}, { 'character': 98, 'nodeHash': hexlify(claim2_node_hash[::-1]) } ]}, {'children': []}, ] } out = verify_proof(proof, hexlify(root_hash[::-1]), 'a') self.assertTrue(out)
def header_hash_to_pow_hash(header_hash: bytes): header_hash_bytes = unhexlify(header_hash)[::-1] h = sha512(header_hash_bytes) pow_hash = double_sha256( ripemd160(h[:len(h) // 2]) + ripemd160(h[len(h) // 2:]) ) return hexlify(pow_hash[::-1])
def get_root_of_merkle_tree(branches, branch_positions, working_branch): for i, branch in enumerate(branches): other_branch = unhexlify(branch)[::-1] other_branch_on_left = bool((branch_positions >> i) & 1) if other_branch_on_left: combined = other_branch + working_branch else: combined = working_branch + other_branch working_branch = double_sha256(combined) return hexlify(working_branch[::-1])
def aes_encrypt(secret: str, value: str, init_vector: bytes = None) -> str: if init_vector is not None: assert len(init_vector) == 16 else: init_vector = os.urandom(16) key = double_sha256(secret.encode()) encryptor = Cipher(AES(key), modes.CBC(init_vector), default_backend()).encryptor() padder = PKCS7(AES.block_size).padder() padded_data = padder.update(value.encode()) + padder.finalize() encrypted_data = encryptor.update(padded_data) + encryptor.finalize() return base64.b64encode(init_vector + encrypted_data).decode()
def aes_decrypt(secret: str, value: str) -> typing.Tuple[str, bytes]: try: data = base64.b64decode(value.encode()) key = double_sha256(secret.encode()) init_vector, data = data[:16], data[16:] decryptor = Cipher(AES(key), modes.CBC(init_vector), default_backend()).decryptor() unpadder = PKCS7(AES.block_size).unpadder() result = unpadder.update(decryptor.update(data)) + unpadder.finalize() return result.decode(), init_vector except ValueError as e: if e.args[0] == 'Invalid padding bytes.': raise InvalidPasswordError() raise
def hash160_to_address(cls, h160): raw_address = cls.pubkey_address_prefix + h160 return Base58.encode( bytearray(raw_address + double_sha256(raw_address)[0:4]))
def hash_header(header: bytes) -> bytes: if header is None: return b'0' * 64 return hexlify(double_sha256(header)[::-1])
def get_hash_for_outpoint(txhash, nout, height_of_last_takeover): return double_sha256( double_sha256(txhash) + double_sha256(str(nout).encode()) + double_sha256(struct.pack('>Q', height_of_last_takeover)) )
def verify_proof(proof, root_hash, name): previous_computed_hash = None reverse_computed_name = '' verified_value = False for i, node in enumerate(proof['nodes'][::-1]): found_child_in_chain = False to_hash = b'' previous_child_character = None for child in node['children']: if child['character'] < 0 or child['character'] > 255: raise InvalidProofError("child character not int between 0 and 255") if previous_child_character: if previous_child_character >= child['character']: raise InvalidProofError("children not in increasing order") previous_child_character = child['character'] to_hash += bytes((child['character'],)) if 'nodeHash' in child: if len(child['nodeHash']) != 64: raise InvalidProofError("invalid child nodeHash") to_hash += binascii.unhexlify(child['nodeHash'])[::-1] else: if previous_computed_hash is None: raise InvalidProofError("previous computed hash is None") if found_child_in_chain is True: raise InvalidProofError("already found the next child in the chain") found_child_in_chain = True reverse_computed_name += chr(child['character']) to_hash += previous_computed_hash if not found_child_in_chain: if i != 0: raise InvalidProofError("did not find the alleged child") if i == 0 and 'txhash' in proof and 'nOut' in proof and 'last takeover height' in proof: if len(proof['txhash']) != 64: raise InvalidProofError(f"txhash was invalid: {proof['txhash']}") if not isinstance(proof['nOut'], int): raise InvalidProofError(f"nOut was invalid: {proof['nOut']}") if not isinstance(proof['last takeover height'], int): raise InvalidProofError( f"last takeover height was invalid: {proof['last takeover height']}") to_hash += get_hash_for_outpoint( binascii.unhexlify(proof['txhash'])[::-1], proof['nOut'], proof['last takeover height'] ) verified_value = True elif 'valueHash' in node: if len(node['valueHash']) != 64: raise InvalidProofError("valueHash was invalid") to_hash += binascii.unhexlify(node['valueHash'])[::-1] previous_computed_hash = double_sha256(to_hash) if previous_computed_hash != binascii.unhexlify(root_hash)[::-1]: raise InvalidProofError("computed hash does not match roothash") if 'txhash' in proof and 'nOut' in proof: if not verified_value: raise InvalidProofError("mismatch between proof claim and outcome") target = reverse_computed_name[::-1].encode('ISO-8859-1').decode() if 'txhash' in proof and 'nOut' in proof: if name != target: raise InvalidProofError("name did not match proof") if not name.startswith(target): raise InvalidProofError("name fragment does not match proof") return True