Coldcard 乱数生成脆弱性の全体像

2026年7月末、ハードウェアウォレット Coldcard で作られた約500のウォレットから、594 BTC が一斉に引き出されました。 被害額は約3,800万ドル、報道によっては7,000万ドル超と推計されています。 開発元の Coinkite は、原因の特定を受けてセキュリティアドバイザリと緊急のファームウェアを公開しました。

https://x.com/COLDCARDwallet/status/2082961993070247948

原因は、ハードウェアウォレットの根幹にあたるシードの乱数生成にありました。 Coldcard は2021年3月公開のファームウェア v4.0.0 以降、シードの生成に、本来使うはずのハードウェア乱数(TRNG)ではなく、決定論的なソフトウェア擬似乱数(Yasmarang)を使っていました。 きっかけは、ビルド設定のマクロを調べる書き方の誤りです。 この状態が約5年間、誰にも気づかれないまま続きました。

何が起きたか

  • 2021年1月: 原因となるコードが libngu(Coinkite の暗号ライブラリ)に入ります。同年3月17日公開のファームウェア v4.0.0 で製品デバイスに載りました。
  • 2021年から2026年: この間に Mk2/Mk3/Mk4/Mk5/Q の各機種がデバイス上で生成したシードの多くが、想定よりはるかに低いエントロピーで作られていました。
  • 2026年7月30日: 被害の報告を受けて、Block(Square の親会社で、Bitkey の開発元)の Bitcoin Engineering / Security チームが、匿名の研究者と協力して原因を特定します。攻撃者側はそれより前に脆弱性を見つけ、該当するシードを総当たりで復元して、静かに資金を移していたとみられます。集中的に抜かれたのは約25分間だったという報道もあります。
  • 2026年7月30日から31日: Coinkite がセキュリティアドバイザリを公開し、緊急のファームウェア(Mk3 は 4.2.0、Mk4/Mk5 は 5.6.0、Q は 1.5.0Q 以降)を出しました。

三つの失敗の連鎖

一つの書き間違いだけなら、ここまで弱くはなりませんでした。 乱数源の取り違え、初期化に使う値の貧しさ、後継機での不十分な手当てが重なって、公称128ビットのシードが総当たりできる範囲まで落ちています。

マクロチェックの書き間違い

libngu は、ハードウェア乱数が使えるかどうかを #ifndef MICROPY_HW_ENABLE_RNG で判定していました。 この書き方が見るのは「マクロが定義されているか」だけで、「値が 1 になっているか」は見ません。 Coldcard の製品ビルドは自前のハードウェア乱数ラッパーを使うため、このマクロを値 0 として定義していました。 定義そのものは存在するので、判定は「ハードウェア乱数あり」として通ります。 一方でコンパイル時には値が 0 と評価されるので、MicroPython 側のソフトウェアフォールバックである Yasmarang が実際に組み込まれます。 「ハードウェア乱数を使っているつもりで、中身は擬似乱数」という、噛み合わせとして最悪の組み合わせでした。

Yasmarang の初期化が予測できる

Yasmarang は決定論的な擬似乱数生成器です。 初期化に使われていたのは、MCU の UID(シリアル番号)、タイマーレジスタ、ボタン入力のタイミングといった値だけでした。 どれも攻撃者が推定したり、範囲を絞って列挙したりできるものです。 Mk3 では、実効エントロピーが約40ビット、組み合わせにして約1.1兆通りまで落ちていました。 128ビットを想定した12単語のシードとしては桁違いに弱く、GPU で現実的に総当たりできる水準です。

後継機の再シードが32ビット分しかない

Mk4/Mk5/Q では、セキュアエレメントからの再シードが入っていました。 ただし32バイトのハッシュから取り出すのは4バイトだけで、擬似乱数の内部状態のうち1ワードを置き換えるにとどまります。 そのため実効エントロピーは最大でも 2³² 程度に制限され、公称の128ビットに対して約72ビットにとどまりました。 72ビットは即座に割れる強度ではありませんが、想定していた安全マージンは大きく割り込んでいます。

補足すると、libngu は Yasmarang の出力を、ハードコードされた公開の定数で初期化した別の Yasmarang インスタンスの出力と XOR していました。 ただし、初期状態が知られている決定論的な列同士を XOR しても、結果は決定論的なままです。 出力を SHA-256 に通しても事情は同じで、入力の候補が 2⁴⁰ 通りなら、出力の候補も 2⁴⁰ 通りにしかなりません。 ハッシュはエントロピーを増やせない、という基本がそのまま効いています。

どこまでが影響を受けるか

デバイス 危険なファームウェア 実効エントロピー
Mk2 / Mk3 v4.0.0〜v4.1.9 約40ビット(実際に盗難が発生)
Mk4 / Mk5 5.6.0 未満 約72ビット
Q 1.5.0Q 未満 約72ビット
Mk1、v4以前の Mk2/Mk3 該当なし 影響なし(ハードウェア乱数を直接使用)

影響はウォレットのシードだけにとどまりません。 同じ乱数の列を消費していたペーパーウォレットの秘密鍵、クローン用の暗号鍵、Key Teleport、Web2FA のシークレットにも及びます。

一方で、サイコロを50回以上自分で振ってシードを作った場合は影響を受けません。 デバイス側の乱数と一緒にハッシュされてはいますが、利用者が持ち込んだエントロピーそのものは本物だからです。

該当する期間にデバイス上で生成したシードについては、ファームウェアを更新したうえで新しいシードを作り、資金を移すことが公式に推奨されています。

この事件が示すこと

エアギャップされていても、乱数生成が壊れていれば守りにはなりません。 秘密鍵が外に漏れる経路がなくても、鍵そのものが推測できるなら結果は同じです。 過去にも Milk Sad(libbitcoin bx)、Trust Wallet、Profanity と、同じ型の「弱い乱数」の事故が起きています。 今回は、それが評判の高い専用ハードウェアで起きました。

多くの目に晒されているコードでも、脆弱性が見つかるとは限りません。 libngu も Coldcard のファームウェアも公開されており、#ifndef#if の取り違えという初歩的な誤りは、誰でも読める場所に5年間置かれていました。 それでも、誰も気づきませんでした。 「公開されている」ことは、誰かがその箇所を、その観点で読んだことを意味しません。

外部からエントロピーを入れる運用には、構造的な意味がありました。 サイコロを併用していた利用者が今回守られたのは、運の良さではありません。 デバイスを信用しきらずに自分でエントロピーを注ぎ込む手順が、デバイス側の乱数が丸ごと壊れるという想定外の事態を吸収した、ということです。

次の記事では、乱数生成の脆弱性によって利用者がどのような攻撃にさらされたのかを解説します。

出典