Skip to content

Commit 9640f10

Browse files
committed
FrodoKEM: Initial implementation
Supports Fast C code, small C code, small stack and assembly for x86_64, Aarch64, Aarch32, Thumb2.
1 parent 95f337a commit 9640f10

73 files changed

Lines changed: 42251 additions & 3234 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.codespellrc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# codespell configuration (read automatically from the repository root).
2+
#
3+
# "SME" is the Arm Scalable Matrix Extension, referenced throughout the
4+
# FrodoKEM Aarch64 code (comments, CPUID_..._SME macros, frodokem_..._sme
5+
# identifiers, "sve2+sme" build strings). codespell's dictionary treats it as
6+
# a misspelling of some/same/sms. The ignore-regex below drops the standalone
7+
# SME token (any case, including "_sme" / "+sme") before spell-checking, while
8+
# still flagging "sme" embedded in a larger alphabetic word - so genuine typos
9+
# are unaffected. Kept out of ignore-words-list so "sme" is not globally
10+
# whitelisted for every file.
11+
[codespell]
12+
ignore-regex = (?i)(?<![a-z])sme(?![a-z])

.github/workflows/pq-all.yml

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
- name: Install dependencies
4444
uses: ./.github/actions/install-apt-deps
4545
with:
46-
packages: autoconf automake libtool build-essential bubblewrap
46+
packages: autoconf automake libtool build-essential bubblewrap crossbuild-essential-arm64 crossbuild-essential-armhf
4747
ghcr-debs-tag: ubuntu-24.04-minimal
4848

4949
# ccache via the cross-platform composite; the script passes the
@@ -154,6 +154,46 @@ jobs:
154154
"--enable-dilithium=yes,no-ctx", "--enable-dual-alg-certs",
155155
"--disable-qt",
156156
"CPPFLAGS=-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"]},
157+
{"name": "all-frodokem", "minutes": 3.5,
158+
"configure": ["--enable-intelasm", "--enable-sp-asm",
159+
"--enable-all", "--enable-testcert", "--enable-experimental",
160+
"--enable-mlkem=yes,kyber,ml-kem",
161+
"--enable-frodokem=aes,ephemeral", "--disable-qt",
162+
"CPPFLAGS=-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"]},
163+
{"name": "frodokem-small-smallstack-noasm", "minutes": 2.5,
164+
"configure": ["--disable-intelasm", "--enable-smallstack",
165+
"--enable-smallstackcache", "--enable-experimental",
166+
"--enable-frodokem=aes,ephemeral,small",
167+
"CPPFLAGS=-Wdeclaration-after-statement"]},
168+
{"name": "frodokem-976-only-noasm", "minutes": 1.5,
169+
"comment": "976-only builds D=16 (q=2^16) alone; no-asm the C path",
170+
"configure": ["--disable-intelasm", "--enable-experimental",
171+
"--enable-frodokem=aes,ephemeral,no-640,no-1344",
172+
"CPPFLAGS=-Wdeclaration-after-statement"]},
173+
{"name": "frodokem-640-shake-only", "minutes": 1.5,
174+
"comment": "640-only builds D=15 (q=2^15); shake-only, with asm",
175+
"configure": ["--enable-intelasm", "--enable-sp-asm",
176+
"--enable-experimental",
177+
"--enable-frodokem=no-976,no-1344,no-aes",
178+
"CPPFLAGS=-Wdeclaration-after-statement"]},
179+
{"name": "frodokem-aarch64-armasm", "minutes": 4, "check": false,
180+
"cc": "ccache aarch64-linux-gnu-gcc",
181+
"comment": "Cross-build only (no ARM runner): catches ARM asm link/compile breaks. sve+sme+aes A-gen all live in the .S.",
182+
"configure": ["--host=aarch64-linux-gnu", "--enable-cryptonly",
183+
"--enable-armasm", "--enable-experimental",
184+
"--enable-frodokem=aes,ephemeral,sve,sme", "--disable-examples"]},
185+
{"name": "frodokem-aarch64-armasm-inline", "minutes": 4,
186+
"check": false, "cc": "ccache aarch64-linux-gnu-gcc",
187+
"comment": "Inline armasm: sve/sme/aes are .S-only, so they must fall back to NEON/C; guards the inline-asm link break.",
188+
"configure": ["--host=aarch64-linux-gnu", "--enable-cryptonly",
189+
"--enable-armasm=inline", "--enable-experimental",
190+
"--enable-frodokem=aes,ephemeral,sve,sme", "--disable-examples"]},
191+
{"name": "frodokem-arm32-armasm", "minutes": 4, "check": false,
192+
"cc": "ccache arm-linux-gnueabihf-gcc",
193+
"comment": "Cross-build only: AArch32 NEON matrix ops + AES-crypto A-gen.",
194+
"configure": ["--host=arm-linux-gnueabihf", "--enable-cryptonly",
195+
"--enable-armasm", "--enable-experimental",
196+
"--enable-frodokem=aes,ephemeral", "--disable-examples"]},
157197
{"name": "ubsan-mldsa-mlkem", "minutes": 2.5,
158198
"configure": ["--disable-shared", "--enable-dilithium",
159199
"--enable-mlkem",

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ ctaocrypt/src/src/
77
*.d
88
*.libs
99
*.cache
10+
*.su
1011
.dirstamp
1112
*.user
1213
!*-VS2022.vcxproj.user

.wolfssl_known_macro_extras

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,8 @@ HSM_OP_KEY_GENERATION_FLAGS_CREATE
324324
HSM_OP_KEY_GENERATION_FLAGS_UPDATE
325325
HSM_SVC_KEY_STORE_FLAGS_UPDATE
326326
HWCAP_ASIMDRDM
327+
HWCAP2_SME
328+
HWCAP_SVE
327329
IDIRECT_DEV_RANDOM
328330
IDIRECT_DEV_TIME
329331
ID_TRNG
@@ -1046,7 +1048,13 @@ __ARCH_STRNCPY_NO_REDIRECT
10461048
__ARCH_STRSTR_NO_REDIRECT
10471049
__ARM_ARCH_7M__
10481050
__ARM_FEATURE_CRYPTO
1051+
__ARM_FEATURE_DSP
1052+
__ARM_FEATURE_SIMD32
1053+
__ARM_FEATURE_SME
1054+
__ARM_FEATURE_SVE
10491055
__ARM_FEATURE_UNALIGNED
1056+
__ARM_NEON
1057+
__ARM_NEON__
10501058
__ASSEMBLER__
10511059
__ATOMIC_CONSUME
10521060
__ATOMIC_RELAXED

CMakeLists.txt

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,56 @@ add_option(WOLFSSL_EXTRA_PQC_HYBRIDS
10371037
"Enable extra PQ/T hybrid combinations (default: disabled)"
10381038
"no" "yes;no")
10391039

1040+
# FrodoKEM reference implementation (experimental)
1041+
add_option(WOLFSSL_FRODOKEM
1042+
"Enable the wolfSSL FrodoKEM reference implementation (requires WOLFSSL_EXPERIMENTAL) (default: disabled)"
1043+
"no" "yes;no")
1044+
# FrodoKEM matrix A generation with SHAKE-128 (default: enabled when FrodoKEM on)
1045+
add_option(WOLFSSL_FRODOKEM_SHAKE
1046+
"Enable FrodoKEM SHAKE-128 matrix A generation (default: enabled)"
1047+
"yes" "yes;no")
1048+
# FrodoKEM matrix A generation with AES-128 (default: disabled)
1049+
add_option(WOLFSSL_FRODOKEM_AES
1050+
"Enable FrodoKEM AES-128 matrix A generation (default: disabled)"
1051+
"no" "yes;no")
1052+
# eFrodoKEM (ephemeral, salt-less) variants (default: disabled)
1053+
add_option(WOLFSSL_FRODOKEM_EPHEMERAL
1054+
"Enable eFrodoKEM (ephemeral) variants (default: disabled)"
1055+
"no" "yes;no")
1056+
# FrodoKEM parameter sets (each default: enabled)
1057+
add_option(WOLFSSL_FRODOKEM_640
1058+
"Enable the FrodoKEM-640 parameter set (default: enabled)"
1059+
"yes" "yes;no")
1060+
add_option(WOLFSSL_FRODOKEM_976
1061+
"Enable the FrodoKEM-976 parameter set (default: enabled)"
1062+
"yes" "yes;no")
1063+
add_option(WOLFSSL_FRODOKEM_1344
1064+
"Enable the FrodoKEM-1344 parameter set (default: enabled)"
1065+
"yes" "yes;no")
1066+
# FrodoKEM operations (each default: enabled)
1067+
add_option(WOLFSSL_FRODOKEM_MAKE_KEY
1068+
"Enable FrodoKEM key generation (default: enabled)"
1069+
"yes" "yes;no")
1070+
add_option(WOLFSSL_FRODOKEM_ENCAPSULATE
1071+
"Enable FrodoKEM encapsulation (default: enabled)"
1072+
"yes" "yes;no")
1073+
add_option(WOLFSSL_FRODOKEM_DECAPSULATE
1074+
"Enable FrodoKEM decapsulation (default: enabled)"
1075+
"yes" "yes;no")
1076+
# Small-footprint FrodoKEM: looped (not unrolled) matrix arithmetic
1077+
# (default: disabled)
1078+
add_option(WOLFSSL_FRODOKEM_SMALL
1079+
"Enable small-footprint FrodoKEM (default: disabled)"
1080+
"no" "yes;no")
1081+
1082+
# FrodoKEM AArch64 SVE / SME acceleration (default: disabled; AArch64 asm only)
1083+
add_option(WOLFSSL_FRODOKEM_SVE
1084+
"Enable FrodoKEM AArch64 SVE acceleration (default: disabled)"
1085+
"no" "yes;no")
1086+
add_option(WOLFSSL_FRODOKEM_SME
1087+
"Enable FrodoKEM AArch64 SME acceleration (default: disabled)"
1088+
"no" "yes;no")
1089+
10401090
message(STATUS "Looking for WOLFSSL_EXPERIMENTAL")
10411091
if (WOLFSSL_EXPERIMENTAL)
10421092
message(STATUS "Looking for WOLFSSL_EXPERIMENTAL - found")
@@ -1092,6 +1142,98 @@ if (WOLFSSL_EXPERIMENTAL)
10921142
message(STATUS "Looking for WOLFSSL_EXTRA_PQC_HYBRIDS - not found")
10931143
endif()
10941144

1145+
# Checking for experimental feature: FrodoKEM
1146+
message(STATUS "Looking for WOLFSSL_FRODOKEM")
1147+
if (WOLFSSL_FRODOKEM)
1148+
set(WOLFSSL_FOUND_EXPERIMENTAL_FEATURE 1)
1149+
message(STATUS "Looking for WOLFSSL_FRODOKEM - found")
1150+
1151+
# At least one matrix A generation method must be enabled.
1152+
if (NOT WOLFSSL_FRODOKEM_SHAKE AND NOT WOLFSSL_FRODOKEM_AES)
1153+
message(FATAL_ERROR
1154+
"WOLFSSL_FRODOKEM requires WOLFSSL_FRODOKEM_SHAKE and/or WOLFSSL_FRODOKEM_AES.")
1155+
endif()
1156+
# At least one parameter set must be enabled.
1157+
if (NOT WOLFSSL_FRODOKEM_640 AND NOT WOLFSSL_FRODOKEM_976 AND
1158+
NOT WOLFSSL_FRODOKEM_1344)
1159+
message(FATAL_ERROR
1160+
"WOLFSSL_FRODOKEM requires at least one of WOLFSSL_FRODOKEM_640, WOLFSSL_FRODOKEM_976 or WOLFSSL_FRODOKEM_1344.")
1161+
endif()
1162+
# At least one operation must be enabled.
1163+
if (NOT WOLFSSL_FRODOKEM_MAKE_KEY AND NOT WOLFSSL_FRODOKEM_ENCAPSULATE
1164+
AND NOT WOLFSSL_FRODOKEM_DECAPSULATE)
1165+
message(FATAL_ERROR
1166+
"WOLFSSL_FRODOKEM requires at least one of WOLFSSL_FRODOKEM_MAKE_KEY, WOLFSSL_FRODOKEM_ENCAPSULATE or WOLFSSL_FRODOKEM_DECAPSULATE.")
1167+
endif()
1168+
1169+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_HAVE_FRODOKEM")
1170+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SHA3")
1171+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SHAKE128")
1172+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SHAKE256")
1173+
1174+
set_wolfssl_definitions("WOLFSSL_HAVE_FRODOKEM" RESULT)
1175+
set_wolfssl_definitions("WOLFSSL_SHA3" RESULT)
1176+
set_wolfssl_definitions("WOLFSSL_SHAKE128" RESULT)
1177+
set_wolfssl_definitions("WOLFSSL_SHAKE256" RESULT)
1178+
1179+
if (WOLFSSL_FRODOKEM_SHAKE)
1180+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_SHAKE")
1181+
set_wolfssl_definitions("WOLFSSL_FRODOKEM_SHAKE" RESULT)
1182+
endif()
1183+
if (WOLFSSL_FRODOKEM_AES)
1184+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_AES")
1185+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_AES_DIRECT")
1186+
list(APPEND WOLFSSL_DEFINITIONS "-DHAVE_AES_ECB")
1187+
set_wolfssl_definitions("WOLFSSL_FRODOKEM_AES" RESULT)
1188+
set_wolfssl_definitions("WOLFSSL_AES_DIRECT" RESULT)
1189+
set_wolfssl_definitions("HAVE_AES_ECB" RESULT)
1190+
endif()
1191+
if (WOLFSSL_FRODOKEM_EPHEMERAL)
1192+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_EPHEMERAL")
1193+
set_wolfssl_definitions("WOLFSSL_FRODOKEM_EPHEMERAL" RESULT)
1194+
endif()
1195+
if (WOLFSSL_FRODOKEM_SMALL)
1196+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_SMALL")
1197+
set_wolfssl_definitions("WOLFSSL_FRODOKEM_SMALL" RESULT)
1198+
endif()
1199+
if (WOLFSSL_FRODOKEM_SVE)
1200+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_SVE")
1201+
set_wolfssl_definitions("WOLFSSL_FRODOKEM_SVE" RESULT)
1202+
endif()
1203+
if (WOLFSSL_FRODOKEM_SME)
1204+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_SME")
1205+
set_wolfssl_definitions("WOLFSSL_FRODOKEM_SME" RESULT)
1206+
endif()
1207+
# Excluded parameter sets.
1208+
if (NOT WOLFSSL_FRODOKEM_640)
1209+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_NO_FRODOKEM_640")
1210+
set_wolfssl_definitions("WOLFSSL_NO_FRODOKEM_640" RESULT)
1211+
endif()
1212+
if (NOT WOLFSSL_FRODOKEM_976)
1213+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_NO_FRODOKEM_976")
1214+
set_wolfssl_definitions("WOLFSSL_NO_FRODOKEM_976" RESULT)
1215+
endif()
1216+
if (NOT WOLFSSL_FRODOKEM_1344)
1217+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_NO_FRODOKEM_1344")
1218+
set_wolfssl_definitions("WOLFSSL_NO_FRODOKEM_1344" RESULT)
1219+
endif()
1220+
# Excluded operations.
1221+
if (NOT WOLFSSL_FRODOKEM_MAKE_KEY)
1222+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_NO_MAKE_KEY")
1223+
set_wolfssl_definitions("WOLFSSL_FRODOKEM_NO_MAKE_KEY" RESULT)
1224+
endif()
1225+
if (NOT WOLFSSL_FRODOKEM_ENCAPSULATE)
1226+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_NO_ENCAPSULATE")
1227+
set_wolfssl_definitions("WOLFSSL_FRODOKEM_NO_ENCAPSULATE" RESULT)
1228+
endif()
1229+
if (NOT WOLFSSL_FRODOKEM_DECAPSULATE)
1230+
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_NO_DECAPSULATE")
1231+
set_wolfssl_definitions("WOLFSSL_FRODOKEM_NO_DECAPSULATE" RESULT)
1232+
endif()
1233+
else()
1234+
message(STATUS "Looking for WOLFSSL_FRODOKEM - not found")
1235+
endif()
1236+
10951237
# Other experimental feature detection can be added here...
10961238

10971239
# Were any experimental features found? Display a message.
@@ -1110,6 +1252,9 @@ else()
11101252
if (WOLFSSL_FALCON)
11111253
message(FATAL_ERROR "Error: WOLFSSL_FALCON requires WOLFSSL_EXPERIMENTAL at this time.")
11121254
endif()
1255+
if (WOLFSSL_FRODOKEM)
1256+
message(FATAL_ERROR "Error: WOLFSSL_FRODOKEM requires WOLFSSL_EXPERIMENTAL at this time.")
1257+
endif()
11131258
endif()
11141259

11151260
# LMS
@@ -4184,6 +4329,7 @@ if(WOLFSSL_EXAMPLES)
41844329
tests/api/test_ed25519.c
41854330
tests/api/test_curve448.c
41864331
tests/api/test_ed448.c
4332+
tests/api/test_frodokem.c
41874333
tests/api/test_mlkem.c
41884334
tests/api/test_mldsa.c
41894335
tests/api/test_mldsa_legacy.c

cmake/functions.cmake

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,9 @@ function(generate_build_flags)
253253
if(WOLFSSL_MLKEM OR WOLFSSL_USER_SETTINGS)
254254
set(BUILD_WC_MLKEM "yes" PARENT_SCOPE)
255255
endif()
256+
if(WOLFSSL_FRODOKEM OR WOLFSSL_USER_SETTINGS)
257+
set(BUILD_WC_FRODOKEM "yes" PARENT_SCOPE)
258+
endif()
256259
if(WOLFSSL_MLDSA OR WOLFSSL_DILITHIUM OR WOLFSSL_USER_SETTINGS)
257260
set(BUILD_MLDSA "yes" PARENT_SCOPE)
258261
endif()
@@ -1175,6 +1178,35 @@ function(generate_lib_src_list LIB_SOURCES)
11751178
endif()
11761179
endif()
11771180

1181+
if(BUILD_WC_FRODOKEM)
1182+
list(APPEND LIB_SOURCES wolfcrypt/src/wc_frodokem.c)
1183+
list(APPEND LIB_SOURCES wolfcrypt/src/wc_frodokem_mat.c)
1184+
1185+
if(BUILD_ARMASM)
1186+
if(BUILD_ARMASM_INLINE)
1187+
list(APPEND LIB_SOURCES
1188+
wolfcrypt/src/port/arm/armv8-frodokem-asm_c.c
1189+
wolfcrypt/src/port/arm/armv8-32-frodokem-asm_c.c)
1190+
else()
1191+
list(APPEND LIB_SOURCES
1192+
wolfcrypt/src/port/arm/armv8-frodokem-asm.S
1193+
wolfcrypt/src/port/arm/armv8-32-frodokem-asm.S)
1194+
endif()
1195+
1196+
if(BUILD_ARMASM_INLINE AND BUILD_ARM_THUMB)
1197+
list(APPEND LIB_SOURCES
1198+
wolfcrypt/src/port/arm/thumb2-frodokem-asm_c.c)
1199+
elseif(BUILD_ARM_THUMB)
1200+
list(APPEND LIB_SOURCES
1201+
wolfcrypt/src/port/arm/thumb2-frodokem-asm.S)
1202+
endif()
1203+
endif()
1204+
1205+
if(BUILD_INTELASM)
1206+
list(APPEND LIB_SOURCES wolfcrypt/src/wc_frodokem_asm.S)
1207+
endif()
1208+
endif()
1209+
11781210
if(BUILD_WC_LMS)
11791211
list(APPEND LIB_SOURCES wolfcrypt/src/wc_lms.c)
11801212
list(APPEND LIB_SOURCES wolfcrypt/src/wc_lms_impl.c)

0 commit comments

Comments
 (0)