wolfCrypt on TI C2000 C28x (LAUNCHXL-F28P55X)#10724
Open
dgarske wants to merge 8 commits into
Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds and CI-guards a bare-metal wolfCrypt port for TI C2000 C28x targets where CHAR_BIT == 16, introducing gated fixes so hashing, DRBG, ML-DSA verify, and SP-math ECC work correctly when a C “byte” is wider than 8 bits.
Changes:
- Introduces
WOLFSSL_NO_OCTET_BYTEdetection and uses octet-wise load/store paths to avoid invalid byte/word aliasing onCHAR_BIT != 8targets (SHA-256/512 family, SHA-3/SHAKE, Base64 CT decode, DRBG helpers, rotate helpers). - Adds “smallest memory” ML-DSA verify mode that streams
zper polynomial to reduce pinned RAM inwc_MlDsaKey. - Adds TI C2000 compile-only guard scripts plus a GitHub Actions workflow that downloads the TI CGT and compiles a scoped subset.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| wolfssl/wolfcrypt/wc_port.h | Makes atomic arg type selection robust for 16-bit int by also checking UINT_MAX. |
| wolfssl/wolfcrypt/wc_mldsa.h | Adds WOLFSSL_MLDSA_VERIFY_SMALLEST_MEM struct layout variant for reduced verify RAM. |
| wolfssl/wolfcrypt/types.h | Adds WOLFSSL_NO_OCTET_BYTE auto-detection; adjusts WC_16BIT_CPU 64-bit availability behavior. |
| wolfssl/wolfcrypt/sp_int.h | Adds support for unsigned char being 16-bit (no native 8-bit type). |
| wolfssl/wolfcrypt/settings.h | Requires explicit opt-in for SP math on 16-bit-int CPUs via WOLFSSL_SP_ALLOW_16BIT_CPU. |
| wolfssl/wolfcrypt/dilithium.h | Adds smallest-mem verify gating and defaults slow Montgomery reduction macros on WC_16BIT_CPU. |
| wolfcrypt/test/test.c | Switches large-digest constants from C strings to byte[] to avoid CHAR_BIT!=8 pitfalls. |
| wolfcrypt/src/wc_port.c | Fixes init-state static assert to use CHAR_BIT instead of hardcoded 8. |
| wolfcrypt/src/wc_mldsa.c | Adds octet-masking for packed bytes and fixes integer-promotion/sign issues on 16-bit int; adds streaming z verify path. |
| wolfcrypt/src/sha512.c | Adds octet-wise word load/store and corrects length carry/length placement for CHAR_BIT!=8. |
| wolfcrypt/src/sha3.c | Forces bytewise Keccak absorb/squeeze for WOLFSSL_NO_OCTET_BYTE and adds squeeze helper. |
| wolfcrypt/src/sha256.c | Adds octet-wise word load/store and corrects length carry/length placement for CHAR_BIT!=8. |
| wolfcrypt/src/random.c | Fixes DRBG serialization/addition helpers for non-8-bit “byte” targets. |
| wolfcrypt/src/misc.c | Fixes rotate helpers to use CHAR_BIT-based bit width when needed. |
| wolfcrypt/src/coding.c | Ensures Base64 CT decode returns 0xFF for invalid chars even when byte is wider than 8 bits. |
| wolfcrypt/benchmark/benchmark.c | Adds static buffers for WOLFSSL_NO_MALLOC benchmarking and adjusts frees/allocations accordingly. |
| scripts/ti-c2000/user_settings.h | Adds minimal CI-only config for cl2000 compile-guard. |
| scripts/ti-c2000/compile.sh | Adds compile-only script to build a scoped source set with TI cl2000. |
| .github/workflows/ti-c2000-compile.yml | Adds CI workflow to download/cache TI CGT and run the compile-only guard. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
39c343a to
afaf660
Compare
0f8a445 to
b5dfdc2
Compare
|
retest this please |
SparkiDev
requested changes
Jul 1, 2026
53c7a2a to
21132b9
Compare
…I C2000 C28x) - core types, misc octet helpers, base64, DRBG
…tation for CHAR_BIT != 8
…MLDSA_VERIFY_SMALLEST_MEM
…<->mp conversion for CHAR_BIT != 8 Curve448/Ed448 build with the CURVE448_SMALL / ED448_SMALL byte-array field backend (the default fe_448 backend needs __uint128_t for the sc448 mod-order arithmetic, which the C28x toolchain lacks). The SMALL fe448 carry-stores wrote each limb through a (word8) cast that does not truncate to an octet when a C byte is wider than 8 bits, so the next carry re-read saw a corrupted limb; mask each carry-store with WC_OCTET (a no-op on the usual 8-bit-byte targets).
…I C2000 compile CI and docs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Companion example PR (wolfssl-examples): wolfSSL/wolfssl-examples#576
Summary
Adds
WOLFSSL_WIDE_BYTEsupport so wolfCrypt builds and runs correctly on word-addressed targets whereCHAR_BIT != 8- specifically the TI C2000 C28x DSP family, where a Cchar/unsigned char(wolfSSL'sbyte) is 16 bits and is the smallest addressable unit. All changes are gated and are a no-op on normal 8-bit-byte targets.The work was validated end-to-end on a TI LAUNCHXL-F28P55X (TMS320F28P550SJ, C28x, 150 MHz) using the bare-metal example added in the companion wolfssl-examples PR. Every algorithm below passes known-answer tests on hardware, and the standard host
wolfcrypt_testcontinues to pass (no 8-bit regression).Validated algorithms (on C28x hardware)
WC_16BIT_CPUthat emits native instructions instead of compiler 64-bit helper calls - ~53% faster SHAKE/SHA3 on this target)What the
CHAR_BIT != 8fixes addressAll behind
WOLFSSL_WIDE_BYTE(auto-enabled forCHAR_BIT != 8and known 16-bit-char TI toolchain macros), each a no-op on 8-bit targets:word32/word64by casting tobyte*moves addressable cells, not octets. Replaced with explicit shift-based octet I/O via shared helpers inmisc.c(WordsFromBytesBE32/BytesFromWordsBE32,BytesFromWordsLE32, the 64-bit variants, octet-correctreadUnalignedWord32/readUnalignedWord64).sp_int.csp_read_unsigned_binuses an endian-/CHAR_BIT-agnostic shift loop for its leftover bytes (a 3-byte RSA exponent previously loaded as 1 instead of 65537).(byte)xnot truncating to an octet (it keeps 16 bits). Masked withWC_OCTET(x)=(byte)((x) & 0xFF). Used across the ML-KEM/ML-DSA encoders, the SP*_to_binserializers, AESGETBYTE, base64, the DRBG, and the Curve448/Ed448CURVE448_SMALLbyte-array field backend (whose carry-store(word8)casts must mask before the next limb re-reads them).1U << nis 16-bit on C28x (use1UL); a bit width writtensizeof(t) * 8is wrong whenCHAR_BIT != 8(useCHAR_BIT * sizeof(t));byteoperands promote to a 16-bitint.sizeofcounting cells, not octets. e.g.CHACHA_CHUNK_BYTESmust be16 * 4, not16 * sizeof(word32)(= 32 on C28x, which halves the ChaCha block and desyncs the counter).xorbufword stride.WOLFSSL_WORD_SIZE_LOG2vssizeof(word)mismatch left half of each buffer un-XORed on a 16-bit-cell target; corrected for theWC_16BIT_CPUword16path.-O2,mldsa_red()'s Barrett reduction emits a stray store that corrupts memory a later allocation trips on, while the reduced value stays correct). Both are worked around indilithium.h, defaulted on underWC_16BIT_CPU, so ML-DSA builds at full-O2with no per-file overrides.New build options (added by this PR)
WOLFSSL_WIDE_BYTE- master gate for theCHAR_BIT != 8support. Auto-enabled bywolfssl/wolfcrypt/types.hwhenCHAR_BIT != 8or a known 16-bit-char TI toolchain macro is seen (__TMS320C28XX__,__TMS320C2000__, ...); can be forced. No effect on 8-bit-byte targets.WC_OCTET(x)(types.h) -(byte)((x) & 0xFF), the octet-truncation helper used wherever a value must be reduced to 8 bits regardless of type width.WOLFSSL_MLDSA_VERIFY_SMALLEST_MEM- streams the ML-DSA signature response vector one polynomial at a time instead of buffering all of it. Combined withWOLFSSL_MLDSA_ASSIGN_KEY(public key referenced in flash) andWOLFSSL_DILITHIUM_VERIFY_NO_MALLOC, brings ML-DSA-87 verify to ~10.8 KB RAM with zero heap.MLDSA_MUL_QINV_WIDE64andMLDSA_MUL_Q_SLOW(dilithium.h) - the two cl2000 workarounds above, defaulted on underWC_16BIT_CPU(no-ops elsewhere); each can be disabled with an override.WC_SHA3_SPLIT64- the 32-bit split Keccak permutation, auto-enabled forWOLFSSL_WIDE_BYTE(~53% faster SHAKE/SHA3 on this target; portable C, no assembly).Recommended configuration (C28x / CHAR_BIT != 8)
WOLFSSL_SP_MATH,SP_WORD_SIZE 32,WOLFSSL_SP_ALLOW_16BIT_CPU(addWOLFSSL_SP_NO_MALLOCfor a no-heap build).WOLFSSL_MLDSA_VERIFY_SMALLEST_MEM+WOLFSSL_MLDSA_ASSIGN_KEY+WOLFSSL_DILITHIUM_VERIFY_NO_MALLOC(~10.8 KB RAM, zero heap).WOLFSSL_MLDSA_SIGN_SMALL_MEM(min RAM) ->WOLFSSL_MLDSA_SIGN_SMALL_MEM_PRECALC_A(faster) -> full memory (fastest). ML-DSA keygen:WOLFSSL_MLDSA_MAKE_KEY_SMALL_MEM. Cross-op caches:WC_DILITHIUM_CACHE_MATRIX_A/CACHE_PUB_VECTORS/CACHE_PRIV_VECTORSfor repeated ops with one key.WOLFSSL_MLKEM_SMALL,WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM,WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM,WOLFSSL_MLKEM_CACHE_A.wc_mldsa.cbuild at-O2.See
IDE/C2000/user_settings.hfor a minimal reference config andIDE/C2000/README.mdfor the full write-up.Footprint (measured on F28P55X, cl2000 25.11.0; octets, KB = 1024 octets)
Code size is per-object
.textfrom the linker map (16-bit words x2). Builds are single-parameter: ML-DSA-87 only, ML-KEM-1024 only.wc_mldsa.obj)wc_mlkem+wc_mlkem_poly)WOLFSSL_SHA3_SMALL/ split-64 fast path)RAM per operation, measured on hardware (heap high-water via
wolfSSL_SetAllocators, stack via paint/scan):WOLFSSL_MLDSA_ASSIGN_KEY(zero heap); ~15.9 KB copying the public key into the key structPerformance (F28P55X @ 150 MHz, generic portable C - no assembly or accelerator)
Hashing / RNG throughput:
Post-quantum, measured on hardware (ms/op):
ML-KEM-768 is bracketed by the measured 512/1024 figures (the exact line drops over the slow JTAG-CIO console). ML-DSA sign reflects the RAM-optimized
WOLFSSL_MLDSA_SIGN_SMALL_MEMbuild and varies run-to-run (rejection sampling); the higher-RAM configurations above trade RAM for faster signing.Testing
./configure --enable-dilithium --enable-experimental --enable-shake256 --enable-shake128 && make && ./wolfcrypt/test/testwolfcrypt- passes (RSA, ECC, ML-DSA, ML-KEM, SHA-2/3, all crypto). No behavior change on 8-bit-byte targets.wolfcrypt_testcrypto passes.IDE/C2000/compile.shrunscl2000 --compile_onlyover theCHAR_BIT != 8wolfCrypt subset (SHA-1/2/3, AES + modes, ChaCha/Poly1305, X25519/Ed25519, X448/Ed448, ML-DSA verify, SP-ECC);.github/workflows/ti-c2000-compile.ymlruns it on PRs (fetches/caches the TI C2000 code generation tools, with optional SHA-256 pinning of the installer).Notes
wolfcrypt/src/sp_c32.cis generated. The& 0xFFoctet masks added to itssp_*_to_bin_*serializers are also applied in the SP generator templates (kept in sync so a regeneration preserves them).IDE/C2000/README.mddescribes the support, the build options, and the benchmark/footprint results; the full bare-metal example (with KATs, benchmark, linker scripts, and per-algorithmmaketoggles) is in wolfssl-examples atembedded/ti-c2000-f28p55x/.