A Bitcoin wallet addresses … ‘1’ or ‘3’?

In creating bitcoins, Satoshi created a P2PKH (Pay to Public Key Hash) address. These addresses are used to identify the wallet to be paid…

Photo by Emil Kalibradov on Unsplash

Bitcoin wallet addresses … ‘1’ or ‘3’?

In creating bitcoins, Satoshi created a P2PKH (Pay to Public Key Hash) address. These addresses are used to identify the wallet to be paid and links to the public key of the owner. Basically, when a payer signs a transaction with their private key, this signature can be checked again the wallet address.

The original addresses started with a ‘1’, such as [here]:

In order to support the sending of bitcoins to and from multiple addresses, Bitcoin was upgraded with SegWit (defined in BIP141). The wallet address then integrates the pay to witness public key hash (Pay to script hash — P2SH). These addresses start with a ‘3’, such as [here]:

If you are interested, here is the first transaction to use the P2SH address [here]:

Generating the key pair

In generating both types of addresses, we start with the creation of a random 256-bit private key (sk). As we use the sepc256k1 curve, we compute the public key (pk) from pk=sk.G, and where G is the base point on the curve. We then generate a compressed public key point. This starts with a ‘0x04’ (to identify it is a compressed point) and followed by the hex value for the x-coordinate and then the hex value of the y-coordinate. For example, the public key point of:

(d48244894b841891152ad0c319d756535d3ecdf165a67b604e243cbda686ad8b, 4bdac1c339a1f589ea6445a59bd4448e6b3c0a6dbf048391e687bcd32c27f30d)

will have a compressed point value of:

04d48244894b841891152ad0c319d756535d3ecdf165a67b604e243cbda686ad8b4bdac1c339a1f589ea6445a59bd4448e6b3c0a6dbf048391e687bcd32c27f30d

The compressed public key will thus have 130 hex characters, as we use two characters for the ‘04’ part, and then each co-ordinate value is a 256-bit value (64 hex characters). For the private key, we covert to a Wif value, and which is stored in the wallet. This is the key that is used to sign a transaction and is basically a Base-58 version of the private key. Base-58 takes six bits at a time and converts the output as Base-64, but where we remove: 0 (zero), O (capital o), I (capital i) and l (lower case L), and non-alphanumeric characters of + (plus) and / (slash). The Base-58 alphabet is then:

123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

Computing the wallet address

Next, we compute the wallet address based on the public key, and is created a SHA-256 hash of the public key, and then hashing again with a 160-bit RIPEMD-160 hash:

Address=’1'+RIPEMD160(SHA-256(pub))

For SegWit, we basically define a version of ‘3’, a PUSH(20) value (0x0014), and then the same hash as before:

Address=’3'+RIPEMD160(SHA-256(‘0014’+pub))

An overview of this process is:

Code

The following is an outline is [code]:

from bip32utils import Base58
import hashlib
import binascii
import ecdsa
import random
def hash160(x): # Both accepts & returns bytes
return hashlib.new('ripemd160', hashlib.sha256(x).digest()).digest()
def SegWit_address(pk, testnet=False):
    # The Script sig is PUSH(20) and then Hash160(pk) and where pk is the compressed public key
push_20 = bytes.fromhex("0014")
script_sig = push_20 + hash160(bytes.fromhex(pk))
    prefix = b"\xc4" if testnet else b"\x05"
address = Base58.check_encode(prefix + hash160(script_sig))
return address
def pubKeyToAddr(s):
ripemd160 = hash160(bytes.fromhex(s))
return '1'+Base58.check_encode(ripemd160)
def privateKeyToWif(key_hex):    
return Base58.check_encode(bytes.fromhex(key_hex))

def privateKeyToPublicKey(s):
pk = ecdsa.SigningKey.from_string(bytes.fromhex(s), curve=ecdsa.SECP256k1)
pk=pk.get_verifying_key().to_string()
pk="04"+binascii.b2a_hex(pk).decode()
return (pk)

private_key = ''.join(['%x' % random.randrange(16) for x in range(0, 64)])
print ('Private key: ',private_key)
pub = privateKeyToPublicKey(private_key)
print ('\nPublic key: ',pub)
print ('\nWif: ',privateKeyToWif(private_key))
print ('\nAddress: ',pubKeyToAddr(private_key))
print ("\n===BIP 141===")
print ("SegWit address: ",SegWit_address(pub))
print ("Test net: ",SegWit_address(pub, testnet=True))

A sample run is [here]:

Private key:  004290d3940a179420b7c5f4d37a1480c652473cd337bd3bbd115bc9e4947084
Public key:  042a32ac582016213e91f22dd40e78cd00a6bb79fb527958067a4414e284b74f01c4dcbf6aacfe8638c7f4b7510d4c34031c4021153aeb5facae7b756ed331f242
Wif:  17eERopZsEWvTjqtQi9SeUxTz8W7KeZHwvGL1BBx61Z9Hpo9r
Address:  13Jkybvi3qV3YJAFetAZP9CwJtA3LP3hUG

===BIP 141===
SegWit address: 38xNaCLWdqtTag6WmrJbKzvrxGt2Uj9vyL
Test net: 2MzWadwGYFJPonTj4SyvTwwv8Ad6CHRJTvs

and here is some code:

Conclusions

Satoshi created, he/she then left the stage and left his engine running. Without ever stopping, it has managed to keep going for over a decade. While it’s a long way off being efficient, you must marvel at its simplicity and its trustworthiness.