hex

34.5. Proving the secp256k1, P-384 and Curve448 field primes🔗

The field primes for secp256k1, P-384 and Curve448 have short formulas but hundreds of bits. Hex can discover primality certificates for all three and prove them in Lean. You supply the number, and the tactic finds the factors and recursively proves the smaller primality statements it needs.

34.5.1. Start here🔗

Use a checkout of the hex-dev repository. The ECM provider is part of HexIntFactor, which is not yet included in the published split libraries. Start a Lean file with these imports:

import HexIntFactor

The examples use Hex.Nat.Prime, so they need no Mathlib import. To state the same goals with Nat.Prime, also import HexPrimalityMathlib. The same tactic syntax then applies.

Put the examples in a section with local options:

section set_option maxHeartbeats 4000000

The finite heartbeat allowance accommodates certificate construction. All three examples pass with this option alone; it is a tested allowance, not a measured minimum. It does not increase the factor search's shared 1024-attempt budget. Lean 4.34.0 may warn that the powers with exponents 384 and 448 exceed its shortcut threshold of 256. The goals still normalize and the proofs succeed; these examples leave that warning visible.

34.5.2. Three proofs🔗

The secp256k1 field prime is 2^256 - 2^32 - 977:

example : Hex.Nat.Prime (2 ^ 256 - 2 ^ 32 - 977) := by
  primality?

The P-384 field prime is 2^384 - 2^128 - 2^96 + 2^32 - 1:

example : Hex.Nat.Prime
    (2 ^ 384 - 2 ^ 128 - 2 ^ 96 + 2 ^ 32 - 1) := by
  primality?

The Curve448 field prime is 2^448 - 2^224 - 1:

example : Hex.Nat.Prime (2 ^ 448 - 2 ^ 224 - 1) := by
  primality?

Close the section after the examples:

end

Each proof produces a Try this: suggestion containing a complete certificate. Apply the suggestion to replace the search with a proof that replays that certificate. This is particularly useful when sharing a file: other people can check the proof without repeating the factor search.

The standard import makes bounded ECM available automatically. Construction first tries HexPrimality's own methods. If they exhaust with attempts left, it retries with ECM, carrying forward the random state and charging both routes to the same allowance. P-521 and Curve25519 finish on the first route. You do not need to supply factors, curve parameters, seeds or certificates. The expert override primality? (factor := Hex.Nat.ecmFactorSearch) selects that provider directly and bypasses automatic selection. To retain the core-only route, including its faster exhaustion on some unsupported inputs, use primality? (factor := Hex.Nat.Construction.factorSearch). Automatic retry can add substantial work even when it ultimately fails: the tested 507-bit fixture increased from about 0.9 seconds to 20.7 seconds.

If Lean reports a heartbeat limit, include the local option from the setup. A message saying that certificate construction exhausted its attempts instead refers to the factor search budget and identifies the unresolved subject. The factor-search reference describes the optional bounds, curve count and tracing arguments.

Build note: the three construction examples and their exact Try this: suggestions are checked in the field construction tests. Run lake build HexIntFactorFieldConformance to check them together. The manual build checks the saved proof below without repeating the searches.

34.5.3. What the saved proof looks like🔗

Here is a saved secp256k1 certificate in full, with abbreviated constructor names. This standalone proof needs only import HexPrimality.Cert and uses the numeral to avoid the options for normalizing powers:

example : Hex.Nat.Prime 115792089237316195423570985008687907853269984665640564039457584007908834671663 := ⊢ Hex.Nat.Prime 115792089237316195423570985008687907853269984665640564039457584007908834671663 exact Hex.Nat.prime_of_checkPrimeAt (c := .pock 115792089237316195423570985008687907853269984665640564039457584007908834671663 [(2, 0, .pock 205115282021455665897114700593932402728804164701536103180137503955397371 [(2, 0, .pock3 255515944373312847190720520512484175977 185873736969223 6447496504 185873736969222 [(3, 2, .small 2), (2, 0, .small 4423), (2, 0, .small 41201), (2, 0, .small 96557)])])]) (⊢ ((Hex.Nat.PrimeCert.pock 115792089237316195423570985008687907853269984665640564039457584007908834671663 [(2, 0, Hex.Nat.PrimeCert.pock 205115282021455665897114700593932402728804164701536103180137503955397371 [(2, 0, Hex.Nat.PrimeCert.pock3 255515944373312847190720520512484175977 185873736969223 6447496504 185873736969222 [(3, 2, Hex.Nat.PrimeCert.small 2), (2, 0, Hex.Nat.PrimeCert.small 4423), (2, 0, Hex.Nat.PrimeCert.small 41201), (2, 0, Hex.Nat.PrimeCert.small 96557)])])]).subject == 115792089237316195423570985008687907853269984665640564039457584007908834671663 && Hex.Nat.checkPrime (Hex.Nat.PrimeCert.pock 115792089237316195423570985008687907853269984665640564039457584007908834671663 [(2, 0, Hex.Nat.PrimeCert.pock 205115282021455665897114700593932402728804164701536103180137503955397371 [(2, 0, Hex.Nat.PrimeCert.pock3 255515944373312847190720520512484175977 185873736969223 6447496504 185873736969222 [(3, 2, Hex.Nat.PrimeCert.small 2), (2, 0, Hex.Nat.PrimeCert.small 4423), (2, 0, Hex.Nat.PrimeCert.small 41201), (2, 0, Hex.Nat.PrimeCert.small 96557)])])])) = true All goals completed! 🐙)

The kernel checks the certificate through Hex.Nat.prime_of_checkPrimeAt. The search is untrusted: finding a factor is not enough to establish primality, and every necessary recursive certificate must pass the same checker. The complete saved certificates also include P-384 and Curve448.

34.5.4. How long does it take?🔗

Allow a few minutes to try all three searches in Lean. Construction and its factor provider run natively during elaboration; the complete module build also includes imports, certificate rendering and kernel checking.

The recorded shared-host automatic-construction medians were 26.0 seconds for secp256k1, 32.2 seconds for P-384, and 21.6 seconds for Curve448. Direct kernel replay medians were about 3.6–11.8 milliseconds per proof, excluding imports and elaboration. These are host-specific observations, not time limits or guarantees. See the automatic construction report for separate construction, rendering, kernel and caller-resource measurements, and the ECM construction report for the explicit-provider experiments.

The native search is synchronous. Lean can report a heartbeat overrun only after that computation returns; the heartbeat allowance is not a wall-clock timeout. The finite attempt limit bounds the search schedule.

The search has a fixed, bounded schedule and can still exhaust on other primes. The primality construction reference explains reusable certificates and the available budget override.