ETH Logo

EthVanity

Custom Address Generator

Buy us a coffee

Our free tools run entirely on donations. Your support pays for the servers and GPU power that make every generation possible. If we helped you today, a small donation helps keep this service free for everyone.

ETH · Ethereum network
0xcf5777b71c31146bd396cece6d3128e42d0ad9f7

Thank you for keeping us running! ❤️

Fundamentals

How Ethereum Addresses Are Derived from a Private Key

From secp256k1 private key to Keccak-256 hash, last 20 bytes and EIP-55 checksum, with an ethers v6 example and why it is one-way.

By Updated 7 min readRead as Markdown

From secret to address. Private key: A secret scalar on secp256k1; Public key: Derived by elliptic-curve multiplication; Address: Last 20 bytes of the public-key Keccak-256 hash.
From secret to address. Private key: A secret scalar on secp256k1; Public key: Derived by elliptic-curve multiplication; Address: Last 20 bytes of the public-key Keccak-256 hash.Open full-size diagram (SVG)Download diagram (PNG)About these visual guides
Short answer: An Ethereum address comes from a 32-byte secp256k1 private key: multiply it by the curve's generator point to get a 64-byte public key, hash that with Keccak-256, and keep the last 20 bytes, written as 0x plus 40 hex characters. Each step is one-way, so the address reveals nothing usable about the key.

Step 1: the private key

A private key is a 256-bit number, stored as 32 bytes or 64 hex characters. It must lie between 1 and n - 1, where n is the order of the secp256k1 curve: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141, about 1.158 x 10^77. Almost every random 256-bit value is valid, since the excluded range is a tiny fraction of the total.

Security rests entirely on how the key is chosen. It must come from a cryptographically secure random number generator with the full 256 bits of entropy. Wallets usually derive keys from a BIP-39 recovery phrase through BIP-32 hierarchical derivation, with m/44'/60'/0'/0/0 as the common path for the first Ethereum account, but the end result is the same kind of 32-byte key. Vanity generators skip the phrase and search raw keys directly, which is why weak seeding, as in the Profanity vulnerability, is so damaging.

The size of the space is what makes random keys safe. With about 1.158 x 10^77 valid keys and roughly 2^160, or 1.46 x 10^48, possible addresses, two independently generated keys colliding is not a practical concern. The risk lies entirely in non-random generation, such as keys derived from short passwords, timestamps or 32-bit seeds, which attackers scan systematically.

Step 2: the secp256k1 public key

The public key is the elliptic-curve point K = k x G, where k is the private key and G is secp256k1's fixed generator point. The point has two 32-byte coordinates, X and Y. In uncompressed SEC1 form it is written as 65 bytes: a 0x04 marker followed by X and Y. Ethereum drops the marker and uses the 64 bytes X || Y.

Computing K from k takes milliseconds. Going back from K to k is the elliptic-curve discrete logarithm problem, for which the best known classical attacks on a 256-bit curve need on the order of 2^128 operations. That asymmetry is the foundation of the whole account system.

A compressed form of the public key also exists: 33 bytes made of a 0x02 or 0x03 prefix, which records whether Y is even or odd, followed by X. Ethereum addresses are always computed from the uncompressed 64-byte X || Y, so hashing a compressed key, or hashing the 65-byte form with the 0x04 marker still attached, produces a wrong address.

Step 3 and 4: Keccak-256 and the last 20 bytes

Ethereum hashes the 64-byte public key with Keccak-256, producing 32 bytes, and keeps the rightmost 20 bytes (160 bits) as the address. Ethereum uses the original Keccak submission, whose padding differs from the final NIST SHA3-256 standard, so a generic SHA3-256 function gives the wrong result.

Using private key 1 as a worked example, the public key is G itself, its Keccak-256 hash is 0xc0a6c424ac7157ae408398df7e5f4552091a69125d5dfcb7b8c2659029395bdf, and the last 20 bytes give the address 0x7e5f4552091a69125d5dfcb7b8c2659029395bdf. The first 12 bytes, c0a6c424ac7157ae408398df, are simply discarded.

StageSizeExample for private key 1
Private key32 bytes0x00...0001
Public key (uncompressed, no 0x04)64 bytes79be667e...(X) followed by Y
Keccak-256 of public key32 bytesc0a6c424...395bdf
Address (last 20 bytes)20 bytes0x7e5f4552...29395bdf
EIP-55 display42 characters0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf

Step 5: hex encoding and the EIP-55 checksum

The 20 bytes are written as 40 hexadecimal characters with a 0x prefix. Most software then applies EIP-55: it hashes the lowercase hex text with Keccak-256 and uppercases each letter whose matching hash nibble is 8 or higher. For private key 1 that gives 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf. The algorithm and a worked example are in hex characters and EIP-55.

