Why Bitcoin address is not like an account number

Abubakar Sadiq Ismail
9 min readFeb 13, 2023

Bitcoin address is a set of alphanumeric characters which can also be encoded in a QR code format, bitcoin addresses have uniform prefixes 1, 3, bc1 etc., and each prefix type has a meaning. Bitcoin addresses are used to receive bitcoin payments from other bitcoin holders.

what exactly are those alphanumeric characters? why are those characters used not names? well, the Bitcoin network is decentralized, without any central authority that controls who owns a certain amount of bitcoin, the security of bitcoin relies upon decentralization, mathematical computations, and cryptography.

The bitcoin address plays a vital role in the mathematical process and cryptography that enables us to establish proof of ownership using public and private key cryptography.

Initially, every bitcoin user has some key/pairs which are generated by his wallet applications. these key pairs come in the form of a private and public key, public keys, or sometimes scripts are converted to bitcoin addresses to receive bitcoin from other bitcoin users, and the private keys are used to create signatures in other to spend those bitcoins.

Let's look at the process of generating an address from the base layer which is the private key.

Private Key

The private key is a very large random number, a randomly selected 256-bit number. from a source of entropy or randomness, it’s very important to use a good source of randomness when generating a private key, usually a Cryptographically secure pseudorandom number generator (CPRNG) is used to generate private keys because it uses a quality source of randomness.

(Note it is not advisable to use a default programming language random number generator to generate private keys, because it’s deterministic and follows a certain algorithm to generate the numbers that appear to be random, but are not, if an attacker knows the algorithm combined with some details like the time the private key is generated he might be able to regenerate the private key, CPRNG uses the operating system hardware random number generators that are not deterministic and therefore more secure)

E.g of randomly generated private key.

1384017014564581673784225148274743428035711376255840355808824913

They are called private keys because it’s important to hide them as much as possible, anyone who gets hold of your private key can spend funds sent to the public keys generated from those private keys.

Public Key

Private keys are used to create a public key from a one-way function also known as an asymmetric function, they are called one-way because using the private key we can always generate the public key, but using the public key is infeasible to generate the private key. the function uses an elliptic curve multiplication.

The private key k is an input of the public key generation function.

The elliptic curve for bitcoin is generated from a standard defined as secp256k1. y² = x³ +7 over a very large prime number which is a randomly scattered points.

This is an example of secp256k1 over real numbers.

A point in the curve is selected as the generator point G.

The function computes

k(private key) *G (Generator point) = K (the resulting public key),

k*G = K

E.g k = 7, therefore 7*G = K,

7*G = G + G + G + G + G + G + G.

This basically means k*G is a point on the elliptic curve with the x and y axis, anytime we have k (private key) it will result in the same K (x,y) public key.

