Coldcardのシード生成の脆弱性を受けて、ビットコインユーザーの間ではサイコロなどによる、手動で生成したエントロピー(ランダムデータ)を使ったシード生成に関心が集まっています。

シードフレーズの生成はウォレットを作成するときの一番最初の段階にすぎませんが、ここに問題があると後から修正は効きません。今回のように、問題になる前に急いで別のウォレットに送金することになりますが、運が悪いと間に合わない可能性もあります。Coldcard同様の問題に対して私たちが取れる対策は

  • シードフレーズと同じくらい強力なパスフレーズを設定する
  • 深刻な脆弱性のありうるソフトウェア依存のランダム性を使用せず、自然なエントロピーを使ってシードフレーズを生成する

くらいしか選択肢がありません(もちろん、ハードウェアウォレットメーカーも各社シード生成が脆弱になりにくいように試行錯誤していますが)。セルフカストディは最初が肝心なのです。

今回の記事では、改めてサイコロやトランプを使ってランダムなシードフレーズを生成する方法を、実践的なガイドとして解説します。どれも1時間かからないので、週末などにご自身で自由研究気分で試していただければと思います。

💡
なお、この記事で紹介する方法は実際に使用可能な水準のシードフレーズが生成可能ですが、もし生成するシードフレーズを実際にご使用される予定であれば生成時の環境に注意し、シードフレーズやサイコロの目などが他人の目やカメラの範囲に写らないようご注意ください。

エントロピーからシードフレーズが生まれる仕組み

ビットコインのシードフレーズは、128 bit(12単語)または256 bit(24単語)のエントロピーを、人間が書き写しやすいように英単語の形にエンコードしたものです。詳細な仕様はBIP-39として公開されています。

bips/bip-0039.mediawiki at master · bitcoin/bips
Bitcoin Improvement Proposals. Contribute to bitcoin/bips development by creating an account on GitHub.

現在ではほぼ全てのウォレットが対応しているBIP-39は、2013年頃にSatoshi Labs(Trezorの開発元)が提案して生まれました。それまではBitcoin CoreのウォレットファイルをUSBなどにバックアップするのがビットコインウォレットのバックアップ方法の定番で、セキュリティ面でも保管面でも問題が大きいものでした。ウォレットを簡単な文字列という形で保存できるようになったのは、ビットコインを簡単に失ってしまわないための大きな革新でした。

BIP-39は1単語あたり11ビットのデータに対応

BIP-39ニモニック(シードフレーズ)は2048単語のリストから単語を選ぶことによって、それぞれの単語に対応するビット列(2進数のデータ)を示します。具体的には下図のようなイメージです:

BIP39は1単語あたり11 bitのデータをエンコードする。

したがって、非常にシンプルに説明するならば、12単語あるいは24単語をワードリスト内の順番に応じて2進数に変換していけば、シードフレーズが表すエントロピーを復元できます。このエントロピーがウォレットの元となっているので、シードフレーズをリカバリーに利用できるわけですね。

bips/bip-0039/english.txt at master · bitcoin/bips
Bitcoin Improvement Proposals. Contribute to bitcoin/bips development by creating an account on GitHub.

GitHubのページにあるワードリストの単語の横の数字は「ファイル内の行数」ですが、実際に対応するデータは0から始まるので、この数字とは1ずつずれています。

最後の単語のみチェックサムが含まれ、選択肢が絞られる

勘の良いあなたはもしかすると気づいているかもしれません。11 bit×12単語=132 bitで、12単語は128 bitを表すという説明と一致しません。11 bit×24単語=264 bitで、こちらも256 bitより少し多めです。この差分はチェックサムといって、最初の11単語が正しく記述できていない場合に検知するための仕組みを内蔵していることによります。

例えば12単語の場合、12単語目の最初の7 bitはランダムデータの部分で、最後の4 bitはチェックサムとなります。24単語の場合、チェックサムは8 bitあります。

チェックサムの長さはシードフレーズの長さによって異なるが、最後の単語に含まれている。

書き写しのときの間違い対策として存在します。チェックサムが一致しない場合、ウォレットが警告を発するでしょう。

また、24単語の場合は、最後の単語はわずか3 bitしかエントロピーを含まず、チェックサムは計算で求められるので、24単語目の候補は8通りしかないことになります。これはあとで重要になってきます。

