Skip to main content
The KeyStore is a standalone contract that stores and manages public keys for smart accounts. It is the identity layer - answering the question: who is authorized to use this account?

What it stores

For each account, the KeyStore maintains a set of keys:
FieldDescription
keyIdUnique identifier for the key (bytes32 hash)
publicKeyThe public key material (format depends on signature scheme)
authenticatorIdIdentifier of the authenticator device (for WebAuthn keys)
signCountMonotonically increasing counter for replay protection
activeWhether the key is currently authorized
lastUpdatedTimestamp of the last state change

Key lifecycle

Registration - the first key is registered via initialRegisterKey(), which verifies the account has no existing keys. Subsequent keys are added via registerKey(), which requires authorization (the account owner or an authorized contract). Deactivation - a compromised key can be deactivated immediately. The key remains in storage (for audit purposes) but is no longer valid for signing. Reactivation - a deactivated key can be reactivated if needed.

Replay protection

Each key tracks a signCount - a monotonically increasing counter. Every time the key is used to sign, the validator extracts the sign count from the authenticator data and compares it to the stored value. If the new count isn’t strictly greater, the signature is rejected. This prevents replay attacks where a captured signature is resubmitted.

Authorization model

Two types of callers can manage keys:
  1. The account itself - the smart account owner can always manage their own keys
  2. Authorized contracts - validator modules registered by the KeyStore owner can manage keys on behalf of accounts (e.g., the WebAuthnValidator migrates the initial key to the KeyStore after the first transaction)

Key registration fee

Registering a key costs a flat fee, paid in ETH. This prevents storage spam attacks (especially important on L2s where gas is cheap) and generates protocol revenue. The fee is transferred directly to the Functor treasury. The KeyStore contract holds zero user funds.

Multiple keys per account

An account can have multiple active keys - enabling multi-device access. A developer can register a passkey from their laptop, another from their phone, and a session key for their agent. Each key has its own keyId, and policies in the FunctorPolicyHook can be configured per keyId. Revoking one key doesn’t affect the others.