vatt'ghern jaskier's ballads

2026 年 10 月 15 日 UTC 凌晨 01 時 07 分 51 秒,有人領走了一筆懸了三年的賞金:NIST 橢圓曲線的種子,並不是某句英文的雜湊,而是 POSIX 的 drand48 亂數產生器,從 1997 到 1998 年間的某個時間戳吐出來的輸出。

NIST 曲線種子之謎收場

這套曲線的參數號稱可以從種子重算驗證,種子的來歷卻是個懸案:本該是一句英文的雜湊,那句英文已經遺失,當事人事後回憶的說法又證實是錯的。這個缺口留了二十多年,Filippo Valsorda 在 2023 年為它開出賞金,2026 年 10 月答案出現,和長年流傳的說法完全不同。

1997 2005 2010 2020 2025 五條質數曲線的種子產生 1997-05 至 1998-04 2000 · FIPS 186-2 曲線公開,稱 verifiably at random 2015 Koblitz 與 Menezes A riddle wrapped in an enigma 2023 · Solinas 過世 2023-10-05 賞金公告 12,288 美元 2026-10-15 賞金被領走 距種子產生約 29 年
空心圓是只知年份、不知月份的事件,所以按年份位置標在 2023 年,與賞金公告相鄰只是刻度造成的,兩者先後不明。「約 29 年」是 1997 年 5 月到 2026 年 10 月的算術差。

一串沒有人說得出來歷的 160 位元

NIST 的質數橢圓曲線 P-192、P-224、P-256、P-384、P-521,在 2000 年隨 FIPS 186-2 公開。三年前的賞金公告引述的說法是,這些曲線依 ANSI X9.62 產生,屬於「verifiably at random」。曲線的參數由一個種子經過公開的程序算出來,任何人都能照程序重算,確認參數出自這個種子。這個設計的用意,是讓設計者沒辦法為了私下的目的去調整曲線;這是我對機制的理解。

可驗證的只到種子為止。種子本身從哪裡來,程序沒有管。賞金公告列出了五個種子的十六進位值,每個都是 SHA-1 的輸出,P-256 的是 C49D360886E704936A6678E1139D26B7819F7E90。照 ANSI X9.62 的做法,這些種子本來該是對某個任意輸入做 SHA-1 的結果,那個輸入就是賞金要找的 pre-seed,一句英文。公告說的歷史是:種子由 NSA 提供,Jerry Solinas 在 1997 年生成,而原本的那些句子已經遺失。

於是出現一個結構上的缺口。曲線標榜可以驗證,驗證鏈的最上游卻是一個沒有人能出示的輸入。Anthropic 的文章補了另一段:2015 年 Koblitz 與 Menezes 發表〈A Riddle Wrapped in an Enigma〉時,Solinas 回憶的說法是,種子是一句幽默口令的雜湊。這句話後來證實是錯的。賞金公告與 Filippo 的文章都連到那篇論文,標題本身就說明,這個疑問早有人認真提過,也有人試著向當事人問出答案。

時間在這裡成了壓力。種子產生於 1997 到 1998 年,Solinas 在 2023 年過世,其他同事沒有回應詢問,這是 Anthropic 文章的交代。從 1997 年算到 2023 年,隔了約 26 年;能直接說出那句英文來歷的人,在賞金公告的同一年離開了。文章沒有給出過世的月份,所以上面的時間軸只把他標在年份上,與 10 月 5 日的公告誰先誰後並不清楚。

疑慮的形狀決定了後面的結果「解開」了什麼。疑慮是:不知道種子的來歷,就沒辦法排除有人在幾乎無限的可能種子裡挑了一個,讓曲線帶著只有挑選者知道的性質。文章的說法比較克制:Filippo 把這個謎團當作待解的歷史問題,沒有宣稱這些曲線有已知的弱點。

三年前的賞金:五個種子,一個條件

賞金公告的日期是 2023 年 10 月 5 日。Filippo 在文章裡把它稱為「the full bounty I announced three years ago」。公告頁面列的金額是 12,288 美元,寫成 12 Ki$,並註明是從 8,192 美元提高上來的。出資者除了 Filippo 本人,還有十一位具名的人,包括 Matt Green、Ryan Sleevi、Soatok 等;Filippo 個人保證全額兌付。

規則簡單。任務是找出五條質數曲線種子對應的英文 pre-seed。一半,也就是 6,144 美元,給第一位交出至少一個 pre-seed 的人;另一半給第一位交出全部五個的人。如果得主把獎金捐給美國的 501(c)(3) 慈善機構,金額會變成三倍,也就是 36,864 美元。這個數字等於 12,288 乘以三。公告還寫了一句對解法完全不設限的話:發現的方法不重要。

這個分成兩半的設計,讓只找出部分答案的人也能拿到一半獎金;這是我從條款結構做的讀法,公告沒有說明用意。條款要的是英文 pre-seed,答案卻是沒有 pre-seed。Filippo 的文章仍寫「claimed the full bounty」,全額付出,兩份材料沒有說明這個落差怎麼處理。

此後到 2026 年 10 月,賞金懸了三年。文章沒有交代這段時間有哪些人試過、用什麼方法試過,所以我也不寫。可以確定的只有兩端:2023 年 10 月 5 日公告,2026 年 10 月 15 日 UTC 01 時 07 分 51 秒有人領走。這個時間戳是文章給的,精確到秒。

不帶提示,不到半小時

解法來自 Anthropic。Filippo 的文章用了「solved the riddle」連到 Anthropic 的研究頁面,並說領獎的是 Anthropic 的團隊。他們選擇把獎金捐給 ISRG,也就是營運 Let's Encrypt 的非營利組織,Filippo 的文字是「tripling its value to $36,864」,三倍之後是 36,864 美元,他也寫成 36 Ki$。

Anthropic 的文章交代了過程。2026 年 10 月,一位員工請內部的研究模型在不給提示的情況下,推導這些種子是怎麼產生的。這裡的「提示」指的就是 Solinas 那個「幽默口令的雜湊」的說法。按他們的說法,模型在不到半小時內找到了出處。這是 Anthropic 自己的敘述,沒有第二個來源可以交叉比對,下面的細節也都出自這篇文章。

推理的起點是一個猜測:種子可能來自 1990 年代 C 函式庫附帶的弱亂數產生器,因為這類產生器的輸出有辦法被辨認出來。於是模型逐位元掃描每個種子,找連續輸出像是這類產生器的跡象,涵蓋 34 種「產生器與切片方式」的組合。突破口是一個統計上的異常:把種子寫成五個 32 位元字,十個種子裡有四個,其 20 個字的最高位元全是 0。他們給的機率是約 1/5,810,推導這裡不重現。

這個樣態對上了 lrand48。lrand48 只回傳 48 位元內部狀態的高 31 位元,所以輸出的最高位元永遠是 0。48 位元的狀態只露出 31 位元,對這四個種子,隱藏的位元就剩 17 個(48 減 31),窮舉 2 的 17 次方,也就是 131,072 種可能,再檢查後續的字是否吻合,就能還原內部狀態。對其餘的質數曲線種子,每次輸出保留的位元更少,他們說它們取的是 lrand48 輸出右移 23 位的結果。這時窮舉不夠用,模型改用 LLL 格基約化還原狀態,由於不知道狀態的哪些位元會出現在種子裡,求解器對每個視窗都跑了一遍。最後把還原的狀態倒推回 srand48 會產生的樣子,其中低 16 位元是 0x330E。

到這一步,種子的來源有了具體的時間。五條質數曲線的 srand48 輸入都是時間戳,全部落在 1997 年 5 月到 1998 年 4 月之間。最早的是 P-192,1997 年 5 月 18 日;最晚的是 P-224,1998 年 4 月 3 日,兩者相隔不到 11 個月;中間依序是 P-521(8 月 8 日)、P-256(8 月 16 日)、P-384(8 月 30 日)。下面的長條圖畫的是該文章列出的括號數字,也就是每條曲線採用的候選編號。

各曲線採用的候選編號(線性刻度,依種子產生日期排序) P-192 1997-05-18 139 P-521 1997-08-08 1,136 P-256 1997-08-16 1,842 綠線 876:也是有效曲線,但沒被採用 P-384 1997-08-30 2,688 P-224 1998-04-03 7,026
數字來自 Anthropic 的文章,括號中的「candidates」。綠線的 876 來自同一篇文章的例子:P-256 採用候選 1,842,但候選 876 同樣得到有效曲線,作者不知道為什麼沒選它。

依日期排序,採用的候選編號也依序變大:139、1,136、1,842、2,688、7,026,最晚的 P-224 約是最早的 P-192 的 50 倍(7,026 除以 139 約 50.5)。文章沒有說這個順序有沒有因果關係,這裡只列出觀察。

驗證的部分,Anthropic 講得很明確。每個還原出的 48 位元狀態,都能重新產生對應種子的全部 160 位元,作者認為這不可能是巧合。他們公開了重現程式碼,輸出和已公布的種子一致。Filippo 的文章則寫道,他自己用 Go 重新實作了這個演算法,目的是驗證這個說法,程式碼放在 GitHub 的 mostly-harmless 倉庫(seeds.go)。他的文章建立在 Anthropic 團隊的成果上,這個實作因此不算獨立的第二方佐證。

