Claude Traces NIST's ECDSA Curve Seeds to lrand48 and 1997 Timestamps, Winning $36,864 Bounty
TL;DR
On October 16 Anthropic's Frontier Red Team published the answer to a question cryptographers have poked at since 2000: where did the NSA get the seed values behind the NIST elliptic curves in FIPS 186-2? The lore said Jerry Solinas hashed a joke passphrase, and the lore was wrong. An internal Claude research model, asked cold and without the passphrase hint, worked out in under half an hour that all five prime-curve seeds (P-192, P-224, P-256, P-384, P-521) are output from the C library's lrand48 generator, seeded with the Unix clock on dates between May 1997 and April 1998. Filippo Valsorda reimplemented the recipe in Go, confirmed every seed, and paid out the $36,864 charity-rate bounty to the Internet Security Research Group. Nothing is broken. The seeds came from a procedure so plain that there was almost no room to hide anything in it.
The mystery, in one paragraph
ECDSA curves are defined by a coefficient b that is derived from a published 160-bit seed via SHA-1, per ANSI X9.62. The NSA handed NIST the seeds in the late 1990s with no explanation. After the Dual_EC_DRBG affair, "unexplained constants from the NSA" became a genre of its own, and Koblitz and Menezes wrote a whole paper, "A Riddle Wrapped in an Enigma," on whether the curves could have been cooked. The best lead came from Solinas himself, who in 2015 recalled a counter plus a phrase "along the lines of 'Give Bob and Jerry a raise'" and added that any archives were "no doubt sitting on a hard drive near the Ark of the Covenant." Steve Weis chased it with FOIA requests; NIST had no records. Solinas died in 2023, and that October Valsorda posted a bounty: $12,288 in cash, tripled to $36,864 if the winner sent it to a charity. The bounty page listed roughly 12,000 candidate hashes to compare against. Nothing ever matched, because there was no passphrase.
What Claude actually found
The generating program called srand48(time), then pulled 20-byte candidates off lrand48() one after another, keeping only the top eight bits of each 31-bit output (lrand48() >> 23) and trying each candidate as an X9.62 seed until one produced an acceptable curve. P-256's seed is candidate 1,842 of a run started at 01:52:34 UTC on August 16, 1997. P-224 needed 7,026 candidates. Five more seeds from the ANSI X9.62 example curves (prime192v2, prime192v3, prime239v1 to v3) fall out of the same runs. The four binary-field seeds, B-233 through B-571, fit the same generator with the full 31-bit outputs kept, except that the recovered timestamps read as February 1984 until you double them, at which point all four land on the afternoon of April 17, 1998, two weeks after the P-224 run. Someone's program was apparently halving the clock.
The code to regenerate all fourteen seeds is about thirty lines of Python, published on the Anthropic page under CC0. The core step is one line:
x = (0x5DEECE66D * x + 0xB) % 2**48 # one step of lrand48
# state after srand48(t) is (t << 16) | 0x330E
A note on naming: Anthropic's writeup says lrand48, Valsorda's says drand48. They are the same POSIX 48-bit generator behind different return types, so the discrepancy is cosmetic.
How Claude found it
Nobody was looking for a weak PRNG because the story everyone had been told was about a hash. Claude ignored the story and asked a different question: what would 1990s curve-generation software plausibly have done? Old C library generators leak structure, so it wrote a scanner that slid along each published seed one bit at a time and tested whether adjacent chunks looked like consecutive outputs from any of 34 generator-and-slice combinations.
The tell was in the top bits. Written as five 32-bit words, four of the ten seeds had a zero in the top bit of every word, which happens by chance with probability about 1 in 5,810 and is exactly what lrand48 produces, since it returns only the top 31 bits of a 48-bit state. For those four seeds, recovering the state meant brute-forcing the 17 hidden bits (217 guesses) and checking that the next four words followed. They did.
The prime-curve seeds kept fewer bits per output, so brute force was off the table. Recovering the internal state of a truncated linear congruential generator from partial outputs is a textbook lattice problem, and Claude solved it with the LLL basis-reduction algorithm, run over every possible bit window because it did not know in advance which slice of the state the seeds exposed. If you want the picture: imagine an odometer that advances by a fixed, known rule each tick, and you are shown only the leading digits of a handful of readings. Lattice reduction is the trick that finds the one starting mileage consistent with all of them at once. Each recovered 48-bit state regenerated all 160 bits of its seed, which does not happen by accident, ten times over.
The generator runs backwards as easily as forwards, so the last move was stepping each state back until it hit the shape srand48 produces (low 16 bits equal to 0x330E). That shape recurs every 65,536 steps, so on its own it proves nothing. What proves it is that every one of the ten prime-curve initializations decoded to a plausible 1997-98 date.
Anthropic also published a slice of the model's reasoning at the moment it landed, and it is the best part of the writeup: "Hmm wait. Let me be skeptical: am I in some sort of simulated/test environment? ... All top bits clear, 20 bits, chance 1e-6. So indeed real-world. Wow, it's a real discovery." A model checking whether it is being evaluated before it allows itself to be impressed is a very 2026 kind of humility.
Independent verification
Valsorda received the submission on October 15 at 01:07:51 UTC from ten Anthropic researchers (John Wood, Henry de Valence, Ava Howell, Zack Voase, Lucy Sweet, Amir Omidi, Paul Crowley, Iain McGinniss, Nicholas Carlini and Steve Weis), rewrote the algorithm from scratch in Go, and reproduced all five NIST prime-curve seeds plus the ANSI ones. The team took the charity option, so the $36,864 goes to ISRG, the nonprofit behind Let's Encrypt. Anthropic's own Python reproduces all fourteen seeds in seconds.
The base points too
Each curve also ships a base point G, which the seed does not determine. While checking the seeds, Claude found that the base points for the six curves generated in May 1997 (P-192 and the five ANSI example curves) come from the random number generator in FreeLIP, Arjen Lenstra's long-integer package, which early versions of Victor Shoup's NTL also shipped. The recipe: seed with a small integer (20000 for P-192; 20420, 20507, 20509 for prime239v1 to v3; 20512 and 20517 for prime192v2 and v3), discard seven outputs, then draw 26-bit candidate x-coordinates mod p until one lands on the curve. Anthropic says no NIST base point had been explained before. The base points for P-224, P-256, P-384 and P-521 do not fit this recipe and remain open.
What it means for the curves you use
Anthropic's line is blunt: "This is not a cryptographic break, new attack, or weakness in the ECDSA curves," and there is nothing to rotate. Valsorda goes further on the security argument. The scenario Bernstein and Lange described in 2017, where an attacker with roughly 70 bits of freedom in choosing a seed could land on a hypothetical class of 261 weak curves, is now dead: a clock value plus a candidate counter gives the NSA "barely 30 bits of freedom" even on generous assumptions, far too little to steer toward a weak curve or a NOBUS backdoor. He now says he would personally recommend the NIST curves over Curve25519, Ed25519 and X25519, with the caveat that post-quantum signatures may retire all of them soon anyway.
Thomas Ptacek's summary on Hacker News: "This is devastating news... for an entire generation of NIST cryptography conspiracy theories." He also noted what Koblitz and Menezes argued a decade ago, that nobody conversant in the field believed the seed-backdoor story in the first place. The Bitcoin angle is a footnote: secp256k1 never had a seed to worry about, and the finding changes nothing for it.
What is still unexplained
- Skipped candidates. For P-256, candidate 876 of the same run also yields a prime-order curve of the right size, yet the published seed is candidate 1,842. P-224's run passed over three such curves, and the two ANSI runs passed over seven more. Valsorda counts roughly twice as many valid seeds as were published. One extra filter is clear (reject the seed if the bit length of the curve order exceeds that of the field prime); a second criterion is still unknown, and so is whether the gaps are a rule or a 1997 bug.
- B-163. The fifth binary-curve seed fits nothing Claude tried.
- Four base points. P-224, P-256, P-384 and P-521's generators, plus all the NIST binary curves', have no recovered recipe.
Anthropic reads the skipped candidates as evidence against a weakened-curve selection: if a handful of skips were enough to find a weak curve, weak curves would have to be common, and they are not. The one caveat left is that nothing in the numbers reveals how many separate runs were tried before these dates.
Why a builder should care
Two lessons travel beyond cryptography. First, the method: when a search on the received narrative keeps failing, model the artifact's production process instead. Claude asked what a 1997 C program would do, and 1997 C programs seed rand48 with time(). Second, a time-seeded LCG leaks its entire state from a few partial outputs, and the tooling to recover it is a short script and an off-the-shelf LLL. If anything in your stack still derives a secret from a clock-seeded libc generator, that is the finding to act on today.
Key Takeaways
- The NIST P-192, P-224, P-256, P-384 and P-521 seeds are
lrand48() >> 23output fromsrand48(time)runs on six dates between May 15, 1997 and April 3, 1998; the four published binary-curve seeds come from April 17, 1998 with the clock halved. - An internal Claude research model found this in under half an hour by scanning for weak-PRNG signatures across 34 generator variants, then recovering the state via a 217 search and LLL lattice reduction.
- Filippo Valsorda independently reimplemented the recipe in Go and paid the $36,864 bounty, which Anthropic's team directed to the Internet Security Research Group.
- It is not a break. The result shrinks the NSA's possible seed-selection freedom to about 30 bits, which rules out the Bernstein-Lange weak-curve scenario; Valsorda now rates the NIST curves above Curve25519.
- Open threads remain: roughly half the valid candidates in each run were skipped for a reason nobody has recovered, the B-163 seed is unexplained, and four NIST base points still have no known origin.
- Reproduction code is CC0 on the Anthropic page; the whole derivation runs in seconds.
Sources: Anthropic, "Claude reveals ECDSA curve origins", Filippo Valsorda, "The NIST Elliptic Curves Seeds Bounty Has Been Claimed", Filippo Valsorda, bounty announcement (2023), Valsorda's Go reimplementation, Steve Weis, "How were the NIST ECDSA curve parameters generated?", Koblitz and Menezes, "A Riddle Wrapped in an Enigma", Hacker News discussion, CoinDesk