This EIP introduces a new EIP-2718 typed transaction that wraps (contains) another transaction, this EIP nullifies the default signature parameters and appends signature data to the front of the transaction with a selector, this effectively wraps a transaction and swaps out signature data for alternative algorithms and data. It also creates a new precompile to be able to decode these additional signature algorithms.
Motivation
As quantum computers are getting more advanced, several new post-quantum (PQ) algorithms have been designed. These algorithms all contain drawbacks such as large key sizes (>1KiB), large signature sizes or long verification times. These issues make them more expensive to compute and store than the current secp256k1 curve in use (as of 2025-04-12).
This EIP provides a future-proof solution to these algorithms by adding a standardized way to represent alternative algorithms within a transaction.
Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.
Note: The “verification function” referred to by this EIP is the one specified by additional EIP & their signature types. When calling explicitly the “verification function” implementations MUST NOT call the precompile due to differing gas costs.
Parameters
Constant
Value
ALG_TX_TYPE
Bytes1(0x07)
GAS_PER_ADDITIONAL_VERIFICATION_BYTE
16
SIGRECOVER_PRECOMPILE_ADDRESS
Bytes20(0x12)
SIGRECOVER_PRECOMPILE_BASE_GAS
3000
Algorithmic Transaction
This EIP introduces a new EIP-2718 transaction with a TransactionType of ALG_TX_TYPE and a TransactionPayload of the RLP serialization of the AlgTransactionPayloadBody defined below:
The field alg_type is an unsigned 8-bit integer (uint8) that represents the algorithm used to sign the transaction in the parent field. This EIP does not define algorithms for use with this transaction type; however, it does specify a NULL algorithm (0xFF) which MUST trigger implementations to verify transaction fields.
The signature_info field contains information required to verify the signature of the transaction in the parent field. This is a byte-array of arbitrary length, which would be passed to the verification function.
The parent field contains another serialized EIP-2718 Typed Transaction Envelope (i.e. the parent field type is bytes), which MUST be able to contain every possible TransactionType, including legacy transactions with a TransactionType of > 0x7f, but the only exception to this rule is the Algorithmic Transaction itself, which MUST NOT be placed within itself.
These parent transactions all contain y_parity, r, s values, which MUST be set to Bytes0() if wrapped in a AlgTransactionPayloadBody, there are two exceptions to this rule however:
If the alg_type is the NULL algorithm, the signature field MUST be left unchanged.
If the transaction type is that of a legacy transaction, where y_parity MUST be equal to the chain ID value, the transactions signing data MUST also be calculated the same way as EIP-155 specifies
All other transaction values MUST be unchanged from their original values.
The additional_info field only needs to be populated if additional protocol level signatures are required such as EIP-7702’s authorization_list. This field MUST contain the RLP serialization of a list of the signatures [alg_type, signature_info] and MUST be repeated for every NON-NULL signature inside the transaction. The order of which MUST be the same as the signatures appear in the parent tx. This signature MUST also be checked to ensure that alg_type is known and is not the NULL algorithm (0xFF), len(signature_info) <= alg.MAX_SIZE and then MUST also be verified using the verify function for the specific algorithm.
If new transaction types are specified they MUST NOT attempt to build on this EIP but instead MUST include the y_parity, r, s values, this will prevent backwards compatibility issues and ensure that any transaction other than EIP-7932 txs can be safely assumed to be secp256k1.
The Algorithmic Transaction MUST NOT generate a transaction receipt with a TransactionType of ALG_TX_TYPE, it MUST emit the receipt of the transaction it is wrapping (the tx in the parent field). Implementations MUST not be able to differentiate between an unwrapped and wrapped transaction by receipts alone.
When clients receive an Algorithmic Transaction via gossip or RPC, they MUST validate both the Algorithmic Transaction and the transaction in the parent field, any ordering (e.g. based on gas price) MUST be done on the transaction in the parent field. If either transaction is invalid they MUST NOT propagate the transaction to peers.
Example transaction
This is an example wrapped EIP-1559 transaction where alg_type == 0x5
The parent field serializes to 0x02ce01010101825208800180c0808080, therefore the above transaction serializes to 0x07df058c7369676e696e672d646174619002ce01010101825208800180c0808080
Algorithm specification
Further algorithms MUST be specified via an additional EIP.
Each type of algorithm MUST specify the following fields:
| Field Name | Description |
|-|-|
|ALG_TYPE| The uint8 of the algorithm unique ID |
|MAX_SIZE| The maximum size of signature_info field in a transaction |
|GAS_PENALTY| The additional gas penalty from verification of the signature |
The GAS_PENALTY field MUST only account for verification costs, not storage nor signing.
New algorithms MUST also specify how to recover and verify a valid address (bytes20) from the signature_info field inside the transaction, the verification function MUST follow the following signature:
The verify function MUST return 0x0 if there was an error recovering a valid address from the signature, otherwise the function MUST return the address of the signer.
Specifications MUST also justify why their GAS_PENALTY is high enough to not cause a DOS vector, and MUST include some form of security analysis on the algorithm and that it will not cause potential security issues.
An example of this specification can be found here.
This EIP uses the Algorithms object to signify final and active algorithms. These are selected via the EIP process and hard-fork inclusion.
Verification
Implementations MUST consider transactions invalid where len(tx.signature_info) > alg.MAX_SIZE, this also applies for objects inside additional_info.
The following checks MUST always be made against any type of signature_info and alg_type. If the result of these checks do not pass then one of the following apply:
The transaction is invalid
If called from the precompile, the precompile MUST return 0x0 as the address.
assert(Algorithms[alg_type]!=None)# `Algorithms` is a dictionary containing every defined algorithm
assert(len(signature_info)<=alg.MAX_SIZE)
The validity/processing of the transaction should be processed similarly to the following function:
defprocess_transaction(tx:Transaction,from_address:bytes20=None,start_gas=21000,additional_info:List[Callable[[bytes32],bytes20]]):matchtx:# Verification for other transactions, if `from_address != None`
# then the verifier MUST NOT attempt to validate the `y_parity`, `r`, `s`
# parameters. Additionally, the verification function MUST start the initial gas value
# at `start_gas`. Every further signature where all parameters are null MUST instead use
# `additional_info` field corresponding to to which they appeared (i.e. the first signature to be null is at additional_info[0]).
# If the transaction is a legacy transaction and `from_address != None`, implementations
# MUST ensure that `y_parity == chainid`.
...ALG_TX:assert(from_address==None)# Ensure no double-wrapping
assert(Algorithms[alg_type]!=None)alg=Algorithms[alg_type]assert(len(signature_info)<=alg.MAX_SIZE)from_address=Noneifalg_type!=0xFF:# NULL TX
valid,from_address=alg.verify(tx.signature_info,calculate_signing_hash(wrapped),chain_id)# calculate_signing_hash is defined within the wrapped transaction's EIP.
assert(valid)# This is only an example, a method like this should not be used in production, instead the signature info should be passed
# into the processing function.
additional_info_verifiers=[]foradditional_infointx[3:]:additional_info_verifiers.append(lambdasig_hash:Algorithms[additional_info.alg_type].verify(additional_info.signature_info,calculate_signing_hash(sig_hash)))process_transaction(tx.parent,from_address,21000+calculate_penalty(tx.signature_info,alg))
Gas calculation
All transactions that use more resources than the secp256k1 curve suffer an additional penalty. This penalty MUST be calculated as follows:
The penalty MUST be added onto the 21000 base gas of each transaction BEFORE the transaction is processed. If the wrapped tx’s gas_limit is less then 21000 + calculate_penalty(signing_data, algorithm) than the transaction MUST be considered invalid and MUST NOT be included within blocks. This transaction also MUST inherit the intrinsics of the wrapped tx’s fee structure (e.g. a wrapped EIP-1559 tx would behave as a EIP-1559 tx).
The penalty MUST be applied to every instance of an additional_info object, which then MUST be added onto the transaction’s initial gas.
sigrecover precompile
This EIP also introduces a new precompile located at SIGRECOVER_PRECOMPILE_ADDRESS.
This precompile MUST NOT be called when verifying transaction parameters, instead this call should be verified as specified above.
This precompile MUST cost SIGRECOVER_PRECOMPILE_BASE_GAS when calling even if algorithm does not exist, this price MUST be aggregated with algorithm specific GAS_PENALTY and the output of calculate_penalty for the signature data, this penalty is charged once the sigrecover precompile executes.
The precompile logic executes the following logic:
defsigrecover_precompile(input:Bytes)->Bytes:# Recover signature length and type
assert(len(input)>=64)hash=input[:32]alg_type=input[32]sig_length=int.from_bytes(input[33:64],"little")# Ensure the algorithm exists and signature is correct size
ifalg_typenotinAlgorithms:returnbytes20(0x0)alg=Algorithms[alg_type]ifsig_length>alg.MAX_SIZE:returnbytes20(0x0)# Run verify function
returnalg.verify(input[64:64+sig_length],hash)
NULL algorithm
The NULL algorithm (0xFF) MUST be present if the signature parameters inside the wrapped transaction are still valid for secp256k1, but there are more parameters in the transaction such as EIP-7702’s authorization_list that require swapping out for different algorithms.
The signature_info field MUST be zero-sized if the NULL algorithm is not present.
The NULL algorithm MUST NOT be present if the transaction does not contain additional signatures.
Rationale
Setting y_parity, r, s values to zero rather than removing them
Keeping the y_parity, r, s values inside the transactions keeps the previous parsing, verification and processing logic the same and allows for minimal modification to the other specifications while still preventing excessive space usage.
Opaque signature_info type
As each algorithm has unique properties, i.e. signature recovery and key sizes, a object is needed to hold every permutation of every possible key and signature. A bytearray of dynamic size would be able to achieve this goal, this does lead to a DoS vector which the Gas penalties section solves along with the MAX_SIZE parameter.
Gas penalties
Having multiple different algorithms results in multiple different signature sizes, and verification costs. Hence, every signature algorithm that is more expensive than the default ECDSA secp256k1 curve, incurs an additional gas penalty, this is to discourage the use of overly expensive algorithms for no specific reason.
The GAS_PER_ADDITIONAL_VERIFICATION_BYTE value being 16 was taken from the calldata cost of a transaction, as it is a similar datatype and must persist indefinitely to ensure later verification.
Not adding the secp256k1 curve
Having a type for secp256k1 allows for several iterations of the same object to be present across the network. Additionally the only purpose for this curve would be for prototyping and testing with client teams, as the resultant receipt, logs and state change would be the same as a non-wrapped transaction.
Not specifying account key-sharing / migration
Allowing a single account to share multiple keys creates a security risk as it reduces the security to the weakest algorithm. This is also out of scope for this EIP and could be implemented via a future EIP.
Keeping a similar address rather than introducing a new address format
While adding a new address format for every new algorithm would ensure that collisions never happen and that security is not bound by the lowest common denominator, the amount of changes that would have to be made and backwards compatibility issues would be too vast to warrant this.
New precompile over modifying the ecrecover precompile
Initially, modifying the ecrecover precompile was going to be selected over creating a new precompile, however, this was ruled out after it took too much complexity to implement or may break backwards compatibility.
This EIP allows for EIP‑4337Bundlers to settle UserOperations onchain using a different algorithm which in the future may be the only option if post-quantum issues cause the secp256k1 curve to be phased out.
Backwards Compatibility
Non-EIP-7932 transactions will still be included within blocks and will be treated as the default secp256k1 curve. Therefore there would be no backwards compatibility issues will processing other transactions. However, as a new EIP-2718 transaction has been added non-upgraded clients would not be able to process these transactions nor blocks that include these transactions.
Test Cases
These test cases do not involve processing other types of transactions. Only the wrapping, unwrapping and verification of these transactions without interfacing with the parent tx held inside the main tx.
All the following test cases use the parameters from the example eip specified in the Algorithm Specification Section listed above.
Security Considerations
Allowing more ways to potentially create transactions for a single account may decrease overall security for that specific account, however this is partially mitigated by the increase in processing power required to trial all algorithms. Even still, adding additional algorithms may need further discussing to ensure that the security of the network would not be compromised.
Having signature_info be of no concrete type creates a chance that an algorithms logic could be specified or implemented incorrectly, which could lead to, in the best case, invalid blocks, or at worst, the ability for anyone to sign a fraudulent transaction for any account. This security consideration is delegated to the algorithms specification, therefore care must be taken when writing these algorithm specifications to avoid critical security flaws.