|
| 1 | +--- |
| 2 | +fork: Osaka |
| 3 | +--- |
| 4 | + |
| 5 | +## Notes |
| 6 | + |
| 7 | +P256VERIFY performs ECDSA signature verification over the secp256r1 elliptic curve (also known as P-256 or prime256v1). This curve is a NIST-standardized curve widely supported in modern secure hardware including Apple Secure Enclave, Android Keystore, HSMs, TEEs, and FIDO2/WebAuthn authenticators. |
| 8 | + |
| 9 | +Native secp256r1 support enables sophisticated account abstraction patterns like device-native signing, multi-factor authentication, and simplified key management - reducing friction for mainstream adoption through familiar authentication flows. |
| 10 | + |
| 11 | +This precompile is specified in [EIP-7951](https://eips.ethereum.org/EIPS/eip-7951) and supersedes RIP-7212 by implementing the same functionality with the same interface, but with critical security fixes: |
| 12 | +- **Point-at-infinity check**: Ensures the recovered point R' is not the point at infinity, preventing non-deterministic behavior. |
| 13 | +- **Modular comparison**: Uses `r' ≡ r (mod n)` instead of `r' == r` to handle cases where the x-coordinate exceeds the curve order. |
| 14 | + |
| 15 | +## Inputs |
| 16 | + |
| 17 | +| Byte range | Name | Description | |
| 18 | +|-----------:|-----:|------------:| |
| 19 | +| `[0; 31]` (32 bytes) | hash | Message hash to verify | |
| 20 | +| `[32; 63]` (32 bytes) | r | Signature component r, must satisfy `0 < r < n` | |
| 21 | +| `[64; 95]` (32 bytes) | s | Signature component s, must satisfy `0 < s < n` | |
| 22 | +| `[96; 127]` (32 bytes) | qx | Public key x-coordinate, must satisfy `0 ≤ qx < p` | |
| 23 | +| `[128; 159]` (32 bytes) | qy | Public key y-coordinate, must satisfy `0 ≤ qy < p` | |
| 24 | + |
| 25 | +Input must be exactly **160 bytes**. All values are encoded as big-endian unsigned integers. |
| 26 | + |
| 27 | +### Input Validation |
| 28 | + |
| 29 | +The precompile performs the following validation checks: |
| 30 | +- Input length must be exactly 160 bytes |
| 31 | +- Signature components `r` and `s` must be in range `(0, n)` |
| 32 | +- Public key coordinates must be valid field elements `[0, p)` |
| 33 | +- The point `(qx, qy)` must satisfy the curve equation `qy² ≡ qx³ + ax + b (mod p)` |
| 34 | +- The point `(qx, qy)` must not be the point at infinity |
| 35 | + |
| 36 | +### Curve Parameters |
| 37 | + |
| 38 | +| Parameter | Value | |
| 39 | +|----------:|------:| |
| 40 | +| Field modulus (p) | `0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff` | |
| 41 | +| Subgroup order (n) | `0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551` | |
| 42 | +| Coefficient a | `0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc` | |
| 43 | +| Coefficient b | `0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b` | |
| 44 | + |
| 45 | +## Output |
| 46 | + |
| 47 | +| Byte range | Name | Description | |
| 48 | +|-----------:|-----:|------------:| |
| 49 | +| `[0; 31]` (32 bytes) | success | `0x0000000000000000000000000000000000000000000000000000000000000001` for valid signatures | |
| 50 | + |
| 51 | +Returns empty output (``) for: |
| 52 | +- Invalid input length |
| 53 | +- Invalid field element encoding |
| 54 | +- Invalid signature component bounds |
| 55 | +- Invalid public key (not on curve or point at infinity) |
| 56 | +- Signature verification failure |
| 57 | + |
| 58 | +## Example |
| 59 | + |
| 60 | +| Input | Output | |
| 61 | +|------:|-------:| |
| 62 | +| `0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca6050232ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e184cd60b855d442f5b3c7b11eb6c4e0ae7525fe710fab9aa7c77a67f79e6fadd762927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838c7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e` | `0x0000000000000000000000000000000000000000000000000000000000000001` | |
| 63 | + |
| 64 | +The example above breaks down as: |
| 65 | +- **hash**: `0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023` |
| 66 | +- **r**: `0x2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18` |
| 67 | +- **s**: `0x4cd60b855d442f5b3c7b11eb6c4e0ae7525fe710fab9aa7c77a67f79e6fadd76` |
| 68 | +- **qx**: `0x2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838` |
| 69 | +- **qy**: `0xc7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513e` |
| 70 | + |
| 71 | +## Gas |
| 72 | + |
| 73 | +The gas cost is fixed at **6900** gas. This cost is based on benchmarking against the existing ECRECOVER precompile (3000 gas). If the input does not allow computation of a valid result, all the gas sent is consumed. |
0 commit comments