💡
チェックサムの計算については、ハッシュ計算を伴うので残念ながら手動で行うのは現実的ではありません。そこで、ハードウェアウォレットなどの助けを借りることになりますが、助けを借りる度合いには強弱があったりします。これも後述します。

ランダムデータさえあれば、シードフレーズにできる

以上のことから、ランダムな2進数のデータさえあれば、それを順にBIP-39の単語リストに当てはめていくことでシードフレーズが生成できることがイメージ出来たかと思います。

2進数のランダムデータの生成で一番イメージしやすいのはコイントスでしょうか。表=1、裏=0などと決めて、指の上のときの初期状態を定めず、しっかりと空中でたくさん回転するようなコイントスを行えばシードフレーズは生成できます。

しかし、256回もコイントスをするのは親指が痛くなってしまいそうなので、身近にあるお手軽なアイテムで試す方法を2つ紹介します。サイコロとトランプです。

本当に自分で生成したシードフレーズは安全なのか?

その前に、今回の企画の安全性について納得していただきます。以下の過去記事をご覧いただければ、この部分はスキップしていただいても構いません。

サイコロによる乱数生成はどれくらい安全なのか?24単語のシードフレーズが選べる理由
サイコロで生成するシードフレーズはどこまで安全なのか?偏りの影響、24単語との関係、ハードウェアウォレットが生成するシードとの比較まで分かりやすく解説します。

「サイコロやトランプでシードを生成するなんて心もとない。サイコロの精度が悪かったら弱いシードが生成されてしまうのではないか」という心配な声をよく見かけます。安心してください。現実的な範囲のダイスやトランプを使って、24単語分のエントロピーを生成していれば全く問題ありません。

数学的には、1回あたりN通りの結果を等しい確率で示す試行には、log2(N)の情報があります。簡単な例で代入すると、256bitのエントロピーを得るためには、コイントスの場合は256回、サイコロの場合は99~100回の試行が必要なことがわかります。

サイコロで256 bitのエントロピーを目指せば、相当安全

では、ポンコツなサイコロの場合はどうでしょう?256 bitを目指せば非常に安全なので、理想的なサイコロと同じ100回転がすことを想定します。

1,2,3しか出ないサイコロでも、100回振れば158 bitもエントロピーが得られる

100回試行すれば158bitと、理想的な12単語のシードフレーズよりも強固なエントロピーが得られます。

確率の分布自体が偏っている場合も、Shannon Entropyという計算方法があります。例えば60%の確率で1が、それぞれ20%の確率で2と3がでるサイコロの場合は次のようになります:

とんでもなく偏ったサイコロでも、100回振れば137 bitもエントロピーが得られる

100回あたり137 bitと、やはり12単語シードフレーズを超えるエントロピーが得られます。こんなトンデモサイコロでも問題ないということになります。

ただし、あえて脆弱なエントロピー源を使うことはよくないので、せめて普通のサイコロを使いましょう。また安全のため、よほどの事情がなければ24単語生成しましょう。

💡
シードフレーズに12単語(128bit)と24単語(256bit)がありますが、実はビットコインアドレスで利用する鍵には128bitのセキュリティしかありません。それなのに24単語で256bitのエントロピーに対応しているのは、「乱数が偏っていて、思ったよりエントロピーが少なかった」場合の対策です。したがって、自分自身でシードを生成するくらい乱数を気にしている場合は、必ず24単語で生成しましょう。
💡
今回の記事の趣旨からは少し逸れますが、たとえサイコロであっても人間が生成するランダムデータより機械が正しく生成したランダムデータのほうが高品質で、人間は上記のようなオリジナル要素を加えて脆弱なシードフレーズを生成してしまう可能性もあるという意見もあります。確かに、できる限りいろんなソースから独立した大量のエントロピーを集めてくることができれば、個々のソースの脆弱性の影響は受けにくく理想的だといえるでしょう。

一方で、機械は機械で設計やソフトウェアの問題によって乱数生成が脆弱になる可能性もあり、一般的なユーザーにとってはサイコロよりも検証が難しいエントロピー源という側面もあります。実際に今回のColdcardの件は、この理論上の脅威が現実化したケースでした。

