def get_redeem_pub_key_obj(): # # Get the private key for the p2pkh of the redeem script # # Using a public key has not been tested. # Support for public from user submitted text looks like it's limited in bitcoin-utils lib. # function_section = 'Function 1' private_key_to = Common.get_config_value(function_section, 'private_key_to') public_key_to = Common.get_config_value(function_section, 'public_key_to') if len(private_key_to) > 0: redeem_pub_key_obj = Common.get_pub_key_from_priv_key_obj( private_key_to) return redeem_pub_key_obj # Not tested and copied the line below from the lib. elif len(public_key_to) > 0: return PublicKey.from_hex( hexlify(public_key_to.to_string()).decode('utf-8')) else: sys.exit( 'No private or public key provided in configuration of function 1!' )
def main(): #Connect to the regtest setup('regtest') proxy = NodeProxy('user', 'bitcoin').get_proxy() #Accept a Public Key from User and derive a P2PKH address from it pk = PublicKey.from_hex(input('Please input your Public Key\n')) pk_p2pkh_addr = pk.get_address() #Accept future absolute block amount from User current_blocks = proxy.getblockcount() absolute_blocks = int( input( f'\nPlease input the future block height. The current block height is: {current_blocks}\n' )) #Set the timelock sequence and create a redeemScript accordingly redeem_script = Script([ absolute_blocks, 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 'OP_DUP', 'OP_HASH160', pk_p2pkh_addr.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG' ]) #Generate a P2SH Address from the redeemScript and show it p2sh_addr = P2shAddress.from_script(redeem_script) print( f'\nThe P2SH Address is:\n{p2sh_addr.to_string()} Now, go on and send some funds to it.\n' )
def validate_certificate(cert, issuer_identifier, testnet, blockchain_services): filename = os.path.basename(cert) tmp_filename = '__' + filename shutil.copy(cert, tmp_filename) issuer_address = get_issuer_address(tmp_filename) proof = get_and_remove_chainpoint_proof(tmp_filename) if proof == None: os.remove(tmp_filename) return False, "no chainpoint_proof in metadata" # get the hash after removing the metadata filehash = '' with open(tmp_filename, 'rb') as pdf_file: filehash = hashlib.sha256(pdf_file.read()).hexdigest() # instantiate chainpoint object cp = ChainPointV2() txid = cp.get_txid_from_receipt(proof) # make request to get txs regarding this address # issuance is the first element of data_before_issuance data_before_issuance, data_after_issuance = \ network_utils.get_all_op_return_hexes(issuer_address, txid, blockchain_services, testnet) # validate receipt valid, reason = cp.validate_receipt(proof, data_before_issuance[0], filehash, issuer_identifier, testnet) # display error except when the certificate expired; this is because we want # revoked certificate error to be displayed before cert expired error # TODO clean hard-coded reason if not valid and not reason.startswith("certificate expired"): return False, reason # set bitcoin network (required for addr->pkh in revoke address) if testnet: setup('testnet') else: setup('mainnet') # check if cert's issuance is after a revoke address cmd on that address # and if yes then the issuance is invalid (address was revoked) # we check before checking for cert revocations since if the issuance was # after an address revocation it should show that as an invalid reason # 0 index is the actual issuance -- ignore it for i in range(len(data_before_issuance))[1:]: cred_dict = cred_protocol.parse_op_return_hex(data_before_issuance[i]) if cred_dict: if cred_dict['cmd'] == cred_protocol.hex_op('op_revoke_address'): issuer_pkh = P2pkhAddress(issuer_address).to_hash160() if issuer_pkh == cred_dict['data']['pkh']: return False, "address was revoked" # check if cert or batch was revoked from oldest to newest for op_return in reversed(data_after_issuance): cred_dict = cred_protocol.parse_op_return_hex(op_return) if cred_dict: if cred_dict['cmd'] == cred_protocol.hex_op('op_revoke_batch'): if txid == cred_dict['data']['txid']: return False, "batch was revoked" elif cred_dict['cmd'] == cred_protocol.hex_op('op_revoke_creds'): if txid == cred_dict['data']['txid']: # compare the certificate hash bytes filehash_bytes = utils.hex_to_bytes(filehash) ripemd_filehash = utils.ripemd160(filehash_bytes) ripemd_hex = utils.bytes_to_hex(ripemd_filehash) if ripemd_hex == cred_dict['data']['hashes'][0]: return False, "cert hash was revoked" if len(cred_dict['data']['hashes']) > 1: if ripemd_hex == cred_dict['data']['hashes'][1]: return False, "cert hash was revoked" elif cred_dict['cmd'] == cred_protocol.hex_op('op_revoke_address'): # if address revocation is found stop looking since all other # revocations will be invalid issuer_pkh = P2pkhAddress(issuer_address).to_hash160() if issuer_pkh == cred_dict['data']['pkh']: break # if not revoked but not valid this means that it was expired; now that we # checked for revocations we can show the expiry error if not valid: return False, reason # now that the issuer (anchoring) was validated validate the certificate # with the owner's public key (vpdf v2) # get owner and owner_proof removing the latter owner, owner_proof = get_owner_and_remove_owner_proof(tmp_filename) if owner: # get public key pk = PublicKey.from_hex(owner['pk']) # get file hash sha256_hash = None with open(tmp_filename, 'rb') as pdf: sha256_hash = hashlib.sha256(pdf.read()).hexdigest() # cleanup now that we got original filehash os.remove(tmp_filename) # finally check if owner signature is valid #print(pk.get_address().to_string(), pk.to_hex(), sha256_hash, owner_proof) try: if (pk.verify(owner_proof, sha256_hash)): pass except Exception: #BadSignatureError: return False, 'owner signature could not be validated' # in a valid credential the reason could contain an expiry date return True, reason
def load_data_json(priv=False, pub=False, pub_hash=False, timelock_csv=False, timelock_tx=False, timelock_log=False, p2pk=False): """loads parameters used to create P2SH address and spending transactions from the data.json file - initiates/converts applicable objects/data returns : dict of data for the Attributes specified - e.g {'priv_key': object, 'pub': object, 'pub_hash': 'string'} """ # reads user data from data.json with open('data.json', 'r') as json_file: data = json.load(json_file) usr_inputs = data['csv_timelock']['inputs'] # initiates key objects if priv or pub or pub_hash: usr_priv = usr_inputs['priv_key'] usr_pub = usr_inputs['pub_key'] if priv and not usr_priv: errors.missing_data('private key') elif usr_priv: priv_key = PrivateKey.from_wif(usr_priv) pub_key = priv_key.get_public_key() elif usr_pub: pub_key = PublicKey.from_hex(usr_pub) else: # prints error msg & raises systemExit errors.missing_data('public key') # loads timelock condition and converts format if timelock_csv or timelock_tx or timelock_log: lock_height = usr_inputs['block_lock'] if lock_height: seq = Sequence(TYPE_RELATIVE_TIMELOCK, lock_height) timelock_script = seq.for_script() timelock_txin = seq.for_input_sequence() else: # prints error msg & raises systemExit errors.missing_data('timelock period') # initaites P2pkhAddress object if p2pk: address = usr_inputs['p2pkh_address'] if address: p2pkh_address = P2pkhAddress.from_address(address) else: # prints error msg & raises systemExit errors.missing_data('P2PKH address') # fills return outputs with specified data from func arguments outputs = {} if priv: outputs['priv_key'] = priv_key if pub: outputs['pub_key'] = pub_key if pub_hash: outputs['pub_key_hash'] = pub_key.to_hash160() if timelock_csv: outputs['timelock_csv'] = timelock_script if timelock_tx: outputs['timelock_tx'] = timelock_txin if timelock_log: outputs['timelock_log'] = lock_height if p2pk: outputs['p2pk_addr'] = p2pkh_address return outputs
def test_pubkey_uncompressed_from_hex(self): pub = PublicKey.from_hex(self.public_key_hex) self.assertEqual(pub.to_hex(compressed=False), self.public_key_hex)