ECDH Key Agreement
Performance benchmarks

This benchmarks one end of an ECDH key agreement on a Kinetis K66 device with Cortex-M4 core running at 168 MHz from flash memory. All times are in milliseconds.
Curve | SEGGER Embedded Studio [1] Version 3.22 [ms] | IAR Embedded Workbench [2] Version 8.11.1 [ms] | Execution time Shorter is better | |
---|---|---|---|---|
secp192r1 | 168.82 | 192.04 | x1.14 | |
secp224r1 | 190.39 | 225.8 | x1.19 | |
secp256r1 | 285.08 | 337.88 | x1.19 | |
secp384r1 | 477.45 | 537.31 | x1.13 | |
secp521r1 | 934.95 | 1104.28 | x1.18 | |
brainpoolP160r1 | 198.93 | 256.31 | x1.29 | |
brainpoolP160t1 | 179.1 | 231.65 | x1.29 | |
brainpoolP192r1 | 262.99 | 352.02 | x1.34 | |
brainpoolP192t1 | 255.86 | 320.01 | x1.25 | |
brainpoolP224r1 | 347.8 | 447.97 | x1.29 | |
brainpoolP224t1 | 326.51 | 406.66 | x1.25 | |
brainpoolP256r1 | 492.47 | 616.41 | x1.25 | |
brainpoolP256t1 | 437.95 | 549.88 | x1.26 | |
brainpoolP320r1 | 721.92 | 915.46 | x1.27 | |
brainpoolP320t1 | 664.48 | 847.24 | x1.28 | |
brainpoolP384r1 | 1172.36 | 1422.41 | x1.21 | |
brainpoolP384t1 | 1116.23 | 1310.96 | x1.17 | |
brainpoolP512r1 | 2154.36 | 2860.05 | x1.33 | |
brainpoolP512t1 | 2035.86 | 2573.09 | x1.26 |
[1] Optimized for speed using -O3
[2] Optimized for speed using -Ohs
Benchmarks
Compiler: clang 4.0.0
(c) 2014-2017 SEGGER Microcontroller GmbH & Co. KG www.segger.com
ECDH Key Agreement Benchmark compiled Jul 3 2017 14:04:05
Compiler: clang 4.0.0 (tags/RELEASE_400/final)
System: Processor speed = 168.000 MHz
Config: Static heap size = 3256 bytes
Config: CRYPTO_MPI_BITS_PER_LIMB = 32
This benchmarks both ends of an ECDH key agreement, but.
timing is reported as the time for one end's calculation.
+------------------+--------------+--------------+
| Curve | ms/Agreement | Memory |
+------------------+--------------+--------------+
| secp192r1 | 168.82 | 704 |
| secp224r1 | 190.39 | 792 |
| secp256r1 | 285.08 | 880 |
| secp384r1 | 477.45 | 1232 |
| secp521r1 | 934.95 | 1628 |
| brainpoolP160r1 | 198.93 | 616 |
| brainpoolP160t1 | 179.10 | 616 |
| brainpoolP192r1 | 262.99 | 704 |
| brainpoolP192t1 | 255.86 | 704 |
| brainpoolP224r1 | 347.80 | 792 |
| brainpoolP224t1 | 326.51 | 792 |
| brainpoolP256r1 | 492.47 | 880 |
| brainpoolP256t1 | 437.95 | 880 |
| brainpoolP320r1 | 721.92 | 1056 |
| brainpoolP320t1 | 664.48 | 1056 |
| brainpoolP384r1 | 1172.36 | 1232 |
| brainpoolP384t1 | 1116.23 | 1232 |
| brainpoolP512r1 | 2154.36 | 1584 |
| brainpoolP512t1 | 2035.86 | 1584 |
+------------------+--------------+--------------+
Compiler: IAR icc 8.11.1
(c) 2014-2017 SEGGER Microcontroller GmbH & Co. KG www.segger.com
ECDH Key Agreement Benchmark compiled Jul 3 2017 14:04:36
Compiler: IAR icc 8.11.1
System: Processor speed = 168.000 MHz
Config: Static heap size = 3256 bytes
Config: CRYPTO_MPI_BITS_PER_LIMB = 32
This benchmarks both ends of an ECDH key agreement, but.
timing is reported as the time for one end's calculation.
+------------------+--------------+--------------+
| Curve | ms/Agreement | Memory |
+------------------+--------------+--------------+
| secp192r1 | 192.04 | 704 |
| secp224r1 | 225.80 | 792 |
| secp256r1 | 337.88 | 880 |
| secp384r1 | 537.31 | 1232 |
| secp521r1 | 1104.28 | 1628 |
| brainpoolP160r1 | 256.31 | 616 |
| brainpoolP160t1 | 231.65 | 616 |
| brainpoolP192r1 | 352.02 | 704 |
| brainpoolP192t1 | 320.01 | 704 |
| brainpoolP224r1 | 447.97 | 792 |
| brainpoolP224t1 | 406.66 | 792 |
| brainpoolP256r1 | 616.41 | 880 |
| brainpoolP256t1 | 549.88 | 880 |
| brainpoolP320r1 | 915.46 | 1056 |
| brainpoolP320t1 | 847.24 | 1056 |
| brainpoolP384r1 | 1422.41 | 1232 |
| brainpoolP384t1 | 1310.96 | 1232 |
| brainpoolP512r1 | 2860.05 | 1584 |
| brainpoolP512t1 | 2573.09 | 1584 |
+------------------+--------------+--------------+
Program listing
/*********************************************************************
* (c) SEGGER Microcontroller GmbH & Co. KG *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
File : CRYPTO_Bench_ECDH.c
Purpose : Benchmark ECDH key agreement performance.
*/
/*********************************************************************
*
* #include section
*
**********************************************************************
*/
#include "CRYPTO_Int.h"
#include "SEGGER_MEM.h"
#include "SEGGER_SYS.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#define MAX_CHUNKS 22
/*********************************************************************
*
* Local data types
*
**********************************************************************
*/
// Maximum prime size is 521 bits, but require additional 63 bits
// for underlying fast prime field reduction.
typedef CRYPTO_MPI_LIMB MPI_UNIT[CRYPTO_MPI_LIMBS_REQUIRED(2*521+63)+2];
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
static MPI_UNIT _aUnits[MAX_CHUNKS];
static SEGGER_MEM_CONTEXT _MemContext;
static SEGGER_MEM_SELFTEST_HEAP _Heap;
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
/*********************************************************************
*
* _LFSR_Get()
*
* Function description
* Get pseudo-random data.
*
* Parameters
* pData - Pointer to object the receives the random data.
* DataLen - Octet length of the random data.
*
* Additional information
* This LFSR PRNG does not need to be cryptographically strong as
* its purpose is only to deliver repeatable pseudo-random data
* that does not depend upon a nondeterministic source (such as
* a hardware RNG or the availability of hardware ciphering and
* hashing in the DRBG code). Therefore, this RNG is suitable
* for deterministic benchmarking across compilers and systems.
*/
static void _LFSR_Get(U8 *pData, unsigned Len) {
static U32 State32 = 0xFEDCBA8uL;
static U32 State31 = 0x1234567uL;
//
while (Len > 0) {
if (State32 & 1) {
State32 >>= 1;
State32 ^= 0xB4BCD35CuL;
} else {
State32 >>= 1;
}
if (State32 & 1) {
State31 >>= 1;
State31 ^= 0x7A5BC2E3uL;
} else {
State31 >>= 1;
}
if (Len >= 2) {
CRYPTO_WRU16LE(pData, (U16)(State31 ^ State32));
pData += 2;
Len -= 2;
} else {
*pData = (U8)(State31 ^ State32);
Len -= 1;
}
}
}
/*********************************************************************
*
* _ConvertTicksToSeconds()
*
* Function description
* Convert ticks to seconds.
*
* Parameters
* Ticks - Number of ticks reported by SEGGER_SYS_OS_GetTimer().
*
* Return value
* Number of seconds corresponding to tick.
*/
static float _ConvertTicksToSeconds(U64 Ticks) {
return SEGGER_SYS_OS_ConvertTicksToMicros(Ticks) / 1000000.0f;
}
/*********************************************************************
*
* _BenchmarkECDHKeyAgreement()
*
* Function description
* Benchmark ECDH key agreement, both sides.
*
* Parameters
* pCurve - Pointer to elliptic curve.
*/
static void _BenchmarkECDHKeyAgreement(const CRYPTO_EC_CURVE *pCurve) {
CRYPTO_ECDH_KA_CONTEXT Us;
CRYPTO_ECDH_KA_CONTEXT Them;
U64 OneSecond;
U64 T0;
U64 Elapsed;
int Loops;
int Status;
unsigned PeakBytes;
unsigned UnitSize;
float Time;
//
// Make PC-lint quiet, it's dataflow analysis provides false positives.
//
Loops = 0;
Elapsed = 0;
PeakBytes = 0;
UnitSize = CRYPTO_MPI_BYTES_REQUIRED(2*CRYPTO_MPI_BitCount(&pCurve->P)+63) + 2*CRYPTO_MPI_BYTES_PER_LIMB;
//
SEGGER_SYS_IO_Printf("| %-16s |", pCurve->aCurveName);
//
OneSecond = SEGGER_SYS_OS_ConvertMicrosToTicks(1000000);
T0 = SEGGER_SYS_OS_GetTimer();
do {
//
_Heap.Stats.NumInUseMax = _Heap.Stats.NumInUse;
//
CRYPTO_ECDH_KA_Init(&Us, &_MemContext);
CRYPTO_ECDH_KA_Init(&Them, &_MemContext);
//
CRYPTO_CHECK(CRYPTO_ECDH_KA_Start(&Us, pCurve, &_MemContext));
CRYPTO_CHECK(CRYPTO_ECDH_KA_Start(&Them, pCurve, &_MemContext));
//
CRYPTO_CHECK(CRYPTO_ECDH_KA_Agree(&Us, &Them.Public.Y, &_MemContext));
CRYPTO_CHECK(CRYPTO_ECDH_KA_Agree(&Them, &Us.Public.Y, &_MemContext));
//
CRYPTO_ECDH_KA_Kill(&Us);
CRYPTO_ECDH_KA_Kill(&Them);
//
PeakBytes = _Heap.Stats.NumInUseMax * UnitSize;
//
Elapsed = SEGGER_SYS_OS_GetTimer() - T0;
++Loops;
} while (Status >= 0 && Elapsed < OneSecond);
//
cleanup:
CRYPTO_ECDH_KA_Kill(&Us);
CRYPTO_ECDH_KA_Kill(&Them);
//
if (Status < 0 || Loops == 0) {
SEGGER_SYS_IO_Printf("%13s |%13s | ", "-Fail-", "-Fail-");
} else {
Loops *= 2; // Two agreements per loop
PeakBytes /= 2; // Two agreements per loop
Time = 1000.0f * _ConvertTicksToSeconds(Elapsed) / Loops;
SEGGER_SYS_IO_Printf("%13.2f |%13d |", Time, PeakBytes);
}
SEGGER_SYS_IO_Printf("\n");
}
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* MainTask()
*
* Function description
* Main entry point for application to run all the tests.
*/
void MainTask(void);
void MainTask(void) {
static const CRYPTO_RNG_API LFSR = { NULL, _LFSR_Get, NULL, NULL };
//
CRYPTO_Init();
SEGGER_SYS_Init();
SEGGER_MEM_SELFTEST_HEAP_Init(&_MemContext, &_Heap, _aUnits, MAX_CHUNKS, sizeof(MPI_UNIT));
CRYPTO_RNG_Install(&LFSR);
//
SEGGER_SYS_IO_Printf("\n");
SEGGER_SYS_IO_Printf("(c) 2014-2017 SEGGER Microcontroller GmbH & Co. KG www.segger.com\n");
SEGGER_SYS_IO_Printf("ECDH Key Agreement Benchmark compiled " __DATE__ " " __TIME__ "\n\n");
//
SEGGER_SYS_IO_Printf("Compiler: %s\n", SEGGER_SYS_GetCompiler());
if (SEGGER_SYS_GetProcessorSpeed() > 0) {
SEGGER_SYS_IO_Printf("System: Processor speed = %.3f MHz\n", (double)SEGGER_SYS_GetProcessorSpeed() / 1000000.0f);
}
SEGGER_SYS_IO_Printf("Config: Static heap size = %u bytes\n", sizeof(_aUnits));
SEGGER_SYS_IO_Printf("Config: CRYPTO_MPI_BITS_PER_LIMB = %u\n", CRYPTO_MPI_BITS_PER_LIMB);
SEGGER_SYS_IO_Printf("\n");
//
SEGGER_SYS_IO_Printf("This benchmarks both ends of an ECDH key agreement, but.\n");
SEGGER_SYS_IO_Printf("timing is reported as the time for one end's calculation.\n");
SEGGER_SYS_IO_Printf("\n");
SEGGER_SYS_IO_Printf("+------------------+--------------+--------------+\n");
SEGGER_SYS_IO_Printf("| Curve | ms/Agreement | Memory |\n");
SEGGER_SYS_IO_Printf("+------------------+--------------+--------------+\n");
//
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_P192);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_P224);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_P256);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_P384);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_P521);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_brainpoolP160r1);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_brainpoolP160t1);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_brainpoolP192r1);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_brainpoolP192t1);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_brainpoolP224r1);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_brainpoolP224t1);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_brainpoolP256r1);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_brainpoolP256t1);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_brainpoolP320r1);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_brainpoolP320t1);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_brainpoolP384r1);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_brainpoolP384t1);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_brainpoolP512r1);
_BenchmarkECDHKeyAgreement(&CRYPTO_EC_CURVE_brainpoolP512t1);
//
SEGGER_SYS_IO_Printf("+------------------+--------------+--------------+\n");
SEGGER_SYS_IO_Printf("\n");
//
SEGGER_SYS_IO_Printf("Benchmark complete\n");
SEGGER_SYS_OS_PauseBeforeHalt();
SEGGER_SYS_OS_Halt(0);
}
/*************************** End of file ****************************/