From 8078c2a352d1f93c288c06addb6c7dbf24da9bdf Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 17 Jun 2026 16:32:45 -0700 Subject: [PATCH 01/13] Add TI LAUNCHXL-F28P55X (C2000 C28x) bare-metal wolfCrypt example New embedded/ti-c2000-f28p55x/ example for the TMS320F28P550SJ (C28x DSP, CHAR_BIT==16). Scoped bare-metal build (cl2000) demonstrating, validated on hardware: SHA-256/384/512(+512-224/256), SHA-3, SHAKE128/256; ML-DSA-87 verify, keygen and sign (make SIGN=1); and ECDSA + ECDH P-256 via SP math (make ECC=1). ML-DSA verify uses the smallest-mem streaming verifier. Includes BSP/startup, SCIA + JTAG-RAM logging, linker scripts, KAT headers, a wolfcrypt test/benchmark harness, a stack-usage profiler, and a 'make compile-ci' guard. Needs a wolfSSL checkout with the CHAR_BIT!=8 fixes (set WOLFROOT). --- embedded/ti-c2000-f28p55x/.gitignore | 2 + .../28p55x_wolf_flash_lnk.cmd | 78 ++ .../ti-c2000-f28p55x/28p55x_wolf_sign_lnk.cmd | 75 ++ .../ti-c2000-f28p55x/Header/user_settings.h | 339 ++++++++ embedded/ti-c2000-f28p55x/Makefile | 150 ++++ embedded/ti-c2000-f28p55x/README.md | 80 ++ .../ti-c2000-f28p55x/Source/ecc_p256_kat.h | 39 + .../ti-c2000-f28p55x/Source/mldsa87_kat.h | 611 +++++++++++++++ embedded/ti-c2000-f28p55x/Source/wolf_main.c | 731 ++++++++++++++++++ .../ti-c2000-f28p55x/ccxml/F28P550SJ.ccxml | 32 + 10 files changed, 2137 insertions(+) create mode 100644 embedded/ti-c2000-f28p55x/.gitignore create mode 100644 embedded/ti-c2000-f28p55x/28p55x_wolf_flash_lnk.cmd create mode 100644 embedded/ti-c2000-f28p55x/28p55x_wolf_sign_lnk.cmd create mode 100644 embedded/ti-c2000-f28p55x/Header/user_settings.h create mode 100644 embedded/ti-c2000-f28p55x/Makefile create mode 100644 embedded/ti-c2000-f28p55x/README.md create mode 100644 embedded/ti-c2000-f28p55x/Source/ecc_p256_kat.h create mode 100644 embedded/ti-c2000-f28p55x/Source/mldsa87_kat.h create mode 100644 embedded/ti-c2000-f28p55x/Source/wolf_main.c create mode 100644 embedded/ti-c2000-f28p55x/ccxml/F28P550SJ.ccxml diff --git a/embedded/ti-c2000-f28p55x/.gitignore b/embedded/ti-c2000-f28p55x/.gitignore new file mode 100644 index 000000000..586061447 --- /dev/null +++ b/embedded/ti-c2000-f28p55x/.gitignore @@ -0,0 +1,2 @@ +out/ +*.obj diff --git a/embedded/ti-c2000-f28p55x/28p55x_wolf_flash_lnk.cmd b/embedded/ti-c2000-f28p55x/28p55x_wolf_flash_lnk.cmd new file mode 100644 index 000000000..0cb0dee16 --- /dev/null +++ b/embedded/ti-c2000-f28p55x/28p55x_wolf_flash_lnk.cmd @@ -0,0 +1,78 @@ +/* 28p55x_wolf_flash_lnk.cmd + * + * Linker command file for the wolfCrypt test/benchmark on the + * TI LAUNCHXL-F28P55X (TMS320F28P550SJ), running from flash. EABI only + * (build driverlib and this project with --abi=eabi). + * + * Differs from the stock C2000Ware generic flash linker in three ways that + * the ML-DSA-87 verify path requires: + * - A large STACK in low RAM. The C28x stack pointer is 16-bit, so the + * stack must live below 0x10000. RAMLS0-7 (0x8000..0xBFFF, 16 KW) is the + * largest contiguous low block; the verify key struct (~7 KW pinned by + * WOLFSSL_MLDSA_VERIFY_NO_MALLOC) plus Keccak frames live here. + * - A real heap (.sysmem) in low RAMGS0-1 for the test/benchmark malloc + * temporaries (ML-DSA verify itself allocates nothing). + * - .bss/.data placed in the high RAMGS2-3 + RAMLS8-9 blocks so they do not + * compete with the stack for low RAM. + * + * Copyright (C) 2006-2026 wolfSSL Inc. GPLv3 - see project headers. + */ + +-stack 0x4000 /* 16 KW C28x stack (full RAMLS0-7); wolfcrypt_test's deep call + * chain + SHAKE/large-hash locals (~1.6 KW) need the headroom */ +-heap 0x4000 /* 16 KW heap (full RAMGS0-1) for test/benchmark temporaries; + * benchmark needs ~2 KW of block buffers after the suite */ + +MEMORY +{ + BEGIN : origin = 0x080000, length = 0x000002 + + BOOT_RSVD : origin = 0x000002, length = 0x000126 /* M0, used by boot ROM stack */ + RAMM0 : origin = 0x000128, length = 0x0002D8 + RAMM1 : origin = 0x000400, length = 0x000400 + + /* Low RAM (< 0x10000): usable for the 16-bit-SP stack and the heap. */ + RAMLS_STACK : origin = 0x008000, length = 0x004000 /* RAMLS0-7, 16 KW */ + RAMGS_HEAP : origin = 0x00C000, length = 0x004000 /* RAMGS0-1, 16 KW (< 0x10000) */ + + /* High RAM (>= 0x10000): data only (no stack). */ + RAMGS_HI : origin = 0x010000, length = 0x004000 /* RAMGS2-3, 16 KW */ + RAMLS_HI : origin = 0x014000, length = 0x004000 /* RAMLS8-9, 16 KW */ + + /* Flash banks (ML-DSA verify code + const test vectors are large). */ + FLASH_BANK0 : origin = 0x080002, length = 0x01FFFE + FLASH_BANK1 : origin = 0x0A0000, length = 0x020000 + FLASH_BANK2 : origin = 0x0C0000, length = 0x020000 + FLASH_BANK3 : origin = 0x0E0000, length = 0x020000 + FLASH_BANK4 : origin = 0x100000, length = 0x008000 + + RESET : origin = 0x3FFFC0, length = 0x000002 +} + +SECTIONS +{ + codestart : > BEGIN + .text : >> FLASH_BANK0 | FLASH_BANK1 | FLASH_BANK2 | FLASH_BANK3, ALIGN(8) + .cinit : > FLASH_BANK0, ALIGN(8) + .switch : > FLASH_BANK0, ALIGN(8) + .reset : > RESET, TYPE = DSECT /* unused */ + + .stack : > RAMLS_STACK + + .bss : >> RAMGS_HI | RAMLS_HI + .bss:output : > RAMGS_HI + .init_array : > FLASH_BANK0, ALIGN(8) + .const : >> FLASH_BANK0 | FLASH_BANK1, ALIGN(8) + .data : >> RAMGS_HI | RAMLS_HI + .sysmem : > RAMGS_HEAP + + .TI.ramfunc : {} LOAD = FLASH_BANK0, + RUN = RAMM0, + LOAD_START(RamfuncsLoadStart), + LOAD_SIZE(RamfuncsLoadSize), + LOAD_END(RamfuncsLoadEnd), + RUN_START(RamfuncsRunStart), + RUN_SIZE(RamfuncsRunSize), + RUN_END(RamfuncsRunEnd), + ALIGN(8) +} diff --git a/embedded/ti-c2000-f28p55x/28p55x_wolf_sign_lnk.cmd b/embedded/ti-c2000-f28p55x/28p55x_wolf_sign_lnk.cmd new file mode 100644 index 000000000..91c1fccb8 --- /dev/null +++ b/embedded/ti-c2000-f28p55x/28p55x_wolf_sign_lnk.cmd @@ -0,0 +1,75 @@ +/* 28p55x_wolf_sign_lnk.cmd + * + * Linker command file for the FULL ML-DSA-87 (keygen + sign + verify) build of + * the wolfCrypt example on the TI LAUNCHXL-F28P55X (TMS320F28P550SJ), running + * from flash. EABI only. Selected by `make SIGN=1`. + * + * ML-DSA-87 keygen/sign/verify need a much larger heap than the verify-only + * build. Even with every small-memory path enabled the peak is ~30 KW in a + * single allocation, so this script dedicates the whole contiguous RAMGS0-3 + * block (32 KW) to the heap (.sysmem). The stack stays in low RAMLS0-7 (the + * 16-bit SP needs RAM < 0x10000) and .bss/.data live in RAMLS8-9. The full + * wolfcrypt test/benchmark are NOT built in this mode (they would not fit + * alongside the 32 KW heap), so .bss is small. + * + * Copyright (C) 2006-2026 wolfSSL Inc. GPLv3 - see project headers. + */ + +-stack 0x3000 /* 12 KW C28x stack (< 0x10000); big arrays go to heap via + * WOLFSSL_SMALL_STACK */ +-heap 0x7E00 /* ~31.5 KW heap - ML-DSA-87 keygen/sign peak ~30.5 KW */ + +MEMORY +{ + BEGIN : origin = 0x080000, length = 0x000002 + + BOOT_RSVD : origin = 0x000002, length = 0x000126 /* M0, used by boot ROM stack */ + RAMM0 : origin = 0x000128, length = 0x0002D8 + RAMM1 : origin = 0x000400, length = 0x000400 + + /* Low RAM (< 0x10000): the 16-bit-SP stack. */ + RAMLS_STACK : origin = 0x008000, length = 0x004000 /* RAMLS0-7, 16 KW */ + + /* RAMGS0-3 is one contiguous 32 KW block (0xC000..0x13FFF): the heap. */ + RAMGS_BIG : origin = 0x00C000, length = 0x008000 /* RAMGS0-3, 32 KW */ + + /* High RAM: .bss/.data (no stack here). */ + RAMLS_HI : origin = 0x014000, length = 0x004000 /* RAMLS8-9, 16 KW */ + + /* Flash banks (ML-DSA sign code is large). */ + FLASH_BANK0 : origin = 0x080002, length = 0x01FFFE + FLASH_BANK1 : origin = 0x0A0000, length = 0x020000 + FLASH_BANK2 : origin = 0x0C0000, length = 0x020000 + FLASH_BANK3 : origin = 0x0E0000, length = 0x020000 + FLASH_BANK4 : origin = 0x100000, length = 0x008000 + + RESET : origin = 0x3FFFC0, length = 0x000002 +} + +SECTIONS +{ + codestart : > BEGIN + .text : >> FLASH_BANK0 | FLASH_BANK1 | FLASH_BANK2 | FLASH_BANK3, ALIGN(8) + .cinit : > FLASH_BANK0, ALIGN(8) + .switch : > FLASH_BANK0, ALIGN(8) + .reset : > RESET, TYPE = DSECT /* unused */ + + .stack : > RAMLS_STACK + + .bss : > RAMLS_HI + .bss:output : > RAMLS_HI + .init_array : > FLASH_BANK0, ALIGN(8) + .const : >> FLASH_BANK0 | FLASH_BANK1, ALIGN(8) + .data : > RAMLS_HI + .sysmem : > RAMGS_BIG + + .TI.ramfunc : {} LOAD = FLASH_BANK0, + RUN = RAMM0, + LOAD_START(RamfuncsLoadStart), + LOAD_SIZE(RamfuncsLoadSize), + LOAD_END(RamfuncsLoadEnd), + RUN_START(RamfuncsRunStart), + RUN_SIZE(RamfuncsRunSize), + RUN_END(RamfuncsRunEnd), + ALIGN(8) +} diff --git a/embedded/ti-c2000-f28p55x/Header/user_settings.h b/embedded/ti-c2000-f28p55x/Header/user_settings.h new file mode 100644 index 000000000..fd5ed445c --- /dev/null +++ b/embedded/ti-c2000-f28p55x/Header/user_settings.h @@ -0,0 +1,339 @@ +/* user_settings.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* wolfSSL user settings for the TI C2000 C28x DSP (LAUNCHXL-F28P55X). + * + * IMPORTANT - this is a SCOPED build for a new architecture bring-up: + * - The C28x has 16-bit bytes (CHAR_BIT == 16). wolfSSL's byte-packing + * code assumes 8-bit octets, so this build is deliberately limited to the + * algorithms whose correctness we validate with known-answer tests: + * SHA-256, SHA-384/512, SHA3, SHAKE128/256, and ML-DSA-87 verify only. + * - RSA / ECC / DH / TFM / SP-bignum are NOT built, which avoids the + * big-integer code paths most sensitive to the 16-bit-byte layout. + * - The device has no hardware TRNG and no SHA3 accelerator; everything here + * is portable C software crypto. ML-DSA verify is deterministic and uses + * no entropy. The RNG stub below is for benchmark/test wiring ONLY and is + * NOT cryptographically secure - do not ship it. + */ + +#ifndef WOLFSSL_USER_SETTINGS_C2000_H +#define WOLFSSL_USER_SETTINGS_C2000_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------------------------------------------------------------- */ +/* Platform / C28x toolchain */ +/* ------------------------------------------------------------------------- */ +#undef SINGLE_THREADED +#define SINGLE_THREADED + +#undef WOLFCRYPT_ONLY /* crypto only, no TLS layer */ +#define WOLFCRYPT_ONLY + +#undef NO_FILESYSTEM +#define NO_FILESYSTEM + +#undef NO_WRITEV +#define NO_WRITEV + +#undef NO_MAIN_DRIVER /* our main() lives in wolf_main.c */ +#define NO_MAIN_DRIVER + +#undef NO_DEV_RANDOM +#define NO_DEV_RANDOM + +#undef NO_SESSION_CACHE +#define NO_SESSION_CACHE + +#undef WOLFSSL_IGNORE_FILE_WARN +#define WOLFSSL_IGNORE_FILE_WARN + +#undef BENCH_EMBEDDED /* reduced benchmark sizes for an MCU */ +#define BENCH_EMBEDDED + +/* C28x integer widths: char/short/int = 16-bit, long = 32-bit, + * long long = 64-bit. wolfCrypt needs a true 64-bit word for SHA3/SHA-512 + * and ML-DSA, which long long provides. */ +#undef SIZEOF_LONG +#define SIZEOF_LONG 4 +#undef SIZEOF_LONG_LONG +#define SIZEOF_LONG_LONG 8 + +/* Pull in the toolchain's so CHAR_BIT is the real value (16 on + * C28x) instead of wolfSSL's 8-bit fallback, and so UINT_MAX reflects the + * 16-bit int. This is critical for correct byte math. */ +#undef HAVE_LIMITS_H +#define HAVE_LIMITS_H + +/* C28x has 16-bit int. WC_16BIT_CPU makes wolfSSL use the correct integer + * widths (word16 = unsigned int = 16-bit, word32 = unsigned long = 32-bit); + * without it wolfSSL assumes int is 32-bit and word32 comes out only 16 bits, + * silently truncating all 32-bit crypto math. C28x also has a native 64-bit + * long long, so WORD64_AVAILABLE is preserved via the SIZEOF_LONG_LONG==8 + * guard added to types.h (for SHA-512/SHA-3/ML-DSA). */ +#undef WC_16BIT_CPU +#define WC_16BIT_CPU + +/* The C28x is little-endian. Leave BIG_ENDIAN_ORDER undefined so the default + * little-endian path is used. (Verify on hardware with the SHA KATs.) */ + +/* CHAR_BIT==16 portability levers (see README "16-bit byte" section): + * ML-DSA bit-packing has fast paths that cast a byte buffer to word32/word64 + * (gated on WOLFSSL_MLDSA_ALIGNMENT <= 2/4/8). On a 16-bit-byte machine a + * wordN spans N/2 cells, not N octets, so every such cast is wrong. Force + * the fully portable byte-by-byte path by making the alignment exceed all + * the gates (max gate is <= 8). + * The Keccak state-aliasing hazard (xorbuf/memcpy over the word64 state) is + * handled by the gated octet-wise SHA3 path in sha3.c (WC_SHA3_BYTEWISE). */ +#undef WOLFSSL_GENERAL_ALIGNMENT +#define WOLFSSL_GENERAL_ALIGNMENT 2 +#undef WOLFSSL_MLDSA_ALIGNMENT +#define WOLFSSL_MLDSA_ALIGNMENT 16 + +/* Force portable C cores - no x86/ARM assembly. */ +#undef WOLFSSL_NO_ASM +#define WOLFSSL_NO_ASM +#undef WC_SHA3_NO_ASM +#define WC_SHA3_NO_ASM + +/* Compile misc.c as its own translation unit (extern, not inline). The TI + * CGT treats a plain `inline` definition as a C99 extern-inline and emits no + * out-of-line copy, so the inline-misc path leaves xorbuf/ByteReverseWords64 + * unresolved at link. NO_INLINE makes them ordinary extern functions; the + * build compiles wolfcrypt/src/misc.c once. */ +#undef NO_INLINE +#define NO_INLINE + +/* ------------------------------------------------------------------------- */ +/* Hashing - the scoped subset */ +/* ------------------------------------------------------------------------- */ +/* SHA-256/224 are on by default (NO_SHA256 not defined). */ + +#undef WOLFSSL_SHA512 +#define WOLFSSL_SHA512 +#undef WOLFSSL_SHA384 +#define WOLFSSL_SHA384 + +#undef WOLFSSL_SHA3 +#define WOLFSSL_SHA3 +#undef WOLFSSL_SHAKE128 +#define WOLFSSL_SHAKE128 +#undef WOLFSSL_SHAKE256 +#define WOLFSSL_SHAKE256 + +/* ------------------------------------------------------------------------- */ +/* ML-DSA-87 (Dilithium L5) - VERIFY ONLY */ +/* ------------------------------------------------------------------------- */ +#undef WOLFSSL_HAVE_MLDSA +#define WOLFSSL_HAVE_MLDSA + +/* Build only ML-DSA-87 (level 5). */ +#undef WOLFSSL_NO_ML_DSA_44 +#define WOLFSSL_NO_ML_DSA_44 +#undef WOLFSSL_NO_ML_DSA_65 +#define WOLFSSL_NO_ML_DSA_65 + +/* Raw key/sig import - no ASN.1 (both modes). */ +#undef WOLFSSL_MLDSA_NO_ASN1 +#define WOLFSSL_MLDSA_NO_ASN1 + +#ifdef WOLF_MLDSA_SIGN +/* Full ML-DSA-87 (keygen + sign + verify). Build with `make SIGN=1`. ML-DSA-87 + * keygen/sign/verify need a large working set; enabling EVERY small-memory path + * brings the peak heap to ~30 KW (measured on host), which fits the C28x when + * the sign linker script gives .sysmem the RAMGS0-3 block. NOTE: the dev RNG + * stub below is NOT secure - real signing needs a true TRNG. */ +#undef WOLFSSL_MLDSA_MAKE_KEY_SMALL_MEM +#define WOLFSSL_MLDSA_MAKE_KEY_SMALL_MEM +#undef WOLFSSL_MLDSA_SIGN_SMALL_MEM +#define WOLFSSL_MLDSA_SIGN_SMALL_MEM +#undef WOLFSSL_MLDSA_VERIFY_SMALL_MEM +#define WOLFSSL_MLDSA_VERIFY_SMALL_MEM +#undef WOLFSSL_MLDSA_SMALL_MEM_POLY64 +#define WOLFSSL_MLDSA_SMALL_MEM_POLY64 +/* ML-DSA-87 sign/keygen put large polynomial arrays on the stack by default, + * which overflows the C28x's low-RAM (< 0x10000) stack. WOLFSSL_SMALL_STACK + * moves those to the heap (sized by the sign linker for ~31 KW peak). */ +#undef WOLFSSL_SMALL_STACK +#define WOLFSSL_SMALL_STACK +#else +/* Verify path only (auto-derives NO_MAKE_KEY + NO_SIGN + public-key-only), + * with the small-memory streaming verifier and no heap (buffers pinned into + * the key struct). */ +#undef WOLFSSL_MLDSA_VERIFY_ONLY +#define WOLFSSL_MLDSA_VERIFY_ONLY +#undef WOLFSSL_MLDSA_VERIFY_SMALL_MEM +#define WOLFSSL_MLDSA_VERIFY_SMALL_MEM +#undef WOLFSSL_MLDSA_VERIFY_NO_MALLOC +#define WOLFSSL_MLDSA_VERIFY_NO_MALLOC +/* Smallest verify RAM: stream the signature's z vector one polynomial at a + * time instead of pinning the whole l-vector (saves ~6 KB on ML-DSA-87). + * Measured on F28P55x: sizeof(wc_MlDsaKey) 20,048 -> 13,904 bytes. */ +#undef WOLFSSL_MLDSA_VERIFY_SMALLEST_MEM +#define WOLFSSL_MLDSA_VERIFY_SMALLEST_MEM +/* Optional on this part: also define WOLFSSL_MLDSA_ASSIGN_KEY to keep the + * public key in flash (by reference) instead of copying it into the key + * struct - that removes a further ~5 KB of RAM (the 2,592-octet public key is + * a 5,184-byte byte[] on the 16-bit-cell C28x), bringing ML-DSA-87 verify to + * ~10.7 KB total RAM. Left off by default because the caller must keep the + * public-key buffer valid for the key's lifetime. */ +#endif + +/* ------------------------------------------------------------------------- */ +/* Disabled: big-integer / asymmetric (keeps TFM/ECC/integer out of build) */ +/* ------------------------------------------------------------------------- */ +#ifdef WOLF_ECC +/* ------------------------------------------------------------------------- */ +/* ECC P-256 (SECP256R1) via SP single-precision math (sp_c32.c), no malloc. */ +/* Enabled with EXTRA_CFLAGS=--define=WOLF_ECC (ECC=1 build). Covers ECDSA */ +/* keygen/sign/verify and ECDH. Uses raw mp_int (sign/verify _ex) APIs so no */ +/* ASN/DER is required for bring-up. */ +/* ------------------------------------------------------------------------- */ +#undef HAVE_ECC +#define HAVE_ECC +#undef ECC_USER_CURVES /* build only the curves we name (just P-256) */ +#define ECC_USER_CURVES +#undef HAVE_ECC256 +#define HAVE_ECC256 +#undef HAVE_ECC_VERIFY +#define HAVE_ECC_VERIFY +#undef HAVE_ECC_SIGN +#define HAVE_ECC_SIGN +#undef HAVE_ECC_DHE /* ECDH shared secret */ +#define HAVE_ECC_DHE +#undef ECC_TIMING_RESISTANT +#define ECC_TIMING_RESISTANT +/* SP single-precision P-256 backend (32-bit limbs in sp_c32.c). */ +#undef WOLFSSL_SP_MATH +#define WOLFSSL_SP_MATH +#undef WOLFSSL_HAVE_SP_ECC +#define WOLFSSL_HAVE_SP_ECC +#undef WOLFSSL_SP_NO_MALLOC +#define WOLFSSL_SP_NO_MALLOC +#undef WOLFSSL_SP_SMALL +#define WOLFSSL_SP_SMALL +#undef SP_WORD_SIZE +#define SP_WORD_SIZE 32 +/* C28x int is 16-bit (WC_16BIT_CPU) but we use 32-bit SP digits + octet-wise + * byte I/O, so opt past the conservative SP-vs-16-bit guard. */ +#undef WOLFSSL_SP_ALLOW_16BIT_CPU +#define WOLFSSL_SP_ALLOW_16BIT_CPU +/* NO_BIG_INT stays off: SP provides the mp_int interface. */ +#else +/* No multi-precision integer math at all (no SP/TFM/integer.c). ML-DSA verify + * and the hashes use no mp_int, and this avoids the SP-math vs WC_16BIT_CPU + * conflict. */ +#undef NO_BIG_INT +#define NO_BIG_INT +#endif /* WOLF_ECC */ + +#undef NO_RSA +#define NO_RSA +#undef NO_DH +#define NO_DH +#undef NO_DSA +#define NO_DSA +#ifndef WOLF_ECC +/* HAVE_ECC intentionally not defined - no ECC. */ +#endif +#undef WOLFSSL_HAVE_MLKEM /* no ML-KEM this pass */ +#undef NO_ASN +#define NO_ASN /* ML-DSA + ECC raw import; no asn.c needed */ +#undef NO_CERTS +#define NO_CERTS +#undef NO_PWDBASED +#define NO_PWDBASED +#undef NO_PKCS7 +#define NO_PKCS7 +#undef NO_PKCS12 +#define NO_PKCS12 +#undef NO_SIG_WRAPPER +#define NO_SIG_WRAPPER + +/* ------------------------------------------------------------------------- */ +/* Disabled: unused symmetric / legacy (shrink the first build) */ +/* ------------------------------------------------------------------------- */ +#undef NO_AES /* AES accelerator support is a later phase */ +#define NO_AES +#undef NO_DES3 +#define NO_DES3 +#undef NO_RC4 +#define NO_RC4 +#undef NO_MD4 +#define NO_MD4 +#undef NO_MD5 +#define NO_MD5 +#undef NO_SHA /* SHA-1 not in scope */ +#define NO_SHA +#undef NO_HMAC /* relax if the harness needs it */ +#define NO_HMAC + +/* ------------------------------------------------------------------------- */ +/* Memory */ +/* ------------------------------------------------------------------------- */ +/* Use the TI runtime heap (malloc/free) for test/benchmark temporaries. + * ML-DSA verify itself allocates nothing (WOLFSSL_MLDSA_VERIFY_NO_MALLOC). + * NO_WOLFSSL_MEMORY routes XMALLOC straight to malloc/free with no wrapper. */ +#undef NO_WOLFSSL_MEMORY +#define NO_WOLFSSL_MEMORY + +/* ------------------------------------------------------------------------- */ +/* Time - benchmark elapsed time comes from a CPU timer (wolf_main.c) */ +/* ------------------------------------------------------------------------- */ +#undef NO_ASN_TIME +#define NO_ASN_TIME + +#undef WOLFSSL_USER_CURRTIME /* benchmark.c uses our current_time() */ +#define WOLFSSL_USER_CURRTIME + +/* XTIME stub - hashing and ML-DSA verify never use wall-clock time. Define + * XTIME directly (not TIME_OVERRIDES) so wolfSSL leaves ours in place and + * defaults XGMTIME on its own (nothing in this scoped build calls XGMTIME). */ +extern long my_time(long* t); +#undef XTIME +#define XTIME(tl) my_time((tl)) + +/* ------------------------------------------------------------------------- */ +/* RNG - real SHA-256 Hash-DRBG seeded by a DEV-ONLY test seed */ +/* ------------------------------------------------------------------------- */ +/* The F28P550SJ has no hardware TRNG, so there is no real entropy source. + * WOLFSSL_GENSEED_FORTEST makes random.c supply a built-in wc_GenerateSeed + * (an incrementing test value) that feeds the standard SHA-256 Hash-DRBG. + * This exercises the real DRBG code path (what a production build with a TRNG + * would use) and lets random_test pass - but the seed is NOT random, so this + * is DEV/TEST ONLY and MUST NOT be shipped. Replace wc_GenerateSeed with a + * real TRNG before any production use. */ +#undef WOLFSSL_GENSEED_FORTEST +#define WOLFSSL_GENSEED_FORTEST + +/* Run every self-test to completion and report each, so macro_test (a 16-bit + * safe-math self-test that currently fails on C28x) does not abort the suite + * before the SHA/SHAKE/ML-DSA KATs run. */ +#undef TEST_ALWAYS_RUN_TO_END +#define TEST_ALWAYS_RUN_TO_END + +#ifdef __cplusplus +} +#endif + +#endif /* WOLFSSL_USER_SETTINGS_C2000_H */ diff --git a/embedded/ti-c2000-f28p55x/Makefile b/embedded/ti-c2000-f28p55x/Makefile new file mode 100644 index 000000000..842e81457 --- /dev/null +++ b/embedded/ti-c2000-f28p55x/Makefile @@ -0,0 +1,150 @@ +# Makefile - headless wolfCrypt test/benchmark build for TI LAUNCHXL-F28P55X +# (TMS320F28P550SJ, C2000 C28x DSP), built from flash with cl2000. +# +# Copyright (C) 2006-2026 wolfSSL Inc. GPLv3 - see project headers. +# +# Usage: +# make CGT_ROOT=/path/to/ti-cgt-c2000_xx.y.z [C2000WARE=/path/to/C2000Ware] +# +# CGT_ROOT must point at a TI C2000 codegen install (the dir containing +# bin/cl2000). It ships with Code Composer Studio or as a standalone package. +# C2000WARE defaults to ~/ti/C2000Ware_26_01_00_00. +# +# This is the SCOPED bring-up build: SHA-2, SHA-3/SHAKE, and ML-DSA-87 verify +# only. See README.md. + +CGT_ROOT ?= +C2000WARE ?= $(HOME)/ti/C2000Ware_26_01_00_00 + +# wolfSSL source tree (this example lives in wolfssl-examples; point WOLFROOT +# at a wolfSSL checkout that has the CHAR_BIT!=8 fixes). Override on the +# command line, e.g. make WOLFROOT=/path/to/wolfssl. +WOLFROOT ?= $(abspath $(CURDIR)/../../../wolfssl-alt) + +DEV := $(C2000WARE)/device_support/f28p55x +DRV := $(C2000WARE)/driverlib/f28p55x/driverlib +DRVLIB := $(DRV)/ccs/Release + +OUT := out +TARGET := $(OUT)/wolfcrypt_f28p55x.out +MAP := $(OUT)/wolfcrypt_f28p55x.map + +ifeq ($(CGT_ROOT),) +$(error Set CGT_ROOT to your TI C2000 codegen install, e.g. \ + make CGT_ROOT=$(HOME)/ti/ccs/tools/compiler/ti-cgt-c2000_22.6.2.LTS) +endif + +CL := $(CGT_ROOT)/bin/cl2000 + +INCS := \ + -I$(CGT_ROOT)/include \ + -I$(DRV) \ + -I$(DEV)/common/include \ + -I$(DEV)/headers/include \ + -I$(WOLFROOT) \ + -I$(CURDIR)/Header + +# --float_support=fpu32 and --abi=eabi must match the prebuilt driverlib.lib. +# Define WOLF_C2000_SCI_STDOUT to route printf to SCIA (XDS110 COM); omit it to +# use the CCS console (CIO over JTAG) for first light. +CFLAGS := \ + -v28 --float_support=fpu32 --tmu_support=tmu1 --abi=eabi \ + -O2 \ + --define=_LAUNCHXL_F28P55X \ + --define=_FLASH \ + --define=WOLFSSL_USER_SETTINGS \ + --gen_func_subsections=on \ + --diag_warning=225 --display_error_number \ + $(EXTRA_CFLAGS) \ + $(INCS) + +LFLAGS := \ + --reread_libs --warn_sections \ + -i$(CGT_ROOT)/lib -i$(DRVLIB) \ + -m $(MAP) + +# wolfCrypt source subset (the only files that compile under CHAR_BIT==16). +WC_SRCS := \ + $(WOLFROOT)/wolfcrypt/src/error.c \ + $(WOLFROOT)/wolfcrypt/src/wc_port.c \ + $(WOLFROOT)/wolfcrypt/src/memory.c \ + $(WOLFROOT)/wolfcrypt/src/logging.c \ + $(WOLFROOT)/wolfcrypt/src/misc.c \ + $(WOLFROOT)/wolfcrypt/src/coding.c \ + $(WOLFROOT)/wolfcrypt/src/hash.c \ + $(WOLFROOT)/wolfcrypt/src/sha256.c \ + $(WOLFROOT)/wolfcrypt/src/sha512.c \ + $(WOLFROOT)/wolfcrypt/src/sha3.c \ + $(WOLFROOT)/wolfcrypt/src/wc_mldsa.c \ + $(WOLFROOT)/wolfcrypt/src/random.c + +# ECC=1 adds ECDSA/ECDH over SECP256R1 via SP single-precision math. +ECC ?= 0 +ifeq ($(ECC),1) + CFLAGS += --define=WOLF_ECC + WC_SRCS += \ + $(WOLFROOT)/wolfcrypt/src/ecc.c \ + $(WOLFROOT)/wolfcrypt/src/sp_int.c \ + $(WOLFROOT)/wolfcrypt/src/sp_c32.c +endif + +HARNESS_SRCS := \ + $(WOLFROOT)/wolfcrypt/test/test.c \ + $(WOLFROOT)/wolfcrypt/benchmark/benchmark.c + +BSP_SRCS := \ + $(CURDIR)/Source/wolf_main.c \ + $(DEV)/common/source/device.c + +ASM_SRCS := \ + $(DEV)/common/source/f28p55x_codestartbranch.asm + +# SIGN=1 builds the full ML-DSA-87 (keygen + sign + verify) demo. It needs a +# 32 KW heap, so the wolfcrypt test/benchmark harness is left out and a +# dedicated linker script is used. Default (SIGN=0) is the verify-only build +# with the full test/benchmark harness. +SIGN ?= 0 +# BENCH=1 runs ONLY the benchmark (skips wolfcrypt_test). wolfcrypt_test's +# heap high-water leaves too little for the benchmark's block buffers on this +# RAM-limited part, so run them in separate images: default = KATs + test, and +# BENCH=1 = KATs + benchmark. +BENCH ?= 0 +ifeq ($(SIGN),1) + CFLAGS += --define=WOLF_MLDSA_SIGN --define=NO_CRYPT_TEST \ + --define=NO_CRYPT_BENCHMARK + LNKCMD := $(CURDIR)/28p55x_wolf_sign_lnk.cmd + HARNESS_SRCS := +else + LNKCMD := $(CURDIR)/28p55x_wolf_flash_lnk.cmd + ifeq ($(BENCH),1) + CFLAGS += --define=NO_CRYPT_TEST + endif +endif + +ALL_SRCS := $(WC_SRCS) $(HARNESS_SRCS) $(BSP_SRCS) $(ASM_SRCS) + +.PHONY: all clean + +all: $(TARGET) + +$(TARGET): $(ALL_SRCS) $(LNKCMD) user_settings_dep + @mkdir -p $(OUT) + $(CL) $(CFLAGS) \ + $(ALL_SRCS) \ + -z $(LFLAGS) \ + --output_file=$(TARGET) \ + $(LNKCMD) \ + -l driverlib.lib -l libc.a + +# touch-only dependency so editing user_settings.h forces a rebuild +user_settings_dep: Header/user_settings.h + +# Compile-only guard (no link, no C2000Ware): mirrors the upstream CI job at +# wolfssl/.github/workflows/ti-c2000-compile.yml. Builds the CHAR_BIT!=8 +# wolfCrypt subset with cl2000 to catch regressions locally. +.PHONY: compile-ci +compile-ci: + CGT_ROOT=$(CGT_ROOT) $(WOLFROOT)/scripts/ti-c2000/compile.sh + +clean: + rm -rf $(OUT) *.obj *.map *.asm diff --git a/embedded/ti-c2000-f28p55x/README.md b/embedded/ti-c2000-f28p55x/README.md new file mode 100644 index 000000000..b58de5ca6 --- /dev/null +++ b/embedded/ti-c2000-f28p55x/README.md @@ -0,0 +1,80 @@ +# wolfCrypt on TI C2000 C28x (LAUNCHXL-F28P55X) + +Bare-metal wolfCrypt test/benchmark for the TI LAUNCHXL-F28P55X board (TMS320F28P550SJ, C2000 C28x DSP, 150 MHz, 133 KB RAM, 1088 KB flash). This is a **new-architecture bring-up** and is intentionally scoped. + +## What this build includes + +A deliberately limited algorithm set, validated with known-answer tests: + +- SHA-256 / SHA-224 +- SHA-384 / SHA-512 +- SHA3-224/256/384/512, SHAKE128, SHAKE256 +- **ML-DSA-87 (Dilithium level 5), verify only** + +RSA / ECC / DH / TFM / SP-bignum and most symmetric ciphers are **not** built. See the 16-bit-byte section below for why. + +## The 16-bit-byte issue (read this first) + +The C28x is a word-addressed DSP: **`CHAR_BIT == 16`**. A `char`/`unsigned char` (wolfSSL's `byte`) holds 16 bits, the minimum addressable unit is 16 bits, and `(byte)x` masks to 16 bits, not 8. Most of wolfCrypt assumes 8-bit octets. This build sidesteps the worst of it by: + +- Building only hashing + ML-DSA verify (no bignum), so the `tfm.c`/`ecc.c`/`integer.c` byte-packing paths are never compiled. +- `WOLFSSL_GENERAL_ALIGNMENT 2` (nonzero) selects ML-DSA's byte-by-byte packing path instead of the word-cast path, which is octet-layout dependent and wrong here. +- `WOLFSSL_NO_XOR_OPS` forces the byte-by-byte `xorbuf` used by the Keccak absorb, avoiding the `byte*`->`wolfssl_word*` cast hazard in `misc.c`. + +Correctness of SHA-3/SHAKE and ML-DSA under 16-bit bytes is **not proven** until the KATs pass on hardware. Validate strictly in this order (stop and fix at the first failure): + +1. SHA-256 KAT -- confirms basic byte storage + `XMEMCPY` semantics. +2. SHA-512 KAT. +3. **SHA3-256 + SHAKE256 KAT** -- confirms Keccak lane packing/squeeze. This is **expected to fail before a fix**: `sha3.c` aliases the `word64` state as a raw byte stream (`xorbuf(state,...)`, `((byte*)s)[i] ^= pad`, `XMEMCPY(hash, s, rate)`), which only works when a `word64` is 8 octets in memory. On C28x it is four 16-bit cells. The absorb/pad already have an octet-safe `Load64BitLittleEndian` path (currently gated under `BIG_ENDIAN_ORDER`/`WC_SHA3_FAULT_HARDEN`); the missing piece is a little-endian **octet-wise squeeze** to replace `XMEMCPY(hash, s, rate)` with `hash[k] = (byte)((s[k>>3] >> (8*(k&7))) & 0xFF)` (same for the SHAKE `SqueezeBlocks`/`Final` outputs). Add this behind a `CHAR_BIT != 8` gate so other targets are unaffected. If SHA3/SHAKE is wrong, ML-DSA cannot work; fix here first. +4. ML-DSA-87 verify KAT (consumes SHAKE via `SqueezeBlocks`). + +## Toolchain + +- **C2000Ware** (driverlib + device support). This example assumes `~/ti/C2000Ware_26_01_00_00`; override with `C2000WARE=`. +- **TI C2000 codegen** (`cl2000`, the classic CGT -- not the C2000 Clang compiler for this first bring-up). It ships with Code Composer Studio or as a standalone package. Point `CGT_ROOT` at the dir containing `bin/cl2000`. +- For flashing: **DSLite** (bundled with CCS) or **UniFlash**, driving the onboard XDS110. + +## Build + +Headless, from this directory: + +``` +make CGT_ROOT=/path/to/ti-cgt-c2000_xx.y.z +``` + +Output: `out/wolfcrypt_f28p55x.out` (load image) and `out/wolfcrypt_f28p55x.map`. + +Key compiler flags (see `Makefile`): `-v28 --float_support=fpu32 --abi=eabi`, which must match the prebuilt `driverlib.lib`. The repo root is on the include path so the inline `#include ` in `sha3.c`/`wc_mldsa.c` resolves, and `WOLFSSL_USER_SETTINGS` pulls in `Header/user_settings.h`. + +CCS GUI alternative: create an empty F28P550SJ project, add the wolfCrypt source subset listed in the `Makefile` (`WC_SRCS`), `Source/wolf_main.c`, the device-support `device.c` + `f28p55x_codestartbranch.asm`, link `driverlib.lib`, set the predefines (`_LAUNCHXL_F28P55X`, `_FLASH`, `WOLFSSL_USER_SETTINGS`) and the include paths, and use `28p55x_wolf_flash_lnk.cmd` as the linker command file. + +## Console output + +- **First light (no wiring):** build without `WOLF_C2000_SCI_STDOUT`. `printf` goes to the CCS console via CIO over JTAG. Good for proving crypto before debugging the UART. +- **Headless:** add `--define=WOLF_C2000_SCI_STDOUT`. `stdout` is redirected to **SCIA on GPIO28/29**, the XDS110 virtual COM, at **115200 8N1**. Read it with the `uart-monitor` skill on the XDS110 user-UART `/dev/ttyACM*` (identify by udev `XDS110` match). + +## Flash and run + +Boot-mode switch S3 default (GPIO24 + GPIO32 both high) boots from flash. With CCS DSLite: + +``` +DSLite flash --config=F28P550SJ.ccxml -f -v -e out/wolfcrypt_f28p55x.out +``` + +Generate `F28P550SJ.ccxml` once in CCS (Target Configuration: XDS110 + TMS320F28P550SJ). + +## Memory notes + +- Clock: 150 MHz from the 20 MHz crystal Y2 (`device.h` `DEVICE_SETCLOCK_CFG`), flash `RWAIT=3`. Confirm the Y2 frequency against the board silkscreen. +- The C28x stack pointer is 16-bit, so the stack must live below address `0x10000`. `28p55x_wolf_flash_lnk.cmd` puts a 12 KW stack in RAMLS0-7, a 12 KW heap in RAMGS0-1, and `.bss`/`.data` in the high RAMGS2-3 / RAMLS8-9 blocks. +- ML-DSA-87 verify uses `WOLFSSL_MLDSA_VERIFY_NO_MALLOC` + `WOLFSSL_MLDSA_VERIFY_SMALL_MEM`: ~7 KW of buffers pinned in the key struct, **zero heap**. Measure the stack high-water on hardware (sentinel fill) to record the real footprint. + +## RNG caveat + +The F28P55x has **no hardware TRNG**. `my_rng_seed_gen()` in `wolf_main.c` is a **development-only** counter seed so the benchmark's RNG-gated cases link and run -- it is **not** cryptographically secure. ML-DSA verify and the hash tests are deterministic and consume no RNG output. For a no-RNG build you can instead define `WC_NO_RNG` (the ML-DSA verify *test* still runs; the verify *benchmark* is then skipped). + +## Known iteration points + +- `NO_HMAC` / `NO_ASN`: relax if the test/benchmark harness references them unconditionally in this scoped path. +- If the link reports unresolved `XMALLOC` from a non-gated test path, raise the heap size or switch to a static-memory pool. +- `WC_16BIT_CPU`: off by default (ML-DSA/SHA use explicit `word32`/`word64`); enable only if int-width build errors appear. diff --git a/embedded/ti-c2000-f28p55x/Source/ecc_p256_kat.h b/embedded/ti-c2000-f28p55x/Source/ecc_p256_kat.h new file mode 100644 index 000000000..24cbdcfb4 --- /dev/null +++ b/embedded/ti-c2000-f28p55x/Source/ecc_p256_kat.h @@ -0,0 +1,39 @@ +/* ecc_p256_kat.h - deterministic ECDSA P-256 (SECP256R1) known-answer vector. + * + * Source: RFC 6979 Appendix A.2.5 (P-256), message "sample", hash SHA-256. + * Used for an RNG-free verify KAT on the TI C2000 C28x bring-up. + * + * Brace-init byte arrays (NOT "\x.." string literals): on cl2000 a char[]/byte[] + * initialized from a "\x.." string sign-extends bytes >= 0x80 into the 16-bit + * cell; a brace-init list stores clean octets. + */ +#ifndef ECC_P256_KAT_H +#define ECC_P256_KAT_H + +/* Public key Q = (Ux, Uy), 32 bytes each, big-endian. */ +static const unsigned char kat_p256_qx[32] = { + 0x60,0xFE,0xD4,0xBA,0x25,0x5A,0x9D,0x31,0xC9,0x61,0xEB,0x74,0xC6,0x35,0x6D,0x68, + 0xC0,0x49,0xB8,0x92,0x3B,0x61,0xFA,0x6C,0xE6,0x69,0x62,0x2E,0x60,0xF2,0x9F,0xB6 +}; +static const unsigned char kat_p256_qy[32] = { + 0x79,0x03,0xFE,0x10,0x08,0xB8,0xBC,0x99,0xA4,0x1A,0xE9,0xE9,0x56,0x28,0xBC,0x64, + 0xF2,0xF1,0xB2,0x0C,0x2D,0x7E,0x9F,0x51,0x77,0xA3,0xC2,0x94,0xD4,0x46,0x22,0x99 +}; + +/* SHA-256("sample") - the message digest that was signed. */ +static const unsigned char kat_p256_hash[32] = { + 0xAF,0x2B,0xDB,0xE1,0xAA,0x9B,0x6E,0xC1,0xE2,0xAD,0xE1,0xD6,0x94,0xF4,0x1F,0xC7, + 0x1A,0x83,0x1D,0x02,0x68,0xE9,0x89,0x15,0x62,0x11,0x3D,0x8A,0x62,0xAD,0xD1,0xBF +}; + +/* Signature (r, s), 32 bytes each, big-endian. */ +static const unsigned char kat_p256_r[32] = { + 0xEF,0xD4,0x8B,0x2A,0xAC,0xB6,0xA8,0xFD,0x11,0x40,0xDD,0x9C,0xD4,0x5E,0x81,0xD6, + 0x9D,0x2C,0x87,0x7B,0x56,0xAA,0xF9,0x91,0xC3,0x4D,0x0E,0xA8,0x4E,0xAF,0x37,0x16 +}; +static const unsigned char kat_p256_s[32] = { + 0xF7,0xCB,0x1C,0x94,0x2D,0x65,0x7C,0x41,0xD4,0x36,0xC7,0xA1,0xB6,0xE2,0x9F,0x65, + 0xF3,0xE9,0x00,0xDB,0xB9,0xAF,0xF4,0x06,0x4D,0xC4,0xAB,0x2F,0x84,0x3A,0xCD,0xA8 +}; + +#endif /* ECC_P256_KAT_H */ diff --git a/embedded/ti-c2000-f28p55x/Source/mldsa87_kat.h b/embedded/ti-c2000-f28p55x/Source/mldsa87_kat.h new file mode 100644 index 000000000..fa03dc6c1 --- /dev/null +++ b/embedded/ti-c2000-f28p55x/Source/mldsa87_kat.h @@ -0,0 +1,611 @@ +/* Auto-extracted ML-DSA-87 verify KAT vectors from wolfcrypt/test/test.c + * (ml_dsa_87_pub_key + ml_dsa_87_sig). For on-target verify validation. */ +#ifndef MLDSA87_KAT_H +#define MLDSA87_KAT_H +static const unsigned char kat_mldsa87_pub[] = { + 0x8a, 0x66, 0xe3, 0x6e, 0x3c, 0x11, 0x70, 0x9f, 0x82, 0xdd, 0xeb, 0x9e, + 0xc0, 0xd7, 0x25, 0x87, 0x0c, 0x65, 0x07, 0x9d, 0x47, 0x39, 0x5d, 0x04, + 0x42, 0x5c, 0xd6, 0x0a, 0xdc, 0x39, 0x44, 0x04, 0xd9, 0x79, 0x43, 0x87, + 0x98, 0x64, 0x88, 0x82, 0x3a, 0x31, 0xbd, 0xec, 0x66, 0xcb, 0x01, 0x90, + 0xf9, 0x85, 0xcc, 0xde, 0x54, 0x69, 0x7d, 0x84, 0xb3, 0x84, 0x3c, 0x42, + 0x0d, 0x09, 0x63, 0xdb, 0xe6, 0x5d, 0xc2, 0x8a, 0xcf, 0xe1, 0xf4, 0x86, + 0x13, 0x05, 0x09, 0x9a, 0x4d, 0x05, 0xd4, 0x31, 0xe7, 0x27, 0x39, 0xfd, + 0x3a, 0xdb, 0x63, 0x9f, 0x1c, 0x67, 0x0b, 0x01, 0xec, 0xf9, 0xff, 0xf3, + 0xda, 0xa9, 0xf4, 0x9a, 0x59, 0x52, 0x76, 0xc2, 0xd2, 0xd5, 0xdd, 0x8d, + 0xb1, 0xa2, 0xef, 0xb3, 0x73, 0x99, 0xe3, 0xcd, 0x1c, 0xf5, 0xca, 0x6e, + 0x39, 0xfa, 0x26, 0x83, 0x45, 0xe7, 0xd0, 0x9c, 0x1b, 0xf7, 0xb2, 0x64, + 0xf1, 0x70, 0x00, 0x10, 0xc0, 0x7c, 0x7f, 0xb2, 0x32, 0xce, 0x6d, 0x71, + 0xa5, 0x43, 0x7c, 0x40, 0x71, 0x09, 0x54, 0x74, 0xac, 0xb5, 0xeb, 0xe0, + 0x04, 0x02, 0xe5, 0x82, 0x4d, 0x5a, 0x85, 0x1e, 0x19, 0x86, 0x39, 0x33, + 0x92, 0x2f, 0xa9, 0xa8, 0x10, 0xd2, 0x31, 0x60, 0x16, 0x08, 0x99, 0xe3, + 0x2c, 0x93, 0x13, 0xc4, 0x4b, 0x10, 0xe0, 0x42, 0xca, 0x3f, 0x32, 0xa7, + 0xa4, 0xd2, 0xfc, 0x9c, 0x93, 0xb6, 0x5f, 0xe2, 0x5b, 0x6e, 0x40, 0x0c, + 0x63, 0xf8, 0xf8, 0xe1, 0x2d, 0xcd, 0x86, 0x07, 0x79, 0xdb, 0x61, 0xad, + 0x24, 0xfd, 0x1e, 0x66, 0x3e, 0x8d, 0x76, 0xba, 0x98, 0x8e, 0x94, 0xc7, + 0x57, 0xb1, 0x65, 0xce, 0x4f, 0x97, 0xfa, 0x34, 0x7c, 0x97, 0x6b, 0xcd, + 0x3c, 0x42, 0x81, 0xa4, 0xd1, 0x75, 0xeb, 0x6d, 0x0c, 0x31, 0x0e, 0x6f, + 0xd5, 0x75, 0xe7, 0xff, 0x83, 0xdd, 0x7a, 0x4d, 0x83, 0x67, 0xa7, 0x4b, + 0xc1, 0x74, 0xad, 0x37, 0x38, 0x99, 0xe0, 0xf5, 0x5a, 0x44, 0x36, 0xa2, + 0x20, 0x2b, 0xfc, 0xc9, 0xfa, 0x68, 0xcb, 0xf0, 0x6f, 0x0a, 0x46, 0x1d, + 0xb5, 0xca, 0x5b, 0x96, 0x1b, 0x3a, 0xaf, 0x7d, 0x01, 0x7a, 0xd2, 0x09, + 0xcc, 0xd4, 0xe4, 0xb1, 0x49, 0x34, 0x56, 0x68, 0x9c, 0x0f, 0x23, 0xe9, + 0xb3, 0x4b, 0xed, 0x3d, 0xe7, 0x8d, 0x19, 0x6e, 0xe6, 0xfa, 0x06, 0x55, + 0xb8, 0x06, 0x4d, 0xa8, 0x45, 0x20, 0x91, 0xf7, 0xfa, 0x0b, 0x6b, 0xce, + 0x55, 0xa7, 0x14, 0x1b, 0xf9, 0xea, 0xc5, 0x79, 0x78, 0xf7, 0x3a, 0xd9, + 0xfc, 0x07, 0x43, 0x06, 0x90, 0x94, 0x5e, 0xc9, 0x48, 0x51, 0xe5, 0x96, + 0x68, 0x78, 0xc8, 0xcb, 0xd1, 0xf3, 0x65, 0xef, 0x14, 0x91, 0xa3, 0xca, + 0x8b, 0x77, 0x40, 0x84, 0xf4, 0x2e, 0xe7, 0x56, 0xe3, 0xab, 0xa0, 0xa8, + 0x61, 0x93, 0x17, 0x95, 0x9e, 0xff, 0x3a, 0xd4, 0x12, 0xea, 0x13, 0xe6, + 0x82, 0x16, 0xed, 0x14, 0x70, 0x91, 0xcc, 0x72, 0x58, 0x99, 0xa1, 0x7f, + 0xf3, 0x84, 0x10, 0xf4, 0x01, 0x0d, 0x05, 0x45, 0x4d, 0xca, 0x05, 0x03, + 0x75, 0x7e, 0xbb, 0x44, 0x2e, 0xf5, 0xee, 0xed, 0x64, 0x9b, 0xd3, 0xde, + 0x3e, 0xfc, 0x31, 0x8c, 0xca, 0x23, 0x66, 0x25, 0xac, 0x5f, 0x0f, 0x33, + 0x0f, 0xd2, 0xe9, 0xc9, 0x96, 0x2a, 0xe2, 0xb8, 0xed, 0x93, 0xd3, 0x78, + 0xd8, 0x81, 0xe4, 0x52, 0x9a, 0xc6, 0x64, 0x1d, 0x2d, 0x5f, 0x93, 0x9a, + 0x2e, 0x73, 0xc4, 0x17, 0xae, 0xc6, 0x08, 0x0d, 0x2d, 0xe9, 0x4b, 0x10, + 0x29, 0xa8, 0x4e, 0x8c, 0x08, 0x59, 0x87, 0x10, 0x0d, 0x5d, 0xfa, 0xec, + 0xd6, 0x42, 0xf6, 0x5c, 0xa4, 0x0d, 0xaa, 0x64, 0x8e, 0x20, 0xa5, 0x50, + 0x9f, 0x0b, 0x85, 0x37, 0x57, 0x15, 0x7c, 0xb1, 0xe4, 0xdd, 0xd5, 0x19, + 0x3b, 0x10, 0x7d, 0x22, 0xdb, 0x53, 0x8b, 0x7b, 0x32, 0xf7, 0xf2, 0x24, + 0x92, 0xb2, 0x05, 0xd1, 0xfd, 0xfc, 0x11, 0xd6, 0xfd, 0x3c, 0x8d, 0xd7, + 0xb0, 0x58, 0x50, 0x06, 0x84, 0x61, 0xa6, 0x78, 0x04, 0x1d, 0x7f, 0x92, + 0x0e, 0x8b, 0xb3, 0x63, 0x43, 0xc5, 0x30, 0x4c, 0xce, 0x2b, 0x44, 0x70, + 0x53, 0x7c, 0xb5, 0xbd, 0x30, 0xcb, 0x41, 0x19, 0x27, 0x69, 0xfe, 0x41, + 0x92, 0xae, 0xf0, 0x37, 0x33, 0xf0, 0x95, 0xe4, 0xe8, 0x4f, 0x75, 0x41, + 0x64, 0x87, 0xc5, 0x68, 0xd3, 0xce, 0xfa, 0xaa, 0xe8, 0x59, 0x88, 0xfe, + 0x24, 0x46, 0x27, 0x60, 0x71, 0x36, 0x78, 0x66, 0x3c, 0x36, 0x8e, 0xdb, + 0x90, 0x67, 0xa5, 0x6a, 0xfe, 0xd3, 0x23, 0x28, 0x91, 0x34, 0x24, 0x67, + 0x4b, 0x01, 0x6a, 0x0e, 0x02, 0xb7, 0xf0, 0xa8, 0xd4, 0x76, 0xd5, 0xa8, + 0x1c, 0xd3, 0xb3, 0x7d, 0x74, 0xc6, 0x17, 0x96, 0xa7, 0xf9, 0xad, 0x24, + 0x36, 0xd2, 0xeb, 0x34, 0x5a, 0xcc, 0x9c, 0x01, 0x99, 0xbe, 0x21, 0x4f, + 0x27, 0x9d, 0x6b, 0xca, 0x27, 0x1b, 0x60, 0x51, 0x41, 0x23, 0xe1, 0xcb, + 0xfc, 0x17, 0x2e, 0x1a, 0x4d, 0x3d, 0x51, 0xb3, 0x91, 0x8c, 0x53, 0x4d, + 0xd7, 0xbc, 0xa4, 0x07, 0xd7, 0x17, 0x19, 0x18, 0x61, 0x38, 0x4e, 0x05, + 0x81, 0x3f, 0x43, 0x8a, 0x00, 0x60, 0xdc, 0x30, 0xf4, 0x38, 0x3f, 0x93, + 0x82, 0x10, 0x29, 0x73, 0xa9, 0xbd, 0x63, 0x15, 0x7d, 0xac, 0x2e, 0xc9, + 0x05, 0xc1, 0x01, 0x41, 0x18, 0x5a, 0xc0, 0xc8, 0xc7, 0x81, 0x69, 0xe7, + 0x24, 0x21, 0x57, 0xaf, 0x88, 0x73, 0x7c, 0x53, 0x29, 0xae, 0x5a, 0xdf, + 0x76, 0x37, 0x56, 0x4f, 0x1f, 0x6b, 0xfd, 0x71, 0xbb, 0x80, 0x4a, 0xd7, + 0x53, 0x50, 0x10, 0x2d, 0xfc, 0x1a, 0xaf, 0x7c, 0x1f, 0xe8, 0xd0, 0x6c, + 0xa6, 0x45, 0x3d, 0xb5, 0x3d, 0xb2, 0xfc, 0x97, 0xa9, 0xbf, 0x7c, 0x0f, + 0x32, 0x7a, 0xcc, 0xa9, 0x2f, 0xd0, 0xc6, 0xe6, 0xcd, 0x04, 0x1d, 0x71, + 0x91, 0xb9, 0x59, 0x4b, 0xad, 0xa0, 0xde, 0x9e, 0xdc, 0x9c, 0x10, 0xeb, + 0x8d, 0xd6, 0x65, 0x57, 0xbc, 0x96, 0xfd, 0x0f, 0xcc, 0x73, 0xbe, 0x39, + 0x27, 0x99, 0x94, 0xf5, 0xe1, 0xbb, 0x32, 0xcd, 0x27, 0x7e, 0x08, 0xa0, + 0xd2, 0x92, 0x39, 0xeb, 0x71, 0xc8, 0xe8, 0x34, 0x57, 0x34, 0x4b, 0x20, + 0x3f, 0xe2, 0x68, 0xec, 0xc0, 0x8a, 0x71, 0xa3, 0x16, 0xa2, 0x91, 0x77, + 0xde, 0x41, 0x12, 0xa5, 0xf5, 0x2a, 0x63, 0x60, 0x55, 0xd0, 0x33, 0xa4, + 0xa7, 0x2e, 0xcb, 0x80, 0x08, 0xe5, 0x76, 0x16, 0x75, 0x04, 0x57, 0xe3, + 0x14, 0x71, 0x4e, 0x57, 0x29, 0x23, 0x0e, 0xc0, 0xcc, 0xad, 0xba, 0xdc, + 0x96, 0x5d, 0x23, 0x49, 0x42, 0xd8, 0x91, 0x08, 0x0d, 0x52, 0xf4, 0x5f, + 0xcd, 0xb7, 0x03, 0xaa, 0x73, 0x26, 0xa8, 0xd5, 0x5b, 0x0c, 0x85, 0xc8, + 0x84, 0x50, 0x9e, 0x70, 0x18, 0x45, 0x27, 0x82, 0x20, 0x75, 0xad, 0x52, + 0x5c, 0x80, 0x4b, 0xb1, 0x0b, 0x3b, 0x30, 0x39, 0x02, 0x54, 0x18, 0x5d, + 0x02, 0x9e, 0x85, 0x31, 0x4a, 0x07, 0x9c, 0x59, 0x5d, 0xab, 0x13, 0x4f, + 0x8f, 0x6e, 0x39, 0x20, 0xb2, 0xc5, 0x31, 0x93, 0xc6, 0xcc, 0xfb, 0xdc, + 0x15, 0xba, 0x3d, 0xcc, 0xbb, 0xd2, 0x6f, 0x04, 0x21, 0xdf, 0x0b, 0x27, + 0x5c, 0xd2, 0x6e, 0xfa, 0xda, 0x86, 0x5d, 0xe4, 0xca, 0xa4, 0x90, 0x22, + 0xa2, 0x80, 0xb5, 0x33, 0x17, 0xdb, 0x9b, 0x7b, 0x0a, 0xcc, 0x0f, 0x9b, + 0x38, 0x06, 0xdf, 0x10, 0x11, 0xa1, 0xd7, 0x2c, 0x24, 0xf0, 0xa8, 0x34, + 0x24, 0xfb, 0x99, 0xba, 0x0a, 0xb5, 0xa1, 0x94, 0x6c, 0x2d, 0xf8, 0xda, + 0x74, 0xaf, 0x19, 0x59, 0x84, 0xb2, 0x68, 0x1c, 0xef, 0xa1, 0xf5, 0x18, + 0x8f, 0x10, 0xf6, 0xb3, 0x6d, 0x33, 0x87, 0xe0, 0x25, 0xc8, 0x65, 0x5c, + 0x2f, 0x51, 0x07, 0x83, 0x69, 0x1b, 0xce, 0xa8, 0xe6, 0xe4, 0x27, 0x62, + 0x5d, 0x9b, 0x7f, 0xa7, 0x07, 0xc8, 0x54, 0x86, 0x90, 0xa5, 0x06, 0x6a, + 0x94, 0x80, 0x84, 0x97, 0xaa, 0x2a, 0xb9, 0x79, 0xe5, 0x19, 0x7a, 0x91, + 0xef, 0x8b, 0x58, 0xdc, 0xf9, 0x90, 0x94, 0xa2, 0x25, 0x4c, 0x69, 0xd8, + 0x6e, 0x9e, 0xad, 0xf8, 0x82, 0x17, 0x37, 0xc9, 0x20, 0x15, 0x24, 0x40, + 0xe5, 0xc6, 0xc1, 0xc7, 0xbd, 0xd4, 0x62, 0xff, 0x16, 0x6d, 0xa5, 0xec, + 0xe9, 0x67, 0x41, 0x9d, 0x3e, 0xfb, 0x22, 0x81, 0x80, 0x61, 0x37, 0x45, + 0xa5, 0x9f, 0x70, 0xff, 0xd4, 0x99, 0x3d, 0x79, 0x45, 0xd0, 0x27, 0xc2, + 0x32, 0xbe, 0xd4, 0xe2, 0x53, 0xa8, 0x8c, 0x94, 0x8b, 0xbe, 0x8a, 0x43, + 0xf7, 0x2a, 0x28, 0x49, 0xf4, 0xce, 0x2e, 0x0b, 0x98, 0xc7, 0xaf, 0x7d, + 0x51, 0x2e, 0xda, 0xd0, 0x7a, 0xfa, 0x91, 0x3a, 0xe6, 0xe7, 0x64, 0xd6, + 0x09, 0xd8, 0x5d, 0x6a, 0x97, 0xcf, 0x89, 0x96, 0x72, 0x21, 0x97, 0x61, + 0xc5, 0x1b, 0xd8, 0xa1, 0xf0, 0xcd, 0x9d, 0xe4, 0xe9, 0x13, 0xd0, 0x16, + 0x41, 0x20, 0xa4, 0x2c, 0x33, 0xf5, 0x3d, 0xfe, 0x80, 0xe8, 0xb2, 0x52, + 0x0e, 0x18, 0x31, 0x19, 0x50, 0xeb, 0xc6, 0x99, 0x43, 0xab, 0x9a, 0x59, + 0x5d, 0x6c, 0x84, 0x00, 0x88, 0x45, 0x7c, 0x73, 0xdf, 0x56, 0x61, 0x3a, + 0xe1, 0x55, 0xb8, 0x59, 0x13, 0xcc, 0x0e, 0x53, 0xe9, 0xf4, 0x74, 0xa0, + 0xf2, 0x15, 0xd2, 0xa8, 0xf9, 0xd4, 0x0d, 0x3d, 0xe7, 0x3d, 0x7d, 0x5b, + 0x19, 0x89, 0x8b, 0x2c, 0x4d, 0x8a, 0xeb, 0xc3, 0x43, 0x31, 0x9a, 0x45, + 0x72, 0x5b, 0x25, 0xb6, 0xa2, 0xc1, 0x98, 0xe3, 0x8a, 0xd4, 0x90, 0xd0, + 0x3e, 0x13, 0xf0, 0xd7, 0x90, 0x34, 0x94, 0xcc, 0xf1, 0x0a, 0xa9, 0x30, + 0xd1, 0x95, 0x43, 0x07, 0xcd, 0xd2, 0xca, 0xb0, 0xe5, 0xd4, 0xf1, 0xa1, + 0xc5, 0x9b, 0xf4, 0x98, 0x28, 0xba, 0xde, 0x40, 0xd6, 0x98, 0x98, 0x20, + 0x9c, 0x84, 0x9e, 0xc6, 0x57, 0xd8, 0x84, 0xc4, 0xa2, 0x9b, 0x53, 0x50, + 0xa5, 0xa6, 0x0b, 0x47, 0xe8, 0x08, 0x7d, 0xd7, 0x09, 0xa4, 0x0c, 0x2b, + 0x27, 0xde, 0xf9, 0x78, 0xbc, 0xa4, 0xb6, 0xc6, 0x1b, 0xda, 0xce, 0x6a, + 0xf8, 0x1a, 0xf5, 0xfe, 0x7b, 0xab, 0x58, 0x7c, 0xdc, 0x72, 0x02, 0x94, + 0x99, 0xf0, 0x3c, 0x37, 0x87, 0x5b, 0xd2, 0x4b, 0x5a, 0x80, 0x83, 0xd7, + 0xfc, 0x9d, 0xa7, 0x51, 0x81, 0xb8, 0x62, 0xff, 0x4b, 0xb3, 0x9f, 0x07, + 0xc3, 0x54, 0xfb, 0x41, 0x85, 0x42, 0x9d, 0xac, 0x27, 0x81, 0x2e, 0xaf, + 0x98, 0x67, 0x8c, 0x23, 0xad, 0x45, 0xfe, 0x6a, 0x57, 0x9f, 0x18, 0xc5, + 0x71, 0x8c, 0xad, 0x3f, 0x30, 0x3c, 0xaa, 0x47, 0x8d, 0xba, 0xc8, 0x7f, + 0x03, 0x1c, 0x86, 0xee, 0xba, 0x3f, 0x59, 0x45, 0xd4, 0xd0, 0xf5, 0x54, + 0x9e, 0xcb, 0x08, 0xcf, 0xca, 0x40, 0x0a, 0x06, 0xc0, 0x1e, 0x60, 0x1f, + 0x33, 0xbf, 0x2c, 0xa8, 0x5f, 0xce, 0x23, 0xa0, 0xe2, 0x1c, 0x2d, 0x56, + 0x2a, 0x44, 0x61, 0x58, 0xf1, 0x84, 0x63, 0x4f, 0x0d, 0x5e, 0xfb, 0x83, + 0x0f, 0x36, 0x1b, 0xf4, 0x8f, 0x17, 0x82, 0x2e, 0x04, 0x2c, 0x77, 0x9d, + 0x32, 0x58, 0xb8, 0xb0, 0xf9, 0x44, 0xd2, 0xf6, 0x84, 0xa4, 0x8b, 0x28, + 0x53, 0xd6, 0x99, 0x81, 0x84, 0x43, 0xf0, 0xc1, 0x15, 0xc6, 0x74, 0x4f, + 0xab, 0x05, 0xcc, 0x80, 0xdf, 0xef, 0xcf, 0xaf, 0x14, 0x82, 0xdf, 0x51, + 0x7c, 0x28, 0x5e, 0x5b, 0x27, 0x5e, 0x91, 0x8b, 0x54, 0x3d, 0x54, 0x26, + 0xb0, 0x3f, 0xd7, 0xc5, 0xce, 0xf3, 0x6d, 0x2c, 0x12, 0xc6, 0xb4, 0x48, + 0x60, 0x11, 0x9c, 0xef, 0x29, 0x98, 0x9c, 0x76, 0x4e, 0x73, 0x2b, 0xd2, + 0x23, 0x53, 0x7d, 0x03, 0xc2, 0x2f, 0x8a, 0xa1, 0xe2, 0x84, 0x54, 0x2d, + 0xd8, 0xc6, 0x55, 0x77, 0x9d, 0x07, 0x67, 0x1f, 0x1a, 0xd3, 0x57, 0x4c, + 0x25, 0x79, 0x8f, 0xd8, 0x82, 0xc2, 0x4d, 0x87, 0x84, 0x33, 0xdc, 0x47, + 0xed, 0x9e, 0xfb, 0xd2, 0x62, 0xc8, 0x50, 0x76, 0xda, 0x3c, 0x3c, 0x05, + 0x0e, 0x2d, 0x30, 0x56, 0xca, 0x4d, 0x6a, 0xe2, 0x17, 0x24, 0x26, 0x9c, + 0xff, 0x09, 0xec, 0xb3, 0x94, 0xec, 0xab, 0x69, 0xb2, 0xf0, 0xa5, 0x66, + 0x18, 0x92, 0x49, 0x6b, 0x90, 0xf5, 0x77, 0x5a, 0x18, 0xe5, 0x51, 0x36, + 0x4a, 0x35, 0x54, 0x98, 0x48, 0x04, 0xa9, 0x0f, 0xcb, 0x55, 0xf1, 0x71, + 0xad, 0x1a, 0x4a, 0x2c, 0x0e, 0x5d, 0x5e, 0x77, 0x47, 0xf5, 0x46, 0x17, + 0x6b, 0x94, 0x2a, 0xbc, 0x40, 0xe5, 0xa7, 0xa6, 0x88, 0x41, 0x76, 0x22, + 0x47, 0xd1, 0xe8, 0x2b, 0x18, 0x48, 0x21, 0xc0, 0xe8, 0x4f, 0xe2, 0xb2, + 0x7e, 0x03, 0xbb, 0x25, 0x9c, 0xc8, 0x68, 0x66, 0x48, 0x25, 0x6a, 0xf2, + 0x64, 0x29, 0xec, 0x79, 0xba, 0xdb, 0x34, 0xe1, 0xd4, 0xf9, 0x52, 0x0e, + 0xfd, 0x8d, 0x86, 0x94, 0x71, 0xd8, 0xe0, 0x86, 0x02, 0x9b, 0xd4, 0x65, + 0x69, 0x5e, 0x01, 0x32, 0x87, 0x59, 0xd8, 0x6c, 0xbc, 0x8a, 0x9f, 0x58, + 0x28, 0x8c, 0x97, 0xef, 0x33, 0xb2, 0xda, 0x45, 0xa0, 0xec, 0xe5, 0x5b, + 0xac, 0xc6, 0x65, 0xc1, 0xb6, 0xcb, 0xf7, 0x85, 0x0e, 0xfa, 0x78, 0x36, + 0x30, 0x84, 0x90, 0xa8, 0xf8, 0x42, 0x25, 0xa5, 0xdd, 0xdc, 0xdc, 0x89, + 0xd3, 0xf0, 0x73, 0x9a, 0xd8, 0x95, 0x8f, 0x04, 0xbf, 0xc1, 0xfd, 0x94, + 0xff, 0xe6, 0xf8, 0x4e, 0xc6, 0x43, 0xc9, 0x60, 0x30, 0xe9, 0x68, 0xa8, + 0x76, 0xfb, 0xfa, 0xdf, 0xc0, 0x9b, 0xbc, 0xbc, 0x34, 0xe4, 0x38, 0xfd, + 0x93, 0xb0, 0x47, 0xb2, 0x3e, 0x83, 0x6c, 0xef, 0xe1, 0xaf, 0x35, 0xb4, + 0x90, 0x2a, 0x32, 0xaf, 0x25, 0x3f, 0x3e, 0x72, 0x61, 0xc0, 0x0f, 0x29, + 0xbb, 0x46, 0x6e, 0x2e, 0x94, 0x7d, 0xdd, 0xb7, 0x67, 0x1f, 0x7b, 0x64, + 0xcb, 0xa5, 0x9a, 0x58, 0x63, 0x20, 0xa7, 0xc0, 0x94, 0xa9, 0xad, 0x90, + 0x7d, 0xf3, 0x2b, 0x61, 0x2b, 0x64, 0x3d, 0x8a, 0xc3, 0xd1, 0xcb, 0xad, + 0x36, 0x44, 0xe6, 0x29, 0x8b, 0x3d, 0x95, 0x7c, 0xa7, 0xa2, 0xfa, 0x1b, + 0x16, 0x8d, 0x9e, 0xc4, 0xf8, 0x4c, 0x76, 0x20, 0x00, 0x68, 0x07, 0x99, + 0x9c, 0x60, 0xe6, 0x16, 0x6a, 0x6f, 0x8a, 0xbe, 0x71, 0x95, 0xa1, 0xcb, + 0xfe, 0x7c, 0x41, 0x59, 0x61, 0x20, 0xf9, 0x54, 0x3c, 0xb1, 0x19, 0x5c, + 0x42, 0x67, 0x3f, 0xff, 0xf3, 0x32, 0x21, 0x9c, 0x9e, 0x88, 0xf9, 0x97, + 0x00, 0x43, 0x73, 0x4a, 0xfc, 0x54, 0xeb, 0x27, 0x79, 0x14, 0x85, 0xd3, + 0xdc, 0x47, 0xb3, 0x6d, 0x24, 0xd3, 0xf7, 0x7a, 0xfb, 0x90, 0x7c, 0x6e, + 0xcd, 0x4e, 0xbf, 0x26, 0x76, 0xd2, 0xe8, 0xcc, 0x67, 0xd1, 0x23, 0x3c, + 0x94, 0x16, 0x1e, 0x07, 0x36, 0x7c, 0x96, 0xf6, 0xe8, 0x50, 0x72, 0x26, + 0x56, 0x67, 0x89, 0xa9, 0x11, 0xfb, 0x1d, 0xb8, 0xb9, 0x2a, 0x55, 0xb7, + 0x85, 0xf7, 0x40, 0xa2, 0xfc, 0x9f, 0x30, 0xec, 0x8f, 0x9a, 0x1c, 0xc8, + 0xe4, 0xc5, 0x1f, 0xcb, 0x0a, 0x60, 0x80, 0x41, 0xec, 0x88, 0x8a, 0xda, + 0x7c, 0x7a, 0xa1, 0x96, 0x51, 0x62, 0x16, 0x63, 0x75, 0x36, 0x28, 0x7c, + 0xc9, 0xd0, 0x27, 0x0c, 0x9e, 0x18, 0x4a, 0x82, 0xf7, 0x02, 0xb9, 0x40, + 0x8f, 0xd5, 0x97, 0x7a, 0x35, 0xa9, 0x3a, 0xb3, 0x8b, 0x6b, 0xf1, 0x9a, + 0xd1, 0xe7, 0x14, 0x38, 0x5e, 0xba, 0x8c, 0xbf, 0x32, 0xaa, 0x34, 0x30, + 0x7c, 0x1e, 0x11, 0xcd, 0x1f, 0x9f, 0xcf, 0x4d, 0x14, 0xce, 0x67, 0xf9, + 0x9c, 0x89, 0x07, 0x92, 0x44, 0x6e, 0x9a, 0x16, 0xe4, 0xfb, 0x67, 0x01, + 0x3f, 0x4c, 0x14, 0x89, 0x33, 0x87, 0x46, 0xc6, 0xe4, 0x66, 0x94, 0xd4, + 0x87, 0x4f, 0x2c, 0x92, 0x1b, 0xae, 0x82, 0xe7, 0x99, 0xaa, 0xb4, 0x99, + 0x81, 0x26, 0xa6, 0x6f, 0x1d, 0xc1, 0x95, 0x80, 0xe9, 0xea, 0xe3, 0x44, + 0x6a, 0x2b, 0xd2, 0xe0, 0x0d, 0x69, 0x42, 0xf7, 0x27, 0x6b, 0x4f, 0x02, + 0x7a, 0x33, 0x7b, 0x43, 0x3d, 0xef, 0x10, 0xaa, 0xab, 0xc5, 0xa2, 0xf0, + 0xbb, 0x07, 0x4b, 0x26, 0x0c, 0x58, 0xcd, 0x3b, 0xd2, 0x6d, 0xa5, 0x32, + 0x37, 0x88, 0x4e, 0x8b, 0xe3, 0x75, 0xb0, 0xbb, 0x87, 0xea, 0xa4, 0x53, + 0xf3, 0xff, 0x39, 0x92, 0x44, 0xab, 0x7b, 0x71, 0x62, 0x31, 0x6b, 0x31, + 0xca, 0x97, 0xba, 0xd7, 0x41, 0xe0, 0x47, 0x47, 0x4f, 0x77, 0xa2, 0x35, + 0x62, 0x7a, 0xc1, 0xb6, 0x69, 0x10, 0x09, 0xce, 0xfc, 0x92, 0xcc, 0xc5, + 0x7a, 0x11, 0xf1, 0xc1, 0xa0, 0x80, 0xe5, 0x42, 0x17, 0xb6, 0x3f, 0xab, + 0xc1, 0xa2, 0x41, 0xfb, 0xe3, 0x98, 0x2d, 0x7a, 0xe4, 0x1b, 0x1f, 0x7e, + 0x71, 0x3c, 0x3e, 0x90, 0x8c, 0x60, 0x30, 0xb7, 0x73, 0x06, 0x1f, 0x8a, + 0xce, 0x50, 0x20, 0x7c, 0xfa, 0x8c, 0xf2, 0x14, 0xd9, 0x00, 0xa2, 0x21, + 0xea, 0x10, 0x36, 0x21, 0x6f, 0x7f, 0x13, 0xe3, 0x6c, 0xb2, 0xd6, 0xa5, + 0xa6, 0x6e, 0xa9, 0xe7, 0x1d, 0xdf, 0xc9, 0x97, 0x60, 0x75, 0xa3, 0x55, + 0xa1, 0x2c, 0x94, 0xd7, 0x85, 0x4b, 0x44, 0xc6, 0x9c, 0x17, 0xc2, 0xad, + 0xe6, 0x56, 0x72, 0x1d, 0xb9, 0x13, 0x54, 0xfe, 0x8c, 0xec, 0xf4, 0xa3, + 0x54, 0x6b, 0x31, 0xbc, 0x55, 0x9e, 0x01, 0xd4, 0x9b, 0x24, 0x9e, 0x51, + 0xaf, 0x67, 0x76, 0x02, 0xf7, 0x34, 0x6a, 0xaa, 0xb0, 0x3c, 0x70, 0x2e, + 0xc8, 0x86, 0xfa, 0x40, 0x89, 0x12, 0xb7, 0x49, 0x38, 0x0b, 0xf7, 0x66, + 0xd2, 0x2e, 0x58, 0xf1, 0x22, 0x3b, 0xb3, 0x40, 0x6b, 0x7a, 0x68, 0x4d, + 0x42, 0xfd, 0xbf, 0xa0, 0xf7, 0x2f, 0x63, 0x4a, 0x87, 0xe7, 0x99, 0x52, + 0x6e, 0xe7, 0xdd, 0xca, 0x19, 0x71, 0xee, 0x92, 0xe2, 0x68, 0x0e, 0xe1, + 0xb7, 0x90, 0x1f, 0xc4, 0xef, 0xf8, 0xf6, 0x85, 0x53, 0x18, 0x33, 0x86, + 0x15, 0xc8, 0x29, 0x58, 0x6f, 0xf0, 0x1c, 0x14, 0x73, 0xa9, 0x8e, 0x88, + 0x74, 0xd4, 0x21, 0xf5, 0xc6, 0x7c, 0xd8, 0x96, 0x0f, 0xb0, 0xa6, 0x7b, + 0xf7, 0x72, 0x15, 0xd7, 0x30, 0x6b, 0x15, 0x1d, 0x3f, 0xb7, 0x4e, 0xaa, + 0xc0, 0x52, 0x1d, 0x84, 0xbf, 0x98, 0xbd, 0x33, 0x02, 0xab, 0x8b, 0xd0, + 0x9c, 0x85, 0x2f, 0xa3, 0xfb, 0x46, 0x8d, 0x4d, 0x97, 0x1a, 0x8a, 0x3c, + 0x73, 0x5b, 0x3b, 0x58, 0x26, 0xba, 0x6b, 0x45, 0x2e, 0x24, 0x66, 0x79, + 0x7d, 0xc4, 0xf8, 0x8c, 0x05, 0x7d, 0x5c, 0x23, 0xb9, 0xe8, 0x5d, 0xfe, + 0xc9, 0x84, 0xe5, 0x58, 0x40, 0xa4, 0xb7, 0x55, 0x74, 0x69, 0x92, 0x9c, + 0x3e, 0x19, 0xb1, 0xb6, 0x51, 0xe9, 0x71, 0xcc, 0x96, 0x2b, 0x01, 0x71, + 0xf5, 0xb9, 0xde, 0x77, 0xfe, 0x2e, 0x74, 0x9c, 0x6a, 0x52, 0x17, 0x1e, + 0xea, 0xd9, 0xc8, 0x14, 0xbe, 0x61, 0xdf, 0xe9, 0x96, 0x24, 0x5a, 0x9a, + 0xd8, 0xd7, 0xad, 0x71, 0xe0, 0xf4, 0xbb, 0x9e, 0xae, 0x95, 0xcd, 0x58, + 0x94, 0x81, 0xee, 0x46, 0x84, 0x65, 0x39, 0xb1, 0x1b, 0x1e, 0xf5, 0x50, + 0xad, 0x56, 0x58, 0xb7, 0x53, 0x9b, 0x2a, 0x2f, 0x09, 0x61, 0x57, 0xda, + 0xf5, 0xdc, 0x9f, 0x3c, 0x6c, 0x69, 0x0d, 0x61, 0x49, 0xb2, 0xe0, 0xb2, + 0xe5, 0xef, 0x19, 0xbe, 0x04, 0xf6, 0x6b, 0xad, 0x41, 0x4c, 0x5a, 0x50, + 0xf6, 0xac, 0x1b, 0x25, 0x8a, 0xdd, 0xe3, 0x57, 0xab, 0x7c, 0x92, 0xe4 +}; +static const unsigned char kat_mldsa87_sig[] = { + 0x20, 0xff, 0x12, 0xe1, 0x87, 0xf6, 0x11, 0x38, 0xff, 0x41, 0xd0, 0x8f, + 0xcd, 0x7e, 0xd1, 0xf6, 0x21, 0x17, 0xd0, 0x46, 0xe9, 0x86, 0x83, 0x1b, + 0xaf, 0xe5, 0x2b, 0x59, 0x21, 0xd1, 0x6b, 0xc9, 0xdb, 0x34, 0xdc, 0xba, + 0xfd, 0xd3, 0xf8, 0x71, 0x49, 0xd8, 0x31, 0xbc, 0x48, 0x83, 0x22, 0x7b, + 0xfd, 0x6a, 0x93, 0xa6, 0x39, 0x4c, 0xda, 0xdb, 0x15, 0xe7, 0x41, 0x14, + 0xb4, 0xb8, 0xfe, 0xb0, 0x1f, 0xf9, 0x0a, 0x2c, 0x0b, 0xc0, 0xac, 0x09, + 0x84, 0x69, 0x5e, 0x64, 0x8c, 0xa8, 0xee, 0xa1, 0x52, 0x22, 0xde, 0x0d, + 0xc7, 0x25, 0xef, 0xa8, 0xfd, 0x8c, 0xb9, 0x45, 0x4f, 0xa4, 0x9c, 0xbc, + 0x70, 0xf2, 0x88, 0xea, 0x79, 0x13, 0xb0, 0xfc, 0xe6, 0x41, 0x48, 0x1c, + 0x33, 0x48, 0xa2, 0x77, 0x75, 0x37, 0x9f, 0xc1, 0x86, 0x94, 0xcd, 0x69, + 0x98, 0x87, 0x47, 0x49, 0x75, 0x93, 0xf1, 0xa4, 0x2d, 0x8e, 0xa8, 0x7e, + 0x0f, 0x95, 0xf5, 0x3e, 0x5d, 0x31, 0x2d, 0xc9, 0x58, 0x1c, 0x42, 0xfd, + 0x79, 0x6a, 0x49, 0xa3, 0x84, 0xc5, 0x2e, 0x8d, 0x96, 0x9c, 0xc8, 0x05, + 0x93, 0xdb, 0x6d, 0xbf, 0x83, 0x34, 0xc2, 0x81, 0x47, 0x90, 0xc9, 0xa9, + 0x82, 0xbd, 0xe1, 0xc8, 0x89, 0xa2, 0x36, 0x47, 0xed, 0xfb, 0x47, 0x57, + 0x01, 0x1a, 0x75, 0x8c, 0x6b, 0x83, 0xcf, 0x56, 0xae, 0x52, 0x66, 0x8b, + 0xab, 0x7f, 0x0c, 0xec, 0xde, 0x5c, 0x13, 0xbe, 0xbd, 0x5b, 0x74, 0x28, + 0xb5, 0xd7, 0x68, 0xd5, 0xd2, 0xe9, 0x96, 0x3b, 0x55, 0xda, 0x3a, 0x93, + 0x3c, 0xd9, 0x9f, 0x53, 0x2a, 0x31, 0x84, 0x45, 0x3f, 0xee, 0x2b, 0xfc, + 0x92, 0xb0, 0x9c, 0xc6, 0x16, 0x16, 0x4f, 0x33, 0x41, 0x17, 0x58, 0xbe, + 0x5d, 0x57, 0x4b, 0x04, 0x82, 0xe3, 0xb3, 0x68, 0xdf, 0x7c, 0x93, 0xce, + 0x9d, 0xf6, 0x7e, 0x21, 0x3d, 0x28, 0x1c, 0xf0, 0x37, 0x46, 0xf2, 0xc2, + 0x73, 0x7c, 0xbe, 0x98, 0x0e, 0x09, 0x75, 0xa7, 0x21, 0x11, 0xa9, 0xd6, + 0xd1, 0x47, 0xac, 0xd0, 0x19, 0x48, 0x3b, 0x74, 0xc1, 0x3c, 0x37, 0x43, + 0x49, 0x12, 0x62, 0xee, 0xaf, 0x5c, 0x38, 0xf7, 0x8a, 0xce, 0xb3, 0x7a, + 0x05, 0x16, 0xd4, 0x71, 0x8b, 0xbe, 0x1a, 0xe0, 0x1e, 0xbc, 0x4b, 0x54, + 0x0f, 0xb5, 0x73, 0x2b, 0xb8, 0x3a, 0x75, 0xf0, 0x26, 0xcd, 0xf9, 0xca, + 0x32, 0xf9, 0x7e, 0x15, 0x38, 0x75, 0x9c, 0x4d, 0xbc, 0x11, 0xf8, 0xea, + 0x8e, 0xe8, 0x38, 0x17, 0xc5, 0x62, 0xf4, 0x34, 0xfb, 0xd6, 0xf5, 0x76, + 0xfc, 0xa3, 0xf3, 0x44, 0xf9, 0xab, 0x2e, 0x9a, 0x68, 0xcd, 0xa1, 0x29, + 0xff, 0xda, 0xe8, 0xb5, 0xb0, 0x20, 0x5d, 0x02, 0x01, 0x62, 0x26, 0x44, + 0x32, 0xc8, 0x94, 0xf8, 0xf1, 0xaa, 0xf9, 0xc2, 0x86, 0xcb, 0x55, 0x7f, + 0x8d, 0xb3, 0xf6, 0x63, 0xb1, 0xa4, 0x95, 0x57, 0xb8, 0x1d, 0xc3, 0x42, + 0xd2, 0x4b, 0x69, 0xcd, 0x7a, 0x10, 0x5b, 0x6a, 0x13, 0xd1, 0x02, 0x98, + 0x38, 0x87, 0x9b, 0x9a, 0x5a, 0x66, 0x73, 0xcb, 0x75, 0xd0, 0x7a, 0x4b, + 0xad, 0x23, 0x06, 0x1c, 0xc8, 0x6b, 0x0c, 0xa8, 0xfe, 0x7b, 0x8f, 0x65, + 0x50, 0xd7, 0xf7, 0x76, 0x88, 0x42, 0xe0, 0x5e, 0x18, 0x91, 0x8b, 0x99, + 0x37, 0x56, 0x08, 0x91, 0xe7, 0x01, 0xe7, 0x05, 0xd5, 0xed, 0x43, 0x25, + 0x71, 0x7e, 0x3e, 0xfc, 0xc4, 0xfd, 0xed, 0x8b, 0x85, 0x16, 0x8c, 0xe3, + 0x05, 0xee, 0x51, 0x02, 0xa4, 0x4b, 0xd8, 0x3c, 0xcf, 0x4d, 0x2f, 0x2d, + 0x68, 0x6e, 0xc1, 0xd5, 0xfa, 0x91, 0xfd, 0x6a, 0xe0, 0x64, 0x85, 0x35, + 0x9c, 0x75, 0xe6, 0x0d, 0xb8, 0xec, 0x97, 0x88, 0x62, 0x98, 0x78, 0x75, + 0xc7, 0x1e, 0x68, 0xa7, 0xb9, 0x7b, 0xab, 0x75, 0x7a, 0x72, 0x3c, 0x7b, + 0xab, 0x60, 0x03, 0xb7, 0x38, 0x13, 0xe4, 0x96, 0x6e, 0xcb, 0x95, 0xcc, + 0xdc, 0x6a, 0x47, 0x67, 0x77, 0xd7, 0x95, 0xc4, 0x87, 0x66, 0xc2, 0x7e, + 0x42, 0x90, 0x59, 0x4f, 0xd6, 0xf3, 0xf4, 0xa7, 0xd0, 0x29, 0xf9, 0x5d, + 0x4b, 0x06, 0x06, 0xf7, 0x6e, 0xb2, 0xab, 0xb0, 0x8e, 0x21, 0xa6, 0xff, + 0x5e, 0x7b, 0x47, 0xb6, 0x3a, 0xa6, 0x9e, 0x19, 0xf6, 0xdf, 0x9b, 0x3b, + 0x3d, 0x07, 0x37, 0xd1, 0x0b, 0xa8, 0xf3, 0x9c, 0x43, 0x89, 0xee, 0xba, + 0x03, 0xee, 0x38, 0x74, 0x13, 0x09, 0x8e, 0x47, 0x4e, 0xa9, 0x14, 0xf5, + 0xb0, 0x55, 0xe0, 0x03, 0xe5, 0xb9, 0x53, 0xef, 0x03, 0x15, 0x60, 0xb3, + 0x4a, 0x71, 0x31, 0x4b, 0xf1, 0xc8, 0xe4, 0x63, 0x9b, 0x8b, 0x78, 0x3c, + 0x1f, 0xac, 0x27, 0x20, 0xa8, 0x53, 0x7d, 0xdd, 0x72, 0xd3, 0x90, 0x8f, + 0x71, 0xa6, 0xa7, 0xeb, 0xb0, 0xeb, 0x42, 0x96, 0xa4, 0xc3, 0xba, 0xc6, + 0x3c, 0xe7, 0x7b, 0x15, 0x1e, 0xfa, 0x15, 0x23, 0x37, 0xf3, 0xc8, 0xb2, + 0xf9, 0x46, 0x04, 0xd1, 0x5e, 0x44, 0xd7, 0x8f, 0x70, 0xb1, 0x0a, 0xde, + 0x6a, 0xe3, 0xaf, 0x9e, 0x49, 0x55, 0x78, 0x79, 0x11, 0x22, 0x87, 0xa9, + 0x54, 0x7c, 0xb4, 0x83, 0xe1, 0x25, 0xcd, 0x89, 0xa6, 0x91, 0x21, 0x7b, + 0xbe, 0x3d, 0x2f, 0x46, 0xb5, 0x5b, 0x50, 0x1a, 0xc8, 0x8d, 0x32, 0xf3, + 0x62, 0x1f, 0x24, 0x64, 0xe8, 0xb6, 0x02, 0x4f, 0x1f, 0x52, 0x3c, 0x40, + 0xfc, 0x72, 0x38, 0xd4, 0xba, 0x40, 0x8e, 0xb7, 0xc0, 0x97, 0x06, 0x16, + 0xd5, 0xe3, 0x39, 0x45, 0xd7, 0x7c, 0x0e, 0xed, 0x6b, 0x19, 0x19, 0x0a, + 0x8e, 0xcb, 0x2b, 0xee, 0x4d, 0xa1, 0x5e, 0x84, 0x22, 0x66, 0xcd, 0x4f, + 0xb9, 0x1a, 0x25, 0x85, 0x02, 0xc0, 0x67, 0xc4, 0xd5, 0x1a, 0xcb, 0xbb, + 0xde, 0x4d, 0x3c, 0x3c, 0x62, 0x9f, 0x76, 0x8f, 0x15, 0x29, 0xa5, 0xbb, + 0x5a, 0x48, 0x38, 0x66, 0xfa, 0x56, 0x0a, 0x09, 0xbd, 0xdf, 0xdf, 0x4a, + 0xe7, 0x0e, 0xa6, 0xb1, 0xb5, 0x7c, 0xe1, 0xed, 0x8d, 0x63, 0x07, 0x42, + 0xf3, 0xf8, 0x15, 0x28, 0x7c, 0x09, 0xf5, 0x02, 0x69, 0x1b, 0x88, 0x1e, + 0x3d, 0xad, 0x5f, 0x46, 0xed, 0xab, 0x2b, 0x11, 0x96, 0x73, 0xa8, 0xe8, + 0xe6, 0x64, 0x7d, 0xae, 0x13, 0xa1, 0x7d, 0x54, 0xae, 0xc0, 0x82, 0xeb, + 0x2a, 0xd1, 0x76, 0xb7, 0x9f, 0xbd, 0x33, 0x8f, 0xe7, 0xe6, 0x79, 0x92, + 0xa6, 0xaf, 0x61, 0x91, 0x49, 0xbc, 0xd2, 0x3c, 0x6f, 0x8b, 0xbe, 0x8f, + 0x5f, 0x1f, 0x00, 0x2c, 0x2e, 0x2c, 0xa0, 0x14, 0xcf, 0x34, 0x42, 0x44, + 0x41, 0x11, 0xd7, 0x37, 0xd3, 0x99, 0x44, 0x36, 0x43, 0x03, 0xb9, 0x50, + 0x4f, 0xab, 0xfe, 0x48, 0xe2, 0x4b, 0xed, 0x51, 0x8b, 0xe0, 0x04, 0x3c, + 0x93, 0x28, 0x55, 0xc8, 0x5a, 0xb3, 0x52, 0x2c, 0x56, 0xbd, 0x43, 0xb9, + 0x4a, 0x6c, 0x4c, 0xcc, 0xda, 0xba, 0x9c, 0xe6, 0x3e, 0x50, 0x8b, 0x1a, + 0xe5, 0x83, 0xc1, 0x60, 0x55, 0xb2, 0x02, 0x16, 0x54, 0x33, 0x62, 0x69, + 0x7c, 0x7d, 0x94, 0xf2, 0xb0, 0x3a, 0x22, 0xf0, 0x21, 0x46, 0xd7, 0x94, + 0x53, 0xec, 0x63, 0x4c, 0x3e, 0xc3, 0x71, 0xd1, 0xb9, 0x2e, 0x16, 0xe8, + 0x17, 0x63, 0x7e, 0x0c, 0x83, 0x05, 0x72, 0xe6, 0x20, 0x60, 0x34, 0xae, + 0x0e, 0x54, 0xa0, 0x57, 0x75, 0x93, 0x2e, 0xb8, 0x6c, 0xec, 0xda, 0x44, + 0x1b, 0xac, 0xd6, 0x75, 0xc5, 0x79, 0x3c, 0xc2, 0xa6, 0xa2, 0x7f, 0x3a, + 0xb0, 0xec, 0xeb, 0xc1, 0xe6, 0xd6, 0xae, 0xac, 0x2e, 0x55, 0x30, 0x1c, + 0x81, 0xa4, 0x4c, 0x35, 0x0e, 0xd8, 0xa6, 0x4e, 0xea, 0x0e, 0xbf, 0x79, + 0xf7, 0xdf, 0x55, 0xfc, 0xf9, 0x24, 0xb0, 0xa6, 0xba, 0xc3, 0x72, 0x42, + 0x60, 0x06, 0x44, 0x03, 0xe3, 0x40, 0x3c, 0x2a, 0x13, 0xf7, 0xdf, 0x3d, + 0xb7, 0x0d, 0x86, 0x6c, 0xb0, 0x0f, 0x2e, 0x72, 0x91, 0x16, 0x4f, 0x5f, + 0xd0, 0x3e, 0x8c, 0x36, 0xed, 0xa8, 0x6f, 0xbc, 0x65, 0xb0, 0x65, 0x99, + 0x47, 0x50, 0xa5, 0x9c, 0xea, 0xee, 0x8a, 0x44, 0x70, 0xf5, 0x31, 0x1a, + 0xe9, 0x11, 0xc1, 0xce, 0xe0, 0x21, 0x52, 0x70, 0x89, 0xf7, 0xc3, 0x35, + 0xfa, 0x55, 0x5a, 0xc5, 0x10, 0x02, 0xc4, 0xc7, 0xf7, 0xe1, 0xaf, 0x49, + 0x48, 0x61, 0xe7, 0x0d, 0xa1, 0x2d, 0x7d, 0x03, 0x00, 0x38, 0xa7, 0xd5, + 0xd3, 0xbf, 0x95, 0x29, 0xed, 0xcc, 0x70, 0x3e, 0xbe, 0x95, 0x8a, 0xdf, + 0xaf, 0xbf, 0xec, 0xf8, 0x6a, 0x4f, 0x9e, 0x69, 0xee, 0x4e, 0x3d, 0x8b, + 0x58, 0xa0, 0x2e, 0xb5, 0x83, 0x6a, 0x0e, 0x04, 0xa4, 0xa9, 0x74, 0xcb, + 0x4f, 0xb0, 0x39, 0x37, 0x8f, 0xcf, 0xbf, 0x77, 0xe4, 0x1a, 0x74, 0xcf, + 0x0e, 0x0d, 0x2d, 0x6e, 0x1d, 0xba, 0xc1, 0xf5, 0x7c, 0x54, 0x6e, 0x92, + 0xec, 0x4b, 0x03, 0xc3, 0xa4, 0x44, 0xad, 0x3e, 0x4f, 0xa4, 0xd9, 0xe9, + 0x71, 0x3c, 0xe6, 0xb6, 0xbe, 0xe7, 0xfc, 0x72, 0x76, 0x86, 0x9a, 0x73, + 0xb1, 0xb3, 0xf3, 0x84, 0xb6, 0x2a, 0x40, 0x0b, 0x8c, 0xae, 0xb3, 0xc4, + 0xdc, 0xb5, 0x21, 0x85, 0x87, 0xdc, 0x19, 0x18, 0xd5, 0xba, 0xa4, 0x5e, + 0x88, 0x89, 0xa4, 0xf4, 0x88, 0x75, 0xc2, 0x7a, 0xb4, 0xee, 0x9d, 0x54, + 0x66, 0x97, 0x70, 0x08, 0x8f, 0x99, 0x84, 0x5d, 0x5e, 0xa7, 0x6f, 0x92, + 0xe8, 0xa3, 0x65, 0xfa, 0x0e, 0x87, 0xfb, 0x3c, 0xe9, 0x17, 0x2d, 0xc7, + 0x2d, 0x30, 0x8f, 0x41, 0x82, 0x68, 0x2b, 0xf1, 0x67, 0x8e, 0xf7, 0x05, + 0x78, 0xfa, 0xc3, 0x61, 0xba, 0x35, 0xe7, 0x2f, 0x19, 0xef, 0x71, 0x36, + 0xac, 0x5b, 0xf0, 0x45, 0x30, 0x70, 0xdc, 0xc7, 0xab, 0x7b, 0x62, 0x17, + 0x9d, 0xc4, 0x43, 0x6f, 0xfc, 0x02, 0x56, 0x5f, 0x65, 0xaa, 0x68, 0x3b, + 0x5c, 0xfa, 0x71, 0x28, 0x89, 0xe9, 0x28, 0x2f, 0x95, 0x4b, 0xfc, 0xe6, + 0xe7, 0xc8, 0x44, 0x28, 0x5c, 0x3c, 0x08, 0x5f, 0x9c, 0xbc, 0x41, 0x68, + 0x91, 0x98, 0x7a, 0x00, 0x63, 0xc9, 0x5c, 0x75, 0x8f, 0xcc, 0x33, 0x77, + 0x7b, 0xd0, 0x2d, 0xe8, 0xa2, 0x98, 0xa4, 0x1b, 0xfa, 0x09, 0x67, 0x7b, + 0x25, 0x96, 0x19, 0xf4, 0x77, 0x33, 0x20, 0x4f, 0x19, 0xf6, 0x9c, 0x6c, + 0x2e, 0xd9, 0x68, 0x95, 0xb0, 0xe2, 0x18, 0x06, 0xe5, 0x84, 0x8e, 0xf7, + 0xbf, 0x6c, 0x96, 0xa8, 0x9d, 0x37, 0xc7, 0x28, 0xa1, 0x3d, 0x90, 0x8c, + 0x40, 0x3d, 0xe2, 0x51, 0xfd, 0x55, 0x09, 0xf8, 0x83, 0x43, 0x44, 0x4d, + 0x1c, 0x8a, 0x8d, 0x36, 0x84, 0x64, 0xc4, 0xfa, 0x1d, 0x72, 0x04, 0x0b, + 0x1d, 0x49, 0x13, 0x88, 0x78, 0x5f, 0x07, 0x9b, 0xc8, 0x01, 0x9c, 0x3c, + 0xfc, 0xff, 0x0f, 0xd5, 0x13, 0xcd, 0x15, 0x98, 0xcc, 0xe6, 0x59, 0x1e, + 0x83, 0x38, 0x8f, 0x6c, 0x75, 0xbe, 0xdf, 0xe9, 0x1b, 0xc5, 0xb9, 0x6b, + 0xa4, 0x5a, 0x0c, 0xae, 0x98, 0x8d, 0x93, 0xfa, 0x76, 0x7f, 0x0d, 0x0b, + 0xe8, 0xa0, 0x3b, 0x9e, 0x5e, 0xc8, 0xa8, 0xcc, 0x02, 0xc9, 0x86, 0x9c, + 0x78, 0xaf, 0x6e, 0x6a, 0xf4, 0xfe, 0x49, 0xad, 0xc5, 0x93, 0xae, 0x62, + 0xbd, 0xe3, 0x3a, 0xa8, 0xf2, 0x60, 0xb5, 0x29, 0xde, 0x5f, 0x12, 0x02, + 0x2d, 0x43, 0x90, 0xf5, 0x9d, 0x9d, 0x97, 0x29, 0xfa, 0xdd, 0x60, 0x41, + 0x64, 0xb7, 0xa5, 0x03, 0x72, 0x10, 0x2b, 0xdd, 0x5b, 0x60, 0xe6, 0xf0, + 0xe1, 0xd7, 0xa5, 0x97, 0xec, 0xb4, 0x9a, 0x4c, 0x3e, 0x16, 0xa2, 0x82, + 0xb3, 0xc3, 0x3f, 0x3e, 0x5d, 0x32, 0xac, 0x5a, 0x40, 0xb4, 0x00, 0xfa, + 0xd9, 0x47, 0xe8, 0x77, 0xa8, 0x96, 0x5c, 0x60, 0x04, 0x9c, 0x5c, 0xdf, + 0x24, 0x3b, 0xa7, 0x4a, 0x58, 0x25, 0x12, 0x9a, 0xa8, 0x7b, 0x3e, 0x14, + 0xc8, 0x06, 0x79, 0x23, 0xea, 0x91, 0x7f, 0xe1, 0x78, 0x41, 0x6c, 0xdb, + 0x8c, 0xeb, 0x66, 0x35, 0x87, 0x87, 0x81, 0x65, 0x2c, 0xef, 0x3a, 0x6e, + 0xae, 0xb3, 0x6c, 0xe9, 0x86, 0x50, 0x6d, 0x89, 0xd6, 0x27, 0x0a, 0xdb, + 0xf8, 0xd4, 0xb8, 0x85, 0x8e, 0x37, 0xa6, 0x56, 0xf7, 0x58, 0x18, 0x4c, + 0x44, 0xcf, 0xeb, 0xc4, 0x79, 0x19, 0xfc, 0x2e, 0x53, 0x18, 0x0e, 0x7b, + 0x51, 0x86, 0xf3, 0x59, 0x13, 0xb2, 0xaf, 0xd3, 0xee, 0xf4, 0xd5, 0xbf, + 0x2c, 0xb8, 0x6d, 0x71, 0x74, 0x7c, 0x67, 0x54, 0xa7, 0x4b, 0x03, 0xa9, + 0x1b, 0x62, 0x95, 0x9f, 0xc3, 0xf0, 0x71, 0x39, 0x2d, 0x26, 0xaf, 0xaf, + 0xa7, 0xa5, 0x58, 0xf8, 0xf8, 0x8a, 0xe0, 0x62, 0x90, 0x3f, 0x72, 0x9d, + 0x21, 0x82, 0x76, 0x3e, 0x4c, 0x5d, 0xe0, 0xb5, 0x67, 0x23, 0xe3, 0x13, + 0x1a, 0x29, 0xa3, 0xda, 0xa4, 0xb4, 0x5c, 0x1d, 0x47, 0xdf, 0xdf, 0xc9, + 0x93, 0x6c, 0xb2, 0xb5, 0x22, 0xb3, 0x47, 0x2b, 0xcf, 0xf0, 0x36, 0x87, + 0x51, 0x3c, 0x79, 0x41, 0x70, 0xbd, 0xea, 0x70, 0xa2, 0x29, 0x90, 0x55, + 0x30, 0x6f, 0x3e, 0x50, 0xc8, 0x38, 0xd6, 0xfa, 0x6f, 0xe3, 0x39, 0x67, + 0x88, 0x52, 0x1f, 0xd3, 0x52, 0xbf, 0x3e, 0x7b, 0x2a, 0xe5, 0x1e, 0xcd, + 0xf9, 0xf1, 0x91, 0x1d, 0x04, 0x61, 0x25, 0xbb, 0xe1, 0x33, 0xe3, 0x66, + 0x46, 0xed, 0x06, 0x8d, 0xc3, 0x4f, 0x20, 0xc6, 0x24, 0xa7, 0xb5, 0x49, + 0x3b, 0xc7, 0xe6, 0xa0, 0x77, 0x58, 0xd9, 0x70, 0xb1, 0xf5, 0xec, 0x94, + 0x19, 0xf3, 0x5b, 0x0f, 0x9a, 0xe4, 0xad, 0x37, 0x81, 0xaf, 0x68, 0x7b, + 0xe5, 0x67, 0xb5, 0xae, 0x7f, 0x2d, 0x64, 0x78, 0x68, 0x5a, 0xd1, 0x8f, + 0x1c, 0xc0, 0xc3, 0x5b, 0x21, 0x77, 0xe4, 0xa8, 0x5d, 0x05, 0x50, 0xc1, + 0x92, 0xee, 0x36, 0x2d, 0xd2, 0xff, 0xee, 0xc2, 0x11, 0x99, 0xee, 0xd7, + 0x48, 0xfb, 0x6a, 0xa3, 0xc9, 0xb7, 0x0c, 0xc1, 0xe5, 0x12, 0xbf, 0x6f, + 0x58, 0x66, 0x35, 0x34, 0x26, 0xaa, 0xbe, 0xc3, 0x33, 0x86, 0xfd, 0xc0, + 0x1c, 0xa5, 0xe4, 0x1e, 0x91, 0xc4, 0x55, 0x4e, 0xf1, 0xcb, 0xd2, 0x0b, + 0xe8, 0x0d, 0x89, 0x6a, 0x00, 0xbd, 0x7b, 0xf5, 0x3d, 0x1a, 0x4a, 0x48, + 0xfc, 0xf0, 0x5b, 0xcd, 0xdb, 0xb2, 0xa0, 0x27, 0x4b, 0x8f, 0xf7, 0x87, + 0x78, 0x13, 0xdb, 0x3f, 0xfb, 0x0b, 0xda, 0x22, 0xb3, 0x2b, 0x3a, 0x38, + 0xd2, 0x29, 0x73, 0x77, 0xb8, 0xd6, 0xec, 0xab, 0xb4, 0xfe, 0xbe, 0xbb, + 0x6e, 0xe2, 0xc8, 0x45, 0x7b, 0x0d, 0x36, 0x28, 0x0f, 0x45, 0x72, 0xea, + 0x6d, 0x38, 0x02, 0x5e, 0x48, 0x89, 0x12, 0x24, 0x1b, 0x33, 0x0f, 0xe9, + 0xf4, 0xce, 0xf8, 0x27, 0x16, 0x37, 0x29, 0xae, 0xe8, 0x22, 0x03, 0x31, + 0xa9, 0xa0, 0x73, 0x0c, 0x40, 0xe4, 0xfc, 0x6b, 0xe2, 0x1c, 0x8d, 0x7c, + 0x40, 0x82, 0x72, 0x28, 0xd0, 0x7d, 0xe5, 0xef, 0x05, 0x14, 0x80, 0x28, + 0x11, 0x32, 0x0d, 0x63, 0x8a, 0xc3, 0x7c, 0xfe, 0xf5, 0x06, 0x0e, 0xb0, + 0x78, 0x5c, 0x3a, 0xb6, 0x54, 0x37, 0x46, 0xa7, 0x43, 0x4f, 0x05, 0xec, + 0xe4, 0x9f, 0xd8, 0x55, 0x1f, 0x70, 0xb3, 0xe6, 0xbc, 0x46, 0x34, 0x9e, + 0xfc, 0xa4, 0x57, 0x8f, 0x0f, 0x25, 0x6f, 0x9f, 0xb3, 0x80, 0x21, 0x0b, + 0xa1, 0xca, 0x59, 0xcd, 0x37, 0xf7, 0xc9, 0xcb, 0xbe, 0x91, 0xad, 0x07, + 0x4f, 0xc7, 0x4e, 0x04, 0xbd, 0x38, 0x8b, 0x63, 0xb5, 0x51, 0xac, 0xc8, + 0x83, 0x3a, 0xa7, 0xe1, 0x77, 0xbc, 0xa4, 0x0c, 0x6c, 0x50, 0xeb, 0x46, + 0xe1, 0x45, 0x9a, 0x7b, 0x01, 0xca, 0x54, 0xf0, 0x0f, 0xa0, 0x1f, 0x43, + 0x9a, 0x19, 0x70, 0x2e, 0x70, 0x5a, 0xcf, 0x3b, 0x1b, 0x41, 0xfd, 0xd3, + 0x9a, 0xa2, 0x36, 0x14, 0xf0, 0xdd, 0xb0, 0x12, 0x6d, 0xcf, 0x55, 0x3f, + 0xef, 0x0a, 0xc1, 0x80, 0xa9, 0x68, 0xc3, 0x98, 0x03, 0x46, 0x34, 0xce, + 0x91, 0xb2, 0x7a, 0x94, 0xd2, 0xe7, 0xb9, 0x9c, 0x56, 0xb8, 0xf8, 0xd6, + 0xff, 0xbf, 0x8b, 0x39, 0x45, 0x04, 0x45, 0xc9, 0xa2, 0xe2, 0xbb, 0x50, + 0x68, 0x13, 0x32, 0x1e, 0x09, 0x51, 0xb7, 0xb9, 0xcf, 0x5f, 0xcc, 0x54, + 0xd2, 0xf3, 0xc1, 0x9d, 0xa0, 0x8d, 0x22, 0xc8, 0x7e, 0x1b, 0xc6, 0x14, + 0xde, 0x5f, 0x52, 0xb4, 0x69, 0x71, 0xca, 0x58, 0x1d, 0x1e, 0x89, 0xcb, + 0x56, 0x78, 0x7a, 0x85, 0xee, 0xfd, 0xf6, 0x7e, 0xbe, 0x49, 0x9b, 0xb1, + 0x05, 0x95, 0x12, 0xe9, 0x63, 0xbd, 0x61, 0x9a, 0x26, 0xf9, 0x0b, 0x9f, + 0x23, 0x0a, 0x59, 0x55, 0x93, 0xd3, 0x2d, 0xca, 0x66, 0x45, 0x03, 0xb7, + 0xf0, 0x88, 0x9e, 0xc1, 0x11, 0xbb, 0x62, 0x2c, 0x6f, 0xac, 0x3e, 0x87, + 0xd7, 0xe6, 0x4a, 0x44, 0x83, 0x04, 0x5d, 0x5d, 0xbc, 0x3c, 0xce, 0x83, + 0x2b, 0x11, 0x42, 0x02, 0x73, 0x1c, 0x24, 0x90, 0xd9, 0x1a, 0x7d, 0x96, + 0x82, 0x33, 0x75, 0x1e, 0x59, 0xea, 0xa7, 0x99, 0xe1, 0x5b, 0xdc, 0xe4, + 0x07, 0xc5, 0x48, 0x07, 0xb4, 0xbc, 0x80, 0x0e, 0xbd, 0x63, 0x6e, 0x66, + 0xf1, 0x12, 0xb6, 0x67, 0xe0, 0x14, 0x74, 0x9f, 0xbb, 0xb3, 0xb8, 0x16, + 0xd0, 0x25, 0xe9, 0x21, 0x80, 0x1a, 0x32, 0xb0, 0x58, 0x9a, 0x62, 0x17, + 0x18, 0x9d, 0x64, 0x2d, 0x47, 0x89, 0x82, 0x3b, 0x8c, 0x5d, 0x60, 0xc4, + 0x54, 0x69, 0xaa, 0xb4, 0x6a, 0x1d, 0x16, 0xb0, 0xe2, 0x5d, 0x7d, 0xeb, + 0xb9, 0x80, 0x37, 0xcd, 0x5b, 0xf0, 0xa1, 0xa8, 0x39, 0xb2, 0xd6, 0x3a, + 0xc8, 0xcd, 0xca, 0xaf, 0xcb, 0x3b, 0x54, 0xc2, 0x67, 0x49, 0xf3, 0xf1, + 0x11, 0x4d, 0x53, 0x7c, 0x46, 0x8d, 0x22, 0xf6, 0x9a, 0x0d, 0x9e, 0xda, + 0x37, 0xc6, 0x06, 0x00, 0xca, 0xb6, 0xb6, 0x99, 0xc5, 0xb6, 0x81, 0x7e, + 0x87, 0x62, 0xcf, 0x07, 0x76, 0xc1, 0x5f, 0xfe, 0x86, 0xfc, 0x5b, 0xa0, + 0xac, 0xca, 0xcb, 0x7d, 0xf5, 0x5a, 0xc2, 0x5e, 0x41, 0x48, 0x35, 0xc4, + 0x71, 0x9d, 0xc4, 0x0a, 0x79, 0x6f, 0xe3, 0x6d, 0x47, 0xd4, 0xaa, 0xfd, + 0x97, 0xe7, 0xb0, 0x7e, 0x61, 0xf1, 0x7d, 0x7e, 0xf8, 0x78, 0x4c, 0x2e, + 0x65, 0x51, 0xeb, 0x99, 0xd0, 0x3e, 0x24, 0x4c, 0xe0, 0x40, 0x7e, 0x2d, + 0xf7, 0x00, 0x9d, 0x50, 0x87, 0xce, 0x1f, 0x9a, 0xd2, 0x76, 0x00, 0x09, + 0xeb, 0x10, 0x1b, 0x4c, 0xf1, 0x43, 0x0e, 0x35, 0xbb, 0x23, 0x2e, 0x26, + 0x3d, 0x66, 0xa3, 0x0f, 0xf6, 0x10, 0x8b, 0x67, 0xce, 0x66, 0xfd, 0xb5, + 0x07, 0xdc, 0x04, 0x69, 0xad, 0xe0, 0x4d, 0xdf, 0xdb, 0x2f, 0x87, 0xf7, + 0xde, 0xc3, 0x77, 0x89, 0x71, 0xfd, 0x70, 0x38, 0xed, 0xe6, 0x27, 0xb1, + 0xbd, 0x94, 0x5f, 0x39, 0x20, 0x72, 0x59, 0xc4, 0x39, 0xd0, 0x20, 0x5d, + 0xe2, 0xe7, 0xe0, 0x00, 0x61, 0xc7, 0x65, 0xbd, 0xef, 0x05, 0xb3, 0xc7, + 0x7e, 0xae, 0xc5, 0x83, 0x7f, 0xc1, 0x32, 0x4e, 0x2a, 0x17, 0x64, 0x4e, + 0x2a, 0x9a, 0x2d, 0x26, 0x99, 0xa2, 0xd7, 0x37, 0x3a, 0x10, 0x6a, 0x89, + 0x72, 0x43, 0x0e, 0x3a, 0x03, 0x4c, 0xf9, 0xfe, 0xe8, 0xfc, 0x87, 0x71, + 0x37, 0x71, 0x5a, 0x05, 0xbc, 0x4e, 0x20, 0x4c, 0xd7, 0xf9, 0x8d, 0x4e, + 0xb8, 0xb8, 0x56, 0x07, 0xc8, 0x6e, 0x34, 0x6d, 0x45, 0x83, 0x34, 0xf0, + 0x77, 0xfb, 0x18, 0xec, 0x72, 0xf6, 0x4c, 0xfb, 0xba, 0x84, 0xe9, 0x89, + 0x3d, 0xfd, 0xb7, 0x0d, 0x70, 0xae, 0xa4, 0x48, 0x6b, 0x39, 0xf8, 0x62, + 0xc0, 0x7f, 0x0c, 0xf2, 0xa3, 0xfa, 0x7a, 0x64, 0x83, 0x57, 0x7d, 0x4c, + 0x04, 0x96, 0xd7, 0x9d, 0x10, 0x8b, 0x34, 0x48, 0x17, 0xff, 0x74, 0x5c, + 0x9c, 0xbe, 0xeb, 0xe5, 0x52, 0x94, 0x6a, 0x34, 0x6f, 0xf7, 0x95, 0x32, + 0x38, 0x5a, 0x9b, 0x08, 0xf6, 0xda, 0x8c, 0x0f, 0x9c, 0x5d, 0x04, 0x45, + 0xd4, 0xe9, 0xa4, 0x7a, 0xc4, 0xfd, 0x70, 0xfe, 0xa1, 0x3d, 0x21, 0xa0, + 0x01, 0xe5, 0x21, 0xca, 0xa7, 0xd9, 0xf1, 0x9f, 0x45, 0xe1, 0xe8, 0x2d, + 0x27, 0xe6, 0x87, 0xc8, 0x0d, 0xad, 0x13, 0xdb, 0xfe, 0x2f, 0xaa, 0x2b, + 0xdc, 0xa6, 0x1a, 0xc9, 0x19, 0x78, 0x1a, 0x1f, 0x10, 0xcf, 0x31, 0xe1, + 0x06, 0x28, 0x66, 0xb3, 0xa7, 0xa2, 0xa6, 0xf1, 0x3b, 0x2d, 0xd3, 0x81, + 0xaf, 0x6f, 0xc9, 0x88, 0x76, 0xe9, 0x83, 0x6c, 0x52, 0xb9, 0x70, 0x51, + 0x87, 0x6b, 0x8b, 0xbd, 0x5b, 0x9c, 0xa9, 0xf3, 0xcb, 0x55, 0xd1, 0x76, + 0x40, 0xe1, 0x90, 0xb9, 0x4c, 0xbd, 0xab, 0x1d, 0xa0, 0x5b, 0x5b, 0x34, + 0x14, 0x2f, 0x87, 0x8f, 0x63, 0xa0, 0x2d, 0x29, 0x4e, 0x50, 0x4b, 0x18, + 0x5f, 0x86, 0xac, 0x1b, 0x93, 0xe9, 0x59, 0x38, 0xa1, 0x2a, 0x36, 0x21, + 0xb2, 0xa4, 0xc0, 0x79, 0xc1, 0x60, 0xfc, 0x0f, 0xbf, 0x99, 0x04, 0x9d, + 0x4b, 0x17, 0x60, 0x5b, 0xcd, 0x78, 0x03, 0xd7, 0x7c, 0x4b, 0x9b, 0x17, + 0x58, 0x24, 0x60, 0xb8, 0x08, 0x92, 0x48, 0x4f, 0x66, 0x42, 0x9a, 0x98, + 0x2a, 0x99, 0x9a, 0x8f, 0xdd, 0xd7, 0x09, 0xf3, 0x22, 0x66, 0x62, 0xef, + 0xe5, 0x64, 0xd3, 0xdf, 0x31, 0xaa, 0x84, 0x4c, 0xa5, 0x3f, 0x4e, 0x27, + 0x48, 0x37, 0x96, 0x63, 0xbf, 0x8d, 0xe1, 0xf0, 0xd1, 0xef, 0x95, 0x1a, + 0xe6, 0xf4, 0x02, 0x61, 0xbf, 0xe3, 0xbc, 0x8b, 0x3d, 0x0b, 0x77, 0x91, + 0xc0, 0x5d, 0xfb, 0xe6, 0x7e, 0xab, 0x5e, 0xc5, 0x1c, 0x5b, 0x16, 0xfd, + 0x88, 0xa4, 0x78, 0x4c, 0x06, 0x77, 0xc3, 0x6e, 0x84, 0x0c, 0xda, 0xbf, + 0xf3, 0x8e, 0xd3, 0x61, 0x65, 0xac, 0xf2, 0x18, 0x70, 0x68, 0x84, 0x6f, + 0x9f, 0x3a, 0x94, 0x81, 0xa6, 0xc7, 0xc3, 0x92, 0xee, 0x4b, 0x20, 0x15, + 0x4e, 0x03, 0x76, 0x51, 0x5b, 0x4e, 0xe1, 0x5c, 0x51, 0x5e, 0x1b, 0x9c, + 0x30, 0x25, 0x79, 0xdd, 0x70, 0x12, 0xec, 0xdc, 0x45, 0x95, 0x45, 0x43, + 0xcd, 0xbb, 0xae, 0xa0, 0x0d, 0x43, 0xb4, 0xc9, 0x8c, 0x62, 0xfd, 0x7b, + 0xed, 0x50, 0x78, 0xb7, 0xa6, 0x94, 0xcb, 0x98, 0xb0, 0xbe, 0x09, 0xd9, + 0x0c, 0xb2, 0xc4, 0x8b, 0x96, 0x93, 0xd9, 0x26, 0xc6, 0x6d, 0x26, 0x93, + 0x32, 0x4e, 0x86, 0x72, 0x74, 0x92, 0x00, 0x72, 0x0b, 0x20, 0xa3, 0x2b, + 0x94, 0xe6, 0x10, 0x56, 0x5a, 0x41, 0x71, 0x92, 0x08, 0xce, 0x6c, 0xc4, + 0x1d, 0x9e, 0x71, 0x82, 0x64, 0x23, 0xe5, 0x15, 0xef, 0x4a, 0x7c, 0x4d, + 0xe3, 0x92, 0xbc, 0xa3, 0xa2, 0x29, 0xb7, 0x46, 0xfa, 0x8f, 0x9f, 0xc2, + 0x5d, 0xe4, 0xc0, 0x9c, 0x3f, 0x40, 0x17, 0xae, 0x44, 0xf3, 0x28, 0x10, + 0x29, 0x24, 0xa9, 0x1c, 0x9e, 0xd2, 0x55, 0x4c, 0xee, 0x45, 0xfe, 0x4a, + 0x45, 0x12, 0xf5, 0xde, 0xc7, 0x64, 0x15, 0xc3, 0x4a, 0x77, 0x63, 0x05, + 0x8d, 0xa6, 0x31, 0xa0, 0xad, 0x64, 0xaf, 0x3c, 0x69, 0x2c, 0x25, 0x78, + 0xae, 0xa0, 0x88, 0x96, 0x8a, 0xc2, 0x9b, 0x8d, 0xee, 0x6f, 0x2e, 0x79, + 0x1f, 0xec, 0x32, 0x35, 0x75, 0x83, 0x19, 0x8b, 0xda, 0xca, 0xd0, 0xaf, + 0x6a, 0x6c, 0x42, 0xe8, 0x81, 0xb5, 0x69, 0x31, 0x0b, 0x7d, 0xbc, 0xd8, + 0xd2, 0xb7, 0x7a, 0x8f, 0xfa, 0xcf, 0x91, 0x07, 0x1f, 0xda, 0xa9, 0x1f, + 0xb7, 0x2d, 0xff, 0x50, 0x15, 0x2a, 0xef, 0x8c, 0xa1, 0xe3, 0x7f, 0x08, + 0x95, 0xf2, 0x99, 0x83, 0x1f, 0x97, 0x71, 0x3e, 0x35, 0x3c, 0x8c, 0xe7, + 0x08, 0xd8, 0xa6, 0x1f, 0x0c, 0xa6, 0x52, 0xdc, 0x73, 0xa0, 0xfc, 0xd2, + 0x73, 0xe9, 0x27, 0x9d, 0xfd, 0x7a, 0x4a, 0x29, 0xd3, 0x12, 0x26, 0x13, + 0x0f, 0xce, 0xea, 0x56, 0x99, 0x61, 0x78, 0x47, 0x2c, 0xa0, 0x16, 0xa0, + 0xe2, 0x64, 0x97, 0x57, 0x31, 0xf0, 0x32, 0x5b, 0x44, 0x93, 0x76, 0x8b, + 0x59, 0x63, 0x5c, 0x5b, 0x0f, 0xe1, 0xe7, 0x74, 0x98, 0x11, 0x2d, 0x90, + 0xe4, 0xde, 0xd4, 0x3a, 0xc2, 0xfd, 0x24, 0xe3, 0x1f, 0x7a, 0xf4, 0x40, + 0xbb, 0x51, 0x92, 0x8f, 0x68, 0x9c, 0x51, 0xab, 0xdc, 0xf6, 0x1e, 0x96, + 0xca, 0x56, 0x5c, 0x92, 0xca, 0xb2, 0x1b, 0x2e, 0x6d, 0x20, 0x28, 0xb3, + 0x0a, 0x8e, 0xfd, 0xa9, 0xa2, 0x38, 0x74, 0x60, 0x37, 0xa6, 0x96, 0x02, + 0x20, 0x8a, 0x9a, 0x2b, 0x8c, 0xb9, 0x6d, 0xec, 0xff, 0xbf, 0x88, 0xbd, + 0x6c, 0xb4, 0x10, 0xbd, 0xfa, 0x5a, 0xeb, 0xb2, 0x6b, 0x74, 0x13, 0x2d, + 0xa5, 0xdb, 0x60, 0x93, 0xc6, 0xed, 0x39, 0x4f, 0xc5, 0x63, 0xe1, 0x9e, + 0x57, 0x1f, 0xe7, 0x47, 0xa4, 0xfb, 0x7f, 0xfa, 0x3a, 0x46, 0x50, 0x3a, + 0xd8, 0xd3, 0x83, 0xf5, 0xe6, 0x5e, 0xf8, 0x09, 0x0d, 0xfa, 0x33, 0xe1, + 0x50, 0xe4, 0x36, 0x3e, 0x0a, 0x5d, 0xe6, 0xf8, 0x2e, 0x17, 0x87, 0x8f, + 0xe1, 0x8c, 0x82, 0x73, 0xbd, 0xdd, 0x3b, 0x77, 0x47, 0x9f, 0x42, 0xd7, + 0xf4, 0x2d, 0x6c, 0xef, 0xcc, 0x22, 0x15, 0x3c, 0xe9, 0x26, 0xea, 0xbc, + 0xee, 0x09, 0xd3, 0xea, 0x84, 0x0f, 0x46, 0xa8, 0xe0, 0xda, 0xc5, 0x57, + 0x02, 0x54, 0xb6, 0x88, 0x2b, 0x37, 0xe5, 0x96, 0xc5, 0x33, 0xb7, 0x45, + 0x5d, 0xb7, 0xc7, 0xfd, 0xa0, 0xfa, 0x85, 0x1b, 0x2f, 0xe1, 0xec, 0x89, + 0xc6, 0xb2, 0x51, 0x71, 0xcb, 0x08, 0x82, 0x3e, 0xc9, 0xed, 0x80, 0x9d, + 0x37, 0x31, 0x9d, 0x15, 0xde, 0x24, 0x6f, 0xbd, 0x0e, 0x73, 0xa2, 0xb8, + 0x7e, 0x29, 0x7e, 0x96, 0xe4, 0xbb, 0xd6, 0x23, 0x17, 0xff, 0x33, 0x97, + 0x9c, 0x87, 0xe0, 0xe5, 0x0f, 0xb9, 0xb6, 0x31, 0x33, 0xad, 0xf8, 0xd8, + 0xdb, 0xa0, 0x71, 0x13, 0xe4, 0x1c, 0xce, 0xd0, 0x7e, 0x65, 0x7b, 0xa0, + 0x38, 0x17, 0x53, 0x4f, 0x71, 0x75, 0x6d, 0x02, 0x61, 0xc4, 0x52, 0xf8, + 0xe4, 0x2e, 0xbc, 0x52, 0xc1, 0xb1, 0x7e, 0x83, 0x0a, 0xa1, 0xd1, 0xcd, + 0x2f, 0xa0, 0x30, 0xfd, 0x41, 0x86, 0x7f, 0x26, 0xd1, 0xe7, 0xfc, 0xd7, + 0xc7, 0x37, 0xe5, 0x11, 0xa6, 0xc0, 0x9a, 0x75, 0x18, 0x04, 0x36, 0xca, + 0x8e, 0x26, 0x7d, 0xcf, 0xa2, 0x6a, 0x94, 0x9b, 0xc4, 0xf7, 0xc7, 0xeb, + 0x51, 0x13, 0xa3, 0x6f, 0x8c, 0x80, 0x5f, 0xae, 0xf0, 0x18, 0xa0, 0x88, + 0xe0, 0x8d, 0xb7, 0x80, 0x4e, 0x8c, 0xec, 0xc8, 0x7b, 0xeb, 0xac, 0x29, + 0xb7, 0x4a, 0x0f, 0x33, 0xdd, 0x9d, 0x89, 0x0a, 0x10, 0xb0, 0xce, 0x74, + 0x59, 0xa2, 0x62, 0x91, 0xc9, 0xac, 0x56, 0xcd, 0x69, 0xd3, 0x01, 0x6d, + 0x51, 0xe7, 0x04, 0xc3, 0xfb, 0xe9, 0x79, 0x1b, 0x72, 0x72, 0x1a, 0x90, + 0x0a, 0x20, 0x55, 0x85, 0xc1, 0x8b, 0xeb, 0x1e, 0x9f, 0x9f, 0x4a, 0x81, + 0x47, 0x97, 0x96, 0xbc, 0xc2, 0xe4, 0xc2, 0xfe, 0xa0, 0x20, 0xda, 0x70, + 0x0c, 0x2b, 0xe2, 0xd4, 0xc8, 0xcb, 0x46, 0x00, 0xb6, 0x7c, 0xfb, 0xbd, + 0x56, 0x94, 0x3d, 0x7f, 0x64, 0xf7, 0x88, 0xb5, 0xa7, 0xfe, 0xbe, 0x64, + 0x8a, 0xe4, 0x00, 0x08, 0x82, 0x5b, 0x8f, 0x98, 0x77, 0x87, 0xda, 0xaf, + 0x16, 0x25, 0x4a, 0x9a, 0xed, 0xfb, 0x50, 0x18, 0x45, 0x46, 0x2b, 0x73, + 0xff, 0xb9, 0xb9, 0xab, 0xa2, 0x8f, 0x3a, 0xaf, 0xc5, 0x0a, 0x14, 0x91, + 0xb2, 0x3f, 0xa6, 0x93, 0xf4, 0x81, 0x20, 0x77, 0xfa, 0x51, 0x79, 0x62, + 0xe8, 0xe6, 0x89, 0x52, 0x39, 0xd5, 0x01, 0xa2, 0x87, 0xa3, 0x53, 0x74, + 0x3c, 0x36, 0x8a, 0xc3, 0xb4, 0x44, 0x3b, 0x15, 0x21, 0xf6, 0xdc, 0x18, + 0x02, 0xd2, 0x57, 0xe5, 0x10, 0xf0, 0x3d, 0x61, 0xa7, 0x16, 0x85, 0x6f, + 0x71, 0x07, 0x75, 0x50, 0x4b, 0x21, 0x53, 0x47, 0x38, 0x35, 0x9e, 0xa7, + 0xd8, 0xfd, 0x74, 0x59, 0x15, 0x32, 0x7b, 0x89, 0xd0, 0x2c, 0xd9, 0xf6, + 0x40, 0x49, 0x79, 0xdc, 0xfb, 0x0a, 0x64, 0x59, 0x9b, 0x17, 0x47, 0x36, + 0xcb, 0xf0, 0xc3, 0xcc, 0x14, 0x8e, 0x1f, 0xa8, 0x12, 0xaa, 0xb7, 0x6a, + 0xba, 0x45, 0xf9, 0xc4, 0x44, 0xe7, 0xb5, 0x7c, 0xdd, 0xbe, 0x16, 0x76, + 0x52, 0x92, 0x3d, 0x78, 0xb7, 0xec, 0x81, 0x96, 0xd8, 0x7f, 0x34, 0x2a, + 0xa2, 0x64, 0x5f, 0xfd, 0xb1, 0x42, 0x4c, 0x79, 0x98, 0xc9, 0x17, 0x48, + 0x74, 0x12, 0x72, 0x2c, 0xde, 0x91, 0x7e, 0xa9, 0x49, 0x2a, 0xcc, 0x5c, + 0x60, 0x05, 0x25, 0x09, 0x72, 0x20, 0x80, 0x42, 0x7b, 0x18, 0xc2, 0xfc, + 0x2a, 0x5e, 0x3e, 0x2d, 0x61, 0xa6, 0xf6, 0x82, 0x42, 0x83, 0x81, 0x66, + 0x4d, 0xa6, 0xe1, 0xf9, 0xf6, 0x48, 0xd4, 0xc8, 0x69, 0xed, 0xee, 0xb5, + 0x7a, 0xcb, 0xf6, 0x0a, 0x76, 0x0e, 0x61, 0x8b, 0xf2, 0x1a, 0x8a, 0xa7, + 0x88, 0xb0, 0x90, 0xd5, 0x23, 0xaa, 0xe0, 0x2b, 0xd6, 0xd0, 0xef, 0x49, + 0x13, 0x88, 0xc7, 0x50, 0xf0, 0x9e, 0xd5, 0x28, 0xe1, 0xaa, 0x1d, 0xaf, + 0xd9, 0x73, 0xb3, 0x9e, 0xa7, 0xd8, 0xfc, 0xb9, 0x22, 0x97, 0x0e, 0x21, + 0xa0, 0xb9, 0xf9, 0xea, 0x1e, 0x95, 0x88, 0xda, 0x85, 0x7c, 0x32, 0x7c, + 0xbd, 0xef, 0xf8, 0x44, 0x25, 0x5f, 0x23, 0xfd, 0x14, 0x78, 0xc6, 0xdb, + 0x86, 0xee, 0xf8, 0xda, 0xc0, 0xae, 0x92, 0x6a, 0x03, 0xa9, 0x0a, 0xee, + 0x4a, 0x22, 0x5a, 0x6c, 0x39, 0xd3, 0x91, 0x7d, 0x91, 0x43, 0xac, 0x79, + 0xad, 0xab, 0xb7, 0x91, 0xb1, 0x20, 0x84, 0x7f, 0x0a, 0xd7, 0xa8, 0x62, + 0x95, 0xab, 0x04, 0xb6, 0xb2, 0xf1, 0xd4, 0xb0, 0xac, 0x52, 0x89, 0xb0, + 0x93, 0xdf, 0xdf, 0x80, 0x26, 0x0c, 0x32, 0x31, 0xb3, 0xba, 0xa1, 0xba, + 0x6f, 0xa3, 0x14, 0x5c, 0xfa, 0x37, 0x3b, 0x6a, 0xf2, 0xc4, 0x34, 0x27, + 0x08, 0x1a, 0xe4, 0xfc, 0x89, 0x58, 0x79, 0x34, 0x36, 0xe4, 0xad, 0x4b, + 0x3f, 0x57, 0x7b, 0xc1, 0x59, 0x2d, 0xb6, 0x54, 0x44, 0xbe, 0x4e, 0x5d, + 0x0d, 0x6a, 0xf3, 0xcd, 0xbf, 0xcd, 0x4d, 0x9f, 0x9a, 0x50, 0x09, 0xa4, + 0x6b, 0x8b, 0xb3, 0x01, 0x69, 0x6c, 0x69, 0x5d, 0x28, 0x73, 0x9e, 0xb5, + 0xc2, 0xc7, 0x6e, 0xff, 0x4c, 0x5c, 0x6b, 0x93, 0x22, 0xc1, 0x9f, 0xa6, + 0x71, 0xbf, 0x4d, 0x2d, 0x4e, 0x4e, 0x98, 0xa3, 0x6d, 0xab, 0x05, 0xa0, + 0xde, 0x34, 0x41, 0x28, 0xa4, 0x38, 0x75, 0x4e, 0xdf, 0x7f, 0xc9, 0xdd, + 0xbf, 0x5a, 0xd4, 0xcd, 0x38, 0x0c, 0x89, 0xe7, 0x0e, 0xfc, 0x0f, 0x27, + 0x39, 0x21, 0xa4, 0xa6, 0x07, 0x7b, 0x2a, 0x13, 0x56, 0xe7, 0x4e, 0x55, + 0x57, 0x71, 0x98, 0xb9, 0x3d, 0x59, 0xb5, 0xa8, 0x24, 0x18, 0x08, 0xa2, + 0x6e, 0x9a, 0xe5, 0x97, 0xa7, 0x38, 0xd9, 0x43, 0x9b, 0x19, 0x17, 0x34, + 0x03, 0xd6, 0xba, 0xe9, 0x71, 0x38, 0x26, 0x90, 0x78, 0x9e, 0x1c, 0x41, + 0x8d, 0x60, 0xdd, 0x0e, 0x12, 0x46, 0x37, 0xb4, 0x79, 0x87, 0x33, 0x12, + 0x24, 0xc4, 0x5a, 0x6c, 0x70, 0xa2, 0xb2, 0x58, 0xbb, 0xe7, 0xd6, 0x88, + 0x42, 0x2d, 0x49, 0xc8, 0x67, 0x1e, 0xc5, 0xed, 0x16, 0xa8, 0x1f, 0x36, + 0x2b, 0xfb, 0x0d, 0x51, 0x96, 0xc8, 0x78, 0xf2, 0xab, 0x82, 0xa1, 0xe2, + 0xaf, 0x8c, 0xa4, 0x13, 0x54, 0x90, 0xf1, 0xe7, 0xbb, 0xd1, 0x09, 0x23, + 0x76, 0x0e, 0x50, 0x32, 0xc5, 0x54, 0xbb, 0x1e, 0x12, 0x5d, 0x59, 0xf3, + 0xe9, 0xc9, 0xa4, 0xaa, 0xbc, 0x13, 0x1d, 0xf0, 0x79, 0x54, 0xae, 0x70, + 0xc0, 0xea, 0xcb, 0x21, 0x32, 0xe6, 0xe6, 0x8e, 0xaa, 0x51, 0x46, 0x25, + 0x1e, 0xf1, 0x3f, 0x9f, 0xf6, 0xff, 0x19, 0x53, 0x97, 0xbc, 0xa2, 0xb6, + 0x91, 0x59, 0x27, 0x1e, 0x39, 0x76, 0x76, 0x02, 0x0b, 0x03, 0x25, 0x6b, + 0x00, 0x02, 0xfa, 0x7d, 0x69, 0x5e, 0xde, 0x64, 0x33, 0xbf, 0xab, 0x3e, + 0x3f, 0x24, 0x32, 0x68, 0xbf, 0x90, 0x8f, 0x0f, 0xc5, 0x36, 0x58, 0x9e, + 0x9b, 0x11, 0xd1, 0x2a, 0x8a, 0x0d, 0xac, 0x3a, 0x23, 0xe2, 0x8e, 0xd6, + 0x0d, 0x4a, 0x8b, 0x45, 0x04, 0x47, 0xd9, 0x5a, 0x46, 0x6c, 0x70, 0x82, + 0xc7, 0x81, 0x67, 0xdc, 0xa6, 0xfa, 0x6a, 0x86, 0xfd, 0x01, 0xed, 0x90, + 0xf6, 0xe6, 0x26, 0x6d, 0xac, 0x52, 0x03, 0x4a, 0x91, 0x08, 0x7b, 0xa5, + 0x9c, 0xca, 0xd3, 0x2d, 0x79, 0xf1, 0xed, 0xcb, 0xaa, 0x8f, 0x77, 0xc8, + 0x17, 0xa8, 0xfb, 0x6c, 0x15, 0x62, 0xab, 0x34, 0xd1, 0xdd, 0x94, 0x3e, + 0xd4, 0x0c, 0x47, 0xed, 0x04, 0x91, 0xd2, 0xd7, 0x98, 0xb4, 0x43, 0x57, + 0xd1, 0x54, 0xef, 0x63, 0xba, 0xe3, 0x8a, 0x72, 0xc5, 0xb9, 0xf4, 0x30, + 0xfa, 0x16, 0x3c, 0xe1, 0xbb, 0xbe, 0x57, 0x90, 0xb9, 0xa1, 0xa0, 0x23, + 0xfa, 0xdd, 0xbe, 0x2f, 0xb3, 0xec, 0x41, 0x8b, 0x64, 0xeb, 0xc5, 0x41, + 0xea, 0xa8, 0x16, 0x76, 0x6f, 0x28, 0xda, 0x2b, 0x5f, 0x03, 0x0b, 0xe8, + 0x1c, 0x29, 0x71, 0xd8, 0x4e, 0x41, 0xdf, 0x39, 0x8e, 0x6a, 0x95, 0x79, + 0x85, 0x9c, 0xa9, 0x79, 0xd9, 0x8f, 0x33, 0xaf, 0x15, 0x3b, 0x5a, 0x82, + 0x56, 0x32, 0x98, 0x0c, 0xf6, 0xf6, 0x64, 0x42, 0xd4, 0x6a, 0x15, 0x0f, + 0xb9, 0x75, 0x22, 0xbd, 0x9a, 0x58, 0xa6, 0x01, 0x3a, 0x63, 0xf0, 0x80, + 0x78, 0x22, 0x80, 0xa0, 0x14, 0xe1, 0x37, 0x6b, 0xd4, 0x99, 0x3f, 0xc2, + 0xba, 0x2b, 0x8f, 0xf3, 0x56, 0xc8, 0x1b, 0xe4, 0x7a, 0x5e, 0x96, 0x60, + 0xee, 0x74, 0x54, 0xb6, 0x6d, 0x5c, 0x3d, 0x3e, 0x05, 0xf0, 0x9a, 0xf6, + 0xcd, 0xdd, 0x06, 0xdb, 0x8c, 0x21, 0xb9, 0xf5, 0x28, 0x57, 0x9c, 0x4f, + 0xb4, 0x08, 0xcf, 0xac, 0x6c, 0xfe, 0x30, 0xaf, 0xa2, 0xef, 0xcf, 0x93, + 0x15, 0xdd, 0x12, 0x16, 0x19, 0x7d, 0xbc, 0x57, 0xd9, 0xce, 0xbe, 0x0e, + 0xfc, 0xe1, 0xf0, 0x4a, 0x7c, 0xaa, 0xbf, 0x20, 0x64, 0x00, 0x34, 0x59, + 0xed, 0xea, 0x12, 0x58, 0x46, 0x4c, 0xc6, 0x2f, 0x77, 0x62, 0x1d, 0x82, + 0x5c, 0xe8, 0x98, 0x0d, 0xef, 0x5c, 0x0e, 0xec, 0x5d, 0x2e, 0x5f, 0xd2, + 0x22, 0x43, 0x2d, 0xe1, 0x02, 0xd5, 0x4a, 0x0a, 0x79, 0x6f, 0xa5, 0xec, + 0x48, 0xaa, 0xee, 0xf8, 0xe3, 0x5f, 0xdd, 0xe7, 0x26, 0x87, 0xb5, 0xc4, + 0xcf, 0xd9, 0x7f, 0xa8, 0xaa, 0xb6, 0xbe, 0xe9, 0x02, 0x49, 0x5d, 0x5f, + 0x81, 0x8b, 0xb9, 0xbd, 0xc0, 0xc9, 0xd5, 0xfe, 0x36, 0x3e, 0x49, 0x56, + 0x63, 0x8b, 0xce, 0xef, 0x48, 0x6e, 0xc0, 0xd4, 0x04, 0x0c, 0x33, 0x45, + 0x6e, 0x97, 0x9e, 0xa3, 0xae, 0xbc, 0xc2, 0xce, 0xdc, 0xe3, 0xff, 0x48, + 0x51, 0x68, 0x89, 0xad, 0xae, 0xc7, 0xd1, 0xde, 0xe2, 0xf9, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x0c, 0x18, 0x20, 0x24, 0x2f, 0x33, 0x3f +}; +#endif /* MLDSA87_KAT_H */ diff --git a/embedded/ti-c2000-f28p55x/Source/wolf_main.c b/embedded/ti-c2000-f28p55x/Source/wolf_main.c new file mode 100644 index 000000000..697f63c07 --- /dev/null +++ b/embedded/ti-c2000-f28p55x/Source/wolf_main.c @@ -0,0 +1,731 @@ +/* wolf_main.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* Bare-metal entry point and board support for the wolfCrypt test/benchmark + * on the TI LAUNCHXL-F28P55X (TMS320F28P550SJ, C2000 C28x DSP). + * + * Output: by default printf goes to the CCS console over JTAG (CIO), which + * needs no wiring - good for first light. Define WOLF_C2000_SCI_STDOUT to + * route stdout to SCIA (GPIO28/29), the XDS110 virtual COM, at 115200 8N1 for + * headless runs. + * + * The C28x has no hardware TRNG, so my_rng_seed_gen() is a DEV-ONLY counter + * seed - NOT secure. ML-DSA verify and the hash tests are deterministic and + * do not consume it. + */ + +#include "driverlib.h" +#include "device.h" + +#include +#include +#ifdef WOLF_C2000_SCI_STDOUT +#include +#endif + +#include +#include +#include +#include +#include +#ifdef WOLF_ECC +#include +#include +#include +#endif +#include +#include +#include "mldsa87_kat.h" +#ifdef WOLF_ECC +#include "ecc_p256_kat.h" +#endif + +/* ------------------------------------------------------------------------- */ +/* SCIA console (XDS110 virtual COM) */ +/* ------------------------------------------------------------------------- */ +static void c2000_sciInit(void) +{ + /* RX pin */ + GPIO_setPinConfig(DEVICE_GPIO_CFG_SCIRXDA); + GPIO_setDirectionMode(DEVICE_GPIO_PIN_SCIRXDA, GPIO_DIR_MODE_IN); + GPIO_setPadConfig(DEVICE_GPIO_PIN_SCIRXDA, GPIO_PIN_TYPE_STD); + GPIO_setQualificationMode(DEVICE_GPIO_PIN_SCIRXDA, GPIO_QUAL_ASYNC); + + /* TX pin */ + GPIO_setPinConfig(DEVICE_GPIO_CFG_SCITXDA); + GPIO_setDirectionMode(DEVICE_GPIO_PIN_SCITXDA, GPIO_DIR_MODE_OUT); + GPIO_setPadConfig(DEVICE_GPIO_PIN_SCITXDA, GPIO_PIN_TYPE_STD); + GPIO_setQualificationMode(DEVICE_GPIO_PIN_SCITXDA, GPIO_QUAL_ASYNC); + + SCI_performSoftwareReset(SCIA_BASE); + SCI_setConfig(SCIA_BASE, DEVICE_LSPCLK_FREQ, 115200, + (SCI_CONFIG_WLEN_8 | SCI_CONFIG_STOP_ONE | SCI_CONFIG_PAR_NONE)); + SCI_resetChannels(SCIA_BASE); + SCI_resetRxFIFO(SCIA_BASE); + SCI_resetTxFIFO(SCIA_BASE); + SCI_enableFIFO(SCIA_BASE); + SCI_enableModule(SCIA_BASE); + SCI_performSoftwareReset(SCIA_BASE); +} + +/* RAM capture buffer: every stdout byte is mirrored here so the host can read + * program output back over JTAG (symbol g_log / g_logpos), independent of SCI + * routing or CIO. Lives in .bss (RAM); survives a warm reset. The full ML-DSA + * sign build needs the RAM for two key structs, so use a smaller capture + * buffer there (the log only ever holds a few KB of text). */ +#ifdef WOLF_MLDSA_SIGN +volatile char g_log[2048]; +#else +volatile char g_log[12288]; +#endif +volatile unsigned long g_logpos = 0; + +#ifdef WOLF_STACK_PROFILE +/* Stack high-water profiling for the ML-DSA-87 verify path. The C28x SP grows + * UP from the base of the .stack section (RAMLS_STACK 0x8000..0xC000). Paint + * the as-yet-unused upper stack with a sentinel just before the call, then scan + * from the top down afterwards to find the deepest address touched. */ +#define WOLF_STK_BASE 0x8000UL +#define WOLF_STK_TOP 0xC000UL +volatile unsigned long g_stk_paint = 0; /* address paint started from */ +volatile unsigned long g_stk_peak = 0; /* highest address left touched */ +static void wolf_paint_stack(void) +{ + unsigned int marker; + unsigned int* p = &marker + 8; /* just above this frame */ + unsigned int* top = (unsigned int*)WOLF_STK_TOP; + g_stk_paint = (unsigned long)▮ + while (p < top) { + *p = 0xCCCCU; + p++; + } +} +static void wolf_measure_stack(void) +{ + unsigned int* p = (unsigned int*)(WOLF_STK_TOP - 1UL); + unsigned int* base = (unsigned int*)WOLF_STK_BASE; + while ((p > base) && (*p == 0xCCCCU)) { + p--; + } + g_stk_peak = (unsigned long)p; +} +#endif /* WOLF_STACK_PROFILE */ + +static void wolf_logbyte(char c) +{ + if (g_logpos < (unsigned long)sizeof(g_log)) { + g_log[g_logpos++] = c; + } +} + +#ifdef WOLF_C2000_SCI_STDOUT +/* Minimal CGT low-level I/O device that writes to SCIA, so printf/stdout can + * be redirected with add_device()/freopen(). Only write() does real work. */ +int WOLF_open(const char *path, unsigned flags, int llv_fd); +int WOLF_close(int dev_fd); +int WOLF_read(int dev_fd, char *buf, unsigned count); +int WOLF_write(int dev_fd, const char *buf, unsigned count); +fpos_t WOLF_lseek(int dev_fd, fpos_t offset, int origin); +int WOLF_unlink(const char *path); +int WOLF_rename(const char *old_name, const char *new_name); + +int WOLF_open(const char *path, unsigned flags, int llv_fd) +{ + (void)path; (void)flags; (void)llv_fd; + return 0; +} +int WOLF_close(int dev_fd) { (void)dev_fd; return 0; } +int WOLF_read(int dev_fd, char *buf, unsigned count) +{ + (void)dev_fd; (void)buf; (void)count; + return 0; +} +int WOLF_write(int dev_fd, const char *buf, unsigned count) +{ + unsigned i; + (void)dev_fd; + for (i = 0; i < count; i++) { + wolf_logbyte(buf[i]); + if (buf[i] == '\n') { + SCI_writeCharBlockingFIFO(SCIA_BASE, (uint16_t)'\r'); + } + SCI_writeCharBlockingFIFO(SCIA_BASE, (uint16_t)(buf[i] & 0xFF)); + } + return (int)count; +} +fpos_t WOLF_lseek(int dev_fd, fpos_t offset, int origin) +{ + (void)dev_fd; (void)offset; (void)origin; + return (fpos_t)0; +} +int WOLF_unlink(const char *path) { (void)path; return 0; } +int WOLF_rename(const char *old_name, const char *new_name) +{ + (void)old_name; (void)new_name; + return 0; +} + +static void c2000_stdoutToSci(void) +{ + add_device("wolf", _SSA, WOLF_open, WOLF_close, WOLF_read, WOLF_write, + WOLF_lseek, WOLF_unlink, WOLF_rename); + freopen("wolf:", "w", stdout); + setvbuf(stdout, NULL, _IONBF, 0); /* unbuffered: lines appear promptly */ +} +#endif /* WOLF_C2000_SCI_STDOUT */ + +/* ------------------------------------------------------------------------- */ +/* Benchmark time source - free-running CPU Timer 0 at SYSCLK */ +/* ------------------------------------------------------------------------- */ +static void c2000_timerInit(void) +{ + CPUTimer_stopTimer(CPUTIMER0_BASE); + CPUTimer_setPeriod(CPUTIMER0_BASE, 0xFFFFFFFFUL); + CPUTimer_setPreScaler(CPUTIMER0_BASE, 0U); + CPUTimer_setEmulationMode(CPUTIMER0_BASE, + CPUTIMER_EMULATIONMODE_RUNFREE); + CPUTimer_reloadTimerCounter(CPUTIMER0_BASE); + CPUTimer_startTimer(CPUTIMER0_BASE); +} + +/* benchmark.c (WOLFSSL_USER_CURRTIME) calls this for elapsed seconds. + * CPU Timer 0 is a 32-bit down-counter that auto-reloads from 0xFFFFFFFF; we + * accumulate in 64 bits across reloads. NOTE: a single measured interval must + * be shorter than 2^32 / SYSCLK (~28.6 s at 150 MHz) for the wrap handling to + * be exact - true for all BENCH_EMBEDDED cases here. */ +double current_time(int reset) +{ + static unsigned long long accum = 0; + static uint32_t last = 0; + static int started = 0; + uint32_t now; + + now = CPUTimer_getTimerCount(CPUTIMER0_BASE); + + if (!started || reset) { + accum = 0; + last = now; + started = 1; + return 0.0; + } + + if (last >= now) { + accum += (unsigned long long)(last - now); + } + else { + /* counter reloaded once since the last sample */ + accum += (unsigned long long)last + + (0xFFFFFFFFULL - (unsigned long long)now) + 1ULL; + } + last = now; + + return (double)accum / (double)DEVICE_SYSCLK_FREQ; +} + +/* ------------------------------------------------------------------------- */ +/* wolfSSL port hooks (referenced from user_settings.h) */ +/* ------------------------------------------------------------------------- */ +/* XTIME stub - hashing and ML-DSA verify never use wall-clock time. */ +long my_time(long* t) +{ + if (t != NULL) { + *t = 0; + } + return 0; +} + +/* The RNG now uses the real SHA-256 Hash-DRBG seeded by WOLFSSL_GENSEED_FORTEST + * (random.c's built-in test seed) - see user_settings.h. Switching off the old + * WC_NO_HASHDRBG custom-stub RNG (which leaked heap on every wc_InitRng) is what + * lets wolfcrypt_test and the benchmark both run in one image. */ + +#ifdef WOLF_ECC +/* ECDSA P-256 + ECDH bring-up on the C28x (SP single-precision math): + * 1. RNG-free verify KAT (RFC 6979 raw r/s; no ASN). + * 2. keygen + sign + verify round-trip (uses the test DRBG). + * 3. ECDH shared-secret agreement (both directions must match). + */ +static void wolf_ecc_test(void) +{ + /* ecc_key/WC_RNG are large under SP_NO_MALLOC; keep them off the stack so + * the SP point-math call tree has the full 16 KW stack to work in. */ + static ecc_key key; + static ecc_key keyA; + static ecc_key keyB; + static WC_RNG rng; + mp_int r; + mp_int s; + byte secretA[32]; + byte secretB[32]; + word32 lenA; + word32 lenB; + int ret; + int res; + int verified; + int ok; + word32 i; + + /* 1. Deterministic verify KAT (no RNG; raw r/s -> no ASN/DER). */ + res = 0; + ret = wc_ecc_init(&key); + if (ret == 0) { + ret = wc_ecc_import_unsigned(&key, (byte*)kat_p256_qx, + (byte*)kat_p256_qy, NULL, ECC_SECP256R1); + } + if (ret == 0) { + ret = mp_init(&r); + } + if (ret == 0) { + ret = mp_init(&s); + } + if (ret == 0) { + ret = mp_read_unsigned_bin(&r, kat_p256_r, (int)sizeof(kat_p256_r)); + } + if (ret == 0) { + ret = mp_read_unsigned_bin(&s, kat_p256_s, (int)sizeof(kat_p256_s)); + } + if (ret == 0) { + ret = wc_ecc_verify_hash_ex(&r, &s, kat_p256_hash, + (word32)sizeof(kat_p256_hash), &res, &key); + } + printf("ECDSA P-256 verify KAT: %s (ret=%d res=%d)\r\n", + (ret == 0 && res == 1) ? "PASS" : "FAIL", ret, res); + mp_clear(&r); + mp_clear(&s); + wc_ecc_free(&key); + + /* 2. keygen + sign + verify round-trip. */ + res = 0; + verified = 0; + ret = wc_InitRng(&rng); + if (ret == 0) { + ret = wc_ecc_init(&keyA); + } + if (ret == 0) { + ret = wc_ecc_make_key_ex(&rng, 32, &keyA, ECC_SECP256R1); + } + if (ret == 0) { + ret = wc_ecc_set_rng(&keyA, &rng); + } + if (ret == 0) { + ret = mp_init(&r); + } + if (ret == 0) { + ret = mp_init(&s); + } + if (ret == 0) { + ret = wc_ecc_sign_hash_ex(kat_p256_hash, + (word32)sizeof(kat_p256_hash), &rng, &keyA, &r, &s); + } + if (ret == 0) { + ret = wc_ecc_verify_hash_ex(&r, &s, kat_p256_hash, + (word32)sizeof(kat_p256_hash), &verified, &keyA); + } + printf("ECDSA P-256 keygen/sign/verify: %s (ret=%d res=%d)\r\n", + (ret == 0 && verified == 1) ? "PASS" : "FAIL", ret, verified); + mp_clear(&r); + mp_clear(&s); + + /* 3. ECDH: a second key + shared secret both ways must agree. */ + ret = wc_ecc_init(&keyB); + if (ret == 0) { + ret = wc_ecc_make_key_ex(&rng, 32, &keyB, ECC_SECP256R1); + } + if (ret == 0) { + ret = wc_ecc_set_rng(&keyB, &rng); + } + lenA = (word32)sizeof(secretA); + lenB = (word32)sizeof(secretB); + if (ret == 0) { + ret = wc_ecc_shared_secret(&keyA, &keyB, secretA, &lenA); + } + if (ret == 0) { + ret = wc_ecc_shared_secret(&keyB, &keyA, secretB, &lenB); + } + ok = (ret == 0) && (lenA == lenB) && (lenA > 0); + for (i = 0; ok && (i < lenA); i++) { + if (secretA[i] != secretB[i]) { + ok = 0; + } + } + printf("ECDH P-256 shared secret: %s (ret=%d len=%lu)\r\n", + ok ? "PASS" : "FAIL", ret, (unsigned long)lenA); + wc_ecc_free(&keyB); + wc_ecc_free(&keyA); + wc_FreeRng(&rng); +} +#endif /* WOLF_ECC */ + +/* ------------------------------------------------------------------------- */ +/* main */ +/* ------------------------------------------------------------------------- */ +int main(void) +{ +#ifndef NO_CRYPT_TEST + wc_test_ret_t test_ret; +#endif +#ifndef NO_CRYPT_BENCHMARK + int bench_ret; +#endif + + /* PLL to 150 MHz, flash wait states, disable watchdog, enable clocks. */ + Device_init(); + Device_initGPIO(); + c2000_sciInit(); +#ifdef WOLF_C2000_SCI_STDOUT + c2000_stdoutToSci(); +#endif + c2000_timerInit(); + + /* Unbuffered stdout so output appears immediately and survives a crash, + * whether routed to SCIA or the CCS console (CIO). */ + setvbuf(stdout, NULL, _IONBF, 0); + + printf("\r\n"); + printf("=== wolfSSL wolfCrypt on TI C2000 LAUNCHXL-F28P55X ===\r\n"); + + /* Focused SHA3-256 known-answer test (SHA3-256("abc")), to confirm the + * 16-bit-byte Keccak path is correct on the C28x. */ + { + static const byte kat_msg[3] = { 'a', 'b', 'c' }; + static const byte kat_exp[WC_SHA3_256_DIGEST_SIZE] = { + 0x3a,0x98,0x5d,0xa7,0x4f,0xe2,0x25,0xb2, + 0x04,0x5c,0x17,0x2d,0x6b,0xd3,0x90,0xbd, + 0x85,0x5f,0x08,0x6e,0x3e,0x9d,0x52,0x5b, + 0x46,0xbf,0xe2,0x45,0x11,0x43,0x15,0x32 + }; + wc_Sha3 kat_sha; + byte kat_out[WC_SHA3_256_DIGEST_SIZE]; + int ki; + int kok = 1; + + if (wc_InitSha3_256(&kat_sha, NULL, INVALID_DEVID) == 0) { + (void)wc_Sha3_256_Update(&kat_sha, kat_msg, (word32)sizeof(kat_msg)); + (void)wc_Sha3_256_Final(&kat_sha, kat_out); + wc_Sha3_256_Free(&kat_sha); + printf("SHA3-256(abc)="); + for (ki = 0; ki < (int)sizeof(kat_out); ki++) { + printf("%02x", (unsigned)(kat_out[ki] & 0xFF)); + } + printf("\r\n"); + for (ki = 0; ki < (int)sizeof(kat_out); ki++) { + if (kat_out[ki] != kat_exp[ki]) { + kok = 0; + } + } + printf("SHA3-256 KAT: %s\r\n", kok ? "PASS" : "FAIL"); + } + else { + printf("SHA3-256 KAT: init failed\r\n"); + } + } + + /* SHA-256 multi-block KAT (64 bytes 0x00..0x3f) - exercises the full-block + * input path, not just the single-block Final path. */ + { + static byte s2_msg[64]; + static const byte s2_exp[WC_SHA256_DIGEST_SIZE] = { + 0xfd,0xea,0xb9,0xac,0xf3,0x71,0x03,0x62, + 0xbd,0x26,0x58,0xcd,0xc9,0xa2,0x9e,0x8f, + 0x9c,0x75,0x7f,0xcf,0x98,0x11,0x60,0x3a, + 0x8c,0x44,0x7c,0xd1,0xd9,0x15,0x11,0x08 + }; + wc_Sha256 s2; + byte s2o[WC_SHA256_DIGEST_SIZE]; + int si, sok = 1; + for (si = 0; si < 64; si++) { s2_msg[si] = (byte)si; } + if (wc_InitSha256(&s2) == 0) { + (void)wc_Sha256Update(&s2, s2_msg, 64); + (void)wc_Sha256Final(&s2, s2o); + wc_Sha256Free(&s2); + printf("SHA-256(64)="); + for (si = 0; si < (int)sizeof(s2o); si++) { + printf("%02x", (unsigned)(s2o[si] & 0xFF)); + } + printf("\r\n"); + for (si = 0; si < (int)sizeof(s2o); si++) { + if (s2o[si] != s2_exp[si]) { sok = 0; } + } + printf("SHA-256 (multiblock) KAT: %s\r\n", sok ? "PASS" : "FAIL"); + } + } + + /* SHAKE256 multi-block KAT (256 bytes 0x00..0xff), 32-byte output - + * exercises multi-block absorb (the path ML-DSA's mu/tr use). */ + { + static byte sk_msg[256]; + static const byte sk_exp[32] = { + 0x33,0x6c,0x8a,0xa7,0xf2,0xb0,0x8b,0xda, + 0x6b,0xd7,0x40,0x2c,0xd2,0xea,0x89,0x76, + 0x0b,0x77,0x28,0xa8,0xb3,0x18,0x02,0xb8, + 0x05,0x24,0x75,0x63,0x61,0x16,0x53,0x66 + }; + wc_Shake sk1; + byte o1[32]; + int i, match = 1; + for (i = 0; i < 256; i++) { sk_msg[i] = (byte)i; } + if (wc_InitShake256(&sk1, NULL, INVALID_DEVID) == 0) { + (void)wc_Shake256_Update(&sk1, sk_msg, 256); + (void)wc_Shake256_Final(&sk1, o1, (word32)sizeof(o1)); + printf("SHAKE256(256)="); + for (i = 0; i < 32; i++) { printf("%02x", (unsigned)(o1[i] & 0xFF)); } + printf("\r\n"); + for (i = 0; i < 32; i++) { if (o1[i] != sk_exp[i]) { match = 0; } } + printf("SHAKE256 (multiblock) KAT: %s\r\n", match ? "PASS" : "FAIL"); + wc_Shake256_Free(&sk1); + } + /* Same 256 bytes via 3 Updates (100+100+56) - exercises the + * partial-buffer-fills-to-full absorb across Update calls (ML-DSA's + * mu/tr feed several Updates). Must match the single-Update result. */ + if (wc_InitShake256(&sk1, NULL, INVALID_DEVID) == 0) { + int mu_ok = 1; + (void)wc_Shake256_Update(&sk1, sk_msg, 100); + (void)wc_Shake256_Update(&sk1, sk_msg + 100, 100); + (void)wc_Shake256_Update(&sk1, sk_msg + 200, 56); + (void)wc_Shake256_Final(&sk1, o1, (word32)sizeof(o1)); + for (i = 0; i < 32; i++) { if (o1[i] != sk_exp[i]) { mu_ok = 0; } } + printf("SHAKE256 (split Updates) KAT: %s\r\n", mu_ok ? "PASS" : "FAIL"); + wc_Shake256_Free(&sk1); + } + /* SHAKE256 large hash (100x1024 absorb -> 250-byte multi-block squeeze), + * the exact test.c large-hash scenario, compared to test.c's + * large_digest - validates multi-block absorb + multi-block squeeze on + * the C28x. Skipped in the SIGN build: its ~1.4 KW of static buffers + * would not fit alongside the sign key + 32 KW heap. */ +#ifndef WOLF_MLDSA_SIGN + { + static byte lg_in[1024]; + static byte lg_out[250]; + static const byte lg_exp[114] = { + 0x90,0x32,0x4a,0xcc,0xd1,0xdf,0xb8,0x0b,0x79,0x1f,0xb8,0xc8, + 0x5b,0x54,0xc8,0xe7,0x45,0xf5,0x60,0x6b,0x38,0x26,0xb2,0x0a, + 0xee,0x38,0x01,0xf3,0xd9,0xfa,0x96,0x9f,0x6a,0xd7,0x15,0xdf, + 0xb6,0xc2,0xf4,0x20,0x33,0x44,0x55,0xe8,0x2a,0x09,0x2b,0x68, + 0x2e,0x18,0x65,0x5e,0x65,0x93,0x28,0xbc,0xb1,0x9e,0xe2,0xb1, + 0x92,0xea,0x98,0xac,0x21,0xef,0x4c,0xe1,0xb4,0xb7,0xbe,0x81, + 0x5c,0x1d,0xd3,0xb7,0x17,0xe5,0xbb,0xc5,0x8c,0x68,0xb7,0xfb, + 0xac,0x55,0x8a,0x9b,0x4d,0x91,0xe4,0x9f,0x72,0xbb,0x6e,0x38, + 0xaf,0x21,0x7d,0x21,0xaa,0x98,0x4e,0x75,0xc4,0xb4,0x1c,0x7c, + 0x50,0x45,0x54,0xf9,0xea,0x26 }; + int li, ok; + for (li = 0; li < 1024; li++) { lg_in[li] = (byte)(li & 0xFF); } + if (wc_InitShake256(&sk1, NULL, INVALID_DEVID) == 0) { + for (li = 0; li < 100; li++) + (void)wc_Shake256_Update(&sk1, lg_in, 1024); + (void)wc_Shake256_Final(&sk1, lg_out, (word32)sizeof(lg_out)); + ok = 1; + for (li = 0; li < 114; li++) if (lg_out[li] != lg_exp[li]) ok = 0; + printf("SHAKE256 (large multiblock) KAT: %s\r\n", + ok ? "PASS" : "FAIL"); + wc_Shake256_Free(&sk1); + } + } +#endif /* !WOLF_MLDSA_SIGN */ + } + + /* SHA-512 / SHA-384 multi-block KATs (200 bytes 0x00..0xc7) - exercises the + * octet-wise word64 byte-I/O (input load, 128-bit length, digest store). */ + { + static byte h5_msg[200]; + static const byte sha512_exp[WC_SHA512_DIGEST_SIZE] = { + 0x98,0x60,0x58,0xe9,0x89,0x5e,0x2c,0x2a, + 0xb8,0xf9,0xe8,0xcb,0xdf,0x80,0x1d,0xb1, + 0x2a,0x44,0x84,0x2a,0x56,0xa9,0x1d,0x5a, + 0x4e,0x87,0xb1,0xfc,0x98,0xb2,0x93,0x72, + 0x2c,0x46,0x64,0x14,0x2e,0x42,0xc3,0xc5, + 0x51,0xff,0x89,0x86,0x46,0x26,0x8c,0xd9, + 0x2b,0x84,0xed,0x23,0x0b,0x8c,0x94,0xbe, + 0xd7,0x79,0x8d,0x4f,0x27,0xcd,0x74,0x65 + }; + static const byte sha384_exp[WC_SHA384_DIGEST_SIZE] = { + 0x7e,0xa4,0xbb,0x25,0x34,0xc6,0x70,0x36, + 0xf4,0x9d,0xe7,0xbe,0xb5,0xfe,0x8a,0x24, + 0x78,0xdf,0x04,0xff,0x3f,0xef,0x40,0xa9, + 0xcd,0x49,0x23,0x99,0x9a,0x59,0x0e,0x99, + 0x12,0xdf,0x12,0x97,0x21,0x7c,0xe1,0xa0, + 0x21,0xaa,0x2f,0xb1,0x01,0x34,0x98,0xb8 + }; + wc_Sha512 h512; + wc_Sha384 h384; + byte h5o[WC_SHA512_DIGEST_SIZE]; + int hi, h5ok = 1, h3ok = 1; + for (hi = 0; hi < 200; hi++) { h5_msg[hi] = (byte)(hi & 0xFF); } + if (wc_InitSha512(&h512) == 0) { + (void)wc_Sha512Update(&h512, h5_msg, 200); + (void)wc_Sha512Final(&h512, h5o); + wc_Sha512Free(&h512); + for (hi = 0; hi < WC_SHA512_DIGEST_SIZE; hi++) { + if (h5o[hi] != sha512_exp[hi]) { h5ok = 0; } + } + printf("SHA-512 (multiblock) KAT: %s\r\n", h5ok ? "PASS" : "FAIL"); + } + if (wc_InitSha384(&h384) == 0) { + (void)wc_Sha384Update(&h384, h5_msg, 200); + (void)wc_Sha384Final(&h384, h5o); + wc_Sha384Free(&h384); + for (hi = 0; hi < WC_SHA384_DIGEST_SIZE; hi++) { + if (h5o[hi] != sha384_exp[hi]) { h3ok = 0; } + } + printf("SHA-384 (multiblock) KAT: %s\r\n", h3ok ? "PASS" : "FAIL"); + } + } + + /* ML-DSA-87 verify known-answer test (real pk/msg/sig from test.c). This + * is the primary deliverable: a deterministic, RNG-free verify on HW. + * Key struct is static (large; WOLFSSL_MLDSA_VERIFY_NO_MALLOC pins buffers + * into it). msg matches test.c's mldsa_param_vfy_test: msg[i] = (byte)i. + * Skipped in the SIGN build: its static verify key would not fit alongside + * the sign key + 32 KW heap, and the sign round-trip below also exercises + * verify (of a freshly produced signature). */ +#ifndef WOLF_MLDSA_SIGN + { + static wc_MlDsaKey mldsa_key; + byte md_msg[512]; + int md_i; + int md_res = 0; + int md_ret; + + /* test.c builds this as msg[i] = (byte)i. On an 8-bit-byte host that + * wraps mod 256; a wolfCrypt 'byte' buffer must hold octet values, so + * mask explicitly (a C28x 'byte' is a 16-bit cell and would otherwise + * store 256..511 verbatim, corrupting the octet-wise hash input). */ + for (md_i = 0; md_i < (int)sizeof(md_msg); md_i++) { + md_msg[md_i] = (byte)(md_i & 0xFF); + } + md_ret = wc_MlDsaKey_Init(&mldsa_key, NULL, INVALID_DEVID); + if (md_ret == 0) { + md_ret = wc_MlDsaKey_SetParams(&mldsa_key, WC_ML_DSA_87); + } + if (md_ret == 0) { + md_ret = wc_MlDsaKey_ImportPubRaw(&mldsa_key, kat_mldsa87_pub, + (word32)sizeof(kat_mldsa87_pub)); + } + if (md_ret == 0) { +#ifdef WOLF_STACK_PROFILE + wolf_paint_stack(); +#endif + md_ret = wc_MlDsaKey_VerifyCtx(&mldsa_key, kat_mldsa87_sig, + (word32)sizeof(kat_mldsa87_sig), NULL, 0, md_msg, + (word32)sizeof(md_msg), &md_res); +#ifdef WOLF_STACK_PROFILE + wolf_measure_stack(); +#endif + } + printf("ML-DSA-87 verify KAT: %s (ret=%d res=%d)\r\n", + (md_ret == 0 && md_res == 1) ? "PASS" : "FAIL", md_ret, md_res); +#ifdef WOLF_MLDSA_VERIFY_BENCH + /* Time the deterministic verify (CPU Timer 0 via current_time); 10 ops + * keeps the interval under the ~28 s single-measurement wrap. */ + if ((md_ret == 0) && (md_res == 1)) { + int bi; + int br = 0; + double t; + (void)current_time(1); + for (bi = 0; bi < 10; bi++) { + (void)wc_MlDsaKey_VerifyCtx(&mldsa_key, kat_mldsa87_sig, + (word32)sizeof(kat_mldsa87_sig), NULL, 0, md_msg, + (word32)sizeof(md_msg), &br); + } + t = current_time(0); + printf("ML-DSA-87 verify bench: 10 ops in %.3f s = %.2f ms/op, " + "%.2f ops/sec\r\n", t, (t * 1000.0) / 10.0, 10.0 / t); + } +#endif +#ifdef WOLF_STACK_PROFILE + printf("ML-DSA-87 verify: stack peak=0x%lx used=%lu words (key struct " + "sizeof=%lu words); heap: VERIFY_NO_MALLOC\r\n", + g_stk_peak, (g_stk_peak - WOLF_STK_BASE + 1UL), + (unsigned long)sizeof(mldsa_key)); +#endif + wc_MlDsaKey_Free(&mldsa_key); + } +#endif /* !WOLF_MLDSA_SIGN */ + +#ifdef WOLF_MLDSA_SIGN + /* ML-DSA-87 sign+verify round-trip (keygen -> sign -> verify). Exercises + * the full signer on the C28x. Uses the DEV RNG stub (NOT secure) - this + * proves functional correctness, not security. */ + { + static wc_MlDsaKey sgk; + static byte sg_sig[5000]; + static byte sg_msg[64]; + WC_RNG sg_rng; + word32 sg_sigLen = (word32)sizeof(sg_sig); + int sg_i, sg_res = 0, sg_ret; + + for (sg_i = 0; sg_i < (int)sizeof(sg_msg); sg_i++) { + sg_msg[sg_i] = (byte)(sg_i & 0xFF); + } + sg_ret = wc_InitRng(&sg_rng); + if (sg_ret == 0) { + sg_ret = wc_MlDsaKey_Init(&sgk, NULL, INVALID_DEVID); + } + if (sg_ret == 0) { + sg_ret = wc_MlDsaKey_SetParams(&sgk, WC_ML_DSA_87); + } + if (sg_ret == 0) { + sg_ret = wc_MlDsaKey_MakeKey(&sgk, &sg_rng); + } + printf("ML-DSA-87 MakeKey: ret=%d\r\n", sg_ret); + if (sg_ret == 0) { + sg_ret = wc_MlDsaKey_SignCtx(&sgk, NULL, 0, sg_sig, &sg_sigLen, + sg_msg, (word32)sizeof(sg_msg), &sg_rng); + } + printf("ML-DSA-87 Sign: ret=%d sigLen=%lu\r\n", sg_ret, + (unsigned long)sg_sigLen); + if (sg_ret == 0) { + sg_ret = wc_MlDsaKey_VerifyCtx(&sgk, sg_sig, sg_sigLen, NULL, 0, + sg_msg, (word32)sizeof(sg_msg), &sg_res); + } + printf("ML-DSA-87 sign/verify round-trip: %s (ret=%d res=%d)\r\n", + (sg_ret == 0 && sg_res == 1) ? "PASS" : "FAIL", sg_ret, sg_res); + wc_MlDsaKey_Free(&sgk); + wc_FreeRng(&sg_rng); + } +#endif /* WOLF_MLDSA_SIGN */ + +#ifdef WOLF_ECC + printf("\r\n--- ECDSA/ECDH P-256 (SP) ---\r\n"); + wolf_ecc_test(); +#endif + + printf("SYSCLK %lu Hz, CHAR_BIT %d, sizeof(long)=%d sizeof(long long)=%d\r\n", + (unsigned long)DEVICE_SYSCLK_FREQ, (int)CHAR_BIT, + (int)sizeof(long), (int)sizeof(long long)); + +#ifndef NO_CRYPT_TEST + printf("\r\n--- wolfcrypt_test ---\r\n"); + test_ret = wolfcrypt_test(NULL); + printf("wolfcrypt_test result: %ld\r\n", (long)test_ret); +#endif + +#ifndef NO_CRYPT_BENCHMARK + printf("\r\n--- benchmark_test ---\r\n"); + bench_ret = benchmark_test(NULL); + printf("benchmark_test result: %d\r\n", bench_ret); +#endif + + printf("\r\n=== done ===\r\n"); + + for (;;) { + /* spin */ + } +} diff --git a/embedded/ti-c2000-f28p55x/ccxml/F28P550SJ.ccxml b/embedded/ti-c2000-f28p55x/ccxml/F28P550SJ.ccxml new file mode 100644 index 000000000..c6c30fb83 --- /dev/null +++ b/embedded/ti-c2000-f28p55x/ccxml/F28P550SJ.ccxml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From d2a1395fcd3990184db5aa18bcaaae1d7db40108 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 18 Jun 2026 11:44:31 -0700 Subject: [PATCH 02/13] ti-c2000: run BlockSha3 and the ML-DSA NTTs from RAM At 150 MHz the F28P55x flash has wait states and there is no instruction cache, so the Keccak permutation and the ML-DSA NTT/INTT (the hot inner loops of ML-DSA-87 verify) stall on instruction fetch. Relocate them into a .TI.ramfunc section (LOAD from flash, RUN from RAMGS0, copied at startup by Device_init's Ramfuncs memcpy): BlockSha3 plus mldsa_ntt_c / mldsa_invntt_c / mldsa_ntt_small_c. Split RAMGS into an 8 KW RAM-code block (RAMGS0) and the 8 KW heap (RAMGS1). Measured on hardware: ML-DSA-87 verify 353.6 -> 316.9 ms/op (with the wolfSSL 64-bit-widened Montgomery change, 305.2 ms/op). --- .../28p55x_wolf_flash_lnk.cmd | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/embedded/ti-c2000-f28p55x/28p55x_wolf_flash_lnk.cmd b/embedded/ti-c2000-f28p55x/28p55x_wolf_flash_lnk.cmd index 0cb0dee16..56c7e5523 100644 --- a/embedded/ti-c2000-f28p55x/28p55x_wolf_flash_lnk.cmd +++ b/embedded/ti-c2000-f28p55x/28p55x_wolf_flash_lnk.cmd @@ -20,8 +20,8 @@ -stack 0x4000 /* 16 KW C28x stack (full RAMLS0-7); wolfcrypt_test's deep call * chain + SHAKE/large-hash locals (~1.6 KW) need the headroom */ --heap 0x4000 /* 16 KW heap (full RAMGS0-1) for test/benchmark temporaries; - * benchmark needs ~2 KW of block buffers after the suite */ +-heap 0x2000 /* 8 KW heap (RAMGS1); RAMGS0 now hosts RAM-resident hot code. + * ML-DSA verify uses no heap; test/benchmark temporaries fit. */ MEMORY { @@ -33,7 +33,11 @@ MEMORY /* Low RAM (< 0x10000): usable for the 16-bit-SP stack and the heap. */ RAMLS_STACK : origin = 0x008000, length = 0x004000 /* RAMLS0-7, 16 KW */ - RAMGS_HEAP : origin = 0x00C000, length = 0x004000 /* RAMGS0-1, 16 KW (< 0x10000) */ + /* RAMGS0 hosts RAM-resident hot code (.TI.ramfunc), RAMGS1 the heap. At + * 150 MHz the flash has wait states; running the Keccak permutation and the + * ML-DSA NTTs from RAM removes the instruction-fetch stalls. */ + RAMGS_RAMCODE : origin = 0x00C000, length = 0x002000 /* RAMGS0, 8 KW */ + RAMGS_HEAP : origin = 0x00E000, length = 0x002000 /* RAMGS1, 8 KW */ /* High RAM (>= 0x10000): data only (no stack). */ RAMGS_HI : origin = 0x010000, length = 0x004000 /* RAMGS2-3, 16 KW */ @@ -52,6 +56,23 @@ MEMORY SECTIONS { codestart : > BEGIN + /* Hot crypto relocated to RAM (loaded from flash, copied by Device_init's + * Ramfuncs memcpy). Listed before .text so these subsections are claimed + * here, not by the generic .text below. --gen_func_subsections=on makes + * each function its own .text: input section. */ + .TI.ramfunc : { sha3.obj(.text:BlockSha3) + wc_mldsa.obj(.text:mldsa_ntt_c) + wc_mldsa.obj(.text:mldsa_invntt_c) + wc_mldsa.obj(.text:mldsa_ntt_small_c) } + LOAD = FLASH_BANK0, + RUN = RAMGS_RAMCODE, + LOAD_START(RamfuncsLoadStart), + LOAD_SIZE(RamfuncsLoadSize), + LOAD_END(RamfuncsLoadEnd), + RUN_START(RamfuncsRunStart), + RUN_SIZE(RamfuncsRunSize), + RUN_END(RamfuncsRunEnd), + ALIGN(8) .text : >> FLASH_BANK0 | FLASH_BANK1 | FLASH_BANK2 | FLASH_BANK3, ALIGN(8) .cinit : > FLASH_BANK0, ALIGN(8) .switch : > FLASH_BANK0, ALIGN(8) @@ -65,14 +86,4 @@ SECTIONS .const : >> FLASH_BANK0 | FLASH_BANK1, ALIGN(8) .data : >> RAMGS_HI | RAMLS_HI .sysmem : > RAMGS_HEAP - - .TI.ramfunc : {} LOAD = FLASH_BANK0, - RUN = RAMM0, - LOAD_START(RamfuncsLoadStart), - LOAD_SIZE(RamfuncsLoadSize), - LOAD_END(RamfuncsLoadEnd), - RUN_START(RamfuncsRunStart), - RUN_SIZE(RamfuncsRunSize), - RUN_END(RamfuncsRunEnd), - ALIGN(8) } From 435e8020b12387e943fb7d6034eb029907a31835 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 18 Jun 2026 16:47:19 -0700 Subject: [PATCH 03/13] ti-c2000: run BlockSha3 from RAM in SIGN build (keygen -10%/sign -9%); add sign bench --- .../ti-c2000-f28p55x/28p55x_wolf_sign_lnk.cmd | 12 ++++++---- embedded/ti-c2000-f28p55x/Source/wolf_main.c | 22 +++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/embedded/ti-c2000-f28p55x/28p55x_wolf_sign_lnk.cmd b/embedded/ti-c2000-f28p55x/28p55x_wolf_sign_lnk.cmd index 91c1fccb8..d9675ba6d 100644 --- a/embedded/ti-c2000-f28p55x/28p55x_wolf_sign_lnk.cmd +++ b/embedded/ti-c2000-f28p55x/28p55x_wolf_sign_lnk.cmd @@ -27,8 +27,11 @@ MEMORY RAMM0 : origin = 0x000128, length = 0x0002D8 RAMM1 : origin = 0x000400, length = 0x000400 - /* Low RAM (< 0x10000): the 16-bit-SP stack. */ - RAMLS_STACK : origin = 0x008000, length = 0x004000 /* RAMLS0-7, 16 KW */ + /* Low RAM (< 0x10000): the 16-bit-SP stack (12 KW), plus 4 KW of RAM- + * resident hot code carved from the top of RAMLS0-7. The stack only uses + * 0x3000, so 0xB000..0xBFFF is free for the Keccak permutation. */ + RAMLS_STACK : origin = 0x008000, length = 0x003000 /* RAMLS0-5, 12 KW */ + RAMLS_RAMCODE : origin = 0x00B000, length = 0x001000 /* RAMLS6-7, 4 KW */ /* RAMGS0-3 is one contiguous 32 KW block (0xC000..0x13FFF): the heap. */ RAMGS_BIG : origin = 0x00C000, length = 0x008000 /* RAMGS0-3, 32 KW */ @@ -63,8 +66,9 @@ SECTIONS .data : > RAMLS_HI .sysmem : > RAMGS_BIG - .TI.ramfunc : {} LOAD = FLASH_BANK0, - RUN = RAMM0, + .TI.ramfunc : { sha3.obj(.text:BlockSha3) } + LOAD = FLASH_BANK0, + RUN = RAMLS_RAMCODE, LOAD_START(RamfuncsLoadStart), LOAD_SIZE(RamfuncsLoadSize), LOAD_END(RamfuncsLoadEnd), diff --git a/embedded/ti-c2000-f28p55x/Source/wolf_main.c b/embedded/ti-c2000-f28p55x/Source/wolf_main.c index 697f63c07..261e98b53 100644 --- a/embedded/ti-c2000-f28p55x/Source/wolf_main.c +++ b/embedded/ti-c2000-f28p55x/Source/wolf_main.c @@ -697,6 +697,28 @@ int main(void) } printf("ML-DSA-87 sign/verify round-trip: %s (ret=%d res=%d)\r\n", (sg_ret == 0 && sg_res == 1) ? "PASS" : "FAIL", sg_ret, sg_res); +#ifdef WOLF_MLDSA_SIGN_BENCH + if (sg_ret == 0) { + double t; + int b; + (void)current_time(1); + for (b = 0; b < 3; b++) { + (void)wc_MlDsaKey_MakeKey(&sgk, &sg_rng); + } + t = current_time(0); + printf("ML-DSA-87 keygen bench: 3 ops in %.3f s = %.2f ms/op\r\n", + t, t * 1000.0 / 3); + (void)current_time(1); + for (b = 0; b < 3; b++) { + sg_sigLen = (word32)sizeof(sg_sig); + (void)wc_MlDsaKey_SignCtx(&sgk, NULL, 0, sg_sig, &sg_sigLen, + sg_msg, (word32)sizeof(sg_msg), &sg_rng); + } + t = current_time(0); + printf("ML-DSA-87 sign bench: 3 ops in %.3f s = %.2f ms/op\r\n", + t, t * 1000.0 / 3); + } +#endif /* WOLF_MLDSA_SIGN_BENCH */ wc_MlDsaKey_Free(&sgk); wc_FreeRng(&sg_rng); } From 051aeb38d56b720fc5094c8a27cd440269df3a25 Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 18 Jun 2026 17:20:25 -0700 Subject: [PATCH 04/13] ti-c2000: WIP ML-KEM-768 build (MLKEM=1) + round-trip harness (round-trip FAILs on C28x, debugging CHAR_BIT==16 logic) --- .../ti-c2000-f28p55x/Header/user_settings.h | 25 +++++++++++- embedded/ti-c2000-f28p55x/Makefile | 9 +++++ embedded/ti-c2000-f28p55x/Source/wolf_main.c | 39 +++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/embedded/ti-c2000-f28p55x/Header/user_settings.h b/embedded/ti-c2000-f28p55x/Header/user_settings.h index fd5ed445c..fcd0095da 100644 --- a/embedded/ti-c2000-f28p55x/Header/user_settings.h +++ b/embedded/ti-c2000-f28p55x/Header/user_settings.h @@ -256,7 +256,30 @@ extern "C" { #ifndef WOLF_ECC /* HAVE_ECC intentionally not defined - no ECC. */ #endif -#undef WOLFSSL_HAVE_MLKEM /* no ML-KEM this pass */ +#ifdef WOLF_MLKEM +/* ML-KEM (FIPS 203) via the wolfCrypt C implementation. Build only the + * ML-KEM-768 parameter set, force the generic C path (no x86/ARM asm), and use + * the small-memory / no-malloc options so it fits the bare-metal RAM budget. + * Validated on the C28x by test.c's mlkem_test KAT. */ +#undef WOLFSSL_HAVE_MLKEM +#define WOLFSSL_HAVE_MLKEM +#undef WOLFSSL_WC_MLKEM +#define WOLFSSL_WC_MLKEM +#undef WOLFSSL_NO_ML_KEM_512 +#define WOLFSSL_NO_ML_KEM_512 +#undef WOLFSSL_NO_ML_KEM_1024 +#define WOLFSSL_NO_ML_KEM_1024 +#undef WC_MLKEM_NO_ASM +#define WC_MLKEM_NO_ASM +#undef WOLFSSL_MLKEM_NO_MALLOC +#define WOLFSSL_MLKEM_NO_MALLOC +#undef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM +#define WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM +#undef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM +#define WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM +#else +#undef WOLFSSL_HAVE_MLKEM /* no ML-KEM unless MLKEM=1 */ +#endif #undef NO_ASN #define NO_ASN /* ML-DSA + ECC raw import; no asn.c needed */ #undef NO_CERTS diff --git a/embedded/ti-c2000-f28p55x/Makefile b/embedded/ti-c2000-f28p55x/Makefile index 842e81457..b4031dc60 100644 --- a/embedded/ti-c2000-f28p55x/Makefile +++ b/embedded/ti-c2000-f28p55x/Makefile @@ -88,6 +88,15 @@ ifeq ($(ECC),1) $(WOLFROOT)/wolfcrypt/src/sp_c32.c endif +# MLKEM=1 adds ML-KEM-768 (FIPS 203) via the wolfCrypt C implementation. +MLKEM ?= 0 +ifeq ($(MLKEM),1) + CFLAGS += --define=WOLF_MLKEM + WC_SRCS += \ + $(WOLFROOT)/wolfcrypt/src/wc_mlkem.c \ + $(WOLFROOT)/wolfcrypt/src/wc_mlkem_poly.c +endif + HARNESS_SRCS := \ $(WOLFROOT)/wolfcrypt/test/test.c \ $(WOLFROOT)/wolfcrypt/benchmark/benchmark.c diff --git a/embedded/ti-c2000-f28p55x/Source/wolf_main.c b/embedded/ti-c2000-f28p55x/Source/wolf_main.c index 261e98b53..636527a84 100644 --- a/embedded/ti-c2000-f28p55x/Source/wolf_main.c +++ b/embedded/ti-c2000-f28p55x/Source/wolf_main.c @@ -46,6 +46,9 @@ #include #include #include +#ifdef WOLF_MLKEM +#include +#endif #ifdef WOLF_ECC #include #include @@ -729,6 +732,42 @@ int main(void) wolf_ecc_test(); #endif +#ifdef WOLF_MLKEM + printf("\r\n--- ML-KEM-768 ---\r\n"); + { + static MlKemKey kemk; + static byte kem_ct[WC_ML_KEM_768_CIPHER_TEXT_SIZE]; + static byte kem_ss1[WC_ML_KEM_SS_SZ]; + static byte kem_ss2[WC_ML_KEM_SS_SZ]; + WC_RNG kem_rng; + int kem_ret, kem_ok = 0; + + kem_ret = wc_InitRng(&kem_rng); + if (kem_ret == 0) { + kem_ret = wc_MlKemKey_Init(&kemk, WC_ML_KEM_768, NULL, INVALID_DEVID); + } + if (kem_ret == 0) { + kem_ret = wc_MlKemKey_MakeKey(&kemk, &kem_rng); + } + printf("ML-KEM-768 MakeKey: ret=%d\r\n", kem_ret); + if (kem_ret == 0) { + kem_ret = wc_MlKemKey_Encapsulate(&kemk, kem_ct, kem_ss1, &kem_rng); + } + printf("ML-KEM-768 Encapsulate: ret=%d\r\n", kem_ret); + if (kem_ret == 0) { + kem_ret = wc_MlKemKey_Decapsulate(&kemk, kem_ss2, kem_ct, + (word32)sizeof(kem_ct)); + } + if (kem_ret == 0) { + kem_ok = (XMEMCMP(kem_ss1, kem_ss2, WC_ML_KEM_SS_SZ) == 0); + } + printf("ML-KEM-768 encap/decap round-trip: %s (ret=%d ss_match=%d)\r\n", + (kem_ret == 0 && kem_ok) ? "PASS" : "FAIL", kem_ret, kem_ok); + wc_MlKemKey_Free(&kemk); + wc_FreeRng(&kem_rng); + } +#endif /* WOLF_MLKEM */ + printf("SYSCLK %lu Hz, CHAR_BIT %d, sizeof(long)=%d sizeof(long long)=%d\r\n", (unsigned long)DEVICE_SYSCLK_FREQ, (int)CHAR_BIT, (int)sizeof(long), (int)sizeof(long long)); From d6ef0e9b8c3923ad0cf9df39d4c477f74221bfa6 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 19 Jun 2026 11:34:19 -0700 Subject: [PATCH 05/13] ti-c2000: ML-KEM deterministic dump harness for host-vs-device diff (WIP) --- embedded/ti-c2000-f28p55x/Source/wolf_main.c | 57 ++++++++++++++++---- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/embedded/ti-c2000-f28p55x/Source/wolf_main.c b/embedded/ti-c2000-f28p55x/Source/wolf_main.c index 636527a84..d10555be4 100644 --- a/embedded/ti-c2000-f28p55x/Source/wolf_main.c +++ b/embedded/ti-c2000-f28p55x/Source/wolf_main.c @@ -243,6 +243,27 @@ double current_time(int reset) return (double)accum / (double)DEVICE_SYSCLK_FREQ; } +#ifdef WOLF_MLKEM +/* Dump head bytes + ".." + tail bytes of a buffer as hex, matching the host + * reference dumper, to localize a CHAR_BIT==16 divergence. */ +static void kem_dump(const char* name, const byte* b, int len, int head, + int tail) +{ + int i; + printf("%s[%d]: ", name, len); + for (i = 0; i < head && i < len; i++) { + printf("%02x", (unsigned)(b[i] & 0xFF)); + } + if (len > head + tail) { + printf(".."); + for (i = len - tail; i < len; i++) { + printf("%02x", (unsigned)(b[i] & 0xFF)); + } + } + printf("\r\n"); +} +#endif /* WOLF_MLKEM */ + /* ------------------------------------------------------------------------- */ /* wolfSSL port hooks (referenced from user_settings.h) */ /* ------------------------------------------------------------------------- */ @@ -736,24 +757,43 @@ int main(void) printf("\r\n--- ML-KEM-768 ---\r\n"); { static MlKemKey kemk; + static byte kem_pk[WC_ML_KEM_768_PUBLIC_KEY_SIZE]; static byte kem_ct[WC_ML_KEM_768_CIPHER_TEXT_SIZE]; static byte kem_ss1[WC_ML_KEM_SS_SZ]; static byte kem_ss2[WC_ML_KEM_SS_SZ]; - WC_RNG kem_rng; - int kem_ret, kem_ok = 0; - - kem_ret = wc_InitRng(&kem_rng); - if (kem_ret == 0) { - kem_ret = wc_MlKemKey_Init(&kemk, WC_ML_KEM_768, NULL, INVALID_DEVID); + static byte kem_seed[64]; + static byte kem_coins[32]; + word32 kem_pklen = (word32)sizeof(kem_pk); + int kem_ret, kem_ok = 0, i; + + /* Deterministic seed/coins identical to the host reference dumper, so + * pk/ct/ss can be diffed byte-for-byte to localize a CHAR_BIT==16 bug. */ + for (i = 0; i < 64; i++) { + kem_seed[i] = (byte)i; + } + for (i = 0; i < 32; i++) { + kem_coins[i] = (byte)(0x40 + i); } + kem_ret = wc_MlKemKey_Init(&kemk, WC_ML_KEM_768, NULL, INVALID_DEVID); if (kem_ret == 0) { - kem_ret = wc_MlKemKey_MakeKey(&kemk, &kem_rng); + kem_ret = wc_MlKemKey_MakeKeyWithRandom(&kemk, kem_seed, 64); } printf("ML-KEM-768 MakeKey: ret=%d\r\n", kem_ret); if (kem_ret == 0) { - kem_ret = wc_MlKemKey_Encapsulate(&kemk, kem_ct, kem_ss1, &kem_rng); + kem_ret = wc_MlKemKey_EncodePublicKey(&kemk, kem_pk, kem_pklen); + } + if (kem_ret == 0) { + kem_dump("PK", kem_pk, (int)kem_pklen, 32, 16); + } + if (kem_ret == 0) { + kem_ret = wc_MlKemKey_EncapsulateWithRandom(&kemk, kem_ct, kem_ss1, + kem_coins, 32); } printf("ML-KEM-768 Encapsulate: ret=%d\r\n", kem_ret); + if (kem_ret == 0) { + kem_dump("CT", kem_ct, (int)sizeof(kem_ct), 32, 16); + kem_dump("SS", kem_ss1, (int)WC_ML_KEM_SS_SZ, 32, 0); + } if (kem_ret == 0) { kem_ret = wc_MlKemKey_Decapsulate(&kemk, kem_ss2, kem_ct, (word32)sizeof(kem_ct)); @@ -764,7 +804,6 @@ int main(void) printf("ML-KEM-768 encap/decap round-trip: %s (ret=%d ss_match=%d)\r\n", (kem_ret == 0 && kem_ok) ? "PASS" : "FAIL", kem_ret, kem_ok); wc_MlKemKey_Free(&kemk); - wc_FreeRng(&kem_rng); } #endif /* WOLF_MLKEM */ From b08a533f4215f3640a5ad0d1cd8e750606d967f3 Mon Sep 17 00:00:00 2001 From: David Garske Date: Sun, 21 Jun 2026 10:16:34 -0700 Subject: [PATCH 06/13] ti-c2000: ML-KEM-768 round-trip + deterministic dump (KAT-exact, PASS on C28x) --- embedded/ti-c2000-f28p55x/Source/wolf_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/embedded/ti-c2000-f28p55x/Source/wolf_main.c b/embedded/ti-c2000-f28p55x/Source/wolf_main.c index d10555be4..19c18541b 100644 --- a/embedded/ti-c2000-f28p55x/Source/wolf_main.c +++ b/embedded/ti-c2000-f28p55x/Source/wolf_main.c @@ -758,6 +758,7 @@ int main(void) { static MlKemKey kemk; static byte kem_pk[WC_ML_KEM_768_PUBLIC_KEY_SIZE]; + static byte kem_sk[WC_ML_KEM_768_PRIVATE_KEY_SIZE]; static byte kem_ct[WC_ML_KEM_768_CIPHER_TEXT_SIZE]; static byte kem_ss1[WC_ML_KEM_SS_SZ]; static byte kem_ss2[WC_ML_KEM_SS_SZ]; @@ -785,6 +786,13 @@ int main(void) if (kem_ret == 0) { kem_dump("PK", kem_pk, (int)kem_pklen, 32, 16); } + if (kem_ret == 0) { + word32 kem_sklen = (word32)sizeof(kem_sk); + kem_ret = wc_MlKemKey_EncodePrivateKey(&kemk, kem_sk, kem_sklen); + if (kem_ret == 0) { + kem_dump("SK", kem_sk, (int)sizeof(kem_sk), 32, 16); + } + } if (kem_ret == 0) { kem_ret = wc_MlKemKey_EncapsulateWithRandom(&kemk, kem_ct, kem_ss1, kem_coins, 32); From df98d3110bc33b10fd142718d3664a2aad03beea Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 22 Jun 2026 08:37:32 -0700 Subject: [PATCH 07/13] ti-c2000: add AES-CBC/CTR/CFB/GCM KAT (AES=1) to F28P55X example --- .../ti-c2000-f28p55x/Header/user_settings.h | 28 ++++++- embedded/ti-c2000-f28p55x/Makefile | 8 ++ embedded/ti-c2000-f28p55x/Source/wolf_main.c | 83 +++++++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) diff --git a/embedded/ti-c2000-f28p55x/Header/user_settings.h b/embedded/ti-c2000-f28p55x/Header/user_settings.h index fcd0095da..3d62e783e 100644 --- a/embedded/ti-c2000-f28p55x/Header/user_settings.h +++ b/embedded/ti-c2000-f28p55x/Header/user_settings.h @@ -296,8 +296,34 @@ extern "C" { /* ------------------------------------------------------------------------- */ /* Disabled: unused symmetric / legacy (shrink the first build) */ /* ------------------------------------------------------------------------- */ -#undef NO_AES /* AES accelerator support is a later phase */ +#ifdef WOLF_AES +/* AES software (table-driven) with CBC, CTR, CFB and GCM. GCM_SMALL selects + * the byte-wise GHASH (cleanest on a 16-bit-byte target; no word64 needed). */ +#undef NO_AES +#undef HAVE_AES_CBC +#define HAVE_AES_CBC +#undef HAVE_AES_DECRYPT +#define HAVE_AES_DECRYPT +#undef WOLFSSL_AES_COUNTER +#define WOLFSSL_AES_COUNTER +#undef WOLFSSL_AES_CFB +#define WOLFSSL_AES_CFB +#undef HAVE_AESGCM +#define HAVE_AESGCM +#undef GCM_SMALL +#define GCM_SMALL +#undef WOLFSSL_AES_DIRECT +#define WOLFSSL_AES_DIRECT +#undef WOLFSSL_AES_128 +#define WOLFSSL_AES_128 +#undef WOLFSSL_AES_192 +#define WOLFSSL_AES_192 +#undef WOLFSSL_AES_256 +#define WOLFSSL_AES_256 +#else +#undef NO_AES /* AES enabled only with AES=1 */ #define NO_AES +#endif #undef NO_DES3 #define NO_DES3 #undef NO_RC4 diff --git a/embedded/ti-c2000-f28p55x/Makefile b/embedded/ti-c2000-f28p55x/Makefile index b4031dc60..bc21a1a6b 100644 --- a/embedded/ti-c2000-f28p55x/Makefile +++ b/embedded/ti-c2000-f28p55x/Makefile @@ -97,6 +97,14 @@ ifeq ($(MLKEM),1) $(WOLFROOT)/wolfcrypt/src/wc_mlkem_poly.c endif +# AES=1 adds AES-CBC/CTR/CFB/GCM (software, table-driven; GCM_SMALL GHASH). +AES ?= 0 +ifeq ($(AES),1) + CFLAGS += --define=WOLF_AES + WC_SRCS += \ + $(WOLFROOT)/wolfcrypt/src/aes.c +endif + HARNESS_SRCS := \ $(WOLFROOT)/wolfcrypt/test/test.c \ $(WOLFROOT)/wolfcrypt/benchmark/benchmark.c diff --git a/embedded/ti-c2000-f28p55x/Source/wolf_main.c b/embedded/ti-c2000-f28p55x/Source/wolf_main.c index 19c18541b..3f26854eb 100644 --- a/embedded/ti-c2000-f28p55x/Source/wolf_main.c +++ b/embedded/ti-c2000-f28p55x/Source/wolf_main.c @@ -49,6 +49,9 @@ #ifdef WOLF_MLKEM #include #endif +#ifdef WOLF_AES +#include +#endif #ifdef WOLF_ECC #include #include @@ -815,6 +818,86 @@ int main(void) } #endif /* WOLF_MLKEM */ +#ifdef WOLF_AES + printf("\r\n--- AES (CBC/CTR/CFB/GCM) ---\r\n"); + { + /* AES-128 NIST SP800-38A vectors (CBC/CTR/CFB) + McGrew GCM case 2. */ + static const byte k[16] = { + 0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6, + 0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c}; + static const byte iv[16] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; + static const byte pt[16] = { + 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96, + 0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a}; + static const byte cbc_ct[16] = { + 0x76,0x49,0xab,0xac,0x81,0x19,0xb2,0x46, + 0xce,0xe9,0x8e,0x9b,0x12,0xe9,0x19,0x7d}; + static const byte ctr_iv[16] = { + 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, + 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff}; + static const byte ctr_ct[16] = { + 0x87,0x4d,0x61,0x91,0xb6,0x20,0xe3,0x26, + 0x1b,0xef,0x68,0x64,0x99,0x0d,0xb6,0xce}; + static const byte cfb_ct[16] = { + 0x3b,0x3f,0xd9,0x2e,0xb7,0x2d,0xad,0x20, + 0x33,0x34,0x49,0xf8,0xe8,0x3c,0xfb,0x4a}; + static const byte gk[16] = {0}; + static const byte giv[12] = {0}; + static const byte gpt[16] = {0}; + static const byte gct[16] = { + 0x03,0x88,0xda,0xce,0x60,0xb6,0xa3,0x92, + 0xf3,0x28,0xc2,0xb9,0x71,0xb2,0xfe,0x78}; + static const byte gtag[16] = { + 0xab,0x6e,0x47,0xd4,0x2c,0xec,0x13,0xbd, + 0xf5,0x3a,0x67,0xb2,0x12,0x57,0xbd,0xdf}; + static Aes aes; + static byte o[16], o2[16], tag[16]; + int r; + + /* CBC */ + r = wc_AesSetKey(&aes, k, 16, iv, AES_ENCRYPTION); + if (r == 0) r = wc_AesCbcEncrypt(&aes, o, pt, 16); + printf("AES-128-CBC encrypt: %s\r\n", + (r == 0 && XMEMCMP(o, cbc_ct, 16) == 0) ? "PASS" : "FAIL"); + r = wc_AesSetKey(&aes, k, 16, iv, AES_DECRYPTION); + if (r == 0) r = wc_AesCbcDecrypt(&aes, o2, cbc_ct, 16); + printf("AES-128-CBC decrypt: %s\r\n", + (r == 0 && XMEMCMP(o2, pt, 16) == 0) ? "PASS" : "FAIL"); + + /* CTR (encrypt == decrypt) */ + r = wc_AesSetKey(&aes, k, 16, ctr_iv, AES_ENCRYPTION); + if (r == 0) r = wc_AesCtrEncrypt(&aes, o, pt, 16); + printf("AES-128-CTR: %s\r\n", + (r == 0 && XMEMCMP(o, ctr_ct, 16) == 0) ? "PASS" : "FAIL"); + + /* CFB128 */ + r = wc_AesSetKey(&aes, k, 16, iv, AES_ENCRYPTION); + if (r == 0) r = wc_AesCfbEncrypt(&aes, o, pt, 16); + printf("AES-128-CFB encrypt: %s\r\n", + (r == 0 && XMEMCMP(o, cfb_ct, 16) == 0) ? "PASS" : "FAIL"); + r = wc_AesSetKey(&aes, k, 16, iv, AES_ENCRYPTION); + if (r == 0) r = wc_AesCfbDecrypt(&aes, o2, cfb_ct, 16); + printf("AES-128-CFB decrypt: %s\r\n", + (r == 0 && XMEMCMP(o2, pt, 16) == 0) ? "PASS" : "FAIL"); + + /* GCM */ + r = wc_AesGcmSetKey(&aes, gk, 16); + if (r == 0) r = wc_AesGcmEncrypt(&aes, o, gpt, 16, giv, 12, + tag, 16, NULL, 0); + printf("AES-128-GCM encrypt: %s (ct=%d tag=%d)\r\n", + (r == 0 && XMEMCMP(o, gct, 16) == 0 && + XMEMCMP(tag, gtag, 16) == 0) ? "PASS" : "FAIL", + (r == 0) ? (XMEMCMP(o, gct, 16) == 0) : -1, + (r == 0) ? (XMEMCMP(tag, gtag, 16) == 0) : -1); + r = wc_AesGcmDecrypt(&aes, o2, gct, 16, giv, 12, gtag, 16, NULL, 0); + printf("AES-128-GCM decrypt+verify: %s\r\n", + (r == 0 && XMEMCMP(o2, gpt, 16) == 0) ? "PASS" : "FAIL"); + wc_AesFree(&aes); + } +#endif /* WOLF_AES */ + printf("SYSCLK %lu Hz, CHAR_BIT %d, sizeof(long)=%d sizeof(long long)=%d\r\n", (unsigned long)DEVICE_SYSCLK_FREQ, (int)CHAR_BIT, (int)sizeof(long), (int)sizeof(long long)); From 3ec06d18cf30f907f5151cfb030c1a3f4f49dda3 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 22 Jun 2026 09:55:38 -0700 Subject: [PATCH 08/13] ti-c2000: add X25519 + Ed25519 KAT (X25519=1) to F28P55X example --- .../ti-c2000-f28p55x/Header/user_settings.h | 20 ++++ embedded/ti-c2000-f28p55x/Makefile | 11 +++ embedded/ti-c2000-f28p55x/Source/wolf_main.c | 94 +++++++++++++++++++ 3 files changed, 125 insertions(+) diff --git a/embedded/ti-c2000-f28p55x/Header/user_settings.h b/embedded/ti-c2000-f28p55x/Header/user_settings.h index 3d62e783e..3b3580099 100644 --- a/embedded/ti-c2000-f28p55x/Header/user_settings.h +++ b/embedded/ti-c2000-f28p55x/Header/user_settings.h @@ -324,6 +324,26 @@ extern "C" { #undef NO_AES /* AES enabled only with AES=1 */ #define NO_AES #endif + +/* Curve25519 (X25519) + Ed25519. Enabled with EXTRA_CFLAGS=--define=WOLF_25519 + * (X25519=1 build). No __uint128_t and no SP-25519 backend on C28x, so the + * default fe[10] 32-bit-limb field arithmetic is used; Ed25519 reuses the + * already-enabled SHA-512. */ +#ifdef WOLF_25519 +#undef HAVE_CURVE25519 +#define HAVE_CURVE25519 +#undef HAVE_CURVE25519_KEY_IMPORT +#define HAVE_CURVE25519_KEY_IMPORT +#undef HAVE_CURVE25519_KEY_EXPORT +#define HAVE_CURVE25519_KEY_EXPORT +#undef HAVE_ED25519 +#define HAVE_ED25519 +#undef HAVE_ED25519_KEY_IMPORT +#define HAVE_ED25519_KEY_IMPORT +#undef HAVE_ED25519_KEY_EXPORT +#define HAVE_ED25519_KEY_EXPORT +#endif + #undef NO_DES3 #define NO_DES3 #undef NO_RC4 diff --git a/embedded/ti-c2000-f28p55x/Makefile b/embedded/ti-c2000-f28p55x/Makefile index bc21a1a6b..ba79bfb31 100644 --- a/embedded/ti-c2000-f28p55x/Makefile +++ b/embedded/ti-c2000-f28p55x/Makefile @@ -105,6 +105,17 @@ ifeq ($(AES),1) $(WOLFROOT)/wolfcrypt/src/aes.c endif +# X25519=1 adds Curve25519 (X25519) + Ed25519 (default fe[10] 32-bit backend). +X25519 ?= 0 +ifeq ($(X25519),1) + CFLAGS += --define=WOLF_25519 + WC_SRCS += \ + $(WOLFROOT)/wolfcrypt/src/curve25519.c \ + $(WOLFROOT)/wolfcrypt/src/ed25519.c \ + $(WOLFROOT)/wolfcrypt/src/fe_operations.c \ + $(WOLFROOT)/wolfcrypt/src/ge_operations.c +endif + HARNESS_SRCS := \ $(WOLFROOT)/wolfcrypt/test/test.c \ $(WOLFROOT)/wolfcrypt/benchmark/benchmark.c diff --git a/embedded/ti-c2000-f28p55x/Source/wolf_main.c b/embedded/ti-c2000-f28p55x/Source/wolf_main.c index 3f26854eb..2fe9da75d 100644 --- a/embedded/ti-c2000-f28p55x/Source/wolf_main.c +++ b/embedded/ti-c2000-f28p55x/Source/wolf_main.c @@ -52,6 +52,11 @@ #ifdef WOLF_AES #include #endif +#ifdef WOLF_25519 +#include +#include +#include +#endif #ifdef WOLF_ECC #include #include @@ -898,6 +903,95 @@ int main(void) } #endif /* WOLF_AES */ +#ifdef WOLF_25519 + printf("\r\n--- Curve25519 (X25519) + Ed25519 ---\r\n"); + { + /* X25519 RFC 7748 6.1 Diffie-Hellman test vectors (little-endian). */ + static const byte a_priv[32] = { + 0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d,0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45, + 0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a,0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a}; + static const byte a_pub[32] = { + 0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54,0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a, + 0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4,0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a}; + static const byte b_priv[32] = { + 0x5d,0xab,0x08,0x7e,0x62,0x4a,0x8a,0x4b,0x79,0xe1,0x7f,0x8b,0x83,0x80,0x0e,0xe6, + 0x6f,0x3b,0xb1,0x29,0x26,0x18,0xb6,0xfd,0x1c,0x2f,0x8b,0x27,0xff,0x88,0xe0,0xeb}; + static const byte b_pub[32] = { + 0xde,0x9e,0xdb,0x7d,0x7b,0x7d,0xc1,0xb4,0xd3,0x5b,0x61,0xc2,0xec,0xe4,0x35,0x37, + 0x3f,0x83,0x43,0xc8,0x5b,0x78,0x67,0x4d,0xad,0xfc,0x7e,0x14,0x6f,0x88,0x2b,0x4f}; + static const byte x_K[32] = { + 0x4a,0x5d,0x9d,0x5b,0xa4,0xce,0x2d,0xe1,0x72,0x8e,0x3b,0xf4,0x80,0x35,0x0f,0x25, + 0xe0,0x7e,0x21,0xc9,0x47,0xd1,0x9e,0x33,0x76,0xf0,0x9b,0x3c,0x1e,0x16,0x17,0x42}; + /* Ed25519 RFC 8032 Test 1 (empty message). */ + static const byte ed_sk[32] = { + 0x9d,0x61,0xb1,0x9d,0xef,0xfd,0x5a,0x60,0xba,0x84,0x4a,0xf4,0x92,0xec,0x2c,0xc4, + 0x44,0x49,0xc5,0x69,0x7b,0x32,0x69,0x19,0x70,0x3b,0xac,0x03,0x1c,0xae,0x7f,0x60}; + static const byte ed_pk[32] = { + 0xd7,0x5a,0x98,0x01,0x82,0xb1,0x0a,0xb7,0xd5,0x4b,0xfe,0xd3,0xc9,0x64,0x07,0x3a, + 0x0e,0xe1,0x72,0xf3,0xda,0xa6,0x23,0x25,0xaf,0x02,0x1a,0x68,0xf7,0x07,0x51,0x1a}; + static const byte ed_sig[64] = { + 0xe5,0x56,0x43,0x00,0xc3,0x60,0xac,0x72,0x90,0x86,0xe2,0xcc,0x80,0x6e,0x82,0x8a, + 0x84,0x87,0x7f,0x1e,0xb8,0xe5,0xd9,0x74,0xd8,0x73,0xe0,0x65,0x22,0x49,0x01,0x55, + 0x5f,0xb8,0x82,0x15,0x90,0xa3,0x3b,0xac,0xc6,0x1e,0x39,0x70,0x1c,0xf9,0xb4,0x6b, + 0xd2,0x5b,0xf5,0xf0,0x59,0x5b,0xbe,0x24,0x65,0x51,0x41,0x43,0x8e,0x7a,0x10,0x0b}; + static curve25519_key ca, cpa, cb, cpb; + static ed25519_key ed; + static WC_RNG rng; + byte sh[32], sig[64], ap[32], bp[32]; + word32 shLen = sizeof(sh), sigLen = sizeof(sig); + int r, vres = 0, ci; + + /* X25519: shared = X25519(a_priv, b_pub) == X25519(b_priv, a_pub) == K. + * wolfSSL requires the scalar to be pre-clamped (RFC 7748 sec 5); the + * raw RFC 6.1 keys are not, so clamp a local copy (X25519 clamps the + * same bits internally, so the shared secret still equals K). The + * default C build enables WOLFSSL_CURVE25519_BLINDING, so each private + * key needs an RNG set (the result is unaffected). */ + if (wc_InitRng(&rng) != 0) + printf("X25519: RNG init FAIL\r\n"); + for (ci = 0; ci < 32; ci++) { ap[ci] = a_priv[ci]; bp[ci] = b_priv[ci]; } + ap[0] &= 248; ap[31] &= 127; ap[31] |= 64; + bp[0] &= 248; bp[31] &= 127; bp[31] |= 64; + wc_curve25519_init(&ca); wc_curve25519_init(&cpb); + r = wc_curve25519_import_private_ex(ap, 32, &ca, EC25519_LITTLE_ENDIAN); + if (r == 0) r = wc_curve25519_set_rng(&ca, &rng); + if (r == 0) r = wc_curve25519_import_public_ex(b_pub, 32, &cpb, + EC25519_LITTLE_ENDIAN); + if (r == 0) r = wc_curve25519_shared_secret_ex(&ca, &cpb, sh, &shLen, + EC25519_LITTLE_ENDIAN); + printf("X25519 a*Bpub: %s\r\n", + (r == 0 && shLen == 32 && XMEMCMP(sh, x_K, 32) == 0) ? "PASS":"FAIL"); + + wc_curve25519_init(&cb); wc_curve25519_init(&cpa); + shLen = sizeof(sh); + r = wc_curve25519_import_private_ex(bp, 32, &cb, EC25519_LITTLE_ENDIAN); + if (r == 0) r = wc_curve25519_set_rng(&cb, &rng); + if (r == 0) r = wc_curve25519_import_public_ex(a_pub, 32, &cpa, + EC25519_LITTLE_ENDIAN); + if (r == 0) r = wc_curve25519_shared_secret_ex(&cb, &cpa, sh, &shLen, + EC25519_LITTLE_ENDIAN); + printf("X25519 b*Apub: %s\r\n", + (r == 0 && shLen == 32 && XMEMCMP(sh, x_K, 32) == 0) ? "PASS":"FAIL"); + wc_curve25519_free(&ca); wc_curve25519_free(&cpb); + wc_curve25519_free(&cb); wc_curve25519_free(&cpa); + wc_FreeRng(&rng); + + /* Ed25519 RFC 8032 Test 1 (empty message): import (re-derives and + * validates the public key on import), sign, compare to the RFC sig, + * then verify. inLen 0 still needs a non-NULL message pointer. */ + wc_ed25519_init(&ed); + r = wc_ed25519_import_private_key(ed_sk, 32, ed_pk, 32, &ed); + if (r == 0) r = wc_ed25519_sign_msg(ap, 0, sig, &sigLen, &ed); + printf("Ed25519 sign: %s\r\n", + (r == 0 && sigLen == 64 && XMEMCMP(sig, ed_sig, 64) == 0) ? + "PASS":"FAIL"); + r = wc_ed25519_verify_msg(ed_sig, 64, ap, 0, &vres, &ed); + printf("Ed25519 verify: %s\r\n", + (r == 0 && vres == 1) ? "PASS":"FAIL"); + wc_ed25519_free(&ed); + } +#endif /* WOLF_25519 */ + printf("SYSCLK %lu Hz, CHAR_BIT %d, sizeof(long)=%d sizeof(long long)=%d\r\n", (unsigned long)DEVICE_SYSCLK_FREQ, (int)CHAR_BIT, (int)sizeof(long), (int)sizeof(long long)); From d76f626801e4ba51a3ddc25eb015cc1aa0d6ef9e Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 22 Jun 2026 12:57:10 -0700 Subject: [PATCH 09/13] ti-c2000: reset JTAG log buffer before benchmark_test so the full benchmark fits the capture window --- embedded/ti-c2000-f28p55x/Source/wolf_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/embedded/ti-c2000-f28p55x/Source/wolf_main.c b/embedded/ti-c2000-f28p55x/Source/wolf_main.c index 2fe9da75d..8a30b8e77 100644 --- a/embedded/ti-c2000-f28p55x/Source/wolf_main.c +++ b/embedded/ti-c2000-f28p55x/Source/wolf_main.c @@ -1003,6 +1003,7 @@ int main(void) #endif #ifndef NO_CRYPT_BENCHMARK + g_logpos = 0; /* reset capture so the full benchmark fits the JTAG log */ printf("\r\n--- benchmark_test ---\r\n"); bench_ret = benchmark_test(NULL); printf("benchmark_test result: %d\r\n", bench_ret); From 8bc8482b3b916e55a21647ccec2258c7f700cb74 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 22 Jun 2026 18:59:43 -0700 Subject: [PATCH 10/13] ti-c2000: add HMAC-SHA256 + HKDF-SHA256 KAT (HKDF=1); Makefile toggles for upcoming CHACHA/AESEXTRA/RSA --- .../ti-c2000-f28p55x/Header/user_settings.h | 8 +++ embedded/ti-c2000-f28p55x/Makefile | 40 +++++++++++++ embedded/ti-c2000-f28p55x/Source/wolf_main.c | 59 +++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/embedded/ti-c2000-f28p55x/Header/user_settings.h b/embedded/ti-c2000-f28p55x/Header/user_settings.h index 3b3580099..e74bc2981 100644 --- a/embedded/ti-c2000-f28p55x/Header/user_settings.h +++ b/embedded/ti-c2000-f28p55x/Header/user_settings.h @@ -354,8 +354,16 @@ extern "C" { #define NO_MD5 #undef NO_SHA /* SHA-1 not in scope */ #define NO_SHA +/* HMAC + HKDF (RFC 2104 / RFC 5869) on top of the SHA-2/SHA-3 hashes. + * Enabled with EXTRA_CFLAGS=--define=WOLF_HKDF (HKDF=1 build). */ +#ifdef WOLF_HKDF +#undef NO_HMAC +#undef HAVE_HKDF +#define HAVE_HKDF +#else #undef NO_HMAC /* relax if the harness needs it */ #define NO_HMAC +#endif /* ------------------------------------------------------------------------- */ /* Memory */ diff --git a/embedded/ti-c2000-f28p55x/Makefile b/embedded/ti-c2000-f28p55x/Makefile index ba79bfb31..3016c6ff3 100644 --- a/embedded/ti-c2000-f28p55x/Makefile +++ b/embedded/ti-c2000-f28p55x/Makefile @@ -116,6 +116,46 @@ ifeq ($(X25519),1) $(WOLFROOT)/wolfcrypt/src/ge_operations.c endif +# HKDF=1 adds HMAC + HKDF (RFC 2104 / RFC 5869) on top of the SHA-2/3 hashes. +HKDF ?= 0 +ifeq ($(HKDF),1) + CFLAGS += --define=WOLF_HKDF + WC_SRCS += \ + $(WOLFROOT)/wolfcrypt/src/hmac.c \ + $(WOLFROOT)/wolfcrypt/src/kdf.c +endif + +# CHACHA=1 adds ChaCha20-Poly1305 AEAD (RFC 8439). +CHACHA ?= 0 +ifeq ($(CHACHA),1) + CFLAGS += --define=WOLF_CHACHA + WC_SRCS += \ + $(WOLFROOT)/wolfcrypt/src/chacha.c \ + $(WOLFROOT)/wolfcrypt/src/poly1305.c \ + $(WOLFROOT)/wolfcrypt/src/chacha20_poly1305.c +endif + +# AESEXTRA=1 adds AES-CCM, CMAC and GMAC on top of the AES core. +AESEXTRA ?= 0 +ifeq ($(AESEXTRA),1) + CFLAGS += --define=WOLF_AES --define=WOLF_AESEXTRA + WC_SRCS += \ + $(WOLFROOT)/wolfcrypt/src/aes.c \ + $(WOLFROOT)/wolfcrypt/src/cmac.c +endif + +# RSA=1 adds RSA verify (SP math backend, shared with the ECC P-256 build). +RSA ?= 0 +ifeq ($(RSA),1) + CFLAGS += --define=WOLF_RSA + WC_SRCS += \ + $(WOLFROOT)/wolfcrypt/src/rsa.c \ + $(WOLFROOT)/wolfcrypt/src/asn.c \ + $(WOLFROOT)/wolfcrypt/src/wolfmath.c \ + $(WOLFROOT)/wolfcrypt/src/sp_int.c \ + $(WOLFROOT)/wolfcrypt/src/sp_c32.c +endif + HARNESS_SRCS := \ $(WOLFROOT)/wolfcrypt/test/test.c \ $(WOLFROOT)/wolfcrypt/benchmark/benchmark.c diff --git a/embedded/ti-c2000-f28p55x/Source/wolf_main.c b/embedded/ti-c2000-f28p55x/Source/wolf_main.c index 8a30b8e77..c75565e18 100644 --- a/embedded/ti-c2000-f28p55x/Source/wolf_main.c +++ b/embedded/ti-c2000-f28p55x/Source/wolf_main.c @@ -57,6 +57,22 @@ #include #include #endif +#ifdef WOLF_HKDF +#include +#include +#endif +#ifdef WOLF_CHACHA +#include +#endif +#ifdef WOLF_AESEXTRA +#include +#include +#endif +#ifdef WOLF_RSA +#include +#include +#include +#endif #ifdef WOLF_ECC #include #include @@ -992,6 +1008,49 @@ int main(void) } #endif /* WOLF_25519 */ +#ifdef WOLF_HKDF + printf("\r\n--- HMAC-SHA256 + HKDF-SHA256 ---\r\n"); + { + /* HMAC-SHA256: RFC 4231 test case 2. */ + static const byte hk[4] = {0x4a,0x65,0x66,0x65}; /* "Jefe" */ + static const byte hd[28] = { + 0x77,0x68,0x61,0x74,0x20,0x64,0x6f,0x20,0x79,0x61,0x20,0x77,0x61,0x6e, + 0x74,0x20,0x66,0x6f,0x72,0x20,0x6e,0x6f,0x74,0x68,0x69,0x6e,0x67,0x3f}; + static const byte hmac_exp[32] = { + 0x5b,0xdc,0xc1,0x46,0xbf,0x60,0x75,0x4e,0x6a,0x04,0x24,0x26,0x08,0x95, + 0x75,0xc7,0x5a,0x00,0x3f,0x08,0x9d,0x27,0x39,0x83,0x9d,0xec,0x58,0xb9, + 0x64,0xec,0x38,0x43}; + /* HKDF-SHA256: RFC 5869 test case 1. */ + static const byte ikm[22] = { + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b, + 0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b}; + static const byte salt[13] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c}; + static const byte info[10] = { + 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9}; + static const byte okm_exp[42] = { + 0x3c,0xb2,0x5f,0x25,0xfa,0xac,0xd5,0x7a,0x90,0x43,0x4f,0x64,0xd0,0x36, + 0x2f,0x2a,0x2d,0x2d,0x0a,0x90,0xcf,0x1a,0x5a,0x4c,0x5d,0xb0,0x2d,0x56, + 0xec,0xc4,0xc5,0xbf,0x34,0x00,0x72,0x08,0xd5,0xb8,0x87,0x18,0x58,0x65}; + Hmac hmac; + byte mac[32], okm[42]; + int r; + + r = wc_HmacInit(&hmac, NULL, INVALID_DEVID); + if (r == 0) r = wc_HmacSetKey(&hmac, WC_SHA256, hk, sizeof(hk)); + if (r == 0) r = wc_HmacUpdate(&hmac, hd, sizeof(hd)); + if (r == 0) r = wc_HmacFinal(&hmac, mac); + printf("HMAC-SHA256: %s\r\n", + (r == 0 && XMEMCMP(mac, hmac_exp, 32) == 0) ? "PASS":"FAIL"); + wc_HmacFree(&hmac); + + r = wc_HKDF(WC_SHA256, ikm, sizeof(ikm), salt, sizeof(salt), + info, sizeof(info), okm, sizeof(okm)); + printf("HKDF-SHA256: %s\r\n", + (r == 0 && XMEMCMP(okm, okm_exp, 42) == 0) ? "PASS":"FAIL"); + } +#endif /* WOLF_HKDF */ + printf("SYSCLK %lu Hz, CHAR_BIT %d, sizeof(long)=%d sizeof(long long)=%d\r\n", (unsigned long)DEVICE_SYSCLK_FREQ, (int)CHAR_BIT, (int)sizeof(long), (int)sizeof(long long)); From 23375fe08b67cd88e41217078f6e1efd0ba30be1 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 22 Jun 2026 20:04:44 -0700 Subject: [PATCH 11/13] ti-c2000: add ChaCha20-Poly1305 + standalone Poly1305 KAT (CHACHA=1); stage AESEXTRA/RSA user_settings --- .../ti-c2000-f28p55x/Header/user_settings.h | 46 +++++++++++++++ embedded/ti-c2000-f28p55x/Source/wolf_main.c | 58 +++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/embedded/ti-c2000-f28p55x/Header/user_settings.h b/embedded/ti-c2000-f28p55x/Header/user_settings.h index e74bc2981..ec4aed592 100644 --- a/embedded/ti-c2000-f28p55x/Header/user_settings.h +++ b/embedded/ti-c2000-f28p55x/Header/user_settings.h @@ -365,6 +365,52 @@ extern "C" { #define NO_HMAC #endif +/* ChaCha20-Poly1305 AEAD (RFC 8439). Enabled with --define=WOLF_CHACHA. */ +#ifdef WOLF_CHACHA +#undef HAVE_CHACHA +#define HAVE_CHACHA +#undef HAVE_POLY1305 +#define HAVE_POLY1305 +#endif + +/* AES-CCM / CMAC / GMAC on top of the AES core (--define=WOLF_AESEXTRA). */ +#ifdef WOLF_AESEXTRA +#undef HAVE_AESCCM +#define HAVE_AESCCM +#undef WOLFSSL_CMAC +#define WOLFSSL_CMAC +#undef HAVE_AESGCM /* GMAC is GCM with no plaintext */ +#define HAVE_AESGCM +#undef GCM_SMALL +#define GCM_SMALL +#endif + +/* RSA verify via the SP math backend (--define=WOLF_RSA). */ +#ifdef WOLF_RSA +#undef NO_RSA +#undef WOLFSSL_SP_MATH +#define WOLFSSL_SP_MATH +#undef WOLFSSL_SP_MATH_ALL +#undef WOLFSSL_HAVE_SP_RSA +#define WOLFSSL_HAVE_SP_RSA +#undef WOLFSSL_SP_NO_2048 +#undef WOLFSSL_SP_NO_3072 +#undef WOLFSSL_SP_4096 +#define WOLFSSL_SP_4096 +#undef WOLFSSL_SP_ALLOW_16BIT_CPU +#define WOLFSSL_SP_ALLOW_16BIT_CPU +#undef WOLFSSL_SP_NO_MALLOC +#define WOLFSSL_SP_NO_MALLOC +#undef WC_RSA_BLINDING /* verify only; no blinding RNG needed */ +#undef WOLFSSL_RSA_VERIFY_ONLY +#define WOLFSSL_RSA_VERIFY_ONLY +#undef WOLFSSL_RSA_PUBLIC_ONLY +#define WOLFSSL_RSA_PUBLIC_ONLY +#else +#undef NO_RSA +#define NO_RSA +#endif + /* ------------------------------------------------------------------------- */ /* Memory */ /* ------------------------------------------------------------------------- */ diff --git a/embedded/ti-c2000-f28p55x/Source/wolf_main.c b/embedded/ti-c2000-f28p55x/Source/wolf_main.c index c75565e18..67f1ed3d7 100644 --- a/embedded/ti-c2000-f28p55x/Source/wolf_main.c +++ b/embedded/ti-c2000-f28p55x/Source/wolf_main.c @@ -1051,6 +1051,64 @@ int main(void) } #endif /* WOLF_HKDF */ +#ifdef WOLF_CHACHA + printf("\r\n--- ChaCha20-Poly1305 AEAD (RFC 8439) ---\r\n"); + { + /* Standalone Poly1305 (RFC 8439 sec 2.5.2) to isolate MAC vs AEAD. */ + static const byte pk[32] = { + 0x85,0xd6,0xbe,0x78,0x57,0x55,0x6d,0x33,0x7f,0x44,0x52,0xfe,0x42,0xd5,0x06,0xa8, + 0x01,0x03,0x80,0x8a,0xfb,0x0d,0xb2,0xfd,0x4a,0xbf,0xf6,0xaf,0x41,0x49,0xf5,0x1b}; + static const byte pm[34] = { + 0x43,0x72,0x79,0x70,0x74,0x6f,0x67,0x72,0x61,0x70,0x68,0x69,0x63,0x20,0x46,0x6f, + 0x72,0x75,0x6d,0x20,0x52,0x65,0x73,0x65,0x61,0x72,0x63,0x68,0x20,0x47,0x72,0x6f, + 0x75,0x70}; + static const byte ptag_exp[16] = { + 0xa8,0x06,0x1d,0xc1,0x30,0x51,0x36,0xc6,0xc2,0x2b,0x8b,0xaf,0x0c,0x01,0x27,0xa9}; + Poly1305 poly; + byte ptag[16]; + int pr; + pr = wc_Poly1305SetKey(&poly, pk, sizeof(pk)); + if (pr == 0) pr = wc_Poly1305Update(&poly, pm, sizeof(pm)); + if (pr == 0) pr = wc_Poly1305Final(&poly, ptag); + printf("Poly1305 (standalone): %s (t=%02x%02x%02x%02x exp=a8061dc1)\r\n", + (pr == 0 && XMEMCMP(ptag, ptag_exp, 16) == 0) ? "PASS":"FAIL", + ptag[0]&0xFF, ptag[1]&0xFF, ptag[2]&0xFF, ptag[3]&0xFF); + } + { + static const byte key[32] = { + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f}; + static const byte iv[12] = { + 0x07,0x00,0x00,0x00,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47}; + static const byte aad[12] = { + 0x50,0x51,0x52,0x53,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7}; + static const byte pt[114] = { + 0x4c,0x61,0x64,0x69,0x65,0x73,0x20,0x61,0x6e,0x64,0x20,0x47,0x65,0x6e,0x74,0x6c, + 0x65,0x6d,0x65,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x63,0x6c,0x61,0x73, + 0x73,0x20,0x6f,0x66,0x20,0x27,0x39,0x39,0x3a,0x20,0x49,0x66,0x20,0x49,0x20,0x63, + 0x6f,0x75,0x6c,0x64,0x20,0x6f,0x66,0x66,0x65,0x72,0x20,0x79,0x6f,0x75,0x20,0x6f, + 0x6e,0x6c,0x79,0x20,0x6f,0x6e,0x65,0x20,0x74,0x69,0x70,0x20,0x66,0x6f,0x72,0x20, + 0x74,0x68,0x65,0x20,0x66,0x75,0x74,0x75,0x72,0x65,0x2c,0x20,0x73,0x75,0x6e,0x73, + 0x63,0x72,0x65,0x65,0x6e,0x20,0x77,0x6f,0x75,0x6c,0x64,0x20,0x62,0x65,0x20,0x69, + 0x74,0x2e}; + static const byte ct0[4] = {0xd3,0x1a,0x8d,0x34}; /* RFC ciphertext head */ + static const byte tag_exp[16] = { + 0x1a,0xe1,0x0b,0x59,0x4f,0x09,0xe2,0x6a,0x7e,0x90,0x2e,0xcb,0xd0,0x60,0x06,0x91}; + static byte ct[114], tag[16], dec[114]; + int r; + + r = wc_ChaCha20Poly1305_Encrypt(key, iv, aad, sizeof(aad), + pt, sizeof(pt), ct, tag); + printf("ChaCha20-Poly1305 encrypt: %s\r\n", + (r == 0 && XMEMCMP(ct, ct0, 4) == 0 && + XMEMCMP(tag, tag_exp, 16) == 0) ? "PASS":"FAIL"); + r = wc_ChaCha20Poly1305_Decrypt(key, iv, aad, sizeof(aad), + ct, sizeof(ct), tag, dec); + printf("ChaCha20-Poly1305 decrypt+verify: %s\r\n", + (r == 0 && XMEMCMP(dec, pt, sizeof(pt)) == 0) ? "PASS":"FAIL"); + } +#endif /* WOLF_CHACHA */ + printf("SYSCLK %lu Hz, CHAR_BIT %d, sizeof(long)=%d sizeof(long long)=%d\r\n", (unsigned long)DEVICE_SYSCLK_FREQ, (int)CHAR_BIT, (int)sizeof(long), (int)sizeof(long long)); From 7cfe6e8410a26afba0bf7ab8740995449f4a0c2a Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 22 Jun 2026 21:10:28 -0700 Subject: [PATCH 12/13] ti-c2000: add AES-CMAC/CCM/GMAC KAT (AESEXTRA=1); compiles clean, on-HW KAT pending probe replug --- embedded/ti-c2000-f28p55x/Source/wolf_main.c | 77 ++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/embedded/ti-c2000-f28p55x/Source/wolf_main.c b/embedded/ti-c2000-f28p55x/Source/wolf_main.c index 67f1ed3d7..b0d5ec668 100644 --- a/embedded/ti-c2000-f28p55x/Source/wolf_main.c +++ b/embedded/ti-c2000-f28p55x/Source/wolf_main.c @@ -1109,6 +1109,83 @@ int main(void) } #endif /* WOLF_CHACHA */ +#ifdef WOLF_AESEXTRA + printf("\r\n--- AES-CMAC / CCM / GMAC ---\r\n"); + { + /* AES-128-CMAC (NIST SP800-38B example, 16-byte message). */ + static const byte ck[16] = { + 0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6, + 0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c}; + static const byte cmsg[16] = { + 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96, + 0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a}; + static const byte cmac_exp[16] = { + 0x07,0x0a,0x16,0xb4,0x6b,0x4d,0x41,0x44, + 0xf7,0x9b,0xdd,0x9d,0xd0,0x4a,0x28,0x7c}; + /* AES-128-CCM (RFC 3610 packet vector #1). */ + static const byte ek[16] = { + 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, + 0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf}; + static const byte enonce[13] = { + 0x00,0x00,0x00,0x03,0x02,0x01,0x00,0xa0,0xa1,0xa2,0xa3,0xa4,0xa5}; + static const byte eaad[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}; + static const byte ept[23] = { + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13, + 0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e}; + static const byte ect_exp[23] = { + 0x58,0x8c,0x97,0x9a,0x61,0xc6,0x63,0xd2,0xf0,0x66,0xd0,0xc2, + 0xc0,0xf9,0x89,0x80,0x6d,0x5f,0x6b,0x61,0xda,0xc3,0x84}; + static const byte etag_exp[8] = { + 0x17,0xe8,0xd1,0x2c,0xfd,0xf9,0x26,0xe0}; + static Aes aes; + byte mac[16], cct[23], ctag[8], cdec[23]; + word32 macSz = sizeof(mac); + int r; + + r = wc_AesCmacGenerate(mac, &macSz, cmsg, sizeof(cmsg), ck, sizeof(ck)); + printf("AES-128-CMAC: %s\r\n", + (r == 0 && macSz == 16 && XMEMCMP(mac, cmac_exp, 16) == 0) ? + "PASS":"FAIL"); + + r = wc_AesInit(&aes, NULL, INVALID_DEVID); + if (r == 0) r = wc_AesCcmSetKey(&aes, ek, sizeof(ek)); + if (r == 0) r = wc_AesCcmEncrypt(&aes, cct, ept, sizeof(ept), + enonce, sizeof(enonce), ctag, sizeof(ctag), eaad, sizeof(eaad)); + printf("AES-128-CCM encrypt: %s\r\n", + (r == 0 && XMEMCMP(cct, ect_exp, 23) == 0 && + XMEMCMP(ctag, etag_exp, 8) == 0) ? "PASS":"FAIL"); + r = wc_AesCcmDecrypt(&aes, cdec, ect_exp, sizeof(ect_exp), + enonce, sizeof(enonce), etag_exp, sizeof(etag_exp), eaad, sizeof(eaad)); + printf("AES-128-CCM decrypt+verify: %s\r\n", + (r == 0 && XMEMCMP(cdec, ept, sizeof(ept)) == 0) ? "PASS":"FAIL"); + wc_AesFree(&aes); + + /* GMAC = AES-GCM authentication of AAD with no plaintext. */ + { + static const byte gk[16] = { + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, + 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f}; + static const byte giv[12] = { + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b}; + static const byte gaad[16] = { + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, + 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f}; + byte gtag[16], gtag2[16]; + /* Self-consistent GMAC: generate then verify (KAT-cross-checked on + * host). */ + r = wc_AesInit(&aes, NULL, INVALID_DEVID); + if (r == 0) r = wc_AesGcmSetKey(&aes, gk, sizeof(gk)); + if (r == 0) r = wc_AesGcmEncrypt(&aes, NULL, NULL, 0, giv, + sizeof(giv), gtag, sizeof(gtag), gaad, sizeof(gaad)); + if (r == 0) r = wc_AesGcmDecrypt(&aes, NULL, NULL, 0, giv, + sizeof(giv), gtag, sizeof(gtag), gaad, sizeof(gaad)); + printf("AES-128-GMAC (gen+verify): %s\r\n", (r == 0) ? "PASS":"FAIL"); + (void)gtag2; + wc_AesFree(&aes); + } + } +#endif /* WOLF_AESEXTRA */ + printf("SYSCLK %lu Hz, CHAR_BIT %d, sizeof(long)=%d sizeof(long long)=%d\r\n", (unsigned long)DEVICE_SYSCLK_FREQ, (int)CHAR_BIT, (int)sizeof(long), (int)sizeof(long long)); From e58567d8488847793c598fe9201ad735357610d6 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 22 Jun 2026 21:17:58 -0700 Subject: [PATCH 13/13] ti-c2000: add RSA-2048 PKCS#1v1.5 SHA-256 verify KAT (RSA=1, SP backend, 2048-only); host-validated vector, on-HW KAT pending probe replug --- .../ti-c2000-f28p55x/Header/rsa2048_kat.h | 69 +++++++++++++++++++ .../ti-c2000-f28p55x/Header/user_settings.h | 7 +- embedded/ti-c2000-f28p55x/Source/wolf_main.c | 27 ++++++++ 3 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 embedded/ti-c2000-f28p55x/Header/rsa2048_kat.h diff --git a/embedded/ti-c2000-f28p55x/Header/rsa2048_kat.h b/embedded/ti-c2000-f28p55x/Header/rsa2048_kat.h new file mode 100644 index 000000000..a42911755 --- /dev/null +++ b/embedded/ti-c2000-f28p55x/Header/rsa2048_kat.h @@ -0,0 +1,69 @@ +/* RSA-2048 SHA-256 PKCS#1 v1.5 verify KAT (openssl-generated). */ +#ifndef RSA2048_KAT_H +#define RSA2048_KAT_H + +static const byte kat_rsa2048_n[256] = { + 0x9e,0xc7,0x03,0xbc,0x24,0x7e,0xaf,0xbd,0x45,0x36,0xf9,0x52, + 0x97,0x0c,0x35,0x3a,0xbe,0xe6,0xe8,0x0f,0x2e,0x79,0xa2,0xd8, + 0xf0,0x7d,0x6c,0x72,0x27,0x7b,0x38,0x58,0xab,0x90,0xe2,0xe0, + 0x06,0xf1,0x40,0xc9,0x1b,0xba,0x6f,0xcd,0x2b,0xc6,0xad,0x1d, + 0x7d,0x26,0x0d,0x0b,0x40,0x66,0xe9,0x92,0xb1,0x47,0x2f,0x9d, + 0x97,0xfc,0x94,0xd0,0xeb,0x4c,0x02,0xa2,0xf2,0xd0,0xe8,0x52, + 0xc1,0xbe,0x31,0xb5,0x06,0x17,0x80,0x9a,0x31,0x48,0x30,0x3e, + 0xbd,0x2a,0x66,0x59,0x1a,0x87,0x1d,0xdf,0xea,0xff,0x4c,0xe9, + 0xb3,0x87,0xd9,0xac,0x47,0x38,0xbd,0x74,0xa1,0x8a,0x36,0x99, + 0x62,0xfd,0xe0,0xae,0x46,0x72,0x67,0x69,0x94,0x58,0x4e,0xcc, + 0x15,0xd9,0xea,0x62,0x6d,0x18,0x11,0xfb,0x28,0x1f,0xc1,0x2b, + 0xca,0x8b,0x6d,0x96,0x62,0x42,0x52,0x8c,0x11,0xc0,0xd3,0xb6, + 0x22,0xbf,0xc7,0xb1,0x24,0xe1,0x9d,0x39,0x49,0xc5,0xff,0x01, + 0xbb,0x15,0xc5,0x22,0x6a,0xfa,0xa6,0x74,0xb2,0xf9,0x9e,0xb5, + 0x1d,0x50,0x80,0xee,0x1f,0xcb,0x24,0xf4,0xb5,0x50,0xf2,0x2b, + 0xea,0xf6,0x12,0x74,0x12,0xf0,0xf5,0xf2,0x00,0xde,0x58,0x16, + 0x16,0x38,0x07,0xbb,0xf0,0x45,0x5f,0xab,0xf3,0x18,0xda,0x25, + 0xdf,0x1f,0xf2,0x0c,0xb6,0x58,0x76,0x78,0x18,0x2a,0x8f,0xf5, + 0x52,0x52,0xc7,0xc6,0xa0,0xf5,0x02,0x4c,0xfe,0xbd,0xf4,0x02, + 0xd8,0x78,0x83,0xc0,0xc5,0xc2,0xd2,0x60,0xca,0xbb,0xbf,0xa2, + 0xbd,0x90,0x66,0xff,0x10,0x28,0xf3,0xa7,0x32,0x2c,0xf1,0x59, + 0x28,0x41,0x75,0x35, +}; +static const byte kat_rsa2048_e[3] = { + 0x01,0x00,0x01, +}; +static const byte kat_rsa2048_sig[256] = { + 0x92,0x96,0x49,0x52,0x64,0x83,0x87,0x39,0x3a,0xae,0x1e,0x1a, + 0x45,0x3f,0x94,0x5b,0xd2,0x0c,0x44,0x51,0xfa,0x12,0xf3,0x88, + 0x59,0x35,0x78,0xe5,0x0e,0xcf,0x76,0xa2,0x81,0x71,0x0e,0xe0, + 0x2c,0x0f,0x1d,0x24,0xae,0x11,0xa0,0x94,0xd2,0x21,0xc0,0xd3, + 0x18,0x2e,0xfc,0x59,0x09,0x34,0x7b,0x94,0x08,0x83,0x3d,0xe5, + 0x1f,0x27,0x70,0x5e,0x14,0x11,0x7c,0xdf,0x7a,0xda,0xf7,0x73, + 0x31,0xe5,0xbc,0xcb,0x86,0xb2,0x0f,0x8c,0xa9,0x06,0xc0,0xd1, + 0x3b,0xd5,0x9a,0xd8,0x8a,0x51,0xd9,0x51,0xd1,0x48,0xb8,0xff, + 0xa3,0x61,0x38,0xc4,0x9e,0x7f,0xc0,0x06,0x4c,0x0b,0xec,0xae, + 0xbc,0xf3,0xc8,0xa0,0x20,0x76,0xf0,0x51,0xf9,0xc2,0xfe,0x01, + 0xdc,0x31,0xf6,0xdf,0xe7,0xe6,0xf9,0x2c,0x6f,0x93,0x3d,0x3e, + 0x89,0x73,0x6f,0xc9,0x5f,0xad,0x60,0x1f,0x48,0x81,0x09,0xd6, + 0xab,0x2b,0xcf,0xb5,0x9a,0x70,0x3d,0x04,0x0f,0x59,0xcc,0xc2, + 0x7f,0x95,0x9a,0x3e,0xd5,0xb7,0x8b,0x7e,0xb0,0x6e,0xcc,0xee, + 0xfc,0xe5,0x17,0xa2,0x2c,0xf1,0xf6,0x1f,0xaf,0xf7,0x05,0x2c, + 0x15,0xea,0xae,0x26,0x8b,0xde,0xb8,0x53,0xf7,0x9a,0x4f,0x09, + 0x2a,0x27,0x9b,0x78,0x1a,0xaf,0x22,0xf5,0xfa,0x22,0xe8,0x75, + 0x39,0x79,0x46,0x8f,0xc2,0x40,0xd3,0x0f,0xae,0xad,0xfd,0x84, + 0x03,0x20,0x30,0xb9,0x65,0xf4,0xab,0x44,0x8b,0x57,0xa6,0xbb, + 0x44,0xa8,0x86,0xa1,0x4f,0xad,0x94,0x31,0x18,0xdd,0x26,0x3b, + 0x71,0x39,0x8b,0x22,0x3f,0xcc,0x2f,0x65,0x3f,0x87,0xee,0xfa, + 0xaf,0x4a,0x91,0x93, +}; +static const byte kat_rsa2048_msg[35] = { + 0x77,0x6f,0x6c,0x66,0x43,0x72,0x79,0x70,0x74,0x20,0x52,0x53, + 0x41,0x20,0x76,0x65,0x72,0x69,0x66,0x79,0x20,0x4b,0x41,0x54, + 0x20,0x6f,0x6e,0x20,0x54,0x49,0x20,0x43,0x32,0x38,0x78, +}; +static const byte kat_rsa2048_digestinfo[51] = { + 0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03, + 0x04,0x02,0x01,0x05,0x00,0x04,0x20,0x55,0x1e,0x09,0xfe,0xd6, + 0x65,0x76,0x79,0xbd,0xe6,0x13,0xbb,0xa8,0x7e,0xf4,0xe9,0x3c, + 0x89,0x57,0x97,0x0c,0x04,0x12,0x5f,0xf7,0x47,0x59,0x5e,0x6b, + 0x62,0xac,0xc0, +}; + +#endif /* RSA2048_KAT_H */ diff --git a/embedded/ti-c2000-f28p55x/Header/user_settings.h b/embedded/ti-c2000-f28p55x/Header/user_settings.h index ec4aed592..d50319e4e 100644 --- a/embedded/ti-c2000-f28p55x/Header/user_settings.h +++ b/embedded/ti-c2000-f28p55x/Header/user_settings.h @@ -388,15 +388,18 @@ extern "C" { /* RSA verify via the SP math backend (--define=WOLF_RSA). */ #ifdef WOLF_RSA #undef NO_RSA +#undef NO_BIG_INT /* SP provides the mp_int interface (was off) */ +#undef SP_WORD_SIZE +#define SP_WORD_SIZE 32 /* 32-bit SP digits on the 16-bit-int C28x */ #undef WOLFSSL_SP_MATH #define WOLFSSL_SP_MATH #undef WOLFSSL_SP_MATH_ALL #undef WOLFSSL_HAVE_SP_RSA #define WOLFSSL_HAVE_SP_RSA -#undef WOLFSSL_SP_NO_2048 +#undef WOLFSSL_SP_NO_2048 /* RSA-2048 verify only (KAT is 2048-bit) */ #undef WOLFSSL_SP_NO_3072 +#define WOLFSSL_SP_NO_3072 #undef WOLFSSL_SP_4096 -#define WOLFSSL_SP_4096 #undef WOLFSSL_SP_ALLOW_16BIT_CPU #define WOLFSSL_SP_ALLOW_16BIT_CPU #undef WOLFSSL_SP_NO_MALLOC diff --git a/embedded/ti-c2000-f28p55x/Source/wolf_main.c b/embedded/ti-c2000-f28p55x/Source/wolf_main.c index b0d5ec668..90db1c1f2 100644 --- a/embedded/ti-c2000-f28p55x/Source/wolf_main.c +++ b/embedded/ti-c2000-f28p55x/Source/wolf_main.c @@ -84,6 +84,9 @@ #ifdef WOLF_ECC #include "ecc_p256_kat.h" #endif +#ifdef WOLF_RSA +#include "rsa2048_kat.h" +#endif /* ------------------------------------------------------------------------- */ /* SCIA console (XDS110 virtual COM) */ @@ -1186,6 +1189,30 @@ int main(void) } #endif /* WOLF_AESEXTRA */ +#ifdef WOLF_RSA + printf("\r\n--- RSA-2048 verify (PKCS#1 v1.5, SHA-256) ---\r\n"); + { + /* Recover the PKCS#1 v1.5 DigestInfo from the signature with the public + * key and compare to the expected DigestInfo (SHA-256 prefix + hash). */ + static RsaKey rsaKey; + byte out[64]; + int r, outLen = -1; + + r = wc_InitRsaKey(&rsaKey, NULL); + if (r == 0) r = wc_RsaPublicKeyDecodeRaw(kat_rsa2048_n, + (word32)sizeof(kat_rsa2048_n), kat_rsa2048_e, + (word32)sizeof(kat_rsa2048_e), &rsaKey); + if (r == 0) outLen = wc_RsaSSL_Verify(kat_rsa2048_sig, + (word32)sizeof(kat_rsa2048_sig), out, (word32)sizeof(out), &rsaKey); + printf("RSA-2048 verify: %s (recovered=%d exp=%d)\r\n", + (outLen == (int)sizeof(kat_rsa2048_digestinfo) && + XMEMCMP(out, kat_rsa2048_digestinfo, + sizeof(kat_rsa2048_digestinfo)) == 0) ? "PASS":"FAIL", + outLen, (int)sizeof(kat_rsa2048_digestinfo)); + wc_FreeRsaKey(&rsaKey); + } +#endif /* WOLF_RSA */ + printf("SYSCLK %lu Hz, CHAR_BIT %d, sizeof(long)=%d sizeof(long long)=%d\r\n", (unsigned long)DEVICE_SYSCLK_FREQ, (int)CHAR_BIT, (int)sizeof(long), (int)sizeof(long long));