BuildRiot
Sign in

Article · AI

Five federal curve seeds reproduce exactly, but selection questions remain

Anthropic reports reproducing five prime-field curve seeds from the historical federal digital signature standard. Skipped candidates and unexplained parameter origins limit what those matches establish about security.

Five matching blue and ivory curve pairs receive paper ribbons from a red-draped archive, beside discarded candidates in a sunlit miniature coastal amphitheatre.
Illustration: BuildRiot (AI-generated)

Key takeaway

Reproducing public curve parameters does not recover signing keys or demonstrate an exploit. The findings establish no immediate patch or migration requirement and do not replace existing algorithm policy.

Five exact matches with a limited security meaning

Anthropic reports reproducing all five prime-field curve seeds from Federal Information Processing Standard 186-2. Anthropic and Filippo Valsorda say the discovery strengthens their confidence in the curves. That assessment does not prove every historical selection decision was benign. Sources: Anthropic, Filippo Valsorda, NIST

Anthropic published the timestamp and candidate inputs. The complete P-256 time is August 16, 1997, at 01:52:34 Coordinated Universal Time (UTC). The reported matches establish a reproducible route to the public seed bytes. They do not establish every historical selection decision or prove the absence of cryptographic backdoors. Sources: Anthropic

The reference values below are transcribed from the historical standard, rather than expected strings embedded in either published reproducer. The standard lists those seeds on printed pages 29–33. Its appendices separately describe deriving a curve from a seed and checking the relationship to the curve coefficient. Regenerating a seed therefore checks one link in a longer chain. The table below pairs each published input with its matching historical constant. Sources: Anthropic, NIST

Table

Five prime-field seed matches

CurveUTC inputOne-based candidateMatching hexadecimal seed
P-192May 18, 1997, 14:45:341393045AE6FC8422F64ED579528D38120EAE12196D5
P-224April 3, 1998, 12:52:077,026BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5
P-256August 16, 1997, 01:52:341,842C49D360886E704936A6678E1139D26B7819F7E90
P-384August 30, 1997, 14:50:082,688A335926AA319A27A1D00896A6773A4827ACDAC73
P-521August 8, 1997, 01:12:041,136D09E8800291CB85396CC6717393284AAA0DA64BA
Published timestamp and candidate inputs reproduce the seed strings in Federal Information Processing Standard 186-2.Sources: Anthropic, NIST

Reproduce the bytes with explicit indexing

The generator follows the 48-bit recurrence in Anthropic’s Python reproducer and Valsorda’s Go verifier. It initializes from a timestamp, advances the state and extracts the upper byte. Twenty successive bytes form one candidate. Numbering starts at one, and initialization emits no byte. Taking the upper byte also agrees with shifting the 31-bit lrand48 output another 23 bits. Sources: Anthropic, GitHub

Save the implementation below as reproduce.mjs. Its BigInt arithmetic avoids intermediate rounding. Its timestamps and candidate indices come from Anthropic. Sources: Anthropic

The JavaScript below is an unverified adaptation of the published generation procedure. Its assertions compare generated seeds with the historical constants; they do not test cryptographic security.

import { readFileSync } from "node:fs";
import assert from "node:assert/strict";
function candidate(iso, k, per=20, shift=40, width=2, divisor=1) {
  if (!Number.isInteger(k) || k < 1)
    throw Error("one-based index required");
  const t = BigInt(Math.floor(Date.parse(iso) / 1000 / divisor));
  let x = (t << 16n) | 0x330en;
  let out = "";
  for (let j = 0; j < per * k; j++) {
    x = (0x5deece66dn * x + 11n) & ((1n << 48n) - 1n);
    if (j >= per * (k - 1))
      out += (x >> BigInt(shift)).toString(16).padStart(width, "0");
  }
  return out.toUpperCase();
}
const cases = [
  ["P-192", "1997-05-18T14:45:34Z", 139],
  ["P-224", "1998-04-03T12:52:07Z", 7026],
  ["P-256", "1997-08-16T01:52:34Z", 1842],
  ["P-384", "1997-08-30T14:50:08Z", 2688],
  ["P-521", "1997-08-08T01:12:04Z", 1136],
];
// Independent reference file transcribed from FIPS, not either verifier.
const reference = new Map(
  readFileSync(process.argv[2], "utf8").trim().split(/\r?\n/)
    .map(line => {
      const [name, ...words] = line.trim().split(/\s+/);
      return [name, words.join("").toUpperCase()];
    })
);
for (const [name, iso, k] of cases) {
  const expected = reference.get(name);
  assert.match(expected ?? "", /^[0-9A-F]{40}$/);
  assert.equal(candidate(iso, k), expected);
}

Save the reference values below separately as fips-seeds.txt; they reproduce the historical standard’s seed constants. Keeping the reference input separate makes the comparison easier to inspect. The commands that follow record the local Node version, run the assertions and calculate checksums for a separately logged execution. Sources: NIST

