예제 #1
0
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!'
        )
예제 #2
0
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
예제 #5
0
 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)