Skip to content

Optimize EOA signature verification#2661

Merged
frangio merged 16 commits into
OpenZeppelin:masterfrom
k06a:patch-5
Aug 6, 2021
Merged

Optimize EOA signature verification#2661
frangio merged 16 commits into
OpenZeppelin:masterfrom
k06a:patch-5

Conversation

@k06a

@k06a k06a commented May 5, 2021

Copy link
Copy Markdown
Contributor

Optimize EOA signature verification. Since Berlin HF isContract() would cost 2000 gas.

Prev gas:


EOA: 2000 + 3500

SC: 2000



Now gas:


EOA: 3500

SC: (signature.length is 64 or 65 ? 3500 : 0) + 2000

k06a added 2 commits May 5, 2021 10:36
Prev gas:
EOA: 2000 + 3500
SC: 2000

Now gas:
EOA: 3500
SC: (signature.length is 64 or 65 ? 3500 : 0) + 2000
@frangio frangio requested a review from Amxx July 5, 2021 16:20
@Amxx

Amxx commented Jul 12, 2021

Copy link
Copy Markdown
Collaborator

Hello @k06a,

First of all, thank you for this PR, we noticed it a while back and failed to let you know. For that I am sorry.
The idea itself is sound, it would result in interesting saving in the EOA case, which is the one we expect to happen the most often. However this PR breaks one thing:

  • ERC1271 doesn't assume anything about the wallet's signature verification primitive, might be secp256k1 ecrecover like for EOAs, but it might be something different, particularly in the future.
  • Some wallets may used another crypto primitive that also uses 64 or 65 bytes long signatures.
  • If these signature return an invalid value for ecrecover, and we fallback to 1271, that is good, but if signature doesn't follow the right format, our ecrecover (which include some checks) could revert.

Unfortunatelly, we have no way to catch an internal library call :/

We will investigate other options (like having a non reverting ecrecover that returns an "error" enum + the recovered address).

What do you think ?

@Amxx Amxx left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[duplicate]

@Amxx Amxx left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should ensure that, if signer is an ERC1271 implementing contract, the initial ecrecover doesn't revert and the contract call is performed.

@k06a

k06a commented Jul 12, 2021

Copy link
Copy Markdown
Contributor Author

@Amxx WDYT about ECDSA-tryRecover introduced in the latest commit?

Comment thread contracts/utils/cryptography/ECDSA.sol Outdated
Comment thread contracts/utils/cryptography/SignatureChecker.sol Outdated
Amxx added 3 commits July 13, 2021 00:20
Conflicts:
	contracts/utils/cryptography/ECDSA.sol
	contracts/utils/cryptography/SignatureChecker.sol
@Amxx Amxx self-requested a review July 12, 2021 22:28
Amxx
Amxx previously approved these changes Jul 12, 2021
@Amxx Amxx requested a review from frangio July 12, 2021 22:29
@k06a

k06a commented Jul 12, 2021

Copy link
Copy Markdown
Contributor Author

@Amxx nice changes! I believe this tryRecover will be very useful for developers.

@Amxx Amxx self-requested a review July 12, 2021 23:24
@frangio

frangio commented Jul 13, 2021

Copy link
Copy Markdown
Contributor

The problem I see with this try pattern is that I don't know how we'll migrate it from revert strings to custom errors, once we do that in a couple of months ideally and minimizing breaking changes.

As far as I know custom errors cannot be passed around as values. Perhaps this is something we should raise with the Solidity team.

sudiptab2100
sudiptab2100 previously approved these changes Jul 14, 2021
@k06a

k06a commented Jul 14, 2021

Copy link
Copy Markdown
Contributor Author

@frangio possibly we could return ABI-encoded version (bytes) of error after migration to custom errors.

@Amxx

Amxx commented Jul 14, 2021

Copy link
Copy Markdown
Collaborator

@frangio
Maybe we can

  • replace revert strings with an enum, making the return type of tryRecover address, uint8.
  • in the recover functions, replace the bytes(error).length > 0 with error != 0
  • have a error enum → string private function that we call
(address recovered, RecoveryError error) = tryRecover(hash, v, r, s)
if (error != RecoveryError.NoError) {
    revert(_recoveryErrorString(error));
}

In the futur we can remove the _recoveryErrorString private function in favor of custom errors.

Amxx
Amxx previously approved these changes Jul 14, 2021
Amxx
Amxx previously approved these changes Aug 5, 2021
@Amxx Amxx mentioned this pull request Aug 5, 2021
2 tasks
frangio
frangio previously approved these changes Aug 6, 2021

@frangio frangio left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks everyone.

@frangio frangio merged commit 541e821 into OpenZeppelin:master Aug 6, 2021
@matias904

Copy link
Copy Markdown

Good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants