BIP39 Seed Phrases ما يمثله 12 كلمة فعلاً وطريقة توليد محفظة HD
مُصطلح BIP39 هو ترميز القدرة على التمثيل بعبارات — هي البنية الكRYPTOغرافية وراء استعادة المحفظة. يُحلل هذا الدليل المعادلات الخاصة بالقائمة المكونة من الكلمات، خطوة بذرة PBKDF2، مسارات توليد BIP44، لماذا تختلف المحفظات في عناوينها، ونماذج فشل الأمان التي يجب أن يعرفها المطورون.
A BIP39 mnemonic is 128 or 256 bits of random data, encoded as human-readable words using a fixed 2048-word list. That’s the whole trick. The “magic” is just that words are easier to write on paper than hex strings — cryptographically, there’s nothing special about the words themselves.
Where it gets interesting is the four-layer stack built on top of that encoding: BIP39 (the word list and encoding), BIP32 (hierarchical deterministic key derivation), BIP43 (purpose field conventions), and BIP44 (coin/account/address structure). Most explanations conflate all four. This one separates them.
The word list: 11 bits per word, checksum included
ال BIP39 English word list has exactly 2048 words. 211 = 2048, so each word encodes 11 bits of information. A 12-word phrase carries 132 bits total; a 24-word phrase carries 264 bits.
Not all of those bits are entropy. The last few bits of the last word are a checksum — the first ENT/32 bits of SHA256(entropy_bytes), where ENT is the entropy length in bits:
| Phrase length | Entropy bits (ENT) | Checksum bits (CS = ENT/32) | Total bits |
|---|---|---|---|
| 12 words | 128 | 4 | 132 |
| 15 words | 160 | 5 | 165 |
| 18 words | 192 | 6 | 198 |
| 21 words | 224 | 7 | 231 |
| 24 words | 256 | 8 | 264 |
The checksum is why “almost valid” mnemonics fail. Flip a single bit of entropy and the checksum byte changes, making the phrase invalid. This catches transcription errors — specifically the ones that land in the checksum bits. Wallets that validate before deriving keys will reject the phrase entirely. Some don’t validate; they just quietly derive a wallet from garbage entropy.
The entropy-to-words mapping in Python:
import hashlib, os
# Generate 128 bits of entropy
entropy = os.urandom(16) # 16 bytes = 128 bits
# Compute checksum: first 4 bits of SHA256(entropy)
h = hashlib.sha256(entropy).digest()
checksum_bits = format(h[0], '08b')[:4] # first 4 bits of SHA256 output
# Combine entropy bits + checksum bits
all_bits = format(int.from_bytes(entropy, 'big'), '0128b') + checksum_bits
# all_bits is now 132 bits
# Split into 11-bit groups -> 12 word indices (0-2047)
word_indices = [int(all_bits[i:i+11], 2) for i in range(0, 132, 11)]
# Look up each index in the BIP39 word list to get the mnemonic
The mnemonic is not the key: the PBKDF2 step
This is where most explanations go wrong. The 12 words are not your private key and are not used directly for signing. They’re an intermediate encoding. Before any key material is derived, the mnemonic is stretched through PBKDF2-HMAC-SHA512:
import hashlib
mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
passphrase = "" # optional; empty string = no passphrase
seed = hashlib.pbkdf2_hmac(
'sha512',
mnemonic.encode('utf-8'), # password: the mnemonic words
('mnemonic' + passphrase).encode('utf-8'), # salt: always "mnemonic" + passphrase
2048, # iterations
dklen=64 # 512 bits output
)
# seed is 64 bytes (512 bits) -- this is what actually seeds key derivation
Two things to note:
- The salt is always the literal string
"mnemonic"concatenated with the passphrase. An empty passphrase means the salt is just"mnemonic"— there’s no separate “no passphrase” mode. - The passphrase completely changes the resulting seed. The same 12 words with passphrase
"A"— أي منهما تحتاجه؟"a"produce entirely different wallets with entirely different addresses. This is the “25th word” feature: a passphrase lets you maintain plausible deniability (two wallets from one phrase), but losing the passphrase is permanent, even with the 12 words in hand.
From seed to master key: BIP32
The 512-bit seed feeds into HMAC-SHA512 with the fixed key string "Bitcoin seed". The 64-byte output splits into two 256-bit halves:
import hmac, hashlib
master = hmac.new(b'Bitcoin seed', seed, hashlib.sha512).digest()
master_private_key = master[:32] # left 256 bits: the actual EC private key
master_chain_code = master[32:] # right 256 bits: used for all child derivation
The chain code is the key to why HD wallets work: it prevents derived keys from being brute-forced even if the parent key is known. Without it, knowing a parent public key plus any child private key would leak every sibling private key. With the chain code, child key derivation requires both the parent key and the chain code as inputs — and for hardened derivation, the parent private key directly.
Together, master_private_key + master_chain_code form the master extended private key, encoded as an xprv... Base58Check string. The corresponding extended public key is xpub... — useful for watch-only wallets that need to derive addresses without exposing private key material.
BIP44 derivation paths: m/44’/60’/0’/0/0 decoded
BIP44 defines a five-level derivation hierarchy. Here’s m/44’/60’/0’/0/0 — the standard Ethereum first-address path — broken down component by component:
| مستوى | قيمة | Hex index | معنى |
|---|---|---|---|
m | — | — | Master key root |
44' | purpose | 0x8000002C | BIP44 purpose. Hardened (apostrophe = 0x80000000 + index). |
60' | coin type | 0x8000003C | Ethereum, per SLIP-0044. Bitcoin = 0′, Solana = 501′, etc. |
0' | account | 0x80000000 | First account. Increment for separate isolated accounts. |
0 | change | 0 | External chain (0 = receiving addresses, 1 = change addresses). Wallets rarely use the change chain for EVM chains. |
0 | index | 0 | Address index. Increment for the 2nd address, 3rd, etc. |
The apostrophes denote hardened derivation. Hardened child keys can only be derived from the parent private key, not the parent public key. This matters because with normal (non-hardened) derivation, a compromised child private key plus the parent public key would expose the parent private key and all sibling keys. For purpose, coin type, and account levels, hardened derivation is the spec.
Why the same phrase gives different addresses in different wallets
The phrase and the wallet’s default path are independent variables. Wallets have historically disagreed on the path, and some disagreements are still unresolved.
For Ethereum, the main split:
- MetaMask, Ledger Live, most modern wallets:
m/44'/60'/0'/0/N— standard BIP44. - MyEtherWallet (legacy default):
m/44'/60'/0'/N— one level shorter. A wallet restored from the same phrase in MEW with the legacy path produces a completely different set of addresses than MetaMask. - Trezor Suite: Follows standard BIP44 for ETH now, but historically had its own quirks with some altcoins.
For Bitcoin, the divergence is structural: BIP44 (m/44'/0'/0', legacy P2PKH, addresses start with 1), BIP49 (m/49'/0'/0', P2SH-P2WPKH, addresses start with 3), and BIP84 (m/84'/0'/0', native segwit P2WPKH, addresses start with bc1q) all produce different addresses from the same seed. The address format tells you which path was used, which is why address format matters when troubleshooting a recovery.
If you import a phrase and “the funds aren’t there,” check the derivation path before assuming the phrase is wrong. Most wallets let you specify the path manually during advanced import.
Security failure modes
The cryptography here is not the weak point. Every attack that works against BIP39 wallets targets the human side of the pipeline.
Phishing: “enter your recovery phrase to continue”
The highest-volume attack by a significant margin. Fake wallet UIs, browser extensions injected by malicious scripts, customer support impersonators in Discord — all asking users to type their 12 words somewhere. The correct mental model: legitimate wallet software never asks for your seed phrase after initial setup. A request for the phrase is the attack, regardless of how legitimate the UI looks.
Clipboard monitoring
Malware that polls the clipboard, detects a sequence of 12 or 24 known BIP39 words, and exfiltrates. The exfiltration window is milliseconds. Copy-pasting a seed phrase anywhere — even briefly into a text editor — creates exposure. Clipboard history managers (Windows Clipboard History, macOS clipboard managers, IDE paste history) are especially high-risk.
Screenshots and cloud photo sync
Taking a screenshot of a seed phrase on a phone uploads it to iCloud Photos or Google Photos in seconds, before most people finish reading it back. Those backups aren’t encrypted client-side. “I took a screenshot to keep it safe” is a direct exfiltration path. A paper backup in a physically secure location is not a joke recommendation.
Server-side mnemonic generation
Any website that generates a BIP39 phrase server-side has a copy of the entropy. The only safe place to generate is a device you control, offline at generation time. A hardware wallet, an air-gapped machine, or an audited client-side tool. A website is none of those things — even if the JavaScript looks correct, you can’t verify that the server isn’t logging the output.
If you need to inspect or verify a phrase’s structure — check entropy, see the derived seed, verify a path — the محول BIP39 Mnemonic runs entirely in-browser. The phrase never leaves your machine, which is the only architecture that’s safe for this use case.
The developer angle: you almost certainly shouldn’t handle seed phrases in your app
If you’re building a crypto-adjacent application, the instinct to “handle the seed phrase” in your backend is almost always the wrong call. The attack surface:
- Logging. Every web framework logs request bodies somewhere. One debug line, one misconfigured log level, and every phrase that transited your API is on disk — indefinitely, across multiple log destinations you didn’t audit.
- Transit. HTTPS protects the wire. It does not protect the load balancer, the backend process memory, the database, or the log aggregator. Each is a separate breach surface.
- Memory. Process dumps, crash reports, core files, and heap snapshots capture in-memory strings. A seed phrase in a Python dict or JavaScript object is not zero-copy; it likely appears in multiple allocations before it’s “deleted.”
- Liability. If your backend processes user seed phrases and you get breached, the damage is permanent. Unlike passwords, there’s no reset mechanism. Affected users lose funds with no recourse.
The architecture that actually works: derive what you need on the client side and only transmit the output — a public key, a read-only xpub, a signed transaction. The backend never sees the phrase. Libraries that do this correctly: @scure/bip39 (audited, dependency-minimal), ethers.jsو، و bitcoinjs-lib. For hardware wallet integrations, the Trezor and Ledger SDKs return a signed transaction — the key never leaves the device.
The full derivation chain at a glance
| خطوة | مدخل | عملية | انتاج | |
|---|---|---|---|
| 1. Entropy | 128–256 random bits | SHA256 checksum → 11-bit groups | 12–24 word mnemonic |
| 2. Seed | Mnemonic words + “mnemonic” + passphrase | PBKDF2-HMAC-SHA512, 2048 rounds | 512-bit seed (64 bytes) |
| 3. Master key | Seed bytes | HMAC-SHA512(“Bitcoin seed”, seed) | Master private key (256 bits) + chain code (256 bits) |
| 4. Account key | Master key + path m/44’/60’/0’ | BIP32 hardened child derivation × 3 | Account extended private key |
| 5. Address key | Account key + path /0/N | BIP32 normal child derivation × 2 | Child private key → secp256k1 public key → keccak256 → address |
BIP39 did exactly what it was designed to do: make entropy writable and recoverable. The attack surface isn’t in the cryptography — PBKDF2 with 2048 rounds, HMAC-SHA512, secp256k1 — all of it is sound. The attacks are entirely operational: entering the phrase somewhere you shouldn’t, storing it digitally, trusting a tool that generates it server-side. The math is fine. The humans are the weak link, which is why the developer advice is “architect your system so the phrase never touches your infrastructure.”
تثبيت ملحقاتنا
أضف أدوات IO إلى متصفحك المفضل للوصول الفوري والبحث بشكل أسرع
恵 وصلت لوحة النتائج!
لوحة النتائج هي طريقة ممتعة لتتبع ألعابك، يتم تخزين جميع البيانات في متصفحك. المزيد من الميزات قريبا!
