BIP39 セードフレーズ その12の言葉が実際に何であるかおよびHDウォレットの派生方式
BIP39の暗号語は単語でエンタロピーをエンコードしており、ウォレット回復の暗号構造を表しています。このガイドでは、単語リストの数学的計算、PBKDF2シードステップ、BIP44の派生パス、ウォレットがアドレスについて意見を分ける理由、および開発者が理解すべきセキュリティの失敗モードについて詳しく解説します。
BIP39の記憶語は、128ビットまたは256ビットのランダムデータであり、固定された2048語のリストを使って人間が読みやすい語としてエンコードされている。これがすべてのポイントである。「魔法」は単に語がhex文字列よりも紙に書くのが簡単であるという点にすぎない。暗号的に、語そのものには特別な意味はない。
興味深いのは、そのエンコードの上に構築された四層のスタックである。BIP39(語リストとエンコード)、BIP32(階層的決定鍵生成)、BIP43(目的フィールドの規約)、およびBIP44(通貨/アカウント/アドレス構造)である。多くの説明ではこれらを混同している。この説明ではそれらを分離している。
語リスト:1語あたり11ビット、チェックサムを含む
の BIP39 英語語リスト ちょうど2048語。211 = 2048であり、各語が11ビットの情報をエンコードしている。12語のフレーズは合計132ビット、24語のフレーズは合計264ビットを含む。
そのすべてのビットがエントロピーではない。最後の語の最後のいくつかのビットがチェックサムである — それはエントロピーのバイトの最初のENT/32ビットのSHA256(エントロピー_バイト)である。ENTはエントロピーのビット長である。
| フレーズ長 | エントロピービット(ENT) | チェックサムビット(CS = ENT/32) | 総ビット数 |
|---|---|---|---|
| 12語 | 128 | 4 | 132 |
| 15語 | 160 | 5 | 165 |
| 18語 | 192 | 6 | 198 |
| 21語 | 224 | 7 | 231 |
| 24語 | 256 | 8 | 264 |
チェックサムが「ほぼ有効」な記憶語が失敗する理由である。エントロピーの1ビットを反転させるとチェックサムバイトが変化し、フレーズが無効になる。これは入力ミスを検出するもので、特にチェックサムビットに落ちたミスを指す。鍵を導出する前に検証を行うウォレットは、フレーズ全体を拒否する。一部は検証を行わず、エントロピーのゴミから静かにウォレットを導出する。
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
記憶語は鍵ではない:PBKDF2ステップ
ここでは多くの説明が間違っている。12語はあなたのプライベートキーではなく、直接署名に使われない。鍵材料が導出される前に、記憶語は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
2つの注意点:
- サルトは常に文字列
"mnemonic"パスフレーズに接続される。パスフレーズが空であれば、サルトはただ"mnemonic"— それがある「パスフレーズなし」モードではない。 - パスフレーズは結果のシードを完全に変える。同じ12語のフレーズにパスフレーズ
"A"vs"a"を加えると、まったく異なるウォレットとまったく異なるアドレスが生成される。これは「25語」機能である:パスフレーズにより、一フレーズから複数のウォレットを維持できる(可能性の否定)が、パスフレーズを失うと、12語を持っていても永久に失われる。
シードからマスター鍵へ:BIP32
512ビットのシードは、固定キー文字列 "Bitcoin seed"にHMAC-SHA512で入力される。64バイトの出力は2つの256ビットの半分に分割される。
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
チェーンコードがHDウォレットが機能する理由である:親鍵が知られている場合でも、導出された鍵が暴力的に攻撃されない。そうでなければ、親公開鍵と子プライベート鍵が知られると、すべての兄弟プライベート鍵が漏れる。チェーンコードがあることで、子鍵の導出には親鍵とチェーンコードの両方の入力が必要であり、硬化導出では親プライベート鍵が直接使用される。
これらが master_private_key + master_chain_code マスター拡張プライベート鍵を形成し、Base58Check文字列としてエンコードされる。対応する拡張公開鍵は xprv... — プライベート鍵材料を暴露せずにアドレスを導出するためのウォレット(ウォッチオンリー)に有用である。 xpub... BIP44導出パス:m/44’/60’/0’/0/0を解読
BIP44は五段階の導出階層を定義している。ここに
— エシリアの標準的な最初のアドレスパス — 各成分を分解している。 m/44’/60’/0’/0/0 16進インデックス
| レベル | 価値 | マスター鍵ルート | 意味 |
|---|---|---|---|
m | — | — | 目的 |
44' | 0x8000002C | BIP44の目的。硬化(アポストロフィー = 0x80000000 + インデックス)。 | コインタイプ |
60' | 0x8000003C | エシリア、SLIP-0044に従う | ビットコイン = 0′、ソラナ = 501′、など。 アカウント0x80000000 |
0' | 最初のアカウント。別の孤立アカウントのためにインクリメントする。 | 変更 | 外部チェーン(0 = 受け入れアドレス、1 = 変更アドレス)。ウォレットはEVMチェーンで変更チェーンを使用することがほとんどない。 |
0 | インデックス | 0 | アドレスインデックス。2番目のアドレス、3番目のアドレスなどにインクリメントする。 |
0 | アポストロフィーは | 0 | 硬化導出を表す。 |
硬化された子鍵は、親プライベート鍵からのみ導出され、親公開鍵からは導出されない。これは、通常(非硬化)導出において、子プライベート鍵が侵害され、親公開鍵が公開されると、親プライベート鍵およびすべての兄弟鍵が暴露されるため、目的、コインタイプ、アカウントレベルでは硬化導出が規格である。 同じフレーズが異なるウォレットで異なるアドレスを生成する理由フレーズとウォレットのデフォルトパスは独立した変数である。ウォレットは歴史的にパスを異なえており、いくつかの違いはまだ解決されていない。
エシリアの場合、主な分岐は:
MetaMask、Ledger Live、ほとんどの現代のウォレット:
— 標準BIP44。
- MyEtherWallet(legacy default):
m/44'/60'/0'/0/N— 1レベル短い。同じフレーズをMEWでlegacyパスで復元した場合、MetaMaskとまったく異なるアドレスセットが生成される。 - Trezor Suite:
m/44'/60'/0'/N現在は標準BIP44に従い、かつてはいくつかのアルトコインに対して独自の特徴を持っていた。 - ビットコインの場合、分岐は構造的である:BIP44( 、legacy P2PKH、アドレスは1で始まる)、BIP49(
、P2SH-P2WPKH、アドレスは3で始まる)、およびBIP84(m/44'/0'/0'、ネイティブセグウィットP2WPKH、アドレスはbc1qで始まる)が同じシードから異なるアドレスを生成する。アドレス形式がどのパスを使用したかを示しており、回復時にアドレス形式が重要である。m/49'/0'/0'フレーズをインポートして「資金が見つからない」という場合、導出パスを確認する前にフレーズが間違っていると仮定しない。ほとんどのウォレットは、高度インポート時にパスを手動で指定できる。m/84'/0'/0'セキュリティの失敗モード
ここでの暗号学的弱点ではない。BIP39ウォレットに働くすべての攻撃は、人間側のパイプラインに向けられている。
フィッシング:「復元フレーズを入力して進む」
非常に高い頻度で発生する攻撃。偽のウォレットUI、ブラウザ拡張機能に悪意のあるスクリプトが注入されたもの、Discordでのカスタマーサポートの偽装者など、すべてがユーザーに12語または24語のフレーズを入力させる。正しいメンタルモデル:合法的なウォレットソフトウェアは、初期設定後に復元フレーズを尋ねない。フレーズの要求は攻撃であり、UIがどれだけ合法に見えるかに関係なく。
クリップボードモニタリング
クリップボードをポリスするマルウェアが、12語または24語のBIP39語のシーケンスを検出し、外部に送信する。外部化の時間はミリ秒である。フレーズをテキストエディタなどにコピー&ペーストする場合、すら一瞬でも暴露が生じる。クリップボード履歴マネージャー(Windowsクリップボード履歴、macOSクリップボードマネージャー、IDEペースト履歴)は特に高リスクである。
スクリーンショットとクラウドフォト同期
スマートフォンでフレーズをスクリーンショットを取ると、数秒以内にiCloudフォトやGoogleフォトにアップロードされ、ほとんどの人がそれを読む前に終わる。これらのバックアップはクライアント側で暗号化されていない。『スクリーンショットを取って安全に保存した』というのは直接的な外部化パスである。物理的に安全な場所に紙バックアップを置くことは、まったくの推奨ではない。
サーバー側の記憶語生成
BIP39フレーズをサーバー側で生成するすべてのウェブサイトは、エントロピーのコピーを持っている。安全な生成場所は、あなたが制御できるデバイスであり、生成時にオフラインであるべきである。ハードウェアウォレット、空気隔離されたマシン、または検証されたクライアント側ツールである。ウェブサイトはそれらのすべてではない — たとえJavaScriptが正しいように見えても、サーバーが出力のログを取っているかは確認できない。
フレーズの構造を確認または検証する必要がある場合 — エントロピーを確認、導出されたシードを確認、パスを検証 — は
ブラウザ内での実行のみ。フレーズはあなたのマシンに残り、これはこの用途における唯一の安全なアーキテクチャである。
開発者視点:アプリで記憶語を処理すべきではない BIP39ニーモニックコンバーター あなたが暗号関連アプリを構築している場合、バックエンドで「記憶語を処理する」という直感はほぼ常に間違っている。攻撃面:
ログ記録。
すべてのウェブフレームワークはリクエストボディをどこかにログ記録している。1行のデバッグログ、誤ったログレベル設定で、すべてのフレーズがディスク上に残り、無限に、複数のログデストレーションにわたって確認されていない。
- 移動。 HTTPSは通信を保護する。しかし、ロードバランサ、バックエンドプロセスのメモリ、データベース、またはログ集約器はすべて、別の攻撃面である。
- メモリ。 プロセスダンプ、クラッシュレポート、コアファイル、およびヒープスナップショットは、メモリ内の文字列をキャプチャする。シードフレーズがPythonの辞書やJavaScriptオブジェクトに存在している場合、ゼロコピーではない。おそらく複数のアロケーションにわたって表示される。
- 責任。 バックエンドがユーザーのシードフレーズを処理し、攻撃された場合、損害は永久である。パスワードとは異なり、リセットメカニズムがない。影響を受けたユーザーは資金を失い、補償の手段がない。
- 実際に機能するアーキテクチャ:必要なものをクライアント側で導出し、出力のみを送信する — 公開鍵、読み取り専用xpub、署名された取引。バックエンドはフレーズを見ない。正しいライブラリは: @scure/bip39
(検証済み、依存関係が最小化), ethers.js bitcoinjs-lib 。ハードウェアウォレット統合では、TrezorおよびLedgerのSDKは署名された取引を返す — 鍵はデバイス内に存在する。と、 一時的な導出チェーンの概要1. エントロピー
128–256ビットのランダムデータ
| ステップ | 入力 | 手術 | 出力 |
|---|---|---|---|
| SHA256チェックサム → 11ビットグループ | 12–24語の記憶語 | 2. シード | 記憶語語 + 「mnemonic」+ パスフレーズ |
| PBKDF2-HMAC-SHA51及、2048回 | 512ビットシード(64バイト) | 3. マスター鍵 | シードバイト |
| HMAC-SHA512(“Bitcoin seed”, シード) | マスタープライベート鍵(256ビット)+ チェーンコード(256ビット) | 4. アカウント鍵 | マスター鍵 + パス m/44’/60’/0’ |
| BIP32硬化子導出 × 3 | アカウント拡張プライベート鍵 | 5. アドレス鍵 | アカウント鍵 + パス /0/N |
| BIP32通常子導出 × 2 | 子プライベート鍵 → secp256k1公開鍵 → keccak256 → アドレス | BIP39は設計された通りに機能した。エントロピーを書くことができ、回復できるようにした。攻撃面は暗号学にあるわけではない — PBKDF2 2048回、HMAC-SHA512、secp256k1 すべてが安全である。攻撃はすべて運用的なものである:どこかにフレーズを入力する、デジタルに保存する、サーバー側で生成する信頼するツール。数学は問題ない。人間が弱いリンクであり、開発者アドバイスは「フレーズがインフラに触れないようにシステムを設計する」である。 | 子供のプライベートキー → secp256k1の公開キー → keccak25-56 → アドレス |
BIP39は、設計された通りに機能しました:エントロピーを書き出し、回復可能にしました。攻撃面は暗号学にありません。PBKDF2(2048回)、HMAC-SHA512、secp256k1というすべての暗号技術は信頼性があります。攻撃はすべて運用上のものです:適切な場所にパスフレーズを入力すること、デジタルに保存すること、サーバー側で生成されるツールに信頼を置くこと。数学的には問題ありません。人間が弱みであり、開発者へのアドバイスは「パスフレーズがインフラに触れないようにシステムを設計する」ということです。
恵 スコアボードが到着しました!
スコアボード ゲームを追跡する楽しい方法です。すべてのデータはブラウザに保存されます。さらに多くの機能がまもなく登場します!
