Repository navigation
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
The cross-architecture cryptographic state-machine refactor requires maintainer validation of constant-time behavior and worst-case per-yield latency on supported targets.
No open issues 🎉
What changed in this PR
This PR reduces yield overhead in wolfCrypt’s non-blocking SP ECC operations, improving asynchronous TLS handshake performance by doing more arithmetic per step.
Changes:
- Replaces field-level sub-state machines with complete point operations, grouped window doubles, and single-step order inversion.
- Resets completed ECC verification contexts and adds a regression test for repeated verification.
- Preserves non-blocking contexts when reinitializing RSA, ECC, and X25519 keys.
| File | Description |
|---|---|
wolfcrypt/test/test.c |
Tests context reuse with valid and corrupted signatures. |
wolfcrypt/src/sp_x86_64.c |
Coarsens non-blocking ECC steps and resets verification contexts on x86_64. |
wolfcrypt/src/sp_arm64.c |
Applies the same ECC stepping and context-reset changes on ARM64. |
src/internal.c |
Reattaches non-blocking contexts after key reinitialization. |
Review effort: Balanced
|
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #12025
Scan targets checked: wolfcrypt-src, wolfcrypt-bugs, wolfssl-src, wolfssl-bugs
Not reviewed (no scan target covers them): wolfcrypt/src/sp_arm32.c, wolfcrypt/src/sp_arm64.c, wolfcrypt/src/sp_armthumb.c, wolfcrypt/src/sp_cortexm.c, wolfcrypt/src/sp_x86_64.c
Coverage: 5 of 5 in-scope changed file(s) opened by the reviewer
Fenrir result: Approved ✅
No new issues found in the changed files.
Advisory only — this automated result does not count as a GitHub approval.
Review tier: Max
Description
Each SP ECC non-blocking step was a single field multiply or square: the ladder, window and base-table state machines drove the point add and double through their own sub-state machines, and the order inversion stepped one squaring at a time. Every yield costs the caller fixed work that has nothing to do with the math. Under TLS with the software async device that is a
wolfSSL_connect/wolfSSL_acceptre-entry plus awolfSSL_AsyncPoll(event queue walk,wolfAsync_DoSw, ecc.c dispatch), about 10 us per yield on a 375 MHz Cortex-A53 against well under 1 us of field arithmetic, and a TLS 1.2 ECDHE-ECDSA mutual-auth handshake took about 50,000 yields. A customer driving that handshake from a 50 Hz control loop with a 2 ms slice per tick therefore spent several seconds of wall time per handshake, almost all of it yield overhead rather than crypto. Each step is now one point operation; the window doubles run as one step and the order inversion processes one digit of exponent bits per step, so the longest step in every operation is the final conversion out of projective coordinates, which was already a single step, and the same handshake takes about 1,600 yields. The_nbpoint add and double state machines and their contexts are removed, and the base-point path uses the Z=1 add like the blocking code. Yields per operation (WOLFSSL_DEBUG_NONBLOCKcounts) and longest single step in microseconds (Raspberry Pi 5, Cortex-A76 at 2.4 GHz, one core, median of five runs), before -> after:Two related fixes:
sp_ecc_verify_*_nbdid not reset its context on completion, so a second verify through the same key and context returned the stale result, and a shared secret through that context afterwards never completed because the mulmod state machine has no state matching the leftover one (ecc_test_nonblocknow verifies twice through one context, the second with a corrupted signature), andReuseKeydropped the non-blocking context across the key free and re-init, leaking it and running blocking crypto on a reusedWOLFSSL; it now re-attaches it for ECC, X25519 and RSA.ZD 22480
Testing
Tested with
testwolfcryptunder--enable-ecc=nonblockon x86_64 (asm large, small and 32-bit C), aarch64 asm large and small on a Raspberry Pi 5, ARM32 asm, Cortex-M and Thumb-1 asm compile only, andmake checkwith--enable-asynccrypt --enable-asynccrypt-sw(ECC, X25519 and RSA non-blocking). The step timings in the table come from a loop callingwc_ecc_make_key_ex,wc_ecc_sign_hash,wc_ecc_verify_hashandwc_ecc_shared_secretwith a non-blocking context and timing each call, pinned to one core.