このトレードオフは思想の違いとして様々なプロダクトで見て取れます。例えばサイコロによるシード生成を機能として提供しているハードウェアウォレットは、上級者向けのニッチなものに限られる傾向があります。

さらに余談ですが、下記の過去記事の中に「偏ったダイスから真性乱数を得る方法」としてフォン・ノイマンのアルゴリズムを紹介しているので、もし興味があれば参考にしてみてください。

紙とペンでシャミアの秘密分散法を使いシードフレーズを分割する:Codex32
コアなビットコイナーは秘密鍵の管理にうるさかったり、一家言ある人が多いというイメージはありませんか?少なくとも自分の印象ではWeb3系の人たちよりよほど秘密鍵の生成や管理に関心がある気がします。 ビットコイナーの一部の間ではマルチシグによって自身のコールドストレージのセキュリティを強化する人も見られるようになりました。しかし通常のシードフレーズとは異なり、複数のシードフレーズとスクリプト文のデータなどを用意し別々の場所で安全に保管するのが煩雑なのも間違いありません。 他にはシャミアの秘密分散法という知名度の高い手法を使って1つのシードフレーズを複数の「シェア」に分割し、それらのシェアを使ってn-of-mのマルチシグを擬似的に再現することも考えられます。実際には1つのシードフレーズを復元するので狭義のマルチシグトランザクションにはなりませんが、比較的シンプルな手法で(ビットコイン以外のブロックチェーン系のウォレットで)人気があります。 例えば友人や親戚にシェアを1つ預けてソーシャルリカバリーできるようなウォレットの多くはこのスキームになっています。数人に結託して裏切られないように注

サイコロでも十分にランダムなシードフレーズが生成できることに納得いただけたら、早速その方法を見ていきましょう。

サイコロでシードフレーズを生成する方法が王道

さて、サイコロからシードを生成する方法はたくさん考えられますが、主に2通りになります。

ハードウェアウォレットに直接サイコロの出目を逐次入力し、シードフレーズを生成してもらう方法

ハードウェアウォレットに直接サイコロの出目を入力していく方法

ColdcardやSeedSigner、Kruxなど、サイコロの出目をハードウェアウォレットに入力する機能が提供されている場合に使える方法です。サイコロを振りながら、出た目を次々とハードウェアウォレットに入力していきます。この方法の特徴は、任意の回数サイコロを振ることができるので、怖い場合は200回振ってもいいところです。(回数を少なめに振ると危ないので、必ず100回は振りましょう)

ハードウェアウォレット内部では、サイコロの出目をひと続きのテキストとして扱い、SHA256というハッシュ計算を通すことで256 bitに整形したものをエントロピーとして扱っているようです。最終的にはそこに8 bitのチェックサムが加わり、シードフレーズに変換されます。

最終的には256 bitになりますが、サイコロのエントロピーが脆弱なことを見越してそれ以上のエントロピーを生成するところから始められるのがメリットです。

多めにサイコロを振ったらそれがちゃんと根本的なエントロピーとして機能することがメリット

逆にデメリットとしては、SHA256の計算が正しく行われているか人間に検証するのは難しいので、別のウォレットでも同じ方法で生成してみるなど、検証のステップがほしいところです(使う予定のないシードを生成して、Webベースのツールなどで検証することもできます)。

💡
さすがにビットコインのウォレットでSHA256の計算がおかしいのはウォレットに悪意がある場合だけだと思いますが、悪意に対してさえ対策できるのはいいですね。

手動で最初の23単語を生成し、最後の単語はハードウェアウォレットに提案させた中から決める方法

一方、ひと目見て検証できるものを好む場合は、Dicewareと呼ばれる方法でサイコロの出目から直接単語を決定します。細かい部分ではいろんな方法がありますが、ここで紹介するものであればどれもランダムなシードを生成できます。

サイコロから手動でシードフレーズを生成する方法はネットに公開されているものがいくつかありますが、以下に3つガイドを貼ります。Blockstream Jadeのガイドは16面サイコロ・8面サイコロというボードゲームマニアしか持ってなさそうなアイテムが必要ですがガイドとしてはよくできています。BitBoxのガイドはサイコロ5つとコイン1枚を組み合わせます。著者が作ったバイナリ→BIP39ワードリストには、コメントとして一般的な6面サイコロを用いた作り方を添えています。

