Add EIP: Frame type for PQ sig and STARK aggregation#11772
Conversation
Adds a frame type for quantum-resistant Signature and STARK Aggregation This supports signatures and STARKs (for privacy or for eg. L2s) in a post-quantum world in a highly gas-efficient way, by providing a way for transactions to declare them as "dependencies", in a way that allows the mempool and the block builder to replace them with a recursive STARK proving that they all exist.
File
|
|
I agree
…On Mon, 15 Jun 2026 at 3:28 pm, Andrew B Coathup ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In EIPS/eip-9999.md
<#11772 (comment)>:
> @@ -0,0 +1,508 @@
+---
+eip: 9999
+title: Frame type for PQ sig and STARK aggregation
+description: Add recursive STARK-based aggregation for quantum-resistant signatures and STARKs via EIP-8141 frame types
+author: Vitalik Buterin ***@***.***), Thomas Coratger
⬇️ Suggested change
-author: Vitalik Buterin ***@***.***), Thomas Coratger
+author: Vitalik Buterin ***@***.***), Thomas Coratger ***@***.***)
—
Reply to this email directly, view it on GitHub
<#11772?email_source=notifications&email_token=BHSKXHA2GSF7KOZE7ONCHPD476CPTA5CNFSNUABKM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UKJSXM2LFO4XTINBZGQ3DKMJXGA3KM4TFMFZW63VKON2WE43DOJUWEZLEUVSXMZLOOSWGM33PORSXEX3DNRUWG2Y#pullrequestreview-4494651706>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/BHSKXHDFYMCRU4OUFY563D3476CPTAVCNFSNUABEKJSXA33TNF2G64TZHM2DIOJXGE3TKMR3JFZXG5LFHM2DMMBQGQ4TMOBRHCQXMAQ>
.
Triage notifications, keep track of coding agent tasks and review pull
requests on the go with GitHub Mobile for iOS
<https://github.com/notifications/mobile/ios/BHSKXHCRUKMIJH5EG73RQWD476CPTA5CNFSNUABKM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UKJSXM2LFO4XTINBZGQ3DKMJXGA3KM4TFMFZW63VKON2WE43DOJUWEZLEUVSXMZLOOSVGM33PORSXEX3JN5ZQ>
and Android
<https://github.com/notifications/mobile/android/BHSKXHB3O5HAW25BGWKTUYD476CPTA5CNFSNUABKM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UKJSXM2LFO4XTINBZGQ3DKMJXGA3KM4TFMFZW63VKON2WE43DOJUWEZLEUVSXMZLOOSXGM33PORSXEX3BNZSHE33JMQ>.
Download it today!
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
Co-authored-by: Andrew B Coathup <28278242+abcoathup@users.noreply.github.com>
Co-authored-by: Andrew B Coathup <28278242+abcoathup@users.noreply.github.com>
Co-authored-by: Andrew B Coathup <28278242+abcoathup@users.noreply.github.com>
|
|
||
| ### New Frame Types | ||
|
|
||
| This EIP introduces two new frame modes for [EIP-8141](./eip-8141.md) frame transactions: |
There was a problem hiding this comment.
Only one new frame mode
jochem-brouwer
left a comment
There was a problem hiding this comment.
Exciting EIP 😄 👍
Some editorial comments!
|
|
||
| Because these dependencies are at the transaction body level and are not created inside the EVM, they are not affected by transaction execution reverting, and the gas is still fully charged even if the transaction reverts. This is similar to eg. intrinsic gas for calldata. | ||
|
|
||
| ### Backwards Compatibility |
There was a problem hiding this comment.
This section should be a top-level header (##) and should be between Rationale and Test Cases. (so after Rationale, not before it)
|
|
||
| ## Copyright | ||
|
|
||
| Copyright and related rights waived via CC0. |
There was a problem hiding this comment.
| Copyright and related rights waived via CC0. | |
| Copyright and related rights waived via [CC0](../LICENSE.md). |
|
|
||
| 1. The `deps` list is the concatenation of all dependencies from each transaction in `transactions` | ||
| 2. The total number of leanSPHINCS deps is `<= MAX_LEANSIG_DEPS_PER_WRAPPER` | ||
| 3. The total number of leanSTARK deps is `<= MAX_LEANSTARK_DEPS_PER_WRAPPER` |
There was a problem hiding this comment.
MAX_LEANSIG_DEPS_PER_WRAPPER and MAX_LEANSIG_DEPS_PER_WRAPPER are used here before definition, please define these constants before using them.`
| ``` | ||
| block_deps_hash = hash(concat([ | ||
| int_to_bytes32_big_endian(t.scheme) + t.data_hash + t.verification_key | ||
| for t in get_dependencies(block) |
There was a problem hiding this comment.
| for t in get_dependencies(block) | |
| for t in dependencies(block) |
get_dependencies is not defined
|
|
||
| A block is valid if and only if: | ||
|
|
||
| 1. The `block_deps_hash` in the recursive STARK header entry matches the result of hashing `get_dependencies(block)` |
There was a problem hiding this comment.
| 1. The `block_deps_hash` in the recursive STARK header entry matches the result of hashing `get_dependencies(block)` | |
| 1. The `block_deps_hash` in the recursive STARK header entry matches the result of hashing `dependencies(block)` |
|
|
||
| ## Motivation | ||
|
|
||
| Quantum-resistant signatures and zero-knowledge proofs both have a very high calldata requirement and gas cost. Current proposals for hash-based signatures are in the range of ~2-3 kB and ~150,000 to 200,000 gas to verify. Lattice-based signatures have a similar cost. Meanwhile, hash-based zero-knowledge proofs (STARKs) all take over 128 kB, or as much as 512 kB if fast generation is a goal (which it is client-side), which implies a STARK will take many millions of gas to verify. This on its own would mean that privacy protocols will have an impractically high cost, and be completely incompatible with FOCIL and Frame Transactions. |
There was a problem hiding this comment.
| Quantum-resistant signatures and zero-knowledge proofs both have a very high calldata requirement and gas cost. Current proposals for hash-based signatures are in the range of ~2-3 kB and ~150,000 to 200,000 gas to verify. Lattice-based signatures have a similar cost. Meanwhile, hash-based zero-knowledge proofs (STARKs) all take over 128 kB, or as much as 512 kB if fast generation is a goal (which it is client-side), which implies a STARK will take many millions of gas to verify. This on its own would mean that privacy protocols will have an impractically high cost, and be completely incompatible with FOCIL and Frame Transactions. | |
| Quantum-resistant signatures and zero-knowledge proofs both have a very high calldata requirement and gas cost. Current proposals for hash-based signatures are in the range of ~2-3 kB and ~150,000 to 200,000 gas to verify. Lattice-based signatures have a similar cost. Meanwhile, hash-based zero-knowledge proofs (STARKs) all take over 128 kB, or as much as 512 kB if fast generation is a goal (which it is client-side), which implies a STARK will take many millions of gas to verify. This on its own would mean that privacy protocols will have an impractically high cost, and be completely incompatible with FOCIL ([EIP-7805](./eip-7805.md)) and Frame Transactions ([EIP-8141](./eip-8141.md)). |
|
|
||
| The recursive STARK is generated using Lean Ethereum tooling. It proves the following statement: | ||
|
|
||
| ``` |
There was a problem hiding this comment.
If possible, add the language here for better rendering (for all code blocks)
Like: ```python
| - Reuses **lean Ethereum** tooling (for signatures and STARKs), to maximize shared codebase. | ||
| - Provides a **mempool wrapper** format that bundles transactions with their dependencies and proofs. | ||
| - Supports **recursive aggregation** at the mempool layer, allowing mempool nodes to combine proofs and reduce bandwidth overhead. | ||
| - Is **compatible with FOCIL** (EIP-7805), ensuring that the aggregation scheme works with fork-choice enforced inclusion lists. |
There was a problem hiding this comment.
| - Is **compatible with FOCIL** (EIP-7805), ensuring that the aggregation scheme works with fork-choice enforced inclusion lists. | |
| - Is **compatible with FOCIL** ([EIP-7805](./eip-7805.md)), ensuring that the aggregation scheme works with fork-choice enforced inclusion lists. |
|
|
||
| ### Lean Ethereum Integration | ||
|
|
||
| This EIP assumes the use of Lean Ethereum tooling for generating and verifying the recursive STARKs. |
There was a problem hiding this comment.
I strongly advise to help the reader find the context of Lean Ethereum. Although we cannot link to external URLs, we can do it like EIP-3675 (the Merge) which states:
Full specification of the beacon chain can be found in the
ethereum/consensus-specsrepository.
Something like this is also possible here, for instance linking to the leanEthereum GitHub organization:
| This EIP assumes the use of Lean Ethereum tooling for generating and verifying the recursive STARKs. | |
| This EIP assumes the use of Lean Ethereum tooling for generating and verifying the recursive STARKs. This tooling can be found at the leanEthereum GitHub organization. |
(This reference is likely not entirely correct, please help the reader find the correct context for all Lean Ethereum references here)
| type: Standards Track | ||
| category: Core | ||
| created: 2026-06-03 | ||
| requires: 2718, 2929, 2930, 7702, 8141 |
There was a problem hiding this comment.
| requires: 2718, 2929, 2930, 7702, 8141 | |
| requires: 2718, 8141 |
EIP-7702 is a requirement of EIP-8141. I don´t see why EIP-2929 or EIP-2930 are strictly required here, but correct me if I'm wrong here.
Since big parts of this EIP are about FOCIL compatibility, it almost makes FOCIL a requirement here. But I can understand why it is not strictly a requirement here as we also support it just fine without FOCIL.
One could consider moving the FOCIL compatibility to a new EIP. This would make this EIP focus on the new Frame Transaction, and the other EIP would handle the FOCIL compatibility. If a chain then wants to ship this EIP on a chain where FOCIL is already active, or activated in the next fork together with these EIPs, then the FOCIL-compatible version should be included in the fork. The FOCIL-compatible version thus requires this EIP (EIP-8288) and FOCIL.
| **This EIP's use case — processing many thousands of signatures and STARKs per slot without extreme data overhead — is almost identical to the consensus layer's use case.** The main differences are: | ||
|
|
||
| 1. Hashes vs bitfields as identifiers of what objects are being proven | ||
| 2. Many-time signatures (leanSPHINCS), instead of the one-time signatures that the consensus layer can use because it needs to enforce one-signature-per-slot anyway. |
There was a problem hiding this comment.
This is a bit confusing, because leanXMSS on the CL is many-time. I think what you want to say here is "stateless many-time (leanSPHINCS)" vs. "stateful / index-based many-time (leanXMSS)"
b-wagn
left a comment
There was a problem hiding this comment.
I left some minor comments. Here is my biggest one about security of the recursion:
Scope / Disclaimer
To be clear up front: I'm not claiming a concrete attack here. This is purely about the usual proof strategy for knowledge soundness — I think the standard argument would not go through as written. Because my proposed fix below seems to be low cost, I would strongly vote for adding it.
The problem
Knowledge soundness for recursive/PCD proofs is normally argued by recursive extraction: extract the outer witness, observe it contains an inner proof, run the extractor on that, and continue down until we reach a base case (here: a direct signature or a non-recursive STARK). My impression is that if we do this strategy here, with this particular definition of the circuit, this recursive extractor will not be guaranteed to terminate: it could be that we are always extracting a single recursive proof (i.e., one for "verify recursive proofs and collect their deps") and continue extracting. There is nothing that guarantees that our extractor will terminate. Worth emphasizing: this holds even assuming idealized, perfect single-step extractors for the individual STARKs. The gap is not in the per-step extractor (straight-line, believed-sound, whatever), it's in the recursoin. Maybe I am missing something, but I don't see how we guarantee here that we reach the base case.
Proposed Fix
The standard way to fix this is to add as a public input a depth_counter, which defines the recursive depth. The circuit then must check that this counter is >= 0 and is decreased when we are in the "verify recursive proofs and collect their deps" part, and that if depth_counter = 0, then only the base cases are valid. In this way, if we run one extractor for a public input, we at least decrease the counter by one, meaning that after a finite number of extractions, we must hit a base case and extract a leaf STARK or signature. In the mempool, aggregators need to increase the counters accordingly (something like taking the max of all previous counters + 1). In the block, we would now not only store the top level STARK but also its counter.
My impression is that the overhead from adding this is small, and it buys much more confidence in security.
Note that I don't suggest to limit the recursive depth (this would be against the rationale of the EIP), I just say it is important to keep track of it.
| # Add the inner deps to the union | ||
| all_deps.extend(inner_deps) | ||
|
|
||
| # Remove discards and duplicates |
There was a problem hiding this comment.
Can a block contain the same triple twice? If so this may be unprovable (block_deps_hash keeps duplicates, the circuit dedups). I suspect it cannot happen for signatures because of the signed nonce, but maybe it can happen for two STARKs proving the same statement? Worth a clarifying note either way.
|
|
||
| 1. **Soundness of Lean Ethereum circuits**: The STARK circuits must correctly implement the verification logic. | ||
| 2. **Soundness of the hash function used for `deps_hash` and `block_deps_hash`**: the realistic choices are Poseidon and BLAKE3. Poseidon is far more efficient to prove, but its security still remains to be fully verified. | ||
| 3. **Soundness of recursive STARKs, up to at least depth 2**: a STARK of a STARK must be sound. This is widely believed to be true and many constructions running live onchain already depend on this. However, this adds difficulty to end-to-end formally proving the scheme and its applications. Note also that the STARK verification keys that users put in to this system are up to users, and may potentially have unlimited recursion depth. |
There was a problem hiding this comment.
I am not sure "up to at least depth 2" is the right framing here.
The proven relation itself recurses without bounding the depth (the "Verify recursive proofs and collect their deps" loop verifies inner proofs generated by this same relation, so depth is unbounded by construction.)
The mempool loop described in the EIP also seems to rely on such an unbounded/high-depth recursion. So as far as I understand, the EIP relies on recursion beyond depth 2.
You do mention unlimited recursion depth, but the "depth 2" phrasing reads as if depth 2 were the default assumption.
Adds a frame type for quantum-resistant Signature and STARK Aggregation
This supports signatures and STARKs (for privacy or for eg. L2s) in a post-quantum world in a highly gas-efficient way, by providing a way for transactions to declare them as "dependencies", in a way that allows the mempool and the block builder to replace them with a recursive STARK proving that they all exist.
ATTENTION: ERC-RELATED PULL REQUESTS NOW OCCUR IN ETHEREUM/ERCS
--
When opening a pull request to submit a new EIP, please use the suggested template: https://github.com/ethereum/EIPs/blob/master/eip-template.md
We have a GitHub bot that automatically merges some PRs. It will merge yours immediately if certain criteria are met: