ハードウェアウォレット(Hardware Wallet)は、秘密鍵をネットワークから切り離した装置で保管する。そのColdcardの一部ファームウェアでは、秘密鍵の基になる乱数が予測可能な経路へ切り替わっていた。装置への侵入や偽ファームウェアの導入がなくても、生成時の候補が狭ければ、公開されたアドレスから対応する秘密鍵を探索されるおそれがある。

製造元Coinkiteは2026年7月30日に安全公告を出し、Mk2とMk3の4.0.1〜4.1.9、Mk4とMk5、Qの修正版より前のファームウェアで生成したシードを影響対象とした。全対象機種に修正版が出ているが、更新だけでは過去に作ったシードは直らない。問題の中心は保管中の鍵が装置から盗まれたことではなく、鍵を作った時点の予測困難性が不足していたことだ。

設定値「0」を有効と扱った組み合わせ

根因は乱数アルゴリズム単体ではなく、基板設定、MicroPython、暗号ライブラリーlibnguの接点にあった。Coldcardの製品設定は、独自のハードウェア乱数ラッパーを持つため、MICROPY_HW_ENABLE_RNG0にしていた。ところがlibngu側は#ifndefでマクロが定義されているかだけを確認し、その値が有効かを調べなかった。

Blockの技術分析によると、マクロは値が0でも定義済みだったためビルドは成功し、libnguの乱数要求はMicroPythonのrng_get()へ結び付いた。MicroPython側は値を見てハードウェア乱数を無効と判断し、決定論的なYasmarangを代替処理として組み込んだ。同じ設定を二つの部品が別の意味で読んだ結果、警告のないまま意図しない経路が完成した。

設定値0が定義済みと判定され、低エントロピーのソフトウェア乱数へ切り替わる流れを示す図

Yasmarangは装置の識別子、SysTickの値、リアルタイムクロックのレジスターから初期状態を作る。これらは固定値または時刻に関係する値で、暗号学的な秘密ではない。初期状態と、それ以前に乱数が何回呼ばれたかが絞られれば、その後の出力も再現可能になる。別のYasmarang出力との排他的論理和やSHA-256によるハッシュを重ねても、元の候補数そのものは増えない。

機種で異なる探索空間

Blockの分析では、Mk2とMk3のv4系は秘密の再シードを加えず、装置識別子、タイマー状態、呼び出し履歴が固定されれば出力も一意になる。識別子が既知でタイマーを広く数えた上限は約2の40.7乗で、通常のコールドブートでリアルタイムクロックが固定される想定では約2の16.3乗まで狭まるとしている。

Mk4、Mk5、Qはセキュアエレメント由来の値を加えるが、ハッシュ結果のうち4バイトだけをYasmarangの再シードに渡す。既存の状態と呼び出し履歴が判明していれば、秘密に区別される出力系列は最大2の32乗となる。タイマー項目を互いに独立と仮定した緩い上限は2の73.3乗未満だが、Blockはこれを73ビットの暗号強度とはみなせないと明記した。

この幅は重要である。すべての遠隔攻撃者が直ちにすべてのシードを復元できるとの意味ではない。現実の費用は、装置識別子をどこまで絞れるか、起動時刻を推定できるか、事前の呼び出し履歴を再現できるか、候補ごとの鍵導出にかかる計算量に左右される。Block自身も、完全な実機試験による悪用可能性の確認と一貫した総当たり性能の数値は示していない。

見た目のランダムさでは検出できない

決定論的な疑似乱数でも、隣り合う値は異なり、出力の分布は一見すると乱数らしくなる。今回の経路には同じ値の連続を拒む検査があったが、Yasmarangは通常それを通過する。生成した32バイトをSHA-256で処理すれば、出力の偏りはさらに見えにくくなる。それでも、入力になかった予測困難性が後処理で生まれるわけではない。

米国立標準技術研究所(NIST)のSP 800-90Bは、乱数生成器に使うエントロピー源の設計原則、要件、検証試験を定め、決定論的乱数生成器と組み合わせる前段の品質を独立して扱っている。出力形式や統計的な見栄えの確認だけでは足りず、どのノイズ源からどれだけの最小エントロピーを得たかを評価する必要がある。

通常のハードウェア乱数経路と、まれに使うはずの代替経路を比較した図

修正版を入れても旧シードは直らない

Coinkiteが示した修正版は、Mk2とMk3が4.2.0以降、Mk4とMk5の標準版が5.6.0以降、Edge版が6.6.0X以降、Q標準版が1.5.0Q以降、Q Edge版が6.6.0QX以降である。TAPSIGNER、OPENDIME、SATSCARDは別のコードベースを使うため、同じ不具合の対象外とされた。

影響の判定基準は現在のファームウェアではなく、シードを生成した時点の版だ。旧版で作ったシードを別のウォレットへ読み込んでも、元の候補空間は変わらない。Coinkiteは、修正版を確認して新しいシードと受取アドレスを作り、少額の試験送金を確認してから残額を移し、移行完了まで旧バックアップを残す手順を案内している。

少なくとも50回の公正で独立した非公開のサイコロ入力をシード生成時に加えた場合、その入力だけで128ビット以上のエントロピーを持つとCoinkiteは説明する。強く固有のBIP-39パスフレーズも別の障壁になる。ただし、短い語句、使い回し、規則的な文字列は推測され得る。強いパスフレーズも元の弱いシードを修復しないため、同社は該当する利用者に新しいシードへの移行を求めている。

開発側が確認すべき三つの境界

第一は、安全に直結する経路で静かな代替処理を認めないことだ。想定したエントロピー源を取得できない場合は秘密値の生成を中止し、原因を記録する。形式の正しい弱い値を返すより、明示的な失敗として扱う設計が要る。

第二は、起動時と運用中に実際の乱数経路を確かめることだ。ハードウェア乱数生成器の健全性試験に加え、呼び出し先が意図した実装へ結び付いているかをテストする。出力の統計検査は補助にはなるが、エントロピー源とコード経路の確認を置き換えない。

第三は、ビルド設定をセキュリティーレビューの対象に含めることだ。#ifdef#if、未定義と値0の違いは小さく見えるが、コンパイル後の呼び出し先を変える。重要な設定については許される値をコンパイル時に限定し、生成物のシンボルや実行時の自己診断で選択された経路を検証する必要がある。

静かな代替処理の禁止、起動時検査、ビルド設定の審査という三つの確認点を示す図

日本での影響は公表資料に空白

日本国内でColdcardを使う人数、国内の被害申告件数、円換算した損失額を示す公的な資料は、本稿の執筆時点で確認できていない。この空白は、国内に利用者や被害がないことを意味しない。影響の有無は居住地では決まらず、シードを作った機種とファームウェア、独立した追加エントロピー、パスフレーズの条件で決まる。

事件の技術的な教訓は暗号資産製品に限られない。認証トークン、暗号鍵、一時コードなど予測困難性を前提とする値では、APIが正常な長さの値を返した事実と、必要なエントロピーを得た事実を分けて検証する必要がある。特定の医療情報システムで同じ劣化が発生したとの国内資料は確認できないため、本稿では個別システムへの被害を推定しない。

よくある質問

Coldcard本体へ侵入されたのか
公開資料が示す根因は、シード生成時に意図しない決定論的乱数経路を使った実装上の欠陥だ。秘密鍵を装置から読み取らなくても、候補を再現し、公開アドレスと照合する攻撃が成立し得る。

ファームウェアを更新すれば十分か
新しいシードの生成には修正版が必要だが、旧版で作った既存シードは更新で直らない。Coinkiteは修正版で新しいシードを作り、受取アドレスと少額送金を確認した後に資産を移すよう案内している。

「72ビットなら安全」と判断してよいか
一律には判断できない。約72ビットはCoinkiteが示したMk4、Mk5、Qの概算で、Blockのコード分析は、既存状態が判明した場合に秘密の再シードが最大32ビットへ制限されると指摘した。実際の探索量は機種、タイマー、識別子、呼び出し履歴で変わる。

オープンソースなら同じ問題を防げるのか
ソースの公開は検証可能性を高めるが、自動的に安全を保証しない。今回の欠陥は公開コードとビルド設定の境界に長く残った。設定値を含むレビュー、実際の生成物の検査、実機での経路確認を組み合わせる必要がある。