Research — ERC-4337 WebAuthn Accounts

TokenSight
6 min readJan 30, 2024

--

Account Abstraction is an incredibly powerful feature that is already simplifying onboarding to Web3. It avoids the complexities related to managing private keys while allowing users to manage their on-chain activities with familiar authentication methods, like their existing social profiles.

On the other hand, passkeys are becoming an increasingly popular option towards a password-less online experience, boosted by the fact that modern devices (tables, phones, laptops) have an integrated module for fingerprint or face detection that simplifies the creation of these passkeys.

The actual implementation of passkeys is based on the WebAuthn specification, which is a standard that allows apps to interact with built-in or external device authenticators. Built-in authenticators can be considered Trusted Platform Modules or biometric sensors (ex. TouchID), while external authenticators refer to Yubi Keys or mobile devices.

Having an on-chain smart contract account (wallet) controlled by a passkey in your possession would be the ultimate experience for Web3 users. The only catch is that the cryptographic curve specified in the WebAuthn standard is the secp256r1, while Ethereum uses secp256rk1 curve for signature generation and validation, and there is currently no precompiled option for gas-efficient secp256r1 validation on-chain. This makes the validation of a passkey-generated signature on-chain a very expensive endeavour.

In the past few months we have worked on figuring out a gas-efficient implementation for on-chain secp256r1 signature validation, that will enable a trustless and fully on-chain AA account experience with passkeys. Our work builds on top of an open-source research available at FCL which introduces significant sec256r1 optimizations for EVM chains using a precomputation table generated for a certain public key. The end result is a deployed smart contract account connected to a passkey where the signature validation step costs around 300k — 400k gas, with a slightly higher entry fee required to deploy two smart contracts instead of one — a contract with the precomputations bytecode and the actual ERC4337 smart contract account.

The entire flow is depicted in the following illustration:

Deployment

The deployment of a new WebAuthnAccount requires a factory contract to be ready and deployed on-chain. It also requires the precomputations server to be up and running.

  1. The user generates a new WebAuthn credential
  2. The decoded attestation object is processed to extract the public key coordinates x & y
  3. A precomputation bytecode is generated for those coordinates using a server
  4. The WebAuthnAccountFactory is used to deploy a new account using the precomputations, public key coordinates and the credential ID

Signature validation

  1. The user obtains the current account nonce, which will serve as a unique challenge for obtaining a WebAuthn assertion.
  2. The user prompts the WebAuthn device for an assertion.
  3. The auth data, client data and signature are extracted and decoded from the assertion. The client data is an encoded JSON object which contains the encoded challenge.
  4. The auth data and client data are encoded and sent to the UserOp as call data, along with the signature.
  5. The on-chain signature validation step validates the challenge and reconstructs the message that was signed by using the encoded auth, client data and on-chain extracted challenge.
  6. Finally, the provided signature is verified using the precomputations and the reconstructed message hash that was signed.

In our implementation, the account nonce is used as a unique challenge for each signature to avoid signature replay attacks. However, any other source of on-chain verifiable uniqueness per transaction can be used as a challenge, where one example would be a dedicated uint256 account counter.

So far we have included the following resources in our open-source repo, which can be found at the following link —
http://tinyurl.com/webauthn-wallet:

  1. The actual smart contracts for the WebAuthnAccount and WebAuthnAccountFactory.
  2. A simple precomputations server written in Rust that utilises SageMath (using the precomputation logic in FCL)
  3. A simple SDK with utility functions to deploy a WebAuthnAccount and to abstract away integration with WebAuthn and parsing of payloads.
  4. An example app in Next.js that showcases the creation of a wallet and the simulation of a UserOp with a valid signature.

WebAuthn Add-On

The introduction of the on-chain sec256r1 validation introduces different possibilities, one of which is a WebAuthnAddOn module, which we have included in the repo.

This module provides the necessary components to add/remove a WebAuthn credential and validate sec256r1 signatures on-chain. This can be used for different purposes in different ERC4337 accounts, but one specific use case we can think of is creating on-chain multisig accounts with both ECDSA and WebAuthn signatures. This can serve as on chain MFA experience for signing transactions, while the signatures will need to be first collected off-chain, then submitted all at once as part of the UserOp.

However, integrating such a wallet would require an entire flow from a frontend to the backend to the smart contract implementation, including recovery options as well, and we are open to suggestions from the community and collaborations to make this happen.

Potential Risks

The full fledged development of the WebAuthnAccount is still in progress, and as you might have noticed so far, there are a few certain risks with the current state of the account:

Passkey Recovery

The most simple explanation is that losing your passkey would mean losing your funds.

Even though it’s fairly simple to store your passkey across multiple devices (ex. using iCloud), losing it is still an option, and we wouldn’t want you to lose control over your funds if that scenario was to happen. An on-chain direct recovery option would simply mean a replacement of the current passkey with a new passkey, which would be a rather complicated and expensive task to perform, but worth it nevertheless.

One gas-efficient option we are currently exploring is one which includes a recovery private key, which then can be used to replace a passkey (whether it’s lost or not). Even though the entire point of the WebAuthnAccounts is to avoid using private keys at all, we need a computationally cheap alternative for on-chain second factor for account recovery. The process will require several steps:

  1. You will first need to register a public key (of an ECDSA key pair) in the WebAuthnAccount as a passkey recovery method.
  2. You can generate a new WebAuthn attestation with a new passkey.
  3. A valid ECDSA signature is generated using the new public key coordinates, ex. ecdsa(keccak256(new_pub_key_x, new_pub_key_y))
  4. New precomputations code is generated by interacting with the precomputations server for the newly created public key
  5. A specific “Reset” or “Recovery” UserOp is triggered that will deploy the new precomputations table and update the credential and public key in the WebAuthnAccount only if a valid ECDSA signature is provided for the new public key coordinates using the previously registered ECDSA public key.

Trusted Precomputation Server

Generating a ready to be deployed precomputations bytecode is a compute-heavy task that needs to be done on a server. That introduces a centralisation step and a potential vulnerability that, in the current state, could lead to loss of funds if the account is deployed using a non-trusted precomputation server.

One scenario that can happen is for a given x & y coordinates of a public key, the server would return a precomputation bytecode for different credential, which could be in a possession of a hacker. The user ends up deploying the account with their public key but with a different precomputation bytecode. This can lead to the user sending invalid signatures to the smart contract, however the hacker is not able to send valid signatures and pull any funds as well, since the signature verification step is expicitly linked to the user’s public key.

This issue can certainly lead to a bad outcome if account is not generated using a trusted precomputations server.

One way to mitigate this would be a local validation/simulation of the generated precomputation bytecode, which would require the user an extra interaction with their authenticator device and impact the overall UX. We will be exploring this and other approaches to remove the need to always rely on a trusted precomputation server, while maintaining a smooth UX.

Future Work

The current WebAuthnAccount implementation will be expanded further with on-chain recovery mechanisms, passkey replacement as well as with session keys. Session keys are of paramount importance for providing a fully self-custodial experience while authorising a third party with full or limited set of permissions for performing certain operations on your behalf within a limited timeframe.

It will be ready to be integrated within TokenSight as another wallet generation mechanism once recovery mechanisms, passkey replacement and session keys are in full swing. Stay tuned!

--

--

TokenSight

Advanced DEX Trading Platform. Fast, reliable and secure on-chain trading. Trade on Ethereum, Solana, Base, Arbitrum and BSC. https://app.tokensight.io