What securing a CAN node costs in flash, RAM, and time.

MCU Crypto Benchmarks

Cryptographic protection has a price in flash, RAM, and time, and on a microcontroller that budget is tight. This page reports measured code size, peak stack, and per-operation time for the cryptographic primitives taken into consideration when securing a CAN FD node: SHA-256, HKDF, AES-128-GCM, Ed25519, and X25519. The figures come from the EmSA CryptoEval harness running on representative parts, so a designer can size the cost before committing to an approach.

Cryptographic Primitives and Acceptable Truncation

The overview below lists each primitive with its key material, its nonce or salt, and the size of the value it produces. The final column gives an output size that can be acceptable in a constrained node, where a shorter value trades security margin for bandwidth or storage. Truncation is sound only where the relevant standard permits it, and two of these primitives cannot be truncated at all.

Function Key size Nonce / salt Full output Acceptable truncation*
SHA-256 hash 32 B digest 16 B (128-bit)
HKDF-SHA-256 derive IKM (variable) 12 B salt (+7 B info) 32 B key 16 B (derive only what the key needs)
AES-128-GCM (enc / dec / auth) 16 B (128-bit) 12 B nonce 16 B tag 8 B (64-bit)
Ed25519 (sign / verify) 32 B seed / 32 B public – (deterministic) 64 B signature none (fixed structure)
X25519 (keygen / ECDH) 32 B secret (+32 B peer) 32 B shared secret none (use full via a KDF)

* Truncate only where the standard permits. A SHA-256 digest may be cut to 128 bits (NIST SP 800-107), and HKDF derives only the bytes the key needs (RFC 5869). Ed25519 signatures and X25519 secrets cannot be truncated at all. NIST SP 800-38D permits a 64-bit GCM tag only under strict per-key limits on message count and length (Appendix C). Treat it as a last resort, not a default.

The measurements use two portable software libraries, both at a pinned version so the figures stay reproducible: Mbed TLS 3.6.5 for SHA-256, HKDF, and AES-128-GCM, and Monocypher 4.0.2 for Ed25519 and X25519. Both are open-source C libraries built from unmodified upstream sources, Mbed TLS under Apache-2.0 and Monocypher in the public domain under CC0, with no algorithm-level patches. Any figure here can therefore be traced to a specific released version rather than to a local variant. On the STM32H573 the hardware hash and AES paths run through the ST Mbed-TLS ALT drivers over the on-chip HASH and AES peripherals.

How to Read the Benchmark Tables

Every figure in the tables that follow is an Arm Compiler build at optimization level -O2, timed on a 64-byte input, taken as the minimum of twelve repeats with the measurement overhead subtracted. Each table lists the devices down the page in ascending order of core clock, three rows per device, and the functions across it. Code is the flash footprint in bytes, stack is the peak stack high-water mark in bytes, and 64 B is the time for one operation in milliseconds. Code and stack do not depend on the payload size. A new part adds rows rather than columns, so the tables grow downward as the harness covers more devices.

Some functions share a code object, so the size appears once, in the column that owns it, and the remaining columns are marked as shared. Ed25519 sign and verify share one object, carried in the verify column. For AES-128-GCM, decrypt and authenticate-only reuse the encrypt object, and the init and setup step, which builds the key schedule and the GHASH table, has no separate code of its own. X25519 has a single column because keygen and ECDH are the same operation: deriving a public key is a scalar multiplication against the curve base point, agreeing a shared secret is the same scalar multiplication against the peer public key, and the implementation runs identical constant-time code for both. A key agreement therefore costs two of these scalar multiplications per side, one to produce the ephemeral public key and one to consume the peer's. The devices span a low-end Cortex-M4F at 40 MHz, a mid Cortex-M33 at 120 MHz, a Cortex-M33 at 240 MHz that carries a hardware AES and HASH accelerator, and both cores of a dual-core part: an i.MX RT1186 whose Cortex-M33 at 240 MHz reaches its EdgeLock enclave through a mailbox rather than driving a peripheral directly, and whose Cortex-M7 at 792 MHz sets the upper bound of the set. Listing both cores of one chip is deliberate: it separates what the silicon costs from what the core running the code costs, and the two differ by roughly a factor of six on the curve operations. Between those two cores sits a sixth device: a Renesas RA8M1, a Cortex-M85 at 480 MHz whose RSIP-E51A security engine covers Ed25519 as well as AES and SHA-256. It is the first part here that offers a hardware path for the curves at all, and what that path costs is the most surprising result on this page.