文章對這個結果的整體說法是:「we now know they were instead generated with the POSIX-standard drand48 random number generator」。這句話裡的「instead」承接的就是長年的口耳相傳,種子是某句話的雜湊。結論是它們不是。

時間戳怎麼變成曲線

知道來源之後,剩下的是機制。解題的方向是從種子倒推到時間戳,種子的產生方向則相反。根據兩篇文章的描述,正向的流程是這樣:拿一個 Unix 時間戳去給 drand48 當起點,吐出 20 位元組的候選種子,再把候選種子送進 ANSI X9.62 的流程;只有能產出有效曲線的候選才會被留下。有些時間戳不只產出一條曲線,因為程序在第一個被接受的種子之後可以繼續往下走。下面的圖把這條路徑畫出來,注意「否」的那條回頭箭頭:它說明為什麼每條曲線都附著一個候選編號。

Unix 時間戳 1997 至 1998 年 srand48 的輸入 drand48 POSIX 亂數產生器 候選種子 20 位元組 共 160 位元 ANSI X9.62 標準條件 另有兩條 未文件化條件 有效曲線? 全部通過才算 否:換下一個候選 是:該候選成為曲線的種子,例如 P-192 試到第 139 個、P-224 試到第 7,026 個 文章指出:有些時間戳在第一個被接受的種子之後繼續往下走,產出了不只一條曲線
第 4 個方塊裡的「兩條未文件化條件」出自 Filippo 的文章,下一段解釋。「換下一個候選」以及把候選編號當成試到第幾個,是我根據該文章中「candidate 1,842」「candidate 876」這類說法所作的讀法,兩份來源沒有逐字描述迴圈。

兩條「未文件化條件」是這個流程裡最有意思的部分。Filippo 的原話是:「There are two additional undocumented criteria beyond the ANSI X9.62 ones, one fairly clear and one that still escapes us」。按 Filippo 的描述,比較清楚的一條是:曲線的階 n 的位元長度超過基礎域 p 的位元長度時,種子會被拒絕;另一條至今沒有人弄懂。換句話說,重算出已公布種子的程序,比標準裡寫的多了兩道篩選,而其中一道,作者群還說不出它在篩什麼。

不明白的那道篩選,直接造成上圖的那個奇怪現象:P-256 採用了候選 1,842,但候選 876 也能得到有效曲線。如果有人要質疑「為什麼偏偏是這個」,876 就是他手邊最具體的證據。Anthropic 的文章直接承認不知道原因。這個細節的分量在於:已公布的種子並不是時間戳之後第一個能用的候選,所以選取的規則至少有一部分還不在已知的條件裡。這是我從 876 與 1,842 並存所做的讀法,文章只陳述了兩個編號。

二元域曲線(B 曲線)走了不同的路。Anthropic 的文章說,B 曲線的時間戳直接讀起來是 1984 年 2 月;把數字加倍,得到的是 1998 年 4 月 17 日,比 P-224 的時間戳晚兩個星期。作者因此提出一個假說:產生種子的程式可能把時鐘值減半了。他們明確標示這是假說。依他們的整理,B-233、B-283、B-409、B-571 都是在 1998 年 4 月 17 日前後產生的。Filippo 的文章補了一筆,他們也找出了這些 B 曲線種子的產生方式,但這些曲線很少被使用。B-163 的種子則和所有試過的方法都對不上,仍是未解。

還有基點的問題。曲線除了種子,還有一個基點。該文章寫道,P-192,以及五條 ANSI X9.62 範例曲線(prime192v2、prime192v3、prime239v1 到 v3),它們的基點來自 FreeLIP 這個函式庫的亂數產生器,產生器種子分別是 20000、20420、20507、20509、20512、20517,程式碼能重現六組已公布的 Gx。其他曲線,包括 P-224、P-256、P-384、P-521 與 NIST 的二元曲線,基點怎麼來的,仍未解釋。解開的只有種子,曲線的每一個參數並未全部解釋。

結案之後:能證明的,與不能證明的

Filippo 對安全面的說法是:「even before this discovery there were no serious concerns among practitioners」,也就是從業者之間早就沒有嚴重的疑慮。他算的自由度是這樣:假設 NSA 可以任選 1997 到 1998 年間的任何時間戳,以及前 16 個質數階候選中的任何一個(他說這個假設已經寬鬆地涵蓋了無法解釋的拒絕),結果是「they would have had barely 30 bits of freedom」。對照之下,Bernstein 與 Lange 在 2017 年向 Koblitz 與 Menezes 描述的技術,是「a technique that could have exploited 70 bits of freedom in selection of the seed」。這個 30 位元是在寬鬆假設下的上限,我的讀法是「they」指挑選種子的那一方。

為什麼位元數重要,這是一般性的推理,不屬於任何來源。想讓曲線帶有某種稀有的特殊性質,挑選者要靠嘗試很多個種子,直到撞上一個。可嘗試的種子數是 2 的 n 次方,n 就是自由度的位元數。30 位元代表大約十億種選擇,70 位元代表大約 1.2 乘以 10 的 21 次方種。兩者相差 2 的 40 次方倍。下面的滑桿讓你自己拖到不同的位元數,看選擇空間怎麼爆炸。

拖曳滑桿,看 n 位元自由度對應多少種可嘗試的種子 · 0 到 80 位元

自由度 30 位元
30 位元 文章:barely 30 bits 70 位元 文章:70 bits of freedom 0 10 20 30 40 50 60 70 80 目前 30 位元

30 位元 = 2^30 = 1,073,741,824 種組合。70 位元 = 2^70 = 1,180,591,620,717,411,303,424 種,是 30 位元的 2^40 = 1,099,511,627,776 倍。

30 與 70 這兩個位元數來自 Filippo 的文章,組合數是 2 的冪次的算術。「自由度」在這裡解讀成可嘗試的獨立種子數取 2 為底的對數,這是我的簡化,文章沒有給出這個定義。

預設停在 30 位元,約十億種選擇。這個量級的直觀含義是:十億種嘗試對現代電腦不算大,但要在十億個種子裡找到某種「十億分之一」等級稀有的性質,已經是碰運氣的邊緣,更別說比這更稀有的性質。拖到 70 位元,空間就從十億個擴大到十的二十一次方個,這是 Bernstein 與 Lange 那種技術假設的規模。我的推論是:若自由度只有約 30 位元,那個需要 70 位元的技術就用不上。

Anthropic 的文章給了同方向、語氣更保守的說法。作者表示,這不是密碼學上的破解,也不是發現了弱點;他們寫的是「This is not a cryptographic break, new attack, or weakness in the ECDSA curves」,並把種子描述為以簡單、可重現的程序產生。他們也寫了「In fact, this makes us more confident the curves were chosen without any backdoors or intentional weaknesses」,並說這些發現讓後門的說法「much less plausible」。這是 Anthropic 自己的判斷,強度低於證明,下表照這個強度標示。

說法現在的狀態依據(誰說的)
種子是某句英文的雜湊被推翻Filippo:它們是用 POSIX 的 drand48 產生的;Anthropic:Solinas 回憶的說法錯了
種子的產生程序可以被重現已重現Anthropic 公開的重現程式碼輸出與已公布種子一致;Filippo 用 Go 重新實作以驗證,但他的文章建立在 Anthropic 的成果上,不算獨立佐證
曲線藏有後門未被證明不存在,但可能性下降Anthropic:不是 break 或 weakness,程序簡單可重現(Anthropic:much less plausible);Filippo:實際自由度約 30 位元
曲線在密碼學上有弱點兩份來源都未報告弱點Anthropic:不是 break 或 weakness;Filippo:此前沒有嚴重疑慮
所有生成細節都已解釋沒有Filippo:一條未文件化條件仍不明;Anthropic:多數基點、B-163 種子、被略過的候選都未解
為什麼選這幾個時間戳兩份來源都未交代我讀到的材料沒有討論;不推測

表裡第一列推翻的是 Solinas 的回憶,與 NIST 或 NSA 的任何正式聲明無關;賞金公告只說原句已經遺失。第三列的「可能性下降」複述 Anthropic 的措辭,強度不能再往上調。以上只依據 Filippo 的文章、他連到的賞金公告與 Anthropic 的研究頁面;他文中連到的 Steve Weis 文章、2015 年的論文與 Go 程式碼沒有打開。

把這些收攏,有三句話可以直接說。種子是 drand48 加上 1997 到 1998 年間的時間戳,Anthropic 的重現程式碼對得上已公布的種子;若有人想在種子上動手腳,Filippo 在寬鬆假設下算出的自由度約 30 位元,遠小於 Bernstein 與 Lange 的技術所需的 70 位元;仍待解釋的,包括那條沒人讀懂的篩選條件、像候選 876 這樣有效卻沒採用的種子、其餘曲線的基點、B-163 的種子,以及為什麼選了這些時間戳。

If asked:有人問 P-256 或 NIST 曲線能不能繼續用,我的讀法是照上面三句回答,不要多說也不要少說:不要說這證明整條曲線沒有後門,也不要說已經沒有任何未解之處。Filippo 在文章裡寫道,這「nicely completes the 『rehabilitation arc』 of NIST elliptic curve cryptography」,並說他現在會個人推薦 NIST 曲線勝過 Curve25519、Ed25519、X25519,這是他在 2026 年 10 月的個人判斷。兩份材料都沒有建議因此遷移,這是我讀這兩份材料的結果,不是他們的明文結論。