# P-256 (secp256r1)

```c
#define FIO_P256
#include "fio-stl.h"
```

P-256 is the NIST `secp256r1` curve used by TLS and certificate tooling. This module covers two jobs: ECDSA signatures over SHA-256 message hashes, and ECDH shared-secret creation.

**Security note:** this implementation has not been independently audited. Use it when the zero-dependency STL path matters; prefer a tested crypto library for long-lived keys, compliance, or high-value trust decisions.

## What It Provides

| Use | Function | Notes |
| --- | --- | --- |
| Sign | `fio_ecdsa_p256_sign` | Creates a DER-encoded ECDSA signature from a 32-byte SHA-256 hash. |
| Verify DER signature | `fio_ecdsa_p256_verify` | Accepts `SEQUENCE { r INTEGER, s INTEGER }` and a 65-byte uncompressed public key. |
| Verify raw signature | `fio_ecdsa_p256_verify_raw` | Accepts raw 32-byte `r`, `s`, `x`, and `y` values. |
| Key pair | `fio_p256_keypair` | Produces a 32-byte secret key and a 65-byte uncompressed public key. |
| Shared secret | `fio_p256_shared_secret` | Accepts compressed or uncompressed peer public keys and returns the x-coordinate. |

The curve parameters are the standard P-256 parameters from NIST FIPS 186-4:

- `p = 2^256 - 2^224 + 2^192 + 2^96 - 1`
- `n = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551`
- curve equation: `y² = x³ - 3x + b (mod p)`

## ECDSA Signatures

### `fio_ecdsa_p256_sign`

```c
SFUNC int fio_ecdsa_p256_sign(uint8_t *sig,
                              size_t *sig_len,
                              size_t sig_capacity,
                              const uint8_t msg_hash[32],
                              const uint8_t secret_key[32]);
```

Signs a 32-byte SHA-256 message hash. The function writes a DER-encoded signature to `sig` and stores the actual length in `sig_len`.

- `sig_capacity` must be at least `72` bytes.
- `secret_key` is a 32-byte big-endian scalar and must be in the valid range `1..n-1`.
- The function generates a random ECDSA nonce internally and retries invalid nonces.
- Returns `0` on success, `-1` on invalid input or signing failure.

It signs the hash you give it; it does not hash the original message. No sneaky kitchen work here.

### `fio_ecdsa_p256_verify`

```c
SFUNC int fio_ecdsa_p256_verify(const uint8_t *sig,
                                size_t sig_len,
                                const uint8_t *msg_hash,
                                const uint8_t *pubkey,
                                size_t pubkey_len);
```

Verifies a DER-encoded ECDSA signature against a 32-byte SHA-256 hash.

- `sig` is a DER `SEQUENCE { r INTEGER, s INTEGER }`.
- `msg_hash` is exactly 32 bytes.
- `pubkey` must be an uncompressed P-256 public key: `0x04 || x || y`.
- `pubkey_len` must be `65`.
- Returns `0` for a valid signature, `-1` for invalid input or a bad signature.

### `fio_ecdsa_p256_verify_raw`

```c
SFUNC int fio_ecdsa_p256_verify_raw(const uint8_t r[32],
                                    const uint8_t s[32],
                                    const uint8_t msg_hash[32],
                                    const uint8_t pubkey_x[32],
                                    const uint8_t pubkey_y[32]);
```

Verifies a signature when `r` and `s` are already decoded. Public-key coordinates are 32-byte big-endian values.

The verifier checks that `r` and `s` are in range, checks the public point is on the P-256 curve, performs the ECDSA verification equation, and returns `0` only when the signature matches.

## ECDH Key Exchange

### `fio_p256_keypair`

```c
SFUNC int fio_p256_keypair(uint8_t secret_key[32], uint8_t public_key[65]);
```

Generates a P-256 key pair.

- `secret_key` receives a 32-byte scalar.
- `public_key` receives `0x04 || x || y` (65 bytes).
- Returns `0` on success, `-1` on bad arguments or random generation failure.

### `fio_p256_shared_secret`

```c
SFUNC int fio_p256_shared_secret(uint8_t shared_secret[32],
                                 const uint8_t secret_key[32],
                                 const uint8_t *their_public_key,
                                 size_t their_public_key_len);
```

Computes a P-256 ECDH shared secret using your secret key and their public key.

- `secret_key` is a 32-byte scalar in the valid range `1..n-1`.
- `their_public_key` may be uncompressed (`65` bytes, `0x04 || x || y`) or compressed (`33` bytes, `0x02/0x03 || x`).
- The peer point is decompressed when needed and checked against the curve.
- `shared_secret` receives the 32-byte x-coordinate of the result.
- Returns `0` on success, `-1` on invalid input, invalid point, point at infinity, or all-zero result.

Run the shared secret through a KDF such as HKDF before using it as an encryption key. Raw ECDH output is an ingredient, not dinner.

## Example

```c
#define FIO_P256
#define FIO_SHA2
#include "fio-stl.h"

int main(void) {
  uint8_t secret_key[32];
  uint8_t public_key[65];
  if (fio_p256_keypair(secret_key, public_key))
    return 1;

  const char *message = "hello, p-256";
  fio_u256 hash = fio_sha256(message, strlen(message));

  uint8_t sig[72];
  size_t sig_len = 0;
  if (fio_ecdsa_p256_sign(sig, &sig_len, sizeof(sig), hash.u8, secret_key))
    return 1;

  if (fio_ecdsa_p256_verify(sig, sig_len, hash.u8, public_key, 65))
    return 1;

  return 0;
}
```

------------------------------------------------------------
