Skip to content

Conversation

@amiecorso
Copy link

@amiecorso amiecorso commented Oct 17, 2025

The verify function in WebAuthn-sol checks the validity of a passkey signature. It’s called during the validation phase of an ERC-4337 flow for passkey-signed userOps. When preparing a userOp, the wallet client must estimate the “verification gas limit” (VGL) for the userOp, which is the estimation of how much gas will be consumed during the onchain validation of the userOp before the execution of it’s actual payload. There is some tolerance for error in this estimation, but using a value that’s too high or too low will cause the bundler to reject the userOp.

When the verification flow is simulated without a valid passkey signature, the verify function was returning much earlier in its execution flow than it would when executing with a valid passkey signature during the actual onchain verification. This was leading to an underestimation of simulated verification gas.

To resolve this, we change the verify function so that it does not return early and always executes the heavy path (computing the SHA‑256 hashes and attempting signature verification) regardless of whether the inputs are ultimately valid. With these changes, valid and invalid inputs now cost roughly the same gas, so simulations without a final signature approximate the true cost of a later, valid verification.

There is one trade‑off: genuinely invalid signatures onchain are now slightly more expensive than before because we no longer revert early. In practice, this is a rare scenario as it will usually be caught by simulation, and if not, the gas cost is still relatively minor.

@cb-heimdall
Copy link
Collaborator

cb-heimdall commented Oct 17, 2025

✅ Heimdall Review Status

Requirement Status More Info
Reviews 1/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 0
Sum 1

@amiecorso amiecorso marked this pull request as ready for review October 20, 2025 22:54
Comment on lines 108 to +110
returns (bool)
{
bool hasFailedChecks = false;
Copy link
Member

Choose a reason for hiding this comment

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

nit: Could use hasFailedChecks as return param and accumulate sig checks into it

Copy link
Author

Choose a reason for hiding this comment

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

the actual return is an expression that incorporates multiple booleans

Comment on lines 14 to 16
baseFork = vm.createFork("https://mainnet.base.org");
ethFork = vm.createFork("https://ethereum-rpc.publicnode.com");
arbFork = vm.createFork("https://arb1.arbitrum.io/rpc");
Copy link
Member

Choose a reason for hiding this comment

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

We should opt to use env based rpc urls so that CI/CD is more reliable

Copy link
Member

Choose a reason for hiding this comment

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

What's the motivation for fork testing on arb, base and eth specifically? How were these networks chosen?

Copy link
Author

Choose a reason for hiding this comment

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

originally this was to get a sense of the gas difference between the early-return v.s. the heavy path on chains that do/don't implement RIP-7212 (precompile for secp256r1 ec i.e. passkey signatures). Ethereum mainnet does not implement this, but Base and Arbitrum should (among other rollups). we're not actually able to see a difference in fork testing, so I'm not sure if foundry's fork testing environment incorporates precompiles. Would be open to removing arbitrum to make it somewhat less arbitrary (i.e. one 7212-compatible chain and one non-7212 chain)

Choose a reason for hiding this comment

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

we're not actually able to see a difference in fork testing, so I'm not sure if foundry's fork testing environment incorporates precompiles. Would be open to removing arbitrum to make it somewhat less arbitrary (i.e. one 7212-compatible chain and one non-7212 chain)

Think this would be nice for clarity

Copy link

@ilikesymmetry ilikesymmetry left a comment

Choose a reason for hiding this comment

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

Looks good, thanks for the additional tests

Comment on lines +156 to +162
/// @dev Verifies a P256 signature using the precompiled contract or FCL.
/// @param messageHash The hash of the message to verify.
/// @param r The r value of the signature.
/// @param s The s value of the signature.
/// @param x The x coordinate of the public key.
/// @param y The y coordinate of the public key.
/// @return True if the signature is valid, false otherwise.

Choose a reason for hiding this comment

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

nit: separate tag types with empty line

Choose a reason for hiding this comment

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

we're not actually able to see a difference in fork testing, so I'm not sure if foundry's fork testing environment incorporates precompiles. Would be open to removing arbitrum to make it somewhat less arbitrary (i.e. one 7212-compatible chain and one non-7212 chain)

Think this would be nice for clarity

Comment on lines +1 to +6
WebAuthnForkTest:test_verify_fullPath_arb() (gas: 253734)
WebAuthnForkTest:test_verify_fullPath_base() (gas: 253756)
WebAuthnForkTest:test_verify_fullPath_eth() (gas: 253757)
WebAuthnForkTest:test_verify_invalidChallenge_arb() (gas: 43717)
WebAuthnForkTest:test_verify_invalidChallenge_base() (gas: 43740)
WebAuthnForkTest:test_verify_invalidChallenge_eth() (gas: 43739)

Choose a reason for hiding this comment

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

wow crazy difference 😮

@cb-heimdall
Copy link
Collaborator

Review Error for ilikesymmetry @ 2025-10-21 16:18:19 UTC
User must have write permissions to review

@cb-heimdall
Copy link
Collaborator

Review Error for stevieraykatz @ 2025-10-21 17:18:52 UTC
User must have write permissions to review

@stevieraykatz
Copy link
Member

Ci/Cd is failing because we include snapshot checking:

      - name: Check snapshot
        run: |
          forge snapshot --check
        id: snapshot

We can safely merge with failed ci/cd in this instance.

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.

4 participants