Skip navigation
emcrypt-product-icon.svg

emCrypt benchmarks - ECDH Key Agreement

ECDH Key Agreement

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 !CALCULATE_BAR_0_1!
secp224r1 190.39 225.8 x1.19 !CALCULATE_BAR_0_1!
secp256r1 285.08 337.88 x1.19 !CALCULATE_BAR_0_1!
secp384r1 477.45 537.31 x1.13 !CALCULATE_BAR_0_1!
secp521r1 934.95 1104.28 x1.18 !CALCULATE_BAR_0_1!
brainpoolP160r1 198.93 256.31 x1.29 !CALCULATE_BAR_0_1!
brainpoolP160t1 179.1 231.65 x1.29 !CALCULATE_BAR_0_1!
brainpoolP192r1 262.99 352.02 x1.34 !CALCULATE_BAR_0_1!
brainpoolP192t1 255.86 320.01 x1.25 !CALCULATE_BAR_0_1!
brainpoolP224r1 347.8 447.97 x1.29 !CALCULATE_BAR_0_1!
brainpoolP224t1 326.51 406.66 x1.25 !CALCULATE_BAR_0_1!
brainpoolP256r1 492.47 616.41 x1.25 !CALCULATE_BAR_0_1!
brainpoolP256t1 437.95 549.88 x1.26 !CALCULATE_BAR_0_1!
brainpoolP320r1 721.92 915.46 x1.27 !CALCULATE_BAR_0_1!
brainpoolP320t1 664.48 847.24 x1.28 !CALCULATE_BAR_0_1!
brainpoolP384r1 1172.36 1422.41 x1.21 !CALCULATE_BAR_0_1!
brainpoolP384t1 1116.23 1310.96 x1.17 !CALCULATE_BAR_0_1!
brainpoolP512r1 2154.36 2860.05 x1.33 !CALCULATE_BAR_0_1!
brainpoolP512t1 2035.86 2573.09 x1.26 !CALCULATE_BAR_0_1!

[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 ****************************/