A small ECDH and ECDSA implementation for 32-bit microcontrollers. See easy-ecc for a fast and secure pure-C implementation for *nix and Windows.
To reduce code size, all large integers are represented using little-endian words - so the least significant word is first. For example, the standard representation of the prime modulus for the curve secp128r1 is FFFFFFFD FFFFFFFF FFFFFFFF FFFFFFFF
; in micro-ecc, this would be represented as uint32_t p[4] = {0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffd};
.
You can use the ecc_bytes2native()
and ecc_native2bytes()
functions to convert between the native integer representation and the standardized octet representation.
You can use the makekeys
program in the apps
directory to generate keys (on Linux or OS X). You can run make
in that directory to build for your native platform (or use emk). To generate a single public/private key pair, run makekeys
. It will print out the public and private keys in a representation suitable to be copied into your source code. You can generate multiple key pairs at once using makekeys <n>
to generate n keys.
I recommend just copying (or symlink) ecc.h and ecc.c into your project. Then just #include "ecc.h"
to use the micro-ecc functions.
See ecc.h for documentation for each function.
Available optimizations are:
ECC_SQUARE_FUNC
- Use a separate function for squaring.ECC_ASM
- Choose the type of inline assembly to use. The available options are ecc_asm_none
, ecc_asm_thumb
, ecc_asm_thumb2
, and ecc_asm_arm
.All tests were performed on an LPC1114 running at 48MHz. The listed code sizes include all code and data required by the micro-ecc library (including aebi_lmul
when not using assembly), but do not include the sizes of the code using the library functions.
The following compiler options were used (using gcc 4.8):
-mcpu=cortex-m0 -mthumb -ffunction-sections -fdata-sections -Os
-mcpu=cortex-m0 -mthumb -nostartfiles -nostdlib -Wl,--gc-sections
These tests were performed using the curve secp192r1. Only ECDH code was used (no ECDSA). When enabled, ECC_ASM was defined to ecc_asm_thumb
.
Optimizations | ECDH time (ms) | Code size (bytes) |
---|---|---|
none | 438.9 | 2212 |
ECC_SQUARE_FUNC | 406.7 | 2412 |
ECC_ASM | 186.3 | 2036 |
both | 175.7 | 2170 |
In these tests, ECC_ASM
was defined to ecc_asm_thumb
and ECC_SQUARE_FUNC
was defined to 1
in all cases.
secp128r1 | secp192r1 | secp256r1 | secp384r1 | |
---|---|---|---|---|
ECDH time (ms): | 89.9 | 175.7 | 465.1 | 1370.3 |
Code size (bytes): | 2324 | 2170 | 2512 | 2244 |
In these tests, the measured speed is the time to verify an ECDSA signature. The measured code size is the combined code size for ECDH and ECDSA. ECC_ASM
was defined to ecc_asm_thumb
and ECC_SQUARE_FUNC
was defined to 1
in all cases.
secp128r1 | secp192r1 | secp256r1 | secp384r1 | |
---|---|---|---|---|
ECDSA verify time (ms): | 106.7 | 217.1 | 555.2 | 1576.1 |
Code size (bytes): | 3138 | 3014 | 3334 | 3158 |
In these tests, ECC_ASM
was defined to ecc_asm_thumb
and ECC_SQUARE_FUNC
was defined to 1
in all cases. The table values are the maximum possible stack usage for each function, in bytes.
secp128r1 | secp192r1 | secp256r1 | secp384r1 | |
---|---|---|---|---|
ecc_make_key() | 336 | 416 | 528 | 728 |
ecc_valid_public_key() | 192 | 232 | 304 | 424 |
ecdh_shared_secret() | 360 | 456 | 584 | 816 |
ecdsa_sign() | 400 | 504 | 640 | 888 |
ecdsa_verify() | 400 | 520 | 672 | 952 |