Skip to content

Replace liboqs SPHINCS+ with native SLH-DSA in certificate layer#5

Closed
Frauschi wants to merge 1 commit intomasterfrom
claude/sphincs-to-slhdsa-transition-VhszI
Closed

Replace liboqs SPHINCS+ with native SLH-DSA in certificate layer#5
Frauschi wants to merge 1 commit intomasterfrom
claude/sphincs-to-slhdsa-transition-VhszI

Conversation

@Frauschi
Copy link
Copy Markdown
Owner

@Frauschi Frauschi commented Apr 10, 2026

Summary

This PR replaces the liboqs-based pre-standardization SPHINCS+ implementation with the native FIPS 205 SLH-DSA implementation across the certificate/ASN.1/X.509 layers. All liboqs SPHINCS+ code is removed.

This enables SLH-DSA for certificate chain authentication (CA certificates signed with SLH-DSA, certificate verification). TLS 1.3 entity authentication via CertificateVerify with SLH-DSA will be added in the follow-up PR #6.

Follows RFC 9909 (X.509 Algorithm Identifiers for SLH-DSA).

Changes

New DER codec for SLH-DSA

  • wc_SlhDsaKey_PrivateKeyDecode, wc_SlhDsaKey_PublicKeyDecode
  • wc_SlhDsaKey_KeyToDer, wc_SlhDsaKey_PrivateKeyToDer, wc_SlhDsaKey_PublicKeyToDer
  • RFC 9909 compliant encoding: bare OCTET STRING in PKCS#8 (no nested wrapper), compatible with OpenSSL 3.5
  • OID auto-detection across all 6 SHAKE parameter sets

OIDs (RFC 9909)

12 standardized NIST OIDs under 2.16.840.1.101.3.4.3:

  • SHA2 variants: sigAlgs 20-25 (definitions only, no implementation yet)
  • SHAKE variants: sigAlgs 26-31 (fully functional)

AlgorithmIdentifier parameters are absent per RFC 9909. Context string is empty for X.509 certificate signing.

Certificate/ASN.1 layer

  • Replaced ~500 SPHINCS lines in wolfcrypt/src/asn.c and ~70 in asn_orig.c
  • All SPHINCS PEM headers/footers replaced with SLH-DSA equivalents
  • Certificate signing uses wc_SlhDsaKey_Sign(key, NULL, 0, ...)
  • Certificate verification uses wc_SlhDsaKey_Verify(key, NULL, 0, ...)
  • OID collision mechanism cleaned up (NIST OIDs don't collide)
  • Simplified GetKeyOID from 7 per-variant attempts to single auto-detect call

X.509 layer

  • Replaced sphincs_key handling with SlhDsaKey in src/x509.c

Build system

  • HAVE_SPHINCS removed from HAVE_LIBOQS block in settings.h
  • sphincs.c removed from BUILD_LIBOQS sources
  • Updated all IDE project files (VS, VS2022, Xcode, INTIME-RTOS, MPLABX16, Espressif, Zephyr, Renesas, CSharp wrapper)

Test infrastructure

  • test_wc_slhdsa_der_roundtrip: DER encode/decode round-trip for all compiled-in SHAKE parameter sets with deliberate placeholder param mismatch to verify auto-detection
  • Generated 6 SLH-DSA test key DER files in certs/slhdsa/
  • Updated certs_test.h and gencertbuf.pl

Removed

  • wolfcrypt/src/sphincs.c, wolfssl/wolfcrypt/sphincs.h
  • certs/sphincs/ directory
  • SPHINCS+ benchmark code

Follow-up

PR #6 adds SLH-DSA TLS 1.3 entity authentication (CertificateVerify signing/verification, SignatureScheme negotiation, record fragmentation for large signatures, OQS interop).

Test plan

  • Build succeeds: ./configure --enable-slhdsa && make
  • SLH-DSA test passed! including DER round-trip test
  • No remaining SPHINCS references (except DYNAMIC_TYPE_SPHINCS = 98 ABI placeholder)
  • Build works without liboqs (SLH-DSA is native)

https://claude.ai/code/session_019gqvW3ZMKGGyi6zCRNPDYV

Comment thread .wolfssl_known_macro_extras Outdated
Comment thread INSTALL
Comment thread wolfssl/internal.h Outdated
Comment thread wolfssl/internal.h Outdated
Comment thread wolfssl/wolfcrypt/settings.h Outdated
Comment thread wolfcrypt/src/asn.c Outdated
Comment thread wolfcrypt/src/asn.c Outdated
Comment thread wolfcrypt/src/asn.c Outdated
Comment thread wolfcrypt/src/asn.c
Comment thread wolfcrypt/src/asn.c Outdated
Comment thread src/internal.c Outdated
Comment thread src/internal.c Outdated
}
#endif /* HAVE_DILITHIUM */
#if defined(WOLFSSL_HAVE_SLHDSA)
#if !defined(NO_RSA) || defined(HAVE_ECC)
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still open

