Pay to Public Key Hash (P2PKH)
The early versions of Bitcoin allowed a sender to use the recipients IP Addresses instead of their Public Key to transfer funds
Alice’s full node would connect directly to Bob’s full node and request his wallet for a public key. The wallet would generate a new public key for this transaction
Alice’s wallet would create a transaction that has an output that pays to Bob’s key
Bob can later spend the funds by creating a transaction that has input with his digital signature
# Output Script
<Bob's public key> OP_CHECKSIG
# Input Script
<Bob's signature>
# Processing Order
<Bob's signature> <Bob's public key> OP_CHECKSIG
To process a transaction the output of the previous transaction and the input of the current transaction are placed on a stack
The input script is placed first which is followed by the output script
OP_CHECKSIG
function takes 2 inputs so it consumes the 2 values that are present below it on the stack
The function checks if the public key and signature are related
It also checks if the signature commits to the various fields in the transaction
This type of output is called “Pay to Public Key (P2PK)”
This approach not widely used. New versions Bitcoin do not support this method
Legacy Address Drawbacks
This legacy method had many downsides for one the receiver had to be online at the IP addresses entered by the sender in order for the public key to be fetched
This also meant that the IP address had to be accessible from the internet this was not always possible
The reason this approach was because was because the public keys is a very large number and it was not possible to share it easily
An alternative to sharing the public key is to share the commitment of a public key
This is done using hash functions. The output is an commitment to the input value
The output of SHA256 would produce a 256 bit (32 byte) result which is less than half the size of the Bitcoin public key
This output is still quite long so its passed threw the RIPEMD160 hash function that produces an output that is 160 bit (20 byte) long
This final result (hash) acts as the commitment for the input (public key)
# Output Script
OP_DUP OP_HASH160 <Bob's commitment> OP_EQUAL OP_CHECKSIG
# Input Script
<Bob's signature> <Bob's public key>
# Processing Order
<sig> <pubkey> OP_DUP OP_HASH160 <commitment> OP_EQUALVERIFY OP_CHECKSIG
OP_DUP
duplicates the value that is provided below it
<sig> <pubkey> <pubkey> OP_HASH160 <commitment> OP_EQUALVERIFY OP_CHECKSIG
OP_HASH160
takes the previous value and calculates its hash (commitment)
<sig> <pubkey> <commitment> <commitment> OP_EQUALVERIFY OP_CHECKSIG
OP_EQUALVERIFY
takes 2 inputs. It checks the the commitment provided and commitment calculated are the same.
<sig> <pubkey> OP_CHECKSIG
OP_CHECKSIG
takes 2 inputs. It will check if the signature and public key are related
Using this approach Bob’s no longer has to share a very long string with Alice. But there is still a problem. Alice needs to ensure that she inputs the correct hash else the coins will be sent to an incorrect address.
Base58check Encoding
Base58 = Base64 without 0 (zero), O, l (lowercase L), I (Capital i) and “+” and “/”
They were removed as they could be confused for other characters
For extra security base58 encoding includes a 4 byte checksum with the data
The checksum is derived from the hash of the data
This prevents wallets from sending funds to nonexistent addresses
To convert a number to Base58 a prefix is added to the data (version byte)
This values is double-SHA hashed. This produces a 32 byte result
The 1st 4 bytes of of this result is used as the checksum. Added as footer
This (prefix + data + checksum) is passed to the Base58 encoding function
For P2PKH addresses the public key commitment is used as the input to the Base58check encoding function
In Bitcoin other information is also represented using Base58check
For each of the data the data prefix changed
Each data prefix causes the hash to be begin with the same value
Pay to Script Hash (P2SH)
The output of an transaction can have constraints that have to be satisfied before the coins can be spent (e.g. require multiple signatures)
In P2PK the only constraint required was the digital signature
In P2SH various constraint like public key and time lock was supported
For Alice to place the constraints she would first have to communicate with Bob to get the necessary data
Providing this data directly is not feasible as data like public key are very long
So similar to P2PK a commitment hash is created (redemption script)
The hash is generated hashing using SHA256 followed by RIPEMD-160
Alice sends the coins to the redeem script provided by Bob
When Bob wants to use the coins he needs to provided the redeem script (along with the data) that matches the input redeem script
This is also a legacy addressing approach and has been replaced by Bech32
Legacy addresses were ditched as hash collisions were theoretical possible