Skip to content

fix(StdSecp256k1): reject non-canonical coordinates in isOnCurve - #928

Open
ara-stock wants to merge 1 commit into
foundry-rs:masterfrom
ara-stock:fix/secp256k1-is-on-curve-canonical
Open

ara-stock wants to merge 1 commit into
foundry-rs:masterfrom
ara-stock:fix/secp256k1-is-on-curve-canonical

Conversation

@ara-stock

Copy link
Copy Markdown

Motivation

StdSecp256k1.isOnCurve(x, y) only compares y² mod P with x³ + 7 mod P, so it also returns true for non-canonical coordinates x >= P or y >= P that are congruent to a curve point. For example, (1 + P, y) is accepted because (1, y) is on the curve.

This disagrees with the go-ethereum function referenced in the code (crypto/secp256k1/curve.go, IsOnCurve), which returns false when x >= P || y >= P. It also disagrees with the library's own docs ("Affine coordinates (x, y) are canonically in [0, P)") and with isIdentityProjective, which already requires y < P. If a test validates a public key with isOnCurve, a value like (x, y + P) passes, and toAddress then gives a different address.

Solution

Return false from isOnCurve when either coordinate is not in [0, P), and say so in the natspec. Add a test with two on-curve points (x = 1, and a point with y = 1) where adding P to one coordinate still fits in uint256. Before the change, the new test fails with assertion failed. After the change, it passes. forge fmt --check is clean on the touched files.

I used an AI assistant (Claude) while preparing this. I reproduced the issue and checked the fix and tests myself.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant