In the world of blockchain and decentralized technologies, understanding how cryptographic keys and wallet addresses are generated is essential. This article dives into the core mechanics behind private keys, public keys, addresses, and mnemonics—the foundational elements of Web3 identity and security. Using clear explanations and practical Go code examples, we’ll walk through the step-by-step process of generating these components from scratch.
Whether you're a developer building a wallet or a curious learner exploring blockchain fundamentals, this guide will clarify the relationships between these concepts while adhering to industry standards like secp256k1 and Ethereum’s address derivation.
Core Concepts Behind Key Generation
Before writing any code, it’s crucial to understand the cryptographic principles that underpin blockchain wallets.
What Is an Elliptic Curve?
Both Bitcoin and Ethereum use the same elliptic curve: secp256k1. This curve enables secure digital signatures and key generation through asymmetric cryptography.
A public key is a point (x, y) on this curve. The x and y coordinates are each 32 bytes long, resulting in a 64-byte public key. You may also encounter a 65-byte version—this includes a one-byte prefix (0x04), indicating an uncompressed public key, which stores both coordinates fully.
👉 Discover how secure cryptographic systems power modern blockchain wallets.
However, due to the mathematical properties of the secp256k1 equation, knowing one coordinate allows you to derive the other. This leads to compressed public keys, where only the x-coordinate and a single byte (0x02 or 0x03) indicating the sign of y are stored—reducing the size to just 33 bytes.
This compression is widely used because it halves storage requirements without compromising security.
Understanding Private Keys
A private key in Ethereum is simply a randomly generated 256-bit integer. It must be:
- Cryptographically secure
- Unpredictable
- Never reused
You could theoretically generate one by flipping a coin 256 times, but in practice, developers rely on cryptographically secure random number generators (CSPRNGs). In Go, this means using crypto/rand, not basic pseudo-random functions.
b := make([]byte, 32)
_, err := rand.Read(b)
if err != nil {
log.Fatal("Failed to read random bytes")
}The private key is the root of all control over a blockchain account. Unlike traditional banking systems, there's no "forgot password" option. Lose your private key, and you lose access forever—this is the trade-off for decentralization and self-sovereignty.
The Role of Mnemonics
Managing multiple private keys manually is impractical. That's where mnemonic phrases come in—a standardized way (defined by BIP-39) to represent a seed that can generate many keys.
A typical mnemonic consists of 12 or 24 words (e.g., "apple banana cat...") derived from entropy. This phrase can regenerate the same set of private keys every time, making backup and recovery feasible.
While we’ll explore mnemonics in depth later, it’s important to know they simplify wallet management by replacing complex hexadecimal strings with human-readable words.
Generating Keys and Addresses in Go
Now let’s implement the entire flow in code—from private key to wallet address—using Go and Ethereum libraries.
Required Imports
import (
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"log"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
)Step 1: Generate a Private Key
We start by generating 32 cryptographically secure random bytes:
privateKey, err := crypto.GenerateKey()
if err != nil {
log.Fatal("Failed to generate private key:", err)
}
// Convert to hex string for display
privateKeyBytes := crypto.FromECDSA(privateKey)
fmt.Println("Private Key (hex):", hex.EncodeToString(privateKeyBytes))This private key is your secret credential—guard it at all costs.
Step 2: Derive the Public Key
Using elliptic curve multiplication (scalar base multiplication), we compute the public key from the private key:
publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
log.Fatal("Error casting public key to ECDSA")
}
pubKeyBytes := crypto.FromECDSAPub(publicKeyECDSA)
fmt.Println("Public Key (uncompressed):", hex.EncodeToString(pubKeyBytes))By default, this outputs a 65-byte uncompressed public key starting with 0x04.
👉 Learn how developers build secure blockchain applications using cryptographic primitives.
Step 3: Create the Wallet Address
An Ethereum address is derived as follows:
- Hash the full public key using Keccak-256
- Take the last 20 bytes of the hash
- Format as a 40-character hex string (prefixed with
0x)
hash := sha256.Sum256(pubKeyBytes)
keccakHash := crypto.Keccak256(pubKeyBytes[1:]) // Skip 0x04 prefix
address := common.BytesToAddress(keccakHash[12:])
fmt.Println("Wallet Address:", address.Hex())Note: We use crypto.Keccak256 instead of standard SHA3 because Ethereum uses a variant of Keccak defined before finalization.
Frequently Asked Questions
Q1: Can two different private keys produce the same address?
While theoretically possible due to hash collisions, the probability is astronomically low—about 1 in 2^160. For practical purposes, each address is unique.
Q2: Why do some public keys start with 0x04, others with 0x02 or 0x03?
The prefix indicates encoding:
0x04: Uncompressed (stores full x and y)0x02: Compressed, positive y0x03: Compressed, negative y
Compression reduces data size without losing information.
Q3: Is it safe to generate keys using online tools?
No. Any tool running in an untrusted environment (like a website) risks exposing your private key. Always use offline or open-source audited tools for real assets.
Q4: How does a mnemonic relate to a private key?
A mnemonic generates a seed via PBKDF2, which then derives a master private key using HMAC-SHA512. From there, hierarchical deterministic (HD) wallets generate multiple child keys—enabling multi-account support from one phrase.
Q5: Can I recover my wallet if I only have the private key?
Yes. The private key alone is sufficient to derive the public key and address. However, you won’t get back the original mnemonic unless it was used initially.
Final Thoughts
Understanding how private keys, public keys, and addresses are generated gives you deeper insight into blockchain security and wallet design. By mastering these fundamentals:
- You appreciate why randomness and secrecy matter
- You avoid dangerous practices like weak RNGs
- You're better equipped to build or audit wallet software
Remember: your private key is your identity on the blockchain. With great power comes great responsibility.
👉 Explore secure ways to manage digital identities in Web3 ecosystems.
Keywords Used
- private key
- public key
- wallet address
- mnemonic phrase
- secp256k1
- Keccak256
- Go programming
- cryptography
These keywords have been naturally integrated throughout the text to enhance SEO relevance while maintaining readability and technical accuracy.
This foundational knowledge sets the stage for more advanced topics like HD wallets, BIP-44 paths, and multi-signature schemes—subjects we’ll explore in upcoming articles.