EIP-3074: AUTH and AUTHCALL opcodes

yes, how i understand it is that nonce mentioned here is not used for replay protection as we usually think of when we see the word “nonce”, it is more like a circuit breaker to make sure EOA owners can always revoke, so the absolute worst case of permanently losing EOA control is mitigated.

It’s up for the invoker to implement replay protection, allowing more flexibility for a signature more than once with invokers’ logic.

I have a stupid question:
For AUTH, why is the commit in the memory and not taken from the stack?

I envision a typical use case like:

  • The signature is passed in as an argument and can be easily copied to memory with CALLDATACOPY (e.g. that is what happens when using a bytes memory in solidity)
  • The commit is computed based on the desired parameters (application nonce, gas, application calldata …)
  • Now the commit is on the stack and the signature is in memory
  • Now in many cases an unnecessary memory copying and packing needs to take place. In solidity developers will presumably do something like abi.encodePacked(signature, commit) so that they can have them consecutively in memory
  • If instead the commit was simply taken from the stack, it would be a lot easier

Sorry, if I missed this argument previously.

It’s fairly easy to construct an example where the behavior isn’t obviously dependent on the literal text of the withdraw() function. For example, calling from a nonreentrant-protected function vs not-protected, or modifying the value of myToken using pointer aliasing (e.g. sstore in assembly).

You’re absolutely right, and this is a constant source of bugs.

And you want to introduce more edge cases like this?

It might be more productive, @charles-cooper, to come up with something that’s mutually acceptable?

I don’t know if vyper has decorators, but annotating the function in some way to show that it can be called from within an auth might make me happy.

This snippet should compile fine:

@impersonates
def approve_erc20():
    extcall erc20.approve(...)

def sudo(...):
    with authorized(msg.sender, sig):
        approve_erc20()

While functions without the @impersonates decorator would generate an error if used inside an authorized block or function annotated with @impersonates.

I mean these are things I have of course thought about and are indeed potential ways to expose AUTH to the user in Vyper. I guess the point I’m driving towards is that context managers and correct abstraction of scope can be addressed in the language or library design. The lack of “authorized” staticcall on the other hand, cannot.

As a workaround to depending on the authorising EOAs nonce, what if during AUTH we instead allow users to specific another “management” key owned by the same user and depend on the nonce of this management key for AUTH validation?

Let’s say we modify the AUTH message to the following:
keccak256(MAGIC || chainId || managementEoa || managementEoaNonce || invokerAddress || commit)
And the assumption is that the management EOA is owned by the same user, and is not used for doing general transactions and only to invalidate AUTH if the user wishes to.

This allows the main authorising EOA to continue doing transactions without invalidating AUTH, and still allow users to invalidate it by doing a transaction with the management EOA.

1 Like

This is a very promising idea! I think the managementEoa can be a smart contract as well, since smart contracts have nonces too. So I would change it to:

keccak256(MAGIC || chainId || nonceManagerAddress || nonceManagerNonce || invokerAddress || commit)

In fact, I’d imagine that the nonceManagerAddress being a smart contract would be more useful, since then the EOA can just “own” the smart contract as opposed to having to guard a separate key.

The nonce manager can even be deployed lazily — its address can be computed deterministically from a well-known factory. That way, EOA users can use nonce managers without paying for the cost of deployment, and a lot of EOA users probably won’t ever deploy any nonce managers if they don’t ever have to resort to global revocation.

3 Likes

Agreed, owning a Smart Contract to manage this would be much easier.

1 Like

One significant tradeoff of having nonceManagerAddress be a smart contract is it makes the implementation of this opcode more complicated.

How about nonceManagerAddress being able to be either an EOA or a smart contract, in both cases it checks the nonce of the account like today’s implementation. And when it’s a smart contract, it’ll use the CREATE opcode in order to increase its nonce?

More thoughts:

  1. It can also be used by smart contracts as a “nonce oracle” - till now contracts did not have access to the nonce of accounts. Not sure what are the implications of this.
  2. It will change the gas pricing of the opcode because it will be accessing another address which might be cold.

Yup, that is what we’re proposing above.

  1. t can also be used by smart contracts as a “nonce oracle” - till now contracts did not have access to the nonce of accounts. Not sure what are the implications of this.

