Bitcoin Keys and Addresses: A Comprehensive Guide

·

Table of Contents

1. Bitcoin Private Keys

Bitcoin uses the elliptic curve Secp256k1, where a private key is a random number between 1 and n-1. The value of n is:

n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F

This enormous range (~1.15792 × 10⁷⁷) makes private keys practically impossible to guess.

1.1. Private Key Encoding

A 256-bit private key can be encoded in three formats:

  1. Hexadecimal form
  2. Wallet Import Format (WIF)
  3. WIF-compressed format

Example private key encodings:

FormatExample
Hex0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d
WIF5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ (starts with 5)
WIF-compressedKwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617 (starts with K/L)

1.1.1. WIF and WIF-Compressed Encoding

WIF encoding process:

  1. Add version byte (0x80 for mainnet)
  2. For WIF-compressed: append 0x01
  3. Perform SHA-256 twice
  4. Take first 4 bytes as checksum
  5. Base58Check encode

Python implementation available in section 1.1.2.

1.1.3. Encrypted Private Keys (BIP38)

BIP38 proposes AES encryption for private keys, producing addresses starting with "6P":

ItemExample
Private Key (WIF)5J3mBbAH58CpQ3Y5RNJpUKPE62SQ5tfcvU2JpbnkeyhfsYB1Jcn
PassphraseMyTestPassphrase
Encrypted Key6PRTHL6mWa48xSopbU1cKrVjpKbBZxcLRRCdctLJ3z5yxE87MobKoXdTsJ

2. Bitcoin Public Keys

A public key K is a point on the elliptic curve calculated as:

[ K = kG ]

Where:

2.1. Public Key Formats

Two representation formats:

  1. Uncompressed: Prefix 0x04 + x-coordinate + y-coordinate
    Example: 04f028892bad...505bdb
  2. Compressed: Prefix 0x02 (even y) or 0x03 (odd y) + x-coordinate
    Example: 03f028892bad...dc341a

2.1.1. Python Implementation for Public Key Derivation

import ecdsa
from ecdsa.ellipticcurve import PointJacobi

def derive_public_key(private_key: bytes, compressed: bool = False) -> bytes:
    Q: PointJacobi = int.from_bytes(private_key, byteorder='big') * ecdsa.curves.SECP256k1.generator
    xstr: bytes = Q.x().to_bytes(32, byteorder='big')
    if compressed:
        parity: int = Q.y() & 1
        return (2 + parity).to_bytes(1, byteorder='big') + xstr
    else:
        ystr: bytes = Q.y().to_bytes(32, byteorder='big')
        return b'\04' + xstr + ystr

3. Bitcoin Addresses

3.1. P2PKH (Legacy Addresses)

Pay-to-Public-Key-Hash addresses start with "1". Generation steps:

  1. Public key → SHA-256 → RIPEMD-160
  2. Add version byte (0x00 for mainnet)
  3. Compute checksum (double SHA-256)
  4. Base58 encode

Example: 1J7mdg5rbQyUHENYdx39WVWK7fsLpEoXZy

3.1.1. Python Implementation for P2PKH Address Generation

def pubkey_to_p2pkh_addr(pubkey: bytes, version: bytes) -> bytes:
    out1 = sha256(pubkey)
    out2 = ripemd160(out1)
    checksum = base58_cksum(version + out2)
    return base58.b58encode(version + out2 + checksum)

3.2. P2SH (SegWit-Compatible Addresses)

Pay-to-Script-Hash addresses start with "3". P2SH-P2WPKH example: 3FyC6EYuxW22uj4CaEGjNCjxeg7gHyFeVv

3.3. Bech32 (Native SegWit Addresses)

Native SegWit addresses start with "bc1q". P2WPKH example: bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4

3.4. Bech32m (Taproot Addresses)

Bech32m addresses start with "bc1p" (Taproot). Key differences from Bech32:

4. Appendix

4.1. Bech32 and Bech32m Encoding

Bech32 character set (32 chars):

qpzry9x8gf2tvdw0s3jn54khce6mua7l

Key differences:

5. References

FAQ

Q: Can one private key have multiple addresses?

A: Yes, a single private key corresponds to both compressed and uncompressed addresses.

Q: What's the difference between Bech32 and Bech32m?

A: Bech32 is for witness version 0, while Bech32m is for versions 1-16 with improved checksums.

Q: Are P2SH addresses still secure?

A: Yes, P2SH remains secure but native SegWit (Bech32) offers better efficiency.

👉 Learn more about Bitcoin security
👉 Advanced key management techniques