In the world of blockchain and decentralized applications, understanding how wallets work at a foundational level is essential. At the heart of every wallet lies a cryptographic system that generates private keys, public keys, and addresses—all derived from a simple yet powerful concept known as mnemonics. This article breaks down the core principles behind these components using clear explanations and practical code examples in Go, helping you grasp the underlying mechanics of Web3 identity management.
Whether you're a developer diving into blockchain programming or a curious learner exploring crypto fundamentals, this guide will walk you through the step-by-step process of generating secure digital identities—while highlighting best practices and common pitfalls.
Core Concepts: Private Keys, Public Keys, and Addresses
Before writing any code, it's crucial to understand the foundational building blocks of blockchain wallets.
What Is an Elliptic Curve?
Both Bitcoin and Ethereum use the same elliptic curve for cryptography: secp256k1. This curve enables secure key generation through mathematical operations. A public key is a point (x, y) on this curve, where both coordinates are 32 bytes long—resulting in a 64-byte public key.
You may encounter public keys represented as 65 bytes. That extra byte is a prefix defined by the SECG (Standards for Efficient Cryptography Group) standard:
04: Uncompressed format (stores full x and y values)02or03: Compressed format (stores only x and a parity bit for y)
Why compress? Because given one coordinate (x), the other (y) can be derived from the curve equation. Compression reduces storage size by half—from 65 bytes to just 33—making it more efficient for blockchain transactions.
👉 Discover how secure wallet systems protect your digital assets
Understanding Private Keys
A private key in Ethereum is simply a randomly generated 256-bit number—essentially a 32-byte sequence. The randomness must be cryptographically secure. You could theoretically flip a coin 256 times to generate one, but in practice, developers rely on secure random number generators.
Here’s what matters:
- The number must be unpredictable.
- It must never be reused.
- It should come from a cryptographically secure source, not a basic programming language random function.
Once generated, this private key unlocks control over a blockchain address. Unlike traditional banking systems, there's no "forgot password" option. Lose your private key, and you lose access forever—this is the trade-off of decentralization.
While centralized systems offer recovery options, they compromise privacy. In contrast, decentralized networks prioritize ownership and control—but demand greater personal responsibility.
The Role of Mnemonics
Managing multiple private keys manually is impractical. Imagine needing to securely store thousands of random 256-bit numbers! That’s where mnemonic phrases come in.
A mnemonic (often 12 or 24 words) serves as a human-readable representation of a seed that can generate many private keys deterministically. This system follows standards like BIP-39 and BIP-44, enabling hierarchical deterministic (HD) wallets.
With a single mnemonic, users can derive countless accounts across different blockchains—making backup and recovery seamless. We’ll explore HD wallets in detail in future articles, but for now, think of mnemonics as the master key to your entire digital identity ecosystem.
Generating Keys and Addresses in Go
Let’s now implement the core workflow: generating a private key, deriving its public key, and computing the Ethereum address—all using Go.
Required Dependencies
Start by importing essential packages:
import (
"crypto/rand"
"encoding/hex"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
)Step 1: Generate a Cryptographically Secure Private Key
curve := secp256k1.S256()
b := make([]byte, 32) // 256 bits = 32 bytes
_, err := rand.Read(b)
if err != nil {
panic("Failed to read random bytes")
}
privateKey := new(big.Int).SetBytes(b)
fmt.Printf("Private Key: %x\n", privateKey.Bytes())This creates a truly random private key using Go’s secure crypto/rand package—not math/rand.
Step 2: Derive the Public Key
Use elliptic curve scalar multiplication to compute the public key from the private key:
x, y := curve.ScalarBaseMult(b)
pubKey := crypto.CompressPubkey(&ecdsa.PublicKey{Curve: curve, X: x, Y: y})
fmt.Printf("Public Key: %x\n", pubKey)Note: We use compressed format (crypto.CompressPubkey) to keep the output compact (33 bytes).
Step 3: Generate the Ethereum Address
An Ethereum address is the last 20 bytes of the Keccak-256 hash of the public key:
hashed := crypto.Keccak256(pubKey)
address := common.BytesToAddress(hashed[12:]) // Last 20 bytes
fmt.Printf("Address: %s\n", address.Hex())This resulting address is what you share for receiving funds.
Step 4: Verify Key-Address Pairing
To confirm correctness:
- Import the private key into MetaMask.
- Check if the displayed address matches your computed result.
If they match, your implementation works!
👉 Learn how modern wallets streamline key management securely
Frequently Asked Questions
What makes a private key secure?
A private key is secure only if it's generated using a cryptographically strong random number generator. Predictable or weak randomness (like timestamps or simple RNGs) can make keys vulnerable to brute-force attacks.
Can two people have the same private key?
Theoretically possible—but practically impossible. With 2^256 possible combinations, the odds are astronomically low—less likely than winning the lottery every day for a year.
Why do we compress public keys?
Compression halves the data size (from 65 to 33 bytes), reducing blockchain storage and transaction costs without sacrificing security. Since y can be derived from x via the curve equation, storing both is redundant.
Is it safe to generate keys with code?
Yes—as long as you use trusted libraries (like go-ethereum) and secure entropy sources (crypto/rand). Avoid homemade cryptography; stick to battle-tested tools.
How does a mnemonic relate to private keys?
A mnemonic phrase encodes entropy used to generate a seed. This seed then deterministically produces one or more private keys via HMAC-SHA512 and derivation paths—enabling HD wallets.
Can I recover my wallet without a private key?
Only if you have the mnemonic or keystore file with password. Without any of these, recovery is impossible due to decentralization.
Final Thoughts
Understanding how private keys, public keys, addresses, and mnemonics interconnect forms the foundation of Web3 literacy. By walking through actual code, we demystify what often feels abstract or intimidating.
Remember:
- Your private key = ultimate control
- Losing it = permanent loss
- Backups via mnemonics = critical
As blockchain adoption grows, so does the need for robust digital hygiene. Whether you're building apps or managing assets, knowing these basics empowers you to act confidently and securely.
👉 Explore advanced tools that simplify Web3 development and asset management