Isn’t this possible (for EOAs) with the current 3074 standard as well?

Oh okay cool.

Kind of: it’s currently only possible to get an oracle for your own EOA’s nonce, and with this, you can use the oracle for any address.

Good point, didn’t consider the fact this allows you to verify the nonce of arbitrary contracts on-chain.
Although I’m unsure what the implications of this are.

Actually a lot of assumptions have to hold. The user also has to understand what it means to sign an EIP 3074 transaction. Wallets either don’t let you authorize any invoker not on their whitelist (e.g., Metamask will only let you use the Metamask invoker) or they open users to scams and poorly written invokers. Incidents are bound to happen so strict whitelists will be the standard and they’ll be justified as a sad but necessary trade off of permissionless innovation in favor of “security”. Developers having full control over the account allows them to do a bunch of interesting things like intents, but in practice only developers that work for a large wallet company like Metamask will be able to access that power.

The root problem is EIP 3074’s all or nothing security model. It’s the old sudo/setuid model, which produced an endless stream of security breaches on Unix. Modern systems have moved to a capability based design. EIP 3074 forces us to choose between restricting innovation to a handful of players and endless scamming.

EIP 3074 is just a bad idea on so many levels. The campaign’s modus operandi was bait and switch. Appeal to developer’s desire for EOA programmability and don’t mention the whitelisting that will be necessary. Appease the security experts by adding nonce and chainID, and then once it passes ACD you start campaigning to remove those “concessions”.

EIP 3074 would never have gotten this far on technical merit. The only reason we seem to be seriously considering it for inclusion now is the some of the people involved seem to be quite adept at using social engineering techniques to play backroom politics.

I think we have very different definitions of permissionless. Anyone can create a wallet with whatever whitelist they want / no whitelist at all. If a wallet decides to gatekeep a feature, that is their choice. They could already do so today. The protocol has no concept of permissions. That is permissionless.

This is an oversimplification of the security model. 3074 allows you develop arbitrary capabilities. When you sign to an invoker, you are signing only to a certain capability implemented by that invoker. The correctness of this can be determined by auditing the contract. This is far more powerful than implementing such features directly in the protocol.

It’s also the same type of security model as a smart contract wallet. When you’re executing in the context of the wallet, it has “sudo” capabilities. It is the implementation of the wallet which enforces the security model. In both cases, you can be certain of the safety by reviewing the code.

This isn’t Linux. There aren’t RCEs in smart contracts. We can formally verify an invoker and be certain it implements only the defined capability.

ACD doesn’t accept EIPs w/o merit. And no EIP makes it without a champion. I have spent a lot of time discussing the EIP with many different members of the community, sometimes in non public discussions. Each has had the opportunity to decide the merit of the proposal themselves. Of course, many EOA wallets and their users are excited about the proposal because it finally breaks the monopoly of UX improvements held by smart contract wallets.

This isn’t social engineering. 3074 is extremely beneficial to a lot of Ethereum users and they voiced their support.

1 Like

The security experts are not the ones demanding nonce and chainID.

1 Like

This would need to be constrained to within a single EVM call frame. Otherwise you could call some third party contract and change its internal behavior by setting the authorized flag.

Being able to AUTH_STATIC_CALL would definitely be nice, it does feel like it is “missing”, though it could be added later in theory.

It’s not just the commit, it’s the entire signature to. The stack is limited to 256 bits. Taking the commit and signature from memory preserves design space so that AUTH could use different signature schemes (such as BLS) or more divergent mechanisms such as SNARKS or quantum safe lattice signatures. Given yParity is 1 or 0 the first byte can still easily be used to signal type.

1 Like

I didn’t ask for nonce, I demanded single-action-revocation. Nonce was the EIPs authors solution to that request. If you can hand over total control of your account with a single action, you should be able to revoke it with a single action too.

2 Likes

Agreed

I also like to second the concern about introducing nonce and chainId. Introducing these values alone doesn’t guarantee protection of replay attack, while makes it hard to handle other situations such as more than one outstanding TX.

Editorial suggestion

Invoker is first introduced in this EIP and was not a common terminology prior. Can we give a definition of invoker at the first time when the word invoker appear? (Especially to clarify relationship with signer)