Create a recovery phrase using dice
Get help for the Blockstream app, Jade, Satellite, Liquid Network, and Explorer API. Guides, how-tos, and troubleshooting.

"View our downloadable guide"から最初の23単語を生成する方法のPDFが閲覧できます

Roll your own Bitcoin seed
Learn how to create your own random Bitcoin hardware wallet seed with these easy step-by-step instructions.

"BitBox02 Diceware instructions" "BitBox02 Diceware lookup table"も開いてください

Binary bits to BIP39 words (English)
Binary bits to BIP39 words (English). GitHub Gist: instantly share code, notes, and snippets.

6面サイコロの出目によって、1~2bitずつ決定したものをリストに照らし合わせて単語に変換します

基本的には、サイコロなどの出目をビット列に変換していき、単語を順に決定していきます。23単語を決定したら、最後の単語は手動では決定できないのでハードウェアウォレットなどの「復元/インポート」メニューを使うことになります。

BitBox、Jade、SeedSignerなど「復元」メニューから23単語入力したら24単語目をサジェストしてくれるハードウェアウォレットを利用すると、24単語目はリストから選ぶ方式になります。このリストに出てきた単語はチェックサムが通る単語なので、やはりサイコロやコイントス、鉛筆転がしなどで24単語目を選びましょう。

これで24単語のシードフレーズが完成しました。自分が決定した最初の23語が確かに使われていることが確認できると思います。ハードウェアやソフトウェアに依存しないシードフレーズの完成です。

トランプでシードフレーズを生成する方法も

だいたいの人は家にサイコロかトランプがあると思いますが、トランプを使ってシードフレーズを生成することもできます。マイナーな手段ではありますが、Seed Picker Solitaireとして公開されているリポジトリがあったり、Bull Bitcoinという取引所がグッズとしてトランプを出していたりします:

GitHub - jimbojw/seed-picker-solitaire: Generate a BIP39 seed phrase offline using an ordinary deck of playing cards.
Generate a BIP39 seed phrase offline using an ordinary deck of playing cards. - jimbojw/seed-picker-solitaire

詳細なやり方は上記リンクを参照していただくとして、簡単に説明すると

  1. トランプをよく混ぜる(7回以上シャッフルする。方法はいわゆるショットガンシャッフル・ディールシャッフルが好ましい。詳細はGitHubリンクからご確認ください)
  2. 最初の2枚をめくる。同じ柄(マーク)なら1.からやりなおし
  3. 1枚目のカードの対照表を開く。2枚目のカードに対応する単語が決定する(場合によっては単語がなくてやり直し)
  4. カードを戻して1.へ戻る

これを23回以上繰り返してから、24単語目を先述の方法でハードウェアウォレットなどに候補として出させる流れになります。

BIP39ワードへの変換表の読みやすさは、ビット列からの変換表よりトランプからのもののほうが良い気がします。完全に好みの問題ですが、それでも自分はサイコロのほうが安心できます。(一応カードのシャッフルについての研究もたくさん存在するようなので、興味がある方は調べてみると面白いかもしれません)

シードフレーズを機械に頼らず生成するのは簡単、あとはトレードオフをどう考えるかの問題

この記事で見てきたように、サイコロやトランプを使って、機械やソフトウェアに頼らないエントロピーを生成し、シードフレーズを作成することは容易です。情報科学に詳しい方であれば、何らかの別のエントロピー源を追加する方法も取れるかもしれません(例えばPCで256bitのエントロピーを生成して、自分が生成した256bitと排他的論理和を取るなど)。エントロピーは別のエントロピー源を追加することで減ることはありません。

あとは、機械に生成させた理屈の上では強固なエントロピーだが実装によっては脆弱かもしれないものと、自分自身で生成したもの、どちらを選ぶかというトレードオフの問題です。人によってはリスク分散の観点から両方を別々のウォレットとして利用したり、1つのマルチシグの中でのリスク分散として鍵ごとにエントロピーの生成方法を分ける場合もあるかもしれません。

いずれにせよ、ビットコインを裏付ける技術のエクササイズとして、週末のアクティビティに適している乱数生成をぜひ試してみていただければと思います。ベストプラクティスかどうかは意見が分かれる部分があっても、人間の直感よりは安全性が高いことを理解していただけたら幸いです。