---
eip: 8310
title: Post-Quantum Keystore for Stateful Keys
description: A keystore format for XMSS and other consumable signing keys, defining state authority, durability ordering, and safe import/export.
author: Anshal Shukla (@anshalshukla), Benedikt Wagner (@benedikt-wagner), Gajinder Singh (@g11tech), Guillaume Ballet (@gballet), Justin Drake (@JustinDrake), Kolby Moroz Liebl (@KolbyML), Parthasarathy Ramanujam (@ch4r10t33r), Shariq Naiyer (@shariqnaiyer), Thomas Coratger (@tcoratger), Unnawut Leepaisalsuwanna (@unnawut)
discussions-to: https://ethereum-magicians.org/t/eip-8310-post-quantum-keystore-for-stateful-keys/28853
status: Draft
type: Standards Track
category: Interface
created: 2026-06-19
requires: 2335, 3076
---

## Abstract

This standard defines a keystore format for **stateful hash-based signing keys**, specifically eXtended Merkle Signature Scheme (XMSS) as used by the Lean Ethereum consensus layer (hereafter `leanxmss`). It extends [ERC-2335](./eip-2335.md) so that the encrypted secret may be an XMSS seed and adds the machinery a *consumable* key requires: an explicit scheme-parameter block, a non-authoritative capacity snapshot, normative rules for where the authoritative signing state lives, a commit-before-sign durability requirement, reserved leaf ranges for concurrent signers, and import/export semantics that forbid silently resetting a key's signing position.

The encryption upgrades (Advanced Encryption Standard with 256-bit keys (AES-256) and Authenticated Encryption with Associated Data (AEAD)) are minor. The substance of this EIP is **state management**, because an XMSS key is destroyed by leaf reuse and the existing keystore model assumes keys are immutable, freely copyable, and restore-safe, three assumptions that are unsafe for consumable keys.

## Motivation

[ERC-2335](./eip-2335.md) stores a 32-byte BLS scalar. Lean Ethereum replaces BLS validator keys with XMSS for post-quantum security. An XMSS secret can also be reduced to a small seed, so the *container* needs only modest change. The danger is elsewhere.

Each XMSS signature consumes a one-time Winternitz One-Time Signature Plus (WOTS+) leaf identified by an index that must not ever be reused. Reuse of a leaf across two distinct messages enables forgery and is therefore key-destroying. This single property breaks three behaviors that are safe today and that operators, wallets, and clients currently take for granted:

1. **Immutability.** A 2335 keystore never changes after creation. An XMSS key advances state on every signature.
2. **Free copying.** A BLS keystore may run on two machines harmlessly. Two copies of an XMSS key signing independently will reuse leaves.
3. **Restore-safety.** Restoring a BLS keystore from any backup is safe. Restoring a *stale* XMSS state rolls back the high-water mark and invites reuse.

Validators already solve an isomorphic problem for BLS: [EIP-3076](./eip-3076.md) slashing protection enforces "never sign two different messages for the same slot." For the synchronized XMSS variant, where one leaf is bound to one epoch/slot, *"never reuse a leaf" and "never double-sign a slot" are the same invariant*. This EIP makes that coupling normative rather than coincidental, and specifies the remaining cases (off-protocol signers such as builder-bid signing) that fall outside the slashing-protection database.

## Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", and "MAY" in this document are to be interpreted as described in [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119) and [RFC 8174](https://www.rfc-editor.org/rfc/rfc8174).

### 1. Terminology

- **Consumable key**: a signing key whose security depends on never reusing an index (e.g. XMSS, Leighton-Micali Signatures (LMS)). Contrast with *reusable* keys (ECDSA, BLS).
- **Leaf index**: the position of the one-time key consumed by a signature.
- **High-water mark**: the highest leaf index that has been (or is reserved as) consumed. Signing is permitted only strictly above it.
- **Authoritative state**: the single source of truth for the high-water mark that a signer consults and advances. It is NOT the keystore file.
- **Synchronized mode**: leaf index is a deterministic function of consensus position (`leaf = f(epoch)` or `f(slot)`); state authority is the slashing-protection database.
- **Counter mode**: leaf index is a free-running counter not bound to consensus position (e.g. off-protocol signing); state authority is a dedicated atomically-updated store.

### 2. File format

This EIP defines keystore `version` **5**. A v5 keystore is a v4 keystore with the changes below.

#### 2.1 Cipher and Key Derivation Function (KDF)

- `crypto.cipher.function` MUST be an AEAD or 256-bit construction. `aes-256-gcm` is RECOMMENDED. `aes-128-ctr` MUST NOT be used in v5.
- `crypto.kdf.function` MAY be `argon2id` in addition to the `scrypt` and `pbkdf2` of v4. Parameters MUST target current memory-hardness guidance.

These are precautionary against Grover and do not affect the consumable-key semantics below.

#### 2.2 Encrypted secret