Hash, KDF, and Signature Cost

The table reports code (B), stack (B), and the 64-byte time (ms) for each hash, KDF, and signature primitive at Arm Compiler -O2. On the STM32H573 the hash and derivation figures use the on-chip HASH accelerator; the curve operations have no hardware path and run in software on all boards.

Device Metric SHA-256
hash
HKDF-SHA-256
derive
Ed25519
verify
Ed25519
sign
X25519
scalar mult§
NXP LPC54618Cortex-M4F · 40 MHz code (B) 2816 4687 29916 shared 24632
stack (B) 752 936 2228 1684 1172
64 B (ms) 0.309 1.582 74.469 28.147 51.720
NXP LPC55S16Cortex-M33 · 120 MHz code (B) 2836 4707 29754 shared 24444
stack (B) 752 936 2208 1664 1152
64 B (ms) 0.120 0.604 27.603 10.711 19.115
ST STM32H573Cortex-M33 · 240 MHz · HASH accel code (B) 2050 3923 29754 shared 24444
stack (B) 684 580 2208 1664 1152
64 B (ms) 0.008 0.075 8.599 3.448 5.790
NXP i.MX RT1186 M33Cortex-M33 · 240 MHz · XIP code (B) 2836 4707 29754 shared 24444
stack (B) 768 952 2208 1672 1152
64 B (ms) 0.031 0.142 8.632 4.120 5.823
Renesas RA8M1Cortex-M85 · 480 MHz code (B) 2844 4729 29424 shared 24526
stack (B) 536 720 1996 1532 972
64 B (ms) 0.011 0.056 2.792 1.053 1.903
NXP i.MX RT1186 M7Cortex-M7 · 792 MHz · TCM code (B) 2966 4877 29994 shared 24618
stack (B) 768 952 2208 1688 1144
64 B (ms) 0.005 0.024 1.476 0.553 1.029

STM32H573 SHA-256 and HKDF figures use the on-chip HASH accelerator through the ST Mbed-TLS ALT driver.§ The harness times the scalar multiplication against a fixed secret key held in flash, so the figure excludes the random draw that generating a real ephemeral key needs. Budget the entropy source separately; its cost depends on the part, not on the curve. The i.MX RT1186 has no internal program flash. Its M33 executes in place from external QSPI flash through a cache, so a short operation varies widely from run to run and the figure shown is the warm-cache cost. The M7 cannot fetch from that window at all: an M33 launcher copies its firmware into tightly-coupled memory first, so nothing in the measured path touches a cache or the serial flash and its figures are steady to within about two percent. Both i.MX RT1186 rows are the software path.

AES-128-GCM Cost

The software AES implementation needs a lookup table of 8892 bytes, and where that table lives is the one configuration choice that moves these numbers. The two tables below are the same measurement under the two placements, so read them as a pair: the columns are aligned deliberately, and only the placement changes between them. Putting the table in flash costs roughly 7.4 KB more flash and saves the 8.9 KB of RAM, and because the table is then read through flash wait states every operation also runs slower, by 21 percent on the LPC54618 and 46 percent on the LPC55S16. RAM is the default and the faster path; flash is the option you reach for when RAM is the binding constraint.

The RA8M1 shows what actually drives that penalty. It has a data cache, the flash-resident table lands in it, and the flash build comes out a few percent faster than the RAM build rather than slower. The rule is therefore not that flash placement is slow; it is that flash placement is slow on a part that reads flash through wait states with nothing caching it. Where a data cache is present, the placement costs almost nothing in time and the decision is only about which memory you can spare.

The i.MX RT1186 appears only in the RAM table. It has no internal program flash, so the flash-table build would put the table in external QSPI, which is a different experiment rather than the same one on another part. On that part the table sits in tightly-coupled memory. The STM32H573 column in the RAM table is its on-chip AES peripheral rather than a software path, so its code figure includes the HAL AES driver. AES-CCM has no hardware path on any of these parts.

