Merge pull request #650 from dgarske/c28x_ecdsa_bench
Add ECDSA and SHA-384 image-verify timings to the TI C2000 examplepull/649/head
commit
321f4578a1
|
|
@ -0,0 +1,42 @@
|
|||
/* ecc_p384_kat.h - deterministic ECDSA P-384 (SECP384R1) known-answer vector.
|
||||
*
|
||||
* Source: RFC 6979 Appendix A.2.6 (P-384), message "sample", hash SHA-384.
|
||||
* The same vector wolfCrypt's own ecc384_test_deterministic_k() uses. The
|
||||
* digest is not stored: the device hashes "sample" with SHA-384 itself, so the
|
||||
* KAT covers the hash-to-verify chain rather than just the curve math.
|
||||
*
|
||||
* Brace-init byte arrays (NOT "\x.." string literals): on cl2000 a char[]/byte[]
|
||||
* initialized from a "\x.." string sign-extends bytes >= 0x80 into the 16-bit
|
||||
* cell; a brace-init list stores clean octets.
|
||||
*/
|
||||
#ifndef ECC_P384_KAT_H
|
||||
#define ECC_P384_KAT_H
|
||||
|
||||
/* Public key Q = (Ux, Uy), 48 bytes each, big-endian. */
|
||||
static const unsigned char kat_p384_qx[48] = {
|
||||
0xEC,0x3A,0x4E,0x41,0x5B,0x4E,0x19,0xA4,0x56,0x86,0x18,0x02,0x9F,0x42,0x7F,0xA5,
|
||||
0xDA,0x9A,0x8B,0xC4,0xAE,0x92,0xE0,0x2E,0x06,0xAA,0xE5,0x28,0x6B,0x30,0x0C,0x64,
|
||||
0xDE,0xF8,0xF0,0xEA,0x90,0x55,0x86,0x60,0x64,0xA2,0x54,0x51,0x54,0x80,0xBC,0x13
|
||||
};
|
||||
static const unsigned char kat_p384_qy[48] = {
|
||||
0x80,0x15,0xD9,0xB7,0x2D,0x7D,0x57,0x24,0x4E,0xA8,0xEF,0x9A,0xC0,0xC6,0x21,0x89,
|
||||
0x67,0x08,0xA5,0x93,0x67,0xF9,0xDF,0xB9,0xF5,0x4C,0xA8,0x4B,0x3F,0x1C,0x9D,0xB1,
|
||||
0x28,0x8B,0x23,0x1C,0x3A,0xE0,0xD4,0xFE,0x73,0x44,0xFD,0x25,0x33,0x26,0x47,0x20
|
||||
};
|
||||
|
||||
/* Signature (r, s), 48 bytes each, big-endian. */
|
||||
static const unsigned char kat_p384_r[48] = {
|
||||
0x94,0xED,0xBB,0x92,0xA5,0xEC,0xB8,0xAA,0xD4,0x73,0x6E,0x56,0xC6,0x91,0x91,0x6B,
|
||||
0x3F,0x88,0x14,0x06,0x66,0xCE,0x9F,0xA7,0x3D,0x64,0xC4,0xEA,0x95,0xAD,0x13,0x3C,
|
||||
0x81,0xA6,0x48,0x15,0x2E,0x44,0xAC,0xF9,0x6E,0x36,0xDD,0x1E,0x80,0xFA,0xBE,0x46
|
||||
};
|
||||
static const unsigned char kat_p384_s[48] = {
|
||||
0x99,0xEF,0x4A,0xEB,0x15,0xF1,0x78,0xCE,0xA1,0xFE,0x40,0xDB,0x26,0x03,0x13,0x8F,
|
||||
0x13,0x0E,0x74,0x0A,0x19,0x62,0x45,0x26,0x20,0x3B,0x63,0x51,0xD0,0xA3,0xA9,0x4F,
|
||||
0xA3,0x29,0xC1,0x45,0x78,0x6E,0x67,0x9E,0x7B,0x82,0xC7,0x1A,0x38,0x62,0x8A,0xC8
|
||||
};
|
||||
|
||||
/* The message that was signed; the device computes SHA-384 over it. */
|
||||
static const char kat_p384_msg[] = "sample";
|
||||
|
||||
#endif /* ECC_P384_KAT_H */
|
||||
|
|
@ -235,10 +235,18 @@ extern "C" {
|
|||
/* ------------------------------------------------------------------------- */
|
||||
#undef HAVE_ECC
|
||||
#define HAVE_ECC
|
||||
#undef ECC_USER_CURVES /* build only the curves we name (just P-256) */
|
||||
#undef ECC_USER_CURVES /* build only the curves named below: P-256, */
|
||||
/* plus P-384 when WOLF_ECC384 is set */
|
||||
#define ECC_USER_CURVES
|
||||
#undef HAVE_ECC256
|
||||
#define HAVE_ECC256
|
||||
#ifdef WOLF_ECC384
|
||||
/* SECP384R1 alongside P-256 (ECC384=1 build); pairs with SHA-384. */
|
||||
#undef HAVE_ECC384
|
||||
#define HAVE_ECC384
|
||||
#undef WOLFSSL_SP_384
|
||||
#define WOLFSSL_SP_384
|
||||
#endif
|
||||
#undef HAVE_ECC_VERIFY
|
||||
#define HAVE_ECC_VERIFY
|
||||
#undef HAVE_ECC_SIGN
|
||||
|
|
@ -254,8 +262,12 @@ extern "C" {
|
|||
#define WOLFSSL_HAVE_SP_ECC
|
||||
#undef WOLFSSL_SP_NO_MALLOC
|
||||
#define WOLFSSL_SP_NO_MALLOC
|
||||
#ifndef WOLF_ECC_FAST
|
||||
/* Small (looped) SP code by default; ECCFAST=1 picks the windowed SP path,
|
||||
* which trades flash for roughly ten times the ECDSA throughput. */
|
||||
#undef WOLFSSL_SP_SMALL
|
||||
#define WOLFSSL_SP_SMALL
|
||||
#endif
|
||||
#undef SP_WORD_SIZE
|
||||
#define SP_WORD_SIZE 32
|
||||
/* C28x int is 16-bit (WC_16BIT_CPU) but we use 32-bit SP digits + octet-wise
|
||||
|
|
|
|||
|
|
@ -91,6 +91,17 @@ WC_SRCS := \
|
|||
$(WOLFROOT)/wolfcrypt/src/wc_mldsa.c \
|
||||
$(WOLFROOT)/wolfcrypt/src/random.c
|
||||
|
||||
# ECC384=1 adds SECP384R1, ECCFAST=1 drops WOLFSSL_SP_SMALL, and ECCBENCH=1
|
||||
# adds the ECDSA / SHA-384 image-verify timing harness. All three imply ECC.
|
||||
ECC384 ?= 0
|
||||
ECCFAST ?= 0
|
||||
ECCBENCH ?= 0
|
||||
ifneq ($(ECC384)$(ECCFAST)$(ECCBENCH),000)
|
||||
# override: a command-line ECC=0 alongside one of these would otherwise leave
|
||||
# WOLF_ECC384 defined with the ECC sources and HAVE_ECC block compiled out.
|
||||
override ECC := 1
|
||||
endif
|
||||
|
||||
# ECC=1 adds ECDSA/ECDH over SECP256R1 via SP single-precision math.
|
||||
ECC ?= 0
|
||||
ifeq ($(ECC),1)
|
||||
|
|
@ -102,6 +113,19 @@ ifeq ($(ECC),1)
|
|||
$(WOLFROOT)/wolfcrypt/src/sp_c32.c
|
||||
endif
|
||||
|
||||
ifeq ($(ECC384),1)
|
||||
CFLAGS += --define=WOLF_ECC384
|
||||
endif
|
||||
ifeq ($(ECCFAST),1)
|
||||
CFLAGS += --define=WOLF_ECC_FAST
|
||||
endif
|
||||
# The timing harness runs on its own: the wolfcrypt test and benchmark are left
|
||||
# out so the run is short and the heap uncontended.
|
||||
ifeq ($(ECCBENCH),1)
|
||||
CFLAGS += --define=WOLF_ECC_BENCH --define=NO_CRYPT_TEST \
|
||||
--define=NO_CRYPT_BENCHMARK
|
||||
endif
|
||||
|
||||
# MLKEM=1 adds ML-KEM-768 (FIPS 203) via the wolfCrypt C implementation.
|
||||
MLKEM ?= 0
|
||||
ifeq ($(MLKEM),1)
|
||||
|
|
|
|||
|
|
@ -90,6 +90,9 @@ Each is `make <NAME>=1` (default 0 unless noted), additive on top of the default
|
|||
| Option | Adds |
|
||||
|---|---|
|
||||
| `ECC=1` | ECDSA/ECDH over SECP256R1 (SP math) |
|
||||
| `ECC384=1` | Adds SECP384R1 (`HAVE_ECC384` + `WOLFSSL_SP_384`) |
|
||||
| `ECCFAST=1` | Drops `WOLFSSL_SP_SMALL` for the windowed SP path (~10x faster ECDSA, +30 KB flash for P-256). Needs a wolfSSL with the SP scalar-recode fix for 16-bit bytes; older trees fail to build with `identifier "int8_t" is undefined`. |
|
||||
| `ECCBENCH=1` | ECDSA sign/verify, ECDH and SHA-256/384 image-hash timings instead of the test/benchmark harness |
|
||||
| `MLKEM=1` | ML-KEM-768 (FIPS 203) |
|
||||
| `AES=1` | AES-CBC/CTR/CFB/GCM (table-driven, `GCM_SMALL`) |
|
||||
| `AESEXTRA=1` | AES-CMAC, AES-CCM, AES-GMAC (implies the AES core) |
|
||||
|
|
@ -136,6 +139,23 @@ Measured at 150 MHz (SHA-256 Hash-DRBG via `WOLFSSL_GENSEED_FORTEST`; build with
|
|||
| SHAKE128 / SHAKE256 | ~319 / 264 KiB/s |
|
||||
| RNG (Hash-DRBG) | ~122 KiB/s |
|
||||
|
||||
ECDSA and ECDH (@150 MHz, `ECC_TIMING_RESISTANT` on). The default `WOLFSSL_SP_SMALL` build keeps SP code small at a large cost in speed; `ECCFAST=1` selects the windowed SP path:
|
||||
|
||||
| Operation | Default SP | Windowed SP (`ECCFAST=1`) |
|
||||
|---|---|---|
|
||||
| ECDSA P-256 sign | ~350 ms/op | 46 ms/op |
|
||||
| ECDSA P-256 verify | ~635 ms/op | 64 ms/op |
|
||||
| ECDH P-256 agree | ~308 ms/op | 57 ms/op |
|
||||
| ECDSA P-384 sign | ~1280 ms/op | 98 ms/op |
|
||||
| ECDSA P-384 verify | ~2260 ms/op | 183 ms/op |
|
||||
| ECDH P-384 agree | ~1108 ms/op | 163 ms/op |
|
||||
|
||||
The default-SP column varies by a few percent run to run, since each run makes a fresh key and ECDSA verify is a public operation with no timing-resistance constraint.
|
||||
|
||||
The image hash walks a 4 KiB flash-resident block repeatedly to reach 128 KiB. That is equivalent to one sweep over a 128 KiB array on this part, which has no data cache in front of flash: measured on hardware, a true single pass took 0.740 s against 0.736 s for the repeated block. The small block is the default because a genuine 128 KiB octet array costs 256 KB of flash, one octet per 16-bit cell, and fills a whole flash bank. Build with `-DWOLF_IMG_BLK=131072` in `EXTRA_CFLAGS` for the single sweep.
|
||||
|
||||
For a secure-boot style check of a 128 KB flash image, the hash dominates once the windowed path is in use: SHA-384 over the image takes 0.75 s, giving 0.81 s for SHA-384 plus a P-256 verify and 0.93 s with P-384 (1.39 s and 2.96 s respectively on the default SP path). SHA-256 over the same image takes 0.46 s. Building with `EXTRA_CFLAGS="--opt_level=3 --opt_for_speed=5"` takes SHA-384 down to 0.64 s for about 7 KB more flash, but does not move the ECC math. The windowed path itself costs about 30 KB of flash for P-256 alone, 82 KB for both curves.
|
||||
|
||||
ML-DSA-87 (asymmetric, @150 MHz): verify 244 ms/op default, **189 ms/op** with `FASTVERIFY=1` and `--opt_level=3 --opt_for_speed=5` (23% faster, RAM 10.7 -> 23.9 KB, zero heap either way); keygen and signing also run (`SIGN=1`). ML-DSA-87 verify memory: ~10.7 KB total (key/workspace struct + ~2 KB stack, zero heap) with `WOLFSSL_MLDSA_VERIFY_SMALLEST_MEM` + `WOLFSSL_MLDSA_ASSIGN_KEY`.
|
||||
|
||||
## Memory notes
|
||||
|
|
|
|||
|
|
@ -118,6 +118,9 @@
|
|||
#endif
|
||||
#ifdef WOLF_ECC
|
||||
#include "ecc_p256_kat.h"
|
||||
#ifdef WOLF_ECC384
|
||||
#include "ecc_p384_kat.h"
|
||||
#endif
|
||||
#endif
|
||||
#ifdef WOLF_RSA
|
||||
#include "rsa2048_kat.h"
|
||||
|
|
@ -664,6 +667,372 @@ static void wolf_ecc_test(void)
|
|||
wc_ecc_free(&keyA);
|
||||
wc_FreeRng(&rng);
|
||||
}
|
||||
|
||||
#ifdef WOLF_ECC_BENCH
|
||||
/* Timings for a secure-boot style image check: hash a flash-resident image,
|
||||
* then one ECDSA verify. CPU Timer 0 is sampled every iteration so no single
|
||||
* interval can outrun the counter's ~28 s wrap. A benchmark that reports a
|
||||
* rate for work that failed is worse than one that reports nothing, so every
|
||||
* loop below stops at the first error and divides by the number of operations
|
||||
* that actually completed. */
|
||||
#ifndef WOLF_IMG_TOTAL
|
||||
#define WOLF_IMG_TOTAL 131072UL /* octets hashed in total */
|
||||
#endif
|
||||
#ifndef WOLF_IMG_BLK
|
||||
#define WOLF_IMG_BLK 4096U /* size of the flash-resident block */
|
||||
#endif
|
||||
#ifndef WOLF_IMG_CHUNK
|
||||
#define WOLF_IMG_CHUNK 4096U /* octets handed to each Update */
|
||||
#endif
|
||||
|
||||
/* const lands in .const, i.e. flash, so the hash reads at flash wait states
|
||||
* the way a real image check does rather than out of RAM. One octet per
|
||||
* 16-bit cell, matching how wolfCrypt addresses bytes on this target.
|
||||
*
|
||||
* By default the block is smaller than WOLF_IMG_TOTAL and is walked repeatedly
|
||||
* to reach the total, so this measures hashing 128 KiB of flash-resident data
|
||||
* rather than a single sweep over a 128 KiB address range. The two are
|
||||
* equivalent here: the C28x has no data cache in front of flash, and measuring
|
||||
* both on hardware gave 0.740 s for a true single pass over a 128 KiB array
|
||||
* against 0.736 s for a repeated 4 KiB block - within run-to-run spread. The
|
||||
* small block is the default because a genuine 128 KiB octet array costs 256 KB
|
||||
* of flash (one octet per 16-bit cell) and fills an entire flash bank. Build
|
||||
* with -DWOLF_IMG_BLK=131072 to do the single sweep instead. */
|
||||
static const unsigned char wolf_img[WOLF_IMG_BLK] = { 0 };
|
||||
|
||||
/* Hash WOLF_IMG_TOTAL octets of flash-resident data. */
|
||||
static void wolf_sha_image_bench(int use384)
|
||||
{
|
||||
static wc_Sha256 sha256;
|
||||
static wc_Sha384 sha384;
|
||||
unsigned char dig[WC_SHA384_DIGEST_SIZE];
|
||||
const char* nm = use384 ? "SHA-384" : "SHA-256";
|
||||
unsigned long off;
|
||||
double t;
|
||||
int ret;
|
||||
|
||||
ret = use384 ? wc_InitSha384(&sha384) : wc_InitSha256(&sha256);
|
||||
if (ret != 0) {
|
||||
printf("%s image bench: init FAIL ret=%d\r\n", nm, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
(void)current_time(1);
|
||||
for (off = 0; off < WOLF_IMG_TOTAL; off += WOLF_IMG_CHUNK) {
|
||||
unsigned long left = WOLF_IMG_TOTAL - off;
|
||||
word32 n = (word32)((left < WOLF_IMG_CHUNK) ? left : WOLF_IMG_CHUNK);
|
||||
/* walk within the block, wrapping when it is smaller than the total */
|
||||
unsigned long pos = off % (unsigned long)WOLF_IMG_BLK;
|
||||
|
||||
if (pos + n > (unsigned long)WOLF_IMG_BLK) {
|
||||
n = (word32)((unsigned long)WOLF_IMG_BLK - pos);
|
||||
}
|
||||
ret = use384 ? wc_Sha384Update(&sha384, wolf_img + pos, n)
|
||||
: wc_Sha256Update(&sha256, wolf_img + pos, n);
|
||||
(void)current_time(0);
|
||||
if (ret != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Only finalize a context whose updates all succeeded. */
|
||||
if (ret == 0) {
|
||||
ret = use384 ? wc_Sha384Final(&sha384, dig)
|
||||
: wc_Sha256Final(&sha256, dig);
|
||||
}
|
||||
t = current_time(0);
|
||||
|
||||
if (use384) {
|
||||
wc_Sha384Free(&sha384);
|
||||
}
|
||||
else {
|
||||
wc_Sha256Free(&sha256);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
printf("%s over %lu KiB image: FAIL ret=%d (no timing)\r\n",
|
||||
nm, WOLF_IMG_TOTAL / 1024UL, ret);
|
||||
return;
|
||||
}
|
||||
printf("%s over %lu KiB image: %.3f s\r\n", nm, WOLF_IMG_TOTAL / 1024UL, t);
|
||||
}
|
||||
|
||||
static void wolf_ecdsa_bench(int curveId, int keySz, int reps, const char* nm)
|
||||
{
|
||||
static ecc_key bk;
|
||||
static WC_RNG brng;
|
||||
static mp_int br;
|
||||
static mp_int bs;
|
||||
unsigned char dig[WC_SHA384_DIGEST_SIZE];
|
||||
double t;
|
||||
int i, ret, res = 0, done;
|
||||
int rngOk = 0, keyOk = 0, rOk = 0, sOk = 0;
|
||||
|
||||
/* A SHA-384 digest; ECDSA truncates it to the curve order for P-256. */
|
||||
XMEMSET(dig, 0xA5, sizeof(dig));
|
||||
|
||||
ret = wc_InitRng(&brng);
|
||||
if (ret == 0) {
|
||||
rngOk = 1;
|
||||
ret = wc_ecc_init(&bk);
|
||||
}
|
||||
if (ret == 0) {
|
||||
keyOk = 1;
|
||||
ret = wc_ecc_make_key_ex(&brng, keySz, &bk, curveId);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_set_rng(&bk, &brng);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = mp_init(&br);
|
||||
}
|
||||
if (ret == 0) {
|
||||
rOk = 1;
|
||||
ret = mp_init(&bs);
|
||||
}
|
||||
if (ret == 0) {
|
||||
sOk = 1;
|
||||
}
|
||||
if (ret != 0) {
|
||||
printf("ECDSA %s bench: setup FAIL ret=%d\r\n", nm, ret);
|
||||
goto bench_done;
|
||||
}
|
||||
|
||||
done = 0;
|
||||
(void)current_time(1);
|
||||
for (i = 0; i < reps; i++) {
|
||||
ret = wc_ecc_sign_hash_ex(dig, (word32)keySz, &brng, &bk, &br, &bs);
|
||||
(void)current_time(0);
|
||||
if (ret != 0) {
|
||||
break;
|
||||
}
|
||||
done++;
|
||||
}
|
||||
t = current_time(0);
|
||||
if (done == 0) {
|
||||
printf("ECDSA %s sign: FAIL ret=%d (no timing)\r\n", nm, ret);
|
||||
goto bench_done;
|
||||
}
|
||||
printf("ECDSA %s sign: %d ops in %.3f s = %.1f ms/op%s\r\n",
|
||||
nm, done, t, (t * 1000.0) / (double)done,
|
||||
(done < reps) ? " [STOPPED EARLY]" : "");
|
||||
|
||||
done = 0;
|
||||
(void)current_time(1);
|
||||
for (i = 0; i < reps; i++) {
|
||||
ret = wc_ecc_verify_hash_ex(&br, &bs, dig, (word32)keySz, &res, &bk);
|
||||
(void)current_time(0);
|
||||
if ((ret != 0) || (res != 1)) {
|
||||
break;
|
||||
}
|
||||
done++;
|
||||
}
|
||||
t = current_time(0);
|
||||
if (done == 0) {
|
||||
printf("ECDSA %s verify: FAIL ret=%d res=%d (no timing)\r\n",
|
||||
nm, ret, res);
|
||||
goto bench_done;
|
||||
}
|
||||
printf("ECDSA %s verify: %d ops in %.3f s = %.1f ms/op%s\r\n",
|
||||
nm, done, t, (t * 1000.0) / (double)done,
|
||||
(done < reps) ? " [STOPPED EARLY]" : "");
|
||||
|
||||
bench_done:
|
||||
if (sOk) {
|
||||
mp_clear(&bs);
|
||||
}
|
||||
if (rOk) {
|
||||
mp_clear(&br);
|
||||
}
|
||||
if (keyOk) {
|
||||
wc_ecc_free(&bk);
|
||||
}
|
||||
if (rngOk) {
|
||||
wc_FreeRng(&brng);
|
||||
}
|
||||
}
|
||||
|
||||
static void wolf_ecdh_bench(int curveId, int keySz, int reps, const char* nm)
|
||||
{
|
||||
static ecc_key ka;
|
||||
static ecc_key kb;
|
||||
static WC_RNG brng;
|
||||
static byte secret[48];
|
||||
word32 len = 0;
|
||||
double t;
|
||||
int i, ret, done;
|
||||
int rngOk = 0, kaOk = 0, kbOk = 0;
|
||||
|
||||
ret = wc_InitRng(&brng);
|
||||
if (ret == 0) {
|
||||
rngOk = 1;
|
||||
ret = wc_ecc_init(&ka);
|
||||
}
|
||||
if (ret == 0) {
|
||||
kaOk = 1;
|
||||
ret = wc_ecc_init(&kb);
|
||||
}
|
||||
if (ret == 0) {
|
||||
kbOk = 1;
|
||||
ret = wc_ecc_make_key_ex(&brng, keySz, &ka, curveId);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_make_key_ex(&brng, keySz, &kb, curveId);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_set_rng(&ka, &brng);
|
||||
}
|
||||
if (ret != 0) {
|
||||
printf("ECDH %s bench: setup FAIL ret=%d\r\n", nm, ret);
|
||||
goto ecdh_done;
|
||||
}
|
||||
|
||||
done = 0;
|
||||
(void)current_time(1);
|
||||
for (i = 0; i < reps; i++) {
|
||||
len = (word32)sizeof(secret);
|
||||
ret = wc_ecc_shared_secret(&ka, &kb, secret, &len);
|
||||
(void)current_time(0);
|
||||
if (ret != 0) {
|
||||
break;
|
||||
}
|
||||
done++;
|
||||
}
|
||||
t = current_time(0);
|
||||
if (done == 0) {
|
||||
printf("ECDH %s agree: FAIL ret=%d (no timing)\r\n", nm, ret);
|
||||
goto ecdh_done;
|
||||
}
|
||||
printf("ECDH %s agree: %d ops in %.3f s = %.1f ms/op (len=%lu)%s\r\n",
|
||||
nm, done, t, (t * 1000.0) / (double)done, (unsigned long)len,
|
||||
(done < reps) ? " [STOPPED EARLY]" : "");
|
||||
|
||||
ecdh_done:
|
||||
if (kbOk) {
|
||||
wc_ecc_free(&kb);
|
||||
}
|
||||
if (kaOk) {
|
||||
wc_ecc_free(&ka);
|
||||
}
|
||||
if (rngOk) {
|
||||
wc_FreeRng(&brng);
|
||||
}
|
||||
}
|
||||
|
||||
static void wolf_ecc_bench(void)
|
||||
{
|
||||
wolf_sha_image_bench(0);
|
||||
wolf_sha_image_bench(1);
|
||||
wolf_ecdsa_bench(ECC_SECP256R1, 32, 10, "P-256");
|
||||
wolf_ecdh_bench(ECC_SECP256R1, 32, 10, "P-256");
|
||||
#ifdef WOLF_ECC384
|
||||
wolf_ecdsa_bench(ECC_SECP384R1, 48, 5, "P-384");
|
||||
wolf_ecdh_bench(ECC_SECP384R1, 48, 5, "P-384");
|
||||
#endif
|
||||
}
|
||||
#endif /* WOLF_ECC_BENCH */
|
||||
|
||||
|
||||
#ifdef WOLF_ECC384
|
||||
/* P-384 correctness, independent of the timing harness: an RFC 6979 verify KAT
|
||||
* over a device-computed SHA-384 digest, then a two-sided ECDH agreement. The
|
||||
* KAT uses externally supplied public-key and signature octets, so it catches
|
||||
* the serialization defects a self-generated sign/verify pair cannot. */
|
||||
static void wolf_ecc384_test(void)
|
||||
{
|
||||
/* Large under SP_NO_MALLOC - keep off the 16 KW stack. */
|
||||
static ecc_key k384;
|
||||
static ecc_key k384a;
|
||||
static ecc_key k384b;
|
||||
static WC_RNG rng384;
|
||||
static mp_int r384;
|
||||
static mp_int s384;
|
||||
static wc_Sha384 sha384;
|
||||
static byte secA[48];
|
||||
static byte secB[48];
|
||||
unsigned char dig[WC_SHA384_DIGEST_SIZE];
|
||||
word32 lenA, lenB;
|
||||
int ret, res = 0;
|
||||
|
||||
ret = wc_InitSha384(&sha384);
|
||||
if (ret == 0) {
|
||||
ret = wc_Sha384Update(&sha384, (const byte*)kat_p384_msg,
|
||||
(word32)(sizeof(kat_p384_msg) - 1));
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_Sha384Final(&sha384, dig);
|
||||
}
|
||||
wc_Sha384Free(&sha384);
|
||||
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_init(&k384);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_import_unsigned(&k384, (byte*)kat_p384_qx,
|
||||
(byte*)kat_p384_qy, NULL, ECC_SECP384R1);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = mp_init(&r384);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = mp_init(&s384);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = mp_read_unsigned_bin(&r384, kat_p384_r,
|
||||
(word32)sizeof(kat_p384_r));
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = mp_read_unsigned_bin(&s384, kat_p384_s,
|
||||
(word32)sizeof(kat_p384_s));
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_verify_hash_ex(&r384, &s384, dig,
|
||||
(word32)sizeof(dig), &res, &k384);
|
||||
}
|
||||
printf("ECDSA P-384 verify KAT: %s (ret=%d res=%d)\r\n",
|
||||
(ret == 0 && res == 1) ? "PASS" : "FAIL", ret, res);
|
||||
mp_clear(&s384);
|
||||
mp_clear(&r384);
|
||||
wc_ecc_free(&k384);
|
||||
|
||||
/* Two-sided ECDH: both parties must derive the same secret. */
|
||||
ret = wc_InitRng(&rng384);
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_init(&k384a);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_init(&k384b);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_make_key_ex(&rng384, 48, &k384a, ECC_SECP384R1);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_make_key_ex(&rng384, 48, &k384b, ECC_SECP384R1);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_set_rng(&k384a, &rng384);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_set_rng(&k384b, &rng384);
|
||||
}
|
||||
lenA = (word32)sizeof(secA);
|
||||
lenB = (word32)sizeof(secB);
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_shared_secret(&k384a, &k384b, secA, &lenA);
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = wc_ecc_shared_secret(&k384b, &k384a, secB, &lenB);
|
||||
}
|
||||
printf("ECDH P-384 shared secret: %s (ret=%d len=%lu)\r\n",
|
||||
(ret == 0 && lenA == lenB && lenA == 48U &&
|
||||
XMEMCMP(secA, secB, lenA) == 0) ? "PASS" : "FAIL",
|
||||
ret, (unsigned long)lenA);
|
||||
|
||||
wc_ecc_free(&k384b);
|
||||
wc_ecc_free(&k384a);
|
||||
wc_FreeRng(&rng384);
|
||||
}
|
||||
#endif /* WOLF_ECC384 */
|
||||
|
||||
#endif /* WOLF_ECC */
|
||||
|
||||
/* Focused SHA3-256 known-answer test (SHA3-256("abc")), to confirm the
|
||||
|
|
@ -2510,6 +2879,16 @@ int main(void)
|
|||
wolf_ecc_test();
|
||||
#endif
|
||||
|
||||
#ifdef WOLF_ECC384
|
||||
printf("\r\n--- ECDSA/ECDH P-384 (SP) ---\r\n");
|
||||
wolf_ecc384_test();
|
||||
#endif
|
||||
|
||||
#ifdef WOLF_ECC_BENCH
|
||||
printf("\r\n--- ECDSA / SHA-384 image-verify timings ---\r\n");
|
||||
wolf_ecc_bench();
|
||||
#endif
|
||||
|
||||
#ifdef WOLF_MLKEM
|
||||
printf("\r\n--- ML-KEM-768 ---\r\n");
|
||||
wolf_mlkem768_test();
|
||||
|
|
|
|||
Loading…
Reference in New Issue