Skip to content

Cache P-256 curve parameters per thread in p256_verify_impl - #2525

Merged
khordadi merged 1 commit into
mainfrom
amir/p256-curve-params
Aug 28, 2026
Merged

Cache P-256 curve parameters per thread in p256_verify_impl#2525
khordadi merged 1 commit into
mainfrom
amir/p256-curve-params

Conversation

@khordadi

Copy link
Copy Markdown
Contributor

Fixes #1646.

  • Cache the secp256r1 curve parameters per thread. DL_GroupParameters_EC<ECP> was constructed on every call; it now lives in a function-local thread_local. Not a shared global: Crypto++'s ECP writes mutable scratch state under Add/Multiply, so one object shared across execution threads would be a data race. This matches the thread_local secp256k1_context pattern in ecrecover_impl.
  • Check the (0, 0) infinity public key before the curve equation. Both orders reject identically — (0, 0) is not on the curve since b ≠ 0 for P-256 — so the cheap check runs first.

The issue's remaining suggestion (constexpr empty_result) was already resolved by the zkvm precompiles refactor (1ce42ff).

No consensus-visible behavior change; all 19 p256_verify test instantiations pass (782 geth/wycheproof vectors each). The zkvm build shadows this header and is unaffected.

🤖 Generated with Claude Code

Copilot AI lite review requested due to automatic review settings August 28, 2026 14:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR optimizes the EIP-7951 p256_verify precompile implementation by reducing per-call Crypto++ curve setup overhead and slightly reordering validation to fail faster on the infinity-key sentinel.

Changes:

  • Cache DL_GroupParameters_EC<ECP> as a function-local thread_local in p256_verify_impl to avoid reconstructing P-256 parameters on every call.
  • Reorder public key checks to reject (qx, qy) == (0, 0) before invoking ec.VerifyPoint(...).

Verdict: CORRECT

🤖 Generated with Claude Code


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed per REVIEW.md. No findings.

  • The thread_local (rather than static) cache is correct: Crypto++'s ECP writes through a mutable Point m_R scratch member in its const Add/Double methods, so a single shared instance across execution threads would be a data race — the code comment documents this accurately. Per-thread caching eliminates the per-call ASN.1 decode of the secp256r1 parameters without changing behavior.
  • No dangling references into the now-persistent object: Multiply returns Point by value, and auto const r_prime = ec.Add(p1, p2) deduces Point and copies out of the scratch before the next use.
  • A block-scope thread_local in this header-defined inline function is ODR-safe (function-local statics in inline functions are unique across TUs), and the function has no suspension points, so the thread-bound references cannot outlive their thread even under fiber scheduling.
  • Reordering the (0, 0) infinity check ahead of VerifyPoint is behavior-preserving: P-256 has b ≠ 0, so (0, 0) fails the curve equation, meaning both orders reject the identical input set — and the diff comment explains the divergence from the EIP-7951 pseudocode order.
  • Existing coverage applies: the p256Verify.json vector suite (precompiles_test.cpp, TYPED_TEST(TraitsTest, p256_verify)) exercises both rejection paths across trait instantiations.
  • PR hygiene: single commit, single file, scope is exactly what the title says.

Verdict: CORRECT

🤖 Generated with Claude Code

@khordadi
khordadi force-pushed the amir/p256-curve-params branch from 344960d to 59861a0 Compare August 28, 2026 15:03
Baltoli
Baltoli previously approved these changes Aug 28, 2026
ryankeleti
ryankeleti previously approved these changes Aug 28, 2026
Comment thread category/execution/ethereum/precompiles_impl.hpp Outdated
Comment thread category/execution/ethereum/precompiles_impl.hpp Outdated
@khordadi
khordadi requested a review from mkolosick August 28, 2026 15:31
@khordadi
khordadi force-pushed the amir/p256-curve-params branch from 59861a0 to 87834e2 Compare August 28, 2026 15:31
DL_GroupParameters_EC<ECP> construction decodes the secp256r1 domain
parameters (OID lookup, hex-decoding the curve constants, Montgomery
conversion) on every call to p256_verify_impl, costing ~11.6us per
invocation. Cache the parameters in a thread_local instead.

thread_local rather than a shared static because Crypto++'s ECP writes
mutable scratch state under Add and the small-scalar Multiply fallback,
execution is fiber-parallel across OS threads, and the small-scalar path
is reachable from attacker-controlled r and s; a single shared object
would be a data race. This matches the thread_local secp256k1_context
already used by ecrecover_impl.

Also check for the (0, 0) infinity public key before evaluating the
curve equation: both orders reject identically ((0, 0) is not on the
curve since b != 0 for P-256), and doing the cheap check first skips the
more expensive point validation.

Measured with all four variants compiled into one binary over the 782
geth/wycheproof vectors (identical verdicts on every vector): full valid
verify 695.3 -> 684.2us (-1.6%), early-reject inputs 14.3 -> 2.7us
(5.3x), infinity inputs 3.25 -> 3.04us from the reorder. No
consensus-visible behavior change.

Raised by @guidovranken in #1646.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@khordadi
khordadi force-pushed the amir/p256-curve-params branch from 87834e2 to ccc4c64 Compare August 28, 2026 20:29
@khordadi
khordadi merged commit 68d444b into main Aug 28, 2026
15 checks passed
@khordadi
khordadi deleted the amir/p256-curve-params branch August 28, 2026 20:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

P256 Verify precompile speed optimizations

6 participants