The checksum changes only how the address is displayed. The underlying value, and the account it identifies, is the same in lowercase, uppercase or checksummed form.

Code example with ethers v6

The snippet reproduces every step with ethers v6 and checks the result against the library's Wallet class. It uses private key 1, a famous test value whose address is publicly known and constantly watched by bots. Never send funds to this address or use any published key, including Hardhat's documented default account 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, for anything real.

// npm install ethers@6
import { SigningKey, keccak256, dataSlice, getAddress, Wallet } from "ethers";

// TEST KEY ONLY - publicly known, never use for real funds
const privateKey = "0x0000000000000000000000000000000000000000000000000000000000000001";

const publicKey = SigningKey.computePublicKey(privateKey, false); // 0x04 + X + Y (65 bytes)
const hash = keccak256("0x" + publicKey.slice(4));            // drop 0x04, hash 64 bytes
const address = getAddress(dataSlice(hash, 12));               // last 20 bytes + EIP-55

console.log(address);                       // 0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf
console.log(new Wallet(privateKey).address); // same result

Where wallet keys come from: BIP-39, BIP-32 and BIP-44

Wallets such as MetaMask do not store a single random key. BIP-39 encodes 128 bits of entropy plus a 4-bit checksum as 12 words, or 256 bits plus an 8-bit checksum as 24 words, from a 2,048-word list. The phrase is stretched with PBKDF2-HMAC-SHA512 over 2,048 iterations into a 512-bit seed, and BIP-32 turns that seed into a tree of keys. BIP-44 fixes the path m/44'/60'/0'/0/i, where 60 is Ethereum's SLIP-44 coin type and i is the account index.

Each leaf of that tree is an ordinary 32-byte secp256k1 private key, so the address derivation from step 2 onward is identical. Vanity generators usually skip the phrase layer because searching phrases would add thousands of hash iterations to every attempt. The result is a standalone key that a recovery phrase cannot restore, which is why importing one into a wallet needs separate backup, as explained in importing a vanity key into MetaMask.

LayerStandardOutput
MnemonicBIP-3912 or 24 words (128 or 256 bits of entropy)
SeedBIP-39 PBKDF2, 2,048 rounds512-bit seed
Key treeBIP-32Master key and child keys
PathBIP-44 with coin type 60m/44'/60'/0'/0/0 for the first account

Why the derivation cannot be reversed

Each step is one-way. Reversing the hash would require a Keccak-256 preimage, and even with the public key in hand, recovering the private key requires solving the discrete logarithm. The truncation to 160 bits also means about 2^96 different public keys map to each address on average, so the address does not even determine a unique public key.

This is also why vanity addresses are a search problem rather than a calculation: there is no way to compute a key for a chosen address, only to try keys until one fits. Each try has a 1 in 16^n chance of matching an n-character pattern, as the difficulty guide shows. Contract addresses follow different formulas, covered in EOA vs CREATE2 vanity.

Quantum computers are the one known long-term threat to this model. Shor's algorithm would in principle solve the elliptic-curve discrete logarithm, which is why accounts whose public keys are exposed on-chain are the ones discussed in Ethereum's post-quantum research. Hashing to an address protects only keys whose public key has never been revealed. An address that has never signed anything exposes just 20 bytes of a hash, not the curve point an attacker would need.

Explore the related mechanism

Frequently asked questions

Can two private keys produce the same Ethereum address?

Mathematically yes, because 2^256 keys map to 2^160 addresses. Finding such a collision deliberately would take around 2^80 work by the birthday bound, and hitting a specific existing address would take around 2^160, so it does not happen in practice.

Why does Ethereum use Keccak-256 instead of SHA3-256?

Ethereum adopted Keccak before NIST finalized SHA-3 with different padding. The two functions produce different outputs for the same input, so libraries expose keccak256 separately.

Does the chain ID affect the address?

No. The derivation uses only the key, so the same address exists on every EVM chain, as explained in same address on every EVM chain.

Can I derive a vanity address from a recovery phrase?

In principle you could search phrases, but each attempt costs 2,048 PBKDF2 rounds plus BIP-32 derivation, so it is far slower than searching raw keys. Vanity keys are therefore usually standalone private keys that need their own backup.

Why is the public key visible after I send a transaction?

Ethereum signatures let anyone recover the signer's public key from the signature and the signed message. Nodes use this to check that the recovered key hashes to the sender's address.

Sources and editorial method

The technical references below support the concepts discussed in this article. Examples and comparison worksheets are explanatory, not measured service benchmarks.

Read how these articles are prepared.