Table 1 of 2 · lookup table in FLASH (Mbed-TLS MBEDTLS_AES_ROM_TABLES) Table costs 8892 B of flash, 0 B of RAM. Encrypt code about 16.5 KB. Slower than the RAM placement on a part with no data cache.

AES-128-GCM with the lookup table in flash. Code (B), stack (B), and 64-byte time (ms), Arm Compiler -O2.
Device Metric init /
setup
encrypt decrypt auth-only
NXP LPC54618Cortex-M4F · 40 MHz code (B) n/a 16488 shared shared
stack (B) 840 496 512 448
64 B (ms) 0.312 0.475 0.480 0.234
NXP LPC55S16Cortex-M33 · 120 MHz code (B) n/a 16608 shared shared
stack (B) 840 496 512 448
64 B (ms) 0.117 0.244 0.246 0.107
ST STM32H573Cortex-M33 · 240 MHz code (B) n/a 16608 shared shared
stack (B) 840 496 512 448
64 B (ms) 0.052 0.057 0.058 0.028
Renesas RA8M1*Cortex-M85 · 480 MHz code (B) n/a 16624 shared shared
stack (B) 640 288 304 232
64 B (ms) 0.012 0.012 0.013 0.006

* Code runs in place from internal flash in both builds; only the lookup table moves. The RA8M1 has a data cache, so the flash-resident table costs it nothing in time, unlike the two parts here that have none.

Table 2 of 2 · lookup table in RAM (the Mbed-TLS default) Table costs 8892 B of RAM, 0 B of flash. Encrypt code about 9.1 KB, roughly 7.4 KB less than the flash build. Faster, and the default choice.

AES-128-GCM on each device's fastest path: the lookup table in RAM on the LPC parts and in tightly-coupled memory on the i.MX RT1186 (the default software path), and the on-chip accelerator on the STM32H573. Code (B), stack (B), and 64-byte time (ms), Arm Compiler -O2.
Device Metric init /
setup
encrypt decrypt auth-only
NXP LPC54618Cortex-M4F · 40 MHz code (B) n/a 9114 shared shared
stack (B) 840 496 512 448
64 B (ms) 0.291 0.392 0.397 0.217
NXP LPC55S16Cortex-M33 · 120 MHz code (B) n/a 9152 shared shared
stack (B) 840 496 512 448
64 B (ms) 0.098 0.167 0.169 0.092
ST STM32H573Cortex-M33 · 240 MHz · AES accel code (B) n/a 16530 shared shared
stack (B) 456 444 532 444
64 B (ms) 0.010 0.010 0.011 0.008
NXP i.MX RT1186 M33Cortex-M33 · 240 MHz · XIP code (B) n/a 9152 shared shared
stack (B) 856 512 528 464
64 B (ms) 0.020 0.048 0.049 0.029
Renesas RA8M1Cortex-M85 · 480 MHz code (B) n/a 9386 shared shared
stack (B) 632 280 296 224
64 B (ms) 0.012 0.013 0.013 0.006
NXP i.MX RT1186 M7Cortex-M7 · 792 MHz · TCM code (B) n/a 9502 shared shared
stack (B) 1296 512 528 464
64 B (ms) 0.003 0.007 0.007 0.004

Both i.MX RT1186 rows are the software path. The part does carry an EdgeLock enclave that performs AES-128-GCM, but each call crosses a mailbox to a separate security core, which costs 0.074 ms against 0.048 ms in software on a 64-byte payload. Only the M33 may call it: the enclave is granted to one core at a time. An enclave earns its place by holding keys the application core never sees, not by speed.

What AES-256-GCM Changes

Every figure above is AES-128-GCM. The harness also measured AES-256-GCM on all six cores, and the result is worth stating plainly because it is easy to assume the stronger key costs more than it does. Across every build, at both optimization levels and under both compilers, AES-256-GCM needs exactly the same code and exactly the same stack as AES-128-GCM. Not approximately: the same byte counts, because one AES core serves both key lengths and only the length of the key schedule differs.

