First, what you defining as public key and private key are actually a
bitcoin address and a
private key encoded in Wallet Import Format
In order to check that the
WIF and the
bitcoin addresses are from the same key pair, we will need to decode the
private key from its
WIF format (checking that the encoding is ok), derive the
public key from the
private key, and generate the
bitcoin address using the
public key. If the generated
bitcoin address matches with the provided one, then the provided one and the
WIF are created from the same key pair.
In order to decode the
WIF we will follow the steps from the bitcoin wiki.
Lets see how we can do this in python:
from binascii import hexlify, unhexlify
from ecdsa import SigningKey, SECP256k1
from hashlib import sha256
from bitcoin_tools.wallet import generate_btc_addr, WIF, TESTNET_WIF
def wif_to_sk(wif, network='main'):
if network not in ['main', 'test']:
# Add more networks if needed.
raise Exception('Bad network')
if network is 'main':
version = WIF
version = TESTNET_WIF
decoded_wif = b58decode(wif)
c = decoded_wif[-4:]
v = decoded_wif[:1]
# The byte defines the version, assert that is correct.
assert v == chr(version)
# The four last bytes of the WIF are the four first bytes of the checksum, check that it holds
checksum = sha256(sha256(decoded_wif[:-4]).digest()).digest()
assert checksum[:4] == c
# If the private key in the WIF corresponds to a compressed public key, you must also drop the last byte, that will
# be 01. We can check that by checking the length of the current key. 32 bytes wil mean uncompressed, while 33 and
# a leading 01 means compressed.
sk = hexlify(decoded_wif[1:-4])
compressed = False
# Notice that since we have hexlified the sk, the sizes are doubled.
if len(sk) is 66 and sk[-2:] == '01':
sk = unhexlify(sk[:-2])
compressed = True
sk = unhexlify(sk)
return sk, compressed
# Your provided data
wif = 'KwfNqMip1ZdgG2o6wYQUBXv8BqkMQ8VWWeScVU5TLPZp31M5EHeq'
btc_addr = '13YcHBzsBX8SxHoBftb69cXJkdXLfAVQos'
network = 'main'
sk, compressed = wif_to_sk(wif, network=network)
# Derive the public key from the private key
pk = SigningKey.from_string(sk, curve=SECP256k1).get_verifying_key()
# Assert that the computed bitcoin address and the provided one matches.
assert generate_btc_addr(pk, v=network, compressed=compressed) == btc_addr
To decode the
WIF format there is a couple of things that you may know. First, the
version of the network (normally either
testnet) and then, if the
private key corresponds to a compressed or uncompressed
public key. The version of the network will determine the first byte of the
WIF format, while whether the related
public key is compressed or uncompressed will determine the last byte before the
Disclaimer: The provided code uses a function
generate_btc_addr, from a python library I've developed, that computes a
bitcoin address from a given
public key. Such function call a bunch of other simple functions to derive the
bitcoin address, but including all on the answer will make it even longer that what it is. You can either get the library from GitHub, or get the functions from the specific file.