-
Notifications
You must be signed in to change notification settings - Fork 0
Footprint
The crypto floor is the same wolfcrypt objects in wolfNano and wolfSSL, so it is not the differentiator. The TLS layer is. Run the comparison with:
sh bench/footprint.sh| __TEXT bytes | source lines | |
|---|---|---|
| wolfNano slim shell (full TLS 1.3 PSK+ECDHE client) | 8,724 | 1,351 |
wolfSSL TLS layer (tls13.c + tls.c only) |
52,318 | (subset) |
wolfSSL tls13.c+tls.c+internal.c+ssl.c
|
n/a | 96,433 |
The complete wolfNano TLS 1.3 client (handshake driver, ClientHello/ServerHello,
key schedule, transcript, record protection, key share, wire codec) is roughly
6x smaller in compiled .text than just tls13.c + tls.c, and it omits
internal.c and ssl.c entirely (the WOLFSSL object model), which is the
bulk of the wolfSSL TLS-layer size.
Code size is static, so the on-target crypto floor can be measured on the host
by cross-compiling for Thumb2 and running size (no device needed):
make floor-thumb2 # cross-compile the floor for Cortex-M33
arm-none-eabi-size -t build/thumb2/*.oThe default floor (all curves + ASN + both SP backends, pre---gc-sections)
sums to ~250 KB .text as an upper bound. The shippable number is much
smaller: roughly 40% is optional adders (X.509/ASN ~50 KB, Ed25519 group ops
~49 KB) a minimal PSK/ECDHE-P256 build does not link, and --gc-sections drops
the unreferenced remainder. A minimal TLS 1.3 floor (ECDHE-P256 + AES-GCM +
SHA-256 + HKDF + DRBG) lands far lower.
Whole TLS 1.3 client linked from source for Cortex-M33 (X25519, AES-128-GCM,
SHA-256), arm-none-eabi-gcc -Os -flto -ffunction-sections -fdata-sections -Wl,--gc-sections + nano specs (ArmGNU 14.2), with wolfNano and mbedTLS 3.6
both hard-minimized to the identical scope. .text bytes:
| Client | wolfNano | mbedTLS (hard-min) | full wolfSSL | smaller by |
|---|---|---|---|---|
| PSK + ECDHE, X25519 | 18000 | 42100 | - | 57% |
| PSK + ECDHE, P-256 | 25840 | 50848 | - | 49% |
| PSK + X25519MLKEM768 (PQC) | 33664 | - | - | - |
| cert / X.509, P-256 | 62297 | 101232 | 150913 | 38% |
The wolfNano column builds from the public configs/ starter templates
(user_settings_minimal.h, user_settings_psk_p256.h, user_settings_pqc.h,
user_settings_cert.h), so the numbers reproduce from the same user_settings.h
a deployment ships. The PQC client is a complete TLS 1.3 PSK handshake with the
X25519MLKEM768 hybrid (ML-KEM-768 + X25519); the ~15 KB over the classical
X25519 client is the ML-KEM lattice math plus SHA-3/SHAKE, the same wc_mlkem
code wolfSSL ships.
mbedTLS is given its smallest config too (MBEDTLS_ECP_FIXED_POINT_OPTIM 0,
ECP_WINDOW_SIZE 2) so the comparison is not inflated in wolfNano's favor.
Both sides are hard-minimized to SHA-256 only (verified: zero SHA-384/512/3,
MD5, SHA-1, DES, ChaCha, CBC/CTR, RSA, ECDSA symbols in either PSK binary).
SHA-256 itself is mandatory in TLS 1.3 (HKDF key schedule, transcript hash,
Finished MAC, PSK binder) and present on both. The remaining wolfNano vs mbedTLS
gap is architectural: wolfNano uses specialized fe_* X25519 field arithmetic
and direct wc_* calls; mbedTLS routes X25519 through its general ECP + bignum
and the mandatory PSA dispatch layer, and links full AES tables. P-256's SP math
is heavier than Curve25519, so both sides grow for P-256. The P-256 PSK client is
interop-verified live against OpenSSL and wolfSSL.
The honest framing:
-
Hard-minimized both sides (the fair number): 34% (PSK) / 40% (cert)
smaller. Getting mbedTLS this small required a custom minimal
PSA_WANT_*crypto config (MBEDTLS_PSA_CRYPTO_CONFIG) and stripping restartable-ECP, SHA-384/512, and the non-GCM AES modes, because mbedTLS 3.6's PSA layer pulls in RSA, SHA-1/3, Camellia, DES, ChaCha by default (~80 KB stock PSK). -
Reproduce:
sh bench/footprint-clients.sh. Exact configs:bench/min/mbedtls_config_psk_hardmin.h+bench/min/mbedtls_crypto_config_psk.h(mbedTLS),configs/user_settings_*.h(wolfNano). - Both harness clients use opaque (volatile) I/O stubs. A constant-returning stub lets LTO prove the handshake aborts after ClientHello and dead-strip the rest, understating the footprint; the opaque stub forces the whole reachable handshake to stay. Verified: making the mbedTLS bio opaque too moved its PSK number by <30 bytes, so neither side is being dead-stripped.
- Raw crypto primitives are ~parity (mbedTLS's compact bignum/ECP is its design strength); wolfNano's win is the TLS layer plus whole-stack assembly.
- Full wolfSSL with X.509 is ~147 KB, which is the reason a slim shell exists.
- Classical numbers. Enabling PQC or asm adds flash; this is the lean classical floor.
| Build | flash + RAM budget | device classes |
|---|---|---|
| PSK (17 KB) | ~17 KB flash, ~8-16 KB RAM | Cortex-M0+/M3/M4 from ~32 KB flash: LoRaWAN/NB-IoT/Matter sensors, wearables (STM32L0/L4, nRF52) |
| cert (60 KB) | ~60 KB flash, ~24-40 KB RAM | Cortex-M4/M33 from ~128 KB flash: cloud-IoT endpoints, gateways (STM32L4/U5/H5, nRF53, ESP32) |
The footprint edge lands hardest on small parts: at ~17 KB the X25519 PSK client fits where even a hard-minimized mbedTLS (41 KB) cannot, and a stock mbedTLS (~80 KB) is out of the question.
- The crypto-floor and TLS-layer numbers earlier are host (x86_64) for relative comparison; the whole-client table above is on-target Cortex-M33.
- The comparison is deliberately the TLS layer only; the shared crypto floor is excluded because it is byte-identical in both.
- This measures the current shell (key schedule, transcript, record). It grows
as the handshake state machine lands, but stays a small fraction of the
wolfSSL TLS layer because the
WOLFSSL/internal.cmachinery is never pulled in.