EIP-7212: Precompiled for secp256r1 Curve Support

@doganalpaslan sorry, I should have just reviewed the EIP again before commenting. I would echo the other comments made here around wishing there was consistency against the existing ecrecover implementation.

I appreciate concerns around multiplying curves with various distinct interfaces; I think in an ideal world one could choose the desired curve points and format through a generic interface, but that seems unlikely at this point and I wouldn’t hold up this precompile waiting for such an effort.

1 Like

Hello. We implemented a secp256r1 verification and presented it at ethCC Paris.
https://eprint.iacr.org/2023/939

If having an ecrecover version benefits to the probability of adoption, it is trivial to modify the front code that relay the ouput of the authenticator from the ‘classic’ edsa to ‘ecdsa with recovery’ version. It only requires to add the parity of Q. While not of interest in the context of 4337, it would also enable to have a ‘multiplier checking with witness’ from the precompile.

We also advocate for ed25519, but it will require to implement sha512 in the nodes (while secp256r1 implementation only requires sha256). Also current authenticator implements the r1 and not the ed25519.

It could also be considered that if not choosing an ecrecover version, pushing a double scalar multiplication with addition would get rid of the hash function (the overcost of a single opcode being negligible compared to the whole computation), and compatible with zk mechanisms (hash function like sha and keccak are restraining their use). That is why a EC_MULMULADD performing uP+vQ would be superior in this context. (zk implementations like Circom implementation replaces SHA by poseidon in the ecdsa).

4 Likes

Hello everyone.

I implemented P256VERIFY as a precompile inside Revm, which is the EVM implementation used in Reth, the new execution layer by Paradigm.

Here is my branch where you can find it: GitHub - alessandromazza98/revm at eip-7212

Specifically here is the precompile: https://github.com/alessandromazza98/revm/blob/eip-7212/crates/precompile/src/secp256r1.rs

The only difference is the address. The EIP says 0x19 while right now I used 0x0a only because of some assumptions that Revm uses about precompiles being in a crescent order without any wholes in between. But it is super easy to change that address.

I also wrote a little blog article to explain the steps if you are curios: Notion – The all-in-one workspace for your notes, tasks, wikis, and databases.

4 Likes

It’s a great contribution!

Can you elaborate on this more?

Can you explain more why current version wouldn’t support hash functions other than sha and keccak? EIP itself doesn’t have a restriction on which hash to use, so I think it should be possible to use it with, say, Poseidon or other ZK-friendly hashes.

  • If one want to tweak the precompile to compute u.G like in You can *kinda* abuse ECRECOVER to do ECMUL in secp256k1 today - Applications - Ethereum Research, the parity of the point is missing. you only obtain the x coordinates of the result (might be sufficient in many cases)

  • to use the precompile in a userOp, one will have to use it with the target hash function. As it is not strictly ecdsa (you have to sequence it with another call to the hash), why not designing uG+vQ as the precompile, which would have more use than only ECDSA ? Using UG+vQ, one can directly implement Schnorr. In my opinion there are 3 ways:
    ** precompile returns uG+vQ : can be used directly in many protocols (ECDSA, Schnorr)
    ** mimic ecrecover : backward compatibility for use cases using ecrecover on k1 without breaking APIs, can be used to compute uG+vQ, providing the hash as a witness
    ** ecdsa verification from hash (current specification) : only provide the x-value of the result uG+vQ if ‘abused’ not compatible with existing.

1 Like

Would you have the resulting gas cost of a single verification of this implementation pls ?

It should be 26974 units of gas

How is it calculated? It has to be constant for clients following the Final specification.

Sorry, maybe I did not understand properly the previous question.

The P256VERIFY precompile consumes a fixed amount of gas which is specified in the EIP itself, which is 3450

1 Like

I wasn’t clear, my question was about the cost of the REVM resulting gas cost for a verification without precompile.

Concerning the pricing of the precompile, sec256k1 allows fastest verification thanks to the GLV speed up, which is not possible over sec256r1. This speed up cut the cost by 50%. Following this logic the cost of the precompile (and the extra burden on nodes) should be 6000.

I don’t think that it depends on different clients.

My test cases show that p256verify is ~15% slower than ecrecover. Do you think that there is incorrect calculation or method? Maybe we should include comparisons for more clients.

Also, what do you mean by “extra burden”?

The fact that it is only 15% indicates that GLV method is not used in this specific implementation. Asymptotically sec256k1 is twice faster. This means that the precompile cost shall be doubled. This is fact I was describing as a 'burden". Replacing k1 by r1 would lead to more workload on nodes.

The test cases have run in the geth client. As geth is the major client with a huge use, I think that we can consider GLV not dominant or used in Ethereum and ignore the GLV performance boost of the k1.

So, I don’t think that we should change the gas cost.

Since it’s not a replacement for the k1 curve, why do you think that it’s a workload?

Couple of comments:

Indeed, I love the approach @ulerdogan although taking this contract address as the reference address can impact performance versus having an address with 38 zeros like… 0x10 ?

For reference, here the link to the EthCC talk on p256 “WebAuthn Optimization: optimizing ECC sec256r1

Regarding concerns on p256 (vs ed25519)

Audited implementation in most execution client languages are available, specifically for Verification afaIk. Constant-time is notably available in Go. Adding a precompile for this curve doesn’t delay support for other curve, I would argue this instead sets a template for other curves to be supported swiftly. Progressive support with a smartcontract first helps a lot Imho. Regarding concerns on the security of p256, it should be noted that this precompile improves smartwallets which themselves can hold rules to mitigate that risk.

Regarding the Verify vs Recover:

I would prefer to stick with Verify for readiness purposes rather than recover.

I implemented a smart contract and command-line wallet software that uses secp256r1 via FIDO2 security tokens at the HackMoney 2020 hackathon. Each signature verification cost about a million gas, but it did prove the concept:

The judging for this was quite amusing. At the end, in the question period, it became clear that the panel thought “security tokens” referred to “ERC-20 token securities”. Once they understood the concept, it was dismissed since “why not just get a ledger?”.

BTW I see some references to webauthn. Has anyone actually tried this? When I looked into it, it didn’t seem like you could use this without tying your wallet to a particular DNS domain name, or possibly self-hosting at localhost or something – both bad UX. It might work better with CTAP2 over WebUSB. My defido2 app uses CTAP2, abstracted by libfido2.

Little known fact: recent-ish YubiKey firmware in fact supports secp256k1 (and ed25519 and others), so if you are using a recent YubiKey over CTAP2 you may not even need a new pre-compile. I wanted to link to the yubi docs, but new users can’t include so many links apparently.

2 Likes

Hello, thanks for highliting this implementation. Sorry that the jury didn’t not understood better the fact that it provides the highest security level you can have with a device we all already have in our pocket.

The point with secp256r1 is to benefit from smartphone secure enclave, giving access to the best security you can have with a smartphone. The day Ed25519 is implemented, it will be superior (might happen from 6 month to several years). I doubt secp256k1 will ever be.

This is not the subject here, but Yubikey are not more UX friendly than a hardware wallet. From my biased perspective (i have conflict of interest in the next sentence), if you are to buy a device, buy a Ledger. Fido is implemented as a secondary feature (https://support.ledger.com/hc/en-us/articles/115005198545-FIDO-U2F?docs=true), and its core function is cryptocurrencies handling.

I disagree with adding SECP256K1 as a precompiled contract, for the following reasons:

  1. SECP256R1 may have a backdoor (although there are no known public attacks).
    • Given that contract wallets may become widely adopted, this is a risk that cannot be ignored.
  2. Device-dependent SECP256R1 signatures may be vulnerable to attacks, such as:
    • Some device manufacturers might leak private keys stored in a secure chip to law enforcement agencies under certain circumstances.
    • Some device manufacturers might submit your device’s public key to law enforcement agencies, potentially exposing the purchase records of anonymous wallet owners on the blockchain.

But we can’t ignore the advantages of SECP256K1 widely supported by devices. We can address the drawbacks of SECP256K1 through zk-proof while harnessing its benefits!

Fortunately, webauthn-halo2 provides inspiration, as it can address these issues to some extent:

  1. Gas:
    • While ZKP in contracts often result in high gas cost, it’s not an absolute rule. Some algorithms can bring gas advantages through clever circuit design. For example, the gas consumption of webauthn-halo2 is only half of that of conventional signature algorithms! ( AND Consider batch proofs again! The cost of zkp will approach zero! )
  2. Backdoors and Manufacturer Attacks:
    • In on-chain contracts, we cannot directly store SECP256R1 public keys but should store the hash value of the public key. To prevent “rainbow table attacks,” this hashing algorithm should accept a secret “setting,” such as the zkp-friendly Pedersen-Hash. Generating this hash requires user input (such as the user wallet’s unlock password).

those are my main points. Thank you.

[The above content is from the article I previously posted]

1 Like

After adding precompiled contracts, ‘backdoor’ and ‘vendor attacks’ will become like the Sword of Damocles, making the entire ecosystem difficult to escape from. If ‘backdoor’ and ‘vendor attacks’ were to come true, it would plunge the entire ecosystem into panic, even if the probability is extremely low~

  • Argument for device-dependant also hold for the native sec256k1. If Ledger trapped its device, 6M users may be rugged (tinfoil scenario, not believing it).
  • SHA3/SHA256 aez out of reach of a rainbow attack, no need for Pedersen to have a ‘secret’ as setting. This is what HMAC does and can be efficiently performed by the related opcodes.
  • If sec256r1 appears to be trapped, most of tls connections, mastercards EMV are exposed. While Ethereum is important, let’s not forget that it is still a grain of sand compared to those. And as opposite to those, ERC4337 will allow instant replacement of the signer. (I also expect any decent smart account to integrate fallback solutions from the start).

Secp256r1 precompile shall not aim to replace secp256k1, only provides an option for a lighter UX. From my point of view it aims to target low value tx (as your contact less VISA/MASTERCARD, limited to low amounts) with fast UX. For larger stakes, use multisig and solution like gnosis-safe, (or other multisig base framework, just citing the most known here).

2 Likes

Hey guys, FWIW, ~28hrs ago I decided to not touch grass this weekend and instead write the first ever P256 signature verification contract in :snake:Vyper. My Vyper contract passes all tests of the original Daimo implementation in Solidity! You can find my repo here. Furthermore, I deployed the contract to Sepolia, Goerli and Holesky:

7 Likes