diff --git a/doc/crypt.tex b/doc/crypt.tex
index 4e68dce55..111e2d1fa 100644
--- a/doc/crypt.tex
+++ b/doc/crypt.tex
@@ -6622,6 +6622,688 @@ \subsection{DSA Key Import}
This function generates a private DSA key containing both \textit{x} and \textit{y} parts.
+
+\chapter{Post-Quantum Cryptography (PQC)}
+
+LibTomCrypt includes implementations of the three NIST post-quantum cryptographic standards:
+
+\begin{itemize}
+\item \textbf{ML-KEM} (FIPS 203) --- Module-Lattice-Based Key-Encapsulation Mechanism, formerly known as CRYSTALS-Kyber.
+\item \textbf{ML-DSA} (FIPS 204) --- Module-Lattice-Based Digital Signature Algorithm, formerly known as CRYSTALS-Dilithium.
+\item \textbf{SLH-DSA} (FIPS 205) --- Stateless Hash-Based Digital Signature Algorithm, formerly known as SPHINCS+.
+\end{itemize}
+
+These algorithms are designed to be secure against attacks by both classical and quantum computers.
+All three are enabled by defining \code{LTC\_MLKEM}, \code{LTC\_MLDSA}, and \code{LTC\_SLHDSA} respectively
+in \textit{tomcrypt\_custom.h}.
+ML-KEM, ML-DSA, and the SLH-DSA SHAKE variants require \code{LTC\_SHA3} to be enabled.
+The SLH-DSA SHA-2 variants require \code{LTC\_SHA256} (and \code{LTC\_SHA512} for the 192-bit and 256-bit security levels).
+In addition to the raw FIPS key formats, the library also provides DER import/export helpers for
+\textit{SubjectPublicKeyInfo}, \textit{X.509} certificates, and \textit{PKCS \#8} key containers.
+
+All PQC functions follow the same conventions as the rest of LibTomCrypt: they return \code{CRYPT\_OK} on success,
+use \code{unsigned char *} for byte buffers and \code{unsigned long} for lengths,
+and use the standard \code{prng\_state}/\code{wprng} interface for randomness.
+
+\mysection{ML-KEM (FIPS 203)}
+
+ML-KEM is a Key Encapsulation Mechanism (KEM). Unlike traditional public-key encryption, a KEM does not encrypt
+a message directly. Instead, it generates a random shared secret and a ciphertext. The shared secret can then be
+used as a symmetric key.
+
+\subsection{Parameter Sets}
+
+ML-KEM supports three parameter sets with increasing security levels:
+
+\begin{center}
+\begin{tabular}{|l|c|c|c|c|}
+\hline
+\textbf{Parameter Set (alg ID)} & \textbf{Public Key} & \textbf{Secret Key} & \textbf{Ciphertext} & \textbf{Shared Secret} \\
+\hline
+LTC\_MLKEM\_512 & 800 bytes & 1632 bytes & 768 bytes & 32 bytes \\
+LTC\_MLKEM\_768 & 1184 bytes & 2400 bytes & 1088 bytes & 32 bytes \\
+LTC\_MLKEM\_1024 & 1568 bytes & 3168 bytes & 1568 bytes & 32 bytes \\
+\hline
+\end{tabular}
+\end{center}
+
+\subsection{Size Query}
+
+\index{mlkem\_get\_sizes()}
+\begin{verbatim}
+int mlkem_get_sizes(int alg,
+ unsigned long *public_key_sz,
+ unsigned long *secret_key_sz,
+ unsigned long *ciphertext_sz,
+ unsigned long *shared_secret_sz);
+\end{verbatim}
+
+Returns the key, ciphertext, and shared secret sizes in bytes for the parameter set specified by \textit{alg}.
+Any output pointer may be \code{NULL} if the caller does not need that particular size.
+Returns \code{CRYPT\_OK} on success, or \code{CRYPT\_INVALID\_ARG} if \textit{alg} is not a valid ML-KEM parameter set.
+
+\subsection{Key Generation}
+
+\index{mlkem\_make\_key()}
+\begin{verbatim}
+int mlkem_make_key(prng_state *prng, int wprng,
+ int alg, mlkem_key *key);
+\end{verbatim}
+
+Generates an ML-KEM key pair (both encapsulation and decapsulation keys).
+The \textit{prng} and \textit{wprng} parameters specify the PRNG to use for randomness.
+The \textit{alg} parameter selects the parameter set
+(\code{LTC\_MLKEM\_512}, \code{LTC\_MLKEM\_768}, or \code{LTC\_MLKEM\_1024}).
+The resulting key is stored in \textit{key} and has type \code{PK\_PRIVATE}.
+The caller must eventually call \code{mlkem\_free()} to release the key.
+
+\index{mlkem\_make\_key\_from\_seed()}
+\begin{verbatim}
+int mlkem_make_key_from_seed(int alg,
+ const unsigned char *seed, unsigned long seedlen,
+ mlkem_key *key);
+\end{verbatim}
+
+Creates an ML-KEM key pair deterministically from a seed.
+The \textit{seedlen} must be exactly 64 bytes; otherwise the function returns
+\code{CRYPT\_INVALID\_ARG}.
+The \textit{alg} parameter selects the parameter set
+(\code{LTC\_MLKEM\_512}, \code{LTC\_MLKEM\_768}, or \code{LTC\_MLKEM\_1024}).
+The resulting key is stored in \textit{key} and has type \code{PK\_PRIVATE}.
+This function is primarily useful for deterministic key reconstruction and for importing RFC 9935 seed-based private keys.
+
+\subsection{Key Export and Import}
+
+\index{mlkem\_export()}
+\begin{verbatim}
+int mlkem_export(unsigned char *out, unsigned long *outlen,
+ int which, const mlkem_key *key);
+\end{verbatim}
+
+To export a key, the function \textit{mlkem\_export} is provided.
+
+It has support for the following output formats:
+
+\begin{figure}[H]
+\begin{center}
+\begin{tabular}{|c|c|}
+\hline \textbf{which} & \textbf{output format} \\
+\hline PK\_PRIVATE & Raw decapsulation key \\
+\hline PK\_PRIVATE \& PK\_STD & PKCS \#8 \\
+\hline PK\_PUBLIC & Raw encapsulation key \\
+\hline PK\_PUBLIC \& PK\_STD & SubjectPublicKeyInfo \\
+\hline
+\end{tabular}
+\end{center}
+\caption{Possible mlkem\_export() output formats}
+\end{figure}
+
+The standard formats are DER encoded.
+For \code{PK\_PRIVATE \& PK\_STD}, the current implementation emits a PKCS \#8 structure
+containing the expanded ML-KEM private key.
+
+\index{mlkem\_export\_raw()}
+\begin{verbatim}
+int mlkem_export_raw(unsigned char *out, unsigned long *outlen,
+ int which, const mlkem_key *key);
+\end{verbatim}
+
+Exports a key to a raw byte buffer in the format defined by FIPS 203.
+The \textit{out} buffer must be large enough to hold the key; on entry, \textit{*outlen} is the
+buffer size, and on exit it is set to the number of bytes written.
+Set \textit{which} to \code{PK\_PUBLIC} to export the encapsulation (public) key,
+or \code{PK\_PRIVATE} to export the decapsulation (secret) key.
+The required buffer sizes can be obtained from \code{mlkem\_get\_sizes()} or the parameter table above.
+Returns \code{CRYPT\_BUFFER\_OVERFLOW} if the buffer is too small (with \textit{*outlen} set to the required size).
+
+\index{mlkem\_import()}
+\begin{verbatim}
+int mlkem_import(const unsigned char *in, unsigned long inlen,
+ mlkem_key *key);
+\end{verbatim}
+
+The \textit{mlkem\_import} function can be used to import a public key in DER-encoded
+\textit{SubjectPublicKeyInfo} format.
+
+\index{mlkem\_import\_raw()}
+\begin{verbatim}
+int mlkem_import_raw(const unsigned char *in, unsigned long inlen,
+ int which, int alg, mlkem_key *key);
+\end{verbatim}
+
+Imports a key from a raw byte buffer.
+The \textit{inlen} must exactly match the expected key size for the given \textit{alg} and \textit{which}.
+Set \textit{which} to \code{PK\_PUBLIC} to import an encapsulation key, or \code{PK\_PRIVATE}
+to import a decapsulation key. When importing a private key, the embedded public key is automatically
+extracted so the key can also be used for encapsulation.
+The caller must eventually call \code{mlkem\_free()} to release the imported key.
+
+\index{mlkem\_import\_x509()}
+\begin{verbatim}
+int mlkem_import_x509(const unsigned char *in, unsigned long inlen,
+ mlkem_key *key);
+\end{verbatim}
+
+To import a public key from a DER-encoded \textit{X.509} certificate, one can use the function
+\textit{mlkem\_import\_x509}.
+
+\index{mlkem\_import\_pkcs8()}
+\begin{verbatim}
+int mlkem_import_pkcs8(const unsigned char *in, unsigned long inlen,
+ const password_ctx *pw_ctx, mlkem_key *key);
+\end{verbatim}
+
+To import a private key in the \textit{OneAsymmetricKey} a.k.a. \textit{PKCS \#8} format,
+either plain or PBES encrypted, one can use the function \textit{mlkem\_import\_pkcs8}.
+The importer accepts the raw expanded private key encoding as well as the RFC 9935 seed-based
+and combined encodings.
+
+\subsection{Encapsulation}
+
+\index{mlkem\_encaps()}
+\begin{verbatim}
+int mlkem_encaps(unsigned char *ct, unsigned long *ctlen,
+ unsigned char *shared_secret, unsigned long *sslen,
+ prng_state *prng, int wprng,
+ const mlkem_key *key);
+\end{verbatim}
+
+Performs ML-KEM encapsulation: generates a random 32-byte shared secret and a ciphertext
+that encapsulates it under the given public key.
+The \textit{ct} buffer receives the ciphertext and \textit{shared\_secret} receives the shared secret.
+On entry, \textit{*ctlen} and \textit{*sslen} specify the buffer sizes; on exit they are set to the actual sizes.
+The \textit{key} must contain at least a public key (either \code{PK\_PUBLIC} or \code{PK\_PRIVATE}).
+Returns \code{CRYPT\_BUFFER\_OVERFLOW} if either buffer is too small.
+
+\subsection{Decapsulation}
+
+\index{mlkem\_decaps()}
+\begin{verbatim}
+int mlkem_decaps(unsigned char *shared_secret, unsigned long *sslen,
+ const unsigned char *ct, unsigned long ctlen,
+ const mlkem_key *key);
+\end{verbatim}
+
+Performs ML-KEM decapsulation: recovers the shared secret from a ciphertext using a private key.
+The \textit{key} must be of type \code{PK\_PRIVATE}.
+On entry, \textit{*sslen} specifies the buffer size; on exit it is set to 32 (the shared secret size).
+If the ciphertext is invalid, a pseudorandom value is returned instead of an error code ---
+this is the ``implicit rejection'' behavior required by the ML-KEM specification to prevent
+chosen-ciphertext attacks. The function always returns \code{CRYPT\_OK} on successful decapsulation
+(regardless of whether the ciphertext was valid).
+Returns \code{CRYPT\_PK\_NOT\_PRIVATE} if the key is not a private key,
+or \code{CRYPT\_INVALID\_PACKET} if \textit{ctlen} does not match the expected ciphertext size.
+
+\subsection{Key Cleanup}
+
+\index{mlkem\_free()}
+\begin{verbatim}
+void mlkem_free(mlkem_key *key);
+\end{verbatim}
+
+Frees all memory associated with an ML-KEM key and zeros sensitive data.
+After this call the \textit{key} structure is zeroed and must not be used until re-initialized
+by \code{mlkem\_make\_key()} or \code{mlkem\_import\_raw()}.
+
+\subsection{Example}
+
+\begin{small}
+\begin{verbatim}
+mlkem_key key, pubkey;
+unsigned char ct[1568], ss1[32], ss2[32], pk[1568];
+unsigned long ctlen, sslen, pklen;
+int prng_idx = find_prng("yarrow");
+
+/* Generate key pair */
+mlkem_make_key(&yarrow_prng, prng_idx, LTC_MLKEM_768, &key);
+
+/* Export public key */
+pklen = sizeof(pk);
+mlkem_export_raw(pk, &pklen, PK_PUBLIC, &key);
+mlkem_import_raw(pk, pklen, PK_PUBLIC, LTC_MLKEM_768, &pubkey);
+
+/* Encapsulate */
+ctlen = sizeof(ct);
+sslen = sizeof(ss1);
+mlkem_encaps(ct, &ctlen, ss1, &sslen, &yarrow_prng, prng_idx, &pubkey);
+
+/* Decapsulate */
+sslen = sizeof(ss2);
+mlkem_decaps(ss2, &sslen, ct, ctlen, &key);
+/* ss1 and ss2 are now equal */
+
+mlkem_free(&key);
+mlkem_free(&pubkey);
+\end{verbatim}
+\end{small}
+
+
+\mysection{ML-DSA (FIPS 204)}
+
+ML-DSA is a digital signature algorithm based on module lattices. It supports hedged signing
+(using randomness to protect against side-channel attacks) and optional context strings.
+
+\subsection{Parameter Sets}
+
+\begin{center}
+\begin{tabular}{|l|c|c|c|}
+\hline
+\textbf{Parameter Set (alg ID)} & \textbf{Public Key} & \textbf{Secret Key} & \textbf{Signature} \\
+\hline
+LTC\_MLDSA\_44 & 1312 bytes & 2560 bytes & 2420 bytes \\
+LTC\_MLDSA\_65 & 1952 bytes & 4032 bytes & 3309 bytes \\
+LTC\_MLDSA\_87 & 2592 bytes & 4896 bytes & 4627 bytes \\
+\hline
+\end{tabular}
+\end{center}
+
+\subsection{Size Query}
+
+\index{mldsa\_get\_sizes()}
+\begin{verbatim}
+int mldsa_get_sizes(int alg,
+ unsigned long *public_key_sz,
+ unsigned long *secret_key_sz,
+ unsigned long *signature_sz);
+\end{verbatim}
+
+Returns the public key, secret key, and signature sizes in bytes for the parameter set specified by \textit{alg}.
+Any output pointer may be \code{NULL} if the caller does not need that particular size.
+Returns \code{CRYPT\_OK} on success, or \code{CRYPT\_INVALID\_ARG} if \textit{alg} is not a valid ML-DSA parameter set.
+
+\subsection{Key Generation}
+
+\index{mldsa\_make\_key()}
+\begin{verbatim}
+int mldsa_make_key(prng_state *prng, int wprng,
+ int alg, mldsa_key *key);
+\end{verbatim}
+
+Generates an ML-DSA key pair (both signing and verification keys).
+The \textit{prng} and \textit{wprng} parameters specify the PRNG to use for randomness.
+The \textit{alg} parameter selects the parameter set
+(\code{LTC\_MLDSA\_44}, \code{LTC\_MLDSA\_65}, or \code{LTC\_MLDSA\_87}).
+The resulting key is stored in \textit{key} and has type \code{PK\_PRIVATE}.
+The caller must eventually call \code{mldsa\_free()} to release the key.
+
+\index{mldsa\_make\_key\_from\_seed()}
+\begin{verbatim}
+int mldsa_make_key_from_seed(int alg,
+ const unsigned char *seed, unsigned long seedlen,
+ mldsa_key *key);
+\end{verbatim}
+
+Creates an ML-DSA key pair deterministically from a seed.
+The \textit{seedlen} must be exactly 32 bytes; otherwise the function returns
+\code{CRYPT\_INVALID\_ARG}.
+The \textit{alg} parameter selects the parameter set
+(\code{LTC\_MLDSA\_44}, \code{LTC\_MLDSA\_65}, or \code{LTC\_MLDSA\_87}).
+The resulting key is stored in \textit{key} and has type \code{PK\_PRIVATE}.
+This function is primarily useful for deterministic key reconstruction and for importing RFC 9881 seed-based private keys.
+
+\subsection{Key Export and Import}
+
+\index{mldsa\_export()}
+\begin{verbatim}
+int mldsa_export(unsigned char *out, unsigned long *outlen,
+ int which, const mldsa_key *key);
+\end{verbatim}
+
+To export a key, the function \textit{mldsa\_export} is provided.
+
+It has support for the following output formats:
+
+\begin{figure}[H]
+\begin{center}
+\begin{tabular}{|c|c|}
+\hline \textbf{which} & \textbf{output format} \\
+\hline PK\_PRIVATE & Raw signing key \\
+\hline PK\_PRIVATE \& PK\_STD & PKCS \#8 \\
+\hline PK\_PUBLIC & Raw verification key \\
+\hline PK\_PUBLIC \& PK\_STD & SubjectPublicKeyInfo \\
+\hline
+\end{tabular}
+\end{center}
+\caption{Possible mldsa\_export() output formats}
+\end{figure}
+
+The standard formats are DER encoded.
+For \code{PK\_PRIVATE \& PK\_STD}, the current implementation emits a PKCS \#8 structure
+containing the expanded ML-DSA private key.
+
+\index{mldsa\_export\_raw()}
+\begin{verbatim}
+int mldsa_export_raw(unsigned char *out, unsigned long *outlen,
+ int which, const mldsa_key *key);
+\end{verbatim}
+
+Exports a key to a raw byte buffer in the format defined by FIPS 204.
+On entry, \textit{*outlen} is the buffer size; on exit it is set to the number of bytes written.
+Set \textit{which} to \code{PK\_PUBLIC} to export the verification (public) key,
+or \code{PK\_PRIVATE} to export the signing (secret) key.
+The required buffer sizes can be obtained from \code{mldsa\_get\_sizes()} or the parameter table above.
+Returns \code{CRYPT\_BUFFER\_OVERFLOW} if the buffer is too small (with \textit{*outlen} set to the required size).
+
+\index{mldsa\_import()}
+\begin{verbatim}
+int mldsa_import(const unsigned char *in, unsigned long inlen,
+ mldsa_key *key);
+\end{verbatim}
+
+The \textit{mldsa\_import} function can be used to import a public key in DER-encoded
+\textit{SubjectPublicKeyInfo} format.
+
+\index{mldsa\_import\_raw()}
+\begin{verbatim}
+int mldsa_import_raw(const unsigned char *in, unsigned long inlen,
+ int which, int alg, mldsa_key *key);
+\end{verbatim}
+
+Imports a key from a raw byte buffer.
+The \textit{inlen} must exactly match the expected key size for the given \textit{alg} and \textit{which}.
+Set \textit{which} to \code{PK\_PUBLIC} to import a verification key, or \code{PK\_PRIVATE}
+to import a signing key. When importing a private key, the corresponding public key is
+reconstructed automatically so the key can also be used for verification.
+The caller must eventually call \code{mldsa\_free()} to release the imported key.
+
+\index{mldsa\_import\_x509()}
+\begin{verbatim}
+int mldsa_import_x509(const unsigned char *in, unsigned long inlen,
+ mldsa_key *key);
+\end{verbatim}
+
+To import a public key from a DER-encoded \textit{X.509} certificate, one can use the function
+\textit{mldsa\_import\_x509}.
+
+\index{mldsa\_import\_pkcs8()}
+\begin{verbatim}
+int mldsa_import_pkcs8(const unsigned char *in, unsigned long inlen,
+ const password_ctx *pw_ctx, mldsa_key *key);
+\end{verbatim}
+
+To import a private key in the \textit{OneAsymmetricKey} a.k.a. \textit{PKCS \#8} format,
+either plain or PBES encrypted, one can use the function \textit{mldsa\_import\_pkcs8}.
+The importer accepts the raw expanded private key encoding as well as the RFC 9881 seed-based
+and combined encodings.
+
+\subsection{Signing}
+
+\index{mldsa\_sign()}
+\begin{verbatim}
+int mldsa_sign(const unsigned char *msg, unsigned long msglen,
+ unsigned char *sig, unsigned long *siglen,
+ const unsigned char *ctx, unsigned long ctxlen,
+ prng_state *prng, int wprng,
+ const mldsa_key *key);
+\end{verbatim}
+
+Signs a message using a private key.
+The signature is written to \textit{sig}; on entry \textit{*siglen} is the buffer size,
+on exit it is set to the actual signature size.
+The \textit{ctx} parameter is an optional context string (up to 255 bytes per FIPS 204)
+that binds the signature to a particular application context; pass \code{NULL} and 0 if not needed.
+The \textit{prng} and \textit{wprng} parameters provide randomness for hedged signing, which helps
+protect against side-channel attacks.
+The \textit{key} must be of type \code{PK\_PRIVATE}.
+Returns \code{CRYPT\_BUFFER\_OVERFLOW} if the signature buffer is too small.
+
+\subsection{Verification}
+
+\index{mldsa\_verify()}
+\begin{verbatim}
+int mldsa_verify(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *msg, unsigned long msglen,
+ const unsigned char *ctx, unsigned long ctxlen,
+ int *stat,
+ const mldsa_key *key);
+\end{verbatim}
+
+Verifies an ML-DSA signature against a message and public key.
+Sets \textit{*stat} to 1 if the signature is valid, or 0 if it is invalid.
+The \textit{ctx} and \textit{ctxlen} parameters must match the context string used during signing.
+The function returns \code{CRYPT\_OK} even if the signature is invalid --- the caller must
+check \textit{*stat} to determine validity.
+
+\subsection{Key Cleanup}
+
+\index{mldsa\_free()}
+\begin{verbatim}
+void mldsa_free(mldsa_key *key);
+\end{verbatim}
+
+Frees all memory associated with an ML-DSA key and zeros sensitive data.
+After this call the \textit{key} structure is zeroed and must not be used until re-initialized.
+
+\subsection{Example}
+
+\begin{small}
+\begin{verbatim}
+mldsa_key key;
+unsigned char sig[4627];
+unsigned long siglen;
+int stat, prng_idx = find_prng("yarrow");
+
+mldsa_make_key(&yarrow_prng, prng_idx, LTC_MLDSA_65, &key);
+
+siglen = sizeof(sig);
+mldsa_sign(msg, msglen, sig, &siglen, NULL, 0,
+ &yarrow_prng, prng_idx, &key);
+
+mldsa_verify(sig, siglen, msg, msglen, NULL, 0, &stat, &key);
+/* stat == 1 means valid */
+
+mldsa_free(&key);
+\end{verbatim}
+\end{small}
+
+
+\mysection{SLH-DSA (FIPS 205)}
+
+SLH-DSA is a stateless hash-based digital signature algorithm. Unlike ML-KEM and ML-DSA which are
+lattice-based, SLH-DSA relies only on the security of hash functions. This makes it a conservative
+choice but results in larger signatures.
+
+\subsection{Parameter Sets}
+
+SLH-DSA has 24 parameter sets: 12 Pure SLH-DSA variants and 12 HashSLH-DSA variants.
+Each family contains 6 SHA-2 based parameter sets and 6 SHAKE based parameter sets, with ``small'' (S) and
+``fast'' (F) variants at each security level.
+The S variants produce smaller signatures but are slower; the F variants are faster but produce larger signatures.
+SHA-2 and SHAKE variants at the same security level have identical key and signature sizes but differ in the
+hash function used internally.
+The HashSLH-DSA parameter sets use the same API as the pure variants; the selected algorithm identifier determines
+the pre-hash function used by the signature scheme.
+
+\begin{center}
+\begin{tabular}{|l|c|c|c|}
+\hline
+\textbf{Parameter Set (alg ID)} & \textbf{Public Key} & \textbf{Secret Key} & \textbf{Signature} \\
+\hline
+LTC\_SLHDSA\_SHA2\_128S & 32 bytes & 64 bytes & 7856 bytes \\
+LTC\_SLHDSA\_SHA2\_128F & 32 bytes & 64 bytes & 17088 bytes \\
+LTC\_SLHDSA\_SHA2\_192S & 48 bytes & 96 bytes & 16224 bytes \\
+LTC\_SLHDSA\_SHA2\_192F & 48 bytes & 96 bytes & 35664 bytes \\
+LTC\_SLHDSA\_SHA2\_256S & 64 bytes & 128 bytes & 29792 bytes \\
+LTC\_SLHDSA\_SHA2\_256F & 64 bytes & 128 bytes & 49856 bytes \\
+\hline
+LTC\_SLHDSA\_SHAKE\_128S & 32 bytes & 64 bytes & 7856 bytes \\
+LTC\_SLHDSA\_SHAKE\_128F & 32 bytes & 64 bytes & 17088 bytes \\
+LTC\_SLHDSA\_SHAKE\_192S & 48 bytes & 96 bytes & 16224 bytes \\
+LTC\_SLHDSA\_SHAKE\_192F & 48 bytes & 96 bytes & 35664 bytes \\
+LTC\_SLHDSA\_SHAKE\_256S & 64 bytes & 128 bytes & 29792 bytes \\
+LTC\_SLHDSA\_SHAKE\_256F & 64 bytes & 128 bytes & 49856 bytes \\
+\hline
+\end{tabular}
+\end{center}
+
+The HashSLH-DSA parameter sets use the same public-key, private-key, and signature sizes as the corresponding
+Pure SLH-DSA parameter sets at the same security level and performance profile.
+
+\subsection{Size Query}
+
+\index{slhdsa\_get\_sizes()}
+\begin{verbatim}
+int slhdsa_get_sizes(int alg,
+ unsigned long *public_key_sz,
+ unsigned long *secret_key_sz,
+ unsigned long *signature_sz);
+\end{verbatim}
+
+Returns the public key, secret key, and signature sizes in bytes for the parameter set specified by \textit{alg}.
+Any output pointer may be \code{NULL} if the caller does not need that particular size.
+This function works for all 24 parameter sets (Pure SLH-DSA and HashSLH-DSA, both SHA-2 and SHAKE variants).
+Returns \code{CRYPT\_OK} on success, or \code{CRYPT\_INVALID\_ARG} if \textit{alg} is not a valid SLH-DSA parameter set.
+
+\subsection{Key Generation}
+
+\index{slhdsa\_make\_key()}
+\begin{verbatim}
+int slhdsa_make_key(prng_state *prng, int wprng,
+ int alg, slhdsa_key *key);
+\end{verbatim}
+
+Generates an SLH-DSA key pair (both signing and verification keys).
+The \textit{prng} and \textit{wprng} parameters specify the PRNG to use for randomness.
+The \textit{alg} parameter selects one of the 24 parameter sets (e.g. \code{LTC\_SLHDSA\_SHAKE\_128F},
+\code{LTC\_SLHDSA\_SHA2\_256S}, \code{LTC\_SLHDSA\_HASH\_SHA2\_128S\_WITH\_SHA256},
+\code{LTC\_SLHDSA\_HASH\_SHAKE\_256F\_WITH\_SHAKE256}, etc.).
+The resulting key is stored in \textit{key} and has type \code{PK\_PRIVATE}.
+Note that SLH-DSA key generation involves computing a Merkle tree root, which can be slow
+for the ``small'' (S) parameter sets.
+The caller must eventually call \code{slhdsa\_free()} to release the key.
+
+\subsection{Key Export and Import}
+
+\index{slhdsa\_export()}
+\begin{verbatim}
+int slhdsa_export(unsigned char *out, unsigned long *outlen,
+ int which, const slhdsa_key *key);
+\end{verbatim}
+
+To export a key, the function \textit{slhdsa\_export} is provided.
+
+It has support for the following output formats:
+
+\begin{figure}[H]
+\begin{center}
+\begin{tabular}{|c|c|}
+\hline \textbf{which} & \textbf{output format} \\
+\hline PK\_PRIVATE & Raw signing key \\
+\hline PK\_PRIVATE \& PK\_STD & PKCS \#8 \\
+\hline PK\_PUBLIC & Raw verification key \\
+\hline PK\_PUBLIC \& PK\_STD & SubjectPublicKeyInfo \\
+\hline
+\end{tabular}
+\end{center}
+\caption{Possible slhdsa\_export() output formats}
+\end{figure}
+
+The standard formats are DER encoded.
+
+\index{slhdsa\_export\_raw()}
+\begin{verbatim}
+int slhdsa_export_raw(unsigned char *out, unsigned long *outlen,
+ int which, const slhdsa_key *key);
+\end{verbatim}
+
+Exports a key to a raw byte buffer in the format defined by FIPS 205.
+On entry, \textit{*outlen} is the buffer size; on exit it is set to the number of bytes written.
+Set \textit{which} to \code{PK\_PUBLIC} to export the verification (public) key,
+or \code{PK\_PRIVATE} to export the signing (secret) key.
+The required buffer sizes can be obtained from \code{slhdsa\_get\_sizes()} or the parameter table above.
+Returns \code{CRYPT\_BUFFER\_OVERFLOW} if the buffer is too small (with \textit{*outlen} set to the required size).
+
+\index{slhdsa\_import()}
+\begin{verbatim}
+int slhdsa_import(const unsigned char *in, unsigned long inlen,
+ slhdsa_key *key);
+\end{verbatim}
+
+The \textit{slhdsa\_import} function can be used to import a public key in DER-encoded
+\textit{SubjectPublicKeyInfo} format.
+
+\index{slhdsa\_import\_raw()}
+\begin{verbatim}
+int slhdsa_import_raw(const unsigned char *in, unsigned long inlen,
+ int which, int alg, slhdsa_key *key);
+\end{verbatim}
+
+Imports a key from a raw byte buffer.
+The \textit{inlen} must exactly match the expected key size for the given \textit{alg} and \textit{which}.
+Set \textit{which} to \code{PK\_PUBLIC} to import a verification key, or \code{PK\_PRIVATE}
+to import a signing key. When importing a private key, the public key is automatically
+extracted (it is embedded in the secret key format).
+The caller must eventually call \code{slhdsa\_free()} to release the imported key.
+
+\index{slhdsa\_import\_x509()}
+\begin{verbatim}
+int slhdsa_import_x509(const unsigned char *in, unsigned long inlen,
+ slhdsa_key *key);
+\end{verbatim}
+
+To import a public key from a DER-encoded \textit{X.509} certificate, one can use the function
+\textit{slhdsa\_import\_x509}.
+
+\index{slhdsa\_import\_pkcs8()}
+\begin{verbatim}
+int slhdsa_import_pkcs8(const unsigned char *in, unsigned long inlen,
+ const password_ctx *pw_ctx, slhdsa_key *key);
+\end{verbatim}
+
+To import a private key in the \textit{OneAsymmetricKey} a.k.a. \textit{PKCS \#8} format,
+either plain or PBES encrypted, one can use the function \textit{slhdsa\_import\_pkcs8}.
+The private key payload uses the raw SLH-DSA private-key octets defined for the selected parameter set.
+
+\subsection{Signing}
+
+\index{slhdsa\_sign()}
+\begin{verbatim}
+int slhdsa_sign(const unsigned char *msg, unsigned long msglen,
+ unsigned char *sig, unsigned long *siglen,
+ const unsigned char *ctx, unsigned long ctxlen,
+ prng_state *prng, int wprng,
+ const slhdsa_key *key);
+\end{verbatim}
+
+Signs a message using a private key.
+The signature is written to \textit{sig}; on entry \textit{*siglen} is the buffer size,
+on exit it is set to the actual signature size. SLH-DSA signatures are large
+(between 7,856 and 49,856 bytes depending on the parameter set), so the buffer should be
+allocated accordingly using the size returned by \code{slhdsa\_get\_sizes()}.
+The \textit{ctx} parameter is an optional context string (up to 255 bytes per FIPS 205);
+pass \code{NULL} and 0 if not needed.
+The \textit{prng} and \textit{wprng} parameters provide randomness for non-deterministic signing.
+The \textit{key} must be of type \code{PK\_PRIVATE}.
+Returns \code{CRYPT\_BUFFER\_OVERFLOW} if the signature buffer is too small.
+
+\subsection{Verification}
+
+\index{slhdsa\_verify()}
+\begin{verbatim}
+int slhdsa_verify(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *msg, unsigned long msglen,
+ const unsigned char *ctx, unsigned long ctxlen,
+ int *stat,
+ const slhdsa_key *key);
+\end{verbatim}
+
+Verifies an SLH-DSA signature against a message and public key.
+Sets \textit{*stat} to 1 if the signature is valid, or 0 if it is invalid.
+The \textit{ctx} and \textit{ctxlen} parameters must match the context string used during signing.
+The function returns \code{CRYPT\_OK} even if the signature is invalid --- the caller must
+check \textit{*stat} to determine validity.
+
+\subsection{Key Cleanup}
+
+\index{slhdsa\_free()}
+\begin{verbatim}
+void slhdsa_free(slhdsa_key *key);
+\end{verbatim}
+
+Frees all memory associated with an SLH-DSA key and zeros sensitive data.
+After this call the \textit{key} structure is zeroed and must not be used until re-initialized.
+
+\clearpage
\chapter{The PKA Union}
\index{ltc\_pka\_key}
@@ -6637,7 +7319,11 @@ \chapter{The PKA Union}
LTC_PKA_EC,
LTC_PKA_X25519,
LTC_PKA_ED25519,
+ LTC_PKA_MLDSA,
+ LTC_PKA_SLHDSA,
+ LTC_PKA_MLKEM,
LTC_PKA_DH,
+ LTC_PKA_NUM
};
typedef struct {
@@ -6658,6 +7344,37 @@ \chapter{The PKA Union}
#ifdef LTC_MRSA
rsa_key rsa;
#endif
+#ifdef LTC_MLKEM
+ struct {
+ int alg;
+ int type;
+ unsigned char *pk;
+ unsigned long pklen;
+ unsigned char *sk;
+ unsigned long sklen;
+ } mlkem;
+#endif
+#ifdef LTC_MLDSA
+ struct {
+ int alg;
+ int type;
+ unsigned char *pk;
+ unsigned long pklen;
+ unsigned char *sk;
+ unsigned long sklen;
+ } mldsa;
+#endif
+#ifdef LTC_SLHDSA
+ struct {
+ int alg;
+ int type;
+ unsigned char *pk;
+ unsigned long pklen;
+ unsigned char *sk;
+ unsigned long sklen;
+ } slhdsa;
+#endif
+ char dummy;
} u;
enum ltc_pka_id id;
} ltc_pka_key;
@@ -7929,12 +8646,12 @@ \subsection{PKCS PEM files}
\begin{small}
\begin{tabular}{|l|l|l|l|l|}
\hline \textbf{Identifier} & \textbf{Key type} & \textbf{File content} & \textbf{Standard} & \textbf{Algorithm} \\
-\hline \texttt{BEGIN CERTIFICATE} & Public & Plain & \texttt{X.509} & DH, DSA, ECC, Ed25519, RSA, X25519 \\
+\hline \texttt{BEGIN CERTIFICATE} & Public & Plain & \texttt{X.509} & DH, DSA, ECC, Ed25519, ML-DSA, ML-KEM, RSA, SLH-DSA, X25519 \\
\hline \texttt{BEGIN DSA PRIVATE KEY} & Private & Maybe encrypted & \texttt{OpenSSL\footnote{There are two de-facto standard for DSA private key structures, LibTomCrypt implements OpenSSL's}} & DSA \\
\hline \texttt{BEGIN EC PRIVATE KEY} & Private & Maybe encrypted & \texttt{RFC 5915} & ECC \\
-\hline \texttt{BEGIN ENCRYPTED PRIVATE KEY} & Private & Encrypted & \texttt{PKCS \#8} & DH, DSA, ECC, Ed25519, RSA, X25519 \\
-\hline \texttt{BEGIN PRIVATE KEY} & Private & Plain & \texttt{PKCS \#8} & DH, DSA, ECC, Ed25519, RSA, X25519 \\
-\hline \texttt{BEGIN PUBLIC KEY} & Public & Plain & \texttt{X.509\footnote{Specifically, SubjectPublicKeyInfo}} & DH, DSA, ECC, Ed25519, RSA, X25519 \\
+\hline \texttt{BEGIN ENCRYPTED PRIVATE KEY} & Private & Encrypted & \texttt{PKCS \#8} & DH, DSA, ECC, Ed25519, ML-DSA, ML-KEM, RSA, SLH-DSA, X25519 \\
+\hline \texttt{BEGIN PRIVATE KEY} & Private & Plain & \texttt{PKCS \#8} & DH, DSA, ECC, Ed25519, ML-DSA, ML-KEM, RSA, SLH-DSA, X25519 \\
+\hline \texttt{BEGIN PUBLIC KEY} & Public & Plain & \texttt{X.509\footnote{Specifically, SubjectPublicKeyInfo}} & DH, DSA, ECC, Ed25519, ML-DSA, ML-KEM, RSA, SLH-DSA, X25519 \\
\hline \texttt{BEGIN RSA PRIVATE KEY} & Private & Maybe encrypted & \texttt{PKCS \#1} & RSA \\
\hline \texttt{BEGIN RSA PUBLIC KEY} & Public & Plain & \texttt{PKCS \#1} & RSA \\
\hline
@@ -10511,8 +11228,6 @@ \subsection{Elliptic Curve Cryptography - $GF(p)$}
These two ECC verify functions have been deprecated in favor of \code{ecc\_verify\_hash\_v2()}.
Please check Chapter \ref{ecc-verify} for details.
-
-\clearpage
\addcontentsline{toc}{chapter}{Index}
\printindex
diff --git a/libtomcrypt_VS2008.vcproj b/libtomcrypt_VS2008.vcproj
index 69a5e2d69..7df8188b3 100644
--- a/libtomcrypt_VS2008.vcproj
+++ b/libtomcrypt_VS2008.vcproj
@@ -1059,6 +1059,10 @@
RelativePath="src\headers\tomcrypt_pkcs.h"
>
+
+
@@ -2812,6 +2816,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/makefile.mingw b/makefile.mingw
index 5d388f55e..3f3a8c1d3 100644
--- a/makefile.mingw
+++ b/makefile.mingw
@@ -219,7 +219,11 @@ src/pk/rsa/rsa_make_key.o src/pk/rsa/rsa_set.o src/pk/rsa/rsa_sign_hash.o \
src/pk/rsa/rsa_sign_saltlen_get.o src/pk/rsa/rsa_verify_hash.o src/pk/x25519/x25519_export.o \
src/pk/x25519/x25519_import.o src/pk/x25519/x25519_import_pkcs8.o src/pk/x25519/x25519_import_raw.o \
src/pk/x25519/x25519_import_x509.o src/pk/x25519/x25519_make_key.o \
-src/pk/x25519/x25519_shared_secret.o src/prngs/chacha20.o src/prngs/fortuna.o src/prngs/rc4.o \
+src/pk/x25519/x25519_shared_secret.o src/pqc/mldsa.o src/pqc/mldsa_export.o src/pqc/mldsa_import.o \
+src/pqc/mldsa_import_pkcs8.o src/pqc/mldsa_import_x509.o src/pqc/mlkem.o src/pqc/mlkem_export.o \
+src/pqc/mlkem_import.o src/pqc/mlkem_import_pkcs8.o src/pqc/mlkem_import_x509.o src/pqc/slhdsa.o \
+src/pqc/slhdsa_export.o src/pqc/slhdsa_import.o src/pqc/slhdsa_import_pkcs8.o \
+src/pqc/slhdsa_import_x509.o src/prngs/chacha20.o src/prngs/fortuna.o src/prngs/rc4.o \
src/prngs/rng_get_bytes.o src/prngs/rng_make_prng.o src/prngs/sober128.o src/prngs/sprng.o \
src/prngs/yarrow.o src/stream/chacha/chacha_crypt.o src/stream/chacha/chacha_done.o \
src/stream/chacha/chacha_ivctr32.o src/stream/chacha/chacha_ivctr64.o \
@@ -242,15 +246,16 @@ tests/dh_test.o tests/dsa_test.o tests/ecc_test.o tests/ed25519_test.o tests/fil
tests/misc_test.o tests/modes_test.o tests/mpi_test.o tests/multi_test.o \
tests/no_null_termination_check_test.o tests/no_prng.o tests/padding_test.o tests/pem_test.o \
tests/pk_oid_test.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o tests/pkcs_1_oaep_test.o \
-tests/pkcs_1_pss_test.o tests/pkcs_1_test.o tests/prng_test.o tests/rotate_test.o tests/rsa_test.o \
-tests/scrypt_test.o tests/ssh_test.o tests/store_test.o tests/test.o tests/x25519_test.o
+tests/pkcs_1_pss_test.o tests/pkcs_1_test.o tests/pqc_mldsa_test.o tests/pqc_mlkem_test.o \
+tests/pqc_slhdsa_test.o tests/prng_test.o tests/rotate_test.o tests/rsa_test.o tests/scrypt_test.o \
+tests/ssh_test.o tests/store_test.o tests/test.o tests/x25519_test.o
#The following headers will be installed by "make install"
HEADERS_PUB=src/headers/tomcrypt.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cfg.h \
src/headers/tomcrypt_cipher.h src/headers/tomcrypt_custom.h src/headers/tomcrypt_hash.h \
src/headers/tomcrypt_mac.h src/headers/tomcrypt_macros.h src/headers/tomcrypt_math.h \
src/headers/tomcrypt_misc.h src/headers/tomcrypt_pk.h src/headers/tomcrypt_pkcs.h \
-src/headers/tomcrypt_prng.h
+src/headers/tomcrypt_pqc.h src/headers/tomcrypt_prng.h
HEADERS=$(HEADERS_PUB) src/headers/tomcrypt_private.h
diff --git a/makefile.msvc b/makefile.msvc
index 9f530931c..538f498c7 100644
--- a/makefile.msvc
+++ b/makefile.msvc
@@ -212,7 +212,11 @@ src/pk/rsa/rsa_make_key.obj src/pk/rsa/rsa_set.obj src/pk/rsa/rsa_sign_hash.obj
src/pk/rsa/rsa_sign_saltlen_get.obj src/pk/rsa/rsa_verify_hash.obj src/pk/x25519/x25519_export.obj \
src/pk/x25519/x25519_import.obj src/pk/x25519/x25519_import_pkcs8.obj src/pk/x25519/x25519_import_raw.obj \
src/pk/x25519/x25519_import_x509.obj src/pk/x25519/x25519_make_key.obj \
-src/pk/x25519/x25519_shared_secret.obj src/prngs/chacha20.obj src/prngs/fortuna.obj src/prngs/rc4.obj \
+src/pk/x25519/x25519_shared_secret.obj src/pqc/mldsa.obj src/pqc/mldsa_export.obj src/pqc/mldsa_import.obj \
+src/pqc/mldsa_import_pkcs8.obj src/pqc/mldsa_import_x509.obj src/pqc/mlkem.obj src/pqc/mlkem_export.obj \
+src/pqc/mlkem_import.obj src/pqc/mlkem_import_pkcs8.obj src/pqc/mlkem_import_x509.obj src/pqc/slhdsa.obj \
+src/pqc/slhdsa_export.obj src/pqc/slhdsa_import.obj src/pqc/slhdsa_import_pkcs8.obj \
+src/pqc/slhdsa_import_x509.obj src/prngs/chacha20.obj src/prngs/fortuna.obj src/prngs/rc4.obj \
src/prngs/rng_get_bytes.obj src/prngs/rng_make_prng.obj src/prngs/sober128.obj src/prngs/sprng.obj \
src/prngs/yarrow.obj src/stream/chacha/chacha_crypt.obj src/stream/chacha/chacha_done.obj \
src/stream/chacha/chacha_ivctr32.obj src/stream/chacha/chacha_ivctr64.obj \
@@ -235,15 +239,16 @@ tests/dh_test.obj tests/dsa_test.obj tests/ecc_test.obj tests/ed25519_test.obj t
tests/misc_test.obj tests/modes_test.obj tests/mpi_test.obj tests/multi_test.obj \
tests/no_null_termination_check_test.obj tests/no_prng.obj tests/padding_test.obj tests/pem_test.obj \
tests/pk_oid_test.obj tests/pkcs_1_eme_test.obj tests/pkcs_1_emsa_test.obj tests/pkcs_1_oaep_test.obj \
-tests/pkcs_1_pss_test.obj tests/pkcs_1_test.obj tests/prng_test.obj tests/rotate_test.obj tests/rsa_test.obj \
-tests/scrypt_test.obj tests/ssh_test.obj tests/store_test.obj tests/test.obj tests/x25519_test.obj
+tests/pkcs_1_pss_test.obj tests/pkcs_1_test.obj tests/pqc_mldsa_test.obj tests/pqc_mlkem_test.obj \
+tests/pqc_slhdsa_test.obj tests/prng_test.obj tests/rotate_test.obj tests/rsa_test.obj tests/scrypt_test.obj \
+tests/ssh_test.obj tests/store_test.obj tests/test.obj tests/x25519_test.obj
#The following headers will be installed by "make install"
HEADERS_PUB=src/headers/tomcrypt.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cfg.h \
src/headers/tomcrypt_cipher.h src/headers/tomcrypt_custom.h src/headers/tomcrypt_hash.h \
src/headers/tomcrypt_mac.h src/headers/tomcrypt_macros.h src/headers/tomcrypt_math.h \
src/headers/tomcrypt_misc.h src/headers/tomcrypt_pk.h src/headers/tomcrypt_pkcs.h \
-src/headers/tomcrypt_prng.h
+src/headers/tomcrypt_pqc.h src/headers/tomcrypt_prng.h
HEADERS=$(HEADERS_PUB) src/headers/tomcrypt_private.h
diff --git a/makefile.unix b/makefile.unix
index df169e288..0b478d8dc 100644
--- a/makefile.unix
+++ b/makefile.unix
@@ -233,7 +233,11 @@ src/pk/rsa/rsa_make_key.o src/pk/rsa/rsa_set.o src/pk/rsa/rsa_sign_hash.o \
src/pk/rsa/rsa_sign_saltlen_get.o src/pk/rsa/rsa_verify_hash.o src/pk/x25519/x25519_export.o \
src/pk/x25519/x25519_import.o src/pk/x25519/x25519_import_pkcs8.o src/pk/x25519/x25519_import_raw.o \
src/pk/x25519/x25519_import_x509.o src/pk/x25519/x25519_make_key.o \
-src/pk/x25519/x25519_shared_secret.o src/prngs/chacha20.o src/prngs/fortuna.o src/prngs/rc4.o \
+src/pk/x25519/x25519_shared_secret.o src/pqc/mldsa.o src/pqc/mldsa_export.o src/pqc/mldsa_import.o \
+src/pqc/mldsa_import_pkcs8.o src/pqc/mldsa_import_x509.o src/pqc/mlkem.o src/pqc/mlkem_export.o \
+src/pqc/mlkem_import.o src/pqc/mlkem_import_pkcs8.o src/pqc/mlkem_import_x509.o src/pqc/slhdsa.o \
+src/pqc/slhdsa_export.o src/pqc/slhdsa_import.o src/pqc/slhdsa_import_pkcs8.o \
+src/pqc/slhdsa_import_x509.o src/prngs/chacha20.o src/prngs/fortuna.o src/prngs/rc4.o \
src/prngs/rng_get_bytes.o src/prngs/rng_make_prng.o src/prngs/sober128.o src/prngs/sprng.o \
src/prngs/yarrow.o src/stream/chacha/chacha_crypt.o src/stream/chacha/chacha_done.o \
src/stream/chacha/chacha_ivctr32.o src/stream/chacha/chacha_ivctr64.o \
@@ -256,15 +260,16 @@ tests/dh_test.o tests/dsa_test.o tests/ecc_test.o tests/ed25519_test.o tests/fil
tests/misc_test.o tests/modes_test.o tests/mpi_test.o tests/multi_test.o \
tests/no_null_termination_check_test.o tests/no_prng.o tests/padding_test.o tests/pem_test.o \
tests/pk_oid_test.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o tests/pkcs_1_oaep_test.o \
-tests/pkcs_1_pss_test.o tests/pkcs_1_test.o tests/prng_test.o tests/rotate_test.o tests/rsa_test.o \
-tests/scrypt_test.o tests/ssh_test.o tests/store_test.o tests/test.o tests/x25519_test.o
+tests/pkcs_1_pss_test.o tests/pkcs_1_test.o tests/pqc_mldsa_test.o tests/pqc_mlkem_test.o \
+tests/pqc_slhdsa_test.o tests/prng_test.o tests/rotate_test.o tests/rsa_test.o tests/scrypt_test.o \
+tests/ssh_test.o tests/store_test.o tests/test.o tests/x25519_test.o
#The following headers will be installed by "make install"
HEADERS_PUB=src/headers/tomcrypt.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cfg.h \
src/headers/tomcrypt_cipher.h src/headers/tomcrypt_custom.h src/headers/tomcrypt_hash.h \
src/headers/tomcrypt_mac.h src/headers/tomcrypt_macros.h src/headers/tomcrypt_math.h \
src/headers/tomcrypt_misc.h src/headers/tomcrypt_pk.h src/headers/tomcrypt_pkcs.h \
-src/headers/tomcrypt_prng.h
+src/headers/tomcrypt_pqc.h src/headers/tomcrypt_prng.h
HEADERS=$(HEADERS_PUB) src/headers/tomcrypt_private.h
diff --git a/makefile_include.mk b/makefile_include.mk
index 52013d7f3..0327fe72f 100644
--- a/makefile_include.mk
+++ b/makefile_include.mk
@@ -404,7 +404,11 @@ src/pk/rsa/rsa_make_key.o src/pk/rsa/rsa_set.o src/pk/rsa/rsa_sign_hash.o \
src/pk/rsa/rsa_sign_saltlen_get.o src/pk/rsa/rsa_verify_hash.o src/pk/x25519/x25519_export.o \
src/pk/x25519/x25519_import.o src/pk/x25519/x25519_import_pkcs8.o src/pk/x25519/x25519_import_raw.o \
src/pk/x25519/x25519_import_x509.o src/pk/x25519/x25519_make_key.o \
-src/pk/x25519/x25519_shared_secret.o src/prngs/chacha20.o src/prngs/fortuna.o src/prngs/rc4.o \
+src/pk/x25519/x25519_shared_secret.o src/pqc/mldsa.o src/pqc/mldsa_export.o src/pqc/mldsa_import.o \
+src/pqc/mldsa_import_pkcs8.o src/pqc/mldsa_import_x509.o src/pqc/mlkem.o src/pqc/mlkem_export.o \
+src/pqc/mlkem_import.o src/pqc/mlkem_import_pkcs8.o src/pqc/mlkem_import_x509.o src/pqc/slhdsa.o \
+src/pqc/slhdsa_export.o src/pqc/slhdsa_import.o src/pqc/slhdsa_import_pkcs8.o \
+src/pqc/slhdsa_import_x509.o src/prngs/chacha20.o src/prngs/fortuna.o src/prngs/rc4.o \
src/prngs/rng_get_bytes.o src/prngs/rng_make_prng.o src/prngs/sober128.o src/prngs/sprng.o \
src/prngs/yarrow.o src/stream/chacha/chacha_crypt.o src/stream/chacha/chacha_done.o \
src/stream/chacha/chacha_ivctr32.o src/stream/chacha/chacha_ivctr64.o \
@@ -432,15 +436,16 @@ tests/dh_test.o tests/dsa_test.o tests/ecc_test.o tests/ed25519_test.o tests/fil
tests/misc_test.o tests/modes_test.o tests/mpi_test.o tests/multi_test.o \
tests/no_null_termination_check_test.o tests/no_prng.o tests/padding_test.o tests/pem_test.o \
tests/pk_oid_test.o tests/pkcs_1_eme_test.o tests/pkcs_1_emsa_test.o tests/pkcs_1_oaep_test.o \
-tests/pkcs_1_pss_test.o tests/pkcs_1_test.o tests/prng_test.o tests/rotate_test.o tests/rsa_test.o \
-tests/scrypt_test.o tests/ssh_test.o tests/store_test.o tests/test.o tests/x25519_test.o
+tests/pkcs_1_pss_test.o tests/pkcs_1_test.o tests/pqc_mldsa_test.o tests/pqc_mlkem_test.o \
+tests/pqc_slhdsa_test.o tests/prng_test.o tests/rotate_test.o tests/rsa_test.o tests/scrypt_test.o \
+tests/ssh_test.o tests/store_test.o tests/test.o tests/x25519_test.o
# The following headers will be installed by "make install"
HEADERS_PUB=src/headers/tomcrypt.h src/headers/tomcrypt_argchk.h src/headers/tomcrypt_cfg.h \
src/headers/tomcrypt_cipher.h src/headers/tomcrypt_custom.h src/headers/tomcrypt_hash.h \
src/headers/tomcrypt_mac.h src/headers/tomcrypt_macros.h src/headers/tomcrypt_math.h \
src/headers/tomcrypt_misc.h src/headers/tomcrypt_pk.h src/headers/tomcrypt_pkcs.h \
-src/headers/tomcrypt_prng.h
+src/headers/tomcrypt_pqc.h src/headers/tomcrypt_prng.h
HEADERS=$(HEADERS_PUB) src/headers/tomcrypt_private.h
diff --git a/sources.cmake b/sources.cmake
index a192ed391..6fb3243ee 100644
--- a/sources.cmake
+++ b/sources.cmake
@@ -124,6 +124,7 @@ src/headers/tomcrypt_math.h
src/headers/tomcrypt_misc.h
src/headers/tomcrypt_pk.h
src/headers/tomcrypt_pkcs.h
+src/headers/tomcrypt_pqc.h
src/headers/tomcrypt_private.h
src/headers/tomcrypt_prng.h
src/mac/blake2/blake2bmac.c
@@ -496,6 +497,21 @@ src/pk/x25519/x25519_import_raw.c
src/pk/x25519/x25519_import_x509.c
src/pk/x25519/x25519_make_key.c
src/pk/x25519/x25519_shared_secret.c
+src/pqc/mldsa.c
+src/pqc/mldsa_export.c
+src/pqc/mldsa_import.c
+src/pqc/mldsa_import_pkcs8.c
+src/pqc/mldsa_import_x509.c
+src/pqc/mlkem.c
+src/pqc/mlkem_export.c
+src/pqc/mlkem_import.c
+src/pqc/mlkem_import_pkcs8.c
+src/pqc/mlkem_import_x509.c
+src/pqc/slhdsa.c
+src/pqc/slhdsa_export.c
+src/pqc/slhdsa_import.c
+src/pqc/slhdsa_import_pkcs8.c
+src/pqc/slhdsa_import_x509.c
src/prngs/chacha20.c
src/prngs/fortuna.c
src/prngs/rc4.c
@@ -549,6 +565,7 @@ src/headers/tomcrypt_math.h
src/headers/tomcrypt_misc.h
src/headers/tomcrypt_pk.h
src/headers/tomcrypt_pkcs.h
+src/headers/tomcrypt_pqc.h
src/headers/tomcrypt_prng.h
)
diff --git a/src/headers/tomcrypt.h b/src/headers/tomcrypt.h
index 8fddb432c..e456132b1 100644
--- a/src/headers/tomcrypt.h
+++ b/src/headers/tomcrypt.h
@@ -88,6 +88,7 @@ enum {
#include "tomcrypt_mac.h"
#include "tomcrypt_prng.h"
#include "tomcrypt_pk.h"
+#include "tomcrypt_pqc.h"
#include "tomcrypt_math.h"
#include "tomcrypt_misc.h"
#include "tomcrypt_argchk.h"
diff --git a/src/headers/tomcrypt_custom.h b/src/headers/tomcrypt_custom.h
index 970e9c67b..fcc70c99a 100644
--- a/src/headers/tomcrypt_custom.h
+++ b/src/headers/tomcrypt_custom.h
@@ -453,6 +453,11 @@
/* Ed25519 & X25519 */
#define LTC_CURVE25519
+/* Post-Quantum Cryptography */
+#define LTC_MLKEM
+#define LTC_MLDSA
+#define LTC_SLHDSA
+
/* ECC */
#define LTC_MECC
diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h
index a6b893128..15f74724a 100644
--- a/src/headers/tomcrypt_pk.h
+++ b/src/headers/tomcrypt_pk.h
@@ -39,6 +39,9 @@ enum ltc_pka_id {
LTC_PKA_EC,
LTC_PKA_X25519,
LTC_PKA_ED25519,
+ LTC_PKA_MLDSA,
+ LTC_PKA_SLHDSA,
+ LTC_PKA_MLKEM,
LTC_PKA_DH,
LTC_PKA_NUM
};
@@ -639,6 +642,36 @@ typedef struct {
#endif
#ifdef LTC_MRSA
rsa_key rsa;
+#endif
+#ifdef LTC_MLKEM
+ struct {
+ int alg;
+ int type;
+ unsigned char *pk;
+ unsigned long pklen;
+ unsigned char *sk;
+ unsigned long sklen;
+ } mlkem;
+#endif
+#ifdef LTC_MLDSA
+ struct {
+ int alg;
+ int type;
+ unsigned char *pk;
+ unsigned long pklen;
+ unsigned char *sk;
+ unsigned long sklen;
+ } mldsa;
+#endif
+#ifdef LTC_SLHDSA
+ struct {
+ int alg;
+ int type;
+ unsigned char *pk;
+ unsigned long pklen;
+ unsigned char *sk;
+ unsigned long sklen;
+ } slhdsa;
#endif
char dummy;
} u;
diff --git a/src/headers/tomcrypt_pqc.h b/src/headers/tomcrypt_pqc.h
new file mode 100644
index 000000000..016e7db2d
--- /dev/null
+++ b/src/headers/tomcrypt_pqc.h
@@ -0,0 +1,176 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/* ---- Post-Quantum Cryptography ---- */
+
+/* ---- ML-KEM (FIPS 203) ---- */
+#ifdef LTC_MLKEM
+
+/** ML-KEM parameter set identifiers */
+enum ltc_mlkem_id {
+ LTC_MLKEM_512 = 0,
+ LTC_MLKEM_768 = 1,
+ LTC_MLKEM_1024 = 2
+};
+
+/** ML-KEM key */
+typedef struct mlkem_key {
+ /** Algorithm identifier (ltc_mlkem_id) */
+ int alg;
+ /** Type of key, PK_PRIVATE or PK_PUBLIC */
+ int type;
+ /** Public key (encapsulation key) */
+ unsigned char *pk;
+ unsigned long pklen;
+ /** Secret key (decapsulation key, private only) */
+ unsigned char *sk;
+ unsigned long sklen;
+} mlkem_key;
+
+int mlkem_make_key(prng_state *prng, int wprng, int alg, mlkem_key *key);
+int mlkem_make_key_from_seed(int alg, const unsigned char *seed, unsigned long seedlen, mlkem_key *key);
+void mlkem_free(mlkem_key *key);
+
+int mlkem_export(unsigned char *out, unsigned long *outlen, int which, const mlkem_key *key);
+int mlkem_export_raw(unsigned char *out, unsigned long *outlen, int which, const mlkem_key *key);
+int mlkem_import(const unsigned char *in, unsigned long inlen, mlkem_key *key);
+int mlkem_import_raw(const unsigned char *in, unsigned long inlen, int which, int alg, mlkem_key *key);
+int mlkem_import_x509(const unsigned char *in, unsigned long inlen, mlkem_key *key);
+int mlkem_import_pkcs8(const unsigned char *in, unsigned long inlen, const password_ctx *pw_ctx, mlkem_key *key);
+
+int mlkem_encaps(unsigned char *ct, unsigned long *ctlen,
+ unsigned char *shared_secret, unsigned long *sslen,
+ prng_state *prng, int wprng,
+ const mlkem_key *key);
+
+int mlkem_decaps(unsigned char *shared_secret, unsigned long *sslen,
+ const unsigned char *ct, unsigned long ctlen,
+ const mlkem_key *key);
+
+int mlkem_get_sizes(int alg, unsigned long *public_key_sz, unsigned long *secret_key_sz, unsigned long *ciphertext_sz, unsigned long *shared_secret_sz);
+
+#endif /* LTC_MLKEM */
+
+
+/* ---- ML-DSA (FIPS 204) ---- */
+#ifdef LTC_MLDSA
+
+/** ML-DSA parameter set identifiers */
+enum ltc_mldsa_id {
+ LTC_MLDSA_44 = 0,
+ LTC_MLDSA_65 = 1,
+ LTC_MLDSA_87 = 2
+};
+
+/** ML-DSA key */
+typedef struct mldsa_key {
+ /** Algorithm identifier (ltc_mldsa_id) */
+ int alg;
+ /** Type of key, PK_PRIVATE or PK_PUBLIC */
+ int type;
+ /** Public key (verification key) */
+ unsigned char *pk;
+ unsigned long pklen;
+ /** Secret key (signing key, private only) */
+ unsigned char *sk;
+ unsigned long sklen;
+} mldsa_key;
+
+int mldsa_make_key(prng_state *prng, int wprng, int alg, mldsa_key *key);
+int mldsa_make_key_from_seed(int alg, const unsigned char *seed, unsigned long seedlen, mldsa_key *key);
+void mldsa_free(mldsa_key *key);
+
+int mldsa_export(unsigned char *out, unsigned long *outlen, int which, const mldsa_key *key);
+int mldsa_export_raw(unsigned char *out, unsigned long *outlen, int which, const mldsa_key *key);
+int mldsa_import(const unsigned char *in, unsigned long inlen, mldsa_key *key);
+int mldsa_import_raw(const unsigned char *in, unsigned long inlen, int which, int alg, mldsa_key *key);
+int mldsa_import_x509(const unsigned char *in, unsigned long inlen, mldsa_key *key);
+int mldsa_import_pkcs8(const unsigned char *in, unsigned long inlen, const password_ctx *pw_ctx, mldsa_key *key);
+
+int mldsa_sign(const unsigned char *msg, unsigned long msglen,
+ unsigned char *sig, unsigned long *siglen,
+ const unsigned char *ctx, unsigned long ctxlen,
+ prng_state *prng, int wprng,
+ const mldsa_key *key);
+
+int mldsa_verify(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *msg, unsigned long msglen,
+ const unsigned char *ctx, unsigned long ctxlen,
+ int *stat,
+ const mldsa_key *key);
+
+int mldsa_get_sizes(int alg, unsigned long *public_key_sz, unsigned long *secret_key_sz, unsigned long *signature_sz);
+
+#endif /* LTC_MLDSA */
+
+
+/* ---- SLH-DSA (FIPS 205) ---- */
+#ifdef LTC_SLHDSA
+
+/** SLH-DSA parameter set identifiers */
+enum ltc_slhdsa_id {
+ LTC_SLHDSA_SHA2_128S = 0,
+ LTC_SLHDSA_SHA2_128F = 1,
+ LTC_SLHDSA_SHA2_192S = 2,
+ LTC_SLHDSA_SHA2_192F = 3,
+ LTC_SLHDSA_SHA2_256S = 4,
+ LTC_SLHDSA_SHA2_256F = 5,
+ LTC_SLHDSA_SHAKE_128S = 6,
+ LTC_SLHDSA_SHAKE_128F = 7,
+ LTC_SLHDSA_SHAKE_192S = 8,
+ LTC_SLHDSA_SHAKE_192F = 9,
+ LTC_SLHDSA_SHAKE_256S = 10,
+ LTC_SLHDSA_SHAKE_256F = 11,
+ LTC_SLHDSA_HASH_SHA2_128S_WITH_SHA256 = 12,
+ LTC_SLHDSA_HASH_SHA2_128F_WITH_SHA256 = 13,
+ LTC_SLHDSA_HASH_SHA2_192S_WITH_SHA512 = 14,
+ LTC_SLHDSA_HASH_SHA2_192F_WITH_SHA512 = 15,
+ LTC_SLHDSA_HASH_SHA2_256S_WITH_SHA512 = 16,
+ LTC_SLHDSA_HASH_SHA2_256F_WITH_SHA512 = 17,
+ LTC_SLHDSA_HASH_SHAKE_128S_WITH_SHAKE128 = 18,
+ LTC_SLHDSA_HASH_SHAKE_128F_WITH_SHAKE128 = 19,
+ LTC_SLHDSA_HASH_SHAKE_192S_WITH_SHAKE256 = 20,
+ LTC_SLHDSA_HASH_SHAKE_192F_WITH_SHAKE256 = 21,
+ LTC_SLHDSA_HASH_SHAKE_256S_WITH_SHAKE256 = 22,
+ LTC_SLHDSA_HASH_SHAKE_256F_WITH_SHAKE256 = 23
+};
+
+/** SLH-DSA key */
+typedef struct slhdsa_key {
+ /** Algorithm identifier (ltc_slhdsa_id) */
+ int alg;
+ /** Type of key, PK_PRIVATE or PK_PUBLIC */
+ int type;
+ /** Public key (verification key) */
+ unsigned char *pk;
+ unsigned long pklen;
+ /** Secret key (signing key, private only) */
+ unsigned char *sk;
+ unsigned long sklen;
+} slhdsa_key;
+
+int slhdsa_make_key(prng_state *prng, int wprng, int alg, slhdsa_key *key);
+void slhdsa_free(slhdsa_key *key);
+
+int slhdsa_export(unsigned char *out, unsigned long *outlen, int which, const slhdsa_key *key);
+int slhdsa_export_raw(unsigned char *out, unsigned long *outlen, int which, const slhdsa_key *key);
+int slhdsa_import(const unsigned char *in, unsigned long inlen, slhdsa_key *key);
+int slhdsa_import_raw(const unsigned char *in, unsigned long inlen, int which, int alg, slhdsa_key *key);
+int slhdsa_import_x509(const unsigned char *in, unsigned long inlen, slhdsa_key *key);
+int slhdsa_import_pkcs8(const unsigned char *in, unsigned long inlen, const password_ctx *pw_ctx, slhdsa_key *key);
+
+int slhdsa_sign(const unsigned char *msg, unsigned long msglen,
+ unsigned char *sig, unsigned long *siglen,
+ const unsigned char *ctx, unsigned long ctxlen,
+ prng_state *prng, int wprng,
+ const slhdsa_key *key);
+
+int slhdsa_verify(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *msg, unsigned long msglen,
+ const unsigned char *ctx, unsigned long ctxlen,
+ int *stat,
+ const slhdsa_key *key);
+
+int slhdsa_get_sizes(int alg, unsigned long *public_key_sz, unsigned long *secret_key_sz, unsigned long *signature_sz);
+
+#endif /* LTC_SLHDSA */
diff --git a/src/headers/tomcrypt_private.h b/src/headers/tomcrypt_private.h
index 4de5e5edc..27123c7b0 100644
--- a/src/headers/tomcrypt_private.h
+++ b/src/headers/tomcrypt_private.h
@@ -59,6 +59,36 @@ enum ltc_oid_id {
LTC_OID_EC_PRIMEF,
LTC_OID_X25519,
LTC_OID_ED25519,
+ LTC_OID_MLDSA_44,
+ LTC_OID_MLDSA_65,
+ LTC_OID_MLDSA_87,
+ LTC_OID_SLHDSA_SHA2_128S,
+ LTC_OID_SLHDSA_SHA2_128F,
+ LTC_OID_SLHDSA_SHA2_192S,
+ LTC_OID_SLHDSA_SHA2_192F,
+ LTC_OID_SLHDSA_SHA2_256S,
+ LTC_OID_SLHDSA_SHA2_256F,
+ LTC_OID_SLHDSA_SHAKE_128S,
+ LTC_OID_SLHDSA_SHAKE_128F,
+ LTC_OID_SLHDSA_SHAKE_192S,
+ LTC_OID_SLHDSA_SHAKE_192F,
+ LTC_OID_SLHDSA_SHAKE_256S,
+ LTC_OID_SLHDSA_SHAKE_256F,
+ LTC_OID_HASH_SLHDSA_SHA2_128S_WITH_SHA256,
+ LTC_OID_HASH_SLHDSA_SHA2_128F_WITH_SHA256,
+ LTC_OID_HASH_SLHDSA_SHA2_192S_WITH_SHA512,
+ LTC_OID_HASH_SLHDSA_SHA2_192F_WITH_SHA512,
+ LTC_OID_HASH_SLHDSA_SHA2_256S_WITH_SHA512,
+ LTC_OID_HASH_SLHDSA_SHA2_256F_WITH_SHA512,
+ LTC_OID_HASH_SLHDSA_SHAKE_128S_WITH_SHAKE128,
+ LTC_OID_HASH_SLHDSA_SHAKE_128F_WITH_SHAKE128,
+ LTC_OID_HASH_SLHDSA_SHAKE_192S_WITH_SHAKE256,
+ LTC_OID_HASH_SLHDSA_SHAKE_192F_WITH_SHAKE256,
+ LTC_OID_HASH_SLHDSA_SHAKE_256S_WITH_SHAKE256,
+ LTC_OID_HASH_SLHDSA_SHAKE_256F_WITH_SHAKE256,
+ LTC_OID_MLKEM_512,
+ LTC_OID_MLKEM_768,
+ LTC_OID_MLKEM_1024,
LTC_OID_DH,
LTC_OID_NUM
};
@@ -652,6 +682,16 @@ int ec25519_crypto_ctx( unsigned char *out, unsigned long *outlen,
const unsigned char *ctx, unsigned long ctxlen);
#endif /* LTC_CURVE25519 */
+#ifdef LTC_MLKEM
+int mlkem_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, mlkem_key *key);
+#endif
+#ifdef LTC_MLDSA
+int mldsa_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, mldsa_key *key);
+#endif
+#ifdef LTC_SLHDSA
+int slhdsa_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, slhdsa_key *key);
+#endif
+
#ifdef LTC_DER
#define LTC_ASN1_IS_TYPE(e, t) (((e) != NULL) && ((e)->type == (t)))
diff --git a/src/misc/crypt/crypt.c b/src/misc/crypt/crypt.c
index a07a191ba..f924551bf 100644
--- a/src/misc/crypt/crypt.c
+++ b/src/misc/crypt/crypt.c
@@ -378,6 +378,15 @@ const char *crypt_build_settings =
" X25519\n"
#endif
#endif
+#if defined(LTC_MLKEM)
+ " ML-KEM\n"
+#endif
+#if defined(LTC_MLDSA)
+ " ML-DSA\n"
+#endif
+#if defined(LTC_SLHDSA)
+ " SLH-DSA\n"
+#endif
#if defined(LTC_PK_MAX_RETRIES)
" "NAME_VALUE(LTC_PK_MAX_RETRIES)"\n"
#endif
diff --git a/src/misc/pem/pem_pkcs.c b/src/misc/pem/pem_pkcs.c
index 17aa47705..03f8872c9 100644
--- a/src/misc/pem/pem_pkcs.c
+++ b/src/misc/pem/pem_pkcs.c
@@ -63,6 +63,42 @@ static const struct {
[LTC_OID_X25519] = { LTC_PKA_X25519, (pkcs8_import_fn)x25519_import_pkcs8_asn1 },
[LTC_OID_ED25519] = { LTC_PKA_ED25519, (pkcs8_import_fn)ed25519_import_pkcs8_asn1 },
#endif
+#ifdef LTC_MLDSA
+ [LTC_OID_MLDSA_44] = { LTC_PKA_MLDSA, (pkcs8_import_fn)mldsa_import_pkcs8_asn1 },
+ [LTC_OID_MLDSA_65] = { LTC_PKA_MLDSA, (pkcs8_import_fn)mldsa_import_pkcs8_asn1 },
+ [LTC_OID_MLDSA_87] = { LTC_PKA_MLDSA, (pkcs8_import_fn)mldsa_import_pkcs8_asn1 },
+#endif
+#ifdef LTC_SLHDSA
+ [LTC_OID_SLHDSA_SHA2_128S] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_SLHDSA_SHA2_128F] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_SLHDSA_SHA2_192S] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_SLHDSA_SHA2_192F] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_SLHDSA_SHA2_256S] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_SLHDSA_SHA2_256F] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_SLHDSA_SHAKE_128S] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_SLHDSA_SHAKE_128F] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_SLHDSA_SHAKE_192S] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_SLHDSA_SHAKE_192F] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_SLHDSA_SHAKE_256S] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_SLHDSA_SHAKE_256F] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_HASH_SLHDSA_SHA2_128S_WITH_SHA256] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_HASH_SLHDSA_SHA2_128F_WITH_SHA256] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_HASH_SLHDSA_SHA2_192S_WITH_SHA512] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_HASH_SLHDSA_SHA2_192F_WITH_SHA512] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_HASH_SLHDSA_SHA2_256S_WITH_SHA512] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_HASH_SLHDSA_SHA2_256F_WITH_SHA512] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_HASH_SLHDSA_SHAKE_128S_WITH_SHAKE128] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_HASH_SLHDSA_SHAKE_128F_WITH_SHAKE128] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_HASH_SLHDSA_SHAKE_192S_WITH_SHAKE256] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_HASH_SLHDSA_SHAKE_192F_WITH_SHAKE256] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_HASH_SLHDSA_SHAKE_256S_WITH_SHAKE256] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+ [LTC_OID_HASH_SLHDSA_SHAKE_256F_WITH_SHAKE256] = { LTC_PKA_SLHDSA, (pkcs8_import_fn)slhdsa_import_pkcs8_asn1 },
+#endif
+#ifdef LTC_MLKEM
+ [LTC_OID_MLKEM_512] = { LTC_PKA_MLKEM, (pkcs8_import_fn)mlkem_import_pkcs8_asn1 },
+ [LTC_OID_MLKEM_768] = { LTC_PKA_MLKEM, (pkcs8_import_fn)mlkem_import_pkcs8_asn1 },
+ [LTC_OID_MLKEM_1024] = { LTC_PKA_MLKEM, (pkcs8_import_fn)mlkem_import_pkcs8_asn1 },
+#endif
};
static int s_import_pkcs8(unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k, const password_ctx *pw_ctx)
@@ -122,6 +158,15 @@ static const import_fn s_import_openssl_fns[LTC_PKA_NUM] = {
[LTC_PKA_X25519] = (import_fn)x25519_import,
[LTC_PKA_ED25519] = (import_fn)ed25519_import,
#endif
+#ifdef LTC_MLDSA
+ [LTC_PKA_MLDSA] = (import_fn)mldsa_import,
+#endif
+#ifdef LTC_SLHDSA
+ [LTC_PKA_SLHDSA] = (import_fn)slhdsa_import,
+#endif
+#ifdef LTC_MLKEM
+ [LTC_PKA_MLKEM] = (import_fn)mlkem_import,
+#endif
};
static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_ctx)
diff --git a/src/pk/asn1/der/integer/der_decode_integer.c b/src/pk/asn1/der/integer/der_decode_integer.c
index e2555b92a..4481ac238 100644
--- a/src/pk/asn1/der/integer/der_decode_integer.c
+++ b/src/pk/asn1/der/integer/der_decode_integer.c
@@ -25,6 +25,11 @@ int der_decode_integer(const unsigned char *in, unsigned long inlen, void *num)
LTC_ARGCHK(num != NULL);
LTC_ARGCHK(in != NULL);
+ /* DER INTEGER decodes into an MPI, so fail cleanly when no math provider is active. */
+ if (ltc_mp.name == NULL) {
+ return CRYPT_INVALID_ARG;
+ }
+
/* min DER INTEGER is 0x02 01 00 == 0 */
if (inlen < (1 + 1 + 1)) {
return CRYPT_INVALID_PACKET;
diff --git a/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c b/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c
index ada1bd67a..422e12d9c 100644
--- a/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c
+++ b/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c
@@ -153,6 +153,12 @@ static int s_der_decode_sequence_flexi(const unsigned char *in, unsigned long *i
goto error;
}
+ /* Flexi INTEGER nodes are MPI-backed, so reject no-math builds before ltc_mp_init(). */
+ if (ltc_mp.name == NULL) {
+ err = CRYPT_INVALID_ARG;
+ goto error;
+ }
+
/* init field */
l->size = 1;
if ((err = ltc_mp_init(&l->data)) != CRYPT_OK) {
diff --git a/src/pk/asn1/oid/pk_get.c b/src/pk/asn1/oid/pk_get.c
index 1fd5872e2..cb6801bee 100644
--- a/src/pk/asn1/oid/pk_get.c
+++ b/src/pk/asn1/oid/pk_get.c
@@ -18,6 +18,36 @@ static const oid_table_entry pka_oids[] = {
{ LTC_OID_EC_PRIMEF, LTC_PKA_EC, "1.2.840.10045.1.1" },
{ LTC_OID_X25519, LTC_PKA_X25519, "1.3.101.110" },
{ LTC_OID_ED25519, LTC_PKA_ED25519, "1.3.101.112" },
+ { LTC_OID_MLDSA_44, LTC_PKA_MLDSA, "2.16.840.1.101.3.4.3.17" },
+ { LTC_OID_MLDSA_65, LTC_PKA_MLDSA, "2.16.840.1.101.3.4.3.18" },
+ { LTC_OID_MLDSA_87, LTC_PKA_MLDSA, "2.16.840.1.101.3.4.3.19" },
+ { LTC_OID_SLHDSA_SHA2_128S, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.20" },
+ { LTC_OID_SLHDSA_SHA2_128F, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.21" },
+ { LTC_OID_SLHDSA_SHA2_192S, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.22" },
+ { LTC_OID_SLHDSA_SHA2_192F, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.23" },
+ { LTC_OID_SLHDSA_SHA2_256S, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.24" },
+ { LTC_OID_SLHDSA_SHA2_256F, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.25" },
+ { LTC_OID_SLHDSA_SHAKE_128S, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.26" },
+ { LTC_OID_SLHDSA_SHAKE_128F, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.27" },
+ { LTC_OID_SLHDSA_SHAKE_192S, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.28" },
+ { LTC_OID_SLHDSA_SHAKE_192F, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.29" },
+ { LTC_OID_SLHDSA_SHAKE_256S, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.30" },
+ { LTC_OID_SLHDSA_SHAKE_256F, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.31" },
+ { LTC_OID_HASH_SLHDSA_SHA2_128S_WITH_SHA256, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.35" },
+ { LTC_OID_HASH_SLHDSA_SHA2_128F_WITH_SHA256, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.36" },
+ { LTC_OID_HASH_SLHDSA_SHA2_192S_WITH_SHA512, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.37" },
+ { LTC_OID_HASH_SLHDSA_SHA2_192F_WITH_SHA512, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.38" },
+ { LTC_OID_HASH_SLHDSA_SHA2_256S_WITH_SHA512, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.39" },
+ { LTC_OID_HASH_SLHDSA_SHA2_256F_WITH_SHA512, LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.40" },
+ { LTC_OID_HASH_SLHDSA_SHAKE_128S_WITH_SHAKE128,LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.41" },
+ { LTC_OID_HASH_SLHDSA_SHAKE_128F_WITH_SHAKE128,LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.42" },
+ { LTC_OID_HASH_SLHDSA_SHAKE_192S_WITH_SHAKE256,LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.43" },
+ { LTC_OID_HASH_SLHDSA_SHAKE_192F_WITH_SHAKE256,LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.44" },
+ { LTC_OID_HASH_SLHDSA_SHAKE_256S_WITH_SHAKE256,LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.45" },
+ { LTC_OID_HASH_SLHDSA_SHAKE_256F_WITH_SHAKE256,LTC_PKA_SLHDSA, "2.16.840.1.101.3.4.3.46" },
+ { LTC_OID_MLKEM_512, LTC_PKA_MLKEM, "2.16.840.1.101.3.4.4.1" },
+ { LTC_OID_MLKEM_768, LTC_PKA_MLKEM, "2.16.840.1.101.3.4.4.2" },
+ { LTC_OID_MLKEM_1024,LTC_PKA_MLKEM, "2.16.840.1.101.3.4.4.3" },
{ LTC_OID_DH, LTC_PKA_DH, "1.2.840.113549.1.3.1" },
};
diff --git a/src/pk/asn1/x509/x509_import_spki.c b/src/pk/asn1/x509/x509_import_spki.c
index 8b360852e..13fff8e17 100644
--- a/src/pk/asn1/x509/x509_import_spki.c
+++ b/src/pk/asn1/x509/x509_import_spki.c
@@ -25,6 +25,15 @@ static const import_fn s_import_x509_fns[LTC_PKA_NUM] = {
[LTC_PKA_X25519] = (import_fn)x25519_import_x509,
[LTC_PKA_ED25519] = (import_fn)ed25519_import_x509,
#endif
+#ifdef LTC_MLKEM
+ [LTC_PKA_MLKEM] = (import_fn)mlkem_import_x509,
+#endif
+#ifdef LTC_MLDSA
+ [LTC_PKA_MLDSA] = (import_fn)mldsa_import_x509,
+#endif
+#ifdef LTC_SLHDSA
+ [LTC_PKA_SLHDSA] = (import_fn)slhdsa_import_x509,
+#endif
};
int x509_import_spki(const unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k, ltc_asn1_list **root)
diff --git a/src/pk/pka_key.c b/src/pk/pka_key.c
index d88ee3d30..9668ee505 100644
--- a/src/pk/pka_key.c
+++ b/src/pk/pka_key.c
@@ -37,6 +37,21 @@ void pka_key_free(ltc_pka_key *key)
case LTC_PKA_EC:
#if defined(LTC_MECC)
ecc_free(&key->u.ecc);
+#endif
+ break;
+ case LTC_PKA_MLDSA:
+#if defined(LTC_MLDSA)
+ mldsa_free((mldsa_key*)&key->u.mldsa);
+#endif
+ break;
+ case LTC_PKA_SLHDSA:
+#if defined(LTC_SLHDSA)
+ slhdsa_free((slhdsa_key*)&key->u.slhdsa);
+#endif
+ break;
+ case LTC_PKA_MLKEM:
+#if defined(LTC_MLKEM)
+ mlkem_free((mlkem_key*)&key->u.mlkem);
#endif
break;
default:
diff --git a/src/pqc/mldsa.c b/src/pqc/mldsa.c
new file mode 100644
index 000000000..6d531487d
--- /dev/null
+++ b/src/pqc/mldsa.c
@@ -0,0 +1,1877 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/**
+ @file mldsa.c
+ ML-DSA (FIPS 204) implementation: polynomial arithmetic, NTT, packing,
+ signing, and verification.
+ Based on the CRYSTALS-Dilithium reference implementation (public domain).
+*/
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MLDSA
+
+/* Constants */
+
+#define MLDSA_N 256
+#define MLDSA_Q 8380417
+#define MLDSA_D 13
+#define MLDSA_QINV 58728449 /* Q^{-1} mod 2^32 */
+
+#define MLDSA_SEEDBYTES 32
+#define MLDSA_CRHBYTES 64
+#define MLDSA_TRBYTES 64
+#define MLDSA_RNDBYTES 32
+
+#define MLDSA_K_MAX 8
+#define MLDSA_L_MAX 7
+
+#define MLDSA_POLYT1_PACKEDBYTES 320
+#define MLDSA_POLYT0_PACKEDBYTES 416
+
+#define MLDSA_SHAKE128_RATE 168
+#define MLDSA_SHAKE256_RATE 136
+
+/* Runtime parameter set */
+
+typedef struct {
+ int k, l, eta, tau, omega;
+ int beta;
+ int gamma1, gamma2;
+ int ctilde_bytes;
+ unsigned long polyz_packed, polyw1_packed, polyeta_packed;
+ unsigned long pk_bytes, sk_bytes, sig_bytes;
+} mldsa_params;
+
+/* Polynomial types */
+
+typedef struct {
+ int coeffs[MLDSA_N];
+} mldsa_poly;
+
+typedef struct {
+ mldsa_poly vec[MLDSA_L_MAX];
+} mldsa_polyvecl;
+
+typedef struct {
+ mldsa_poly vec[MLDSA_K_MAX];
+} mldsa_polyveck;
+
+/* Montgomery / Barrett reduction */
+
+static int s_mldsa_montgomery_reduce(long64 a)
+{
+ int t;
+ t = (long64)(int)a * MLDSA_QINV;
+ t = (a - (long64)t * MLDSA_Q) >> 32;
+ return t;
+}
+
+static int s_mldsa_reduce32(int a)
+{
+ int t;
+ t = (a + (1 << 22)) >> 23;
+ t = a - t * MLDSA_Q;
+ return t;
+}
+
+static int s_mldsa_caddq(int a)
+{
+ a += (a >> 31) & MLDSA_Q;
+ return a;
+}
+
+
+/* NTT */
+
+static const int s_mldsa_zetas[MLDSA_N] = {
+ 0, 25847, -2608894, -518909, 237124, -777960, -876248, 466468,
+ 1826347, 2353451, -359251, -2091905, 3119733, -2884855, 3111497, 2680103,
+ 2725464, 1024112, -1079900, 3585928, -549488, -1119584, 2619752, -2108549,
+ -2118186, -3859737, -1399561, -3277672, 1757237, -19422, 4010497, 280005,
+ 2706023, 95776, 3077325, 3530437, -1661693, -3592148, -2537516, 3915439,
+ -3861115, -3043716, 3574422, -2867647, 3539968, -300467, 2348700, -539299,
+ -1699267, -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596,
+ 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, -2797779,
+ -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, 2176455, -1585221,
+ -1257611, 1939314, -4083598, -1000202, -3190144, -3157330, -3632928, 126922,
+ 3412210, -983419, 2147896, 2715295, -2967645, -3693493, -411027, -2477047,
+ -671102, -1228525, -22981, -1308169, -381987, 1349076, 1852771, -1430430,
+ -3343383, 264944, 508951, 3097992, 44288, -1100098, 904516, 3958618,
+ -3724342, -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856,
+ 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, 1341330,
+ 1285669, -1584928, -812732, -1439742, -3019102, -3881060, -3628969, 3839961,
+ 2091667, 3407706, 2316500, 3817976, -3342478, 2244091, -2446433, -3562462,
+ 266997, 2434439, -1235728, 3513181, -3520352, -3759364, -1197226, -3193378,
+ 900702, 1859098, 909542, 819034, 495491, -1613174, -43260, -522500,
+ -655327, -3122442, 2031748, 3207046, -3556995, -525098, -768622, -3595838,
+ 342297, 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044,
+ 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, 1595974,
+ -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, 1903435, -1050970,
+ -1333058, 1237275, -3318210, -1430225, -451100, 1312455, 3306115, -1962642,
+ -1279661, 1917081, -2546312, -1374803, 1500165, 777191, 2235880, 3406031,
+ -542412, -2831860, -1671176, -1846953, -2584293, -3724270, 594136, -3776993,
+ -2013608, 2432395, 2454455, -164721, 1957272, 3369112, 185531, -1207385,
+ -3183426, 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107,
+ -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, 472078,
+ -426683, 1723600, -1803090, 1910376, -1667432, -1104333, -260646, -3833893,
+ -2939036, -2235985, -420899, -2286327, 183443, -976891, 1612842, -3545687,
+ -554416, 3919660, -48306, -1362209, 3937738, 1400424, -846154, 1976782
+};
+
+static void s_mldsa_ntt(int a[MLDSA_N])
+{
+ unsigned int len, start, j, k;
+ int zeta, t;
+
+ k = 0;
+ for (len = 128; len > 0; len >>= 1) {
+ for (start = 0; start < (unsigned)MLDSA_N; start = j + len) {
+ zeta = s_mldsa_zetas[++k];
+ for (j = start; j < start + len; ++j) {
+ t = s_mldsa_montgomery_reduce((long64)zeta * a[j + len]);
+ a[j + len] = a[j] - t;
+ a[j] = a[j] + t;
+ }
+ }
+ }
+}
+
+static void s_mldsa_invntt_tomont(int a[MLDSA_N])
+{
+ unsigned int start, len, j, k;
+ int t, zeta;
+ const int f = 41978; /* mont^2/256 */
+
+ k = 256;
+ for (len = 1; len < (unsigned)MLDSA_N; len <<= 1) {
+ for (start = 0; start < (unsigned)MLDSA_N; start = j + len) {
+ zeta = -s_mldsa_zetas[--k];
+ for (j = start; j < start + len; ++j) {
+ t = a[j];
+ a[j] = t + a[j + len];
+ a[j + len] = t - a[j + len];
+ a[j + len] = s_mldsa_montgomery_reduce((long64)zeta * a[j + len]);
+ }
+ }
+ }
+
+ for (j = 0; j < (unsigned)MLDSA_N; ++j) {
+ a[j] = s_mldsa_montgomery_reduce((long64)f * a[j]);
+ }
+}
+
+/* Rounding */
+
+static int s_power2round(int *a0, int a)
+{
+ int a1;
+ a1 = (a + (1 << (MLDSA_D - 1)) - 1) >> MLDSA_D;
+ *a0 = a - (a1 << MLDSA_D);
+ return a1;
+}
+
+static int s_decompose(int *a0, int a, int gamma2)
+{
+ int a1;
+
+ a1 = (a + 127) >> 7;
+ if (gamma2 == (MLDSA_Q - 1) / 32) {
+ a1 = (a1 * 1025 + (1 << 21)) >> 22;
+ a1 &= 15;
+ } else {
+ /* gamma2 == (MLDSA_Q - 1) / 88 */
+ a1 = (a1 * 11275 + (1 << 23)) >> 24;
+ a1 ^= ((43 - a1) >> 31) & a1;
+ }
+
+ *a0 = a - a1 * 2 * gamma2;
+ *a0 -= (((MLDSA_Q - 1) / 2 - *a0) >> 31) & MLDSA_Q;
+ return a1;
+}
+
+static unsigned int s_make_hint(int a0, int a1, int gamma2)
+{
+ if (a0 > gamma2 || a0 < -gamma2 || (a0 == -gamma2 && a1 != 0))
+ return 1;
+ return 0;
+}
+
+static int s_use_hint(int a, unsigned int hint, int gamma2)
+{
+ int a0, a1;
+
+ a1 = s_decompose(&a0, a, gamma2);
+ if (hint == 0)
+ return a1;
+
+ if (gamma2 == (MLDSA_Q - 1) / 32) {
+ if (a0 > 0)
+ return (a1 + 1) & 15;
+ else
+ return (a1 - 1) & 15;
+ } else {
+ /* gamma2 == (MLDSA_Q - 1) / 88 */
+ if (a0 > 0)
+ return (a1 == 43) ? 0 : a1 + 1;
+ else
+ return (a1 == 0) ? 43 : a1 - 1;
+ }
+}
+
+/* Parameter lookup */
+
+static int s_mldsa_get_params(int alg, mldsa_params *p)
+{
+ LTC_ARGCHK(p != NULL);
+
+ XMEMSET(p, 0, sizeof(*p));
+
+ switch (alg) {
+ case LTC_MLDSA_44:
+ p->k = 4; p->l = 4; p->eta = 2; p->tau = 39;
+ p->beta = 78; p->gamma1 = (1 << 17);
+ p->gamma2 = (MLDSA_Q - 1) / 88; p->omega = 80;
+ p->ctilde_bytes = 32;
+ break;
+ case LTC_MLDSA_65:
+ p->k = 6; p->l = 5; p->eta = 4; p->tau = 49;
+ p->beta = 196; p->gamma1 = (1 << 19);
+ p->gamma2 = (MLDSA_Q - 1) / 32; p->omega = 55;
+ p->ctilde_bytes = 48;
+ break;
+ case LTC_MLDSA_87:
+ p->k = 8; p->l = 7; p->eta = 2; p->tau = 60;
+ p->beta = 120; p->gamma1 = (1 << 19);
+ p->gamma2 = (MLDSA_Q - 1) / 32; p->omega = 75;
+ p->ctilde_bytes = 64;
+ break;
+ default:
+ return CRYPT_INVALID_ARG;
+ }
+
+ p->polyz_packed = (p->gamma1 == (1 << 17)) ? 576u : 640u;
+ p->polyw1_packed = (p->gamma2 == (MLDSA_Q - 1) / 88) ? 192u : 128u;
+ p->polyeta_packed = (p->eta == 2) ? 96u : 128u;
+ p->pk_bytes = MLDSA_SEEDBYTES + (unsigned long)p->k * MLDSA_POLYT1_PACKEDBYTES;
+ p->sk_bytes = 2u * MLDSA_SEEDBYTES + MLDSA_TRBYTES
+ + (unsigned long)p->l * p->polyeta_packed
+ + (unsigned long)p->k * p->polyeta_packed
+ + (unsigned long)p->k * MLDSA_POLYT0_PACKEDBYTES;
+ p->sig_bytes = (unsigned long)p->ctilde_bytes
+ + (unsigned long)p->l * p->polyz_packed
+ + (unsigned long)p->omega + (unsigned long)p->k;
+
+ return CRYPT_OK;
+}
+
+/* Symmetric primitives using libtomcrypt SHA3 */
+
+static int s_shake256(unsigned char *out, unsigned long outlen,
+ const unsigned char *in, unsigned long inlen)
+{
+ int err;
+ hash_state md;
+
+ if ((err = sha3_shake_init(&md, 256)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, in, inlen)) != CRYPT_OK) return err;
+ return sha3_shake_done(&md, out, outlen);
+}
+
+static int s_shake128_stream_init(hash_state *state,
+ const unsigned char seed[MLDSA_SEEDBYTES],
+ unsigned int nonce)
+{
+ int err;
+ unsigned char t[2];
+ t[0] = (unsigned char)(nonce & 0xff);
+ t[1] = (unsigned char)(nonce >> 8);
+
+ if ((err = sha3_shake_init(state, 128)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(state, seed, MLDSA_SEEDBYTES)) != CRYPT_OK) return err;
+ return sha3_shake_process(state, t, 2);
+}
+
+static int s_shake256_stream_init(hash_state *state,
+ const unsigned char *seed,
+ unsigned long seedlen,
+ unsigned int nonce)
+{
+ int err;
+ unsigned char t[2];
+ t[0] = (unsigned char)(nonce & 0xff);
+ t[1] = (unsigned char)(nonce >> 8);
+
+ if ((err = sha3_shake_init(state, 256)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(state, seed, seedlen)) != CRYPT_OK) return err;
+ return sha3_shake_process(state, t, 2);
+}
+
+/* Poly operations */
+
+static void s_mldsa_poly_reduce(mldsa_poly *a)
+{
+ unsigned int i;
+ for (i = 0; i < MLDSA_N; ++i)
+ a->coeffs[i] = s_mldsa_reduce32(a->coeffs[i]);
+}
+
+static void s_poly_caddq(mldsa_poly *a)
+{
+ unsigned int i;
+ for (i = 0; i < MLDSA_N; ++i)
+ a->coeffs[i] = s_mldsa_caddq(a->coeffs[i]);
+}
+
+static void s_mldsa_poly_add(mldsa_poly *c, const mldsa_poly *a, const mldsa_poly *b)
+{
+ unsigned int i;
+ for (i = 0; i < MLDSA_N; ++i)
+ c->coeffs[i] = a->coeffs[i] + b->coeffs[i];
+}
+
+static void s_mldsa_poly_sub(mldsa_poly *c, const mldsa_poly *a, const mldsa_poly *b)
+{
+ unsigned int i;
+ for (i = 0; i < MLDSA_N; ++i)
+ c->coeffs[i] = a->coeffs[i] - b->coeffs[i];
+}
+
+static void s_poly_shiftl(mldsa_poly *a)
+{
+ unsigned int i;
+ for (i = 0; i < MLDSA_N; ++i)
+ a->coeffs[i] <<= MLDSA_D;
+}
+
+static void s_mldsa_poly_ntt(mldsa_poly *a)
+{
+ s_mldsa_ntt(a->coeffs);
+}
+
+static void s_mldsa_poly_invntt_tomont(mldsa_poly *a)
+{
+ s_mldsa_invntt_tomont(a->coeffs);
+}
+
+static void s_poly_pointwise_montgomery(mldsa_poly *c, const mldsa_poly *a, const mldsa_poly *b)
+{
+ unsigned int i;
+ for (i = 0; i < MLDSA_N; ++i)
+ c->coeffs[i] = s_mldsa_montgomery_reduce((long64)a->coeffs[i] * b->coeffs[i]);
+}
+
+static void s_poly_power2round(mldsa_poly *a1, mldsa_poly *a0, const mldsa_poly *a)
+{
+ unsigned int i;
+ for (i = 0; i < MLDSA_N; ++i)
+ a1->coeffs[i] = s_power2round(&a0->coeffs[i], a->coeffs[i]);
+}
+
+static void s_poly_decompose(mldsa_poly *a1, mldsa_poly *a0, const mldsa_poly *a, int gamma2)
+{
+ unsigned int i;
+ for (i = 0; i < MLDSA_N; ++i)
+ a1->coeffs[i] = s_decompose(&a0->coeffs[i], a->coeffs[i], gamma2);
+}
+
+static unsigned int s_poly_make_hint(mldsa_poly *h, const mldsa_poly *a0,
+ const mldsa_poly *a1, int gamma2)
+{
+ unsigned int i, s = 0;
+ for (i = 0; i < MLDSA_N; ++i) {
+ h->coeffs[i] = s_make_hint(a0->coeffs[i], a1->coeffs[i], gamma2);
+ s += h->coeffs[i];
+ }
+ return s;
+}
+
+static void s_poly_use_hint(mldsa_poly *b, const mldsa_poly *a, const mldsa_poly *h, int gamma2)
+{
+ unsigned int i;
+ for (i = 0; i < MLDSA_N; ++i)
+ b->coeffs[i] = s_use_hint(a->coeffs[i], h->coeffs[i], gamma2);
+}
+
+static int s_poly_chknorm(const mldsa_poly *a, int B)
+{
+ unsigned int i;
+ int t;
+
+ if (B > (MLDSA_Q - 1) / 8)
+ return 1;
+
+ for (i = 0; i < MLDSA_N; ++i) {
+ t = a->coeffs[i] >> 31;
+ t = a->coeffs[i] - (t & 2 * a->coeffs[i]);
+ if (t >= B)
+ return 1;
+ }
+ return 0;
+}
+
+/* Sampling */
+
+static unsigned int s_rej_uniform(int *a, unsigned int len,
+ const unsigned char *buf, unsigned int buflen)
+{
+ unsigned int ctr, pos;
+ ulong32 t;
+
+ ctr = pos = 0;
+ while (ctr < len && pos + 3 <= buflen) {
+ t = buf[pos++];
+ t |= (ulong32)buf[pos++] << 8;
+ t |= (ulong32)buf[pos++] << 16;
+ t &= 0x7FFFFF;
+
+ if (t < (ulong32)MLDSA_Q)
+ a[ctr++] = (int)t;
+ }
+
+ return ctr;
+}
+
+static int s_poly_uniform(mldsa_poly *a, const unsigned char seed[MLDSA_SEEDBYTES],
+ unsigned int nonce)
+{
+ unsigned int ctr, off, i;
+ /* SHAKE128 rate = 168. We need ceil(768/168)=5 blocks initially */
+ #define S_POLY_UNIFORM_NBLOCKS ((768 + MLDSA_SHAKE128_RATE - 1) / MLDSA_SHAKE128_RATE)
+ unsigned int buflen = S_POLY_UNIFORM_NBLOCKS * MLDSA_SHAKE128_RATE;
+ unsigned char buf[S_POLY_UNIFORM_NBLOCKS * MLDSA_SHAKE128_RATE + 2];
+ hash_state state;
+ int err;
+
+ if ((err = s_shake128_stream_init(&state, seed, nonce)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_done(&state, buf, buflen)) != CRYPT_OK) return err;
+
+ ctr = s_rej_uniform(a->coeffs, MLDSA_N, buf, buflen);
+
+ while (ctr < MLDSA_N) {
+ off = buflen % 3;
+ for (i = 0; i < off; ++i)
+ buf[i] = buf[buflen - off + i];
+
+ /* sha3_shake_done supports incremental squeezing */
+ if ((err = sha3_shake_done(&state, buf + off, MLDSA_SHAKE128_RATE)) != CRYPT_OK) return err;
+ buflen = MLDSA_SHAKE128_RATE + off;
+ ctr += s_rej_uniform(a->coeffs + ctr, MLDSA_N - ctr, buf, buflen);
+ }
+ #undef S_POLY_UNIFORM_NBLOCKS
+
+ return CRYPT_OK;
+}
+
+static unsigned int s_rej_eta(int *a, unsigned int len,
+ const unsigned char *buf, unsigned int buflen,
+ int eta)
+{
+ unsigned int ctr, pos;
+ ulong32 t0, t1;
+
+ ctr = pos = 0;
+ while (ctr < len && pos < buflen) {
+ t0 = buf[pos] & 0x0F;
+ t1 = buf[pos++] >> 4;
+
+ if (eta == 2) {
+ if (t0 < 15) {
+ t0 = t0 - (205 * t0 >> 10) * 5;
+ a[ctr++] = 2 - (int)t0;
+ }
+ if (t1 < 15 && ctr < len) {
+ t1 = t1 - (205 * t1 >> 10) * 5;
+ a[ctr++] = 2 - (int)t1;
+ }
+ } else {
+ /* eta == 4 */
+ if (t0 < 9)
+ a[ctr++] = 4 - (int)t0;
+ if (t1 < 9 && ctr < len)
+ a[ctr++] = 4 - (int)t1;
+ }
+ }
+
+ return ctr;
+}
+
+static int s_poly_uniform_eta(mldsa_poly *a, const unsigned char seed[MLDSA_CRHBYTES],
+ unsigned int nonce, int eta)
+{
+ unsigned int ctr;
+ /* For eta==2: need 136 bytes. For eta==4: need 227 bytes.
+ ceil(227/136)=2 blocks of SHAKE256 (rate 136) = 272 bytes max */
+ unsigned char buf[2 * MLDSA_SHAKE256_RATE];
+ unsigned int buflen;
+ hash_state state;
+ int err;
+
+ if (eta == 2)
+ buflen = 136;
+ else
+ buflen = 227;
+
+ if ((err = s_shake256_stream_init(&state, seed, MLDSA_CRHBYTES, nonce)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_done(&state, buf, buflen)) != CRYPT_OK) return err;
+
+ ctr = s_rej_eta(a->coeffs, MLDSA_N, buf, buflen, eta);
+
+ while (ctr < MLDSA_N) {
+ /* sha3_shake_done supports incremental squeezing */
+ if ((err = sha3_shake_done(&state, buf, MLDSA_SHAKE256_RATE)) != CRYPT_OK) return err;
+ ctr += s_rej_eta(a->coeffs + ctr, MLDSA_N - ctr, buf, MLDSA_SHAKE256_RATE, eta);
+ }
+
+ return CRYPT_OK;
+}
+
+/* Polynomial packing */
+
+static void s_polyeta_pack(unsigned char *r, const mldsa_poly *a, int eta)
+{
+ unsigned int i;
+ unsigned char t[8];
+
+ if (eta == 2) {
+ for (i = 0; i < MLDSA_N / 8; ++i) {
+ t[0] = (unsigned char)(eta - a->coeffs[8 * i + 0]);
+ t[1] = (unsigned char)(eta - a->coeffs[8 * i + 1]);
+ t[2] = (unsigned char)(eta - a->coeffs[8 * i + 2]);
+ t[3] = (unsigned char)(eta - a->coeffs[8 * i + 3]);
+ t[4] = (unsigned char)(eta - a->coeffs[8 * i + 4]);
+ t[5] = (unsigned char)(eta - a->coeffs[8 * i + 5]);
+ t[6] = (unsigned char)(eta - a->coeffs[8 * i + 6]);
+ t[7] = (unsigned char)(eta - a->coeffs[8 * i + 7]);
+
+ r[3 * i + 0] = (t[0] >> 0) | (t[1] << 3) | (t[2] << 6);
+ r[3 * i + 1] = (t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7);
+ r[3 * i + 2] = (t[5] >> 1) | (t[6] << 2) | (t[7] << 5);
+ }
+ } else {
+ /* eta == 4 */
+ for (i = 0; i < MLDSA_N / 2; ++i) {
+ t[0] = (unsigned char)(eta - a->coeffs[2 * i + 0]);
+ t[1] = (unsigned char)(eta - a->coeffs[2 * i + 1]);
+ r[i] = t[0] | (t[1] << 4);
+ }
+ }
+}
+
+static void s_polyeta_unpack(mldsa_poly *r, const unsigned char *a, int eta)
+{
+ unsigned int i;
+
+ if (eta == 2) {
+ for (i = 0; i < MLDSA_N / 8; ++i) {
+ r->coeffs[8 * i + 0] = (a[3 * i + 0] >> 0) & 7;
+ r->coeffs[8 * i + 1] = (a[3 * i + 0] >> 3) & 7;
+ r->coeffs[8 * i + 2] = ((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 7;
+ r->coeffs[8 * i + 3] = (a[3 * i + 1] >> 1) & 7;
+ r->coeffs[8 * i + 4] = (a[3 * i + 1] >> 4) & 7;
+ r->coeffs[8 * i + 5] = ((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 7;
+ r->coeffs[8 * i + 6] = (a[3 * i + 2] >> 2) & 7;
+ r->coeffs[8 * i + 7] = (a[3 * i + 2] >> 5) & 7;
+
+ r->coeffs[8 * i + 0] = eta - r->coeffs[8 * i + 0];
+ r->coeffs[8 * i + 1] = eta - r->coeffs[8 * i + 1];
+ r->coeffs[8 * i + 2] = eta - r->coeffs[8 * i + 2];
+ r->coeffs[8 * i + 3] = eta - r->coeffs[8 * i + 3];
+ r->coeffs[8 * i + 4] = eta - r->coeffs[8 * i + 4];
+ r->coeffs[8 * i + 5] = eta - r->coeffs[8 * i + 5];
+ r->coeffs[8 * i + 6] = eta - r->coeffs[8 * i + 6];
+ r->coeffs[8 * i + 7] = eta - r->coeffs[8 * i + 7];
+ }
+ } else {
+ /* eta == 4 */
+ for (i = 0; i < MLDSA_N / 2; ++i) {
+ r->coeffs[2 * i + 0] = a[i] & 0x0F;
+ r->coeffs[2 * i + 1] = a[i] >> 4;
+ r->coeffs[2 * i + 0] = eta - r->coeffs[2 * i + 0];
+ r->coeffs[2 * i + 1] = eta - r->coeffs[2 * i + 1];
+ }
+ }
+}
+
+static void s_polyt1_pack(unsigned char *r, const mldsa_poly *a)
+{
+ unsigned int i;
+
+ for (i = 0; i < MLDSA_N / 4; ++i) {
+ r[5 * i + 0] = (unsigned char)(a->coeffs[4 * i + 0] >> 0);
+ r[5 * i + 1] = (unsigned char)((a->coeffs[4 * i + 0] >> 8) | (a->coeffs[4 * i + 1] << 2));
+ r[5 * i + 2] = (unsigned char)((a->coeffs[4 * i + 1] >> 6) | (a->coeffs[4 * i + 2] << 4));
+ r[5 * i + 3] = (unsigned char)((a->coeffs[4 * i + 2] >> 4) | (a->coeffs[4 * i + 3] << 6));
+ r[5 * i + 4] = (unsigned char)(a->coeffs[4 * i + 3] >> 2);
+ }
+}
+
+static void s_polyt1_unpack(mldsa_poly *r, const unsigned char *a)
+{
+ unsigned int i;
+
+ for (i = 0; i < MLDSA_N / 4; ++i) {
+ r->coeffs[4 * i + 0] = ((a[5 * i + 0] >> 0) | ((ulong32)a[5 * i + 1] << 8)) & 0x3FF;
+ r->coeffs[4 * i + 1] = ((a[5 * i + 1] >> 2) | ((ulong32)a[5 * i + 2] << 6)) & 0x3FF;
+ r->coeffs[4 * i + 2] = ((a[5 * i + 2] >> 4) | ((ulong32)a[5 * i + 3] << 4)) & 0x3FF;
+ r->coeffs[4 * i + 3] = ((a[5 * i + 3] >> 6) | ((ulong32)a[5 * i + 4] << 2)) & 0x3FF;
+ }
+}
+
+static void s_polyt0_pack(unsigned char *r, const mldsa_poly *a)
+{
+ unsigned int i;
+ ulong32 t[8];
+
+ for (i = 0; i < MLDSA_N / 8; ++i) {
+ t[0] = (1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 0];
+ t[1] = (1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 1];
+ t[2] = (1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 2];
+ t[3] = (1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 3];
+ t[4] = (1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 4];
+ t[5] = (1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 5];
+ t[6] = (1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 6];
+ t[7] = (1 << (MLDSA_D - 1)) - a->coeffs[8 * i + 7];
+
+ r[13 * i + 0] = (unsigned char)(t[0]);
+ r[13 * i + 1] = (unsigned char)(t[0] >> 8);
+ r[13 * i + 1] |= (unsigned char)(t[1] << 5);
+ r[13 * i + 2] = (unsigned char)(t[1] >> 3);
+ r[13 * i + 3] = (unsigned char)(t[1] >> 11);
+ r[13 * i + 3] |= (unsigned char)(t[2] << 2);
+ r[13 * i + 4] = (unsigned char)(t[2] >> 6);
+ r[13 * i + 4] |= (unsigned char)(t[3] << 7);
+ r[13 * i + 5] = (unsigned char)(t[3] >> 1);
+ r[13 * i + 6] = (unsigned char)(t[3] >> 9);
+ r[13 * i + 6] |= (unsigned char)(t[4] << 4);
+ r[13 * i + 7] = (unsigned char)(t[4] >> 4);
+ r[13 * i + 8] = (unsigned char)(t[4] >> 12);
+ r[13 * i + 8] |= (unsigned char)(t[5] << 1);
+ r[13 * i + 9] = (unsigned char)(t[5] >> 7);
+ r[13 * i + 9] |= (unsigned char)(t[6] << 6);
+ r[13 * i + 10] = (unsigned char)(t[6] >> 2);
+ r[13 * i + 11] = (unsigned char)(t[6] >> 10);
+ r[13 * i + 11] |= (unsigned char)(t[7] << 3);
+ r[13 * i + 12] = (unsigned char)(t[7] >> 5);
+ }
+}
+
+static void s_polyt0_unpack(mldsa_poly *r, const unsigned char *a)
+{
+ unsigned int i;
+
+ for (i = 0; i < MLDSA_N / 8; ++i) {
+ r->coeffs[8 * i + 0] = a[13 * i + 0];
+ r->coeffs[8 * i + 0] |= (ulong32)a[13 * i + 1] << 8;
+ r->coeffs[8 * i + 0] &= 0x1FFF;
+
+ r->coeffs[8 * i + 1] = a[13 * i + 1] >> 5;
+ r->coeffs[8 * i + 1] |= (ulong32)a[13 * i + 2] << 3;
+ r->coeffs[8 * i + 1] |= (ulong32)a[13 * i + 3] << 11;
+ r->coeffs[8 * i + 1] &= 0x1FFF;
+
+ r->coeffs[8 * i + 2] = a[13 * i + 3] >> 2;
+ r->coeffs[8 * i + 2] |= (ulong32)a[13 * i + 4] << 6;
+ r->coeffs[8 * i + 2] &= 0x1FFF;
+
+ r->coeffs[8 * i + 3] = a[13 * i + 4] >> 7;
+ r->coeffs[8 * i + 3] |= (ulong32)a[13 * i + 5] << 1;
+ r->coeffs[8 * i + 3] |= (ulong32)a[13 * i + 6] << 9;
+ r->coeffs[8 * i + 3] &= 0x1FFF;
+
+ r->coeffs[8 * i + 4] = a[13 * i + 6] >> 4;
+ r->coeffs[8 * i + 4] |= (ulong32)a[13 * i + 7] << 4;
+ r->coeffs[8 * i + 4] |= (ulong32)a[13 * i + 8] << 12;
+ r->coeffs[8 * i + 4] &= 0x1FFF;
+
+ r->coeffs[8 * i + 5] = a[13 * i + 8] >> 1;
+ r->coeffs[8 * i + 5] |= (ulong32)a[13 * i + 9] << 7;
+ r->coeffs[8 * i + 5] &= 0x1FFF;
+
+ r->coeffs[8 * i + 6] = a[13 * i + 9] >> 6;
+ r->coeffs[8 * i + 6] |= (ulong32)a[13 * i + 10] << 2;
+ r->coeffs[8 * i + 6] |= (ulong32)a[13 * i + 11] << 10;
+ r->coeffs[8 * i + 6] &= 0x1FFF;
+
+ r->coeffs[8 * i + 7] = a[13 * i + 11] >> 3;
+ r->coeffs[8 * i + 7] |= (ulong32)a[13 * i + 12] << 5;
+ r->coeffs[8 * i + 7] &= 0x1FFF;
+
+ r->coeffs[8 * i + 0] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 0];
+ r->coeffs[8 * i + 1] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 1];
+ r->coeffs[8 * i + 2] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 2];
+ r->coeffs[8 * i + 3] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 3];
+ r->coeffs[8 * i + 4] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 4];
+ r->coeffs[8 * i + 5] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 5];
+ r->coeffs[8 * i + 6] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 6];
+ r->coeffs[8 * i + 7] = (1 << (MLDSA_D - 1)) - r->coeffs[8 * i + 7];
+ }
+}
+
+static void s_polyz_pack(unsigned char *r, const mldsa_poly *a, int gamma1)
+{
+ unsigned int i;
+ ulong32 t[4];
+
+ if (gamma1 == (1 << 17)) {
+ for (i = 0; i < MLDSA_N / 4; ++i) {
+ t[0] = gamma1 - a->coeffs[4 * i + 0];
+ t[1] = gamma1 - a->coeffs[4 * i + 1];
+ t[2] = gamma1 - a->coeffs[4 * i + 2];
+ t[3] = gamma1 - a->coeffs[4 * i + 3];
+
+ r[9 * i + 0] = (unsigned char)(t[0]);
+ r[9 * i + 1] = (unsigned char)(t[0] >> 8);
+ r[9 * i + 2] = (unsigned char)(t[0] >> 16);
+ r[9 * i + 2] |= (unsigned char)(t[1] << 2);
+ r[9 * i + 3] = (unsigned char)(t[1] >> 6);
+ r[9 * i + 4] = (unsigned char)(t[1] >> 14);
+ r[9 * i + 4] |= (unsigned char)(t[2] << 4);
+ r[9 * i + 5] = (unsigned char)(t[2] >> 4);
+ r[9 * i + 6] = (unsigned char)(t[2] >> 12);
+ r[9 * i + 6] |= (unsigned char)(t[3] << 6);
+ r[9 * i + 7] = (unsigned char)(t[3] >> 2);
+ r[9 * i + 8] = (unsigned char)(t[3] >> 10);
+ }
+ } else {
+ /* gamma1 == (1 << 19) */
+ for (i = 0; i < MLDSA_N / 2; ++i) {
+ t[0] = gamma1 - a->coeffs[2 * i + 0];
+ t[1] = gamma1 - a->coeffs[2 * i + 1];
+
+ r[5 * i + 0] = (unsigned char)(t[0]);
+ r[5 * i + 1] = (unsigned char)(t[0] >> 8);
+ r[5 * i + 2] = (unsigned char)(t[0] >> 16);
+ r[5 * i + 2] |= (unsigned char)(t[1] << 4);
+ r[5 * i + 3] = (unsigned char)(t[1] >> 4);
+ r[5 * i + 4] = (unsigned char)(t[1] >> 12);
+ }
+ }
+}
+
+static void s_polyz_unpack(mldsa_poly *r, const unsigned char *a, int gamma1)
+{
+ unsigned int i;
+
+ if (gamma1 == (1 << 17)) {
+ for (i = 0; i < MLDSA_N / 4; ++i) {
+ r->coeffs[4 * i + 0] = a[9 * i + 0];
+ r->coeffs[4 * i + 0] |= (ulong32)a[9 * i + 1] << 8;
+ r->coeffs[4 * i + 0] |= (ulong32)a[9 * i + 2] << 16;
+ r->coeffs[4 * i + 0] &= 0x3FFFF;
+
+ r->coeffs[4 * i + 1] = a[9 * i + 2] >> 2;
+ r->coeffs[4 * i + 1] |= (ulong32)a[9 * i + 3] << 6;
+ r->coeffs[4 * i + 1] |= (ulong32)a[9 * i + 4] << 14;
+ r->coeffs[4 * i + 1] &= 0x3FFFF;
+
+ r->coeffs[4 * i + 2] = a[9 * i + 4] >> 4;
+ r->coeffs[4 * i + 2] |= (ulong32)a[9 * i + 5] << 4;
+ r->coeffs[4 * i + 2] |= (ulong32)a[9 * i + 6] << 12;
+ r->coeffs[4 * i + 2] &= 0x3FFFF;
+
+ r->coeffs[4 * i + 3] = a[9 * i + 6] >> 6;
+ r->coeffs[4 * i + 3] |= (ulong32)a[9 * i + 7] << 2;
+ r->coeffs[4 * i + 3] |= (ulong32)a[9 * i + 8] << 10;
+ r->coeffs[4 * i + 3] &= 0x3FFFF;
+
+ r->coeffs[4 * i + 0] = gamma1 - r->coeffs[4 * i + 0];
+ r->coeffs[4 * i + 1] = gamma1 - r->coeffs[4 * i + 1];
+ r->coeffs[4 * i + 2] = gamma1 - r->coeffs[4 * i + 2];
+ r->coeffs[4 * i + 3] = gamma1 - r->coeffs[4 * i + 3];
+ }
+ } else {
+ /* gamma1 == (1 << 19) */
+ for (i = 0; i < MLDSA_N / 2; ++i) {
+ r->coeffs[2 * i + 0] = a[5 * i + 0];
+ r->coeffs[2 * i + 0] |= (ulong32)a[5 * i + 1] << 8;
+ r->coeffs[2 * i + 0] |= (ulong32)a[5 * i + 2] << 16;
+ r->coeffs[2 * i + 0] &= 0xFFFFF;
+
+ r->coeffs[2 * i + 1] = a[5 * i + 2] >> 4;
+ r->coeffs[2 * i + 1] |= (ulong32)a[5 * i + 3] << 4;
+ r->coeffs[2 * i + 1] |= (ulong32)a[5 * i + 4] << 12;
+ r->coeffs[2 * i + 1] &= 0xFFFFF;
+
+ r->coeffs[2 * i + 0] = gamma1 - r->coeffs[2 * i + 0];
+ r->coeffs[2 * i + 1] = gamma1 - r->coeffs[2 * i + 1];
+ }
+ }
+}
+
+static void s_polyw1_pack(unsigned char *r, const mldsa_poly *a, int gamma2)
+{
+ unsigned int i;
+
+ if (gamma2 == (MLDSA_Q - 1) / 88) {
+ for (i = 0; i < MLDSA_N / 4; ++i) {
+ r[3 * i + 0] = (unsigned char)(a->coeffs[4 * i + 0]);
+ r[3 * i + 0] |= (unsigned char)(a->coeffs[4 * i + 1] << 6);
+ r[3 * i + 1] = (unsigned char)(a->coeffs[4 * i + 1] >> 2);
+ r[3 * i + 1] |= (unsigned char)(a->coeffs[4 * i + 2] << 4);
+ r[3 * i + 2] = (unsigned char)(a->coeffs[4 * i + 2] >> 4);
+ r[3 * i + 2] |= (unsigned char)(a->coeffs[4 * i + 3] << 2);
+ }
+ } else {
+ /* gamma2 == (MLDSA_Q - 1) / 32 */
+ for (i = 0; i < MLDSA_N / 2; ++i)
+ r[i] = (unsigned char)(a->coeffs[2 * i + 0] | (a->coeffs[2 * i + 1] << 4));
+ }
+}
+
+/* Now implement s_poly_uniform_gamma1 */
+static int s_poly_uniform_gamma1(mldsa_poly *a, const unsigned char seed[MLDSA_CRHBYTES],
+ unsigned int nonce, const mldsa_params *p)
+{
+ /* polyz_packed bytes: 576 or 640. SHAKE256 rate=136.
+ ceil(640/136) = 5 blocks = 680 bytes max */
+ unsigned char buf[5 * MLDSA_SHAKE256_RATE];
+ unsigned int buflen;
+ hash_state state;
+ int err;
+
+ buflen = (unsigned int)p->polyz_packed;
+ if (buflen > sizeof(buf))
+ buflen = sizeof(buf);
+
+ if ((err = s_shake256_stream_init(&state, seed, MLDSA_CRHBYTES, nonce)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_done(&state, buf, buflen)) != CRYPT_OK) return err;
+
+ s_polyz_unpack(a, buf, p->gamma1);
+ return CRYPT_OK;
+}
+
+static int s_poly_challenge(mldsa_poly *c, const unsigned char *seed,
+ int ctilde_bytes, int tau)
+{
+ unsigned int i, b, pos;
+ ulong64 signs;
+ unsigned char buf[MLDSA_SHAKE256_RATE];
+ hash_state state;
+ int err;
+
+ if ((err = sha3_shake_init(&state, 256)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&state, seed, ctilde_bytes)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_done(&state, buf, MLDSA_SHAKE256_RATE)) != CRYPT_OK) return err;
+
+ signs = 0;
+ for (i = 0; i < 8; ++i)
+ signs |= (ulong64)buf[i] << (8 * i);
+ pos = 8;
+
+ for (i = 0; i < MLDSA_N; ++i)
+ c->coeffs[i] = 0;
+
+ for (i = MLDSA_N - (unsigned int)tau; i < MLDSA_N; ++i) {
+ do {
+ if (pos >= MLDSA_SHAKE256_RATE) {
+ /* sha3_shake_done supports incremental squeezing */
+ if ((err = sha3_shake_done(&state, buf, MLDSA_SHAKE256_RATE)) != CRYPT_OK) return err;
+ pos = 0;
+ }
+
+ b = buf[pos++];
+ } while (b > i);
+
+ c->coeffs[i] = c->coeffs[b];
+ c->coeffs[b] = 1 - 2 * (int)(signs & 1);
+ signs >>= 1;
+ }
+
+ return CRYPT_OK;
+}
+
+/* Polyvec operations (runtime k/l) */
+
+static int s_polyvec_matrix_expand(mldsa_polyvecl *mat, int k, int l,
+ const unsigned char rho[MLDSA_SEEDBYTES])
+{
+ int i, j, err;
+
+ for (i = 0; i < k; ++i)
+ for (j = 0; j < l; ++j) {
+ if ((err = s_poly_uniform(&mat[i].vec[j], rho, (unsigned int)((i << 8) + j))) != CRYPT_OK)
+ return err;
+ }
+
+ return CRYPT_OK;
+}
+
+static void s_polyvec_matrix_pointwise_montgomery(mldsa_polyveck *t,
+ const mldsa_polyvecl *mat,
+ const mldsa_polyvecl *v,
+ int k, int l)
+{
+ int i, j;
+ mldsa_poly tmp;
+
+ for (i = 0; i < k; ++i) {
+ s_poly_pointwise_montgomery(&t->vec[i], &mat[i].vec[0], &v->vec[0]);
+ for (j = 1; j < l; ++j) {
+ s_poly_pointwise_montgomery(&tmp, &mat[i].vec[j], &v->vec[j]);
+ s_mldsa_poly_add(&t->vec[i], &t->vec[i], &tmp);
+ }
+ }
+}
+
+/* ---- polyvecl operations ---- */
+
+static int s_polyvecl_uniform_eta(mldsa_polyvecl *v,
+ const unsigned char seed[MLDSA_CRHBYTES],
+ unsigned int nonce, int l, int eta)
+{
+ int i, err;
+ for (i = 0; i < l; ++i) {
+ if ((err = s_poly_uniform_eta(&v->vec[i], seed, nonce++, eta)) != CRYPT_OK)
+ return err;
+ }
+ return CRYPT_OK;
+}
+
+static int s_polyvecl_uniform_gamma1(mldsa_polyvecl *v,
+ const unsigned char seed[MLDSA_CRHBYTES],
+ unsigned int nonce, int l,
+ const mldsa_params *p)
+{
+ int i, err;
+ for (i = 0; i < l; ++i) {
+ if ((err = s_poly_uniform_gamma1(&v->vec[i], seed, (unsigned int)(l * nonce + i), p)) != CRYPT_OK)
+ return err;
+ }
+ return CRYPT_OK;
+}
+
+static void s_polyvecl_reduce(mldsa_polyvecl *v, int l)
+{
+ int i;
+ for (i = 0; i < l; ++i)
+ s_mldsa_poly_reduce(&v->vec[i]);
+}
+
+static void s_polyvecl_add(mldsa_polyvecl *w, const mldsa_polyvecl *u,
+ const mldsa_polyvecl *v, int l)
+{
+ int i;
+ for (i = 0; i < l; ++i)
+ s_mldsa_poly_add(&w->vec[i], &u->vec[i], &v->vec[i]);
+}
+
+static void s_polyvecl_ntt(mldsa_polyvecl *v, int l)
+{
+ int i;
+ for (i = 0; i < l; ++i)
+ s_mldsa_poly_ntt(&v->vec[i]);
+}
+
+static void s_polyvecl_invntt_tomont(mldsa_polyvecl *v, int l)
+{
+ int i;
+ for (i = 0; i < l; ++i)
+ s_mldsa_poly_invntt_tomont(&v->vec[i]);
+}
+
+static void s_polyvecl_pointwise_poly_montgomery(mldsa_polyvecl *r,
+ const mldsa_poly *a,
+ const mldsa_polyvecl *v, int l)
+{
+ int i;
+ for (i = 0; i < l; ++i)
+ s_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]);
+}
+
+static int s_polyvecl_chknorm(const mldsa_polyvecl *v, int bound, int l)
+{
+ int i;
+ for (i = 0; i < l; ++i)
+ if (s_poly_chknorm(&v->vec[i], bound))
+ return 1;
+ return 0;
+}
+
+/* ---- polyveck operations ---- */
+
+static int s_polyveck_uniform_eta(mldsa_polyveck *v,
+ const unsigned char seed[MLDSA_CRHBYTES],
+ unsigned int nonce, int k, int eta)
+{
+ int i, err;
+ for (i = 0; i < k; ++i) {
+ if ((err = s_poly_uniform_eta(&v->vec[i], seed, nonce++, eta)) != CRYPT_OK)
+ return err;
+ }
+ return CRYPT_OK;
+}
+
+static void s_polyveck_reduce(mldsa_polyveck *v, int k)
+{
+ int i;
+ for (i = 0; i < k; ++i)
+ s_mldsa_poly_reduce(&v->vec[i]);
+}
+
+static void s_polyveck_caddq(mldsa_polyveck *v, int k)
+{
+ int i;
+ for (i = 0; i < k; ++i)
+ s_poly_caddq(&v->vec[i]);
+}
+
+static void s_polyveck_add(mldsa_polyveck *w, const mldsa_polyveck *u,
+ const mldsa_polyveck *v, int k)
+{
+ int i;
+ for (i = 0; i < k; ++i)
+ s_mldsa_poly_add(&w->vec[i], &u->vec[i], &v->vec[i]);
+}
+
+static void s_polyveck_sub(mldsa_polyveck *w, const mldsa_polyveck *u,
+ const mldsa_polyveck *v, int k)
+{
+ int i;
+ for (i = 0; i < k; ++i)
+ s_mldsa_poly_sub(&w->vec[i], &u->vec[i], &v->vec[i]);
+}
+
+static void s_polyveck_shiftl(mldsa_polyveck *v, int k)
+{
+ int i;
+ for (i = 0; i < k; ++i)
+ s_poly_shiftl(&v->vec[i]);
+}
+
+static void s_polyveck_ntt(mldsa_polyveck *v, int k)
+{
+ int i;
+ for (i = 0; i < k; ++i)
+ s_mldsa_poly_ntt(&v->vec[i]);
+}
+
+static void s_polyveck_invntt_tomont(mldsa_polyveck *v, int k)
+{
+ int i;
+ for (i = 0; i < k; ++i)
+ s_mldsa_poly_invntt_tomont(&v->vec[i]);
+}
+
+static void s_polyveck_pointwise_poly_montgomery(mldsa_polyveck *r,
+ const mldsa_poly *a,
+ const mldsa_polyveck *v, int k)
+{
+ int i;
+ for (i = 0; i < k; ++i)
+ s_poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]);
+}
+
+static int s_polyveck_chknorm(const mldsa_polyveck *v, int bound, int k)
+{
+ int i;
+ for (i = 0; i < k; ++i)
+ if (s_poly_chknorm(&v->vec[i], bound))
+ return 1;
+ return 0;
+}
+
+static void s_polyveck_power2round(mldsa_polyveck *v1, mldsa_polyveck *v0,
+ const mldsa_polyveck *v, int k)
+{
+ int i;
+ for (i = 0; i < k; ++i)
+ s_poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]);
+}
+
+static void s_polyveck_decompose(mldsa_polyveck *v1, mldsa_polyveck *v0,
+ const mldsa_polyveck *v, int k, int gamma2)
+{
+ int i;
+ for (i = 0; i < k; ++i)
+ s_poly_decompose(&v1->vec[i], &v0->vec[i], &v->vec[i], gamma2);
+}
+
+static unsigned int s_polyveck_make_hint(mldsa_polyveck *h,
+ const mldsa_polyveck *v0,
+ const mldsa_polyveck *v1,
+ int k, int gamma2)
+{
+ unsigned int i, s = 0;
+ for (i = 0; i < (unsigned)k; ++i)
+ s += s_poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i], gamma2);
+ return s;
+}
+
+static void s_polyveck_use_hint(mldsa_polyveck *w, const mldsa_polyveck *u,
+ const mldsa_polyveck *h, int k, int gamma2)
+{
+ int i;
+ for (i = 0; i < k; ++i)
+ s_poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i], gamma2);
+}
+
+static void s_polyveck_pack_w1(unsigned char *r, const mldsa_polyveck *w1,
+ int k, unsigned long polyw1_packed, int gamma2)
+{
+ int i;
+ for (i = 0; i < k; ++i)
+ s_polyw1_pack(r + (unsigned long)i * polyw1_packed, &w1->vec[i], gamma2);
+}
+
+/* Packing (key and signature) */
+
+static void s_pack_pk(unsigned char *pk, const unsigned char rho[MLDSA_SEEDBYTES],
+ const mldsa_polyveck *t1, int k)
+{
+ unsigned int i;
+
+ XMEMCPY(pk, rho, MLDSA_SEEDBYTES);
+ pk += MLDSA_SEEDBYTES;
+
+ for (i = 0; i < (unsigned)k; ++i)
+ s_polyt1_pack(pk + i * MLDSA_POLYT1_PACKEDBYTES, &t1->vec[i]);
+}
+
+static void s_unpack_pk(unsigned char rho[MLDSA_SEEDBYTES], mldsa_polyveck *t1,
+ const unsigned char *pk, int k)
+{
+ unsigned int i;
+
+ XMEMCPY(rho, pk, MLDSA_SEEDBYTES);
+ pk += MLDSA_SEEDBYTES;
+
+ for (i = 0; i < (unsigned)k; ++i)
+ s_polyt1_unpack(&t1->vec[i], pk + i * MLDSA_POLYT1_PACKEDBYTES);
+}
+
+static void s_pack_sk(unsigned char *sk,
+ const unsigned char rho[MLDSA_SEEDBYTES],
+ const unsigned char tr[MLDSA_TRBYTES],
+ const unsigned char key[MLDSA_SEEDBYTES],
+ const mldsa_polyveck *t0,
+ const mldsa_polyvecl *s1,
+ const mldsa_polyveck *s2,
+ const mldsa_params *p)
+{
+ unsigned int i;
+
+ XMEMCPY(sk, rho, MLDSA_SEEDBYTES);
+ sk += MLDSA_SEEDBYTES;
+
+ XMEMCPY(sk, key, MLDSA_SEEDBYTES);
+ sk += MLDSA_SEEDBYTES;
+
+ XMEMCPY(sk, tr, MLDSA_TRBYTES);
+ sk += MLDSA_TRBYTES;
+
+ for (i = 0; i < (unsigned)p->l; ++i)
+ s_polyeta_pack(sk + i * p->polyeta_packed, &s1->vec[i], p->eta);
+ sk += (unsigned long)p->l * p->polyeta_packed;
+
+ for (i = 0; i < (unsigned)p->k; ++i)
+ s_polyeta_pack(sk + i * p->polyeta_packed, &s2->vec[i], p->eta);
+ sk += (unsigned long)p->k * p->polyeta_packed;
+
+ for (i = 0; i < (unsigned)p->k; ++i)
+ s_polyt0_pack(sk + i * MLDSA_POLYT0_PACKEDBYTES, &t0->vec[i]);
+}
+
+static void s_unpack_sk(unsigned char rho[MLDSA_SEEDBYTES],
+ unsigned char tr[MLDSA_TRBYTES],
+ unsigned char key[MLDSA_SEEDBYTES],
+ mldsa_polyveck *t0,
+ mldsa_polyvecl *s1,
+ mldsa_polyveck *s2,
+ const unsigned char *sk,
+ const mldsa_params *p)
+{
+ unsigned int i;
+
+ XMEMCPY(rho, sk, MLDSA_SEEDBYTES);
+ sk += MLDSA_SEEDBYTES;
+
+ XMEMCPY(key, sk, MLDSA_SEEDBYTES);
+ sk += MLDSA_SEEDBYTES;
+
+ XMEMCPY(tr, sk, MLDSA_TRBYTES);
+ sk += MLDSA_TRBYTES;
+
+ for (i = 0; i < (unsigned)p->l; ++i)
+ s_polyeta_unpack(&s1->vec[i], sk + i * p->polyeta_packed, p->eta);
+ sk += (unsigned long)p->l * p->polyeta_packed;
+
+ for (i = 0; i < (unsigned)p->k; ++i)
+ s_polyeta_unpack(&s2->vec[i], sk + i * p->polyeta_packed, p->eta);
+ sk += (unsigned long)p->k * p->polyeta_packed;
+
+ for (i = 0; i < (unsigned)p->k; ++i)
+ s_polyt0_unpack(&t0->vec[i], sk + i * MLDSA_POLYT0_PACKEDBYTES);
+}
+
+static void s_pack_sig(unsigned char *sig,
+ const unsigned char *c, int ctilde_bytes,
+ const mldsa_polyvecl *z,
+ const mldsa_polyveck *h,
+ const mldsa_params *p)
+{
+ unsigned int i, j, k;
+
+ XMEMCPY(sig, c, ctilde_bytes);
+ sig += ctilde_bytes;
+
+ for (i = 0; i < (unsigned)p->l; ++i)
+ s_polyz_pack(sig + i * p->polyz_packed, &z->vec[i], p->gamma1);
+ sig += (unsigned long)p->l * p->polyz_packed;
+
+ /* Encode h */
+ for (i = 0; i < (unsigned long)p->omega + (unsigned long)p->k; ++i)
+ sig[i] = 0;
+
+ k = 0;
+ for (i = 0; i < (unsigned)p->k; ++i) {
+ for (j = 0; j < MLDSA_N; ++j)
+ if (h->vec[i].coeffs[j] != 0)
+ sig[k++] = (unsigned char)j;
+ sig[p->omega + i] = (unsigned char)k;
+ }
+}
+
+static int s_unpack_sig(unsigned char *c, int ctilde_bytes,
+ mldsa_polyvecl *z,
+ mldsa_polyveck *h,
+ const unsigned char *sig,
+ const mldsa_params *p)
+{
+ unsigned int i, j, k;
+
+ XMEMCPY(c, sig, ctilde_bytes);
+ sig += ctilde_bytes;
+
+ for (i = 0; i < (unsigned)p->l; ++i)
+ s_polyz_unpack(&z->vec[i], sig + i * p->polyz_packed, p->gamma1);
+ sig += (unsigned long)p->l * p->polyz_packed;
+
+ /* Decode h */
+ k = 0;
+ for (i = 0; i < (unsigned)p->k; ++i) {
+ for (j = 0; j < MLDSA_N; ++j)
+ h->vec[i].coeffs[j] = 0;
+
+ if (sig[p->omega + i] < k || sig[p->omega + i] > (unsigned)p->omega)
+ return 1;
+
+ for (j = k; j < sig[p->omega + i]; ++j) {
+ /* Coefficients are ordered for strong unforgeability */
+ if (j > k && sig[j] <= sig[j - 1]) return 1;
+ h->vec[i].coeffs[sig[j]] = 1;
+ }
+
+ k = sig[p->omega + i];
+ }
+
+ /* Extra indices are zero for strong unforgeability */
+ for (j = k; j < (unsigned)p->omega; ++j)
+ if (sig[j])
+ return 1;
+
+ return 0;
+}
+
+/* Sign / verify core */
+
+static int s_sign_internal(unsigned char *sig, unsigned long *siglen,
+ const unsigned char *msg, unsigned long msglen,
+ const unsigned char *pre, unsigned long prelen,
+ const unsigned char rnd[MLDSA_RNDBYTES],
+ const unsigned char *sk,
+ const mldsa_params *p)
+{
+ unsigned int n;
+ unsigned char seedbuf[2 * MLDSA_SEEDBYTES + MLDSA_TRBYTES + 2 * MLDSA_CRHBYTES];
+ unsigned char *rho, *tr, *key, *mu, *rhoprime;
+ unsigned int nonce = 0;
+ mldsa_polyvecl mat[MLDSA_K_MAX], s1, y, z;
+ mldsa_polyveck t0, s2, w1, w0, h;
+ mldsa_poly cp;
+ hash_state state;
+ int err;
+
+ XMEMSET(mat, 0, sizeof(mat));
+ XMEMSET(&s1, 0, sizeof(s1));
+ XMEMSET(&s2, 0, sizeof(s2));
+ XMEMSET(&t0, 0, sizeof(t0));
+
+ rho = seedbuf;
+ tr = rho + MLDSA_SEEDBYTES;
+ key = tr + MLDSA_TRBYTES;
+ mu = key + MLDSA_SEEDBYTES;
+ rhoprime = mu + MLDSA_CRHBYTES;
+ s_unpack_sk(rho, tr, key, &t0, &s1, &s2, sk, p);
+
+ /* Compute mu = CRH(tr, pre, msg) */
+ if ((err = sha3_shake_init(&state, 256)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&state, tr, MLDSA_TRBYTES)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&state, pre, prelen)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&state, msg, msglen)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_done(&state, mu, MLDSA_CRHBYTES)) != CRYPT_OK) return err;
+
+ /* Compute rhoprime = CRH(key, rnd, mu) */
+ if ((err = sha3_shake_init(&state, 256)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&state, key, MLDSA_SEEDBYTES)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&state, rnd, MLDSA_RNDBYTES)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&state, mu, MLDSA_CRHBYTES)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_done(&state, rhoprime, MLDSA_CRHBYTES)) != CRYPT_OK) return err;
+
+ /* Expand matrix and transform vectors */
+ if ((err = s_polyvec_matrix_expand(mat, p->k, p->l, rho)) != CRYPT_OK) return err;
+ s_polyvecl_ntt(&s1, p->l);
+ s_polyveck_ntt(&s2, p->k);
+ s_polyveck_ntt(&t0, p->k);
+
+rej:
+ /* Sample intermediate vector y */
+ if ((err = s_polyvecl_uniform_gamma1(&y, rhoprime, nonce++, p->l, p)) != CRYPT_OK) return err;
+
+ /* Matrix-vector multiplication */
+ z = y;
+ s_polyvecl_ntt(&z, p->l);
+ s_polyvec_matrix_pointwise_montgomery(&w1, mat, &z, p->k, p->l);
+ s_polyveck_reduce(&w1, p->k);
+ s_polyveck_invntt_tomont(&w1, p->k);
+
+ /* Decompose w and call the random oracle */
+ s_polyveck_caddq(&w1, p->k);
+ s_polyveck_decompose(&w1, &w0, &w1, p->k, p->gamma2);
+ s_polyveck_pack_w1(sig, &w1, p->k, p->polyw1_packed, p->gamma2);
+
+ if ((err = sha3_shake_init(&state, 256)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&state, mu, MLDSA_CRHBYTES)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&state, sig, (unsigned long)p->k * p->polyw1_packed)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_done(&state, sig, p->ctilde_bytes)) != CRYPT_OK) return err;
+ if ((err = s_poly_challenge(&cp, sig, p->ctilde_bytes, p->tau)) != CRYPT_OK) return err;
+ s_mldsa_poly_ntt(&cp);
+
+ /* Compute z, reject if it reveals secret */
+ s_polyvecl_pointwise_poly_montgomery(&z, &cp, &s1, p->l);
+ s_polyvecl_invntt_tomont(&z, p->l);
+ s_polyvecl_add(&z, &z, &y, p->l);
+ s_polyvecl_reduce(&z, p->l);
+ if (s_polyvecl_chknorm(&z, p->gamma1 - p->beta, p->l))
+ goto rej;
+
+ /* Check that subtracting cs2 does not change high bits of w and low bits
+ * do not reveal secret information */
+ s_polyveck_pointwise_poly_montgomery(&h, &cp, &s2, p->k);
+ s_polyveck_invntt_tomont(&h, p->k);
+ s_polyveck_sub(&w0, &w0, &h, p->k);
+ s_polyveck_reduce(&w0, p->k);
+ if (s_polyveck_chknorm(&w0, p->gamma2 - p->beta, p->k))
+ goto rej;
+
+ /* Compute hints for w1 */
+ s_polyveck_pointwise_poly_montgomery(&h, &cp, &t0, p->k);
+ s_polyveck_invntt_tomont(&h, p->k);
+ s_polyveck_reduce(&h, p->k);
+ if (s_polyveck_chknorm(&h, p->gamma2, p->k))
+ goto rej;
+
+ s_polyveck_add(&w0, &w0, &h, p->k);
+ n = s_polyveck_make_hint(&h, &w0, &w1, p->k, p->gamma2);
+ if (n > (unsigned)p->omega)
+ goto rej;
+
+ /* Write signature */
+ s_pack_sig(sig, sig, p->ctilde_bytes, &z, &h, p);
+ *siglen = p->sig_bytes;
+ return CRYPT_OK;
+}
+
+static int s_verify_internal(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *msg, unsigned long msglen,
+ const unsigned char *pre, unsigned long prelen,
+ const unsigned char *pk,
+ const mldsa_params *p)
+{
+ unsigned int i;
+ unsigned char *buf = NULL;
+ unsigned char rho[MLDSA_SEEDBYTES];
+ unsigned char mu[MLDSA_CRHBYTES];
+ unsigned char c[64]; /* max ctilde_bytes = 64 */
+ unsigned char c2[64];
+ mldsa_poly cp;
+ mldsa_polyvecl mat[MLDSA_K_MAX], z;
+ mldsa_polyveck t1, w1, h;
+ hash_state state;
+ int err;
+
+ XMEMSET(mat, 0, sizeof(mat));
+ XMEMSET(&z, 0, sizeof(z));
+ XMEMSET(&t1, 0, sizeof(t1));
+
+ if (siglen != p->sig_bytes)
+ return CRYPT_INVALID_PACKET;
+
+ buf = XMALLOC((unsigned long)p->k * p->polyw1_packed);
+ if (buf == NULL)
+ return CRYPT_MEM;
+
+ s_unpack_pk(rho, &t1, pk, p->k);
+ if (s_unpack_sig(c, p->ctilde_bytes, &z, &h, sig, p)) {
+ XFREE(buf);
+ return CRYPT_INVALID_PACKET;
+ }
+ if (s_polyvecl_chknorm(&z, p->gamma1 - p->beta, p->l)) {
+ XFREE(buf);
+ return CRYPT_INVALID_PACKET;
+ }
+
+ /* Compute CRH(H(rho, t1), pre, msg) */
+ if ((err = s_shake256(mu, MLDSA_TRBYTES, pk, p->pk_bytes)) != CRYPT_OK) {
+ XFREE(buf);
+ return err;
+ }
+ if ((err = sha3_shake_init(&state, 256)) != CRYPT_OK) { XFREE(buf); return err; }
+ if ((err = sha3_shake_process(&state, mu, MLDSA_TRBYTES)) != CRYPT_OK) { XFREE(buf); return err; }
+ if ((err = sha3_shake_process(&state, pre, prelen)) != CRYPT_OK) { XFREE(buf); return err; }
+ if ((err = sha3_shake_process(&state, msg, msglen)) != CRYPT_OK) { XFREE(buf); return err; }
+ if ((err = sha3_shake_done(&state, mu, MLDSA_CRHBYTES)) != CRYPT_OK) { XFREE(buf); return err; }
+
+ /* Matrix-vector multiplication; compute Az - c2^dt1 */
+ if ((err = s_poly_challenge(&cp, c, p->ctilde_bytes, p->tau)) != CRYPT_OK) { XFREE(buf); return err; }
+ if ((err = s_polyvec_matrix_expand(mat, p->k, p->l, rho)) != CRYPT_OK) { XFREE(buf); return err; }
+
+ s_polyvecl_ntt(&z, p->l);
+ s_polyvec_matrix_pointwise_montgomery(&w1, mat, &z, p->k, p->l);
+
+ s_mldsa_poly_ntt(&cp);
+ s_polyveck_shiftl(&t1, p->k);
+ s_polyveck_ntt(&t1, p->k);
+ s_polyveck_pointwise_poly_montgomery(&t1, &cp, &t1, p->k);
+
+ s_polyveck_sub(&w1, &w1, &t1, p->k);
+ s_polyveck_reduce(&w1, p->k);
+ s_polyveck_invntt_tomont(&w1, p->k);
+
+ /* Reconstruct w1 */
+ s_polyveck_caddq(&w1, p->k);
+ s_polyveck_use_hint(&w1, &w1, &h, p->k, p->gamma2);
+ s_polyveck_pack_w1(buf, &w1, p->k, p->polyw1_packed, p->gamma2);
+
+ /* Call random oracle and verify challenge */
+ if ((err = sha3_shake_init(&state, 256)) != CRYPT_OK) { XFREE(buf); return err; }
+ if ((err = sha3_shake_process(&state, mu, MLDSA_CRHBYTES)) != CRYPT_OK) { XFREE(buf); return err; }
+ if ((err = sha3_shake_process(&state, buf, (unsigned long)p->k * p->polyw1_packed)) != CRYPT_OK) { XFREE(buf); return err; }
+ if ((err = sha3_shake_done(&state, c2, p->ctilde_bytes)) != CRYPT_OK) { XFREE(buf); return err; }
+
+ XFREE(buf);
+
+ for (i = 0; i < (unsigned)p->ctilde_bytes; ++i)
+ if (c[i] != c2[i])
+ return CRYPT_INVALID_PACKET;
+
+ return CRYPT_OK;
+}
+
+/* Public API */
+
+static int s_mldsa_make_key_seed(int alg,
+ const unsigned char seedbuf[MLDSA_SEEDBYTES],
+ mldsa_key *key)
+{
+ mldsa_params p;
+ unsigned char expanded[2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES];
+ unsigned char hashbuf[MLDSA_SEEDBYTES + 2];
+ unsigned char tr[MLDSA_TRBYTES];
+ const unsigned char *rho, *rhoprime, *kk;
+ mldsa_polyvecl mat[MLDSA_K_MAX], s1, s1hat;
+ mldsa_polyveck s2, t1, t0;
+ int err = CRYPT_OK;
+
+ LTC_ARGCHK(key != NULL);
+
+ XMEMSET(mat, 0, sizeof(mat));
+ XMEMSET(&s1, 0, sizeof(s1));
+ XMEMSET(&s2, 0, sizeof(s2));
+ XMEMSET(key, 0, sizeof(*key));
+
+ if ((err = s_mldsa_get_params(alg, &p)) != CRYPT_OK) goto cleanup;
+
+ /* Expand seed: SHAKE256(xi || k || l) -> rho || rhoprime || key */
+ XMEMCPY(hashbuf, seedbuf, MLDSA_SEEDBYTES);
+ hashbuf[MLDSA_SEEDBYTES] = (unsigned char)p.k;
+ hashbuf[MLDSA_SEEDBYTES + 1] = (unsigned char)p.l;
+ if ((err = s_shake256(expanded, 2 * MLDSA_SEEDBYTES + MLDSA_CRHBYTES,
+ hashbuf, MLDSA_SEEDBYTES + 2)) != CRYPT_OK) {
+ goto cleanup;
+ }
+
+ rho = expanded;
+ rhoprime = rho + MLDSA_SEEDBYTES;
+ kk = rhoprime + MLDSA_CRHBYTES;
+
+ /* Expand matrix */
+ if ((err = s_polyvec_matrix_expand(mat, p.k, p.l, rho)) != CRYPT_OK) goto cleanup;
+
+ /* Sample short vectors s1 and s2 */
+ if ((err = s_polyvecl_uniform_eta(&s1, rhoprime, 0, p.l, p.eta)) != CRYPT_OK) goto cleanup;
+ if ((err = s_polyveck_uniform_eta(&s2, rhoprime, (unsigned)p.l, p.k, p.eta)) != CRYPT_OK) goto cleanup;
+
+ /* Matrix-vector multiplication */
+ s1hat = s1;
+ s_polyvecl_ntt(&s1hat, p.l);
+ s_polyvec_matrix_pointwise_montgomery(&t1, mat, &s1hat, p.k, p.l);
+ s_polyveck_reduce(&t1, p.k);
+ s_polyveck_invntt_tomont(&t1, p.k);
+
+ /* Add error vector s2 */
+ s_polyveck_add(&t1, &t1, &s2, p.k);
+
+ /* Extract t1 and write public key */
+ s_polyveck_caddq(&t1, p.k);
+ s_polyveck_power2round(&t1, &t0, &t1, p.k);
+
+ /* Allocate key storage */
+ key->pk = XMALLOC(p.pk_bytes);
+ key->sk = XMALLOC(p.sk_bytes);
+ if (key->pk == NULL || key->sk == NULL) {
+ err = CRYPT_MEM;
+ goto cleanup;
+ }
+
+ s_pack_pk(key->pk, rho, &t1, p.k);
+
+ /* Compute H(rho, t1) = tr */
+ if ((err = s_shake256(tr, MLDSA_TRBYTES, key->pk, p.pk_bytes)) != CRYPT_OK) {
+ goto cleanup;
+ }
+
+ s_pack_sk(key->sk, rho, tr, kk, &t0, &s1, &s2, &p);
+
+ key->alg = alg;
+ key->type = PK_PRIVATE;
+ key->pklen = p.pk_bytes;
+ key->sklen = p.sk_bytes;
+
+cleanup:
+ if (err != CRYPT_OK) {
+ mldsa_free(key);
+ }
+ zeromem(hashbuf, sizeof(hashbuf));
+ zeromem(expanded, sizeof(expanded));
+ zeromem(tr, sizeof(tr));
+ return err;
+}
+
+/**
+ Generate an ML-DSA key pair deterministically from a seed.
+ @param alg The parameter set (LTC_MLDSA_44, LTC_MLDSA_65, or LTC_MLDSA_87)
+ @param seed The input seed (exactly 32 bytes)
+ @param seedlen Length of the seed in bytes
+ @param key [out] Destination for the newly created key pair
+ @return CRYPT_OK if successful
+*/
+int mldsa_make_key_from_seed(int alg, const unsigned char *seed, unsigned long seedlen,
+ mldsa_key *key)
+{
+ LTC_ARGCHK(seed != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if (seedlen != MLDSA_SEEDBYTES) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ return s_mldsa_make_key_seed(alg, seed, key);
+}
+
+/**
+ Generate an ML-DSA key pair.
+ @param prng An active PRNG state
+ @param wprng The index of the desired PRNG
+ @param alg The parameter set (LTC_MLDSA_44, LTC_MLDSA_65, or LTC_MLDSA_87)
+ @param key [out] Destination for the newly created key pair
+ @return CRYPT_OK if successful
+*/
+int mldsa_make_key(prng_state *prng, int wprng, int alg, mldsa_key *key)
+{
+ unsigned char seedbuf[MLDSA_SEEDBYTES];
+ int err;
+
+ LTC_ARGCHK(key != NULL);
+
+ if ((err = prng_is_valid(wprng)) != CRYPT_OK) return err;
+ if (prng_descriptor[wprng].read(seedbuf, MLDSA_SEEDBYTES, prng) != MLDSA_SEEDBYTES)
+ return CRYPT_ERROR_READPRNG;
+
+ err = s_mldsa_make_key_seed(alg, seedbuf, key);
+ zeromem(seedbuf, sizeof(seedbuf));
+ return err;
+}
+
+/**
+ Free an ML-DSA key from memory.
+ @param key The key to free
+*/
+void mldsa_free(mldsa_key *key)
+{
+ if (key == NULL) return;
+ if (key->sk != NULL) {
+ zeromem(key->sk, key->sklen);
+ XFREE(key->sk);
+ }
+ if (key->pk != NULL) {
+ XFREE(key->pk);
+ }
+ XMEMSET(key, 0, sizeof(*key));
+}
+
+/**
+ Export an ML-DSA key to a byte buffer.
+ @param out [out] Destination for the exported key
+ @param outlen [in/out] Max size and resulting size of the exported key
+ @param which PK_PUBLIC for the verification key, PK_PRIVATE for the signing key
+ @param key The key to export
+ @return CRYPT_OK if successful
+*/
+int mldsa_export_raw(unsigned char *out, unsigned long *outlen, int which, const mldsa_key *key)
+{
+ mldsa_params p;
+ unsigned long needed;
+ int err;
+
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if ((err = s_mldsa_get_params(key->alg, &p)) != CRYPT_OK) return err;
+
+ if (which == PK_PUBLIC) {
+ needed = p.pk_bytes;
+ if (*outlen < needed) { *outlen = needed; return CRYPT_BUFFER_OVERFLOW; }
+ if (key->pk == NULL) return CRYPT_PK_NOT_PRIVATE;
+ XMEMCPY(out, key->pk, needed);
+ } else if (which == PK_PRIVATE) {
+ if (key->type != PK_PRIVATE) return CRYPT_PK_NOT_PRIVATE;
+ needed = p.sk_bytes;
+ if (*outlen < needed) { *outlen = needed; return CRYPT_BUFFER_OVERFLOW; }
+ XMEMCPY(out, key->sk, needed);
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ *outlen = needed;
+ return CRYPT_OK;
+}
+
+/**
+ Import an ML-DSA key from a byte buffer.
+ @param in The buffer to import from
+ @param inlen Length of the buffer
+ @param which PK_PUBLIC for a verification key, PK_PRIVATE for a signing key
+ @param alg The parameter set (LTC_MLDSA_44, LTC_MLDSA_65, or LTC_MLDSA_87)
+ @param key [out] Destination for the imported key
+ @return CRYPT_OK if successful
+*/
+int mldsa_import_raw(const unsigned char *in, unsigned long inlen, int which, int alg, mldsa_key *key)
+{
+ mldsa_params p;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if ((err = s_mldsa_get_params(alg, &p)) != CRYPT_OK) return err;
+
+ XMEMSET(key, 0, sizeof(*key));
+ key->alg = alg;
+
+ if (which == PK_PUBLIC) {
+ if (inlen != p.pk_bytes) return CRYPT_INVALID_PACKET;
+ key->pk = XMALLOC(p.pk_bytes);
+ if (key->pk == NULL) return CRYPT_MEM;
+ XMEMCPY(key->pk, in, p.pk_bytes);
+ key->pklen = p.pk_bytes;
+ key->type = PK_PUBLIC;
+ } else if (which == PK_PRIVATE) {
+ if (inlen != p.sk_bytes) return CRYPT_INVALID_PACKET;
+ key->sk = XMALLOC(p.sk_bytes);
+ if (key->sk == NULL) return CRYPT_MEM;
+ XMEMCPY(key->sk, in, p.sk_bytes);
+ key->sklen = p.sk_bytes;
+
+ /* Reconstruct pk from sk: pk = (rho, t1) where rho is at offset 0 of sk.
+ We need to extract rho and recompute t1 from sk components. Actually,
+ the pk is NOT embedded in the sk for ML-DSA (unlike ML-KEM).
+ We need to reconstruct it: unpack sk to get rho,key,tr,s1,s2,t0,
+ then compute t = A*s1 + s2, t1 = power2round(t). */
+ {
+ unsigned char rho[MLDSA_SEEDBYTES], tr[MLDSA_TRBYTES], kk[MLDSA_SEEDBYTES];
+ mldsa_polyvecl mat[MLDSA_K_MAX], s1, s1hat;
+ mldsa_polyveck s2, t0, t1, t0_dummy;
+
+ XMEMSET(mat, 0, sizeof(mat));
+ XMEMSET(&s1, 0, sizeof(s1));
+ XMEMSET(&s2, 0, sizeof(s2));
+
+ s_unpack_sk(rho, tr, kk, &t0, &s1, &s2, in, &p);
+
+ /* Expand matrix */
+ if ((err = s_polyvec_matrix_expand(mat, p.k, p.l, rho)) != CRYPT_OK) {
+ mldsa_free(key);
+ return err;
+ }
+
+ s1hat = s1;
+ s_polyvecl_ntt(&s1hat, p.l);
+ s_polyvec_matrix_pointwise_montgomery(&t1, mat, &s1hat, p.k, p.l);
+ s_polyveck_reduce(&t1, p.k);
+ s_polyveck_invntt_tomont(&t1, p.k);
+ s_polyveck_add(&t1, &t1, &s2, p.k);
+ s_polyveck_caddq(&t1, p.k);
+ s_polyveck_power2round(&t1, &t0_dummy, &t1, p.k);
+
+ key->pk = XMALLOC(p.pk_bytes);
+ if (key->pk == NULL) {
+ mldsa_free(key);
+ return CRYPT_MEM;
+ }
+ s_pack_pk(key->pk, rho, &t1, p.k);
+ key->pklen = p.pk_bytes;
+ }
+
+ key->type = PK_PRIVATE;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ return CRYPT_OK;
+}
+
+/**
+ Sign a message with ML-DSA.
+ @param msg The message to sign
+ @param msglen Length of the message
+ @param sig [out] The signature
+ @param siglen [in/out] Max size and resulting size of the signature
+ @param ctx Optional context string (can be NULL if ctxlen is 0)
+ @param ctxlen Length of the context string (max 255 bytes per FIPS 204)
+ @param prng An active PRNG state (for hedged signing)
+ @param wprng The index of the desired PRNG
+ @param key The private (signing) key
+ @return CRYPT_OK if successful
+*/
+int mldsa_sign(const unsigned char *msg, unsigned long msglen,
+ unsigned char *sig, unsigned long *siglen,
+ const unsigned char *ctx, unsigned long ctxlen,
+ prng_state *prng, int wprng,
+ const mldsa_key *key)
+{
+ mldsa_params p;
+ unsigned char pre[257];
+ unsigned char rnd[MLDSA_RNDBYTES];
+ unsigned long i;
+ int err;
+
+ LTC_ARGCHK(msg != NULL || msglen == 0);
+ LTC_ARGCHK(sig != NULL);
+ LTC_ARGCHK(siglen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if (key->type != PK_PRIVATE) return CRYPT_PK_NOT_PRIVATE;
+ if (ctxlen > 255) return CRYPT_INVALID_ARG;
+
+ if ((err = s_mldsa_get_params(key->alg, &p)) != CRYPT_OK) return err;
+ if (*siglen < p.sig_bytes) { *siglen = p.sig_bytes; return CRYPT_BUFFER_OVERFLOW; }
+ if ((err = prng_is_valid(wprng)) != CRYPT_OK) return err;
+
+ /* Prepare pre = (0, ctxlen, ctx) */
+ pre[0] = 0;
+ pre[1] = (unsigned char)ctxlen;
+ if (ctxlen > 0 && ctx != NULL) {
+ for (i = 0; i < ctxlen; i++)
+ pre[2 + i] = ctx[i];
+ }
+
+ /* Hedged signing: get randomness */
+ if (prng_descriptor[wprng].read(rnd, MLDSA_RNDBYTES, prng) != MLDSA_RNDBYTES)
+ return CRYPT_ERROR_READPRNG;
+
+ err = s_sign_internal(sig, siglen, msg, msglen, pre, 2 + ctxlen, rnd, key->sk, &p);
+
+ zeromem(rnd, sizeof(rnd));
+ return err;
+}
+
+/**
+ Verify a signature with ML-DSA.
+ @param sig The signature to verify
+ @param siglen Length of the signature
+ @param msg The message that was signed
+ @param msglen Length of the message
+ @param ctx Optional context string (can be NULL if ctxlen is 0)
+ @param ctxlen Length of the context string (max 255 bytes per FIPS 204)
+ @param stat [out] Result of the verification: 1==valid, 0==invalid
+ @param key The public (verification) key
+ @return CRYPT_OK if successful (even if the signature is invalid)
+*/
+int mldsa_verify(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *msg, unsigned long msglen,
+ const unsigned char *ctx, unsigned long ctxlen,
+ int *stat,
+ const mldsa_key *key)
+{
+ mldsa_params p;
+ unsigned char pre[257];
+ unsigned long i;
+ int err;
+
+ LTC_ARGCHK(sig != NULL);
+ LTC_ARGCHK(msg != NULL || msglen == 0);
+ LTC_ARGCHK(stat != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ *stat = 0;
+
+ if (ctxlen > 255) return CRYPT_INVALID_ARG;
+ if (key->pk == NULL) return CRYPT_INVALID_ARG;
+
+ if ((err = s_mldsa_get_params(key->alg, &p)) != CRYPT_OK) return err;
+
+ /* Prepare pre = (0, ctxlen, ctx) */
+ pre[0] = 0;
+ pre[1] = (unsigned char)ctxlen;
+ if (ctxlen > 0 && ctx != NULL) {
+ for (i = 0; i < ctxlen; i++)
+ pre[2 + i] = ctx[i];
+ }
+
+ err = s_verify_internal(sig, siglen, msg, msglen, pre, 2 + ctxlen, key->pk, &p);
+ if (err == CRYPT_OK)
+ *stat = 1;
+ else if (err == CRYPT_INVALID_PACKET)
+ err = CRYPT_OK; /* Verification failed but no internal error */
+
+ return err;
+}
+
+/**
+ Get the sizes for a given ML-DSA parameter set.
+ Any output pointer may be NULL if the caller does not need that value.
+ @param alg The parameter set (LTC_MLDSA_44, LTC_MLDSA_65, or LTC_MLDSA_87)
+ @param public_key_sz [out] Public key size in bytes
+ @param secret_key_sz [out] Secret key size in bytes
+ @param signature_sz [out] Signature size in bytes
+ @return CRYPT_OK if successful
+*/
+int mldsa_get_sizes(int alg, unsigned long *public_key_sz, unsigned long *secret_key_sz,
+ unsigned long *signature_sz)
+{
+ mldsa_params p;
+ int err;
+
+ if ((err = s_mldsa_get_params(alg, &p)) != CRYPT_OK) return err;
+
+ if (public_key_sz != NULL) *public_key_sz = p.pk_bytes;
+ if (secret_key_sz != NULL) *secret_key_sz = p.sk_bytes;
+ if (signature_sz != NULL) *signature_sz = p.sig_bytes;
+
+ return CRYPT_OK;
+}
+
+#endif /* LTC_MLDSA */
diff --git a/src/pqc/mldsa_export.c b/src/pqc/mldsa_export.c
new file mode 100644
index 000000000..d1fc52477
--- /dev/null
+++ b/src/pqc/mldsa_export.c
@@ -0,0 +1,114 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_private.h"
+
+/**
+ @file mldsa_export.c
+ Export a ML-DSA key to a binary packet
+*/
+
+#ifdef LTC_MLDSA
+
+static int s_mldsa_alg_to_oid(int alg, enum ltc_oid_id *oid_id)
+{
+ LTC_ARGCHK(oid_id != NULL);
+
+ switch (alg) {
+ case LTC_MLDSA_44:
+ *oid_id = LTC_OID_MLDSA_44;
+ return CRYPT_OK;
+ case LTC_MLDSA_65:
+ *oid_id = LTC_OID_MLDSA_65;
+ return CRYPT_OK;
+ case LTC_MLDSA_87:
+ *oid_id = LTC_OID_MLDSA_87;
+ return CRYPT_OK;
+ default:
+ return CRYPT_PK_INVALID_TYPE;
+ }
+}
+
+/**
+ Export a ML-DSA key to a binary packet
+ @param out [out] The destination for the key
+ @param outlen [in/out] The max size and resulting size of the ML-DSA key
+ @param which Which type of key (PK_PRIVATE, PK_PUBLIC|PK_STD or PK_PUBLIC)
+ @param key The key you wish to export
+ @return CRYPT_OK if successful
+*/
+int mldsa_export(unsigned char *out, unsigned long *outlen,
+ int which, const mldsa_key *key)
+{
+ int err, std;
+ enum ltc_oid_id oid_id;
+
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ std = which & PK_STD;
+ which &= ~PK_STD;
+
+ if ((err = s_mldsa_alg_to_oid(key->alg, &oid_id)) != CRYPT_OK) {
+ return err;
+ }
+
+ if (which == PK_PRIVATE) {
+ const char *OID;
+ unsigned long version, oid[16], oidlen;
+ unsigned char *private_key;
+ unsigned long private_key_len;
+ ltc_asn1_list alg_id[1];
+
+ if (key->type != PK_PRIVATE || key->sk == NULL) return CRYPT_PK_INVALID_TYPE;
+
+ if (std != PK_STD) {
+ return mldsa_export_raw(out, outlen, which, key);
+ }
+
+ if ((err = pk_get_oid(oid_id, &OID)) != CRYPT_OK) {
+ return err;
+ }
+ oidlen = LTC_ARRAY_SIZE(oid);
+ if ((err = pk_oid_str_to_num(OID, oid, &oidlen)) != CRYPT_OK) {
+ return err;
+ }
+ LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid, oidlen);
+
+ if ((err = der_length_octet_string(key->sklen, &private_key_len)) != CRYPT_OK) {
+ return err;
+ }
+ private_key = XMALLOC(private_key_len);
+ if (private_key == NULL) {
+ return CRYPT_MEM;
+ }
+
+ err = der_encode_octet_string(key->sk, key->sklen, private_key, &private_key_len);
+ if (err == CRYPT_OK) {
+ version = 0;
+ err = der_encode_sequence_multi(out, outlen,
+ LTC_ASN1_SHORT_INTEGER, 1uL, &version,
+ LTC_ASN1_SEQUENCE, 1uL, alg_id,
+ LTC_ASN1_OCTET_STRING, private_key_len, private_key,
+ LTC_ASN1_EOL, 0uL, NULL);
+ }
+
+ XFREE(private_key);
+ return err;
+ }
+
+ if (which != PK_PUBLIC) {
+ return CRYPT_INVALID_ARG;
+ }
+ if (key->pk == NULL) return CRYPT_PK_INVALID_TYPE;
+
+ if (std == PK_STD) {
+ return x509_encode_subject_public_key_info(out, outlen, oid_id,
+ key->pk, key->pklen,
+ LTC_ASN1_EOL, NULL, 0uL);
+ }
+
+ return mldsa_export_raw(out, outlen, which, key);
+}
+
+#endif
diff --git a/src/pqc/mldsa_import.c b/src/pqc/mldsa_import.c
new file mode 100644
index 000000000..739d0c1dc
--- /dev/null
+++ b/src/pqc/mldsa_import.c
@@ -0,0 +1,65 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_private.h"
+
+/**
+ @file mldsa_import.c
+ Import a ML-DSA key from a SubjectPublicKeyInfo
+*/
+
+#ifdef LTC_MLDSA
+
+typedef struct {
+ enum ltc_oid_id oid;
+ int alg;
+} mldsa_oid_map;
+
+static const mldsa_oid_map s_mldsa_oid_map[] = {
+ { LTC_OID_MLDSA_44, LTC_MLDSA_44 },
+ { LTC_OID_MLDSA_65, LTC_MLDSA_65 },
+ { LTC_OID_MLDSA_87, LTC_MLDSA_87 },
+};
+
+/**
+ Import a ML-DSA public key
+ @param in The packet to read
+ @param inlen The length of the input packet
+ @param key [out] Where to import the key to
+ @return CRYPT_OK if successful, on error all allocated memory is freed automatically
+*/
+int mldsa_import(const unsigned char *in, unsigned long inlen, mldsa_key *key)
+{
+ unsigned char *pub;
+ unsigned long pub_len, max_pub_len;
+ unsigned long i;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if ((err = mldsa_get_sizes(LTC_MLDSA_87, &max_pub_len, NULL, NULL)) != CRYPT_OK) {
+ return err;
+ }
+
+ pub = XMALLOC(max_pub_len);
+ if (pub == NULL) {
+ return CRYPT_MEM;
+ }
+
+ err = CRYPT_PK_INVALID_TYPE;
+ for (i = 0; i < LTC_ARRAY_SIZE(s_mldsa_oid_map); ++i) {
+ pub_len = max_pub_len;
+ err = x509_decode_subject_public_key_info(in, inlen, s_mldsa_oid_map[i].oid,
+ pub, &pub_len,
+ LTC_ASN1_EOL, NULL, 0uL);
+ if (err == CRYPT_OK) {
+ err = mldsa_import_raw(pub, pub_len, PK_PUBLIC, s_mldsa_oid_map[i].alg, key);
+ break;
+ }
+ }
+
+ XFREE(pub);
+ return err;
+}
+
+#endif
diff --git a/src/pqc/mldsa_import_pkcs8.c b/src/pqc/mldsa_import_pkcs8.c
new file mode 100644
index 000000000..e60997e04
--- /dev/null
+++ b/src/pqc/mldsa_import_pkcs8.c
@@ -0,0 +1,162 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_private.h"
+
+/**
+ @file mldsa_import_pkcs8.c
+ Import a ML-DSA key in PKCS#8 format
+*/
+
+#ifdef LTC_MLDSA
+
+static int s_mldsa_oid_to_alg(enum ltc_oid_id oid_id, int *alg)
+{
+ LTC_ARGCHK(alg != NULL);
+
+ switch (oid_id) {
+ case LTC_OID_MLDSA_44:
+ *alg = LTC_MLDSA_44;
+ return CRYPT_OK;
+ case LTC_OID_MLDSA_65:
+ *alg = LTC_MLDSA_65;
+ return CRYPT_OK;
+ case LTC_OID_MLDSA_87:
+ *alg = LTC_MLDSA_87;
+ return CRYPT_OK;
+ default:
+ return CRYPT_PK_INVALID_TYPE;
+ }
+}
+
+int mldsa_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key,
+ mldsa_key *key)
+{
+ ltc_asn1_list *decoded = NULL;
+ ltc_asn1_list *seed = NULL, *raw_key = NULL;
+ ltc_asn1_list seed_custom[1];
+ der_flexi_check flexi_should[4];
+ enum ltc_oid_id oid_id;
+ int alg, err;
+ unsigned char *raw_buf = NULL;
+ unsigned char seed_buf[32];
+ unsigned long inlen, raw_buf_len, key_len, n;
+ mldsa_key seed_key;
+
+ LTC_ARGCHK(alg_id != NULL);
+ LTC_ARGCHK(priv_key != NULL);
+ LTC_ARGCHK(key != NULL);
+ XMEMSET(&seed_key, 0, sizeof(seed_key));
+
+ if ((err = pk_get_oid_from_asn1(alg_id->child, &oid_id)) != CRYPT_OK) {
+ return err;
+ }
+ if ((err = s_mldsa_oid_to_alg(oid_id, &alg)) != CRYPT_OK) {
+ return err;
+ }
+
+ if ((err = mldsa_get_sizes(alg, NULL, &key_len, NULL)) != CRYPT_OK) {
+ return err;
+ }
+ if (priv_key->size == key_len) {
+ return mldsa_import_raw(priv_key->data, priv_key->size, PK_PRIVATE, alg, key);
+ }
+
+ raw_buf = XMALLOC(key_len);
+ if (raw_buf == NULL) {
+ return CRYPT_MEM;
+ }
+ raw_buf_len = key_len;
+ err = der_decode_octet_string(priv_key->data, priv_key->size, raw_buf, &raw_buf_len);
+ if (err == CRYPT_OK) {
+ err = (raw_buf_len == key_len)
+ ? mldsa_import_raw(raw_buf, raw_buf_len, PK_PRIVATE, alg, key)
+ : CRYPT_INVALID_PACKET;
+ XFREE(raw_buf);
+ return err;
+ }
+ XFREE(raw_buf);
+
+ LTC_SET_ASN1_CUSTOM_PRIMITIVE(seed_custom, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0,
+ LTC_ASN1_OCTET_STRING, seed_buf, sizeof(seed_buf));
+ err = der_decode_custom_type(priv_key->data, priv_key->size, seed_custom);
+ if (err == CRYPT_OK) {
+ return mldsa_make_key_from_seed(alg, seed_buf, seed_custom[0].size, key);
+ }
+
+ inlen = priv_key->size;
+ err = der_decode_sequence_flexi(priv_key->data, &inlen, &decoded);
+ if (err != CRYPT_OK) {
+ return err;
+ }
+
+ n = 0;
+ LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OCTET_STRING, &seed);
+ LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OCTET_STRING, &raw_key);
+ LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
+ err = der_flexi_sequence_cmp(decoded, flexi_should);
+ if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) {
+ goto cleanup;
+ }
+
+ if (seed == NULL || raw_key == NULL) {
+ err = CRYPT_INVALID_PACKET;
+ goto cleanup;
+ }
+ if ((err = mldsa_make_key_from_seed(alg, seed->data, seed->size, &seed_key)) != CRYPT_OK) {
+ goto cleanup;
+ }
+ if (seed_key.sklen != raw_key->size ||
+ XMEMCMP(seed_key.sk, raw_key->data, raw_key->size) != 0) {
+ err = CRYPT_INVALID_PACKET;
+ goto cleanup;
+ }
+
+ err = mldsa_import_raw(raw_key->data, raw_key->size, PK_PRIVATE, alg, key);
+
+cleanup:
+ mldsa_free(&seed_key);
+ der_free_sequence_flexi(decoded);
+ return err;
+}
+
+/**
+ Import a ML-DSA private key in PKCS#8 format
+ @param in The packet to import from
+ @param inlen It's length (octets)
+ @param pw_ctx The password context when decrypting the private key
+ @param key [out] Destination for newly imported key
+ @return CRYPT_OK if successful, on error all allocated memory is freed automatically
+*/
+int mldsa_import_pkcs8(const unsigned char *in, unsigned long inlen, const password_ctx *pw_ctx, mldsa_key *key)
+{
+ int alg, err;
+ ltc_asn1_list *l = NULL;
+ ltc_asn1_list *alg_id, *priv_key;
+ enum ltc_oid_id oid_id;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ err = pkcs8_decode_flexi(in, inlen, pw_ctx, &l);
+ if (err != CRYPT_OK) {
+ return err;
+ }
+
+ if ((err = pkcs8_get_children(l, &oid_id, &alg_id, &priv_key)) != CRYPT_OK) {
+ goto cleanup;
+ }
+ err = s_mldsa_oid_to_alg(oid_id, &alg);
+ if (err != CRYPT_OK) {
+ err = CRYPT_INVALID_PACKET;
+ goto cleanup;
+ }
+ LTC_UNUSED_PARAM(alg);
+
+ err = mldsa_import_pkcs8_asn1(alg_id, priv_key, key);
+
+cleanup:
+ der_free_sequence_flexi(l);
+ return err;
+}
+
+#endif
diff --git a/src/pqc/mldsa_import_x509.c b/src/pqc/mldsa_import_x509.c
new file mode 100644
index 000000000..7be402c34
--- /dev/null
+++ b/src/pqc/mldsa_import_x509.c
@@ -0,0 +1,65 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_private.h"
+
+/**
+ @file mldsa_import_x509.c
+ Import a ML-DSA key from a X.509 certificate
+*/
+
+#ifdef LTC_MLDSA
+
+typedef struct {
+ mldsa_key *key;
+ int alg;
+} mldsa_x509_ctx;
+
+typedef struct {
+ enum ltc_oid_id oid;
+ int alg;
+} mldsa_oid_map_x509;
+
+static const mldsa_oid_map_x509 s_mldsa_oid_map_x509[] = {
+ { LTC_OID_MLDSA_44, LTC_MLDSA_44 },
+ { LTC_OID_MLDSA_65, LTC_MLDSA_65 },
+ { LTC_OID_MLDSA_87, LTC_MLDSA_87 },
+};
+
+static int s_mldsa_decode(const unsigned char *in, unsigned long inlen, mldsa_x509_ctx *ctx)
+{
+ return mldsa_import_raw(in, inlen, PK_PUBLIC, ctx->alg, ctx->key);
+}
+
+/**
+ Import a ML-DSA public key from a X.509 certificate
+ @param in The DER encoded X.509 certificate
+ @param inlen The length of the certificate
+ @param key [out] Where to import the key to
+ @return CRYPT_OK if successful, on error all allocated memory is freed automatically
+*/
+int mldsa_import_x509(const unsigned char *in, unsigned long inlen, mldsa_key *key)
+{
+ mldsa_x509_ctx ctx;
+ unsigned long i;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ err = CRYPT_PK_INVALID_TYPE;
+ for (i = 0; i < LTC_ARRAY_SIZE(s_mldsa_oid_map_x509); ++i) {
+ ctx.key = key;
+ ctx.alg = s_mldsa_oid_map_x509[i].alg;
+ err = x509_decode_public_key_from_certificate(in, inlen,
+ s_mldsa_oid_map_x509[i].oid,
+ LTC_ASN1_EOL, NULL, NULL,
+ (public_key_decode_cb)s_mldsa_decode, &ctx);
+ if (err == CRYPT_OK) {
+ break;
+ }
+ }
+
+ return err;
+}
+
+#endif
diff --git a/src/pqc/mlkem.c b/src/pqc/mlkem.c
new file mode 100644
index 000000000..3cd6e5689
--- /dev/null
+++ b/src/pqc/mlkem.c
@@ -0,0 +1,1230 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/**
+ @file mlkem.c
+ ML-KEM (FIPS 203) implementation: polynomial arithmetic, IND-CPA scheme,
+ KEM operations, and public API.
+ Based on the CRYSTALS-Kyber reference implementation (public domain).
+*/
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MLKEM
+
+/* Exact 16-bit types for lattice arithmetic.
+ * Assumes short is 16-bit, which holds on all platforms libtomcrypt targets. */
+typedef signed short ishort16;
+typedef unsigned short ushort16;
+
+/* ---- ML-KEM constants ---- */
+#define MLKEM_N 256
+#define MLKEM_Q 3329
+#define MLKEM_SYMBYTES 32
+#define MLKEM_SSBYTES 32
+#define MLKEM_POLYBYTES 384
+#define MLKEM_K_MAX 4
+#define MLKEM_QINV (-3327) /* q^{-1} mod 2^16 */
+#define MLKEM_XOF_BLOCKBYTES 168 /* SHAKE128 rate */
+
+/* ---- Runtime parameter set ---- */
+typedef struct {
+ int k, eta1, eta2, du, dv;
+ unsigned long polyvec_bytes, polyvec_compressed_bytes, poly_compressed_bytes;
+ unsigned long indcpa_pk_bytes, indcpa_sk_bytes, indcpa_ct_bytes;
+ unsigned long pk_bytes, sk_bytes, ct_bytes;
+} mlkem_params;
+
+/* ---- Polynomial types ---- */
+typedef struct {
+ ishort16 coeffs[MLKEM_N];
+} mlkem_poly;
+
+typedef struct {
+ mlkem_poly vec[MLKEM_K_MAX];
+} mlkem_polyvec;
+
+/* Montgomery / Barrett reduction */
+
+static ishort16 s_mlkem_montgomery_reduce(int a)
+{
+ ishort16 t;
+ t = (ishort16)a * MLKEM_QINV;
+ t = (a - (int)t * MLKEM_Q) >> 16;
+ return t;
+}
+
+static ishort16 s_mlkem_barrett_reduce(ishort16 a)
+{
+ ishort16 t;
+ const ishort16 v = ((1 << 26) + MLKEM_Q / 2) / MLKEM_Q;
+ t = ((int)v * a + (1 << 25)) >> 26;
+ t *= MLKEM_Q;
+ return a - t;
+}
+
+static ishort16 s_mlkem_fqmul(ishort16 a, ishort16 b)
+{
+ return s_mlkem_montgomery_reduce((int)a * b);
+}
+
+/* NTT */
+
+static const ishort16 s_mlkem_zetas[128] = {
+ -1044, -758, -359, -1517, 1493, 1422, 287, 202,
+ -171, 622, 1577, 182, 962, -1202, -1474, 1468,
+ 573, -1325, 264, 383, -829, 1458, -1602, -130,
+ -681, 1017, 732, 608, -1542, 411, -205, -1571,
+ 1223, 652, -552, 1015, -1293, 1491, -282, -1544,
+ 516, -8, -320, -666, -1618, -1162, 126, 1469,
+ -853, -90, -271, 830, 107, -1421, -247, -951,
+ -398, 961, -1508, -725, 448, -1065, 677, -1275,
+ -1103, 430, 555, 843, -1251, 871, 1550, 105,
+ 422, 587, 177, -235, -291, -460, 1574, 1653,
+ -246, 778, 1159, -147, -777, 1483, -602, 1119,
+ -1590, 644, -872, 349, 418, 329, -156, -75,
+ 817, 1097, 603, 610, 1322, -1285, -1465, 384,
+ -1215, -136, 1218, -1335, -874, 220, -1187, -1659,
+ -1185, -1530, -1278, 794, -1510, -854, -870, 478,
+ -108, -308, 996, 991, 958, -1460, 1522, 1628
+};
+
+static void s_mlkem_ntt(ishort16 r[256])
+{
+ unsigned int len, start, j, k;
+ ishort16 t, zeta;
+
+ k = 1;
+ for (len = 128; len >= 2; len >>= 1) {
+ for (start = 0; start < 256; start = j + len) {
+ zeta = s_mlkem_zetas[k++];
+ for (j = start; j < start + len; j++) {
+ t = s_mlkem_fqmul(zeta, r[j + len]);
+ r[j + len] = r[j] - t;
+ r[j] = r[j] + t;
+ }
+ }
+ }
+}
+
+static void s_mlkem_invntt(ishort16 r[256])
+{
+ unsigned int start, len, j, k;
+ ishort16 t, zeta;
+ const ishort16 f = 1441; /* mont^2/128 */
+
+ k = 127;
+ for (len = 2; len <= 128; len <<= 1) {
+ for (start = 0; start < 256; start = j + len) {
+ zeta = s_mlkem_zetas[k--];
+ for (j = start; j < start + len; j++) {
+ t = r[j];
+ r[j] = s_mlkem_barrett_reduce(t + r[j + len]);
+ r[j + len] = r[j + len] - t;
+ r[j + len] = s_mlkem_fqmul(zeta, r[j + len]);
+ }
+ }
+ }
+
+ for (j = 0; j < 256; j++)
+ r[j] = s_mlkem_fqmul(r[j], f);
+}
+
+static void s_mlkem_basemul(ishort16 r[2], const ishort16 a[2], const ishort16 b[2], ishort16 zeta)
+{
+ r[0] = s_mlkem_fqmul(a[1], b[1]);
+ r[0] = s_mlkem_fqmul(r[0], zeta);
+ r[0] += s_mlkem_fqmul(a[0], b[0]);
+ r[1] = s_mlkem_fqmul(a[0], b[1]);
+ r[1] += s_mlkem_fqmul(a[1], b[0]);
+}
+
+/* CBD (Centered Binomial Distribution) */
+
+static ulong32 s_mlkem_load32_le(const unsigned char *x)
+{
+ ulong32 r;
+ LOAD32L(r, x);
+ return r;
+}
+
+static ulong32 s_mlkem_load24_le(const unsigned char *x)
+{
+ return ((ulong32)(x[0] & 255))
+ | ((ulong32)(x[1] & 255) << 8)
+ | ((ulong32)(x[2] & 255) << 16);
+}
+
+static void s_mlkem_cbd2(mlkem_poly *r, const unsigned char *buf)
+{
+ unsigned int i, j;
+ ulong32 t, d;
+ ishort16 a, b;
+
+ for (i = 0; i < MLKEM_N / 8; i++) {
+ t = s_mlkem_load32_le(buf + 4 * i);
+ d = t & 0x55555555u;
+ d += (t >> 1) & 0x55555555u;
+
+ for (j = 0; j < 8; j++) {
+ a = (d >> (4 * j + 0)) & 0x3;
+ b = (d >> (4 * j + 2)) & 0x3;
+ r->coeffs[8 * i + j] = a - b;
+ }
+ }
+}
+
+static void s_mlkem_cbd3(mlkem_poly *r, const unsigned char *buf)
+{
+ unsigned int i, j;
+ ulong32 t, d;
+ ishort16 a, b;
+
+ for (i = 0; i < MLKEM_N / 4; i++) {
+ t = s_mlkem_load24_le(buf + 3 * i);
+ d = t & 0x00249249u;
+ d += (t >> 1) & 0x00249249u;
+ d += (t >> 2) & 0x00249249u;
+
+ for (j = 0; j < 4; j++) {
+ a = (d >> (6 * j + 0)) & 0x7;
+ b = (d >> (6 * j + 3)) & 0x7;
+ r->coeffs[4 * i + j] = a - b;
+ }
+ }
+}
+
+static void s_mlkem_poly_cbd_eta(mlkem_poly *r, const unsigned char *buf, int eta)
+{
+ if (eta == 3) {
+ s_mlkem_cbd3(r, buf);
+ } else {
+ s_mlkem_cbd2(r, buf);
+ }
+}
+
+/* Constant-time operations */
+
+static int s_mlkem_ct_verify(const unsigned char *a, const unsigned char *b, unsigned long len)
+{
+ unsigned long i;
+ unsigned char r = 0;
+
+ for (i = 0; i < len; i++)
+ r |= a[i] ^ b[i];
+
+ return (-(ulong64)r) >> 63;
+}
+
+static void s_mlkem_cmov(unsigned char *r, const unsigned char *x, unsigned long len, unsigned char b)
+{
+ unsigned long i;
+
+#if defined(__GNUC__) || defined(__clang__)
+ __asm__("" : "+r"(b) : /* no inputs */);
+#endif
+
+ b = -b;
+ for (i = 0; i < len; i++)
+ r[i] ^= b & (r[i] ^ x[i]);
+}
+
+static void s_mlkem_cmov_int16(ishort16 *r, ishort16 v, ushort16 b)
+{
+ b = -b;
+ *r ^= b & ((*r) ^ v);
+}
+
+/* Parameter lookup */
+
+static int s_mlkem_get_params(int alg, mlkem_params *p)
+{
+ LTC_ARGCHK(p != NULL);
+
+ XMEMSET(p, 0, sizeof(*p));
+
+ switch (alg) {
+ case LTC_MLKEM_512:
+ p->k = 2; p->eta1 = 3; p->eta2 = 2; p->du = 10; p->dv = 4;
+ break;
+ case LTC_MLKEM_768:
+ p->k = 3; p->eta1 = 2; p->eta2 = 2; p->du = 10; p->dv = 4;
+ break;
+ case LTC_MLKEM_1024:
+ p->k = 4; p->eta1 = 2; p->eta2 = 2; p->du = 11; p->dv = 5;
+ break;
+ default:
+ return CRYPT_INVALID_ARG;
+ }
+
+ p->polyvec_bytes = (unsigned long)p->k * MLKEM_POLYBYTES;
+ p->polyvec_compressed_bytes = (unsigned long)p->k * (p->du == 11 ? 352 : 320);
+ p->poly_compressed_bytes = p->dv == 5 ? 160 : 128;
+ p->indcpa_pk_bytes = p->polyvec_bytes + MLKEM_SYMBYTES;
+ p->indcpa_sk_bytes = p->polyvec_bytes;
+ p->indcpa_ct_bytes = p->polyvec_compressed_bytes + p->poly_compressed_bytes;
+ p->pk_bytes = p->indcpa_pk_bytes;
+ p->sk_bytes = p->indcpa_sk_bytes + p->indcpa_pk_bytes + 2 * MLKEM_SYMBYTES;
+ p->ct_bytes = p->indcpa_ct_bytes;
+
+ return CRYPT_OK;
+}
+
+/* Symmetric primitives using libtomcrypt SHA3 */
+
+static int s_mlkem_hash_h(unsigned char out[32], const unsigned char *in, unsigned long inlen)
+{
+ int idx;
+ unsigned long outlen = 32;
+ idx = find_hash("sha3-256");
+ if (idx == -1) return CRYPT_INVALID_HASH;
+ return hash_memory(idx, in, inlen, out, &outlen);
+}
+
+static int s_mlkem_hash_g(unsigned char out[64], const unsigned char *in, unsigned long inlen)
+{
+ int idx;
+ unsigned long outlen = 64;
+ idx = find_hash("sha3-512");
+ if (idx == -1) return CRYPT_INVALID_HASH;
+ return hash_memory(idx, in, inlen, out, &outlen);
+}
+
+static int s_mlkem_xof_absorb(hash_state *state, const unsigned char seed[MLKEM_SYMBYTES],
+ unsigned char x, unsigned char y)
+{
+ int err;
+ unsigned char extseed[MLKEM_SYMBYTES + 2];
+
+ XMEMCPY(extseed, seed, MLKEM_SYMBYTES);
+ extseed[MLKEM_SYMBYTES + 0] = x;
+ extseed[MLKEM_SYMBYTES + 1] = y;
+
+ if ((err = sha3_shake_init(state, 128)) != CRYPT_OK) return err;
+ return sha3_shake_process(state, extseed, sizeof(extseed));
+}
+
+static int s_mlkem_xof_squeeze(hash_state *state, unsigned char *out, unsigned long outlen)
+{
+ return sha3_shake_done(state, out, outlen);
+}
+
+static int s_mlkem_prf(unsigned char *out, unsigned long outlen,
+ const unsigned char key[MLKEM_SYMBYTES], unsigned char nonce)
+{
+ int err;
+ hash_state md;
+ unsigned char extkey[MLKEM_SYMBYTES + 1];
+
+ XMEMCPY(extkey, key, MLKEM_SYMBYTES);
+ extkey[MLKEM_SYMBYTES] = nonce;
+
+ if ((err = sha3_shake_init(&md, 256)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, extkey, sizeof(extkey))) != CRYPT_OK) return err;
+ return sha3_shake_done(&md, out, outlen);
+}
+
+static int s_mlkem_rkprf(unsigned char out[MLKEM_SSBYTES],
+ const unsigned char key[MLKEM_SYMBYTES],
+ const unsigned char *ct, unsigned long ctlen)
+{
+ int err;
+ hash_state md;
+
+ if ((err = sha3_shake_init(&md, 256)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, key, MLKEM_SYMBYTES)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, ct, ctlen)) != CRYPT_OK) return err;
+ return sha3_shake_done(&md, out, MLKEM_SSBYTES);
+}
+
+/* Polynomial operations */
+
+static void s_mlkem_poly_compress(unsigned char *r, const mlkem_poly *a, int dv)
+{
+ unsigned int i, j;
+ ishort16 u;
+ ulong32 d0;
+ unsigned char t[8];
+
+ if (dv == 4) {
+ for (i = 0; i < MLKEM_N / 8; i++) {
+ for (j = 0; j < 8; j++) {
+ u = a->coeffs[8 * i + j];
+ u += (u >> 15) & MLKEM_Q;
+ d0 = u << 4;
+ d0 += 1665;
+ d0 *= 80635;
+ d0 >>= 28;
+ t[j] = d0 & 0xf;
+ }
+ r[0] = t[0] | (t[1] << 4);
+ r[1] = t[2] | (t[3] << 4);
+ r[2] = t[4] | (t[5] << 4);
+ r[3] = t[6] | (t[7] << 4);
+ r += 4;
+ }
+ } else { /* dv == 5 */
+ for (i = 0; i < MLKEM_N / 8; i++) {
+ for (j = 0; j < 8; j++) {
+ u = a->coeffs[8 * i + j];
+ u += (u >> 15) & MLKEM_Q;
+ d0 = u << 5;
+ d0 += 1664;
+ d0 *= 40318;
+ d0 >>= 27;
+ t[j] = d0 & 0x1f;
+ }
+ r[0] = (t[0] >> 0) | (t[1] << 5);
+ r[1] = (t[1] >> 3) | (t[2] << 2) | (t[3] << 7);
+ r[2] = (t[3] >> 1) | (t[4] << 4);
+ r[3] = (t[4] >> 4) | (t[5] << 1) | (t[6] << 6);
+ r[4] = (t[6] >> 2) | (t[7] << 3);
+ r += 5;
+ }
+ }
+}
+
+static void s_mlkem_poly_decompress(mlkem_poly *r, const unsigned char *a, int dv)
+{
+ unsigned int i;
+
+ if (dv == 4) {
+ for (i = 0; i < MLKEM_N / 2; i++) {
+ r->coeffs[2 * i + 0] = (((ushort16)(a[0] & 15) * MLKEM_Q) + 8) >> 4;
+ r->coeffs[2 * i + 1] = (((ushort16)(a[0] >> 4) * MLKEM_Q) + 8) >> 4;
+ a += 1;
+ }
+ } else { /* dv == 5 */
+ unsigned int j;
+ unsigned char t[8];
+ for (i = 0; i < MLKEM_N / 8; i++) {
+ t[0] = (a[0] >> 0);
+ t[1] = (a[0] >> 5) | (a[1] << 3);
+ t[2] = (a[1] >> 2);
+ t[3] = (a[1] >> 7) | (a[2] << 1);
+ t[4] = (a[2] >> 4) | (a[3] << 4);
+ t[5] = (a[3] >> 1);
+ t[6] = (a[3] >> 6) | (a[4] << 2);
+ t[7] = (a[4] >> 3);
+ a += 5;
+
+ for (j = 0; j < 8; j++)
+ r->coeffs[8 * i + j] = ((ulong32)(t[j] & 31) * MLKEM_Q + 16) >> 5;
+ }
+ }
+}
+
+static void s_mlkem_poly_tobytes(unsigned char *r, const mlkem_poly *a)
+{
+ unsigned int i;
+ ushort16 t0, t1;
+
+ for (i = 0; i < MLKEM_N / 2; i++) {
+ t0 = a->coeffs[2 * i];
+ t0 += ((ishort16)t0 >> 15) & MLKEM_Q;
+ t1 = a->coeffs[2 * i + 1];
+ t1 += ((ishort16)t1 >> 15) & MLKEM_Q;
+ r[3 * i + 0] = (t0 >> 0);
+ r[3 * i + 1] = (t0 >> 8) | (t1 << 4);
+ r[3 * i + 2] = (t1 >> 4);
+ }
+}
+
+static void s_mlkem_poly_frombytes(mlkem_poly *r, const unsigned char *a)
+{
+ unsigned int i;
+ for (i = 0; i < MLKEM_N / 2; i++) {
+ r->coeffs[2 * i] = ((a[3 * i + 0] >> 0) | ((ushort16)a[3 * i + 1] << 8)) & 0xFFF;
+ r->coeffs[2 * i + 1] = ((a[3 * i + 1] >> 4) | ((ushort16)a[3 * i + 2] << 4)) & 0xFFF;
+ }
+}
+
+static void s_mlkem_poly_frommsg(mlkem_poly *r, const unsigned char msg[MLKEM_SYMBYTES])
+{
+ unsigned int i, j;
+
+ for (i = 0; i < MLKEM_N / 8; i++) {
+ for (j = 0; j < 8; j++) {
+ r->coeffs[8 * i + j] = 0;
+ s_mlkem_cmov_int16(r->coeffs + 8 * i + j, (MLKEM_Q + 1) / 2, (msg[i] >> j) & 1);
+ }
+ }
+}
+
+static void s_mlkem_poly_tomsg(unsigned char msg[MLKEM_SYMBYTES], const mlkem_poly *a)
+{
+ unsigned int i, j;
+ ulong32 t;
+
+ for (i = 0; i < MLKEM_N / 8; i++) {
+ msg[i] = 0;
+ for (j = 0; j < 8; j++) {
+ t = a->coeffs[8 * i + j];
+ t <<= 1;
+ t += 1665;
+ t *= 80635;
+ t >>= 28;
+ t &= 1;
+ msg[i] |= t << j;
+ }
+ }
+}
+
+static void s_mlkem_poly_reduce(mlkem_poly *r)
+{
+ unsigned int i;
+ for (i = 0; i < MLKEM_N; i++)
+ r->coeffs[i] = s_mlkem_barrett_reduce(r->coeffs[i]);
+}
+
+static void s_mlkem_poly_getnoise(mlkem_poly *r, const unsigned char seed[MLKEM_SYMBYTES],
+ unsigned char nonce, int eta)
+{
+ unsigned char buf[3 * MLKEM_N / 4] = {0}; /* max for eta=3 */
+ unsigned long buflen = (unsigned long)eta * MLKEM_N / 4;
+ s_mlkem_prf(buf, buflen, seed, nonce);
+ s_mlkem_poly_cbd_eta(r, buf, eta);
+}
+
+static void s_mlkem_poly_ntt(mlkem_poly *r)
+{
+ s_mlkem_ntt(r->coeffs);
+ s_mlkem_poly_reduce(r);
+}
+
+static void s_mlkem_poly_invntt_tomont(mlkem_poly *r)
+{
+ s_mlkem_invntt(r->coeffs);
+}
+
+static void s_mlkem_poly_basemul_montgomery(mlkem_poly *r, const mlkem_poly *a, const mlkem_poly *b)
+{
+ unsigned int i;
+ for (i = 0; i < MLKEM_N / 4; i++) {
+ s_mlkem_basemul(&r->coeffs[4 * i], &a->coeffs[4 * i],
+ &b->coeffs[4 * i], s_mlkem_zetas[64 + i]);
+ s_mlkem_basemul(&r->coeffs[4 * i + 2], &a->coeffs[4 * i + 2],
+ &b->coeffs[4 * i + 2], -s_mlkem_zetas[64 + i]);
+ }
+}
+
+static void s_mlkem_poly_tomont(mlkem_poly *r)
+{
+ unsigned int i;
+ const ishort16 f = (1ULL << 32) % MLKEM_Q;
+ for (i = 0; i < MLKEM_N; i++)
+ r->coeffs[i] = s_mlkem_montgomery_reduce((int)r->coeffs[i] * f);
+}
+
+static void s_mlkem_poly_add(mlkem_poly *r, const mlkem_poly *a, const mlkem_poly *b)
+{
+ unsigned int i;
+ for (i = 0; i < MLKEM_N; i++)
+ r->coeffs[i] = a->coeffs[i] + b->coeffs[i];
+}
+
+static void s_mlkem_poly_sub(mlkem_poly *r, const mlkem_poly *a, const mlkem_poly *b)
+{
+ unsigned int i;
+ for (i = 0; i < MLKEM_N; i++)
+ r->coeffs[i] = a->coeffs[i] - b->coeffs[i];
+}
+
+/* Polynomial vector operations */
+
+static void s_mlkem_polyvec_compress(unsigned char *r, const mlkem_polyvec *a, const mlkem_params *p)
+{
+ unsigned int i, j, k;
+ ulong64 d0;
+
+ if (p->du == 11) {
+ ushort16 t[8];
+ for (i = 0; i < (unsigned)p->k; i++) {
+ for (j = 0; j < MLKEM_N / 8; j++) {
+ for (k = 0; k < 8; k++) {
+ t[k] = a->vec[i].coeffs[8 * j + k];
+ t[k] += ((ishort16)t[k] >> 15) & MLKEM_Q;
+ d0 = t[k];
+ d0 <<= 11;
+ d0 += 1664;
+ d0 *= 645084;
+ d0 >>= 31;
+ t[k] = d0 & 0x7ff;
+ }
+ r[ 0] = (t[0] >> 0);
+ r[ 1] = (t[0] >> 8) | (t[1] << 3);
+ r[ 2] = (t[1] >> 5) | (t[2] << 6);
+ r[ 3] = (t[2] >> 2);
+ r[ 4] = (t[2] >> 10) | (t[3] << 1);
+ r[ 5] = (t[3] >> 7) | (t[4] << 4);
+ r[ 6] = (t[4] >> 4) | (t[5] << 7);
+ r[ 7] = (t[5] >> 1);
+ r[ 8] = (t[5] >> 9) | (t[6] << 2);
+ r[ 9] = (t[6] >> 6) | (t[7] << 5);
+ r[10] = (t[7] >> 3);
+ r += 11;
+ }
+ }
+ } else { /* du == 10 */
+ ushort16 t[4];
+ for (i = 0; i < (unsigned)p->k; i++) {
+ for (j = 0; j < MLKEM_N / 4; j++) {
+ for (k = 0; k < 4; k++) {
+ t[k] = a->vec[i].coeffs[4 * j + k];
+ t[k] += ((ishort16)t[k] >> 15) & MLKEM_Q;
+ d0 = t[k];
+ d0 <<= 10;
+ d0 += 1665;
+ d0 *= 1290167;
+ d0 >>= 32;
+ t[k] = d0 & 0x3ff;
+ }
+ r[0] = (t[0] >> 0);
+ r[1] = (t[0] >> 8) | (t[1] << 2);
+ r[2] = (t[1] >> 6) | (t[2] << 4);
+ r[3] = (t[2] >> 4) | (t[3] << 6);
+ r[4] = (t[3] >> 2);
+ r += 5;
+ }
+ }
+ }
+}
+
+static void s_mlkem_polyvec_decompress(mlkem_polyvec *r, const unsigned char *a, const mlkem_params *p)
+{
+ unsigned int i, j, k;
+
+ if (p->du == 11) {
+ ushort16 t[8];
+ for (i = 0; i < (unsigned)p->k; i++) {
+ for (j = 0; j < MLKEM_N / 8; j++) {
+ t[0] = (a[0] >> 0) | ((ushort16)a[ 1] << 8);
+ t[1] = (a[1] >> 3) | ((ushort16)a[ 2] << 5);
+ t[2] = (a[2] >> 6) | ((ushort16)a[ 3] << 2) | ((ushort16)a[4] << 10);
+ t[3] = (a[4] >> 1) | ((ushort16)a[ 5] << 7);
+ t[4] = (a[5] >> 4) | ((ushort16)a[ 6] << 4);
+ t[5] = (a[6] >> 7) | ((ushort16)a[ 7] << 1) | ((ushort16)a[8] << 9);
+ t[6] = (a[8] >> 2) | ((ushort16)a[ 9] << 6);
+ t[7] = (a[9] >> 5) | ((ushort16)a[10] << 3);
+ a += 11;
+
+ for (k = 0; k < 8; k++)
+ r->vec[i].coeffs[8 * j + k] = ((ulong32)(t[k] & 0x7FF) * MLKEM_Q + 1024) >> 11;
+ }
+ }
+ } else { /* du == 10 */
+ ushort16 t[4];
+ for (i = 0; i < (unsigned)p->k; i++) {
+ for (j = 0; j < MLKEM_N / 4; j++) {
+ t[0] = (a[0] >> 0) | ((ushort16)a[1] << 8);
+ t[1] = (a[1] >> 2) | ((ushort16)a[2] << 6);
+ t[2] = (a[2] >> 4) | ((ushort16)a[3] << 4);
+ t[3] = (a[3] >> 6) | ((ushort16)a[4] << 2);
+ a += 5;
+
+ for (k = 0; k < 4; k++)
+ r->vec[i].coeffs[4 * j + k] = ((ulong32)(t[k] & 0x3FF) * MLKEM_Q + 512) >> 10;
+ }
+ }
+ }
+}
+
+static void s_mlkem_polyvec_tobytes(unsigned char *r, const mlkem_polyvec *a, int k)
+{
+ int i;
+ for (i = 0; i < k; i++)
+ s_mlkem_poly_tobytes(r + i * MLKEM_POLYBYTES, &a->vec[i]);
+}
+
+static void s_mlkem_polyvec_frombytes(mlkem_polyvec *r, const unsigned char *a, int k)
+{
+ int i;
+ for (i = 0; i < k; i++)
+ s_mlkem_poly_frombytes(&r->vec[i], a + i * MLKEM_POLYBYTES);
+}
+
+static void s_mlkem_polyvec_ntt(mlkem_polyvec *r, int k)
+{
+ int i;
+ for (i = 0; i < k; i++)
+ s_mlkem_poly_ntt(&r->vec[i]);
+}
+
+static void s_mlkem_polyvec_invntt_tomont(mlkem_polyvec *r, int k)
+{
+ int i;
+ for (i = 0; i < k; i++)
+ s_mlkem_poly_invntt_tomont(&r->vec[i]);
+}
+
+static void s_mlkem_polyvec_basemul_acc_montgomery(mlkem_poly *r, const mlkem_polyvec *a,
+ const mlkem_polyvec *b, int k)
+{
+ int i;
+ mlkem_poly t;
+
+ s_mlkem_poly_basemul_montgomery(r, &a->vec[0], &b->vec[0]);
+ for (i = 1; i < k; i++) {
+ s_mlkem_poly_basemul_montgomery(&t, &a->vec[i], &b->vec[i]);
+ s_mlkem_poly_add(r, r, &t);
+ }
+
+ s_mlkem_poly_reduce(r);
+}
+
+static void s_mlkem_polyvec_reduce(mlkem_polyvec *r, int k)
+{
+ int i;
+ for (i = 0; i < k; i++)
+ s_mlkem_poly_reduce(&r->vec[i]);
+}
+
+static void s_mlkem_polyvec_add(mlkem_polyvec *r, const mlkem_polyvec *a,
+ const mlkem_polyvec *b, int k)
+{
+ int i;
+ for (i = 0; i < k; i++)
+ s_mlkem_poly_add(&r->vec[i], &a->vec[i], &b->vec[i]);
+}
+
+/* IND-CPA: rejection sampling and matrix generation */
+
+static unsigned int s_mlkem_rej_uniform(ishort16 *r, unsigned int len,
+ const unsigned char *buf, unsigned int buflen)
+{
+ unsigned int ctr, pos;
+ ushort16 val0, val1;
+
+ ctr = pos = 0;
+ while (ctr < len && pos + 3 <= buflen) {
+ val0 = ((buf[pos + 0] >> 0) | ((ushort16)buf[pos + 1] << 8)) & 0xFFF;
+ val1 = ((buf[pos + 1] >> 4) | ((ushort16)buf[pos + 2] << 4)) & 0xFFF;
+ pos += 3;
+
+ if (val0 < MLKEM_Q)
+ r[ctr++] = val0;
+ if (ctr < len && val1 < MLKEM_Q)
+ r[ctr++] = val1;
+ }
+
+ return ctr;
+}
+
+#define GEN_MATRIX_NBLOCKS ((12*MLKEM_N/8*(1 << 12)/MLKEM_Q + MLKEM_XOF_BLOCKBYTES)/MLKEM_XOF_BLOCKBYTES)
+
+static int s_mlkem_gen_matrix(mlkem_polyvec *a, const unsigned char seed[MLKEM_SYMBYTES],
+ int transposed, int k)
+{
+ unsigned int ctr, i, j, buflen;
+ unsigned char buf[GEN_MATRIX_NBLOCKS * MLKEM_XOF_BLOCKBYTES + MLKEM_XOF_BLOCKBYTES];
+ hash_state state;
+ int err;
+
+ for (i = 0; i < (unsigned)k; i++) {
+ for (j = 0; j < (unsigned)k; j++) {
+ if (transposed)
+ err = s_mlkem_xof_absorb(&state, seed, (unsigned char)i, (unsigned char)j);
+ else
+ err = s_mlkem_xof_absorb(&state, seed, (unsigned char)j, (unsigned char)i);
+ if (err != CRYPT_OK) return err;
+
+ buflen = GEN_MATRIX_NBLOCKS * MLKEM_XOF_BLOCKBYTES;
+ if ((err = s_mlkem_xof_squeeze(&state, buf, buflen)) != CRYPT_OK) return err;
+ ctr = s_mlkem_rej_uniform(a[i].vec[j].coeffs, MLKEM_N, buf, buflen);
+
+ while (ctr < MLKEM_N) {
+ if ((err = s_mlkem_xof_squeeze(&state, buf, MLKEM_XOF_BLOCKBYTES)) != CRYPT_OK) return err;
+ ctr += s_mlkem_rej_uniform(a[i].vec[j].coeffs + ctr, MLKEM_N - ctr,
+ buf, MLKEM_XOF_BLOCKBYTES);
+ }
+ }
+ }
+
+ return CRYPT_OK;
+}
+
+/* IND-CPA scheme */
+
+static int s_mlkem_indcpa_keypair(unsigned char *pk, unsigned char *sk,
+ const unsigned char coins[MLKEM_SYMBYTES],
+ const mlkem_params *p)
+{
+ unsigned int i;
+ unsigned char buf[2 * MLKEM_SYMBYTES];
+ const unsigned char *publicseed = buf;
+ const unsigned char *noiseseed = buf + MLKEM_SYMBYTES;
+ unsigned char nonce = 0;
+ mlkem_polyvec a[MLKEM_K_MAX], e, pkpv, skpv;
+ int err;
+
+ XMEMCPY(buf, coins, MLKEM_SYMBYTES);
+ buf[MLKEM_SYMBYTES] = (unsigned char)p->k;
+ if ((err = s_mlkem_hash_g(buf, buf, MLKEM_SYMBYTES + 1)) != CRYPT_OK) return err;
+
+ if ((err = s_mlkem_gen_matrix(a, publicseed, 0, p->k)) != CRYPT_OK) return err;
+
+ for (i = 0; i < (unsigned)p->k; i++)
+ s_mlkem_poly_getnoise(&skpv.vec[i], noiseseed, nonce++, p->eta1);
+ for (i = 0; i < (unsigned)p->k; i++)
+ s_mlkem_poly_getnoise(&e.vec[i], noiseseed, nonce++, p->eta1);
+
+ s_mlkem_polyvec_ntt(&skpv, p->k);
+ s_mlkem_polyvec_ntt(&e, p->k);
+
+ for (i = 0; i < (unsigned)p->k; i++) {
+ s_mlkem_polyvec_basemul_acc_montgomery(&pkpv.vec[i], &a[i], &skpv, p->k);
+ s_mlkem_poly_tomont(&pkpv.vec[i]);
+ }
+
+ s_mlkem_polyvec_add(&pkpv, &pkpv, &e, p->k);
+ s_mlkem_polyvec_reduce(&pkpv, p->k);
+
+ s_mlkem_polyvec_tobytes(sk, &skpv, p->k);
+ s_mlkem_polyvec_tobytes(pk, &pkpv, p->k);
+ XMEMCPY(pk + p->polyvec_bytes, publicseed, MLKEM_SYMBYTES);
+
+ return CRYPT_OK;
+}
+
+static int s_mlkem_indcpa_enc(unsigned char *c,
+ const unsigned char m[MLKEM_SYMBYTES],
+ const unsigned char *pk,
+ const unsigned char coins[MLKEM_SYMBYTES],
+ const mlkem_params *p)
+{
+ unsigned int i;
+ unsigned char seed[MLKEM_SYMBYTES];
+ unsigned char nonce = 0;
+ mlkem_polyvec sp, pkpv, ep, at[MLKEM_K_MAX], b;
+ mlkem_poly v, k, epp;
+ int err;
+
+ s_mlkem_polyvec_frombytes(&pkpv, pk, p->k);
+ XMEMCPY(seed, pk + p->polyvec_bytes, MLKEM_SYMBYTES);
+ s_mlkem_poly_frommsg(&k, m);
+ if ((err = s_mlkem_gen_matrix(at, seed, 1, p->k)) != CRYPT_OK) return err;
+
+ for (i = 0; i < (unsigned)p->k; i++)
+ s_mlkem_poly_getnoise(&sp.vec[i], coins, nonce++, p->eta1);
+ for (i = 0; i < (unsigned)p->k; i++)
+ s_mlkem_poly_getnoise(&ep.vec[i], coins, nonce++, p->eta2);
+ s_mlkem_poly_getnoise(&epp, coins, nonce++, p->eta2);
+
+ s_mlkem_polyvec_ntt(&sp, p->k);
+
+ for (i = 0; i < (unsigned)p->k; i++)
+ s_mlkem_polyvec_basemul_acc_montgomery(&b.vec[i], &at[i], &sp, p->k);
+
+ s_mlkem_polyvec_basemul_acc_montgomery(&v, &pkpv, &sp, p->k);
+
+ s_mlkem_polyvec_invntt_tomont(&b, p->k);
+ s_mlkem_poly_invntt_tomont(&v);
+
+ s_mlkem_polyvec_add(&b, &b, &ep, p->k);
+ s_mlkem_poly_add(&v, &v, &epp);
+ s_mlkem_poly_add(&v, &v, &k);
+ s_mlkem_polyvec_reduce(&b, p->k);
+ s_mlkem_poly_reduce(&v);
+
+ s_mlkem_polyvec_compress(c, &b, p);
+ s_mlkem_poly_compress(c + p->polyvec_compressed_bytes, &v, p->dv);
+
+ return CRYPT_OK;
+}
+
+static void s_mlkem_indcpa_dec(unsigned char m[MLKEM_SYMBYTES],
+ const unsigned char *c,
+ const unsigned char *sk,
+ const mlkem_params *p)
+{
+ mlkem_polyvec b, skpv;
+ mlkem_poly v, mp;
+
+ s_mlkem_polyvec_decompress(&b, c, p);
+ s_mlkem_poly_decompress(&v, c + p->polyvec_compressed_bytes, p->dv);
+ s_mlkem_polyvec_frombytes(&skpv, sk, p->k);
+
+ s_mlkem_polyvec_ntt(&b, p->k);
+ s_mlkem_polyvec_basemul_acc_montgomery(&mp, &skpv, &b, p->k);
+ s_mlkem_poly_invntt_tomont(&mp);
+
+ s_mlkem_poly_sub(&mp, &v, &mp);
+ s_mlkem_poly_reduce(&mp);
+
+ s_mlkem_poly_tomsg(m, &mp);
+}
+
+/* KEM operations */
+
+static int s_mlkem_kem_keypair(unsigned char *pk, unsigned char *sk,
+ const unsigned char coins[2 * MLKEM_SYMBYTES],
+ const mlkem_params *p)
+{
+ int err;
+
+ if ((err = s_mlkem_indcpa_keypair(pk, sk, coins, p)) != CRYPT_OK) return err;
+ XMEMCPY(sk + p->indcpa_sk_bytes, pk, p->pk_bytes);
+ if ((err = s_mlkem_hash_h(sk + p->sk_bytes - 2 * MLKEM_SYMBYTES, pk, p->pk_bytes)) != CRYPT_OK)
+ return err;
+ /* Value z for pseudo-random output on reject */
+ XMEMCPY(sk + p->sk_bytes - MLKEM_SYMBYTES, coins + MLKEM_SYMBYTES, MLKEM_SYMBYTES);
+
+ return CRYPT_OK;
+}
+
+static int s_mlkem_validate_private_key(const unsigned char *sk,
+ const mlkem_params *p)
+{
+ unsigned char h[MLKEM_SYMBYTES];
+ int err;
+
+ if ((err = s_mlkem_hash_h(h, sk + p->indcpa_sk_bytes, p->pk_bytes)) != CRYPT_OK) {
+ return err;
+ }
+
+ return XMEMCMP(h, sk + p->sk_bytes - 2 * MLKEM_SYMBYTES, MLKEM_SYMBYTES) == 0
+ ? CRYPT_OK
+ : CRYPT_INVALID_PACKET;
+}
+
+static int s_mlkem_kem_enc(unsigned char *ct, unsigned char *ss,
+ const unsigned char *pk,
+ const unsigned char coins[MLKEM_SYMBYTES],
+ const mlkem_params *p)
+{
+ unsigned char buf[2 * MLKEM_SYMBYTES];
+ unsigned char kr[2 * MLKEM_SYMBYTES];
+ int err;
+
+ XMEMCPY(buf, coins, MLKEM_SYMBYTES);
+
+ /* Multitarget countermeasure for coins + contributory KEM */
+ if ((err = s_mlkem_hash_h(buf + MLKEM_SYMBYTES, pk, p->pk_bytes)) != CRYPT_OK) return err;
+ if ((err = s_mlkem_hash_g(kr, buf, 2 * MLKEM_SYMBYTES)) != CRYPT_OK) return err;
+
+ /* coins are in kr+MLKEM_SYMBYTES */
+ if ((err = s_mlkem_indcpa_enc(ct, buf, pk, kr + MLKEM_SYMBYTES, p)) != CRYPT_OK) return err;
+
+ XMEMCPY(ss, kr, MLKEM_SYMBYTES);
+ return CRYPT_OK;
+}
+
+static int s_mlkem_kem_dec(unsigned char *ss,
+ const unsigned char *ct,
+ const unsigned char *sk,
+ const mlkem_params *p)
+{
+ int fail, err;
+ unsigned char buf[2 * MLKEM_SYMBYTES];
+ unsigned char kr[2 * MLKEM_SYMBYTES];
+ unsigned char cmp[MLKEM_K_MAX * 352 + 160]; /* max ct size */
+ const unsigned char *pk = sk + p->indcpa_sk_bytes;
+
+ s_mlkem_indcpa_dec(buf, ct, sk, p);
+
+ /* Multitarget countermeasure for coins + contributory KEM */
+ XMEMCPY(buf + MLKEM_SYMBYTES, sk + p->sk_bytes - 2 * MLKEM_SYMBYTES, MLKEM_SYMBYTES);
+ if ((err = s_mlkem_hash_g(kr, buf, 2 * MLKEM_SYMBYTES)) != CRYPT_OK) return err;
+
+ /* coins are in kr+MLKEM_SYMBYTES */
+ if ((err = s_mlkem_indcpa_enc(cmp, buf, pk, kr + MLKEM_SYMBYTES, p)) != CRYPT_OK) return err;
+
+ fail = s_mlkem_ct_verify(ct, cmp, p->ct_bytes);
+
+ /* Compute rejection key */
+ if ((err = s_mlkem_rkprf(ss, sk + p->sk_bytes - MLKEM_SYMBYTES, ct, p->ct_bytes)) != CRYPT_OK)
+ return err;
+
+ /* Copy true key to return buffer if fail is false */
+ s_mlkem_cmov(ss, kr, MLKEM_SYMBYTES, (unsigned char)!fail);
+
+ return CRYPT_OK;
+}
+
+/* Public API */
+
+/**
+ Generate an ML-KEM key pair.
+ @param prng An active PRNG state
+ @param wprng The index of the desired PRNG
+ @param alg The parameter set (LTC_MLKEM_512, LTC_MLKEM_768, or LTC_MLKEM_1024)
+ @param key [out] Destination for the newly created key pair
+ @return CRYPT_OK if successful
+*/
+int mlkem_make_key(prng_state *prng, int wprng, int alg, mlkem_key *key)
+{
+ unsigned char coins[2 * MLKEM_SYMBYTES];
+ int err;
+
+ LTC_ARGCHK(key != NULL);
+
+ if ((err = prng_is_valid(wprng)) != CRYPT_OK) return err;
+ if (prng_descriptor[wprng].read(coins, sizeof(coins), prng) != sizeof(coins))
+ return CRYPT_ERROR_READPRNG;
+
+ err = mlkem_make_key_from_seed(alg, coins, sizeof(coins), key);
+ zeromem(coins, sizeof(coins));
+ return err;
+}
+
+/**
+ Generate an ML-KEM key pair deterministically from a seed.
+ @param alg The parameter set (LTC_MLKEM_512, LTC_MLKEM_768, or LTC_MLKEM_1024)
+ @param seed The input seed (exactly 64 bytes)
+ @param seedlen Length of the seed in bytes
+ @param key [out] Destination for the newly created key pair
+ @return CRYPT_OK if successful
+*/
+int mlkem_make_key_from_seed(int alg, const unsigned char *seed, unsigned long seedlen, mlkem_key *key)
+{
+ mlkem_params p;
+ int err;
+
+ LTC_ARGCHK(seed != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if (seedlen != 2uL * MLKEM_SYMBYTES) {
+ return CRYPT_INVALID_ARG;
+ }
+ if ((err = s_mlkem_get_params(alg, &p)) != CRYPT_OK) {
+ return err;
+ }
+
+ XMEMSET(key, 0, sizeof(*key));
+ key->pk = XMALLOC(p.pk_bytes);
+ key->sk = XMALLOC(p.sk_bytes);
+ if (key->pk == NULL || key->sk == NULL) {
+ mlkem_free(key);
+ return CRYPT_MEM;
+ }
+
+ if ((err = s_mlkem_kem_keypair(key->pk, key->sk, seed, &p)) != CRYPT_OK) {
+ zeromem(key->sk, p.sk_bytes);
+ mlkem_free(key);
+ return err;
+ }
+
+ key->alg = alg;
+ key->type = PK_PRIVATE;
+ key->pklen = p.pk_bytes;
+ key->sklen = p.sk_bytes;
+ err = s_mlkem_validate_private_key(key->sk, &p);
+ if (err != CRYPT_OK) {
+ mlkem_free(key);
+ }
+ return err;
+}
+
+/**
+ Free an ML-KEM key from memory.
+ @param key The key to free
+*/
+void mlkem_free(mlkem_key *key)
+{
+ if (key == NULL) return;
+ if (key->sk != NULL) {
+ zeromem(key->sk, key->sklen);
+ XFREE(key->sk);
+ }
+ if (key->pk != NULL) {
+ XFREE(key->pk);
+ }
+ XMEMSET(key, 0, sizeof(*key));
+}
+
+/**
+ Export an ML-KEM key to a byte buffer.
+ @param out [out] Destination for the exported key
+ @param outlen [in/out] Max size and resulting size of the exported key
+ @param which PK_PUBLIC for the encapsulation key, PK_PRIVATE for the decapsulation key
+ @param key The key to export
+ @return CRYPT_OK if successful
+*/
+int mlkem_export_raw(unsigned char *out, unsigned long *outlen, int which, const mlkem_key *key)
+{
+ mlkem_params p;
+ unsigned long needed;
+ int err;
+
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if ((err = s_mlkem_get_params(key->alg, &p)) != CRYPT_OK) return err;
+
+ if (which == PK_PUBLIC) {
+ needed = p.pk_bytes;
+ if (*outlen < needed) { *outlen = needed; return CRYPT_BUFFER_OVERFLOW; }
+ if (key->pk == NULL) return CRYPT_PK_NOT_PRIVATE;
+ XMEMCPY(out, key->pk, needed);
+ } else if (which == PK_PRIVATE) {
+ if (key->type != PK_PRIVATE) return CRYPT_PK_NOT_PRIVATE;
+ needed = p.sk_bytes;
+ if (*outlen < needed) { *outlen = needed; return CRYPT_BUFFER_OVERFLOW; }
+ XMEMCPY(out, key->sk, needed);
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ *outlen = needed;
+ return CRYPT_OK;
+}
+
+/**
+ Import an ML-KEM key from a byte buffer.
+ @param in The buffer to import from
+ @param inlen Length of the buffer
+ @param which PK_PUBLIC for an encapsulation key, PK_PRIVATE for a decapsulation key
+ @param alg The parameter set (LTC_MLKEM_512, LTC_MLKEM_768, or LTC_MLKEM_1024)
+ @param key [out] Destination for the imported key
+ @return CRYPT_OK if successful
+*/
+int mlkem_import_raw(const unsigned char *in, unsigned long inlen, int which, int alg, mlkem_key *key)
+{
+ mlkem_params p;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if ((err = s_mlkem_get_params(alg, &p)) != CRYPT_OK) return err;
+
+ XMEMSET(key, 0, sizeof(*key));
+ key->alg = alg;
+
+ if (which == PK_PUBLIC) {
+ if (inlen != p.pk_bytes) return CRYPT_INVALID_PACKET;
+ key->pk = XMALLOC(p.pk_bytes);
+ if (key->pk == NULL) return CRYPT_MEM;
+ XMEMCPY(key->pk, in, p.pk_bytes);
+ key->pklen = p.pk_bytes;
+ key->type = PK_PUBLIC;
+ } else if (which == PK_PRIVATE) {
+ if (inlen != p.sk_bytes) return CRYPT_INVALID_PACKET;
+ key->sk = XMALLOC(p.sk_bytes);
+ /* Extract pk from sk (it's embedded at offset indcpa_sk_bytes) */
+ key->pk = XMALLOC(p.pk_bytes);
+ if (key->sk == NULL || key->pk == NULL) {
+ mlkem_free(key);
+ return CRYPT_MEM;
+ }
+ XMEMCPY(key->sk, in, p.sk_bytes);
+ XMEMCPY(key->pk, in + p.indcpa_sk_bytes, p.pk_bytes);
+ key->sklen = p.sk_bytes;
+ key->pklen = p.pk_bytes;
+ key->type = PK_PRIVATE;
+ if ((err = s_mlkem_validate_private_key(key->sk, &p)) != CRYPT_OK) {
+ mlkem_free(key);
+ return err;
+ }
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ return CRYPT_OK;
+}
+
+/**
+ ML-KEM encapsulation: generate a shared secret and ciphertext from a public key.
+ @param ct [out] The ciphertext
+ @param ctlen [in/out] Max size and resulting size of the ciphertext
+ @param shared_secret [out] The shared secret (32 bytes)
+ @param sslen [in/out] Max size and resulting size of the shared secret
+ @param prng An active PRNG state
+ @param wprng The index of the desired PRNG
+ @param key The public (encapsulation) key
+ @return CRYPT_OK if successful
+*/
+int mlkem_encaps(unsigned char *ct, unsigned long *ctlen,
+ unsigned char *shared_secret, unsigned long *sslen,
+ prng_state *prng, int wprng,
+ const mlkem_key *key)
+{
+ mlkem_params p;
+ unsigned char coins[MLKEM_SYMBYTES];
+ int err;
+
+ LTC_ARGCHK(ct != NULL);
+ LTC_ARGCHK(ctlen != NULL);
+ LTC_ARGCHK(shared_secret != NULL);
+ LTC_ARGCHK(sslen != NULL);
+ LTC_ARGCHK(key != NULL);
+ LTC_ARGCHK(key->pk != NULL);
+
+ if ((err = s_mlkem_get_params(key->alg, &p)) != CRYPT_OK) return err;
+ if (*ctlen < p.ct_bytes) { *ctlen = p.ct_bytes; return CRYPT_BUFFER_OVERFLOW; }
+ if (*sslen < MLKEM_SSBYTES) { *sslen = MLKEM_SSBYTES; return CRYPT_BUFFER_OVERFLOW; }
+ if ((err = prng_is_valid(wprng)) != CRYPT_OK) return err;
+ if (prng_descriptor[wprng].read(coins, sizeof(coins), prng) != sizeof(coins))
+ return CRYPT_ERROR_READPRNG;
+
+ err = s_mlkem_kem_enc(ct, shared_secret, key->pk, coins, &p);
+
+ *ctlen = p.ct_bytes;
+ *sslen = MLKEM_SSBYTES;
+
+ zeromem(coins, sizeof(coins));
+ return err;
+}
+
+/**
+ ML-KEM decapsulation: recover a shared secret from a ciphertext using a private key.
+ @param shared_secret [out] The shared secret (32 bytes)
+ @param sslen [in/out] Max size and resulting size of the shared secret
+ @param ct The ciphertext
+ @param ctlen Length of the ciphertext
+ @param key The private (decapsulation) key
+ @return CRYPT_OK if successful
+
+ @note On implicit rejection (invalid ciphertext), a pseudorandom value is
+ returned instead of an error, as required by the ML-KEM specification.
+*/
+int mlkem_decaps(unsigned char *shared_secret, unsigned long *sslen,
+ const unsigned char *ct, unsigned long ctlen,
+ const mlkem_key *key)
+{
+ mlkem_params p;
+ int err;
+
+ LTC_ARGCHK(shared_secret != NULL);
+ LTC_ARGCHK(sslen != NULL);
+ LTC_ARGCHK(ct != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if (key->type != PK_PRIVATE) return CRYPT_PK_NOT_PRIVATE;
+ if ((err = s_mlkem_get_params(key->alg, &p)) != CRYPT_OK) return err;
+ if (ctlen != p.ct_bytes) return CRYPT_INVALID_PACKET;
+ if (*sslen < MLKEM_SSBYTES) { *sslen = MLKEM_SSBYTES; return CRYPT_BUFFER_OVERFLOW; }
+
+ err = s_mlkem_kem_dec(shared_secret, ct, key->sk, &p);
+ *sslen = MLKEM_SSBYTES;
+ return err;
+}
+
+/**
+ Get the sizes for a given ML-KEM parameter set.
+ Any output pointer may be NULL if the caller does not need that value.
+ @param alg The parameter set (LTC_MLKEM_512, LTC_MLKEM_768, or LTC_MLKEM_1024)
+ @param public_key_sz [out] Public key size in bytes
+ @param secret_key_sz [out] Secret key size in bytes
+ @param ciphertext_sz [out] Ciphertext size in bytes
+ @param shared_secret_sz [out] Shared secret size in bytes (always 32)
+ @return CRYPT_OK if successful
+*/
+int mlkem_get_sizes(int alg, unsigned long *public_key_sz, unsigned long *secret_key_sz,
+ unsigned long *ciphertext_sz, unsigned long *shared_secret_sz)
+{
+ mlkem_params p;
+ int err;
+
+ if ((err = s_mlkem_get_params(alg, &p)) != CRYPT_OK) return err;
+
+ if (public_key_sz != NULL) *public_key_sz = p.pk_bytes;
+ if (secret_key_sz != NULL) *secret_key_sz = p.sk_bytes;
+ if (ciphertext_sz != NULL) *ciphertext_sz = p.ct_bytes;
+ if (shared_secret_sz != NULL) *shared_secret_sz = MLKEM_SSBYTES;
+
+ return CRYPT_OK;
+}
+
+#endif /* LTC_MLKEM */
diff --git a/src/pqc/mlkem_export.c b/src/pqc/mlkem_export.c
new file mode 100644
index 000000000..cd6246c72
--- /dev/null
+++ b/src/pqc/mlkem_export.c
@@ -0,0 +1,114 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_private.h"
+
+/**
+ @file mlkem_export.c
+ Export an ML-KEM key to a binary packet
+*/
+
+#ifdef LTC_MLKEM
+
+static int s_mlkem_alg_to_oid(int alg, enum ltc_oid_id *oid_id)
+{
+ LTC_ARGCHK(oid_id != NULL);
+
+ switch (alg) {
+ case LTC_MLKEM_512:
+ *oid_id = LTC_OID_MLKEM_512;
+ return CRYPT_OK;
+ case LTC_MLKEM_768:
+ *oid_id = LTC_OID_MLKEM_768;
+ return CRYPT_OK;
+ case LTC_MLKEM_1024:
+ *oid_id = LTC_OID_MLKEM_1024;
+ return CRYPT_OK;
+ default:
+ return CRYPT_PK_INVALID_TYPE;
+ }
+}
+
+/**
+ Export an ML-KEM key to a binary packet
+ @param out [out] The destination for the key
+ @param outlen [in/out] The max size and resulting size of the ML-KEM key
+ @param which Which type of key (PK_PRIVATE, PK_PUBLIC|PK_STD or PK_PUBLIC)
+ @param key The key you wish to export
+ @return CRYPT_OK if successful
+*/
+int mlkem_export(unsigned char *out, unsigned long *outlen,
+ int which, const mlkem_key *key)
+{
+ int err, std;
+ enum ltc_oid_id oid_id;
+
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ std = which & PK_STD;
+ which &= ~PK_STD;
+
+ if ((err = s_mlkem_alg_to_oid(key->alg, &oid_id)) != CRYPT_OK) {
+ return err;
+ }
+
+ if (which == PK_PRIVATE) {
+ const char *OID;
+ unsigned long version, oid[16], oidlen;
+ unsigned char *private_key;
+ unsigned long private_key_len;
+ ltc_asn1_list alg_id[1];
+
+ if (key->type != PK_PRIVATE || key->sk == NULL) return CRYPT_PK_INVALID_TYPE;
+
+ if (std != PK_STD) {
+ return mlkem_export_raw(out, outlen, which, key);
+ }
+
+ if ((err = pk_get_oid(oid_id, &OID)) != CRYPT_OK) {
+ return err;
+ }
+ oidlen = LTC_ARRAY_SIZE(oid);
+ if ((err = pk_oid_str_to_num(OID, oid, &oidlen)) != CRYPT_OK) {
+ return err;
+ }
+ LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid, oidlen);
+
+ if ((err = der_length_octet_string(key->sklen, &private_key_len)) != CRYPT_OK) {
+ return err;
+ }
+ private_key = XMALLOC(private_key_len);
+ if (private_key == NULL) {
+ return CRYPT_MEM;
+ }
+
+ err = der_encode_octet_string(key->sk, key->sklen, private_key, &private_key_len);
+ if (err == CRYPT_OK) {
+ version = 0;
+ err = der_encode_sequence_multi(out, outlen,
+ LTC_ASN1_SHORT_INTEGER, 1uL, &version,
+ LTC_ASN1_SEQUENCE, 1uL, alg_id,
+ LTC_ASN1_OCTET_STRING, private_key_len, private_key,
+ LTC_ASN1_EOL, 0uL, NULL);
+ }
+
+ XFREE(private_key);
+ return err;
+ }
+
+ if (which != PK_PUBLIC) {
+ return CRYPT_INVALID_ARG;
+ }
+ if (key->pk == NULL) return CRYPT_PK_INVALID_TYPE;
+
+ if (std == PK_STD) {
+ return x509_encode_subject_public_key_info(out, outlen, oid_id,
+ key->pk, key->pklen,
+ LTC_ASN1_EOL, NULL, 0uL);
+ }
+
+ return mlkem_export_raw(out, outlen, which, key);
+}
+
+#endif
diff --git a/src/pqc/mlkem_import.c b/src/pqc/mlkem_import.c
new file mode 100644
index 000000000..65815e841
--- /dev/null
+++ b/src/pqc/mlkem_import.c
@@ -0,0 +1,65 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_private.h"
+
+/**
+ @file mlkem_import.c
+ Import a ML-KEM key from a SubjectPublicKeyInfo
+*/
+
+#ifdef LTC_MLKEM
+
+typedef struct {
+ enum ltc_oid_id oid;
+ int alg;
+} mlkem_oid_map;
+
+static const mlkem_oid_map s_mlkem_oid_map[] = {
+ { LTC_OID_MLKEM_512, LTC_MLKEM_512 },
+ { LTC_OID_MLKEM_768, LTC_MLKEM_768 },
+ { LTC_OID_MLKEM_1024, LTC_MLKEM_1024 },
+};
+
+/**
+ Import a ML-KEM public key
+ @param in The packet to read
+ @param inlen The length of the input packet
+ @param key [out] Where to import the key to
+ @return CRYPT_OK if successful, on error all allocated memory is freed automatically
+*/
+int mlkem_import(const unsigned char *in, unsigned long inlen, mlkem_key *key)
+{
+ unsigned char *pub;
+ unsigned long pub_len, max_pub_len;
+ unsigned long i;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if ((err = mlkem_get_sizes(LTC_MLKEM_1024, &max_pub_len, NULL, NULL, NULL)) != CRYPT_OK) {
+ return err;
+ }
+
+ pub = XMALLOC(max_pub_len);
+ if (pub == NULL) {
+ return CRYPT_MEM;
+ }
+
+ err = CRYPT_PK_INVALID_TYPE;
+ for (i = 0; i < LTC_ARRAY_SIZE(s_mlkem_oid_map); ++i) {
+ pub_len = max_pub_len;
+ err = x509_decode_subject_public_key_info(in, inlen, s_mlkem_oid_map[i].oid,
+ pub, &pub_len,
+ LTC_ASN1_EOL, NULL, 0uL);
+ if (err == CRYPT_OK) {
+ err = mlkem_import_raw(pub, pub_len, PK_PUBLIC, s_mlkem_oid_map[i].alg, key);
+ break;
+ }
+ }
+
+ XFREE(pub);
+ return err;
+}
+
+#endif
diff --git a/src/pqc/mlkem_import_pkcs8.c b/src/pqc/mlkem_import_pkcs8.c
new file mode 100644
index 000000000..e8af9ac16
--- /dev/null
+++ b/src/pqc/mlkem_import_pkcs8.c
@@ -0,0 +1,158 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_private.h"
+
+/**
+ @file mlkem_import_pkcs8.c
+ Import a ML-KEM key in PKCS#8 format
+*/
+
+#ifdef LTC_MLKEM
+
+static int s_mlkem_oid_to_alg(enum ltc_oid_id oid_id, int *alg)
+{
+ LTC_ARGCHK(alg != NULL);
+
+ switch (oid_id) {
+ case LTC_OID_MLKEM_512:
+ *alg = LTC_MLKEM_512;
+ return CRYPT_OK;
+ case LTC_OID_MLKEM_768:
+ *alg = LTC_MLKEM_768;
+ return CRYPT_OK;
+ case LTC_OID_MLKEM_1024:
+ *alg = LTC_MLKEM_1024;
+ return CRYPT_OK;
+ default:
+ return CRYPT_PK_INVALID_TYPE;
+ }
+}
+
+int mlkem_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key,
+ mlkem_key *key)
+{
+ ltc_asn1_list *decoded = NULL;
+ ltc_asn1_list *seed = NULL, *raw_key = NULL;
+ ltc_asn1_list seed_custom[1];
+ der_flexi_check flexi_should[4];
+ enum ltc_oid_id oid_id;
+ int alg, err;
+ unsigned char *raw_buf = NULL;
+ unsigned char seed_buf[64];
+ unsigned long inlen, raw_buf_len, key_len, n;
+ mlkem_key seed_key;
+
+ LTC_ARGCHK(alg_id != NULL);
+ LTC_ARGCHK(priv_key != NULL);
+ LTC_ARGCHK(key != NULL);
+ XMEMSET(&seed_key, 0, sizeof(seed_key));
+
+ if ((err = pk_get_oid_from_asn1(alg_id->child, &oid_id)) != CRYPT_OK) {
+ return err;
+ }
+ if ((err = s_mlkem_oid_to_alg(oid_id, &alg)) != CRYPT_OK) {
+ return err;
+ }
+
+ if ((err = mlkem_get_sizes(alg, NULL, &key_len, NULL, NULL)) != CRYPT_OK) {
+ return err;
+ }
+ if (priv_key->size == key_len) {
+ return mlkem_import_raw(priv_key->data, priv_key->size, PK_PRIVATE, alg, key);
+ }
+
+ raw_buf = XMALLOC(key_len);
+ if (raw_buf == NULL) {
+ return CRYPT_MEM;
+ }
+ raw_buf_len = key_len;
+ err = der_decode_octet_string(priv_key->data, priv_key->size, raw_buf, &raw_buf_len);
+ if (err == CRYPT_OK) {
+ err = (raw_buf_len == key_len)
+ ? mlkem_import_raw(raw_buf, raw_buf_len, PK_PRIVATE, alg, key)
+ : CRYPT_INVALID_PACKET;
+ XFREE(raw_buf);
+ return err;
+ }
+ XFREE(raw_buf);
+
+ LTC_SET_ASN1_CUSTOM_PRIMITIVE(seed_custom, 0, LTC_ASN1_CL_CONTEXT_SPECIFIC, 0,
+ LTC_ASN1_OCTET_STRING, seed_buf, sizeof(seed_buf));
+ err = der_decode_custom_type(priv_key->data, priv_key->size, seed_custom);
+ if (err == CRYPT_OK) {
+ return mlkem_make_key_from_seed(alg, seed_buf, seed_custom[0].size, key);
+ }
+
+ inlen = priv_key->size;
+ err = der_decode_sequence_flexi(priv_key->data, &inlen, &decoded);
+ if (err != CRYPT_OK) {
+ return err;
+ }
+
+ n = 0;
+ LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OCTET_STRING, &seed);
+ LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OCTET_STRING, &raw_key);
+ LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
+ err = der_flexi_sequence_cmp(decoded, flexi_should);
+ if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) {
+ goto cleanup;
+ }
+
+ if (seed == NULL || raw_key == NULL) {
+ err = CRYPT_INVALID_PACKET;
+ goto cleanup;
+ }
+ if ((err = mlkem_make_key_from_seed(alg, seed->data, seed->size, &seed_key)) != CRYPT_OK) {
+ goto cleanup;
+ }
+ if (seed_key.sklen != raw_key->size ||
+ XMEMCMP(seed_key.sk, raw_key->data, raw_key->size) != 0) {
+ err = CRYPT_INVALID_PACKET;
+ goto cleanup;
+ }
+
+ err = mlkem_import_raw(raw_key->data, raw_key->size, PK_PRIVATE, alg, key);
+
+cleanup:
+ mlkem_free(&seed_key);
+ der_free_sequence_flexi(decoded);
+ return err;
+}
+
+/**
+ Import a ML-KEM private key in PKCS#8 format
+ @param in The packet to import from
+ @param inlen It's length (octets)
+ @param pw_ctx The password context when decrypting the private key
+ @param key [out] Destination for newly imported key
+ @return CRYPT_OK if successful, on error all allocated memory is freed automatically
+*/
+int mlkem_import_pkcs8(const unsigned char *in, unsigned long inlen, const password_ctx *pw_ctx, mlkem_key *key)
+{
+ int alg, err;
+ ltc_asn1_list *l = NULL;
+ ltc_asn1_list *alg_id, *priv_key;
+ enum ltc_oid_id oid_id;
+
+ LTC_ARGCHK(in != NULL);
+
+ err = pkcs8_decode_flexi(in, inlen, pw_ctx, &l);
+ if (err != CRYPT_OK) {
+ return err;
+ }
+
+ if ((err = pkcs8_get_children(l, &oid_id, &alg_id, &priv_key)) != CRYPT_OK) {
+ goto cleanup;
+ }
+ if ((err = s_mlkem_oid_to_alg(oid_id, &alg)) != CRYPT_OK) {
+ goto cleanup;
+ }
+ LTC_UNUSED_PARAM(alg);
+ err = mlkem_import_pkcs8_asn1(alg_id, priv_key, key);
+
+cleanup:
+ der_free_sequence_flexi(l);
+ return err;
+}
+
+#endif
diff --git a/src/pqc/mlkem_import_x509.c b/src/pqc/mlkem_import_x509.c
new file mode 100644
index 000000000..e57aa6704
--- /dev/null
+++ b/src/pqc/mlkem_import_x509.c
@@ -0,0 +1,65 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_private.h"
+
+/**
+ @file mlkem_import_x509.c
+ Import a ML-KEM key from a X.509 certificate
+*/
+
+#ifdef LTC_MLKEM
+
+typedef struct {
+ mlkem_key *key;
+ int alg;
+} mlkem_x509_ctx;
+
+typedef struct {
+ enum ltc_oid_id oid;
+ int alg;
+} mlkem_oid_map_x509;
+
+static const mlkem_oid_map_x509 s_mlkem_oid_map_x509[] = {
+ { LTC_OID_MLKEM_512, LTC_MLKEM_512 },
+ { LTC_OID_MLKEM_768, LTC_MLKEM_768 },
+ { LTC_OID_MLKEM_1024, LTC_MLKEM_1024 },
+};
+
+static int s_mlkem_decode(const unsigned char *in, unsigned long inlen, mlkem_x509_ctx *ctx)
+{
+ return mlkem_import_raw(in, inlen, PK_PUBLIC, ctx->alg, ctx->key);
+}
+
+/**
+ Import a ML-KEM public key from a X.509 certificate
+ @param in The DER encoded X.509 certificate
+ @param inlen The length of the certificate
+ @param key [out] Where to import the key to
+ @return CRYPT_OK if successful, on error all allocated memory is freed automatically
+*/
+int mlkem_import_x509(const unsigned char *in, unsigned long inlen, mlkem_key *key)
+{
+ mlkem_x509_ctx ctx;
+ unsigned long i;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ err = CRYPT_PK_INVALID_TYPE;
+ for (i = 0; i < LTC_ARRAY_SIZE(s_mlkem_oid_map_x509); ++i) {
+ ctx.key = key;
+ ctx.alg = s_mlkem_oid_map_x509[i].alg;
+ err = x509_decode_public_key_from_certificate(in, inlen,
+ s_mlkem_oid_map_x509[i].oid,
+ LTC_ASN1_EOL, NULL, NULL,
+ (public_key_decode_cb)s_mlkem_decode, &ctx);
+ if (err == CRYPT_OK) {
+ break;
+ }
+ }
+
+ return err;
+}
+
+#endif
diff --git a/src/pqc/slhdsa.c b/src/pqc/slhdsa.c
new file mode 100644
index 000000000..6a06b6cf3
--- /dev/null
+++ b/src/pqc/slhdsa.c
@@ -0,0 +1,1906 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+/**
+ @file slhdsa.c
+ SLH-DSA (FIPS 205) implementation: WOTS+, FORS, Merkle trees, signing,
+ and verification (SHAKE-simple and SHA2-simple variants).
+ Based on the SPHINCS+ reference implementation (public domain).
+*/
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_SLHDSA
+
+/* Constants */
+
+#define SPX_N_MAX 32
+#define SPX_ADDR_BYTES 32 /* max address bytes (SHAKE uses 32, SHA-2 uses 22) */
+#define SPX_WOTS_W 16
+#define SPX_WOTS_LOGW 4
+#define SPX_FULL_HEIGHT_MAX 68
+#define SPX_D_MAX 22
+#define SPX_TREE_HEIGHT_MAX 10 /* max(full_height/d) across all param sets */
+#define SPX_FORS_HEIGHT_MAX 14
+#define SPX_FORS_TREES_MAX 35
+#define SPX_WOTS_LEN_MAX 67 /* max len1(64) + len2(3) = 67 for n=32 */
+#define SPX_WOTS_BYTES_MAX (SPX_WOTS_LEN_MAX * SPX_N_MAX) /* 67*32 = 2144 */
+
+/* Address types */
+#define SPX_ADDR_TYPE_WOTS 0
+#define SPX_ADDR_TYPE_WOTSPK 1
+#define SPX_ADDR_TYPE_HASHTREE 2
+#define SPX_ADDR_TYPE_FORSTREE 3
+#define SPX_ADDR_TYPE_FORSPK 4
+#define SPX_ADDR_TYPE_WOTSPRF 5
+#define SPX_ADDR_TYPE_FORSPRF 6
+
+/* Runtime parameter set */
+
+typedef struct {
+ unsigned int n;
+ unsigned int full_height;
+ unsigned int d;
+ unsigned int fors_height;
+ unsigned int fors_trees;
+ unsigned int wots_w;
+ unsigned int wots_logw;
+ unsigned int wots_len1;
+ unsigned int wots_len2;
+ unsigned int wots_len;
+ unsigned int wots_bytes;
+ unsigned int tree_height;
+ unsigned int fors_msg_bytes;
+ unsigned int fors_bytes;
+ unsigned long pk_bytes;
+ unsigned long sk_bytes;
+ unsigned long sig_bytes;
+ int is_shake;
+ /* Address layout */
+ unsigned int addr_bytes;
+ unsigned int off_layer;
+ unsigned int off_tree;
+ unsigned int off_type;
+ unsigned int off_kp_addr;
+ unsigned int off_chain_addr;
+ unsigned int off_hash_addr;
+ unsigned int off_tree_hgt;
+ unsigned int off_tree_index;
+ /* Number of bytes for keypair addr field */
+ unsigned int kp_addr_len;
+} slhdsa_params;
+
+static int s_slhdsa_is_hash_alg(int alg)
+{
+ return alg >= LTC_SLHDSA_HASH_SHA2_128S_WITH_SHA256
+ && alg <= LTC_SLHDSA_HASH_SHAKE_256F_WITH_SHAKE256;
+}
+
+static int s_slhdsa_hash_mode(int alg)
+{
+ switch (alg) {
+ case LTC_SLHDSA_HASH_SHA2_128S_WITH_SHA256:
+ case LTC_SLHDSA_HASH_SHA2_128F_WITH_SHA256:
+ return 1;
+ case LTC_SLHDSA_HASH_SHA2_192S_WITH_SHA512:
+ case LTC_SLHDSA_HASH_SHA2_192F_WITH_SHA512:
+ case LTC_SLHDSA_HASH_SHA2_256S_WITH_SHA512:
+ case LTC_SLHDSA_HASH_SHA2_256F_WITH_SHA512:
+ return 2;
+ case LTC_SLHDSA_HASH_SHAKE_128S_WITH_SHAKE128:
+ case LTC_SLHDSA_HASH_SHAKE_128F_WITH_SHAKE128:
+ return 3;
+ case LTC_SLHDSA_HASH_SHAKE_192S_WITH_SHAKE256:
+ case LTC_SLHDSA_HASH_SHAKE_192F_WITH_SHAKE256:
+ case LTC_SLHDSA_HASH_SHAKE_256S_WITH_SHAKE256:
+ case LTC_SLHDSA_HASH_SHAKE_256F_WITH_SHAKE256:
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+static int s_slhdsa_base_alg(int alg)
+{
+ switch (alg) {
+ case LTC_SLHDSA_HASH_SHA2_128S_WITH_SHA256:
+ return LTC_SLHDSA_SHA2_128S;
+ case LTC_SLHDSA_HASH_SHA2_128F_WITH_SHA256:
+ return LTC_SLHDSA_SHA2_128F;
+ case LTC_SLHDSA_HASH_SHA2_192S_WITH_SHA512:
+ return LTC_SLHDSA_SHA2_192S;
+ case LTC_SLHDSA_HASH_SHA2_192F_WITH_SHA512:
+ return LTC_SLHDSA_SHA2_192F;
+ case LTC_SLHDSA_HASH_SHA2_256S_WITH_SHA512:
+ return LTC_SLHDSA_SHA2_256S;
+ case LTC_SLHDSA_HASH_SHA2_256F_WITH_SHA512:
+ return LTC_SLHDSA_SHA2_256F;
+ case LTC_SLHDSA_HASH_SHAKE_128S_WITH_SHAKE128:
+ return LTC_SLHDSA_SHAKE_128S;
+ case LTC_SLHDSA_HASH_SHAKE_128F_WITH_SHAKE128:
+ return LTC_SLHDSA_SHAKE_128F;
+ case LTC_SLHDSA_HASH_SHAKE_192S_WITH_SHAKE256:
+ return LTC_SLHDSA_SHAKE_192S;
+ case LTC_SLHDSA_HASH_SHAKE_192F_WITH_SHAKE256:
+ return LTC_SLHDSA_SHAKE_192F;
+ case LTC_SLHDSA_HASH_SHAKE_256S_WITH_SHAKE256:
+ return LTC_SLHDSA_SHAKE_256S;
+ case LTC_SLHDSA_HASH_SHAKE_256F_WITH_SHAKE256:
+ return LTC_SLHDSA_SHAKE_256F;
+ default:
+ return alg;
+ }
+}
+
+static int s_slhdsa_hash_oid_der(int alg, const unsigned char **oid, unsigned long *oidlen)
+{
+ static const unsigned char sha256_oid[] = { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 };
+ static const unsigned char sha512_oid[] = { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 };
+ static const unsigned char shake128_oid[] = { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B };
+ static const unsigned char shake256_oid[] = { 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C };
+
+ LTC_ARGCHK(oid != NULL);
+ LTC_ARGCHK(oidlen != NULL);
+
+ switch (s_slhdsa_hash_mode(alg)) {
+ case 1:
+ *oid = sha256_oid;
+ *oidlen = sizeof(sha256_oid);
+ return CRYPT_OK;
+ case 2:
+ *oid = sha512_oid;
+ *oidlen = sizeof(sha512_oid);
+ return CRYPT_OK;
+ case 3:
+ *oid = shake128_oid;
+ *oidlen = sizeof(shake128_oid);
+ return CRYPT_OK;
+ case 4:
+ *oid = shake256_oid;
+ *oidlen = sizeof(shake256_oid);
+ return CRYPT_OK;
+ default:
+ return CRYPT_INVALID_ARG;
+ }
+}
+
+static int s_slhdsa_hash_message_memory(int alg,
+ const unsigned char *msg, unsigned long msglen,
+ unsigned char *out, unsigned long *outlen)
+{
+ int hash_idx;
+
+ LTC_ARGCHK(msg != NULL || msglen == 0);
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+
+ switch (s_slhdsa_hash_mode(alg)) {
+ case 1:
+ hash_idx = find_hash("sha256");
+ if (hash_idx == -1) return CRYPT_INVALID_HASH;
+ return hash_memory(hash_idx, msg, msglen, out, outlen);
+ case 2:
+ hash_idx = find_hash("sha512");
+ if (hash_idx == -1) return CRYPT_INVALID_HASH;
+ return hash_memory(hash_idx, msg, msglen, out, outlen);
+ case 3:
+ return sha3_shake_memory(128, msg, msglen, out, outlen);
+ case 4:
+ return sha3_shake_memory(256, msg, msglen, out, outlen);
+ default:
+ return CRYPT_INVALID_ARG;
+ }
+}
+
+static int s_slhdsa_prepare_message(unsigned char **m_prime,
+ unsigned long *m_prime_len,
+ const unsigned char *msg, unsigned long msglen,
+ const unsigned char *ctx, unsigned long ctxlen,
+ int alg)
+{
+ unsigned long prelen, oidlen = 0, phm_len = 0;
+ const unsigned char *oid = NULL;
+ unsigned char phm[64];
+ int err = CRYPT_OK;
+
+ LTC_ARGCHK(m_prime != NULL);
+ LTC_ARGCHK(m_prime_len != NULL);
+ LTC_ARGCHK(msg != NULL || msglen == 0);
+
+ if (ctxlen > 255) {
+ return CRYPT_INVALID_ARG;
+ }
+
+ if (!s_slhdsa_is_hash_alg(alg)) {
+ prelen = 2 + ctxlen;
+ *m_prime_len = prelen + msglen;
+ *m_prime = XMALLOC(*m_prime_len > 0 ? *m_prime_len : 1);
+ if (*m_prime == NULL) return CRYPT_MEM;
+
+ (*m_prime)[0] = 0x00;
+ (*m_prime)[1] = (unsigned char)ctxlen;
+ if (ctxlen > 0 && ctx != NULL) {
+ XMEMCPY(*m_prime + 2, ctx, ctxlen);
+ }
+ if (msglen > 0 && msg != NULL) {
+ XMEMCPY(*m_prime + prelen, msg, msglen);
+ }
+ return CRYPT_OK;
+ }
+
+ if ((err = s_slhdsa_hash_oid_der(alg, &oid, &oidlen)) != CRYPT_OK) {
+ return err;
+ }
+ phm_len = sizeof(phm);
+ if ((err = s_slhdsa_hash_message_memory(alg, msg, msglen, phm, &phm_len)) != CRYPT_OK) {
+ return err;
+ }
+
+ *m_prime_len = 2 + ctxlen + oidlen + phm_len;
+ *m_prime = XMALLOC(*m_prime_len > 0 ? *m_prime_len : 1);
+ if (*m_prime == NULL) {
+ zeromem(phm, sizeof(phm));
+ return CRYPT_MEM;
+ }
+
+ (*m_prime)[0] = 0x01;
+ (*m_prime)[1] = (unsigned char)ctxlen;
+ if (ctxlen > 0 && ctx != NULL) {
+ XMEMCPY(*m_prime + 2, ctx, ctxlen);
+ }
+ XMEMCPY(*m_prime + 2 + ctxlen, oid, oidlen);
+ XMEMCPY(*m_prime + 2 + ctxlen + oidlen, phm, phm_len);
+ zeromem(phm, sizeof(phm));
+
+ return CRYPT_OK;
+}
+
+/* Parameter lookup */
+
+static int s_slhdsa_get_params(int alg, slhdsa_params *p)
+{
+ LTC_ARGCHK(p != NULL);
+
+ XMEMSET(p, 0, sizeof(*p));
+
+ p->wots_w = SPX_WOTS_W;
+ p->wots_logw = SPX_WOTS_LOGW;
+
+ switch (s_slhdsa_base_alg(alg)) {
+ case LTC_SLHDSA_SHA2_128S:
+ case LTC_SLHDSA_SHAKE_128S:
+ p->n = 16; p->full_height = 63; p->d = 7;
+ p->fors_height = 12; p->fors_trees = 14;
+ p->is_shake = (alg == LTC_SLHDSA_SHAKE_128S) ? 1 : 0;
+ break;
+ case LTC_SLHDSA_SHA2_128F:
+ case LTC_SLHDSA_SHAKE_128F:
+ p->n = 16; p->full_height = 66; p->d = 22;
+ p->fors_height = 6; p->fors_trees = 33;
+ p->is_shake = (alg == LTC_SLHDSA_SHAKE_128F) ? 1 : 0;
+ break;
+ case LTC_SLHDSA_SHA2_192S:
+ case LTC_SLHDSA_SHAKE_192S:
+ p->n = 24; p->full_height = 63; p->d = 7;
+ p->fors_height = 14; p->fors_trees = 17;
+ p->is_shake = (alg == LTC_SLHDSA_SHAKE_192S) ? 1 : 0;
+ break;
+ case LTC_SLHDSA_SHA2_192F:
+ case LTC_SLHDSA_SHAKE_192F:
+ p->n = 24; p->full_height = 66; p->d = 22;
+ p->fors_height = 8; p->fors_trees = 33;
+ p->is_shake = (alg == LTC_SLHDSA_SHAKE_192F) ? 1 : 0;
+ break;
+ case LTC_SLHDSA_SHA2_256S:
+ case LTC_SLHDSA_SHAKE_256S:
+ p->n = 32; p->full_height = 64; p->d = 8;
+ p->fors_height = 14; p->fors_trees = 22;
+ p->is_shake = (alg == LTC_SLHDSA_SHAKE_256S) ? 1 : 0;
+ break;
+ case LTC_SLHDSA_SHA2_256F:
+ case LTC_SLHDSA_SHAKE_256F:
+ p->n = 32; p->full_height = 68; p->d = 17;
+ p->fors_height = 9; p->fors_trees = 35;
+ p->is_shake = (alg == LTC_SLHDSA_SHAKE_256F) ? 1 : 0;
+ break;
+ default:
+ return CRYPT_INVALID_ARG;
+ }
+
+ /* Derived WOTS+ parameters */
+ p->wots_len1 = 8 * p->n / p->wots_logw;
+ /* wots_len2 = floor(log(len1 * (w-1)) / log(w)) + 1, precomputed */
+ if (p->n <= 8) {
+ p->wots_len2 = 2;
+ } else if (p->n <= 136) {
+ p->wots_len2 = 3;
+ } else {
+ p->wots_len2 = 4;
+ }
+ p->wots_len = p->wots_len1 + p->wots_len2;
+ p->wots_bytes = p->wots_len * p->n;
+
+ /* Derived tree parameters */
+ p->tree_height = p->full_height / p->d;
+ p->fors_msg_bytes = (p->fors_height * p->fors_trees + 7) / 8;
+ p->fors_bytes = (p->fors_height + 1) * p->fors_trees * p->n;
+
+ /* Key and signature sizes */
+ p->pk_bytes = 2 * (unsigned long)p->n;
+ p->sk_bytes = 4 * (unsigned long)p->n;
+ p->sig_bytes = (unsigned long)p->n + (unsigned long)p->fors_bytes
+ + (unsigned long)p->d * (unsigned long)p->wots_bytes
+ + (unsigned long)p->full_height * (unsigned long)p->n;
+
+ /* Address offsets depend on variant */
+ if (p->is_shake) {
+ p->addr_bytes = 32;
+ p->off_layer = 3;
+ p->off_tree = 8;
+ p->off_type = 19;
+ p->off_kp_addr = 20;
+ p->off_chain_addr = 27;
+ p->off_hash_addr = 31;
+ p->off_tree_hgt = 27;
+ p->off_tree_index = 28;
+ p->kp_addr_len = 4;
+ } else {
+ p->addr_bytes = 22;
+ p->off_layer = 0;
+ p->off_tree = 1;
+ p->off_type = 9;
+ p->off_kp_addr = 10;
+ p->off_chain_addr = 17;
+ p->off_hash_addr = 21;
+ p->off_tree_hgt = 17;
+ p->off_tree_index = 18;
+ p->kp_addr_len = 4;
+ }
+
+ return CRYPT_OK;
+}
+
+/* Address manipulation */
+
+static void s_set_layer_addr(unsigned char addr[SPX_ADDR_BYTES],
+ ulong32 layer, const slhdsa_params *p)
+{
+ addr[p->off_layer] = (unsigned char)layer;
+}
+
+static void s_set_tree_addr(unsigned char addr[SPX_ADDR_BYTES],
+ ulong64 tree, const slhdsa_params *p)
+{
+ int i;
+ for (i = 7; i >= 0; i--) {
+ addr[p->off_tree + i] = (unsigned char)(tree & 0xff);
+ tree >>= 8;
+ }
+}
+
+static void s_set_type(unsigned char addr[SPX_ADDR_BYTES],
+ ulong32 type, const slhdsa_params *p)
+{
+ addr[p->off_type] = (unsigned char)type;
+}
+
+static void s_copy_subtree_addr(unsigned char out[SPX_ADDR_BYTES],
+ const unsigned char in[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ XMEMCPY(out, in, p->off_tree + 8);
+}
+
+static void s_set_keypair_addr(unsigned char addr[SPX_ADDR_BYTES],
+ ulong32 keypair, const slhdsa_params *p)
+{
+ addr[p->off_kp_addr + 0] = (unsigned char)(keypair >> 24);
+ addr[p->off_kp_addr + 1] = (unsigned char)(keypair >> 16);
+ addr[p->off_kp_addr + 2] = (unsigned char)(keypair >> 8);
+ addr[p->off_kp_addr + 3] = (unsigned char)(keypair);
+}
+
+static void s_copy_keypair_addr(unsigned char out[SPX_ADDR_BYTES],
+ const unsigned char in[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ XMEMCPY(out, in, p->off_tree + 8);
+ XMEMCPY(out + p->off_kp_addr, in + p->off_kp_addr, p->kp_addr_len);
+}
+
+static void s_set_chain_addr(unsigned char addr[SPX_ADDR_BYTES],
+ ulong32 chain, const slhdsa_params *p)
+{
+ addr[p->off_chain_addr] = (unsigned char)chain;
+}
+
+static void s_set_hash_addr(unsigned char addr[SPX_ADDR_BYTES],
+ ulong32 hash, const slhdsa_params *p)
+{
+ addr[p->off_hash_addr] = (unsigned char)hash;
+}
+
+static void s_set_tree_height(unsigned char addr[SPX_ADDR_BYTES],
+ ulong32 tree_height, const slhdsa_params *p)
+{
+ addr[p->off_tree_hgt] = (unsigned char)tree_height;
+}
+
+static void s_set_tree_index(unsigned char addr[SPX_ADDR_BYTES],
+ ulong32 tree_index, const slhdsa_params *p)
+{
+ addr[p->off_tree_index + 0] = (unsigned char)(tree_index >> 24);
+ addr[p->off_tree_index + 1] = (unsigned char)(tree_index >> 16);
+ addr[p->off_tree_index + 2] = (unsigned char)(tree_index >> 8);
+ addr[p->off_tree_index + 3] = (unsigned char)(tree_index);
+}
+
+/* Byte conversion utilities */
+
+static void s_ull_to_bytes(unsigned char *out, unsigned int outlen, ulong64 in)
+{
+ int i;
+ for (i = (int)outlen - 1; i >= 0; i--) {
+ out[i] = (unsigned char)(in & 0xff);
+ in >>= 8;
+ }
+}
+
+static ulong64 s_bytes_to_ull(const unsigned char *in, unsigned int inlen)
+{
+ ulong64 retval = 0;
+ unsigned int i;
+ for (i = 0; i < inlen; i++) {
+ retval |= ((ulong64)in[i]) << (8 * (inlen - 1 - i));
+ }
+ return retval;
+}
+
+/* ========================================================================= */
+/* SHAKE-based hash functions */
+/* ========================================================================= */
+
+/**
+ * Tweakable hash (SHAKE-simple variant).
+ * thash(pub_seed, addr, in, inblocks) = SHAKE256(pub_seed || addr || in)[0:n]
+ */
+static int s_thash_shake(unsigned char *out, const unsigned char *in,
+ unsigned int inblocks, const unsigned char *pub_seed,
+ unsigned char addr[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ hash_state md;
+ int err;
+ unsigned long outlen = p->n;
+
+ if ((err = sha3_shake_init(&md, 256)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, pub_seed, p->n)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, addr, p->addr_bytes)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, in, (unsigned long)inblocks * p->n)) != CRYPT_OK) return err;
+ return sha3_shake_done(&md, out, outlen);
+}
+
+/**
+ * PRF(pub_seed, sk_seed, addr) = SHAKE256(pub_seed || addr || sk_seed)[0:n]
+ */
+static int s_prf_addr_shake(unsigned char *out, const unsigned char *pub_seed,
+ const unsigned char *sk_seed,
+ unsigned char addr[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ hash_state md;
+ int err;
+ unsigned long outlen = p->n;
+
+ if ((err = sha3_shake_init(&md, 256)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, pub_seed, p->n)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, addr, p->addr_bytes)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, sk_seed, p->n)) != CRYPT_OK) return err;
+ return sha3_shake_done(&md, out, outlen);
+}
+
+/**
+ * Compute the message-dependent randomness R (SHAKE variant).
+ * R = SHAKE256(sk_prf || optrand || m)[0:n]
+ */
+static int s_gen_message_random_shake(unsigned char *R,
+ const unsigned char *sk_prf,
+ const unsigned char *optrand,
+ const unsigned char *m, unsigned long mlen,
+ const slhdsa_params *p)
+{
+ hash_state md;
+ int err;
+ unsigned long outlen = p->n;
+
+ if ((err = sha3_shake_init(&md, 256)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, sk_prf, p->n)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, optrand, p->n)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, m, mlen)) != CRYPT_OK) return err;
+ return sha3_shake_done(&md, R, outlen);
+}
+
+/**
+ * Compute the message digest and leaf index from R, PK and M (SHAKE variant).
+ * SHAKE256(R || PK || M) -> (digest, tree, leaf_idx)
+ */
+static int s_hash_message_shake(unsigned char *digest, ulong64 *tree, ulong32 *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, unsigned long mlen,
+ const slhdsa_params *p)
+{
+ unsigned int tree_bits, tree_bytes, leaf_bits, leaf_bytes, dgst_bytes;
+ unsigned char buf[SPX_FORS_HEIGHT_MAX * SPX_FORS_TREES_MAX / 8 + 1 + 8 + 4];
+ unsigned char *bufp;
+ hash_state md;
+ int err;
+ unsigned long outlen;
+
+ tree_bits = p->tree_height * (p->d - 1);
+ tree_bytes = (tree_bits + 7) / 8;
+ leaf_bits = p->tree_height;
+ leaf_bytes = (leaf_bits + 7) / 8;
+ dgst_bytes = p->fors_msg_bytes + tree_bytes + leaf_bytes;
+
+ outlen = dgst_bytes;
+
+ if ((err = sha3_shake_init(&md, 256)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, R, p->n)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, pk, p->pk_bytes)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_process(&md, m, mlen)) != CRYPT_OK) return err;
+ if ((err = sha3_shake_done(&md, buf, outlen)) != CRYPT_OK) return err;
+
+ bufp = buf;
+ XMEMCPY(digest, bufp, p->fors_msg_bytes);
+ bufp += p->fors_msg_bytes;
+
+ if (p->d == 1) {
+ *tree = 0;
+ } else {
+ *tree = s_bytes_to_ull(bufp, tree_bytes);
+ *tree &= (~(ulong64)0) >> (64 - tree_bits);
+ }
+ bufp += tree_bytes;
+
+ *leaf_idx = (ulong32)s_bytes_to_ull(bufp, leaf_bytes);
+ *leaf_idx &= (~(ulong32)0) >> (32 - leaf_bits);
+
+ return CRYPT_OK;
+}
+
+/* ========================================================================= */
+/* SHA-2-based hash functions */
+/* ========================================================================= */
+
+/**
+ * Return the libtomcrypt hash index for SHA-256 or SHA-512.
+ * For n < 24 (128-bit security): SHA-256
+ * For n >= 24 (192/256-bit security): SHA-512
+ */
+static int s_sha2_hash_idx(const slhdsa_params *p)
+{
+ if (p->n >= 24)
+ return find_hash("sha512");
+ return find_hash("sha256");
+}
+
+/**
+ * Tweakable hash (SHA-2-simple variant).
+ * thash(pub_seed, addr, in, inblocks) = SHA-X(pub_seed || addr_c || in)[0:n]
+ *
+ * For single-block (inblocks == 1), always use SHA-256.
+ * For multi-block (inblocks > 1) with n >= 24, use SHA-512 for performance.
+ */
+static int s_thash_sha2(unsigned char *out, const unsigned char *in,
+ unsigned int inblocks, const unsigned char *pub_seed,
+ unsigned char addr[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ hash_state md;
+ int hash_idx, err;
+ unsigned char hash_out[64]; /* max SHA-512 output */
+
+ /* Choose hash function */
+ if (inblocks > 1 && p->n >= 24) {
+ hash_idx = find_hash("sha512");
+ } else {
+ hash_idx = find_hash("sha256");
+ }
+ if (hash_idx == -1) return CRYPT_INVALID_HASH;
+
+ if ((err = hash_descriptor[hash_idx].init(&md)) != CRYPT_OK) return err;
+ if ((err = hash_descriptor[hash_idx].process(&md, pub_seed, p->n)) != CRYPT_OK) return err;
+ if ((err = hash_descriptor[hash_idx].process(&md, addr, p->addr_bytes)) != CRYPT_OK) return err;
+ if ((err = hash_descriptor[hash_idx].process(&md, in, (unsigned long)inblocks * p->n)) != CRYPT_OK) return err;
+ if ((err = hash_descriptor[hash_idx].done(&md, hash_out)) != CRYPT_OK) return err;
+
+ /* Truncate to n bytes */
+ XMEMCPY(out, hash_out, p->n);
+
+ zeromem(hash_out, sizeof(hash_out));
+ return CRYPT_OK;
+}
+
+/**
+ * PRF(pub_seed, sk_seed, addr) for SHA-2 variant.
+ * PRF = SHA-256(pub_seed || addr_c || sk_seed)[0:n]
+ * Always uses SHA-256 regardless of security level.
+ */
+static int s_prf_addr_sha2(unsigned char *out, const unsigned char *pub_seed,
+ const unsigned char *sk_seed,
+ unsigned char addr[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ hash_state md;
+ int hash_idx, err;
+ unsigned char hash_out[32]; /* SHA-256 output */
+
+ hash_idx = find_hash("sha256");
+ if (hash_idx == -1) return CRYPT_INVALID_HASH;
+
+ if ((err = hash_descriptor[hash_idx].init(&md)) != CRYPT_OK) return err;
+ if ((err = hash_descriptor[hash_idx].process(&md, pub_seed, p->n)) != CRYPT_OK) return err;
+ if ((err = hash_descriptor[hash_idx].process(&md, addr, p->addr_bytes)) != CRYPT_OK) return err;
+ if ((err = hash_descriptor[hash_idx].process(&md, sk_seed, p->n)) != CRYPT_OK) return err;
+ if ((err = hash_descriptor[hash_idx].done(&md, hash_out)) != CRYPT_OK) return err;
+
+ XMEMCPY(out, hash_out, p->n);
+
+ zeromem(hash_out, sizeof(hash_out));
+ return CRYPT_OK;
+}
+
+/**
+ * Compute the message-dependent randomness R (SHA-2 variant).
+ * R = HMAC-SHA-X(sk_prf, optrand || m)[0:n]
+ * For n < 24: SHA-256; for n >= 24: SHA-512.
+ */
+static int s_gen_message_random_sha2(unsigned char *R,
+ const unsigned char *sk_prf,
+ const unsigned char *optrand,
+ const unsigned char *m, unsigned long mlen,
+ const slhdsa_params *p)
+{
+ int hash_idx, err;
+ unsigned char hmac_out[64]; /* max SHA-512 HMAC */
+ unsigned long hmac_len;
+
+ hash_idx = s_sha2_hash_idx(p);
+ if (hash_idx == -1) return CRYPT_INVALID_HASH;
+
+ hmac_len = hash_descriptor[hash_idx].hashsize;
+
+ err = hmac_memory_multi(hash_idx,
+ sk_prf, (unsigned long)p->n,
+ hmac_out, &hmac_len,
+ optrand, (unsigned long)p->n,
+ m, mlen,
+ LTC_NULL);
+ if (err != CRYPT_OK) return err;
+
+ XMEMCPY(R, hmac_out, p->n);
+ zeromem(hmac_out, sizeof(hmac_out));
+ return CRYPT_OK;
+}
+
+/**
+ * MGF1 helper for SHA-2 hash_message.
+ * Generates dgst_len bytes of output from mgf_seed of mgf_seed_len bytes.
+ * MGF1-SHA-X: for i=0,1,...: out += SHA-X(mgf_seed || i_be32), truncate.
+ */
+static int s_mgf1_sha2(unsigned char *out, unsigned long dgst_len,
+ const unsigned char *mgf_seed, unsigned long mgf_seed_len,
+ int hash_idx)
+{
+ hash_state md;
+ unsigned char hash_out[64]; /* max SHA-512 */
+ unsigned char counter_buf[4];
+ unsigned long hlen, remaining, copy_len;
+ ulong32 counter;
+ int err;
+
+ hlen = hash_descriptor[hash_idx].hashsize;
+ remaining = dgst_len;
+ counter = 0;
+
+ while (remaining > 0) {
+ counter_buf[0] = (unsigned char)(counter >> 24);
+ counter_buf[1] = (unsigned char)(counter >> 16);
+ counter_buf[2] = (unsigned char)(counter >> 8);
+ counter_buf[3] = (unsigned char)(counter);
+
+ if ((err = hash_descriptor[hash_idx].init(&md)) != CRYPT_OK) return err;
+ if ((err = hash_descriptor[hash_idx].process(&md, mgf_seed, mgf_seed_len)) != CRYPT_OK) return err;
+ if ((err = hash_descriptor[hash_idx].process(&md, counter_buf, 4)) != CRYPT_OK) return err;
+ if ((err = hash_descriptor[hash_idx].done(&md, hash_out)) != CRYPT_OK) return err;
+
+ copy_len = remaining < hlen ? remaining : hlen;
+ XMEMCPY(out, hash_out, copy_len);
+ out += copy_len;
+ remaining -= copy_len;
+ counter++;
+ }
+
+ zeromem(hash_out, sizeof(hash_out));
+ return CRYPT_OK;
+}
+
+/**
+ * Compute the message digest and leaf index from R, PK and M (SHA-2 variant).
+ *
+ * Per FIPS 205 Section 11.2:
+ * seed = SHA-X(R || PK.seed || PK.root || M)
+ * digest = MGF1-SHA-X(R || PK.seed || seed, dgst_bytes)
+ * Then extract (md, tree_idx, leaf_idx) from digest.
+ */
+static int s_hash_message_sha2(unsigned char *digest, ulong64 *tree, ulong32 *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, unsigned long mlen,
+ const slhdsa_params *p)
+{
+ unsigned int tree_bits, tree_bytes, leaf_bits, leaf_bytes, dgst_bytes;
+ unsigned char buf[SPX_FORS_HEIGHT_MAX * SPX_FORS_TREES_MAX / 8 + 1 + 8 + 4];
+ unsigned char *bufp;
+ unsigned char seed[64]; /* max SHA-512 output */
+ unsigned char *mgf_input;
+ unsigned long mgf_input_len, hlen;
+ hash_state md;
+ int hash_idx, err;
+
+ hash_idx = s_sha2_hash_idx(p);
+ if (hash_idx == -1) return CRYPT_INVALID_HASH;
+
+ hlen = hash_descriptor[hash_idx].hashsize;
+
+ tree_bits = p->tree_height * (p->d - 1);
+ tree_bytes = (tree_bits + 7) / 8;
+ leaf_bits = p->tree_height;
+ leaf_bytes = (leaf_bits + 7) / 8;
+ dgst_bytes = p->fors_msg_bytes + tree_bytes + leaf_bytes;
+
+ /* Step 1: seed = SHA-X(R || PK.seed || PK.root || M) */
+ if ((err = hash_descriptor[hash_idx].init(&md)) != CRYPT_OK) return err;
+ if ((err = hash_descriptor[hash_idx].process(&md, R, p->n)) != CRYPT_OK) return err;
+ if ((err = hash_descriptor[hash_idx].process(&md, pk, p->pk_bytes)) != CRYPT_OK) return err;
+ if ((err = hash_descriptor[hash_idx].process(&md, m, mlen)) != CRYPT_OK) return err;
+ if ((err = hash_descriptor[hash_idx].done(&md, seed)) != CRYPT_OK) return err;
+
+ /* Step 2: MGF1-SHA-X(R || PK.seed || seed, dgst_bytes) */
+ mgf_input_len = (unsigned long)p->n + (unsigned long)p->n + hlen;
+ mgf_input = XMALLOC(mgf_input_len);
+ if (mgf_input == NULL) return CRYPT_MEM;
+
+ XMEMCPY(mgf_input, R, p->n);
+ XMEMCPY(mgf_input + p->n, pk, p->n); /* PK.seed */
+ XMEMCPY(mgf_input + 2 * p->n, seed, hlen);
+
+ err = s_mgf1_sha2(buf, dgst_bytes, mgf_input, mgf_input_len, hash_idx);
+ XFREE(mgf_input);
+ zeromem(seed, sizeof(seed));
+ if (err != CRYPT_OK) return err;
+
+ /* Extract digest, tree index, and leaf index */
+ bufp = buf;
+ XMEMCPY(digest, bufp, p->fors_msg_bytes);
+ bufp += p->fors_msg_bytes;
+
+ if (p->d == 1) {
+ *tree = 0;
+ } else {
+ *tree = s_bytes_to_ull(bufp, tree_bytes);
+ *tree &= (~(ulong64)0) >> (64 - tree_bits);
+ }
+ bufp += tree_bytes;
+
+ *leaf_idx = (ulong32)s_bytes_to_ull(bufp, leaf_bytes);
+ *leaf_idx &= (~(ulong32)0) >> (32 - leaf_bits);
+
+ return CRYPT_OK;
+}
+
+/* ========================================================================= */
+/* Dispatch wrappers */
+/* ========================================================================= */
+
+static int s_thash(unsigned char *out, const unsigned char *in,
+ unsigned int inblocks, const unsigned char *pub_seed,
+ unsigned char addr[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ if (p->is_shake)
+ return s_thash_shake(out, in, inblocks, pub_seed, addr, p);
+ else
+ return s_thash_sha2(out, in, inblocks, pub_seed, addr, p);
+}
+
+static int s_prf_addr(unsigned char *out, const unsigned char *pub_seed,
+ const unsigned char *sk_seed,
+ unsigned char addr[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ if (p->is_shake)
+ return s_prf_addr_shake(out, pub_seed, sk_seed, addr, p);
+ else
+ return s_prf_addr_sha2(out, pub_seed, sk_seed, addr, p);
+}
+
+static int s_gen_message_random(unsigned char *R,
+ const unsigned char *sk_prf,
+ const unsigned char *optrand,
+ const unsigned char *m, unsigned long mlen,
+ const slhdsa_params *p)
+{
+ if (p->is_shake)
+ return s_gen_message_random_shake(R, sk_prf, optrand, m, mlen, p);
+ else
+ return s_gen_message_random_sha2(R, sk_prf, optrand, m, mlen, p);
+}
+
+static int s_hash_message(unsigned char *digest, ulong64 *tree, ulong32 *leaf_idx,
+ const unsigned char *R, const unsigned char *pk,
+ const unsigned char *m, unsigned long mlen,
+ const slhdsa_params *p)
+{
+ if (p->is_shake)
+ return s_hash_message_shake(digest, tree, leaf_idx, R, pk, m, mlen, p);
+ else
+ return s_hash_message_sha2(digest, tree, leaf_idx, R, pk, m, mlen, p);
+}
+
+/* WOTS+ */
+
+/**
+ * Computes the chaining function.
+ * out and in have to be n-byte arrays.
+ * Interprets in as start-th value of the chain.
+ */
+static int s_gen_chain(unsigned char *out, const unsigned char *in,
+ unsigned int start, unsigned int steps,
+ const unsigned char *pub_seed,
+ unsigned char addr[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ ulong32 i;
+ int err;
+
+ XMEMCPY(out, in, p->n);
+
+ for (i = start; i < (start + steps) && i < p->wots_w; i++) {
+ s_set_hash_addr(addr, i, p);
+ if ((err = s_thash(out, out, 1, pub_seed, addr, p)) != CRYPT_OK) return err;
+ }
+ return CRYPT_OK;
+}
+
+/**
+ * base_w algorithm: interprets an array of bytes as integers in base w.
+ */
+static void s_base_w(unsigned int *output, int out_len,
+ const unsigned char *input, const slhdsa_params *p)
+{
+ int in_idx = 0;
+ int out_idx = 0;
+ unsigned char total;
+ int bits = 0;
+ int consumed;
+
+ (void)p;
+
+ for (consumed = 0; consumed < out_len; consumed++) {
+ if (bits == 0) {
+ total = input[in_idx];
+ in_idx++;
+ bits += 8;
+ }
+ bits -= SPX_WOTS_LOGW;
+ output[out_idx] = (total >> bits) & (SPX_WOTS_W - 1);
+ out_idx++;
+ }
+}
+
+/**
+ * Computes the WOTS+ checksum over a message (in base_w).
+ */
+static void s_wots_checksum(unsigned int *csum_base_w,
+ const unsigned int *msg_base_w,
+ const slhdsa_params *p)
+{
+ unsigned int csum = 0;
+ unsigned char csum_bytes[(SPX_WOTS_LEN_MAX * SPX_WOTS_LOGW + 7) / 8];
+ unsigned int i;
+ unsigned int csum_bytes_len;
+
+ for (i = 0; i < p->wots_len1; i++) {
+ csum += SPX_WOTS_W - 1 - msg_base_w[i];
+ }
+
+ /* Convert checksum to base_w. */
+ csum = csum << ((8 - ((p->wots_len2 * SPX_WOTS_LOGW) % 8)) % 8);
+ csum_bytes_len = (p->wots_len2 * SPX_WOTS_LOGW + 7) / 8;
+ s_ull_to_bytes(csum_bytes, csum_bytes_len, csum);
+ s_base_w(csum_base_w, (int)p->wots_len2, csum_bytes, p);
+}
+
+/**
+ * Takes a message and derives the matching chain lengths.
+ */
+static void s_chain_lengths(unsigned int *lengths, const unsigned char *msg,
+ const slhdsa_params *p)
+{
+ s_base_w(lengths, (int)p->wots_len1, msg, p);
+ s_wots_checksum(lengths + p->wots_len1, lengths, p);
+}
+
+/**
+ * Takes a WOTS signature and an n-byte message, computes a WOTS public key.
+ */
+static int s_wots_pk_from_sig(unsigned char *pk,
+ const unsigned char *sig,
+ const unsigned char *msg,
+ const unsigned char *pub_seed,
+ unsigned char addr[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ unsigned int lengths[SPX_WOTS_LEN_MAX];
+ ulong32 i;
+ int err;
+
+ s_chain_lengths(lengths, msg, p);
+
+ for (i = 0; i < p->wots_len; i++) {
+ s_set_chain_addr(addr, i, p);
+ if ((err = s_gen_chain(pk + (unsigned long)i * p->n,
+ sig + (unsigned long)i * p->n,
+ lengths[i], SPX_WOTS_W - 1 - lengths[i],
+ pub_seed, addr, p)) != CRYPT_OK) return err;
+ }
+ return CRYPT_OK;
+}
+
+/**
+ * Generate a WOTS leaf node (public key hash).
+ * This also generates the WOTS signature if wots_sign_leaf matches leaf_idx.
+ *
+ * This function corresponds to wots_gen_leafx1 from the reference implementation.
+ *
+ * @param dest [out] The computed leaf node (n bytes)
+ * @param pub_seed The public seed
+ * @param sk_seed The secret seed
+ * @param leaf_idx Current leaf index
+ * @param wots_sig [out] If not NULL and leaf_idx == wots_sign_leaf, the WOTS sig is written here
+ * @param wots_sign_leaf The leaf index to sign with (~0 if not signing)
+ * @param wots_steps Chain lengths for the message being signed
+ * @param leaf_addr Working WOTS address
+ * @param pk_addr Working WOTS-PK address
+ * @param p Parameter set
+ */
+static int s_wots_gen_leaf(unsigned char *dest,
+ const unsigned char *pub_seed,
+ const unsigned char *sk_seed,
+ ulong32 leaf_idx,
+ unsigned char *wots_sig,
+ ulong32 wots_sign_leaf,
+ const unsigned int *wots_steps,
+ unsigned char leaf_addr[SPX_ADDR_BYTES],
+ unsigned char pk_addr[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ unsigned int i, k;
+ unsigned char pk_buffer[SPX_WOTS_BYTES_MAX];
+ unsigned char *buffer;
+ ulong32 wots_k_mask;
+ int err;
+
+ if (leaf_idx == wots_sign_leaf) {
+ wots_k_mask = 0;
+ } else {
+ wots_k_mask = (ulong32)~0;
+ }
+
+ s_set_keypair_addr(leaf_addr, leaf_idx, p);
+ s_set_keypair_addr(pk_addr, leaf_idx, p);
+
+ for (i = 0, buffer = pk_buffer; i < p->wots_len; i++, buffer += p->n) {
+ ulong32 wots_k = (wots_steps != NULL) ? (wots_steps[i] | wots_k_mask) : ((ulong32)~0);
+
+ /* Start with the secret seed */
+ s_set_chain_addr(leaf_addr, i, p);
+ s_set_hash_addr(leaf_addr, 0, p);
+ s_set_type(leaf_addr, SPX_ADDR_TYPE_WOTSPRF, p);
+
+ if ((err = s_prf_addr(buffer, pub_seed, sk_seed, leaf_addr, p)) != CRYPT_OK)
+ return err;
+
+ s_set_type(leaf_addr, SPX_ADDR_TYPE_WOTS, p);
+
+ /* Iterate down the WOTS chain */
+ for (k = 0; ; k++) {
+ /* Check if this is the value that needs to be saved as a
+ part of the WOTS signature */
+ if (k == wots_k && wots_sig != NULL) {
+ XMEMCPY(wots_sig + (unsigned long)i * p->n, buffer, p->n);
+ }
+
+ /* Check if we hit the top of the chain */
+ if (k == SPX_WOTS_W - 1) break;
+
+ /* Iterate one step on the chain */
+ s_set_hash_addr(leaf_addr, k, p);
+ if ((err = s_thash(buffer, buffer, 1, pub_seed, leaf_addr, p)) != CRYPT_OK)
+ return err;
+ }
+ }
+
+ /* Do the final thash to generate the public key */
+ return s_thash(dest, pk_buffer, p->wots_len, pub_seed, pk_addr, p);
+}
+
+/* Tree operations */
+
+/**
+ * Computes a root node given a leaf and an auth path.
+ */
+static int s_compute_root(unsigned char *root, const unsigned char *leaf,
+ ulong32 leaf_idx, ulong32 idx_offset,
+ const unsigned char *auth_path, ulong32 tree_height,
+ const unsigned char *pub_seed,
+ unsigned char addr[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ ulong32 i;
+ unsigned char buffer[2 * SPX_N_MAX];
+ int err;
+
+ if (leaf_idx & 1) {
+ XMEMCPY(buffer + p->n, leaf, p->n);
+ XMEMCPY(buffer, auth_path, p->n);
+ } else {
+ XMEMCPY(buffer, leaf, p->n);
+ XMEMCPY(buffer + p->n, auth_path, p->n);
+ }
+ auth_path += p->n;
+
+ for (i = 0; i < tree_height - 1; i++) {
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ s_set_tree_height(addr, i + 1, p);
+ s_set_tree_index(addr, leaf_idx + idx_offset, p);
+
+ if (leaf_idx & 1) {
+ if ((err = s_thash(buffer + p->n, buffer, 2, pub_seed, addr, p)) != CRYPT_OK) return err;
+ XMEMCPY(buffer, auth_path, p->n);
+ } else {
+ if ((err = s_thash(buffer, buffer, 2, pub_seed, addr, p)) != CRYPT_OK) return err;
+ XMEMCPY(buffer + p->n, auth_path, p->n);
+ }
+ auth_path += p->n;
+ }
+
+ leaf_idx >>= 1;
+ idx_offset >>= 1;
+ s_set_tree_height(addr, tree_height, p);
+ s_set_tree_index(addr, leaf_idx + idx_offset, p);
+ return s_thash(root, buffer, 2, pub_seed, addr, p);
+}
+
+/**
+ * For a given leaf index, computes the authentication path and the resulting
+ * root node using Merkle's TreeHash algorithm.
+ *
+ * This is the treehashx1 variant that supports generating WOTS signatures
+ * during traversal (needed by merkle_sign).
+ *
+ * @param root [out] Root of the tree (n bytes)
+ * @param auth_path [out] Authentication path (tree_height * n bytes)
+ * @param pub_seed Public seed
+ * @param sk_seed Secret seed
+ * @param leaf_idx Target leaf index
+ * @param idx_offset Offset applied to leaf indices
+ * @param tree_height Height of the tree
+ * @param tree_addr Address structure for the tree
+ * @param wots_sig [out] If not NULL, WOTS signature for wots_sign_leaf
+ * @param wots_sign_leaf Leaf to sign with (~0 if not signing)
+ * @param wots_steps Chain lengths for signing
+ * @param wots_addr Working WOTS address (for leaf generation)
+ * @param p Parameter set
+ */
+static int s_treehashx1(unsigned char *root, unsigned char *auth_path,
+ const unsigned char *pub_seed,
+ const unsigned char *sk_seed,
+ ulong32 leaf_idx, ulong32 idx_offset,
+ ulong32 tree_height,
+ unsigned char tree_addr[SPX_ADDR_BYTES],
+ unsigned char *wots_sig,
+ ulong32 wots_sign_leaf,
+ const unsigned int *wots_steps,
+ unsigned char wots_addr[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ unsigned char *stack;
+ ulong32 idx;
+ ulong32 max_idx = ((ulong32)1 << tree_height) - 1;
+ int err;
+
+ /* Allocate stack: tree_height * n bytes for intermediate nodes */
+ stack = XMALLOC((unsigned long)tree_height * p->n);
+ if (stack == NULL) return CRYPT_MEM;
+
+ for (idx = 0; ; idx++) {
+ unsigned char current[2 * SPX_N_MAX];
+ unsigned char leaf_addr[SPX_ADDR_BYTES];
+ unsigned char pk_addr[SPX_ADDR_BYTES];
+
+ XMEMSET(leaf_addr, 0, SPX_ADDR_BYTES);
+ XMEMSET(pk_addr, 0, SPX_ADDR_BYTES);
+
+ s_copy_subtree_addr(leaf_addr, wots_addr, p);
+ s_copy_subtree_addr(pk_addr, wots_addr, p);
+ s_set_type(pk_addr, SPX_ADDR_TYPE_WOTSPK, p);
+
+ /* Generate the leaf node */
+ err = s_wots_gen_leaf(¤t[p->n], pub_seed, sk_seed,
+ idx + idx_offset,
+ wots_sig, wots_sign_leaf, wots_steps,
+ leaf_addr, pk_addr, p);
+ if (err != CRYPT_OK) { XFREE(stack); return err; }
+
+ /* Combine with previously generated nodes */
+ {
+ ulong32 internal_idx_offset = idx_offset;
+ ulong32 internal_idx = idx;
+ ulong32 internal_leaf = leaf_idx;
+ ulong32 h;
+
+ for (h = 0; ; h++, internal_idx >>= 1, internal_leaf >>= 1) {
+ if (h == tree_height) {
+ XMEMCPY(root, ¤t[p->n], p->n);
+ XFREE(stack);
+ return CRYPT_OK;
+ }
+
+ if ((internal_idx ^ internal_leaf) == 0x01) {
+ XMEMCPY(&auth_path[h * p->n], ¤t[p->n], p->n);
+ }
+
+ if ((internal_idx & 1) == 0 && idx < max_idx) {
+ break;
+ }
+
+ /* Combine left and right nodes */
+ internal_idx_offset >>= 1;
+ s_set_tree_height(tree_addr, h + 1, p);
+ s_set_tree_index(tree_addr, internal_idx / 2 + internal_idx_offset, p);
+
+ XMEMCPY(¤t[0], &stack[h * p->n], p->n);
+ err = s_thash(¤t[p->n], ¤t[0], 2, pub_seed, tree_addr, p);
+ if (err != CRYPT_OK) { XFREE(stack); return err; }
+ }
+
+ XMEMCPY(&stack[h * p->n], ¤t[p->n], p->n);
+ }
+ }
+}
+
+/**
+ * Simplified treehash for FORS: uses a callback-style leaf generation.
+ * This version generates FORS leaf nodes directly.
+ *
+ * @param root [out] Root of the tree (n bytes)
+ * @param auth_path [out] Authentication path
+ * @param pub_seed Public seed
+ * @param sk_seed Secret seed
+ * @param leaf_idx Target leaf index
+ * @param idx_offset Offset applied to leaf indices
+ * @param tree_height Height of the tree
+ * @param tree_addr Address structure for the tree
+ * @param fors_leaf_addr FORS leaf address
+ * @param p Parameter set
+ */
+static int s_treehash_fors(unsigned char *root, unsigned char *auth_path,
+ const unsigned char *pub_seed,
+ const unsigned char *sk_seed,
+ ulong32 leaf_idx, ulong32 idx_offset,
+ ulong32 tree_height,
+ unsigned char tree_addr[SPX_ADDR_BYTES],
+ unsigned char fors_leaf_addr[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ unsigned char *stack;
+ ulong32 idx;
+ ulong32 max_idx = ((ulong32)1 << tree_height) - 1;
+ int err;
+
+ stack = XMALLOC((unsigned long)tree_height * p->n);
+ if (stack == NULL) return CRYPT_MEM;
+
+ for (idx = 0; ; idx++) {
+ unsigned char current[2 * SPX_N_MAX];
+
+ /* Generate the FORS leaf */
+ s_set_tree_index(fors_leaf_addr, idx + idx_offset, p);
+ s_set_type(fors_leaf_addr, SPX_ADDR_TYPE_FORSPRF, p);
+ if ((err = s_prf_addr(¤t[p->n], pub_seed, sk_seed, fors_leaf_addr, p)) != CRYPT_OK) {
+ XFREE(stack);
+ return err;
+ }
+
+ s_set_type(fors_leaf_addr, SPX_ADDR_TYPE_FORSTREE, p);
+ if ((err = s_thash(¤t[p->n], ¤t[p->n], 1, pub_seed, fors_leaf_addr, p)) != CRYPT_OK) {
+ XFREE(stack);
+ return err;
+ }
+
+ /* Combine with previously generated nodes */
+ {
+ ulong32 internal_idx_offset = idx_offset;
+ ulong32 internal_idx = idx;
+ ulong32 internal_leaf = leaf_idx;
+ ulong32 h;
+
+ for (h = 0; ; h++, internal_idx >>= 1, internal_leaf >>= 1) {
+ if (h == tree_height) {
+ XMEMCPY(root, ¤t[p->n], p->n);
+ XFREE(stack);
+ return CRYPT_OK;
+ }
+
+ if ((internal_idx ^ internal_leaf) == 0x01) {
+ XMEMCPY(&auth_path[h * p->n], ¤t[p->n], p->n);
+ }
+
+ if ((internal_idx & 1) == 0 && idx < max_idx) {
+ break;
+ }
+
+ internal_idx_offset >>= 1;
+ s_set_tree_height(tree_addr, h + 1, p);
+ s_set_tree_index(tree_addr, internal_idx / 2 + internal_idx_offset, p);
+
+ XMEMCPY(¤t[0], &stack[h * p->n], p->n);
+ err = s_thash(¤t[p->n], ¤t[0], 2, pub_seed, tree_addr, p);
+ if (err != CRYPT_OK) { XFREE(stack); return err; }
+ }
+
+ XMEMCPY(&stack[h * p->n], ¤t[p->n], p->n);
+ }
+ }
+}
+
+/* FORS */
+
+/**
+ * Interprets m as fors_height-bit unsigned integers.
+ */
+static void s_message_to_indices(ulong32 *indices, const unsigned char *m,
+ const slhdsa_params *p)
+{
+ unsigned int i, j;
+ unsigned int offset = 0;
+
+ for (i = 0; i < p->fors_trees; i++) {
+ indices[i] = 0;
+ for (j = 0; j < p->fors_height; j++) {
+ indices[i] ^= (((ulong32)(m[offset >> 3] >> (offset & 0x7))) & 1u) << j;
+ offset++;
+ }
+ }
+}
+
+/**
+ * Signs a message m, deriving the secret key from sk_seed and the FTS address.
+ */
+static int s_fors_sign(unsigned char *sig, unsigned char *pk,
+ const unsigned char *m,
+ const unsigned char *pub_seed,
+ const unsigned char *sk_seed,
+ const unsigned char fors_addr[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ ulong32 indices[SPX_FORS_TREES_MAX];
+ unsigned char *roots;
+ unsigned char fors_tree_addr[SPX_ADDR_BYTES];
+ unsigned char fors_leaf_addr[SPX_ADDR_BYTES];
+ unsigned char fors_pk_addr[SPX_ADDR_BYTES];
+ ulong32 idx_offset;
+ unsigned int i;
+ int err;
+
+ roots = XMALLOC((unsigned long)p->fors_trees * p->n);
+ if (roots == NULL) return CRYPT_MEM;
+
+ XMEMSET(fors_tree_addr, 0, SPX_ADDR_BYTES);
+ XMEMSET(fors_leaf_addr, 0, SPX_ADDR_BYTES);
+ XMEMSET(fors_pk_addr, 0, SPX_ADDR_BYTES);
+
+ s_copy_keypair_addr(fors_tree_addr, fors_addr, p);
+ s_copy_keypair_addr(fors_leaf_addr, fors_addr, p);
+ s_copy_keypair_addr(fors_pk_addr, fors_addr, p);
+ s_set_type(fors_pk_addr, SPX_ADDR_TYPE_FORSPK, p);
+
+ s_message_to_indices(indices, m, p);
+
+ for (i = 0; i < p->fors_trees; i++) {
+ idx_offset = i * ((ulong32)1 << p->fors_height);
+
+ s_set_tree_height(fors_tree_addr, 0, p);
+ s_set_tree_index(fors_tree_addr, indices[i] + idx_offset, p);
+ s_set_type(fors_tree_addr, SPX_ADDR_TYPE_FORSPRF, p);
+
+ /* Include the secret key part that produces the selected leaf node. */
+ if ((err = s_prf_addr(sig, pub_seed, sk_seed, fors_tree_addr, p)) != CRYPT_OK) {
+ XFREE(roots);
+ return err;
+ }
+ s_set_type(fors_tree_addr, SPX_ADDR_TYPE_FORSTREE, p);
+ sig += p->n;
+
+ /* Compute the authentication path for this leaf node. */
+ err = s_treehash_fors(roots + (unsigned long)i * p->n, sig,
+ pub_seed, sk_seed,
+ indices[i], idx_offset, p->fors_height,
+ fors_tree_addr, fors_leaf_addr, p);
+ if (err != CRYPT_OK) {
+ XFREE(roots);
+ return err;
+ }
+
+ sig += (unsigned long)p->n * p->fors_height;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ err = s_thash(pk, roots, p->fors_trees, pub_seed, fors_pk_addr, p);
+ XFREE(roots);
+ return err;
+}
+
+/**
+ * Derives the FORS public key from a signature.
+ */
+static int s_fors_pk_from_sig(unsigned char *pk,
+ const unsigned char *sig,
+ const unsigned char *m,
+ const unsigned char *pub_seed,
+ const unsigned char fors_addr[SPX_ADDR_BYTES],
+ const slhdsa_params *p)
+{
+ ulong32 indices[SPX_FORS_TREES_MAX];
+ unsigned char *roots;
+ unsigned char leaf[SPX_N_MAX];
+ unsigned char fors_tree_addr[SPX_ADDR_BYTES];
+ unsigned char fors_pk_addr[SPX_ADDR_BYTES];
+ ulong32 idx_offset;
+ unsigned int i;
+ int err;
+
+ roots = XMALLOC((unsigned long)p->fors_trees * p->n);
+ if (roots == NULL) return CRYPT_MEM;
+
+ XMEMSET(fors_tree_addr, 0, SPX_ADDR_BYTES);
+ XMEMSET(fors_pk_addr, 0, SPX_ADDR_BYTES);
+
+ s_copy_keypair_addr(fors_tree_addr, fors_addr, p);
+ s_copy_keypair_addr(fors_pk_addr, fors_addr, p);
+
+ s_set_type(fors_tree_addr, SPX_ADDR_TYPE_FORSTREE, p);
+ s_set_type(fors_pk_addr, SPX_ADDR_TYPE_FORSPK, p);
+
+ s_message_to_indices(indices, m, p);
+
+ for (i = 0; i < p->fors_trees; i++) {
+ idx_offset = i * ((ulong32)1 << p->fors_height);
+
+ s_set_tree_height(fors_tree_addr, 0, p);
+ s_set_tree_index(fors_tree_addr, indices[i] + idx_offset, p);
+
+ /* Derive the leaf from the included secret key part. */
+ err = s_thash(leaf, sig, 1, pub_seed, fors_tree_addr, p);
+ if (err != CRYPT_OK) { XFREE(roots); return err; }
+ sig += p->n;
+
+ /* Derive the corresponding root node of this tree. */
+ err = s_compute_root(roots + (unsigned long)i * p->n, leaf,
+ indices[i], idx_offset,
+ sig, p->fors_height, pub_seed, fors_tree_addr, p);
+ if (err != CRYPT_OK) { XFREE(roots); return err; }
+ sig += (unsigned long)p->n * p->fors_height;
+ }
+
+ /* Hash horizontally across all tree roots to derive the public key. */
+ err = s_thash(pk, roots, p->fors_trees, pub_seed, fors_pk_addr, p);
+ XFREE(roots);
+ return err;
+}
+
+/* Merkle */
+
+/**
+ * Generate a Merkle signature (WOTS signature followed by authentication path).
+ */
+static int s_merkle_sign(unsigned char *sig, unsigned char *root,
+ const unsigned char *pub_seed,
+ const unsigned char *sk_seed,
+ unsigned char wots_addr[SPX_ADDR_BYTES],
+ unsigned char tree_addr[SPX_ADDR_BYTES],
+ ulong32 idx_leaf,
+ const slhdsa_params *p)
+{
+ unsigned char *auth_path = sig + p->wots_bytes;
+ unsigned int steps[SPX_WOTS_LEN_MAX];
+
+ s_chain_lengths(steps, root, p);
+
+ s_set_type(tree_addr, SPX_ADDR_TYPE_HASHTREE, p);
+
+ return s_treehashx1(root, auth_path, pub_seed, sk_seed,
+ idx_leaf, 0, p->tree_height,
+ tree_addr, sig, idx_leaf, steps,
+ wots_addr, p);
+}
+
+/**
+ * Compute root node of the top-most subtree.
+ */
+static int s_merkle_gen_root(unsigned char *root,
+ const unsigned char *pub_seed,
+ const unsigned char *sk_seed,
+ const slhdsa_params *p)
+{
+ unsigned char auth_path[SPX_TREE_HEIGHT_MAX * SPX_N_MAX + SPX_WOTS_BYTES_MAX];
+ unsigned char top_tree_addr[SPX_ADDR_BYTES];
+ unsigned char wots_addr[SPX_ADDR_BYTES];
+
+ XMEMSET(top_tree_addr, 0, SPX_ADDR_BYTES);
+ XMEMSET(wots_addr, 0, SPX_ADDR_BYTES);
+
+ s_set_layer_addr(top_tree_addr, p->d - 1, p);
+ s_set_layer_addr(wots_addr, p->d - 1, p);
+
+ return s_merkle_sign(auth_path, root, pub_seed, sk_seed,
+ wots_addr, top_tree_addr,
+ (ulong32)~0, /* ~0 means "don't generate an auth path" */
+ p);
+}
+
+/* Sign / verify core */
+
+static int s_sign_core(unsigned char *sig, unsigned long *siglen,
+ const unsigned char *m, unsigned long mlen,
+ const unsigned char *sk,
+ const unsigned char *optrand,
+ const slhdsa_params *p)
+{
+ const unsigned char *sk_seed = sk;
+ const unsigned char *sk_prf = sk + p->n;
+ const unsigned char *pk = sk + 2 * p->n;
+ const unsigned char *pub_seed = pk;
+ unsigned char mhash[SPX_FORS_HEIGHT_MAX * SPX_FORS_TREES_MAX / 8 + 1];
+ unsigned char root[SPX_N_MAX];
+ ulong64 tree;
+ ulong32 idx_leaf;
+ unsigned char wots_addr[SPX_ADDR_BYTES];
+ unsigned char tree_addr[SPX_ADDR_BYTES];
+ ulong32 i;
+ int err;
+
+ XMEMSET(wots_addr, 0, SPX_ADDR_BYTES);
+ XMEMSET(tree_addr, 0, SPX_ADDR_BYTES);
+
+ s_set_type(wots_addr, SPX_ADDR_TYPE_WOTS, p);
+ s_set_type(tree_addr, SPX_ADDR_TYPE_HASHTREE, p);
+
+ /* Compute the digest randomization value R. */
+ if ((err = s_gen_message_random(sig, sk_prf, optrand, m, mlen, p)) != CRYPT_OK) return err;
+
+ /* Derive the message digest and leaf index from R, PK and M. */
+ if ((err = s_hash_message(mhash, &tree, &idx_leaf, sig, pk, m, mlen, p)) != CRYPT_OK) return err;
+ sig += p->n;
+
+ s_set_tree_addr(wots_addr, tree, p);
+ s_set_keypair_addr(wots_addr, idx_leaf, p);
+
+ /* Sign the message hash using FORS. */
+ if ((err = s_fors_sign(sig, root, mhash, pub_seed, sk_seed, wots_addr, p)) != CRYPT_OK) return err;
+ sig += p->fors_bytes;
+
+ for (i = 0; i < p->d; i++) {
+ s_set_layer_addr(tree_addr, i, p);
+ s_set_tree_addr(tree_addr, tree, p);
+
+ s_copy_subtree_addr(wots_addr, tree_addr, p);
+ s_set_keypair_addr(wots_addr, idx_leaf, p);
+
+ if ((err = s_merkle_sign(sig, root, pub_seed, sk_seed,
+ wots_addr, tree_addr, idx_leaf, p)) != CRYPT_OK) return err;
+ sig += p->wots_bytes + (unsigned long)p->tree_height * p->n;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (ulong32)(tree & (((ulong64)1 << p->tree_height) - 1));
+ tree = tree >> p->tree_height;
+ }
+
+ *siglen = p->sig_bytes;
+ return CRYPT_OK;
+}
+
+static int s_verify_core(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *m, unsigned long mlen,
+ const unsigned char *pk,
+ const slhdsa_params *p)
+{
+ const unsigned char *pub_seed = pk;
+ const unsigned char *pub_root = pk + p->n;
+ unsigned char mhash[SPX_FORS_HEIGHT_MAX * SPX_FORS_TREES_MAX / 8 + 1];
+ unsigned char wots_pk[SPX_WOTS_BYTES_MAX];
+ unsigned char root[SPX_N_MAX];
+ unsigned char leaf[SPX_N_MAX];
+ unsigned int i;
+ ulong64 tree;
+ ulong32 idx_leaf;
+ unsigned char wots_addr[SPX_ADDR_BYTES];
+ unsigned char tree_addr[SPX_ADDR_BYTES];
+ unsigned char wots_pk_addr[SPX_ADDR_BYTES];
+ int err;
+
+ if (siglen != p->sig_bytes) return CRYPT_INVALID_PACKET;
+
+ XMEMSET(wots_addr, 0, SPX_ADDR_BYTES);
+ XMEMSET(tree_addr, 0, SPX_ADDR_BYTES);
+ XMEMSET(wots_pk_addr, 0, SPX_ADDR_BYTES);
+
+ s_set_type(wots_addr, SPX_ADDR_TYPE_WOTS, p);
+ s_set_type(tree_addr, SPX_ADDR_TYPE_HASHTREE, p);
+ s_set_type(wots_pk_addr, SPX_ADDR_TYPE_WOTSPK, p);
+
+ /* Derive the message digest and leaf index from R || PK || M. */
+ if ((err = s_hash_message(mhash, &tree, &idx_leaf, sig, pk, m, mlen, p)) != CRYPT_OK) return err;
+ sig += p->n;
+
+ /* Layer correctly defaults to 0, so no need to set_layer_addr */
+ s_set_tree_addr(wots_addr, tree, p);
+ s_set_keypair_addr(wots_addr, idx_leaf, p);
+
+ if ((err = s_fors_pk_from_sig(root, sig, mhash, pub_seed, wots_addr, p)) != CRYPT_OK) return err;
+ sig += p->fors_bytes;
+
+ /* For each subtree.. */
+ for (i = 0; i < p->d; i++) {
+ s_set_layer_addr(tree_addr, i, p);
+ s_set_tree_addr(tree_addr, tree, p);
+
+ s_copy_subtree_addr(wots_addr, tree_addr, p);
+ s_set_keypair_addr(wots_addr, idx_leaf, p);
+
+ s_copy_keypair_addr(wots_pk_addr, wots_addr, p);
+
+ /* The WOTS public key is only correct if the signature was correct. */
+ if ((err = s_wots_pk_from_sig(wots_pk, sig, root, pub_seed, wots_addr, p)) != CRYPT_OK)
+ return err;
+ sig += p->wots_bytes;
+
+ /* Compute the leaf node using the WOTS public key. */
+ if ((err = s_thash(leaf, wots_pk, p->wots_len, pub_seed, wots_pk_addr, p)) != CRYPT_OK)
+ return err;
+
+ /* Compute the root node of this subtree. */
+ if ((err = s_compute_root(root, leaf, idx_leaf, 0, sig, p->tree_height,
+ pub_seed, tree_addr, p)) != CRYPT_OK) return err;
+ sig += (unsigned long)p->tree_height * p->n;
+
+ /* Update the indices for the next layer. */
+ idx_leaf = (ulong32)(tree & (((ulong64)1 << p->tree_height) - 1));
+ tree = tree >> p->tree_height;
+ }
+
+ /* Check if the root node equals the root node in the public key. */
+ {
+ unsigned int j;
+ unsigned char diff = 0;
+ for (j = 0; j < p->n; j++) {
+ diff |= root[j] ^ pub_root[j];
+ }
+ if (diff != 0) return CRYPT_INVALID_PACKET;
+ }
+
+ return CRYPT_OK;
+}
+
+/* Public API */
+
+/**
+ Generate an SLH-DSA key pair.
+ @param prng An active PRNG state
+ @param wprng The index of the desired PRNG
+ @param alg The parameter set (one of ltc_slhdsa_id)
+ @param key [out] Destination for the newly created key pair
+ @return CRYPT_OK if successful
+*/
+int slhdsa_make_key(prng_state *prng, int wprng, int alg, slhdsa_key *key)
+{
+ slhdsa_params p;
+ unsigned char seed[3 * SPX_N_MAX]; /* SK_SEED || SK_PRF || PUB_SEED */
+ int err;
+
+ LTC_ARGCHK(key != NULL);
+
+ if ((err = s_slhdsa_get_params(alg, &p)) != CRYPT_OK) return err;
+ if ((err = prng_is_valid(wprng)) != CRYPT_OK) return err;
+
+ /* Generate random seed: SK_SEED || SK_PRF || PUB_SEED */
+ if (prng_descriptor[wprng].read(seed, 3 * p.n, prng) != 3 * p.n)
+ return CRYPT_ERROR_READPRNG;
+
+ /* Allocate key storage:
+ * sk = [SK_SEED || SK_PRF || PUB_SEED || root] (4*n bytes)
+ * pk = [PUB_SEED || root] (2*n bytes) */
+ key->sk = XMALLOC(p.sk_bytes);
+ key->pk = XMALLOC(p.pk_bytes);
+ if (key->sk == NULL || key->pk == NULL) {
+ if (key->sk) { XFREE(key->sk); key->sk = NULL; }
+ if (key->pk) { XFREE(key->pk); key->pk = NULL; }
+ zeromem(seed, sizeof(seed));
+ return CRYPT_MEM;
+ }
+
+ /* Initialize SK_SEED, SK_PRF and PUB_SEED from seed. */
+ XMEMCPY(key->sk, seed, 3 * p.n);
+ XMEMCPY(key->pk, seed + 2 * p.n, p.n); /* PUB_SEED */
+
+ /* Compute root node of the top-most subtree. */
+ err = s_merkle_gen_root(key->sk + 3 * p.n, key->pk, key->sk, &p);
+ if (err != CRYPT_OK) {
+ zeromem(key->sk, p.sk_bytes);
+ XFREE(key->sk); key->sk = NULL;
+ XFREE(key->pk); key->pk = NULL;
+ zeromem(seed, sizeof(seed));
+ return err;
+ }
+
+ XMEMCPY(key->pk + p.n, key->sk + 3 * p.n, p.n); /* root */
+
+ key->alg = alg;
+ key->type = PK_PRIVATE;
+ key->pklen = p.pk_bytes;
+ key->sklen = p.sk_bytes;
+
+ zeromem(seed, sizeof(seed));
+ return CRYPT_OK;
+}
+
+/**
+ Free an SLH-DSA key from memory.
+ @param key The key to free
+*/
+void slhdsa_free(slhdsa_key *key)
+{
+ if (key == NULL) return;
+ if (key->sk != NULL) {
+ zeromem(key->sk, key->sklen);
+ XFREE(key->sk);
+ }
+ if (key->pk != NULL) {
+ XFREE(key->pk);
+ }
+ XMEMSET(key, 0, sizeof(*key));
+}
+
+/**
+ Export an SLH-DSA key to a byte buffer.
+ @param out [out] Destination for the exported key
+ @param outlen [in/out] Max size and resulting size of the exported key
+ @param which PK_PUBLIC for the verification key, PK_PRIVATE for the signing key
+ @param key The key to export
+ @return CRYPT_OK if successful
+*/
+int slhdsa_export_raw(unsigned char *out, unsigned long *outlen, int which, const slhdsa_key *key)
+{
+ slhdsa_params p;
+ unsigned long needed;
+ int err;
+
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if ((err = s_slhdsa_get_params(key->alg, &p)) != CRYPT_OK) return err;
+
+ if (which == PK_PUBLIC) {
+ needed = p.pk_bytes;
+ if (*outlen < needed) { *outlen = needed; return CRYPT_BUFFER_OVERFLOW; }
+ if (key->pk == NULL) return CRYPT_PK_NOT_PRIVATE;
+ XMEMCPY(out, key->pk, needed);
+ } else if (which == PK_PRIVATE) {
+ if (key->type != PK_PRIVATE) return CRYPT_PK_NOT_PRIVATE;
+ needed = p.sk_bytes;
+ if (*outlen < needed) { *outlen = needed; return CRYPT_BUFFER_OVERFLOW; }
+ XMEMCPY(out, key->sk, needed);
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ *outlen = needed;
+ return CRYPT_OK;
+}
+
+/**
+ Import an SLH-DSA key from a byte buffer.
+ @param in The buffer to import from
+ @param inlen Length of the buffer
+ @param which PK_PUBLIC for a verification key, PK_PRIVATE for a signing key
+ @param alg The parameter set (one of ltc_slhdsa_id)
+ @param key [out] Destination for the imported key
+ @return CRYPT_OK if successful
+*/
+int slhdsa_import_raw(const unsigned char *in, unsigned long inlen, int which, int alg, slhdsa_key *key)
+{
+ slhdsa_params p;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if ((err = s_slhdsa_get_params(alg, &p)) != CRYPT_OK) return err;
+
+ XMEMSET(key, 0, sizeof(*key));
+ key->alg = alg;
+
+ if (which == PK_PUBLIC) {
+ if (inlen != p.pk_bytes) return CRYPT_INVALID_PACKET;
+ key->pk = XMALLOC(p.pk_bytes);
+ if (key->pk == NULL) return CRYPT_MEM;
+ XMEMCPY(key->pk, in, p.pk_bytes);
+ key->pklen = p.pk_bytes;
+ key->type = PK_PUBLIC;
+ } else if (which == PK_PRIVATE) {
+ if (inlen != p.sk_bytes) return CRYPT_INVALID_PACKET;
+ key->sk = XMALLOC(p.sk_bytes);
+ if (key->sk == NULL) return CRYPT_MEM;
+ XMEMCPY(key->sk, in, p.sk_bytes);
+ key->sklen = p.sk_bytes;
+
+ /* Reconstruct pk from sk:
+ * sk = [SK_SEED || SK_PRF || PUB_SEED || root]
+ * pk = [PUB_SEED || root] */
+ key->pk = XMALLOC(p.pk_bytes);
+ if (key->pk == NULL) {
+ slhdsa_free(key);
+ return CRYPT_MEM;
+ }
+ XMEMCPY(key->pk, in + 2 * p.n, 2 * p.n); /* PUB_SEED || root */
+ key->pklen = p.pk_bytes;
+ key->type = PK_PRIVATE;
+ } else {
+ return CRYPT_INVALID_ARG;
+ }
+
+ return CRYPT_OK;
+}
+
+/**
+ Sign a message with SLH-DSA.
+ @param msg The message to sign
+ @param msglen Length of the message
+ @param sig [out] The signature
+ @param siglen [in/out] Max size and resulting size of the signature
+ @param ctx Optional context string (can be NULL if ctxlen is 0)
+ @param ctxlen Length of the context string (max 255 bytes per FIPS 205)
+ @param prng An active PRNG state (for hedged signing)
+ @param wprng The index of the desired PRNG
+ @param key The private (signing) key
+ @return CRYPT_OK if successful
+*/
+int slhdsa_sign(const unsigned char *msg, unsigned long msglen,
+ unsigned char *sig, unsigned long *siglen,
+ const unsigned char *ctx, unsigned long ctxlen,
+ prng_state *prng, int wprng,
+ const slhdsa_key *key)
+{
+ slhdsa_params p;
+ unsigned char optrand[SPX_N_MAX];
+ unsigned char *m_prime = NULL;
+ unsigned long m_prime_len;
+ int err;
+
+ LTC_ARGCHK(msg != NULL || msglen == 0);
+ LTC_ARGCHK(sig != NULL);
+ LTC_ARGCHK(siglen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if (key->type != PK_PRIVATE) return CRYPT_PK_NOT_PRIVATE;
+
+ if ((err = s_slhdsa_get_params(key->alg, &p)) != CRYPT_OK) return err;
+ if (*siglen < p.sig_bytes) { *siglen = p.sig_bytes; return CRYPT_BUFFER_OVERFLOW; }
+ if ((err = prng_is_valid(wprng)) != CRYPT_OK) return err;
+
+ if ((err = s_slhdsa_prepare_message(&m_prime, &m_prime_len,
+ msg, msglen, ctx, ctxlen, key->alg)) != CRYPT_OK) {
+ return err;
+ }
+
+ /* Hedged signing: generate random opt_rand */
+ if (prng_descriptor[wprng].read(optrand, p.n, prng) != p.n) {
+ XFREE(m_prime);
+ return CRYPT_ERROR_READPRNG;
+ }
+
+ err = s_sign_core(sig, siglen, m_prime, m_prime_len, key->sk, optrand, &p);
+
+ zeromem(optrand, sizeof(optrand));
+ XFREE(m_prime);
+ return err;
+}
+
+/**
+ Verify a signature with SLH-DSA.
+ @param sig The signature to verify
+ @param siglen Length of the signature
+ @param msg The message that was signed
+ @param msglen Length of the message
+ @param ctx Optional context string (can be NULL if ctxlen is 0)
+ @param ctxlen Length of the context string (max 255 bytes per FIPS 205)
+ @param stat [out] Result of the verification: 1==valid, 0==invalid
+ @param key The public (verification) key
+ @return CRYPT_OK if successful (even if the signature is invalid)
+*/
+int slhdsa_verify(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *msg, unsigned long msglen,
+ const unsigned char *ctx, unsigned long ctxlen,
+ int *stat,
+ const slhdsa_key *key)
+{
+ slhdsa_params p;
+ unsigned char *m_prime = NULL;
+ unsigned long m_prime_len;
+ int err;
+
+ LTC_ARGCHK(sig != NULL);
+ LTC_ARGCHK(msg != NULL || msglen == 0);
+ LTC_ARGCHK(stat != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ *stat = 0;
+
+ if (key->pk == NULL) return CRYPT_INVALID_ARG;
+
+ if ((err = s_slhdsa_get_params(key->alg, &p)) != CRYPT_OK) return err;
+
+ if ((err = s_slhdsa_prepare_message(&m_prime, &m_prime_len,
+ msg, msglen, ctx, ctxlen, key->alg)) != CRYPT_OK) {
+ return err;
+ }
+
+ err = s_verify_core(sig, siglen, m_prime, m_prime_len, key->pk, &p);
+ XFREE(m_prime);
+
+ if (err == CRYPT_OK)
+ *stat = 1;
+ else if (err == CRYPT_INVALID_PACKET)
+ err = CRYPT_OK; /* Verification failed but no internal error */
+
+ return err;
+}
+
+/**
+ Get the sizes for a given SLH-DSA parameter set.
+ Any output pointer may be NULL if the caller does not need that value.
+ @param alg The parameter set (one of ltc_slhdsa_id)
+ @param public_key_sz [out] Public key size in bytes
+ @param secret_key_sz [out] Secret key size in bytes
+ @param signature_sz [out] Signature size in bytes
+ @return CRYPT_OK if successful
+*/
+int slhdsa_get_sizes(int alg, unsigned long *public_key_sz, unsigned long *secret_key_sz,
+ unsigned long *signature_sz)
+{
+ slhdsa_params p;
+ int err;
+
+ if ((err = s_slhdsa_get_params(alg, &p)) != CRYPT_OK) return err;
+
+ if (public_key_sz != NULL) *public_key_sz = p.pk_bytes;
+ if (secret_key_sz != NULL) *secret_key_sz = p.sk_bytes;
+ if (signature_sz != NULL) *signature_sz = p.sig_bytes;
+
+ return CRYPT_OK;
+}
+
+#endif /* LTC_SLHDSA */
diff --git a/src/pqc/slhdsa_export.c b/src/pqc/slhdsa_export.c
new file mode 100644
index 000000000..7db9ad899
--- /dev/null
+++ b/src/pqc/slhdsa_export.c
@@ -0,0 +1,160 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_private.h"
+
+/**
+ @file slhdsa_export.c
+ Export a SLH-DSA key to a binary packet
+*/
+
+#ifdef LTC_SLHDSA
+
+static int s_slhdsa_alg_to_oid(int alg, enum ltc_oid_id *oid_id)
+{
+ LTC_ARGCHK(oid_id != NULL);
+
+ switch (alg) {
+ case LTC_SLHDSA_SHA2_128S:
+ *oid_id = LTC_OID_SLHDSA_SHA2_128S;
+ return CRYPT_OK;
+ case LTC_SLHDSA_SHA2_128F:
+ *oid_id = LTC_OID_SLHDSA_SHA2_128F;
+ return CRYPT_OK;
+ case LTC_SLHDSA_SHA2_192S:
+ *oid_id = LTC_OID_SLHDSA_SHA2_192S;
+ return CRYPT_OK;
+ case LTC_SLHDSA_SHA2_192F:
+ *oid_id = LTC_OID_SLHDSA_SHA2_192F;
+ return CRYPT_OK;
+ case LTC_SLHDSA_SHA2_256S:
+ *oid_id = LTC_OID_SLHDSA_SHA2_256S;
+ return CRYPT_OK;
+ case LTC_SLHDSA_SHA2_256F:
+ *oid_id = LTC_OID_SLHDSA_SHA2_256F;
+ return CRYPT_OK;
+ case LTC_SLHDSA_SHAKE_128S:
+ *oid_id = LTC_OID_SLHDSA_SHAKE_128S;
+ return CRYPT_OK;
+ case LTC_SLHDSA_SHAKE_128F:
+ *oid_id = LTC_OID_SLHDSA_SHAKE_128F;
+ return CRYPT_OK;
+ case LTC_SLHDSA_SHAKE_192S:
+ *oid_id = LTC_OID_SLHDSA_SHAKE_192S;
+ return CRYPT_OK;
+ case LTC_SLHDSA_SHAKE_192F:
+ *oid_id = LTC_OID_SLHDSA_SHAKE_192F;
+ return CRYPT_OK;
+ case LTC_SLHDSA_SHAKE_256S:
+ *oid_id = LTC_OID_SLHDSA_SHAKE_256S;
+ return CRYPT_OK;
+ case LTC_SLHDSA_SHAKE_256F:
+ *oid_id = LTC_OID_SLHDSA_SHAKE_256F;
+ return CRYPT_OK;
+ case LTC_SLHDSA_HASH_SHA2_128S_WITH_SHA256:
+ *oid_id = LTC_OID_HASH_SLHDSA_SHA2_128S_WITH_SHA256;
+ return CRYPT_OK;
+ case LTC_SLHDSA_HASH_SHA2_128F_WITH_SHA256:
+ *oid_id = LTC_OID_HASH_SLHDSA_SHA2_128F_WITH_SHA256;
+ return CRYPT_OK;
+ case LTC_SLHDSA_HASH_SHA2_192S_WITH_SHA512:
+ *oid_id = LTC_OID_HASH_SLHDSA_SHA2_192S_WITH_SHA512;
+ return CRYPT_OK;
+ case LTC_SLHDSA_HASH_SHA2_192F_WITH_SHA512:
+ *oid_id = LTC_OID_HASH_SLHDSA_SHA2_192F_WITH_SHA512;
+ return CRYPT_OK;
+ case LTC_SLHDSA_HASH_SHA2_256S_WITH_SHA512:
+ *oid_id = LTC_OID_HASH_SLHDSA_SHA2_256S_WITH_SHA512;
+ return CRYPT_OK;
+ case LTC_SLHDSA_HASH_SHA2_256F_WITH_SHA512:
+ *oid_id = LTC_OID_HASH_SLHDSA_SHA2_256F_WITH_SHA512;
+ return CRYPT_OK;
+ case LTC_SLHDSA_HASH_SHAKE_128S_WITH_SHAKE128:
+ *oid_id = LTC_OID_HASH_SLHDSA_SHAKE_128S_WITH_SHAKE128;
+ return CRYPT_OK;
+ case LTC_SLHDSA_HASH_SHAKE_128F_WITH_SHAKE128:
+ *oid_id = LTC_OID_HASH_SLHDSA_SHAKE_128F_WITH_SHAKE128;
+ return CRYPT_OK;
+ case LTC_SLHDSA_HASH_SHAKE_192S_WITH_SHAKE256:
+ *oid_id = LTC_OID_HASH_SLHDSA_SHAKE_192S_WITH_SHAKE256;
+ return CRYPT_OK;
+ case LTC_SLHDSA_HASH_SHAKE_192F_WITH_SHAKE256:
+ *oid_id = LTC_OID_HASH_SLHDSA_SHAKE_192F_WITH_SHAKE256;
+ return CRYPT_OK;
+ case LTC_SLHDSA_HASH_SHAKE_256S_WITH_SHAKE256:
+ *oid_id = LTC_OID_HASH_SLHDSA_SHAKE_256S_WITH_SHAKE256;
+ return CRYPT_OK;
+ case LTC_SLHDSA_HASH_SHAKE_256F_WITH_SHAKE256:
+ *oid_id = LTC_OID_HASH_SLHDSA_SHAKE_256F_WITH_SHAKE256;
+ return CRYPT_OK;
+ default:
+ return CRYPT_PK_INVALID_TYPE;
+ }
+}
+
+/**
+ Export a SLH-DSA key to a binary packet
+ @param out [out] The destination for the key
+ @param outlen [in/out] The max size and resulting size of the SLH-DSA key
+ @param which Which type of key (PK_PRIVATE, PK_PUBLIC|PK_STD or PK_PUBLIC)
+ @param key The key you wish to export
+ @return CRYPT_OK if successful
+*/
+int slhdsa_export(unsigned char *out, unsigned long *outlen,
+ int which, const slhdsa_key *key)
+{
+ int err, std;
+ enum ltc_oid_id oid_id;
+
+ LTC_ARGCHK(out != NULL);
+ LTC_ARGCHK(outlen != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ std = which & PK_STD;
+ which &= ~PK_STD;
+
+ if ((err = s_slhdsa_alg_to_oid(key->alg, &oid_id)) != CRYPT_OK) {
+ return err;
+ }
+
+ if (which == PK_PRIVATE) {
+ const char *OID;
+ unsigned long version, oid[16], oidlen;
+ ltc_asn1_list alg_id[1];
+
+ if (key->type != PK_PRIVATE || key->sk == NULL) return CRYPT_PK_INVALID_TYPE;
+
+ if (std != PK_STD) {
+ return slhdsa_export_raw(out, outlen, which, key);
+ }
+
+ if ((err = pk_get_oid(oid_id, &OID)) != CRYPT_OK) {
+ return err;
+ }
+ oidlen = LTC_ARRAY_SIZE(oid);
+ if ((err = pk_oid_str_to_num(OID, oid, &oidlen)) != CRYPT_OK) {
+ return err;
+ }
+ LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid, oidlen);
+ version = 0;
+ return der_encode_sequence_multi(out, outlen,
+ LTC_ASN1_SHORT_INTEGER, 1uL, &version,
+ LTC_ASN1_SEQUENCE, 1uL, alg_id,
+ LTC_ASN1_OCTET_STRING, key->sklen, key->sk,
+ LTC_ASN1_EOL, 0uL, NULL);
+ }
+
+ if (which != PK_PUBLIC) {
+ return CRYPT_INVALID_ARG;
+ }
+ if (key->pk == NULL) return CRYPT_PK_INVALID_TYPE;
+
+ if (std == PK_STD) {
+ return x509_encode_subject_public_key_info(out, outlen, oid_id,
+ key->pk, key->pklen,
+ LTC_ASN1_EOL, NULL, 0uL);
+ }
+
+ return slhdsa_export_raw(out, outlen, which, key);
+}
+
+#endif
diff --git a/src/pqc/slhdsa_import.c b/src/pqc/slhdsa_import.c
new file mode 100644
index 000000000..7b1256814
--- /dev/null
+++ b/src/pqc/slhdsa_import.c
@@ -0,0 +1,92 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_private.h"
+
+/**
+ @file slhdsa_import.c
+ Import a SLH-DSA key from a SubjectPublicKeyInfo
+*/
+
+#ifdef LTC_SLHDSA
+
+typedef struct {
+ enum ltc_oid_id oid;
+ int alg;
+} slhdsa_oid_map;
+
+static const slhdsa_oid_map s_slhdsa_oid_map[] = {
+ { LTC_OID_SLHDSA_SHA2_128S, LTC_SLHDSA_SHA2_128S },
+ { LTC_OID_SLHDSA_SHA2_128F, LTC_SLHDSA_SHA2_128F },
+ { LTC_OID_SLHDSA_SHA2_192S, LTC_SLHDSA_SHA2_192S },
+ { LTC_OID_SLHDSA_SHA2_192F, LTC_SLHDSA_SHA2_192F },
+ { LTC_OID_SLHDSA_SHA2_256S, LTC_SLHDSA_SHA2_256S },
+ { LTC_OID_SLHDSA_SHA2_256F, LTC_SLHDSA_SHA2_256F },
+ { LTC_OID_SLHDSA_SHAKE_128S, LTC_SLHDSA_SHAKE_128S },
+ { LTC_OID_SLHDSA_SHAKE_128F, LTC_SLHDSA_SHAKE_128F },
+ { LTC_OID_SLHDSA_SHAKE_192S, LTC_SLHDSA_SHAKE_192S },
+ { LTC_OID_SLHDSA_SHAKE_192F, LTC_SLHDSA_SHAKE_192F },
+ { LTC_OID_SLHDSA_SHAKE_256S, LTC_SLHDSA_SHAKE_256S },
+ { LTC_OID_SLHDSA_SHAKE_256F, LTC_SLHDSA_SHAKE_256F },
+ { LTC_OID_HASH_SLHDSA_SHA2_128S_WITH_SHA256, LTC_SLHDSA_HASH_SHA2_128S_WITH_SHA256 },
+ { LTC_OID_HASH_SLHDSA_SHA2_128F_WITH_SHA256, LTC_SLHDSA_HASH_SHA2_128F_WITH_SHA256 },
+ { LTC_OID_HASH_SLHDSA_SHA2_192S_WITH_SHA512, LTC_SLHDSA_HASH_SHA2_192S_WITH_SHA512 },
+ { LTC_OID_HASH_SLHDSA_SHA2_192F_WITH_SHA512, LTC_SLHDSA_HASH_SHA2_192F_WITH_SHA512 },
+ { LTC_OID_HASH_SLHDSA_SHA2_256S_WITH_SHA512, LTC_SLHDSA_HASH_SHA2_256S_WITH_SHA512 },
+ { LTC_OID_HASH_SLHDSA_SHA2_256F_WITH_SHA512, LTC_SLHDSA_HASH_SHA2_256F_WITH_SHA512 },
+ { LTC_OID_HASH_SLHDSA_SHAKE_128S_WITH_SHAKE128, LTC_SLHDSA_HASH_SHAKE_128S_WITH_SHAKE128 },
+ { LTC_OID_HASH_SLHDSA_SHAKE_128F_WITH_SHAKE128, LTC_SLHDSA_HASH_SHAKE_128F_WITH_SHAKE128 },
+ { LTC_OID_HASH_SLHDSA_SHAKE_192S_WITH_SHAKE256, LTC_SLHDSA_HASH_SHAKE_192S_WITH_SHAKE256 },
+ { LTC_OID_HASH_SLHDSA_SHAKE_192F_WITH_SHAKE256, LTC_SLHDSA_HASH_SHAKE_192F_WITH_SHAKE256 },
+ { LTC_OID_HASH_SLHDSA_SHAKE_256S_WITH_SHAKE256, LTC_SLHDSA_HASH_SHAKE_256S_WITH_SHAKE256 },
+ { LTC_OID_HASH_SLHDSA_SHAKE_256F_WITH_SHAKE256, LTC_SLHDSA_HASH_SHAKE_256F_WITH_SHAKE256 },
+};
+
+/**
+ Import a SLH-DSA public key
+ @param in The packet to read
+ @param inlen The length of the input packet
+ @param key [out] Where to import the key to
+ @return CRYPT_OK if successful, on error all allocated memory is freed automatically
+*/
+int slhdsa_import(const unsigned char *in, unsigned long inlen, slhdsa_key *key)
+{
+ unsigned char *pub;
+ unsigned long max_pub_len, pub_len;
+ unsigned long i;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ max_pub_len = 0;
+ for (i = 0; i < LTC_ARRAY_SIZE(s_slhdsa_oid_map); ++i) {
+ if ((err = slhdsa_get_sizes(s_slhdsa_oid_map[i].alg, &pub_len, NULL, NULL)) != CRYPT_OK) {
+ return err;
+ }
+ if (pub_len > max_pub_len) {
+ max_pub_len = pub_len;
+ }
+ }
+
+ pub = XMALLOC(max_pub_len);
+ if (pub == NULL) {
+ return CRYPT_MEM;
+ }
+
+ err = CRYPT_PK_INVALID_TYPE;
+ for (i = 0; i < LTC_ARRAY_SIZE(s_slhdsa_oid_map); ++i) {
+ pub_len = max_pub_len;
+ err = x509_decode_subject_public_key_info(in, inlen, s_slhdsa_oid_map[i].oid,
+ pub, &pub_len,
+ LTC_ASN1_EOL, NULL, 0uL);
+ if (err == CRYPT_OK) {
+ err = slhdsa_import_raw(pub, pub_len, PK_PUBLIC, s_slhdsa_oid_map[i].alg, key);
+ break;
+ }
+ }
+
+ XFREE(pub);
+ return err;
+}
+
+#endif
diff --git a/src/pqc/slhdsa_import_pkcs8.c b/src/pqc/slhdsa_import_pkcs8.c
new file mode 100644
index 000000000..a69ce8c73
--- /dev/null
+++ b/src/pqc/slhdsa_import_pkcs8.c
@@ -0,0 +1,178 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_private.h"
+
+/**
+ @file slhdsa_import_pkcs8.c
+ Import a SLH-DSA key in PKCS#8 format
+*/
+
+#ifdef LTC_SLHDSA
+
+static int s_slhdsa_oid_to_alg(enum ltc_oid_id oid_id, int *alg)
+{
+ LTC_ARGCHK(alg != NULL);
+
+ switch (oid_id) {
+ case LTC_OID_SLHDSA_SHA2_128S:
+ *alg = LTC_SLHDSA_SHA2_128S;
+ return CRYPT_OK;
+ case LTC_OID_SLHDSA_SHA2_128F:
+ *alg = LTC_SLHDSA_SHA2_128F;
+ return CRYPT_OK;
+ case LTC_OID_SLHDSA_SHA2_192S:
+ *alg = LTC_SLHDSA_SHA2_192S;
+ return CRYPT_OK;
+ case LTC_OID_SLHDSA_SHA2_192F:
+ *alg = LTC_SLHDSA_SHA2_192F;
+ return CRYPT_OK;
+ case LTC_OID_SLHDSA_SHA2_256S:
+ *alg = LTC_SLHDSA_SHA2_256S;
+ return CRYPT_OK;
+ case LTC_OID_SLHDSA_SHA2_256F:
+ *alg = LTC_SLHDSA_SHA2_256F;
+ return CRYPT_OK;
+ case LTC_OID_SLHDSA_SHAKE_128S:
+ *alg = LTC_SLHDSA_SHAKE_128S;
+ return CRYPT_OK;
+ case LTC_OID_SLHDSA_SHAKE_128F:
+ *alg = LTC_SLHDSA_SHAKE_128F;
+ return CRYPT_OK;
+ case LTC_OID_SLHDSA_SHAKE_192S:
+ *alg = LTC_SLHDSA_SHAKE_192S;
+ return CRYPT_OK;
+ case LTC_OID_SLHDSA_SHAKE_192F:
+ *alg = LTC_SLHDSA_SHAKE_192F;
+ return CRYPT_OK;
+ case LTC_OID_SLHDSA_SHAKE_256S:
+ *alg = LTC_SLHDSA_SHAKE_256S;
+ return CRYPT_OK;
+ case LTC_OID_SLHDSA_SHAKE_256F:
+ *alg = LTC_SLHDSA_SHAKE_256F;
+ return CRYPT_OK;
+ case LTC_OID_HASH_SLHDSA_SHA2_128S_WITH_SHA256:
+ *alg = LTC_SLHDSA_HASH_SHA2_128S_WITH_SHA256;
+ return CRYPT_OK;
+ case LTC_OID_HASH_SLHDSA_SHA2_128F_WITH_SHA256:
+ *alg = LTC_SLHDSA_HASH_SHA2_128F_WITH_SHA256;
+ return CRYPT_OK;
+ case LTC_OID_HASH_SLHDSA_SHA2_192S_WITH_SHA512:
+ *alg = LTC_SLHDSA_HASH_SHA2_192S_WITH_SHA512;
+ return CRYPT_OK;
+ case LTC_OID_HASH_SLHDSA_SHA2_192F_WITH_SHA512:
+ *alg = LTC_SLHDSA_HASH_SHA2_192F_WITH_SHA512;
+ return CRYPT_OK;
+ case LTC_OID_HASH_SLHDSA_SHA2_256S_WITH_SHA512:
+ *alg = LTC_SLHDSA_HASH_SHA2_256S_WITH_SHA512;
+ return CRYPT_OK;
+ case LTC_OID_HASH_SLHDSA_SHA2_256F_WITH_SHA512:
+ *alg = LTC_SLHDSA_HASH_SHA2_256F_WITH_SHA512;
+ return CRYPT_OK;
+ case LTC_OID_HASH_SLHDSA_SHAKE_128S_WITH_SHAKE128:
+ *alg = LTC_SLHDSA_HASH_SHAKE_128S_WITH_SHAKE128;
+ return CRYPT_OK;
+ case LTC_OID_HASH_SLHDSA_SHAKE_128F_WITH_SHAKE128:
+ *alg = LTC_SLHDSA_HASH_SHAKE_128F_WITH_SHAKE128;
+ return CRYPT_OK;
+ case LTC_OID_HASH_SLHDSA_SHAKE_192S_WITH_SHAKE256:
+ *alg = LTC_SLHDSA_HASH_SHAKE_192S_WITH_SHAKE256;
+ return CRYPT_OK;
+ case LTC_OID_HASH_SLHDSA_SHAKE_192F_WITH_SHAKE256:
+ *alg = LTC_SLHDSA_HASH_SHAKE_192F_WITH_SHAKE256;
+ return CRYPT_OK;
+ case LTC_OID_HASH_SLHDSA_SHAKE_256S_WITH_SHAKE256:
+ *alg = LTC_SLHDSA_HASH_SHAKE_256S_WITH_SHAKE256;
+ return CRYPT_OK;
+ case LTC_OID_HASH_SLHDSA_SHAKE_256F_WITH_SHAKE256:
+ *alg = LTC_SLHDSA_HASH_SHAKE_256F_WITH_SHAKE256;
+ return CRYPT_OK;
+ default:
+ return CRYPT_PK_INVALID_TYPE;
+ }
+}
+
+int slhdsa_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, slhdsa_key *key)
+{
+ enum ltc_oid_id oid_id;
+ int alg, err;
+ unsigned char *raw_buf = NULL;
+ unsigned long key_len, raw_buf_len;
+
+ LTC_ARGCHK(alg_id != NULL);
+ LTC_ARGCHK(priv_key != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ if ((err = pk_get_oid_from_asn1(alg_id->child, &oid_id)) != CRYPT_OK) {
+ return err;
+ }
+ if ((err = s_slhdsa_oid_to_alg(oid_id, &alg)) != CRYPT_OK) {
+ return err;
+ }
+
+ if ((err = slhdsa_get_sizes(alg, NULL, &key_len, NULL)) != CRYPT_OK) {
+ return err;
+ }
+ if (priv_key->size == key_len) {
+ return slhdsa_import_raw(priv_key->data, priv_key->size, PK_PRIVATE, alg, key);
+ }
+
+ raw_buf = XMALLOC(key_len);
+ if (raw_buf == NULL) {
+ return CRYPT_MEM;
+ }
+ raw_buf_len = key_len;
+ err = der_decode_octet_string(priv_key->data, priv_key->size, raw_buf, &raw_buf_len);
+ if (err == CRYPT_OK) {
+ err = (raw_buf_len == key_len)
+ ? slhdsa_import_raw(raw_buf, raw_buf_len, PK_PRIVATE, alg, key)
+ : CRYPT_INVALID_PACKET;
+ }
+ XFREE(raw_buf);
+ if (err != CRYPT_OK) {
+ return err;
+ }
+
+ return CRYPT_OK;
+}
+
+/**
+ Import a SLH-DSA private key in PKCS#8 format
+ @param in The packet to import from
+ @param inlen It's length (octets)
+ @param pw_ctx The password context when decrypting the private key
+ @param key [out] Destination for newly imported key
+ @return CRYPT_OK if successful, on error all allocated memory is freed automatically
+*/
+int slhdsa_import_pkcs8(const unsigned char *in, unsigned long inlen, const password_ctx *pw_ctx, slhdsa_key *key)
+{
+ int alg, err;
+ ltc_asn1_list *l = NULL;
+ ltc_asn1_list *alg_id, *priv_key;
+ enum ltc_oid_id oid_id;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ err = pkcs8_decode_flexi(in, inlen, pw_ctx, &l);
+ if (err != CRYPT_OK) {
+ return err;
+ }
+
+ if ((err = pkcs8_get_children(l, &oid_id, &alg_id, &priv_key)) != CRYPT_OK) {
+ goto cleanup;
+ }
+ err = s_slhdsa_oid_to_alg(oid_id, &alg);
+ if (err != CRYPT_OK) {
+ err = CRYPT_INVALID_PACKET;
+ goto cleanup;
+ }
+ LTC_UNUSED_PARAM(alg);
+
+ err = slhdsa_import_pkcs8_asn1(alg_id, priv_key, key);
+
+cleanup:
+ der_free_sequence_flexi(l);
+ return err;
+}
+
+#endif
diff --git a/src/pqc/slhdsa_import_x509.c b/src/pqc/slhdsa_import_x509.c
new file mode 100644
index 000000000..52d48911e
--- /dev/null
+++ b/src/pqc/slhdsa_import_x509.c
@@ -0,0 +1,86 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_private.h"
+
+/**
+ @file slhdsa_import_x509.c
+ Import a SLH-DSA key from a X.509 certificate
+*/
+
+#ifdef LTC_SLHDSA
+
+typedef struct {
+ slhdsa_key *key;
+ int alg;
+} slhdsa_x509_ctx;
+
+typedef struct {
+ enum ltc_oid_id oid;
+ int alg;
+} slhdsa_oid_map_x509;
+
+static const slhdsa_oid_map_x509 s_slhdsa_oid_map_x509[] = {
+ { LTC_OID_SLHDSA_SHA2_128S, LTC_SLHDSA_SHA2_128S },
+ { LTC_OID_SLHDSA_SHA2_128F, LTC_SLHDSA_SHA2_128F },
+ { LTC_OID_SLHDSA_SHA2_192S, LTC_SLHDSA_SHA2_192S },
+ { LTC_OID_SLHDSA_SHA2_192F, LTC_SLHDSA_SHA2_192F },
+ { LTC_OID_SLHDSA_SHA2_256S, LTC_SLHDSA_SHA2_256S },
+ { LTC_OID_SLHDSA_SHA2_256F, LTC_SLHDSA_SHA2_256F },
+ { LTC_OID_SLHDSA_SHAKE_128S, LTC_SLHDSA_SHAKE_128S },
+ { LTC_OID_SLHDSA_SHAKE_128F, LTC_SLHDSA_SHAKE_128F },
+ { LTC_OID_SLHDSA_SHAKE_192S, LTC_SLHDSA_SHAKE_192S },
+ { LTC_OID_SLHDSA_SHAKE_192F, LTC_SLHDSA_SHAKE_192F },
+ { LTC_OID_SLHDSA_SHAKE_256S, LTC_SLHDSA_SHAKE_256S },
+ { LTC_OID_SLHDSA_SHAKE_256F, LTC_SLHDSA_SHAKE_256F },
+ { LTC_OID_HASH_SLHDSA_SHA2_128S_WITH_SHA256, LTC_SLHDSA_HASH_SHA2_128S_WITH_SHA256 },
+ { LTC_OID_HASH_SLHDSA_SHA2_128F_WITH_SHA256, LTC_SLHDSA_HASH_SHA2_128F_WITH_SHA256 },
+ { LTC_OID_HASH_SLHDSA_SHA2_192S_WITH_SHA512, LTC_SLHDSA_HASH_SHA2_192S_WITH_SHA512 },
+ { LTC_OID_HASH_SLHDSA_SHA2_192F_WITH_SHA512, LTC_SLHDSA_HASH_SHA2_192F_WITH_SHA512 },
+ { LTC_OID_HASH_SLHDSA_SHA2_256S_WITH_SHA512, LTC_SLHDSA_HASH_SHA2_256S_WITH_SHA512 },
+ { LTC_OID_HASH_SLHDSA_SHA2_256F_WITH_SHA512, LTC_SLHDSA_HASH_SHA2_256F_WITH_SHA512 },
+ { LTC_OID_HASH_SLHDSA_SHAKE_128S_WITH_SHAKE128, LTC_SLHDSA_HASH_SHAKE_128S_WITH_SHAKE128 },
+ { LTC_OID_HASH_SLHDSA_SHAKE_128F_WITH_SHAKE128, LTC_SLHDSA_HASH_SHAKE_128F_WITH_SHAKE128 },
+ { LTC_OID_HASH_SLHDSA_SHAKE_192S_WITH_SHAKE256, LTC_SLHDSA_HASH_SHAKE_192S_WITH_SHAKE256 },
+ { LTC_OID_HASH_SLHDSA_SHAKE_192F_WITH_SHAKE256, LTC_SLHDSA_HASH_SHAKE_192F_WITH_SHAKE256 },
+ { LTC_OID_HASH_SLHDSA_SHAKE_256S_WITH_SHAKE256, LTC_SLHDSA_HASH_SHAKE_256S_WITH_SHAKE256 },
+ { LTC_OID_HASH_SLHDSA_SHAKE_256F_WITH_SHAKE256, LTC_SLHDSA_HASH_SHAKE_256F_WITH_SHAKE256 },
+};
+
+static int s_slhdsa_decode(const unsigned char *in, unsigned long inlen, slhdsa_x509_ctx *ctx)
+{
+ return slhdsa_import_raw(in, inlen, PK_PUBLIC, ctx->alg, ctx->key);
+}
+
+/**
+ Import a SLH-DSA public key from a X.509 certificate
+ @param in The DER encoded X.509 certificate
+ @param inlen The length of the certificate
+ @param key [out] Where to import the key to
+ @return CRYPT_OK if successful, on error all allocated memory is freed automatically
+*/
+int slhdsa_import_x509(const unsigned char *in, unsigned long inlen, slhdsa_key *key)
+{
+ slhdsa_x509_ctx ctx;
+ unsigned long i;
+ int err;
+
+ LTC_ARGCHK(in != NULL);
+ LTC_ARGCHK(key != NULL);
+
+ err = CRYPT_PK_INVALID_TYPE;
+ for (i = 0; i < LTC_ARRAY_SIZE(s_slhdsa_oid_map_x509); ++i) {
+ ctx.key = key;
+ ctx.alg = s_slhdsa_oid_map_x509[i].alg;
+ err = x509_decode_public_key_from_certificate(in, inlen,
+ s_slhdsa_oid_map_x509[i].oid,
+ LTC_ASN1_EOL, NULL, NULL,
+ (public_key_decode_cb)s_slhdsa_decode, &ctx);
+ if (err == CRYPT_OK) {
+ break;
+ }
+ }
+
+ return err;
+}
+
+#endif
diff --git a/tests/pem/openssl_ML-DSA-44_pk.pem b/tests/pem/openssl_ML-DSA-44_pk.pem
new file mode 100644
index 000000000..7d3ff6b1a
--- /dev/null
+++ b/tests/pem/openssl_ML-DSA-44_pk.pem
@@ -0,0 +1,30 @@
+-----BEGIN PUBLIC KEY-----
+MIIFMjALBglghkgBZQMEAxEDggUhAFZG+tnmR+uk5xEaWOY2EDZmyXmaE7Slm+a0
+6n7QORNU67wsvlG46MI3TdeoaOJSaU9afU4PEMt4C0+ILS0hjQq4mP+pGJ6MgYLw
+zo/DhE/34T0iRASnDe3sdhUajX93kB8hUNTHwwNXkH7qdFeUioTUMy0JNRkuM25o
+O+hIO5DhK5FwXR+i3CFnqu8Y1mL75AOpNSdIJoQ4lAmOKeM0l/CyvMZrE9AvlKpZ
+NUG4GnmJ1bBTU5eG1CytFZZi4B9HeV0gr2CE/kOpq0mDb2wstKbQO+A/IIPC75B3
+pcL7qi15zAfobIp9tA/2WKOZ0I/6PfDkRO1KhaRB6WOLvlHIzGFSGdNd7jvGfHnm
+RWZPRxcDi9v/1UCYGXGncyHeMX/mvhDROJ8bWWv8RYbXrrzej5djm6c1QYMeK4pd
+4n+vhekvZaxuc72SFl7SV5MT3DqpnJknDXthvu/W7DwwMGjqW2q05TJqqzvDhBOU
+e+GaHEOZTCJ5e9oM4fWb91TesajETW/erDJ7L7hJxYBMdq944WjiW5PzCIRuZe6y
+WUaXABJmuVNTTxyhPonstSEJEiPyTHB/yml1jrAppK9ZS1g41fEY2S642sESuG7a
+X4UfUXV//uT+4IrdSGZ4vxzny2T2FxA9XJ6KYZ2l3loS3xUzSWyl2sOITn3dcZh0
+TuQEhAOpfoWxaFlnnRKldvOqtJ5DfuJv7jUTX5g5qa0hesW54cpfxbTv7JOUAVFT
+8wdo9U8LH2us/fbl0oHWsYdJDqgA77QrwO8xy+O8Bi18JdLnkrSEwwAQzrmJ/aFI
+NhPmAY2w9ZYPEk4EFv7ODW8ZA1xMpSiV5rDwgwNO8eevn/crb57gone11RiIuUka
+LUxCMr9zueZ44ifyMmfSuf3gZgQD9GO18CmgYGzdNytxkUatrvhPzVu3LpZ8G0qg
+BB109yjf7nhbXTMxD2N3bkLMWA8e68uh3kfimpA0SMfSXS1ehwP/vPYTUXamF7KH
+a1Io0O1ukiuIPNy2LAvQLGjPplSDrhKjhPZB748xRwHxWzXtXL/vcBnFn8NnG+w4
+ONIj8kTDI5Lt32i6or7QWLxQ+H1V3hpDimj3Qj7kuuRwstvf0dxJxwJl3O+A0NsE
+TZfcKXExYnl27O+psxeYtTveAIjqZdmvOQonQRXrzWlb8uinz9046WlCZRUxwr6L
+9mrfDXLoQ4Wd2q0m9Yz5yPS9FArPyi/VYYf83sPnwwiY0hmQ+9com92u5/yEYE6f
+DV337TQqe/DDZhz3M/bzJAjRKFZxhkZoQ1Ya8tn/LU9//hpI/NM0hWPArhSnG4RZ
+5MTzsX42swq/eFKBTyeZ9hQdWnuPEujUxYFB+UBxrsm7OXYFkIb/8GE7J+d+5Av0
+wJYB8D7qJ7ulJaSOkXhrVgBcMd97Eb0EfPJBRyREc2wFR0KhYWD6PuQrfrppwHhO
+366djWJU0Rtpe3doYbP4a8XArcm1ceoQrjkSsABT1fSJtYkCIHPxhypzuaKvSPdE
+yUyjeSh0+i0cb2UjpLE/XiGhALpn56BL/AfUhrqYlroLf1Ptpqsgd+xwaA4LMQ/G
+SRH5oyxddPwN6grNQSEcekAXdsPHfmyIedRWGMNkadfI351AhE4xtSxBeoDO5ELq
+PhfKMhu5s43TxbzeyNML12Mlhb+1koNFhfi/0WL4dkqovAS5NKStZOZxzCCDqERh
+1rdTOHRSXcSFsDrRlVt05gcWJqlw2cjg6JaccUUNaECLyKBhJbY=
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_ML-DSA-44_sk.pem b/tests/pem/openssl_ML-DSA-44_sk.pem
new file mode 100644
index 000000000..69c08c8c9
--- /dev/null
+++ b/tests/pem/openssl_ML-DSA-44_sk.pem
@@ -0,0 +1,57 @@
+-----BEGIN PRIVATE KEY-----
+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
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_ML-DSA-44_x509.pem b/tests/pem/openssl_ML-DSA-44_x509.pem
new file mode 100644
index 000000000..831b06286
--- /dev/null
+++ b/tests/pem/openssl_ML-DSA-44_x509.pem
@@ -0,0 +1,85 @@
+-----BEGIN CERTIFICATE-----
+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
+AAAAABUoNkA=
+-----END CERTIFICATE-----
diff --git a/tests/pem/openssl_ML-DSA-65_pk.pem b/tests/pem/openssl_ML-DSA-65_pk.pem
new file mode 100644
index 000000000..73efba05d
--- /dev/null
+++ b/tests/pem/openssl_ML-DSA-65_pk.pem
@@ -0,0 +1,44 @@
+-----BEGIN PUBLIC KEY-----
+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
+F2shVx5s
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_ML-DSA-65_sk.pem b/tests/pem/openssl_ML-DSA-65_sk.pem
new file mode 100644
index 000000000..79d16aa83
--- /dev/null
+++ b/tests/pem/openssl_ML-DSA-65_sk.pem
@@ -0,0 +1,88 @@
+-----BEGIN PRIVATE KEY-----
+MIIP/gIBADALBglghkgBZQMEAxIEgg/qMIIP5gQgTH1RVhpMwV8jOFkwEmQwNK8n
+IKbOi8rxBxdjv/+qBn4Egg/Abi8l5ZjLk1uEKxgidm2T+oTHvQUmyg77pGRhQd6i
+IJ4/SroGIEqcRBS5HamQuJej1kJAkRul7Y/9N5WnFUCOcpdpwSDYKodxaucXf4v8
+KCUHqPkD2FZoOucPS9I6/bJk3cOCHZqTBh4IHKCcEz551AIwcIyhxWex/8js4g4r
+NLtnUEZhJghncVAyZEQQFAd4BWYYI1MXBwZxIGJFZAEVJCJxNCZ0E4YkZFUVRXFA
+hmZTBFAgUViGQHYHEBdINYQCBWYEQEhWIDI4eIEzKHEjZmgHVwJWYjFHJDB4AXAm
+SGKAIHgiCEMRRVQYGIZlJ2SIdyEjYIc1BDQ0Y0KHgCFQMDI1J1V2QzRGdgRGcHhH
+JRM2GAcYeFMkVHcTZXJDYFAlNUEYcEZQYSRAQBAihodIUzhAdWIRAgFVhYMlZAQY
+NiMHckCEaDMmgBQ1VwgYUIVSYXRjgCKDFlA3YSVDUXFAQRYEKDd1Z2AwAmI1M1gX
+cng2GChnBBVSUCIWcYQhgxFnYTJHEiRERRIYYIYEUQdACCJUYyhSM4JXQzWIFIYi
+AgQRGFJFElQXOAFWZAhRdEFhVyVUd3R0ZhIDExQzc0VHB3ARhAgWgBMIRjJHAwED
+VwIQAAF4gRKIeFEiYEACVTaDQxVFJCEzJzghcyEmQSRhSENERBCHRANDF2KBYTBj
+RXaFJAWIUYUVVgUwYyIHBEN3IBcwVhVog2AWRWVnU4hDdiKBNGJzYxSEWCIWIIUG
+h3EnhRgnBoEGdQEIZxGBeAdYYgUCSCQjYVd1g1VRI3iCBzgXSHMXUyJXIwiHAgRg
+eCAgRVYgIHR1NCQ3RAQzQCaCGGgzRwcDQnBGgyMiOIFYEAYUcnd2ZWIFECJCIldX
+h0WDQzBoc2aDRRWIJ4gyRSZTE2hzWGE0CHMjVXGEcjYIiBKDMScQcXIggjSBgEJo
+QGeBBUcXNYRDZ1gndFNlSHQDERgCVyAThmVoZiIjFBhiI0SDA1iCWEFlUVeBZoFQ
+YwFIYSaHACQzVwN4CGJRaFIIERGDYlQmeGNjYndAAjYUBih3IBIAJwZmZWWCJDQH
+BGd4GAEmJVgXdQZxEDA0A2hhYWcGIEEUYBNmWIZoNohRUHUgQWiEc4YCBRaBB3V2
+OFN1UkJXNXgWIUQFdgAhRTUVdBJXJFB0cFMSBQdTh4IlRwgARYRChUBjQ0IoAyJC
+dUVmYwhnQkZTYCNyFSKBgXQ4QHFHRzAyc1QIVFKERUFnQQMAIjR3QjgkdUBnJRBn
+Z2SCVlRWEFJHZodRCBBAVXUEQ4UDeGFGVYgwd0gxICQgUSWDAQZHY4RIUlBUN1Zy
+eGUWR2gzEjWIhEAQVncRMQhiJVdXdGAIVyVTKBJEU2E4cwaAFGQWMDNYNXAjE4FQ
+GFBChoNBJReEBhUSMjYEODVlVCB1EBVzhDc2OBExJxBodCBIhjA2ZBM4ECNFVYIl
+gmBoEUYkAmUyNjFCGCNgKHiIYyUjUDBkAiWANTYTViVoE1gggBcjA4UmYCiCERBD
+c0dmBxAkEWZ2AkOIdkWCIxQEJmJCI1EiV0RyVVRBgkdzVSMYZCQ3InOHRTNFZSAB
+BFdAURVVgSNQKIh4BUKBUzAlBwcoByJFBAUHJnRDEmghNHVCEFV4FAVkR3gFEAQx
+EBYVWDE2EnMyMYgziEBAJzMjZSVBQgdhIDgBJjc2OHIzeFM3VWMYEHhQFgdRRUNj
+M1VjdoZIM1hoKHEjIFgWQ2BxFHQCY0MzgwMnaBdmdIVEIlcSECWDGFEIICM2UEAT
+U4QSFjcQFTNXYRN1dXgUVQQIQih0JSRyBzhoFFBHOGaIU3MkZgY3gWJiYVcXMBFy
+U3IAQDhHdlYgZCJSGGglFEJFhgdDUzQAZyYjAWUBgIU0GDcmV1QTBEUYYBdYdTIx
+dSUxiDIHIIVYGBhjYIJmFIQ2NISAAwEIYQcTiENRgVVkhHQYVShUFxUHEwIINAQV
+AyMjN4gHBlEVQkc0J2hQNFN1KCU1JiZ2JiEhcxMBhwcCYVaIgxhyQhaFVgUiBgZU
+NRgTQ3FjJSM1JWgSJiEkBTh0v9gEQvlhZYZ5EjPaFsb30afoMf4Go8P2MWAac+eL
+vLQLMFkOUtrPSVlVPG2hyn0+aOTXBkWLzeiKRAwNCWj0O/PpYOrfvPKtCppQAAO4
+lBVaaJsiYqq/4Jwxql7BwF018Az4PvWxpy8wPYbx1iyASvvdOPft6udP2YY5+zzo
+cfZsmMgfT7c+1VLZQBAOsi6BEWZGIGFp43Cd5UphM+c3TcItaCFo3Q9ZzUYSqKGX
+yjNybk1VYbr3Rb1yQf0+zMd2FQHITEC0CM7ila6HTfxqfmx3gOP1KlJj1zykfz17
+AiH47H9a8lfE+c/9tbq8ThzQhdxly4XnbFyMof0FGnxkwbke5Gan5K7RVohSMoJr
+bf3ow9Emlsj0AUS91fisW7Q180TXrdg8ma9P9ozuv0yNLw0WvUxXWNZjWtuu4e1s
+SMSSO1bv3xVgXcqAfMuoLzozV4woj/uCmwdQx52Wunj31bZPlVQOu2xBFXZGL5pW
+4gWz2RPfLlesGimr+66NExjjH60D8Vbc7QJEjKGHZN2eMufstyqeRf8u1DRJjMtQ
+CpLFh+W4ByFBxH+rmd1WI5AU1fNpZLXD7BiDITXXn2xFw8c4Saa5xEKnO7gpIwC3
+KYsxsnKxgSYhewmHaSaUKy8kVTXRSQkrhIRbY8LKpcunYnhnZ/PHJnNpbXyW3qAD
+wI33sLZcSCaVjlsWg9/wn45e6GbHWs+iTs8sGiBDwh5bYxhnQZgpHi+UhyFgpdO/
+RTRTP+zLXUEJvKn3W8xZuBPXpm2I1NQkFkepEb1ucNRcwuLvWICP6PKlRJpx4w4/
+l3V4PVXH7gjEHmXt7V/aBACDcyBiNmVlAPG2UKDi+lXYBycojwNNSBbM1oyvCDQD
+DemBrRTj6dj4N5fgMBp9yi/TCvtAziaatQvtZokVr2B1orjbRqCLER7w9ei3SGeu
+HobS08z6uyEWIG69VF3xLNEhY1H9swRCwHStBN4J4FK4BDuk72xQLq0hpA3CPOKn
+zpfHBPsvn9BLrpZwVSKNOilIBm59CPJxzmbQQujFH2Nq5BxWxr4O4CQL6212/ptG
+LjzRIl1qNsJCkKo/ayQDyGInA/LAg7c82BzxhpnCu8cyiO7MuJMXkS0fH1fUqYuW
+g9evRV7fJi+YoV84bXTG46LXlSiyjQccO2kc01QRltuwwZ266QZR8CfW+SCABsbp
+6nzDNm9D4v4M+EsNDsUYY2DxD1jdsQKMCDQLUCMIlWg8kkUqQ5k4ChM3T+DN5fzH
+DOSBB9PXE2t8hjzrL8xB57Q3ysuvdOj8Ot/LYBOIuMZFOrKL1yfvZAVhM0cRivjM
+qI7/9XFla/5/LfW0Ns9lBZn2nZBlmp3CehKOyiBvMT+8KGGpfidC03MEVnYu5H2f
+cfkX1tLDwhwMS15PTym3UdyAEoJWbBQtabazbU29TfLvSTHvf7ToEkJuiViaHQ/0
+s79TYVqO9OA3aD464ANMQUk1M75Q8JTfaTJWFCyCzPaTM40ij284Ymw2F+tXjCYj
+HsbWfor/pBmKgnH1PTjF6KoCNR1vbRhIKHXZMcDfWhCVAq6HV3AyWg8zmRjnQA9A
+cEwXZI3VUpGyA5/kWtiox4oqjDt9WcNEJOe4DXHTbTX2Jyb7kbiqxv3z2SdsfskU
+4fK+vE0466imvBHrvw6cFxPF/6B6DxR8V+Jt1/QljfOVt0afwNVdYysTX1HmcUbc
+KPFT4sDGHICQda/MXFYJde1vuuh+O8zE5Zs1OUEEGwmLPoogUlzZ1jWSuItjb512
+0KgsL3b2qRqypNHpAqBRuP0RVGOmu4TPsWNZT7/R9IkUw+fs9y5jCDMhMKeetbzd
+bPehlRZyvldh7icthI9iL/ol1jh2R6P70UVblg5bC97s1/RMOZMSYzTBAPRvHflG
+ID5XPAt67/VtFbDgrZuCynYcNy56AtbIy9O58ackydO0AbfVNZ+tqSiXHvZlEO9/
+2BRfswB53Ai4uosdNu5giU1tiaerkUkAp+s7Ms6WibTUH40aZqmiI3lRlz1tTdLe
+/gFim9Gc35XmRS71WoUqh0XkpKgpdqV4rGxoN2St2cDKMx43f/ZwFXhdK7SUNwWZ
+kDLFtWnofNWb7a7359SvluUPBf/TtImzeaJKy9nH5jGj3FGYCmi5WrCC0vWebDYR
+AizCPVpa2Lk0WJNLJO39ZgY7y6VM4stulQCCzgWnW9MwcOh7uymiZnNTBEiBQVg0
+bM+LmvhkHcg/1GsvWuPindBzES/fOp0fzG9fypDM1NI6h+qDS2uqSkLOxWimwNy1
+MhCxIJ8UkZHnzrRxRBslBwI5Ngq7ysGrR3X8p0gSWx7JWDEDVKUT/zzco4Gv061k
+isHAUGlvPMXK2s8n5IGxElnijCOE2Jjy1iLFqh8AtcA267ojgJrmIr8fVgNxoJJX
+1BgxAqZsFVntfaDtmYNX2LJXONyIqduY1f75lDChM38yn8KGnXcuMVN2ZnQ8VLir
+LSDe7HkJscqzuOwYZANv3f4OLIeUMGDkLgKe+VqJn7HbkPcHFn5JJ7/+gL63E3HV
+KAFJOxneZYyKDezdg30HL2X86RhLwwCci3vbsGoM0Jnd5X9RYPjRAfglH0Yu3P20
+UOu18q9SKy9Ehlwno6bZ3+vtnWj1B0tPjmxYyB/Alkb0aI2we45bplaa9/C1E/Vt
+1wgVPmaOipXRo/HcQKdgSqlp0q97zlT3BzprvTFWC/pPSjfGMiHLBtS4ABIpop19
+zD3HosKy7S9WWaCQsA/0nTs++Wf2ttpEQIqVggcn2Sg78tDPM/zeookoIli7ypPh
+VQ1DcX2CI60NLAj0L9bY7Fro+jM2Flod2UTpv1ozZVUZK8FyJ0UUFOk8KVpeAhkP
+h/JfxXY+B+H5gT7n/EF2z7QZdyDwj4QzqFHv0i9yg3DWWTzl7MlElAqnlMJ4VM0p
+qpRXIYix2YzEUFfZIg9F4S+rGWlUz9xa9hYAsyKH+ztjnseexs9qDQI90maE0NpH
+bo9mqmNxWas1OHO9qz5wFmz97pwo+KARGUp2pp5iC7HZXguRHKw142oeZl198+qJ
+Vtn0bJLLvx2z0cJNBSJKIgn4lRBIjhq09HhPS6iuMBd2jJYUjgi9OpTsntr6pegf
+sBnBmfUilcBm2YklSRwif1NpqDiJcHZVcwjdFwC9+GTMBuO6q4/2ueBqpJdRxTDv
+V+ZvF7tZod6Gn1PAy817n3tYoyDjKaLgywsyBg8MzLr3ZmkS+QkAsVxkzDH0Gt75
+O0fplkgzbdVfEvvjCVUfzi/gKF4SS9UZ3vDC0mCVncjyGQhPKFXl3PPAONUoLyrB
+YNHz506CNXEWxqm0vDoPx0l/
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_ML-DSA-65_x509.pem b/tests/pem/openssl_ML-DSA-65_x509.pem
new file mode 100644
index 000000000..e9def5b5f
--- /dev/null
+++ b/tests/pem/openssl_ML-DSA-65_x509.pem
@@ -0,0 +1,117 @@
+-----BEGIN CERTIFICATE-----
+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
+Gg==
+-----END CERTIFICATE-----
diff --git a/tests/pem/openssl_ML-DSA-87_pk.pem b/tests/pem/openssl_ML-DSA-87_pk.pem
new file mode 100644
index 000000000..48fec3a48
--- /dev/null
+++ b/tests/pem/openssl_ML-DSA-87_pk.pem
@@ -0,0 +1,57 @@
+-----BEGIN PUBLIC KEY-----
+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
+huT6X1dJIIVKkrPgKeTJqeUlW3317g==
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_ML-DSA-87_sk.pem b/tests/pem/openssl_ML-DSA-87_sk.pem
new file mode 100644
index 000000000..b59bef518
--- /dev/null
+++ b/tests/pem/openssl_ML-DSA-87_sk.pem
@@ -0,0 +1,106 @@
+-----BEGIN PRIVATE KEY-----
+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
+0WLBwubkJ64Ilb/qv20O9j1X
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_ML-DSA-87_x509.pem b/tests/pem/openssl_ML-DSA-87_x509.pem
new file mode 100644
index 000000000..4dbe932f2
--- /dev/null
+++ b/tests/pem/openssl_ML-DSA-87_x509.pem
@@ -0,0 +1,157 @@
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
diff --git a/tests/pem/openssl_ML-KEM-1024_pk.pem b/tests/pem/openssl_ML-KEM-1024_pk.pem
new file mode 100644
index 000000000..96dabf00a
--- /dev/null
+++ b/tests/pem/openssl_ML-KEM-1024_pk.pem
@@ -0,0 +1,36 @@
+-----BEGIN PUBLIC KEY-----
+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
+Q0jH8ACP
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_ML-KEM-1024_sk.pem b/tests/pem/openssl_ML-KEM-1024_sk.pem
new file mode 100644
index 000000000..565883d0d
--- /dev/null
+++ b/tests/pem/openssl_ML-KEM-1024_sk.pem
@@ -0,0 +1,71 @@
+-----BEGIN PRIVATE KEY-----
+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
+nos=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_ML-KEM-512_pk.pem b/tests/pem/openssl_ML-KEM-512_pk.pem
new file mode 100644
index 000000000..4c7c6aabb
--- /dev/null
+++ b/tests/pem/openssl_ML-KEM-512_pk.pem
@@ -0,0 +1,20 @@
+-----BEGIN PUBLIC KEY-----
+MIIDMjALBglghkgBZQMEBAEDggMhAKc8U5shf746BkXmGeO4mi67hTkVnVMnC328
+oC7it2unroFHjNm3JQshppVRFXACwQBqrwwQDS7mtvPsTW7Kn7kXMwz8TMN5dkUL
+AxeyGX5VeYWLsVNyGNmxXYB5IXkKVZb1sNqECCTrenG1Ph4LiivqGCDIXWMDD5k2
+WxfqEmZZFOHhkqxLMbL6tb9ppcmqa8krPLUGEOpKCujlC/ApGPNaCv01iP23N/vF
+IM7JKhOFWb/SLGUhEWRrXuV7mmWYLS9mOdKxDf4liS8bJOO1PIcSwvECUNyKZuyw
+KC9FX/q3NfHJX4CGn45gNX7jfJVQJEwQc92liWN4m7tHdl1Dk26pq3ohR0f0TaCg
+L1qXm44sAScZO8kFktYcTDyyZt6EibmsDzcqoqimBrwHmfWhvuz2rmRpfgNWIix0
+DeRLDkUKtccnhxtamU3kRMUsWykDtbxVPx/ZTbNQN0KQmqfABy1TTTOALGkKMBkl
+xDTDeFDIvUO4Nd7EFKB2DnkwvfI1KPzCdXM5qYJnAeWiyxxzp81iMjfzJFWTwAzr
+dPSjoTrGJt/za1sgRkPwKCoCXJuHgmZUyjb3tgsyR150V7oSjv6hkHJbpmOYoF2l
+KyyUWc8bXzgQGjXzsT9cPONMgTg1MXYHYKhUExXzHDUUYTPVn+mafuHTu+8sV+fA
+KpSQCiZhaq53yWxQqLXGVaLUMTBBjHIrtmbKNoX7GsV4u9swV4dYIGXzq4H1EPTs
+EsZUCfvKZZ7oB2K4U6o7H1BgrfBIYetnRP2AwtyZBoI4sCWKr54idywosPQwM7fG
+LBeiur4Mp6h1a7OVk/PAzePAcQhGgOJhmFiQRH1VM2ronB2nTynpA+yJG0lSPgTG
+QbTCXlEGQmrQMmQUIxUrVUnEuchZfK8IfNC6GDsHG0nEIBeaU0tzUe1Ax3tXyjqM
+AT87G0SRS2/cDxxYFL7hkLn6caBwQIMjmbBUG6oas7bqNJzSmd9yXGjbjD64wL1n
+Wn8SM0ZoeYKYNcujovRcHB62EKuxBBlXF6WvCfzv4dsOcFPHz5nvy/0noqP+gYgD
+ZWK2kteu
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_ML-KEM-512_sk.pem b/tests/pem/openssl_ML-KEM-512_sk.pem
new file mode 100644
index 000000000..a88b1918b
--- /dev/null
+++ b/tests/pem/openssl_ML-KEM-512_sk.pem
@@ -0,0 +1,39 @@
+-----BEGIN PRIVATE KEY-----
+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
+kXk=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_ML-KEM-768_pk.pem b/tests/pem/openssl_ML-KEM-768_pk.pem
new file mode 100644
index 000000000..ec1aa7b36
--- /dev/null
+++ b/tests/pem/openssl_ML-KEM-768_pk.pem
@@ -0,0 +1,28 @@
+-----BEGIN PUBLIC KEY-----
+MIIEsjALBglghkgBZQMEBAIDggShAG3kjC6FUbdBreYhT/akPKJwdJzkRkzHFzgM
+QqU1NBIhPoDFBe0Loj4GE697jp0KF3YIMamVsrMzorS4FJgnwIxDRAGDEHPbFq7n
+D1iEor9BdLIVABAhkWFUJW8oBgAzXkycbLbjTt9QIGlaURtra+eKIG83vfEbhptW
+jp5kJp06VMMRY7XzGTMmAEOzqvurNotGR2hKIMdrpvbXI31brIg8NysbUQHaIFbA
+Sh9hN/zXwmqWXHmByBm1sTh2hmp6v7pSIkvgTIw2sRLLYHOJYlz6bm7GQMyiatDI
+OJH7MSsEV4dzMcErmFAzTdWKKaa1Ko+iDtmBMUcFgy1VgekKl11KAxtVXcP0EYk1
+nU2YHs53a7lyjQ6Jt4mrbR4jWUiWHC5lKg/qzIUrBJZpEz0XJcIVCBqaFaPUacj0
+wq0anDwjVzBmbK6qoFeBOsaUTpd4hhgCqJiRE0C7k5MilC16VLKxkRHnyPH4LMja
+CJmIkatLXJ1mW97JWDRnrGE8Gr98BfiCD30UYNdFwpkCuspqnQopnz9Br+NMVecV
+Ul7qyNPng23qIRsbAwh8tOjimxdCj8Ybr76iulVExbuGx3kJmWmUA4fzF/RCSw+2
+MMJkLCGMGEXKU3EaY3fWOz7cSKbrqmKhQW2qosRFjBzIJY4kwHqSwuv5r5Mnw1OA
+IEA8coUTIDXYt7lHvPq6u2kwBkpAAlzVRrr2ngrxl9khlM2VBW8bEq/qzBO3Ywbk
+wz6mbo6aspgmHTKmlPYTOAaVhuUztehze7gIWeG3Ww+iydJ5EiMFvOuJv4jSXSz1
+Inoltf8lXDvyxhK8DnJ2KvZorYRrHFYgrIqkfZLYYkgKTgUyrFdXVqtihRDzI1P5
+zhWyMLPEfoK2pI2IJU7EnL1cBrLFJKp7yA4AzsynZwhUtT+Uuyl4lTKpZWugCVWC
+NGJ7n6dKUmrlkXcWj+ToDooCB0lpkk2owiwrYHIbIucaWzDAKJw3g8tnsgw8hqGM
+bqLimUqiBRTykIeiJB5TtNtEQBQ1RZoCwLxcGbEEw89wLTDSsRrpAoCss1bny14C
+prmMGOU5hAITlqyli/W5iVtoVcDkvad1nPISY7wJrMRkVrOnyk3aXLFbYyCzHYui
+IBshYeRGJFhKy1pwctokSxscMjPAhau1T5PUF+C7FpNLk/8Se0XpyvV0YGDzkUTM
+XoP8RD9WSQLrBU57UDy1h1lcGKBmRXvFic4mU/tSjmjMhX6YLRHIZKB2TG9yHmCF
+S0oMsz3lSooKyQtzDbm0O0m0L7ySfA6iOTQEk/dJjsbGPqz1r/Ixl1W4secKWhtH
+giI4zfvYuh6XWWzgFKBCjKShkCYTgINEAJPwfSMJK0ppX8wwS5qHUFyIqgcDaGYi
+VF1ZNaO8HGpxIuW3ozxGmbtgtddprOvgahsotsVlK3OQyrebH+8TDG/VC2O6bMiC
+LsSwoMWgD+jHos0JAUwkY2tokKoGUPDEMCp6uhUKH1bgErEhhrSDyKrkAiEHJzMT
+IGO0MdvovPX0idGBvLfBziSZfxOYdQnj413yvAembdusFV0RkuXy3KCDVJYGYVv1
+Vy6xEkvF
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_ML-KEM-768_sk.pem b/tests/pem/openssl_ML-KEM-768_sk.pem
new file mode 100644
index 000000000..8425ba73f
--- /dev/null
+++ b/tests/pem/openssl_ML-KEM-768_sk.pem
@@ -0,0 +1,55 @@
+-----BEGIN PRIVATE KEY-----
+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
+4KA=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-128f_pk.pem b/tests/pem/openssl_SLH-DSA-SHA2-128f_pk.pem
new file mode 100644
index 000000000..65c7b766a
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-128f_pk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MDAwCwYJYIZIAWUDBAMVAyEA0RtPrNG/pSj+lH+XYkQMfPYfKuunCr0fq5uRnGv4
+SOU=
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-128f_sk.pem b/tests/pem/openssl_SLH-DSA-SHA2-128f_sk.pem
new file mode 100644
index 000000000..aa88ac0cb
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-128f_sk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MFICAQAwCwYJYIZIAWUDBAMVBEA1lg4CCurnTC94IstEyqr2rle53arfbjKJhKZs
+FBn2oNEbT6zRv6Uo/pR/l2JEDHz2Hyrrpwq9H6ubkZxr+Ejl
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-128f_x509.pem b/tests/pem/openssl_SLH-DSA-SHA2-128f_x509.pem
new file mode 100644
index 000000000..4f3d39815
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-128f_x509.pem
@@ -0,0 +1,363 @@
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-128s_pk.pem b/tests/pem/openssl_SLH-DSA-SHA2-128s_pk.pem
new file mode 100644
index 000000000..459593b69
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-128s_pk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MDAwCwYJYIZIAWUDBAMUAyEAueNkSlUIUcv2YcDL1avShv6Dr9L+YYLSVDu3uvb1
+Jwk=
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-128s_sk.pem b/tests/pem/openssl_SLH-DSA-SHA2-128s_sk.pem
new file mode 100644
index 000000000..23f609b66
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-128s_sk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MFICAQAwCwYJYIZIAWUDBAMUBEBgZT7mw3+QfGFarrsdPPcuUeqzs1MGILndoOXP
+FLpS8bnjZEpVCFHL9mHAy9Wr0ob+g6/S/mGC0lQ7t7r29ScJ
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-128s_x509.pem b/tests/pem/openssl_SLH-DSA-SHA2-128s_x509.pem
new file mode 100644
index 000000000..cdb36eecb
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-128s_x509.pem
@@ -0,0 +1,171 @@
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-192f_pk.pem b/tests/pem/openssl_SLH-DSA-SHA2-192f_pk.pem
new file mode 100644
index 000000000..2e1dbed56
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-192f_pk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MEAwCwYJYIZIAWUDBAMXAzEA2zkbAGFMYUgjTniq9wHHOtkNNMy/st4bpj7czk3+
+pSLhf0/BvidnnCbwzOk+Ry4i
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-192f_sk.pem b/tests/pem/openssl_SLH-DSA-SHA2-192f_sk.pem
new file mode 100644
index 000000000..0d60b8fa7
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-192f_sk.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MHICAQAwCwYJYIZIAWUDBAMXBGBAEsQTugRaD9VO7wExjzcYXO4HdV3cwLSMLV/m
+H3ldQUFbG4efpVdp2evkUlke0zXbORsAYUxhSCNOeKr3Acc62Q00zL+y3humPtzO
+Tf6lIuF/T8G+J2ecJvDM6T5HLiI=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-192f_x509.pem b/tests/pem/openssl_SLH-DSA-SHA2-192f_x509.pem
new file mode 100644
index 000000000..d857e7a81
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-192f_x509.pem
@@ -0,0 +1,751 @@
+-----BEGIN CERTIFICATE-----
+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
+FE0TtbTjZglDT5lA6EVo
+-----END CERTIFICATE-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-192s_pk.pem b/tests/pem/openssl_SLH-DSA-SHA2-192s_pk.pem
new file mode 100644
index 000000000..03c5763b0
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-192s_pk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MEAwCwYJYIZIAWUDBAMWAzEAro8jyREeOprwVhevuAEXGSTP2zhCXv1EBvL7+bKa
+xHXtiAwCs6/dJgqLRwKFDDxA
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-192s_sk.pem b/tests/pem/openssl_SLH-DSA-SHA2-192s_sk.pem
new file mode 100644
index 000000000..3c5bd0f7b
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-192s_sk.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MHICAQAwCwYJYIZIAWUDBAMWBGAdRzeipR0t1igxK/zxNFW0o+oF2bJlsM723nhY
+/t88XO/B0638T2JCGyE6KncNui+ujyPJER46mvBWF6+4ARcZJM/bOEJe/UQG8vv5
+sprEde2IDAKzr90mCotHAoUMPEA=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-192s_x509.pem b/tests/pem/openssl_SLH-DSA-SHA2-192s_x509.pem
new file mode 100644
index 000000000..0dfb0d2cd
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-192s_x509.pem
@@ -0,0 +1,346 @@
+-----BEGIN CERTIFICATE-----
+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
+TuVM7r0BjpnRHmKqOQOn
+-----END CERTIFICATE-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-256f_pk.pem b/tests/pem/openssl_SLH-DSA-SHA2-256f_pk.pem
new file mode 100644
index 000000000..ef0ecda99
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-256f_pk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFAwCwYJYIZIAWUDBAMZA0EA753F2qJlsmSZqFAYFoZmVXU0VjUPkufuikUBaWj1
+T2OvhoRswcZyj0b2YhOeGBM0rb7/AR+uFxCd04ms3d9EPQ==
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-256f_sk.pem b/tests/pem/openssl_SLH-DSA-SHA2-256f_sk.pem
new file mode 100644
index 000000000..a9e195551
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-256f_sk.pem
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIGTAgEAMAsGCWCGSAFlAwQDGQSBgPiFpG7nIWOA1u3W+JPiWedAMIZyfbJoq6g/
+um+1GeI9lVVTQdR4/KqRTmx5IUZUKFeymXRMt/FePp+Ex7u8xZjvncXaomWyZJmo
+UBgWhmZVdTRWNQ+S5+6KRQFpaPVPY6+GhGzBxnKPRvZiE54YEzStvv8BH64XEJ3T
+iazd30Q9
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-256f_x509.pem b/tests/pem/openssl_SLH-DSA-SHA2-256f_x509.pem
new file mode 100644
index 000000000..a263017c3
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-256f_x509.pem
@@ -0,0 +1,1047 @@
+-----BEGIN CERTIFICATE-----
+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
+wetlRRAL38LamiTSHLNA
+-----END CERTIFICATE-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-256s_pk.pem b/tests/pem/openssl_SLH-DSA-SHA2-256s_pk.pem
new file mode 100644
index 000000000..4b8f97a9b
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-256s_pk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFAwCwYJYIZIAWUDBAMYA0EABSZd4agdHX3trfc+4vHL8Meg7FSwe9TsQd1FDGv5
+RkBTHzp5a6nF7q5DTriurtMg5GIKSUueiH9Wciq1ggoi4Q==
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-256s_sk.pem b/tests/pem/openssl_SLH-DSA-SHA2-256s_sk.pem
new file mode 100644
index 000000000..ea51671d6
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-256s_sk.pem
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIGTAgEAMAsGCWCGSAFlAwQDGASBgMJmhWMsHC+ZaCdeI8NGfz8qwmL+3K/x78SY
+QPkNr1U1Wu20BFU5XxVAdVAwO7kFamzk7yKWBqJDlPyuDZ/YX20FJl3hqB0dfe2t
+9z7i8cvwx6DsVLB71OxB3UUMa/lGQFMfOnlrqcXurkNOuK6u0yDkYgpJS56If1Zy
+KrWCCiLh
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHA2-256s_x509.pem b/tests/pem/openssl_SLH-DSA-SHA2-256s_x509.pem
new file mode 100644
index 000000000..77f880bf8
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHA2-256s_x509.pem
@@ -0,0 +1,629 @@
+-----BEGIN CERTIFICATE-----
+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
+diPixZGf44SlUxO3QYWdCt7AtavoYfoHx/O5kxpDouC/twM/pz+8zQM1F60ob9YS
+g/jelCJ1OuRa7/ySqpxYyrb4ahkv+jDjqKW3fFaGp7jO+Cf0UX2li7x0d5FcRyPS
+vbvxL0p0YBQ/KNra0PtJc9hYo8hPk4/ySVrkn7pgMI/LelTloj2NQ7UarcZK2WRl
+4eUn6aYneL3ZIz0ZEnbMf4ELzGtZZ1F3MNWU0VTtLZuWN0YQ5MEzH7aQov9pHswq
+/1gxI9LIeo/tM05wWMAeFOoPZrXi1bltOTR8DXAepM9NXh+jFMWGbDCkEyCooFqI
+chpJ1WAHeAmn6MNFO2aUOxlpjVBSBD1KoyfEY/YPCge2wwUIH2YGuFVCIDSe6nej
+wid/wSzZIe2WV0qGPEA+m9qeYS6l5dez0GtloDsjyyJXCc5a/9nKhsrcrGLPQaHH
+5dEkvVPYM7zDLHg6nueqKXz4RazCGmQicR1Fx5uDHsOc1DqlHFLNzTj2Z6yjhXxI
+Qq/1TrQPkbX/r9GKlayKHl/UVDUKIRz1VD9skxxWKdVriMpIouMtTrdNYrac4KJG
+Qk0WUmoJnUGnseGhdcBJaSDZGfJBx65N2mFnrdSB9bfE8d64T4WY0RcMXLKOo2/x
+eKtv7yJ9k1tYTmM68F5qWTOve+gS8zMBhuG7lg3sV+EK7uHGEQLxKEdtlQa1N8h4
+JKeGH/uxyIrkCvmmgDlCG9JrTgaLA0N8mN72rKR/Ak4nd+lSBuNJ0c9fh5GQi9Jr
+jQfMfIEGL6PhHVEj+fRWlK2m2lyOKKxhkwpYHNkJR6ndQNK5GaY2RTW7maH8Lu0E
+WZBkMQSdu8Hruu6oe8zwqVkqwGe56dMJ9FcmGGnSmkhCMFqEM9YlSvtb0RvKrTU2
+hPJMexzjI9MlQgAkoW807Pqr2DRlSTNTNv/GPMmEdF/YZitNzMg2AGavgIiaKD6l
+MXJySEtD7dZGY2J6S0f4yn3CdPbjPZCTqf6RBi3pIkct3+Ik66sa5kugHR3fxuru
+fn7J56pgmfTblZRE4nMsmTR+FqxUyNd60tNbGQLtVimMZtdLKsL7fu09Hi7r+XQK
+TESNVp+mm/i3iD2FOhAO5LIZwxAwPxGuD+Tm9CQlsIKkP5ebHOjPNy0XxWPrJsVh
+8UKqsuHUezubrDHzxyfGoSKXPHLi18YBKtOhDTKnf+QDm75/HXgTmUm0hM0fdvH8
+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
+D6lrLGi2ZtL+NoCReeOn
+-----END CERTIFICATE-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-128f_pk.pem b/tests/pem/openssl_SLH-DSA-SHAKE-128f_pk.pem
new file mode 100644
index 000000000..3178295b4
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-128f_pk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MDAwCwYJYIZIAWUDBAMbAyEAzKaH0PGWcrB7K85TgPMR9sZUkpShri9isdzbkdBM
+d4Q=
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-128f_sk.pem b/tests/pem/openssl_SLH-DSA-SHAKE-128f_sk.pem
new file mode 100644
index 000000000..3358009c3
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-128f_sk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MFICAQAwCwYJYIZIAWUDBAMbBEBU7rgPl3R3DDS4y5nE8QhQH96+ByRCKKYQso2W
+BrAGHMymh9DxlnKweyvOU4DzEfbGVJKUoa4vYrHc25HQTHeE
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-128f_x509.pem b/tests/pem/openssl_SLH-DSA-SHAKE-128f_x509.pem
new file mode 100644
index 000000000..4092c82d2
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-128f_x509.pem
@@ -0,0 +1,363 @@
+-----BEGIN CERTIFICATE-----
+MIJDqzCB1qADAgECAhQP7/EonDmbPwAusFF21sWdkKlunTALBglghkgBZQMEAxsw
+ETEPMA0GA1UEAwwGQ3J5cHRYMCAXDTI2MDQxNDE2MTUyMFoYDzIzMDAwMTI3MTYx
+NTIwWjARMQ8wDQYDVQQDDAZDcnlwdFgwMDALBglghkgBZQMEAxsDIQDMpofQ8ZZy
+sHsrzlOA8xH2xlSSlKGuL2Kx3NuR0Ex3hKMyMDAwHQYDVR0OBBYEFLtpNZzu5hKA
+bgjCJAkjO9DZCZwbMA8GA1UdEwEB/wQFMAMBAf8wCwYJYIZIAWUDBAMbA4JCwQAt
+g8MQxDaBEAhtGPVgduypST6efHU61BURPOPeacMdp/cN3PL0aAnGDmy3qVzcuDHB
+o3njUmOlLkvRWt8HAQXo8rdusDyL3wKxX1pfKwYMge+q+4bZCnPS1Z0GwilKR9Zs
+zL7z05QmdDgP2b/EZcI1+hdjWUIB3LnyTFaFdVZNaHWJbOHscfa53m9nmmhvN0m/
+MgJHl4SOavAy3Ta7lIdvzOQSt4XkwT0TkIlB3u60MVGv9rOPpNgDDZMCFU1cFWHp
+g3+c73wOTVSUCWuxOHhJaEW736UxlQd2qMEMfalWMiAQFz0JXWoPK3zDNWcpXZii
+XaUh5Dd2kQ03jOdV/a4m5qHeLnoV3QmLZOfrVwkEzwFfe07xhtso5ayg6uU7MfH7
+xSVE57sdZpm3Se7/ydMYNwzKUuj8XWSwY6xDrNWlKdrfqcyq29DY6wr55bkEbRiw
+LUXYbCtXWUMkjgQdoqAv7dD2JlJ/cw5dRrrajh5o8/fZ1UCaaEXz2PTs7PHahDrb
+zLEYHOMU2TxWc59H7sQ25xz00JOQCieMRGweKJMmq6F//m34HYmnBKN5ZS3tUuXL
+NlIGyf5rGtYCcP5tU4WIxuhvHxMgX2HX77BSiN51g0W5pNgHpeXAMmKPkEILQdPr
+/tDQbTrWzn9VXSxnzXYUV7mekh6qCLAgmnYudwpJ7hxy/O3rngl2cnio3DsKgWZJ
+ONb1jkkHyWdVRP6QZyNvJSbGEd/iguuTGV3VHecEYnVyoux4r52sYXPMUWw3n8jd
+ga7cQPCFUxccUPw9A97tKR/H/irlAxkEOVAhddJIWzBVFOPCLEr29k2rdpczBuVT
+4VsFJbeNyGU1cpmfYi/PqndhjLSh5rrH1XhsmSgtp551aMoE3WGX+NzT128SuxLB
+W2d84RGFdABhfLJ9AYuNDCTGJLn7djxEeLUIf7pAvdje2IGchLdNiLjKS9VMQBev
+yGvIJgeht59lYGG++HHY7oIHi0QgZUM71q2dQ2wviFTdHBnw3AghqXEiYSCi5xop
+2W9xEEs0Mv0ifCWKhlJYqmvU12EgxfFrNf35lcIPydNUgV3RiInjnNAry4u80xHK
+08d5jeJy4AWRlorkMwSAOD2eAN3V8DHYAtwazel33N9gVYl9N7zI6lHA523TXvBQ
+ffQFZTQPVs/e1lRLfH5eHYvpwfJDnMH3ZVwPdZLAkZD9m0yhejCEsyYxq5LFgh1D
+5y2UtqELwGyB3BR3FBQBfOi3Xi4KSsM9a+8Uc/Y191Em4N7ldrp3ZRMghMHrBvB9
+xA4Xirt5rjN9fnEoQrMXyP2YR9TudPm551+5xjqynO0bHIrRUmlYVlpZ0pfTQ5SA
+M/R3WK+bC/QG/FYVL2dQ1k62F4aD29bTftc1gU73Aby3Or6aBksfcxTctgfBNpaV
+CH/3kdrzZd+0mfOn/SxkEcnOVEJHk48BGXJYEaFKAxl1WKDv7yxw3DwuH2GFKRbJ
+FoeF2yCvbsGEO1rBqF+bGEvlUvtXdsC/x+v/Py+rFk5NXiop1/ZToJPG8qXkMMm1
+y/Trno2i9MTQbN16BL4kK2dgDc1bEFmAzHopacOYsqri2NRNSET35qZ2Jd7CSz86
+ncj7ko9bnWQTM2QpyW6aDTeY/ZmTXFAv9SJo/OjbG0UTAJZvDbn6qcOQ91umhDeN
+njtKxS9Jr6iimr8dUYaUWgdqkRmt/6oJ+S0ppou92t2BHuEPSVkkj4oiJlHyyu2Z
+fHjv0ZCaA1AOmBbfZ+aRA5YQeFlEh1VjyX/l6F8VwXT4uNCUvQYXmBb4gn3/KpQ4
+T+K91b6W8O6xRZNYve556SMa035wHPWAAdU3M4n2WH1EV7nYHgi1Z2NTanNgINZ/
+6Q1lTNdZYcS3Vd5MWnwiWI7W5Q30ZjDMruj28NqhG3LMpV2KMcOKByk3GvHrvEVW
+Lti+RXzUynX6PU0buUibJuDQ/rCP6JKVCqX+SC5vpnLI2jImIbI7PUMuhDitj2fT
+PtO/MqvP1G4hAQ52sMhl+AYUP6fqVYrFi+xprRyNdKYaCsTq8Th4PVY8rCQtOjx1
+IpwLraknY5Ha+euM9hIpMs5N+Zhuq1jQBmY4XHKSkNs+qfklK2+d/I8cW8lVCHHS
+QTtAwcYqC0AAiR0RbpUdBV12lV9E3wXtnPxIBV+x0vllbpXntsoGXh5xDIWBUfmB
+HVMKwNdJqNpYlhCDOzKan/glOgiA4PAN5br+F5UIRTUpXlZdAdiOo5qhmQDZpiL/
++G0UxMqqRgmwMXeXZLL7twGwJS3W1GX4pOVK3pb3XcxFWAdiH0w+K04Zz70eDQCh
+MZPk7muVQ8/Nl6U/6qofKLH4D8d/K2Rxl3+JA6rp7Ndpaw3iYX0rY5OrFNh4DCiQ
+LsARoaTN7niJq0ihptLykUJ1WJ+ThdFFnw+x9OEwbary61kjBnTO05/8FgStyIAM
+mlYw5dsopwK+4NGm8nCAIhU2ogdFmChNvCq2oVYr/J1790hArO/MeiIUpWZfquaO
+ingnyvz/Yj5XN8YkIQnaWRSW//7QjtJqhQDo+nbVPIc3dXthMcxECd96xAQrXGZX
++hePeVW0keFiSMSUU/MAiNwKkUuhOvsVP97/AyGyK9JQ2Cosn9Er5mNtlRi23obc
+dfJfr5oWXGRB1QVNXpvKQm4RBk6p4L+QElJh76PM1vUmwfbZjVk1yenPk9WdY4I2
+M+fJb1w4cUjyUOzr3gtKIQMGL9fgtMZ6RC8RjBJ7soAnt8bRH2cmxDjKojs5CuDy
+U1oyPvYKJ6yZdXa+bTKxj2f1MNOZUuRM4w+i8b7m0l0/u6QwiRYHiTizsd70mZq+
+sezjy98YHfaFbq4bTO3eIFq0JpO/zi70ybOqxqr9V5ZWpufXubiuNFcTPkaB+udo
+b+z6mMTYE/W6ZwasXsJrd7ydZhyqxt+1y3pOBhQkTMOGMv9UarmDbECYsPDEzXZv
+tFhrvMfwBFNOzomr6JUIzjyneGkTqwKX9uC+W+c1U4ACxodlpgPUroIBMoPIzg98
+K4S/yjIhjFFW+GJ5MnwW9LCl3HiftHT4bahLSuAAGRGRrLQHggezHsVGyttOTpGc
+JOpsE/Hn/yK/eaZLU7lqI5jWkj6eWWdgO5HYjZDk3A1LIQyAqvF6YMiOi9AJaIeJ
+sd+AZFwrWjp4uBYxF9lXVzjXM76rCcqLNfl8H+H/Yn568HmMAlPGXKnWkp9zkw25
+zABbEBhJuitt7vv1eZ2BicuIEJKQW1nD7IbIHcAQ5RLTjVViSx/ZURKLjur/G0/V
+51E73JQ9qCzV4Nu9/VcXmKXIxrQlJhN9mmy7H5g3Ged9HTiCtmE/B+gUQdE9YaWL
+gvd16lMq8dzkvslQK4MpqAlr27YZBK+Ao8VNtyVjmu4nRfc6xQtUr91iyo7cJHrP
+H+5yT0jwQprhm9orTs6hAbye7LDDOcpG3XHZ3un+vphsxNwLmYANjVR9zsLKXkBm
+ykOz98TgDuhscxCTEUHLhokIbNDIT/8qkbJfAZbafFuAP1aLgfWMhEqM2QaHcVMG
+y+u0xAGsXewflMgrWPz1BRX/ZR448y2+d6jyZcrYpOgx+rEkhF9oOJLRuVA215Sr
+JgdGGck7GPCMOe8SEfMJN9yHf/1rjMsOhdY7hHI97tKKYpEL1maTIl9XaBIQX3fc
+cR+tTk3UOxbSRe4iDtbRlzs7/RxKiXrgfNjEEvfnnbKeyu8E6U4bKR60WoMR81bv
+qtJNZlg8tnVG08if73szGpNL7dJ+IsgL9wIGZCn+3cS+gIDGXDZbpKscPKzjZVv+
+HVlvrz3b9gbo6s7eb2+q2dmG0yi+YaHocvKvpHiN/jxc52qcItcnNrs4fx5XIcFr
+zhx2MQ9NzJ2TVWJHjixaJswc2ZbmiEE8xRSi2pOJZ6TVV8SuT7mRadN3SN21+YSy
+R0W/Gry//0SzJUvDy1poGu6VZMf86AxORqMJCQ4KDwlSNO3Uw+JYrcGgeR08o5kd
+24RHoz6wJducLx+BRO/n+WZh2RDNggchu6CHrnvEunB5oXutdTJF3oySirv5LP/U
+tMTGCoOKWakyjgLDf9/KEvTJXBVMmdklcmVDkDo8kr9xWDMuUYMGonLt8OqlI+11
+4HW4nwbRW9oX3FW6X7/S79EfKd9CC9uACGxHBUh8JtnvsygAnndim8KKyir5l/wn
+KxS4i67VPG+GDa4wNLort49bTyGMkxX0dL1OhbASfdJPXyQ2YFkwWesp3H7R+9x9
+TmmcTbF/PJjF8CLJ9WRqblfCHXfIXP6MZEsddzNxX+QI1kNLt50CrOQt5EXhTDy9
+t/tVxOmJP6fb2usqetBTVVNp242WUh3XRQauTv5Rpr782Z22n3iZ9ix3G0/o2nN6
+ivH5by9HVMoTmtNtTpqVXu7yV6xnVxS8tj4leLKzbxMlBKGy4su6qD6CSXtphGEB
+WABi0h9SeRXC1w4BnS2ojRLWDgY9hWq15FKqS7YNwcrp7Wc2D91+O3vmGJBEzrPg
+SDUZAtmz4p7isJgnBBCiFYWBOexMQ8q2PrwjTHP/1KOtrc4oFbhtF/49PV3C2Muy
+AAz5p5rwuFD2nAODckLcXESjiKLr52kfjBOcjdtTWZHHqQ8YehpcLfXRtLVEdrna
+OS2Pebi4cwxGXPZ7ujQyz+jAxal50LJZhBnWlml5lzZuCZrWB4Dr6bKeg8yR0uiG
+i9HbJoFa/V1FwmpfNBNzA8x65FDnZj8VtF4QFisEYiVe4eyMKYQKGlcDAgycWnPC
+7Q4j4uAOoloxaMkc4s9BZYJMQuZbQmP+D/n8kDq+MWuVIEznTazPUwXQ3UJljZac
+THX91cy4wesFdrzwQ1+xlXoDrPBorLfW4E0hTDn5jlg7kaE2SnrncZNQHKQEU6Jm
+NREO7OUVfWsO4rMHVkEqZwSI46Eaxq+qtj6Zy6yvuPVLlYDuIlWkCLSUlIM1o6TT
+G2iXqot1yn4Rtyj3XPLekE565+b2ZimFVlpZdaod7kFuclfMcOwjVREzafAwcrvm
+PjsausOPx4CqksKcabs+rX090w4m9Pq+UI9/x7WcozGpUDlNX7kMQs8DQQwbKqCx
+UAzApJejxWQjKqxvtnl76fCQFmzyE0Tqx4TW4koVm34czO2579Y+Eli03cKFpnIf
+CTgKSKIa9B1dWODWjDu475xsRnrSNP/PLJJ2kFMKYECe6btUhj/jxannNKy9QI2a
+CR5VHZPLC6tn9Tscrj2xDxNYuRjCdCGmnzMVbSZGZEc7lcnQ/qd7QrcIixQ5LGgr
+//L+YLcwbSsFv5vdeOznRi4QojnZDfk1lZOqu7dT4qTRDTu+S4Ci8O6XQeadcBk9
+5uSP8w5xFemi6GbSJ4jKFQs9q8FlhU3QMkeHO1tbcvRY5reZr72h9+zXv/4Qhj70
+x4xIhM0GCujYNYYlOZpUJ8Ruq3poQdvXgKXrdzRGk+/dVmRTCfmXp7ID2qwSLn66
+fFoa7E7kWirrr/bTD4vKQLKvA//QclHPoOV2LdKaHJtK0DJtN0EUVmacYKpLuoSH
+bFdcoNTlmX0vg+k15t2JMYaiwmIhXlxI41j+jM6FX2quFK1TU+HY8soSAk9Wmr/1
+Bv+4fXrEuC8PLtKqBq402J39mzYuHBd+nB+hv3W+cQHgaVepE43lzU7ug8p3zTin
+XoemDLhTJzKb48JUqJ0+kuloXdyytfYsWzjw6P5c4tFSfGbeTcF1j2j4L700Cr2M
+jI9zPj3zSK0aFEetL+bPLqV3ZSe8Xj1Ma4sl0D/L508aQVK1CKFNctOymp/SUrG5
+maP1+8AAEsphFkjj94eXNdQ6k/9q6uU64UBiFS7bA0gwqAcfFPO/9c5ml35K12UB
+vp32fkXgZH18wo66hnegbRDqPu89dTKcNvW2j4Z8XwAm+bWEOmEjzGglBCRKXhN8
+t3BujBCxUAu3GQuKhelNVZSeTYmNjWwZTa4viOtC9+oTl5GRGlYcCXjYGbqXp10J
+qs0+mVUC5eCY7S+r1CPpTh761X0OR12qawU0JmxszIfJklEez17ctVZf9HYrpo8e
+YMDWNf7Gy1oDwaI2lzlc5NckIXpgu2hdH1QHD4Ws2PKcLsvQ/HbS5FHpK+LHNpXz
+A6HIro44CP1/xFp8x+VAyoplzaFG/sQ1iwrQkJDnXCE713wnQLoWi1t4rzg3ncQj
+NUGye9OREfYYbfhBuLRzIX50k1dgcN1UInjoZ/2XZJqGQVyAYgKh9Mi5x60F37+F
+soLz4I+0CUWQXHjJm85frGU8K5qA2CVegY9ueM9AX7GlKUBr/rYABRDPvB06UWva
+CXrjHEmPh9Nj8ZtA7eMRTTurCIMqTmlj3NK9lUz2n6470/ESPJO6lSpgFlYAdIjH
+EOhNcuMlQ1mVK1zbWesSrYzU33ct0/1FQaIfuIoRylh4XPJvnDGFuz003BJ7lyZ4
+aWIag0Spglmp9hS8P8uCv+JCrVuXDdIqd79RClUbKB9YG6ARZkF/a8xU8orZzVd/
+EgUKkF3DAbmwTu8ohWxxjGtIZn9dZoQ4+co3HEkTJ+jkZ5V0f5gyS+dD8KxQjtOn
+5TqUa0fa7S1Pgpk1mg8wNvfhAW51E3dqTyS0fj7HFlleeDC8UB9H7hhJ0Ri/CRx2
+popEH8+/9oNZc0qFkR9ercv8YMKMts0pRKfsLW41iox0OxhhdSztDyj8OBtkBuJQ
+zBcPnN7dIraxVtgwY1Q39dz/s6Vmkczof3XnNRXBSRaxjP5JbjqArOe+fqK+R9jY
+H9uznEY6mjaN5wj7xN2BM1lZrz01jKa9GKlfsc7pWGF3KRzw5wH0IqsEmxHYJBS3
+N6pf6W7BoW05Wh124v/iDvZsAlkWMNvAEOwYFkBSG5vrbXKcoC+8CoUijJkVBFVs
+14YVQn0de6cWdJAGJn64c0oDr5J8muL2wsxjlTqG98ep1fgHNQ+T+d/ANfwyp/6P
+SkRE5AMDVT3QJNPFDARAl3YuparmBnuwEPqh0hxXP8tBJh1bmtg2pwJQnEWAB6Zv
+k23Z4a8mlHw4kEP1JJimvR6sZ1CCsuNgEaVv+qOU1ryb0wJZGNzlJCc4or7HlTn0
+/0xt1lahqKTcupgQPhxYS+bWubCeJlmnC646sNAzCHa/5XtNnjoVzmALUm3Nlcw/
+8jZdUvPStAB+n9Yc071puiIMbs3CvgiJH850FapC63rlYcwbNZS7cWw0PvfR80JO
+wv5Ei0VHTAW75fw2ngc6LA+0dM32/vz2YppoMHgGqZObDb3rXJSCm/+08Ju0kQLO
+RC6hyq4QkxNAkWew8pvE0oRnGktwfGvEPEEPnSeG+Fsp1vLft1nYbyGRzJxyVh0v
+XH4vp8exrto8FFKh61oh9LhmxOanE6mW0p7DFAVyKDB3n41d4vQLmjnsRjiIebXQ
+WPeaNAZ69OZBgZ9xJFduBogU3mC8sMglyzqPv5D5rFitQEcbahMA0Xriras6vcBG
+tkBj8mpnZjEHJMvWqEMCaWMqtW5NxVjJfsShExwzMQ/3L4ov5nrm9CxRuaoouBrZ
+/95FVfAE3PPIStfjjd2R7yISgwiczWvrc/+OMs3f18DlqZ1dMm1Z9mc1e28BGo7F
+3kFO80NUMRiO7sl9hvQUHYpOQk6QkoR8Cr7zW53NvfMLmR1RDB7TyWb4RBvsPX79
+/IZBoPUl0lB39HlrMYfCSGqmOflhLgcZjG42nRpIAP4y2ij4XQlUhxI2gR5YPV+4
+ALkvMSmsJmbED1o9HsQ9DikoZPw/S85WqNXZtadLMthRTpNaeP5Ty129SikWQFBR
+7BmbwSm8Nx5SNoyexk4A+iS+TkwxcTs7EB0kRiSvVSKtMGFzwJ39IHencVNLxMEJ
+7OfUdxExtw3tUQNcIB82NZA50QNInRcyIQi1PS5BO3xnCBulqrCBuY/oVVV822KA
+YVuiDaD2TPxKANsTXHYN/jf0MSG9iEpyCtCE6zbYVHJL/kZn6i97b9Wj1OLmlLa0
+rRjJtQ5fgWQmc/2WyaThBXfAPWkBQKpEo0rJMoE73LqpehWBNJ1gMVOUBmjbsmTe
+5AOMChiixZfkz09fp/H64EO7BCRC4STncHwqbWVlgd6HIFkjaAmJ2d79H/aj8thu
+M5ss2rJCN89R2syj1z26boE4AE2RNPJEpKbXsamCmhwKWTruKqo0jbGVW3z9pukR
+uY6KKEyvafCWsnp8gDt049HqgppCwnmmWVYmAWDBya7uf4HB1uyXVNcsjLvM9VJN
+dLLZyj3DuC2HnzANRtyiSumKUEqnMYofTF756y/l95z+RlKKA34skoeTGi7am/h9
+BQmbYisVq4MC8T/ivJApd8802ybbTVhgaGYTbuoImZmm9tJTII2InmYtEvvc8Ui3
++Dv8v0n2a9hhrPm04Li90P1eAEBTKSlZDHGTAVPAz7NaRYZI5Dhz0iFPlmnVU+qN
+p47Y1hbYUqXk7P2Do1EwLlpS+/kRUeblK6cOiHLaFJFVl6a1GqukDck87iQDHTfm
+ildKtj87yftSo30hQ2F2GNUhbyuOfe3/ZZf2xL7ewTcFa85nlsCB7eHhR8s1lrCq
+U84h0GUgErZLimXLRSR9u6fAfRSLbHDdd2z5njE4bKZ01X29m/OLdKiaeajCBiv4
+ze1VUZ1dvh98DGeIpPTHQohSN3GJ3NvgryOgZig307Hvmjy8gcCx9UVXpjKUmlny
+ijM3JYMTPgoKT0AgfE1ancWH8lTIvuOx+zvvlbyVdSypTlRjR718F2B3NLYtxlJv
+R++ScGYg8QoBmsKxcjLvvDUsyVQ7aMtT8Lfma1078Pte8R4AFPzCr8+aOUvsAa/A
+e+nyxpwKTCUaciHmtDSbBQH+s7FZz0Hb0NeGEpTOc8aKk40asMxqtpEz8BnThyep
+YJxcO22/rVlQbclHBIFDRIo7zaxPAAD98vzUVW8Vw6/uHUSUHL1GJbRyxCHS1hit
+VxfrV6wNJbnyH8k5/gkJbPbjbpg5EWwuRLmTOMwhVSwWzxK+Zi+aol+1tY383/QB
+J+W2Ds8e4HVCRNmCG3mbPQ978VlHQZFgTKos06otiKGnHzTa+H25nLlaGNOg/cY1
+kVTiURypy6peTDdr0YCKLT/7Y9tWPRa6Cc6+CsO0Hh5GC/0PRXoHMMhKG/KjiMyt
+bS3NQ5Q4UpaqjYNy56/4kcsto1zI0zKfyiHAPESBYtKgnJVlBhFtW4s4rXWt2d3x
+KqpgZJbMeQTY8bPT+K52szWovLdfXD5b5pxzOt/XfqmzRAV1ObWTtL8kqgexkgP6
+K60XWzLKFZk/0Xr9Isa/p8j9AETS3EzV3GTBOEgYb5FOGxkiWx+3weZcXhpL7O6+
+6V+rVIqcXIckfPNeAUWzN5EpuQobcM7iZUAybH4F8XeYJxRcXo0PW9/ylwikxUgr
+fP6HedR8K7sO5WSPZk9Mb09rBzpM5Pd+S2gCVOP65M26yDtHUXziDOSH0VvYWnlM
+/BKTa83VcVuLiQXWFwoQ60n+buH44DRUYb/JldgqeQJ+4ouDCk5PtR2KnFBhDTvd
+gtf+BfPjWyrNuMpZUqoTWq/RMRvILdt3XwnME5xCjY+cDH9eA8cpdtuRwPmA/PjN
+ZES/4Slkooa10HSxyLiNvj5bY/NYENX9azS70Y0T1RRO2Q7FgDsmjp58iQWcWlhm
+IUEGhqvJvE6oyXANMXMbvHWchOpllm3cyj85lbNlZ9O37LgPxcu9pRxkohWvqIHL
+X1/xvCs8KjYs5QSwzcDf7e+cKLGyX363jjviUqjTTo24upqKVsHPTSTGFMXXoXE5
+4UTUQISmrtHb0kEomBitDPCUdPhP97WlgCRDFPv4b2zWZ1DSq+/FXcoGIXx7Ez6a
+5VZchsoIyeOD8ZNLaGhYZxpnxL9dRmCfFm0ye5q0XsR5Dy7Y3ptkicb3PlzXo8BL
+EGJaNPA3kMDw1tcmWMW/Elg3y8G7eWmIrLy4RoXKOTvHIzsvhgv+4pVjp3UBi7kF
+Ie7ymxFNXV7Wu3fvGxDfSRuCvpqnPbtVLWprwQlJVLphqUYOKWd80DO/hLhgKad9
+MTFPoo7u5K3u+gwjSUxwQasmYl8oAaKqYN3ivx6y1eI03H7lYEbC78kG0+ADFgRJ
+zDoXGoPTQ+GLmxXcZszR7HgchBXJVw4blIvSPTkG0Nb6cFNE0dkC9Szf5QUDnpSY
+zsmabDNliiTU27MgPGk3kpCK5MPpTbvNVeNBY/QVONfImS+6xTyfz11NkgcBmauK
+PPwMTZmfNDFu9+MaigUMKHiPbtt6Y3fgyMPzkZ5jyZBYH/pz1lQO5FMudhShPVIs
+r9jZvmbdEh0Y4LfSJf8XNPMCY3RWZ9ZBtmulvE+wPNqfcoiLuefrmd9Sn0hgpBgq
+aIIJbpuwrd2uapQM1VLMnFbuSGxpJj1d8utgFFA/I09+7hoMgRZW2ghm6CgJGx9F
+iXcKOijUN41/AeImPY8Sm0NgEQka+7yBqFqzRufkISPD5gkdsykCTIOI6mnQhNxs
+4NcpC7YoRW2tKif0ow1qUhaIe7faEhrWMS72qoYDGR1MXqujsMPf6+jg3aXvk9nx
+a98mRTAtNGCnbse4ooKXcrjp8o4DOsXirrHcAW5CRS5YWbq3Gvs1ZsZ2/801Jf2n
+5YNDiOKUMpj2WJGARqaGO3fqkOV+Ir15ihmaWGL9iPUU4ihBY+D006r9Cb3tnHbr
+QKFHuL2fk5ULzLzC4GGZ/MDUfGimMlKsOzYBJaPF0vZcPnaHYKkygmp+Sr9rPFu3
+0azS/7SuRDSiG2eSlo7IdtgIQ99TgzaxNHT0/+GHBJ+QLWGGSMj/gXcdvcOFSahz
+mzKkO8wf5X3ts+hqg2zjPbTzLWVE2Gs/4thFmkM+2Iu8LaCK6M5OGeY4WzpDK9RT
+kSMSfN9XpdGmYtffESX0BH1pMRVEWQkTTHR1IPMpIccpqGTGob67eHCochcNblR0
+U9vgTalRAk+rsL5XCBDLapFU96enI1BIEHcmS5Mjhn4sPwNL2nLprYJeCYxMEzDh
+YAwErcb2kz5zam7ALlcyu/u/4yrpxcZ5bUEs6wGrnwvgHForEhPBs3ObkFJV1DzA
+fBmsP4Y/azhduBk1MvXD8jfc6CqlFFvraRt1Nuk1kkyLp+RQ9X5nsGnjSIvoGpuG
+SOpEeSfz52JJzwiXID63jqRX3RHTv3UFEh6Fi0ctv9qV8XGTRf39/9/9OpsK6w5b
+vYenFih0/Bmjna6sbaEODYnn90An6iqmMl4jMbQbth5h9nwgAJ3rnxWoWZF17wm/
+XmyMHSVHh3aG9TUcv7zswsn5JqtuX+B/sQJtOnCY6FYpdoyqCHZl9MDOOeVtGsYb
+18V5vQbeQdBZL9wo2UiK/cRdSgrF9P5y/Y1DFEFn2FH8PxO25a9ry2OYblGOxWZ8
+WZ8rv+SkbL+VwdxUxDnZSmt1aTGRjvnevQmiceN5stCGgQ+/RQTuXnBGl+aHbrRZ
+psxbS/lJOp/v7xIQsGc7AnHh3f97zRv/dLfoZm1sokvMaPrlW2JU0S4g2q1VmflY
+fQVl5RNXaytpYFfZiYMb6c6Hg3bBAZyfp758v1sG9EqjXB+NLo2I2HX7mUIzMHyp
+6VDMBurjxVCOkLl7OCKiJ0HefG7kVYIlsQMCRIizYkMIRGH64ATTFzkM1E1DlgFo
+HrdDFlEVOo74R10KuvwtyizPhx5mnWGbTz1pTSDJOEC+lECex4/kl3wJSfEbH7th
+Qx235aw87OqSmHKkVBiHSZ52NgfSRvR4kza73jfLJXGkd5inphh7tDdD8TvQGo7L
+2zB9G9TJ/lqDXkdN9fcJirJ2b60bytyieWB7S2hnh8MBfhJdCB0dnHDBdiuu2cg5
+ArZo4If99e3vcbFlFEUVBwOuzErVR5ay2s7xPKYju0IP+Gf2oib4frPIdZPl2LMy
+Z+S/aPc2+131zLI+NCf+Wcuc3eUBNmizuHNrcqK47oUVr81uckCfjUCL5X1TMbJT
+Gnt96/rKZrNRHwP8k3tnoakSQToxrSwY9wYb5TWDEvvvpJKCd6qZgrdq7jEXaFd/
+41fmykC50vFl7w0cutlLGscQjs/+dCg8lPz7R/vyJaLCIqm6KJf+BLARFEnn6AwY
+Yl56qJpruRaglZpMV6oCOQyW6y39SRBBiqSC/+kf7KFl9cll0Szfm6oj1gHEMgUS
+d20eW6fQ5ZvrbNhCI67srSChKeCz4Vxxgp4hVSQAFREC0qEnd7VXBF+cxnziiOEA
+dhQXkAtedL4148B7hliGUzjKi/EMS4y7VziYOQnwIl5RhKvnWHBcp4LtljdZ+96x
+FrLue3r9JTLhbGHTyCpLVA4JDe9dIeeq9xMlGJ62wuG48ueAQU9APKTYipj3E1Lq
+UGkhjL+fenreqiWKhHSm78okSpIY9fKbkKQFaLnjVC3fvo1V9W2ZG/KKsvE8uQDR
+45klTY7wDtKGYeyA78A4PxHtK8NgSTXqTMH2Bu2X4cR3NFvC3AHB34b5vjLHXJIU
+cCc+MGZTJCbPpl71sclaiKJjDnik+xWbyOS6lj9lmCSnnVqTHYmXIlD0yALV7vVx
+Jjr/P+v2qFlRCjHCu9iXfpCLbyPZlbUspnoACQwn6UHjZCb+eP9+Tc/BnE00PV8j
+NWeuQ0QcAaC4cKTCA2UYjYqKQ1Q3kUT3u/WZ8XvFpj3qX3pRjo3z5ia9dY3E0Luw
+utjtGa3xbPhIgrYWgBecPsdte14ZRpo6HvOTVC3E3ozKEdnG1QuRxT015rD6wefn
+8sSmfGlEsyQJxOyXGRAL2kztvEykk8DHBhTIyd/OqAj8rqGlcES7sxoZypRTuFDs
+BOE1dXZL+Bz4UbxLPeMkWWlTTdrK+DNsdOZe0B8iX7MDMkx1c8EEZUefWIVxv5EP
+e4buYUtvUiT6J+WcaII6EacuIPU+PAA05i5curbwHMTqHOgqU69RIFt/4YMuVaSy
+0FXTnUfyl02rfmPyTH9FBN4tHmIzeJzZjRkBOoGa76Q8OqADCiJCHhG54S7UIiwq
+YTSMQ/Xxw6xhsZZev1FGx6OflOCUsR1T5xRSbLPTe0BPQ9Xde+lI2b/6iDXZn8IF
+1qVc2FYQqov7BdFR7geH3CZ4Pv4E7PkGoNSwql0Gj9DhViVrff0GLsAt1Nry3xf5
+zEE3tj8vXrfAOZxJUAtXKM97M43GiOOfi6czTOKbal+blhoX0hqDfhmP/u21zJCI
+JGUYUh1z5YKYZozLd1jbodyN/OkWDLOJlrHd+RovFZoDJFP2VV3Pl5iLTwcRXhia
+28QoUYPIOd9MwfQPKMKrkevr9+OnAbBpvNRE4CabW4n2cQOmiQodBasguZmPHI/Q
+APuIjCv56IjejUDC26kuod/6jFg98PuqdvZzLa7Ph7QAR42opCDGna+63KOHTg5L
+Cpy/mlllj1c0j37W/XVpeihSBfmwyVlIgIOD9zJNFZAB//EL+bFx9HWZGt7OS0Mv
+2IBtjzBP1dnS3I/MQtub4ud8PGkwoGthCFEZ/skLUba489IhA8zfi0ARi4k9P6ZR
+9pXiQ9UEl0PEeYul7wz8z3WHwhboYYwsuq64IwCZd01QrZBOv6hONqQZ3oYxirAR
+Urhuqre9PDI/WjSMJtiPOvuEDe7/yGKsDsLDaKYy7HEBIiRwQsDuVdQC+7g2TO0B
+1+CGNR7cW8rdpH7RoJ5b3b9S0SranNa9NAImv6zUge62NFzqa3TVMZja5hVQCR++
+9dsda3USxFoocIUpogk6PHqGxpbFW4t+gyq4M8HBNhwg7mIYUwS0dxR/A1YuqBfM
++E/cH52bDx9VPfO/IgxQEXvvubjgu9xrG9+sdF4HQAo950CWX6n5EDYwDIFijhFb
+BwB9WDZUkJp5H8P0XOW7e/nCjUbLAiwHvm9k3hQEo9787CvCqi+Cp5xac+vRIhmG
+zglprJU1eMTuvHyMRaemThBde0vE/spHkhCgM2v17WBTSawhUn4DGC9w/ISlaSmd
+1AvibYKnRw3eE04srLL621W7gy2KXn3Z4CiX06Jlb+5H+OFtAeHQlpsUuJqTrWg2
+89XwAvL/zuC9ItR2ygGcp22ddMEp/rq+nmH4f2p37waY0DK3ftlQXo00uTqOqL/q
+iXLR2vcvBKi7J+7i8257MfUgOw5kmn7Fm8pwPHyCkxAGMXou2qLsTzgPnb7tDTr2
+Qpippmm/GOsW3zNX9IQFyfZm4P6k+gSaCjQGipA4ylgBMI9SB6oJa2c94VdVjtFP
+FeCWGwIrOuFjGNV2VaSKdv/xdgVjAc3SPX+9sd0cUTgrOTupopVfJFDzJORNGq4F
+8KY/Y59KseAY+ol2bZUs6vJQgHKaoV9At6j0KxEf52UMGpw+5fPYciEHlqn7uCA3
+xykMKT6RL5rQxsw3+hgD0HDjEtdAVAdK8X46rw1sFh3ffW4mUC8bS9fNkRW+vEuD
+1fRWng6cqjZuol74d5jbCyKRbhB0VH1KmMOpw5jewoWLStDIb9qZfKELYXbiS1ow
+tCYycqN0QrAuVgQpV8/hAHnfnHz0hXZJkGnNJMJnrVaPDhdKgzIDxydi4juaanDn
+FzwNkv27kFQFF/1DjIjB0XGsWkxegxYHiZhs4ZN06/EKwBW9Bv8atCRXWKjyYpnG
++Zp93sxpTkDPh+jT1tcriQ6pzVQ5tuMSYRHCRR13p/d/07wwlnttblcv5Go+vEW4
+i3GsXH1e+uwWNM8cswM+FXAq9zf/sF0tATxqOQ5S8lLvDZVll8U2Pj5jWfznb7KG
+HpLbYiYuaV+k7NMeIn6GUsh9NthGVASD/5Wbge/9lb/N1OJlq6vhkljUyN/6bqXA
+fVWFEzxCs0lfKv2cqeaIZOyNHbGudaAFka/Ip9x7+GQ0BlL94SYiJcTUu/qtDcjY
+VcMDHMqfol3Tf00iiV2WI/AbofCawqlgpM6Ux6Mrih1bgJs4rBdiyhOGoNL1K/kI
+65H/jB7mvq/V5AVjz9I03deOkjDrT56nGCol2Q5TQI1tLTuCOKFsGcGGBeY5fd/6
+CAxy0iHp9BKA75JLfEHa849jRUsrh1KGoFlwcX+rVRsUu9oPDTu0QakBHkkcjpnL
+p0DzR7475PavjFYpDlelTMD0jIPtRCMKDuzRH+2cDnDNHc1cGDNJThNhaFrzOJxv
+MrDthijiJsZoBV1c864Kf/uvbUERUPfg/cuPZJJ1g4ailyqhNFgpRRA4FR9hG9/R
+LZlk/Y2acnJrctBNmLfv+ruKpsfaPdVk+vtxLnMjh7KYD+UtaUALrUrY2VMEpN/P
+LbHwFq7hKEoAs9LyvUQfJ6Zhbq+mGvzfeDooPROMQFE7SWVVm9emX3QIT4+oSgLk
+Ox0Fd2N5cXCC0U8vZxqZ8KfxEcwn5TMkAxAnP5Xgp+6jMvmNODKeBNiKwOhCJIma
+y+MB54ECswkhOof4qvFpPJVIt8YFSyPa1E00t7YN/kyVXrp2Elpm/i0hw6qc9of2
+7C3vhQz3AcEGMdtn5d2bBHQ33rgSqme/PQizpC/skUAzqQB5fyMwN4oyxcU0fYZZ
+DvJXv/0dCVdQWD+xGFcJUX+WGwdvxyUnHop4shQKMVkhJozMmzA+ZSI5v8PRr7XH
+qZgRN+ruvv6iFjKFMPWf/7JuO4EHr+6zEuonHz7ALyePVyBoVN57VNEld7vQ+k1M
+JMu6AqTsP2xBWJlW0U/92F8IFOr3LYK/FQU+3luwuDvFoo7zfXKpZ0aKhXeoEidl
+9U+UlI43k7rvvqgDn2B7PA31UCYVYVPnawnvSzkC72o5FmoYZ67BMLHhSWzzb1RE
+U7OX5ZJXVNf/Hjs+P9kI19GkUgQJjHNkjKQ1V4FNf3FJeE0xfRnZavlgGJkrqHgo
+kJS5hNTprUOBro1QM0EvJV2JmA76KQDLKgJl6jEFjN7ts1mPpYprpjOHPZJEtNDV
+E9JO9Ey1ymaN+BqMx2+lOf3HyaCf0rNbCEcH9dJaPOux80M8jztInsB2DwGcbWx/
+c1Whe1UYeORqOCBTnvTyce/+TPolh5RUEvc85I7fy5FaqimNmWZuiPzf6J2B4dWa
+2IhCd6patC+D+MQ/jFNydSG/VYLu0tDRcErsDZW/Xs4x4ib9YpzQYAraVgRNBAVc
+A+6AOVbtWWN8N1KEa9df2EdXrNYrR/DehJ/7MI4gfKpVd3VgI3cgKaekPVt++DDE
+8dlY9SmEeo2C1+2MCOz55iUtxlqfSGKbygTPCHlqW9+00uR22QHizpQv9t02CFnr
+93/51QltQoOyHv0oB/ZFAHbSZOIj5W/qK3YaP0ubas74ecTtZYq9izoiu5+NrcxD
+NfFoPpW6btdSdHt2Oxppu2qDIFhTqejsZiUsiiEwx/7+cis3gUKL+/msEU2iZkQw
+yWhJxogNfKC6ZRZGj/k9R6oaSobgm4FBcQYQZ/xncOC4zKNaxA22id48b/9NPBLX
+2jjFGBO8noHjwS5AWmjvxdwFuoVNKhXT3iZ1shc4FW9+nCt+CGm+Id/+AIi9BkGx
+Pu9feLUvEHCN/SR36jiR/EO1IIAsSowwlYgKimkiPPJ/68H0hCE/zvRBnJYsamLE
+LsvTLyG8o15dXEQH5nDR/vK/cI9lUxK8aLom2kz19BZ0sYM3Ed5hgWQEssK2CQI9
+XZahGZio8ZK47i8oOBxOCxtHFYR6rTIPRwN2bNn/Z+tZweLTyeS5P95hJIwk0X3I
+4GI+dig0ua4ASd3F/mqALSThP6S33MQlBJazuFOzlZ/c5s0UxMUs9nKRJaC8DHY0
+b24cfofgQrOsSvU5dTfIFQDqfZklpCCD4WS0OaIOUETeVDhjuJP1yGWhobocJ5wD
+F9WjroxFg18VcCHvuKCtrRTMWF14cJNiJZCJFZqhvZsnPbDhB4cwgRJTrH6ollie
+es5VNwCW687gRDdvbXBaQAatWJWH+lJHFVIcp0u3LRdapnDfJo8YYo8SLX+Y1wBB
+wFL4vsZY2y6SFYlhbDGv9b1d+Dq41PDmvOmfUYGR5ZknH2l5lGR22+oyEUANKv86
+vSTSxVB6eXUmqlcYRMzLNrr7ftG9Iu4mB5eqNYidOp9KH6QJ29QiK4UgaP4AX/yt
+j42OC8q95ANOFFKpAwYhlyeZfIQkYrxcdYMJuukoQp3czkQ3cBUJyzzO5tcOLjUR
+2tzCMZM4yJLN4UgC+fI9Isz7iOBoQdKRtISYdzkUuZ4ic3h3qLusf512HC/ho0xf
+9uHaL1zJ+1YqmHINTknVcW/s6spHR4F3TtzVIlC4mZeIYdse47oYgaR6VocD5CVS
+ybY5Ys3jKT+gHowTOrqckuf9ZPhTK6LUx+EI/RPVmULBgKmDjtsj8DZcki6vpM3f
+thuf9p9+W1WJ5VYhZWO6kWuO3XQ1KWUvuuKPRqAGRVsck9uQXTmIVIQK9ZYacyzy
+y24WxdembFSHXTHZyyONcIVJ4qMUkn1p4RGEtieicqYVPtoe3MY0lIOVQDqM3Cen
+wFtcuX3tsY00UcOXP+XiR5c5lr33bQZIeapl/KMQMET1V4REV220F05CryNWGDfq
+ZmXdKI3MrNbwV0hUN8ePp/whX5L/Xhu0sHCfPDuvjTyINQTgUO1HOF2rqDUsuF65
+wjIYqr55gLpNZgWp2qpOKxaIFnqL4aizEHfjSQCnhnuIUuv5SigHi3g6/8OQv0uH
+knb6Y1nOFEX5W4VbfTqtpROI2TtxaY+tqtZl6oK+utE0Vc850X8tGV4kia+6FT4p
+rlTXfx3HiFAgsxEXP0ttTCejO+jbo7rDmTn1lWne1hiR0Q2ZtbN7kuH0KePeaDfs
+SM45CyzEEWr5uVBDqyrVLczmLhDmjrMLYz7S9tLWptJOOlrVgXXnM1wWjq+aS3JO
+E8Ul+agBT6AMzm/DXOPAvhxGhBqH9XsLUHhAmxQwOXMsOVMgQff5xY09YU6pbn+/
+JA6qLBBXuMKRF7MP4BDo3ZvpMO1PjDGoZoR8KbMd2uSdbO4ABAnxpg8obD1TPH5t
+Iqa+WfQp/8rovEk9gmcFfPJ5Pa9D/t5v0txXkRREenGuDk41yRehDfEj7p5jybAP
+4+01YQTt4d7ee/yWg3fZ1Ab3nxuXeDHbJvxGXttnj81prHbDYgOkgluEb4DjK86W
+hZJXNZWhCOYnLz/ts+133cC80E6rm9I3gOXhZrSgW1z8k4eQhsKyPBDXKpsJOENQ
+uPBpmtXUk9Jl8RUVOiuyzzlQcKA+4mvhzPYs3hXu/A8PoavY6JQr97sGgsac0BsT
+ZHjTY2OAeEgInz0CMEiNQHsYIJlwHfokR1mVL/GwZMvBAmnMlBCrUeocKGMTo96G
+fv29unx0grDQwKf0D3ZQNQcFF+7G0QBG48jLuflwd7cdCMeILc1b5M7q4Fxr0qwJ
+4CGBnL2dEhpctiyLZH9uo9zQAdesVjIgulMMSXCtLDJX1edIMSMMr3io2VniU9iK
+78vyGLOiFfxK83o409R9NXGDocV0NZyAFJhIms/qiodvrCBR89+kbWv9rp2Quu3R
+AA7KwdPsXamOgo7cbrXFqgcw5Op9AU+uw3K18NP/DWAVB89Go+BkQwsXp5UW9bIF
+CYeaxIA422jhJ25pxa03sOfS0J6j2l2bnpPd4BkUk/gOO69cCGLiIP6o5HMXyE7t
+Eg+qukWDYGzOUgFZPjdFmxXMpBmBxAX6LfXSAojf7fwstdv6q0JS540ZxtLdRP9Y
+nqij0nvGtDLXcPr2TmGaBXRBHr8MXFRuBmJXdA5qqJSa44Tvc+4ndNBPAXyPfTQO
+c25A64v9wHALLRWlyBO3lynMy1xSVuBSRCMsHXoYc4ang4ZRSqL3y8GNnAGNOPCP
+HGMxg8n2vtaaPSmeI9Xs8eguH7E4dasI4nZ7EULvuMnrUd/HakMTOmDw41utuZ24
+toly1NCNk9sq5HpfHF3ShZ3ktzcCFKuEPKGjb6jKQ6vWRI+kCgIHLJfiaPnBaZsk
+2hn+EpkiKUS62a76NDzEq9sbLNIelOX6pEbClJEqytsROOoEDNToihY9ZhEh3vjN
+WqQy/ipufAX/ivWpix+KStXt7bvGBc+kZbjIy49sI87pWQsvRX8kcFzFs1k5wUwC
+ynyZNnv3/3QOndStOcq6tbvA0wS255GIPkELqETWExdCIbJnLsIeOD9e2X+Ld0Kb
+S3VPjLsEMFaiB7umzA/yQRKqAqiuTd/AMf7kFHJOE5/aJdC3oYNQAdBW+/ABSqEE
+NM+0XS+nhg9zKTz2hkPRV68C9IQjpHNKr2Qnv2WNbxdn+ZGCPHbGzRhEssuwT3cM
+OJNBov2XnOTcjA9ILNg2NdhWv17LWlJKV+qEng6/BPcWQfjwS4TIBmVfAbj7qBTH
+fG3VGc+EZrZ4mCXSKoJOasGSKW+5xC8EuHXTn3laBnUmqHrfTNl6ftAEPPWFuHYZ
+i6vc+8dQL8EAPODFe/GcoTAi/zMFuGe6OfJ5GcUgIfnIR6amJp5R8j3UOtLTRTgv
+J3u2HD/Uh7UOSi6PwTWlkht/mJ6iLvzB9I8Q3k6Xqy4uthAykEWlSIiQy2JCtBNU
+i7fLYR2+pqz/BtEm3SN2zNCZ7nz04gwAxMnd/xQWKVT1Ob4vECVYFGdEgk8DXxlV
+DbwcWM2ZY8dHgzwC39btIL5bc2mansNPAdRd6CTPoYCAKRxJuN79ySwJr1fbBINo
+zOMhWBvMVx8anTuxB5u91+i5S3DAdaHtTIEWjUO6LxmpV8xCrRkZ6XMyqp2IArqB
+6kRwYXQnrJsmfu9ANLvJVHRcwXgLQZzKmm2dLm066frsumIg5jhDcE9AqpTBuXNL
+oniAX/TOzBkRH09nOn9817Do/kK7TnBsGGtjFHQkai8JbOAVNWZgWGUvNtuXFAnl
+0xLrQHaSgd0Kj1kGWVyoyf/n8S9vCKvY7PLHCXWRp3dignITt2FYT7g/BJRPEXG2
+VBtzuOZy9+O3l888dEIvZo7PhB/jf9mam8yNMEEyUkScJRijrTSUwua7HUxbUVC1
+Hhl/FZfknSSuD2lHyEf/JUfWpx5rknOH8xsuUYZ07xd6ResVijCJLkZcY/Cykc6z
+S0F6wJ+sgprI4S3UzU7ZTDufpH2jnCyXFB2pDVT3Y9wEObHWT7fP5dN6PzIyYsrC
+/MPV5+ToGIKKBqwUD8yp2GOkruGOqA7FgB/H0NNOt8bEg/JTgJgNKuDKP9Kn3G5N
+ATebkbUa4YoQdvP5DqZ3Pnzyjt2HZvzDKYSAV7Df9TqqzMLikSRL0azf/rbOmhcA
+1uSVdQhy9rYeWfDVxv+fI9tCamIJ/Q8INPZKyMpkoWFmUGYNdiRPeEws4pg8CcnE
+6IgfjC6z6paG65oCHHwgPJZFeLt38BvpT3wj5enmlDAJpGJAPFJICxP2I3V4SaLT
+iRqH+Dho/wFhSbj+riH9kOxTgEJ7G6wQpyRSvfhbq1qb2bX6FBFzZvsL58Zz2FgL
+8PkFGQF6Pmz43f81m+74rYpNCaif9Z1w3mC7OGdlNNgoeE/3CpXQ8ZvTe9pe5NHw
+G9ZX+y0/tTv9aEb3B63atMQhOlBMjjI+52ZZ/uchwDHb87aDXf5iOLhFtdBvJyGp
+waIj2P1HyYVpZlB9jTSm/sKr94z5jpOdx0hF29dgMuDqWoEiyEti8t+xGaRut3at
+oVEkyPTp2d+MRyAkMcGo16209xqdjqUEJ7Uln2UNjBW5gHkmBCYSKml5I7IPFXNO
+mPHovTHgutB/TKN1lyfJrdSkg3iAzpOqIbf87UOvuhPT/nHxrDRR654F42bsBCOV
+7FuBxxnNQRthxv4n6jw5Aj764Xj0TkCcZeHxRh/sxpTaGTj1xvZ923sc+CRvPBxk
+4rkJ3c0nvx4hOrgJnFH8ZY5EFD4tzWT7fRa0w1scpLbaNCo5DUayAqzWVSqVP5OV
+8i5wWx159auyQhxmmlRvawVLtRePUhvXqdvcOWRQWfU+XLqCtGOFeWbKZND22GP9
+kgZ9U5RrjJjXuNYPHOUuNhaL8x2fOefBn8dujPAtZuyJ8BGkMUAsKC4xinrfjuv3
+vtxTAsR3t4JcQ61O7UuuEyvWk0UIxu83zOWI6kCbRBkX85qbMTBQFHCny+vt4cBD
+DBhAyaPCqfdfM+aExf6BuBLtSOW4XaPJTjBHoCd6uQd9FqQ68iN062O5Wk9C+61K
+5JBKCQVA9akqH9nOiN/KIUoHSm/fQhJ64emSVukYGsA50UgNmcCMh5g61Xs+dx0f
+gEYJEdM3UnoYpo313NTrT0nz9DlosLoaEHnuqSdEV49sge2GqCaEYnPt6klrK72C
+k7IT2hGe7eELkD7am9oYxTMfgngIJkhBftflUJ1UdMOmNbT3HHGBxbbzKqLn1w/q
+Vi6p8Fe4eOLstQ7JPmLuqSZ3m8Ky3B02B8KR2W4IyH9xo0pW5KWZyqP3KVdOKR+X
+ujZ+QFIFMmejM0E8ob7572YsWWnTVgdmbsd3npzT8T5HxkZPxRCGCY36XNDsjNho
+IObwoWXZj+FWD28PYDQu0M9c5SZNXVTEEX1CGcYKQxo2r7QEEGtvNtIjznZ5ILt/
+E8zwl7ZNWAbOrIioJyrXiJlLfXBiSZVU9phul3NpcnIg7WMjHL2aRHJjHGe4x3QP
+icgYH4gBhPdzrmRxDMMe+/bSPsTNI4UdgdZADoovcj+oWX1lSrdDEc9FKy2mhBTv
+/9jF0cdDw3ZSGKNFJFDECyx3rQn6hg83203ySpvyiBcZDdjNB699e4V9AxOLTuxt
+ivDLtEVEJ6bhlWbm04mgBHMOqi5bjFbiKOxKdkOzU6ty2YPhznrWGZ4r8PV0XfjX
+m7EXKEGZyH59PCrztyFEnBwylbqkrAyqLmEiqdy9DxKZ3iAOg0bEWyfzMDhXJh6z
+wY7lzs381eoA/b69VuHWG82uVeww+GMrUpdzuhWTSzYsvC9ASDgR5uU1/iU9HeFk
+vG26M5hD3RYROPvnGyOnoe4LLpP94hP108TSGS8cCvGmnhf4W47IWr4rzSAvO3Eo
+2trqjEnfzrMV3CEx+s/KtI7jvt1ODHSv6s76AcO+RnoZjIi1GznWhSB+0U+V0hkR
+P9Ghms/DO04HkQ8FKkkjSKvtlIW7tNqmbSSrTVbG1iJx1GtZpp4V5SXO3H3Q/4wj
+i2Yt2JgXuFu+5gNJOb5d+j7aiQRo1Lk0OUdNZy/Wf1LUriikGFEx7dBntCfIl0JW
+Fop03L7nTMlxprYqq1jq/pNzUGISCkEmbD93iQ3AhR1bJubuZfA64L8o8mnmWxGN
+/ZwhYfGlmkg5nGg/k+L459SYYWZJWP6wDRzX0uUtofi9u2F9KxlG+UGU7l3rFSt9
+tzua1wVtUtAKvKofb+d8eb1hffkJe8vaCyVbLhs4HB2OaEdrkdX1LsIX6/qFi3W4
+tQrc8DSwJimeGzh3OAumrVGDFf1Bl9Snd+0+aMq0UPwxScudJm+sjDovgjnltn08
+9WiDX9IS4ukBAM++mZTeT12TrbLl3NTQ973qxOguzcMND2ZJ5WLsP35/IQLGXpC/
+dd35nWCD1obHOJbL9GfFy3943zxVaMYhpS9BQe5WcwFan++xBR06fOG8D2NS6hLT
+RPBcvS6tslT3kDzlgjvinliv7VJQ4+l95fKfbrAoYaBfH2Xtn+XIq87Lebnep9j2
+3yIq0HEWnvT1mkkxJFkdAdbbbAV3Hvih9GHrRYlXU84VoNf5lQLPMloBTe1nGOlp
+rxJtcX8Mozs81XQScPpRp3uQbkQl8JpGMZqwaC7S6tYsKM+8GA7MUzIWR1bItlrE
+nQS7ZVer8plxo+tDO08VEa2yxJkcN47ObyaJyFP6dy69N0HNEx86Dn+SYy3hkqGX
+DpGe3jH7AyIBIdZ0ulLQE5Y5VK3T7IWQ7HnywfVmOjhL0SGegPPV99mRK12g28In
+flUWWH0ThCo48b7RQut3h4dYKwd3O4wTYlLQocBx2uArfhUDL2bDtB4bDDq70V0=
+-----END CERTIFICATE-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-128s_pk.pem b/tests/pem/openssl_SLH-DSA-SHAKE-128s_pk.pem
new file mode 100644
index 000000000..33c5aea74
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-128s_pk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MDAwCwYJYIZIAWUDBAMaAyEA8BnVeEF7x81JDltLtrpTDXC3ld43Kug7uDDYhzpH
+5TM=
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-128s_sk.pem b/tests/pem/openssl_SLH-DSA-SHAKE-128s_sk.pem
new file mode 100644
index 000000000..d5f4363d3
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-128s_sk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MFICAQAwCwYJYIZIAWUDBAMaBEB7rogexDBq0MrVndGhZM9Ip/DHPf3BMdYs9eML
+zm2TkPAZ1XhBe8fNSQ5bS7a6Uw1wt5XeNyroO7gw2Ic6R+Uz
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-128s_x509.pem b/tests/pem/openssl_SLH-DSA-SHAKE-128s_x509.pem
new file mode 100644
index 000000000..1ef402308
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-128s_x509.pem
@@ -0,0 +1,171 @@
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-192f_pk.pem b/tests/pem/openssl_SLH-DSA-SHAKE-192f_pk.pem
new file mode 100644
index 000000000..e3f1efb56
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-192f_pk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MEAwCwYJYIZIAWUDBAMdAzEASaCrU5yiL0A/0qAg5DZqoqJwlTfYvfH074NLp8tE
+ib7jde0ZqQL2DwQe5IdUFRfI
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-192f_sk.pem b/tests/pem/openssl_SLH-DSA-SHAKE-192f_sk.pem
new file mode 100644
index 000000000..126800e10
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-192f_sk.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MHICAQAwCwYJYIZIAWUDBAMdBGAfLiGWaHJHuK7cRkilfIq7ElzRSb2p7Xd2oCxc
+SSbC4BOc2hl7LoHHV8U24okZ5lxJoKtTnKIvQD/SoCDkNmqionCVN9i98fTvg0un
+y0SJvuN17RmpAvYPBB7kh1QVF8g=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-192f_x509.pem b/tests/pem/openssl_SLH-DSA-SHAKE-192f_x509.pem
new file mode 100644
index 000000000..30382254c
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-192f_x509.pem
@@ -0,0 +1,751 @@
+-----BEGIN CERTIFICATE-----
+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
+grptOIIa1c2OoAFULng9
+-----END CERTIFICATE-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-192s_pk.pem b/tests/pem/openssl_SLH-DSA-SHAKE-192s_pk.pem
new file mode 100644
index 000000000..4083607b6
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-192s_pk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MEAwCwYJYIZIAWUDBAMcAzEA+kg+Uy3W0yajj+T92AVw1/0Hh2RHXP4LhkfBLyeL
+UIzxIfUFfvwu+a/kPS3Ke0Ru
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-192s_sk.pem b/tests/pem/openssl_SLH-DSA-SHAKE-192s_sk.pem
new file mode 100644
index 000000000..2bc39afa6
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-192s_sk.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MHICAQAwCwYJYIZIAWUDBAMcBGCPViyYzFgskhv80UvTD6F4foinF/Z7CqPbHjI7
+oEDz+w8HDewZ3rddSoqr+52t1T76SD5TLdbTJqOP5P3YBXDX/QeHZEdc/guGR8Ev
+J4tQjPEh9QV+/C75r+Q9Lcp7RG4=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-192s_x509.pem b/tests/pem/openssl_SLH-DSA-SHAKE-192s_x509.pem
new file mode 100644
index 000000000..c4d9ebce5
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-192s_x509.pem
@@ -0,0 +1,346 @@
+-----BEGIN CERTIFICATE-----
+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
+rZqLxMITFhoQbSpIo12q
+-----END CERTIFICATE-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-256f_pk.pem b/tests/pem/openssl_SLH-DSA-SHAKE-256f_pk.pem
new file mode 100644
index 000000000..358a1c7e2
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-256f_pk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFAwCwYJYIZIAWUDBAMfA0EAjTMCf7dSy7kI47DnDyGGhevesZO2WAm/fCXO1ka7
+NC8qMaaNBATfQfXJu9n1M5r6+diiqzPOI8QziN8FxU1oow==
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-256f_sk.pem b/tests/pem/openssl_SLH-DSA-SHAKE-256f_sk.pem
new file mode 100644
index 000000000..39a1fe59b
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-256f_sk.pem
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIGTAgEAMAsGCWCGSAFlAwQDHwSBgMVZdsa0IQvt7lOKPYtawZ7J35zp3zIgWQJW
+ByhZ6BVrZmBSdkTD7jqSd8ErsTyiF0uwimICgrpGbRhMvNptbdKNMwJ/t1LLuQjj
+sOcPIYaF696xk7ZYCb98Jc7WRrs0Lyoxpo0EBN9B9cm72fUzmvr52KKrM84jxDOI
+3wXFTWij
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-256f_x509.pem b/tests/pem/openssl_SLH-DSA-SHAKE-256f_x509.pem
new file mode 100644
index 000000000..2549bb0ba
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-256f_x509.pem
@@ -0,0 +1,1047 @@
+-----BEGIN CERTIFICATE-----
+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
+RQiRkVSEidG855BHxoJD
+-----END CERTIFICATE-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-256s_pk.pem b/tests/pem/openssl_SLH-DSA-SHAKE-256s_pk.pem
new file mode 100644
index 000000000..5a378186a
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-256s_pk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFAwCwYJYIZIAWUDBAMeA0EAHOI8wNemjExTa9JIB1MIM3BnxVWHGLj8iGKNqvgx
+x0aMwmkku2PtPCiH1LSE+/yS7/LjZW8yfdIHHcAM7N6O5Q==
+-----END PUBLIC KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-256s_sk.pem b/tests/pem/openssl_SLH-DSA-SHAKE-256s_sk.pem
new file mode 100644
index 000000000..9fb5847b3
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-256s_sk.pem
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIGTAgEAMAsGCWCGSAFlAwQDHgSBgN1wX3/vz/MUGwgQO7WFRur3rE1LPirFjDje
+e0dVJXjN/sBEfELWkUzx7jo/VtsWkwyyKhjtYQFlAF7hiGK4R74c4jzA16aMTFNr
+0kgHUwgzcGfFVYcYuPyIYo2q+DHHRozCaSS7Y+08KIfUtIT7/JLv8uNlbzJ90gcd
+wAzs3o7l
+-----END PRIVATE KEY-----
diff --git a/tests/pem/openssl_SLH-DSA-SHAKE-256s_x509.pem b/tests/pem/openssl_SLH-DSA-SHAKE-256s_x509.pem
new file mode 100644
index 000000000..5e966d32c
--- /dev/null
+++ b/tests/pem/openssl_SLH-DSA-SHAKE-256s_x509.pem
@@ -0,0 +1,629 @@
+-----BEGIN CERTIFICATE-----
+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
+gYNsrbXSmSoHL0+mtn13
+-----END CERTIFICATE-----
diff --git a/tests/pem/pkcs/openssl_ML-DSA-44_sk.pk8 b/tests/pem/pkcs/openssl_ML-DSA-44_sk.pk8
new file mode 100644
index 000000000..69c08c8c9
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-DSA-44_sk.pk8
@@ -0,0 +1,57 @@
+-----BEGIN PRIVATE KEY-----
+MIIKPgIBADALBglghkgBZQMEAxEEggoqMIIKJgQgvd5Y1xUMhIaFsmkcYL4QMmAd
+/8aArk10HyjogirjhcYEggoAVkb62eZH66TnERpY5jYQNmbJeZoTtKWb5rTqftA5
+E1SaW7PRhMzJBFQ9GxZVPxgj9gAqjqQgk1eikz/b/BslPZSUDafYcqiUIPG3LeRH
+Wpod2n7Abi7n/PAkReyvZlPhSyIXGDcqxMxgC6A2rfzy9rQ6/KyTTtY1kYthNjO7
+9qdcFoUQI2ZJIg7AlEgjBAyMFpHbNgBUImZDtCGMSGDDBnAYoGCQkC0MpUSgkEwT
+IIJYQkJUiASUFBIhA45DFiCbsAWZQmxkqEjCxoQLMm3EhkXcOC1EplAkwlGRQA4S
+OEACkCkRFUITAEVRsjCJxiRhsDEBRIVKRGHTOEKRBBGCkkUaIzHbFA4EuAgLMyKY
+RmGChoEJMSiaFjIEMUUQFAjEMkgJCWRQRg3bkGFCiIjgKCgSshCMuGkYkI1QBIIC
+mCxAQkgciIBbKBHUCDAktJASEWgLslDUKCHDoAVCBCBaAgYESEmiBHBAOJHaRmIR
+uG3ilnFDRoWIhgzhEI1KQGyTNEYSqFDSwGXDMEoURjBRkgkDFW7jmGkRl2nBQkza
+wDDJgmWkSCUTk4VRREACFI0aMXEbFJHMOCaRtA2BJGIAOAybRkgcx4nMBJDDwAQh
+KYLTiEHDoAQEiSxhxHGBOEWKtIUAJ4BLoCgbAIALGUxSiFAkkZAJsQ2RFEIcEiwi
+oBFMsjHbCIGUBHAgQ2nboIwAOZBRKDESpBGjlglMQmAgwm2ZiCGjqJGCwi0ERigZ
+wpDggGULNWIZJQzYsgUDpgjERIycwIlbNGkAiIULQ2gSo4HLxkjAsEgEiG0jFlBA
+RowZN4KMwmChFBCcwCWKtHASFi2AhAmBpmibECihIGbIAkVgEipCmE0ZJWRUQAkT
+iGxLMjKYsG0iSIpYxowSx2ULkSnguEwEQi7BgJBTBgnYEIFYMCJbgCkhQigAEGQK
+mEkUEBETSFDYFkFJEIAQJi3KQBEUxYzcQIQBM3ILpmFhkIkEJXISAiQDmCkMOWUB
+E0pcpgDREEZQQjECJ0EcRFJBIERRFEgkQiZgRDHStlEUpJCMACkKFoxCQGGACIwa
+pwXTlGUJwmDgMCQaCIQMwSkawkmKmA2IsElahkxEOCrbJpLgggTkFoBiEhLSKFKI
+FggIGSVLwIUgRXAAxDFUFGwaA0HhOCHJBFFIMnEBtiVUIErbxHFhtCigQGhiyGiS
+NGDyb+exTM9WS69yNB0yaJj7ZM0l8OJvRwod+CYpmCHueUiKD8UhYUhpe0XsKRAJ
+4j1h0UZx72B6gJeeXc4cXJSdkjQw3GnFDvU+DBasEPZXOd22GjlX4/w5jEc0RUPQ
+i0nQtN21m9Mh37+6gb8hP14mchJcsIa3h777XQ2x08Lzt9UxdJLhEKv4vHdc3Gm1
+q/Ofy/Wvu6hiDFPwZrIzGpNxt6kTV3JGU7M28Pxlce1BN25BZupwZR7cbYjumRrc
+Y7/Dny+cE/+iAgZywJQ5mlJkVcJi2pMHJAP9nyzIF6yc8kAhIpJWovf6aXmVotWO
+ZTSxHdxXx5M1mxPZIkVB/xvMM/PMjQdPd6QyKcc9FRzXoFYh6lHNFbbHnW2B4sXt
+bcaAA/pqw1QqFekZjmEP5efWPZRkBysO9Tr2Y7FDDmYhShxWaISkMho+FY+NphMS
+9JHNRMOH7Zr9bK8FjJl98xFCUcMu9og77RWo/L4eBK6fqUFRxp+8INspFZmOjzBh
+OjasRVfTx1tQfMg+AwAuDVl9pJMyZJoMjSRO/HyOm6tHixw4U6dVUjAuvmvXIZvh
+xX6Q116QRBY3UQMlKFyROS9w8mjrQVqebCjOwyqZZQporLgHlAAjEjbjMt31v9Qt
+TOP9p0Wmy6ArAdY2yETeC8ZpKuoWME0wT0YKl2IEKT0kXQKfeSQHRlq9MQgvm8gc
+aGmcb+hi19lzXYTuiY7A3yyVUdDSJsy635KQ5dAj8MOUQNCXwgaxwSUH6iPsPna2
+HMXkHkPbwAewawYxf3bv+FA84AbGmZJL9VO97oRTCavRkJwDLo8XzN+uHXIoBjvW
+E3VNpmoUt5T6t4HHRN/6A6jErcTHFmuXI+nlYB+tfPEZgph1nibnR4t1wsDKwVHY
++/purrBUG3ZkxWMQzx4HEij7cXi5Eh/5fuhBEdAVBuou2W/wqd9u+W0VuAZOLARJ
+pgBRtbsS0ONTagv7B5l5L3fbuYwYG13sgOWsZrlb8XQkISap7+KRsSJPUKAzCdpG
+1ByOpKc9gsbEQjCbJaJazCtPK377QwCjL8/mYKEaNECZJzQ/m9FVUkhO7NDsdthR
+H5qgu8Sy/1iy3q82bXg5N9VNBm8+Tz1Ffz+4fHCUbo5RTp3WinLSGt5bh0mzdXXu
+ip5kJxmw34fL4wzCh2sN45vk294TPR992yC3+cKcfIUkjDnn5cJZLbTS6MGlJUiX
+FTL4mHfqsMWXADQ8AOBKYoOFDSZItuWNnl2i27cXkY1gN68sifiRKuWnz/oegk6V
+n1SdVrkZKG9AhmlDaaoKiVaZCjBmzKfhrhjwZEkoI6eRSKUjIYdZHuUEgNjAeU4y
+mZUv0ZaGGwe8QdYiFd+exP0j5QCYPUDyCiY6Bfej7id4/cVjMExZ4HPCFF/BM/sI
+xRBTepQW51wUWLNW8Jvj1G9K36tflNMtB3cTkPf1TlEE7woJ/FYmHLvWP7eEQc9K
+xR9i26WQn9cp3YDiL9ePXvoBXK/0DSbalcwA2uAGIX5CvOJ4Upo6b19FSxowYF55
+CmO7SaKvfDDr8WtczHsVa8Tnz2Rr2RecEdD0p1upPLfhTKR6k6VwNmMXVmFctliP
+RJsfLVeQNwSfkNGvbJtuSVSnMzamUyxHYmEbW+eQfJ/p/5ia3Q+5YfhiRadaC+2G
+gP7CE8+QmueZaa3pk0CW6eWeoVX6A8Ct+p/naWYD5CJXYWD2MqpdXS3SYFT4pqmi
+bRCQU2rxdp6FLHG7C2Mrzgxx7U7crAjLp3woEf42piqq7y82S0TfTJggNqxZA7LD
+NF/HXRPcVK0mJXZ+YiqptKNt1xHIDsKhlStKUoVHYHcxh3Go5IFr6ClVoTuHd5sq
+HtQpGxaeDBY8uKgn6Yt5kj4KT6Ca+KY/OXthlxsIWCQaKDnmKYdR0RdFUaCBtOTG
+hgckyD+jdrcTDZgRM/oi14sIItP7nOmSpk16qGyrXuzZrNWW80b1dYwsgR3fVdgf
+PlBHN5iES58tm4OOD/oCg9i6IeOuUCWOT+ZA2wZIdXJOlaU+QD7oikKuyPYYoyrG
+sYy5JyLC8PL3xNSUyWq/T8vuJQ/xhLX4/CBnbKVyZTZiQ3bCohK88ShY4WHw8JpK
+iGU2B7A7K2/Ox0tPWJGVPN2n9D4JPztMaQPWlWxoe1QxeFOuCVEsdNvkBcnkjwAX
+WYlul2zCV+ZAT1hrET7U6aG/ITIUvUWf6B6hAcm0mNVUbw==
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-DSA-44_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_ML-DSA-44_sk_pbes1.pk8
new file mode 100644
index 000000000..8a4ecae78
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-DSA-44_sk_pbes1.pk8
@@ -0,0 +1,58 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+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
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-DSA-44_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_ML-DSA-44_sk_pbes2.pk8
new file mode 100644
index 000000000..2825d9a69
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-DSA-44_sk_pbes2.pk8
@@ -0,0 +1,60 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+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
+cMTjqJv2LXrC
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-DSA-65_sk.pk8 b/tests/pem/pkcs/openssl_ML-DSA-65_sk.pk8
new file mode 100644
index 000000000..79d16aa83
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-DSA-65_sk.pk8
@@ -0,0 +1,88 @@
+-----BEGIN PRIVATE KEY-----
+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
+YNHz506CNXEWxqm0vDoPx0l/
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-DSA-65_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_ML-DSA-65_sk_pbes1.pk8
new file mode 100644
index 000000000..12225adc6
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-DSA-65_sk_pbes1.pk8
@@ -0,0 +1,89 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+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
+X7ZLxOsZ4CKWZzXxSiI=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-DSA-65_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_ML-DSA-65_sk_pbes2.pk8
new file mode 100644
index 000000000..5f8b3418a
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-DSA-65_sk_pbes2.pk8
@@ -0,0 +1,90 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+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
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-DSA-87_sk.pk8 b/tests/pem/pkcs/openssl_ML-DSA-87_sk.pk8
new file mode 100644
index 000000000..b59bef518
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-DSA-87_sk.pk8
@@ -0,0 +1,106 @@
+-----BEGIN PRIVATE KEY-----
+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
+0WLBwubkJ64Ilb/qv20O9j1X
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-DSA-87_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_ML-DSA-87_sk_pbes1.pk8
new file mode 100644
index 000000000..e819bd22d
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-DSA-87_sk_pbes1.pk8
@@ -0,0 +1,107 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+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
+Hym9hLu6V59RWgXde4M=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-DSA-87_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_ML-DSA-87_sk_pbes2.pk8
new file mode 100644
index 000000000..4ca048c00
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-DSA-87_sk_pbes2.pk8
@@ -0,0 +1,108 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+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
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-KEM-1024_sk.pk8 b/tests/pem/pkcs/openssl_ML-KEM-1024_sk.pk8
new file mode 100644
index 000000000..565883d0d
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-KEM-1024_sk.pk8
@@ -0,0 +1,71 @@
+-----BEGIN PRIVATE KEY-----
+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
+nos=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-KEM-1024_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_ML-KEM-1024_sk_pbes1.pk8
new file mode 100644
index 000000000..f2885a4f0
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-KEM-1024_sk_pbes1.pk8
@@ -0,0 +1,71 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+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
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-KEM-1024_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_ML-KEM-1024_sk_pbes2.pk8
new file mode 100644
index 000000000..750d9945c
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-KEM-1024_sk_pbes2.pk8
@@ -0,0 +1,73 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+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
+PXtYMbm4fQUNJGf9J7IoFDk4NZ2/10ojzA==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-KEM-512_sk.pk8 b/tests/pem/pkcs/openssl_ML-KEM-512_sk.pk8
new file mode 100644
index 000000000..a88b1918b
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-KEM-512_sk.pk8
@@ -0,0 +1,39 @@
+-----BEGIN PRIVATE KEY-----
+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
+kXk=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-KEM-512_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_ML-KEM-512_sk_pbes1.pk8
new file mode 100644
index 000000000..7f3646465
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-KEM-512_sk_pbes1.pk8
@@ -0,0 +1,39 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+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
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-KEM-512_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_ML-KEM-512_sk_pbes2.pk8
new file mode 100644
index 000000000..e6c3b006e
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-KEM-512_sk_pbes2.pk8
@@ -0,0 +1,41 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+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
+KMz7bJ4dJ5mfexRG2AwIugCWK3NHezDspg==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-KEM-768_sk.pk8 b/tests/pem/pkcs/openssl_ML-KEM-768_sk.pk8
new file mode 100644
index 000000000..8425ba73f
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-KEM-768_sk.pk8
@@ -0,0 +1,55 @@
+-----BEGIN PRIVATE KEY-----
+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
+4KA=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-KEM-768_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_ML-KEM-768_sk_pbes1.pk8
new file mode 100644
index 000000000..52fc7f7f3
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-KEM-768_sk_pbes1.pk8
@@ -0,0 +1,55 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+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
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_ML-KEM-768_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_ML-KEM-768_sk_pbes2.pk8
new file mode 100644
index 000000000..3830720e0
--- /dev/null
+++ b/tests/pem/pkcs/openssl_ML-KEM-768_sk_pbes2.pk8
@@ -0,0 +1,57 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+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
+zVbnoCF6TO1Bb1hx4FcWxdsPK/nD/9svAQ==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128f_sk.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128f_sk.pk8
new file mode 100644
index 000000000..aa88ac0cb
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128f_sk.pk8
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MFICAQAwCwYJYIZIAWUDBAMVBEA1lg4CCurnTC94IstEyqr2rle53arfbjKJhKZs
+FBn2oNEbT6zRv6Uo/pR/l2JEDHz2Hyrrpwq9H6ubkZxr+Ejl
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128f_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128f_sk_pbes1.pk8
new file mode 100644
index 000000000..9002ed483
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128f_sk_pbes1.pk8
@@ -0,0 +1,5 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MHgwHAYKKoZIhvcNAQwBAzAOBAj++dEHcnBKBAICCAAEWCq2kNbLseH2me2NGcC+
+3JjjSTczUCulo20FRsMgsCW+g99LelnNNJQUdlugkerPKtcn+yMdDrTTDtleBEkG
+AE6RXDwii3TcuyrW2HWo3LJ8OVQ9IKN46ow=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128f_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128f_sk_pbes2.pk8
new file mode 100644
index 000000000..119a85111
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128f_sk_pbes2.pk8
@@ -0,0 +1,7 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIHDMF8GCSqGSIb3DQEFDTBSMDEGCSqGSIb3DQEFDDAkBBAZGxWFuIRd07ozc9My
+eZmDAgIIADAMBggqhkiG9w0CCwUAMB0GCWCGSAFlAwQBKgQQsgYXiEdGI/JEYL5r
+ibhfrQRg2d+7RiancBu6HT4Hr/r7F5gN94wIskMfHS/efjKIaCYtUxhkrkxNts8h
+27SF2EsrvVlPl7N5KK+Tt7hGkvd87uoMNtSuPWEGh/+ZrRD3Z4NSycXskmh9OMKD
+B8er0iNx
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128s_sk.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128s_sk.pk8
new file mode 100644
index 000000000..23f609b66
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128s_sk.pk8
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MFICAQAwCwYJYIZIAWUDBAMUBEBgZT7mw3+QfGFarrsdPPcuUeqzs1MGILndoOXP
+FLpS8bnjZEpVCFHL9mHAy9Wr0ob+g6/S/mGC0lQ7t7r29ScJ
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128s_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128s_sk_pbes1.pk8
new file mode 100644
index 000000000..44e43b6f5
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128s_sk_pbes1.pk8
@@ -0,0 +1,5 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MHgwHAYKKoZIhvcNAQwBAzAOBAgzvdh7GJl/XwICCAAEWCsJtY6IDvr7+EbL4HUK
+P+B5JW9MYTNhsxeN7LrKME+NR3SzUM0LxQCtGmhZ1l+3oUTYRYCgE1pXBZYsd8BS
+RMd52Wsx5oZkJAGOj8Xz/+06/GTKPlrxZmk=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128s_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128s_sk_pbes2.pk8
new file mode 100644
index 000000000..b5d8600aa
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-128s_sk_pbes2.pk8
@@ -0,0 +1,7 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIHDMF8GCSqGSIb3DQEFDTBSMDEGCSqGSIb3DQEFDDAkBBDHnEddiI/4RDeaL8DA
+RrzYAgIIADAMBggqhkiG9w0CCwUAMB0GCWCGSAFlAwQBKgQQ1QhOMCj49KNM+vGa
+nCMnWARgX9fEHnS958lxH6y/FfEO2wOLEpovjayysIbe29dHuZ6wmnUW5qKr0/Cn
+Vbd2t4HWf1A4aaBy6EG4deY69fC2jilYkyiSb2sRCQRNo5uG2wfTju2og9UkMviY
+rD38gLQF
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192f_sk.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192f_sk.pk8
new file mode 100644
index 000000000..0d60b8fa7
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192f_sk.pk8
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MHICAQAwCwYJYIZIAWUDBAMXBGBAEsQTugRaD9VO7wExjzcYXO4HdV3cwLSMLV/m
+H3ldQUFbG4efpVdp2evkUlke0zXbORsAYUxhSCNOeKr3Acc62Q00zL+y3humPtzO
+Tf6lIuF/T8G+J2ecJvDM6T5HLiI=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192f_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192f_sk_pbes1.pk8
new file mode 100644
index 000000000..d65d3e1b3
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192f_sk_pbes1.pk8
@@ -0,0 +1,6 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIGYMBwGCiqGSIb3DQEMAQMwDgQII1Q+Q8nARIkCAggABHjH/kCXtMRHh2ylKQVa
+ATqZSUKtzsS7h+bzN4sVGF+oyjqG/MtOb335/rEskHWov6GM4GGS+hzn34FD2n+H
+5GloJOYC8ZsTbsHaKfW3je1ooHdxd856tvCamEddQfnPzHpkLgJroAjKIXKky9Tq
+RC6suVu3iCULhdo=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192f_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192f_sk_pbes2.pk8
new file mode 100644
index 000000000..d0a7db46f
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192f_sk_pbes2.pk8
@@ -0,0 +1,7 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIHkMF8GCSqGSIb3DQEFDTBSMDEGCSqGSIb3DQEFDDAkBBBmCNaJv/qoQ78ts3JT
+gc80AgIIADAMBggqhkiG9w0CCwUAMB0GCWCGSAFlAwQBKgQQC0z61JY4lMBopXDh
+5d3QbQSBgMGbi19uU0rfg71XuIpVDwfrSiRIq5fKP5Xa4oziRnCelsQxXgRiTMB+
+UoqECqOdVUMbXbvM/wcTVY8RY+Yg9/D9AkZSLTMTWLE4hw2qnwXLOHIDPip3D0Ov
+hURnTWGVsLi+FeyIXk4kAOWcr4rYFgzIGwqU0x0o9gnOnooqXRU7
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192s_sk.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192s_sk.pk8
new file mode 100644
index 000000000..3c5bd0f7b
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192s_sk.pk8
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MHICAQAwCwYJYIZIAWUDBAMWBGAdRzeipR0t1igxK/zxNFW0o+oF2bJlsM723nhY
+/t88XO/B0638T2JCGyE6KncNui+ujyPJER46mvBWF6+4ARcZJM/bOEJe/UQG8vv5
+sprEde2IDAKzr90mCotHAoUMPEA=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192s_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192s_sk_pbes1.pk8
new file mode 100644
index 000000000..92860895b
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192s_sk_pbes1.pk8
@@ -0,0 +1,6 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIGYMBwGCiqGSIb3DQEMAQMwDgQINirhkCHm0dACAggABHgaPUR9iSGwZUGgCEMp
+diSdVK3Y9rbr/5QMMvvWfQJJ2TGeJVoqJEMKksaM+q1mgRhF4YkBOzaMk6hMRaaz
+pIVgM/G5hJ6YdCdKJ4ZZdkFYrbivJNhOHN1I6dCK+lk7xliJIhHjt93uKc8fRMQJ
+Ss0c5DfFVCLgsKs=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192s_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192s_sk_pbes2.pk8
new file mode 100644
index 000000000..0af66547f
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-192s_sk_pbes2.pk8
@@ -0,0 +1,7 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIHkMF8GCSqGSIb3DQEFDTBSMDEGCSqGSIb3DQEFDDAkBBBtwHzyKUIKT8clOzUH
+hdjkAgIIADAMBggqhkiG9w0CCwUAMB0GCWCGSAFlAwQBKgQQA9+ee4a7vuFrYtcU
+KhxZpQSBgBb7fqxgqiQrrdcXg/DSKZEvFsKXWZ++T2qi5xzfsefsbRKwTBA1KYLq
+2+2K4bh/H5r1EEkdJeRBGHvqTVmGULOcH6rfz8NyxBhbSOPCvjHRr0hA0tr2Nzcr
+1hUKzEM4afxQGJnTc99Wj3I/3fF9Bbn8wuXtrVVavFtUNxFxHdoN
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256f_sk.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256f_sk.pk8
new file mode 100644
index 000000000..a9e195551
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256f_sk.pk8
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIGTAgEAMAsGCWCGSAFlAwQDGQSBgPiFpG7nIWOA1u3W+JPiWedAMIZyfbJoq6g/
+um+1GeI9lVVTQdR4/KqRTmx5IUZUKFeymXRMt/FePp+Ex7u8xZjvncXaomWyZJmo
+UBgWhmZVdTRWNQ+S5+6KRQFpaPVPY6+GhGzBxnKPRvZiE54YEzStvv8BH64XEJ3T
+iazd30Q9
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256f_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256f_sk_pbes1.pk8
new file mode 100644
index 000000000..9a3f039c6
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256f_sk_pbes1.pk8
@@ -0,0 +1,6 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIG5MBwGCiqGSIb3DQEMAQMwDgQIrfqIOck0OswCAggABIGYqPCghjLIzRDW6TKO
+NwM/BoxyqF6yQ/i/GhQnNZn1SypL+G8I16B5pbkNJrNkj15Cnq51Sy1M01iKhW3Y
+F8R8ad3UJ0S7hflyOcOzHcqFpC3dzeWTWn/xNj6GtZfftbsXeIvOFlHyAceNDbMh
+mZTQK+hE3RJ7DEyP3pQqA+6N4RhrE/i2tw2BO3J/AMqg5nkPvDqdmOivXUg=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256f_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256f_sk_pbes2.pk8
new file mode 100644
index 000000000..a3d2ffd44
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256f_sk_pbes2.pk8
@@ -0,0 +1,8 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBBDBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQpcV9LeKicwrXVEaQ
+nyQDngICCAAwDAYIKoZIhvcNAgsFADAdBglghkgBZQMEASoEENou36nZE/ZWmdNM
+WLeOA00EgaDWzO7GufOAY+8HZOu7TYAJIe08LrZXb9+2bSJqyxg7VV6mWOIi0WAc
+oGBvtZKpHROWU74hAwPjBJIdbabRH+VjfP7ZjGdFmvZlJCwyLLQ5AxyEUPH8j73H
+rwWbF+j4wS7wWDCkN6Q1PWtVNSNqf+XxgpiV6gHPsbKN0KTXNDHgsSYEhBLj994w
+ty4DyptNElkDrgfZD6FxQepmzyMGUohl
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256s_sk.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256s_sk.pk8
new file mode 100644
index 000000000..ea51671d6
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256s_sk.pk8
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIGTAgEAMAsGCWCGSAFlAwQDGASBgMJmhWMsHC+ZaCdeI8NGfz8qwmL+3K/x78SY
+QPkNr1U1Wu20BFU5XxVAdVAwO7kFamzk7yKWBqJDlPyuDZ/YX20FJl3hqB0dfe2t
+9z7i8cvwx6DsVLB71OxB3UUMa/lGQFMfOnlrqcXurkNOuK6u0yDkYgpJS56If1Zy
+KrWCCiLh
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256s_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256s_sk_pbes1.pk8
new file mode 100644
index 000000000..ac8340c32
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256s_sk_pbes1.pk8
@@ -0,0 +1,6 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIG5MBwGCiqGSIb3DQEMAQMwDgQI/EVJTakP4HwCAggABIGYdfSQ6jSA4iEs8VO5
+Ri+sjCdafwFZDP3bwratjkUU6OnjUUxZAosvabMLkSXz/oXZzbFjpE0sVYVyL7wa
+i2GnHHJuclpTrqJhBPv/eorMIdEhsU9YDl98OgdmGkTzQDCbQz843TO/3bezambT
+OkCNxDRRe+kFLgpSSoVHgl6thtJSTNWDKiqut6a6t7ilid7a+X9W8LKXM30=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256s_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256s_sk_pbes2.pk8
new file mode 100644
index 000000000..0258d87be
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHA2-256s_sk_pbes2.pk8
@@ -0,0 +1,8 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBBDBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQTSs1VqVr5spd6UOu
+xq3qtwICCAAwDAYIKoZIhvcNAgsFADAdBglghkgBZQMEASoEEFGrf828L/s81dQ7
+DiJtDEYEgaCJXOJMVf+PdjIwpfdUE3NPvxj8Oi0DZ7AM3/0q4ocCMOiNlEjjdqNp
+WUugdros5pY9nPIIG9klnVfxaxLQbKq4BjDJM/daChuZ6AJZTS0OX6//Ya9WH8fh
+oM8+YfxxUZlfspr62w2Tqil8OZebV4FZZ292842cAVw+lCI1RN6sY+unoBqW0Bok
+bFYdirDrznsodXmz4QyFGv+CWcodRj95
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128f_sk.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128f_sk.pk8
new file mode 100644
index 000000000..3358009c3
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128f_sk.pk8
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MFICAQAwCwYJYIZIAWUDBAMbBEBU7rgPl3R3DDS4y5nE8QhQH96+ByRCKKYQso2W
+BrAGHMymh9DxlnKweyvOU4DzEfbGVJKUoa4vYrHc25HQTHeE
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128f_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128f_sk_pbes1.pk8
new file mode 100644
index 000000000..7b67bb901
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128f_sk_pbes1.pk8
@@ -0,0 +1,5 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MHgwHAYKKoZIhvcNAQwBAzAOBAjoNSpTlrltPwICCAAEWK3Y07vX5J17xzfYsXnv
+28A7u5KWno/t5/oDZ6Yvm7g8pZnmNEq8KDvxeMnd75XUPIck/4zUlIAw+chupc6P
+Sx2tPyhx9VSHCnCL7N3R41eeKlhYKH5o/wM=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128f_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128f_sk_pbes2.pk8
new file mode 100644
index 000000000..9b5692bba
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128f_sk_pbes2.pk8
@@ -0,0 +1,7 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIHDMF8GCSqGSIb3DQEFDTBSMDEGCSqGSIb3DQEFDDAkBBBIPcsVVkylDCesdhNN
+u3i8AgIIADAMBggqhkiG9w0CCwUAMB0GCWCGSAFlAwQBKgQQdevzuPfHSkV+aWzd
+HdL83gRgJC1W4Vb9MzNryKMdxXbNrSJVsViOsZSCUgL+gkaIBPBHRA80f3ToedgI
+U+juv3QDJ/rVFZzEn2+3uNHi/mZGjd/y7c1T4rFGGUFUa16s5931IiyccsFgcIQQ
+4a3C9GSw
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128s_sk.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128s_sk.pk8
new file mode 100644
index 000000000..d5f4363d3
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128s_sk.pk8
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MFICAQAwCwYJYIZIAWUDBAMaBEB7rogexDBq0MrVndGhZM9Ip/DHPf3BMdYs9eML
+zm2TkPAZ1XhBe8fNSQ5bS7a6Uw1wt5XeNyroO7gw2Ic6R+Uz
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128s_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128s_sk_pbes1.pk8
new file mode 100644
index 000000000..c78d7c782
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128s_sk_pbes1.pk8
@@ -0,0 +1,5 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MHgwHAYKKoZIhvcNAQwBAzAOBAg5hSfuMmJcbwICCAAEWJvNaVpediEhplI5kuDZ
+x1eEiK4EYZMzRNGe3Rv0wfT/1Rjxy7AhAhQ3ryrOCUn648qu/lM66zFKI+uJoSuG
+TjaxcXnVHF2S5YTw3CI0dw1ZlOmKT6cbc+E=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128s_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128s_sk_pbes2.pk8
new file mode 100644
index 000000000..09d58e924
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-128s_sk_pbes2.pk8
@@ -0,0 +1,7 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIHDMF8GCSqGSIb3DQEFDTBSMDEGCSqGSIb3DQEFDDAkBBDH8brnRdv/Qp0WbjrX
+UAH0AgIIADAMBggqhkiG9w0CCwUAMB0GCWCGSAFlAwQBKgQQhGKGtN7nM1ACmQ/G
+TVzabwRgBMc7UKCPH6rk5ivxwNg0/P/sSHnM5lzx0BRxPTFx8fc2xs6KS8xBm3/X
+e3SJ9Cbz19ZURWj0mnLFgjXf4ICuTvA9pM4Hos3O5vc+jiCAjFYmCJEgHjlaNTci
+sOiSeIsy
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192f_sk.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192f_sk.pk8
new file mode 100644
index 000000000..126800e10
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192f_sk.pk8
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MHICAQAwCwYJYIZIAWUDBAMdBGAfLiGWaHJHuK7cRkilfIq7ElzRSb2p7Xd2oCxc
+SSbC4BOc2hl7LoHHV8U24okZ5lxJoKtTnKIvQD/SoCDkNmqionCVN9i98fTvg0un
+y0SJvuN17RmpAvYPBB7kh1QVF8g=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192f_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192f_sk_pbes1.pk8
new file mode 100644
index 000000000..bb1ac5ab0
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192f_sk_pbes1.pk8
@@ -0,0 +1,6 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIGYMBwGCiqGSIb3DQEMAQMwDgQI+2YLc92YrEsCAggABHj7fKFcwC/YXPH/rp/L
+yXbnhWVM/nauoYztKp3MnQresUfkK461TDmQrcCfjs2b/ShQqJyRPgWYc8qUIwqK
+113YeLedNEvq8dUpaxPg8Ad9LBQxSVEtn3btSGWZpGMyPuq+Yx9/N1ZkHEvwps83
+Z6hii1ihY08ZqYI=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192f_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192f_sk_pbes2.pk8
new file mode 100644
index 000000000..8e37d6c0d
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192f_sk_pbes2.pk8
@@ -0,0 +1,7 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIHkMF8GCSqGSIb3DQEFDTBSMDEGCSqGSIb3DQEFDDAkBBBsuYPHyhP4TXWZIHpa
+JlK9AgIIADAMBggqhkiG9w0CCwUAMB0GCWCGSAFlAwQBKgQQ8GTH9MsIyfnXn6ah
+SeuM/QSBgMt3MprN6lB04fUcOwTlRkGmGTQtaEqNBVwSJxY5lfeCR+67y85Wh1vs
+IUxhCRNYV+8Jkdm5Uxij0O70cjwDYHCLdtSd2cRTAwPISeYcbMi8VPSH8btLINBI
+ehK6P546iUvvgSoN7D2EHoqtSFwM0eF9R8u82HrveEawxtB18zOp
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192s_sk.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192s_sk.pk8
new file mode 100644
index 000000000..2bc39afa6
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192s_sk.pk8
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MHICAQAwCwYJYIZIAWUDBAMcBGCPViyYzFgskhv80UvTD6F4foinF/Z7CqPbHjI7
+oEDz+w8HDewZ3rddSoqr+52t1T76SD5TLdbTJqOP5P3YBXDX/QeHZEdc/guGR8Ev
+J4tQjPEh9QV+/C75r+Q9Lcp7RG4=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192s_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192s_sk_pbes1.pk8
new file mode 100644
index 000000000..0c843610a
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192s_sk_pbes1.pk8
@@ -0,0 +1,6 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIGYMBwGCiqGSIb3DQEMAQMwDgQI1be7kfx1mPkCAggABHgg+DZ+8C9WTgq0VsWD
+o48fIhcVHziuz3VmVaC6e6WdHHAcWlJN/DZi/fvlRzbYeyEf5mFuESgznLzKbCmz
+Tk0IW7JhScI5un2KrvJ47znA6/nC5xqMgIPjsGBzoTrqhEjfqxTkabW52+M2wr8i
+rtCgaObrSSDS1vI=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192s_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192s_sk_pbes2.pk8
new file mode 100644
index 000000000..5fa28a105
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-192s_sk_pbes2.pk8
@@ -0,0 +1,7 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIHkMF8GCSqGSIb3DQEFDTBSMDEGCSqGSIb3DQEFDDAkBBBejP+WqlaR5jFNEPBS
+N3gCAgIIADAMBggqhkiG9w0CCwUAMB0GCWCGSAFlAwQBKgQQm1rVkdnOS7qDZ6Yn
+0z0kEgSBgAWpnbP04I2CSHOhLyDReUqfuSwf/H5ot0x25ozk1CUM4OOrBQOFLU2D
+77cVhpIaVCcjnJwARJPguoOiAP+ar6esQfo81Wi9L31MZ+71eif5AUynI6j7YQ+4
+cGf7JasFsH3QjAU82ajJ36ADBjlxvIqqP0Uqui9A6xUpG4kNmk8o
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256f_sk.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256f_sk.pk8
new file mode 100644
index 000000000..39a1fe59b
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256f_sk.pk8
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIGTAgEAMAsGCWCGSAFlAwQDHwSBgMVZdsa0IQvt7lOKPYtawZ7J35zp3zIgWQJW
+ByhZ6BVrZmBSdkTD7jqSd8ErsTyiF0uwimICgrpGbRhMvNptbdKNMwJ/t1LLuQjj
+sOcPIYaF696xk7ZYCb98Jc7WRrs0Lyoxpo0EBN9B9cm72fUzmvr52KKrM84jxDOI
+3wXFTWij
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256f_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256f_sk_pbes1.pk8
new file mode 100644
index 000000000..f4e78976c
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256f_sk_pbes1.pk8
@@ -0,0 +1,6 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIG5MBwGCiqGSIb3DQEMAQMwDgQIrZMZz/FmXN4CAggABIGYRsZe0kF+ayzMr28K
+qhpwBATCP0GpYU4lqc2hXRurt9HJ93TgUDwQclsTLRasOmfRc0Yvu088U3gEGOl1
+O3A4LfKnpB1uygy19dvGhyUIHL2fg8Ykbk8xzYvCX4TmIiA54rwYM956cfe4bOux
+P2O7xwhEWlm7EOYzQMIP3rRj/hMP9+uC+8L4/pBe5zYadYKFuWcdCkiPGFU=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256f_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256f_sk_pbes2.pk8
new file mode 100644
index 000000000..4120d79a8
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256f_sk_pbes2.pk8
@@ -0,0 +1,8 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBBDBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQu0+wQdGXjO6wNwLa
+awXQNgICCAAwDAYIKoZIhvcNAgsFADAdBglghkgBZQMEASoEEKx0JCUUEg8UxEUE
+k26t3WIEgaAOw5aXveyqGLEvw/uExdrFF3QDvLaq9h9v5rfABzjfzppk9NB6N/ER
+gbU1Hm6XKVavlRgfp0Ex48BihfgcS0f/XYusf76ASS7GiuL9GkVbtCyGNVl4nJlH
+ZSlr4iRxt4G7H5UNslrw8AFXYURpmGokoll2UZdTC81Mx8VIsFJfeEohrYrveJyd
+bGR9kfhUTR/J6bChASiPkmbuvYLjUGRv
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256s_sk.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256s_sk.pk8
new file mode 100644
index 000000000..9fb5847b3
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256s_sk.pk8
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIGTAgEAMAsGCWCGSAFlAwQDHgSBgN1wX3/vz/MUGwgQO7WFRur3rE1LPirFjDje
+e0dVJXjN/sBEfELWkUzx7jo/VtsWkwyyKhjtYQFlAF7hiGK4R74c4jzA16aMTFNr
+0kgHUwgzcGfFVYcYuPyIYo2q+DHHRozCaSS7Y+08KIfUtIT7/JLv8uNlbzJ90gcd
+wAzs3o7l
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256s_sk_pbes1.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256s_sk_pbes1.pk8
new file mode 100644
index 000000000..7e3aebedb
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256s_sk_pbes1.pk8
@@ -0,0 +1,6 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIG5MBwGCiqGSIb3DQEMAQMwDgQI7leqlL1jWPACAggABIGYfIz3vSA9zqCeS/qD
+Jm6sEyO3JaVzWutyACLGao62QVm72FQ1w6O8yPoLDwM5ybPG6lzXg+G7HSd2RZUM
+hECL8CSYgwV0zmLFfkoORVlitcCPBigZWH9POiphzo5V0GB9TzAwSc3KM7axU+6h
+sYhmfLlMiOiFWhYEwi7Mv/vGLzVuGWd2uEp/aTJbv/xh+39N3WFnPDDLEmY=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256s_sk_pbes2.pk8 b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256s_sk_pbes2.pk8
new file mode 100644
index 000000000..903b8adfd
--- /dev/null
+++ b/tests/pem/pkcs/openssl_SLH-DSA-SHAKE-256s_sk_pbes2.pk8
@@ -0,0 +1,8 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBBDBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQQWHbYGjqVbI3v5L8l
+T0xdtQICCAAwDAYIKoZIhvcNAgsFADAdBglghkgBZQMEASoEEB0GCqN6Uj/oQ+Xj
+9nuBWcgEgaCucJfC4UMzQoBjFfXEtCepthJ3EhSFLizSfOvWWDCSBJ1ccgleZBCP
+8gMW10DByRFEzF4ek8eqkhw96kQcPmpF6S0WXAmi2H80TlMsKi0o3QphOc6eS207
+/KVomDuXJYY4KMtYGGYUZM5huiBDZV2AONvoIw7Cqq3+XTStijqond0FdxbKAhNm
+RXk7AoeynQmZ2It9nd+eAgahxEcbE4FS
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/pem/pkcs/rfc9881_ML-DSA-44_seed.pk8 b/tests/pem/pkcs/rfc9881_ML-DSA-44_seed.pk8
new file mode 100644
index 000000000..93febbe04
--- /dev/null
+++ b/tests/pem/pkcs/rfc9881_ML-DSA-44_seed.pk8
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MDQCAQAwCwYJYIZIAWUDBAMRBCKAIAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ
+GhscHR4f
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/rfc9881_ML-DSA-65_seed.pk8 b/tests/pem/pkcs/rfc9881_ML-DSA-65_seed.pk8
new file mode 100644
index 000000000..733f324dc
--- /dev/null
+++ b/tests/pem/pkcs/rfc9881_ML-DSA-65_seed.pk8
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MDQCAQAwCwYJYIZIAWUDBAMSBCKAIAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ
+GhscHR4f
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/rfc9881_ML-DSA-87_seed.pk8 b/tests/pem/pkcs/rfc9881_ML-DSA-87_seed.pk8
new file mode 100644
index 000000000..87b2f0f43
--- /dev/null
+++ b/tests/pem/pkcs/rfc9881_ML-DSA-87_seed.pk8
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MDQCAQAwCwYJYIZIAWUDBAMTBCKAIAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ
+GhscHR4f
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/rfc9909_SLH-DSA-SHA2-128s_sk.pk8 b/tests/pem/pkcs/rfc9909_SLH-DSA-SHA2-128s_sk.pk8
new file mode 100644
index 000000000..a13f1457a
--- /dev/null
+++ b/tests/pem/pkcs/rfc9909_SLH-DSA-SHA2-128s_sk.pk8
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MFICAQAwCwYJYIZIAWUDBAMUBECiJjvKRYYINlIxYASVI9YhZ3+tkNUetgZ6Mn4N
+HmSlASuBCex3fKpOHwJMz8+Ul9mRgFCSgPQlavKwevgCibSU
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/rfc9935_ML-KEM-1024_seed.pk8 b/tests/pem/pkcs/rfc9935_ML-KEM-1024_seed.pk8
new file mode 100644
index 000000000..e9d876880
--- /dev/null
+++ b/tests/pem/pkcs/rfc9935_ML-KEM-1024_seed.pk8
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MFQCAQAwCwYJYIZIAWUDBAQDBEKAQAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ
+GhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/rfc9935_ML-KEM-512_seed.pk8 b/tests/pem/pkcs/rfc9935_ML-KEM-512_seed.pk8
new file mode 100644
index 000000000..8222519fa
--- /dev/null
+++ b/tests/pem/pkcs/rfc9935_ML-KEM-512_seed.pk8
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MFQCAQAwCwYJYIZIAWUDBAQBBEKAQAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ
+GhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/pkcs/rfc9935_ML-KEM-768_seed.pk8 b/tests/pem/pkcs/rfc9935_ML-KEM-768_seed.pk8
new file mode 100644
index 000000000..4e7d5a0b9
--- /dev/null
+++ b/tests/pem/pkcs/rfc9935_ML-KEM-768_seed.pk8
@@ -0,0 +1,4 @@
+-----BEGIN PRIVATE KEY-----
+MFQCAQAwCwYJYIZIAWUDBAQCBEKAQAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ
+GhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8=
+-----END PRIVATE KEY-----
diff --git a/tests/pem/rfc9909_SLH-DSA-SHA2-128s_pk.pem b/tests/pem/rfc9909_SLH-DSA-SHA2-128s_pk.pem
new file mode 100644
index 000000000..ccc73ac55
--- /dev/null
+++ b/tests/pem/rfc9909_SLH-DSA-SHA2-128s_pk.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MDAwCwYJYIZIAWUDBAMUAyEAK4EJ7Hd8qk4fAkzPz5SX2ZGAUJKA9CVq8rB6+AKJ
+tJQ=
+-----END PUBLIC KEY-----
diff --git a/tests/pem_test.c b/tests/pem_test.c
index 4dc14cbd7..b8684e925 100644
--- a/tests/pem_test.c
+++ b/tests/pem_test.c
@@ -85,6 +85,9 @@ static int s_key_cmp(ltc_pka_key *key)
break;
case LTC_PKA_ED25519:
case LTC_PKA_X25519:
+ case LTC_PKA_MLDSA:
+ case LTC_PKA_SLHDSA:
+ case LTC_PKA_MLKEM:
case LTC_PKA_DH:
return CRYPT_OK;
default:
diff --git a/tests/pqc_mldsa_test.c b/tests/pqc_mldsa_test.c
new file mode 100644
index 000000000..8d897349f
--- /dev/null
+++ b/tests/pqc_mldsa_test.c
@@ -0,0 +1,518 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_test.h"
+
+#ifdef LTC_MLDSA
+
+/* OpenSSL 4.0.0 ML-DSA vectors extracted from:
+ * test/recipes/30-test_evp_data/evppkey_ml_dsa_44_wycheproof_verify.txt
+ * test/recipes/30-test_evp_data/evppkey_ml_dsa_65_wycheproof_verify.txt
+ * test/recipes/30-test_evp_data/evppkey_ml_dsa_87_wycheproof_verify.txt
+ */
+
+static const char mldsa_44_pubkey_hex[] =
+ "db9ac67708f2ba0fac1f92bd802f9be89ecab966feef59872a1a9ac90b1111170a561290ae86b13968f2506023c014ba09fa449a26e4e9d35595e73986506cc8"
+ "790e4d07a94d6c736f7ae78cc5e3e3cf025ce06a09252bef97fe92e94cbd107b1844d1a7c690d88bff9e9336f8f58e0bd5ee384de9c7ffbb149a6fcd87c77288"
+ "601d8843e28e0c7a60149d02ebc57b183c39888d98b61cd8ad48135ddb8a1666743bb689f44c1a92d52017b6a8fa493eeb839dffb086a9a6c399b194a52f0e41"
+ "64c96ff8a2a54337de24350a866b5fe4195257778e72511221778f1eae5fa93ed3532f696b9b0767aded85f62ea311027c7f5fc4182dcd2864b1c26bd6dcf72e"
+ "bdedf70471327be0ea1c2ae53e46489c6dbefa512a78fdd7be0ad3ada16a7f7b1ece49817b44868a2cc234bfdba556c32cc92ec2c5e8a5d206f2e4ee372d4168"
+ "1e67d1b7e7b0061870c57f600fafca85f98aed8ce4ba76bba961f9ed56e563220d3ced853b6b28e7527da0e0912bc932a23c8bab811429bbb4d49b2770bcda44"
+ "abb932b11c0a5866409fce39fed2b459c86c8f6e1ab0aefc5879503f4b21a49b4b2de6760c9b6aaf041144a656a26af39f4578e1d482ddc1360ef751d9784b86"
+ "0ec373d415360fe99f32e126a2ac1243430e8bed1bc90b19b3d219c2712edcf81c44b4331f6421088e662b695e1fd8fa5091f616ab60af70f159b63368f1ac60"
+ "d77b279ed47ef7f24ec2044bb6c2bc76d933ecd568f7e663392afc1d335abac6c03670adf87747dde90052f5cd45f7d30f43a4dc3c500ceb658fce235c171240"
+ "baca1b5a14733d774b9416c540f53eb83481afc98344b12a4309e6222b08d978430467497010314c6f6b8caf65361c216106395275a67d7500dbc120f7918c6f"
+ "8db7aa63fa965b4a22c70dc88f727d768ce2bfc7597fd470184e1c59a6b2e1204cc8c3d052c594d5771e0ccc8cfb191f47038b1c0672f07caf4747562d3d76a9"
+ "816fb1def1391cf0f05fcdbf2a0eb6c21ac24b26e74ee403133e80a79313ddb02c1fa386c6dd1d420195343e3a104aff6d60887f7304fa9e3bb59bb55f820dd8"
+ "5b1445c54e9a38dc1c7f3b88eb36a9f48d13455e51c934825ff3cd8bedb2b5422344120399eef83a360b83440ebdd8ea6e01c95159e3735bb4408500caa785ca"
+ "4049891c7331c4ea31ad9060ece768fd339e6904f88e27bad3b28845687be2cc9314f300fda56fe3ff2508e54c59123b068f86fe00213d5af8da1b1735423ed6"
+ "88f097c306dbc121b81f532fcaf872d9f80596642295d6e4bead478644081618ab903b39e9b5e7cc0b5f2742d8337b18d4ad4788db7443e946cafc1762a5da84"
+ "070e8c2fd86d6c633f0b44ee234ba11b9e1440c94a08d0437015279690405353059020fd2f58f15dab18754177244adfb81ceab79c7840bf3884a3d364afc8c4"
+ "53a425fd8c5378eaa7445f8c6256bfbd03a66c53e8cf27e2c52f14ef3294afe79cda408f5dff933ca0211a78a4e3be3d9a932558ed71ed19bbb57f87937fa3d4"
+ "a78128491ff096a261045bdd186325c42caa8c7564195a4d2499a1c17d21a52d1aacd221d9c8a1866963a20390f2fd43dcf56b308a1c01c38091fd3e04c12b69"
+ "5de497d48bcc268d50cb0bed793b8e6937e8d533afd568521f1c9377a3804d38e785674d7ce868d289938e33dda6edc76d25b15fcb38852b7803cfe62f08d9fb"
+ "d070957c4e6f134973964c9dc009985c8501e7d8f72e7ec285d5289fdd07f64d62acaa9737b039efa7a9d1d175577c6bcf9dddcf692877af38e75263bebe2453"
+ "155be61f0723c274388a532abe29dd7023e327085f4c9dda41839b7b3357ab9d";
+
+static const char mldsa_44_msg_hex[] =
+ "48656c6c6f20776f726c64";
+
+static const char mldsa_44_sig_hex[] =
+ "1aa69cb5ed35204534f25f40a17eb0d767f8981f5e7cec46d3bf3252bfc78e09d02ef0c82da6dde973611c849472890106158cb15ffa6ca891615e888efa0d2d"
+ "8a121b75ca440228ad32991be34249620f158ffd6f74d7b03bf919218ce259b500808ec157ead67b56b79e9e6607eafb9227b8a30adbec087d35bc1aec2f1a0c"
+ "4dd126dfcfb9fbf0bd74fb1e092495fa994ab5a7cd1333281aafe834694a6dc11e889c762b5645638e172dfab3060031ebcdc1fd455d5de6050bf71b074a4dd3"
+ "4af5ebf15487651f0f13e5d3cee231b9b347810bfc418196df9d7231780c09171b9aae732bea27a1649d8c03220f417e30a016b08ccb1d55c9337b4812e20e04"
+ "523f5d29a760a01b3a80d76285521206481ee1e44df09a76913ba54ae50c8eb973a3ced73950fbf39c4c0c1262a216821a442072c10cc82839ac57b898411be9"
+ "e810f893272a2546ff7d1d920f146210efc2b4528bc98a099a398302d301fc1dea31b3d8ff78246a66f690ef536b68e02bd7ea23a5378930dde7f1beb5174989"
+ "6a7944e5a40e6fbbb1f76c3fda09e32e0a58062c24cac7ddb8c1d2cbb352a81e336425c5f551246db45ecd0ab29dac88cdebf51c60bebc2e27c974f56da12c1f"
+ "ec4f5745850429b607f5ed7cd821f2c91fc2dda8c2c8e8ec278d1b2a5bf50ec70c5623fc681b4d1dccff96b324cb53ff97470f9de177c2006a89af8f18603a6d"
+ "4ea2625794695fe79cd30318a1e76307a4c2a353db1e076ad9b609a2489b94cb6dd821c3af31046bb7a5d43d190e09fce4969fe4e93c8393975e64cb2d9c2294"
+ "fc427ef5191c40937929b3b0e1b037e6b84cc0299d5af2b5410118bfd88ef6491af6f21233390ca7a19f1576e6c5a10a673796905562075047896e3a2379f64d"
+ "fbbc12b9bfe64939c2d05efbc5f6e4b5ca69ce1ed4b7d25e8c835b0612b33e13ed7a8a7233b4b3d58eead0bc4c841acb65a5ec0ed45e2584c23c2a162392b578"
+ "9c62358e4038864e20c10e10c67d940ce78993178dbeb3de1fea1e50e7c29f4d7d938c3bfe50229ea040102f30d5b3a64cb8e13420065d54a1ac50a77383bdff"
+ "3cae2340ebf15a1557fde897007c1b67d04f19431ca00cb0f08db87e90e166e0f4ce6fd69c6ecef1b3f70d9eb601b57a7bf931057c2afe2d3567b6bbec7891c6"
+ "64713385122fdd789c1d5a8a9cfd491f407c16d0b0c5dfc53a6862208e264b981bf2ddbdd1d7db9729b5265c4c3868a947c982880bc55b786153b89ef3324067"
+ "b35a928c51236bcbe9f860ad9eee5644478f894a9fe78d26a5a17d482612f1cb9983b864e6fba84591c0f73b7b27918819d2121d4af640f533e2939d3da0f0aa"
+ "6b9df80837a80165ae8b7579715192eb0f6cca78a43d8ad8d7abb56d816e3af2de59b88bfdcf6767abfb043d3ae24223d05001953faa292671c57ade1fe28988"
+ "075ab8d14ac98363412bd694c40ae85b1f104afcd0f25aa590f57ba4f5dfdf613bf8594e3f54baadfdf50c0881af2475590758a23b7eee725513e4d1ea9f4630"
+ "159c424a289f18a9879e5e173390f8e630f6ee2a6043d82a1983dc97c7acfea3b0c03e27e865d810d012daeec28dc454f59334edf24627d435701d329ff5e68d"
+ "19bbdca5ef7d5e00204fa947d08f81cb6484cabe60989d2f61fbe70940f7e4f449b3fcb103a89143d74b15d72e7913dce9193a0b9c5a7b2a97bde6d7f396ae80"
+ "b4b566f9f2e7345bc42ce3b002818e19f0f16416b850832cd02279ee8d58a381deaac09b1b4d4613f4d066805d2faea6716e015fe361c0526c6e4617a389ffdf"
+ "930213c1dc0c4c905c3106a7517dce7abea7a9341132f8ad98de3e42f6b75809fff38f6eeafb97398e79d50a5622338763c4e45a88ddda7fb87ab7f5cec61109"
+ "fdc1c5d4a16310275241fc34178028a49fd79581a05c3b6984eecd6cb9bd60a44da72600f8f2604a4ff4578126194fb2269c8e6e71447445e8e80bf8c6063dbb"
+ "f29c7ded58abbc0d2eed347bf495b6a9cbe68585a594aa0e65834bfbcccc3f6bf42fe4ef42d86232c3fb1412dd0b5f8a0489958f5c3b883bf7851337a35b13dd"
+ "2b6517626ff2d1064cd189beb402497dd6b8893d414dde7d1d51018c7a83766a2d8a29b80e8f428237732f7ee5ba878163f0aa8af5b60533b4d4621a38fdc543"
+ "83acb3325b5e876e21483eddcc64c419596e656d1557be31b530ea66054f79d4f4a755f9ee33c84fed5d552ec5e2eccd061cf4c4b5c3c16a70a7baecccfc208d"
+ "2430e78621c9ae5b0d080973b4e1df0a1f5c0415db6d3c85f9ea9041e9a9abdde71d6776a522aa957f708b14a33eda10ebbab93bb8ec2b7a04679f38eb44fc55"
+ "8ee698d3c6937e0e647dce898d7599fef6de32ae4d52adc722443610b2126559756aa36f3c79696b99be3d908f780fcbaef33b215693634d63ce2a0777dfbbc8"
+ "99d2be72efdbafbc10aefb26a1a63cdcfda00235b34db723c91624ee5f939024dfedba0863ad08f648767d41fc7fd6b317c51f4b1b87e21e07d488c9423581f9"
+ "bbdae43e4d32b37e8283960524f9a601ab69f5cd7fb01c9a8a5c64fe863519a1e9f3426398f691a96e1748491b4e209fca2ab29481a674621c797614ba16fbfd"
+ "fd1a4184e7f84667e720e6bcd9debef32c2b9e891a6e3c0423158f539838d8413e9fc707d5c65b23368b6edc95d9c3f8e20bbb844499311614945606c1487ef4"
+ "015d1e260fa8239abaa071be572163132bdb06ef21e31be0f9d4b6747134e4842bedcd3bf53b0d6f054693bc428e9a715d5a32a79e6a3cb8b81faf2c04087d88"
+ "16752637a2fe11eacb38341e024848562a29d4585e4ee56552ce9b1fad43b965a37bff8558921790ef0f4ac55bcac4327d1783f5e1e79bf01e96934bb4a8f5dd"
+ "06c83bb70b2377189d622a106100f0cbdd38e34c0565900c616561161b3261859133f83893feb22b0bafc82cf4f0dbafde0648e2f86260e6e747034e5cb3ece9"
+ "8087fbf74179c6306f0c460b5d609b9b3a66761472ee0b9dabb5dfa872d5c6bc9b33461a27b5427bd8833f874f479ecc5f0a20304b9a75aacc82420a87af6469"
+ "daaef53391ae8a25468e717dc47f464fce45a31147c0c4e12ac2f834567e4005b0827d13b3ec80cd8b7a907436e6624c6c8ac6a80add35cfa1a28872fb65cb3f"
+ "a46894d116a052f19b5fe20c7ead10bd24d27ad2b5683f299d1193ec6d9ff3379f3b3e39cb9991831f194af2041085508da4dcb7b8785cbdc4e04cf4d826d1ef"
+ "4a11036e4c5803c3aaa7669b4dd3bc12ff888984e9bbdace0e772ab59332b47300334757677578808e90929697a9cecfd6ed1b303d4250738a97a0aabac6d91e"
+ "283a4b696f7181828493aec8cdcfe1eaecfc0227484957595badbcbfc8fa000000000000000000000000000000000000121f323e";
+
+static const char mldsa_65_pubkey_hex[] =
+ "f5408337d0fee65c28851226a5fa81b58464632c78e2a9bef70d330f2e3a5f74d9cf676aedd1067c91a5dd5d4edc46f868a93ffec9f44e254e44f682a153aead"
+ "f228e8db7c5fcfed30cc3408e261ab896876bee56660d2a7c1d7eac20c5754255206a178f7156295065ce7876f90c48f44bc37f3a00e32eefd3a4bb1e298fe28"
+ "3d106eaef92a33a594253a2a0790976a1d04636f8672d28c06c852ea8bb43b84bff512996e7616963d5b9a2906466a152c7ea9be178be35405683b44367af85d"
+ "2daad87630c1e21ba5490154f0141780f5ed0407cb0b975dd56d5930f9b26413b843b83f3693304b0038bd3e4bb398868060ea18c9c67099376470a50deb052e"
+ "4056743fbcdf0341b192663bd1c21ba3b3d5666e0d0e29c4e1ed0759ab0bd9d1d355011b94e0ff0c049b03ddb7138640667144fcacd7265f55a07e5387f1abd3"
+ "0c037cf14d436aa855f827049215440d8007f61460500d943f57ffb6bfee6fedd2fcec52882d7d8da1aab29e892c8beac3df3234b4a7d2eca3a45c6623c52bbd"
+ "d07c1c94314b706988a52029f8f8b06e874b741d72926652c78c6ace2cfd8864eadb2e4b39cafe6e03e4edbafa2747db9bc42f92af8b031e3e380846b1bfd15a"
+ "de88c285d6a6fffe91eafc8b17de6cbc68575f323cc09fc20e49e8efd76f9568bec486b78df4245428d8d0d5f53873e11de65fda4c770b521a8c67f5c51d48cc"
+ "26358954514447881fd9a42e5891dac7e1db5249d7861b322111e5fb929bee9ff5e9d5a2667ba93e63fc03040d2e82648f89e89dec1d1d2dfb9efeceb7940f7d"
+ "cbebeb5a239cc1c54d8f7d52cba220d0634e15df46a58280bc5a48840bd39274cfde150f9ad9a40f6398d715350925f0e0501944409f32331a362bdaaafb3d8c"
+ "e71c964332d6afb7e684f99951246d88081c86744ae68133f22c53a4b5ae258f230a98491d2d43a79a6d0f4d54a3b62013965ac7c82d0507125a38a0277f81cb"
+ "c1d46cef2a131c6f51b88ec0baae0c82a6a0e72831cb06f9116cff5111d597e01057d32805a008f52c9aec3311139bfb35982789ff83bdd0c31e9f1080e8ed8e"
+ "b99fde66bafb29e3357389fe3785b60c78e229ef073e1b65e34d848bd4d8a4f251551e2d38d2546afbc205d3c6dab34d2b962b1afb44f1d22fc10c6744fcd6b6"
+ "36afd3cb414b16c2e0d708fe9f51ff19120bde693b028b6d1e6dbe37b4b8b3bc7c6f7a842701603869d3ded572500f085502efc8d3cc62b30e5cdbcb5e86d9c0"
+ "d42973bf755df539cc0aea58f9148386db67bd2bf70cd12ccd96d5c66fb271416b772465228dc44b079178f9b766370b66a79b871faca246ca6f8f63be9f0668"
+ "297ac446cad5cf4a83318b1b00ecbd283f0eecee60a9a37a27abdbdbe382e307970002837dfc0bd3934ebd008918fd4bd383c02c9d37f694996e989a49075767"
+ "ebc4a2981ef5275455e026cb0bd70946cdd1fadaf251381d324f9efbb860d1b280c29685bab97d010676273b45cca12ac3966aae342c84e2357eccf252577743"
+ "b8787967b40b07ef2d3d9e6c1a3bcb059cba0fdb7f0d4f815c242b8e14acd3375e608e9230ba3cf8718f43882a3e1e661a2bbe81830d34741f33473e263b3790"
+ "abe67acf29f5df44865b2ffbc96975fd62738a64112deda5a2534fb0a23b3b3024df986391badf9041c593c313a7ca1e1fcffcb65b07b9a99337b4a4acf616cb"
+ "e1553eb9541f38aa6247342905995233a28172ca13396b2a9662970120f82b92a213f43de7a232ccca3268265c9ce042d50915430a6c455f32277da42f9962fb"
+ "9163b623231ebc080fa7b8e9f9021fcf85b98f9c483e4d2226b9326a5bcb2e7449ef029ae142d3a0f0c28bd4f7e9c51a12e1336f24dfacbc3f808a8f7dd68302"
+ "7bc948763b808fb0037394b8b41bc9b2ec7887e67584e03d11b15ca203b2bcb43f8881638c4e4eee7f846d09c7f89b7739df22b2c3acc235032ba8f7ae27b5b9"
+ "d25733143e80a4cdde6770719c1e66ec2ce683612233e88fafff84c0745a98aa1254c8219c6c556348c2b5d1beeb61532d6bf7bde153271dc647460beb65fe00"
+ "55b33fd6480dcbb9d7d471952cfa5be260c39721a8c5c89b9e966ae2dc9036451ec9f2c49433b2225e13f23e20c2bfba81a7b3a555883449238f7d48213e9f10"
+ "ce19e76f1bdcfc73ee5524bd7d8be0a4b46784e238233c04fb99383ec7726f9717e1179dd14fba9ad6c2ebd1699f0ab0e57e6cad23875b029e89cfda06f51266"
+ "ecd2eed4edafb51e82f2a506d57ba74da611774ca5fa2fff4a976519de425885e7d09219cf815b1767d4fc5a72c18918991a285086a6a766614a4d245387da50"
+ "f28dd778fb33ab88c0918feba3768c55bb1f07aec33cfeed33d6faa4d34fd7227b365533c1e67dbc89f0b20195cf1cbd480d333ade1c9bb28308085b72ced430"
+ "268c1492a27050c43668adc9cf8b8509447cfcd3c8f8d8eb554f704101786aa9ebca86991d250776a37a1f56fbf7d08e591f978da49c3870625879f70e2418ae"
+ "c5cba32fa8c346fa9038baebc35ad0068a4d03537aee14c2e71570a87490377fa8dd66f995aa044a522f0c7025a7ab2dd5ad30a64268dc112b7f9fa156df64d6"
+ "31f55f1d6edc55cec570a9c7372e29e02c8d4867bae249431dcf6ed2794a0183f0f7501201feca4a81d334c642fc8d38e9a90fa77429665e09e214797dfa455f"
+ "f47c4f219d3a2cb0176bc2236455123c1c5da714ad29d580fb194f87173a18dc";
+
+static const char mldsa_65_msg_hex[] =
+ "48656c6c6f20776f726c64";
+
+static const char mldsa_65_sig_hex[] =
+ "69da5aec6d5f58fbf29439c520bd68b966e3dd2ca633b68351c2862344713a1e9c086a44f9a870a3ccc14de62d6c12b278c354d7197c4d6d7f83d1422b29b250"
+ "f5ee3fec118311d905e5db2b4b8b23b8d542202d6652f6dc3f9d7ed51f2463082d3f145cfd0fa7ac548a47e91c1ccb1a55b215e90ab355bfc6d67154287b1dfa"
+ "e0fb530264dbb841a7684b396e5ca0459d795216416a9d232bc89b32e0f9461f53107c78e66c8e876554e8ddd501867b55dcfc1fb33f102e03373cdd192640f1"
+ "027a08ce277b468f6ed0fe80a9d6cd2d6b2f7a3738c8325d95b0ccc6e7b9fb000c923b92298e0867d4a9f6dd5513e8001033c633bb1641ee66349487224dd433"
+ "86c7fcc29916332066a868100d46e2c5b8354c28f087a024cba27694afc4c1665e0d72b37686919ad55052cc63a144febe4e2a0c9ae416e064e289f9f69cbb88"
+ "3665d1130826b7b74e30c94a2b98b67b471663e3d66326db3b43bebf958e8665b68eda90e8c5d9494b0c7c9ec48800910dd6d906b1fcd47a0aac462ac87b126d"
+ "21b5ba150df61f752257ddf5a063b4a5b150371d625535e3b2874b9fe548960ff67931cd6c12496e8213e2ace6fff48e6bdc60310e49389f62579db26b92ad73"
+ "e9d3f23942cab51784f48b3660b6450caecbb0df2aa4c8e56577f5ea450d2f7f51aacc0b304a62250bf2cae7b99dcd955b6596625d06da1c67f730b706fdba63"
+ "0f00fd891830d251484640b7258ab364d6fd9986878fffa69b7c44b92e43143affae8b098e1d27716850f37553bf266cdfb561abbcdbfeb80752b364434e64b8"
+ "0429b54cc88693ce03dc0fa147f0741b215f0728499bdc25140aafc976ac99e910ba8a8a50d21b7bddaa28626b3b90a93fd44077068357c81d36e735eda43629"
+ "30adead4951a0baa104f384fc70e842a9f329e1868b07b455e9cc3fecd54805c9052e70f88c3b92fe0fc6a4d7dda18cf5694e5398860e439a1e19d5a66f2fbc0"
+ "aacdd1a498711bb16054796c015a715395ef6174e37b04eda589b673c4d5dda737817fb52f392caf7a72d7a3e84b2180cb5b75bc8af065bdc05c3e4040435a1b"
+ "160081352ac43e09cbf2ead6e09c2b0be0e37894888fe2812f68806f957c13fce6ff167bcee21d4f412ec95a4847f3db7bf441223a4d4ca9ed69adb4de8a4b5b"
+ "01c775f2721226e6c59ff26fc38e1bb78a384b30e7b55f082e264d8f25e31518619ddd6b6a9faf8aa6cdb5eab75ed59a33825d5ef8b93bde5d120ada773fcc08"
+ "52b918f4f03e2d2a543b15363adb823eb1f6c533b98d940411e1f5c1cf521f9f63d5454697608326625fffe01bf87f44187dad631df2898effd2c291d98222e5"
+ "64abe3b042b75e90c9c54667842fa8ebb68a1244bf8e0c3ae3ee5f97d5ddeefd986c4bd3f99d877c2cc2381a89abdc61713d38cee58bf69805a485c288d21b15"
+ "843147066b4a74c69dc25de878e21d35fdfe6746feb4c166606bf3219e42cf63581e7e6bd6570f40f8fae590cedf5106fe57037ccb2324b74fca6500f6ed3d07"
+ "36cdcc67d04f8fa9e80054a5bd7c8459fc1abb1c4c78677d7f6b325af94a0e5c9c7db0a748e12c5265e8724947d9b5c4bab1a8b6faec827cc41ec115ef3c2d73"
+ "48cddabddfbc8436f3b41765e13f3762b3b45ed23156f085831e726a55d4b83848b3d1d3352aab9edcc0ac2388f2383f6301ad813b917ee3f23734e057832ae4"
+ "cf65e668c9ddd0bdd0f9d8b6693254649668aa91a1fa5eb7c59859bb6ddd36c25f4a2223f5d688b480d0388fa307ea69298f9bf7737f6b3dbfda87b331affd75"
+ "cd8d88f0460e98ebc2890b217bd6d11000a3a088cd837f4f8859a43f76afaaab05a0c3007a149d4d6b9155cadc2c9b55003efdec5012b6272b87183694c505f0"
+ "446ede55f35b8ab201f9eda974ff840eccb0f004fa3acf753acd0613f66e2a6ac82e322199d37b4af83cbb3d98371c31be79bb42331e819644cbad2ce27a04e4"
+ "c517998692cd8331552892e199a01a6922bda4d38ac4c01f708809e529c3216eaab399ef25b350ea213ba47126f278140e17391ca7139bd13c56f415e6b74aed"
+ "8dbfbf38c95dc6db366fd72aa863a27fa1ebf198716400b978a3709e35039731930406588ebdffd35fa230a9b75fce41d7acd214ca4f0029896c137495eade0c"
+ "f4d10fe621c73f01061acb077de72177ff5dbc6f0c5bec681aa34668ca4fcdd727525068b0b0e9072971b84ef6ce11d5c3c6024da40966703dcc2b33ae04f677"
+ "677635a55db508f34f1403cdbe37960c8577dac3d848b29f3b5c5c6c56fb74f34c8f4634c04b8cce9b218f1760ca00e6de87efd14087c633469c892bf3e31944"
+ "3336733bb60cfb44941bfa25229aa24384d812db90fe74e0f93fda005eea87400736cabc036f71421b6657b1674d4a8f76cbbf3a8b1c0af82f72973927752257"
+ "c532db439d96762ad64f102551a9d03f9ce3d8cc850c393c128bf8054bb55bb92ea31ec0706f083a9cf90424c617f8ad2a21225d1913c30e8f47a6b7131304d5"
+ "36a85596ebfd987b64b6bf3c51638d6c839214b53c3c10aa52bd9c6eb77fcf80b5e3b724dec1381d0e02207a6adc73ff53d9d1ffcee1c4a28fa5445ce518eee9"
+ "37074ff7a402f5bbcb362ff090415f9dbd93b62ee56dc8c50e4d2e34c6c621650c0dffe311484e95d68de77170c909c815828946aeeec7ede56bcf433e22fc63"
+ "a33f764ced1f9242f3d26dc7558686e471f30fbe9304d3d56af8b23e72a4088970b24b2f7e968c1d0392eeeb0b0f0ac8c176547a5383d948ed15484b79e21314"
+ "a1f28ed624f61e5aaecf2269e5b027e1910ffddede52fad4e8da224e8a10b079548fa7cd44172f4991adfd7623d13e5a19c812824bcf990c07c9721ded9093be"
+ "6ce7bc7da3ac8c932133a64396b822be92b088844991596df893625a4ef24543bf75a10d7d17ff70350ef62ce3a7758aebbf9b3977b08becb9ea28376082f607"
+ "965f2cded28bbdb39dab7e00833b0488370d221742b66e27d9ee2d9dd07f401bc22a62c8a9d8d3a290c63804991496aafa47a32578f583cfb53d0c2199055973"
+ "440d7535e0da6cb2957f4e04002ecea68f9c3ff76cade27ed15fd7835989d0abb197fe32f68636139a42710644bb25860ff33f539200e3ccb8a7738422ca0fa0"
+ "c744b4c19d15c5d4a3cb082e20a78e20b5a4965b043595cbcacad500b5adbb6cd597e6a4b9c5ea6a1f2e653b5474da277f1818048094ac9e0e1e0b20068d1c1c"
+ "e5a114a4db7195057a6ce4d221c336fdc29190fee8ff855cae8b7f7c02eec21f972c827066d9c6dcc4a4179bc44ea9b88abe5124bf78b071e09e9af43f739a6e"
+ "1030091fc091e73edc447f25c68bf84b8df7aa8f091ab42662b93e02c27003afc7b0ca69efcfa60bd53d4d78ceb7c4d2c8fd5ed7e8b35024de849e06400ad145"
+ "fdb28348d22b317ccec704c401f88db1af2a5348223f5cefd914e404c9d73805d0de77211881486f1bf4aadacadd3ae2588f0db7b5e6957fed50a374f541cfe5"
+ "e4e923c82ec47e5b3d2c70ad6760c79cd5080b490bdc75f9ef5e1d17f0978b1e8770775f902b9463e6980e1683b2454751ba2dad4a2e6460924bd60ff49b0323"
+ "0cb11fcd04a0388e60874c35d3f6cfc4dd487665e1b16578751eaea89e126bf58044596e3188c7a9631017be1f2dcd7d612331832ff8755460dc496aa99a61ea"
+ "053c78e72607a18213ff9ef4bb880903b91e9a43e0b1f0ed1511b2eca2f4253fcfbd7d0faebf3680fbf0a45df231544882c9c46505c726d56905d02fd046c165"
+ "2d8fd06d15286a1a8f8b69fbd825ca421fd80f5e9ba1a23f924937ad049adeec60c78fea1adf9b1ef7e8ac4d1ded18f1a801b0bda8fe9a88098825ff3eef5c1f"
+ "c68cbea143310b39543293f3f5fbcf4773b02054c0bc79f00554947c7604b36389c0c45f597a88f3713456b4cfd83b30cb6520b624aa09c812066a8cd542dc67"
+ "e19e4c92b562b4e0f6799fe57d9d4f4f3e0b6fabff4b1fc190bf1e78775ebcbe3655d370ca6c08f48decf6153a4989eeab6921f8475f85197f51d651e5639942"
+ "57df57977e5f219b4879751de57ab0374b407a21adb4ba520bb35e7b7508675bf49f4e432190451423cbd529fc79b22baae9cb1d8660c3a49c456ac03bc06c0e"
+ "f3b02f7d8acd40919315206fb38e715139c9bd6f89a58634fe683df03f5bda719764f6c38131bc5ba1c53244472ef73834ade04b86ca08dd753141ac0a9a230e"
+ "246735060a044018bc9b75d50134b20e6219c13f8325b5a0201e9453f6f012fe72e829ee1c637fe30037a9212a31c6e713726a6cd4cf2dd66ffdba77f1e2800e"
+ "717940f231d04aa2e4e88dea084754947d848c0271856bfe659922408449858a81fa6583f062d96898d18ec53664f0067eb9b9c40ad2579ba9802abd8d1bf287"
+ "e49d94ae397e784db14b5f7010ee4fc42e6e3c8ba80370afc188fcecaf466ea830d7b16362e5c9329980b981decc7174f3ff70a35d8a180ee12ed0cbffd4e8d1"
+ "4eb503387e4959f702d4293109e922eb561371f9ab21475821f8555d92f0aa1c3d841a6f1eabd4e663993636c754ce2b3c3f6a6b6d0b161e777b8296d7dce7fd"
+ "162970496494d4f60716244a5a7fb7cee40e1d565e6566697e8f9300000000000000000000000005101318212b";
+
+static const char mldsa_87_pubkey_hex[] =
+ "17a508179b35057099111733da28fd1a2265de7d8ab22d5279f13bca84cc42a5b8c9644c121e7e1b81723c5295be288fb6c36bfa188b6e08d913a152350947fa"
+ "2c8ccc3fd01b319f65a2058a1dff54133946cfeb408d0b6dfde6bbebd7e0591cfe83b8b5452ceef6c855f7d33e06a0d269345089ed0d3ad67d84d8a4a34d1683"
+ "6004cff125469e8c3387abd788b620e30c1fc23909117a0e34c42a6631d9791347b1b2a3c9ab3082416211afb7bc3f6ce630a7019af19f736cdfacb1e7db66b6"
+ "5ef56844d2a2b0753d09283a7a0b66f77596384e95f7ceddd1c4ba20edc11f1eaab695bb963f6eda1c383754aa372a0d7729bfa6e0f142131c2367ba3f89ce3d"
+ "e6c357f9a7225b7cb85f6b3e8a3a122e8501fd1446b8152a415c19dda1d2e4590cd994f6664b4d1abd7381468c3a085abe2741a0cfbb81880664b271677245c4"
+ "a471bf8bb8e0192eb32e4fb5e8560f3c50d6b19a353e486d0fcc2a35ac046286e707e095f61786d92212686a65d39b6863e0f8cec1e1997f2f845e4878ca9df6"
+ "50c746765296790863e51d012d32dffcbd746aa2276d04c0a57cd1b3d6ed06c0d66a0897aae5c49c97b6f19ae829baaafbfed28a52c05963c6eea9eff6952829"
+ "4207f8cda75280f7c486e6848791c8e37015479f2e13c28a9fe654dbde11689875203aaec51be3da7cab1cf31e4ec476c0c830cbdd04ac02167c0a6fbfdd6548"
+ "b1fa525d235c7e3fca8d63e6427503b0a45c0bfddb428b837c32e8755441077bfe1c0142bac357b012a46545bf4148d465472dcf89c9d73b62357087e229f53a"
+ "450d3cce41c8ee21a9d54b61e34a794f5b1406a70724ab0c3712c49df231ef30a956075e907c51b63dd1f9453dbe60e25b0f3cc0354dfd7c9119313919e77cb2"
+ "c92f544d3e5302b8827603e936b567e99bfe9904932585a9f01a5a1b5bce07565f1d84c6b1c5c86259e1fefcff18cd06861122be6836be21e40be4eaf6bcabee"
+ "8f634f95520aa914bb51c54dbd67d1b9dc5e38831e786c283979a963a3206b98e339edec4128b0502d4d47813869713e431a529a03c7f54b50123680f2b7f256"
+ "f5d2b40642203259b9e85c62253d5670ce372193f28b5aa48ddd643c54756a2cff808c109f74772961d8db6bb8a17547c8f29c7f5ff3ea06740b867d84917e07"
+ "f3978ad0281a20689eef58467e768b6178a9b36a567289fd39762bb3e4254031b2798a4550857f6af369d484392cddd7b48eaa2942e2cbfe754d5ee2da2b7fa7"
+ "1222e4a525ff5224d551a778ebd828e4e0499adc74ff0d59a5abc78ad6a8abafeedb3c99045a14423507f85597b1a7f540982f7d72ea13449110b442d54b7802"
+ "9b4c7fe3b49396dc6c3b7d58792538fa907963de10a4b724548142541cdf1512e0f7ff1b10a93de63541b8cc3268b4de20ed26739ee8973b6507ebe48965602c"
+ "35fa3f7d4278146b598d7d7044e16e97e9351f7c51ac25573b7232ae2432638e9166190e7f7a7dcb5096ecb5d10017cdea2a82b4f56c7385041c6919a7e36e11"
+ "beac77ec3f25df44e7b596c1542c1e376de3667c0e903fe25b57c338e9d93c5570c484f0ddab4f57d38f292b23599d9efc7a9fd9e078aaddca0acb1a196d6c45"
+ "d3c8be6f39e8cdbe3299e370b262e0bf6fb5f005cae2b12879289d00bd8039de6a571c310d87557f5c9a4f64a0bde7177a8464722a04bf87fa2cb0e312d4fa6e"
+ "536c61d65dc2c1baf144b0d1d1d75f4c860626ff773933efa9941d105c53a1d92c4f7c7bba4aa969590acef1e50901870f59715ac14d9846d83871a77367be57"
+ "c63f88bc2c02eabafe678f44925a3e605979282fcd3f284736a1d346c033cb782dd615e886683fc37cd87a91422857774c63c6659096eba393c56225ed8c3485"
+ "b4f89ecb07d53526281a6426ae7d67cda52fec5ac32320caae9b96000bcbe9e8782be88cb1ca6dcaffb74ef04c77e03a994bea2c89e4fcfa44cd0c9f4e30705a"
+ "8b7b20df8c76b05a4479400e07db03d243e9fe4c90d34e9245f1e574be9a388f5355482077e4e98b919de024e666fdd7d51ed2a0d58a823e7497eb07303cf1d6"
+ "d5f10a536be980220de5856727e5c13981839cfa19740988e7771a2b984f53ae3a5916ed881a4a90fe524f0bb3778355882864f8961fade32e656fcf9f524e74"
+ "8c8196a1f1bbc57bf8da7b36de9b0080f0c7bb8487a2b7bb7a81a8ff43a2539b367c9a48c70041520f05ca3dae316dbbe3118218216f52b7bcdba7557c4c9d86"
+ "1803a5e2ee01d3682e1261d7cae0a99fb8de909eb2bc1e112aa43cc2fa9c76a222bd85faaaba5d9ec2198ac45a295181a324a0592632b89e2752582cd5e01e1a"
+ "610e7563faee10b76d853109e257e7c0c248a9fb7933f514b07b4f4e3a4a3d2cd22e8cc45ebda3bef5948aa050f01eff85ae98d19f69c51e67ff89f2df0c5268"
+ "acfdd325e84591317e05cab4f9e6358f249c4ddf4019fbc8f511549a733898a50efa9e0793083de0b15b5bf78d9f63d8df830d42df2fefa27b89e0ede2a702eb"
+ "9467118fc0ed44edc63ad1b1935877c34843fea06fdf388bbf83e501723a13cc6cc2efbb9691fe28fc1d45270591e5bdf7aa1c82673544ee29d9e6c9da3328f2"
+ "1e9729bffd7f4e56de585909679a74037105fdac3f51ae35f69d9763d2e4cfeb1d4a8fdce99bf1aa21f866a9f523b2a9549e12258a4d19900cf5db37b67da19b"
+ "23563bd1d701c6106fccb28e4689c62e1a6cf1abd763d7239c2258b765610d4478be9f1650cb8d18923592ad0024076e52f9bd0a3894fe97bc0a1646b4c37f62"
+ "c27f32d0df270260f47c49a5caf110e4cf80168a7d54b1c70bed9bd5d9a143ce869a05cd44ee266aecd6bfedb39be79e7c7d5c11a99575ebc0f389cc55a4fe14"
+ "69a2d61b70bfe4b74e3e27521a037d2b9f4fdb377231e2ceb214ba90f6953865c683215203ce963875c6524c01b789e0389a9f0c386eb236f0dfba6c95df4f28"
+ "ccc7ae7cd473f9dcd20817cccdd211bcbc78b064e936e4ba2813df531128428ddf410e6ca07044aeb4cfcc0a16c995ec51c8af16a541ce18dbeb69a26635632d"
+ "cc24ee52a5eedce38c502cd0e356ec31341c893f92e6063c3a160a53d34b85e92357a8ebaaad8f206771be43ee48cc409825a7094bda529ee18776d9e67f1fa1"
+ "c1419514309d70ba2443be2f63b6943478d6c0f56dd058731e53de4c30bfc7d915e9284a56248e81944392881666680d4991f04269ec9a83b24b458ed59a6c27"
+ "4de452ab3013c103a4920543e6a7d22dadfd764f6ea39d49b910ee0dc216e547aa5fb4382a72a568ebe83ec00416fb5830dc21c24ae72416602870cb52c3a8a1"
+ "c4c12a4b287b9b800d31c287ca161f404a9e598a5358d28b3aae43e534846bcd0d7a9c7652ae01e6698c79e315aca8198f36de45af7084b1cb21ca2ba0ee3a54"
+ "7a7343a10ef9e3fd17b0a4060badd1409a0562cba25b84fd578268fac53cfbca08e6cf6e5419f57262eb5813c1d1324e0df1d483ade08d8f6c62498e262485ac"
+ "7c2872b11b42e5c1b797fc12e838b38a711d364d45cd1ed35f7faffdf4b0fb0eaa312fc3d5af77909b0649cbbacea10c9831273922b5b05172face9ce6cf324e"
+ "df6e2f5f5fa0a9f0463eee938b30adf3e55664f94d274cd87dea901a7e08e805";
+
+static const char mldsa_87_msg_hex[] =
+ "48656c6c6f20776f726c64";
+
+static const char mldsa_87_sig_hex[] =
+ "ba4275ff54c22d2d09ea1937a0667362acd44925c6d6965fad350b111d1cbcce68ddbd0e576d1a8810eb4e71623781f32f747d44c8e693749df191682f588906"
+ "949d97617a4b0ec54ad966818dee88b95f0f28ca24bfc5bfe0c316140b0662c43093ae48b899cc71e5739e9d67095ed987a79b6a0e7aac960c3c4125f0e92bc9"
+ "435d10bfffae34bb3af05e977ebe0bafcbeb2381c5afe3379667b4c201aebf162dbd0a4bd1baa88fb2f88fa970499a848737d3cf94cc8ce278880a169cad91f3"
+ "04e4e8f1091d4cf39d9a3ab9f88dcc6f3bc4df311a5be0cba290365b3e879527e2a77f0cb6eccc9d85a5e592fb00f3a2e925a26d295a6b82746d7f534c83c35b"
+ "c4826ee4910216b9a2867032698996fb0e1669b539ccd2ec74d181f4844e8f4d28f9c174316c12dadb54cb1dde7338238a20731c2565bb959f8e3086273ed03a"
+ "bc7ac515728750633083c0b397b29d385d13f5afd2529b32f00dce66c9dc8ea93d99c8b61c5e0ab2fc70de2a8dabdcaf290d53e8fca7561bda8c516ad475e4ec"
+ "6c7cd2603aa3c8a71d9fa5dc7efc33cf318bebc1f1594e6ea25c69b8f9ce34a65b8ab0ae8dd3538bd267d86c584b8f354d7e4776ed4dd59a73f9e70a1df572f0"
+ "33b69b3eafa5a901e02515472e37258608875ca469de07db71cd6b8dc7edeb3d866ed2d219e44fcb133a066e89d8e3013569ca6f1fee7bf4ae56a6d32a5f3e5a"
+ "530819c31aadabc8a88503edbea9cdfa3171762e1e8bcebaf9bb6af7e540102d5fc810bbcf1e02ae564e04d9dc55dab0a9392d6c95a317730d9793954da2cb16"
+ "544d15403d0db01e85881e2d4f1b9b98458e1af0985f98b014f08f200558f2fed7a70c352a27423bedeebb3775c0a1ede9d461d2aea303c09c8b1f73fc37a5b3"
+ "a01fb24a131574f7eac90c78baa38cebe81e2335dafda20299f76d6a0ba77d2954d11381674f4069f45e133886d64222d92583d5908e3ab6eb6a72cfb41f7dc3"
+ "e71c1383888f61624bdcaf12fb716de98232ee329af1dd045f30d377234db7bfd11ddab0b3108329e16ce568c8bada39a98df5a5f72a72f063fa4253313a8060"
+ "13f61ce5adbe54cf42180ebf6e496bd4b42aeacf069aaa8e1c231fd037b394d78a69d1742b45bc5784ab8593a198077423c4c357d734f9899cfe9b3b62b6b9c3"
+ "f4d781b8484a3fd0eea7e8d6945f4ba2b046fee079b7f032bebbc402918daa2aa1c9433dc3bcfbd7f49a5d7a293833c21c1bade3e8a7ec3c83d485529de51b59"
+ "93cdffe23b770e25acab0ab9fb3059f14952d9464ebfa36a6274d8da317a7b07c2afe38ba28ca942cf7bfaee4020e59911c047b2aa24d1787baae1bc3546364b"
+ "782358676d75c7698769f1d4a0d5dccade7fcf80e308437f7fc24fdfbf72625abf1b0f534da62cf860da1efd986950e3e19a085999f4d008fce38459c673befc"
+ "df2287c1766e106beb4f3175e97812da141330dcb2beb3265e38c8423c19dd50a655c9e8dc969f6367f3383b644d53a26875d53cea26de429266b506e70e7e68"
+ "32886ed06d81738b0b482bd23bda396eb674ddfdb64803d6c4fae2f040170b5a28923279838b7b876220d02dc7478666f7c3287b1ba4a2f8228e8c491a55ba45"
+ "9805c601b986caea27ee9436f63383351c74d673643b15f6007fc6dc49e337a65a8a96ecd7eef4ad730bf3dc1972fc396703ee26af1156dc4beb46c47d99bb69"
+ "ebdaf81c2d738d0f70e57a2c7162f5a55242255675f22082aa43f5b3dd862b535b2a15bb815b4e9faf16a302552cd6098d40930dfad7a7c609d6aeade814242a"
+ "8bf0721c1c26d0d3daa7a638880a6411c6538d80c259d31b639aadaea49563a8d7f5ddb64291d6b086c80d72bfe7d26802cbd20fd6ba5495011e42da1c82483c"
+ "be8e37838e73c48f79f65b205476bee600399feda6aaaa939eee12cb34be4e6bdbd18032c85b54a2713551de677a16ca0142ff97b77bc963e8f3c57d91df9b49"
+ "474b01ca514641842893abc3181caee3f49b635d17daf41bcc4aeb1116ec4b3e78ff1480cf3a5d9c6a154384b88516834d19196976e2ba97cee91f7a0d73f7f8"
+ "146e58dc0fc8f510511d39d82a7ba531a4abcce6b624035d753a37c5980343cfc7724cf83efb0c33fc4abb5b002241bf57a46b67cb5a4cbd637b2f19bc93b368"
+ "d97e13c6a62c8443c8222e0a90c3ed1972cc739b824fdf729ed8eca02ad96bd78bf6d2b3d2853e24fa93199ff41635176b31aab2207013d0a9317fa49668dfeb"
+ "672b8129e6175a2998642ab8e74f0823e3b5480ae80180ca395f5348744a3c7b344891f008aab65914760b5fe852615ad6425216b1c5e777db1a46517cd01a77"
+ "b277cfa2c6f250c2d68c495fef28feee6e0716817d6b30716f5ca48001805042133eca17a41c2219784ce0f12858ccfd371c77b90966ea04c3996851edf31aef"
+ "962946628007de5531b06fddf3449f6c552eaf6e16b3e9160e265900b8c8e414732505e02660e123d45a3d6f1b15e56fd759d38e821e27e84967e95c4b0d2a48"
+ "e008897e655d1b65b76299f1e3074209abe44b37f8786b02df23aa4dcebe512e6312f1a3d6d781d749635247aca897626f5ee688f517df6cfe947ddead820f07"
+ "fed4bcbe7f1bee3f19117b5666dc123d528f2bf03db346d6afb53804b0681aea98a9479fc6de5ae974d2c0d2055f07ba8a1d2d8b6a7e08a6805bd8634cc190c4"
+ "988b502f475c36d78c7b3dda0057c818835bbf21c5a7c13bb6fd91cd3cfd76abe4c2ff908a08a3000b9021500ff94b297cec0fb3e51b1cae7026ab4347bfd5b6"
+ "a641a3d347f45a2a2aacd22e521e00da0c3986c67672c5d7d7e61e7edafc15d42aa42cb37fa8621f79e9096b092efe853ab318b3e4bbd90f20165a1be1d3aa5b"
+ "3de43751b65abbd952599869778393c4351ab8f534fd49e16547df01c40bfaf56de60b4fb0019bc34177cc8e2236d219fb3c0b84dedae6b88e134280eabd1823"
+ "420cd1afe6d929774967fd7d885fbad33d89ed9dc5e0eb978eab5d96c50bed5887aa8277880c7b06bf2780cee82ce639a1e3344c88a25102edcc17a4cb48989c"
+ "4ad6a998726ede31deb0b98107f40858bad7864983f6ecdf0c9761a42751b19d5360daa7fddbbd2e2292638b95c763ca1e747eedef0dd387e9d9ec9e5afee207"
+ "d8c45703c5befc2de3878d313655ce85ad984250cdf054360f33d41dc193060d42cf9528b1fb91d6ca3395199e25a1a7739eba9a6a4ac2c417ae615940b3eb1b"
+ "746dd0ecc7b2f7acdff887110115629f70877dafcd7a6625fa1b9e256bc8fe1d66005dbcf12fde0a5fcda5d4f23d58ece91d60eb91274df8d9d17d4a39e63533"
+ "acf1b317db979b04ca3ab9a0bcba652d0010ca3fcd33ed8f8a62faf42f78b37912d3adb410f20bf16b31359cacc25fb783083a3f065f0a2dd6fe58b8f594e11a"
+ "87bf0f4c5f5493f334c18b03ebdefebce50228937ec13a8c221b617450486291071f3c14f64f66c927dd4bd623c214ac35433b8a6875cdf00916476eac0f1968"
+ "58aa1484bc1cd45b726d33a965619829b8deaa9d9fa0c3c210f23967ce26a4bdd939cff8aa662f70fb0af97ee44bcb9e2755000a195741d8919e4dcb1a5caae2"
+ "1009f686fa1489c72f16f9fee76b5410ece7f406947f4a19f394a5121da79f3216777b0fee5423328156ecf0b4548dbd5b3f7b526d6b9cfd57576f67dd521c31"
+ "4c2d37474ed0cf732c3b073a101c735a4c4e6b33c9aaa12c91d147ad1075a20287d36c388657614a9c648d8e49cce8cfa282b2a2e8e9da6e4444e4b6aed1bd0a"
+ "da5009a335cd0500bdae9a01b97f7e8cfe8372398e750de92ee4a524393a19826d19de5e762fb53a88b9b4657e9c6d7d01a4124e3e39532f614aec5cb88d982b"
+ "78b2ff568017c92f6a1ce5298b5f323b5ee61695038ef0c3a7a339cfac31cf7875a4563046a40e7b35cef1d37d811b342fcbb5373122415befc23cb656a619f7"
+ "c262c443403b23ba20e341a079918dec6f4f801b92781179ad7ac1951f39ddb0b1f1fb95b28c0f4593a04486f0e0e86bb3b014674879aad10f41e0bad34d40bc"
+ "817b6fd43c1dde8547882d82e5111e208107e9c9736d16ca77ac7453d7b6c7976a7dd6a4c6c0252185bc9948660a07b66151b09b980d8572ae829ab2f6d900cc"
+ "63066c4ecb3a0317e8a9acaa8e22a216721f3d69c67843df2fbedd88bc424f761cdf420de4ff2c55b6925b1826c1c4134090d2aae82a7f64a8d428efe1b21097"
+ "a6fdbc9b8a31c4d46c7b32d478bf5b9181bef8af4d3486958d7c198c46a5ad771090bb64e7fc2bd7677ae7618b861c83c13177075063517eff40cfd52ae56650"
+ "e9e7035f783bfe8920c754e98470b327909ac2a407e07864710544b8adbc075502c75b5f0fdbca0cde5d94b013141c96b55ae1b60ab63f9e792641690af41b05"
+ "a78233935fd7f82852ebb2602a10459a709256c41d108c2aeb71925089cc79b121eabd5edc54f3f7c8929685b88ab29700c7fb2f247cd7962c8ce6dc9f79f935"
+ "8d6a7989d24ccc17d0dbaa0b7fbe73479164181ae7d6b6a02678cce46f74ea2bd387ecb73041817b429a0220e1c3635fe492f5f3a8e2b65c086fe24c375563d7"
+ "220856dd8f970716d548492964a156554dc88810c3c4f81dcc3ae80243e19679a3be9c9b1b8c707b416e9166c54a568bb9d84728c1a283d9231a12b13688ce23"
+ "62901342652d66bf44cec223f561d2735d977c6adcf57e9066220d0770fc77fdf6ff367a2f36ae20062887beb88d1b453f267aef9bc763ab716bacb9214c38b9"
+ "5f4f2f3f6c236aa71aef83c1ae4b26133678884476c1d7c6d3e7b99f13e028ac6cebddfae4793f9ae975f3d66b725b500e7c7d2f664eaa0c358deb91cb2d6173"
+ "394b306749d2bfb2684b985769bdb682e922b75555d38dad1899057a64ef6ea361e4712244d02d0dfec8c3d40770122770c2538d6a14a8462ef18eb705c16e5b"
+ "a30aa5366447c94869060e4df155f7d01ffda04c1ced0ad5fbe5fdd85856e1e49320319687d31a6e4c7145479f45f43a9b8e9ffe4cbacfad4a21e5445e119df2"
+ "996cce8b11d0f224efb4f18b544d456e2fb1d96fcd99fc319dbd86720621ac25b490f3611f7e5655bb3940a503c07dbf41f4b87593595a66008808744668371a"
+ "54ce1b9dfdaa16f90415e57470bc23898d13d8351ba34369e96347da13d012b4eab32ada90668654c5ed2b433716b1b4170f640cf4b40659efcf4150237bbc25"
+ "f72b248be85cd482b55ce2f5f73e8f02efd2465805b37d12487465ec1085bc6602b71862771af13e13baece4916b1ddef9ce016c92db9fb9e82aee5e1c4e22c4"
+ "5090ad1c19801ce1c541ff3902baea7a12dbcac6ec2d128ac7acb203463921ca6ce1d182d60d553ddecc4a3175eec2e924e9191e0d69aa49ca0b653495b8c62b"
+ "802e443e669220f2a4047a56ed5cb7431a3387a435070795e6e63d242a74555e97371989c6d0040748e89ac316618d5d6eb7bff8d91e953afbe00464df4e4f63"
+ "80c273b7ac5934cacb6c3be4da6649c8a5ea12bdf9afa1ec1e5053db7668c10ae2df75c4b3b14525369bf33741525a7630158aca3d3c7da5c1d71d3f63c0c294"
+ "8a43236968d623c6c163eb757f0c78d6ae682ff4e4b673be07193e8d6c106c92851b393f0523491d5152e06de675fa22ae7bded329836a8ca0b955a59cb57539"
+ "5952c6ea0cb1644f2cada196b96b44ee12115ff9668e32886103d8f8109fac4a2287738ee1d2d4c1c19dab94eaa2757ea32016df60d7286099eb010ba570b579"
+ "1ce4c54d860b15d56c53a5ddb543b0b602b3a87ca5213aa9647e51b1cb1736697506081240f4f7163a646f2be30e62c617d7572d820a113f96320834a2f43842"
+ "160511923bd1ef4f723a2ab9b242fffe97cf0199c9f2ebca266a63beea0af279f2d18651b2ea9789d03025857c8aefc5f8bc6ee92ab7c6ffed2606f9c7ef25cb"
+ "6c96140256a08cc58218869c52f3e5074fe5ace87a86057cc29fc845ff275f1b2dbc5991cbebe4c556b29ce3da3415958f0c9c68a5c664a1da60365ce56b9a4d"
+ "f24ec5d69c6f5a2e685885f6973c0ccd4caf7e000346bdea502b1418c8819e05bb7bee31bbd235819b49c892f7dadade576cb8ca68bda916a598c32ec03cceba"
+ "2d01a7960f38680facccdaaf05e254dd8c3631a7222d1561c998c54b16f17a425f3247232dca035d545202e1b180340219ce31c66987bc86f983240e7fd2c926"
+ "e8af77e6ea9f4139ff1edc0c323b67ceadead8f64a8004164d942f6aa65a28544d7205d41aafe62c5bfc6fd9fc322e2a8b620532d00d1add7a0d25a9dbaff90e"
+ "19de14ac2ca97e83a2d77e63888ba0f7eaf9b18a7f2e5f148d16887580e55e894ae79024385f439acd071494e6469b77d07e763553652a470f3b4bd8bb796805"
+ "2f3a969dacced51572bd125870849ce3e55359b2e17eabc3153b5f62868ea0ca1f40738488dbe0020c103f53678b9eb1c1000000000000000000000000000000"
+ "0000000000000000000000070a111518202731";
+
+static int s_decode_hex(const char *hex, unsigned char *buf, unsigned long *len)
+{
+ return base16_decode(hex, XSTRLEN(hex), buf, len);
+}
+
+static int s_mldsa_sign_verify(int alg)
+{
+ mldsa_key key, pubkey, imported_priv, imported_pub;
+ const unsigned char msg[] = "test message for ML-DSA";
+ unsigned char der_buf[5200], sig[4700], pk_buf[2600], sk_buf[4900], cmp_buf[4900];
+ unsigned long derlen, siglen, pklen, sklen, cmplen;
+ int stat, prng_idx;
+
+ prng_idx = find_prng("yarrow");
+ XMEMSET(&key, 0, sizeof(key));
+ XMEMSET(&pubkey, 0, sizeof(pubkey));
+ XMEMSET(&imported_priv, 0, sizeof(imported_priv));
+ XMEMSET(&imported_pub, 0, sizeof(imported_pub));
+
+ /* keygen */
+ DO(mldsa_make_key(&yarrow_prng, prng_idx, alg, &key));
+ ENSURE(key.type == PK_PRIVATE);
+
+ /* export/import private key in PKCS#8 format */
+ derlen = sizeof(der_buf);
+ DO(mldsa_export(der_buf, &derlen, PK_PRIVATE | PK_STD, &key));
+ DO(mldsa_import_pkcs8(der_buf, derlen, NULL, &imported_priv));
+
+ /* sign */
+ siglen = sizeof(sig);
+ DO(mldsa_sign(msg, sizeof(msg), sig, &siglen, NULL, 0,
+ &yarrow_prng, prng_idx, &key));
+
+ sklen = sizeof(sk_buf);
+ DO(mldsa_export_raw(sk_buf, &sklen, PK_PRIVATE, &key));
+ cmplen = sizeof(cmp_buf);
+ DO(mldsa_export_raw(cmp_buf, &cmplen, PK_PRIVATE, &imported_priv));
+ COMPARE_TESTVECTOR(cmp_buf, cmplen, sk_buf, sklen, "ML-DSA private std round-trip", alg);
+
+ /* export/import public key */
+ pklen = sizeof(pk_buf);
+ DO(mldsa_export_raw(pk_buf, &pklen, PK_PUBLIC, &key));
+ DO(mldsa_import_raw(pk_buf, pklen, PK_PUBLIC, alg, &pubkey));
+
+ cmplen = sizeof(cmp_buf);
+ DO(mldsa_export_raw(cmp_buf, &cmplen, PK_PUBLIC, &imported_priv));
+ COMPARE_TESTVECTOR(cmp_buf, cmplen, pk_buf, pklen, "ML-DSA public from imported private", alg);
+
+ /* export/import public key in SubjectPublicKeyInfo format */
+ derlen = sizeof(der_buf);
+ DO(mldsa_export(der_buf, &derlen, PK_PUBLIC | PK_STD, &key));
+ DO(mldsa_import(der_buf, derlen, &imported_pub));
+ cmplen = sizeof(cmp_buf);
+ DO(mldsa_export_raw(cmp_buf, &cmplen, PK_PUBLIC, &imported_pub));
+ COMPARE_TESTVECTOR(cmp_buf, cmplen, pk_buf, pklen, "ML-DSA public std round-trip", alg);
+
+ /* sign/verify with exported/imported std keys */
+ siglen = sizeof(sig);
+ DO(mldsa_sign(msg, sizeof(msg), sig, &siglen, NULL, 0,
+ &yarrow_prng, prng_idx, &imported_priv));
+ stat = 0;
+ DO(mldsa_verify(sig, siglen, msg, sizeof(msg), NULL, 0, &stat, &imported_pub));
+ ENSURE(stat == 1);
+
+ /* verify with public key */
+ stat = 0;
+ DO(mldsa_verify(sig, siglen, msg, sizeof(msg), NULL, 0, &stat, &pubkey));
+ ENSURE(stat == 1);
+
+ /* corrupted signature must fail */
+ sig[0] ^= 1;
+ stat = 1;
+ DO(mldsa_verify(sig, siglen, msg, sizeof(msg), NULL, 0, &stat, &pubkey));
+ ENSURE(stat == 0);
+
+ /* export/import private key round-trip */
+ sklen = sizeof(sk_buf);
+ DO(mldsa_export_raw(sk_buf, &sklen, PK_PRIVATE, &key));
+ mldsa_free(&key);
+ DO(mldsa_import_raw(sk_buf, sklen, PK_PRIVATE, alg, &key));
+ ENSURE(key.type == PK_PRIVATE);
+
+ /* sign again after reimport */
+ sig[0] ^= 1; /* undo corruption */
+ siglen = sizeof(sig);
+ DO(mldsa_sign(msg, sizeof(msg), sig, &siglen, NULL, 0,
+ &yarrow_prng, prng_idx, &key));
+ stat = 0;
+ DO(mldsa_verify(sig, siglen, msg, sizeof(msg), NULL, 0, &stat, &pubkey));
+ ENSURE(stat == 1);
+
+ /* sign with context string */
+ siglen = sizeof(sig);
+ DO(mldsa_sign(msg, sizeof(msg), sig, &siglen,
+ (const unsigned char *)"ctx", 3,
+ &yarrow_prng, prng_idx, &key));
+ stat = 0;
+ DO(mldsa_verify(sig, siglen, msg, sizeof(msg),
+ (const unsigned char *)"ctx", 3, &stat, &pubkey));
+ ENSURE(stat == 1);
+
+ /* wrong context must fail */
+ stat = 1;
+ DO(mldsa_verify(sig, siglen, msg, sizeof(msg),
+ (const unsigned char *)"bad", 3, &stat, &pubkey));
+ ENSURE(stat == 0);
+
+ mldsa_free(&key);
+ mldsa_free(&pubkey);
+ mldsa_free(&imported_priv);
+ mldsa_free(&imported_pub);
+ return CRYPT_OK;
+}
+
+static int s_mldsa_sizes_test(void)
+{
+ unsigned long pk, sk, sig;
+
+ DO(mldsa_get_sizes(LTC_MLDSA_44, &pk, &sk, &sig));
+ ENSURE(pk == 1312 && sk == 2560 && sig == 2420);
+
+ DO(mldsa_get_sizes(LTC_MLDSA_65, &pk, &sk, &sig));
+ ENSURE(pk == 1952 && sk == 4032 && sig == 3309);
+
+ DO(mldsa_get_sizes(LTC_MLDSA_87, &pk, &sk, &sig));
+ ENSURE(pk == 2592 && sk == 4896 && sig == 4627);
+
+ SHOULD_FAIL(mldsa_get_sizes(99, &pk, &sk, &sig));
+
+ return CRYPT_OK;
+}
+
+static int s_mldsa_from_seed_test(void)
+{
+ static const unsigned char seed[32] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+ };
+ mldsa_key key1, key2;
+ unsigned char pk1[2600], pk2[2600], sk1[4900], sk2[4900];
+ unsigned long pk1len, pk2len, sk1len, sk2len;
+
+ XMEMSET(&key1, 0, sizeof(key1));
+ XMEMSET(&key2, 0, sizeof(key2));
+
+ DO(mldsa_make_key_from_seed(LTC_MLDSA_44, seed, sizeof(seed), &key1));
+ DO(mldsa_make_key_from_seed(LTC_MLDSA_44, seed, sizeof(seed), &key2));
+
+ pk1len = sizeof(pk1);
+ pk2len = sizeof(pk2);
+ sk1len = sizeof(sk1);
+ sk2len = sizeof(sk2);
+ DO(mldsa_export_raw(pk1, &pk1len, PK_PUBLIC, &key1));
+ DO(mldsa_export_raw(pk2, &pk2len, PK_PUBLIC, &key2));
+ DO(mldsa_export_raw(sk1, &sk1len, PK_PRIVATE, &key1));
+ DO(mldsa_export_raw(sk2, &sk2len, PK_PRIVATE, &key2));
+
+ COMPARE_TESTVECTOR(pk1, pk1len, pk2, pk2len, "ML-DSA deterministic public key", 0);
+ COMPARE_TESTVECTOR(sk1, sk1len, sk2, sk2len, "ML-DSA deterministic private key", 0);
+
+ SHOULD_FAIL(mldsa_make_key_from_seed(LTC_MLDSA_44, seed, sizeof(seed) - 1, &key2));
+
+ mldsa_free(&key1);
+ mldsa_free(&key2);
+ return CRYPT_OK;
+}
+
+static int s_mldsa_openssl_verify_test(void)
+{
+ static const struct {
+ int alg;
+ const char *pubkey_hex;
+ const char *msg_hex;
+ const char *sig_hex;
+ } vectors[] = {
+ { LTC_MLDSA_44, mldsa_44_pubkey_hex, mldsa_44_msg_hex, mldsa_44_sig_hex },
+ { LTC_MLDSA_65, mldsa_65_pubkey_hex, mldsa_65_msg_hex, mldsa_65_sig_hex },
+ { LTC_MLDSA_87, mldsa_87_pubkey_hex, mldsa_87_msg_hex, mldsa_87_sig_hex }
+ };
+ unsigned char pub[2600], msg[32], sig[4700];
+ unsigned long publen, msglen, siglen;
+ unsigned long n;
+
+ for (n = 0; n < sizeof(vectors) / sizeof(vectors[0]); n++) {
+ mldsa_key key;
+ int stat = 0;
+
+ XMEMSET(&key, 0, sizeof(key));
+
+ publen = sizeof(pub);
+ msglen = sizeof(msg);
+ siglen = sizeof(sig);
+ DO(s_decode_hex(vectors[n].pubkey_hex, pub, &publen));
+ DO(s_decode_hex(vectors[n].msg_hex, msg, &msglen));
+ DO(s_decode_hex(vectors[n].sig_hex, sig, &siglen));
+
+ DO(mldsa_import_raw(pub, publen, PK_PUBLIC, vectors[n].alg, &key));
+ DO(mldsa_verify(sig, siglen, msg, msglen, NULL, 0, &stat, &key));
+ ENSURE(stat == 1);
+
+ mldsa_free(&key);
+ }
+
+ return CRYPT_OK;
+}
+
+int pqc_mldsa_test(void)
+{
+ if (ltc_mp.name == NULL) return CRYPT_NOP;
+
+ DO(s_mldsa_sizes_test());
+ DO(s_mldsa_from_seed_test());
+ DO(s_mldsa_openssl_verify_test());
+ DO(s_mldsa_sign_verify(LTC_MLDSA_44));
+ DO(s_mldsa_sign_verify(LTC_MLDSA_65));
+ DO(s_mldsa_sign_verify(LTC_MLDSA_87));
+ return CRYPT_OK;
+}
+
+#else
+
+int pqc_mldsa_test(void)
+{
+ return CRYPT_NOP;
+}
+
+#endif
diff --git a/tests/pqc_mlkem_test.c b/tests/pqc_mlkem_test.c
new file mode 100644
index 000000000..0c72ff174
--- /dev/null
+++ b/tests/pqc_mlkem_test.c
@@ -0,0 +1,340 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_test.h"
+
+#ifdef LTC_MLKEM
+
+/* OpenSSL 4.0.0 test vectors from test/evp_extra_test.c */
+static const char ml_kem_seed_hex[] =
+ "7c9935a0b07694aa0c6d10e4db6b1add2fd81a25ccb148032dcd739936737f2d8626ed79d451140800e03b59b956f8210e556067407d13dc90fa9e8b872bfb8f";
+
+static const char ml_kem_512_pubkey_hex[] =
+ "400865ed10b619aa5811139bc086825782b2b7124f757c83ae794444bc78a47896acf1262c81351077893bfc56f90449c2fa5f6e586dd37c0b9b581992638cb7"
+ "e7bcbbb99afe4781d80a50e69463fbd988722c3635423e27466c71dcc674527ccd728968cbcdc00c5c9035bb0af2c9922c7881a41dd2875273925131230f6ca5"
+ "9e9136b39f956c93b3b2d14c641b089e07d0a840c893ecd76bbf92c805456668d07c621491c5c054991a656f511619556eb97782e27a3c785124c70b0daba6c6"
+ "24d18e0f9793f96ba9e1599b17b30dccc0b4f3766a07b23b257309cd76aba072c2b9c9744394c6ab9cb6c54a97b5c57861a58dc0a03519832ee32a07654a070c"
+ "0c8c4e8648addc355f274fc6b92a087b3f9751923e44274f858c49caba72b65851b3adc48936955097cad9553f5a263f1844b52a020ff7ca89e881a01b95d957"
+ "a3153c0a5e0a1ccd66b1821a2b8632546e24c7cbbc4cb08808cac37f7da6b16f8aced052cdb2564948f1ab0f768a0d3286ccc7c3749c63c781530fa1ae670542"
+ "855004a645b522881ec1412bdae342085a9dd5f8126af96bbdb0c1af69a15562cb2a155a100309d1b641d08b2d4ed17bfbf0bc04265f9b10c108f850309504d7"
+ "72811bba8e2be16249aa737d879fc7fb255ee7a6a0a753bd93741c61658ec074f6e002b019345769113cc013ff7494ba8378b11a172260aaa53421bde03a3558"
+ "9d57e322fefa4100a4743926ab7d62258b87b31ccbb5e6b89cb10b271aa05d994bb5708b23ab327ecb93c0f3156869f0883da2064f795e0e2ab7d3c64d61d230"
+ "3fc3a29e1619923ca801e59fd752ca6e7649d303c9d20788e1214651b06995eb260c929a1344a849b25ca0a01f1eb52913686bba619e23714464031a78439287"
+ "fca78f4c0476223eea61b7f25a7ce42cca901b2aea129817894ba3470823854f3e5b28d86ba979e54671862d90470b1e7838972a81a48107d6ac0611406b21fb"
+ "cce1db7702ea9dd6ba6e40527b9dc663f3c93bad056dc28511f66c3e0b928db8879d22c592685cc775a6cd574ac3bce3b27591c821929076358a2200b377365f"
+ "7efb9e40c3bf0ff0432986ae4bc1a242ce9921aa9e22448819585dea308eb039";
+
+static const char ml_kem_768_pubkey_hex[] =
+ "a8e651a1e685f22478a8954f007bc7711b930772c78f092e82878e3e937f367967532913a8d53dfdf4bfb1f8846746596705cf345142b972a3f16325c40c2952"
+ "a37b25897e5ef35fbaeb73a4acbeb6a0b89942ceb195531cfc0a07993954483e6cbc87c06aa74ff0cac5207e535b260aa98d1198c07da605c4d11020f6c9f7bb"
+ "68bb3456c73a01b710bc99d17739a51716aa01660c8b628b2f5602ba65f07ea993336e896e83f2c5731bbf03460c5b6c8afecb748ee391e98934a2c57d4d069f"
+ "50d88b30d6966f38c37bc649b82634ce7722645ccd625063364646d6d699db57b45eb67465e16de4d406a818b9eae1ca916a2594489708a43cea88b02a4c03d0"
+ "9b44815c97101caf5048bbcb247ae2366cdc254ba22129f45b3b0eb399ca91a303402830ec01db7b2ca480cf350409b216094b7b0c3ae33ce10a9124e89651ab"
+ "901ea253c8415bd7825f02bb229369af972028f22875ea55af16d3bc69f70c2ee8b75f28b47dd391f989ade314729c331fa04c1917b278c3eb602868512821ad"
+ "c825c64577ce1e63b1d9644a612948a3483c7f1b9a258000e30196944a403627609c76c7ea6b5de01764d24379117b9ea29848dc555c454bceae1ba5cc72c74a"
+ "b96b9c91b910d26b88b25639d4778ae26c7c6151a19c6cd7938454372465e4c5ec29245acb3db5379de3dabfa629a7c04a8353a8530c95acb732bb4bb81932bb"
+ "2ca7a848cd366801444abe23c83b366a87d6a3cf360924c002bae90af65c48060b3752f2badf1ab2722072554a5059753594e6a702761fc97684c8c4a7540a6b"
+ "07fbc9de87c974aa8809d928c7f4cbbf8045aea5bc667825fd05a521f1a4bf539210c7113bc37b3e58b0cbfc53c841cbb0371de2e511b989cb7c70c023366d78"
+ "f9c37ef047f8720be1c759a8d96b93f65a94114ffaf60d9a81795e995c71152a4691a5a602a9e1f3599e37c768c7bc108994c0669f3adc957d46b4b6256968e2"
+ "90d7892ea85464ee7a750f39c5e3152c2dfc56d8b0c924ba8a959a68096547f66423c838982a5794b9e1533771331a9a656c28828beb9126a60e95e8c5d90683"
+ "2c7710705576b1fb9507269ddaf8c95ce9719b2ca8dd112be10bcc9f4a37bd1b1eeeb33ecda76ae9f69a5d4b2923a86957671d619335be1c4c2c77ce87c41f98"
+ "a8cc466460fa300aaf5b301f0a1d09c88e65da4d8ee64f68c02189bbb3584baff716c85db654048a004333489393a07427cd3e217e6a345f6c2c2b13c27b3372"
+ "71c0b27b2dbaa00d237600b5b594e8cf2dd625ea76cf0ed899122c9796b4b0187004258049a477cd11d68c49b9a0e7b00bce8cac7864cbb375140084744c9306"
+ "2694ca795c4f40e7acc9c5a1884072d8c38dafb501ee4184dd5a819ec24ec1651261f962b17a7215aa4a748c15836c389137678204838d7195a85b4f98a1b574"
+ "c4cd7909cd1f833effd1485543229d3748d9b5cd6c17b9b3b84aef8bce13e683733659c79542d615782a71cdeee792bab51bdc4bbfe8308e663144ede8491830"
+ "ad98b4634f64aba8b9c042272653920f380c1a17ca87ced7aac41c82888793181a6f76e197b7b90ef90943bb3844912911d8551e5466c5767ab0bc61a1a3f736"
+ "162ec098a900b12dd8fabbfb3fe8cb1dc4e8315f2af0d32f0017ae136e19f028";
+
+static const char ml_kem_1024_pubkey_hex[] =
+ "537911957c125148a87f41589cb222d0d19229e2cb55e1a044791e7ca61192a46460c3183d2bcd6de08a5e7651603acc349ca16cba18abb23a3e8c330d742159"
+ "8a6278ec7ebfabca0ef488b2290554753499c0452e453815309955b8150fa1a1e393386dc12fdb27b38c6745f2944016ec457f39b18d604a07a1abe07bc84405"
+ "0ffa8a06fa154a49d88fac775452d6a7c0e589bfb5c370c2c4b6201dda80c9ab2076ecc08b44522fda3326f033806dd2693f319739f40c4f42b24aca7098fb8f"
+ "f5f9ac20292d02b56ac746801acccc84863dee32878497b69438bf991776286650482c8d9d9587bc6a55b85c4d7fa74d02656b421c9e23e03a48d4b74425c26e"
+ "4a20dd9562a4da0793f3a352ccc0f18217d868c7f5002abe768b1fc73f05744e7cc28f10344062c10e08eccced3c1f7d392c01d979dd718d8398374665a16a98"
+ "70585c39d5589a50e133389c9b9a276c024260d9fc7711c81b6337b57da3c376d0cd74e14c73727b276656b9d8a4eb71896ff589d4b893e7110f3bb948ece291"
+ "dd86c0b7468a678c746980c12aa6b95e2b0cbe4331bb24a33a270153aa472c47312382ca365c5f35259d025746fc6595fe636c767510a69c1e8a176b7949958f"
+ "2697399497a2fc7364a12c8198295239c826cb5082086077282ed628651fc04c639b438522a9de309b14b086d6e923c551623bd72a733cb0dabc54a9416a99e7"
+ "2c9fda1cb3fb9ba06b8adb2422d68cadc553c98202a17656478ac044ef3456378abce9991e0141ba79094fa8f77a300805d2d32ffc62bf0ca4554c330c2bb704"
+ "2db35102f68b1a0062583865381c74dd913af70b26cf0923d0c4cb971692222552a8f4b788b4afd1341a9df415cf203900f5ccf7f65988949a75580d04963985"
+ "3100854b21f4018003502bb1ba95f556a5d67c7eb52410eba288a6d0635ca8a4f6d696d0a020c826938d34943c3808c79cc007768533216bc1b29da6c812eff3"
+ "340baa8d2e65344f09bd47894f5a3a4118715b3c5020679327f9189f7e10856b238bb9b0ab4ca85abf4b21f5c76bccd71850b22e045928276a0f2e951db0707c"
+ "6a116dc19113fa762dc5f20bd5d2ab5be71744dc9cbdb51ea757963aac56a90a0d8023bed1f5cae8a64da047279b353a096a835b0b2b023b6aa048989233079a"
+ "eb467e522fa27a5822921e5c551b4f537536e46f3a6a97e72c3b063104e09a040598940d872f6d871f5ef9b4355073b54769e45454e6a0819599408621ab4413"
+ "b35507b0df578ce2d511d52058d5749df38b29d6cc58870caf92f69a75161406e71c5ff92451a77522b8b2967a2d58a49a81661aa65ac09b08c9fe45abc3851f"
+ "99c730c45003aca2bf0f8424a19b7408a537d541c16f5682bfe3a7faea564f1298611a7f5f60922ba19de73b1917f1853273555199a649318b50773345c99746"
+ "0856972acb43fc81ab6321b1c33c2bb5098bd489d696a0f70679c1213873d08bdad42844927216047205633212310ee9a06cb10016c805503c341a36d87e5607"
+ "2eabe23731e34af7e2328f85cdb370ccaf00515b64c9c54bc837578447aacfaed5969aa351e7da4efa7b115c4c51f4a699779850295ca72d781ad41bc680532b"
+ "89e710e2189eb3c50817ba255c7474c95ca9110cc43b8ba8e682c7fb7b0fdc265c0483a65ca4514ee4b832aac5800c3b08e74f563951c1fbb210353efa1aa866"
+ "856bc1e034733b0485dab1d020c6bf765ff60b3b801984a90c2fe970bf1de97004a6cf44b4984ab58258b4af71221cd17530a700c32959c9436344b5316f09cc"
+ "ca7029a230d639dcb022d8ba79ba91cd6ab12ae1579c50c7bb10e30301a65cae3101d40c7ba927bb553148d1647024d4a06c8166d0b0b81269b7d5f4b34fb022"
+ "f69152f514004a7c685368552343bb60360fbb9945edf446d345bdcaa7455c74ba0a551e184620fef97688773d50b6433ca7a7ac5cb6b7f671a15376e5a6747a"
+ "623fa7bc6630373f5b1b512690a661377870a60a7a189683f9b0cf0466e1f750762631c4ab09f505c42dd28633569472735442851e321616d4009810777b6bd4"
+ "6fa7224461a5cc27405dfbac0d39b002cab33433f2a86eb8ce91c134a6386f860a1994eb4b6875a46d195581d173854b53d2293df3e9a822756cd8f212b325ca"
+ "29b4f9f8cfbadf2e41869abfbad10738ad04cc752bc20c394746850e0c4847db";
+
+static int s_decode_hex(const char *hex, unsigned char *buf, unsigned long *len)
+{
+ return base16_decode(hex, XSTRLEN(hex), buf, len);
+}
+
+static int s_mlkem_keygen_encaps_decaps(int alg)
+{
+ mlkem_key key, pubkey, imported_priv, imported_pub;
+ unsigned char ct[1600], ss1[32], ss2[32];
+ unsigned char der_buf[4096], pk_buf[1600], sk_buf[3200], cmp_buf[3200];
+ unsigned long ctlen, derlen, sslen, pklen, sklen, cmplen;
+ int prng_idx;
+
+ prng_idx = find_prng("yarrow");
+ XMEMSET(&key, 0, sizeof(key));
+ XMEMSET(&pubkey, 0, sizeof(pubkey));
+ XMEMSET(&imported_priv, 0, sizeof(imported_priv));
+ XMEMSET(&imported_pub, 0, sizeof(imported_pub));
+
+ /* keygen */
+ DO(mlkem_make_key(&yarrow_prng, prng_idx, alg, &key));
+ ENSURE(key.type == PK_PRIVATE);
+
+ /* export/import private key in PKCS#8 format */
+ derlen = sizeof(der_buf);
+ DO(mlkem_export(der_buf, &derlen, PK_PRIVATE | PK_STD, &key));
+ DO(mlkem_import_pkcs8(der_buf, derlen, NULL, &imported_priv));
+
+ sklen = sizeof(sk_buf);
+ DO(mlkem_export_raw(sk_buf, &sklen, PK_PRIVATE, &key));
+ cmplen = sizeof(cmp_buf);
+ DO(mlkem_export_raw(cmp_buf, &cmplen, PK_PRIVATE, &imported_priv));
+ COMPARE_TESTVECTOR(cmp_buf, cmplen, sk_buf, sklen, "ML-KEM private std round-trip", alg);
+
+ /* export/import public key */
+ pklen = sizeof(pk_buf);
+ DO(mlkem_export_raw(pk_buf, &pklen, PK_PUBLIC, &key));
+ DO(mlkem_import_raw(pk_buf, pklen, PK_PUBLIC, alg, &pubkey));
+ ENSURE(pubkey.type == PK_PUBLIC);
+
+ cmplen = sizeof(cmp_buf);
+ DO(mlkem_export_raw(cmp_buf, &cmplen, PK_PUBLIC, &imported_priv));
+ COMPARE_TESTVECTOR(cmp_buf, cmplen, pk_buf, pklen, "ML-KEM public from imported private", alg);
+
+ /* export/import public key in SubjectPublicKeyInfo format */
+ derlen = sizeof(der_buf);
+ DO(mlkem_export(der_buf, &derlen, PK_PUBLIC | PK_STD, &key));
+ DO(mlkem_import(der_buf, derlen, &imported_pub));
+ cmplen = sizeof(cmp_buf);
+ DO(mlkem_export_raw(cmp_buf, &cmplen, PK_PUBLIC, &imported_pub));
+ COMPARE_TESTVECTOR(cmp_buf, cmplen, pk_buf, pklen, "ML-KEM public std round-trip", alg);
+
+ /* encaps/decaps with exported/imported std keys */
+ ctlen = sizeof(ct);
+ sslen = sizeof(ss1);
+ DO(mlkem_encaps(ct, &ctlen, ss1, &sslen, &yarrow_prng, prng_idx, &imported_pub));
+ ENSURE(sslen == 32);
+ sslen = sizeof(ss2);
+ DO(mlkem_decaps(ss2, &sslen, ct, ctlen, &imported_priv));
+ COMPARE_TESTVECTOR(ss1, 32, ss2, 32, "ML-KEM std export/import", alg);
+
+ /* encaps with public key */
+ ctlen = sizeof(ct);
+ sslen = sizeof(ss1);
+ DO(mlkem_encaps(ct, &ctlen, ss1, &sslen, &yarrow_prng, prng_idx, &pubkey));
+ ENSURE(sslen == 32);
+
+ /* decaps with private key */
+ sslen = sizeof(ss2);
+ DO(mlkem_decaps(ss2, &sslen, ct, ctlen, &key));
+ ENSURE(sslen == 32);
+
+ /* shared secrets must match */
+ COMPARE_TESTVECTOR(ss1, 32, ss2, 32, "ML-KEM shared secret", alg);
+
+ /* decaps with corrupted ciphertext must produce different ss (implicit rejection) */
+ ct[0] ^= 1;
+ sslen = sizeof(ss2);
+ DO(mlkem_decaps(ss2, &sslen, ct, ctlen, &key));
+ ENSURE(XMEMCMP(ss1, ss2, 32) != 0);
+
+ /* export/import private key round-trip */
+ sklen = sizeof(sk_buf);
+ DO(mlkem_export_raw(sk_buf, &sklen, PK_PRIVATE, &key));
+ mlkem_free(&key);
+ DO(mlkem_import_raw(sk_buf, sklen, PK_PRIVATE, alg, &key));
+ ENSURE(key.type == PK_PRIVATE);
+
+ /* decaps still works after import (undo corruption) */
+ ct[0] ^= 1;
+ sslen = sizeof(ss2);
+ DO(mlkem_decaps(ss2, &sslen, ct, ctlen, &key));
+ COMPARE_TESTVECTOR(ss1, 32, ss2, 32, "ML-KEM decaps after reimport", alg);
+
+ mlkem_free(&key);
+ mlkem_free(&pubkey);
+ mlkem_free(&imported_priv);
+ mlkem_free(&imported_pub);
+ return CRYPT_OK;
+}
+
+static int s_mlkem_sizes_test(void)
+{
+ unsigned long pk, sk, ct, ss;
+
+ DO(mlkem_get_sizes(LTC_MLKEM_512, &pk, &sk, &ct, &ss));
+ ENSURE(pk == 800 && sk == 1632 && ct == 768 && ss == 32);
+
+ DO(mlkem_get_sizes(LTC_MLKEM_768, &pk, &sk, &ct, &ss));
+ ENSURE(pk == 1184 && sk == 2400 && ct == 1088 && ss == 32);
+
+ DO(mlkem_get_sizes(LTC_MLKEM_1024, &pk, &sk, &ct, &ss));
+ ENSURE(pk == 1568 && sk == 3168 && ct == 1568 && ss == 32);
+
+ SHOULD_FAIL(mlkem_get_sizes(99, &pk, &sk, &ct, &ss));
+
+ /* nullable pointers */
+ DO(mlkem_get_sizes(LTC_MLKEM_768, NULL, NULL, NULL, &ss));
+ ENSURE(ss == 32);
+
+ return CRYPT_OK;
+}
+
+static int s_mlkem_from_seed_test(void)
+{
+ static const unsigned char seed[64] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
+ };
+ mlkem_key key1, key2;
+ unsigned char pk1[1600], pk2[1600], sk1[3200], sk2[3200];
+ unsigned long pk1len, pk2len, sk1len, sk2len;
+
+ XMEMSET(&key1, 0, sizeof(key1));
+ XMEMSET(&key2, 0, sizeof(key2));
+
+ DO(mlkem_make_key_from_seed(LTC_MLKEM_512, seed, sizeof(seed), &key1));
+ DO(mlkem_make_key_from_seed(LTC_MLKEM_512, seed, sizeof(seed), &key2));
+
+ pk1len = sizeof(pk1);
+ pk2len = sizeof(pk2);
+ sk1len = sizeof(sk1);
+ sk2len = sizeof(sk2);
+ DO(mlkem_export_raw(pk1, &pk1len, PK_PUBLIC, &key1));
+ DO(mlkem_export_raw(pk2, &pk2len, PK_PUBLIC, &key2));
+ DO(mlkem_export_raw(sk1, &sk1len, PK_PRIVATE, &key1));
+ DO(mlkem_export_raw(sk2, &sk2len, PK_PRIVATE, &key2));
+
+ COMPARE_TESTVECTOR(pk1, pk1len, pk2, pk2len, "ML-KEM deterministic public key", 0);
+ COMPARE_TESTVECTOR(sk1, sk1len, sk2, sk2len, "ML-KEM deterministic private key", 0);
+
+ SHOULD_FAIL(mlkem_make_key_from_seed(LTC_MLKEM_512, seed, sizeof(seed) - 1, &key2));
+
+ mlkem_free(&key1);
+ mlkem_free(&key2);
+ return CRYPT_OK;
+}
+
+static int s_mlkem_openssl_seed_test(void)
+{
+ static const struct {
+ int alg;
+ const char *pubkey_hex;
+ } vectors[] = {
+ { LTC_MLKEM_512, ml_kem_512_pubkey_hex },
+ { LTC_MLKEM_768, ml_kem_768_pubkey_hex },
+ { LTC_MLKEM_1024, ml_kem_1024_pubkey_hex }
+ };
+ unsigned char seed[64], pubkey[1600], expected[1600];
+ unsigned long seedlen, pklen, explen;
+ unsigned long n;
+
+ seedlen = sizeof(seed);
+ DO(s_decode_hex(ml_kem_seed_hex, seed, &seedlen));
+ ENSURE(seedlen == sizeof(seed));
+
+ for (n = 0; n < sizeof(vectors) / sizeof(vectors[0]); n++) {
+ mlkem_key key;
+ XMEMSET(&key, 0, sizeof(key));
+
+ DO(mlkem_make_key_from_seed(vectors[n].alg, seed, seedlen, &key));
+
+ pklen = sizeof(pubkey);
+ DO(mlkem_export_raw(pubkey, &pklen, PK_PUBLIC, &key));
+
+ explen = sizeof(expected);
+ DO(s_decode_hex(vectors[n].pubkey_hex, expected, &explen));
+ COMPARE_TESTVECTOR(pubkey, pklen, expected, explen, "ML-KEM OpenSSL seed public key", vectors[n].alg);
+
+ mlkem_free(&key);
+ }
+
+ return CRYPT_OK;
+}
+
+static int s_mlkem_error_test(void)
+{
+ mlkem_key key;
+ unsigned char ct[1600], ss[32];
+ unsigned long ctlen, sslen;
+ int prng_idx;
+
+ prng_idx = find_prng("yarrow");
+
+ /* invalid alg */
+ SHOULD_FAIL(mlkem_make_key(&yarrow_prng, prng_idx, 99, &key));
+
+ /* encaps with private key is OK (uses embedded pk) */
+ DO(mlkem_make_key(&yarrow_prng, prng_idx, LTC_MLKEM_512, &key));
+ ctlen = sizeof(ct);
+ sslen = sizeof(ss);
+ DO(mlkem_encaps(ct, &ctlen, ss, &sslen, &yarrow_prng, prng_idx, &key));
+
+ /* decaps with public-only key must fail */
+ {
+ mlkem_key pubkey;
+ unsigned char pk_buf[1600];
+ unsigned long pklen = sizeof(pk_buf);
+ DO(mlkem_export_raw(pk_buf, &pklen, PK_PUBLIC, &key));
+ DO(mlkem_import_raw(pk_buf, pklen, PK_PUBLIC, LTC_MLKEM_512, &pubkey));
+ sslen = sizeof(ss);
+ SHOULD_FAIL(mlkem_decaps(ss, &sslen, ct, ctlen, &pubkey));
+ mlkem_free(&pubkey);
+ }
+
+ /* wrong ciphertext length */
+ sslen = sizeof(ss);
+ SHOULD_FAIL(mlkem_decaps(ss, &sslen, ct, ctlen - 1, &key));
+
+ /* buffer too small */
+ ctlen = 1;
+ sslen = sizeof(ss);
+ SHOULD_FAIL_WITH(mlkem_encaps(ct, &ctlen, ss, &sslen, &yarrow_prng, prng_idx, &key),
+ CRYPT_BUFFER_OVERFLOW);
+
+ mlkem_free(&key);
+ return CRYPT_OK;
+}
+
+int pqc_mlkem_test(void)
+{
+ if (ltc_mp.name == NULL) return CRYPT_NOP;
+
+ DO(s_mlkem_sizes_test());
+ DO(s_mlkem_from_seed_test());
+ DO(s_mlkem_openssl_seed_test());
+ DO(s_mlkem_error_test());
+ DO(s_mlkem_keygen_encaps_decaps(LTC_MLKEM_512));
+ DO(s_mlkem_keygen_encaps_decaps(LTC_MLKEM_768));
+ DO(s_mlkem_keygen_encaps_decaps(LTC_MLKEM_1024));
+ return CRYPT_OK;
+}
+
+#else
+
+int pqc_mlkem_test(void)
+{
+ return CRYPT_NOP;
+}
+
+#endif
diff --git a/tests/pqc_slhdsa_test.c b/tests/pqc_slhdsa_test.c
new file mode 100644
index 000000000..7fbb502c2
--- /dev/null
+++ b/tests/pqc_slhdsa_test.c
@@ -0,0 +1,294 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_test.h"
+
+#ifdef LTC_SLHDSA
+
+/* OpenSSL 4.0.0 test vectors from test/slh_dsa.inc */
+static const char slh_dsa_sha2_128s_0_keygen_priv_hex[] =
+ "aa9cc7dca491fc86bcb15a709a15e9b3905c800b6e2fb9b54b6b050ee5e4de9afa5464d1c661fed38b2a51ca3eae71bacae3d1865215e3d3850e8c1b8292bf42";
+
+static const char slh_dsa_sha2_128f_0_keygen_priv_hex[] =
+ "e2bdaa37c8cffe5e8d5676c23267890c31441758f573285881cdc82ab911dd8472dc8d26df6ef708f4c41af9fd04b65a8927927229891d47a60d67ecef3d2c17";
+
+static const char slh_dsa_sha2_192s_0_keygen_priv_hex[] =
+ "442e446e73330afb98704656328f4dd7334f8a9ab4d92cbe790f91c2e92a81afee0a7ec45a3d609346276f5a328755a17dd41608f59e492668d81d03441394fe"
+ "7a8e7e58705d7632ba8bc66d04c99ee5c721e4ff4bbe7815ccf923e81e10c475";
+
+static const char slh_dsa_sha2_192f_0_keygen_priv_hex[] =
+ "942dd588b0e0636060b1023baf1df36002b9d3c7256904f948596f0f2f17505585f022423433b3a3ef50977b98b01e8e3e1d7dcf880c2ea3c8872122a996d5d6"
+ "233bdfbd57fa641fad3c81bbe6778b1f788195131b3fca91854ff3b075bf0009";
+
+static const char slh_dsa_sha2_256s_0_keygen_priv_hex[] =
+ "ae6ca8664ec0b9179d4e33c4defe01fcd589f60ba4502fe7416f2acd96e139f13fda2069147f44eabd5bbf29c74a20cb0f0cc2a12bab5834b773530af504900a"
+ "134d5ed3c60b46344a84a45d4683b1ac55fb22886ba9478ea9ca93f27b9aa2c27c5c9908f086e57956f85de84b438ef1f082cd176dff3c5b8be710bc8699a143";
+
+static const char slh_dsa_sha2_256f_0_keygen_priv_hex[] =
+ "37d1806dd090353064a982276aebd20e7318f36b17ec5209d4006651760ca043896630d51c45a8f7c1da31192f41204deb71bbc4fb47700a91ec47bb4acf3a38"
+ "dabbd00112520e60061da23f4c83a5c475a0ad3ab75f59e5c7b8ce2430deb480c07849dd9f8d993dce5685d0840134bd11592055f74cde3aa9e7d25b33c31067";
+
+static const char slh_dsa_shake_128s_0_keygen_priv_hex[] =
+ "ecd0a05696c2ec6bfe85b8b1b2022486bfd8732b1a42cea236e9822aa9e724e637d664792198176c12e8121ccf69e684fcf6ffe2a04243dc3e8ed3ee6e44cdef";
+
+static const char slh_dsa_shake_128f_0_keygen_priv_hex[] =
+ "bbc74306f75dc2daf7372b3c9841a4d6852c17b459f1692b8e9a1a0dace5ba26380c99304a0ddd32f344b95144e1fdef60bbc2340e08770fb41a80a76cb08e34";
+
+static const char slh_dsa_shake_192s_0_keygen_priv_hex[] =
+ "2d5748b1acda8299e2e905545d2e66dfcec02461bc3673dd9d830416b1b82a665dd435a3f3a8e2124df59a0e2bc2ec73633ff65c724ae17045c094617549081c"
+ "940f2ef4d4a10e7559c7503fe1e96fb67b0e32acdcf712fbef610f8d21daac86";
+
+static const char slh_dsa_shake_192f_0_keygen_priv_hex[] =
+ "3b7889d254f5ad87882dacbf3c58495667401601ec4739797e935cbc27f3d7cd627b611cbef7546c7f27751e18155cc4266b6fb56bd0d922e0482700a4280cc1"
+ "f07052804a8f46fded3954ba0a9da45d0d18867437777f60211bb9cd03a60d4b";
+
+static const char slh_dsa_shake_256s_0_keygen_priv_hex[] =
+ "a653918fa557b5250d11e96a74f5d8c62b5ff67152acf227aaf4bf5211aa600e961b4e679ceb9d4e24df86ed22f405d8ede5623672f4737fc2fb65f8bf3b556c"
+ "315a5e795b701676e6b8309c89cc6ad0c3d69ff4f7f432dc61329fbb1be6069f0887b1a8f1b3a8b9770a0871630e46dd0479c5bd123e8eeb6be70f2999c466a1";
+
+static const char slh_dsa_shake_256f_0_keygen_priv_hex[] =
+ "d50f77713cf59193fe5f10b8aaf1876b0d3e7e4181ed3fae346876269801758436c22b81940403157446d44f04c09fd28df72c6d4021b271544055783081b7c0"
+ "46d2ac50751a0c71ec850bb7d16a679a66901eee05389d4615940efd89c0182fdebcfbf3527cc768c5ec6cb5b6cc10a674390745d8612d0920187df658d3b7ef";
+
+static int s_decode_hex(const char *hex, unsigned char *buf, unsigned long *len)
+{
+ return base16_decode(hex, XSTRLEN(hex), buf, len);
+}
+
+static int s_slhdsa_sign_verify(int alg)
+{
+ slhdsa_key key, pubkey, imported_priv, imported_pub;
+ const unsigned char msg[] = "test message for SLH-DSA";
+ unsigned char *sig, *pk_buf, *sk_buf, *std_buf, *cmp_buf;
+ unsigned long siglen, sig_sz, pklen, pk_sz, sklen, sk_sz, stdlen, std_sz, cmplen;
+ int stat, prng_idx;
+
+ prng_idx = find_prng("yarrow");
+
+ DO(slhdsa_get_sizes(alg, &pk_sz, &sk_sz, &sig_sz));
+
+ sig = XMALLOC(sig_sz);
+ pk_buf = XMALLOC(pk_sz);
+ sk_buf = XMALLOC(sk_sz);
+ std_sz = sk_sz + 128uL;
+ std_buf = XMALLOC(std_sz);
+ cmp_buf = XMALLOC(sk_sz);
+ ENSURE(sig != NULL && pk_buf != NULL && sk_buf != NULL && std_buf != NULL && cmp_buf != NULL);
+ XMEMSET(&key, 0, sizeof(key));
+ XMEMSET(&pubkey, 0, sizeof(pubkey));
+ XMEMSET(&imported_priv, 0, sizeof(imported_priv));
+ XMEMSET(&imported_pub, 0, sizeof(imported_pub));
+
+ /* keygen */
+ DO(slhdsa_make_key(&yarrow_prng, prng_idx, alg, &key));
+ ENSURE(key.type == PK_PRIVATE);
+
+ /* export/import private key in PKCS#8 format */
+ stdlen = std_sz;
+ DO(slhdsa_export(std_buf, &stdlen, PK_PRIVATE | PK_STD, &key));
+ DO(slhdsa_import_pkcs8(std_buf, stdlen, NULL, &imported_priv));
+
+ /* sign */
+ siglen = sig_sz;
+ DO(slhdsa_sign(msg, sizeof(msg), sig, &siglen, NULL, 0,
+ &yarrow_prng, prng_idx, &key));
+ ENSURE(siglen == sig_sz);
+
+ sklen = sk_sz;
+ DO(slhdsa_export_raw(sk_buf, &sklen, PK_PRIVATE, &key));
+ cmplen = sk_sz;
+ DO(slhdsa_export_raw(cmp_buf, &cmplen, PK_PRIVATE, &imported_priv));
+ COMPARE_TESTVECTOR(cmp_buf, cmplen, sk_buf, sklen, "SLH-DSA private std round-trip", alg);
+
+ /* export/import public key */
+ pklen = pk_sz;
+ DO(slhdsa_export_raw(pk_buf, &pklen, PK_PUBLIC, &key));
+ DO(slhdsa_import_raw(pk_buf, pklen, PK_PUBLIC, alg, &pubkey));
+
+ cmplen = pk_sz;
+ DO(slhdsa_export_raw(cmp_buf, &cmplen, PK_PUBLIC, &imported_priv));
+ COMPARE_TESTVECTOR(cmp_buf, cmplen, pk_buf, pklen, "SLH-DSA public from imported private", alg);
+
+ /* export/import public key in SubjectPublicKeyInfo format */
+ stdlen = std_sz;
+ DO(slhdsa_export(std_buf, &stdlen, PK_PUBLIC | PK_STD, &key));
+ DO(slhdsa_import(std_buf, stdlen, &imported_pub));
+ cmplen = pk_sz;
+ DO(slhdsa_export_raw(cmp_buf, &cmplen, PK_PUBLIC, &imported_pub));
+ COMPARE_TESTVECTOR(cmp_buf, cmplen, pk_buf, pklen, "SLH-DSA public std round-trip", alg);
+
+ /* sign/verify with exported/imported std keys */
+ siglen = sig_sz;
+ DO(slhdsa_sign(msg, sizeof(msg), sig, &siglen, NULL, 0,
+ &yarrow_prng, prng_idx, &imported_priv));
+ stat = 0;
+ DO(slhdsa_verify(sig, siglen, msg, sizeof(msg), NULL, 0, &stat, &imported_pub));
+ ENSURE(stat == 1);
+
+ /* verify */
+ stat = 0;
+ DO(slhdsa_verify(sig, siglen, msg, sizeof(msg), NULL, 0, &stat, &pubkey));
+ ENSURE(stat == 1);
+
+ /* corrupted sig must fail */
+ sig[0] ^= 1;
+ stat = 1;
+ DO(slhdsa_verify(sig, siglen, msg, sizeof(msg), NULL, 0, &stat, &pubkey));
+ ENSURE(stat == 0);
+
+ /* export/import private key round-trip */
+ sklen = sk_sz;
+ DO(slhdsa_export_raw(sk_buf, &sklen, PK_PRIVATE, &key));
+ slhdsa_free(&key);
+ DO(slhdsa_import_raw(sk_buf, sklen, PK_PRIVATE, alg, &key));
+
+ /* sign again after reimport */
+ sig[0] ^= 1;
+ siglen = sig_sz;
+ DO(slhdsa_sign(msg, sizeof(msg), sig, &siglen, NULL, 0,
+ &yarrow_prng, prng_idx, &key));
+ stat = 0;
+ DO(slhdsa_verify(sig, siglen, msg, sizeof(msg), NULL, 0, &stat, &pubkey));
+ ENSURE(stat == 1);
+
+ slhdsa_free(&key);
+ slhdsa_free(&pubkey);
+ slhdsa_free(&imported_priv);
+ slhdsa_free(&imported_pub);
+ XFREE(sig);
+ XFREE(pk_buf);
+ XFREE(sk_buf);
+ XFREE(std_buf);
+ XFREE(cmp_buf);
+ return CRYPT_OK;
+}
+
+static int s_slhdsa_sizes_test(void)
+{
+ unsigned long pk, sk, sig;
+
+ /* SHA-2 variants */
+ DO(slhdsa_get_sizes(LTC_SLHDSA_SHA2_128S, &pk, &sk, &sig));
+ ENSURE(pk == 32 && sk == 64 && sig == 7856);
+ DO(slhdsa_get_sizes(LTC_SLHDSA_SHA2_128F, &pk, &sk, &sig));
+ ENSURE(pk == 32 && sk == 64 && sig == 17088);
+ DO(slhdsa_get_sizes(LTC_SLHDSA_SHA2_192S, &pk, &sk, &sig));
+ ENSURE(pk == 48 && sk == 96 && sig == 16224);
+ DO(slhdsa_get_sizes(LTC_SLHDSA_SHA2_192F, &pk, &sk, &sig));
+ ENSURE(pk == 48 && sk == 96 && sig == 35664);
+ DO(slhdsa_get_sizes(LTC_SLHDSA_SHA2_256S, &pk, &sk, &sig));
+ ENSURE(pk == 64 && sk == 128 && sig == 29792);
+ DO(slhdsa_get_sizes(LTC_SLHDSA_SHA2_256F, &pk, &sk, &sig));
+ ENSURE(pk == 64 && sk == 128 && sig == 49856);
+
+ /* SHAKE variants */
+ DO(slhdsa_get_sizes(LTC_SLHDSA_SHAKE_128S, &pk, &sk, &sig));
+ ENSURE(pk == 32 && sk == 64 && sig == 7856);
+ DO(slhdsa_get_sizes(LTC_SLHDSA_SHAKE_128F, &pk, &sk, &sig));
+ ENSURE(pk == 32 && sk == 64 && sig == 17088);
+ DO(slhdsa_get_sizes(LTC_SLHDSA_SHAKE_192S, &pk, &sk, &sig));
+ ENSURE(pk == 48 && sk == 96 && sig == 16224);
+ DO(slhdsa_get_sizes(LTC_SLHDSA_SHAKE_192F, &pk, &sk, &sig));
+ ENSURE(pk == 48 && sk == 96 && sig == 35664);
+ DO(slhdsa_get_sizes(LTC_SLHDSA_SHAKE_256S, &pk, &sk, &sig));
+ ENSURE(pk == 64 && sk == 128 && sig == 29792);
+ DO(slhdsa_get_sizes(LTC_SLHDSA_SHAKE_256F, &pk, &sk, &sig));
+ ENSURE(pk == 64 && sk == 128 && sig == 49856);
+
+ SHOULD_FAIL(slhdsa_get_sizes(99, &pk, &sk, &sig));
+
+ return CRYPT_OK;
+}
+
+static int s_slhdsa_openssl_keygen_test(void)
+{
+ static const struct {
+ int alg;
+ const char *priv_hex;
+ } vectors[] = {
+ { LTC_SLHDSA_SHA2_128S, slh_dsa_sha2_128s_0_keygen_priv_hex },
+ { LTC_SLHDSA_SHA2_128F, slh_dsa_sha2_128f_0_keygen_priv_hex },
+ { LTC_SLHDSA_SHA2_192S, slh_dsa_sha2_192s_0_keygen_priv_hex },
+ { LTC_SLHDSA_SHA2_192F, slh_dsa_sha2_192f_0_keygen_priv_hex },
+ { LTC_SLHDSA_SHA2_256S, slh_dsa_sha2_256s_0_keygen_priv_hex },
+ { LTC_SLHDSA_SHA2_256F, slh_dsa_sha2_256f_0_keygen_priv_hex },
+ { LTC_SLHDSA_SHAKE_128S, slh_dsa_shake_128s_0_keygen_priv_hex },
+ { LTC_SLHDSA_SHAKE_128F, slh_dsa_shake_128f_0_keygen_priv_hex },
+ { LTC_SLHDSA_SHAKE_192S, slh_dsa_shake_192s_0_keygen_priv_hex },
+ { LTC_SLHDSA_SHAKE_192F, slh_dsa_shake_192f_0_keygen_priv_hex },
+ { LTC_SLHDSA_SHAKE_256S, slh_dsa_shake_256s_0_keygen_priv_hex },
+ { LTC_SLHDSA_SHAKE_256F, slh_dsa_shake_256f_0_keygen_priv_hex }
+ };
+ unsigned char sk[128], pk[64], expected[128];
+ unsigned long sklen, pklen, explen;
+ unsigned long n;
+
+ for (n = 0; n < sizeof(vectors) / sizeof(vectors[0]); n++) {
+ slhdsa_key key;
+ XMEMSET(&key, 0, sizeof(key));
+
+ explen = sizeof(expected);
+ DO(s_decode_hex(vectors[n].priv_hex, expected, &explen));
+
+ DO(slhdsa_import_raw(expected, explen, PK_PRIVATE, vectors[n].alg, &key));
+
+ sklen = sizeof(sk);
+ DO(slhdsa_export_raw(sk, &sklen, PK_PRIVATE, &key));
+ COMPARE_TESTVECTOR(sk, sklen, expected, explen, "SLH-DSA OpenSSL private key", vectors[n].alg);
+
+ pklen = sizeof(pk);
+ DO(slhdsa_export_raw(pk, &pklen, PK_PUBLIC, &key));
+ COMPARE_TESTVECTOR(pk, pklen, expected + explen / 2, explen / 2, "SLH-DSA OpenSSL public key", vectors[n].alg);
+
+ slhdsa_free(&key);
+ }
+
+ return CRYPT_OK;
+}
+
+int pqc_slhdsa_test(void)
+{
+ if (ltc_mp.name == NULL) return CRYPT_NOP;
+
+ DO(s_slhdsa_sizes_test());
+ DO(s_slhdsa_openssl_keygen_test());
+ /* All 6 fast variants (covers both SHA-2 and SHAKE at all security levels) */
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_SHA2_128F));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_SHA2_192F));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_SHA2_256F));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_SHAKE_128F));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_SHAKE_192F));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_SHAKE_256F));
+ /* One small variant to verify S-parameter code paths */
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_SHAKE_128S));
+ /* HashSLH-DSA fast variants cover SHA-256, SHA-512, SHAKE128, and SHAKE256 pre-hash paths */
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_HASH_SHA2_128F_WITH_SHA256));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_HASH_SHA2_192F_WITH_SHA512));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_HASH_SHA2_256F_WITH_SHA512));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_HASH_SHAKE_128F_WITH_SHAKE128));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_HASH_SHAKE_192F_WITH_SHAKE256));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_HASH_SHAKE_256F_WITH_SHAKE256));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_HASH_SHAKE_128S_WITH_SHAKE128));
+#ifdef LTC_SLHDSA_TEST_SLOW
+ /* Remaining small variants (very slow) */
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_SHA2_128S));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_SHA2_192S));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_SHA2_256S));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_SHAKE_192S));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_SHAKE_256S));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_HASH_SHA2_128S_WITH_SHA256));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_HASH_SHA2_192S_WITH_SHA512));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_HASH_SHA2_256S_WITH_SHA512));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_HASH_SHAKE_192S_WITH_SHAKE256));
+ DO(s_slhdsa_sign_verify(LTC_SLHDSA_HASH_SHAKE_256S_WITH_SHAKE256));
+#endif
+ return CRYPT_OK;
+}
+
+#else
+
+int pqc_slhdsa_test(void)
+{
+ return CRYPT_NOP;
+}
+
+#endif
diff --git a/tests/sources.cmake b/tests/sources.cmake
index ae348a644..f53d378d6 100644
--- a/tests/sources.cmake
+++ b/tests/sources.cmake
@@ -28,6 +28,9 @@ pkcs_1_emsa_test.c
pkcs_1_oaep_test.c
pkcs_1_pss_test.c
pkcs_1_test.c
+pqc_mldsa_test.c
+pqc_mlkem_test.c
+pqc_slhdsa_test.c
prng_test.c
rotate_test.c
rsa_test.c
diff --git a/tests/test.c b/tests/test.c
index a26604ec4..8902c093c 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -37,6 +37,9 @@ static const test_function test_functions[] =
LTC_TEST_FN(file_test),
LTC_TEST_FN(multi_test),
LTC_TEST_FN(pem_test),
+ LTC_TEST_FN(pqc_mlkem_test),
+ LTC_TEST_FN(pqc_mldsa_test),
+ LTC_TEST_FN(pqc_slhdsa_test),
LTC_TEST_FN(deprecated_test),
/* keep the prng_test always at the end as
* it has to be handled specially when
diff --git a/tests/tomcrypt_test.h b/tests/tomcrypt_test.h
index 747ede567..06b1655a4 100644
--- a/tests/tomcrypt_test.h
+++ b/tests/tomcrypt_test.h
@@ -48,6 +48,9 @@ int scrypt_test(void);
int no_null_termination_check_test(void);
int pk_oid_test(void);
int deprecated_test(void);
+int pqc_mlkem_test(void);
+int pqc_mldsa_test(void);
+int pqc_slhdsa_test(void);
#ifdef LTC_PKCS_1
struct ltc_prng_descriptor* no_prng_desc_get(void);