`crypto.cipher.message` is the encrypted XMSS **seed**, not an expanded private key. The seed length is defined by the scheme parameters. The keystore stores only material required to *recover* the key (see §6); it does not store live signing state.

#### 2.3 New `scheme` object

```json
"scheme": {
  "name": "leanxmss",
  "params": {
    "hash": "<hash identifier>",
    "tree_height": 32,
    "hypertree_layers": 1,
    "encoding": "target_sum",
    "winternitz_w": 8,
    "dimension": 46,
    "target_sum": 200,
    "index_mode": "synchronized",
    "activation_epoch": 0,
    "lifetime_leaves": 4294967296
  }
}
```

- `scheme.name` MUST identify the signature scheme. A reader that does not recognize `scheme.name` MUST refuse to use the keystore.
- `scheme.params` MUST contain every parameter required to deterministically regenerate the public key and to verify a signature. These fields are **immutable**; a writer MUST NOT alter them after creation.
- `hash` identifies the tweakable hash function and its underlying field. This specification is **hash-agnostic**: any hash meeting the security requirements of the signature scheme MAY be used, and `hash` records the concrete choice so that a verifier can reproduce it. The Poseidon1 hash (for example over the KoalaBear field) is still being evaluated for consideration as the recommended instantiation.
- `tree_height` is the height of the (single) Merkle tree; with `hypertree_layers` it determines `lifetime_leaves = 2^(tree_height × hypertree_layers)`.
- `hypertree_layers` is the number of stacked Merkle trees. `leanxmss` is a single-tree Generalized XMSS, so this MUST be `1`.
- `encoding` identifies the incomparable encoding. `leanxmss` uses `target_sum`.
- `winternitz_w` is the base of each hash chain (`BASE` in leanSig).
- `dimension` is the number of hash chains (the hypercube dimension). Together with `winternitz_w` and `target_sum` it fully specifies the target-sum encoding and is REQUIRED to regenerate the public key and verify a signature.
- `target_sum` is the target sum of the target-sum encoding.
- `index_mode` MUST be `synchronized` or `counter` per §1.

The non-hash values above are the recommended production parameter set for a 2^32 key lifetime, matching leanSig's `SIGAbortingTargetSumLifetime32Dim46Base8` instantiation (`LOG_LIFETIME = 32`, `DIMENSION = 46`, `BASE = 8`, `TARGET_SUM = 200`). The format is hash-agnostic; the concrete hash function (for example Poseidon1 over KoalaBear) is still being evaluated for consideration and is recorded in the `hash` field.

#### 2.4 New `state` snapshot object

```json
"state": {
  "authoritative": false,
  "authority": "slashing-protection",
  "reference": "<opaque locator, optional>",
  "capacity": { "total": 4294967296, "consumed": 12345, "remaining": 4294954951 },
  "high_water": 12345,
  "reserved_ranges": []
}
```

- `state.authoritative` MUST be `false` in any keystore file. The file is a snapshot for operator visibility only and MUST NOT be consulted as the high-water mark at signing time.
- `state.authority` MUST be one of `slashing-protection`, `external`, or `embedded` and MUST be consistent with `scheme.params.index_mode`:
  - `synchronized` ⇒ `slashing-protection`.
  - `counter` ⇒ `external` (a dedicated state store).
  - `embedded` is RESERVED and SHOULD NOT be used for production validator keys; it exists only for self-contained single-signer tooling and, if used, the file ceases to be immutable.
- `capacity` and `high_water` are informational. A consumer MUST treat the authoritative store, not these fields, as binding.

### 3. State authority

A signer MUST consult and advance a single authoritative state when producing a signature.

- In **synchronized mode**, the authoritative state is the [EIP-3076](./eip-3076.md) slashing-protection database. The leaf consumed by a signature is `f(epoch)` (or `f(slot)`); refusing to double-sign a slot is exactly refusing to reuse a leaf. Implementations MUST bind the XMSS key and its slashing-protection history as an inseparable unit: any operation that moves, imports, or exports the key MUST move, import, or export the corresponding history atomically with it.
- In **counter mode**, the authoritative state is a dedicated store keyed by the keystore `uuid`, holding the current counter. It MUST provide the same durability and atomicity guarantees as §4.

### 4. Commit-before-sign ordering

For every signature, an implementation MUST, in order:

1. Determine the candidate leaf index.
2. Verify the index is strictly greater than the authoritative high-water mark (or, in synchronized mode, that the slot/epoch has not been signed).
3. **Durably persist** the advanced high-water mark, written, flushed (`fsync` or platform equivalent), and committed via atomic rename or an equivalently atomic transaction, *before* step 5.
4. Compute the signature.
5. Release the signature to the caller.

Releasing a signature before the state advance is durable is a violation: a crash between release and persistence causes index reuse on restart. Step 3 MUST complete before step 5; steps 3 and 4 MAY be reordered relative to each other, but neither may precede step 2.

### 5. Reserved leaf ranges

