EIP-8197: Cryptographically Agile Transactions (CATX)

CATX (Cryptographically Agile Transactions) is an EIP-2718 transaction format that separates the transaction body from its signatures using a flat structure: [payload_type, payload_body, (sig_type, sig_body)+]. This enables future migration to post-quantum cryptography without modifying transaction semantics, supports multi-signature payloads where each signature commits to its position index, and facilitates future support of zk signature aggregation.

Included in the initial format specification is support for bodies that match EIP-2930, EIP-1559, and EIP-4844. This format is also suitable for other transaction payloads such as the frame transaction (EIP-8141) and Tempo transactions.

4 Likes

This reminds me of the original implementation of EIP-7932.

Would it be possible for this to use the EIP-7932 registry for signature algorithms? If not, how can I make it possible?

There isn’t really much point in cryptographic agility if every implementation is siloed because then there is no cryptographic agility between specifications.

We do need standards on signature type to crypto signature algorithm, I intentionally left it to ECDSA only to move that out of scope of the EIP and keep it focused on one core issue.

This spec is RLP only as SSZ is still controversial

It also addresses some of the issues with signature substitution attacks when a TX specifies multiple signatures, like frame sigs or the Tempo Transaction. Those two appear to fix it by committing to addresses in the TX body (frame) or having different signing domains and transaction layouts depending on use (tempo) but by locking it into position it standardizes the hash generation for each signature so each added payload type doesn’t have to encode those into their EIP specification nor have to re-write the transaction body for each signature validation.

Keeping the scope limited does make sense, however, EIP-7932 has gone through many rewrites, and it now stands as just the interface layer. SSZ & RLP were completely removed (The SSZ logic was integrated with EIP-6404).

Regarding the substitution attacks problem, that would still be handled by EIP-8197, EIP-7932 only does signatures.

If you wish to only implement secp256k1, may I ask that you keep address derivation and the definition of the algorithm (type byte, etc) in line with the current EIP-7932 spec not as a hard dependency but just to ensure that future integration would still be possible?

I’ve been keeping my algorithm identifications in line with Tempo Transactions - although they are all pre-quantum right now. ECDSA as zero makes the most sense instead of FF, as locking in FF now prevents multi-byte address numbers. Starting at zero is the most compatible place for such future expansions.

However we do depart from their address derivation standard, I think not domain separating address derivations is a mistake-in-waiting for a algo that allows relatively unrestricted construction of public keys.

1 Like

There is nothing requiring 0xFF to be used for multi-byte algorithm types, I picked 0xFF for secp256k1 because it is a unique algorithm with non-standard behaviour, so separating it from all of the other algorithms made more sense (e.g. like EVM opcodes where special ones are placed at 0xFX). There is no rule that suggests algorithm assignments must be sequential.

From what I am reading on the spec, I could not find where it defined secp256k1 as 0x0 (except for only KeyAuthorization objects), it says that in transaction signatures secp256k1 is unprefixed for backwards compatibility.

With address derivation, I agree that domain separation is important and would probably be a good idea for me to merge the collision check into EIP-7932.

I dropped the algo mappings from the CATX spec I published, there are some things we are not sharing yet. But I am more interested in a ID/algo mapping that is shared across chains and L2s than I am getting my specific choices done, except for the part I want it to be RLP/SSZ expandable which means keeping the high bit clear for now.

I agree that this is one of the most important parts of cryptographic migration, hence many attempts to make EIP-7932 as modular as possible.

In regards to the RLP high bit problem, I’d make the case for signatures to be internally tagged (sig_type || signature) instead of externally as it would allow for the full 0x00 → 0xFF range without the RLP prefix byte, and reduce some of the parsing logic to EIP-7932 (or similar registry EIP) as it provides helper functions such as validate_signature(signature) which directly operates on internally tagged signatures.

Efficiency wise, the RLP serialization would be generally more compact as all the 256 permutations would only use 1 byte, compared to 2 bytes if > 128. Similarly, contracts & intermediaries that need to pass along the signature the would only have to process a byte array rather than a byte array and a variably sized integer.

It’d also making handling extensions to the algorithm id space significantly easier, e.g. 0xFD || ULEB128 integer, which can be implemented without breaking fixed-length implementations. This is out of scope for EIP-7932 and presumably EIP-8197, but is worth noting for future reference.

1 Like

If we are concerned about extending beyond a byte why are we inventing new forms? That’s why I prefer sticking to SSZ/RLP multi-byte integer solutions from the get-go, because those are already known and understood. Or even ULEB128, just start with that eventuality in mind instead of going with the wierd reserved escape hatch byte to go into multibyte. High-bit set means multibyte.

Actually, once I think about it, it does make more sense to reserve 0x80+ for ULEB128 integration in the future.

While I do still believe that having secp256k1 as a high (or at least distinct) byte is important for semantic purposes, it does not provide any inherent technical blocker. If EIP-7932 standardized to to 0x00 secp256k1 (and0x7F reserved as an invalid / undefined / null algorithm - for test cases, example signatures, etc), do you think this be sufficient for EIP-7932 integration with both EIP-8197 and other proposals that implement cryptographic-agility?

For me I look for three things for cryptographic agility:

  1. Relevant and Algorithms. If the algos are not acceptable there’s nothing to be agile to (256P’s up my sleve problem). But FN-DSA when it ships will be acceptable, and ml-dsa is a good backup, but to big for day to day use.
  2. User Switchable. Ultimately the user has to be in control of what is used. It’s a menu that can get updated at each fork.
  3. Easy to add. Supporting a new algo should not require ripping out core pieces of a transaction. v,r,s fields have set us up in a bad place here.

Because tempo used 0x00 and nobody else has set up a table yet that is a strong argument just to start with their table. We don’t have to support everything (webauthn in mainnet I expect is a hard no) but we should collaborate, for the sake of wallets.

1 Like

I agree with your points, keeping the table at least similar to Tempo (e.g. keeping the mapping not the address derivation domains) would make life easier for cross-chain interoperability.

I’ll probably go about updating EIP-7932 with the collision checks and move secp256k1 → 0x00and null → 0x7F. I’ll also need to submit a PR to EIP-6404 for the change in algorithm types (PR).

Do you plan on EIP-8197 having either a soft (or hard) dependency on EIP-7932?

I can make it a soft dependency. The barrier to making it a hard dependency is that the EIP editors do not want ā€œregistry EIPsā€ and that, honsetly, is what is called for in this situation. We can reference an on-chain registry but those will always feed back into the specs. And there is always the case of EIPs that claim a value but never ship, so we cannot rely on simple aggregation.

1 Like

Thank you for considering, I think we both share the opinion that modularity for a concept that is itself modular is important (hence why I have been so pushy about EIP-7932).

I think it is reasonable that 7932 isn’t purely a registry EIP when framed like EIP-2718: Typed Transaction Envelope as they are structurally similar and only define the required interface, not an actual list of mappings. It also has the added similarity to EIP-2718 in that it is completely useless without any dependencies.