Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .codespellrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# codespell configuration (read automatically from the repository root).
#
# "SME" is the Arm Scalable Matrix Extension, referenced throughout the
# FrodoKEM Aarch64 code (comments, CPUID_..._SME macros, frodokem_..._sme
# identifiers, "sve2+sme" build strings). codespell's dictionary treats it as
# a misspelling of some/same/sms. The ignore-regex below drops the standalone
# SME token (any case, including "_sme" / "+sme") before spell-checking, while
# still flagging "sme" embedded in a larger alphabetic word - so genuine typos
# are unaffected. Kept out of ignore-words-list so "sme" is not globally
# whitelisted for every file.
[codespell]
ignore-regex = (?i)(?<![a-z])sme(?![a-z])
42 changes: 41 additions & 1 deletion .github/workflows/pq-all.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
name: Quantum Resistant Tests

# START OF COMMON SECTION
Expand Down Expand Up @@ -43,7 +43,7 @@
- name: Install dependencies
uses: ./.github/actions/install-apt-deps
with:
packages: autoconf automake libtool build-essential bubblewrap
packages: autoconf automake libtool build-essential bubblewrap crossbuild-essential-arm64 crossbuild-essential-armhf
ghcr-debs-tag: ubuntu-24.04-minimal

# ccache via the cross-platform composite; the script passes the
Expand Down Expand Up @@ -154,6 +154,46 @@
"--enable-dilithium=yes,no-ctx", "--enable-dual-alg-certs",
"--disable-qt",
"CPPFLAGS=-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"]},
{"name": "all-frodokem", "minutes": 3.5,
"configure": ["--enable-intelasm", "--enable-sp-asm",
"--enable-all", "--enable-testcert", "--enable-experimental",
"--enable-mlkem=yes,kyber,ml-kem",
"--enable-frodokem=aes,ephemeral", "--disable-qt",
"CPPFLAGS=-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"]},
{"name": "frodokem-small-smallstack-noasm", "minutes": 2.5,
"configure": ["--disable-intelasm", "--enable-smallstack",
"--enable-smallstackcache", "--enable-experimental",
"--enable-frodokem=aes,ephemeral,small",
"CPPFLAGS=-Wdeclaration-after-statement"]},
{"name": "frodokem-976-only-noasm", "minutes": 1.5,
"comment": "976-only builds D=16 (q=2^16) alone; no-asm the C path",
"configure": ["--disable-intelasm", "--enable-experimental",
"--enable-frodokem=aes,ephemeral,no-640,no-1344",
"CPPFLAGS=-Wdeclaration-after-statement"]},
{"name": "frodokem-640-shake-only", "minutes": 1.5,
"comment": "640-only builds D=15 (q=2^15); shake-only, with asm",
"configure": ["--enable-intelasm", "--enable-sp-asm",
"--enable-experimental",
"--enable-frodokem=no-976,no-1344,no-aes",
"CPPFLAGS=-Wdeclaration-after-statement"]},
{"name": "frodokem-aarch64-armasm", "minutes": 4, "check": false,
"cc": "ccache aarch64-linux-gnu-gcc",
"comment": "Cross-build only (no ARM runner): catches ARM asm link/compile breaks. sve+sme+aes A-gen all live in the .S.",
"configure": ["--host=aarch64-linux-gnu", "--enable-cryptonly",
"--enable-armasm", "--enable-experimental",
"--enable-frodokem=aes,ephemeral,sve,sme", "--disable-examples"]},
{"name": "frodokem-aarch64-armasm-inline", "minutes": 4,
"check": false, "cc": "ccache aarch64-linux-gnu-gcc",
"comment": "Inline armasm: sve/sme/aes are .S-only, so they must fall back to NEON/C; guards the inline-asm link break.",
"configure": ["--host=aarch64-linux-gnu", "--enable-cryptonly",
"--enable-armasm=inline", "--enable-experimental",
"--enable-frodokem=aes,ephemeral,sve,sme", "--disable-examples"]},
{"name": "frodokem-arm32-armasm", "minutes": 4, "check": false,
"cc": "ccache arm-linux-gnueabihf-gcc",
"comment": "Cross-build only: AArch32 NEON matrix ops + AES-crypto A-gen.",
"configure": ["--host=arm-linux-gnueabihf", "--enable-cryptonly",
"--enable-armasm", "--enable-experimental",
"--enable-frodokem=aes,ephemeral", "--disable-examples"]},
{"name": "ubsan-mldsa-mlkem", "minutes": 2.5,
"configure": ["--disable-shared", "--enable-dilithium",
"--enable-mlkem",
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ ctaocrypt/src/src/
*.d
*.libs
*.cache
*.su
.dirstamp
*.user
!*-VS2022.vcxproj.user
Expand Down
9 changes: 9 additions & 0 deletions .wolfssl_known_macro_extras
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ HSM_OP_KEY_GENERATION_FLAGS_CREATE
HSM_OP_KEY_GENERATION_FLAGS_UPDATE
HSM_SVC_KEY_STORE_FLAGS_UPDATE
HWCAP_ASIMDRDM
HWCAP2_SME
HWCAP_SVE
IDIRECT_DEV_RANDOM
IDIRECT_DEV_TIME
ID_TRNG
Expand Down Expand Up @@ -838,6 +840,7 @@ WOLFSSL_EXTRA
WOLFSSL_FORCE_OCSP_NONCE_CHECK
WOLFSSL_FRDM_K64
WOLFSSL_FRDM_K64_JENKINS
WOLFSSL_FRODOKEM_NO_ASN1
WOLFSSL_FUNC_TIME
WOLFSSL_FUNC_TIME_LOG
WOLFSSL_GEN_CERT
Expand Down Expand Up @@ -1111,7 +1114,13 @@ __ARCH_STRNCPY_NO_REDIRECT
__ARCH_STRSTR_NO_REDIRECT
__ARM_ARCH_7M__
__ARM_FEATURE_CRYPTO
__ARM_FEATURE_DSP
__ARM_FEATURE_SIMD32
__ARM_FEATURE_SME
__ARM_FEATURE_SVE
__ARM_FEATURE_UNALIGNED
__ARM_NEON
__ARM_NEON__
__ASSEMBLER__
__ATOMIC_CONSUME
__ATOMIC_RELAXED
Expand Down
146 changes: 146 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,56 @@ add_option(WOLFSSL_EXTRA_PQC_HYBRIDS
"Enable extra PQ/T hybrid combinations (default: disabled)"
"no" "yes;no")

# FrodoKEM reference implementation (experimental)
add_option(WOLFSSL_FRODOKEM
"Enable the wolfSSL FrodoKEM reference implementation (requires WOLFSSL_EXPERIMENTAL) (default: disabled)"
"no" "yes;no")
# FrodoKEM matrix A generation with SHAKE-128 (default: enabled when FrodoKEM on)
add_option(WOLFSSL_FRODOKEM_SHAKE
"Enable FrodoKEM SHAKE-128 matrix A generation (default: enabled)"
"yes" "yes;no")
# FrodoKEM matrix A generation with AES-128 (default: disabled)
add_option(WOLFSSL_FRODOKEM_AES
"Enable FrodoKEM AES-128 matrix A generation (default: disabled)"
"no" "yes;no")
# eFrodoKEM (ephemeral, salt-less) variants (default: disabled)
add_option(WOLFSSL_FRODOKEM_EPHEMERAL
"Enable eFrodoKEM (ephemeral) variants (default: disabled)"
"no" "yes;no")
# FrodoKEM parameter sets (each default: enabled)
add_option(WOLFSSL_FRODOKEM_640
"Enable the FrodoKEM-640 parameter set (default: enabled)"
"yes" "yes;no")
add_option(WOLFSSL_FRODOKEM_976
"Enable the FrodoKEM-976 parameter set (default: enabled)"
"yes" "yes;no")
add_option(WOLFSSL_FRODOKEM_1344
"Enable the FrodoKEM-1344 parameter set (default: enabled)"
"yes" "yes;no")
# FrodoKEM operations (each default: enabled)
add_option(WOLFSSL_FRODOKEM_MAKE_KEY
"Enable FrodoKEM key generation (default: enabled)"
"yes" "yes;no")
add_option(WOLFSSL_FRODOKEM_ENCAPSULATE
"Enable FrodoKEM encapsulation (default: enabled)"
"yes" "yes;no")
add_option(WOLFSSL_FRODOKEM_DECAPSULATE
"Enable FrodoKEM decapsulation (default: enabled)"
"yes" "yes;no")
# Small-footprint FrodoKEM: looped (not unrolled) matrix arithmetic
# (default: disabled)
add_option(WOLFSSL_FRODOKEM_SMALL
"Enable small-footprint FrodoKEM (default: disabled)"
"no" "yes;no")

# FrodoKEM AArch64 SVE / SME acceleration (default: disabled; AArch64 asm only)
add_option(WOLFSSL_FRODOKEM_SVE
"Enable FrodoKEM AArch64 SVE acceleration (default: disabled)"
"no" "yes;no")
add_option(WOLFSSL_FRODOKEM_SME
"Enable FrodoKEM AArch64 SME acceleration (default: disabled)"
"no" "yes;no")

message(STATUS "Looking for WOLFSSL_EXPERIMENTAL")
if (WOLFSSL_EXPERIMENTAL)
message(STATUS "Looking for WOLFSSL_EXPERIMENTAL - found")
Expand Down Expand Up @@ -1092,6 +1142,98 @@ if (WOLFSSL_EXPERIMENTAL)
message(STATUS "Looking for WOLFSSL_EXTRA_PQC_HYBRIDS - not found")
endif()

# Checking for experimental feature: FrodoKEM
message(STATUS "Looking for WOLFSSL_FRODOKEM")
if (WOLFSSL_FRODOKEM)
set(WOLFSSL_FOUND_EXPERIMENTAL_FEATURE 1)
message(STATUS "Looking for WOLFSSL_FRODOKEM - found")

# At least one matrix A generation method must be enabled.
if (NOT WOLFSSL_FRODOKEM_SHAKE AND NOT WOLFSSL_FRODOKEM_AES)
message(FATAL_ERROR
"WOLFSSL_FRODOKEM requires WOLFSSL_FRODOKEM_SHAKE and/or WOLFSSL_FRODOKEM_AES.")
endif()
# At least one parameter set must be enabled.
if (NOT WOLFSSL_FRODOKEM_640 AND NOT WOLFSSL_FRODOKEM_976 AND
NOT WOLFSSL_FRODOKEM_1344)
message(FATAL_ERROR
"WOLFSSL_FRODOKEM requires at least one of WOLFSSL_FRODOKEM_640, WOLFSSL_FRODOKEM_976 or WOLFSSL_FRODOKEM_1344.")
endif()
# At least one operation must be enabled.
if (NOT WOLFSSL_FRODOKEM_MAKE_KEY AND NOT WOLFSSL_FRODOKEM_ENCAPSULATE
AND NOT WOLFSSL_FRODOKEM_DECAPSULATE)
message(FATAL_ERROR
"WOLFSSL_FRODOKEM requires at least one of WOLFSSL_FRODOKEM_MAKE_KEY, WOLFSSL_FRODOKEM_ENCAPSULATE or WOLFSSL_FRODOKEM_DECAPSULATE.")
endif()

list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_HAVE_FRODOKEM")
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SHA3")
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SHAKE128")
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_SHAKE256")

set_wolfssl_definitions("WOLFSSL_HAVE_FRODOKEM" RESULT)
set_wolfssl_definitions("WOLFSSL_SHA3" RESULT)
set_wolfssl_definitions("WOLFSSL_SHAKE128" RESULT)
set_wolfssl_definitions("WOLFSSL_SHAKE256" RESULT)

if (WOLFSSL_FRODOKEM_SHAKE)
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_SHAKE")
set_wolfssl_definitions("WOLFSSL_FRODOKEM_SHAKE" RESULT)
endif()
if (WOLFSSL_FRODOKEM_AES)
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_AES")
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_AES_DIRECT")
list(APPEND WOLFSSL_DEFINITIONS "-DHAVE_AES_ECB")
set_wolfssl_definitions("WOLFSSL_FRODOKEM_AES" RESULT)
set_wolfssl_definitions("WOLFSSL_AES_DIRECT" RESULT)
set_wolfssl_definitions("HAVE_AES_ECB" RESULT)
endif()
if (WOLFSSL_FRODOKEM_EPHEMERAL)
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_EPHEMERAL")
set_wolfssl_definitions("WOLFSSL_FRODOKEM_EPHEMERAL" RESULT)
endif()
if (WOLFSSL_FRODOKEM_SMALL)
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_SMALL")
set_wolfssl_definitions("WOLFSSL_FRODOKEM_SMALL" RESULT)
endif()
if (WOLFSSL_FRODOKEM_SVE)
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_SVE")
set_wolfssl_definitions("WOLFSSL_FRODOKEM_SVE" RESULT)
endif()
if (WOLFSSL_FRODOKEM_SME)
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_SME")
set_wolfssl_definitions("WOLFSSL_FRODOKEM_SME" RESULT)
endif()
# Excluded parameter sets.
if (NOT WOLFSSL_FRODOKEM_640)
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_NO_FRODOKEM_640")
set_wolfssl_definitions("WOLFSSL_NO_FRODOKEM_640" RESULT)
endif()
if (NOT WOLFSSL_FRODOKEM_976)
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_NO_FRODOKEM_976")
set_wolfssl_definitions("WOLFSSL_NO_FRODOKEM_976" RESULT)
endif()
if (NOT WOLFSSL_FRODOKEM_1344)
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_NO_FRODOKEM_1344")
set_wolfssl_definitions("WOLFSSL_NO_FRODOKEM_1344" RESULT)
endif()
# Excluded operations.
if (NOT WOLFSSL_FRODOKEM_MAKE_KEY)
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_NO_MAKE_KEY")
set_wolfssl_definitions("WOLFSSL_FRODOKEM_NO_MAKE_KEY" RESULT)
endif()
if (NOT WOLFSSL_FRODOKEM_ENCAPSULATE)
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_NO_ENCAPSULATE")
set_wolfssl_definitions("WOLFSSL_FRODOKEM_NO_ENCAPSULATE" RESULT)
endif()
if (NOT WOLFSSL_FRODOKEM_DECAPSULATE)
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_FRODOKEM_NO_DECAPSULATE")
set_wolfssl_definitions("WOLFSSL_FRODOKEM_NO_DECAPSULATE" RESULT)
endif()
else()
message(STATUS "Looking for WOLFSSL_FRODOKEM - not found")
endif()

# Other experimental feature detection can be added here...

# Were any experimental features found? Display a message.
Expand All @@ -1110,6 +1252,9 @@ else()
if (WOLFSSL_FALCON)
message(FATAL_ERROR "Error: WOLFSSL_FALCON requires WOLFSSL_EXPERIMENTAL at this time.")
endif()
if (WOLFSSL_FRODOKEM)
message(FATAL_ERROR "Error: WOLFSSL_FRODOKEM requires WOLFSSL_EXPERIMENTAL at this time.")
endif()
endif()

# LMS
Expand Down Expand Up @@ -4184,6 +4329,7 @@ if(WOLFSSL_EXAMPLES)
tests/api/test_ed25519.c
tests/api/test_curve448.c
tests/api/test_ed448.c
tests/api/test_frodokem.c
tests/api/test_mlkem.c
tests/api/test_mldsa.c
tests/api/test_mldsa_legacy.c
Expand Down
42 changes: 42 additions & 0 deletions certs/frodokem/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
FrodoKEM test key material for wolfSSL tests.

IMPORTANT - these files are NOT generated by OpenSSL.

FrodoKEM is a Key Encapsulation Mechanism (KEM). Neither OpenSSL nor the
liboqs oqs-provider expose it as a certificate / key-encoding algorithm with
the ISO/IEC 18033-2 key OIDs (arc 1.0.18033.2.2.7.x) that wolfSSL uses - their
FrodoKEM support is KEM-only, for TLS key exchange, and is not going to be
present as a signature/certificate algorithm. So, unlike the ML-DSA material
in certs/mldsa/ (produced with OpenSSL 3.5+), these fixtures are generated by
wolfSSL itself using wc_MakeCert_ex() / wc_MakeCertReq_ex().

A KEM public key cannot sign, so the certificate and the request are signed by
an ECC (P-256) issuer key; the FrodoKEM key is only ever the subject public
key.

Files (material is provided for parameter sets N in {976, 1344}; the 640 set
has no standardised OID and cannot be encoded):
gen_frodokem.c Generator (the "regeneration" tool; see below).
frodokem-ca-ecc-key.der ECC P-256 issuer (CA) private key (DER / PEM).
frodokem-ca-ecc-key.pem
frodokem-ca-ecc-cert.der Self-signed ECC issuer (CA) certificate.
frodokem-ca-ecc-cert.pem
frodokem<N>-key.der FrodoKEM-<N> (SHAKE) private key, PKCS#8.
frodokem<N>-key.pem
frodokem<N>_pub-spki.der FrodoKEM-<N> public key, SubjectPublicKeyInfo.
frodokem<N>-cert.der FrodoKEM-<N> leaf certificate signed by the ECC
frodokem<N>-cert.pem CA (subject key is FrodoKEM, signature is ECDSA).
frodokem<N>-req.der FrodoKEM-<N> certificate request (PKCS#10),
frodokem<N>-req.pem signed by the ECC key.

Regenerating:
wolfSSL must be built with (at least):
--enable-experimental --enable-frodokem --enable-certgen --enable-certreq
--enable-certext --enable-keygen --enable-ecc
CPPFLAGS="-DHAVE_PKCS8 -DWOLFSSL_DER_TO_PEM"
then:
cc gen_frodokem.c -lwolfssl -o gen_frodokem
(cd certs/frodokem && ./gen_frodokem)

The keys are generated fresh each run, so the output bytes differ every time;
the committed copies are a stable snapshot for the test suite.
Binary file added certs/frodokem/frodokem-ca-ecc-cert.der
Binary file not shown.
14 changes: 14 additions & 0 deletions certs/frodokem/frodokem-ca-ecc-cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICEzCCAbmgAwIBAgIQLsJMxJ0pvxI9bYcdLnYYWTAKBggqhkjOPQQDAjBxMQsw
CQYDVQQGEwJVUzEQMA4GA1UECAwHTW9udGFuYTEQMA4GA1UEBwwHQm96ZW1hbjEQ
MA4GA1UECgwHd29sZlNTTDENMAsGA1UECwwEVGVzdDEdMBsGA1UEAwwURnJvZG9L
RU0gVGVzdCBFQ0MgQ0EwIhgPMjAyNjA3MTIwNDE3MzhaGA8yMTI2MDYxOTA0MTcz
OFowcTELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0Jv
emVtYW4xEDAOBgNVBAoMB3dvbGZTU0wxDTALBgNVBAsMBFRlc3QxHTAbBgNVBAMM
FEZyb2RvS0VNIFRlc3QgRUNDIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
lmrJv8E5Z9nxzcyFWnRcQDwQVK0yZW10dS1i2xWRHquf4YNX4C/TXwUVqCGaSgaT
UxwbCF3QtR5y43n6rKNYmqMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU41ak
BnP4505sNDHigUVlOFv0K9gwCgYIKoZIzj0EAwIDSAAwRQIhAPRzykW9LJ8iATDl
jIE5crF2/5YCg+RYMB2XG2VrVoeLAiBAVo3KhhWGCZgSlQ1JmlGSmFnLM7UaiXzE
TeZ8oyaqXA==
-----END CERTIFICATE-----
Binary file added certs/frodokem/frodokem-ca-ecc-key.der
Binary file not shown.
5 changes: 5 additions & 0 deletions certs/frodokem/frodokem-ca-ecc-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEICBWOGxeT5BVTVs82QLQ71ahUMDedN3inIZhqsR+U89ToAoGCCqGSM49
AwEHoUQDQgAElmrJv8E5Z9nxzcyFWnRcQDwQVK0yZW10dS1i2xWRHquf4YNX4C/T
XwUVqCGaSgaTUxwbCF3QtR5y43n6rKNYmg==
-----END EC PRIVATE KEY-----
Binary file added certs/frodokem/frodokem1344-cert.der
Binary file not shown.
Loading
Loading