To support concurrent or high-throughput signers (e.g. builder-bid signing) without serializing every signature on one lock, a keystore MAY partition its leaf space into disjoint **reserved ranges**:

```json
"reserved_ranges": [
  { "id": "signer-a", "start": 0,       "end": 524287,  "high_water": 410022 },
  { "id": "signer-b", "start": 524288,  "end": 1048575, "high_water": 524288 }
]
```

- Ranges MUST be disjoint. A signer assigned a range MUST consume only indices within `[start, end]` and MUST maintain its own authoritative high-water mark for that range under the §4 ordering.
- A range MUST NOT be assigned to more than one signer instance simultaneously.
- Exhaustion of a range MUST cause the signer to refuse rather than wrap or borrow from another range.

This is the recommended mechanism for the builder-bid exhaustion case, where a single global counter is too contended.

### 6. Import, export, recover, resume

This EIP distinguishes two operations that legacy tooling conflates:

- **Recover**: reconstruct the key (regenerate the hypertree, derive the public key) from the encrypted seed. This is always safe and uses only the keystore file.
- **Resume signing**: begin producing signatures. This requires the *latest authoritative state* and is unsafe from the keystore file alone.

Therefore:

- An implementation MUST NOT begin signing from a keystore that lacks authoritative state. "Import with empty/fresh state" MUST be a hard error for a consumable key, not a warning.
- Export of a consumable key MUST include or reference its authoritative state. A bare keystore file MAY be exported for *recovery and verification only* and, if so, MUST be flagged such that no consumer will sign from it.
- Restoring a keystore together with a *stale* state snapshot is the catastrophic case. Implementations MUST detect a regression of the high-water mark and refuse to sign until reconciled with the latest authoritative state.

## Rationale

**Why extend 2335 rather than define a new format.** The encryption envelope, KDF abstraction, and modular design of 2335 are sound and widely implemented; only the cipher strength and the assumption of a fixed-size reusable secret needed changing. Reusing the envelope preserves tooling and review surface.

**Why couple to 3076 instead of a bespoke state mechanism.** In synchronized mode the slashing-protection invariant and the leaf-uniqueness invariant are identical. Defining a second, parallel state mechanism would create two sources of truth that can disagree, the worst outcome for a consumable key. Making the slashing DB authoritative gives the key a single, already-battle-tested guardrail.

**Why a non-authoritative snapshot in the file.** Operators need to see capacity and remaining leaves without a separate tool, but a mutable field in a portable file is a reuse trap. Marking it `authoritative: false` keeps visibility while denying it any role at signing time.

**Why commit-before-sign is normative, not advisory.** It is the single ordering rule that prevents crash-induced reuse. Everything else in the spec is bookkeeping around it.

**Synchronized vs counter.** Synchronized keys map cleanly onto consensus duties and the slashing DB. Off-protocol duties (builder-bid signing being the motivating example) have no slot to key on and need a free counter and its own durable store. Both are specified so a single deployment can hold keys of each kind. *Open issue for discussion:* whether the lean profile mandates synchronized-only for protocol keys and confines counter mode to clearly-separated signing services.

## Backwards Compatibility

v5 is not backwards compatible with v4 consumers, which assume a reusable 32-byte secret and have no notion of state authority. v4 and v5 keystores are distinguished by the `version` field and the presence of the `scheme` object. A v5-aware client must refuse to operate on a consumable key as if it were a v4 reusable key. v4 BLS keystores remain valid under their own standard and are out of scope.

## Test Cases

To be added. At minimum: (1) round-trip encrypt/decrypt of a `leanxmss` seed; (2) refusal to sign on high-water regression; (3) crash-injection between signature computation and state persistence demonstrating no reuse on restart; (4) disjointness and exclusive-assignment checks for reserved ranges. <!-- TODO -->

## Reference Implementation

To be added. <!-- TODO -->

## Security Considerations

- **Leaf reuse is catastrophic and silent.** Unlike a slashing event, reuse may produce no immediate on-chain penalty while fully compromising the key. The §4 ordering and §6 import rules are the primary defenses and must not be relaxed for performance.
- **Stale-restore is the dominant operational risk.** Backups protect the seed but not the state. Operators must be guided toward recover-then-reconcile, never restore-and-sign. Detection of high-water regression (§6) is required.
- **Cloning across hosts.** Running the same key on two hosts without disjoint reserved ranges guarantees reuse. Range assignment (§5) must be exclusive.
- **State store integrity.** An attacker able to roll back the authoritative state can induce reuse. The state store should have integrity protection commensurate with the keystore itself.
- **Encryption strength.** AES-256 and a memory-hard KDF mitigate Grover-accelerated password search; they do not and need not protect the signing scheme, which is post-quantum by construction.
- **Capacity exhaustion as availability risk.** A key that exhausts its leaves can no longer sign. Capacity monitoring (§2.4) and conservative `lifetime_leaves` selection are operational requirements, not optional.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