P-192 3045ae6f c8422f64 ed579528 d38120ea e12196d5
P-224 bd713447 99d5c7fc dc45b59f a3b9ab8f 6a948bc5
P-256 c49d3608 86e70493 6a6678e1 139d26b7 819f7e90
P-384 a335926a a319a27a 1d00896a 6773a482 7acdac73
P-521 d09e8800 291cb853 96cc6717 393284aa a0da64ba
node --version
node reproduce.mjs fips-seeds.txt
sha256sum reproduce.mjs fips-seeds.txt

Skipped candidates leave selection questions

The published implementations answer different questions. Anthropic’s Python selects the final 20 bytes after advancing through the requested candidate. Valsorda’s Go program also derives curves and checks orders, using cached results or a computer algebra system. Its search stops after finding all embedded published seeds. Sources: Anthropic, GitHub

Valsorda reports four earlier acceptable candidates: P-256 candidate 876 and P-224 candidates 777, 1,485 and 5,736. Random-number-generator consumption during validation and implementation bugs are proposed explanations for these skipped candidates, not established causes. A fuller audit should record each seed, derived coefficient, chosen square root, order and rejection reason. Sources: Filippo Valsorda

Requiring the order’s bit length to fit within the field modulus’s bit length differs from requiring a smaller order. Valsorda identifies prime239v2 as having an order above its field modulus but below two to the power of 239. The Go verifier also uses an embedding-degree threshold stricter than the historical X9.62 threshold described in its comments. Acceptance rules therefore need examination alongside the generator. Sources: Filippo Valsorda, GitHub

A conditional selection bound

Valsorda’s selection argument considers every second in 1997–98 and the first 16 prime-order candidates per initialization. The table below gives the article’s arithmetic for those assumptions. It also includes an editorial hypothetical with a wider initialization range. Sources: Filippo Valsorda

This counts choices within a fixed generation setup. It measures neither P-256’s security level nor attack cost. The stopping allowance concerns acceptable candidates, so P-224’s selection at raw candidate 7,026 does not contradict it. Sources: Anthropic, Filippo Valsorda

Table

Assumptions behind the selection-freedom count

AssumptionCalculated countInterpretation
Every second in 1997–9863,072,000 timestamp choicesA wider range changes the count
First 16 prime-order candidates1,009,152,000 combined choicesAcceptable candidates, not raw blocks
Fixed setup with those boundsApproximately 29.9 selection bitsDoes not measure attack cost
Editorial hypothetical: every 32-bit initialization value36 bits with 16 candidate choicesAlternative assumption, not historical evidence
Counts are the article’s arithmetic from stated assumptions. The final row is an editorial hypothetical, not Valsorda’s calculation or historical evidence.Source: Filippo Valsorda

Unknown run counts add no choices beyond an exhaustively counted timestamp range with a fixed stopping rule. They matter because matching an output does not establish that historical operators respected those bounds. Counting trials also requires an estimate of the targeted weakness’s frequency before it can bound the chance of finding one. Valsorda addresses a specific hypothetical weak-curve selection technique; his argument should not become a claim covering every cryptographic backdoor. Sources: Filippo Valsorda

Base points and binary seeds leave provenance gaps

Anthropic reports a FreeLIP-generator recipe reproducing the P-192 base-point x-coordinate and five example x-coordinates from an American National Standards Institute standard. Its displayed verifier compares those coordinates, which alone does not document the choice between two possible y-coordinates. The other four federal prime-curve base points and the binary-curve base points remain unexplained in Anthropic’s account. Sources: Anthropic

Anthropic’s tentative binary-seed interpretation uses half the proposed Unix timestamp and five 31-bit outputs, each encoded as an eight-digit hexadecimal word. Anthropic displays outputs for B-233, B-283, B-409 and B-571. The proposed recipe does not explain why a historical program would halve a clock value. B-163’s seed also remains unexplained. Sources: Anthropic

Valsorda organized the bounty, placing his analysis within that process. An outside assessment should examine whether the timestamp window and stopping allowance adequately bound selection freedom. It should also consider whether skipped candidates suggest additional freedom. Unexplained base points deserve separate scrutiny from reproduced curve seeds. Sources: Filippo Valsorda

Audit provenance while retaining algorithm policy

These results reveal no new operational exploit and establish no immediate patch, key-rotation or migration requirement. Recovering a public parameter’s generation recipe is distinct from recovering a secret signing key. Developers can examine the provenance evidence without treating it as a substitute for implementation review.

For a fuller reproduction, archive the Python source and a Go verifier pinned to a specific commit, then record runtime and computer algebra versions. Recompute orders without the supplied cache and log CPU, elapsed time, cache status and rejection reasons. Keep existing algorithm policy in place: the National Institute of Standards and Technology deprecated binary-field curves in 2023 and strongly recommended other prime curves. Reproducing a binary seed provides no basis for reversing that guidance. Sources: NIST

Attribution

Sources

  1. 1AnthropicClaude reveals ECDSA curve origins
  2. 2Filippo ValsordaThe NIST Elliptic Curves Seeds Bounty Has Been Claimed
  3. 3NISTFIPS 186-2, Digital Signature Standard
  4. 4GitHubmostly-harmless/seeds/seeds.go
  5. 5NISTNIST releases FIPS 186-5 and SP 800-186

Read the original source for full details and context.

Report a problem

Links, dates or what you expected. Do not include passwords or private data.

More on AI

All AI stories