3

So I have already the public key. My question is if I'm applying correctly the b58 encoding, since bitcoin uses b58check, and also adds x00 prefix. Can somebody explain me that? Thanks.

import hashlib
import base58

# ECDSA Public Key
base64_str = 'MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE7P0EE5amecnYKMlq96RUL3Q+mZJCQrta6iHyjQWtsbbgcBMayhR/CTzDi5j4Fb/wD9EclHt3dpYRyJcl9Rtmug=='

hex_str = base64_str.decode('base64').encode('hex')

sha = hashlib.sha256()
rip = hashlib.new('ripemd160')

sha.update(base64_str.decode('base64'))

rip.update(sha.hexdigest())

# Get address
print base58.b58encode(rip.hexdigest())
1

No.

A public key (the data you're going to hash) looks like this:

04 xx xx xx xx xx ... (uncompressed, 65 hex bytes)

or

(02 or 03) xx xx xx xx xx ... (compressed, 33 hex bytes)

It's not a DER format public key.

  • "It's not a DER format public key." It is a base64 string extracted from a PEM certificate generated with: openssl ec -in private_key.pem -pubout -out pub_key.pem So, decoding the base64 string with base64_str.decode('base64') does not help? In such case, How can I generate a private/public key suitable for bitcoin using openssl ? – John Smith Jul 21 '17 at 20:46
  • I haven't found a reference that explains how to actually generate a ECDSA keypair without the PEM format. – John Smith Jul 21 '17 at 20:59
  • This involves rolling your own crypto, which you shouldn't. You might want to use pyecdsa, and you'll not need any external libraries to use it. In the documentation it says that VerifyingKey.to_string() returns the x and y coordinates as a hex string. You just prepend "04" to it and decode it from hex. Additionally, you might want to see pybitcointools, but that library is buggy and I don't recommend using it. – user48462 Jul 22 '17 at 6:38
  • 1
    (1) compressed point begins 02 or 03. (2) the point is exactly the 'value' (after removing unused_bits) of the BIT STRING at the end of the DER-encoded SubjectPublicKeyInfo; since the AlgorithmIdentifier for EC,secp256k1 is always the same, you can simply unbase64, drop the first 23 octets and keep the rest, which is easy in Python. ... – dave_thompson_085 Sep 20 '17 at 7:45
  • ... @JohnSmith: openssl ec or openssl pkey can create binary DER as well as PEM, which saves the trim-and-unbase64, but it's still SPKI and not actually what you want. openssl asn1parse <pubkey.pem -strparse 20 -out point.bin reports error 0D07207B but writes the desired value in spite of the error. (Note asn1parse needs 20 for the tag of the BIT STRING whereas 23 is the 'stripped' value.) – dave_thompson_085 Sep 20 '17 at 7:46
1

If the public key were correct (see Mark's answer), the code is not complete (lacks signature) and contains a hash of an ASCII hexdigest which is not correct.
I'd like to contribute with this implementation of bitcoin address from public key.
It covers the case of both uncompressed and compressed bitcoin addresses (just changing compress_pubkey boolean value).

#!/usr/bin/env python2
# https://en.bitcoin.it/wiki/Protocol_documentation#Addresses

import hashlib
import base58

# ECDSA bitcoin Public Key
pubkey = '0450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b23522cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6'
# See 'compressed form' at https://en.bitcoin.it/wiki/Protocol_documentation#Signatures
compress_pubkey = False


def hash160(hex_str):
    sha = hashlib.sha256()
    rip = hashlib.new('ripemd160')
    sha.update(hex_str)
    rip.update( sha.digest() )
    print ( "key_hash = \t" + rip.hexdigest() )
    return rip.hexdigest()  # .hexdigest() is hex ASCII


if (compress_pubkey):
    if (ord(pubkey[-2:].decode('hex')) % 2 == 0):
        pubkey_compressed = '02'
    else:
        pubkey_compressed = '03'
    pubkey_compressed += pubkey[2:66]
    hex_str = pubkey_compressed.decode('hex')
else:
    hex_str = pubkey.decode('hex')

# Obtain key:

key_hash = '00' + hash160(hex_str)

# Obtain signature:

sha = hashlib.sha256()
sha.update( key_hash.decode('hex') )
checksum = sha.digest()
sha = hashlib.sha256()
sha.update(checksum)
checksum = sha.hexdigest()[0:8]

print ( "checksum = \t" + sha.hexdigest() )
print ( "key_hash + checksum = \t" + key_hash + ' ' + checksum )
print ( "bitcoin address = \t" + base58.b58encode( (key_hash + checksum).decode('hex') ) )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.