ECDSA曲線のシードの出どころをClaudeが解明 — 正体はタイムスタンプ
NIST曲線のシードは文言のハッシュではなく、1990年代のC標準ライブラリの乱数生成器lrand48に時刻を与えた出力でした。Claudeが30分足らずで突き止めた経緯と、残った謎をまとめました。
2026年10月16日、AnthropicのFrontier Red Teamが、ECDSAの標準曲線に付いた「シード」の出どころを突き止めたと発表しました。シードはNSAが提供した数値で、25年以上、由来の説明がありませんでした。答えは、ハッシュ関数でも凝った合言葉でもなく、C標準ライブラリの乱数生成器lrand48にUnix時刻を与えた出力でした。
結論から言うと、暗号上の新しい攻撃でも弱点でもなく、読者が何かを変える必要もありません。この記事では、Claudeがどう手がかりを絞ったのか、暗号の世界でこの発見がどこまでを意味するのか、まだ説明のつかない部分は何かを順に追います。
25年間「出どころ不明」だったシード
ECDSAは最も広く使われている楕円曲線暗号の標準です。2000年にNISTがFIPS 186-2のデジタル署名標準の一部として採用し、大きさと安全性の水準が異なる標準曲線を並べました。素数体とバイナリ体の曲線には「シード」というパラメータが公開されています。このシードのハッシュ値が、曲線の係数bを決める仕組みです。
問題はシードの由来でした。NSAが提供したのに、どう選んだかの説明も根拠もありません。たとえばNIST P-256のシードは次の値です。
SEED = C49D3608 86E70493 6A6678E1 139D26B7 819F7E90不透明な数値から曲線が作られていたため、意図的な裏口(バックドア)が仕込まれたのではないかという疑いが長く残りました。Neal KoblitzとAlfred Menezesが経緯と懸念を「A Riddle Wrapped in an Enigma」にまとめています。アマチュアの調査も生まれ、シードを見つけた人への懸賞金も設けられました。
最も有力だった話は、NSAの技術者Jerry Solinasが、冗談めいた文言をハッシュしてシードを作ったというものです。2015年の本人の回想では、実際にはカウンターで回していたような記憶があり、文言は「Give Bob and Jerry a raise」の類だったそうです。コードを書いたBob Reiterも細部を覚えておらず、古い記録も見つかっていません。Solinasは2023年に亡くなり、当時の同僚からも反応がなく、確かめる道は閉じていました。
文言探しをやめ、乱数生成器を疑う
Anthropicの社員が数人、この文言の線を追いましたが、見つかりませんでした。転機は2026年10月です。ある社員が社内の研究用モデルに「手がかりを渡さずに、シードがどう作られたか分かるか」と尋ねました。Claudeは30分足らずで、NIST P-192、P-224、P-256、P-384、P-521のシードの出どころを突き止めています。
手順1: 1990年代のPRNGを総当たりで当てはめる
Claudeは文言を探す代わりに、曲線を作ったソフトウェアの動きを推測しました。1990年代のC標準ライブラリに付いていた疑似乱数生成器(PRNG)なら、出力から種類を見分けられるほど弱いはずだ、という発想です。
公開されたシードを1ビットずつずらしながら、隣り合う塊が古い生成器の連続した出力になっていないかを調べるスキャナーを書きました。調べた組み合わせは、生成器と出力の切り出し方を合わせて34通りです。
手順2: 上位ビットの偏りでlrand48と判明
スキャンの途中で、Claudeは一部のシードの上位ビットがすべて0であることに気づきます。5つの32ビット語として読むと、10個のシードのうち4個で、20語すべての最上位ビットが0でした。偶然にこうなる確率は約5,810分の1です。
これはlrand48の特徴です。lrand48は48ビットの内部状態のうち、上位31ビットだけを返す線形合同法の生成器です。目で見て分かる偏りですが、見るべき場所を知らなければ気づけません。
バイナリ曲線のシードは、最初の語について隠れた17ビットの2¹⁷通りを試し、続く4語が一致するかで状態を復元できました。該当する4つのシードすべてでうまくいっています。
手順3: 格子問題で内部状態を復元する
素数曲線のシードは、同じlrand48から出ていますが、各出力から残るビットが少なくなります。そこで内部状態の復元が必要になりました。切り詰めた線形合同法の状態復元は、Lenstra–Lenstra–Lovász(LLL)の基底簡約で解ける教科書的な格子問題です。
どのビットがシードに現れるかは分からないので、Claudeはすべての窓位置でソルバーを走らせました。NISTの素数曲線シード5個と、ANSI X9.62規格のシード5個の合計10個で、同じパターンが見つかります。出力はlrand48() >> 23でした。復元した48ビットの状態からは160ビット分のシードがすべて再現され、これは偶然では起こりません。
手順4: 状態を巻き戻すと、日時が出てくる
線形合同法は前にも後ろにも同じように回せます。Claudeは各シードについて状態を巻き戻し、srand48が初期化したときの形、つまり下位16ビットが0x330Eになる状態まで戻しました。この形の状態は65,536ステップに1回現れるので、見つかっただけでは証拠になりません。
決め手は日付です。素数曲線10個の初期化値は、いずれも1997年5月から1998年4月のUnix時刻に当たりました。弱い乱数生成器に時刻を与えていたことになります。バイナリ曲線4個は、そのまま読むと1984年2月です。時刻を2倍すると、P-224の実行から2週間後の1998年4月17日に収まります。プログラムが時計の値を半分にしていた可能性があります。
曲線ごとの初期化時刻と試行回数
次の表は、発表に添えられた再現コードの入力値です。素数曲線はsrand48(時刻)、バイナリ曲線はsrand48(時刻 / 2)と読んだ場合の値で、時刻はUTCです。
| 曲線 | 初期化時刻 | 候補番号 |
|---|---|---|
| P-192 | 初期化時刻1997-05-18 14:45:34 | 候補番号139 |
| prime192v3 | 初期化時刻1997-05-18 14:45:34 | 候補番号5228 |
| prime192v2 | 初期化時刻1997-05-18 14:45:34 | 候補番号6013 |
| prime239v1 | 初期化時刻1997-05-15 15:49:03 | 候補番号2185 |
| prime239v2 | 初期化時刻1997-05-15 15:49:03 | 候補番号2320 |
| prime239v3 | 初期化時刻1997-05-15 15:49:03 | 候補番号3048 |
| P-521 | 初期化時刻1997-08-08 01:12:04 | 候補番号1136 |
| P-256 | 初期化時刻1997-08-16 01:52:34 | 候補番号1842 |
| P-384 | 初期化時刻1997-08-30 14:50:08 | 候補番号2688 |
| P-224 | 初期化時刻1998-04-03 12:52:07 | 候補番号7026 |
| B-233 | 初期化時刻1998-04-17 15:24:18 | 候補番号155 |
| B-283 | 初期化時刻1998-04-17 15:27:44 | 候補番号32 |
| B-409 | 初期化時刻1998-04-17 15:30:18 | 候補番号60 |
| B-571 | 初期化時刻1998-04-17 15:32:08 | 候補番号73 |
表の読み方には癖があります。同じ時刻の行は、1回の実行で複数の曲線を拾ったことを意味します。P-192とprime192v2、v3は同じ時刻で、候補番号だけが違います。prime239の3曲線も同様です。ANSI X9.62の例示曲線の背後には2回の実行があった、とAnthropicは説明しています。
候補番号は、同じ初期化から20バイトずつ取り出した何番目の塊かを示します。1番目の20バイトが候補1、次の20バイトが候補2です。P-256は1842回目の候補が標準のシードになりました。
手元で再現する
発表には、表の値からシードを再現するPythonコードがCC0(パブリックドメイン)で付いています。中核はたった数行の線形合同法です。次のコードは、その要点だけを取り出してP-256を再現するものです。
from datetime import datetime, timezone
t = int(datetime.fromisoformat("1997-08-16 01:52:34")
.replace(tzinfo=timezone.utc).timestamp())
x, out = (t << 16) | 0x330E, "" # srand48(t) が作る状態
for i in range(20 * 1842):
x = (0x5DEECE66D * x + 0xB) % 2**48 # lrand48 の1ステップ
if i >= 20 * 1841: # 1842番目の20バイト
out += "%02X" % (x >> 40) # 状態の上位8ビット(= lrand48() >> 23)
print(out)出力はC49D360886E704936A6678E1139D26B7819F7E90で、公開されているP-256のシードと一致します。表の入力値を差し替えれば、ほかの曲線も同じ形で試せます。
基底点の一部も出どころが分かった
曲線にはシードのほかに、公開鍵の元になる固定点、基底点Gがあります。シードからGは決まらないので、Gの出どころは別の問いでした。シードの検証のついでに、Claudeは一部の基底点の由来も見つけています。
1997年5月に作られた6本の曲線の基底点が対象です。P-192と、ANSI X9.62の例示曲線であるprime192v2、v3、prime239v1からv3までを指します。出どころは、Arjen Lenstraの多倍長整数ライブラリFreeLIPの乱数生成器でした。Victor ShoupのNTLライブラリの初期版にも同じコードが入っていました。
手順は単純です。
FreeLIP乱数生成器による基底点の探し方
- 1
生成器に小さな整数を与える
乱数生成器の初期化に、小さな整数のシードを使います。
- 2
7個の出力を捨てる
最初の7回分の出力は使いません。
- 3
x座標の候補を作る
26ビットの出力を並べ、素数pで割った余りをx座標の候補にします。
- 4
曲線上の点になるまで繰り返す
x座標が曲線上に乗るまで、手順3を繰り返します。
Claudeが見つけた生成器のシードは、P-192が20000、prime239v1からv3が20420、20507、20509、prime192v2とv3が20512、20517です。再現コードは、この6曲線すべてで公開済みのx座標と一致する結果を返します。NISTの基底点の由来が説明されたのは、Anthropicの知る限りこれが初めてです。
暗号上の脆弱性ではない — どこまで言えるのか
ここで線を引いておきます。発見されたのは「シードがどう作られたか」であって、曲線の数学的な弱点ではありません。ECDSAの署名を偽造する新しい方法も、秘密鍵を割り出す新しい攻撃も出ていません。
では何が変わるのか。曲線が裏口なしに選ばれたという確信は強まります。シードはクロックで初期化した普通の疑似乱数生成器から出ており、誰でも再現できます。Anthropicは、これで細工の入り込む余地がずっと小さくなったと説明しています。
ただし、主張できる範囲は限られます。再現できたのは10個の素数曲線シードと4個のバイナリ曲線シードです。シードの作り方が再現できても、裏口が無いことを数学的に証明したことにはなりません。言えるのは、細工の入り込む余地が大きく狭まったところまでです。
NIST曲線を使うTLSや署名の設定、鍵管理の手順は、この発表で変える対象ではありません。研究者の多くは曲線をすでに信頼していた、とも書かれています。
残った謎
解けなかった部分も、Anthropicは明示しています。
飛ばされた候補は何を意味するか
20バイトの候補のすべてが曲線として成立するわけではありません。それでも、成立しうる曲線が飛ばされた例が見つかりました。P-256では、標準のシードは候補1842番ですが、同じ実行の候補876番も、位数が素数で、標準曲線と同じ作り方で得られる適切な大きさの曲線になります。P-224の実行では3つ、ANSI X9.62の例示曲線の2回の実行では合計7つが飛ばされていました。
どんな基準で選んだのか、意図しない偶然だったのかは分かりません。Anthropicの見立ては、飛ばされた数が少ないので、弱い曲線を選んだとは考えにくい、というものです。わずかな候補の中から弱い曲線を選べたのなら、弱い曲線がありふれていることになるからです。
別の可能性も否定されていません。タイムスタンプを変えながら乱数生成器を探索し、特定の性質を持つ曲線を選んだ可能性は理屈の上では残ります。ただ、そのやり方をする理由は、タイムスタンプを根拠として開示し、シードが無害に作られた証拠にしたい場合くらいです。実行が何回あったかは、数値からは分かりません。
説明のつかない部分
- B-163のシードは、Claudeが試した方法のどれにも合わず、未解明です
- P-224、P-256、P-384、P-521の基底点は、FreeLIPの手順に合わず、選ばれ方が説明できていません
- NISTのバイナリ曲線の基底点も、同じく説明がつきません
つまり今回の発見は、素数曲線10個とバイナリ曲線4個のシードの由来と、基底点の一部を埋めた段階です。謎の大半は解けましたが、すべてが閉じたわけではありません。
Claudeは文言ではなくソフトウェアの癖から逆算した
この発見の骨格は、人間が長年追った文言ではなく、ソフトウェアの動きから逆算した点にあります。古い生成器の癖を手がかりに、候補を絞り、格子問題で状態を復元し、巻き戻して日付を得て、再現コードで160ビットの一致を確かめる流れでした。
発表にはClaudeの内部の思考も引用されています。Claudeは当初、これは模擬環境かテストではないかと疑い、25年間解かれなかった謎がこれほど単純な理由で残っていたのかを疑っています。そのうえで、32ビットの種と小さな番号から160ビットが一致する事実を、10個のシードにわたって直接計算で確かめ、偶然ではないと結論づけました。確認を自分の計算で閉じる手順は、結果を信じてよい理由として、結論そのものと同じくらい重要です。
脆弱性の発見でClaudeが使われた例は、Claude Opus 4.6による500件超のゼロデイ発見や、スマートコントラクトの脆弱性発見実験にもあります。今回の対象は、脆弱性ではなく標準の来歴という歴史的な問いでした。同じ日に発表されたClaudeによる量子回路の設計も、楕円曲線の点加算を課題の1つにしています。この発表を出したFrontier Red Teamの役割は、Claudeのレッドチームがフロンティア脅威を追う理由で読めます。
まとめ
ECDSA標準曲線のシードは、冗談の合言葉のハッシュではなく、lrand48にUnix時刻を与えた出力でした。1990年代のNSAが使った道具は、今ならスクリプト数行で再現できるほど単純です。Claudeはこれを30分足らずで見つけています。
読者の実務は変わりません。変わったのは、曲線が裏口なしに選ばれたという見方を支える材料が1つ増えたことです。一方で、飛ばされた候補の基準、B-163のシード、4つの素数曲線とバイナリ曲線の基底点は説明がつかないままです。賞金の36,864ドルは、Internet Security Research Groupへ寄付されます。
この研究はJohn Wood氏、Henry de Valence氏、Ava Howell氏、Zack Voase氏、Lucy Sweet氏、Amir Omidi氏、Paul Crowley氏、Iain McGinniss氏、Nicholas Carlini氏、Steve Weis氏が実施しました。懸賞金を運営したFilippo Valsorda氏と、故Jerry Solinas氏にも謝辞が述べられています。