Comment thread wolfssl/internal.h Outdated
Comment thread wolfssl/internal.h Outdated
Comment thread wolfssl/internal.h
Frauschi pushed a commit that referenced this pull request Apr 14, 2026
Add SLH-DSA as a TLS 1.3 signature algorithm for entity authentication
in the handshake, per draft-reddy-tls-slhdsa-02.

This builds on the certificate-layer SLH-DSA support (PR #5) and adds:

TLS 1.3 SignatureScheme negotiation:
- 6 SHAKE code points (0x0917-0x091C) with PQC_SA_MAJOR = 0x09
- EncodeSigAlg / DecodeTls13SigAlg / DecodeSigAlg
- PickHashSigAlgo with SLH-DSA pkCurveOID matching
- MatchSigAlgo for all 6 SHAKE variants
- SIG_SLHDSA flag in SIG_ALL

CertificateVerify signing and verification:
- SendTls13CertificateVerify with SLH-DSA signing (empty context)
- DoTls13CertificateVerify with SLH-DSA verification
- Record fragmentation for signatures > MAX_RECORD_SIZE (16384 bytes)
  - Saves tail plaintext before in-place encryption
  - Loops through N fragments for arbitrarily large signatures
  - Tested with SHAKE-256f (49856-byte sig, 4 records)

Peer key management:
- peerSlhDsaKey / peerSlhDsaKeyPresent in WOLFSSL struct
- AllocKey / FreeKey / ReuseKey for DYNAMIC_TYPE_SLHDSA
- ProcessPeerCerts extracts SLH-DSA peer keys with param auto-detect

Key loading:
- ProcessBufferTryDecodeSlhDsa for SLH-DSA private key loading
- ProcessBufferCertSetHave / ProcessBufferKeySet for haveSlhDsaSig

Infrastructure:
- haveSlhDsaSig, minSlhDsaKeySz in Options and CTX
- MAX_X509_SIZE = 56*1024 for SLH-DSA (SHAKE-256f cert ~50KB)
- WC_MAX_CERT_VERIFY_SZ = 49920 for SLH-DSA-SHAKE-256f
- OpenSSL 3.5-generated SLH-DSA-SHAKE-128s cert chain for testing

Interop tested with OQS provider (OpenSSL 3.4 + liboqs):
- SHAKE-128s (7856-byte sig, 1 record) - bidirectional
- SHAKE-128f (17088-byte sig, 2 records) - bidirectional
- SHAKE-256f (49856-byte sig, 4 records) - bidirectional

https://claude.ai/code/session_019gqvW3ZMKGGyi6zCRNPDYV
@Frauschi Frauschi changed the title Transition from liboqs SPHINCS+ to native SLH-DSA (FIPS 205) Replace liboqs SPHINCS+ with native SLH-DSA in certificate layer Apr 14, 2026
@Frauschi Frauschi force-pushed the claude/sphincs-to-slhdsa-transition-VhszI branch 2 times, most recently from 38b3c3e to 5f875ba Compare April 16, 2026 05:55
Replace the liboqs-based pre-standardization SPHINCS+ implementation
with the native FIPS 205 SLH-DSA implementation across the
certificate/ASN.1/X.509 layers. All liboqs SPHINCS+ code is removed.

This PR enables SLH-DSA for certificate chain authentication (CA
certificates signed with SLH-DSA, certificate verification). TLS 1.3
entity authentication via CertificateVerify with SLH-DSA will be
added in a follow-up PR.

Follows RFC 9909 (X.509 Algorithm Identifiers for SLH-DSA).

Changes:
- New DER codec for SLH-DSA (PrivateKeyDecode, PublicKeyDecode,
  KeyToDer, PrivateKeyToDer, PublicKeyToDer) with RFC 9909 compliant
  encoding (bare OCTET STRING, no nested wrapper) and OID auto-
  detection across all 6 SHAKE parameter sets
- 12 standardized NIST OIDs (6 SHA2 + 6 SHAKE) per RFC 9909
- Complete ASN.1 layer replacement (~500 lines in asn.c)
- X.509 public key handling in x509.c
- OID collision mechanism cleaned up (NIST OIDs don't collide)
- DER round-trip test for all compiled-in parameter sets
- SLH-DSA test cert chain generated with OpenSSL 3.5
- All build system/IDE project files updated
- SPHINCS+ source files, headers, and test data removed

https://claude.ai/code/session_019gqvW3ZMKGGyi6zCRNPDYV
@Frauschi Frauschi force-pushed the claude/sphincs-to-slhdsa-transition-VhszI branch from 5f875ba to 1d23ad3 Compare April 16, 2026 12:43
@Frauschi Frauschi closed this Apr 23, 2026
@Frauschi Frauschi deleted the claude/sphincs-to-slhdsa-transition-VhszI branch April 23, 2026 17:34
Frauschi pushed a commit that referenced this pull request May 3, 2026
Negative findings from review of 3b2d711:

- Drop redundant `(word16)` inner cast in `wc_xmss_impl.c` (#1):
  `(word16)((word16)hs * n)` -> `(word16)(hs * n)`. The inner cast added
  nothing; word8 promotes to int regardless.
- Normalize `(word32)1` to `(word32)1U` across the file (#5) so the
  pre-existing call sites match the style of the new shifts.
- Defensive guard in `wc_xmss_hash_message` (#2): if `idx_len > params->n`
  ever holds, the explicit `(word32)(params->n - idx_len)` cast that
  silenced the warning would otherwise produce a ~4 GB XMEMSET. Set
  state->ret = WC_FAILURE and bail; the invariant is structural for valid
  parameter sets.
- Defensive guard in `wc_idx_copy` (#3): if `dl < sl` is ever passed, the
  word32 subtraction wraps and the XMEMSET corrupts memory. Same
  structural invariant; early return rather than crash.
- Extend `test_xmss_runtime` (#7, #8) from 2 to 4 configurations:
    1. --enable-xmss (default)
    2. --enable-xmss=yes,small
    3. --enable-xmss=yes,verify-only          (NEW: RFC 8391 test vectors)
    4. --enable-xmss --enable-32bit -m32       (NEW: catches 32-bit
       width-dependent bugs in tree-index arithmetic; XmssIdx narrows to
       word32 there)
  The 32-bit row needs gcc-multilib so the job now installs it.

Verified locally:
- All 13 build_library matrix rows compile clean under the conversion
  flags.
- testwolfcrypt's "XMSS Vfy" / "XMSS" pass for --enable-xmss,
  --enable-xmss=yes,small, --enable-xmss=yes,verify-only, and
  --enable-xmss --enable-32bit (4/4).
- bench_xmss_xmssmt re-run with `-DBENCH_MIN_RUNTIME_SEC=5.0F` for
  longer averaging. Sign/verify deltas range -10% to +15% with no
  coherent regression pattern across parameter sets (the largest moves
  in either direction are on neighbouring rows of the same hash family),
  consistent with shared-system run-to-run noise rather than a real
  perf change. Single-sample keygens (1 op per measurement) carry
  expectedly high variance (-7% to +57%); sign/verify with hundreds to
  thousands of ops per measurement are the meaningful signal.

https://claude.ai/code/session_01EJmy1bKDgHseTwZ5Qqpu1g
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants