#P-256 (secp256r1)
#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 - 1n = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551- curve equation:
y² = x³ - 3x + b (mod p)
#ECDSA Signatures
#fio_ecdsa_p256_sign
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_capacitymust be at least72bytes.secret_keyis a 32-byte big-endian scalar and must be in the valid range1..n-1.- The function generates a random ECDSA nonce internally and retries invalid nonces.
- Returns
0on success,-1on 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
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.
sigis a DERSEQUENCE { r INTEGER, s INTEGER }.msg_hashis exactly 32 bytes.pubkeymust be an uncompressed P-256 public key:0x04 || x || y.pubkey_lenmust be65.- Returns
0for a valid signature,-1for invalid input or a bad signature.
#fio_ecdsa_p256_verify_raw
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
SFUNC int fio_p256_keypair(uint8_t secret_key[32], uint8_t public_key[65]);Generates a P-256 key pair.
secret_keyreceives a 32-byte scalar.public_keyreceives0x04 || x || y(65 bytes).- Returns
0on success,-1on bad arguments or random generation failure.
#fio_p256_shared_secret
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_keyis a 32-byte scalar in the valid range1..n-1.their_public_keymay be uncompressed (65bytes,0x04 || x || y) or compressed (33bytes,0x02/0x03 || x).- The peer point is decompressed when needed and checked against the curve.
shared_secretreceives the 32-byte x-coordinate of the result.- Returns
0on success,-1on 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
#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;
}