The whole cost lands in time, and it is modest. A 256-bit key runs 14 rounds where a 128-bit key runs 10, but the GHASH half of GCM does not change, so the penalty on a 64-byte payload settles between 11 and 14 percent on every core measured, and the RA8M1 sits inside that band at 13 percent. Loading the key costs a little more too, since the schedule is longer.

For a design that is choosing between the two, the practical reading is that key length is close to free here. AES-256 does not change the flash budget, does not change the RAM budget, and leaves the frame-rate headroom essentially intact. If the reason to prefer a 256-bit key is a policy requirement, a longer service life, or a margin against future analysis, none of those has to be argued against a memory cost, because there is not one. The argument is only ever about the roughly one-eighth of extra time per operation.

What a Hardware Accelerator Changes

Three of these parts do cryptographic work in dedicated hardware, and how the core reaches that hardware matters more than whether the datasheet lists an accelerator. The STM32H573 exposes HASH and AES as memory-mapped peripherals: the core writes the data, reads the result, and pays little overhead. The i.MX RT1186 puts cryptography inside an EdgeLock enclave, a separate security core reached by passing messages through a mailbox, so every call pays a fixed round trip. The RA8M1 sits between the two: its RSIP-E51A is a register-mapped engine like the STM32 peripheral, but it works only on keys wrapped inside it, so every keyed operation reloads a key that the core never sees. The three arrangements do not merely differ in degree. One is several times faster than software, one is slower at small payloads, and one is both, depending on the primitive.

Device Path SHA-256, 64 B AES-128-GCM encrypt, 64 B Code, SHA / AES
STM32H573 software 0.046 ms 0.046 ms 2836 / 9152 B
STM32H573 on-chip peripheral 0.008 ms 0.010 ms 2050 / 16530 B
i.MX RT1186 M33 software 0.031 ms 0.048 ms 2836 / 9152 B
i.MX RT1186 M33 EdgeLock enclave 0.103 ms 0.074 ms 43224 / 47894 B
Renesas RA8M1 software 0.011 ms 0.013 ms 2844 / 9386 B
Renesas RA8M1 RSIP-E51A engine 0.004 ms 0.022 ms 52154 / 57340 B

The RT1186 and RA8M1 code figures are one shared driver, not per-primitive code: a command interface to a separate security processor rather than a register-mapped peripheral. Count it once, not once per row.

The peripheral wins outright: SHA-256 about six times faster, AES-128-GCM about four and a half, HKDF from 0.228 to 0.075 ms, and lower stack as well. Its one cost is flash, because that code figure includes the ST HAL driver.

The enclave buys something a peripheral cannot. It is a true on-chip hardware security module: a separate core with its own memory that will not accept a plaintext key at all. Keys are generated inside it and referenced only by a handle, so application firmware never holds one and cannot surrender it when that firmware is compromised. That is a higher assurance level than an accelerator the core has to feed with the key, and it costs about 0.140 ms per 64-byte operation. Because the round trip is fixed rather than proportional, it also fades as payloads grow: at 256 bytes the enclave already beats software on AES-GCM. Let it hold and derive key material, then run per-frame protection elsewhere.

The RA8M1 engine splits the difference, and the split is instructive. On SHA-256 it wins comfortably, and its lead grows with payload because a hash takes no key: 0.004 ms against 0.011 in software at 64 bytes, and five times faster at 256 bytes. On AES-GCM it loses at 64 bytes and wins at 256, for the same reason the enclave does. Each call spends roughly ten thousand cycles before it touches the data, because the engine takes its wrapped key at every operation and the driver offers no way to leave a key loaded, while the software path builds its key schedule once. Read those two rows as a fixed cost plus a rate, not as a single verdict.

The curves are where the assumption breaks. Until this part, no device in the set had a hardware path for Ed25519 or X25519, so there was nothing to measure. The RSIP-E51A does implement Ed25519, and it is eight to eleven times slower than software on the same chip: 11.1 ms to sign against 1.1 ms, and 22.7 ms to verify against 2.8 ms. The figure does not move with payload size, so it is a fixed property of the engine rather than an artifact of the measurement, and verify costs almost exactly twice sign, which is the ratio the mathematics predicts. A Cortex-M85 running well-tuned software is simply quicker at this than the security engine beside it.

The lesson is not that security engines are slow. It is that an accelerator is worth what it accelerates on your part, and nothing more. Check the primitive you actually depend on, at the payload size you actually send, before you plan a design around the block diagram. What these engines reliably offer is key custody: on both the RT1186 and the RA8M1 the key is generated inside the hardware and the application firmware never holds it, so compromising the firmware does not surrender the key. That is worth paying for on its own terms. It is not a speed argument.

Compiler and Optimization Level

The tables above are Arm Compiler (armclang) builds at -O2. The harness also builds the same sources with GNU gcc (arm-none-eabi-gcc), and both compilers at -O3, which makes it possible to say what the toolchain contributes rather than the silicon. The short version is that the compiler moves code size far more than it moves speed, that neither compiler wins across the board, and that -O3 is not the free improvement it looks like.

Code size splits sharply by primitive. On the same part and the same sources, armclang emits 29754 bytes for the shared Ed25519 object against 16368 under gcc, and 24444 for X25519 against 12520, so armclang is 80 to 95 percent larger on the elliptic-curve code, because it inlines and unrolls the 25519 field arithmetic. AES-128-GCM follows the same direction, 9152 against 6084. The permutation-heavy primitives reverse it completely, and by more: for Ascon-AEAD128 armclang emits 13656 bytes against 23296 under gcc, and for Ascon-Hash256 4746 against 13928, so gcc is nearly three times the size there. SHA-256 and HKDF sit close either way, within about five and twelve percent respectively, small either way in absolute terms.

Whether that size buys speed depends on the core. On the Cortex-M33 parts it largely does not: on the LPC55S16 armclang spends 82 percent more flash on the Ed25519 object and verifies a signature in 27.603 ms against gcc's 26.548, slightly slower for much more code, while the STM32H573 and the i.MX RT1186 M33 land within about one percent either way. The Cortex-M7 is the exception that explains the strategy: there armclang verifies in 1.476 ms against gcc's 1.735 and runs X25519 in 1.029 against 1.226, a lead of 17 to 19 percent, because a dual-issue core fetching from tightly-coupled memory can actually use the unrolled field arithmetic. The Cortex-M4F reverses it once more, with gcc 11 to 13 percent faster on the LPC54618. Ascon is the one primitive where armclang is both smaller and faster on every part measured.

-O3 costs code and returns very little. Under armclang it grows the Ed25519 object from 29754 to 31984 bytes, X25519 from 24444 to 26522 and AES-128-GCM encrypt from 9152 to 10038, while the 64-byte times move by a couple of percent in either direction, including one clear regression: X25519 on the STM32H573 slows from 5.790 to 6.742 ms, about 16 percent worse for 8 percent more flash. Under gcc the code growth is far steeper, Ed25519 from 16368 to 22908 bytes and Ascon-AEAD128 from 23296 to 36524, and there the extra size does sometimes buy speed, with AES-128-GCM on the STM32H573 dropping from 0.056 to 0.048 ms and Ascon on the LPC55S16 from 0.147 to 0.122. Those gains are not consistent either: gcc at -O3 speeds X25519 up by 6 percent on the LPC55S16 while slowing it by 7 percent on the STM32H573.

Two conclusions follow for a constrained node. Keep -O2 as the default: these primitives are already compute-bound, and on a wait-stated flash a larger binary can cost more than the extra inlining saves. Then, if one primitive genuinely sits on the critical path, measure that primitive under both compilers rather than trusting a general reputation, because the direction of the difference changes from one algorithm to the next.

Which Primitive for Which Job

The tables above price each primitive; this section says where each one earns that cost. On a constrained CAN node the rule of thumb is to reach for the symmetric primitives first, since they run two to three orders of magnitude faster than the curves, and to add public-key operations only where a shared secret cannot do the job. The table maps each function to the work it suits and the work it does not.

