Skip to content

feat(tests): add EIP-7951 for secp256r1 curve #1670

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Jun 10, 2025

Conversation

LouisTsai-Csie
Copy link
Collaborator

@LouisTsai-Csie LouisTsai-Csie commented May 28, 2025

🗒️ Description

This PR implements EIP-7951 precompile to support secp256r1 curve (based on RIP-7212).

Running the test locally

Since the current EELS repository does not support this functionality, I submitted an EELS PR to implement the P256VERIFY precompile. This precompile relies on cryptographic operations not currently supported by the default Python packages, so two additional packages are required:

Additionally the EELS resolver must have these 2 packages added its setup.cfg.

To test this PR locally, follow the steps below.

  1. Update the EELS resolutions file to the following:
 "Osaka": {
        "git_url": "https://github.com/spencer-tb/execution-specs.git",
        "branch": "forks/osaka-devnet-2",
        "commit": "49e601dfba8248dcbb6a5685c59edb5a02a89589"
    }
  1. Update the EELS resolver to use the following commit within pyproject.toml:
ethereum-spec-evm-resolver = { git = "https://github.com/spencer-tb/ethereum-spec-evm-resolver", rev = "ee273e7344e24a739ebfbf0ea1f758530c4d032b" }

Source of the test vector

In this PR, we convert the Wycheproof dataset into secp256r1_test.json and import the test cases for validation.

While this approach is commonly used across various Layer 2 implementations (see analysis here), adding additional test cases is still necessary to ensure broader coverage.

Implementation Note

In both EIP-7951 & RIP-7212 we could not depend on the output data length to determine whether the low-level call is successful, this might be different from the behavior of BLS precompile (EIP-2537).

Consider the following two scenarios:

  1. A staticcall to the precompile with an invalid signature should return true, with empty return data.
  2. If the staticcall is made with a valid signature but insufficient gas, it should return false, and the return data should also be empty.

🔗 Related Issues

ethereum/execution-specs#1249

✅ Checklist

  • All: Set appropriate labels for the changes.
  • All: Considered squashing commits to improve commit history.
  • All: Added an entry to CHANGELOG.md.
  • All: Considered updating the online docs in the ./docs/ directory.

Copy link
Contributor

@spencer-tb spencer-tb left a comment

Choose a reason for hiding this comment

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

Really nice! Just wondering where you got the vectors from? Are they the same as these and if so do we know how they are generated: https://github.com/google/wycheproof/blob/master/testvectors/ecdsa_secp256r1_sha256_test.json

I think in a future PR we should add some additional edge cases manually. As for BLS (EIP-2537) we initially relied heavily on the external test vectors and missed some important coverage points.

Although the curve itself is extremely well tested the point of these manual cases would be to find divergence between the libraries that clients use or how they integrate the library (or simply a client implementation). Some cases I can think of just now:

  • Zero signature component, s=0 should trigger divide by zero on libraries, r=0 too.
  • All possible point at infinity input cases, (x, y) = (0, 0) is the obvious case.
  • Some/all point at infinity output cases, I think when the hash is 0.
  • Boundary conditions, that aim to trigger overflows. Cases where x, y >= p or r, s >= n, or where they are close to p-1, n-1. The RIP follows NIST so 1 <= s <= n-1, but all ethereum signatures thus far are s <= n/2, adding a case for this would be nice.
  • Input length or encoding cases, i.e < 160 bytes, > 160 bytes, 31 byte components etc.

@spencer-tb spencer-tb added scope:tests Scope: Changes EL client test cases in `./tests` type:feat type: Feature labels May 28, 2025
@LouisTsai-Csie
Copy link
Collaborator Author

@spencer-tb Thanks for your reply

The test vectors are from the Wycheproof repository. We’ve extracted and converted them into a format compatible with our test framework at tests/osaka/eip7212_secp256r1_precompiles/vectors/secp256r1_test.json.

These test cases are widely used across various Layer 2 implementations. We’ve also reviewed the testing strategies and infrastructure from them, and here’s a short summary of our findings.

https://hackmd.io/@3uGN6yZhRLWqNJalNI1kig/BkavbMd-gl
https://hackmd.io/@3uGN6yZhRLWqNJalNI1kig/B1OOHduWxe

Regarding your second point, I agree that adding more test cases is important. Although the current implementation passes all tests, I’ve identified a few edge cases that should be covered — for instance, when the public key point (x, y) is not actually on the curve.

Copy link
Member

@marioevz marioevz left a comment

Choose a reason for hiding this comment

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

Awesome work! I've left a couple of comments to be resolved before proceeding 👍

@LouisTsai-Csie LouisTsai-Csie force-pushed the feat/add-rip-7212 branch 2 times, most recently from bf73eb7 to a1125c8 Compare June 4, 2025 16:28
@spencer-tb
Copy link
Contributor

Amazing! Looks good from myside!

Could we get these 2 comments in:

And maybe update the PR description/name to be 7951, stating that its based on 7212?

@LouisTsai-Csie LouisTsai-Csie changed the title feat(tests): add RIP-7212 for secp256r1 curve feat(tests): add EIP-7951 for secp256r1 curve Jun 9, 2025
@spencer-tb spencer-tb added the fork:osaka Osaka hardfork label Jun 9, 2025
@spencer-tb
Copy link
Contributor

Last couple items from myside! :D

Could we rename:

  • test_p256verify_precompile_module.py to test_p256verify.py, and
  • test_p256verify_precompiles_before_fork.py to test_p256verify_before_fork.py.

Then add a line to the changelog here:
https://github.com/ethereum/execution-spec-tests/blob/main/docs/CHANGELOG.md?plain=1#L66

@spencer-tb
Copy link
Contributor

Rebasing onto main will fix the evmone coverage report fail in ci :)

@LouisTsai-Csie LouisTsai-Csie marked this pull request as ready for review June 10, 2025 07:29
@LouisTsai-Csie
Copy link
Collaborator Author

@spencer-tb I've rebased to main branch, but the evm one ci is still failing, anything I should take a look?

@LouisTsai-Csie LouisTsai-Csie force-pushed the feat/add-rip-7212 branch 2 times, most recently from a887bb6 to bcff1b9 Compare June 10, 2025 13:05
@marioevz marioevz force-pushed the feat/add-rip-7212 branch from c73be2d to 30d9cde Compare June 10, 2025 14:48
Copy link
Member

@marioevz marioevz left a comment

Choose a reason for hiding this comment

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

Awesome work, thanks! 🎉

@marioevz marioevz merged commit 2f66dcc into ethereum:main Jun 10, 2025
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fork:osaka Osaka hardfork scope:tests Scope: Changes EL client test cases in `./tests` type:feat type: Feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants