Home

Awesome

Efficient secp256r1 (aka nist-p256) ECDSA in Cairo

The purpose of this library is to provide a gas-efficient implementation of secp256r1 signature validation in Cairo.

Current implementation performs ECDSA in 180K Cairo steps on average on Project Wycheproof test suite.

Background

Allowing transactions to be signed and validated using the secp256r1 curve enables great end-user experience in the form of signing transactions using the biometrics on the user's device.

On top of great UX, this also have the added benefit of moving away from seed phrases to better security in modern mobile-devices / laptops, and superior security when the user's device supports a dedicated security chip (e.g. Android's Secure Element and Apple's Secure Enclave etc.).

Since secp256r1 ECDSA is not native to Cairo (i.e. it does not have a dedicated Builtin), the Gas cost incurred in validation of the signature is very high. In this library we aim to optimize that as much as possible.

Implementation Notes

We've adapted cairo-lang's secp256k1 ECDSA validation implementation. We had to modify some field operations and handling of BigInt3 limbs as secp256r1's operations only very tightly fit into the BigInt3 representation. Also, cairo-lang uses the public-key recovery algorithm for ECDSA validation while this library uses straight-forward validation since in a secure-hardware signing setup, we don't have v which is necessary for correct public-key recovery.

Some hints were modified to accomodate the above, these will be introduced as part of cairo-lang version 0.11.0. To use this prior to that you will have to apply the patch at cairo-lang-secp256r1-hints.patch on your python virtual env.

patch -s -p2 -d venv/lib/python3.9/site-packages/ < cairo-lang-secp256r1-hints.patch

API

In src/secp256r1/signature.cairo:

verify_secp256r1_signature(msg_hash: BigInt3, r: BigInt3, s: BigInt3, public_key: EcPoint)

Running tests

We adapted Google's Project Wycheproof tests with the exception of asn.1 related tests since our implementation assumes that (r, s) are sent in an already decoded form.

to run tests:

pytest tests/test_secp256r1.py

We kept the same naming conventions and test ids from the original test-suite so filtering on a specific test-case can be done as follows:

pytest tests/test_secp256r1.py -k tc-292

You can use cairo-nile to run coverage:

nile coverage