Skip to content

Claude Reveals ECDSA Curve Origins: Run It Yourself

Claude reveals ECDSA curve origins were 1997 lrand48 timestamps, not secret phrases. Here's the code to reproduce P-256 and what it means for you.

5 min readIntermediate

Key takeaway: The b-seed for NIST P-256 is candidate 1842 from a plain 1990s lrand48 stream started with srand48 at 01:52:34 UTC on 16 August 1997. No passphrase. No clever hash. Anthropic’s internal Claude research model recovered that pattern for the NIST prime curves in under half an hour (announced 16 October 2026). You can reprint the FIPS hex on your laptop from their public-domain Python.

The seed that sets P-256’s b coefficient – the curve under a huge slice of TLS and certificates – is literally that clock-seeded loop counter. Backdoor panic got thinner because anyone can rerun the generator.

Two search spaces. Only one paid out.

For years the default hunt (call it Method A) assumed each 160-bit seed was SHA-1 of some English joke. Dictionaries, counters, staff-name variants – empty. Anthropic folks tried the same dead end.

Method B flips the question: what would a late-1990s NSA programmer actually type? Reverse the weak PRNG fingerprints in the published hex, don’t invent poetry.

Approach Assumption Outcome
Phrase hunt (A) Seed = hash(“funny sentence”) Years of failure
PRNG recovery (B) 1990s C lrand48 + clock Exact FIPS match once the generator is known

NIST shipped the curves in FIPS 186-2 (2000). The NSA handed over seeds with zero provenance; SHA-1(seed) produced coefficient b. That gap fed papers and a public bounty. Koblitz & Menezes (IACR ePrint 2015/1018) still framed the anxiety as “A Riddle Wrapped in an Enigma.” Receipts beat lore.

Claude’s scanner walked 34 generator/slice combos. Tell-tale: top bits cleared – the classic shape when lrand48 only exposes 31 of 48 state bits. State recovery (brute or LLL on the truncated LCG), then walk backward until the srand48 form shows up (low 16 bits 0x330E). Prime-curve hits landed on Unix timestamps from May 1997 through April 1998. Prime-curve pattern in the release: lrand48() >> 23 packing 20-byte candidates.

Pro tip: Wild crypto claim from an LLM? Demand the one-line reproduction first. Can’t regenerate the published hex yourself → treat it as unverified lore.

Reproduce P-256 in one snippet

Core of Anthropic’s public-domain generator, trimmed to the famous curve:

from datetime import datetime, timezone

def unix(when):
 return int(datetime.fromisoformat(when).replace(tzinfo=timezone.utc).timestamp())

def candidate(t, n, per=20, shift=40, width=2):
 x, out = (t << 16) | 0x330E, ""
 for i in range(per * n):
 x = (0x5DEECE66D * x + 0xB) % 2**48 # one lrand48 step
 if i >= per * (n - 1):
 out += "%0*X" % (width, x >> shift)
 return out

t = unix("1997-08-16 01:52:34")
print(candidate(t, 1842))
# C49D360886E704936A6678E1139D26B7819F7E90

Run it. Hex matches the seed printed in FIPS 186-2. Nudge the candidate index by one – match dies. That’s the control.

Independent re-runs line up character-for-character with the listed NIST prime seeds and four binary seeds; CellCog’s verification write-up is one public full-suite check. Same family of clock + counter, per Anthropic’s research post, also covers the other NIST primes and the ANSI X9.62 examples they examined.

Watching the numbers pop feels like finding the original Polaroid of a famous painting. Provenance goes boring. Boring is what you want for constants everyone else has to trust.

Three traps the headlines gloss

  • B-163 still blank. Fifth binary seed matches nothing in the tried set. Open.
  • Good curves got skipped. On the P-256 run, candidate 876 also yields a valid prime-order curve of the right size. P-224 skipped three; ANSI runs skipped seven more. Selection rule unknown. Small skip counts are why “they shopped a weak curve” is a hard sell – but it is still an honest gap.
  • Binary recovery needs a halve. Raw timestamp read lands in February 1984. Feed unix(when) // 2 and the published pairs sit on 17 April 1998 (two weeks after P-224). The release code does exactly that; miss the // 2 and you’ll “disprove” a correct write-up.

Base points for P-224, P-256, P-384, and P-521 stay unexplained. Six older ones (including P-192) trace to FreeLIP’s RNG with tiny seeds such as 20000 – also reproducible from the same Anthropic page.

Why keep staring at skip lists? If the clock-seeded LCG is this shallow, the interesting residual question isn’t “secret phrase,” it’s “who picked among several valid candidates, and with what test?” That selection story is still thin.

Filippo Valsorda’s $36,864 bounty (tripled via donation) went to the Anthropic team and on to ISRG / Let’s Encrypt. His Seeds Solved post is five minutes, tops.

When an LLM hands you an “open problem” win

Anthropic published Claude’s monologue: first “astonishing,” then “am I in a test use?”, then a check that a full 160-bit regenerate isn’t coincidence. Copy that loop – not the victory lap.

Gate every similar claim the same way: public code, third-party re-run, control that fails on purpose. Next drills: have a model sketch lattice recovery on truncated LCGs, or audit fresh “nothing-up-my-sleeve” constants before you ship them.

Bitcoin and Ethereum never sat on these NIST primes; they use secp256k1. No wallet migration. Nothing to patch on the curve math itself – the win is provenance, not a new attack surface.

FAQ

Is ECDSA or P-256 broken now?

No. Not a break, not a new weakness. The generator is simple and public, which makes a deliberate backdoor less plausible.

Can I trust the reproduction on my laptop?

Paste Anthropic’s Python. Aim at a known (timestamp, candidate) pair – P-256 is 1997-08-16 01:52:34 UTC × 1842. You want exact FIPS hex. Stop one candidate early on purpose; if output still matched, your script is wrong. Community suites already matched the published tables.

Why did phrase searches fail for decades while this finished in minutes?

Wrong search space. People (and old oral history) anchored on “hash of a joke.” Weak 1990s PRNG output is a different object: recognizable bit pattern, recoverable state, runnable backward to a clock. Turns out the mundane software fingerprint was enough. The useful habit isn’t genius – it’s refusing to accept a match until a failing control exists.

Open a terminal, run the P-256 snippet, screenshot the matching hex. Personal receipt: Claude reveals ECDSA curve origins weren’t magic – timestamp + old C LCG. Then try the FreeLIP base-point script on the same Anthropic page.