Function Reach for it when Not the tool for
SHA-256 hash You need a fixed fingerprint of data with no secret involved: a firmware image digest, a secure-boot measurement, or the hash that HKDF and Ed25519 build on. Authentication on its own. A bare hash carries no key, so anyone can recompute it; give it a key through HKDF or a MAC.
HKDF-SHA-256 derive You hold one secret and need several: per-device and per-purpose keys from a single root, or session keys expanded from an X25519 shared secret. Protecting data in transit. It produces keys, not ciphertext or tags; feed its output to AES-128-GCM.
AES-128-GCM You need authenticated encryption, or authentication alone through GMAC, on the wire: per-frame protection, protected object access, or an encrypted and authenticated firmware image. This is the default symmetric choice on CAN. Reusing a nonce. Every message under one key needs a fresh nonce; a single repeat breaks both confidentiality and integrity (see the per-key limits in NIST SP 800-38D).
Ed25519 (sign / verify) One party signs and many verify, with no shared secret to distribute: manufacturer firmware signing, device identity certificates, or any claim that must hold up to a third party. Routine per-frame traffic. At about 16 to 30 KB of flash and software-only on these parts, reserve it for update and identity, not the hot path.
X25519 (keygen / ECDH) Two parties must agree a fresh secret over an untrusted channel, giving forward secrecy without a pre-shared key. Using the raw output as a key. Always pass the shared secret through HKDF first, and never truncate it or use it directly.

In practice the two families combine rather than compete. A capable node uses X25519 to agree a session secret and Ed25519 to authenticate the peer, then hands the secret to HKDF and carries the traffic under AES-128-GCM. A very constrained node skips the curves entirely: one root in a hardware module, HKDF for the key ladder, and AES-128-GCM for every protected frame and object. The Symmetric vs Asymmetric page weighs that choice in full.

Two properties are worth designing for from the start. Nonce uniqueness under AES-128-GCM is a correctness requirement, not a tuning option, so the same message counter that provides replay protection should also supply the nonce and trigger a key refresh before the counter wraps. The second is crypto-agility: because a fielded device outlives any single algorithm, keep the choice replaceable: the symmetric primitives hold a comfortable margin at AES-256 and SHA-256, while the curves are the ones most likely to migrate to post-quantum successors, so the update path should be able to carry a new algorithm. BSI TR-02102 RFC 5869 NIST SP 800-108

Frequently Asked Questions

How much flash does public-key crypto need on a CAN node?

The elliptic-curve primitives dominate. In these builds Ed25519, with sign and verify sharing one object, is about 30 KB of flash and X25519 about 24 KB, plus around 2 KB of stack. By comparison SHA-256 and HKDF together fit in under 8 KB, and AES-128-GCM in 9 to 17 KB depending on whether the lookup table sits in RAM or flash. A node that only needs symmetric protection is far cheaper than one that also verifies signatures.

Is a hardware crypto accelerator worth it?

It depends on how the accelerator is reached. A memory-mapped peripheral is a clear win: on the STM32H573 the on-chip HASH and AES blocks run SHA-256 about six times faster than software and AES-128-GCM about four and a half times, on less stack. An enclave reached through a mailbox is a different trade: on the i.MX RT1186 each call pays a fixed round trip, so a 64-byte AES-128-GCM operation takes about 55 percent longer than software and SHA-256 more than three times as long. That cost fades as payloads grow, and it buys a true hardware security module: the enclave will not accept a plaintext key, so a key generated inside it is never held by application firmware. Isolation, not speed, is what it delivers. A third kind sits between them: the RA8M1 security engine is register-mapped, yet it takes its key on every call, so it runs SHA-256 nearly three times faster than software and AES-128-GCM slower at 64 bytes. Its Ed25519 is the sharpest warning in the set, at eight to eleven times slower than software on the same chip. Check the primitive and the payload size you actually use before planning around an accelerator.

Why report time for a 64-byte payload?

Sixty-four bytes is the maximum payload of a single CAN FD frame, so it is the natural unit for per-frame protection on this bus. The harness also measured 8-byte and 256-byte inputs; 64 bytes is reported here as the representative frame-sized case. For the public-key primitives the time is effectively independent of payload size, because they operate on fixed-size keys and hashes.