Skip to content

Keys in accounts, not a registry

A post-quantum public key has to live somewhere. ML-DSA-65 keys are 1,952 bytes and lattice signatures have no public-key recovery, so the verifier must be given the key — it cannot reconstruct one from the signature the way ecrecover does.

There are two structural answers: put the key in a shared registry the protocol consults, or put it in the account itself. Frost puts it in the account. That choice shapes almost everything else about how the chain is used.

A protocol-level registry maps addresses to public keys. Before an account can transact post-quantum, its key must be registered; the protocol then looks up the key when verifying.

It is a coherent design, and it has real advantages — the account model stays recognisable, and existing addresses can be upgraded in place. But it imposes a sequence:

  1. Generate a key.
  2. Register it, on chain, in a transaction.
  3. Then transact.

Step 2 is the problem, and it is not merely an inconvenience. It means a new user cannot receive funds safely at an address until they have already transacted — which requires funds. It means the registry is consensus-critical shared state that every verification path depends on. And it means the protocol’s set of supported algorithms is baked into the registry’s format: adding a scheme is a protocol change.

Each account is a contract that holds its own key and verifies its own signatures. Nothing needs to be registered because nothing is shared. The verification path reads the key from the account’s own code or storage, and the account’s address is derived from that key material through CREATE2 — so the binding between address and key is established by arithmetic, before anything happens on chain.

The consequences are worth spelling out, because they are the reason for the design:

No pre-registration. An address can be computed offline the instant a key exists. It can receive funds immediately. The account materialises itself on its first outgoing transaction, paid for from the balance already sitting there. See Counterfactual onboarding.

No shared bottleneck. There is no registry contract to be a hot spot, a governance surface, or a single point of failure. An account’s security depends on its own code and its own key, and on nothing else.

Crypto-agility is structural. Because the scheme lives in account code, supporting a new signature algorithm means adding a precompile and a new account type. It does not change what an address means, does not migrate a registry, and does not require every user to move at once. Users adopt a new scheme by creating a new account, on their own schedule.

Per-account policy. The account is a contract, so it can implement whatever authorisation logic it wants — multiple keys, thresholds, spending limits, time locks, key rotation. A registry mapping one address to one key cannot express any of that.

This is not free, and the costs are real.

No in-place upgrade for existing addresses. A registry can attach a post-quantum key to an address that already exists. Frost cannot: a post-quantum account is a different address, so adopting one means moving funds. For a new chain that is the right trade; for retrofitting an existing chain it would be a much harder argument.

Every account carries its key. A 1,952-byte public key sits in each account’s code or state. A registry amortises one copy per key across all its uses; here it is per account. This is a genuine storage cost, and it is part of why storage strategy gets first-class attention.

Accounts are contracts, so tooling must know that. tx.origin == msg.sender checks reject them. Some tooling assumes an EOA can sign arbitrary messages directly. This is the same friction smart-contract wallets face everywhere, and it is the price of the flexibility.

This is not a fringe position. The EIP-8141 draft exists precisely to make “the account decides how it is authorised” a first-class transaction shape, and registry-based proposals elsewhere have acknowledged that requiring pre-registration is awkward for users.

Frost’s contribution is not the idea — it is a working execution layer where the account-held-key path is cheap enough to use, because verification is a precompile rather than a Solidity loop.