But having K (x,y) public key, it’s impossible to generate the k private key as it’s the same as solving the known discrete logarithm problem (https://en.wikipedia.org/wiki/Discrete_logarithm), which is like trying all possible combinations of G’s in the curve, the curve is a very large grid with points all over the curve, and it’s hard to know how many combinations are made to generate the public key points.

hence the calculation is one-way which means calculating the private key from the public key is practically infeasible. the public key is two 256-bit numbers which are x and y values.

E.g

x=55066263022277343669578718895168534326250603453777594175500187360389116729240

y = 32670510020758816978083085130507043184471273380659243275938904335757337482424

When the bits are concatenated the result is a 512 bits number which is the public key.

5506626302227734366957871889516853432625060345377759417550018736038911672924032670510020758816978083085130507043184471273380659243275938904335757337482424

Uncompressed Public Key

There are two ways of representing public keys one is the uncompressed public key, using both x and y values with a prefix to indicate it’s an uncompressed public key (prefix+x+y)

A 04 prefix is used as the prefix of uncompressed public keys and hence results in 520 bits.

E.g

045506626302227734366957871889516853432625060345377759417550018736038911672924032670510020758816978083085130507043184471273380659243275938904335757337482424

The result is the uncompressed public key.

Compressed Public Key

Using the x value we can solve for the y value with the y² = x³ +7 function. We solve and get two values (+,-) y because we are computing the square root of (x³ +7) to get y. the initial y can be either the negative or the positive y (but in reality the negative y is not negative but y modulo the prime order which results in a positive number).

We can omit y and only add the x value to save space which is significant to the bitcoin blockchain size almost 50% reduction in the public key size.

In compressed public keys, we use 02 or 03 as the prefix, when 02 is used the y-axis value is positive and when 03 is used then the y-axis is negative.

The result is a 264-bit instead of the initial 520-bit value with the x and y-axis.

E.g 0255066263022277343669578718895168534326250603453777594175500187360389116729240

You now have the public key which you can share with everyone to receive bitcoin. (this means someone can lock an output with your public key), interestingly you can also combine your public key with another public key to receive bitcoin together like a conventional joint account, in bitcoin, you can specify the number of signatures from the combined public keys that will be needed to unlock the bitcoin either 1, 2 or N.

You own the bitcoin sent to your public key and can anytime spend it by signing with your private key to prove you own the output, the signature can be verified by anyone on the bitcoin network.

ScriptPubKey Types (Templates).
P2PK

Using only the public key to create an output is called pay to a public key (P2PK), it’s a standardized way of creating a transaction output, the public key is added in the scriptPubKey field of the transaction output, along with other parameters which we will discuss later, we can keep using this or use a better approach because this public key is not readable and we can easily err when writing it, also why not reduce the size of the public key? and what if I want more than 3 joined bitcoin accounts?

We have two types of bitcoin addresses, one from a public key hash and the other one from a locking script hash.

P2PKH

Public keys hash is generated from the public key by double hashing the public key first with the sha256 hash function which converts the public key into a 256-bit hash value.

Then the 256 bits hash will be input to a RIPEMD160 hash function which converts the 256-bit hash to another 160 bits hash. the result is the public key hash

public key hash = ripemd160(sha256(public-key))

E.g 6034c213bdf29c1f1c4158c4aba24b3714803055

(note this is a format of public key hash not necessarily a public key hash)

The result is often called pay to public key hash (P2PKH)

P2SH

We mentioned that we can create a joined bitcoin account by combining up to three public keys and specifying the number of signatures that will be required to unlock the bitcoin, but using raw public keys it’s limited to only 3 joined public keys, and also when creating the joined account bitcoin scripting provides the ability to add a complex script with a conditional spending condition. to do more than 3 joined accounts and also add a complex spending condition we can leverage the power of hash functions to use the script created as the input. (Note this script is basically combining the public keys, with bitcoin opcodes and maybe spending paths. read about how script can be constructed here https://en.bitcoin.it/wiki/Script)

Script hash is also generated from the constructed script by double hashing the script first with the sha256 hash function which converts the script into a 256-bit hash value.

Then the 256 bits hash will be input to a RIPEMD160 hash function which converts the 256-bit hash to another 160 bits hash. the result is the public key hash

script hash = ripemd160(sha256(script))

E.g 54c557e07dde5bb6cb791c7a540e0a4796f5e97e

(note this is a format of script hash not necessarily a script hash)

The result is often called pay to script hash (P2SH)

The combination of the P2PK, P2PKH, and P2SH all have the necessary opcodes that are added before locking the bitcoin to them.

P2PK

PubKey EQUALVERIFY CHECKSIG

P2PKH

O_P_DUP HASH160 PubkeyHash EQUALVERIFY CHECKSIG

P2SH

HASH160 scriptHash EQUAL

(EQUALVERIFY, CHECKSIG, HASH160, and O_P_DUP are examples of opcodes used in bitcoin in a locking script).

We have other output formats that are called segregated witness outputs, which omit the opcodes and use only a script version, in the beginning, to specify how to construct the unlocking script and evaluate when verification.

P2WPKH

0 PubKeyHash

0 is the script version. whereby the public key hash is often referred to as a witness program.

P2WSH

0 SHA256(P2SH)

Here 0 is also the script version and SHA256(P2SH) is the witness program

The key difference between P2WPKH and P2WSH is the witness program P2WPKH is 160 bits while P2WSH is 256 bits. this reduces the size of transaction outputs by removing the locking opcodes and also provides a way to introduce new verification algorithms using a new script version.

This is what is often seen in the bitcoin blockchain in transaction outputs, not bitcoin addresses only public keys, public key hashes and scripts hashes.

Your balance is the sum of the value of all the unspent transaction outputs with your public key, public key hash or script with a locking condition you can unlock.

Addresses

Bitcoin addresses are encoded P2PK, P2PKH e.t.c in a format that is easier to read, with fewer characters and sometimes omitting similar characters, distinguishing between the types of ScriptPubkeys encoded easily with a prefix that will indicate this is a P2PKH or this is a P2SH, It also provides error detection and correction.

ScriptPubKeys are encoded using the base58check encoding format for P2PK, P2PKH, P2SH, and bech32 encoding for P2WPKH and P2WSH, P2TR(A new scriptPubKey type for segwit version 1) the resulting code is the bitcoin address

the code also can be decoded to get the exact value before constructing a transaction, the encoding is an easy way to share the keys, and distinguish the scriptPubkeys also aids in interoperability between wallet applications.

Base58check encoding.

P2PKH

O_P_DUP HASH160 a1f75380c839f1815531221193a50ac1b7f35909 EQUALVERIFY CHECKSIG

Base58check encoded P2PKH address

14cxpo3MBCYYWCgF74SWTdcmxipnGUsPw3

1 is added by the encoding function as the identifier that the address is a P2PKH, 4 is a prefix of a P2PK, whereas P2SH addresses have a prefix of 3.

Learn about how the base58check encoding works (https://en.bitcoin.it/wiki/Base58Check_encoding)

Bech32 Encoding.

The bech32 is a segwit address format which is used to encode PWPKH or P2WSH and P2TR.

P2WPKH

0 751e76e8199196d454941c45d1b3a323f1433bd6

Bech32 encoded P2WPKH address

bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4

Learn about how the bech32 encoding works (https://www.youtube.com/watch?v=NqiN9VFE4CU)

Conclusion

Bitcoin addresses technically are a set of characters that encode a certain bitcoin transaction output type (P2PKH, P2SH, P2WPKH etc) and the prefix in the address specifies which output type is encoded. An output type is used to receive bitcoin by adding it in a transaction as the locking script known as scriptPubKey of an unlocked output, it specifies the next chain of ownership, and the person that can unlock the locking script claims ownership of the output, in bitcoin transactions we only see output types, not addresses, and to construct users balance we gather the sum of the values of all satoshi in the locked outputs that the user can unlock.

Bitcoin Addresses encode the output types, aid in readability, interoperability between wallet applications and sometimes error detection and correction.

Do addresses ever “receive” bitcoin? One might argue that they do not… When Bitcoin is “sent to an address” really what happens is a new (unspent) output is created in a transaction which can only be unlocked (spent), using a `scriptSig` which corresponds to the `scriptPubKey` encoded by the address. So there really is no moment in time at which bitcoin is ever “sent to an address”… The address isn’t ever a real “location on the blockchain” so to speak.

References

https://river.com/learn/terms/b/bech32/#:~:text=Bech32%20is%20an%20encoding%20scheme,includes%20an%20error%20detection%20mechanism.

https://security.stackexchange.com/questions/4889/using-computer-random-number-generators-to-produce-keys-it-is-secure#:~:text=All%20software%20is%20deterministic.,not%20even%20be%20pseudo%2Drandom.

https://bitcoin.stackexchange.com/questions/71344/what-is-a-discrete-logarithmic-assumption-how-does-it-set-up-trustless-proofs#:~:text=The%20discrete%20logarithm%20problem%20is,of%20much%20of%20modern%20cryptography.&text=where%20b%20%2C%20a%20%2C%20and%20p,need%20to%20brute%20force%20it.

https://bitcoin.stackexchange.com/questions/49158/why-do-you-use-bitcoin-addresses-instead-of-public-keys

https://en.bitcoin.it/

--

--