Skip to main content

Security boundaries

This page explains what the ML-DSA signature authorizes inside the PQ smart-account stack, and what it explicitly does not. The product-level threat model lives in Threat model.

What the ML-DSA signature protects

The signature is over userOpHash, the EIP-4337 hash of a UserOperation. A valid signature proves the holder of the ML-DSA private key authorized exactly this UserOp:

  • This sender (smart account address).
  • This nonce (which encodes the PQ validator and prevents replay).
  • This callData (the calldata to execute — transfer, swap, governance vote, etc.).
  • This factory / factoryData (if the account is being deployed).
  • This paymasterAndData, callGasLimit, verificationGasLimit, and related fields.
  • On this chainId and via this EntryPoint.

An attacker cannot replay the UserOp to a different account, change the calldata, point it at a different EntryPoint, or replay it on a different chain.

What the signature does not protect

Mempool inclusion is not authorization

A signed UserOp is permission to be executed if a bundler accepts it. It does not guarantee that a bundler will accept it, that it will be included in a block, or that it will succeed. The ERC-4337 bundler can drop, censor, or front-run UserOps within the rules of its mempool.

Target-contract behavior is opaque to the validator

The validator approves the calldata that the EntryPoint will execute. The smart account then executes that calldata against whatever target contract was specified. If the target contract has a bug, a centralized admin key, a malicious upgrade path, or unexpected reentrancy, the PQ signature does not help. The signature authorizes the call; it does not bless the callee.

Paymaster behavior is out of scope

If a paymaster is used, the paymaster's own logic — solvency, signature validation, abuse prevention — is independent of the PQ validator.

ECDSA root validator still exists

The standard Kernel v3 setup retains an ECDSA root validator for setup, recovery, and selectors not yet moved under PQ. If that root key is compromised, an attacker can uninstall the PQ module — a privileged operation, but one gated by the root key, not the PQ key. Accounts wanting strict PQ-only security must constrain or remove the root validator after setup. Kernel supports this, but it is a sharp-edge operation.

Off-chain key custody is its own concern

The smart-account stack assumes you have an ML-DSA private key and can sign with it. How that key is stored, encrypted, and protected is outside this stack.

What the verifier promises

The Stylus MLDSAVerifier is a stateless function. Given (public_key, message_hash, signature):

  • Returns true if and only if the signature is a valid ML-DSA-65 signature of message_hash under public_key per FIPS 204.
  • Returns false otherwise, including on malformed signatures.
  • Reverts before reaching Stylus if the public key has the wrong length.
  • Has no storage, no admin, no upgrade, no callbacks — it is a pure function.

Auditable failure modes are limited to: (a) a bug in the underlying ml-dsa crate, (b) a Stylus SDK issue affecting argument decoding or return encoding, and (c) a deployment error pointing the validator module at the wrong verifier address.