$npx -y skills add easyzoom/aix-skills --skill micro-ecc-integrationUse when integrating, porting, or debugging micro-ecc (uECC) ECDH, ECDSA, key generation, uECC_set_rng, signatures, curve selection, or key/signature byte formats on an MCU
| 1 | # micro-ecc Integration |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | Use this skill to integrate micro-ecc (kmackay/micro-ecc, header `uECC.h`) by treating randomness, key storage, curve choice, and test vectors as security-critical. ECC that compiles but never called `uECC_set_rng()` or uses mismatched key byte formats is not working. The core key generation, signing, verification, and ECDH functions return `1` on success and `0` on failure (`uECC_verify` returns `1` only for a valid signature); the size-query helpers instead return a byte count, and `uECC_compress`/`uECC_decompress` return `void`. |
| 6 | |
| 7 | ## When To Use |
| 8 | |
| 9 | Use this skill when: |
| 10 | |
| 11 | - The user wants ECDH (`uECC_shared_secret`), ECDSA (`uECC_sign`/`uECC_verify`), or key generation (`uECC_make_key`) on an MCU using micro-ecc. |
| 12 | - The issue involves `uECC_make_key`/`uECC_sign` returning `0`, bad signatures, key mismatch, RNG, curve selection, endian/format mismatch, or slow scalar multiplication. |
| 13 | - The project uses `uECC.h`, `uECC.c`, a `uECC_Curve`, or `uECC_set_rng`. |
| 14 | |
| 15 | Do not use this skill for full TLS stacks. Use `mbedtls-integration` for TLS. For AES/SHA/HMAC primitives, use `tinycrypt-integration`. |
| 16 | |
| 17 | ## First Questions |
| 18 | |
| 19 | Ask for: |
| 20 | |
| 21 | - Curve and operation: `uECC_secp160r1`, `uECC_secp192r1`, `uECC_secp224r1`, `uECC_secp256r1`, or `uECC_secp256k1`; and ECDH vs ECDSA. |
| 22 | - Target MCU, compiler, and whether a hardware TRNG/crypto peripheral exists. |
| 23 | - The RNG source wired into `uECC_set_rng()` and the key storage policy. |
| 24 | - Public/private key byte format and endian expectations of the peer (`uECC_VLI_NATIVE_LITTLE_ENDIAN` setting, compressed vs uncompressed). |
| 25 | - Test vector, signature, or verification failure details, and the return code seen. |
| 26 | |
| 27 | ## Integration Checklist |
| 28 | |
| 29 | 1. Choose curve deliberately. |
| 30 | Pick a `uECC_Curve` via `uECC_secp256r1()` (or the peer's curve) and enable it with the matching `uECC_SUPPORTS_secp256r1` macro. Disable unused curves to save flash. |
| 31 | |
| 32 | 1. Provide a real RNG first. |
| 33 | Register `uECC_set_rng(uECC_RNG_Function fn)` where `fn` has signature `int fn(uint8_t *dest, unsigned size)` and returns `1` when `dest` is filled with good entropy, `0` otherwise. Without a valid RNG, both `uECC_make_key` and `uECC_sign` return `0`. Only `uECC_sign_deterministic` (RFC 6979-style deterministic nonce, needs a `uECC_HashContext`) works without an RNG. |
| 34 | |
| 35 | 1. Size every buffer from the curve. |
| 36 | Always use `uECC_curve_private_key_size(curve)` and `uECC_curve_public_key_size(curve)` instead of hard-coded lengths or arithmetic on each other. The public key is `x||y` and equals `uECC_curve_public_key_size(curve)`; the private key equals `uECC_curve_private_key_size(curve)`. These are equal to 2x the field size and 1x the field size respectively for every curve EXCEPT `secp160r1`, where the private key is 21 bytes (the order needs an extra byte; the leading byte is often `0x00`) while the public key is 40 bytes. Never derive public-key or signature length from the private-key length. |
| 37 | |
| 38 | 1. Match key/signature byte format. |
| 39 | Default is big-endian; public keys are raw `x||y` with NO `0x04` uncompressed prefix, so prepend `0x04` for SEC1/OpenSSL peers. If interop breaks, check `uECC_VLI_NATIVE_LITTLE_ENDIAN` matches both sides; keys/signatures across the two settings are incompatible. The signature is `r||s` and its length equals the public-key length (`uECC_curve_public_key_size(curve)`) -- for `secp160r1` that is 40 bytes, not `2 * private_key_size` (peers such as python-ecdsa may instead expect 42). |
| 40 | |
| 41 | 1. Sign the hash, not the message. |
| 42 | `uECC_sign(private_key, hash, hash_size, signature, curve)` and `uECC_verify` take a message digest plus `hash_size`; hash the message yourself (e.g. SHA-256) and pass the digest. A hash longer than the curve order is truncated internally. |
| 43 | |
| 44 | 1. Handle compressed points if needed. |
| 45 | With `uECC_SUPPORT_COMPRESSED_POINT`, use `uECC_compress`/`uECC_decompress`; a compressed point is one coordinate plus a leading parity byte, i.e. `(uECC_curve_public_key_size(curve) / 2) + 1` bytes. Validate imported keys with `uECC_valid_public_key`. |
| 46 | |
| 47 | 1. Protect secrets. |
| 48 | Do not log private keys, the ECDSA nonce, or the shared secret from `uECC_shared_secret`. |
| 49 | |
| 50 | ## Common Failures |
| 51 | |
| 52 | - `uECC_set_rng()` never called, so `uECC_make_key`/`uECC_sign` silently return `0`. |
| 53 | - RNG callback returns `0` (or returns success while producing weak/deterministic bytes) in production. |
| 54 | - Public key sent with or expecting a `0x04` prefix; micro-ecc uses raw `x||y` without it. |
| 55 | - `secp160r1` private key allocated as 20 bytes instead of 21, corrupting adjacent memory or the key. |
| 56 | - Deriving signature or public-key length from the private-key length; on `secp160r1` this over-allocates (42 vs 40) and breaks interop. |
| 57 | - `uECC_VLI_NATIVE_LITTLE_ENDIAN` mismatch between device and peer, so by |