# `EEVM.Crypto.ECDSA`
[🔗](https://github.com/mw2000/eevm/blob/v0.1.0/lib/eevm/crypto/ecdsa.ex#L1)

ECDSA over the short-Weierstrass curves `y² = x³ + ax + b (mod p)` that
Ethereum uses, in pure Elixir:

- `:secp256k1` for ECRECOVER (`0x01`) and for transaction and EIP-7702
  authorization signatures: public-key recovery (`recover/5`) and
  deterministic signing (`sign/3`).
- `:p256` (NIST P-256, secp256r1) for P256VERIFY (`0x100`, EIP-7951):
  `verify/5`.

Both curves share one implementation of
[SEC 1 v2](https://www.secg.org/sec1-v2.pdf) §4.1. Points are computed in
Jacobian coordinates `{X, Y, Z}`, which stand for the affine point
`(X / Z², Y / Z³)`, so adding and doubling need no field inversion; the
point at infinity is `:infinity`. Scalar multiplication recodes scalars in
width-w NAF, so about one bit in six or nine costs an addition. Each base
point gets a table of its odd multiples; the base point `G`'s table is wide
and built at compile time. `u₁·G + u₂·Q` shares one chain of doublings
between both products (Shamir's trick). On secp256k1 the GLV endomorphism
splits each scalar into two halves of about 128 bits, which halves the
doublings.

Hashes and private keys are 32-byte big-endian binaries; `r`, `s` and
coordinates are integers.

This code is not constant-time. eevm verifies and recovers public
signatures; `sign/3` serves tests, tooling and examples, not keys that
must resist timing side channels.

# `curve`

```elixir
@type curve() :: :secp256k1 | :p256
```

A supported curve.

# `point`

```elixir
@type point() :: {non_neg_integer(), non_neg_integer()}
```

An affine point `{x, y}`.

# `order`

```elixir
@spec order(curve()) :: pos_integer()
```

Returns the order `n` of `curve`'s base point.

## Example

    iex> EEVM.Crypto.ECDSA.order(:secp256k1)
    0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141

# `public_key`

```elixir
@spec public_key(curve(), &lt;&lt;_::256&gt;&gt;) ::
  {:ok, point()} | {:error, :invalid_private_key}
```

Returns the public key `d·G` of the 32-byte private key `d`, or
`{:error, :invalid_private_key}` unless `0 < d < n`.

## Example

    iex> {:ok, {x, _y}} = EEVM.Crypto.ECDSA.public_key(:secp256k1, <<1::256>>)
    iex> x == 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
    true

# `recover`

```elixir
@spec recover(curve(), &lt;&lt;_::256&gt;&gt;, non_neg_integer(), non_neg_integer(), 0..3) ::
  {:ok, point()} | {:error, :invalid_signature}
```

Recovers the public key that produced the signature `(r, s)` over the
32-byte `hash` (SEC 1 §4.1.6).

`recovery_id` picks the ephemeral point `R`: bit 0 is the parity of its
`y`, and bit 1 says its `x` is `r + n` rather than `r`. Any `s` in
`[1, n)` is accepted; enforcing EIP-2's low `s` is the caller's job.

Returns `{:error, :invalid_signature}` when `r` or `s` is out of range,
no curve point has that `x`, or the result is the point at infinity.

# `sign`

```elixir
@spec sign(curve(), &lt;&lt;_::256&gt;&gt;, &lt;&lt;_::256&gt;&gt;) ::
  {:ok, {pos_integer(), pos_integer(), 0..3}} | {:error, :invalid_private_key}
```

Signs the 32-byte `hash` with the 32-byte `private_key`.

The nonce is deterministic (RFC 6979 with HMAC-SHA256), and `s` is
normalised to the low half of `[1, n)` (EIP-2), flipping the recovery id
to match, as libsecp256k1 does. Returns `{:ok, {r, s, recovery_id}}`, or
`{:error, :invalid_private_key}` unless `0 < d < n`.

# `verify`

```elixir
@spec verify(curve(), &lt;&lt;_::256&gt;&gt;, non_neg_integer(), non_neg_integer(), point()) ::
  boolean()
```

Verifies the signature `(r, s)` over the 32-byte `hash` against
`public_key` (SEC 1 §4.1.4).

False when `r` or `s` is outside `(0, n)`, `public_key` is not on the
curve (which rules out `(0, 0)`), or `R' = u₁·G + u₂·Q` is the point at
infinity; otherwise true when `R'.x mod n == r`. This matches EIP-7951.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
