diff --git a/.gitignore b/.gitignore
index b382cf7..f50ab48 100644
--- a/.gitignore
+++ b/.gitignore
@@ -74,3 +74,5 @@ TestUser51.cert
/nspr-4.36.tar.gz
/nss-3.112.tar.gz
/nss_compat_test_pkcs12.tar
+/nspr-4.39.tar.gz
+/nss-3.124.tar.gz
diff --git a/fips_algorithms.h b/fips_algorithms.h
index c94c9a2..b920af0 100644
--- a/fips_algorithms.h
+++ b/fips_algorithms.h
@@ -7,43 +7,9 @@
* algorithms which have NIST algorithm Certificates.
*/
-/* handle special cases. Classes require existing code to already be
- * in place for that class */
-typedef enum {
- SFTKFIPSNone = 0,
- SFTKFIPSDH, /* allow only specific primes */
- SFTKFIPSECC, /* not just keys but specific curves */
- SFTKFIPSAEAD, /* single shot AEAD functions not allowed in FIPS mode */
- SFTKFIPSRSAPSS, /* make sure salt isn't too big */
- SFTKFIPSPBKDF2, /* handle pbkdf2 FIPS restrictions */
- SFTKFIPSTlsKeyCheck, /* check the output of TLS prf functions */
- SFTKFIPSChkHash, /* make sure the base hash of KDF functions is FIPS */
- SFTKFIPSChkHashTls, /* make sure the base hash of TLS KDF functions is FIPS */
- SFTKFIPSChkHashSp800, /* make sure the base hash of SP-800-108 KDF functions is FIPS */
- SFTKFIPSRSAOAEP, /* make sure that both hashes use the same FIPS compliant algorithm */
-#ifndef NSS_DISABLE_KYBER
- SFKFIPSMLKEM, /* make sure the keys are only mlkem and not kyber */
-#endif
-} SFTKFIPSSpecialClass;
-
-#ifdef NSS_DISABLE_KYBER
-/* if kyber is disable, we don't need to check that we are using
- * a kyber key in the ML_KEM code */
-#define SFTKFIPSMLKEM SFTKFIPSNone
-#endif
-
/* set according to your security policy */
#define SFTKFIPS_PBKDF2_MIN_PW_LEN 8
-typedef struct SFTKFIPSAlgorithmListStr SFTKFIPSAlgorithmList;
-struct SFTKFIPSAlgorithmListStr {
- CK_MECHANISM_TYPE type;
- CK_MECHANISM_INFO info;
- CK_ULONG step;
- SFTKFIPSSpecialClass special;
- size_t offset;
-};
-
SFTKFIPSAlgorithmList sftk_fips_mechs[] = {
/* A sample set of algorithms to allow basic testing in our continous
* testing infrastructure. The vendor version should replace this with
@@ -120,9 +86,9 @@ SFTKFIPSAlgorithmList sftk_fips_mechs[] = {
{ CKM_ML_DSA_KEY_PAIR_GEN, { CK_ALL_KEY, CKF_KPG }, CK_ALL_STEP, SFTKFIPSNone },
{ CKM_ML_DSA, { CK_ALL_KEY, CKF_SGN }, CK_ALL_STEP, SFTKFIPSNone },
/* only allowed keys are implented for ML_KEM */
- { CKM_ML_KEM_KEY_PAIR_GEN, { CK_ALL_KEY, CKF_KPG }, CK_ALL_STEP, SFTKFIPSMLKEM },
+ { CKM_ML_KEM_KEY_PAIR_GEN, { CK_ALL_KEY, CKF_KPG }, CK_ALL_STEP, SFTKFIPSNone },
- { CKM_ML_KEM, { CK_ALL_KEY, CKF_KEM }, CK_ALL_STEP, SFTKFIPSMLKEM },
+ { CKM_ML_KEM, { CK_ALL_KEY, CKF_KEM }, CK_ALL_STEP, SFTKFIPSNone },
/* ------------------------- RC2 Operations --------------------------- */
/* ------------------------- AES Operations --------------------------- */
{ CKM_AES_KEY_GEN, { AES_FB_KEY, CKF_GEN }, AES_FB_STEP, SFTKFIPSNone },
@@ -187,7 +153,7 @@ SFTKFIPSAlgorithmList sftk_fips_mechs[] = {
* to set the FIPS indicators on these (sigh) */
/* NOTE: CKM_NSS_ML_KEM_KEY_GEN and the KYBER equivalent does not do
* pairwise consistency checks on key gen, so are not FIPS */
- { CKM_NSS_ML_KEM, { CK_ALL_KEY, CKF_KEM }, CK_ALL_STEP, SFTKFIPSMLKEM },
+ { CKM_NSS_ML_KEM, { CK_ALL_KEY, CKF_KEM }, CK_ALL_STEP, SFTKFIPSNone },
{ CKM_NSS_AES_KEY_WRAP, { AES_FB_KEY, CKF_ECW }, AES_FB_STEP, SFTKFIPSNone },
{ CKM_NSS_AES_KEY_WRAP_PAD, { AES_FB_KEY, CKF_ECW }, AES_FB_STEP, SFTKFIPSNone },
{ CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256, { 384, 384, CKF_DERIVE }, 1, SFTKFIPSTlsKeyCheck },
diff --git a/nss-3.101-el9-restore-old-pkcs12-default.patch b/nss-3.101-el9-restore-old-pkcs12-default.patch
deleted file mode 100644
index eb206a1..0000000
--- a/nss-3.101-el9-restore-old-pkcs12-default.patch
+++ /dev/null
@@ -1,14 +0,0 @@
-diff -up ./cmd/pk12util/pk12util.c.no_pkcs12_macpbe_default ./cmd/pk12util/pk12util.c
---- ./cmd/pk12util/pk12util.c.no_pkcs12_macpbe_default 2024-07-18 08:26:35.773248450 -0700
-+++ ./cmd/pk12util/pk12util.c 2024-07-18 08:27:05.796595554 -0700
-@@ -1165,10 +1165,6 @@ main(int argc, char **argv)
- }
- }
- }
-- /* in FIPS mode default to encoding with pkcs5v2 for the MAC */
-- if (PK11_IsFIPS()) {
-- hash = SEC_OID_HMAC_SHA256;
-- }
- if (pk12util.options[opt_Mac].activated) {
- char *hashString = pk12util.options[opt_Mac].arg;
-
diff --git a/nss-3.101-fips-review.patches b/nss-3.101-fips-review.patches
deleted file mode 100644
index 755b087..0000000
--- a/nss-3.101-fips-review.patches
+++ /dev/null
@@ -1,490 +0,0 @@
-diff -up ./lib/freebl/dh.c.fips-review ./lib/freebl/dh.c
---- ./lib/freebl/dh.c.fips-review 2024-06-07 09:26:03.000000000 -0700
-+++ ./lib/freebl/dh.c 2024-06-12 12:04:10.639360404 -0700
-@@ -445,7 +445,7 @@ cleanup:
- PRBool
- KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime)
- {
-- mp_int p, q, y, r;
-+ mp_int p, q, y, r, psub1;
- mp_err err;
- int cmp = 1; /* default is false */
- if (!Y || !prime || !subPrime) {
-@@ -456,13 +456,30 @@ KEA_Verify(SECItem *Y, SECItem *prime, S
- MP_DIGITS(&q) = 0;
- MP_DIGITS(&y) = 0;
- MP_DIGITS(&r) = 0;
-+ MP_DIGITS(&psub1) = 0;
- CHECK_MPI_OK(mp_init(&p));
- CHECK_MPI_OK(mp_init(&q));
- CHECK_MPI_OK(mp_init(&y));
- CHECK_MPI_OK(mp_init(&r));
-+ CHECK_MPI_OK(mp_init(&psub1));
- SECITEM_TO_MPINT(*prime, &p);
- SECITEM_TO_MPINT(*subPrime, &q);
- SECITEM_TO_MPINT(*Y, &y);
-+ CHECK_MPI_OK(mp_sub_d(&p, 1, &psub1));
-+ /*
-+ * We check that the public value isn't zero (which isn't in the
-+ * group), one (subgroup of order one) or p-1 (subgroup of order 2). We
-+ * also check that the public value is less than p, to avoid being fooled
-+ * by values like p+1 or 2*p-1.
-+ * This check is required by SP-800-56Ar3. It's also done in derive,
-+ * but this is only called in various FIPS cases, so put it here to help
-+ * reviewers find it.
-+ */
-+ if (mp_cmp_d(&y, 1) <= 0 ||
-+ mp_cmp(&y, &psub1) >= 0) {
-+ err = MP_BADARG;
-+ goto cleanup;
-+ }
- /* compute r = y**q mod p */
- CHECK_MPI_OK(mp_exptmod(&y, &q, &p, &r));
- /* compare to 1 */
-@@ -472,6 +489,7 @@ cleanup:
- mp_clear(&q);
- mp_clear(&y);
- mp_clear(&r);
-+ mp_clear(&psub1);
- if (err) {
- MP_TO_SEC_ERROR(err);
- return PR_FALSE;
-diff -up ./lib/softoken/pkcs11c.c.fips-review ./lib/softoken/pkcs11c.c
---- ./lib/softoken/pkcs11c.c.fips-review 2024-06-12 12:04:10.638360392 -0700
-+++ ./lib/softoken/pkcs11c.c 2024-06-12 13:06:35.410551333 -0700
-@@ -43,6 +43,7 @@
-
- #include "prprf.h"
- #include "prenv.h"
-+#include "prerror.h"
-
- #define __PASTE(x, y) x##y
- #define BAD_PARAM_CAST(pMech, typeSize) (!pMech->pParameter || pMech->ulParameterLen < typeSize)
-@@ -4882,6 +4883,10 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSessi
- * handle the base object stuff
- */
- crv = sftk_handleObject(key, session);
-+ /* we need to do this check at the end, so we can check the generated
-+ * key length against fips requirements */
-+ key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_NSS_GENERATE, key);
-+ session->lastOpWasFIPS = key->isFIPS;
- sftk_FreeSession(session);
- if (crv == CKR_OK && sftk_isTrue(key, CKA_SENSITIVE)) {
- crv = sftk_forceAttribute(key, CKA_ALWAYS_SENSITIVE, &cktrue, sizeof(CK_BBOOL));
-@@ -4889,9 +4894,6 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSessi
- if (crv == CKR_OK && !sftk_isTrue(key, CKA_EXTRACTABLE)) {
- crv = sftk_forceAttribute(key, CKA_NEVER_EXTRACTABLE, &cktrue, sizeof(CK_BBOOL));
- }
-- /* we need to do this check at the end, so we can check the generated key length against
-- * fips requirements */
-- key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_NSS_GENERATE, key);
- if (crv == CKR_OK) {
- *phKey = key->handle;
- }
-@@ -5199,60 +5201,68 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
-
- if (isDerivable) {
- SFTKAttribute *pubAttribute = NULL;
-- CK_OBJECT_HANDLE newKey;
- PRBool isFIPS = sftk_isFIPS(slot->slotID);
-- CK_RV crv2;
-- CK_OBJECT_CLASS secret = CKO_SECRET_KEY;
-- CK_KEY_TYPE generic = CKK_GENERIC_SECRET;
-- CK_ULONG keyLen = 128;
-- CK_BBOOL ckTrue = CK_TRUE;
-- CK_ATTRIBUTE template[] = {
-- { CKA_CLASS, &secret, sizeof(secret) },
-- { CKA_KEY_TYPE, &generic, sizeof(generic) },
-- { CKA_VALUE_LEN, &keyLen, sizeof(keyLen) },
-- { CKA_DERIVE, &ckTrue, sizeof(ckTrue) }
-- };
-- CK_ULONG templateCount = PR_ARRAY_SIZE(template);
-- CK_ECDH1_DERIVE_PARAMS ecParams;
-+ NSSLOWKEYPrivateKey *lowPrivKey = NULL;
-+ ECPrivateKey *ecPriv;
-+ SECItem *lowPubValue = NULL;
-+ SECItem item;
-+ SECStatus rv;
-
- crv = CKR_OK; /*paranoia, already get's set before we drop to the end */
-- /* FIPS 140-2 requires we verify that the resulting key is a valid key.
-- * The easiest way to do this is to do a derive operation, which checks
-- * the validity of the key */
--
-+ /* FIPS 140-3 requires we verify that the resulting key is a valid key
-+ * by recalculating the public can an compare it to our own public
-+ * key. */
-+ lowPrivKey = sftk_GetPrivKey(privateKey, keyType, &crv);
-+ if (lowPrivKey == NULL) {
-+ return sftk_MapCryptError(PORT_GetError());
-+ }
-+ /* recalculate the public key from the private key */
- switch (keyType) {
-- case CKK_DH:
-- mech.mechanism = CKM_DH_PKCS_DERIVE;
-- pubAttribute = sftk_FindAttribute(publicKey, CKA_VALUE);
-- if (pubAttribute == NULL) {
-- return CKR_DEVICE_ERROR;
-- }
-- mech.pParameter = pubAttribute->attrib.pValue;
-- mech.ulParameterLen = pubAttribute->attrib.ulValueLen;
-- break;
-- case CKK_EC:
-- mech.mechanism = CKM_ECDH1_DERIVE;
-- pubAttribute = sftk_FindAttribute(publicKey, CKA_EC_POINT);
-- if (pubAttribute == NULL) {
-- return CKR_DEVICE_ERROR;
-- }
-- ecParams.kdf = CKD_NULL;
-- ecParams.ulSharedDataLen = 0;
-- ecParams.pSharedData = NULL;
-- ecParams.ulPublicDataLen = pubAttribute->attrib.ulValueLen;
-- ecParams.pPublicData = pubAttribute->attrib.pValue;
-- mech.pParameter = &ecParams;
-- mech.ulParameterLen = sizeof(ecParams);
-- break;
-- default:
-- return CKR_DEVICE_ERROR;
-+ case CKK_DH:
-+ rv = DH_Derive(&lowPrivKey->u.dh.base, &lowPrivKey->u.dh.prime,
-+ &lowPrivKey->u.dh.privateValue, &item, 0);
-+ if (rv != SECSuccess) {
-+ return CKR_GENERAL_ERROR;
-+ }
-+ lowPubValue = SECITEM_DupItem(&item);
-+ SECITEM_ZfreeItem(&item, PR_FALSE);
-+ pubAttribute = sftk_FindAttribute(publicKey, CKA_VALUE);
-+ break;
-+ case CKK_EC:
-+ rv = EC_NewKeyFromSeed(&lowPrivKey->u.ec.ecParams, &ecPriv,
-+ lowPrivKey->u.ec.privateValue.data,
-+ lowPrivKey->u.ec.privateValue.len);
-+ if (rv != SECSuccess) {
-+ return CKR_GENERAL_ERROR;
-+ }
-+ /* make sure it has the same encoding */
-+ if (PR_GetEnvSecure("NSS_USE_DECODED_CKA_EC_POINT") ||
-+ lowPrivKey->u.ec.ecParams.type != ec_params_named) {
-+ lowPubValue = SECITEM_DupItem(&ecPriv->publicValue);
-+ } else {
-+ lowPubValue = SEC_ASN1EncodeItem(NULL, NULL, &ecPriv->publicValue,
-+ SEC_ASN1_GET(SEC_OctetStringTemplate));;
-+ }
-+ pubAttribute = sftk_FindAttribute(publicKey, CKA_EC_POINT);
-+ /* clear out our generated private key */
-+ PORT_FreeArena(ecPriv->ecParams.arena, PR_TRUE);
-+ break;
-+ default:
-+ return CKR_DEVICE_ERROR;
- }
-
-- crv = NSC_DeriveKey(hSession, &mech, privateKey->handle, template, templateCount, &newKey);
-- if (crv != CKR_OK) {
-- sftk_FreeAttribute(pubAttribute);
-- return crv;
-+ /* now compare new public key with our already generated key */
-+ if ((pubAttribute == NULL) || (lowPubValue == NULL) ||
-+ (pubAttribute->attrib.ulValueLen != lowPubValue->len) ||
-+ (PORT_Memcmp(pubAttribute->attrib.pValue, lowPubValue->data,
-+ lowPubValue->len) != 0)) {
-+ if (pubAttribute) sftk_FreeAttribute(pubAttribute);
-+ if (lowPubValue) SECITEM_ZfreeItem(lowPubValue, PR_TRUE);
-+ PORT_SetError(SEC_ERROR_BAD_KEY);
-+ return CKR_GENERAL_ERROR;
- }
-+ SECITEM_ZfreeItem(lowPubValue, PR_TRUE);
-+
- /* FIPS requires full validation, but in fipx mode NSC_Derive
- * only does partial validation with approved primes, now handle
- * full validation */
-@@ -5260,44 +5270,78 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
- SECItem pubKey;
- SECItem prime;
- SECItem subPrime;
-+ SECItem base;
-+ SECItem generator;
- const SECItem *subPrimePtr = &subPrime;
-
- pubKey.data = pubAttribute->attrib.pValue;
- pubKey.len = pubAttribute->attrib.ulValueLen;
-- prime.data = subPrime.data = NULL;
-- prime.len = subPrime.len = 0;
-+ base.data = prime.data = subPrime.data = NULL;
-+ base.len = prime.len = subPrime.len = 0;
- crv = sftk_Attribute2SecItem(NULL, &prime, privateKey, CKA_PRIME);
- if (crv != CKR_OK) {
- goto done;
- }
-- crv = sftk_Attribute2SecItem(NULL, &prime, privateKey, CKA_PRIME);
-+ crv = sftk_Attribute2SecItem(NULL, &base, privateKey, CKA_BASE);
-+ if (crv != CKR_OK) {
-+ goto done;
-+ }
- /* we ignore the return code an only look at the length */
-- if (subPrime.len == 0) {
-- /* subprime not supplied, In this case look it up.
-- * This only works with approved primes, but in FIPS mode
-- * that's the only kine of prime that will get here */
-- subPrimePtr = sftk_VerifyDH_Prime(&prime, isFIPS);
-- if (subPrimePtr == NULL) {
-- crv = CKR_GENERAL_ERROR;
-+ /* do we have a known prime ? */
-+ subPrimePtr = sftk_VerifyDH_Prime(&prime, &generator, isFIPS);
-+ if (subPrimePtr == NULL) {
-+ if (subPrime.len == 0) {
-+ /* if not a known prime, subprime must be supplied */
-+ crv = CKR_ATTRIBUTE_VALUE_INVALID;
-+ goto done;
-+ } else {
-+ /* not a known prime, check for primality of prime
-+ * and subPrime */
-+ if (!KEA_PrimeCheck(&prime)) {
-+ crv = CKR_ATTRIBUTE_VALUE_INVALID;
-+ goto done;
-+ }
-+ if (!KEA_PrimeCheck(&subPrime)) {
-+ crv = CKR_ATTRIBUTE_VALUE_INVALID;
-+ goto done;
-+ }
-+ /* if we aren't using a defined group, make sure base is in the
-+ * subgroup. If it's not, then our key could fail or succeed sometimes.
-+ * This makes the failure reliable */
-+ if (!KEA_Verify(&base, &prime, (SECItem *)subPrimePtr)) {
-+ crv = CKR_ATTRIBUTE_VALUE_INVALID;
-+ }
-+ }
-+ subPrimePtr = &subPrime;
-+ } else {
-+ /* we're using a known group, make sure we are using the known generator for that group */
-+ if (SECITEM_CompareItem(&generator, &base) != 0) {
-+ crv = CKR_ATTRIBUTE_VALUE_INVALID;
- goto done;
- }
-+ if (subPrime.len != 0) {
-+ /* we have a known prime and a supplied subPrime,
-+ * make sure the subPrime matches the subPrime for
-+ * the known Prime */
-+ if (SECITEM_CompareItem(subPrimePtr, &subPrime) != 0) {
-+ crv = CKR_ATTRIBUTE_VALUE_INVALID;
-+ goto done;
-+ }
-+ }
- }
- if (!KEA_Verify(&pubKey, &prime, (SECItem *)subPrimePtr)) {
-- crv = CKR_GENERAL_ERROR;
-+ crv = CKR_ATTRIBUTE_VALUE_INVALID;
- }
- done:
-+ SECITEM_ZfreeItem(&base, PR_FALSE);
- SECITEM_ZfreeItem(&subPrime, PR_FALSE);
- SECITEM_ZfreeItem(&prime, PR_FALSE);
- }
- /* clean up before we return */
- sftk_FreeAttribute(pubAttribute);
-- crv2 = NSC_DestroyObject(hSession, newKey);
- if (crv != CKR_OK) {
- return crv;
- }
-- if (crv2 != CKR_OK) {
-- return crv2;
-- }
- }
-
- return CKR_OK;
-@@ -5925,8 +5969,8 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
- * created and linked.
- */
- crv = sftk_handleObject(publicKey, session);
-- sftk_FreeSession(session);
- if (crv != CKR_OK) {
-+ sftk_FreeSession(session);
- sftk_FreeObject(publicKey);
- NSC_DestroyObject(hSession, privateKey->handle);
- sftk_FreeObject(privateKey);
-@@ -5968,6 +6012,7 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
- }
-
- if (crv != CKR_OK) {
-+ sftk_FreeSession(session);
- NSC_DestroyObject(hSession, publicKey->handle);
- sftk_FreeObject(publicKey);
- NSC_DestroyObject(hSession, privateKey->handle);
-@@ -5977,6 +6022,8 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
- /* we need to do this check at the end to make sure the generated key meets the key length requirements */
- privateKey->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_NSS_GENERATE_KEY_PAIR, privateKey);
- publicKey->isFIPS = privateKey->isFIPS;
-+ session->lastOpWasFIPS = privateKey->isFIPS;
-+ sftk_FreeSession(session);
-
- *phPrivateKey = privateKey->handle;
- *phPublicKey = publicKey->handle;
-@@ -8610,7 +8657,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
-
- /* if the prime is an approved prime, we can skip all the other
- * checks. */
-- subPrime = sftk_VerifyDH_Prime(&dhPrime, isFIPS);
-+ subPrime = sftk_VerifyDH_Prime(&dhPrime, NULL, isFIPS);
- if (subPrime == NULL) {
- SECItem dhSubPrime;
- /* If the caller set the subprime value, it means that
-@@ -8792,6 +8839,7 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
- secretlen = tmp.len;
- } else {
- secretlen = keySize;
-+ key->isFIPS = PR_FALSE;
- crv = sftk_ANSI_X9_63_kdf(&secret, keySize,
- &tmp, mechParams->pSharedData,
- mechParams->ulSharedDataLen, mechParams->kdf);
-diff -up ./lib/softoken/pkcs11i.h.fips-review ./lib/softoken/pkcs11i.h
---- ./lib/softoken/pkcs11i.h.fips-review 2024-06-12 12:04:10.638360392 -0700
-+++ ./lib/softoken/pkcs11i.h 2024-06-12 12:04:10.640360416 -0700
-@@ -971,7 +971,7 @@ char **NSC_ModuleDBFunc(unsigned long fu
- /* dh verify functions */
- /* verify that dhPrime matches one of our known primes, and if so return
- * it's subprime value */
--const SECItem *sftk_VerifyDH_Prime(SECItem *dhPrime, PRBool isFIPS);
-+const SECItem *sftk_VerifyDH_Prime(SECItem *dhPrime, SECItem *generator, PRBool isFIPS);
- /* check if dhSubPrime claims dhPrime is a safe prime. */
- SECStatus sftk_IsSafePrime(SECItem *dhPrime, SECItem *dhSubPrime, PRBool *isSafe);
- /* map an operation Attribute to a Mechanism flag */
-diff -up ./lib/softoken/pkcs11u.c.fips-review ./lib/softoken/pkcs11u.c
---- ./lib/softoken/pkcs11u.c.fips-review 2024-06-12 12:04:10.638360392 -0700
-+++ ./lib/softoken/pkcs11u.c 2024-06-12 12:04:10.640360416 -0700
-@@ -2409,15 +2409,27 @@ sftk_handleSpecial(SFTKSlot *slot, CK_ME
- switch (mechInfo->special) {
- case SFTKFIPSDH: {
- SECItem dhPrime;
-+ SECItem dhBase;
-+ SECItem dhGenerator;
-+ PRBool val = PR_FALSE;
- const SECItem *dhSubPrime;
- CK_RV crv = sftk_Attribute2SecItem(NULL, &dhPrime,
- source, CKA_PRIME);
- if (crv != CKR_OK) {
- return PR_FALSE;
- }
-- dhSubPrime = sftk_VerifyDH_Prime(&dhPrime, PR_TRUE);
-+ crv = sftk_Attribute2SecItem(NULL, &dhBase, source, CKA_BASE);
-+ if (crv != CKR_OK) {
-+ return PR_FALSE;
-+ }
-+ dhSubPrime = sftk_VerifyDH_Prime(&dhPrime, &dhGenerator, PR_TRUE);
-+ val = (dhSubPrime) ? PR_TRUE : PR_FALSE;
-+ if (val && (SECITEM_CompareItem(&dhBase, &dhGenerator) != 0)) {
-+ val = PR_FALSE;
-+ }
- SECITEM_ZfreeItem(&dhPrime, PR_FALSE);
-- return (dhSubPrime) ? PR_TRUE : PR_FALSE;
-+ SECITEM_ZfreeItem(&dhBase, PR_FALSE);
-+ return val;
- }
- case SFTKFIPSNone:
- return PR_FALSE;
-diff -up ./lib/softoken/sftkdhverify.c.fips-review ./lib/softoken/sftkdhverify.c
---- ./lib/softoken/sftkdhverify.c.fips-review 2024-06-07 09:26:03.000000000 -0700
-+++ ./lib/softoken/sftkdhverify.c 2024-06-12 12:04:10.641360427 -0700
-@@ -6726,11 +6726,20 @@ static const SECItem subprime_tls_8192 =
- (unsigned char *)subprime_tls_8192_data,
- sizeof(subprime_tls_8192_data) };
-
-+/* generator for all the groups is 2 */
-+static const unsigned char generator_2_data[] = { 2 };
-+
-+
-+static const SECItem generator_2 =
-+ { siBuffer,
-+ (unsigned char *)generator_2_data,
-+ sizeof(generator_2_data) };
-+
- /*
- * verify that dhPrime matches one of our known primes
- */
- const SECItem *
--sftk_VerifyDH_Prime(SECItem *dhPrime, PRBool isFIPS)
-+sftk_VerifyDH_Prime(SECItem *dhPrime, SECItem *g, PRBool isFIPS)
- {
- /* use the length to decide which primes to check */
- switch (dhPrime->len) {
-@@ -6741,56 +6750,67 @@ sftk_VerifyDH_Prime(SECItem *dhPrime, PR
- }
- if (PORT_Memcmp(dhPrime->data, prime_ike_1536,
- sizeof(prime_ike_1536)) == 0) {
-+ if (g) *g = generator_2;
- return &subprime_ike_1536;
- }
- break;
- case 2048 / PR_BITS_PER_BYTE:
- if (PORT_Memcmp(dhPrime->data, prime_tls_2048,
- sizeof(prime_tls_2048)) == 0) {
-+ if (g) *g = generator_2;
- return &subprime_tls_2048;
- }
- if (PORT_Memcmp(dhPrime->data, prime_ike_2048,
- sizeof(prime_ike_2048)) == 0) {
-+ if (g) *g = generator_2;
- return &subprime_ike_2048;
- }
- break;
- case 3072 / PR_BITS_PER_BYTE:
- if (PORT_Memcmp(dhPrime->data, prime_tls_3072,
- sizeof(prime_tls_3072)) == 0) {
-+ if (g) *g = generator_2;
- return &subprime_tls_3072;
- }
- if (PORT_Memcmp(dhPrime->data, prime_ike_3072,
- sizeof(prime_ike_3072)) == 0) {
-+ if (g) *g = generator_2;
- return &subprime_ike_3072;
- }
- break;
- case 4096 / PR_BITS_PER_BYTE:
- if (PORT_Memcmp(dhPrime->data, prime_tls_4096,
- sizeof(prime_tls_4096)) == 0) {
-+ if (g) *g = generator_2;
- return &subprime_tls_4096;
- }
- if (PORT_Memcmp(dhPrime->data, prime_ike_4096,
- sizeof(prime_ike_4096)) == 0) {
-+ if (g) *g = generator_2;
- return &subprime_ike_4096;
- }
- break;
- case 6144 / PR_BITS_PER_BYTE:
- if (PORT_Memcmp(dhPrime->data, prime_tls_6144,
- sizeof(prime_tls_6144)) == 0) {
-+ if (g) *g = generator_2;
- return &subprime_tls_6144;
- }
- if (PORT_Memcmp(dhPrime->data, prime_ike_6144,
- sizeof(prime_ike_6144)) == 0) {
-+ if (g) *g = generator_2;
- return &subprime_ike_6144;
- }
- break;
- case 8192 / PR_BITS_PER_BYTE:
- if (PORT_Memcmp(dhPrime->data, prime_tls_8192,
- sizeof(prime_tls_8192)) == 0) {
-+ if (g) *g = generator_2;
- return &subprime_tls_8192;
- }
- if (PORT_Memcmp(dhPrime->data, prime_ike_8192,
- sizeof(prime_ike_8192)) == 0) {
-+ if (g) *g = generator_2;
- return &subprime_ike_8192;
- }
- break;
-diff -up ./lib/softoken/sftkike.c.fips-review ./lib/softoken/sftkike.c
---- ./lib/softoken/sftkike.c.fips-review 2024-06-07 09:26:03.000000000 -0700
-+++ ./lib/softoken/sftkike.c 2024-06-12 12:04:10.641360427 -0700
-@@ -516,6 +516,11 @@ sftk_ike_prf(CK_SESSION_HANDLE hSession,
- goto fail;
- }
- } else {
-+ /* ikev1 isn't validated, if we use this function in ikev1 mode,
-+ * mark the resulting key as not FIPS */
-+ if (!params->bRekey) {
-+ outKey->isFIPS = PR_FALSE;
-+ }
- crv = prf_init(&context, inKey->attrib.pValue,
- inKey->attrib.ulValueLen);
- if (crv != CKR_OK) {
diff --git a/nss-3.101-fix-shlibsign-fips.patch b/nss-3.101-fix-shlibsign-fips.patch
deleted file mode 100644
index 70e83f5..0000000
--- a/nss-3.101-fix-shlibsign-fips.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -up ./cmd/shlibsign/shlibsign.c.shlibsign ./cmd/shlibsign/shlibsign.c
---- ./cmd/shlibsign/shlibsign.c.shlibsign 2024-06-07 09:26:03.000000000 -0700
-+++ ./cmd/shlibsign/shlibsign.c 2024-10-31 10:49:28.637449054 -0700
-@@ -1426,7 +1426,7 @@ main(int argc, char **argv)
- } else {
- /* NON FIPS mode == C_GetFunctionList */
- pC_GetFunctionList = (CK_C_GetFunctionList)
-- PR_FindFunctionSymbol(lib, "C_GetFunctionList");
-+ PR_FindFunctionSymbol(lib, "NSC_GetFunctionList");
- }
- assert(pC_GetFunctionList != NULL);
- if (!pC_GetFunctionList) {
diff --git a/nss-3.101-revert-libpkix-default.patch b/nss-3.101-revert-libpkix-default.patch
deleted file mode 100644
index e3c0686..0000000
--- a/nss-3.101-revert-libpkix-default.patch
+++ /dev/null
@@ -1,104 +0,0 @@
-diff -up ./lib/certhigh/certvfypkix.c.revert_libpkix ./lib/certhigh/certvfypkix.c
---- ./lib/certhigh/certvfypkix.c.revert_libpkix 2024-06-07 09:26:03.000000000 -0700
-+++ ./lib/certhigh/certvfypkix.c 2024-07-05 13:18:34.285174699 -0700
-@@ -39,7 +39,7 @@ pkix_pl_lifecycle_ObjectTableUpdate(int
- PRInt32 parallelFnInvocationCount;
- #endif /* PKIX_OBJECT_LEAK_TEST */
-
--static PRBool usePKIXValidationEngine = PR_TRUE;
-+static PRBool usePKIXValidationEngine = PR_FALSE;
- #endif /* NSS_DISABLE_LIBPKIX */
-
- /*
-diff -up ./lib/nss/nssinit.c.revert_libpkix ./lib/nss/nssinit.c
---- ./lib/nss/nssinit.c.revert_libpkix 2024-06-07 09:26:03.000000000 -0700
-+++ ./lib/nss/nssinit.c 2024-07-05 13:18:34.285174699 -0700
-@@ -764,9 +764,9 @@ nss_Init(const char *configdir, const ch
- if (pkixError != NULL) {
- goto loser;
- } else {
-- char *ev = PR_GetEnvSecure("NSS_DISABLE_PKIX_VERIFY");
-+ char *ev = PR_GetEnvSecure("NSS_ENABLE_PKIX_VERIFY");
- if (ev && ev[0]) {
-- CERT_SetUsePKIXForValidation(PR_FALSE);
-+ CERT_SetUsePKIXForValidation(PR_TRUE);
- }
- }
- #endif /* NSS_DISABLE_LIBPKIX */
-diff -up ./tests/all.sh.revert_libpkix ./tests/all.sh
---- ./tests/all.sh.revert_libpkix 2024-06-07 09:26:03.000000000 -0700
-+++ ./tests/all.sh 2024-07-05 13:18:34.285174699 -0700
-@@ -143,9 +143,6 @@ run_cycle_standard()
- {
- TEST_MODE=STANDARD
-
-- NSS_DISABLE_LIBPKIX_VERIFY="1"
-- export NSS_DISABLE_LIBPKIX_VERIFY
--
- TESTS="${ALL_TESTS}"
- TESTS_SKIP="libpkix pkits"
-
-@@ -153,8 +150,6 @@ run_cycle_standard()
- export NSS_DEFAULT_DB_TYPE
-
- run_tests
--
-- unset NSS_DISABLE_LIBPKIX_VERIFY
- }
-
- ############################ run_cycle_pkix ############################
-@@ -172,6 +167,9 @@ run_cycle_pkix()
- mkdir -p "${HOSTDIR}"
- init_directories
-
-+ NSS_ENABLE_PKIX_VERIFY="1"
-+ export NSS_ENABLE_PKIX_VERIFY
-+
- TESTS="${ALL_TESTS}"
- TESTS_SKIP="cipher dbtests sdr crmf smime merge multinit"
-
-diff -up ./tests/common/init.sh.revert_libpkix ./tests/common/init.sh
---- ./tests/common/init.sh.revert_libpkix 2024-06-07 09:26:03.000000000 -0700
-+++ ./tests/common/init.sh 2024-07-05 13:18:34.285174699 -0700
-@@ -140,8 +140,8 @@ if [ -z "${INIT_SOURCED}" -o "${INIT_SOU
- echo "NSS_SSL_RUN=\"${NSS_SSL_RUN}\""
- echo "NSS_DEFAULT_DB_TYPE=${NSS_DEFAULT_DB_TYPE}"
- echo "export NSS_DEFAULT_DB_TYPE"
-- echo "NSS_DISABLE_PKIX_VERIFY=${NSS_DISABLE_PKIX_VERIFY}"
-- echo "export NSS_DISABLE_PKIX_VERIFY"
-+ echo "NSS_ENABLE_PKIX_VERIFY=${NSS_ENABLE_PKIX_VERIFY}"
-+ echo "export NSS_ENABLE_PKIX_VERIFY"
- echo "init_directories"
- }
-
-diff -up ./tests/ssl/ssl.sh.revert_libpkix ./tests/ssl/ssl.sh
---- ./tests/ssl/ssl.sh.revert_libpkix 2024-07-05 13:18:34.267174492 -0700
-+++ ./tests/ssl/ssl.sh 2024-07-05 13:23:15.295402481 -0700
-@@ -971,8 +971,9 @@ ssl_policy_pkix_ocsp()
- return 0
- fi
-
-- PKIX_SAVE=${NSS_DISABLE_LIBPKIX_VERIFY-"unset"}
-- unset NSS_DISABLE_LIBPKIX_VERIFY
-+ PKIX_SAVE=${NSS_ENABLE_PKIX_VERIFY-"unset"}
-+ NSS_ENABLE_PKIX_VERIFY="1"
-+ export NSS_ENABLE_PKIX_VERIFY
-
- testname=""
-
-@@ -997,10 +998,12 @@ ssl_policy_pkix_ocsp()
- html_msg $RET $RET_EXP "${testname}" \
- "produced a returncode of $RET, expected is $RET_EXP"
-
-- if [ "{PKIX_SAVE}" != "unset" ]; then
-- export NSS_DISABLE_LIBPKIX_VERIFY=${PKIX_SAVE}
-+ if [ "${PKIX_SAVE}" = "unset" ]; then
-+ unset NSS_ENABLE_PKIX_VERIFY
-+ else
-+ NSS_ENABLE_PKIX_VERIFY=${PKIX_SAVE}
-+ export NSS_ENABLE_PKIX_VERIFY
- fi
--
- cp ${P_R_SERVERDIR}/pkcs11.txt.sav ${P_R_SERVERDIR}/pkcs11.txt
-
- html "
"
diff --git a/nss-3.112-add-ml-dsa-base-dsa.patch b/nss-3.112-add-ml-dsa-base-dsa.patch
deleted file mode 100644
index f384bcd..0000000
--- a/nss-3.112-add-ml-dsa-base-dsa.patch
+++ /dev/null
@@ -1,26084 +0,0 @@
-# HG changeset patch
-# User Robert Relyea
-# Date 1752516179 25200
-# Mon Jul 14 11:02:59 2025 -0700
-# Branch RHEL9
-# Node ID bcc304a631ca5ce266d597e4d58eb6f36f37eba3
-# Parent e3718267d1b9b2de112f9ce3aba94d11f687aaea
-nss-3.112-ml-dsa-base-dsa.patch
-
-diff --git a/.hgignore b/.hgignore
---- a/.hgignore
-+++ b/.hgignore
-@@ -15,8 +15,13 @@ GTAGS
- #*
- .#*
- .ycm_extra_conf.py*
- fuzz/libFuzzer/*
- fuzz/corpus
- fuzz/out
- .chk
- cmd/dbtool/sdb.c
-+lib/freebl/oqs/liboqs/**
-+lib/freebl/oqs/*extract_defines*
-+lib/freebl/leancrypto/leancrypto/**
-+lib/freebl/oqs/**
-+mldsa_samples/**
-diff --git a/cmd/certutil/certutil.c b/cmd/certutil/certutil.c
---- a/cmd/certutil/certutil.c
-+++ b/cmd/certutil/certutil.c
-@@ -296,16 +296,21 @@ CertReq(SECKEYPrivateKey *privk, SECKEYP
- rv = SECOID_SetAlgorithmID(arena, &signAlg,
- SEC_OID_PKCS1_RSA_PSS_SIGNATURE, params);
- if (rv != SECSuccess) {
- PORT_FreeArena(arena, PR_FALSE);
- SECU_PrintError(progName, "unable to set algorithm ID");
- return SECFailure;
- }
- } else {
-+ /* sigh, we need to create a new SEC_GetSignatureAlgorithOidTag()
-+ * that takes a public key and one that takes a private key */
-+ if (keyType == mldsaKey) {
-+ hashAlgTag = pubk->u.mldsa.params;
-+ }
- signAlgTag = SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag);
- if (signAlgTag == SEC_OID_UNKNOWN) {
- PORT_FreeArena(arena, PR_FALSE);
- SECU_PrintError(progName, "unknown Key or Hash type");
- return SECFailure;
- }
- rv = SECOID_SetAlgorithmID(arena, &signAlg, signAlgTag, 0);
- if (rv != SECSuccess) {
-@@ -858,18 +863,20 @@ SECItemToHex(const SECItem *item, char *
- unsigned int len = item->len;
- for (; len > 0; --len, dst += 2) {
- snprintf(dst, 3, "%02x", *src++);
- }
- *dst = '\0';
- }
- }
-
-+/* must be ordered to match KeyType in keythi.h */
- static const char *const keyTypeName[] = {
-- "null", "rsa", "dsa", "fortezza", "dh", "kea", "ec", "rsaPss", "rsaOaep"
-+ "null", "rsa", "dsa", "fortezza", "dh", "kea", "ec", "rsaPss", "rsaOaep",
-+ "kyberKey", "edKey", "ecMontKey", "mldsaKey"
- };
-
- #define MAX_CKA_ID_BIN_LEN 20
- #define MAX_CKA_ID_STR_LEN 40
-
- /* output human readable key ID in buffer, which should have at least
- * MAX_CKA_ID_STR_LEN + 3 octets (quotations and a null terminator) */
- static void
-@@ -899,27 +906,31 @@ formatPrivateKeyID(SECKEYPrivateKey *pri
- /* print key number, key ID (in hex or ASCII), key label (nickname) */
- static SECStatus
- PrintKey(PRFileDesc *out, const char *nickName, int count,
- SECKEYPrivateKey *key, void *pwarg)
- {
- char ckaIDbuf[MAX_CKA_ID_STR_LEN + 4];
- CERTCertificate *cert;
- KeyType keyType;
-+ const char *thisKeyTypeName = "unknown";
-
- formatPrivateKeyID(key, ckaIDbuf);
- cert = PK11_GetCertFromPrivateKey(key);
- if (cert) {
- keyType = CERT_GetCertKeyType(&cert->subjectPublicKeyInfo);
- CERT_DestroyCertificate(cert);
- } else {
- keyType = key->keyType;
- }
-+ if (keyType < PR_ARRAY_SIZE(keyTypeName)) {
-+ thisKeyTypeName = keyTypeName[keyType];
-+ }
- PR_fprintf(out, "<%2d> %-8.8s %-42.42s %s\n", count,
-- keyTypeName[keyType], ckaIDbuf, nickName);
-+ thisKeyTypeName, ckaIDbuf, nickName);
-
- return SECSuccess;
- }
-
- /* returns SECSuccess if ANY keys are found, SECFailure otherwise. */
- static SECStatus
- ListKeysInSlot(PK11SlotInfo *slot, const char *nickName, KeyType keyType,
- void *pwarg)
-@@ -1185,17 +1196,19 @@ PrintSyntax()
- FPS "\t%s -F -k key-id [-d certdir] [-P dbprefix]\n",
- progName);
- FPS "\t%s -G -n key-name [-h token-name] [-k rsa] [-g key-size] [-y exp]\n"
- "\t\t [-f pwfile] [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
- FPS "\t%s -G [-h token-name] -k dsa [-q pqgfile -g key-size] [-f pwfile]\n"
- "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
- FPS "\t%s -G [-h token-name] -k ec -q curve [-f pwfile]\n"
- "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
-- FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|ec|rsa|all]\n",
-+ FPS "\t%s -G [-h token-name] -k mldsa -q paramset [-f pwfile]\n"
-+ "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
-+ FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|ec|rsa|mldsa|all]\n",
- progName);
- FPS "\t\t [-f pwfile] [-X] [-d certdir] [-P dbprefix]\n");
- FPS "\t%s --upgrade-merge --source-dir upgradeDir --upgrade-id uniqueID\n",
- progName);
- FPS "\t\t [--upgrade-token-name tokenName] [-d targetDBDir]\n");
- FPS "\t\t [-P targetDBPrefix] [--source-prefix upgradeDBPrefix]\n");
- FPS "\t\t [-f targetPWfile] [-@ upgradePWFile]\n");
- FPS "\t%s --merge --source-dir sourceDBDir [-d targetDBdir]\n",
-@@ -1419,16 +1432,19 @@ luG(enum usage_level ul, const char *com
- FPS "%-20s prime239v1, prime239v2, prime239v3, c2pnb163v1, \n", "");
- FPS "%-20s c2pnb163v2, c2pnb163v3, c2pnb176v1, c2tnb191v1, \n", "");
- FPS "%-20s c2tnb191v2, c2tnb191v3, \n", "");
- FPS "%-20s c2pnb208w1, c2tnb239v1, c2tnb239v2, c2tnb239v3, \n", "");
- FPS "%-20s c2pnb272w1, c2pnb304w1, \n", "");
- FPS "%-20s c2tnb359w1, c2pnb368w1, c2tnb431r1, secp112r1, \n", "");
- FPS "%-20s secp112r2, secp128r1, secp128r2, sect113r1, sect113r2\n", "");
- FPS "%-20s sect131r1, sect131r2\n", "");
-+ FPS "%-20s ML-DSA parameter set (mldsa only)\n",
-+ " -q paramset");
-+ FPS "%-20s valid values are ml-dsa-44, ml-dsa-65, ml-dsa-87:\n", "");
- FPS "%-20s Key database directory (default is ~/.netscape)\n",
- " -d keydir");
- FPS "%-20s Cert & Key database prefix\n",
- " -P dbprefix");
- FPS "%-20s\n"
- "%-20s PKCS #11 key Attributes.\n",
- " --keyAttrFlags attrflags", "");
- FPS "%-20s Comma separated list of key attribute attribute flags,\n", "");
-@@ -1511,16 +1527,17 @@ luK(enum usage_level ul, const char *com
- "-K");
- if (ul == usage_selected && !is_my_command)
- return;
- FPS "%-20s Name of token to search (\"all\" for all tokens)\n",
- " -h token-name ");
-
- FPS "%-20s Key type (\"all\" (default), \"dsa\","
- " \"ec\","
-+ " \"mldsa\","
- " \"rsa\")\n",
- " -k key-type");
- FPS "%-20s The nickname of the key or associated certificate\n",
- " -n name");
- FPS "%-20s Specify the password file\n",
- " -f password-file");
- FPS "%-20s Key database directory (default is ~/.netscape)\n",
- " -d keydir");
-@@ -1671,16 +1688,20 @@ luR(enum usage_level ul, const char *com
- FPS "%-20s Create a certificate request restricted to RSA-PSS (rsa only)\n",
- " --pss");
- FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
- " -q pqgfile");
- FPS "%-20s Elliptic curve name (ec only)\n",
- " -q curve-name");
- FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
- "");
-+ FPS "%-20s ML-DSA parameter set (mldsa only)\n",
-+ " -q paramset");
-+ FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
-+ "");
- FPS "%-20s Specify the password file\n",
- " -f pwfile");
- FPS "%-20s Key database directory (default is ~/.netscape)\n",
- " -d keydir");
- FPS "%-20s Cert & Key database prefix\n",
- " -P dbprefix");
- FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
- " -p phone");
-@@ -1851,16 +1872,20 @@ luS(enum usage_level ul, const char *com
- FPS "%-20s Create a certificate restricted to RSA-PSS (rsa only)\n",
- " --pss");
- FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
- " -q pqgfile");
- FPS "%-20s Elliptic curve name (ec only)\n",
- " -q curve-name");
- FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
- "");
-+ FPS "%-20s ML-DSA parameter set (mldsa only)\n",
-+ " -q paramset");
-+ FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
-+ "");
- FPS "%-20s Self sign\n",
- " -x");
- FPS "%-20s Sign the certificate with RSA-PSS (the issuer key must be rsa)\n",
- " --pss-sign");
- FPS "%-20s Cert serial number\n",
- " -m serial-number");
- FPS "%-20s Time Warp\n",
- " -w warp-months");
-@@ -2031,16 +2056,39 @@ MakeV1Cert(CERTCertDBHandle *handle,
- }
- if (issuerCert) {
- CERT_DestroyCertificate(issuerCert);
- }
-
- return (cert);
- }
-
-+/* sigh look up the ml-dsa oid by string */
-+static SECOidTag
-+FindTagFromString(char *cipherString)
-+{
-+ SECOidTag tag;
-+ SECOidData *oid;
-+
-+ /* future enhancement: accept dotted oid spec? */
-+
-+ for (tag = 1; (oid = SECOID_FindOIDByTag(tag)) != NULL; tag++) {
-+ /* only interested in oids that we actually understand */
-+ if (oid->mechanism == CKM_INVALID_MECHANISM) {
-+ continue;
-+ }
-+ if (PORT_Strcasecmp(oid->desc, cipherString) != 0) {
-+ continue;
-+ }
-+ return tag;
-+ }
-+ return SEC_OID_UNKNOWN;
-+}
-+
-+
- static SECStatus
- SetSignatureAlgorithm(PLArenaPool *arena,
- SECAlgorithmID *signAlg,
- SECAlgorithmID *spkiAlg,
- SECOidTag hashAlgTag,
- SECKEYPrivateKey *privKey,
- PRBool pssSign)
- {
-@@ -2071,20 +2119,71 @@ SetSignatureAlgorithm(PLArenaPool *arena
- }
- rv = SECOID_SetAlgorithmID(arena, signAlg,
- SEC_OID_PKCS1_RSA_PSS_SIGNATURE,
- params);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "Could not set signature algorithm id.");
- return rv;
- }
-+ } else if (privKey->keyType == mldsaKey) {
-+ /* sigh, we need toexport SECKEY_GetParameterSet(), for now
-+ * just do it inline */
-+ /* this is temp code until we fix it correctly upstream. Don't
-+ * push this upstream */
-+ SECOidTag algID;
-+ SECItem item;
-+ CK_ULONG paramSet;
-+
-+ rv = PK11_ReadRawAttribute(PK11_TypePrivKey, privKey,
-+ CKA_PARAMETER_SET, &item);
-+
-+ if (rv != SECSuccess) {
-+ SECU_PrintError(progName, "missing parameter set for ml-dsa key.");
-+ return SECFailure;
-+ }
-+ if (item.len != sizeof (paramSet)) {
-+ SECU_PrintError(progName, "corrupted parameter set for ml-dsa key.");
-+ PORT_Free(item.data);
-+ return SECFailure;
-+ }
-+ paramSet = *(CK_ULONG *)item.data;
-+ PORT_Free(item.data);
-+ switch (paramSet) {
-+ case CKP_ML_DSA_44:
-+ algID = FindTagFromString("ML-DSA-44");
-+ break;
-+ case CKP_ML_DSA_65:
-+ algID = FindTagFromString("ML-DSA-65");
-+ break;
-+ case CKP_ML_DSA_87:
-+ algID = FindTagFromString("ML-DSA-87");
-+ break;
-+ default:
-+ algID = SEC_OID_UNKNOWN;
-+ break;
-+ }
-+ if (algID == SEC_OID_UNKNOWN) {
-+ PORT_SetError(SEC_ERROR_INVALID_KEY);
-+ SECU_PrintError(progName, "invalid parameter set for ml-dsa key.");
-+ return SECFailure;
-+ }
-+
-+ rv = SECOID_SetAlgorithmID(arena, signAlg, algID, 0);
-+ if (rv != SECSuccess) {
-+ SECU_PrintError(progName, "Could not set signature algorithm id.");
-+ return rv;
-+ }
- } else {
- KeyType keyType = SECKEY_GetPrivateKeyType(privKey);
- SECOidTag algID;
--
-+
-+ /* first, try to get the ParameterSet from the key, If the
-+ * key as a parameter set, use it, otherwise fall back to
-+ * SEC_GetSignatureAlgorithmoidTag */
- algID = SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag);
- if (algID == SEC_OID_UNKNOWN) {
- SECU_PrintError(progName, "Unknown key or hash type for issuer.");
- return SECFailure;
- }
- rv = SECOID_SetAlgorithmID(arena, signAlg, algID, 0);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "Could not set signature algorithm id.");
-@@ -2839,19 +2938,44 @@ certutil_main(int argc, char **argv, PRB
- sourceDir = certutil.options[opt_SourceDir].arg;
-
- if (certutil.options[opt_UpgradeID].activated)
- upgradeID = certutil.options[opt_UpgradeID].arg;
-
- if (certutil.options[opt_UpgradeTokenName].activated)
- upgradeTokenName = certutil.options[opt_UpgradeTokenName].arg;
-
-+ /* must be before opt_KeySize! */
-+ /* -k key type */
-+ if (certutil.options[opt_KeyType].activated) {
-+ char *arg = certutil.options[opt_KeyType].arg;
-+ if (PL_strcmp(arg, "rsa") == 0) {
-+ keytype = rsaKey;
-+ } else if (PL_strcmp(arg, "dsa") == 0) {
-+ keytype = dsaKey;
-+ } else if (PL_strcmp(arg, "ec") == 0) {
-+ keytype = ecKey;
-+ } else if (PL_strcmp(arg, "mldsa") == 0) {
-+ keytype = mldsaKey;
-+ } else if (PL_strcmp(arg, "all") == 0) {
-+ keytype = nullKey;
-+ } else {
-+ /* use an existing private/public key pair */
-+ keysource = arg;
-+ }
-+ } else if (certutil.commands[cmd_ListKeys].activated) {
-+ keytype = nullKey;
-+ }
-+
- if (certutil.options[opt_KeySize].activated) {
- keysize = PORT_Atoi(certutil.options[opt_KeySize].arg);
-- if ((keysize < MIN_KEY_BITS) || (keysize > MAX_KEY_BITS)) {
-+ /* mldsa limits are much different that rsa and dsa, don't
-+ * do the check here */
-+ if ((keytype != mldsaKey) &&
-+ ((keysize < MIN_KEY_BITS) || (keysize > MAX_KEY_BITS))) {
- PR_fprintf(PR_STDERR,
- "%s -g: Keysize must be between %d and %d.\n",
- progName, MIN_KEY_BITS, MAX_KEY_BITS);
- return 255;
- }
- if (keytype == ecKey) {
- PR_fprintf(PR_STDERR, "%s -g: Not for ec keys.\n", progName);
- return 255;
-@@ -2872,34 +2996,16 @@ certutil_main(int argc, char **argv, PRB
- hashAlgTag = SECU_StringToSignatureAlgTag(arg);
- if (hashAlgTag == SEC_OID_UNKNOWN) {
- PR_fprintf(PR_STDERR, "%s -Z: %s is not a recognized type.\n",
- progName, arg);
- return 255;
- }
- }
-
-- /* -k key type */
-- if (certutil.options[opt_KeyType].activated) {
-- char *arg = certutil.options[opt_KeyType].arg;
-- if (PL_strcmp(arg, "rsa") == 0) {
-- keytype = rsaKey;
-- } else if (PL_strcmp(arg, "dsa") == 0) {
-- keytype = dsaKey;
-- } else if (PL_strcmp(arg, "ec") == 0) {
-- keytype = ecKey;
-- } else if (PL_strcmp(arg, "all") == 0) {
-- keytype = nullKey;
-- } else {
-- /* use an existing private/public key pair */
-- keysource = arg;
-- }
-- } else if (certutil.commands[cmd_ListKeys].activated) {
-- keytype = nullKey;
-- }
-
- if (certutil.options[opt_KeyOpFlagsOn].activated) {
- keyOpFlagsOn = GetOpFlags(certutil.options[opt_KeyOpFlagsOn].arg);
- }
- if (certutil.options[opt_KeyOpFlagsOff].activated) {
- keyOpFlagsOff = GetOpFlags(certutil.options[opt_KeyOpFlagsOff].arg);
- keyOpFlagsOn &= ~keyOpFlagsOff; /* make off override on */
- }
-@@ -2933,19 +3039,22 @@ certutil_main(int argc, char **argv, PRB
- srcCertPrefix = certutil.options[opt_SourcePrefix].arg;
- } else {
- Usage();
- }
- }
-
- /* -q PQG file or curve name */
- if (certutil.options[opt_PQGFile].activated) {
-- if ((keytype != dsaKey) && (keytype != ecKey)) {
-+ if ((keytype != dsaKey) && (keytype != ecKey) &&
-+ (keytype != mldsaKey)) {
- PR_fprintf(PR_STDERR, "%s -q: specifies a PQG file for DSA keys"
-- " (-k dsa) or a named curve for EC keys (-k ec)\n)",
-+ " (-k dsa)\n"
-+ " or a named curve for EC keys (-k ec)\n"
-+ " or a parameter set for ML-DSA keys (-k mldsa)\n",
- progName);
- return 255;
- }
- }
-
- /* -s subject name */
- if (certutil.options[opt_Subject].activated) {
- subject = CERT_AsciiToName(certutil.options[opt_Subject].arg);
-diff --git a/cmd/certutil/keystuff.c b/cmd/certutil/keystuff.c
---- a/cmd/certutil/keystuff.c
-+++ b/cmd/certutil/keystuff.c
-@@ -512,16 +512,17 @@ CERTUTIL_GeneratePrivateKey(KeyType keyt
- int publicExponent, const char *noise,
- SECKEYPublicKey **pubkeyp, const char *pqgFile,
- PK11AttrFlags attrFlags, CK_FLAGS opFlagsOn,
- CK_FLAGS opFlagsOff, secuPWData *pwdata)
- {
- CK_MECHANISM_TYPE mechanism;
- PK11RSAGenParams rsaparams;
- SECKEYPQGParams *dsaparams = NULL;
-+ CK_ULONG paramSet;
- void *params;
- SECKEYPrivateKey *privKey = NULL;
-
- if (slot == NULL)
- return NULL;
-
- if (PK11_Authenticate(slot, PR_TRUE, pwdata) != SECSuccess)
- return NULL;
-@@ -564,16 +565,58 @@ CERTUTIL_GeneratePrivateKey(KeyType keyt
- }
- break;
- case ecKey:
- mechanism = CKM_EC_KEY_PAIR_GEN;
- /* For EC keys, PQGFile determines EC parameters */
- if ((params = (void *)getECParams(pqgFile)) == NULL)
- return NULL;
- break;
-+ case mldsaKey:
-+ mechanism = CKM_ML_DSA_KEY_PAIR_GEN;
-+ /* set paramset */
-+ paramSet = 0;
-+ if (pqgFile) {
-+ if (PORT_Strcasecmp(pqgFile, "ML-DSA-44") == 0) {
-+ paramSet = CKP_ML_DSA_44;
-+ } else if (PORT_Strcasecmp(pqgFile, "ML-DSA-65") == 0) {
-+ paramSet = CKP_ML_DSA_65;
-+ } else if (PORT_Strcasecmp(pqgFile, "ML-DSA-87") == 0) {
-+ paramSet = CKP_ML_DSA_87;
-+ } else {
-+ /* if we set pqgfile, it had better be right, don't
-+ * fall back to key size */
-+ return NULL;
-+ }
-+ } else switch (size) {
-+ /* optionally use the size, either the actual size in bytes
-+ * or the short hand ('44', '65', '87') */
-+ case 44:
-+ case 2560:
-+ paramSet = CKP_ML_DSA_44;
-+ break;
-+ case 65:
-+ case 4032:
-+ paramSet = CKP_ML_DSA_65;
-+ break;
-+ case 87:
-+ case 4896:
-+ paramSet = CKP_ML_DSA_87;
-+ break;
-+ default:
-+ /* force a size to be specified somewhere */
-+ return NULL;
-+ }
-+ /* paranoia, shouldn't be able to happen logically. Code
-+ * scanners will scream, but I like belt and suspenders */
-+ if (paramSet == 0) {
-+ return NULL;
-+ }
-+ params = ¶mSet;
-+ break;
- default:
- return NULL;
- }
-
- fprintf(stderr, "\n\n");
- fprintf(stderr, "Generating key. This may take a few moments...\n\n");
-
- privKey = PK11_GenerateKeyPairWithOpFlags(slot, mechanism, params, pubkeyp,
-diff --git a/cmd/lib/secutil.c b/cmd/lib/secutil.c
---- a/cmd/lib/secutil.c
-+++ b/cmd/lib/secutil.c
-@@ -1157,16 +1157,30 @@ secu_PrintValidity(FILE *out, CERTValidi
- {
- SECU_Indent(out, level);
- fprintf(out, "%s:\n", m);
- SECU_PrintTimeChoice(out, &v->notBefore, "Not Before", level + 1);
- SECU_PrintTimeChoice(out, &v->notAfter, "Not After ", level + 1);
- return 0;
- }
-
-+void
-+SECU_PrintOidTag(FILE *out, SECOidTag tag, const char *m, int level)
-+{
-+ const char *desc = SECOID_FindOIDTagDescription(tag);
-+
-+ if (desc == NULL) {
-+ desc = SECOID_FindOIDTagDescription(SEC_OID_UNKNOWN);
-+ }
-+ SECU_Indent(out, level);
-+ if (m != NULL)
-+ fprintf(out, "%s: ", m);
-+ fprintf(out, "%s\n", desc);
-+}
-+
- /* This function does NOT expect a DER type and length. */
- SECOidTag
- SECU_PrintObjectID(FILE *out, const SECItem *oid, const char *m, int level)
- {
- SECOidData *oiddata;
- char *oidString = NULL;
-
- oiddata = SECOID_FindOID(oid);
-@@ -1504,16 +1518,25 @@ SECU_PrintDSAPublicKey(FILE *out, SECKEY
- SECU_Indent(out, level);
- fprintf(out, "%s:\n", m);
- SECU_PrintInteger(out, &pk->u.dsa.params.prime, "Prime", level + 1);
- SECU_PrintInteger(out, &pk->u.dsa.params.subPrime, "Subprime", level + 1);
- SECU_PrintInteger(out, &pk->u.dsa.params.base, "Base", level + 1);
- SECU_PrintInteger(out, &pk->u.dsa.publicValue, "PublicValue", level + 1);
- }
-
-+void
-+SECU_PrintMLDSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level)
-+{
-+ SECU_Indent(out, level);
-+ fprintf(out, "%s:\n", m);
-+ SECU_PrintOidTag(out, pk->u.mldsa.params, "Parameter Set", level+1);
-+ SECU_PrintAsHex(out, &pk->u.mldsa.publicValue, "PublicValue", level+1);
-+}
-+
- static void
- secu_PrintSubjectPublicKeyInfo(FILE *out, PLArenaPool *arena,
- CERTSubjectPublicKeyInfo *i, char *msg, int level)
- {
- SECKEYPublicKey *pk;
-
- SECU_Indent(out, level);
- fprintf(out, "%s:\n", msg);
-@@ -1529,16 +1552,20 @@ secu_PrintSubjectPublicKeyInfo(FILE *out
- case dsaKey:
- SECU_PrintDSAPublicKey(out, pk, "DSA Public Key", level + 1);
- break;
-
- case ecKey:
- secu_PrintECPublicKey(out, pk, "EC Public Key", level + 1);
- break;
-
-+ case mldsaKey:
-+ SECU_PrintMLDSAPublicKey(out, pk, "ML-DSA Public Key", level + 1);
-+ break;
-+
- case dhKey:
- case fortezzaKey:
- case keaKey:
- SECU_Indent(out, level);
- fprintf(out, "unable to format this SPKI algorithm type\n");
- goto loser;
- default:
- SECU_Indent(out, level);
-diff --git a/cmd/pk11importtest/pk11importtest.c b/cmd/pk11importtest/pk11importtest.c
---- a/cmd/pk11importtest/pk11importtest.c
-+++ b/cmd/pk11importtest/pk11importtest.c
-@@ -99,16 +99,19 @@ handleEncryptedPrivateImportTest(char *p
- SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.dh.publicValue);
- break;
- case dsaKey:
- SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.dsa.publicValue);
- break;
- case ecKey:
- SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.ec.publicValue);
- break;
-+ case mldsaKey:
-+ SECITEM_CopyItem(NULL, &pubValue, &pubKey->u.mldsa.publicValue);
-+ break;
- default:
- fprintf(stderr, "Unknown keytype = %d\n", keyType);
- goto cleanup;
- }
- if (pubValue.data == NULL) {
- SECU_PrintError(progName, "Unable to allocate memory");
- goto cleanup;
- }
-@@ -193,16 +196,17 @@ static const char *const usageInfo[] = {
- " -k keysize size of the rsa, dh, and dsa key to test (default 1024)",
- " -C ecc_curve ecc curve (default )",
- " -f pwFile file to fetch the password from",
- " -p pwString password",
- " -r skip rsa test",
- " -D skip dsa test",
- " -h skip dh test",
- " -e skip ec test",
-+ " -m skip mldsa test",
- };
- static int nUsageInfo = sizeof(usageInfo) / sizeof(char *);
-
- static void
- Usage(char *progName, FILE *outFile)
- {
- int i;
- fprintf(outFile, "Usage: %s [ commands ] options\n", progName);
-@@ -215,45 +219,49 @@ enum {
- opt_CertDir,
- opt_KeySize,
- opt_ECCurve,
- opt_PWFile,
- opt_PWString,
- opt_NoRSA,
- opt_NoDSA,
- opt_NoEC,
-- opt_NoDH
-+ opt_NoDH,
-+ opt_NoMLDSA,
- };
-
- static secuCommandFlag options[] = {
- { /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE },
- { /* opt_KeySize */ 'k', PR_TRUE, 0, PR_FALSE },
- { /* opt_ECCurve */ 'C', PR_TRUE, 0, PR_FALSE },
- { /* opt_PWFile */ 'f', PR_TRUE, 0, PR_FALSE },
- { /* opt_PWString */ 'p', PR_TRUE, 0, PR_FALSE },
- { /* opt_NORSA */ 'r', PR_TRUE, 0, PR_FALSE },
- { /* opt_NoDSA */ 'D', PR_TRUE, 0, PR_FALSE },
-+ { /* opt_NoEC */ 'e', PR_TRUE, 0, PR_FALSE },
- { /* opt_NoDH */ 'h', PR_TRUE, 0, PR_FALSE },
-- { /* opt_NoEC */ 'e', PR_TRUE, 0, PR_FALSE },
-+ { /* opt_NoMLDSA */ 'm', PR_TRUE, 0, PR_FALSE },
- };
-
- int
- main(int argc, char **argv)
- {
- char *progName;
- SECStatus rv;
- secuCommand args;
- PK11SlotInfo *slot = NULL;
- PRBool failed = PR_FALSE;
- secuPWData pwArgs = { PW_NONE, 0 };
- PRBool doRSA = PR_TRUE;
- PRBool doDSA = PR_TRUE;
- PRBool doDH = PR_FALSE; /* NSS currently can't export wrapped DH keys */
- PRBool doEC = PR_TRUE;
-+ PRBool doMLDSA = PR_TRUE;
- PQGParams *pqgParams = NULL;
-+ CK_ULONG paramSet = CKP_ML_DSA_44;
- int keySize;
-
- args.numCommands = 0;
- args.numOptions = sizeof(options) / sizeof(secuCommandFlag);
- args.commands = NULL;
- args.options = options;
-
- #ifdef XP_PC
-@@ -295,16 +303,19 @@ main(int argc, char **argv)
- doDSA = PR_FALSE;
- }
- if (args.options[opt_NoDH].activated) {
- doDH = PR_FALSE;
- }
- if (args.options[opt_NoEC].activated) {
- doEC = PR_FALSE;
- }
-+ if (args.options[opt_NoMLDSA].activated) {
-+ doMLDSA = PR_FALSE;
-+ }
-
- slot = PK11_GetInternalKeySlot();
- if (slot == NULL) {
- SECU_PrintError(progName, "Couldn't find the internal key slot\n");
- return 255;
- }
- rv = PK11_Authenticate(slot, PR_TRUE, &pwArgs);
- if (rv != SECSuccess) {
-@@ -383,16 +394,26 @@ main(int argc, char **argv)
- PORT_Free(ecParams.data);
- ec_failed:
- if (rv != SECSuccess) {
- fprintf(stderr, "ECC Import Failed!\n");
- failed = PR_TRUE;
- }
- }
-
-+ if (doMLDSA) {
-+ rv = handleEncryptedPrivateImportTest(progName, slot, "ML-DSA",
-+ CKM_ML_DSA_KEY_PAIR_GEN,
-+ ¶mSet, &pwArgs);
-+ if (rv != SECSuccess) {
-+ fprintf(stderr, "ML-DSA Import Failed!\n");
-+ failed = PR_TRUE;
-+ }
-+ }
-+
- if (pqgParams) {
- PK11_PQG_DestroyParams(pqgParams);
- }
-
- if (slot) {
- PK11_FreeSlot(slot);
- }
-
-diff --git a/coreconf/config.mk b/coreconf/config.mk
---- a/coreconf/config.mk
-+++ b/coreconf/config.mk
-@@ -174,16 +174,20 @@ endif
- ifdef BUILD_LIBPKIX_TESTS
- DEFINES += -DBUILD_LIBPKIX_TESTS
- endif
-
- ifdef NSS_DISABLE_LIBPKIX
- DEFINES += -DNSS_DISABLE_LIBPKIX
- endif
-
-+ifdef NSS_ENABLE_ML_DSA
-+DEFINES += -DNSS_ENABLE_ML_DSA
-+endif
-+
- ifdef NSS_DISABLE_KYBER
- DEFINES += -DNSS_DISABLE_KYBER
- endif
-
- ifdef NSS_DISABLE_DBM
- DEFINES += -DNSS_DISABLE_DBM
- endif
-
-diff --git a/lib/certdb/certdb.c b/lib/certdb/certdb.c
---- a/lib/certdb/certdb.c
-+++ b/lib/certdb/certdb.c
-@@ -1226,16 +1226,17 @@ CERT_CheckKeyUsage(CERTCertificate *cert
- requiredUsage &= (~KU_KEY_AGREEMENT_OR_ENCIPHERMENT);
-
- switch (keyType) {
- case rsaKey:
- requiredUsage |= KU_KEY_ENCIPHERMENT;
- break;
- case rsaPssKey:
- case dsaKey:
-+ case mldsaKey:
- requiredUsage |= KU_DIGITAL_SIGNATURE;
- break;
- case dhKey:
- requiredUsage |= KU_KEY_AGREEMENT;
- break;
- case ecKey:
- /* Accept either signature or agreement. */
- if (!(cert->keyUsage &
-diff --git a/lib/certhigh/certvfy.c b/lib/certhigh/certvfy.c
---- a/lib/certhigh/certvfy.c
-+++ b/lib/certhigh/certvfy.c
-@@ -21,16 +21,17 @@
- #endif /* NSS_DISABLE_LIBPKIX */
-
- #include "nsspki.h"
- #include "pkitm.h"
- #include "pkim.h"
- #include "pki3hack.h"
- #include "base.h"
- #include "keyi.h"
-+#include "secmodti.h"
-
- /*
- * Check the validity times of a certificate
- */
- SECStatus
- CERT_CertTimesValid(CERTCertificate *c)
- {
- SECCertTimeValidity valid = CERT_CheckCertValidTimes(c, PR_Now(), PR_TRUE);
-@@ -152,16 +153,27 @@ checkKeyParams(const SECAlgorithmID *sig
- return SECFailure;
- }
-
- if (len < minLen) {
- return SECFailure;
- }
-
- return SECSuccess;
-+ case SEC_OID_ML_DSA_44:
-+ case SEC_OID_ML_DSA_65:
-+ case SEC_OID_ML_DSA_87:
-+ if (key->keyType != mldsaKey) {
-+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
-+ return SECFailure;
-+ }
-+ if (key->u.mldsa.params != sigAlg) {
-+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
-+ return SECFailure;
-+ }
- default:
- return SECSuccess;
- }
- }
-
- /*
- * verify the signature of a signed data object with the given DER publickey
- */
-diff --git a/lib/crmf/crmfcont.c b/lib/crmf/crmfcont.c
---- a/lib/crmf/crmfcont.c
-+++ b/lib/crmf/crmfcont.c
-@@ -562,16 +562,19 @@ crmf_get_mechanism_from_public_key(SECKE
- }
-
- SECItem *
- crmf_get_public_value(SECKEYPublicKey *pubKey, SECItem *dest)
- {
- SECItem *src;
-
- switch (pubKey->keyType) {
-+ case mldsaKey:
-+ src = &pubKey->u.mldsa.publicValue;
-+ break;
- case dsaKey:
- src = &pubKey->u.dsa.publicValue;
- break;
- case rsaKey:
- src = &pubKey->u.rsa.modulus;
- break;
- case dhKey:
- src = &pubKey->u.dh.publicValue;
-@@ -700,16 +703,21 @@ crmf_encrypted_value_unwrap_priv_key(PLA
- usage = dhUsage;
- usageCount = sizeof(dhUsage) / sizeof(dhUsage[0]);
- break;
- case dsaKey:
- keyType = CKK_DSA;
- usage = dsaUsage;
- usageCount = sizeof(dsaUsage) / sizeof(dsaUsage[0]);
- break;
-+ case mldsaKey:
-+ keyType = CKK_ML_DSA;
-+ usage = dsaUsage;
-+ usageCount = sizeof(dsaUsage) / sizeof(dsaUsage[0]);
-+ break;
- }
- PORT_Assert(usage != NULL);
- PORT_Assert(usageCount != 0);
- *unWrappedKey = PK11_UnwrapPrivKey(slot, wrappingKey, wrapMechType, params,
- &encValue->encValue, nickname,
- publicValue, PR_TRUE, PR_TRUE,
- keyType, usage, usageCount, wincx);
- encValue->encValue.len = origLen;
-diff --git a/lib/crmf/crmfpop.c b/lib/crmf/crmfpop.c
---- a/lib/crmf/crmfpop.c
-+++ b/lib/crmf/crmfpop.c
-@@ -56,22 +56,26 @@ CRMF_CertReqMsgSetRAVerifiedPOP(CRMFCert
- loser:
- PORT_ArenaRelease(poolp, mark);
- return SECFailure;
- }
-
- static SECOidTag
- crmf_get_key_sign_tag(SECKEYPublicKey *inPubKey)
- {
-+ SECOidTag hashAlg = SEC_OID_UNKNOWN;
- /* maintain backward compatibility with older
- * implementations */
- if (inPubKey->keyType == rsaKey) {
- return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION;
- }
-- return SEC_GetSignatureAlgorithmOidTag(inPubKey->keyType, SEC_OID_UNKNOWN);
-+ if (inPubKey->keyType == mldsaKey) {
-+ hashAlg = inPubKey->u.mldsa.params;
-+ }
-+ return SEC_GetSignatureAlgorithmOidTag(inPubKey->keyType, hashAlg);
- }
-
- static SECAlgorithmID *
- crmf_create_poposignkey_algid(PLArenaPool *poolp,
- SECKEYPublicKey *inPubKey)
- {
- SECAlgorithmID *algID;
- SECOidTag tag;
-diff --git a/lib/cryptohi/keyi.h b/lib/cryptohi/keyi.h
---- a/lib/cryptohi/keyi.h
-+++ b/lib/cryptohi/keyi.h
-@@ -49,11 +49,27 @@ SECStatus sec_DecodeRSAPSSParams(PLArena
- unsigned long *saltLength);
-
- /* convert the encoded RSA-PSS parameters into PKCS #11 mechanism parameters */
- SECStatus sec_DecodeRSAPSSParamsToMechanism(PLArenaPool *arena,
- const SECItem *params,
- CK_RSA_PKCS_PSS_PARAMS *mech,
- SECOidTag *hashAlg);
-
-+/* MLDSA mapping functions... private for now */
-+/* map various mldsa parameters and lengths back and forth */
-+typedef enum {
-+ SECKEYPubKeyType=1,
-+ SECKEYPrivKeyType,
-+ SECKEYSignatureType,
-+} SECKEYSizeType;
-+
-+SECOidTag SECKEY_MLDSAPkcs11ParamsToOidParams(CK_ML_DSA_PARAMETER_SET_TYPE paramSet);
-+CK_ML_DSA_PARAMETER_SET_TYPE SECKEY_MLDSAOidParamsToPkcs11Params(SECOidTag tag);
-+unsigned int SECKEY_MLDSAOidParamsToLen(SECOidTag oid, SECKEYSizeType type);
-+unsigned int SECKEY_MLDSAPkcs11ParamsToLen(CK_ML_DSA_PARAMETER_SET_TYPE paramSet,
-+ SECKEYSizeType type);
-+SECOidTag SECKEY_MLDSAOidParamsFromLen(unsigned int len, SECKEYSizeType type);
-+/* get the parameter set, converted to a key oid, only for new keys like mldsa, mlkem, and shldsa */
-+SECOidTag SECKEY_GetParameterSet(const SECKEYPrivateKey *key);
- SEC_END_PROTOS
-
- #endif /* _KEYHI_H_ */
-diff --git a/lib/cryptohi/keythi.h b/lib/cryptohi/keythi.h
---- a/lib/cryptohi/keythi.h
-+++ b/lib/cryptohi/keythi.h
-@@ -33,16 +33,17 @@ typedef enum {
- dhKey = 4,
- keaKey = 5, /* deprecated */
- ecKey = 6,
- rsaPssKey = 7,
- rsaOaepKey = 8,
- kyberKey = 9,
- edKey = 10,
- ecMontKey = 11,
-+ mldsaKey = 12,
- } KeyType;
-
- /*
- ** Template Definitions
- **/
-
- SEC_BEGIN_PROTOS
- extern const SEC_ASN1Template SECKEY_RSAPublicKeyTemplate[];
-@@ -183,32 +184,39 @@ typedef struct SECKEYKEAPublicKeyStr SEC
- */
-
- struct SECKEYKyberPublicKeyStr {
- KyberParams params;
- SECItem publicValue;
- };
- typedef struct SECKEYKyberPublicKeyStr SECKEYKyberPublicKey;
-
-+struct SECKEYMLDSAPublicKeyStr {
-+ SECOidTag params;
-+ SECItem publicValue;
-+};
-+typedef struct SECKEYMLDSAPublicKeyStr SECKEYMLDSAPublicKey;
-+
- /*
- ** A Generic public key object.
- */
- struct SECKEYPublicKeyStr {
- PLArenaPool *arena;
- KeyType keyType;
- PK11SlotInfo *pkcs11Slot;
- CK_OBJECT_HANDLE pkcs11ID;
- union {
- SECKEYRSAPublicKey rsa;
- SECKEYDSAPublicKey dsa;
- SECKEYDHPublicKey dh;
- SECKEYKEAPublicKey kea;
- SECKEYFortezzaPublicKey fortezza;
- SECKEYECPublicKey ec;
- SECKEYKyberPublicKey kyber;
-+ SECKEYMLDSAPublicKey mldsa;
- } u;
- };
- typedef struct SECKEYPublicKeyStr SECKEYPublicKey;
-
- /* bit flag definitions for staticflags */
- #define SECKEY_Attributes_Cached 0x1 /* bit 0 states \
- whether attributes are cached */
- #define SECKEY_CKA_PRIVATE (1U << 1) /* bit 1 is the value of CKA_PRIVATE */
-diff --git a/lib/cryptohi/seckey.c b/lib/cryptohi/seckey.c
---- a/lib/cryptohi/seckey.c
-+++ b/lib/cryptohi/seckey.c
-@@ -10,16 +10,17 @@
- #include "secasn1.h"
- #include "cert.h"
- #include "pk11func.h"
- #include "secerr.h"
- #include "secdig.h"
- #include "prtime.h"
- #include "keyi.h"
- #include "nss.h"
-+#include "secmodti.h" /* for private oids */
-
- SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
- SEC_ASN1_MKSUB(SEC_IntegerTemplate)
-
- const SEC_ASN1Template CERT_SubjectPublicKeyInfoTemplate[] = {
- { SEC_ASN1_SEQUENCE,
- 0, NULL, sizeof(CERTSubjectPublicKeyInfo) },
- { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
-@@ -158,16 +159,169 @@ SECKEY_CreateRSAPrivateKey(int keySizeIn
- param.pe = 65537L;
-
- privk = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, ¶m, pubk,
- PR_FALSE, PR_TRUE, cx);
- PK11_FreeSlot(slot);
- return (privk);
- }
-
-+/* MLDSA helper functions... private for now */
-+SECOidTag
-+SECKEY_MLDSAPkcs11ParamsToOidParams(CK_ML_DSA_PARAMETER_SET_TYPE paramSet)
-+{
-+ switch (paramSet) {
-+ case CKP_ML_DSA_44:
-+ return SEC_OID_ML_DSA_44;
-+ case CKP_ML_DSA_65:
-+ return SEC_OID_ML_DSA_65;
-+ case CKP_ML_DSA_87:
-+ return SEC_OID_ML_DSA_87;
-+ default:
-+ break;
-+ }
-+ return SEC_OID_UNKNOWN;
-+}
-+
-+CK_ML_DSA_PARAMETER_SET_TYPE
-+SECKEY_MLDSAOidParamsToPkcs11Params(SECOidTag tag)
-+{
-+ switch (tag) {
-+ case SEC_OID_ML_DSA_44:
-+ return CKP_ML_DSA_44;
-+ case SEC_OID_ML_DSA_65:
-+ return CKP_ML_DSA_65;
-+ case SEC_OID_ML_DSA_87:
-+ return CKP_ML_DSA_87;
-+ default:
-+ break;
-+ }
-+ return 0;
-+}
-+
-+unsigned int
-+SECKEY_MLDSAOidParamsToLen(SECOidTag oid, SECKEYSizeType type)
-+{
-+ switch (type) {
-+ case SECKEYPubKeyType:
-+ switch (oid) {
-+ case SEC_OID_ML_DSA_44:
-+ return ML_DSA_44_PUBLICKEY_LEN;
-+ case SEC_OID_ML_DSA_65:
-+ return ML_DSA_65_PUBLICKEY_LEN;
-+ case SEC_OID_ML_DSA_87:
-+ return ML_DSA_87_PUBLICKEY_LEN;
-+ default:
-+ break;
-+ }
-+ break;
-+ case SECKEYPrivKeyType:
-+ switch (oid) {
-+ case SEC_OID_ML_DSA_44:
-+ return ML_DSA_44_PRIVATEKEY_LEN;
-+ case SEC_OID_ML_DSA_65:
-+ return ML_DSA_65_PRIVATEKEY_LEN;
-+ case SEC_OID_ML_DSA_87:
-+ return ML_DSA_87_PRIVATEKEY_LEN;
-+ default:
-+ break;
-+ }
-+ break;
-+ case SECKEYSignatureType:
-+ switch (oid) {
-+ case SEC_OID_ML_DSA_44:
-+ return ML_DSA_44_SIGNATURE_LEN;
-+ case SEC_OID_ML_DSA_65:
-+ return ML_DSA_65_SIGNATURE_LEN;
-+ case SEC_OID_ML_DSA_87:
-+ return ML_DSA_87_SIGNATURE_LEN;
-+ default:
-+ break;
-+ }
-+ break;
-+ default:
-+ break;
-+ }
-+ return 0;
-+}
-+
-+unsigned int
-+SECKEY_MLDSAPkcs11ParamsToLen(CK_ML_DSA_PARAMETER_SET_TYPE paramSet,
-+ SECKEYSizeType type)
-+{
-+ SECOidTag tag = SECKEY_MLDSAPkcs11ParamsToOidParams(paramSet);
-+ return SECKEY_MLDSAOidParamsToLen(tag, type);
-+}
-+
-+SECOidTag
-+SECKEY_MLDSAOidParamsFromLen(unsigned int len, SECKEYSizeType type)
-+{
-+ switch (type) {
-+ case SECKEYPubKeyType:
-+ switch (len) {
-+ case ML_DSA_44_PUBLICKEY_LEN:
-+ return SEC_OID_ML_DSA_44;
-+ case ML_DSA_65_PUBLICKEY_LEN:
-+ return SEC_OID_ML_DSA_65;
-+ case ML_DSA_87_PUBLICKEY_LEN:
-+ return SEC_OID_ML_DSA_87;
-+ default:
-+ break;
-+ }
-+ break;
-+ case SECKEYPrivKeyType:
-+ switch (len) {
-+ case ML_DSA_44_PRIVATEKEY_LEN:
-+ return SEC_OID_ML_DSA_44;
-+ case ML_DSA_65_PRIVATEKEY_LEN:
-+ return SEC_OID_ML_DSA_65;
-+ case ML_DSA_87_PRIVATEKEY_LEN:
-+ return SEC_OID_ML_DSA_87;
-+ default:
-+ break;
-+ }
-+ break;
-+ case SECKEYSignatureType:
-+ switch (len) {
-+ case ML_DSA_44_SIGNATURE_LEN:
-+ return SEC_OID_ML_DSA_44;
-+ case ML_DSA_65_SIGNATURE_LEN:
-+ return SEC_OID_ML_DSA_65;
-+ case ML_DSA_87_SIGNATURE_LEN:
-+ return SEC_OID_ML_DSA_87;
-+ default:
-+ break;
-+ }
-+ break;
-+ default:
-+ break;
-+ }
-+ return SEC_OID_UNKNOWN;
-+}
-+
-+/* make this function generic. multiple key types will be able to use
-+ * it (ml-kem, ml=dsa, shl-dsa, fn-dsa, etc. ) */
-+SECOidTag
-+SECKEY_GetParameterSet(const SECKEYPrivateKey *key)
-+{
-+ CK_ULONG paramSet = PK11_ReadULongAttribute(key->pkcs11Slot,
-+ key->pkcs11ID,
-+ CKA_PARAMETER_SET);
-+ if (paramSet == CK_UNAVAILABLE_INFORMATION) {
-+ return SEC_OID_UNKNOWN;
-+ }
-+ switch (key->keyType) {
-+ case mldsaKey:
-+ return SECKEY_MLDSAPkcs11ParamsToOidParams(paramSet);
-+ default:
-+ break;
-+ }
-+ return SEC_OID_UNKNOWN;
-+}
-+
- /* Create a DH key pair in any slot able to do so,
- ** This is a "session" (temporary), not "token" (permanent) key.
- ** Because of the high probability that this key will need to be moved to
- ** another token, and the high cost of moving "sensitive" keys, we attempt
- ** to create this key pair without the "sensitive" attribute, but revert to
- ** creating a "sensitive" key if necessary.
- */
- SECKEYPrivateKey *
-@@ -558,16 +712,21 @@ seckey_GetKeyType(SECOidTag tag)
- case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
- case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
- case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION:
- case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
- case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
- case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
- keyType = rsaKey;
- break;
-+ case SEC_OID_ML_DSA_44:
-+ case SEC_OID_ML_DSA_65:
-+ case SEC_OID_ML_DSA_87:
-+ keyType = mldsaKey;
-+ break;
- default:
- keyType = nullKey;
- }
- return keyType;
- }
-
- /* Function used to determine what kind of cert we are dealing with. */
- KeyType
-@@ -734,17 +893,29 @@ seckey_ExtractPublicKey(const CERTSubjec
- break;
- }
- pubk->u.ec.encoding = ECPoint_Undefined;
- rv = seckey_HasCurveOID(pubk);
- if (rv == SECSuccess) {
- return pubk;
- }
- break;
--
-+ case SEC_OID_ML_DSA_44:
-+ case SEC_OID_ML_DSA_65:
-+ case SEC_OID_ML_DSA_87:
-+ pubk->keyType = mldsaKey;
-+ pubk->u.mldsa.params = tag;
-+ /* key length should match the oid */
-+ if (newOs.len != SECKEY_MLDSAOidParamsToLen(tag, SECKEYPubKeyType)) {
-+ PORT_SetError(SEC_ERROR_INPUT_LEN);
-+ break;
-+ }
-+ /* newOs is already in the arena, we can just copy the data */
-+ pubk->u.mldsa.publicValue = newOs;
-+ return pubk;
- default:
- PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
- break;
- }
-
- SECKEY_DestroyPublicKey(pubk);
- return NULL;
- }
-@@ -1110,29 +1281,34 @@ SECKEY_PublicKeyStrengthInBits(const SEC
- case dhKey:
- bitSize = SECKEY_BigIntegerBitLength(&pubk->u.dh.prime);
- break;
- case ecKey:
- case edKey:
- case ecMontKey:
- bitSize = SECKEY_ECParamsToKeySize(&pubk->u.ec.DEREncodedParams);
- break;
-+ case mldsaKey:
-+ bitSize = SECKEY_MLDSAOidParamsToLen(pubk->u.mldsa.params,
-+ SECKEYPubKeyType)*8;
-+ break;
- default:
- PORT_SetError(SEC_ERROR_INVALID_KEY);
- break;
- }
- return bitSize;
- }
-
- unsigned
- SECKEY_PrivateKeyStrengthInBits(const SECKEYPrivateKey *privk)
- {
- unsigned bitSize = 0;
- SECItem params = { siBuffer, NULL, 0 };
- SECStatus rv;
-+ SECOidTag paramSet;
-
- if (!privk) {
- PORT_SetError(SEC_ERROR_INVALID_KEY);
- return 0;
- }
-
- /* interpret modulus length as key strength */
- switch (privk->keyType) {
-@@ -1172,23 +1348,27 @@ SECKEY_PrivateKeyStrengthInBits(const SE
- rv = PK11_ReadAttribute(privk->pkcs11Slot, privk->pkcs11ID,
- CKA_EC_PARAMS, NULL, ¶ms);
- if ((rv != SECSuccess) || (params.data == NULL)) {
- return 0;
- }
- bitSize = SECKEY_ECParamsToKeySize(¶ms);
- PORT_Free(params.data);
- return bitSize;
-+ case mldsaKey:
-+ paramSet = SECKEY_GetParameterSet(privk);
-+ return SECKEY_MLDSAOidParamsToLen(paramSet, SECKEYPrivKeyType)*8;
- default:
- break;
- }
- PORT_SetError(SEC_ERROR_INVALID_KEY);
- return 0;
- }
-
-+
- /* returns signature length in bytes (not bits) */
- unsigned
- SECKEY_SignatureLen(const SECKEYPublicKey *pubk)
- {
- unsigned size;
-
- switch (pubk->keyType) {
- case rsaKey:
-@@ -1204,16 +1384,19 @@ SECKEY_SignatureLen(const SECKEYPublicKe
- return pubk->u.dsa.params.subPrime.len * 2;
- case ecKey:
- case edKey:
- case ecMontKey:
- /* Get the base point order length in bits and adjust */
- size = SECKEY_ECParamsToBasePointOrderLen(
- &pubk->u.ec.DEREncodedParams);
- return ((size + 7) / 8) * 2;
-+ case mldsaKey:
-+ return SECKEY_MLDSAOidParamsToLen(pubk->u.mldsa.params,
-+ SECKEYSignatureType);
- default:
- break;
- }
- PORT_SetError(SEC_ERROR_INVALID_KEY);
- return 0;
- }
-
- SECKEYPrivateKey *
-@@ -1349,16 +1532,21 @@ SECKEY_CopyPublicKey(const SECKEYPublicK
- break;
- case nullKey:
- return copyk;
- case kyberKey:
- copyk->u.kyber.params = pubk->u.kyber.params;
- rv = SECITEM_CopyItem(arena, ©k->u.kyber.publicValue,
- &pubk->u.kyber.publicValue);
- break;
-+ case mldsaKey:
-+ copyk->u.mldsa.params = pubk->u.mldsa.params;
-+ rv = SECITEM_CopyItem(arena, ©k->u.mldsa.publicValue,
-+ &pubk->u.mldsa.publicValue);
-+ break;
- default:
- PORT_SetError(SEC_ERROR_INVALID_KEY);
- rv = SECFailure;
- break;
- }
- if (rv == SECSuccess)
- return copyk;
-
-@@ -1390,16 +1578,18 @@ SECKEY_EnforceKeySize(KeyType keyType, u
- case dhKey:
- case keaKey:
- opt = NSS_DH_MIN_KEY_SIZE;
- break;
- case ecKey:
- opt = NSS_ECC_MIN_KEY_SIZE;
- break;
- case nullKey:
-+ case mldsaKey:
-+ return SECSuccess; /* add policy later */
- default:
- PORT_SetError(SEC_ERROR_INVALID_KEY);
- return SECFailure;
- }
- PORT_Assert(opt != -1);
- rv = NSS_OptionGet(opt, &optVal);
- if (rv != SECSuccess) {
- return rv;
-@@ -1579,16 +1769,29 @@ SECKEY_ConvertToPublicKey(SECKEYPrivateK
- rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle,
- CKA_EC_POINT, arena, &pubk->u.ec.publicValue);
- if (rv != SECSuccess) {
- break;
- }
- }
- pubk->u.ec.encoding = ECPoint_Undefined;
- return pubk;
-+ case mldsaKey:
-+ pubKeyHandle = seckey_FindPublicKeyHandle(privk, pubk);
-+ if (pubKeyHandle == CK_INVALID_HANDLE)
-+ break;
-+ pubk->u.mldsa.params = SECKEY_GetParameterSet(privk);
-+ if (pubk->u.mldsa.params == SEC_OID_UNKNOWN) {
-+ break;
-+ }
-+ rv = PK11_ReadAttribute(privk->pkcs11Slot, pubKeyHandle,
-+ CKA_VALUE, arena, &pubk->u.mldsa.publicValue);
-+ if (rv != SECSuccess)
-+ break;
-+ return pubk;
- default:
- break;
- }
-
- /* must use Destroy public key here, because some paths create temporary
- * PKCS #11 objects which need to be freed */
- SECKEY_DestroyPublicKey(pubk);
- return NULL;
-@@ -1720,16 +1923,35 @@ seckey_CreateSubjectPublicKeyInfo_helper
- */
- spki->subjectPublicKey.len <<= 3;
- /*
- * We got a good one; return it.
- */
- return spki;
- }
- break;
-+ case mldsaKey:
-+ /* params == Algid for mldsaKey */
-+ rv = SECOID_SetAlgorithmID(arena, &spki->algorithm,
-+ pubk->u.mldsa.params, NULL);
-+ if (rv != SECSuccess) {
-+ break;
-+ }
-+ /* and key == spki */
-+ rv = SECITEM_CopyItem(arena, &spki->subjectPublicKey,
-+ &pubk->u.mldsa.publicValue);
-+ if (rv == SECSuccess) {
-+ /*
-+ * The stored value is supposed to be a BIT_STRING,
-+ * so convert the length.
-+ */
-+ spki->subjectPublicKey.len <<= 3;
-+ return spki;
-+ }
-+ break;
- case dhKey: /* later... */
-
- break;
- default:
- break;
- }
- } else {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
-@@ -2109,16 +2331,28 @@ SECKEY_ImportDERPublicKey(const SECItem
- rv = SEC_QuickDERDecodeItem(pubk->arena, pubk, SECKEY_DSAPublicKeyTemplate, &newDerKey);
- pubk->keyType = dsaKey;
- break;
- case CKK_DH:
- prepare_dh_pub_key_for_asn1(pubk);
- rv = SEC_QuickDERDecodeItem(pubk->arena, pubk, SECKEY_DHPublicKeyTemplate, &newDerKey);
- pubk->keyType = dhKey;
- break;
-+ case CKK_ML_DSA:
-+ pubk->keyType = mldsaKey;
-+ /* ml_dsa has no derencoding */
-+ pubk->u.mldsa.publicValue = newDerKey;
-+ pubk->u.mldsa.params = SECKEY_MLDSAOidParamsFromLen(newDerKey.len,
-+ SECKEYPubKeyType);
-+ if (pubk->u.mldsa.params == SEC_OID_UNKNOWN) {
-+ PORT_SetError(SEC_ERROR_BAD_KEY);
-+ rv = SECFailure;
-+ }
-+ break;
-+
- default:
- rv = SECFailure;
- break;
- }
-
- finish:
- if (rv != SECSuccess) {
- if (arena != NULL) {
-diff --git a/lib/cryptohi/secsign.c b/lib/cryptohi/secsign.c
---- a/lib/cryptohi/secsign.c
-+++ b/lib/cryptohi/secsign.c
-@@ -516,21 +516,28 @@ sec_DerSignData(PLArenaPool *arena, SECI
- default:
- algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST;
- break;
- }
- break;
- case ecKey:
- algID = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE;
- break;
-+ case mldsaKey:
-+ algID = SECKEY_GetParameterSet(pk);
-+ break;
- default:
-- PORT_SetError(SEC_ERROR_INVALID_KEY);
-- return SECFailure;
-+ algID = SEC_OID_UNKNOWN;
-+ break;
- }
- }
-+ if (algID == SEC_OID_UNKNOWN) {
-+ PORT_SetError(SEC_ERROR_INVALID_KEY);
-+ return SECFailure;
-+ }
-
- /* Sign input buffer */
- rv = sec_SignData(&it, buf, len, pk, algID, params);
- if (rv)
- goto loser;
-
- /* Fill out SignedData object */
- PORT_Memset(&sd, 0, sizeof(sd));
-@@ -579,32 +586,40 @@ SGN_Digest(SECKEYPrivateKey *privKey,
- PLArenaPool *arena = 0;
- SGNDigestInfo *di = 0;
- SECOidTag enctag;
- PRUint32 policyFlags;
- PRInt32 optFlags;
-
- result->data = 0;
-
-+
- if (NSS_OptionGet(NSS_KEY_SIZE_POLICY_FLAGS, &optFlags) != SECFailure) {
- if (optFlags & NSS_KEY_SIZE_POLICY_SIGN_FLAG) {
- rv = SECKEY_EnforceKeySize(privKey->keyType,
- SECKEY_PrivateKeyStrengthInBits(privKey),
- SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- }
- }
- /* check the policy on the hash algorithm */
- if ((NSS_GetAlgorithmPolicy(algtag, &policyFlags) == SECFailure) ||
- !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) {
- PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
- return SECFailure;
- }
-+
-+ if (privKey->keyType == mldsaKey) {
-+ /* whatever the input hash was, we now mark it
-+ * as the signature value since mldsaKey is a full
-+ * hash and sign */
-+ algtag = SECKEY_GetParameterSet(privKey);
-+ }
- /* check the policy on the encryption algorithm */
- enctag = sec_GetEncAlgFromSigAlg(
- SEC_GetSignatureAlgorithmOidTag(privKey->keyType, algtag));
- if ((enctag == SEC_OID_UNKNOWN) ||
- (NSS_GetAlgorithmPolicy(enctag, &policyFlags) == SECFailure) ||
- !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) {
- PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
- return SECFailure;
-@@ -714,16 +729,19 @@ SEC_GetSignatureAlgorithmOidTag(KeyType
- case SEC_OID_UNKNOWN: /* default for DSA if not specified */
- case SEC_OID_SHA256:
- sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST;
- break;
- default:
- break;
- }
- break;
-+ case mldsaKey:
-+ sigTag = hashAlgTag;
-+ break;
- case ecKey:
- switch (hashAlgTag) {
- case SEC_OID_SHA1:
- sigTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE;
- break;
- case SEC_OID_SHA224:
- sigTag = SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE;
- break;
-@@ -969,17 +987,16 @@ SEC_CreateSignatureAlgorithmParameters(P
- SECOidTag hashAlgTag,
- const SECItem *params,
- const SECKEYPrivateKey *key)
- {
- switch (signAlgTag) {
- case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
- return sec_CreateRSAPSSParameters(arena, result,
- hashAlgTag, params, key);
--
- default:
- if (params == NULL)
- return NULL;
- if (result == NULL)
- result = SECITEM_AllocItem(arena, NULL, 0);
- if (SECITEM_CopyItem(arena, result, params) != SECSuccess)
- return NULL;
- return result;
-diff --git a/lib/cryptohi/secvfy.c b/lib/cryptohi/secvfy.c
---- a/lib/cryptohi/secvfy.c
-+++ b/lib/cryptohi/secvfy.c
-@@ -13,17 +13,17 @@
- #include "secoid.h"
- #include "pk11func.h"
- #include "pkcs1sig.h"
- #include "secdig.h"
- #include "secerr.h"
- #include "keyi.h"
- #include "nss.h"
- #include "prenv.h"
--
-+#include "secmodti.h"
- /*
- ** Recover the DigestInfo from an RSA PKCS#1 signature.
- **
- ** If givenDigestAlg != SEC_OID_UNKNOWN, copy givenDigestAlg to digestAlgOut.
- ** Otherwise, parse the DigestInfo structure and store the decoded digest
- ** algorithm into digestAlgOut.
- **
- ** Store the encoded DigestInfo into digestInfo.
-@@ -185,16 +185,19 @@ checkedSignatureLen(const SECKEYPublicKe
- maxSigLen = (RSA_MAX_MODULUS_BITS + 7) / 8;
- break;
- case dsaKey:
- maxSigLen = DSA_MAX_SIGNATURE_LEN;
- break;
- case ecKey:
- maxSigLen = 2 * MAX_ECKEY_LEN;
- break;
-+ case mldsaKey:
-+ maxSigLen = MAX_ML_DSA_SIGNATURE_LEN;
-+ break;
- default:
- PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
- return 0;
- }
- PORT_Assert(maxSigLen <= MAX_SIGNATURE_LEN);
- if (sigLen > maxSigLen) {
- PORT_SetError(SEC_ERROR_INVALID_KEY);
- return 0;
-@@ -289,16 +292,20 @@ sec_GetEncAlgFromSigAlg(SECOidTag sigAlg
- case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
- case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE:
- case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
- case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
- case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
- case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
- case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
- return SEC_OID_ANSIX962_EC_PUBLIC_KEY;
-+ case SEC_OID_ML_DSA_44:
-+ case SEC_OID_ML_DSA_65:
-+ case SEC_OID_ML_DSA_87:
-+ return sigAlg;
- /* we don't implement MD4 hashes */
- case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
- default:
- PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
- break;
- }
- return SEC_OID_UNKNOWN;
- }
-@@ -392,16 +399,20 @@ sec_GetCombinedMech(SECOidTag encalg, SE
- case SEC_OID_PKCS1_RSA_ENCRYPTION:
- return sec_RSAPKCS1GetCombinedMech(hashalg);
- case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
- return sec_RSAPSSGetCombinedMech(hashalg);
- case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
- return sec_ECDSAGetCombinedMech(hashalg);
- case SEC_OID_ANSIX9_DSA_SIGNATURE:
- return sec_DSAGetCombinedMech(hashalg);
-+ case SEC_OID_ML_DSA_44:
-+ case SEC_OID_ML_DSA_65:
-+ case SEC_OID_ML_DSA_87:
-+ return CKM_ML_DSA; /* ignore hashalg */
- default:
- break;
- }
- return CKM_INVALID_MECHANISM;
- }
-
- /*
- * Pulls the hash algorithm, signing algorithm, and key type out of a
-@@ -425,16 +436,17 @@ sec_DecodeSigAlg(const SECKEYPublicKey *
- const SECItem *param, SECOidTag *encalgp, SECOidTag *hashalg,
- CK_MECHANISM_TYPE *mechp, SECItem *mechparamsp)
- {
- unsigned int len;
- PLArenaPool *arena;
- SECStatus rv;
- SECItem oid;
- SECOidTag encalg;
-+ PRBool comboRequired = PR_TRUE;
- char *evp;
-
- PR_ASSERT(hashalg != NULL);
- PR_ASSERT(encalgp != NULL);
- PR_ASSERT(mechp != NULL);
- /* Get the expected combined mechanism from the signature OID
- * We'll override it in the table below if necessary */
- *mechp = PK11_AlgtagToMechanism(sigAlg);
-@@ -583,16 +595,23 @@ sec_DecodeSigAlg(const SECKEYPublicKey *
- }
- /* only accept hash algorithms */
- if (HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) {
- /* error set by HASH_GetHashTypeByOidTag */
- return SECFailure;
- }
- *mechp = sec_ECDSAGetCombinedMech(*hashalg);
- break;
-+ case SEC_OID_ML_DSA_44:
-+ case SEC_OID_ML_DSA_65:
-+ case SEC_OID_ML_DSA_87:
-+ comboRequired = PR_TRUE;
-+ *hashalg = sigAlg;
-+ /* decode params to get the sign context and set (mechparamsp) */
-+ break;
- /* we don't implement MD4 hashes */
- case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
- default:
- *mechp = CKM_INVALID_MECHANISM;
- PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
- return SECFailure;
- }
-
-@@ -606,26 +625,31 @@ sec_DecodeSigAlg(const SECKEYPublicKey *
- /* for testing, we want to be able to turn off combo signatures to
- * 1) make sure the fallback code is working correctly so we know
- * we can handle cases where the fallback doesn't work.
- * 2) make sure that the combo code is compatible with the non-combo
- * versions.
- * We know if we are signing or verifying based on the value of 'key'.
- * Since key is a public key, then it's set to NULL for signing */
- evp = PR_GetEnvSecure("NSS_COMBO_SIGNATURES");
-- if (evp) {
-+ if (evp && !comboRequired) {
- if (PORT_Strcasecmp(evp, "none") == 0) {
- *mechp = CKM_INVALID_MECHANISM;
- } else if (key && (PORT_Strcasecmp(evp, "signonly") == 0)) {
- *mechp = CKM_INVALID_MECHANISM;
- } else if (!key && (PORT_Strcasecmp(evp, "vfyonly") == 0)) {
- *mechp = CKM_INVALID_MECHANISM;
- }
- /* anything else we take as use combo, which is the default */
- }
-+ /* now enforce the combo requires requirement */
-+ if (comboRequired && (*mechp == CKM_INVALID_MECHANISM)) {
-+ SECITEM_FreeItem(mechparamsp, PR_FALSE);
-+ return SECFailure;
-+ }
-
- return SECSuccess;
- }
-
- SECStatus
- vfy_ImportPublicKey(VFYContext *cx)
- {
- PK11SlotInfo *slot;
-@@ -805,17 +829,19 @@ vfy_CreateContext(const SECKEYPublicKey
- rv = vfy_SetPKCS11SigFromX509Sig(cx, sig);
- }
- if (rv != SECSuccess) {
- goto loser;
- }
- }
-
- /* check hash alg again, RSA may have changed it.*/
-- if (HASH_GetHashTypeByOidTag(cx->hashAlg) == HASH_AlgNULL) {
-+ /* combo mechs set the hash to the sigAlg */
-+ if ((cx->hashAlg != cx->encAlg) &&
-+ (HASH_GetHashTypeByOidTag(cx->hashAlg) == HASH_AlgNULL)) {
- /* error set by HASH_GetHashTypeByOidTag */
- goto loser;
- }
- /* check the policy on the hash algorithm. Do this after
- * the rsa decode because some uses of this function get hash implicitly
- * from the RSA signature itself. */
- if ((NSS_GetAlgorithmPolicy(cx->hashAlg, &policyFlags) == SECFailure) ||
- !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) {
-@@ -1087,16 +1113,22 @@ vfy_VerifyDigest(const SECItem *digest,
- rv = SECFailure;
- break;
- }
- rv = PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx);
- if (rv != SECSuccess) {
- PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
- }
- break;
-+ case mldsaKey:
-+ rv = PK11_Verify(cx->key, sig, (SECItem *)digest, cx->wincx);
-+ if (rv != SECSuccess) {
-+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
-+ }
-+ break;
- default:
- break;
- }
- VFY_DestroyContext(cx, PR_TRUE);
- }
- return rv;
- }
-
-diff --git a/lib/freebl/Makefile b/lib/freebl/Makefile
---- a/lib/freebl/Makefile
-+++ b/lib/freebl/Makefile
-@@ -603,16 +603,71 @@ ifndef NSS_DISABLE_KYBER
- KYBER_PQCRYSTALS = kyber-pqcrystals-ref.c
- endif
-
- VERIFIED_SRCS += Hacl_Hash_SHA3.c Hacl_P256.c Hacl_P384.c Hacl_P521.c libcrux_mlkem768_portable.c libcrux_mlkem_portable.c libcrux_core.c
- VERIFIED_SRCS += libcrux_mlkem1024_portable.c
- VERIFIED_SRCS += Hacl_Ed25519.c
- VERIFIED_SRCS += Hacl_Curve25519_51.c
-
-+ifdef NSS_ENABLE_ML_DSA
-+ifdef ML_DSA_OQS
-+INCLUDES += -Ioqs
-+ML_DSA_SRCS += ml_dsa_44_ref_ntt.c
-+ML_DSA_SRCS += ml_dsa_44_ref_packing.c
-+ML_DSA_SRCS += ml_dsa_44_ref_poly.c
-+ML_DSA_SRCS += ml_dsa_44_ref_polyvec.c
-+ML_DSA_SRCS += ml_dsa_44_ref_reduce.c
-+ML_DSA_SRCS += ml_dsa_44_ref_rounding.c
-+ML_DSA_SRCS += ml_dsa_44_ref_sign.c
-+ML_DSA_SRCS += ml_dsa_44_ref_symmetric-shake.c
-+ML_DSA_SRCS += ml_dsa_65_ref_ntt.c
-+ML_DSA_SRCS += ml_dsa_65_ref_packing.c
-+ML_DSA_SRCS += ml_dsa_65_ref_poly.c
-+ML_DSA_SRCS += ml_dsa_65_ref_polyvec.c
-+ML_DSA_SRCS += ml_dsa_65_ref_reduce.c
-+ML_DSA_SRCS += ml_dsa_65_ref_rounding.c
-+ML_DSA_SRCS += ml_dsa_65_ref_sign.c
-+ML_DSA_SRCS += ml_dsa_65_ref_symmetric-shake.c
-+ML_DSA_SRCS += ml_dsa_87_ref_ntt.c
-+ML_DSA_SRCS += ml_dsa_87_ref_packing.c
-+ML_DSA_SRCS += ml_dsa_87_ref_poly.c
-+ML_DSA_SRCS += ml_dsa_87_ref_polyvec.c
-+ML_DSA_SRCS += ml_dsa_87_ref_reduce.c
-+ML_DSA_SRCS += ml_dsa_87_ref_rounding.c
-+ML_DSA_SRCS += ml_dsa_87_ref_sign.c
-+ML_DSA_SRCS += ml_dsa_87_ref_symmetric-shake.c
-+else
-+INCLUDES += -Ileancrypto
-+ML_DSA_SRCS += ml_dsa_44_ntt.c
-+ML_DSA_SRCS += ml_dsa_44_poly.c
-+ML_DSA_SRCS += ml_dsa_44_rounding.c
-+ML_DSA_SRCS += ml_dsa_44_signature_c.c
-+ML_DSA_SRCS += ml_dsa_44_signature_helper.c
-+ML_DSA_SRCS += ml_dsa_65_ntt.c
-+ML_DSA_SRCS += ml_dsa_65_poly.c
-+ML_DSA_SRCS += ml_dsa_65_rounding.c
-+ML_DSA_SRCS += ml_dsa_65_signature_c.c
-+ML_DSA_SRCS += ml_dsa_65_signature_helper.c
-+ML_DSA_SRCS += ml_dsa_87_ntt.c
-+ML_DSA_SRCS += ml_dsa_87_poly.c
-+ML_DSA_SRCS += ml_dsa_87_rounding.c
-+ML_DSA_SRCS += ml_dsa_87_signature_c.c
-+ML_DSA_SRCS += ml_dsa_87_signature_helper.c
-+ML_DSA_SRCS += signature_domain_separation.c
-+ML_DSA_SRCS += mldsa_api.c
-+ML_DSA_SRCS += mldsa_zetas.c
-+#ML_DSA_SRCS += ml_dsa_44_debug.c
-+#ML_DSA_SRCS += ml_dsa_65_debug.c
-+#ML_DSA_SRCS += ml_dsa_87_debug.c
-+endif
-+endif
-+
-+
-+
- # Bug 1918767 / Bug 1918711 - by setting KRML_MUSTINLINE=inline here, we
- # avoid it being defined to `inline __forceinline` (for msvc) or `inline
- # __attribute__((always_inline))` (for gcc/clang) in
- # verified/karamel/include/krml/internal/target.h. These other
- # configurations can cause excessive stack usage.
- DEFINES += -DKRML_MUSTINLINE=inline
-
- ifeq (,$(filter-out x86_64 aarch64,$(CPU_ARCH)))
-@@ -640,18 +695,18 @@ include $(CORE_DEPTH)/coreconf/rules.mk
- #######################################################################
-
-
- rijndael_tables:
- $(CC) -o $(OBJDIR)/make_rijndael_tab rijndael_tables.c \
- $(DEFINES) $(INCLUDES) $(OBJDIR)/libfreebl.a
- $(OBJDIR)/make_rijndael_tab
-
--vpath %.h mpi ecl verified deprecated
--vpath %.c mpi ecl verified deprecated
-+vpath %.h mpi ecl verified oqs leancrypto deprecated
-+vpath %.c mpi ecl verified oqs leancrypto deprecated
- vpath %.S mpi ecl
- vpath %.s mpi ecl
- vpath %.asm mpi ecl
- INCLUDES += -Impi -Iecl -Iverified -Iverified/internal -Iverified/karamel/include -Iverified/karamel/krmllib/dist/minimal -Iverified/eurydice -Ideprecated
-
-
- DEFINES += -DMP_API_COMPATIBLE
-
-diff --git a/lib/freebl/blapi.h b/lib/freebl/blapi.h
---- a/lib/freebl/blapi.h
-+++ b/lib/freebl/blapi.h
-@@ -443,17 +443,17 @@ JPAKE_Round2(PLArenaPool *arena, const S
- /* K = (B/g^(x2*x4*s))^x2 (mod p)
- *
- * K will be allocated in the arena. The arena is *not* optional so do not pass
- * NULL for the arena parameter. The arena should be zeroed when it is freed.
- */
- SECStatus
- JPAKE_Final(PLArenaPool *arena, const SECItem *p, const SECItem *q,
- const SECItem *x2, const SECItem *gx4, const SECItem *x2s,
-- const SECItem *B, SECItem *K);
-+ const SECItem *B_, SECItem *K_);
-
- /******************************************************
- ** Elliptic Curve algorithms
- */
-
- /* Generates a public and private key, both of which are encoded
- ** in a single ECPrivateKey struct. Params is input, privKey are
- ** output.
-@@ -1814,18 +1814,18 @@ PQG_ParamGenSeedLen(
- * pick a default value (typically the smallest secure value for these
- * variables).
- *
- * The verify parameters will conform to FIPS186-3 using the smallest
- * permissible hash for the key strength.
- */
- extern SECStatus
- PQG_ParamGenV2(
-- unsigned int L, /* input : determines length of P. */
-- unsigned int N, /* input : determines length of Q. */
-+ unsigned int L_, /* input : determines length of P. */
-+ unsigned int N_, /* input : determines length of Q. */
- unsigned int seedBytes, /* input : length of seed in bytes.*/
- PQGParams **pParams, /* output: P Q and G returned here */
- PQGVerify **pVfy); /* output: counter and seed. */
-
- /* Test PQGParams for validity as DSS PQG values.
- * If vfy is non-NULL, test PQGParams to make sure they were generated
- * using the specified seed, counter, and h values.
- *
-@@ -1942,11 +1942,27 @@ extern SECStatus ED_VerifyMessage(ECPubl
- */
- extern SECStatus ED_DerivePublicKey(const SECItem *privateKey, SECItem *publicKey);
-
- extern SECStatus X25519_DerivePublicKey(const SECItem *privateKey, SECItem *publicKey);
-
- /* Public key derivation is supported only for the curves supporting pt_mul method. */
- extern SECStatus EC_DerivePublicKey(const SECItem *privateKey, const ECParams *ecParams, SECItem *publicKey);
-
-+/*
-+ * ML_DSA functions
-+ */
-+SECStatus MLDSA_NewKey(CK_ML_DSA_PARAMETER_SET_TYPE paramSet, SECItem *seed,
-+ MLDSAPrivateKey *privKey, MLDSAPublicKey *pubKey);
-+SECStatus MLDSA_SignInit(MLDSAPrivateKey *key, CK_HEDGE_TYPE hedgeType,
-+ const SECItem *sgnCtx, MLDSAContext **ctx);
-+SECStatus MLDSA_SignUpdate(MLDSAContext *ctx, const SECItem *data);
-+SECStatus MLDSA_SignFinal(MLDSAContext *ctx, SECItem *signature);
-+
-+SECStatus MLDSA_VerifyInit(MLDSAPublicKey *key, const SECItem *sgnCtx,
-+ MLDSAContext **ctx);
-+SECStatus MLDSA_VerifyUpdate(MLDSAContext *ctx, const SECItem *data) ;
-+SECStatus MLDSA_VerifyFinal(MLDSAContext *ctx, const SECItem *signature);
-+
-+
- SEC_END_PROTOS
-
- #endif /* _BLAPI_H_ */
-diff --git a/lib/freebl/blapit.h b/lib/freebl/blapit.h
---- a/lib/freebl/blapit.h
-+++ b/lib/freebl/blapit.h
-@@ -7,16 +7,18 @@
-
- #ifndef _BLAPIT_H_
- #define _BLAPIT_H_
-
- #include "seccomon.h"
- #include "prlink.h"
- #include "plarena.h"
- #include "ecl-exp.h"
-+#include "pkcs11t.h"
-+#include "ml_dsat.h"
-
- /* RC2 operation modes */
- #define NSS_RC2 0
- #define NSS_RC2_CBC 1
-
- /* RC5 operation modes */
- #define NSS_RC5 0
- #define NSS_RC5_CBC 1
-@@ -150,18 +152,18 @@ typedef int __BLAPI_DEPRECATED __attribu
- */
- #define RSA_MIN_MODULUS_BITS 128
- #define RSA_MAX_MODULUS_BITS 16384
- #define RSA_MAX_EXPONENT_BITS 64
- #define DH_MIN_P_BITS 128
- #define DH_MAX_P_BITS 16384
-
- /* max signature for all our supported signatures */
--/* currently RSA is the biggest */
--#define MAX_SIGNATURE_LEN ((RSA_MAX_MODULUS_BITS + 7) / 8)
-+/* currently ML-DSA is the biggest */
-+#define MAX_SIGNATURE_LEN MAX_ML_DSA_SIGNATURE_LEN
-
- /*
- * The FIPS 186-1 algorithm for generating primes P and Q allows only 9
- * distinct values for the length of P, and only one value for the
- * length of Q.
- * The algorithm uses a variable j to indicate which of the 9 lengths
- * of P is to be used.
- * The following table relates j to the lengths of P and Q in bits.
-@@ -356,16 +358,41 @@ typedef struct DSAPublicKeyStr DSAPublic
-
- struct DSAPrivateKeyStr {
- PQGParams params;
- SECItem publicValue;
- SECItem privateValue;
- };
- typedef struct DSAPrivateKeyStr DSAPrivateKey;
-
-+
-+/* ML DSA structures */
-+typedef struct MLDSAPrivateKeyStr MLDSAPrivateKey;
-+typedef struct MLDSAPublicKeyStr MLDSAPublicKey;
-+typedef struct MLDSAContextStr MLDSAContext;
-+
-+/* if we don't actually have DSA support, don't expose the
-+ * ML_DSA key structures which have defines in the ml_dsa
-+ * headers */
-+#ifdef NSS_ENABLE_ML_DSA
-+struct MLDSAPrivateKeyStr {
-+ CK_ML_DSA_PARAMETER_SET_TYPE paramSet;
-+ unsigned char keyVal[MAX_ML_DSA_PRIVATE_KEY_LEN];
-+ unsigned int keyValLen;
-+ unsigned char seed[ML_DSA_SEED_LEN];
-+ unsigned int seedLen;
-+};
-+
-+struct MLDSAPublicKeyStr {
-+ CK_ML_DSA_PARAMETER_SET_TYPE paramSet;
-+ unsigned char keyVal[MAX_ML_DSA_PUBLIC_KEY_LEN];
-+ unsigned int keyValLen;
-+};
-+#endif
-+
- /***************************************************************************
- ** Diffie-Hellman Public and Private Key and related structures
- ** Structure member names suggested by PKCS#3.
- */
-
- struct DHParamsStr {
- PLArenaPool *arena;
- SECItem prime; /* p */
-@@ -385,16 +412,18 @@ struct DHPrivateKeyStr {
- PLArenaPool *arena;
- SECItem prime;
- SECItem base;
- SECItem publicValue;
- SECItem privateValue;
- };
- typedef struct DHPrivateKeyStr DHPrivateKey;
-
-+
-+
- /***************************************************************************
- ** Data structures used for elliptic curve parameters and
- ** public and private keys.
- */
-
- /*
- ** The ECParams data structures can encode elliptic curve
- ** parameters for both GFp and GF2m curves.
-diff --git a/lib/freebl/ldvector.c b/lib/freebl/ldvector.c
---- a/lib/freebl/ldvector.c
-+++ b/lib/freebl/ldvector.c
-@@ -444,16 +444,26 @@ static const struct FREEBLVectorStr vect
- ED_DerivePublicKey,
- /* End of version 3.028 */
-
- X25519_DerivePublicKey,
- /* End of version 3.029 */
-
- EC_DerivePublicKey,
- /* End of version 3.030 */
-+
-+ MLDSA_NewKey,
-+ MLDSA_SignInit,
-+ MLDSA_SignUpdate,
-+ MLDSA_SignFinal,
-+ MLDSA_VerifyInit,
-+ MLDSA_VerifyUpdate,
-+ MLDSA_VerifyFinal,
-+ /* End of version 3.031 */
-+
- };
-
- const FREEBLVector*
- FREEBL_GetVector(void)
- {
- #ifdef FREEBL_NO_DEPEND
- SECStatus rv;
- #endif
-diff --git a/lib/freebl/leancrypto/alignment.h b/lib/freebl/leancrypto/alignment.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/alignment.h
-@@ -0,0 +1,68 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#ifndef ALIGNMENT_H
-+#define ALIGNMENT_H
-+
-+#include "ext_headers.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#if defined(__GNUC__)
-+#define __align(x) __attribute__((aligned(x)))
-+#elif defined(_MSC_VER)
-+//#define __align(x) __declspec(align(x))
-+#define __align(x) __attribute__((aligned(x)))
-+#elif defined(__ARMCC_VERSION)
-+/* Nothing, the used macro is known to the compiler */
-+#else
-+#define __align(x)
-+#endif
-+
-+#define ALIGNED_UINT8_COEFFS(N) N
-+#define ALIGNED_UINT8_UINT64(N) ((N + 7) / 8)
-+
-+#define BUF_ALIGNED_UINT8_UINT64(N) \
-+ union { \
-+ uint8_t coeffs[ALIGNED_UINT8_COEFFS(N)]; \
-+ uint64_t vec[ALIGNED_UINT8_UINT64(N)]; \
-+ }
-+
-+static inline int aligned(const uint8_t *ptr, uint32_t alignmask)
-+{
-+ if ((uintptr_t)ptr & alignmask)
-+ return 0;
-+ return 1;
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* ALIGNMENT_H */
-diff --git a/lib/freebl/leancrypto/atomic.h b/lib/freebl/leancrypto/atomic.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/atomic.h
-@@ -0,0 +1,248 @@
-+/*
-+ * Copyright (C) 2018 - 2025, Stephan Mueller
-+ *
-+ * License: see COPYING file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef _ATOMIC_H
-+#define _ATOMIC_H
-+
-+#ifndef LINUX_KERNEL
-+
-+/*
-+ * Atomic operations only work on:
-+ * GCC >= 4.1
-+ * Clang / LLVM
-+ */
-+
-+/**
-+ * Atomic type and operations equivalent to the Linux kernel.
-+ */
-+typedef struct {
-+ volatile int counter;
-+} atomic_t;
-+
-+/**
-+ * Memory barrier
-+ */
-+static inline void mb(void)
-+{
-+ __sync_synchronize();
-+}
-+
-+#define ATOMIC_INIT(i) { (i) }
-+
-+/**
-+ * Read atomic variable
-+ * @param v atomic variable
-+ * @return variable content
-+ */
-+static inline int atomic_read(const atomic_t *v)
-+{
-+ int i;
-+
-+ mb();
-+ i = ((v)->counter);
-+ mb();
-+
-+ return i;
-+}
-+
-+/**
-+ * Set atomic variable
-+ * @param v atomic variable
-+ * @param i value to be set
-+ */
-+static inline void atomic_set(atomic_t *v, int i)
-+{
-+ mb();
-+ ((v)->counter) = i;
-+ mb();
-+}
-+
-+/**
-+ * Atomic add operation
-+ * @param i integer value to add
-+ * @param v atomic variable
-+ * @return variable content after operation
-+ */
-+static inline int atomic_add(int i, atomic_t *v)
-+{
-+ return __sync_add_and_fetch(&v->counter, i);
-+}
-+
-+/**
-+ * Atomic add value from variable and test for zero
-+ * @param i integer value to add
-+ * @param v atomic variable
-+ * @return true if the result is zero, or false for all other cases.
-+ */
-+static inline int atomic_add_and_test(int i, atomic_t *v)
-+{
-+ return !(__sync_add_and_fetch(&v->counter, i));
-+}
-+
-+/**
-+ * Atomic increment by 1
-+ * @param v atomic variable
-+ * @return variable content after operation
-+ */
-+static inline int atomic_inc(atomic_t *v)
-+{
-+ return atomic_add(1, v);
-+}
-+
-+/**
-+ * Atomic increment and test for zero
-+ * @param v pointer of type atomic_t
-+ * @return true if the result is zero, or false for all other cases.
-+ */
-+static inline int atomic_inc_and_test(atomic_t *v)
-+{
-+ return atomic_add_and_test(1, v);
-+}
-+
-+/**
-+ * Atomic subtract operation
-+ * @param i integer value to subtract
-+ * @param v atomic variable
-+ * @return variable content after operation
-+ */
-+static inline int atomic_sub(int i, atomic_t *v)
-+{
-+ return __sync_sub_and_fetch(&v->counter, i);
-+}
-+
-+/**
-+ * Atomic subtract value from variable and test for zero
-+ * @param i integer value to subtract
-+ * @param v atomic variable
-+ * @return true if the result is zero, or false for all other cases.
-+ */
-+static inline int atomic_sub_and_test(int i, atomic_t *v)
-+{
-+ return !(__sync_sub_and_fetch(&v->counter, i));
-+}
-+
-+/**
-+ * Atomic decrement by 1
-+ * @param v atomic variable
-+ * @return variable content after operation
-+ */
-+static inline int atomic_dec(atomic_t *v)
-+{
-+ return atomic_sub(1, v);
-+}
-+
-+/**
-+ * Atomic decrement by 1 and test for zero
-+ * @param v atomic variable
-+ * @return true if the result is zero, or false for all other cases.
-+ */
-+static inline int atomic_dec_and_test(atomic_t *v)
-+{
-+ return atomic_sub_and_test(1, v);
-+}
-+
-+/**
-+ * Atomic or operation
-+ * @param i integer value to or
-+ * @param v atomic variable
-+ * @return variable content after operation
-+ */
-+static inline int atomic_or(int i, atomic_t *v)
-+{
-+ return __sync_or_and_fetch(&v->counter, i);
-+}
-+
-+/**
-+ * Atomic xor operation
-+ * @param i integer value to xor
-+ * @param v atomic variable
-+ * @return variable content after operation
-+ */
-+static inline int atomic_xor(int i, atomic_t *v)
-+{
-+ return __sync_xor_and_fetch(&v->counter, i);
-+}
-+
-+/**
-+ * Atomic and operation
-+ * @param i integer value to and
-+ * @param v atomic variable
-+ * @return variable content after operation
-+ */
-+static inline int atomic_and(int i, atomic_t *v)
-+{
-+ return __sync_and_and_fetch(&v->counter, i);
-+}
-+
-+#ifdef __clang__
-+#pragma clang diagnostic push
-+#pragma clang diagnostic ignored "-Wsync-fetch-and-nand-semantics-changed"
-+#endif
-+/**
-+ * Atomic nand operation
-+ * @param i integer value to nand
-+ * @param v atomic variable
-+ * @return variable content after operation
-+ */
-+static inline int atomic_nand(int i, atomic_t *v)
-+{
-+ return __sync_nand_and_fetch(&v->counter, i);
-+}
-+#ifdef __clang__
-+#pragma clang diagnostic pop
-+#endif
-+
-+/**
-+ * Atomic compare and exchange operation (if current value of atomic
-+ * variable is equal to the old value, set the new value)
-+ * @param v atomic variable
-+ * @param old integer value to compare with
-+ * @param new integer value to set atomic variable to
-+ * @return original value if comparison is successful and new was written
-+ * To verify that the exchange was successful, the caller must compare
-+ * the return value with the old value.
-+ */
-+static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
-+{
-+ return __sync_val_compare_and_swap(&v->counter, old, new);
-+}
-+
-+/**
-+ * Atomic operation with a caller-provided function to derive the new
-+ * value from the old value. Note, the caller-provided function may be called
-+ * multiple times.
-+ *
-+ * @param v atomic variable
-+ * @param data parameter that is given to the check function to maintain a state
-+ * @param check_func Function that returns the new value to be set. The function
-+ * is invoked with the old value as input parameter.
-+ */
-+static inline void atomic_update_with_func(atomic_t *v, void *data,
-+ int (*check_func)(void *data,
-+ int old))
-+{
-+ int old;
-+
-+ do {
-+ old = atomic_read(v);
-+ } while (atomic_cmpxchg(v, old, check_func(data, old)) != old);
-+}
-+
-+#endif /* LINUX_KERNEL */
-+#endif /* _ATOMIC_H */
-diff --git a/lib/freebl/leancrypto/atomic_bool.h b/lib/freebl/leancrypto/atomic_bool.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/atomic_bool.h
-@@ -0,0 +1,107 @@
-+/*
-+ * Copyright (C) 2018 - 2025, Stephan Mueller
-+ *
-+ * License: see COPYING file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef _ATOMIC_BOOL_H
-+#define _ATOMIC_BOOL_H
-+
-+#include "bool.h"
-+
-+/*
-+ * Atomic operations only work on:
-+ * GCC >= 4.1
-+ * Clang / LLVM
-+ */
-+
-+/**
-+ * Atomic type and operations equivalent to the Linux kernel.
-+ */
-+typedef struct {
-+ volatile bool counter;
-+} atomic_bool_t;
-+
-+/**
-+ * Memory barrier
-+ */
-+static inline void atomic_bool_mb(void)
-+{
-+ __sync_synchronize();
-+}
-+
-+#define ATOMIC_BOOL_INIT(i) { (i) }
-+
-+/**
-+ * Read atomic variable
-+ * @param v atomic variable
-+ * @return variable content
-+ */
-+static inline bool atomic_bool_read(const atomic_bool_t *v)
-+{
-+ bool i;
-+
-+ atomic_bool_mb();
-+ i = ((v)->counter);
-+ atomic_bool_mb();
-+
-+ return i;
-+}
-+
-+/**
-+ * Set atomic variable
-+ * @param i value to be set
-+ * @param v atomic variable
-+ */
-+static inline void atomic_bool_set(bool i, atomic_bool_t *v)
-+{
-+ atomic_bool_mb();
-+ ((v)->counter) = i;
-+ atomic_bool_mb();
-+}
-+
-+/**
-+ * Set atomic variable to true
-+ * @param v atomic variable
-+ */
-+static inline void atomic_bool_set_true(atomic_bool_t *v)
-+{
-+ atomic_bool_set(true, v);
-+}
-+
-+/**
-+ * Set atomic variable to false
-+ * @param v atomic variable
-+ */
-+static inline void atomic_bool_set_false(atomic_bool_t *v)
-+{
-+ atomic_bool_set(false, v);
-+}
-+
-+/**
-+ * Atomic compare and exchange operation (if current value of atomic
-+ * variable is equal to the old value, set the new value)
-+ * @param v atomic variable
-+ * @param old integer value to compare with
-+ * @param new integer value to set atomic variable to
-+ * @return true if comparison is successful and new was written
-+ */
-+static inline int atomic_bool_cmpxchg(atomic_bool_t *v, bool old, bool new)
-+{
-+ return __sync_bool_compare_and_swap(&v->counter, old, new);
-+}
-+
-+#endif /* _ATOMIC_BOOL_H */
-diff --git a/lib/freebl/leancrypto/binhexbin.h b/lib/freebl/leancrypto/binhexbin.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/binhexbin.h
-@@ -0,0 +1,51 @@
-+/*
-+ * Copyright (C) 2018 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef _BINHEXBIN_H
-+#define _BINHEXBIN_H
-+
-+#include "ext_headers.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+void hex2bin(const char *hex, const size_t hexlen, uint8_t *bin,
-+ const size_t binlen);
-+int hex2bin_alloc(const char *hex, const size_t hexlen, uint8_t **bin,
-+ size_t *binlen);
-+int bin2hex_alloc(const uint8_t *bin, const size_t binlen, char **hex,
-+ size_t *hexlen);
-+void bin2print(const unsigned char *bin, const size_t binlen, FILE *out,
-+ const char *explanation);
-+void bin2hex(const uint8_t *bin, const size_t binlen, char *hex,
-+ const size_t hexlen, const int u);
-+
-+int bin2hex_html(const char *str, const size_t strlen, char *html,
-+ const size_t htmllen);
-+int bin2hex_html_from_url(const char *str, const size_t strlen, char *html,
-+ const size_t htmllen);
-+int bin2hex_html_alloc(const char *str, const size_t strlen, char **html,
-+ size_t *htmllen);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* _BINHEXBIN_H */
-diff --git a/lib/freebl/leancrypto/bitshift.h b/lib/freebl/leancrypto/bitshift.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/bitshift.h
-@@ -0,0 +1,83 @@
-+/* Conversion of a pointer value to an integer
-+ *
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef BITSHIFT_H
-+#define BITSHIFT_H
-+
-+#include "bitshift_le.h"
-+#include "bitshift_be.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-+
-+static inline uint64_t ptr_to_64(const uint8_t *p)
-+{
-+ return ptr_to_be64(p);
-+}
-+
-+static inline uint32_t ptr_to_32(const uint8_t *p)
-+{
-+ return ptr_to_be32(p);
-+}
-+
-+static inline void val64_to_ptr(uint8_t *p, const uint64_t value)
-+{
-+ be64_to_ptr(p, value);
-+}
-+
-+static inline void val32_to_ptr(uint8_t *p, const uint32_t value)
-+{
-+ be32_to_ptr(p, value);
-+}
-+
-+#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-+
-+static inline uint64_t ptr_to_64(const uint8_t *p)
-+{
-+ return ptr_to_le64(p);
-+}
-+
-+static inline uint32_t ptr_to_32(const uint8_t *p)
-+{
-+ return ptr_to_le32(p);
-+}
-+
-+static inline void val64_to_ptr(uint8_t *p, const uint64_t value)
-+{
-+ le64_to_ptr(p, value);
-+}
-+
-+static inline void val32_to_ptr(uint8_t *p, const uint32_t value)
-+{
-+ le32_to_ptr(p, value);
-+}
-+
-+#else
-+#error "Endianess not defined"
-+#endif
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* BITSHIFT_H */
-diff --git a/lib/freebl/leancrypto/bitshift_be.h b/lib/freebl/leancrypto/bitshift_be.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/bitshift_be.h
-@@ -0,0 +1,62 @@
-+/*
-+ * Copyright (C) 2020 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef BITSHIFT_BE_H
-+#define BITSHIFT_BE_H
-+
-+#include "ext_headers.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/*
-+ * Conversion of Big-Endian representations in byte streams - the data
-+ * representation in the integer values is the host representation.
-+ */
-+static inline uint32_t ptr_to_be32(const uint8_t *p)
-+{
-+ return (uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 |
-+ (uint32_t)p[2] << 8 | (uint32_t)p[3];
-+}
-+
-+static inline uint64_t ptr_to_be64(const uint8_t *p)
-+{
-+ return (uint64_t)ptr_to_be32(p) << 32 | (uint64_t)ptr_to_be32(p + 4);
-+}
-+
-+static inline void be32_to_ptr(uint8_t *p, const uint32_t value)
-+{
-+ p[0] = (uint8_t)(value >> 24);
-+ p[1] = (uint8_t)(value >> 16);
-+ p[2] = (uint8_t)(value >> 8);
-+ p[3] = (uint8_t)(value);
-+}
-+
-+static inline void be64_to_ptr(uint8_t *p, const uint64_t value)
-+{
-+ be32_to_ptr(p, (uint32_t)(value >> 32));
-+ be32_to_ptr(p + 4, (uint32_t)(value));
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* BITSHIFT_BE_H */
-diff --git a/lib/freebl/leancrypto/bitshift_le.h b/lib/freebl/leancrypto/bitshift_le.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/bitshift_le.h
-@@ -0,0 +1,62 @@
-+/*
-+ * Copyright (C) 2020 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef BITSHIFT_LE_H
-+#define BITSHIFT_LE_H
-+
-+#include "ext_headers.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/*
-+ * Conversion of Little-Endian representations in byte streams - the data
-+ * representation in the integer values is the host representation.
-+ */
-+static inline uint32_t ptr_to_le32(const uint8_t *p)
-+{
-+ return (uint32_t)p[0] | (uint32_t)p[1] << 8 | (uint32_t)p[2] << 16 |
-+ (uint32_t)p[3] << 24;
-+}
-+
-+static inline uint64_t ptr_to_le64(const uint8_t *p)
-+{
-+ return (uint64_t)ptr_to_le32(p) | (uint64_t)ptr_to_le32(p + 4) << 32;
-+}
-+
-+static inline void le32_to_ptr(uint8_t *p, const uint32_t value)
-+{
-+ p[0] = (uint8_t)(value);
-+ p[1] = (uint8_t)(value >> 8);
-+ p[2] = (uint8_t)(value >> 16);
-+ p[3] = (uint8_t)(value >> 24);
-+}
-+
-+static inline void le64_to_ptr(uint8_t *p, const uint64_t value)
-+{
-+ le32_to_ptr(p + 4, (uint32_t)(value >> 32));
-+ le32_to_ptr(p, (uint32_t)(value));
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* BITSHIFT_LE_H */
-diff --git a/lib/freebl/leancrypto/bool.h b/lib/freebl/leancrypto/bool.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/bool.h
-@@ -0,0 +1,41 @@
-+/*
-+ * Copyright (C) 2018 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef BOOL_H
-+#define BOOL_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#ifndef LINUX_KERNEL
-+
-+#if defined(__STDC_VERSION__) && __STDC_VERSION__ < 202311L && !defined(false)
-+/* Boolean variable */
-+enum { false, true };
-+typedef _Bool bool;
-+#endif
-+
-+#endif /* LINUX_KERNEL */
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* BOOL_H */
-diff --git a/lib/freebl/leancrypto/build_bug_on.h b/lib/freebl/leancrypto/build_bug_on.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/build_bug_on.h
-@@ -0,0 +1,27 @@
-+/*
-+ * Copyright (C) 2018 - 2023, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef _BUILD_BUG_ON_H
-+#define _BUILD_BUG_ON_H
-+
-+#ifndef LINUX_KERNEL
-+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2 * !!(condition)]))
-+#endif
-+
-+#endif /* _BUILD_BUG_ON_H */
-diff --git a/lib/freebl/leancrypto/compare.h b/lib/freebl/leancrypto/compare.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/compare.h
-@@ -0,0 +1,53 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef COMPARE_H
-+#define COMPARE_H
-+
-+#include "ext_headers.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+int get_current_selftest_level(void);
-+
-+#ifdef LC_SELFTEST_ENABLED
-+#define LC_SELFTEST_RUN(x) \
-+ if (*x == get_current_selftest_level()) \
-+ return; \
-+ *x = get_current_selftest_level();
-+#else /* LC_SELFTEST_ENABLED */
-+#define LC_SELFTEST_RUN(x) \
-+ (void)x; \
-+ if (1) \
-+ return;
-+#endif /* LC_SELFTEST_ENABLED */
-+
-+int lc_compare(const uint8_t *act, const uint8_t *exp, const size_t len,
-+ const char *info);
-+void lc_compare_selftest(const uint8_t *act, const uint8_t *exp,
-+ const size_t len, const char *info);
-+void lc_disable_selftest(void);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* COMPARE_H */
-diff --git a/lib/freebl/leancrypto/conv_be_le.h b/lib/freebl/leancrypto/conv_be_le.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/conv_be_le.h
-@@ -0,0 +1,142 @@
-+/* Conversion functions from LE to BE and vice versa
-+ *
-+ * Copyright (C) 2015 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef CONV_BE_LE_H
-+#define CONV_BE_LE_H
-+
-+#include "ext_headers.h"
-+#include "rotate.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#if !defined(CONVERSION_TEST) && (defined(__gcc__) || defined(__clang__))
-+#define __HAVE_BUILTIN_BSWAP16__
-+#define __HAVE_BUILTIN_BSWAP32__
-+#define __HAVE_BUILTIN_BSWAP64__
-+#endif
-+
-+/* Byte swap for 16-bit, 32-bit and 64-bit integers. */
-+#ifndef __HAVE_BUILTIN_BSWAP16__
-+static inline uint16_t _lc_bswap16(uint16_t x)
-+{
-+ return (uint16_t)((rol16(x, 8) & 0x00ff) | (ror16(x, 8) & 0xff00));
-+}
-+#define _lc_swap16(x) _lc_bswap16((uint16_t)(x))
-+#else
-+#define _lc_swap16(x) (uint16_t)__builtin_bswap16((uint16_t)(x))
-+#endif
-+
-+#if !defined(__HAVE_BUILTIN_BSWAP32__) || !defined(__HAVE_BUILTIN_BSWAP64__)
-+static inline uint32_t _lc_bswap32(uint32_t x)
-+{
-+ return ((rol32(x, 8) & 0x00ff00ffL) | (ror32(x, 8) & 0xff00ff00L));
-+}
-+#define _lc_swap32(x) _lc_bswap32((uint32_t)(x))
-+#else
-+#define _lc_swap32(x) (uint32_t)__builtin_bswap32((uint32_t)(x))
-+#endif
-+
-+#ifndef __HAVE_BUILTIN_BSWAP64__
-+static inline uint64_t _lc_bswap64(uint64_t x)
-+{
-+ return ((uint64_t)_lc_bswap32((uint32_t)x) << 32) |
-+ (_lc_bswap32((uint32_t)(x >> 32)));
-+}
-+#define _lc_swap64(x) _lc_bswap64((uint64_t)(x))
-+#else
-+#define _lc_swap64(x) (uint64_t)__builtin_bswap64((uint64_t)(x))
-+#endif
-+
-+/* Endian dependent byte swap operations. */
-+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
-+
-+static inline uint16_t le_bswap16(uint16_t x)
-+{
-+ return _lc_swap16(x);
-+}
-+
-+static inline uint16_t be_bswap16(uint16_t x)
-+{
-+ return x;
-+}
-+
-+static inline uint32_t le_bswap32(uint32_t x)
-+{
-+ return _lc_swap32(x);
-+}
-+
-+static inline uint32_t be_bswap32(uint32_t x)
-+{
-+ return x;
-+}
-+
-+static inline uint64_t le_bswap64(uint64_t x)
-+{
-+ return _lc_swap64(x);
-+}
-+
-+static inline uint64_t be_bswap64(uint64_t x)
-+{
-+ return x;
-+}
-+
-+#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-+
-+static inline uint16_t le_bswap16(uint16_t x)
-+{
-+ return x;
-+}
-+
-+static inline uint16_t be_bswap16(uint16_t x)
-+{
-+ return _lc_swap16(x);
-+}
-+
-+static inline uint32_t le_bswap32(uint32_t x)
-+{
-+ return x;
-+}
-+
-+static inline uint32_t be_bswap32(uint32_t x)
-+{
-+ return _lc_swap32(x);
-+}
-+
-+static inline uint64_t le_bswap64(uint64_t x)
-+{
-+ return x;
-+}
-+
-+static inline uint64_t be_bswap64(uint64_t x)
-+{
-+ return _lc_swap64(x);
-+}
-+
-+#else
-+#error "Endianess not defined"
-+#endif
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* CONV_BE_LE_H */
-diff --git a/lib/freebl/leancrypto/dilithium_debug.h b/lib/freebl/leancrypto/dilithium_debug.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_debug.h
-@@ -0,0 +1,89 @@
-+/*
-+ * Copyright (C) 2023 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef DILITHIUM_DEBUG_H
-+#define DILITHIUM_DEBUG_H
-+
-+#include "dilithium_type.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#ifdef LC_DILITHIUM_DEBUG
-+
-+/* Disable selftests */
-+#define LC_DILITHIUM_TEST_INIT 1
-+
-+void dilithium_print_buffer(const uint8_t *buffer, const size_t bufferlen,
-+ const char *explanation);
-+void dilithium_print_polyvecl_k(polyvecl mat[LC_DILITHIUM_K],
-+ const char *explanation);
-+void dilithium_print_polyvecl(polyvecl *polyvec, const char *explanation);
-+void dilithium_print_polyveck(polyveck *polyvec, const char *explanation);
-+void dilithium_print_poly(poly *vec, const char *explanation);
-+
-+#else /* LC_DILITHIUM_DEBUG */
-+
-+/* Enable selftests */
-+#define LC_DILITHIUM_TEST_INIT 0
-+
-+static inline void dilithium_print_buffer(const uint8_t *buffer,
-+ const size_t bufferlen,
-+ const char *explanation)
-+{
-+ (void)buffer;
-+ (void)bufferlen;
-+ (void)explanation;
-+}
-+
-+static inline void dilithium_print_polyvecl_k(polyvecl mat[LC_DILITHIUM_K],
-+ const char *explanation)
-+{
-+ (void)mat;
-+ (void)explanation;
-+}
-+
-+static inline void dilithium_print_polyvecl(polyvecl *polyvec,
-+ const char *explanation)
-+{
-+ (void)polyvec;
-+ (void)explanation;
-+}
-+
-+static inline void dilithium_print_polyveck(polyveck *polyvec,
-+ const char *explanation)
-+{
-+ (void)polyvec;
-+ (void)explanation;
-+}
-+
-+static inline void dilithium_print_poly(poly *vec, const char *explanation)
-+{
-+ (void)vec;
-+ (void)explanation;
-+}
-+
-+#endif /* LC_DILITHIUM_DEBUG */
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_DEBUG_H */
-diff --git a/lib/freebl/leancrypto/dilithium_ntt.h b/lib/freebl/leancrypto/dilithium_ntt.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_ntt.h
-@@ -0,0 +1,45 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#ifndef DILITHIUM_NTT_H
-+#define DILITHIUM_NTT_H
-+
-+#include "ext_headers.h"
-+#include "dilithium_type.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+void ntt(int32_t a[LC_DILITHIUM_N]);
-+void invntt_tomont(int32_t a[LC_DILITHIUM_N]);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_NTT_H */
-diff --git a/lib/freebl/leancrypto/dilithium_pack.h b/lib/freebl/leancrypto/dilithium_pack.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_pack.h
-@@ -0,0 +1,296 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#ifndef DILITHIUM_PACK_H
-+#define DILITHIUM_PACK_H
-+
-+#include "build_bug_on.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/*******************************************************************************
-+ * Pack / Unpack public key
-+ ******************************************************************************/
-+static inline void pack_pk_rho(struct lc_dilithium_pk *pk,
-+ const uint8_t rho[LC_DILITHIUM_SEEDBYTES])
-+{
-+ memcpy(pk->pk, rho, LC_DILITHIUM_SEEDBYTES);
-+}
-+
-+static inline void pack_pk_t1(struct lc_dilithium_pk *pk, const polyveck *t1)
-+{
-+ unsigned int i;
-+ uint8_t *pubkey = pk->pk + LC_DILITHIUM_SEEDBYTES;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ polyt1_pack(pubkey + i * LC_DILITHIUM_POLYT1_PACKEDBYTES,
-+ &t1->vec[i]);
-+}
-+
-+static inline void unpack_pk_rho(uint8_t rho[LC_DILITHIUM_SEEDBYTES],
-+ const struct lc_dilithium_pk *pk)
-+{
-+ memcpy(rho, pk->pk, LC_DILITHIUM_SEEDBYTES);
-+}
-+
-+static inline void unpack_pk_t1(polyveck *t1, const struct lc_dilithium_pk *pk)
-+{
-+ unsigned int i;
-+ const uint8_t *pubkey = pk->pk + LC_DILITHIUM_SEEDBYTES;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ polyt1_unpack(&t1->vec[i],
-+ pubkey + i * LC_DILITHIUM_POLYT1_PACKEDBYTES);
-+}
-+
-+/*******************************************************************************
-+ * Pack / Unpack secret key
-+ ******************************************************************************/
-+static inline void pack_sk_rho(struct lc_dilithium_sk *sk,
-+ const uint8_t rho[LC_DILITHIUM_SEEDBYTES])
-+{
-+ memcpy(sk->sk, rho, LC_DILITHIUM_SEEDBYTES);
-+}
-+
-+static inline void pack_sk_key(struct lc_dilithium_sk *sk,
-+ const uint8_t key[LC_DILITHIUM_SEEDBYTES])
-+{
-+ memcpy(sk->sk + LC_DILITHIUM_SEEDBYTES, key, LC_DILITHIUM_SEEDBYTES);
-+}
-+
-+static inline void pack_sk_tr(struct lc_dilithium_sk *sk,
-+ const uint8_t tr[LC_DILITHIUM_TRBYTES])
-+{
-+ memcpy(sk->sk + 2 * LC_DILITHIUM_SEEDBYTES, tr, LC_DILITHIUM_TRBYTES);
-+}
-+
-+static inline void pack_sk_s1(struct lc_dilithium_sk *sk, const polyvecl *s1)
-+{
-+ unsigned int i;
-+ uint8_t *seckey =
-+ sk->sk + 2 * LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_TRBYTES;
-+
-+ for (i = 0; i < LC_DILITHIUM_L; ++i)
-+ polyeta_pack(seckey + i * LC_DILITHIUM_POLYETA_PACKEDBYTES,
-+ &s1->vec[i]);
-+}
-+
-+static inline void pack_sk_s2(struct lc_dilithium_sk *sk, const polyveck *s2)
-+{
-+ unsigned int i;
-+ uint8_t *seckey = sk->sk + 2 * LC_DILITHIUM_SEEDBYTES +
-+ LC_DILITHIUM_TRBYTES +
-+ LC_DILITHIUM_L * LC_DILITHIUM_POLYETA_PACKEDBYTES;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ polyeta_pack(seckey + i * LC_DILITHIUM_POLYETA_PACKEDBYTES,
-+ &s2->vec[i]);
-+}
-+
-+static inline void pack_sk_t0(struct lc_dilithium_sk *sk, const polyveck *t0)
-+{
-+ unsigned int i;
-+ uint8_t *seckey = sk->sk + 2 * LC_DILITHIUM_SEEDBYTES +
-+ LC_DILITHIUM_TRBYTES +
-+ LC_DILITHIUM_L * LC_DILITHIUM_POLYETA_PACKEDBYTES +
-+ LC_DILITHIUM_K * LC_DILITHIUM_POLYETA_PACKEDBYTES;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ polyt0_pack(seckey + i * LC_DILITHIUM_POLYT0_PACKEDBYTES,
-+ &t0->vec[i]);
-+}
-+
-+static inline void unpack_sk_rho(uint8_t rho[LC_DILITHIUM_SEEDBYTES],
-+ const struct lc_dilithium_sk *sk)
-+{
-+ memcpy(rho, sk->sk, LC_DILITHIUM_SEEDBYTES);
-+}
-+
-+static inline void unpack_sk_key(uint8_t key[LC_DILITHIUM_SEEDBYTES],
-+ const struct lc_dilithium_sk *sk)
-+{
-+ memcpy(key, sk->sk + LC_DILITHIUM_SEEDBYTES, LC_DILITHIUM_SEEDBYTES);
-+}
-+
-+static inline void unpack_sk_tr(uint8_t tr[LC_DILITHIUM_TRBYTES],
-+ const struct lc_dilithium_sk *sk)
-+{
-+ memcpy(tr, sk->sk + 2 * LC_DILITHIUM_SEEDBYTES, LC_DILITHIUM_TRBYTES);
-+}
-+
-+static inline void unpack_sk_s1(polyvecl *s1, const struct lc_dilithium_sk *sk)
-+{
-+ unsigned int i;
-+ const uint8_t *seckey =
-+ sk->sk + 2 * LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_TRBYTES;
-+
-+ for (i = 0; i < LC_DILITHIUM_L; ++i)
-+ polyeta_unpack(&s1->vec[i],
-+ seckey + i * LC_DILITHIUM_POLYETA_PACKEDBYTES);
-+}
-+
-+static inline void unpack_sk_s2(polyveck *s2, const struct lc_dilithium_sk *sk)
-+{
-+ unsigned int i;
-+ const uint8_t *seckey =
-+ sk->sk + 2 * LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_TRBYTES +
-+ LC_DILITHIUM_L * LC_DILITHIUM_POLYETA_PACKEDBYTES;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ polyeta_unpack(&s2->vec[i],
-+ seckey + i * LC_DILITHIUM_POLYETA_PACKEDBYTES);
-+}
-+
-+static inline void unpack_sk_t0(polyveck *t0, const struct lc_dilithium_sk *sk)
-+{
-+ unsigned int i;
-+ const uint8_t *seckey =
-+ sk->sk + 2 * LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_TRBYTES +
-+ LC_DILITHIUM_L * LC_DILITHIUM_POLYETA_PACKEDBYTES +
-+ LC_DILITHIUM_K * LC_DILITHIUM_POLYETA_PACKEDBYTES;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ polyt0_unpack(&t0->vec[i],
-+ seckey + i * LC_DILITHIUM_POLYT0_PACKEDBYTES);
-+}
-+
-+/**
-+ * @brief pack_sig - Bit-pack signature sig = (c, z, h).
-+ *
-+ * NOTE: A signature is the concatenation of sig = (c || packed z || packed h).
-+ * As c is already present in the first bytes of sig, this function does
-+ * not need to copy it yet again to the right location. This implies that
-+ * this function does not process c.
-+ *
-+ * @param [out] sig signature
-+ * @param [in] z pointer to vector z
-+ * @param [in] h pointer to hint vector h
-+ */
-+static inline void pack_sig(struct lc_dilithium_sig *sig, const polyvecl *z,
-+ const polyveck *h)
-+{
-+ unsigned int i, j, k;
-+ /* Skip c */
-+ uint8_t *signature = sig->sig + LC_DILITHIUM_CTILDE_BYTES;
-+
-+ BUILD_BUG_ON((1ULL << (sizeof(j) << 3)) < LC_DILITHIUM_N);
-+ BUILD_BUG_ON((1ULL << (sizeof(k) << 3)) < LC_DILITHIUM_N);
-+
-+ for (i = 0; i < LC_DILITHIUM_L; ++i)
-+ polyz_pack(signature + i * LC_DILITHIUM_POLYZ_PACKEDBYTES,
-+ &z->vec[i]);
-+ signature += LC_DILITHIUM_L * LC_DILITHIUM_POLYZ_PACKEDBYTES;
-+
-+ /* Encode h */
-+ memset(signature, 0, LC_DILITHIUM_OMEGA + LC_DILITHIUM_K);
-+
-+ k = 0;
-+ for (i = 0; i < LC_DILITHIUM_K; ++i) {
-+ for (j = 0; j < LC_DILITHIUM_N; ++j)
-+ if (h->vec[i].coeffs[j] != 0)
-+ signature[k++] = (uint8_t)j;
-+
-+ signature[LC_DILITHIUM_OMEGA + i] = (uint8_t)k;
-+ }
-+}
-+
-+/**
-+ * @brief unpack_sig_z - Unpack z part of signature sig = (c, z, h).
-+ *
-+ * NOTE: The c value is not unpacked as it can be used right from the signature.
-+ * To access it, a caller simply needs to use the first
-+ * LC_DILITHIUM_CTILDE_BYTES of the signature.
-+ *
-+ * @param [out] z pointer to output vector z
-+ * @param [in] sig signature
-+ */
-+static inline void unpack_sig_z(polyvecl *z, const struct lc_dilithium_sig *sig)
-+{
-+ unsigned int i;
-+ /* Skip c */
-+ const uint8_t *signature = sig->sig + LC_DILITHIUM_CTILDE_BYTES;
-+
-+ for (i = 0; i < LC_DILITHIUM_L; ++i)
-+ polyz_unpack(&z->vec[i],
-+ signature + i * LC_DILITHIUM_POLYZ_PACKEDBYTES);
-+}
-+
-+/**
-+ * @brief unpack_sig - Unpack h value of signature sig = (c, z, h).
-+ *
-+ * NOTE: The c value is not unpacked as it can be used right from the signature.
-+ * To access it, a caller simply needs to use the first
-+ * LC_DILITHIUM_CTILDE_BYTES of the signature.
-+ *
-+ * @param [out] h pointer to output hint vector h
-+ * @param [in] sig signature
-+ *
-+ * @return 1 in case of malformed signature; otherwise 0.
-+ */
-+static inline int unpack_sig_h(polyveck *h, const struct lc_dilithium_sig *sig)
-+{
-+ unsigned int i, j, k;
-+ /* Skip c */
-+ const uint8_t *signature =
-+ sig->sig + LC_DILITHIUM_CTILDE_BYTES +
-+ LC_DILITHIUM_L * LC_DILITHIUM_POLYZ_PACKEDBYTES;
-+
-+ /* Decode h */
-+ k = 0;
-+ for (i = 0; i < LC_DILITHIUM_K; ++i) {
-+ for (j = 0; j < LC_DILITHIUM_N; ++j)
-+ h->vec[i].coeffs[j] = 0;
-+
-+ if (signature[LC_DILITHIUM_OMEGA + i] < k ||
-+ signature[LC_DILITHIUM_OMEGA + i] > LC_DILITHIUM_OMEGA)
-+ return 1;
-+
-+ for (j = k; j < signature[LC_DILITHIUM_OMEGA + i]; ++j) {
-+ /* Coefficients are ordered for strong unforgeability */
-+ if (j > k && signature[j] <= signature[j - 1])
-+ return 1;
-+ h->vec[i].coeffs[signature[j]] = 1;
-+ }
-+
-+ k = signature[LC_DILITHIUM_OMEGA + i];
-+ }
-+
-+ /* Extra indices are zero for strong unforgeability */
-+ for (j = k; j < LC_DILITHIUM_OMEGA; ++j)
-+ if (signature[j])
-+ return 1;
-+
-+ return 0;
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_PACK_H */
-diff --git a/lib/freebl/leancrypto/dilithium_pct.h b/lib/freebl/leancrypto/dilithium_pct.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_pct.h
-@@ -0,0 +1,63 @@
-+/*
-+ * Copyright (C) 2024 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef DILITHIUM_PCT_H
-+#define DILITHIUM_PCT_H
-+
-+#include "fips_mode.h"
-+#include "ret_checkers.h"
-+#include "small_stack_support.h"
-+#include "visibility.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+static inline int _lc_dilithium_pct_fips(const struct lc_dilithium_pk *pk,
-+ const struct lc_dilithium_sk *sk)
-+{
-+ struct workspace {
-+ uint8_t m[32];
-+ struct lc_dilithium_sig sig;
-+ };
-+ int ret;
-+ LC_DECLARE_MEM(ws, struct workspace, sizeof(uint64_t));
-+
-+ CKINT(lc_dilithium_sign(&ws->sig, ws->m, sizeof(ws->m), sk,
-+ lc_seeded_rng));
-+ CKINT(lc_dilithium_verify(&ws->sig, ws->m, sizeof(ws->m), pk));
-+
-+out:
-+ LC_RELEASE_MEM(ws);
-+ return ret;
-+}
-+
-+static inline int lc_dilithium_pct_fips(const struct lc_dilithium_pk *pk,
-+ const struct lc_dilithium_sk *sk)
-+{
-+ FIPS140_PCT_LOOP(_lc_dilithium_pct_fips(pk, sk))
-+
-+ return 0;
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_PCT_H */
-diff --git a/lib/freebl/leancrypto/dilithium_poly.h b/lib/freebl/leancrypto/dilithium_poly.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_poly.h
-@@ -0,0 +1,200 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#ifndef DILITHIUM_POLY_H
-+#define DILITHIUM_POLY_H
-+
-+#include "dilithium_type.h"
-+#include "dilithium_reduce.h"
-+#include "dilithium_rounding.h"
-+#include "ext_headers.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+typedef struct {
-+ int32_t coeffs[LC_DILITHIUM_N];
-+} poly;
-+
-+/**
-+ * @brief poly_add - Add polynomials. No modular reduction is performed.
-+ *
-+ * @param [out] c pointer to output polynomial
-+ * @param [in] a pointer to first summand
-+ * @param [in] b pointer to second summand
-+ */
-+static inline void poly_add(poly *c, const poly *a, const poly *b)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N; ++i)
-+ c->coeffs[i] = a->coeffs[i] + b->coeffs[i];
-+}
-+
-+/**
-+ * @brief poly_sub - Subtract polynomials. No modular reduction is
-+ * performed.
-+ *
-+ * @param [out] c pointer to output polynomial
-+ * @param [in] a pointer to first input polynomial
-+ * @param [in] b pointer to second input polynomial to be subtraced from first
-+ * input polynomial
-+ */
-+static inline void poly_sub(poly *c, const poly *a, const poly *b)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N; ++i)
-+ c->coeffs[i] = a->coeffs[i] - b->coeffs[i];
-+}
-+
-+/**
-+ * @brief poly_shiftl - Multiply polynomial by 2^D without modular reduction.
-+ * Assumes input coefficients to be less than 2^{31-D} in
-+ * absolute value.
-+ *
-+ * @param [in,out] a pointer to input/output polynomial
-+ */
-+static inline void poly_shiftl(poly *a)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N; ++i)
-+ a->coeffs[i] <<= LC_DILITHIUM_D;
-+}
-+
-+/**
-+ * @brief poly_decompose - For all coefficients c of the input polynomial,
-+ * compute high and low bits c0, c1 such
-+ * c mod Q = c1*ALPHA + c0 with
-+ * -ALPHA/2 < c0 <= ALPHA/2 except c1 = (Q-1)/ALPHA
-+ * where we set c1 = 0 and
-+ * -ALPHA/2 <= c0 = c mod Q - Q < 0.
-+ * Assumes coefficients to be standard representatives.
-+ *
-+ * @param [out] a1 pointer to output polynomial with coefficients c1
-+ * @param [out] a0 pointer to output polynomial with coefficients c0
-+ * @param [in] a pointer to input polynomial
-+ */
-+static inline void poly_decompose(poly *a1, poly *a0, const poly *a)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N; ++i)
-+ a1->coeffs[i] = decompose(&a0->coeffs[i], a->coeffs[i]);
-+}
-+
-+/**
-+ * @brief poly_make_hint - Compute hint polynomial. The coefficients of which
-+ * indicate whether the low bits of the corresponding
-+ * coefficient of the input polynomial overflow into the
-+ * high bits.
-+ *
-+ * @param [out] h pointer to output hint polynomial
-+ * @param [in] a0 pointer to low part of input polynomial
-+ * @param [in] a1 pointer to high part of input polynomial
-+ *
-+ * @return number of 1 bits.
-+ */
-+static inline unsigned int poly_make_hint(poly *h, const poly *a0,
-+ const poly *a1)
-+{
-+ unsigned int i, s = 0;
-+
-+ for (i = 0; i < LC_DILITHIUM_N; ++i) {
-+ h->coeffs[i] = make_hint(a0->coeffs[i], a1->coeffs[i]);
-+ s += (unsigned int)h->coeffs[i];
-+ }
-+
-+ return s;
-+}
-+
-+/**
-+ * @brief poly_use_hint - Use hint polynomial to correct the high bits of a
-+ * polynomial.
-+ *
-+ * @param [out] b pointer to output polynomial with corrected high bits
-+ * @param [in] a pointer to input polynomial
-+ * @param [in] h pointer to input hint polynomial
-+ */
-+static inline void poly_use_hint(poly *b, const poly *a, const poly *h)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N; ++i)
-+ b->coeffs[i] = use_hint(a->coeffs[i], h->coeffs[i]);
-+}
-+
-+int poly_chknorm(const poly *a, int32_t B);
-+
-+#define POLY_UNIFORM_NBLOCKS \
-+ ((768 + LC_SHAKE_128_SIZE_BLOCK - 1) / LC_SHAKE_128_SIZE_BLOCK)
-+void poly_uniform(poly *a, const uint8_t seed[LC_DILITHIUM_SEEDBYTES],
-+ uint16_t nonce, void *ws_buf);
-+
-+#if LC_DILITHIUM_ETA == 2
-+#define POLY_UNIFORM_ETA_NBLOCKS \
-+ ((136 + LC_SHAKE_256_SIZE_BLOCK - 1) / LC_SHAKE_256_SIZE_BLOCK)
-+#elif LC_DILITHIUM_ETA == 4
-+#define POLY_UNIFORM_ETA_NBLOCKS \
-+ ((227 + LC_SHAKE_256_SIZE_BLOCK - 1) / LC_SHAKE_256_SIZE_BLOCK)
-+#else
-+#error "Undefined LC_DILITHIUM_ETA"
-+#endif
-+#define POLY_UNIFORM_ETA_BYTES POLY_UNIFORM_ETA_NBLOCKS *LC_SHAKE_256_SIZE_BLOCK
-+void poly_uniform_eta(poly *a, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
-+ uint16_t nonce, void *ws_buf);
-+
-+#define POLY_UNIFORM_GAMMA1_NBLOCKS \
-+ ((LC_DILITHIUM_POLYZ_PACKEDBYTES + LC_SHAKE_256_SIZE_BLOCK - 1) / \
-+ LC_SHAKE_256_SIZE_BLOCK)
-+#define POLY_UNIFORM_GAMMA1_BYTES \
-+ POLY_UNIFORM_GAMMA1_NBLOCKS *LC_SHAKE_256_SIZE_BLOCK
-+
-+#define POLY_CHALLENGE_BYTES LC_SHAKE_256_SIZE_BLOCK
-+void poly_challenge(poly *c, const uint8_t seed[LC_DILITHIUM_CTILDE_BYTES],
-+ void *ws_buf);
-+
-+void polyeta_pack(uint8_t *r, const poly *a);
-+void polyeta_unpack(poly *r, const uint8_t *a);
-+
-+void polyt1_pack(uint8_t *r, const poly *a);
-+
-+void polyt0_pack(uint8_t *r, const poly *a);
-+void polyt0_unpack(poly *r, const uint8_t *a);
-+
-+void polyz_pack(uint8_t *r, const poly *a);
-+void polyz_unpack(poly *r, const uint8_t *a);
-+
-+void polyw1_pack(uint8_t *r, const poly *a);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_POLY_H */
-diff --git a/lib/freebl/leancrypto/dilithium_poly_c.h b/lib/freebl/leancrypto/dilithium_poly_c.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_poly_c.h
-@@ -0,0 +1,150 @@
-+/*
-+ * Copyright (C) 2023 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef DILITHIUM_POLY_C_H
-+#define DILITHIUM_POLY_C_H
-+
-+#include "dilithium_ntt.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/**
-+ * @brief poly_reduce - Inplace reduction of all coefficients of polynomial to
-+ * representative in [-6283009,6283007].
-+ *
-+ * @param [in,out] a pointer to input/output polynomial
-+ */
-+static inline void poly_reduce(poly *a)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N; ++i)
-+ a->coeffs[i] = reduce32(a->coeffs[i]);
-+}
-+
-+/**
-+ * @brief poly_caddq - For all coefficients of in/out polynomial add Q if
-+ * coefficient is negative.
-+ *
-+ * @param [in,out] a pointer to input/output polynomial
-+ */
-+static inline void poly_caddq(poly *a)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N; ++i)
-+ a->coeffs[i] = caddq(a->coeffs[i]);
-+}
-+
-+/**
-+ * @brief poly_pointwise_montgomery - Pointwise multiplication of polynomials in
-+ * NTT domain representation and
-+ * multiplication of resulting polynomial
-+ * by 2^{-32}.
-+ *
-+ * @param [out] c pointer to output polynomial
-+ * @param [in] a pointer to first input polynomial
-+ * @param [in] b pointer to second input polynomial
-+ */
-+static inline void poly_pointwise_montgomery(poly *c, const poly *a,
-+ const poly *b)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N; ++i)
-+ c->coeffs[i] =
-+ montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]);
-+}
-+
-+/**
-+ * @brief poly_power2round - For all coefficients c of the input polynomial,
-+ * compute c0, c1 such that c mod Q = c1*2^D + c0
-+ * with -2^{D-1} < c0 <= 2^{D-1}. Assumes coefficients
-+ * to be standard representatives.
-+ *
-+ * @param [out] a1 pointer to output polynomial with coefficients c1
-+ * @param [out] a0 pointer to output polynomial with coefficients c0
-+ * @param [in] a pointer to input polynomial
-+ */
-+static inline void poly_power2round(poly *a1, poly *a0, const poly *a)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N; ++i)
-+ a1->coeffs[i] = power2round(&a0->coeffs[i], a->coeffs[i]);
-+}
-+
-+/**
-+ * @brief polyt1_unpack - Unpack polynomial t1 with 10-bit coefficients.
-+ * Output coefficients are standard representatives.
-+ *
-+ * @param [out] r pointer to output polynomial
-+ * @param [in] a byte array with bit-packed polynomial
-+ */
-+static inline void polyt1_unpack(poly *r, const uint8_t *a)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N / 4; ++i) {
-+ r->coeffs[4 * i + 0] =
-+ ((a[5 * i + 0] >> 0) | ((uint32_t)a[5 * i + 1] << 8)) &
-+ 0x3FF;
-+ r->coeffs[4 * i + 1] =
-+ ((a[5 * i + 1] >> 2) | ((uint32_t)a[5 * i + 2] << 6)) &
-+ 0x3FF;
-+ r->coeffs[4 * i + 2] =
-+ ((a[5 * i + 2] >> 4) | ((uint32_t)a[5 * i + 3] << 4)) &
-+ 0x3FF;
-+ r->coeffs[4 * i + 3] =
-+ ((a[5 * i + 3] >> 6) | ((uint32_t)a[5 * i + 4] << 2)) &
-+ 0x3FF;
-+ }
-+}
-+
-+/**
-+ * @brief poly_ntt - Inplace forward NTT. Coefficients can grow by
-+ * 8*Q in absolute value.
-+ *
-+ * @param [in,out] a pointer to input/output polynomial
-+ */
-+static inline void poly_ntt(poly *a)
-+{
-+ ntt(a->coeffs);
-+}
-+
-+/**
-+ * @brief poly_invntt_tomont - Inplace inverse NTT and multiplication by 2^{32}.
-+ * Input coefficients need to be less than Q in
-+ * absolute value and output coefficients are again
-+ * bounded by Q.
-+ *
-+ * @param [in,out] a pointer to input/output polynomial
-+ */
-+static inline void poly_invntt_tomont(poly *a)
-+{
-+ invntt_tomont(a->coeffs);
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_POLY_C_H */
-diff --git a/lib/freebl/leancrypto/dilithium_poly_common.h b/lib/freebl/leancrypto/dilithium_poly_common.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_poly_common.h
-@@ -0,0 +1,44 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#ifndef DILITHIUM_POLY_COMMON_H
-+#define DILITHIUM_POLY_COMMON_H
-+
-+#include "dilithium_type.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+void poly_uniform_gamma1(poly *a, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
-+ uint16_t nonce, void *ws_buf);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_POLY_COMMON_H */
-diff --git a/lib/freebl/leancrypto/dilithium_polyvec.h b/lib/freebl/leancrypto/dilithium_polyvec.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_polyvec.h
-@@ -0,0 +1,373 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#ifndef DILITHIUM_POLYVEC_H
-+#define DILITHIUM_POLYVEC_H
-+
-+#include "conv_be_le.h"
-+#include "dilithium_type.h"
-+#include "dilithium_poly.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+typedef struct {
-+ poly vec[LC_DILITHIUM_L];
-+} polyvecl;
-+
-+/* Vectors of polynomials of length K */
-+typedef struct {
-+ poly vec[LC_DILITHIUM_K];
-+} polyveck;
-+
-+/**************************************************************/
-+/************ Vectors of polynomials of length L **************/
-+/**************************************************************/
-+
-+static inline void polyvecl_reduce(polyvecl *v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_L; ++i)
-+ poly_reduce(&v->vec[i]);
-+}
-+
-+/**
-+ * @brief polyvecl_add - Add vectors of polynomials of length L.
-+ * No modular reduction is performed.
-+ *
-+ * @param [out] w pointer to output vector
-+ * @param [in] u pointer to first summand
-+ * @param [in] v pointer to second summand
-+ */
-+static inline void polyvecl_add(polyvecl *w, const polyvecl *u,
-+ const polyvecl *v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_L; ++i)
-+ poly_add(&w->vec[i], &u->vec[i], &v->vec[i]);
-+}
-+
-+/**
-+ * @brief polyvecl_ntt - Forward NTT of all polynomials in vector of length L.
-+ * Output coefficients can be up to 16*Q larger than input
-+ * coefficients.
-+ *
-+ * @param [in,out] v pointer to input/output vector
-+ */
-+static inline void polyvecl_ntt(polyvecl *v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_L; ++i)
-+ poly_ntt(&v->vec[i]);
-+}
-+
-+static inline void polyvecl_invntt_tomont(polyvecl *v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_L; ++i)
-+ poly_invntt_tomont(&v->vec[i]);
-+}
-+
-+static inline void polyvecl_pointwise_poly_montgomery(polyvecl *r,
-+ const poly *a,
-+ const polyvecl *v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_L; ++i)
-+ poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]);
-+}
-+
-+/**
-+ * @brief polyvecl_chknorm - Check infinity norm of polynomials in vector of
-+ * length L. Assumes input polyvecl to be reduced by
-+ * polyvecl_reduce().
-+ *
-+ * @param [in] v pointer to vector
-+ * @param [in] bound norm bound
-+ *
-+ * @return 0 if norm of all polynomials is strictly smaller than B <= (Q-1)/8
-+ * and 1 otherwise.
-+ */
-+static inline int polyvecl_chknorm(const polyvecl *v, int32_t bound)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_L; ++i)
-+ if (poly_chknorm(&v->vec[i], bound))
-+ return 1;
-+
-+ return 0;
-+}
-+
-+/**************************************************************/
-+/************ Vectors of polynomials of length K **************/
-+/**************************************************************/
-+
-+/**
-+ * @brief polyveck_reduce - Reduce coefficients of polynomials in vector of
-+ * length LC_DILITHIUM_K to representatives in
-+ * [-6283009,6283007].
-+ *
-+ * @param [in,out] v pointer to input/output vector
-+ */
-+static inline void polyveck_reduce(polyveck *v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ poly_reduce(&v->vec[i]);
-+}
-+
-+/**
-+ * @brief polyveck_caddq - For all coefficients of polynomials in vector of
-+ * length LC_DILITHIUM_K add LC_DILITHIUM_Q if
-+ * coefficient is negative.
-+ *
-+ * @param [in,out] v pointer to input/output vector
-+ */
-+static inline void polyveck_caddq(polyveck *v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ poly_caddq(&v->vec[i]);
-+}
-+
-+/**
-+ * @brief polyveck_add - Add vectors of polynomials of length LC_DILITHIUM_K.
-+ * No modular reduction is performed.
-+ *
-+ * @param [out] w pointer to output vector
-+ * @param [in] u pointer to first summand
-+ * @param [in] v pointer to second summand
-+ */
-+static inline void polyveck_add(polyveck *w, const polyveck *u,
-+ const polyveck *v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ poly_add(&w->vec[i], &u->vec[i], &v->vec[i]);
-+}
-+
-+/**
-+ * @brief olyveck_sub - Subtract vectors of polynomials of length
-+ * LC_DILITHIUM_K. No modular reduction is performed.
-+ *
-+ * @param [out] w pointer to output vector
-+ * @param [in] u pointer to first input vector
-+ * @param [in] v pointer to second input vector to be subtracted from first
-+ * input vector
-+ */
-+static inline void polyveck_sub(polyveck *w, const polyveck *u,
-+ const polyveck *v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ poly_sub(&w->vec[i], &u->vec[i], &v->vec[i]);
-+}
-+
-+/**
-+ * @brief polyveck_shiftl - Multiply vector of polynomials of Length K by
-+ * 2^D without modular reduction. Assumes input
-+ * coefficients to be less than 2^{31-D}.
-+ *
-+ * @param [in,out] v pointer to input/output vector
-+ */
-+static inline void polyveck_shiftl(polyveck *v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ poly_shiftl(&v->vec[i]);
-+}
-+
-+/**
-+ * @brief polyveck_ntt - Forward NTT of all polynomials in vector of length K.
-+ * Output coefficients can be up to 16*Q larger than input
-+ * coefficients.
-+ *
-+ * @param [in,out] v pointer to input/output vector
-+ */
-+static inline void polyveck_ntt(polyveck *v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ poly_ntt(&v->vec[i]);
-+}
-+
-+/**
-+ * @brief polyveck_invntt_tomont - Inverse NTT and multiplication by 2^{32} of
-+ * polynomials in vector of length K. Input
-+ * coefficients need to be less than 2*Q.
-+ *
-+ * @param [in,out] v pointer to input/output vector
-+ */
-+static inline void polyveck_invntt_tomont(polyveck *v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ poly_invntt_tomont(&v->vec[i]);
-+}
-+
-+static inline void polyveck_pointwise_poly_montgomery(polyveck *r,
-+ const poly *a,
-+ const polyveck *v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]);
-+}
-+
-+/**
-+ * @brief polyveck_chknorm - Check infinity norm of polynomials in vector of
-+ * length K. Assumes input polyveck to be reduced by
-+ * polyveck_reduce().
-+ *
-+ * @param [in] v pointer to vector
-+ * @param [in] bound norm bound
-+ *
-+ * @return 0 if norm of all polynomials are strictly smaller than B <= (Q-1)/8
-+ * and 1 otherwise.
-+ */
-+static inline int polyveck_chknorm(const polyveck *v, int32_t bound)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ if (poly_chknorm(&v->vec[i], bound))
-+ return 1;
-+
-+ return 0;
-+}
-+
-+/**
-+ * @brief polyveck_power2round - For all coefficients a of polynomials in vector
-+ * of length K, compute a0, a1 such that
-+ * a mod^+ Q = a1*2^D + a0 with
-+ * -2^{D-1} < a0 <= 2^{D-1}. Assumes coefficients
-+ * to be standard representatives.
-+ *
-+ * @param [out] v1 pointer to output vector of polynomials with coefficients a1
-+ * @param [in] v0 pointer to output vector of polynomials with coefficients a0
-+ * @param [in] v pointer to input vector
-+ */
-+static inline void polyveck_power2round(polyveck *v1, polyveck *v0,
-+ const polyveck *v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]);
-+}
-+
-+/**
-+ * @brief polyveck_decompose - For all coefficients a of polynomials in vector
-+ * of length K, compute high and low bits a0, a1
-+ * such a mod^+ Q = a1*ALPHA + a0 with
-+ * -ALPHA/2 < a0 <= ALPHA/2 except a1 = (Q-1)/ALPHA
-+ * where we set a1 = 0 and
-+ * -ALPHA/2 <= a0 = a mod Q - Q < 0. Assumes
-+ * coefficients to be standard representatives.
-+ *
-+ * @param [out] v1 pointer to output vector of polynomials with coefficients a1
-+ * @param [in] v0 pointer to output vector of polynomials with coefficients a0
-+ * @param [in] v pointer to input vector
-+ */
-+static inline void polyveck_decompose(polyveck *v1, polyveck *v0,
-+ const polyveck *v)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ poly_decompose(&v1->vec[i], &v0->vec[i], &v->vec[i]);
-+}
-+
-+/**
-+ * @brief polyveck_make_hint - Compute hint vector.
-+ *
-+ * @param [out] h pointer to output vector
-+ * @param [in] v0 pointer to low part of input vector
-+ * @param [in] v1 pointer to high part of input vector
-+ *
-+ * @return number of 1 bits.
-+ */
-+static inline unsigned int polyveck_make_hint(polyveck *h, const polyveck *v0,
-+ const polyveck *v1)
-+{
-+ unsigned int i, s = 0;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ s += poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]);
-+
-+ return s;
-+}
-+
-+/**
-+ * @brief polyveck_use_hint - Use hint vector to correct the high bits of input
-+ * vector.
-+ *
-+ * @param [out] w pointer to output vector of polynomials with corrected high
-+ * bits
-+ * @param [in] u pointer to input vector
-+ * @param [in] h pointer to input hint vector
-+ */
-+static inline void polyveck_use_hint(polyveck *w, const polyveck *u,
-+ const polyveck *h)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]);
-+}
-+
-+static inline void
-+polyveck_pack_w1(uint8_t r[LC_DILITHIUM_K * LC_DILITHIUM_POLYW1_PACKEDBYTES],
-+ const polyveck *w1)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ polyw1_pack(&r[i * LC_DILITHIUM_POLYW1_PACKEDBYTES],
-+ &w1->vec[i]);
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_POLYVEC_H */
-diff --git a/lib/freebl/leancrypto/dilithium_polyvec_c.h b/lib/freebl/leancrypto/dilithium_polyvec_c.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_polyvec_c.h
-@@ -0,0 +1,123 @@
-+/*
-+ * Copyright (C) 2023 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef DILITHIUM_POLYVEC_C_H
-+#define DILITHIUM_POLYVEC_C_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+static inline void
-+polyvecl_uniform_eta(polyvecl *v, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
-+ uint16_t nonce, void *ws_buf)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_L; ++i)
-+ poly_uniform_eta(&v->vec[i], seed, le_bswap16(nonce++), ws_buf);
-+}
-+
-+static inline void
-+polyvecl_uniform_gamma1(polyvecl *v, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
-+ uint16_t nonce, void *ws_buf)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_L; ++i)
-+ poly_uniform_gamma1(
-+ &v->vec[i], seed,
-+ le_bswap16((uint16_t)(LC_DILITHIUM_L * nonce + i)),
-+ ws_buf);
-+}
-+
-+static inline void
-+polyveck_uniform_eta(polyveck *v, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
-+ uint16_t nonce, void *ws_buf)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ poly_uniform_eta(&v->vec[i], seed, le_bswap16(nonce++), ws_buf);
-+}
-+
-+/**
-+ * @brief expand_mat - Implementation of ExpandA. Generates matrix A with
-+ * uniformly random coefficients a_{i,j} by performing
-+ * rejection sampling on the output stream of
-+ * SHAKE128(rho|j|i).
-+ *
-+ * @param [out] mat output matrix
-+ * @param [in] rho byte array containing seed rho
-+ */
-+static inline void
-+polyvec_matrix_expand(polyvecl mat[LC_DILITHIUM_K],
-+ const uint8_t rho[LC_DILITHIUM_SEEDBYTES], void *ws_buf)
-+{
-+ unsigned int i, j;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ for (j = 0; j < LC_DILITHIUM_L; ++j)
-+ poly_uniform(
-+ &mat[i].vec[j], rho,
-+ le_bswap16((uint16_t)(i << 8) + (uint16_t)j),
-+ ws_buf);
-+}
-+
-+/**
-+ * @brief polyvecl_pointwise_acc_montgomery -
-+ * Pointwise multiply vectors of polynomials of length L, multiply
-+ * resulting vector by 2^{-32} and add (accumulate) polynomials
-+ * in it. Input/output vectors are in NTT domain representation.
-+ *
-+ * @param [out] w output polynomial
-+ * @param [in] u pointer to first input vector
-+ * @param [in] v pointer to second input vector
-+ */
-+static inline void polyvecl_pointwise_acc_montgomery(poly *w, const polyvecl *u,
-+ const polyvecl *v,
-+ void *ws_buf)
-+{
-+ unsigned int i;
-+ poly *t = ws_buf;
-+
-+ poly_pointwise_montgomery(w, &u->vec[0], &v->vec[0]);
-+ for (i = 1; i < LC_DILITHIUM_L; ++i) {
-+ poly_pointwise_montgomery(t, &u->vec[i], &v->vec[i]);
-+ poly_add(w, w, t);
-+ }
-+}
-+
-+static inline void
-+polyvec_matrix_pointwise_montgomery(polyveck *t,
-+ const polyvecl mat[LC_DILITHIUM_K],
-+ const polyvecl *v, void *ws_buf)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_K; ++i)
-+ polyvecl_pointwise_acc_montgomery(&t->vec[i], &mat[i], v,
-+ ws_buf);
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_POLYVEC_C_H */
-diff --git a/lib/freebl/leancrypto/dilithium_reduce.h b/lib/freebl/leancrypto/dilithium_reduce.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_reduce.h
-@@ -0,0 +1,110 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#ifndef DILITHIUM_REDUCE_H
-+#define DILITHIUM_REDUCE_H
-+
-+#include "dilithium_type.h"
-+#include "ext_headers.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#define MONT -4186625 // 2^32 % Q
-+#define QINV 58728449 // q^(-1) mod 2^32
-+
-+/**
-+ * @brief montgomery_reduce - For finite field element a with
-+ * -2^{31}Q <= a <= Q*2^31,
-+ * compute r \equiv a*2^{-32} (mod Q) such that
-+ * -Q < r < Q.
-+ *
-+ * @param [in] a finite field element
-+ *
-+ * @return r
-+ */
-+static inline int32_t montgomery_reduce(int64_t a)
-+{
-+ int32_t t;
-+
-+ t = (int32_t)a * QINV;
-+ t = (int32_t)((a - (int64_t)t * LC_DILITHIUM_Q) >> 32);
-+ return t;
-+}
-+
-+/**
-+ * @brief reduce32 - For finite field element a with a <= 2^{31} - 2^{22} - 1,
-+ * compute r \equiv a (mod Q) such that
-+ * -6283009 <= r <= 6283007.
-+ *
-+ * @param [in] a finite field element
-+ *
-+ * @return r
-+ */
-+static inline int32_t reduce32(int32_t a)
-+{
-+ int32_t t;
-+
-+ t = (a + (1 << 22)) >> 23;
-+ t = a - t * LC_DILITHIUM_Q;
-+ return t;
-+}
-+
-+/**
-+ * @brief caddq - Add Q if input coefficient is negative.
-+ *
-+ * @param [in] a finite field element
-+ *
-+ * @return r
-+ */
-+static inline int32_t caddq(int32_t a)
-+{
-+ a += (a >> 31) & LC_DILITHIUM_Q;
-+ return a;
-+}
-+
-+/**
-+ * @brief freeze - For finite field element a, compute standard representative
-+ * r = a mod^+ Q.
-+ *
-+ * @param [in] a finite field element a
-+ *
-+ * @return r
-+ */
-+static inline int32_t freeze(int32_t a)
-+{
-+ a = reduce32(a);
-+ a = caddq(a);
-+ return a;
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_REDUCE_H */
-diff --git a/lib/freebl/leancrypto/dilithium_rounding.h b/lib/freebl/leancrypto/dilithium_rounding.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_rounding.h
-@@ -0,0 +1,47 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#ifndef DILITHIUM_ROUNDING_H
-+#define DILITHIUM_ROUNDING_H
-+
-+#include "dilithium_type.h"
-+#include "ext_headers.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+int32_t power2round(int32_t *a0, int32_t a);
-+int32_t decompose(int32_t *a0, int32_t a);
-+int32_t make_hint(int32_t a0, int32_t a1);
-+int32_t use_hint(int32_t a, int32_t hint);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_ROUNDING_H */
-diff --git a/lib/freebl/leancrypto/dilithium_service_helpers.h b/lib/freebl/leancrypto/dilithium_service_helpers.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_service_helpers.h
-@@ -0,0 +1,108 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef DILITHIUM_SERVICE_HELPERS_H
-+#define DILITHIUM_SERVICE_HELPERS_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/**
-+ * @brief rej_uniform - Sample uniformly random coefficients in [0, Q-1] by
-+ * performing rejection sampling on array of random bytes.
-+ *
-+ * @param [out] a pointer to output array (allocated)
-+ * @param [in] len number of coefficients to be sampled
-+ * @param [in] buf array of random bytes
-+ * @param [in] buflen length of array of random bytes
-+ *
-+ * @return number of sampled coefficients. Can be smaller than len if not enough
-+ * random bytes were given.
-+ */
-+static inline unsigned int rej_uniform(int32_t *a, unsigned int len,
-+ const uint8_t *buf, unsigned int buflen)
-+{
-+ unsigned int ctr, pos;
-+ uint32_t t;
-+
-+ ctr = pos = 0;
-+ while (ctr < len && pos + 3 <= buflen) {
-+ t = buf[pos++];
-+ t |= (uint32_t)buf[pos++] << 8;
-+ t |= (uint32_t)buf[pos++] << 16;
-+ t &= 0x7FFFFF;
-+
-+ if (t < LC_DILITHIUM_Q)
-+ a[ctr++] = (int32_t)t;
-+ }
-+
-+ return ctr;
-+}
-+
-+/**
-+ * @brief rej_eta - Sample uniformly random coefficients in [-ETA, ETA] by
-+ * performing rejection sampling on array of random bytes.
-+ *
-+ * @param [out] a pointer to output array (allocated)
-+ * @param [in] len number of coefficients to be sampled
-+ * @param [in] buf array of random bytes
-+ * @param [in] buflen length of array of random bytes
-+ *
-+ * @return number of sampled coefficients. Can be smaller than len if not enough
-+ * random bytes were given.
-+ */
-+static inline unsigned int rej_eta(int32_t *a, unsigned int len,
-+ const uint8_t *buf, unsigned int buflen)
-+{
-+ unsigned int ctr, pos;
-+ int32_t t0, t1;
-+
-+ ctr = pos = 0;
-+ while (ctr < len && pos < buflen) {
-+ t0 = buf[pos] & 0x0F;
-+ t1 = buf[pos++] >> 4;
-+
-+#if LC_DILITHIUM_ETA == 2
-+ if (t0 < 15) {
-+ t0 = t0 - (205 * t0 >> 10) * 5;
-+ a[ctr++] = 2 - t0;
-+ }
-+ if (t1 < 15 && ctr < len) {
-+ t1 = t1 - (205 * t1 >> 10) * 5;
-+ a[ctr++] = 2 - t1;
-+ }
-+#elif LC_DILITHIUM_ETA == 4
-+ if (t0 < 9)
-+ a[ctr++] = 4 - t0;
-+ if (t1 < 9 && ctr < len)
-+ a[ctr++] = 4 - t1;
-+#else
-+#error "Undefined LC_DILITHIUM_ETA"
-+#endif
-+ }
-+
-+ return ctr;
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_SERVICE_HELPERS_H */
-diff --git a/lib/freebl/leancrypto/dilithium_signature_c.h b/lib/freebl/leancrypto/dilithium_signature_c.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_signature_c.h
-@@ -0,0 +1,70 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef DILITHIUM_SIGNATURE_C_H
-+#define DILITHIUM_SIGNATURE_C_H
-+
-+#include "dilithium_type.h"
-+#include "lc_rng.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+int lc_dilithium_keypair_c(struct lc_dilithium_pk *pk,
-+ struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+int lc_dilithium_keypair_from_seed_c(struct lc_dilithium_pk *pk,
-+ struct lc_dilithium_sk *sk,
-+ const uint8_t *seed, size_t seedlen);
-+
-+int lc_dilithium_sign_c(struct lc_dilithium_sig *sig, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+int lc_dilithium_sign_ctx_c(struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+int lc_dilithium_sign_init_c(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_sk *sk);
-+int lc_dilithium_sign_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+int lc_dilithium_sign_final_c(struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+int lc_dilithium_verify_c(const struct lc_dilithium_sig *sig, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_pk *pk);
-+int lc_dilithium_verify_ctx_c(const struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_pk *pk);
-+int lc_dilithium_verify_init_c(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_pk *pk);
-+int lc_dilithium_verify_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+int lc_dilithium_verify_final_c(const struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_pk *pk);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_SIGNATURE_C_H */
-diff --git a/lib/freebl/leancrypto/dilithium_signature_impl.h b/lib/freebl/leancrypto/dilithium_signature_impl.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_signature_impl.h
-@@ -0,0 +1,1019 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#ifndef DILITHIUM_SIGNATURE_IMPL_H
-+#define DILITHIUM_SIGNATURE_IMPL_H
-+
-+#include "alignment.h"
-+#include "build_bug_on.h"
-+#include "dilithium_type.h"
-+#include "dilithium_debug.h"
-+#include "dilithium_pack.h"
-+#include "lc_hash.h"
-+#include "lc_memcmp_secure.h"
-+#include "lc_sha3.h"
-+#include "ret_checkers.h"
-+#include "signature_domain_separation.h"
-+#include "small_stack_support.h"
-+#include "static_rng.h"
-+#include "timecop.h"
-+#include "visibility.h"
-+#include "binhexbin.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/*
-+ * Enable this macro to report the rejection code paths taken with the
-+ * signature generation operation. When disabled, the compiler should
-+ * eliminate this code which means that the counting code is folded away.
-+ */
-+#undef REJECTION_TEST_SAMPLING
-+
-+#define _WS_POLY_UNIFORM_BUF_SIZE \
-+ (POLY_UNIFORM_NBLOCKS * LC_SHAKE_128_SIZE_BLOCK + 2)
-+
-+#ifndef LC_POLY_UNIFOR_BUF_SIZE_MULTIPLIER
-+#error "LC_POLY_UNIFOR_BUF_SIZE_MULTIPLIER is not defined"
-+#endif
-+
-+#define WS_POLY_UNIFORM_BUF_SIZE \
-+ (_WS_POLY_UNIFORM_BUF_SIZE * LC_POLY_UNIFOR_BUF_SIZE_MULTIPLIER)
-+
-+static int lc_dilithium_keypair_from_seed_impl(struct lc_dilithium_pk *pk,
-+ struct lc_dilithium_sk *sk,
-+ const uint8_t *seed,
-+ size_t seedlen);
-+
-+static int lc_dilithium_keypair_impl(struct lc_dilithium_pk *pk,
-+ struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ struct workspace {
-+ union {
-+ polyvecl s1, s1hat;
-+ } s1;
-+ union {
-+ polyvecl mat[LC_DILITHIUM_K];
-+ polyveck t0;
-+ } matrix;
-+ polyveck s2, t1;
-+ uint8_t seedbuf[2 * LC_DILITHIUM_SEEDBYTES +
-+ LC_DILITHIUM_CRHBYTES];
-+ union {
-+ poly polyvecl_pointwise_acc_montgomery_buf;
-+ uint8_t poly_uniform_buf[WS_POLY_UNIFORM_BUF_SIZE];
-+ uint8_t poly_uniform_eta_buf[POLY_UNIFORM_ETA_BYTES];
-+ uint8_t tr[LC_DILITHIUM_TRBYTES];
-+ } tmp;
-+ };
-+ static const uint8_t dimension[2] = { LC_DILITHIUM_K, LC_DILITHIUM_L };
-+ const uint8_t *rho, *rhoprime, *key;
-+ int ret;
-+ LC_HASH_CTX_ON_STACK(shake256_ctx, lc_shake256);
-+ LC_DECLARE_MEM(ws, struct workspace, sizeof(uint64_t));
-+
-+ CKNULL(pk, -EINVAL);
-+ CKNULL(sk, -EINVAL);
-+
-+ lc_rng_check(&rng_ctx);
-+
-+ /* Get randomness for rho, rhoprime and key */
-+ CKINT(lc_rng_generate(rng_ctx, NULL, 0, ws->seedbuf,
-+ LC_DILITHIUM_SEEDBYTES));
-+ dilithium_print_buffer(ws->seedbuf, LC_DILITHIUM_SEEDBYTES,
-+ "Keygen - Seed");
-+
-+ lc_hash_init(shake256_ctx);
-+ lc_hash_update(shake256_ctx, ws->seedbuf, LC_DILITHIUM_SEEDBYTES);
-+ lc_hash_update(shake256_ctx, dimension, sizeof(dimension));
-+ lc_hash_set_digestsize(shake256_ctx, sizeof(ws->seedbuf));
-+ lc_hash_final(shake256_ctx, ws->seedbuf);
-+ lc_hash_zero(shake256_ctx);
-+
-+ rho = ws->seedbuf;
-+ dilithium_print_buffer(ws->seedbuf, LC_DILITHIUM_SEEDBYTES,
-+ "Keygen - RHO");
-+ pack_pk_rho(pk, rho);
-+ pack_sk_rho(sk, rho);
-+
-+ /*
-+ * Timecop: RHO' is a random number which is enlarged to sample the
-+ * vectors S1 and S2 from. The sampling operation is not considered
-+ * relevant for the side channel operation as (a) an attacker does not
-+ * have access to the random number and (b) only the result after the
-+ * sampling operation of S1 and S2 is released.
-+ */
-+ rhoprime = rho + LC_DILITHIUM_SEEDBYTES;
-+ dilithium_print_buffer(rhoprime, LC_DILITHIUM_CRHBYTES,
-+ "Keygen - RHOPrime");
-+
-+ key = rhoprime + LC_DILITHIUM_CRHBYTES;
-+ dilithium_print_buffer(key, LC_DILITHIUM_SEEDBYTES, "Keygen - Key");
-+
-+ /* Timecop: key goes into the secret key */
-+ poison(key, LC_DILITHIUM_SEEDBYTES);
-+
-+ pack_sk_key(sk, key);
-+
-+ /* Sample short vectors s1 and s2 */
-+
-+ polyvecl_uniform_eta(&ws->s1.s1, rhoprime, 0,
-+ ws->tmp.poly_uniform_eta_buf);
-+ polyveck_uniform_eta(&ws->s2, rhoprime, LC_DILITHIUM_L,
-+ ws->tmp.poly_uniform_eta_buf);
-+
-+ /* Timecop: s1 and s2 are secret */
-+ poison(&ws->s1.s1, sizeof(polyvecl));
-+ poison(&ws->s2, sizeof(polyveck));
-+
-+ dilithium_print_polyvecl(&ws->s1.s1,
-+ "Keygen - S1 L x N matrix after ExpandS:");
-+ dilithium_print_polyveck(&ws->s2,
-+ "Keygen - S2 K x N matrix after ExpandS:");
-+
-+ pack_sk_s1(sk, &ws->s1.s1);
-+ pack_sk_s2(sk, &ws->s2);
-+
-+ polyvecl_ntt(&ws->s1.s1hat);
-+ dilithium_print_polyvecl(&ws->s1.s1hat,
-+ "Keygen - S1 L x N matrix after NTT:");
-+
-+ /* Expand matrix */
-+ polyvec_matrix_expand(ws->matrix.mat, rho, ws->tmp.poly_uniform_buf);
-+ dilithium_print_polyvecl_k(
-+ ws->matrix.mat, "Keygen - MAT K x L x N matrix after ExpandA:");
-+
-+ polyvec_matrix_pointwise_montgomery(
-+ &ws->t1, ws->matrix.mat, &ws->s1.s1hat,
-+ &ws->tmp.polyvecl_pointwise_acc_montgomery_buf);
-+ dilithium_print_polyveck(&ws->t1,
-+ "Keygen - T K x N matrix after A*NTT(s1):");
-+
-+ polyveck_reduce(&ws->t1);
-+ dilithium_print_polyveck(
-+ &ws->t1, "Keygen - T K x N matrix reduce after A*NTT(s1):");
-+
-+ polyveck_invntt_tomont(&ws->t1);
-+ dilithium_print_polyveck(&ws->t1,
-+ "Keygen - T K x N matrix after NTT-1:");
-+
-+ /* Add error vector s2 */
-+ polyveck_add(&ws->t1, &ws->t1, &ws->s2);
-+ dilithium_print_polyveck(&ws->t1,
-+ "Keygen - T K x N matrix after add S2:");
-+
-+ /* Extract t1 and write public key */
-+ polyveck_caddq(&ws->t1);
-+ dilithium_print_polyveck(&ws->t1, "Keygen - T K x N matrix caddq:");
-+
-+ polyveck_power2round(&ws->t1, &ws->matrix.t0, &ws->t1);
-+ dilithium_print_polyveck(&ws->matrix.t0,
-+ "Keygen - T0 K x N matrix after power2round:");
-+ dilithium_print_polyveck(&ws->t1,
-+ "Keygen - T1 K x N matrix after power2round:");
-+
-+ pack_sk_t0(sk, &ws->matrix.t0);
-+ pack_pk_t1(pk, &ws->t1);
-+ dilithium_print_buffer(pk->pk, LC_DILITHIUM_PUBLICKEYBYTES,
-+ "Keygen - PK after pkEncode:");
-+
-+ /* Compute H(rho, t1) and write secret key */
-+ lc_xof(lc_shake256, pk->pk, sizeof(pk->pk), ws->tmp.tr,
-+ sizeof(ws->tmp.tr));
-+ dilithium_print_buffer(ws->tmp.tr, sizeof(ws->tmp.tr), "Keygen - TR:");
-+ pack_sk_tr(sk, ws->tmp.tr);
-+
-+ dilithium_print_buffer(sk->sk, LC_DILITHIUM_SECRETKEYBYTES,
-+ "Keygen - SK:");
-+
-+ /* Timecop: pk and sk are not relevant for side-channels any more. */
-+ unpoison(pk->pk, sizeof(pk->pk));
-+ unpoison(sk->sk, sizeof(sk->sk));
-+
-+out:
-+ LC_RELEASE_MEM(ws);
-+ return ret;
-+}
-+
-+static int lc_dilithium_keypair_from_seed_impl(struct lc_dilithium_pk *pk,
-+ struct lc_dilithium_sk *sk,
-+ const uint8_t *seed,
-+ size_t seedlen)
-+{
-+ struct lc_static_rng_data s_rng_state;
-+ LC_STATIC_DRNG_ON_STACK(s_drng, &s_rng_state);
-+ int ret;
-+
-+ if (seedlen != LC_DILITHIUM_SEEDBYTES)
-+ return -EINVAL;
-+
-+ /* Set the seed that the key generation can pull via the RNG. */
-+ s_rng_state.seed = seed;
-+ s_rng_state.seedlen = seedlen;
-+
-+ /* Generate the key pair from the seed. */
-+ CKINT(lc_dilithium_keypair_impl(pk, sk, &s_drng));
-+
-+out:
-+ return ret;
-+}
-+
-+static int lc_dilithium_sign_internal_ahat(struct lc_dilithium_sig *sig,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_dilithium_ctx *ctx,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ struct workspace_sign {
-+ polyvecl s1, y, z;
-+ polyveck t0, s2, w1, w0, h;
-+ poly cp;
-+ uint8_t seedbuf[LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_RNDBYTES +
-+ LC_DILITHIUM_CRHBYTES];
-+ union {
-+ uint8_t poly_uniform_gamma1_buf[WS_POLY_UNIFORM_BUF_SIZE];
-+ uint8_t poly_challenge_buf[POLY_CHALLENGE_BYTES];
-+ } tmp;
-+ };
-+ unsigned int n;
-+ uint8_t *key, *mu, *rhoprime, *rnd;
-+ const polyvecl *mat = ctx->ahat;
-+ uint16_t nonce = 0;
-+ int ret = 0;
-+ struct lc_hash_ctx *hash_ctx = &ctx->dilithium_hash_ctx;
-+ uint8_t __maybe_unused rej_total = 0;
-+ LC_DECLARE_MEM(ws, struct workspace_sign, sizeof(uint64_t));
-+
-+ /* AHat must be present at this time */
-+ CKNULL(mat, -EINVAL);
-+
-+ key = ws->seedbuf;
-+ rnd = key + LC_DILITHIUM_SEEDBYTES;
-+ mu = rnd + LC_DILITHIUM_RNDBYTES;
-+
-+ /*
-+ * If the external mu is provided, use this verbatim, otherwise
-+ * calculate the mu value.
-+ */
-+ if (ctx->external_mu) {
-+ if (ctx->external_mu_len != LC_DILITHIUM_CRHBYTES)
-+ return -EINVAL;
-+ memcpy(mu, ctx->external_mu, LC_DILITHIUM_CRHBYTES);
-+ } else {
-+ /*
-+ * Set the digestsize - for SHA512 this is a noop, for SHAKE256,
-+ * it sets the value. The BUILD_BUG_ON is to check that the
-+ * SHA-512 output size is identical to the expected length.
-+ */
-+ BUILD_BUG_ON(LC_DILITHIUM_CRHBYTES != LC_SHA3_512_SIZE_DIGEST);
-+ lc_hash_set_digestsize(hash_ctx, LC_DILITHIUM_CRHBYTES);
-+ lc_hash_final(hash_ctx, mu);
-+ }
-+ dilithium_print_buffer(mu, LC_DILITHIUM_CRHBYTES, "Siggen - MU:");
-+
-+ if (rng_ctx) {
-+ CKINT(lc_rng_generate(rng_ctx, NULL, 0, rnd,
-+ LC_DILITHIUM_RNDBYTES));
-+ } else {
-+ memset(rnd, 0, LC_DILITHIUM_RNDBYTES);
-+ }
-+ dilithium_print_buffer(rnd, LC_DILITHIUM_RNDBYTES, "Siggen - RND:");
-+
-+ unpack_sk_key(key, sk);
-+
-+ /* Timecop: key is secret */
-+ poison(key, LC_DILITHIUM_SEEDBYTES);
-+
-+ /* Re-use the ws->seedbuf, but making sure that mu is unchanged */
-+ BUILD_BUG_ON(LC_DILITHIUM_CRHBYTES >
-+ LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_RNDBYTES);
-+ rhoprime = key;
-+
-+ lc_xof(lc_shake256, key,
-+ LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_RNDBYTES +
-+ LC_DILITHIUM_CRHBYTES,
-+ rhoprime, LC_DILITHIUM_CRHBYTES);
-+ dilithium_print_buffer(rhoprime, LC_DILITHIUM_CRHBYTES,
-+ "Siggen - RHOPrime:");
-+
-+ /*
-+ * Timecop: RHO' is the hash of the secret value of key which is
-+ * enlarged to sample the intermediate vector y from. Due to the hashing
-+ * any side channel on RHO' cannot allow the deduction of the original
-+ * key.
-+ */
-+ unpoison(rhoprime, LC_DILITHIUM_CRHBYTES);
-+
-+ unpack_sk_s1(&ws->s1, sk);
-+
-+ /* Timecop: s1 is secret */
-+ poison(&ws->s1, sizeof(polyvecl));
-+
-+ polyvecl_ntt(&ws->s1);
-+ dilithium_print_polyvecl(&ws->s1,
-+ "Siggen - S1 L x N matrix after NTT:");
-+
-+ unpack_sk_s2(&ws->s2, sk);
-+
-+ /* Timecop: s2 is secret */
-+ poison(&ws->s2, sizeof(polyveck));
-+
-+ polyveck_ntt(&ws->s2);
-+ dilithium_print_polyveck(&ws->s2,
-+ "Siggen - S2 K x N matrix after NTT:");
-+
-+ unpack_sk_t0(&ws->t0, sk);
-+ polyveck_ntt(&ws->t0);
-+ dilithium_print_polyveck(&ws->t0,
-+ "Siggen - T0 K x N matrix after NTT:");
-+
-+rej:
-+ /* Sample intermediate vector y */
-+ polyvecl_uniform_gamma1(&ws->y, rhoprime, nonce++,
-+ ws->tmp.poly_uniform_gamma1_buf);
-+ dilithium_print_polyvecl(
-+ &ws->y,
-+ "Siggen - Y L x N matrix after ExpandMask - start of loop");
-+
-+ /* Timecop: s2 is secret */
-+ poison(&ws->y, sizeof(polyvecl));
-+
-+ /* Matrix-vector multiplication */
-+ ws->z = ws->y;
-+ polyvecl_ntt(&ws->z);
-+
-+ /* Use the cp for this operation as it is not used here so far. */
-+ polyvec_matrix_pointwise_montgomery(&ws->w1, mat, &ws->z, &ws->cp);
-+ polyveck_reduce(&ws->w1);
-+ polyveck_invntt_tomont(&ws->w1);
-+ dilithium_print_polyveck(&ws->w1,
-+ "Siggen - W K x N matrix after NTT-1");
-+
-+ /* Decompose w and call the random oracle */
-+ polyveck_caddq(&ws->w1);
-+ polyveck_decompose(&ws->w1, &ws->w0, &ws->w1);
-+
-+ /* Timecop: the signature component w1 is not sensitive any more. */
-+ unpoison(&ws->w1, sizeof(polyveck));
-+ polyveck_pack_w1(sig->sig, &ws->w1);
-+ dilithium_print_buffer(sig->sig,
-+ LC_DILITHIUM_K * LC_DILITHIUM_POLYW1_PACKEDBYTES,
-+ "Siggen - w1Encode of W1");
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, mu, LC_DILITHIUM_CRHBYTES);
-+ lc_hash_update(hash_ctx, sig->sig,
-+ LC_DILITHIUM_K * LC_DILITHIUM_POLYW1_PACKEDBYTES);
-+ lc_hash_set_digestsize(hash_ctx, LC_DILITHIUM_CTILDE_BYTES);
-+ lc_hash_final(hash_ctx, sig->sig);
-+ lc_hash_zero(hash_ctx);
-+ dilithium_print_buffer(sig->sig, LC_DILITHIUM_CTILDE_BYTES,
-+ "Siggen - ctilde");
-+
-+ poly_challenge(&ws->cp, sig->sig, ws->tmp.poly_challenge_buf);
-+ dilithium_print_poly(&ws->cp, "Siggen - c after SampleInBall");
-+ poly_ntt(&ws->cp);
-+ dilithium_print_poly(&ws->cp, "Siggen - c after NTT");
-+
-+ /* Compute z, reject if it reveals secret */
-+ polyvecl_pointwise_poly_montgomery(&ws->z, &ws->cp, &ws->s1);
-+ polyvecl_invntt_tomont(&ws->z);
-+ polyvecl_add(&ws->z, &ws->z, &ws->y);
-+ dilithium_print_polyvecl(&ws->z, "Siggen - z <- y + cs1");
-+
-+ polyvecl_reduce(&ws->z);
-+ dilithium_print_polyvecl(&ws->z, "Siggen - z reduction");
-+
-+ /* Timecop: the signature component z is not sensitive any more. */
-+ unpoison(&ws->z, sizeof(polyvecl));
-+
-+ if (polyvecl_chknorm(&ws->z, LC_DILITHIUM_GAMMA1 - LC_DILITHIUM_BETA)) {
-+ dilithium_print_polyvecl(&ws->z, "Siggen - z rejection");
-+ rej_total |= 1 << 0;
-+ goto rej;
-+ }
-+
-+ /*
-+ * Check that subtracting cs2 does not change high bits of w and low
-+ * bits do not reveal secret information.
-+ */
-+ polyveck_pointwise_poly_montgomery(&ws->h, &ws->cp, &ws->s2);
-+ polyveck_invntt_tomont(&ws->h);
-+ polyveck_sub(&ws->w0, &ws->w0, &ws->h);
-+ polyveck_reduce(&ws->w0);
-+
-+ /* Timecop: verification data w0 is not sensitive any more. */
-+ unpoison(&ws->w0, sizeof(polyveck));
-+
-+ if (polyveck_chknorm(&ws->w0,
-+ LC_DILITHIUM_GAMMA2 - LC_DILITHIUM_BETA)) {
-+ dilithium_print_polyveck(&ws->w0, "Siggen - r0 rejection");
-+ rej_total |= 1 << 1;
-+ goto rej;
-+ }
-+
-+ /* Compute hints for w1 */
-+ polyveck_pointwise_poly_montgomery(&ws->h, &ws->cp, &ws->t0);
-+ polyveck_invntt_tomont(&ws->h);
-+ polyveck_reduce(&ws->h);
-+
-+ /* Timecop: the signature component h is not sensitive any more. */
-+ unpoison(&ws->h, sizeof(polyveck));
-+
-+ if (polyveck_chknorm(&ws->h, LC_DILITHIUM_GAMMA2)) {
-+ dilithium_print_polyveck(&ws->h, "Siggen - ct0 rejection");
-+ rej_total |= 1 << 2;
-+ goto rej;
-+ }
-+
-+ polyveck_add(&ws->w0, &ws->w0, &ws->h);
-+
-+ n = polyveck_make_hint(&ws->h, &ws->w0, &ws->w1);
-+ if (n > LC_DILITHIUM_OMEGA) {
-+ dilithium_print_polyveck(&ws->w0, "Siggen - h rejection");
-+ rej_total |= 1 << 3;
-+ goto rej;
-+ }
-+
-+ /* Write signature */
-+ dilithium_print_buffer(sig->sig, LC_DILITHIUM_CTILDE_BYTES,
-+ "Siggen - Ctilde:");
-+ dilithium_print_polyvecl(&ws->z, "Siggen - Z L x N matrix:");
-+ dilithium_print_polyveck(&ws->h, "Siggen - H K x N matrix:");
-+
-+ pack_sig(sig, &ws->z, &ws->h);
-+
-+ dilithium_print_buffer(sig->sig, LC_DILITHIUM_CRYPTO_BYTES,
-+ "Siggen - Signature:");
-+
-+out:
-+ LC_RELEASE_MEM(ws);
-+#ifdef REJECTION_TEST_SAMPLING
-+ return ret ? ret : rej_total;
-+#else
-+ return ret;
-+#endif
-+}
-+
-+static int lc_dilithium_sign_internal_noahat(struct lc_dilithium_sig *sig,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_dilithium_ctx *ctx,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ struct workspace_sign {
-+ polyvecl mat[LC_DILITHIUM_K];
-+ uint8_t poly_uniform_buf[WS_POLY_UNIFORM_BUF_SIZE];
-+ };
-+ /* The first bytes of the key is rho. */
-+ const uint8_t *rho = sk->sk;
-+ int ret = 0;
-+ LC_DECLARE_MEM(ws, struct workspace_sign, LC_DILITHIUM_AHAT_ALIGNMENT);
-+
-+ polyvec_matrix_expand(ws->mat, rho, ws->poly_uniform_buf);
-+
-+ /* Temporarily set the pointer */
-+ ctx->ahat = ws->mat;
-+
-+ CKINT(lc_dilithium_sign_internal_ahat(sig, sk, ctx, rng_ctx));
-+
-+out:
-+ ctx->ahat = NULL;
-+ LC_RELEASE_MEM(ws);
-+ return ret;
-+}
-+
-+static int lc_dilithium_sk_expand_impl(const struct lc_dilithium_sk *sk,
-+ struct lc_dilithium_ctx *ctx)
-+{
-+ struct workspace_sign {
-+ uint8_t poly_uniform_buf[WS_POLY_UNIFORM_BUF_SIZE];
-+ };
-+ /* The first bytes of the key is rho. */
-+ const uint8_t *rho = sk->sk;
-+ polyvecl *mat = ctx->ahat;
-+ int ret = 0;
-+ LC_DECLARE_MEM(ws, struct workspace_sign, sizeof(uint64_t));
-+
-+ /*
-+ * The compile time sanity check links API header file with
-+ * Dilithium-internal definitions.
-+ *
-+ * Runtime sanity check ensures that the allocated context has
-+ * sufficient size (e.g. not that caller used, say,
-+ * LC_DILITHIUM_44_CTX_ON_STACK_AHAT with a ML-DSA 65 or 87 key)
-+ */
-+#if LC_DILITHIUM_MODE == 2
-+ BUILD_BUG_ON(LC_DILITHIUM_44_AHAT_SIZE !=
-+ sizeof(polyvecl) * LC_DILITHIUM_K);
-+ if (ctx->ahat_size < LC_DILITHIUM_44_AHAT_SIZE) {
-+ ret = -EOVERFLOW;
-+ goto out;
-+ }
-+#elif LC_DILITHIUM_MODE == 3
-+ BUILD_BUG_ON(LC_DILITHIUM_65_AHAT_SIZE !=
-+ sizeof(polyvecl) * LC_DILITHIUM_K);
-+ if (ctx->ahat_size < LC_DILITHIUM_65_AHAT_SIZE) {
-+ ret = -EOVERFLOW;
-+ goto out;
-+ }
-+#elif LC_DILITHIUM_MODE == 5
-+ BUILD_BUG_ON(LC_DILITHIUM_87_AHAT_SIZE !=
-+ sizeof(polyvecl) * LC_DILITHIUM_K);
-+ if (ctx->ahat_size < LC_DILITHIUM_87_AHAT_SIZE) {
-+ ret = -EOVERFLOW;
-+ goto out;
-+ }
-+#else
-+#error "Undefined LC_DILITHIUM_MODE"
-+#endif
-+
-+ polyvec_matrix_expand(mat, rho, ws->poly_uniform_buf);
-+ dilithium_print_polyvecl_k(mat,
-+ "AHAT - A K x L x N matrix after ExpandA:");
-+
-+ ctx->ahat_expanded = 1;
-+
-+out:
-+ LC_RELEASE_MEM(ws);
-+ return ret;
-+}
-+
-+static int lc_dilithium_sign_internal(struct lc_dilithium_sig *sig,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_dilithium_ctx *ctx,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ int ret;
-+
-+ if (!ctx->ahat)
-+ return lc_dilithium_sign_internal_noahat(sig, sk, ctx, rng_ctx);
-+
-+ if (!ctx->ahat_expanded)
-+ CKINT(lc_dilithium_sk_expand_impl(sk, ctx));
-+
-+ CKINT(lc_dilithium_sign_internal_ahat(sig, sk, ctx, rng_ctx));
-+
-+out:
-+ return ret;
-+}
-+
-+static int lc_dilithium_sign_ctx_impl(struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ uint8_t tr[LC_DILITHIUM_TRBYTES];
-+ int ret = 0;
-+
-+ /* rng_ctx is allowed to be NULL as handled below */
-+ if (!sig || !sk || !ctx)
-+ return -EINVAL;
-+ /* Either the message or the external mu must be provided */
-+ if (!m && !ctx->external_mu)
-+ return -EINVAL;
-+
-+ dilithium_print_buffer(m, mlen, "Siggen - Message");
-+
-+ unpack_sk_tr(tr, sk);
-+
-+ if (m) {
-+ /* Compute mu = CRH(tr, msg) */
-+ struct lc_hash_ctx *hash_ctx = &ctx->dilithium_hash_ctx;
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, tr, LC_DILITHIUM_TRBYTES);
-+
-+ CKINT(signature_domain_separation(
-+ &ctx->dilithium_hash_ctx, ctx->ml_dsa_internal,
-+ ctx->dilithium_prehash_type, ctx->userctx,
-+ ctx->userctxlen, m, mlen, ctx->randomizer,
-+ ctx->randomizerlen, LC_DILITHIUM_NIST_CATEGORY));
-+ }
-+
-+ ret = lc_dilithium_sign_internal(sig, sk, ctx, rng_ctx);
-+
-+out:
-+ lc_memset_secure(tr, 0, sizeof(tr));
-+ return ret;
-+}
-+
-+static int lc_dilithium_sign_impl(struct lc_dilithium_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ LC_DILITHIUM_CTX_ON_STACK(dilithium_ctx);
-+ int ret = lc_dilithium_sign_ctx_impl(sig, dilithium_ctx, m, mlen, sk,
-+ rng_ctx);
-+
-+ lc_dilithium_ctx_zero(dilithium_ctx);
-+ return ret;
-+}
-+
-+static int lc_dilithium_sign_init_impl(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_sk *sk)
-+{
-+ uint8_t tr[LC_DILITHIUM_TRBYTES];
-+ struct lc_hash_ctx *hash_ctx;
-+
-+ /* rng_ctx is allowed to be NULL as handled below */
-+ if (!ctx || !sk)
-+ return -EINVAL;
-+
-+ hash_ctx = &ctx->dilithium_hash_ctx;
-+
-+ /* Require the use of SHAKE256 */
-+ if (hash_ctx->hash != lc_shake256)
-+ return -EOPNOTSUPP;
-+
-+ unpack_sk_tr(tr, sk);
-+
-+ /* Compute mu = CRH(tr, msg) */
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, tr, LC_DILITHIUM_TRBYTES);
-+ lc_memset_secure(tr, 0, sizeof(tr));
-+
-+ return signature_domain_separation(
-+ &ctx->dilithium_hash_ctx, ctx->ml_dsa_internal,
-+ ctx->dilithium_prehash_type, ctx->userctx, ctx->userctxlen,
-+ NULL, 0, ctx->randomizer, ctx->randomizerlen,
-+ LC_DILITHIUM_NIST_CATEGORY);
-+}
-+
-+static int lc_dilithium_sign_update_impl(struct lc_dilithium_ctx *ctx,
-+ const uint8_t *m, size_t mlen)
-+{
-+ if (!ctx || !m)
-+ return -EINVAL;
-+
-+ /* Compute CRH(tr, msg) */
-+ lc_hash_update(&ctx->dilithium_hash_ctx, m, mlen);
-+
-+ return 0;
-+}
-+
-+static int lc_dilithium_sign_final_impl(struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ int ret = 0;
-+
-+ /* rng_ctx is allowed to be NULL as handled below */
-+ if (!sig || !ctx || !sk) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ ret = lc_dilithium_sign_internal(sig, sk, ctx, rng_ctx);
-+
-+out:
-+ lc_dilithium_ctx_zero(ctx);
-+ return ret;
-+}
-+
-+static int lc_dilithium_verify_internal_ahat(const struct lc_dilithium_sig *sig,
-+ const struct lc_dilithium_pk *pk,
-+ struct lc_dilithium_ctx *ctx)
-+{
-+ struct workspace_verify {
-+ union {
-+ poly cp;
-+ } matrix;
-+ polyveck w1;
-+ union {
-+ polyveck t1, h;
-+ polyvecl z;
-+ uint8_t mu[LC_DILITHIUM_CRHBYTES];
-+ BUF_ALIGNED_UINT8_UINT64(LC_DILITHIUM_CTILDE_BYTES) c2;
-+ } buf;
-+
-+ union {
-+ poly polyvecl_pointwise_acc_montgomery_buf;
-+ uint8_t buf[LC_DILITHIUM_K *
-+ LC_DILITHIUM_POLYW1_PACKEDBYTES];
-+ uint8_t poly_challenge_buf[POLY_CHALLENGE_BYTES];
-+ } tmp;
-+ };
-+ /* The first bytes of the signature is c~ and thus contains c1. */
-+ const uint8_t *c1 = sig->sig;
-+ const polyvecl *mat = ctx->ahat;
-+ struct lc_hash_ctx *hash_ctx = &ctx->dilithium_hash_ctx;
-+ int ret = 0;
-+ LC_DECLARE_MEM(ws, struct workspace_verify, sizeof(uint64_t));
-+
-+ /* AHat must be present at this time */
-+ CKNULL(mat, -EINVAL);
-+
-+ unpack_sig_z(&ws->buf.z, sig);
-+ if (polyvecl_chknorm(&ws->buf.z,
-+ LC_DILITHIUM_GAMMA1 - LC_DILITHIUM_BETA)) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ polyvecl_ntt(&ws->buf.z);
-+ polyvec_matrix_pointwise_montgomery(
-+ &ws->w1, mat, &ws->buf.z,
-+ &ws->tmp.polyvecl_pointwise_acc_montgomery_buf);
-+
-+ /* Matrix-vector multiplication; compute Az - c2^dt1 */
-+ poly_challenge(&ws->matrix.cp, c1, ws->tmp.poly_challenge_buf);
-+ poly_ntt(&ws->matrix.cp);
-+
-+ unpack_pk_t1(&ws->buf.t1, pk);
-+ polyveck_shiftl(&ws->buf.t1);
-+ polyveck_ntt(&ws->buf.t1);
-+ polyveck_pointwise_poly_montgomery(&ws->buf.t1, &ws->matrix.cp,
-+ &ws->buf.t1);
-+
-+ polyveck_sub(&ws->w1, &ws->w1, &ws->buf.t1);
-+ polyveck_reduce(&ws->w1);
-+ polyveck_invntt_tomont(&ws->w1);
-+
-+ /* Reconstruct w1 */
-+ polyveck_caddq(&ws->w1);
-+ dilithium_print_polyveck(&ws->w1,
-+ "Sigver - W K x N matrix before hint:");
-+
-+ if (unpack_sig_h(&ws->buf.h, sig))
-+ return -EINVAL;
-+ dilithium_print_polyveck(&ws->buf.h, "Siggen - H K x N matrix:");
-+
-+ polyveck_use_hint(&ws->w1, &ws->w1, &ws->buf.h);
-+ dilithium_print_polyveck(&ws->w1,
-+ "Sigver - W K x N matrix after hint:");
-+ polyveck_pack_w1(ws->tmp.buf, &ws->w1);
-+ dilithium_print_buffer(ws->tmp.buf,
-+ LC_DILITHIUM_K * LC_DILITHIUM_POLYW1_PACKEDBYTES,
-+ "Sigver - W after w1Encode");
-+
-+ if (ctx->external_mu) {
-+ if (ctx->external_mu_len != LC_DILITHIUM_CRHBYTES)
-+ return -EINVAL;
-+
-+ /* Call random oracle and verify challenge */
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, ctx->external_mu,
-+ LC_DILITHIUM_CRHBYTES);
-+ } else {
-+ lc_hash_set_digestsize(hash_ctx, LC_DILITHIUM_CRHBYTES);
-+ lc_hash_final(hash_ctx, ws->buf.mu);
-+
-+ /* Call random oracle and verify challenge */
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, ws->buf.mu, LC_DILITHIUM_CRHBYTES);
-+ }
-+
-+ lc_hash_update(hash_ctx, ws->tmp.buf,
-+ LC_DILITHIUM_K * LC_DILITHIUM_POLYW1_PACKEDBYTES);
-+ lc_hash_set_digestsize(hash_ctx, LC_DILITHIUM_CTILDE_BYTES);
-+ lc_hash_final(hash_ctx, ws->buf.c2.coeffs);
-+ lc_hash_zero(hash_ctx);
-+
-+ /* Signature verification operation */
-+ if (lc_memcmp_secure(c1, LC_DILITHIUM_CTILDE_BYTES, ws->buf.c2.coeffs,
-+ LC_DILITHIUM_CTILDE_BYTES))
-+ ret = -EBADMSG;
-+
-+out:
-+ LC_RELEASE_MEM(ws);
-+ return ret;
-+}
-+
-+static int
-+lc_dilithium_verify_internal_noahat(const struct lc_dilithium_sig *sig,
-+ const struct lc_dilithium_pk *pk,
-+ struct lc_dilithium_ctx *ctx)
-+{
-+ struct workspace_verify {
-+ polyvecl mat[LC_DILITHIUM_K];
-+ uint8_t poly_uniform_buf[WS_POLY_UNIFORM_BUF_SIZE];
-+ };
-+ /* The first bytes of the key is rho. */
-+ const uint8_t *rho = pk->pk;
-+ int ret = 0;
-+ LC_DECLARE_MEM(ws, struct workspace_verify, sizeof(uint64_t));
-+
-+ polyvec_matrix_expand(ws->mat, rho, ws->poly_uniform_buf);
-+
-+ /* Temporarily set the pointer */
-+ ctx->ahat = ws->mat;
-+
-+ CKINT(lc_dilithium_verify_internal_ahat(sig, pk, ctx));
-+
-+out:
-+ ctx->ahat = NULL;
-+ LC_RELEASE_MEM(ws);
-+ return ret;
-+}
-+
-+static int lc_dilithium_pk_expand_impl(const struct lc_dilithium_pk *pk,
-+ struct lc_dilithium_ctx *ctx)
-+{
-+ struct workspace_verify {
-+ uint8_t poly_uniform_buf[WS_POLY_UNIFORM_BUF_SIZE];
-+ };
-+ /* The first bytes of the key is rho. */
-+ const uint8_t *rho = pk->pk;
-+ polyvecl *mat = ctx->ahat;
-+ int ret = 0;
-+ LC_DECLARE_MEM(ws, struct workspace_verify, sizeof(uint64_t));
-+
-+ /*
-+ * Runtime sanity check ensures that the allocated context has
-+ * sufficient size (e.g. not that caller used, say,
-+ * LC_DILITHIUM_44_CTX_ON_STACK_AHAT with a ML-DSA 65 or 87 key)
-+ */
-+#if LC_DILITHIUM_MODE == 2
-+ if (ctx->ahat_size < LC_DILITHIUM_44_AHAT_SIZE) {
-+ ret = -EOVERFLOW;
-+ goto out;
-+ }
-+#elif LC_DILITHIUM_MODE == 3
-+ if (ctx->ahat_size < LC_DILITHIUM_65_AHAT_SIZE) {
-+ ret = -EOVERFLOW;
-+ goto out;
-+ }
-+#elif LC_DILITHIUM_MODE == 5
-+ if (ctx->ahat_size < LC_DILITHIUM_87_AHAT_SIZE) {
-+ ret = -EOVERFLOW;
-+ goto out;
-+ }
-+#else
-+#error "Undefined LC_DILITHIUM_MODE"
-+#endif
-+
-+ polyvec_matrix_expand(mat, rho, ws->poly_uniform_buf);
-+ ctx->ahat_expanded = 1;
-+
-+out:
-+ LC_RELEASE_MEM(ws);
-+ return ret;
-+}
-+
-+static int lc_dilithium_verify_internal(const struct lc_dilithium_sig *sig,
-+ const struct lc_dilithium_pk *pk,
-+ struct lc_dilithium_ctx *ctx)
-+{
-+ int ret;
-+
-+ if (!ctx->ahat)
-+ return lc_dilithium_verify_internal_noahat(sig, pk, ctx);
-+
-+ if (!ctx->ahat_expanded)
-+ CKINT(lc_dilithium_pk_expand_impl(pk, ctx));
-+
-+ CKINT(lc_dilithium_verify_internal_ahat(sig, pk, ctx));
-+
-+out:
-+ return ret;
-+}
-+
-+static int lc_dilithium_verify_ctx_impl(const struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_pk *pk)
-+{
-+ uint8_t tr[LC_DILITHIUM_TRBYTES];
-+ int ret = 0;
-+
-+ if (!sig || !pk || !ctx)
-+ return -EINVAL;
-+
-+ /* Either the message or the external mu must be provided */
-+ if (!m && !ctx->external_mu)
-+ return -EINVAL;
-+
-+ /* Make sure that ->mu is large enough for ->tr */
-+ BUILD_BUG_ON(LC_DILITHIUM_TRBYTES > LC_DILITHIUM_CRHBYTES);
-+
-+ /* Compute CRH(H(rho, t1), msg) */
-+ lc_xof(lc_shake256, pk->pk, LC_DILITHIUM_PUBLICKEYBYTES, tr,
-+ LC_DILITHIUM_TRBYTES);
-+
-+ if (m) {
-+ struct lc_hash_ctx *hash_ctx = &ctx->dilithium_hash_ctx;
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, tr, LC_DILITHIUM_TRBYTES);
-+ CKINT(signature_domain_separation(
-+ &ctx->dilithium_hash_ctx, ctx->ml_dsa_internal,
-+ ctx->dilithium_prehash_type, ctx->userctx,
-+ ctx->userctxlen, m, mlen, ctx->randomizer,
-+ ctx->randomizerlen, LC_DILITHIUM_NIST_CATEGORY));
-+ }
-+
-+ ret = lc_dilithium_verify_internal(sig, pk, ctx);
-+
-+out:
-+ lc_memset_secure(tr, 0, sizeof(tr));
-+ return ret;
-+}
-+
-+static int lc_dilithium_verify_impl(const struct lc_dilithium_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_pk *pk)
-+{
-+ LC_DILITHIUM_CTX_ON_STACK(ctx);
-+ int ret = lc_dilithium_verify_ctx_impl(sig, ctx, m, mlen, pk);
-+
-+ lc_dilithium_ctx_zero(ctx);
-+ return ret;
-+}
-+
-+static int lc_dilithium_verify_init_impl(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_pk *pk)
-+{
-+ uint8_t mu[LC_DILITHIUM_TRBYTES];
-+ struct lc_hash_ctx *hash_ctx;
-+
-+ /* rng_ctx is allowed to be NULL as handled below */
-+ if (!ctx || !pk)
-+ return -EINVAL;
-+
-+ hash_ctx = &ctx->dilithium_hash_ctx;
-+
-+ /* Require the use of SHAKE256 */
-+ if (hash_ctx->hash != lc_shake256)
-+ return -EOPNOTSUPP;
-+
-+ /* Compute CRH(H(rho, t1), msg) */
-+ lc_xof(lc_shake256, pk->pk, LC_DILITHIUM_PUBLICKEYBYTES, mu,
-+ LC_DILITHIUM_TRBYTES);
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, mu, LC_DILITHIUM_TRBYTES);
-+ lc_memset_secure(mu, 0, sizeof(mu));
-+
-+ return signature_domain_separation(
-+ &ctx->dilithium_hash_ctx, ctx->ml_dsa_internal,
-+ ctx->dilithium_prehash_type, ctx->userctx, ctx->userctxlen,
-+ NULL, 0, ctx->randomizer, ctx->randomizerlen,
-+ LC_DILITHIUM_NIST_CATEGORY);
-+}
-+
-+static int lc_dilithium_verify_update_impl(struct lc_dilithium_ctx *ctx,
-+ const uint8_t *m, size_t mlen)
-+{
-+ struct lc_hash_ctx *hash_ctx;
-+
-+ if (!ctx || !m)
-+ return -EINVAL;
-+
-+ /* Compute CRH(H(rho, t1), msg) */
-+ hash_ctx = &ctx->dilithium_hash_ctx;
-+ lc_hash_update(hash_ctx, m, mlen);
-+
-+ return 0;
-+}
-+
-+static int lc_dilithium_verify_final_impl(const struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_pk *pk)
-+{
-+ int ret = 0;
-+
-+ if (!sig || !ctx || !pk) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+
-+ ret = lc_dilithium_verify_internal(sig, pk, ctx);
-+
-+out:
-+ lc_dilithium_ctx_zero(ctx);
-+ return ret;
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_SIGNATURE_IMPL_H */
-diff --git a/lib/freebl/leancrypto/dilithium_type.h b/lib/freebl/leancrypto/dilithium_type.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_type.h
-@@ -0,0 +1,349 @@
-+/*
-+ * Copyright (C) 2024 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef DILITHIUM_TYPE_H
-+#define DILITHIUM_TYPE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/* Prevent Dilithium macros from getting undefined */
-+#define LC_DILITHIUM_INTERNAL
-+
-+/*
-+ * This define replaces all symbol names accordingly to allow double compilation
-+ * of the same code base.
-+ *
-+ * Due to the replacement operation, this header file must be included as the
-+ * first header file in the entire stack.
-+ *
-+ * This file can easily be replaced with lc_dilithium.h to achieve the common
-+ * functionality without symbol duplication. But in this case, only the
-+ * Dilithium security strength is compiled defined in lc_dilithium.h. Duplicate
-+ * compilation different sizes would not be possible.
-+ */
-+#ifdef LC_DILITHIUM_TYPE_65
-+#define DILITHIUM_F(name) lc_dilithium_65_##name
-+#define lc_dilithium_pk lc_dilithium_65_pk
-+#define lc_dilithium_sk lc_dilithium_65_sk
-+#define lc_dilithium_sig lc_dilithium_65_sig
-+#define lc_dilithium_ed25519_pk lc_dilithium_65_ed25519_pk
-+#define lc_dilithium_ed25519_sk lc_dilithium_65_ed25519_sk
-+#define lc_dilithium_ed25519_sig lc_dilithium_65_ed25519_sig
-+#define lc_dilithium_ed25519_ctx lc_dilithium_65_ed25519_ctx
-+#define lc_dilithium_ed448_pk lc_dilithium_65_ed448_pk
-+#define lc_dilithium_ed448_sk lc_dilithium_65_ed448_sk
-+#define lc_dilithium_ed448_sig lc_dilithium_65_ed448_sig
-+#define lc_dilithium_ed448_ctx lc_dilithium_65_ed448_ctx
-+
-+#include "lc_dilithium_65.h"
-+
-+#elif defined LC_DILITHIUM_TYPE_44
-+#define DILITHIUM_F(name) lc_dilithium_44_##name
-+#define lc_dilithium_pk lc_dilithium_44_pk
-+#define lc_dilithium_sk lc_dilithium_44_sk
-+#define lc_dilithium_sig lc_dilithium_44_sig
-+#define lc_dilithium_ed25519_pk lc_dilithium_44_ed25519_pk
-+#define lc_dilithium_ed25519_sk lc_dilithium_44_ed25519_sk
-+#define lc_dilithium_ed25519_sig lc_dilithium_44_ed25519_sig
-+#define lc_dilithium_ed25519_ctx lc_dilithium_44_ed25519_ctx
-+#define lc_dilithium_ed448_pk lc_dilithium_44_ed448_pk
-+#define lc_dilithium_ed448_sk lc_dilithium_44_ed448_sk
-+#define lc_dilithium_ed448_sig lc_dilithium_44_ed448_sig
-+#define lc_dilithium_ed448_ctx lc_dilithium_44_ed448_ctx
-+
-+#include "lc_dilithium_44.h"
-+
-+#else
-+#define DILITHIUM_F(name) lc_dilithium_87_##name
-+#define lc_dilithium_pk lc_dilithium_87_pk
-+#define lc_dilithium_sk lc_dilithium_87_sk
-+#define lc_dilithium_sig lc_dilithium_87_sig
-+#define lc_dilithium_ed25519_pk lc_dilithium_87_ed25519_pk
-+#define lc_dilithium_ed25519_sk lc_dilithium_87_ed25519_sk
-+#define lc_dilithium_ed25519_sig lc_dilithium_87_ed25519_sig
-+#define lc_dilithium_ed25519_ctx lc_dilithium_87_ed25519_ctx
-+#define lc_dilithium_ed448_pk lc_dilithium_87_ed448_pk
-+#define lc_dilithium_ed448_sk lc_dilithium_87_ed448_sk
-+#define lc_dilithium_ed448_sig lc_dilithium_87_ed448_sig
-+#define lc_dilithium_ed448_ctx lc_dilithium_87_ed448_ctx
-+
-+#include "lc_dilithium_87.h"
-+
-+#endif
-+
-+/*
-+ * The following defines simply allow duplicate compilation of the
-+ * respective functions.
-+ */
-+#define lc_dilithium_keypair DILITHIUM_F(keypair)
-+#define lc_dilithium_keypair_from_seed DILITHIUM_F(keypair_from_seed)
-+#define lc_dilithium_sign DILITHIUM_F(sign)
-+#define lc_dilithium_sign_ctx DILITHIUM_F(sign_ctx)
-+#define lc_dilithium_sign_init DILITHIUM_F(sign_init)
-+#define lc_dilithium_sign_update DILITHIUM_F(sign_update)
-+#define lc_dilithium_sign_final DILITHIUM_F(sign_final)
-+#define lc_dilithium_verify DILITHIUM_F(verify)
-+#define lc_dilithium_verify_ctx DILITHIUM_F(verify_ctx)
-+#define lc_dilithium_verify_init DILITHIUM_F(verify_init)
-+#define lc_dilithium_verify_update DILITHIUM_F(verify_update)
-+#define lc_dilithium_verify_final DILITHIUM_F(verify_final)
-+#define lc_dilithium_ctx_alloc DILITHIUM_F(ctx_alloc)
-+#define lc_dilithium_ctx_alloc_ahat DILITHIUM_F(ctx_alloc_ahat)
-+#define lc_dilithium_ctx_zero_free DILITHIUM_F(ctx_zero_free)
-+#define lc_dilithium_ctx_zero DILITHIUM_F(ctx_zero)
-+
-+#define lc_dilithium_keypair_c DILITHIUM_F(keypair_c)
-+#define lc_dilithium_keypair_from_seed_c DILITHIUM_F(keypair_from_seed_c)
-+#define lc_dilithium_sign_c DILITHIUM_F(sign_c)
-+#define lc_dilithium_sign_ctx_c DILITHIUM_F(sign_ctx_c)
-+#define lc_dilithium_sign_init_c DILITHIUM_F(sign_init_c)
-+#define lc_dilithium_sign_update_c DILITHIUM_F(sign_update_c)
-+#define lc_dilithium_sign_final_c DILITHIUM_F(sign_final_c)
-+#define lc_dilithium_verify_c DILITHIUM_F(verify_c)
-+#define lc_dilithium_verify_ctx_c DILITHIUM_F(verify_ctx_c)
-+#define lc_dilithium_verify_init_c DILITHIUM_F(verify_init_c)
-+#define lc_dilithium_verify_update_c DILITHIUM_F(verify_update_c)
-+#define lc_dilithium_verify_final_c DILITHIUM_F(verify_final_c)
-+
-+#define lc_dilithium_ed25519_keypair DILITHIUM_F(ed25519_keypair)
-+#define lc_dilithium_ed25519_sign DILITHIUM_F(ed25519_sign)
-+#define lc_dilithium_ed25519_sign_ctx DILITHIUM_F(ed25519_sign_ctx)
-+#define lc_dilithium_ed25519_sign_init DILITHIUM_F(ed25519_sign_init)
-+#define lc_dilithium_ed25519_sign_update DILITHIUM_F(ed25519_sign_update)
-+#define lc_dilithium_ed25519_sign_final DILITHIUM_F(ed25519_sign_final)
-+#define lc_dilithium_ed25519_verify DILITHIUM_F(ed25519_verify)
-+#define lc_dilithium_ed25519_verify_ctx DILITHIUM_F(ed25519_verify_ctx)
-+#define lc_dilithium_ed25519_verify_init DILITHIUM_F(ed25519_verify_init)
-+#define lc_dilithium_ed25519_verify_update DILITHIUM_F(ed25519_verify_update)
-+#define lc_dilithium_ed25519_verify_final DILITHIUM_F(ed25519_verify_final)
-+#define lc_dilithium_ed25519_ctx_alloc DILITHIUM_F(ed25519_ctx_alloc)
-+#define lc_dilithium_ed25519_ctx_zero_free DILITHIUM_F(ed25519_ctx_zero_free)
-+#define lc_dilithium_ed25519_ctx_zero DILITHIUM_F(ed25519_ctx_zero)
-+
-+#define lc_dilithium_ed448_keypair DILITHIUM_F(ed448_keypair)
-+#define lc_dilithium_ed448_sign DILITHIUM_F(ed448_sign)
-+#define lc_dilithium_ed448_sign_ctx DILITHIUM_F(ed448_sign_ctx)
-+#define lc_dilithium_ed448_sign_init DILITHIUM_F(ed448_sign_init)
-+#define lc_dilithium_ed448_sign_update DILITHIUM_F(ed448_sign_update)
-+#define lc_dilithium_ed448_sign_final DILITHIUM_F(ed448_sign_final)
-+#define lc_dilithium_ed448_verify DILITHIUM_F(ed448_verify)
-+#define lc_dilithium_ed448_verify_ctx DILITHIUM_F(ed448_verify_ctx)
-+#define lc_dilithium_ed448_verify_init DILITHIUM_F(ed448_verify_init)
-+#define lc_dilithium_ed448_verify_update DILITHIUM_F(ed448_verify_update)
-+#define lc_dilithium_ed448_verify_final DILITHIUM_F(ed448_verify_final)
-+#define lc_dilithium_ed448_ctx_alloc DILITHIUM_F(ed448_ctx_alloc)
-+#define lc_dilithium_ed448_ctx_zero_free DILITHIUM_F(ed448_ctx_zero_free)
-+#define lc_dilithium_ed448_ctx_zero DILITHIUM_F(ed448_ctx_zero)
-+
-+#define dilithium_keypair_tester DILITHIUM_F(keypair_tester)
-+#define dilithium_siggen_tester DILITHIUM_F(siggen_tester)
-+#define dilithium_sigver_tester DILITHIUM_F(sigver_tester)
-+
-+#define ntt DILITHIUM_F(ntt)
-+#define invntt_tomont DILITHIUM_F(invntt_tomont)
-+#define poly_chknorm DILITHIUM_F(poly_chknorm)
-+#define poly_uniform DILITHIUM_F(poly_uniform)
-+#define poly_uniform_eta DILITHIUM_F(poly_uniform_eta)
-+#define poly_uniform_gamma1 DILITHIUM_F(poly_uniform_gamma1)
-+#define polyz_unpack DILITHIUM_F(polyz_unpack)
-+#define poly_challenge DILITHIUM_F(poly_challenge)
-+#define polyeta_pack DILITHIUM_F(polyeta_pack)
-+#define polyeta_unpack DILITHIUM_F(polyeta_unpack)
-+#define polyt1_pack DILITHIUM_F(polyt1_pack)
-+#define polyt0_pack DILITHIUM_F(polyt0_pack)
-+#define polyt0_unpack DILITHIUM_F(polyt0_unpack)
-+#define polyz_pack DILITHIUM_F(polyz_pack)
-+#define polyw1_pack DILITHIUM_F(polyw1_pack)
-+#define power2round DILITHIUM_F(power2round)
-+#define decompose DILITHIUM_F(decompose)
-+#define make_hint DILITHIUM_F(make_hint)
-+#define use_hint DILITHIUM_F(use_hint)
-+
-+#define dilithium_print_buffer DILITHIUM_F(print_buffer)
-+#define dilithium_print_polyvecl_k DILITHIUM_F(print_polyvecl_k)
-+#define dilithium_print_polyvecl DILITHIUM_F(print_polyvecl)
-+#define dilithium_print_polyveck DILITHIUM_F(print_polyveck)
-+#define dilithium_print_poly DILITHIUM_F(print_poly)
-+
-+/* AVX2 Implementation */
-+#define dilithium_invntt_avx DILITHIUM_F(invntt_avx)
-+#define dilithium_ntt_avx DILITHIUM_F(ntt_avx)
-+#define dilithium_nttunpack_avx DILITHIUM_F(nttunpack_avx)
-+#define dilithium_pointwise_avx DILITHIUM_F(pointwise_avx)
-+#define dilithium_pointwise_acc_avx DILITHIUM_F(pointwise_acc_avx)
-+#define poly_reduce_avx DILITHIUM_F(poly_reduce_avx)
-+#define poly_caddq_avx DILITHIUM_F(poly_caddq_avx)
-+#define poly_add_avx DILITHIUM_F(poly_add_avx)
-+#define poly_sub_avx DILITHIUM_F(poly_sub_avx)
-+#define poly_shiftl_avx DILITHIUM_F(poly_shiftl_avx)
-+#define poly_chknorm_avx DILITHIUM_F(poly_chknorm_avx)
-+#define poly_uniform_4x_avx DILITHIUM_F(poly_uniform_4x_avx)
-+#define poly_uniform_eta_4x_avx DILITHIUM_F(poly_uniform_eta_4x_avx)
-+#define poly_uniform_gamma1_4x_avx DILITHIUM_F(poly_uniform_gamma1_4x_avx)
-+#define polyz_unpack_avx DILITHIUM_F(polyz_unpack_avx)
-+#define poly_challenge_avx DILITHIUM_F(poly_challenge_avx)
-+#define polyeta_pack_avx DILITHIUM_F(polyeta_pack_avx)
-+#define polyeta_unpack_avx DILITHIUM_F(polyeta_unpack_avx)
-+#define polyt1_pack_avx DILITHIUM_F(polyt1_pack_avx)
-+#define polyt1_unpack_avx DILITHIUM_F(polyt1_unpack_avx)
-+#define polyt0_pack_avx DILITHIUM_F(polyt0_pack_avx)
-+#define polyt0_unpack_avx DILITHIUM_F(polyt0_unpack_avx)
-+#define polyz_pack_avx DILITHIUM_F(polyz_pack_avx)
-+#define polyw1_pack_avx DILITHIUM_F(polyw1_pack_avx)
-+#define polyvec_matrix_expand DILITHIUM_F(polyvec_matrix_expand)
-+#define polyvec_matrix_expand_row0 DILITHIUM_F(polyvec_matrix_expand_row0)
-+#define polyvec_matrix_expand_row1 DILITHIUM_F(polyvec_matrix_expand_row1)
-+#define polyvec_matrix_expand_row2 DILITHIUM_F(polyvec_matrix_expand_row2)
-+#define polyvec_matrix_expand_row3 DILITHIUM_F(polyvec_matrix_expand_row3)
-+#define polyvec_matrix_expand_row4 DILITHIUM_F(polyvec_matrix_expand_row4)
-+#define polyvec_matrix_expand_row5 DILITHIUM_F(polyvec_matrix_expand_row5)
-+#define polyvec_matrix_expand_row6 DILITHIUM_F(polyvec_matrix_expand_row6)
-+#define polyvec_matrix_expand_row7 DILITHIUM_F(polyvec_matrix_expand_row7)
-+#define rej_uniform_avx DILITHIUM_F(rej_uniform_avx)
-+#define rej_eta_avx DILITHIUM_F(rej_eta_avx)
-+#define idxlut DILITHIUM_F(idxlut)
-+#define power2round_avx DILITHIUM_F(power2round_avx)
-+#define decompose_avx DILITHIUM_F(decompose_avx)
-+#define make_hint_avx DILITHIUM_F(make_hint_avx)
-+#define use_hint_avx DILITHIUM_F(use_hint_avx)
-+#define lc_dilithium_keypair_avx2 DILITHIUM_F(keypair_avx2)
-+#define lc_dilithium_keypair_from_seed_avx2 DILITHIUM_F(keypair_from_seed_avx2)
-+#define lc_dilithium_sign_avx2 DILITHIUM_F(sign_avx2)
-+#define lc_dilithium_sign_ctx_avx2 DILITHIUM_F(sign_ctx_avx2)
-+#define lc_dilithium_sign_init_avx2 DILITHIUM_F(sign_init_avx2)
-+#define lc_dilithium_sign_update_avx2 DILITHIUM_F(sign_update_avx2)
-+#define lc_dilithium_sign_final_avx2 DILITHIUM_F(sign_final_avx2)
-+#define lc_dilithium_verify_avx2 DILITHIUM_F(verify_avx2)
-+#define lc_dilithium_verify_ctx_avx2 DILITHIUM_F(verify_ctx_avx2)
-+#define lc_dilithium_verify_init_avx2 DILITHIUM_F(verify_init_avx2)
-+#define lc_dilithium_verify_update_avx2 DILITHIUM_F(verify_update_avx2)
-+#define lc_dilithium_verify_final_avx2 DILITHIUM_F(verify_final_avx2)
-+
-+/* ARMv8 Implementation */
-+#define intt_SIMD_top_armv8 DILITHIUM_F(intt_SIMD_top_armv8)
-+#define intt_SIMD_bot_armv8 DILITHIUM_F(intt_SIMD_bot_armv8)
-+#define ntt_SIMD_top_armv8 DILITHIUM_F(ntt_SIMD_top_armv8)
-+#define ntt_SIMD_bot_armv8 DILITHIUM_F(ntt_SIMD_bot_armv8)
-+#define poly_uniformx2 DILITHIUM_F(poly_uniformx2)
-+#define poly_uniform_etax2 DILITHIUM_F(poly_uniform_etax2)
-+#define poly_uniform_gamma1x2 DILITHIUM_F(poly_uniform_gamma1x2)
-+#define armv8_10_to_32 DILITHIUM_F(armv8_10_to_32)
-+#define poly_reduce_armv8 DILITHIUM_F(poly_reduce_armv8)
-+#define poly_caddq_armv8 DILITHIUM_F(poly_caddq_armv8)
-+#define poly_power2round_armv8 DILITHIUM_F(poly_power2round_armv8)
-+#define poly_pointwise_montgomery_armv8 \
-+ DILITHIUM_F(poly_pointwise_montgomery_armv8)
-+#define polyvecl_pointwise_acc_montgomery_armv8 \
-+ DILITHIUM_F(polyvecl_pointwise_acc_montgomery_armv8)
-+#define lc_dilithium_keypair_armv8 DILITHIUM_F(keypair_armv8)
-+#define lc_dilithium_keypair_from_seed_armv8 \
-+ DILITHIUM_F(keypair_from_seed_armv8)
-+#define lc_dilithium_sign_armv8 DILITHIUM_F(sign_armv8)
-+#define lc_dilithium_sign_ctx_armv8 DILITHIUM_F(sign_ctx_armv8)
-+#define lc_dilithium_sign_init_armv8 DILITHIUM_F(sign_init_armv8)
-+#define lc_dilithium_sign_update_armv8 DILITHIUM_F(sign_update_armv8)
-+#define lc_dilithium_sign_final_armv8 DILITHIUM_F(sign_final_armv8)
-+#define lc_dilithium_verify_armv8 DILITHIUM_F(verify_armv8)
-+#define lc_dilithium_verify_ctx_armv8 DILITHIUM_F(verify_ctx_armv8)
-+#define lc_dilithium_verify_init_armv8 DILITHIUM_F(verify_init_armv8)
-+#define lc_dilithium_verify_update_armv8 DILITHIUM_F(verify_update_armv8)
-+#define lc_dilithium_verify_final_armv8 DILITHIUM_F(verify_final_armv8)
-+
-+/* ARMv7 Implementation */
-+#define armv7_ntt_asm_smull DILITHIUM_F(armv7_ntt_asm_smull)
-+#define armv7_inv_ntt_asm_smull DILITHIUM_F(armv7_inv_ntt_asm_smull)
-+#define armv7_poly_pointwise_invmontgomery_asm_smull \
-+ DILITHIUM_F(armv7_poly_pointwise_invmontgomery_asm_smull)
-+#define armv7_poly_pointwise_acc_invmontgomery_asm_smull \
-+ DILITHIUM_F(armv7_poly_pointwise_acc_invmontgomery_asm_smull)
-+#define poly_uniform_armv7 DILITHIUM_F(poly_uniform_armv7)
-+#define armv7_poly_reduce_asm DILITHIUM_F(armv7_poly_reduce_asm)
-+#define armv7_rej_uniform_asm DILITHIUM_F(armv7_rej_uniform_asm)
-+#define lc_dilithium_keypair_armv7 DILITHIUM_F(keypair_armv7)
-+#define lc_dilithium_keypair_from_seed_armv7 \
-+ DILITHIUM_F(keypair_from_seed_armv7)
-+#define lc_dilithium_sign_armv7 DILITHIUM_F(sign_armv7)
-+#define lc_dilithium_sign_ctx_armv7 DILITHIUM_F(sign_ctx_armv7)
-+#define lc_dilithium_sign_init_armv7 DILITHIUM_F(sign_init_armv7)
-+#define lc_dilithium_sign_update_armv7 DILITHIUM_F(sign_update_armv7)
-+#define lc_dilithium_sign_final_armv7 DILITHIUM_F(sign_final_armv7)
-+#define lc_dilithium_verify_armv7 DILITHIUM_F(verify_armv7)
-+#define lc_dilithium_verify_ctx_armv7 DILITHIUM_F(verify_ctx_armv7)
-+#define lc_dilithium_verify_init_armv7 DILITHIUM_F(verify_init_armv7)
-+#define lc_dilithium_verify_update_armv7 DILITHIUM_F(verify_update_armv7)
-+#define lc_dilithium_verify_final_armv7 DILITHIUM_F(verify_final_armv7)
-+
-+/* RISCV 64 ASM Implementation */
-+#define lc_dilithium_keypair_riscv64 DILITHIUM_F(keypair_riscv64)
-+#define lc_dilithium_keypair_from_seed_riscv64 \
-+ DILITHIUM_F(keypair_from_seed_riscv64)
-+#define lc_dilithium_sign_riscv64 DILITHIUM_F(sign_riscv64)
-+#define lc_dilithium_sign_ctx_riscv64 DILITHIUM_F(sign_ctx_riscv64)
-+#define lc_dilithium_sign_init_riscv64 DILITHIUM_F(sign_init_riscv64)
-+#define lc_dilithium_sign_update_riscv64 DILITHIUM_F(sign_update_riscv64)
-+#define lc_dilithium_sign_final_riscv64 DILITHIUM_F(sign_final_riscv64)
-+#define lc_dilithium_verify_riscv64 DILITHIUM_F(verify_riscv64)
-+#define lc_dilithium_verify_ctx_riscv64 DILITHIUM_F(verify_ctx_riscv64)
-+#define lc_dilithium_verify_init_riscv64 DILITHIUM_F(verify_init_riscv64)
-+#define lc_dilithium_verify_update_riscv64 DILITHIUM_F(verify_update_riscv64)
-+#define lc_dilithium_verify_final_riscv64 DILITHIUM_F(verify_final_riscv64)
-+#define dilithium_ntt_8l_rv64im DILITHIUM_F(ntt_8l_rv64im)
-+#define dilithium_intt_8l_rv64im DILITHIUM_F(intt_8l_rv64im)
-+#define dilithium_poly_basemul_8l_init_rv64im \
-+ DILITHIUM_F(poly_basemul_8l_init_rv64im)
-+#define dilithium_poly_basemul_8l_acc_rv64im \
-+ DILITHIUM_F(poly_basemul_8l_acc_rv64im)
-+#define dilithium_poly_basemul_8l_acc_end_rv64im \
-+ DILITHIUM_F(poly_basemul_8l_acc_end_rv64im)
-+#define dilithium_poly_basemul_8l_rv64im DILITHIUM_F(poly_basemul_8l_rv64im)
-+#define dilithium_poly_reduce_rv64im DILITHIUM_F(poly_reduce_rv64im)
-+
-+/* RISCV 64 RVV Implementation */
-+#define lc_dilithium_keypair_riscv64_rvv DILITHIUM_F(keypair_riscv64_rvv)
-+#define lc_dilithium_keypair_from_seed_riscv64_rvv \
-+ DILITHIUM_F(keypair_from_seed_riscv64_rvv)
-+#define lc_dilithium_sign_riscv64_rvv DILITHIUM_F(sign_riscv64_rvv)
-+#define lc_dilithium_sign_ctx_riscv64_rvv DILITHIUM_F(sign_ctx_riscv64_rvv)
-+#define lc_dilithium_sign_init_riscv64_rvv DILITHIUM_F(sign_init_riscv64_rvv)
-+#define lc_dilithium_sign_update_riscv64_rvv \
-+ DILITHIUM_F(sign_update_riscv64_rvv)
-+#define lc_dilithium_sign_final_riscv64_rvv DILITHIUM_F(sign_final_riscv64_rvv)
-+#define lc_dilithium_verify_riscv64_rvv DILITHIUM_F(verify_riscv64_rvv)
-+#define lc_dilithium_verify_ctx_riscv64_rvv DILITHIUM_F(verify_ctx_riscv64_rvv)
-+#define lc_dilithium_verify_init_riscv64_rvv \
-+ DILITHIUM_F(verify_init_riscv64_rvv)
-+#define lc_dilithium_verify_update_riscv64_rvv \
-+ DILITHIUM_F(verify_update_riscv64_rvv)
-+#define lc_dilithium_verify_final_riscv64_rvv \
-+ DILITHIUM_F(verify_final_riscv64_rvv)
-+#define dilithium_ntt_8l_rvv DILITHIUM_F(ntt_8l_rvv)
-+#define dilithium_intt_8l_rvv DILITHIUM_F(intt_8l_rvv)
-+#define dilithium_poly_basemul_8l_rvv DILITHIUM_F(poly_basemul_8l_rvv)
-+#define dilithium_poly_basemul_acc_8l_rvv DILITHIUM_F(poly_basemul_acc_8l_rvv)
-+#define dilithium_ntt2normal_order_8l_rvv DILITHIUM_F(ntt2normal_order_8l_rvv)
-+#define dilithium_normal2ntt_order_8l_rvv DILITHIUM_F(normal2ntt_order_8l_rvv)
-+#define dilithium_poly_reduce_rvv DILITHIUM_F(poly_reduce_rvv)
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_TYPE_H */
-diff --git a/lib/freebl/leancrypto/dilithium_zetas.h b/lib/freebl/leancrypto/dilithium_zetas.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/dilithium_zetas.h
-@@ -0,0 +1,35 @@
-+/*
-+ * Copyright (C) 2024 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef DILITHIUM_ZETAS_H
-+#define DILITHIUM_ZETAS_H
-+
-+#include "dilithium_type.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+extern const int32_t dilithium_zetas[LC_DILITHIUM_N];
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* DILITHIUM_ZETAS_H */
-diff --git a/lib/freebl/leancrypto/errno_private-base.h b/lib/freebl/leancrypto/errno_private-base.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/errno_private-base.h
-@@ -0,0 +1,40 @@
-+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-+#ifndef _ASM_GENERIC_ERRNO_BASE_H
-+#define _ASM_GENERIC_ERRNO_BASE_H
-+
-+#define EPERM 1 /* Operation not permitted */
-+#define ENOENT 2 /* No such file or directory */
-+#define ESRCH 3 /* No such process */
-+#define EINTR 4 /* Interrupted system call */
-+#define EIO 5 /* I/O error */
-+#define ENXIO 6 /* No such device or address */
-+#define E2BIG 7 /* Argument list too long */
-+#define ENOEXEC 8 /* Exec format error */
-+#define EBADF 9 /* Bad file number */
-+#define ECHILD 10 /* No child processes */
-+#define EAGAIN 11 /* Try again */
-+#define ENOMEM 12 /* Out of memory */
-+#define EACCES 13 /* Permission denied */
-+#define EFAULT 14 /* Bad address */
-+#define ENOTBLK 15 /* Block device required */
-+#define EBUSY 16 /* Device or resource busy */
-+#define EEXIST 17 /* File exists */
-+#define EXDEV 18 /* Cross-device link */
-+#define ENODEV 19 /* No such device */
-+#define ENOTDIR 20 /* Not a directory */
-+#define EISDIR 21 /* Is a directory */
-+#define EINVAL 22 /* Invalid argument */
-+#define ENFILE 23 /* File table overflow */
-+#define EMFILE 24 /* Too many open files */
-+#define ENOTTY 25 /* Not a typewriter */
-+#define ETXTBSY 26 /* Text file busy */
-+#define EFBIG 27 /* File too large */
-+#define ENOSPC 28 /* No space left on device */
-+#define ESPIPE 29 /* Illegal seek */
-+#define EROFS 30 /* Read-only file system */
-+#define EMLINK 31 /* Too many links */
-+#define EPIPE 32 /* Broken pipe */
-+#define EDOM 33 /* Math argument out of domain of func */
-+#define ERANGE 34 /* Math result not representable */
-+
-+#endif
-diff --git a/lib/freebl/leancrypto/errno_private.h b/lib/freebl/leancrypto/errno_private.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/errno_private.h
-@@ -0,0 +1,123 @@
-+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-+#ifndef _ASM_GENERIC_ERRNO_H
-+#define _ASM_GENERIC_ERRNO_H
-+
-+#include "errno_private-base.h"
-+
-+#define EDEADLK 35 /* Resource deadlock would occur */
-+#define ENAMETOOLONG 36 /* File name too long */
-+#define ENOLCK 37 /* No record locks available */
-+
-+/*
-+ * This error code is special: arch syscall entry code will return
-+ * -ENOSYS if users try to call a syscall that doesn't exist. To keep
-+ * failures of syscalls that really do exist distinguishable from
-+ * failures due to attempts to use a nonexistent syscall, syscall
-+ * implementations should refrain from returning -ENOSYS.
-+ */
-+#define ENOSYS 38 /* Invalid system call number */
-+
-+#define ENOTEMPTY 39 /* Directory not empty */
-+#define ELOOP 40 /* Too many symbolic links encountered */
-+#define EWOULDBLOCK EAGAIN /* Operation would block */
-+#define ENOMSG 42 /* No message of desired type */
-+#define EIDRM 43 /* Identifier removed */
-+#define ECHRNG 44 /* Channel number out of range */
-+#define EL2NSYNC 45 /* Level 2 not synchronized */
-+#define EL3HLT 46 /* Level 3 halted */
-+#define EL3RST 47 /* Level 3 reset */
-+#define ELNRNG 48 /* Link number out of range */
-+#define EUNATCH 49 /* Protocol driver not attached */
-+#define ENOCSI 50 /* No CSI structure available */
-+#define EL2HLT 51 /* Level 2 halted */
-+#define EBADE 52 /* Invalid exchange */
-+#define EBADR 53 /* Invalid request descriptor */
-+#define EXFULL 54 /* Exchange full */
-+#define ENOANO 55 /* No anode */
-+#define EBADRQC 56 /* Invalid request code */
-+#define EBADSLT 57 /* Invalid slot */
-+
-+#define EDEADLOCK EDEADLK
-+
-+#define EBFONT 59 /* Bad font file format */
-+#define ENOSTR 60 /* Device not a stream */
-+#define ENODATA 61 /* No data available */
-+#define ETIME 62 /* Timer expired */
-+#define ENOSR 63 /* Out of streams resources */
-+#define ENONET 64 /* Machine is not on the network */
-+#define ENOPKG 65 /* Package not installed */
-+#define EREMOTE 66 /* Object is remote */
-+#define ENOLINK 67 /* Link has been severed */
-+#define EADV 68 /* Advertise error */
-+#define ESRMNT 69 /* Srmount error */
-+#define ECOMM 70 /* Communication error on send */
-+#define EPROTO 71 /* Protocol error */
-+#define EMULTIHOP 72 /* Multihop attempted */
-+#define EDOTDOT 73 /* RFS specific error */
-+#define EBADMSG 74 /* Not a data message */
-+#define EOVERFLOW 75 /* Value too large for defined data type */
-+#define ENOTUNIQ 76 /* Name not unique on network */
-+#define EBADFD 77 /* File descriptor in bad state */
-+#define EREMCHG 78 /* Remote address changed */
-+#define ELIBACC 79 /* Can not access a needed shared library */
-+#define ELIBBAD 80 /* Accessing a corrupted shared library */
-+#define ELIBSCN 81 /* .lib section in a.out corrupted */
-+#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
-+#define ELIBEXEC 83 /* Cannot exec a shared library directly */
-+#define EILSEQ 84 /* Illegal byte sequence */
-+#define ERESTART 85 /* Interrupted system call should be restarted */
-+#define ESTRPIPE 86 /* Streams pipe error */
-+#define EUSERS 87 /* Too many users */
-+#define ENOTSOCK 88 /* Socket operation on non-socket */
-+#define EDESTADDRREQ 89 /* Destination address required */
-+#define EMSGSIZE 90 /* Message too long */
-+#define EPROTOTYPE 91 /* Protocol wrong type for socket */
-+#define ENOPROTOOPT 92 /* Protocol not available */
-+#define EPROTONOSUPPORT 93 /* Protocol not supported */
-+#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
-+#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
-+#define EPFNOSUPPORT 96 /* Protocol family not supported */
-+#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
-+#define EADDRINUSE 98 /* Address already in use */
-+#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
-+#define ENETDOWN 100 /* Network is down */
-+#define ENETUNREACH 101 /* Network is unreachable */
-+#define ENETRESET 102 /* Network dropped connection because of reset */
-+#define ECONNABORTED 103 /* Software caused connection abort */
-+#define ECONNRESET 104 /* Connection reset by peer */
-+#define ENOBUFS 105 /* No buffer space available */
-+#define EISCONN 106 /* Transport endpoint is already connected */
-+#define ENOTCONN 107 /* Transport endpoint is not connected */
-+#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
-+#define ETOOMANYREFS 109 /* Too many references: cannot splice */
-+#define ETIMEDOUT 110 /* Connection timed out */
-+#define ECONNREFUSED 111 /* Connection refused */
-+#define EHOSTDOWN 112 /* Host is down */
-+#define EHOSTUNREACH 113 /* No route to host */
-+#define EALREADY 114 /* Operation already in progress */
-+#define EINPROGRESS 115 /* Operation now in progress */
-+#define ESTALE 116 /* Stale file handle */
-+#define EUCLEAN 117 /* Structure needs cleaning */
-+#define ENOTNAM 118 /* Not a XENIX named type file */
-+#define ENAVAIL 119 /* No XENIX semaphores available */
-+#define EISNAM 120 /* Is a named type file */
-+#define EREMOTEIO 121 /* Remote I/O error */
-+#define EDQUOT 122 /* Quota exceeded */
-+
-+#define ENOMEDIUM 123 /* No medium found */
-+#define EMEDIUMTYPE 124 /* Wrong medium type */
-+#define ECANCELED 125 /* Operation Canceled */
-+#define ENOKEY 126 /* Required key not available */
-+#define EKEYEXPIRED 127 /* Key has expired */
-+#define EKEYREVOKED 128 /* Key has been revoked */
-+#define EKEYREJECTED 129 /* Key was rejected by service */
-+
-+/* for robust mutexes */
-+#define EOWNERDEAD 130 /* Owner died */
-+#define ENOTRECOVERABLE 131 /* State not recoverable */
-+
-+#define ERFKILL 132 /* Operation not possible due to RF-kill */
-+
-+#define EHWPOISON 133 /* Memory page has hardware error */
-+
-+#endif
-diff --git a/lib/freebl/leancrypto/ext_headers.h b/lib/freebl/leancrypto/ext_headers.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ext_headers.h
-@@ -0,0 +1,447 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef EXT_HEADERS_H
-+#define EXT_HEADERS_H
-+
-+/******************************************************************************
-+ * Generic Definitions
-+ ******************************************************************************/
-+#define LC_PURE __attribute__((pure))
-+
-+/**
-+ * @brief Return the size of a member variable of a data structure
-+ *
-+ * @param [in] struct data structure containing the member variable
-+ * @param [in] member member variable name whose size shall be obtained
-+ *
-+ * @return size of the variable
-+ */
-+#define lc_member_size(struct, member) (sizeof(((struct *)0)->member))
-+
-+#ifdef LINUX_KERNEL
-+/******************************************************************************
-+ * Linux Kernel
-+ ******************************************************************************/
-+
-+#include
-+#include
-+#include
-+#include
-+
-+/* POSIX Support */
-+unsigned long getauxval(unsigned long type);
-+
-+static inline int mlock(const void *ptr, size_t len)
-+{
-+ (void)ptr;
-+ (void)len;
-+ return 0;
-+}
-+
-+extern const int errno;
-+
-+static inline pid_t getpid(void)
-+{
-+ return 0;
-+}
-+
-+#define restrict
-+
-+#define printf printk
-+
-+#ifndef assert
-+#define assert(x) WARN_ON(!(x))
-+#endif
-+
-+#define PRIu64 "lu"
-+
-+#define LC_DEFINE_CONSTRUCTOR(_func) void _func(void)
-+#define LC_DEFINE_DESTRUCTOR(_func) void _func(void)
-+
-+#define SYSV_ABI
-+
-+typedef s64 time64_t;
-+
-+static inline int lc_get_time(time64_t *time_since_epoch)
-+{
-+ if (!time_since_epoch)
-+ return -EINVAL;
-+
-+ *time_since_epoch = (time64_t)(jiffies / HZ);
-+
-+ return 0;
-+}
-+
-+#define LC_FIPS_RODATA_SECTION
-+
-+#elif (defined(LC_EFI_ENVIRONMENT))
-+/******************************************************************************
-+ * UEFI support
-+ ******************************************************************************/
-+
-+/* POSIX Support */
-+#include
-+#include
-+
-+#include "errno_private.h"
-+
-+#define LC_DEFINE_CONSTRUCTOR(_func) \
-+ void __attribute__((constructor)) _func(void)
-+#define LC_DEFINE_DESTRUCTOR(_func) void __attribute__((destructor)) _func(void)
-+
-+#if !defined __ILP32__
-+#define __WORDSIZE 64
-+#else
-+#define __WORDSIZE 32
-+#endif
-+
-+typedef int pid_t;
-+typedef long time_t;
-+typedef long long time64_t;
-+
-+#ifndef offsetof
-+#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
-+#endif
-+
-+#if __WORDSIZE == 64
-+
-+typedef unsigned long uintptr_t;
-+
-+#ifndef _SIZE_T
-+typedef unsigned long size_t;
-+#define _SIZE_T
-+#endif
-+
-+#ifndef _SSIZE_T
-+typedef long ssize_t;
-+#define _SSIZE_T
-+#endif
-+
-+#elif __WORDSIZE == 32
-+
-+#ifndef _UINTPTR_T
-+typedef unsigned int uintptr_t;
-+#define _UINTPTR_T
-+#endif
-+
-+#error
-+#ifndef _SIZE_T
-+typedef unsigned int size_t;
-+#define _SIZE_T
-+#endif
-+
-+#ifndef _SSIZE_T
-+typedef int ssize_t;
-+#define _SSIZE_T
-+#endif
-+
-+#endif
-+
-+#include "lc_memcpy_secure.h"
-+
-+void *memset(void *d, int c, unsigned long long n);
-+
-+static inline int mlock(const void *ptr, size_t len)
-+{
-+ (void)ptr;
-+ (void)len;
-+ return 0;
-+}
-+
-+static inline pid_t getpid(void)
-+{
-+ return 0;
-+}
-+
-+static inline int snprintf(char *restrict str, size_t size,
-+ const char *restrict format, ...)
-+{
-+ (void)format;
-+ if (size) {
-+ memset(str, 0, size);
-+ return (int)size - 1;
-+ }
-+ return 0;
-+}
-+
-+static inline void *memcpy(void *d, const void *s, size_t n)
-+{
-+ return lc_memcpy_secure(d, n, s, n);
-+}
-+
-+static inline size_t strlen(const char *str)
-+{
-+ size_t len = 0;
-+
-+ while (*str != '\0') {
-+ str++;
-+ len++;
-+ }
-+
-+ return len;
-+}
-+
-+static inline int lc_get_time(time64_t *time_since_epoch)
-+{
-+ if (!time_since_epoch)
-+ return -EINVAL;
-+
-+ *time_since_epoch = -1;
-+
-+ return -EOPNOTSUPP;
-+}
-+
-+#define SYSV_ABI __attribute__((sysv_abi))
-+
-+/*
-+ * See https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html#Statement-Attributes
-+ */
-+#if __has_attribute(__fallthrough__)
-+#define fallthrough __attribute__((__fallthrough__))
-+#else
-+#define fallthrough \
-+ do { \
-+ } while (0)
-+#endif
-+
-+#ifndef assert
-+#define assert(x) \
-+ if (x) { \
-+ Exit(EFI_ABORTED, 0, NULL); \
-+ }
-+#endif
-+
-+#ifndef INT_MAX
-+#define INT_MAX 2147483647
-+#endif
-+
-+#define stdout NULL
-+
-+#define printf(...) Print(L##__VA_ARGS__)
-+
-+#undef errno
-+#define errno errno_private
-+static const int errno_private = 0;
-+
-+#define LC_FIPS_RODATA_SECTION
-+
-+#define noinline __attribute__((__noinline__))
-+
-+#elif (defined(__CYGWIN__) || defined(_WIN32))
-+/******************************************************************************
-+ * Windows
-+ ******************************************************************************/
-+
-+#ifndef MB_LEN_MAX
-+#define MB_LEN_MAX 16
-+#endif
-+
-+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
-+
-+#define LC_DEFINE_CONSTRUCTOR(_func) \
-+ void __attribute__((constructor)) _func(void)
-+#define LC_DEFINE_DESTRUCTOR(_func) void __attribute__((destructor)) _func(void)
-+
-+#else
-+
-+#error "Constructor / destructor not defined for compiler"
-+
-+#endif
-+
-+/*
-+ * Replace GCC-specific alternative keywords
-+ * see https://gcc.gnu.org/onlinedocs/gcc/Alternate-Keywords.html
-+ */
-+#ifndef __GNUC__
-+#define __asm__ asm
-+#define __volatile__ volatile
-+#endif
-+
-+#ifndef _POSIX_C_SOURCE
-+#define _POSIX_C_SOURCE 200112L
-+#endif
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+
-+static inline int mlock(const void *ptr, size_t len)
-+{
-+ (void)ptr;
-+ (void)len;
-+ return 0;
-+}
-+
-+#define SYSV_ABI __attribute__((sysv_abi))
-+
-+/*
-+ * See https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html#Statement-Attributes
-+ */
-+#if __has_attribute(__fallthrough__)
-+#define fallthrough __attribute__((__fallthrough__))
-+#else
-+#define fallthrough \
-+ do { \
-+ } while (0)
-+#endif
-+
-+typedef int64_t time64_t;
-+
-+static inline int lc_get_time(time64_t *time_since_epoch)
-+{
-+ struct timespec tp = { 0 };
-+
-+ if (!time_since_epoch)
-+ return -EINVAL;
-+
-+ if (clock_gettime(CLOCK_REALTIME, &tp) == 0) {
-+ *time_since_epoch = tp.tv_sec;
-+ return 0;
-+ }
-+
-+ *time_since_epoch = (time64_t)-1;
-+ return -errno;
-+}
-+
-+#define LC_FIPS_RODATA_SECTION
-+
-+#define noinline __attribute__((__noinline__))
-+
-+#else /* LINUX_KERNEL */
-+/******************************************************************************
-+ * POSIX
-+ ******************************************************************************/
-+
-+#ifndef MB_LEN_MAX
-+#define MB_LEN_MAX 16
-+#endif
-+
-+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
-+
-+#define LC_DEFINE_CONSTRUCTOR(_func) \
-+ void __attribute__((constructor)) _func(void)
-+#define LC_DEFINE_DESTRUCTOR(_func) void __attribute__((destructor)) _func(void)
-+
-+#else
-+
-+#error "Constructor / destructor not defined for compiler"
-+
-+#endif
-+
-+/*
-+ * Replace GCC-specific alternative keywords
-+ * see https://gcc.gnu.org/onlinedocs/gcc/Alternate-Keywords.html
-+ */
-+#ifndef __GNUC__
-+#define __asm__ asm
-+#define __volatile__ volatile
-+#endif
-+
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+#include
-+
-+#define SYSV_ABI
-+
-+/*
-+ * See https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html#Statement-Attributes
-+ */
-+#if __has_attribute(__fallthrough__)
-+#define fallthrough __attribute__((__fallthrough__))
-+#else
-+#define fallthrough \
-+ do { \
-+ } while (0)
-+#endif
-+
-+typedef int64_t time64_t;
-+
-+static inline int lc_get_time(time64_t *time_since_epoch)
-+{
-+ struct timespec tp = { 0 };
-+
-+ if (!time_since_epoch)
-+ return -EINVAL;
-+
-+ if (clock_gettime(CLOCK_REALTIME, &tp) == 0) {
-+ *time_since_epoch = tp.tv_sec;
-+ return 0;
-+ }
-+
-+ *time_since_epoch = (time64_t)-1;
-+ return -errno;
-+}
-+
-+/*
-+ * FIPS 140 integrity check cannot check the .rodata section. Thus move all
-+ * relevant data to teh fips_rodata section.
-+ */
-+#if defined __ELF__
-+#define LC_FIPS_RODATA_SECTION_NAME_START __start_fips_rodata
-+#define LC_FIPS_RODATA_SECTION_NAME_STOP __stop_fips_rodata
-+#define LC_FIPS_RODATA_SECTION_NAME "fips_rodata"
-+#define LC_FIPS_RODATA_SECTION \
-+ __attribute__((section(LC_FIPS_RODATA_SECTION_NAME)))
-+#else
-+#define LC_FIPS_RODATA_SECTION
-+#endif
-+
-+#define noinline __attribute__((__noinline__))
-+
-+#endif /* LINUX_KERNEL */
-+
-+/******************************************************************************
-+ * Generic Definitions after all includes are present
-+ ******************************************************************************/
-+
-+#ifndef ENOPKG
-+#define ENOPKG 254 /* Package not installed */
-+#endif
-+#ifndef EKEYREJECTED
-+#define EKEYREJECTED 253 /* Key was rejected by service */
-+#endif
-+#ifndef ENOKEY
-+#define ENOKEY 252 /* Key not found */
-+#endif
-+
-+#endif /* EXT_HEADERS_H */
-diff --git a/lib/freebl/leancrypto/fetch_ml_dsa.sh b/lib/freebl/leancrypto/fetch_ml_dsa.sh
-new file mode 100755
---- /dev/null
-+++ b/lib/freebl/leancrypto/fetch_ml_dsa.sh
-@@ -0,0 +1,451 @@
-+#!/bin/sh
-+declare -a versions
-+declare -a modes
-+declare -a type
-+versions=(ml_dsa_44 ml_dsa_65 ml_dsa_87)
-+modes=(2 3 5)
-+types=(44 65 87)
-+keep=0
-+clean=0
-+update=0
-+clean_gen=0
-+branch="master"
-+
-+library=leancrypto
-+git_url=https://github.com/smuellerDD/leancrypto
-+ml_dsa_src=ml-dsa/src
-+#cpufeatures.h
-+#test_helper.h
-+
-+header_gen_list=( lc_dilithium_44.h lc_dilithium_65.h lc_dilithium_87.h)
-+header_gen_internal_list=( lc_memory_support.h )
-+header_internal_list=( alignment.h atomic_bool.h atomic.h binhexbin.h
-+ bitshift_be.h bitshift.h bitshift_le.h bool.h build_bug_on.h
-+ compare.h conv_be_le.h errno_private-base.h errno_private.h
-+ ext_headers.h fips_mode.h helper.h initialization.h lc_init.h
-+ lc_memcmp_secure.h lc_memcpy_secure.h lc_memory_support.h.in
-+ lc_memset_secure.h lc_status.h left_encode.h math_helper.h
-+ mutex_w.h null_buffer.h ret_checkers.h rotate.h
-+ sidechannel_resistantce.h signature_domain_separation.h
-+ small_stack_support.h timecop.h visibility.h xor256.h xor.h )
-+header_api_list=(dilithium_type.h lc_dilithium.h)
-+header_list=( dilithium_debug.h dilithium_ntt.h dilithium_pack.h dilithium_pct.h
-+ dilithium_poly.h dilithium_poly_c.h dilithium_poly_common.h
-+ dilithium_polyvec.h dilithium_polyvec_c.h dilithium_reduce.h
-+ dilithium_rounding.h dilithium_service_helpers.h
-+ dilithium_signature_c.h dilithium_signature_impl.h dilithium_zetas.h)
-+internal_list=(signature_domain_separation.c)
-+common_list=(dilithium_api.c dilithium_zetas.c)
-+specific_list=( dilithium_ntt.c dilithium_poly.c dilithium_rounding.c
-+ dilithium_signature_c.c dilithium_signature_helper.c)
-+
-+
-+process_versions()
-+{
-+ echo "process_version($3)" >&2
-+ local -n vers=$1
-+ local -n mods=$2
-+ declare -p vers
-+ declare -p mods
-+ vers=()
-+ mods=()
-+ for i in ${3//;/ }
-+ do
-+ ver=${i%%:*}
-+ mod=${i##*:}
-+ echo "spec=/$i/ ver=/$ver/ mod=/$mod/" >&2
-+ if [[ "$ver" = "" || "$mod" = "" ]]; then
-+ echo "invalid version spec \"$i\"" >&2
-+ return 1
-+ fi
-+ vers+=($ver)
-+ mods+=($mod)
-+ done
-+ return 0
-+}
-+
-+usage()
-+{
-+ echo "usage: ${0##*/} [--keep_intermediate] [--clean_library]" >&2
-+ echo " [--version list_of_versions_and_modes]" >&2
-+ echo " [--update] [--branch]" >&2
-+ echo "--keep_intermediate don't delete intermediate files used to generate headers" >&2
-+ echo "--clean_library remove old library directory before starting" >&2
-+ echo "--clean_generated remove generated files before starting" >&2
-+ echo "--versions ';' separated list of versions and modes. of the form:" >&2
-+ echo " version:mode. example:" >&2
-+ echo " \"ml_dsa_44_ref:2;ml_dsa_65_avx:3;ml_dsa_65_ref:3\"" >&2
-+ echo "--update if liboq directory exists, update it" >&2
-+ echo "--branch select the git branch to use" >&2
-+ exit 1
-+}
-+
-+
-+while true ; do
-+ case "$1" in
-+ --keep_intermediate|-k) keep=1; shift
-+ ;;
-+ --clean_leancrypto|-C)
-+ clean=1; shift
-+ ;;
-+ --clean_generated|-c)
-+ clean_gen=1; shift
-+ ;;
-+ -versions|-v)
-+ process_versions versions modes "$2"
-+ if (( $? != 0 || ${#modes[@]} != ${#versions[@]} )); then
-+ echo "not all versions have a mode \"$2\"" >&2
-+ echo "number modes=${#modes}, number versions=${#versions}" >&2
-+ echo "versions:${versions[*]}" >&2
-+ echo "modes:${modes[*]}" >&2
-+ usage
-+ fi
-+ shift 2
-+ ;;
-+ --update|-u)
-+ update=1; shift
-+ ;;
-+ --branch|-b)
-+ branch="$2"; shift 2
-+ ;;
-+ "")
-+ break
-+ ;;
-+ *)
-+ echo "$0: Unknown option: \"$1\"" >&2
-+ usage
-+ esac
-+done
-+
-+
-+# first fetch and builds leancrypto
-+top=$(pwd)
-+echo "--------------- fetching $library"
-+if [ -d $library ]; then
-+ if (( $clean == 1 )); then
-+ rm -rf $library
-+ git clone -b main $giturl
-+ elif (( $update == 1 )); then
-+ (cd $library ; git checkout main ; git pull)
-+ fi
-+else
-+ git clone -b main $giturl
-+fi
-+cd $library
-+git checkout $branch
-+if [ $? != 0 ]; then
-+ echo "branch \"$branch\" not found" >&2
-+ echo "valid branches and tags are: " >&2
-+ git branch -l >&2
-+ git tag -l >&2
-+ exit 1
-+fi
-+libdir=$(pwd)
-+ml_dsa_dir=${libdir}/${ml_dsa_src}
-+if [ ! -d $ml_dsa_dir ]; then
-+ echo "ml_dsa not avaliable on this branch or tag ${branch}" >&2
-+ exit 1
-+fi
-+
-+# now set up everything
-+if (( clean_gen == 1 )); then
-+ (cd $top ; rm -f ml_dsa_* fips202.h randombytes.h $library_git_version.txt )
-+fi
-+rm -rf build
-+mkdir build
-+meson setup build -Ddilithium_ed25519=disabled -Ddilithium_ed448=disabled
-+cd build
-+mkdir sed_scripts
-+mkdir generated_code
-+build=$(pwd)
-+sed_scripts=${build}/sed_scripts
-+generated_code=${build}/generated_code
-+cd ${libdir}
-+
-+# these are used to allow is to create 'max' defines
-+# we find the value from each of the different lengths and then we
-+# keep the maximum, so we can define our max value in terms of that value
-+pub_size=0
-+pub_define="UNKNOWN"
-+priv_size=0
-+priv_define="UNKNOWN"
-+sig_size=0
-+sig_define="UNKNOWN"
-+seed_size=0
-+seed_define="UNKNOWN"
-+
-+# ml_dsa_api.h is a completely generated header. It basically resolves the defines in the various
-+# xxxx_sign.h headers, which uses macros redefine all the functions, but they use the same macro and
-+# function names, so the we can't have a single file that includes all the definitions. library itself
-+# handles this by creating their own c stubs for each of the functions. We've already name deconflicted
-+# the filenames, so since we have this program we can safely create a proper header file.
-+#cat > ${generated_code}/ml_dsa_api.h << __EoF__
-+#ifndef ML_DSA_API_H
-+#define ML_DSA_API_H
-+#// This is a generated file from the various XXX_sign.h files
-+#include
-+#include "ml_dsa_apit.h"
-+#__EoF__
-+cat > ${generated_code}/ml_dsa_apit.h << __EoF__
-+// This is a generated file from the various XXX_sign.h files
-+#ifndef ML_DSA_APIT_H
-+#define ML_DSA_APIT_H
-+
-+// to make the function defines work
-+#ifndef RNDBYTES
-+#define RNDBYTES 32
-+#endif
-+__EoF__
-+
-+for i in ${commonlist[@]}
-+do
-+ cp ${ml_dsa_dir}/$i ${generated_code}/
-+done
-+for file in ${header_internal_list[@]}
-+do
-+ cp ${libdir}/internal/api/${file} ${generated_code}/${file}
-+done
-+for file in ${header_gen_internal_list=[@]}
-+do
-+ cp ${libdir}/build/internal/api/${file} ${generated_code}/${file}
-+done
-+for file in ${header_gen_list[@]}
-+do
-+ cp ${libdir}/build/ml-dsa/api/${file} ${generated_code}/${file}
-+done
-+for file in ${header_api_list[@]}
-+do
-+ cp ${ml_dsa_dir}/../api/${file} ${generated_code}/${file}
-+done
-+for file in ${header_list[@]}
-+do
-+ cp ${ml_dsa_dir}/${file} ${generated_code}/${file}
-+done
-+for file in ${internal_list[@]}
-+do
-+ cp ${libdir}/internal/src/${file} ${generated_code}/${file}
-+done
-+for file in ${common_list[@]}
-+do
-+ target_file=${file#dilithium}
-+ cp ${ml_dsa_dir}/${file} ${generated_code}/mldsa${target_file}
-+done
-+# now process the each of the versions we are woring on.
-+for i in ${!versions[@]}
-+do
-+ sig=${versions[$i]}
-+ mode=${modes[$i]}
-+ #ls *.h | sed "s/\(.*\)/s;\1;${sig}_\1;/" > ${sed_scripts}/header_rename_${sig}.sed
-+ #echo "s;;\"blapi.h\";" >> ${sed_scripts}/header_rename_${sig}.sed
-+ #echo "s;OQS_API;;g" >> ${sed_scripts}/header_rename_${sig}.sed
-+ echo "#define LC_DILITHIUM_TYPE_${types[$i]} 1" > ${generated_code}/${sig}_def_header.h
-+
-+ echo "------------------------- Processing $sig mode=$mode ... "
-+ for file in ${specific_list[@]}
-+ do
-+ target_file=${file#dilithium}
-+ echo -n -e "fixup ${file} to ${sig}_${file}\r"
-+ tmp=${generated_code}/${sig}${file}_tmp
-+ cat ${generated_code}/${sig}_def_header.h ${ml_dsa_dir}/${file} > ${tmp}
-+ #sed -f ${sed_scripts}/header_rename_${sig}.sed ${file} > ${tmp}
-+ #unifdef -DLC_DILITHIUM_MODE=${mode} ${tmp} > ${generated_code}/${sig}_${file}
-+ cp ${tmp} ${generated_code}/${sig}${target_file}
-+ rm ${tmp}
-+ done
-+ echo ""
-+ cd ${generated_code}
-+ #process ${sig}_sign.h to get all the function defines into our ml_dsa_api.h
-+# echo "" >> ${generated_code}/ml_dsa_api.h
-+# echo "// from ${sig}_sign.h " >> ${generated_code}/ml_dsa_api.h
-+#grep -v '^#' ${sig}_sign.h | grep -v "^$" | sed -e "s/crypto_sign/pqcrystals_${sig}/" >> ${generated_code}/ml_dsa_api.h
-+
-+ # now let's get unrolled defines for the various sizes (keys, signatures, seeds). We use a C program
-+ # and make C evaluate the final value of several defines which are calculated on the fly.
-+# echo "#include \"${sig}_params.h\"" > ./${sig}_extract_defines.c
-+# echo "const char *sign_ver=\"${sig^^}\";" >> ./${sig}_extract_defines.c
-+# echo "const char *l_sign_ver=\"${sig}\";" >> ./${sig}_extract_defines.c
-+# cat >> ./${sig}_extract_defines.c << __EoF__
-+##include
-+#int main(int argc, char **arv) {
-+# printf("\n");
-+# printf("// from %s_sign.h\n", l_sign_ver);
-+# printf("#define %s_PUBLICKEY_BYTES %d\n", sign_ver, CRYPTO_PUBLICKEYBYTES);
-+# printf("#define %s_PRIVATEKEY_BYTES %d\n", sign_ver, CRYPTO_SECRETKEYBYTES);
-+# printf("#define %s_SIGNATURE_BYTES %d\n", sign_ver, CRYPTO_BYTES);
-+# printf("#define %s_SEED_BYTES %d\n", sign_ver, SEEDBYTES);
-+#}
-+#__EoF__
-+# cc -o ${sig}_extract_defines ${sig}_extract_defines.c
-+# ./${sig}_extract_defines >> ${generated_code}/ml_dsa_apit.h
-+# new_size=$(./${sig}_extract_defines | grep PUBLICKEY | awk '{ print $NF }')
-+# if (( new_size > pub_size )); then
-+# pub_size=$new_size
-+# pub_define=${sig^^}
-+# fi
-+# new_size=$(./${sig}_extract_defines | grep PRIVATEKEY | awk '{ print $NF }')
-+# if (( new_size > priv_size )); then
-+# priv_size=$new_size
-+# priv_define=${sig^^}
-+# fi
-+# new_size=$(./${sig}_extract_defines | grep SIGNATURE | awk '{ print $NF }')
-+# if (( new_size > sig_size )); then
-+# sig_size=$new_size
-+# sig_define=${sig^^}
-+# fi
-+# new_size=$(./${sig}_extract_defines | grep SEED | awk '{ print $NF }')
-+# if (( new_size > seed_size )); then
-+# seed_size=$new_size
-+# seed_define=${sig^^}
-+# fi
-+# if (( $keep != 1 )); then
-+# rm ${sig}_extract_defines*
-+# fi
-+ # sigh clang20 knows about type c, but we only have cpp in our
-+ # .clang-format file, tell clang to use .cpp
-+ for file in *.[c]
-+ do
-+ base=$(basename $file .c)
-+ echo clang-format --assume-filename=${base}.cpp --sort-includes=false -i ${file}
-+ cat ${file} | clang-format --assume-filename=${base}.cpp --sort-includes=false >${file}.clang
-+ mv ${file}.clang ${file}
-+ done
-+ for file in *.[h]
-+ do
-+ clang-format --sort-includes=false -i ${file}
-+ done
-+ tar cf - . | (cd ${top} ; tar xf -)
-+ cd ${libarary}
-+done
-+
-+#if (( $version_found == 0 )); then
-+# echo "no requested versions (${versions[*]}) found in this branch ($branch)" >&2
-+# echo "valid versions are:" >&2
-+# ls ${ml_dsa_dir} | grep pqcrystals | sed 's;pqcrystals-dilithium-standard[_|-];;' >&2
-+# exit 1
-+#fi
-+
-+echo "" >> ${generated_code}/ml_dsa_apit.h
-+#echo "// create the max defines" >> ${generated_code}/ml_dsa_apit.h
-+#echo "#define MAX_MLDSA_REF_PRIVATE_KEY_LEN ${priv_define}_PRIVATEKEY_BYTES" >> ${generated_code}/ml_dsa_apit.h
-+#echo "#define MAX_MLDSA_REF_PUBLIC_KEY_LEN ${priv_define}_PUBLICKEY_BYTES" >> ${generated_code}/ml_dsa_apit.h
-+#echo "#define MAX_MLDSA_REF_SIGNATURE_LEN ${priv_define}_SIGNATURE_BYTES" >> ${generated_code}/ml_dsa_apit.h
-+#echo "#define MAX_MLDSA_REF_SEED_LEN ${priv_define}_SEED_BYTES" >> ${generated_code}/ml_dsa_apit.h
-+#echo "#endif /* ML_DSA_API_H */" >> ${generated_code}/ml_dsa_api.h
-+echo "#endif /* ML_DSA_APIT_H */" >> ${generated_code}/ml_dsa_apit.h
-+
-+cp ${generated_code}/ml_dsa_api.h ${top}
-+cp ${generated_code}/ml_dsa_apit.h ${top}
-+cd ${top}
-+echo "------------------------- wrote ml_dsa_apit.h : ... "
-+# remember what version we are using
-+(cd ${library}; git branch -v) > leancrypto_git_version.txt
-+# Now write out the fixed files
-+cat > fips202.h << __EoF__
-+// SPDX-License-Identifier: MIT
-+// NSS SHA3 bindings for ML-DSA liboqs
-+
-+#ifndef FIPS202_H
-+#define FIPS202_H
-+
-+#include
-+
-+#define SHAKE128_RATE 168
-+#define shake128 SHAKE_128_HashBuf
-+
-+#define SHAKE256_RATE SHA3_256_BLOCK_LENGTH
-+#define shake256 SHAKE_256_HashBuf
-+
-+#ifdef NOT_SUPPORTED
-+#define SHA3_256_RATE SHA3_256_BLOCK_LENGTH
-+#define sha3_256 OQS_SHA3_sha3_256
-+#define sha3_256_inc_init OQS_SHA3_sha3_256_inc_init
-+#define sha3_256_inc_absorb OQS_SHA3_sha3_256_inc_absorb
-+#define sha3_256_inc_finalize OQS_SHA3_sha3_256_inc_finalize
-+#define sha3_256_inc_ctx_clone OQS_SHA3_sha3_256_inc_ctx_clone
-+#define sha3_256_inc_ctx_release OQS_SHA3_sha3_256_inc_ctx_release
-+
-+#define SHA3_384_RATE SHA3_384_BLOCK_LENGTH
-+#define sha3_384 OQS_SHA3_sha3_384
-+#define sha3_384_inc_init OQS_SHA3_sha3_384_inc_init
-+#define sha3_384_inc_absorb OQS_SHA3_sha3_384_inc_absorb
-+#define sha3_384_inc_finalize OQS_SHA3_sha3_384_inc_finalize
-+#define sha3_384_inc_ctx_clone OQS_SHA3_sha3_384_inc_ctx_clone
-+#define sha3_384_inc_ctx_release OQS_SHA3_sha3_384_inc_ctx_release
-+
-+#define SHA3_512_RATE SHA3_512_BLOCK_LENGTH
-+#define sha3_512 OQS_SHA3_sha3_512
-+#define sha3_512_inc_init OQS_SHA3_sha3_512_inc_init
-+#define sha3_512_inc_absorb OQS_SHA3_sha3_512_inc_absorb
-+#define sha3_512_inc_finalize OQS_SHA3_sha3_512_inc_finalize
-+#define sha3_512_inc_ctx_clone OQS_SHA3_sha3_512_inc_ctx_clone
-+#define sha3_512_inc_ctx_release OQS_SHA3_sha3_512_inc_ctx_release
-+#endif
-+
-+typedef SHAKE_128Context *shake128incctx;
-+#define shake128_inc_init(ptr) \
-+ (*(ptr))=SHAKE_128_NewContext(); \
-+ SHAKE_128_Begin(*(ptr))
-+#define shake128_inc_absorb(ptr, input, inlen) \
-+ SHAKE_128_Absorb(*(ptr), input, inlen)
-+#define shake128_inc_finalize(ptr)
-+#define shake128_inc_squeeze(output, outlen, ptr) \
-+ SHAKE_128_SqueezeEnd(*(ptr), output, outlen)
-+#define shake128_inc_ctx_release(ptr) \
-+ SHAKE_128_DestroyContext(*(ptr), PR_TRUE)
-+#define shake128_inc_ctx_reset(ptr) \
-+ SHAKE_128_Begin(ptr)
-+#ifdef NOT_SUPPORTED
-+#define shake128_inc_ctx_clone OQS_SHA3_shake128_inc_ctx_clone
-+#endif
-+
-+typedef SHAKE_256Context *shake256incctx;
-+#define shake256_inc_init(ptr) \
-+ (*(ptr))=SHAKE_256_NewContext(); \
-+ SHAKE_256_Begin(*(ptr))
-+#define shake256_inc_absorb(ptr, input, inlen) \
-+ SHAKE_256_Absorb(*(ptr), input, inlen)
-+#define shake256_inc_finalize(ptr)
-+#define shake256_inc_squeeze(output, outlen, ptr) \
-+ SHAKE_256_SqueezeEnd(*(ptr), output, outlen)
-+#define shake256_inc_ctx_release(ptr) \
-+ SHAKE_256_DestroyContext(*(ptr), PR_TRUE)
-+#define shake256_inc_ctx_reset(ptr) \
-+ SHAKE_256_Begin(*ptr)
-+
-+#ifdef NOT_SUPPORTED
-+#define shake128_absorb_once OQS_SHA3_shake128_absorb_once
-+void OQS_SHA3_shake128_absorb_once(shake128incctx *state, const uint8_t *in, size_t inlen);
-+
-+#define shake256_absorb_once OQS_SHA3_shake256_absorb_once
-+void OQS_SHA3_shake256_absorb_once(shake256incctx *state, const uint8_t *in, size_t inlen);
-+#endif
-+
-+#define shake128_squeezeblocks(OUT, NBLOCKS, STATE) shake128_inc_squeeze(OUT, (NBLOCKS)*SHAKE128_RATE, STATE)
-+
-+#define shake256_squeezeblocks(OUT, NBLOCKS, STATE) shake256_inc_squeeze(OUT, (NBLOCKS)*SHAKE256_RATE, STATE)
-+
-+#endif
-+__EoF__
-+cat > randombytes.h << __EoF__
-+// SPDX-License-Identifier: MIT
-+// NSS stub for liboqs randombytes.h
-+
-+#ifndef RANDOMBYTES_H
-+#define RANDOMBYTES_H
-+
-+// run the random number generator through our mldsa code so we can support
-+// CKA_SEED (both acquiring it and generating keys from it) and
-+// DETERMINISTIC signatures (by returning zeros from the RNG)
-+void mldsa_GetRandomBytes(unsigned char *rdn, int bytes);
-+#define randombytes mldsa_GetRandomBytes
-+
-+#endif
-+__EoF__
-+clang-format -sort-includes=false -i randombytes.h fips202.h ml_dsa_apit.h ml_dsa_api.h
-+#output our generated files for review
-+echo "ml_dsa_abit.h -----------------"
-+cat ml_dsa_apit.h
-+echo "git version used -----------------"
-+cat oqs_git_version.txt
-+#rm -rf ${liboqs}
-+exit 0
-diff --git a/lib/freebl/leancrypto/fips202.h b/lib/freebl/leancrypto/fips202.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/fips202.h
-@@ -0,0 +1,76 @@
-+// SPDX-License-Identifier: MIT
-+// NSS SHA3 bindings for ML-DSA liboqs
-+
-+#ifndef FIPS202_H
-+#define FIPS202_H
-+
-+#include
-+
-+#define SHAKE128_RATE 168
-+#define shake128 SHAKE_128_HashBuf
-+
-+#define SHAKE256_RATE SHA3_256_BLOCK_LENGTH
-+#define shake256 SHAKE_256_HashBuf
-+
-+#ifdef NOT_SUPPORTED
-+#define SHA3_256_RATE SHA3_256_BLOCK_LENGTH
-+#define sha3_256 OQS_SHA3_sha3_256
-+#define sha3_256_inc_init OQS_SHA3_sha3_256_inc_init
-+#define sha3_256_inc_absorb OQS_SHA3_sha3_256_inc_absorb
-+#define sha3_256_inc_finalize OQS_SHA3_sha3_256_inc_finalize
-+#define sha3_256_inc_ctx_clone OQS_SHA3_sha3_256_inc_ctx_clone
-+#define sha3_256_inc_ctx_release OQS_SHA3_sha3_256_inc_ctx_release
-+
-+#define SHA3_384_RATE SHA3_384_BLOCK_LENGTH
-+#define sha3_384 OQS_SHA3_sha3_384
-+#define sha3_384_inc_init OQS_SHA3_sha3_384_inc_init
-+#define sha3_384_inc_absorb OQS_SHA3_sha3_384_inc_absorb
-+#define sha3_384_inc_finalize OQS_SHA3_sha3_384_inc_finalize
-+#define sha3_384_inc_ctx_clone OQS_SHA3_sha3_384_inc_ctx_clone
-+#define sha3_384_inc_ctx_release OQS_SHA3_sha3_384_inc_ctx_release
-+
-+#define SHA3_512_RATE SHA3_512_BLOCK_LENGTH
-+#define sha3_512 OQS_SHA3_sha3_512
-+#define sha3_512_inc_init OQS_SHA3_sha3_512_inc_init
-+#define sha3_512_inc_absorb OQS_SHA3_sha3_512_inc_absorb
-+#define sha3_512_inc_finalize OQS_SHA3_sha3_512_inc_finalize
-+#define sha3_512_inc_ctx_clone OQS_SHA3_sha3_512_inc_ctx_clone
-+#define sha3_512_inc_ctx_release OQS_SHA3_sha3_512_inc_ctx_release
-+#endif
-+
-+typedef SHAKE_128Context *shake128incctx;
-+#define shake128_inc_init(ptr) \
-+ (*(ptr)) = SHAKE_128_NewContext(); \
-+ SHAKE_128_Begin(*(ptr))
-+#define shake128_inc_absorb(ptr, input, inlen) SHAKE_128_Absorb(*(ptr), input, inlen)
-+#define shake128_inc_finalize(ptr)
-+#define shake128_inc_squeeze(output, outlen, ptr) SHAKE_128_SqueezeEnd(*(ptr), output, outlen)
-+#define shake128_inc_ctx_release(ptr) SHAKE_128_DestroyContext(*(ptr), PR_TRUE)
-+#define shake128_inc_ctx_reset(ptr) SHAKE_128_Begin(ptr)
-+#ifdef NOT_SUPPORTED
-+#define shake128_inc_ctx_clone OQS_SHA3_shake128_inc_ctx_clone
-+#endif
-+
-+typedef SHAKE_256Context *shake256incctx;
-+#define shake256_inc_init(ptr) \
-+ (*(ptr)) = SHAKE_256_NewContext(); \
-+ SHAKE_256_Begin(*(ptr))
-+#define shake256_inc_absorb(ptr, input, inlen) SHAKE_256_Absorb(*(ptr), input, inlen)
-+#define shake256_inc_finalize(ptr)
-+#define shake256_inc_squeeze(output, outlen, ptr) SHAKE_256_SqueezeEnd(*(ptr), output, outlen)
-+#define shake256_inc_ctx_release(ptr) SHAKE_256_DestroyContext(*(ptr), PR_TRUE)
-+#define shake256_inc_ctx_reset(ptr) SHAKE_256_Begin(*ptr)
-+
-+#ifdef NOT_SUPPORTED
-+#define shake128_absorb_once OQS_SHA3_shake128_absorb_once
-+void OQS_SHA3_shake128_absorb_once(shake128incctx *state, const uint8_t *in, size_t inlen);
-+
-+#define shake256_absorb_once OQS_SHA3_shake256_absorb_once
-+void OQS_SHA3_shake256_absorb_once(shake256incctx *state, const uint8_t *in, size_t inlen);
-+#endif
-+
-+#define shake128_squeezeblocks(OUT, NBLOCKS, STATE) shake128_inc_squeeze(OUT, (NBLOCKS) * SHAKE128_RATE, STATE)
-+
-+#define shake256_squeezeblocks(OUT, NBLOCKS, STATE) shake256_inc_squeeze(OUT, (NBLOCKS) * SHAKE256_RATE, STATE)
-+
-+#endif
-diff --git a/lib/freebl/leancrypto/fips_mode.h b/lib/freebl/leancrypto/fips_mode.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/fips_mode.h
-@@ -0,0 +1,51 @@
-+/*
-+ * Copyright (C) 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef FIPS_MODE_H
-+#define FIPS_MODE_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/**
-+ * @brief Is FIPS 140 Mode enabled?
-+ *
-+ * return 0 == false, 1 == true
-+ */
-+int fips140_mode_enabled(void);
-+
-+#define FIPS140_PCT_LOOP(func) \
-+ if (fips140_mode_enabled()) { \
-+ unsigned int __i; \
-+ int __ret; \
-+ \
-+ for (__i = 0; __i < 5; __i++) { \
-+ __ret = func; \
-+ if (!__ret) \
-+ return __ret; \
-+ } \
-+ assert(0); \
-+ }
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* FIPS_MODE_H */
-diff --git a/lib/freebl/leancrypto/helper.h b/lib/freebl/leancrypto/helper.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/helper.h
-@@ -0,0 +1,75 @@
-+/*
-+ * Copyright (C) 2018 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef HELPER_H
-+#define HELPER_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#ifndef __not_used
-+#define __not_used __attribute__((__unused__))
-+#endif
-+#ifndef __maybe_unused
-+#define __maybe_unused __attribute__((__unused__))
-+#endif
-+#ifndef __always_inline
-+#define __always_inline __inline __attribute__((__always_inline__))
-+#endif
-+
-+#ifndef likely
-+#define likely(x) __builtin_expect(!!(x), 1)
-+#endif
-+#ifndef unlikely
-+#define unlikely(x) __builtin_expect(!!(x), 0)
-+#endif
-+
-+#ifndef LINUX_KERNEL
-+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-+#endif
-+
-+/**
-+ * @brief Obtain pointer to data structure when having a pointer to one of
-+ * its members.
-+ *
-+ * Example:
-+ * struct foo *val = member_to_struct(&struct->list_entry, struct foo, list_entry);
-+ *
-+ * @param member the pointer to the member.
-+ * @param data_type the data type of the struct the member is part of.
-+ * @param member_var the member variable of the struct the member is
-+ * referenced with
-+ */
-+#define member_to_struct(member, data_type, member_var) \
-+ (data_type *)((char *)(member) - (char *)&((data_type *)0)->member_var)
-+
-+/**
-+ * @brief Obtain size of a member of a data structure
-+ *
-+ * @param struct Data structure
-+ * @param member Member variable to obtain size from
-+ */
-+#define member_size(struct, member) (sizeof(((struct *)0)->member))
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* HELPER_H */
-diff --git a/lib/freebl/leancrypto/initialization.h b/lib/freebl/leancrypto/initialization.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/initialization.h
-@@ -0,0 +1,41 @@
-+/*
-+ * Copyright (C) 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef INITIALIZATION_H
-+#define INITIALIZATION_H
-+
-+#include "visibility.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+void ascon_fastest_impl(void);
-+void sha256_fastest_impl(void);
-+void sha512_fastest_impl(void);
-+void sha3_fastest_impl(void);
-+void aes_fastest_impl(void);
-+void kyber_riscv_rvv_selector(void);
-+void secure_execution_linux(void);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* INITIALIZATION_H */
-diff --git a/lib/freebl/leancrypto/lc_dilithium.h b/lib/freebl/leancrypto/lc_dilithium.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/lc_dilithium.h
-@@ -0,0 +1,1853 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#ifndef LC_DILITHIUM_H
-+#define LC_DILITHIUM_H
-+
-+#include "ext_headers.h"
-+
-+#if defined __has_include
-+#if __has_include("lc_dilithium_87.h")
-+#include "lc_dilithium_87.h"
-+#define LC_DILITHIUM_87_ENABLED
-+#endif
-+#if __has_include("lc_dilithium_65.h")
-+#include "lc_dilithium_65.h"
-+#define LC_DILITHIUM_65_ENABLED
-+#endif
-+#if __has_include("lc_dilithium_44.h")
-+#include "lc_dilithium_44.h"
-+#define LC_DILITHIUM_44_ENABLED
-+#endif
-+#else
-+#error "Compiler misses __has_include"
-+#endif
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+enum lc_dilithium_type {
-+ /** Unknown key type */
-+ LC_DILITHIUM_UNKNOWN,
-+ /** Dilithium 87 */
-+ LC_DILITHIUM_87,
-+ /** Dilithium 65 */
-+ LC_DILITHIUM_65,
-+ /** Dilithium 44 */
-+ LC_DILITHIUM_44,
-+};
-+
-+/** @defgroup Dilithium ML-DSA / CRYSTALS-Dilithium Signature Mechanism
-+ *
-+ * \note Although the API uses the term "dilithium", the implementation complies
-+ * with FIPS 204. Thus the terms Dilithium and ML-DSA are used interchangeably.
-+ *
-+ * Dilithium API concept
-+ *
-+ * The Dilithium API is accessible via the following header files with the
-+ * mentioned purpose.
-+ *
-+ * * lc_dilithium.h: This API is the generic API allowing the caller to select
-+ * which Dilithium type (Dilithium 87, 65 or 44) are to be used. The selection
-+ * is made either with the flag specified during key generation or by matching
-+ * the size of the imported data with the different lc_dilithium_*_load API
-+ * calls. All remaining APIs take the information about the Dilithium type
-+ * from the provided input data.
-+ *
-+ * This header file only provides inline functions which selectively call
-+ * the API provided with the header files below.
-+ *
-+ * * lc_dilithium_87.h: Direct access to Dilithium 87.
-+ *
-+ * * lc_dilithium_65.h: Direct access to Dilithium 65.
-+ *
-+ * * lc_dilithium_44.h: Direct access to Dilithium 44.
-+ *
-+ * To support the stream mode of the Dilithium signature operation, a
-+ * context structure is required. This context structure can be allocated either
-+ * on the stack or heap with \p LC_DILITHIUM_CTX_ON_STACK or
-+ * \p lc_dilithium_ctx_alloc. The context should be zeroized
-+ * and freed (only for heap) with \p lc_dilithium_ctx_zero or
-+ * \p lc_dilithium_ctx_zero_free.
-+ */
-+
-+/**
-+ * @brief Dilithium secret key
-+ */
-+struct lc_dilithium_sk {
-+ enum lc_dilithium_type dilithium_type;
-+ union {
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ struct lc_dilithium_87_sk sk_87;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ struct lc_dilithium_65_sk sk_65;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ struct lc_dilithium_44_sk sk_44;
-+#endif
-+ } key;
-+};
-+
-+/**
-+ * @brief Dilithium public key
-+ */
-+struct lc_dilithium_pk {
-+ enum lc_dilithium_type dilithium_type;
-+ union {
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ struct lc_dilithium_87_pk pk_87;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ struct lc_dilithium_65_pk pk_65;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ struct lc_dilithium_44_pk pk_44;
-+#endif
-+ } key;
-+};
-+
-+/**
-+ * @brief Dilithium signature
-+ */
-+struct lc_dilithium_sig {
-+ enum lc_dilithium_type dilithium_type;
-+ union {
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ struct lc_dilithium_87_sig sig_87;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ struct lc_dilithium_65_sig sig_65;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ struct lc_dilithium_44_sig sig_44;
-+#endif
-+ } sig;
-+};
-+
-+/**
-+ * @brief Allocate stack memory for the Dilithium stream context and additional
-+ * parameter relevant for the signature operation.
-+ *
-+ * In addition, the memory buffer returned by this allocation contains the space
-+ * for an expanded representation of the public key which is required in both,
-+ * signature generation and verification. When using this memory, the first
-+ * signature operation expands the key and any subsequent operation using this
-+ * context will re-use the expanded key which improves performance of the
-+ * signature operation significantly.
-+ *
-+ * As the same expanded structure is used for signature generation and
-+ * verification and the structure can be expanded by either operation, it
-+ * is perfectly legal to use one context for both operations as the expanded
-+ * key can (a) be generated from either the public or the secret key and (b)
-+ * it applies to both operations and (c) is identical irrespective it was
-+ * generated from the public or secret key.
-+ *
-+ * The provided context size is sufficiently large to support all ML-DSA key
-+ * sizes this library version offers support for.
-+ *
-+ * \note: ML-DSA AVX2 signature operation uses a completely different
-+ * algorithm which does not use a pre-pcomputed expanded key. Thus, if you know
-+ * you have AVX2 support, you *may* not need this larger buffer and you *can*
-+ * use \p LC_DILITHIUM_CTX_ON_STACK instead.
-+ *
-+ * \note: The expanded representation only uses public key data. Even when
-+ * deriving the expanded representation from a secret key, this data is only
-+ * obtained from a part that is considered public. Thus, this memory does not
-+ * require special protections. See FIPS 204 section 3.6.3 on the properties
-+ * and handling requirements of the  matrix. Further, see the FIPS 204
-+ * ML-DSA.Sign_internal and ML-DSA.Verify_internal algorithm specification on
-+ * how this  matrix is generated and that the input to the generation is public
-+ * data.
-+ *
-+ * \warning: One instance of the expanded key representation can only ever apply
-+ * to one given key (pair). If you want to reuse the context with multiple keys,
-+ * you MUST invalidate the potentially present expanded key representation. Such
-+ * invalidation is invoked with the method \p lc_dilithium_ctx_drop_ahat. Only
-+ * after this invalidation you can use the context with a different key.
-+ *
-+ * param [in] name Name of the stack variable
-+ */
-+#ifdef LC_DILITHIUM_87_ENABLED
-+#define LC_DILITHIUM_CTX_ON_STACK_AHAT(name) \
-+ LC_DILITHIUM_87_CTX_ON_STACK_AHAT(name)
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+LC_DILITHIUM_CTX_ON_STACK_AHAT(name)
-+LC_DILITHIUM_65_CTX_ON_STACK_AHAT(name)
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+LC_DILITHIUM_CTX_ON_STACK_AHAT(name)
-+LC_DILITHIUM_44_CTX_ON_STACK_AHAT(name)
-+#endif
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Allocates Dilithium context on heap
-+ *
-+ * @param [out] ctx Dilithium context pointer
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ctx_alloc(struct lc_dilithium_ctx **ctx);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Allocates Dilithium context on heap with support to keep the internal
-+ * representation of the key.
-+ *
-+ * \note See \p LC_DILITHIUM_CTX_ON_STACK_AHAT for details.
-+ *
-+ * @param [out] ctx Dilithium context pointer
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ctx_alloc_ahat(struct lc_dilithium_ctx **ctx);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Zeroizes and frees Dilithium context on heap
-+ *
-+ * @param [out] ctx Dilithium context pointer
-+ */
-+void lc_dilithium_ctx_zero_free(struct lc_dilithium_ctx *ctx);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Zeroizes Dilithium context either on heap or on stack
-+ *
-+ * @param [out] ctx Dilithium context pointer
-+ */
-+void lc_dilithium_ctx_zero(struct lc_dilithium_ctx *ctx);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Mark the Dilithium context to execute ML-DSA.Sign_internal /
-+ * ML-DSA.Verify_internal.
-+ *
-+ * @param [in] ctx Dilithium context
-+ */
-+void lc_dilithium_ctx_internal(struct lc_dilithium_ctx *ctx);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Set the hash type that was used for pre-hashing the message. The
-+ * message digest is used with the HashML-DSA. The message digest
-+ * is to be provided via the message pointer in the sign/verify APIs.
-+ *
-+ * @param [in] ctx Dilithium context
-+ * @param [in] hash Hash context referencing the used hash for pre-hashing the
-+ * message
-+ */
-+void lc_dilithium_ctx_hash(struct lc_dilithium_ctx *ctx,
-+ const struct lc_hash *hash);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Specify the optional user context string to be applied with the
-+ * Dilithium signature operation.
-+ *
-+ * @param [in] ctx Dilithium context
-+ * @param [in] userctx User context string
-+ * @param [in] userctxlen Size of the user context string
-+ */
-+void lc_dilithium_ctx_userctx(struct lc_dilithium_ctx *ctx,
-+ const uint8_t *userctx, size_t userctxlen);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Specify the optional external mu value.
-+ *
-+ * \note If the external mu is specified, the signature generation /
-+ * verification APIs do not require a message. In this case, the message buffer
-+ * can be set to NULL.
-+ *
-+ * \note If both a message and an external mu are provided, the external mu
-+ * takes precedence.
-+ *
-+ * @param [in] ctx Dilithium context
-+ * @param [in] external_mu User context string
-+ * @param [in] external_mu_len Size of the user context string
-+ */
-+void lc_dilithium_ctx_external_mu(struct lc_dilithium_ctx *ctx,
-+ const uint8_t *external_mu,
-+ size_t external_mu_len);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Invalidate the expanded key that potentially is stored in the context.
-+ *
-+ * This call can be executed on a context irrespective it was allocated with
-+ * space for the expanded representation or not. Thus, the caller does not need
-+ * to track whether the context supports the expanded key.
-+ *
-+ * @param [in] ctx Dilithium context
-+ */
-+void lc_dilithium_ctx_drop_ahat(struct lc_dilithium_ctx *ctx);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Obtain Dilithium type from secret key
-+ *
-+ * @param [in] sk Secret key from which the type is to be obtained
-+ *
-+ * @return key type
-+ */
-+enum lc_dilithium_type lc_dilithium_sk_type(const struct lc_dilithium_sk *sk);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Obtain Dilithium type from public key
-+ *
-+ * @param [in] pk Public key from which the type is to be obtained
-+ *
-+ * @return key type
-+ */
-+enum lc_dilithium_type lc_dilithium_pk_type(const struct lc_dilithium_pk *pk);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Obtain Dilithium type from signature
-+ *
-+ * @param [in] sig Signature from which the type is to be obtained
-+ *
-+ * @return key type
-+ */
-+enum lc_dilithium_type
-+lc_dilithium_sig_type(const struct lc_dilithium_sig *sig);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Return the size of the Dilithium secret key.
-+ *
-+ * @param [in] dilithium_type Dilithium type for which the size is requested
-+ *
-+ * @return requested size
-+ */
-+LC_PURE unsigned int
-+lc_dilithium_sk_size(enum lc_dilithium_type dilithium_type);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Return the size of the Dilithium public key.
-+ *
-+ * @param [in] dilithium_type Dilithium type for which the size is requested
-+ *
-+ * @return requested size
-+ */
-+LC_PURE unsigned int
-+lc_dilithium_pk_size(enum lc_dilithium_type dilithium_type);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Return the size of the Dilithium signature.
-+ *
-+ * @param [in] dilithium_type Dilithium type for which the size is requested
-+ *
-+ * @return requested size
-+ */
-+LC_PURE unsigned int
-+lc_dilithium_sig_size(enum lc_dilithium_type dilithium_type);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Load a Dilithium secret key provided with a buffer into the leancrypto
-+ * data structure.
-+ *
-+ * @param [out] sk Secret key to be filled (the caller must have it allocated)
-+ * @param [in] src_key Buffer that holds the key to be imported
-+ * @param [in] src_key_len Buffer length that holds the key to be imported
-+ *
-+ * @return 0 on success or < 0 on error
-+ */
-+int lc_dilithium_sk_load(struct lc_dilithium_sk *sk, const uint8_t *src_key,
-+ size_t src_key_len);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Load a Dilithium public key provided with a buffer into the leancrypto
-+ * data structure.
-+ *
-+ * @param [out] pk Secret key to be filled (the caller must have it allocated)
-+ * @param [in] src_key Buffer that holds the key to be imported
-+ * @param [in] src_key_len Buffer length that holds the key to be imported
-+ *
-+ * @return 0 on success or < 0 on error
-+ */
-+int lc_dilithium_pk_load(struct lc_dilithium_pk *pk, const uint8_t *src_key,
-+ size_t src_key_len);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Load a Dilithium signature provided with a buffer into the leancrypto
-+ * data structure.
-+ *
-+ * @param [out] sig Secret key to be filled (the caller must have it allocated)
-+ * @param [in] src_sig Buffer that holds the signature to be imported
-+ * @param [in] src_sig_len Buffer length that holds the signature to be imported
-+ *
-+ * @return 0 on success or < 0 on error
-+ */
-+int lc_dilithium_sig_load(struct lc_dilithium_sig *sig, const uint8_t *src_sig,
-+ size_t src_sig_len);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Obtain the reference to the Dilithium key and its length
-+ *
-+ * \note Only pointer references into the leancrypto data structure are returned
-+ * which implies that any modification will modify the leancrypto key, too.
-+ *
-+ * @param [out] dilithium_key Dilithium key pointer
-+ * @param [out] dilithium_key_len Length of the key buffer
-+ * @param [in] sk Dilithium secret key from which the references are obtained
-+ *
-+ * @return 0 on success, != 0 on error
-+ */
-+int lc_dilithium_sk_ptr(uint8_t **dilithium_key, size_t *dilithium_key_len,
-+ struct lc_dilithium_sk *sk);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Obtain the reference to the Dilithium key and its length
-+ *
-+ * \note Only pointer references into the leancrypto data structure are returned
-+ * which implies that any modification will modify the leancrypto key, too.
-+ *
-+ * @param [out] dilithium_key Dilithium key pointer
-+ * @param [out] dilithium_key_len Length of the key buffer
-+ * @param [in] pk Dilithium publi key from which the references are obtained
-+ *
-+ * @return 0 on success, != 0 on error
-+ */
-+int lc_dilithium_pk_ptr(uint8_t **dilithium_key, size_t *dilithium_key_len,
-+ struct lc_dilithium_pk *pk);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Obtain the reference to the Dilithium signature and its length
-+ *
-+ * \note Only pointer references into the leancrypto data structure are returned
-+ * which implies that any modification will modify the leancrypto signature,
-+ * too.
-+ *
-+ * @param [out] dilithium_sig Dilithium signature pointer
-+ * @param [out] dilithium_sig_len Length of the signature buffer
-+ * @param [in] sig Dilithium signature from which the references are obtained
-+ *
-+ * @return 0 on success, != 0 on error
-+ */
-+int lc_dilithium_sig_ptr(uint8_t **dilithium_sig, size_t *dilithium_sig_len,
-+ struct lc_dilithium_sig *sig);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Generates Dilithium public and private key.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] rng_ctx pointer to seeded random number generator context
-+ * @param [in] dilithium_type type of the Dilithium key to generate
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_keypair(struct lc_dilithium_pk *pk, struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx,
-+ enum lc_dilithium_type dilithium_type);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Generates Dilithium public and private key from a given seed.
-+ *
-+ * The idea of the function is the allowance of FIPS 204 to maintain the seed
-+ * used to generate a key pair in lieu of maintaining a private key or the
-+ * key pair (which used much more memory). The seed must be treated equally
-+ * sensitive as a private key.
-+ *
-+ * The seed is generated by simply obtaining 32 bytes from a properly seeded
-+ * DRNG, i.e. the same way as a symmetric key would be generated.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] seed buffer with the seed data which must be exactly 32 bytes
-+ * in size
-+ * @param [in] seedlen length of the seed buffer
-+ * @param [in] dilithium_type type of the Dilithium key to generate
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_keypair_from_seed(struct lc_dilithium_pk *pk,
-+ struct lc_dilithium_sk *sk,
-+ const uint8_t *seed, size_t seedlen,
-+ enum lc_dilithium_type dilithium_type);
-+
-+/**
-+ * @brief Pairwise consistency check as per FIPS 140 IG
-+ *
-+ * This call should be invoked after generating a key pair in FIPS mode
-+ *
-+ * @param [in] pk Public key
-+ * @param [in] sk Secret key
-+ *
-+ * @return 0 on success, < 0 on error
-+ */
-+int lc_dilithium_pct(const struct lc_dilithium_pk *pk,
-+ const struct lc_dilithium_sk *sk);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Computes signature in one shot
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_sign(struct lc_dilithium_sig *sig, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Computes signature woth user context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * Using the ctx structure, the caller can select 3 different types of ML-DSA:
-+ *
-+ * * ctx->dilithium_prehash_type set to a hash type, HashML-DSA is assumed which
-+ * implies that the message m must be exactly digest size (FIPS 204 section
-+ * 5.4)
-+ *
-+ * * ctx->ml_dsa_internal set to 1, the ML-DSA.Sign_internal and
-+ * .Verify_internal are executed (FIPS 204 chapter 6)
-+ *
-+ * * both aforementioned parameter set to NULL / 0, ML-DSA.Sign and
-+ * ML-DSA.Verify are executed (FIPS 204 sections 5.2 and 5.3)
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_sign_ctx(struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Initializes a signature operation
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_sign_update and lc_dilithium_sign_final.
-+ *
-+ * @param [in,out] ctx pointer Dilithium context
-+ * @param [in] sk pointer to bit-packed secret key
-+ *
-+ * @return 0 (success) or < 0 on error; -EOPNOTSUPP is returned if a different
-+ * hash than lc_shake256 is used.
-+ */
-+int lc_dilithium_sign_init(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_sk *sk);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Add more data to an already initialized signature state
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_sign_init and lc_dilithium_sign_final.
-+ *
-+ * @param [in] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_sign_update(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Computes signature
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init and filled with
-+ * lc_dilithium_sign_update
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_sign_final(struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Verifies signature in one shot
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_verify(const struct lc_dilithium_sig *sig, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_pk *pk);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Verifies signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_verify_ctx(const struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_pk *pk);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Initializes a signature verification operation
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_verify_update and
-+ * lc_dilithium_verify_final.
-+ *
-+ * @param [in,out] ctx pointer to an allocated Dilithium context
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 (success) or < 0 on error; -EOPNOTSUPP is returned if a different
-+ * hash than lc_shake256 is used.
-+ */
-+int lc_dilithium_verify_init(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_pk *pk);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Add more data to an already initialized signature state
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_verify_init and
-+ * lc_dilithium_verify_final.
-+ *
-+ * @param [in] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_verify_update(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+
-+/**
-+ * @ingroup Dilithium
-+ * @brief Verifies signature
-+ *
-+ * @param [in] sig pointer to output signature
-+ * @param [in] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init and filled with
-+ * lc_dilithium_sign_update
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_verify_final(const struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_pk *pk);
-+
-+/****************************** Dilithium ED25510 *****************************/
-+
-+#ifdef LC_DILITHIUM_ED25519_SIG
-+
-+/** @defgroup HybridDilithium ML-DSA / CRYSTALS-Dilithium Hybrid Signature Mechanism
-+ *
-+ * The Dilithium hybrid API performs signature operations with Dilithium and
-+ * the classic ED25519 algorithm at the same time. The API is identical to
-+ * the Dilithium API and can be used as a drop-in replacement.
-+ *
-+ * ED25519ph is used for the hybrid signature operation compliant to
-+ * RFC8032 using a NULL context. This approach is taken to support the
-+ * stream mode operation with init / update / final.
-+ *
-+ * To support the stream mode of the Dilithium signature operation, a
-+ * context structure is required. This context structure can be allocated either
-+ * on the stack or heap with \p LC_DILITHIUM_ED25519_CTX_ON_STACK or
-+ * \p lc_dilithium_ed25519_ctx_alloc. The context should be zeroized
-+ * and freed (only for heap) with \p lc_dilithium_ed25519_ctx_zero or
-+ * \p lc_dilithium_ed25519_ctx_zero_free.
-+ */
-+
-+/**
-+ * @brief Dilithium secret key
-+ */
-+struct lc_dilithium_ed25519_sk {
-+ enum lc_dilithium_type dilithium_type;
-+ union {
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ struct lc_dilithium_87_ed25519_sk sk_87;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ struct lc_dilithium_65_ed25519_sk sk_65;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ struct lc_dilithium_44_ed25519_sk sk_44;
-+#endif
-+ } key;
-+};
-+
-+/**
-+ * @brief Dilithium public key
-+ */
-+struct lc_dilithium_ed25519_pk {
-+ enum lc_dilithium_type dilithium_type;
-+ union {
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ struct lc_dilithium_87_ed25519_pk pk_87;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ struct lc_dilithium_65_ed25519_pk pk_65;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ struct lc_dilithium_44_ed25519_pk pk_44;
-+#endif
-+ } key;
-+};
-+
-+/**
-+ * @brief Dilithium signature
-+ */
-+struct lc_dilithium_ed25519_sig {
-+ enum lc_dilithium_type dilithium_type;
-+ union {
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ struct lc_dilithium_87_ed25519_sig sig_87;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ struct lc_dilithium_65_ed25519_sig sig_65;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ struct lc_dilithium_44_ed25519_sig sig_44;
-+#endif
-+ } sig;
-+};
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Allocates Dilithium-ED25519 context on heap
-+ *
-+ * @param [out] ctx Dilithium-ED25519 context pointer
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed25519_ctx_alloc(struct lc_dilithium_ed25519_ctx **ctx);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Zeroizes and frees Dilithium-ED25519 context on heap
-+ *
-+ * @param [out] ctx Dilithium-ED25519 context pointer
-+ */
-+void lc_dilithium_ed25519_ctx_zero_free(struct lc_dilithium_ed25519_ctx *ctx);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Zeroizes Dilithium-ED25519 context either on heap or on stack
-+ *
-+ * @param [out] ctx Dilithium-ED25519 context pointer
-+ */
-+void lc_dilithium_ed25519_ctx_zero(struct lc_dilithium_ed25519_ctx *ctx);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Set the hash type that was used for pre-hashing the message. The
-+ * message digest ist used with the HashML-DSA. The message digest
-+ * is to be provided via the message pointer in the sign/verify APIs.
-+ *
-+ * @param [in] ctx Dilithium-ED25519 context
-+ * @param [in] hash Hash context referencing the used hash for pre-hashing the
-+ * message
-+ */
-+void lc_dilithium_ed25519_ctx_hash(struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_hash *hash);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Mark the Dilithium context to execute ML-DSA.Sign_internal /
-+ * ML-DSA.Verify_internal.
-+ *
-+ * @param [in] ctx Dilithium-ED25519 context
-+ */
-+void lc_dilithium_ed25519_ctx_internal(struct lc_dilithium_ed25519_ctx *ctx);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Specify the optional user context string to be applied with the
-+ * Dilithium-ED25519 signature operation.
-+ *
-+ * \warning The operation of the HashComposite-ML-DSA operation clears out
-+ * this context during processing. If this context is reused, the caller MUST
-+ * set the cotext again.
-+ *
-+ * @param [in] ctx Dilithium-ED25519 context
-+ * @param [in] userctx User context string
-+ * @param [in] userctxlen Size of the user context string
-+ */
-+void lc_dilithium_ed25519_ctx_userctx(struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *userctx,
-+ size_t userctxlen);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Specify the optional randomizer to be applied with the
-+ * Dilithium-ED25519 signature operation.
-+ *
-+ * @param [in] ctx Dilithium-ED25519 context
-+ * @param [in] randomizer Randomizer
-+ * @param [in] randomizerlen Size of randomizer
-+ */
-+void lc_dilithium_ed25519_ctx_randomizer(struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *randomizer,
-+ size_t randomizerlen);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Obtain Dilithium type from secret key
-+ *
-+ * @param [in] sk Secret key from which the type is to be obtained
-+ *
-+ * @return key type
-+ */
-+enum lc_dilithium_type
-+lc_dilithium_ed25519_sk_type(const struct lc_dilithium_ed25519_sk *sk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Obtain Dilithium type from public key
-+ *
-+ * @param [in] pk Public key from which the type is to be obtained
-+ *
-+ * @return key type
-+ */
-+enum lc_dilithium_type
-+lc_dilithium_ed25519_pk_type(const struct lc_dilithium_ed25519_pk *pk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Obtain Dilithium type from signature
-+ *
-+ * @param [in] sig Signature from which the type is to be obtained
-+ *
-+ * @return key type
-+ */
-+enum lc_dilithium_type
-+lc_dilithium_ed25519_sig_type(const struct lc_dilithium_ed25519_sig *sig);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Return the size of the Dilithium secret key.
-+ *
-+ * @param [in] dilithium_type Dilithium type for which the size is requested
-+ *
-+ * @return requested size
-+ */
-+LC_PURE unsigned int
-+lc_dilithium_ed25519_sk_size(enum lc_dilithium_type dilithium_type);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Return the size of the Dilithium public key.
-+ *
-+ * @param [in] dilithium_type Dilithium type for which the size is requested
-+ *
-+ * @return requested size
-+ */
-+LC_PURE unsigned int
-+lc_dilithium_ed25519_pk_size(enum lc_dilithium_type dilithium_type);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Return the size of the Dilithium signature.
-+ *
-+ * @param [in] dilithium_type Dilithium type for which the size is requested
-+ *
-+ * @return requested size
-+ */
-+LC_PURE unsigned int
-+lc_dilithium_ed25519_sig_size(enum lc_dilithium_type dilithium_type);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Load a Dilithium secret key provided with a buffer into the leancrypto
-+ * data structure.
-+ *
-+ * @param [out] sk Secret key to be filled (the caller must have it allocated)
-+ * @param [in] dilithium_src_key Buffer that holds the Dilithium key to be
-+ * imported
-+ * @param [in] dilithium_src_key_len Buffer length that holds the key to be
-+ * imported
-+ * @param [in] ed25519_src_key Buffer that holds the ED25519 key to be imported
-+ * @param [in] ed25519_src_key_len Buffer length that holds the key to be
-+ * imported
-+ *
-+ * @return 0 on success or < 0 on error
-+ */
-+int lc_dilithium_ed25519_sk_load(struct lc_dilithium_ed25519_sk *sk,
-+ const uint8_t *dilithium_src_key,
-+ size_t dilithium_src_key_len,
-+ const uint8_t *ed25519_src_key,
-+ size_t ed25519_src_key_len);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Load a Dilithium public key provided with a buffer into the leancrypto
-+ * data structure.
-+ *
-+ * @param [out] pk Secret key to be filled (the caller must have it allocated)
-+ * @param [in] dilithium_src_key Buffer that holds the Dilithium key to be
-+ * imported
-+ * @param [in] dilithium_src_key_len Buffer length that holds the key to be
-+ * imported
-+ * @param [in] ed25519_src_key Buffer that holds the ED25519 key to be imported
-+ * @param [in] ed25519_src_key_len Buffer length that holds the key to be
-+ * imported
-+ *
-+ * @return 0 on success or < 0 on error
-+ */
-+int lc_dilithium_ed25519_pk_load(struct lc_dilithium_ed25519_pk *pk,
-+ const uint8_t *dilithium_src_key,
-+ size_t dilithium_src_key_len,
-+ const uint8_t *ed25519_src_key,
-+ size_t ed25519_src_key_len);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Load a Dilithium signature provided with a buffer into the leancrypto
-+ * data structure.
-+ *
-+ * @param [out] sig Secret key to be filled (the caller must have it allocated)
-+ * @param [in] dilithium_src_sig Buffer that holds the Dilithium signature to be
-+ * imported
-+ * @param [in] dilithium_src_sig_len Buffer length that holds the Dilithium
-+ * signature to be imported
-+ * @param [in] ed25519_src_sig Buffer that holds the ED25519 signature to be
-+ * imported
-+ * @param [in] ed25519_src_sig_len Buffer length that holds the ED25519
-+ * signature to be imported
-+ *
-+ * @return 0 on success or < 0 on error
-+ */
-+int lc_dilithium_ed25519_sig_load(struct lc_dilithium_ed25519_sig *sig,
-+ const uint8_t *dilithium_src_sig,
-+ size_t dilithium_src_sig_len,
-+ const uint8_t *ed25519_src_sig,
-+ size_t ed25519_src_sig_len);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Obtain the reference to the Dilithium key and its length
-+ *
-+ * \note Only pointer references into the leancrypto data structure are returned
-+ * which implies that any modification will modify the leancrypto key, too.
-+ *
-+ * @param [out] dilithium_key Dilithium key pointer
-+ * @param [out] dilithium_key_len Length of the key buffer
-+ * @param [out] ed25519_key ED25519 key pointer
-+ * @param [out] ed25519_key_len ED25519 of the key buffer
-+ * @param [in] sk Dilithium secret key from which the references are obtained
-+ *
-+ * @return 0 on success, != 0 on error
-+ */
-+int lc_dilithium_ed25519_sk_ptr(uint8_t **dilithium_key,
-+ size_t *dilithium_key_len,
-+ uint8_t **ed25519_key, size_t *ed25519_key_len,
-+ struct lc_dilithium_ed25519_sk *sk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Obtain the reference to the Dilithium key and its length
-+ *
-+ * \note Only pointer references into the leancrypto data structure are returned
-+ * which implies that any modification will modify the leancrypto key, too.
-+ *
-+ * @param [out] dilithium_key Dilithium key pointer
-+ * @param [out] dilithium_key_len Length of the key buffer
-+ * @param [out] ed25519_key ED25519 key pointer
-+ * @param [out] ed25519_key_len ED25519 of the key buffer
-+ * @param [in] pk Dilithium publi key from which the references are obtained
-+ *
-+ * @return 0 on success, != 0 on error
-+ */
-+int lc_dilithium_ed25519_pk_ptr(uint8_t **dilithium_key,
-+ size_t *dilithium_key_len,
-+ uint8_t **ed25519_key, size_t *ed25519_key_len,
-+ struct lc_dilithium_ed25519_pk *pk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Obtain the reference to the Dilithium signature and its length
-+ *
-+ * \note Only pointer references into the leancrypto data structure are returned
-+ * which implies that any modification will modify the leancrypto signature,
-+ * too.
-+ *
-+ * @param [out] dilithium_sig Dilithium signature pointer
-+ * @param [out] dilithium_sig_len Length of the signature buffer
-+ * @param [out] ed25519_sig ED25519 signature pointer
-+ * @param [out] ed25519_sig_len ED25519 of the signature buffer
-+ * @param [in] sig Dilithium signature from which the references are obtained
-+ *
-+ * @return 0 on success, != 0 on error
-+ */
-+int lc_dilithium_ed25519_sig_ptr(uint8_t **dilithium_sig,
-+ size_t *dilithium_sig_len,
-+ uint8_t **ed25519_sig, size_t *ed25519_sig_len,
-+ struct lc_dilithium_ed25519_sig *sig);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Generates Dilithium public and private key.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] rng_ctx pointer to seeded random number generator context
-+ * @param [in] dilithium_type type of the Dilithium key to generate
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed25519_keypair(struct lc_dilithium_ed25519_pk *pk,
-+ struct lc_dilithium_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx,
-+ enum lc_dilithium_type dilithium_type);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Computes signature in one shot
-+ *
-+ * \note The one-shot API provides the algorithm of Composite-ML-DSA as outlined
-+ * in https://www.ietf.org/archive/id/draft-ietf-lamps-pq-composite-sigs-03.html
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed25519_sign(struct lc_dilithium_ed25519_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Computes signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * \note The one-shot API provides the algorithm of Composite-ML-DSA as outlined
-+ * in https://www.ietf.org/archive/id/draft-ietf-lamps-pq-composite-sigs-03.html
-+ * If the caller specifies a hash algorithm as pre-hash algorithm in the context
-+ * via \p lc_dilithium_ctx_hash then *only* the ML-DSA part is affected and
-+ * changed into a HashML-DSA which implies that the resulting operation is still
-+ * Composite-ML-DSA but with a HashML-DSA used internally - i.e. the resulting
-+ * algorithm does not comply to any standard. Therefore, it is best to not
-+ * use this method.
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed25519_sign_ctx(struct lc_dilithium_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Initializes signature operation in stream mode
-+ *
-+ * \note The stream API provides the algorithm of HashComposite-ML-DSA as
-+ * outlined in
-+ * https://www.ietf.org/archive/id/draft-ietf-lamps-pq-composite-sigs-03.html.
-+ * The reason is that ED25519 cannot operate in stream mode and thus must be
-+ * turned into using a pre-hashed message.
-+ *
-+ * @param [in] ctx Dilithium-ED25519 context pointer
-+ * @param [in] sk pointer to bit-packed secret key
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed25519_sign_init(struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_ed25519_sk *sk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Updates signature in stream mode
-+ *
-+ * @param [in] ctx Dilithium-ED25519 context pointer
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed25519_sign_update(struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Computes signature in stream mode
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx Dilithium-ED25519 context pointer
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed25519_sign_final(struct lc_dilithium_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Verifies signature in one shot
-+ *
-+ * \note The one-shot API provides the algorithm of Composite-ML-DSA as outlined
-+ * in https://www.ietf.org/archive/id/draft-ietf-lamps-pq-composite-sigs-03.html
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_ed25519_verify(const struct lc_dilithium_ed25519_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_ed25519_pk *pk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Verifies signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * \note The one-shot API provides the algorithm of Composite-ML-DSA as outlined
-+ * in https://www.ietf.org/archive/id/draft-ietf-lamps-pq-composite-sigs-03.html
-+ * If the caller specifies a hash algorithm as pre-hash algorithm in the context
-+ * via \p lc_dilithium_ctx_hash then *only* the ML-DSA part is affected and
-+ * changed into a HashML-DSA which implies that the resulting operation is still
-+ * Composite-ML-DSA but with a HashML-DSA used internally - i.e. the resulting
-+ * algorithm does not comply to any standard. Therefore, it is best to not
-+ * use this method.
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_ed25519_verify_ctx(const struct lc_dilithium_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_ed25519_pk *pk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Initializes signature verification operation in stream mode
-+ *
-+ * \note The stream API provides the algorithm of HashComposite-ML-DSA as
-+ * outlined in
-+ * https://www.ietf.org/archive/id/draft-ietf-lamps-pq-composite-sigs-03.html.
-+ * The reason is that ED25519 cannot operate in stream mode and thus must be
-+ * turned into using a pre-hashed message.
-+ *
-+ * @param [in] ctx Dilithium-ED25519 context pointer
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed25519_verify_init(struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_ed25519_pk *pk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Updates signature verification in stream mode
-+ *
-+ * @param [in] ctx Dilithium-ED25519 context pointer
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed25519_verify_update(struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Verifies signature in stream mode
-+ *
-+ * @param [in] sig pointer to input signatur
-+ * @param [in] ctx Dilithium-ED25519 context pointer
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_ed25519_verify_final(const struct lc_dilithium_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_ed25519_pk *pk);
-+
-+#endif /* LC_DILITHIUM_ED25519_SIG */
-+
-+/****************************** Dilithium ED25510 *****************************/
-+
-+#ifdef LC_DILITHIUM_ED448_SIG
-+
-+/** @defgroup HybridDilithium ML-DSA / CRYSTALS-Dilithium Hybrid Signature Mechanism
-+ *
-+ * The Dilithium hybrid API performs signature operations with Dilithium and
-+ * the classic ED448 algorithm at the same time. The API is identical to
-+ * the Dilithium API and can be used as a drop-in replacement.
-+ *
-+ * ED448ph is used for the hybrid signature operation compliant to
-+ * RFC8032 using a NULL context. This approach is taken to support the
-+ * stream mode operation with init / update / final.
-+ *
-+ * To support the stream mode of the Dilithium signature operation, a
-+ * context structure is required. This context structure can be allocated either
-+ * on the stack or heap with \p LC_DILITHIUM_ED448_CTX_ON_STACK or
-+ * \p lc_dilithium_ed448_ctx_alloc. The context should be zeroized
-+ * and freed (only for heap) with \p lc_dilithium_ed448_ctx_zero or
-+ * \p lc_dilithium_ed448_ctx_zero_free.
-+ *
-+ * \note The APIs for ML-DSA ED25519 and ED448 are identical. You can switch
-+ * between both by simply applying a global search and replace of 25519 <-> 448.
-+ */
-+
-+/**
-+ * @brief Dilithium secret key
-+ */
-+struct lc_dilithium_ed448_sk {
-+ enum lc_dilithium_type dilithium_type;
-+ union {
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ struct lc_dilithium_87_ed448_sk sk_87;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ struct lc_dilithium_65_ed448_sk sk_65;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ struct lc_dilithium_44_ed448_sk sk_44;
-+#endif
-+ } key;
-+};
-+
-+/**
-+ * @brief Dilithium public key
-+ */
-+struct lc_dilithium_ed448_pk {
-+ enum lc_dilithium_type dilithium_type;
-+ union {
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ struct lc_dilithium_87_ed448_pk pk_87;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ struct lc_dilithium_65_ed448_pk pk_65;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ struct lc_dilithium_44_ed448_pk pk_44;
-+#endif
-+ } key;
-+};
-+
-+/**
-+ * @brief Dilithium signature
-+ */
-+struct lc_dilithium_ed448_sig {
-+ enum lc_dilithium_type dilithium_type;
-+ union {
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ struct lc_dilithium_87_ed448_sig sig_87;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ struct lc_dilithium_65_ed448_sig sig_65;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ struct lc_dilithium_44_ed448_sig sig_44;
-+#endif
-+ } sig;
-+};
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Allocates Dilithium-ED448 context on heap
-+ *
-+ * @param [out] ctx Dilithium-ED448 context pointer
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed448_ctx_alloc(struct lc_dilithium_ed448_ctx **ctx);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Zeroizes and frees Dilithium-ED448 context on heap
-+ *
-+ * @param [out] ctx Dilithium-ED448 context pointer
-+ */
-+void lc_dilithium_ed448_ctx_zero_free(struct lc_dilithium_ed448_ctx *ctx);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Zeroizes Dilithium-ED448 context either on heap or on stack
-+ *
-+ * @param [out] ctx Dilithium-ED448 context pointer
-+ */
-+void lc_dilithium_ed448_ctx_zero(struct lc_dilithium_ed448_ctx *ctx);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Set the hash type that was used for pre-hashing the message. The
-+ * message digest ist used with the HashML-DSA. The message digest
-+ * is to be provided via the message pointer in the sign/verify APIs.
-+ *
-+ * @param [in] ctx Dilithium-ED448 context
-+ * @param [in] hash Hash context referencing the used hash for pre-hashing the
-+ * message
-+ */
-+void lc_dilithium_ed448_ctx_hash(struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_hash *hash);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Mark the Dilithium context to execute ML-DSA.Sign_internal /
-+ * ML-DSA.Verify_internal.
-+ *
-+ * @param [in] ctx Dilithium-ED448 context
-+ */
-+void lc_dilithium_ed448_ctx_internal(struct lc_dilithium_ed448_ctx *ctx);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Specify the optional user context string to be applied with the
-+ * Dilithium-ED448 signature operation.
-+ *
-+ * \warning The operation of the HashComposite-ML-DSA operation clears out
-+ * this context during processing. If this context is reused, the caller MUST
-+ * set the cotext again.
-+ *
-+ * @param [in] ctx Dilithium-ED448 context
-+ * @param [in] userctx User context string
-+ * @param [in] userctxlen Size of the user context string
-+ */
-+void lc_dilithium_ed448_ctx_userctx(struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *userctx, size_t userctxlen);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Specify the optional randomizer to be applied with the
-+ * Dilithium-ED25519 signature operation.
-+ *
-+ * @param [in] ctx Dilithium-ED25519 context
-+ * @param [in] randomizer Randomizer
-+ * @param [in] randomizerlen Size of randomizer
-+ */
-+void lc_dilithium_ed448_ctx_randomizer(struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *randomizer,
-+ size_t randomizerlen);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Obtain Dilithium type from secret key
-+ *
-+ * @param [in] sk Secret key from which the type is to be obtained
-+ *
-+ * @return key type
-+ */
-+enum lc_dilithium_type
-+lc_dilithium_ed448_sk_type(const struct lc_dilithium_ed448_sk *sk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Obtain Dilithium type from public key
-+ *
-+ * @param [in] pk Public key from which the type is to be obtained
-+ *
-+ * @return key type
-+ */
-+enum lc_dilithium_type
-+lc_dilithium_ed448_pk_type(const struct lc_dilithium_ed448_pk *pk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Obtain Dilithium type from signature
-+ *
-+ * @param [in] sig Signature from which the type is to be obtained
-+ *
-+ * @return key type
-+ */
-+enum lc_dilithium_type
-+lc_dilithium_ed448_sig_type(const struct lc_dilithium_ed448_sig *sig);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Return the size of the Dilithium secret key.
-+ *
-+ * @param [in] dilithium_type Dilithium type for which the size is requested
-+ *
-+ * @return requested size
-+ */
-+LC_PURE unsigned int
-+lc_dilithium_ed448_sk_size(enum lc_dilithium_type dilithium_type);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Return the size of the Dilithium public key.
-+ *
-+ * @param [in] dilithium_type Dilithium type for which the size is requested
-+ *
-+ * @return requested size
-+ */
-+LC_PURE unsigned int
-+lc_dilithium_ed448_pk_size(enum lc_dilithium_type dilithium_type);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Return the size of the Dilithium signature.
-+ *
-+ * @param [in] dilithium_type Dilithium type for which the size is requested
-+ *
-+ * @return requested size
-+ */
-+LC_PURE unsigned int
-+lc_dilithium_ed448_sig_size(enum lc_dilithium_type dilithium_type);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Load a Dilithium secret key provided with a buffer into the leancrypto
-+ * data structure.
-+ *
-+ * @param [out] sk Secret key to be filled (the caller must have it allocated)
-+ * @param [in] dilithium_src_key Buffer that holds the Dilithium key to be
-+ * imported
-+ * @param [in] dilithium_src_key_len Buffer length that holds the key to be
-+ * imported
-+ * @param [in] ed448_src_key Buffer that holds the ED448 key to be imported
-+ * @param [in] ed448_src_key_len Buffer length that holds the key to be
-+ * imported
-+ *
-+ * @return 0 on success or < 0 on error
-+ */
-+int lc_dilithium_ed448_sk_load(struct lc_dilithium_ed448_sk *sk,
-+ const uint8_t *dilithium_src_key,
-+ size_t dilithium_src_key_len,
-+ const uint8_t *ed448_src_key,
-+ size_t ed448_src_key_len);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Load a Dilithium public key provided with a buffer into the leancrypto
-+ * data structure.
-+ *
-+ * @param [out] pk Secret key to be filled (the caller must have it allocated)
-+ * @param [in] dilithium_src_key Buffer that holds the Dilithium key to be
-+ * imported
-+ * @param [in] dilithium_src_key_len Buffer length that holds the key to be
-+ * imported
-+ * @param [in] ed448_src_key Buffer that holds the ED448 key to be imported
-+ * @param [in] ed448_src_key_len Buffer length that holds the key to be
-+ * imported
-+ *
-+ * @return 0 on success or < 0 on error
-+ */
-+int lc_dilithium_ed448_pk_load(struct lc_dilithium_ed448_pk *pk,
-+ const uint8_t *dilithium_src_key,
-+ size_t dilithium_src_key_len,
-+ const uint8_t *ed448_src_key,
-+ size_t ed448_src_key_len);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Load a Dilithium signature provided with a buffer into the leancrypto
-+ * data structure.
-+ *
-+ * @param [out] sig Secret key to be filled (the caller must have it allocated)
-+ * @param [in] dilithium_src_sig Buffer that holds the Dilithium signature to be
-+ * imported
-+ * @param [in] dilithium_src_sig_len Buffer length that holds the Dilithium
-+ * signature to be imported
-+ * @param [in] ed448_src_sig Buffer that holds the ED448 signature to be
-+ * imported
-+ * @param [in] ed448_src_sig_len Buffer length that holds the ED448
-+ * signature to be imported
-+ *
-+ * @return 0 on success or < 0 on error
-+ */
-+int lc_dilithium_ed448_sig_load(struct lc_dilithium_ed448_sig *sig,
-+ const uint8_t *dilithium_src_sig,
-+ size_t dilithium_src_sig_len,
-+ const uint8_t *ed448_src_sig,
-+ size_t ed448_src_sig_len);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Obtain the reference to the Dilithium key and its length
-+ *
-+ * \note Only pointer references into the leancrypto data structure are returned
-+ * which implies that any modification will modify the leancrypto key, too.
-+ *
-+ * @param [out] dilithium_key Dilithium key pointer
-+ * @param [out] dilithium_key_len Length of the key buffer
-+ * @param [out] ed448_key ED448 key pointer
-+ * @param [out] ed448_key_len ED448 of the key buffer
-+ * @param [in] sk Dilithium secret key from which the references are obtained
-+ *
-+ * @return 0 on success, != 0 on error
-+ */
-+int lc_dilithium_ed448_sk_ptr(uint8_t **dilithium_key,
-+ size_t *dilithium_key_len, uint8_t **ed448_key,
-+ size_t *ed448_key_len,
-+ struct lc_dilithium_ed448_sk *sk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Obtain the reference to the Dilithium key and its length
-+ *
-+ * \note Only pointer references into the leancrypto data structure are returned
-+ * which implies that any modification will modify the leancrypto key, too.
-+ *
-+ * @param [out] dilithium_key Dilithium key pointer
-+ * @param [out] dilithium_key_len Length of the key buffer
-+ * @param [out] ed448_key ED448 key pointer
-+ * @param [out] ed448_key_len ED448 of the key buffer
-+ * @param [in] pk Dilithium publi key from which the references are obtained
-+ *
-+ * @return 0 on success, != 0 on error
-+ */
-+int lc_dilithium_ed448_pk_ptr(uint8_t **dilithium_key,
-+ size_t *dilithium_key_len, uint8_t **ed448_key,
-+ size_t *ed448_key_len,
-+ struct lc_dilithium_ed448_pk *pk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Obtain the reference to the Dilithium signature and its length
-+ *
-+ * \note Only pointer references into the leancrypto data structure are returned
-+ * which implies that any modification will modify the leancrypto signature,
-+ * too.
-+ *
-+ * @param [out] dilithium_sig Dilithium signature pointer
-+ * @param [out] dilithium_sig_len Length of the signature buffer
-+ * @param [out] ed448_sig ED448 signature pointer
-+ * @param [out] ed448_sig_len ED448 of the signature buffer
-+ * @param [in] sig Dilithium signature from which the references are obtained
-+ *
-+ * @return 0 on success, != 0 on error
-+ */
-+int lc_dilithium_ed448_sig_ptr(uint8_t **dilithium_sig,
-+ size_t *dilithium_sig_len, uint8_t **ed448_sig,
-+ size_t *ed448_sig_len,
-+ struct lc_dilithium_ed448_sig *sig);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Generates Dilithium public and private key.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] rng_ctx pointer to seeded random number generator context
-+ * @param [in] dilithium_type type of the Dilithium key to generate
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed448_keypair(struct lc_dilithium_ed448_pk *pk,
-+ struct lc_dilithium_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx,
-+ enum lc_dilithium_type dilithium_type);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Computes signature in one shot
-+ *
-+ * \note The one-shot API provides the algorithm of Composite-ML-DSA as outlined
-+ * in https://www.ietf.org/archive/id/draft-ietf-lamps-pq-composite-sigs-03.html
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed448_sign(struct lc_dilithium_ed448_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Computes signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * \note The one-shot API provides the algorithm of Composite-ML-DSA as outlined
-+ * in https://www.ietf.org/archive/id/draft-ietf-lamps-pq-composite-sigs-03.html
-+ * If the caller specifies a hash algorithm as pre-hash algorithm in the context
-+ * via \p lc_dilithium_ctx_hash then *only* the ML-DSA part is affected and
-+ * changed into a HashML-DSA which implies that the resulting operation is still
-+ * Composite-ML-DSA but with a HashML-DSA used internally - i.e. the resulting
-+ * algorithm does not comply to any standard. Therefore, it is best to not
-+ * use this method.
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed448_sign_ctx(struct lc_dilithium_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Initializes signature operation in stream mode
-+ *
-+ * \note The stream API provides the algorithm of HashComposite-ML-DSA as
-+ * outlined in
-+ * https://www.ietf.org/archive/id/draft-ietf-lamps-pq-composite-sigs-03.html.
-+ * The reason is that ED448 cannot operate in stream mode and thus must be
-+ * turned into using a pre-hashed message.
-+ *
-+ * @param [in] ctx Dilithium-ED448 context pointer
-+ * @param [in] sk pointer to bit-packed secret key
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed448_sign_init(struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_ed448_sk *sk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Updates signature in stream mode
-+ *
-+ * @param [in] ctx Dilithium-ED448 context pointer
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed448_sign_update(struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Computes signature in stream mode
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx Dilithium-ED448 context pointer
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed448_sign_final(struct lc_dilithium_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Verifies signature in one shot
-+ *
-+ * \note The one-shot API provides the algorithm of Composite-ML-DSA as outlined
-+ * in https://www.ietf.org/archive/id/draft-ietf-lamps-pq-composite-sigs-03.html
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_ed448_verify(const struct lc_dilithium_ed448_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_ed448_pk *pk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Verifies signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * \note The one-shot API provides the algorithm of Composite-ML-DSA as outlined
-+ * in https://www.ietf.org/archive/id/draft-ietf-lamps-pq-composite-sigs-03.html
-+ * If the caller specifies a hash algorithm as pre-hash algorithm in the context
-+ * via \p lc_dilithium_ctx_hash then *only* the ML-DSA part is affected and
-+ * changed into a HashML-DSA which implies that the resulting operation is still
-+ * Composite-ML-DSA but with a HashML-DSA used internally - i.e. the resulting
-+ * algorithm does not comply to any standard. Therefore, it is best to not
-+ * use this method.
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_ed448_verify_ctx(const struct lc_dilithium_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_ed448_pk *pk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Initializes signature verification operation in stream mode
-+ *
-+ * \note The stream API provides the algorithm of HashComposite-ML-DSA as
-+ * outlined in
-+ * https://www.ietf.org/archive/id/draft-ietf-lamps-pq-composite-sigs-03.html.
-+ * The reason is that ED448 cannot operate in stream mode and thus must be
-+ * turned into using a pre-hashed message.
-+ *
-+ * @param [in] ctx Dilithium-ED448 context pointer
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed448_verify_init(struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_ed448_pk *pk);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Updates signature verification in stream mode
-+ *
-+ * @param [in] ctx Dilithium-ED448 context pointer
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_ed448_verify_update(struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+
-+/**
-+ * @ingroup HybridDilithium
-+ * @brief Verifies signature in stream mode
-+ *
-+ * @param [in] sig pointer to input signatur
-+ * @param [in] ctx Dilithium-ED448 context pointer
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_ed448_verify_final(const struct lc_dilithium_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_ed448_pk *pk);
-+
-+#endif /* LC_DILITHIUM_ED448_SIG */
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* LC_DILITHIUM_H */
-diff --git a/lib/freebl/leancrypto/lc_dilithium_44.h b/lib/freebl/leancrypto/lc_dilithium_44.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/lc_dilithium_44.h
-@@ -0,0 +1,1135 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#ifndef LC_DILITHIUM_44_H
-+#define LC_DILITHIUM_44_H
-+
-+#ifndef __ASSEMBLER__
-+
-+#include "ext_headers.h"
-+#include "lc_hash.h"
-+#include "lc_rng.h"
-+#include "lc_sha3.h"
-+#include "lc_sha512.h"
-+
-+#endif /* __ASSEMBLER__ */
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/// \cond DO_NOT_DOCUMENT
-+/*
-+ * Dilithium Security Levels
-+ * 2 -> 192 bits of security strength
-+ * 3 -> 225 bits of security strength
-+ * 5 -> 257 bits of security strength
-+ */
-+#define LC_DILITHIUM_MODE 2
-+
-+#define LC_DILITHIUM_SEEDBYTES 32
-+#define LC_DILITHIUM_CRHBYTES 64
-+#define LC_DILITHIUM_TRBYTES 64
-+#define LC_DILITHIUM_RNDBYTES 32
-+#define LC_DILITHIUM_N 256
-+#define LC_DILITHIUM_Q 8380417
-+#define LC_DILITHIUM_D 13
-+#define LC_DILITHIUM_ROOT_OF_UNITY 1753
-+
-+#if LC_DILITHIUM_MODE == 2
-+#define LC_DILITHIUM_NIST_CATEGORY 1
-+#define LC_DILITHIUM_LAMBDA 128
-+#define LC_DILITHIUM_K 4
-+#define LC_DILITHIUM_L 4
-+#define LC_DILITHIUM_ETA 2
-+#define LC_DILITHIUM_TAU 39
-+#define LC_DILITHIUM_BETA 78
-+#define LC_DILITHIUM_GAMMA1 (1 << 17)
-+#define LC_DILITHIUM_GAMMA2 ((LC_DILITHIUM_Q - 1) / 88)
-+#define LC_DILITHIUM_OMEGA 80
-+
-+#elif LC_DILITHIUM_MODE == 3
-+#define LC_DILITHIUM_NIST_CATEGORY 3
-+#define LC_DILITHIUM_LAMBDA 192
-+#define LC_DILITHIUM_K 6
-+#define LC_DILITHIUM_L 5
-+#define LC_DILITHIUM_ETA 4
-+#define LC_DILITHIUM_TAU 49
-+#define LC_DILITHIUM_BETA 196
-+#define LC_DILITHIUM_GAMMA1 (1 << 19)
-+#define LC_DILITHIUM_GAMMA2 ((LC_DILITHIUM_Q - 1) / 32)
-+#define LC_DILITHIUM_OMEGA 55
-+
-+#elif LC_DILITHIUM_MODE == 5
-+#define LC_DILITHIUM_NIST_CATEGORY 5
-+#define LC_DILITHIUM_LAMBDA 256
-+#define LC_DILITHIUM_K 8
-+#define LC_DILITHIUM_L 7
-+#define LC_DILITHIUM_ETA 2
-+#define LC_DILITHIUM_TAU 60
-+#define LC_DILITHIUM_BETA 120
-+#define LC_DILITHIUM_GAMMA1 (1 << 19)
-+#define LC_DILITHIUM_GAMMA2 ((LC_DILITHIUM_Q - 1) / 32)
-+#define LC_DILITHIUM_OMEGA 75
-+
-+#endif
-+
-+#define LC_DILITHIUM_CTILDE_BYTES (LC_DILITHIUM_LAMBDA * 2 / 8)
-+#define LC_DILITHIUM_POLYT1_PACKEDBYTES 320
-+#define LC_DILITHIUM_POLYT0_PACKEDBYTES 416
-+#define LC_DILITHIUM_POLYVECH_PACKEDBYTES (LC_DILITHIUM_OMEGA + LC_DILITHIUM_K)
-+
-+#if LC_DILITHIUM_GAMMA1 == (1 << 17)
-+#define LC_DILITHIUM_POLYZ_PACKEDBYTES 576
-+#elif LC_DILITHIUM_GAMMA1 == (1 << 19)
-+#define LC_DILITHIUM_POLYZ_PACKEDBYTES 640
-+#endif
-+
-+#if LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 88
-+#define LC_DILITHIUM_POLYW1_PACKEDBYTES 192
-+#elif LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 32
-+#define LC_DILITHIUM_POLYW1_PACKEDBYTES 128
-+#endif
-+
-+#if LC_DILITHIUM_ETA == 2
-+#define LC_DILITHIUM_POLYETA_PACKEDBYTES 96
-+#elif LC_DILITHIUM_ETA == 4
-+#define LC_DILITHIUM_POLYETA_PACKEDBYTES 128
-+#endif
-+
-+/*
-+ * Sizes of the different Dilithium buffer types.
-+ *
-+ * WARNING: Do not use these defines in your code. If you need the sizes of
-+ * the different variable sizes, use sizeof of the different variable structs or
-+ * use the different *_size functions documented below to retrieve the data size
-+ * of a particular Dilithium component.
-+ */
-+#define LC_DILITHIUM_PUBLICKEYBYTES \
-+ (LC_DILITHIUM_SEEDBYTES + \
-+ LC_DILITHIUM_K * LC_DILITHIUM_POLYT1_PACKEDBYTES)
-+#define LC_DILITHIUM_SECRETKEYBYTES \
-+ (2 * LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_TRBYTES + \
-+ LC_DILITHIUM_L * LC_DILITHIUM_POLYETA_PACKEDBYTES + \
-+ LC_DILITHIUM_K * LC_DILITHIUM_POLYETA_PACKEDBYTES + \
-+ LC_DILITHIUM_K * LC_DILITHIUM_POLYT0_PACKEDBYTES)
-+
-+#define LC_DILITHIUM_CRYPTO_BYTES \
-+ (LC_DILITHIUM_CTILDE_BYTES + \
-+ LC_DILITHIUM_L * LC_DILITHIUM_POLYZ_PACKEDBYTES + \
-+ LC_DILITHIUM_POLYVECH_PACKEDBYTES)
-+/// \endcond
-+
-+#ifndef __ASSEMBLER__
-+/**
-+ * @brief Dilithium secret key
-+ */
-+struct lc_dilithium_44_sk {
-+ uint8_t sk[LC_DILITHIUM_SECRETKEYBYTES];
-+};
-+
-+/**
-+ * @brief Dilithium public key
-+ */
-+struct lc_dilithium_44_pk {
-+ uint8_t pk[LC_DILITHIUM_PUBLICKEYBYTES];
-+};
-+
-+/**
-+ * @brief Dilithium signature
-+ */
-+struct lc_dilithium_44_sig {
-+ uint8_t sig[LC_DILITHIUM_CRYPTO_BYTES];
-+};
-+
-+#ifndef LC_DILITHIUM_CTX_ON_STACK
-+struct lc_dilithium_ctx {
-+ /**
-+ * @brief Hash context used internally to the library - it should not
-+ * be touched by the user
-+ */
-+ struct lc_hash_ctx dilithium_hash_ctx;
-+
-+ /**
-+ * @brief State memory of the hash context used internally to the
-+ * library - it should not be touched by the user
-+ */
-+ uint8_t shake_state[LC_SHA3_STATE_SIZE_ALIGN(LC_SHA3_256_CTX_SIZE)];
-+
-+ /**
-+ * @brief When using HashML-DSA, set the hash reference used for the
-+ * hash operation. Allowed values are lc_sha256, lc_sha512, lc_sha3_256,
-+ * lc_sha3_384, lc_sha3_512, lc_shake128 and lc_shake256. Note, the
-+ * actual message digest operation can be performed external to
-+ * leancrypto. This parameter only shall indicate the used hash
-+ * operation.
-+ *
-+ * \note Use \p lc_dilithium_ctx_hash or
-+ * \p lc_dilithium_ed25519_ctx_hash to set this value.
-+ */
-+ const struct lc_hash *dilithium_prehash_type;
-+
-+ /**
-+ * @brief length of the user context (allowed range between 0 and 255
-+ * bytes)
-+ *
-+ * \note Use \p lc_dilithium_ctx_userctx or
-+ * \p lc_dilithium_ed25519_ctx_userctx to set this value.
-+ */
-+ size_t userctxlen;
-+
-+ /**
-+ * @brief buffer with a caller-specified context string
-+ *
-+ * \note Use \p lc_dilithium_ctx_userctx or
-+ * \p lc_dilithium_ed25519_ctx_userctx to set this value.
-+ */
-+ const uint8_t *userctx;
-+
-+ /**
-+ * @brief Pointer to the AHat buffer. This can be provided by the caller
-+ * or it must be NULL otherwise.
-+ *
-+ * \note Use \p LC_DILITHIUM_CTX_ON_STACK_AHAT to provide memory for
-+ * storing AHat in the caller context and thus make the signature
-+ * operation much faster starting with the 2nd use of the key (pair).
-+ */
-+ void *ahat;
-+ unsigned short ahat_size;
-+
-+ /**
-+ * @brief Pointer to the external mu.
-+ *
-+ * If set, the signature operation will use the provided mu instead of
-+ * the message. In this case, the message pointer to the signature
-+ * generation or verification can be NULL.
-+ */
-+ const uint8_t *external_mu;
-+ size_t external_mu_len;
-+
-+ /**
-+ * @brief Pointer to the randomizer
-+ *
-+ * This is used for the Composite signature: For the discussion of the
-+ * randomizer, see https://lamps-wg.github.io/draft-composite-sigs/draft-ietf-lamps-pq-composite-sigs.html
-+ */
-+ const uint8_t *randomizer;
-+ size_t randomizerlen;
-+
-+ /**
-+ * @brief NIST category required for composite signatures
-+ *
-+ * The domain separation logic depends on the selection of the right
-+ * OID for the "Domain" data.
-+ */
-+ unsigned int nist_category;
-+
-+ /**
-+ * @brief When set to true, only the ML-DSA.Sign_internal or
-+ * ML-DSA.Verify_internal are performed (see FIPS 204 chapter 6).
-+ * Otherwise the ML-DSA.Sign / ML-DSA.Verify (see FIPS chapter 5) is
-+ * applied.
-+ *
-+ * \note Use \p lc_dilithium_ctx_internal or
-+ * \p lc_dilithium_ed25519_ctx_internal to set this value.
-+ *
-+ * \warning Only set this value to true if you exactly know what you are
-+ * doing!.
-+ */
-+ unsigned int ml_dsa_internal : 1;
-+
-+ /**
-+ * @brief Was aHat already filled? This is used and set internally.
-+ */
-+ unsigned int ahat_expanded : 1;
-+};
-+#endif
-+
-+/// \cond DO_NOT_DOCUMENT
-+
-+/*
-+ * The alignment is based on largest alignment of a polyvecl typedef - this is
-+ * the AVX2 definition.
-+ */
-+#define LC_DILITHIUM_AHAT_ALIGNMENT (32)
-+
-+/*
-+ * Padding between struct lc_dilithium_ctx and AHat buffer to ensure AHat buffer
-+ * is aligned to LC_DILITHIUM_AHAT_ALIGNMENT
-+ */
-+#define LC_DILITHIUM_44_AHAT_PAD \
-+ (LC_DILITHIUM_AHAT_ALIGNMENT - \
-+ (sizeof(struct lc_dilithium_ctx) % LC_DILITHIUM_AHAT_ALIGNMENT))
-+
-+/* Size of the AHat matrix for ML-DSA 87 */
-+#define LC_DILITHIUM_44_AHAT_SIZE \
-+ (256 * sizeof(int32_t) * LC_DILITHIUM_K * LC_DILITHIUM_L)
-+
-+#ifndef LC_DILITHIUM_CTX_ON_STACK
-+#define LC_DILITHIUM_CTX_SIZE sizeof(struct lc_dilithium_ctx)
-+
-+#define LC_DILITHIUM_CTX_INIT_HASH(name) \
-+ LC_SHAKE_256_CTX((&(name)->dilithium_hash_ctx))
-+
-+#define LC_DILITHIUM_SET_CTX(name) \
-+ LC_DILITHIUM_CTX_INIT_HASH(name); \
-+ (name)->dilithium_prehash_type = NULL; \
-+ (name)->ml_dsa_internal = 0; \
-+ (name)->userctxlen = 0; \
-+ (name)->userctx = NULL; \
-+ (name)->ahat = NULL; \
-+ (name)->ahat_size = 0; \
-+ (name)->external_mu = NULL; \
-+ (name)->external_mu_len = 0; \
-+ (name)->randomizer = NULL; \
-+ (name)->randomizerlen = 0; \
-+ (name)->nist_category = 0;
-+#endif
-+/// \endcond
-+
-+/**
-+ * @brief Allocate stack memory for the Dilithium stream context or additional
-+ * parameter relevant for the signature operation.
-+ *
-+ * @param [in] name Name of the stack variable
-+ */
-+#ifndef LC_DILITHIUM_CTX_ON_STACK
-+#define LC_DILITHIUM_CTX_ON_STACK(name) \
-+ _Pragma("GCC diagnostic push") _Pragma( \
-+ "GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \
-+ LC_ALIGNED_BUFFER(name##_ctx_buf, LC_DILITHIUM_CTX_SIZE, \
-+ LC_HASH_COMMON_ALIGNMENT); \
-+ struct lc_dilithium_ctx *name = \
-+ (struct lc_dilithium_ctx *)name##_ctx_buf; \
-+ LC_DILITHIUM_SET_CTX(name); \
-+ _Pragma("GCC diagnostic pop")
-+#endif
-+
-+/**
-+ * @brief Allocate stack memory for the Dilithium stream context and additional
-+ * parameter relevant for the signature operation.
-+ *
-+ * In addition, the memory buffer returned by this allocation contains the space
-+ * for an expanded representation of the public key which is required in both,
-+ * signature generation and verification. When using this memory, the first
-+ * signature operation expands the key and any subsequent operation using this
-+ * context will re-use the expanded key which improves performance of the
-+ * signature operation significantly.
-+ *
-+ * As the same expanded structure is used for signature generation and
-+ * verification and the structure can be expanded by either operation, it
-+ * is perfectly legal to use one context for both operations as the expanded
-+ * key can (a) be generated from either the public or the secret key and (b)
-+ * it applies to both operations and (c) is identical irrespective it was
-+ * generated from the public or secret key.
-+ *
-+ * \note: ML-DSA AVX2 signature operation uses a completely different
-+ * algorithm which does not use a pre-pcomputed expanded key. Thus, if you know
-+ * you have AVX2 support, you *may* not need this larger buffer and you *can*
-+ * use \p LC_DILITHIUM_CTX_ON_STACK instead.
-+ *
-+ * \note: The expanded representation only uses public key data. Even when
-+ * deriving the expanded representation from a secret key, this data is only
-+ * obtained from a part that is considered public. Thus, this memory does not
-+ * require special protections. See FIPS 204 section 3.6.3 on the properties
-+ * and handling requirements of the  matrix. Further, see the FIPS 204
-+ * ML-DSA.Sign_internal and ML-DSA.Verify_internal algorithm specification on
-+ * how this  matrix is generated and that the input to the generation is public
-+ * data.
-+ *
-+ * \warning: One instance of the expanded key representation can only ever apply
-+ * to one given key (pair). If you want to reuse the context with multiple keys,
-+ * you MUST invalidate the potentially present expanded key representation. Such
-+ * invalidation is invoked with the method \p lc_dilithium_ctx_drop_ahat. Only
-+ * after this invalidation you can use the context with a different key.
-+ *
-+ * @param [in] name Name of the stack variable
-+ */
-+#define LC_DILITHIUM_44_CTX_ON_STACK_AHAT(name) \
-+ _Pragma("GCC diagnostic push") _Pragma( \
-+ "GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \
-+ LC_ALIGNED_BUFFER(name##_ctx_buf, \
-+ LC_DILITHIUM_CTX_SIZE + \
-+ LC_DILITHIUM_44_AHAT_PAD + \
-+ LC_DILITHIUM_44_AHAT_SIZE, \
-+ LC_HASH_COMMON_ALIGNMENT); \
-+ struct lc_dilithium_ctx *name = \
-+ (struct lc_dilithium_ctx *)name##_ctx_buf; \
-+ LC_DILITHIUM_SET_CTX(name); \
-+ name->ahat = (uint8_t *)name + LC_DILITHIUM_CTX_SIZE + \
-+ LC_DILITHIUM_44_AHAT_PAD; \
-+ name->ahat_expanded = 0; \
-+ name->ahat_size = LC_DILITHIUM_44_AHAT_SIZE; \
-+ _Pragma("GCC diagnostic pop")
-+
-+/**
-+ * @brief Zeroize Dilithium context allocated with
-+ * LC_DILITHIUM_CTX_ON_STACK lc_dilithium_ed25519_alloc
-+ *
-+ * @param [in] ctx Dilithium context to be zeroized
-+ */
-+static inline void lc_dilithium_44_ctx_zero(struct lc_dilithium_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+ lc_hash_zero(&ctx->dilithium_hash_ctx);
-+ if (ctx->ahat) {
-+ lc_memset_secure(ctx->ahat, 0, ctx->ahat_size);
-+ ctx->ahat_expanded = 0;
-+ }
-+}
-+
-+/**
-+ * @brief Allocate Dilithium stream context on heap
-+ *
-+ * @param [out] ctx Allocated Dilithium stream context
-+ *
-+ * @return: 0 on success, < 0 on error
-+ */
-+int lc_dilithium_44_ctx_alloc(struct lc_dilithium_ctx **ctx);
-+
-+/**
-+ * @brief Allocate Dilithium stream context on heap including additional
-+ * parameter relevant for the signature operation.
-+ *
-+ * \note See \p LC_DILITHIUM_44_CTX_ON_STACK_AHAT for details.
-+ *
-+ * @param [out] ctx Allocated Dilithium stream context
-+ *
-+ * @return: 0 on success, < 0 on error
-+ */
-+int lc_dilithium_44_ctx_alloc_ahat(struct lc_dilithium_ctx **ctx);
-+
-+/**
-+ * @brief Zeroize and free Dilithium stream context
-+ *
-+ * @param [in] ctx Dilithium stream context to be zeroized and freed
-+ */
-+void lc_dilithium_44_ctx_zero_free(struct lc_dilithium_ctx *ctx);
-+
-+/**
-+ * @brief Return the size of the Dilithium secret key.
-+ */
-+LC_PURE
-+static inline unsigned int lc_dilithium_44_sk_size(void)
-+{
-+ return lc_member_size(struct lc_dilithium_44_sk, sk);
-+}
-+
-+/**
-+ * @brief Return the size of the Dilithium public key.
-+ */
-+LC_PURE
-+static inline unsigned int lc_dilithium_44_pk_size(void)
-+{
-+ return lc_member_size(struct lc_dilithium_44_pk, pk);
-+}
-+
-+/**
-+ * @brief Return the size of the Dilithium signature.
-+ */
-+LC_PURE
-+static inline unsigned int lc_dilithium_44_sig_size(void)
-+{
-+ return lc_member_size(struct lc_dilithium_44_sig, sig);
-+}
-+
-+/**
-+ * @brief Generates Dilithium public and private key.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] rng_ctx pointer to seeded random number generator context
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_44_keypair(struct lc_dilithium_44_pk *pk,
-+ struct lc_dilithium_44_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Generates Dilithium public and private key from a given seed.
-+ *
-+ * The idea of the function is the allowance of FIPS 204 to maintain the seed
-+ * used to generate a key pair in lieu of maintaining a private key or the
-+ * key pair (which used much more memory). The seed must be treated equally
-+ * sensitive as a private key.
-+ *
-+ * The seed is generated by simply obtaining 32 bytes from a properly seeded
-+ * DRNG, i.e. the same way as a symmetric key would be generated.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] seed buffer with the seed data which must be exactly 32 bytes
-+ * in size
-+ * @param [in] seedlen length of the seed buffer
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_44_keypair_from_seed(struct lc_dilithium_44_pk *pk,
-+ struct lc_dilithium_44_sk *sk,
-+ const uint8_t *seed, size_t seedlen);
-+
-+/**
-+ * @brief Computes ML-DSA signature in one shot
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_44_sign(struct lc_dilithium_44_sig *sig, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_44_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Computes signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_44_sign_ctx(struct lc_dilithium_44_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_44_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Initializes a signature operation
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_sign_update and lc_dilithium_sign_final.
-+ *
-+ * @param [in,out] ctx pointer to an allocated Dilithium context
-+ * @param [in] sk pointer to bit-packed secret key
-+ *
-+ * @return 0 (success) or < 0 on error; -EOPNOTSUPP is returned if a different
-+ * hash than lc_shake256 is used.
-+ */
-+int lc_dilithium_44_sign_init(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_44_sk *sk);
-+
-+/**
-+ * @brief Add more data to an already initialized signature state
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_sign_init and lc_dilithium_sign_final.
-+ *
-+ * @param [in] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_44_sign_update(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+
-+/**
-+ * @brief Computes signature
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init and filled with
-+ * lc_dilithium_sign_update
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_44_sign_final(struct lc_dilithium_44_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_44_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Verifies ML-DSA signature in one shot
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_44_verify(const struct lc_dilithium_44_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_44_pk *pk);
-+
-+/**
-+ * @brief Verifies signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_44_verify_ctx(const struct lc_dilithium_44_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen,
-+ const struct lc_dilithium_44_pk *pk);
-+
-+/**
-+ * @brief Initializes a signature verification operation
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_verify_update and
-+ * lc_dilithium_verify_final.
-+ *
-+ * @param [in,out] ctx pointer to an allocated Dilithium context
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 (success) or < 0 on error; -EOPNOTSUPP is returned if a different
-+ * hash than lc_shake256 is used.
-+ */
-+int lc_dilithium_44_verify_init(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_44_pk *pk);
-+
-+/**
-+ * @brief Add more data to an already initialized signature state
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_verify_init and
-+ * lc_dilithium_verify_final.
-+ *
-+ * @param [in,out] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_44_verify_update(struct lc_dilithium_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+
-+/**
-+ * @brief Verifies signature
-+ *
-+ * @param [in] sig pointer to output signature
-+ * @param [in] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init and filled with
-+ * lc_dilithium_sign_update
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_44_verify_final(const struct lc_dilithium_44_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_44_pk *pk);
-+
-+/****************************** Dilithium ED25510 *****************************/
-+/* Macro set during leancrypto compile time for target platform */
-+#undef LC_DILITHIUM_ED25519_SIG
-+#ifdef LC_DILITHIUM_ED25519_SIG
-+
-+#include "lc_ed25519.h"
-+
-+/**
-+ * @brief Dilithium secret key
-+ */
-+struct lc_dilithium_44_ed25519_sk {
-+ struct lc_dilithium_44_sk sk;
-+ struct lc_ed25519_sk sk_ed25519;
-+};
-+
-+/**
-+ * @brief Dilithium public key
-+ */
-+struct lc_dilithium_44_ed25519_pk {
-+ struct lc_dilithium_44_pk pk;
-+ struct lc_ed25519_pk pk_ed25519;
-+};
-+
-+/**
-+ * @brief Dilithium signature
-+ */
-+struct lc_dilithium_44_ed25519_sig {
-+ struct lc_dilithium_44_sig sig;
-+ struct lc_ed25519_sig sig_ed25519;
-+};
-+
-+/**
-+ * @brief Dilithium stream context
-+ *
-+ * This structure is used for the init/update/final operation of the
-+ * Dilithium-ED25519 hybrid.
-+ */
-+#ifndef LC_DILITHIUM_ED25519_CTX_ON_STACK
-+struct lc_dilithium_ed25519_ctx {
-+ struct lc_dilithium_ctx dilithium_ctx;
-+};
-+#endif
-+
-+/// \cond DO_NOT_DOCUMENT
-+#ifndef LC_DILITHIUM_ED25519_CTX_ON_STACK
-+#define LC_DILITHIUM_ED25519_CTX_SIZE sizeof(struct lc_dilithium_ed25519_ctx)
-+#endif
-+/// \endcond
-+
-+/**
-+ * @brief Allocate stack memory for the Dilithium-ED25519 stream context
-+ *
-+ * @param [in] name Name of the stack variable
-+ */
-+#ifndef LC_DILITHIUM_ED25519_CTX_ON_STACK
-+#define LC_DILITHIUM_ED25519_CTX_ON_STACK(name) \
-+ _Pragma("GCC diagnostic push") _Pragma( \
-+ "GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \
-+ LC_ALIGNED_BUFFER(name##_ctx_buf, \
-+ LC_DILITHIUM_ED25519_CTX_SIZE, \
-+ LC_HASH_COMMON_ALIGNMENT); \
-+ struct lc_dilithium_ed25519_ctx *name = \
-+ (struct lc_dilithium_ed25519_ctx *)name##_ctx_buf; \
-+ LC_DILITHIUM_SET_CTX(&(name)->dilithium_ctx); \
-+ _Pragma("GCC diagnostic pop")
-+#endif
-+
-+/**
-+ * @brief Zeroize Dilithium-ED25519 context allocated with
-+ * LC_DILITHIUM_ED25519_CTX_ON_STACK lc_dilithium_ed25519_alloc
-+ *
-+ * @param [in] ctx Dilithium-ED25519 context to be zeroized
-+ */
-+static inline void
-+lc_dilithium_44_ed25519_ctx_zero(struct lc_dilithium_ed25519_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+ lc_dilithium_44_ctx_zero(&ctx->dilithium_ctx);
-+}
-+
-+/**
-+ * @brief Allocate Dilithium-ED25519 stream context on heap
-+ *
-+ * @param [out] ctx Allocated Dilithium-ED25519 stream context
-+ *
-+ * @return: 0 on success, < 0 on error
-+ */
-+int lc_dilithium_44_ed25519_ctx_alloc(struct lc_dilithium_ed25519_ctx **ctx);
-+
-+/**
-+ * @brief Zeroize and free Dilithium-ED25519 stream context
-+ *
-+ * @param [in] ctx Dilithium-ED25519 stream context to be zeroized and freed
-+ */
-+void lc_dilithium_44_ed25519_ctx_zero_free(struct lc_dilithium_ed25519_ctx *ctx);
-+
-+/**
-+ * @brief Generates Dilithium public and private key.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] rng_ctx pointer to seeded random number generator context
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_44_ed25519_keypair(struct lc_dilithium_44_ed25519_pk *pk,
-+ struct lc_dilithium_44_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Computes signature in one shot
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_44_ed25519_sign(struct lc_dilithium_44_ed25519_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_44_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Computes signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_44_ed25519_sign_ctx(struct lc_dilithium_44_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_44_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+int lc_dilithium_44_ed25519_sign_init(
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_44_ed25519_sk *sk);
-+
-+int lc_dilithium_44_ed25519_sign_update(struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+
-+int lc_dilithium_44_ed25519_sign_final(
-+ struct lc_dilithium_44_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_44_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Verifies signature in one shot
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_44_ed25519_verify(const struct lc_dilithium_44_ed25519_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_44_ed25519_pk *pk);
-+
-+/**
-+ * @brief Verifies signature in one shot with Dilithium context
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_44_ed25519_verify_ctx(
-+ const struct lc_dilithium_44_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx, const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_44_ed25519_pk *pk);
-+
-+int lc_dilithium_44_ed25519_verify_init(
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_44_ed25519_pk *pk);
-+int lc_dilithium_44_ed25519_verify_update(struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+int lc_dilithium_44_ed25519_verify_final(
-+ const struct lc_dilithium_44_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_44_ed25519_pk *pk);
-+
-+#endif /* LC_DILITHIUM_ED25519_SIG */
-+
-+/****************************** Dilithium ED25510 *****************************/
-+/* Macro set during leancrypto compile time for target platform */
-+#undef LC_DILITHIUM_ED448_SIG
-+#ifdef LC_DILITHIUM_ED448_SIG
-+
-+#include "lc_ed448.h"
-+
-+/**
-+ * @brief Dilithium secret key
-+ */
-+struct lc_dilithium_44_ed448_sk {
-+ struct lc_dilithium_44_sk sk;
-+ struct lc_ed448_sk sk_ed448;
-+};
-+
-+/**
-+ * @brief Dilithium public key
-+ */
-+struct lc_dilithium_44_ed448_pk {
-+ struct lc_dilithium_44_pk pk;
-+ struct lc_ed448_pk pk_ed448;
-+};
-+
-+/**
-+ * @brief Dilithium signature
-+ */
-+struct lc_dilithium_44_ed448_sig {
-+ struct lc_dilithium_44_sig sig;
-+ struct lc_ed448_sig sig_ed448;
-+};
-+
-+/**
-+ * @brief Dilithium stream context
-+ *
-+ * This structure is used for the init/update/final operation of the
-+ * Dilithium-ED448 hybrid.
-+ */
-+#ifndef LC_DILITHIUM_ED448_CTX_ON_STACK
-+struct lc_dilithium_ed448_ctx {
-+ struct lc_dilithium_ctx dilithium_ctx;
-+};
-+#endif
-+
-+/// \cond DO_NOT_DOCUMENT
-+#ifndef LC_DILITHIUM_ED448_CTX_ON_STACK
-+#define LC_DILITHIUM_ED448_CTX_SIZE sizeof(struct lc_dilithium_ed448_ctx)
-+#endif
-+/// \endcond
-+
-+/**
-+ * @brief Allocate stack memory for the Dilithium-ED448 stream context
-+ *
-+ * @param [in] name Name of the stack variable
-+ */
-+#ifndef LC_DILITHIUM_ED448_CTX_ON_STACK
-+#define LC_DILITHIUM_ED448_CTX_ON_STACK(name) \
-+ _Pragma("GCC diagnostic push") _Pragma( \
-+ "GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \
-+ LC_ALIGNED_BUFFER(name##_ctx_buf, LC_DILITHIUM_ED448_CTX_SIZE, \
-+ LC_HASH_COMMON_ALIGNMENT); \
-+ struct lc_dilithium_ed448_ctx *name = \
-+ (struct lc_dilithium_ed448_ctx *)name##_ctx_buf; \
-+ LC_DILITHIUM_SET_CTX(&(name)->dilithium_ctx); \
-+ _Pragma("GCC diagnostic pop")
-+#endif
-+
-+/**
-+ * @brief Zeroize Dilithium-ED448 context allocated with
-+ * LC_DILITHIUM_ED448_CTX_ON_STACK lc_dilithium_ed448_alloc
-+ *
-+ * @param [in] ctx Dilithium-ED448 context to be zeroized
-+ */
-+static inline void
-+lc_dilithium_44_ed448_ctx_zero(struct lc_dilithium_ed448_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+ lc_dilithium_44_ctx_zero(&ctx->dilithium_ctx);
-+}
-+
-+/**
-+ * @brief Allocate Dilithium-ED448 stream context on heap
-+ *
-+ * @param [out] ctx Allocated Dilithium-ED448 stream context
-+ *
-+ * @return: 0 on success, < 0 on error
-+ */
-+int lc_dilithium_44_ed448_ctx_alloc(struct lc_dilithium_ed448_ctx **ctx);
-+
-+/**
-+ * @brief Zeroize and free Dilithium-ED448 stream context
-+ *
-+ * @param [in] ctx Dilithium-ED448 stream context to be zeroized and freed
-+ */
-+void lc_dilithium_44_ed448_ctx_zero_free(struct lc_dilithium_ed448_ctx *ctx);
-+
-+/**
-+ * @brief Generates Dilithium public and private key.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] rng_ctx pointer to seeded random number generator context
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_44_ed448_keypair(struct lc_dilithium_44_ed448_pk *pk,
-+ struct lc_dilithium_44_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Computes signature in one shot
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_44_ed448_sign(struct lc_dilithium_44_ed448_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_44_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Computes signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_44_ed448_sign_ctx(struct lc_dilithium_44_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_44_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+int lc_dilithium_44_ed448_sign_init(struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_44_ed448_sk *sk);
-+
-+int lc_dilithium_44_ed448_sign_update(struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+
-+int lc_dilithium_44_ed448_sign_final(struct lc_dilithium_44_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_44_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Verifies signature in one shot
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_44_ed448_verify(const struct lc_dilithium_44_ed448_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_44_ed448_pk *pk);
-+
-+/**
-+ * @brief Verifies signature in one shot with Dilithium context
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_44_ed448_verify_ctx(const struct lc_dilithium_44_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_44_ed448_pk *pk);
-+
-+int lc_dilithium_44_ed448_verify_init(struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_44_ed448_pk *pk);
-+int lc_dilithium_44_ed448_verify_update(struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+int lc_dilithium_44_ed448_verify_final(
-+ const struct lc_dilithium_44_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_44_ed448_pk *pk);
-+
-+#endif /* LC_DILITHIUM_ED448_SIG */
-+
-+#endif /* __ASSEMBLER__ */
-+
-+/*
-+ * To allow including the different lc_dilithium_*.h files, these macros need to
-+ * be undefined. Only during compilation of leancrypto, these macros remain
-+ * defined as this header file is not included multiple times.
-+ */
-+#ifndef LC_DILITHIUM_INTERNAL
-+#undef LC_DILITHIUM_MODE
-+#undef LC_DILITHIUM_NIST_CATEGORY
-+#undef LC_DILITHIUM_SEEDBYTES
-+#undef LC_DILITHIUM_CRHBYTES
-+#undef LC_DILITHIUM_TRBYTES
-+#undef LC_DILITHIUM_RNDBYTES
-+#undef LC_DILITHIUM_N
-+#undef LC_DILITHIUM_Q
-+#undef LC_DILITHIUM_D
-+#undef LC_DILITHIUM_ROOT_OF_UNITY
-+#undef LC_DILITHIUM_LAMBDA
-+#undef LC_DILITHIUM_K
-+#undef LC_DILITHIUM_L
-+#undef LC_DILITHIUM_ETA
-+#undef LC_DILITHIUM_TAU
-+#undef LC_DILITHIUM_BETA
-+#undef LC_DILITHIUM_GAMMA1
-+#undef LC_DILITHIUM_GAMMA2
-+#undef LC_DILITHIUM_OMEGA
-+#undef LC_DILITHIUM_CTILDE_BYTES
-+#undef LC_DILITHIUM_POLYT1_PACKEDBYTES
-+#undef LC_DILITHIUM_POLYT0_PACKEDBYTES
-+#undef LC_DILITHIUM_POLYVECH_PACKEDBYTES
-+#undef LC_DILITHIUM_POLYZ_PACKEDBYTES
-+#undef LC_DILITHIUM_POLYW1_PACKEDBYTES
-+#undef LC_DILITHIUM_POLYETA_PACKEDBYTES
-+#undef LC_DILITHIUM_PUBLICKEYBYTES
-+#undef LC_DILITHIUM_SECRETKEYBYTES
-+#undef LC_DILITHIUM_CRYPTO_BYTES
-+#endif /* LC_DILITHIUM_INTERNAL */
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* LC_DILITHIUM_44_H */
-diff --git a/lib/freebl/leancrypto/lc_dilithium_65.h b/lib/freebl/leancrypto/lc_dilithium_65.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/lc_dilithium_65.h
-@@ -0,0 +1,1135 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#ifndef LC_DILITHIUM_65_H
-+#define LC_DILITHIUM_65_H
-+
-+#ifndef __ASSEMBLER__
-+
-+#include "ext_headers.h"
-+#include "lc_hash.h"
-+#include "lc_rng.h"
-+#include "lc_sha3.h"
-+#include "lc_sha512.h"
-+
-+#endif /* __ASSEMBLER__ */
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/// \cond DO_NOT_DOCUMENT
-+/*
-+ * Dilithium Security Levels
-+ * 2 -> 192 bits of security strength
-+ * 3 -> 225 bits of security strength
-+ * 5 -> 257 bits of security strength
-+ */
-+#define LC_DILITHIUM_MODE 3
-+
-+#define LC_DILITHIUM_SEEDBYTES 32
-+#define LC_DILITHIUM_CRHBYTES 64
-+#define LC_DILITHIUM_TRBYTES 64
-+#define LC_DILITHIUM_RNDBYTES 32
-+#define LC_DILITHIUM_N 256
-+#define LC_DILITHIUM_Q 8380417
-+#define LC_DILITHIUM_D 13
-+#define LC_DILITHIUM_ROOT_OF_UNITY 1753
-+
-+#if LC_DILITHIUM_MODE == 2
-+#define LC_DILITHIUM_NIST_CATEGORY 1
-+#define LC_DILITHIUM_LAMBDA 128
-+#define LC_DILITHIUM_K 4
-+#define LC_DILITHIUM_L 4
-+#define LC_DILITHIUM_ETA 2
-+#define LC_DILITHIUM_TAU 39
-+#define LC_DILITHIUM_BETA 78
-+#define LC_DILITHIUM_GAMMA1 (1 << 17)
-+#define LC_DILITHIUM_GAMMA2 ((LC_DILITHIUM_Q - 1) / 88)
-+#define LC_DILITHIUM_OMEGA 80
-+
-+#elif LC_DILITHIUM_MODE == 3
-+#define LC_DILITHIUM_NIST_CATEGORY 3
-+#define LC_DILITHIUM_LAMBDA 192
-+#define LC_DILITHIUM_K 6
-+#define LC_DILITHIUM_L 5
-+#define LC_DILITHIUM_ETA 4
-+#define LC_DILITHIUM_TAU 49
-+#define LC_DILITHIUM_BETA 196
-+#define LC_DILITHIUM_GAMMA1 (1 << 19)
-+#define LC_DILITHIUM_GAMMA2 ((LC_DILITHIUM_Q - 1) / 32)
-+#define LC_DILITHIUM_OMEGA 55
-+
-+#elif LC_DILITHIUM_MODE == 5
-+#define LC_DILITHIUM_NIST_CATEGORY 5
-+#define LC_DILITHIUM_LAMBDA 256
-+#define LC_DILITHIUM_K 8
-+#define LC_DILITHIUM_L 7
-+#define LC_DILITHIUM_ETA 2
-+#define LC_DILITHIUM_TAU 60
-+#define LC_DILITHIUM_BETA 120
-+#define LC_DILITHIUM_GAMMA1 (1 << 19)
-+#define LC_DILITHIUM_GAMMA2 ((LC_DILITHIUM_Q - 1) / 32)
-+#define LC_DILITHIUM_OMEGA 75
-+
-+#endif
-+
-+#define LC_DILITHIUM_CTILDE_BYTES (LC_DILITHIUM_LAMBDA * 2 / 8)
-+#define LC_DILITHIUM_POLYT1_PACKEDBYTES 320
-+#define LC_DILITHIUM_POLYT0_PACKEDBYTES 416
-+#define LC_DILITHIUM_POLYVECH_PACKEDBYTES (LC_DILITHIUM_OMEGA + LC_DILITHIUM_K)
-+
-+#if LC_DILITHIUM_GAMMA1 == (1 << 17)
-+#define LC_DILITHIUM_POLYZ_PACKEDBYTES 576
-+#elif LC_DILITHIUM_GAMMA1 == (1 << 19)
-+#define LC_DILITHIUM_POLYZ_PACKEDBYTES 640
-+#endif
-+
-+#if LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 88
-+#define LC_DILITHIUM_POLYW1_PACKEDBYTES 192
-+#elif LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 32
-+#define LC_DILITHIUM_POLYW1_PACKEDBYTES 128
-+#endif
-+
-+#if LC_DILITHIUM_ETA == 2
-+#define LC_DILITHIUM_POLYETA_PACKEDBYTES 96
-+#elif LC_DILITHIUM_ETA == 4
-+#define LC_DILITHIUM_POLYETA_PACKEDBYTES 128
-+#endif
-+
-+/*
-+ * Sizes of the different Dilithium buffer types.
-+ *
-+ * WARNING: Do not use these defines in your code. If you need the sizes of
-+ * the different variable sizes, use sizeof of the different variable structs or
-+ * use the different *_size functions documented below to retrieve the data size
-+ * of a particular Dilithium component.
-+ */
-+#define LC_DILITHIUM_PUBLICKEYBYTES \
-+ (LC_DILITHIUM_SEEDBYTES + \
-+ LC_DILITHIUM_K * LC_DILITHIUM_POLYT1_PACKEDBYTES)
-+#define LC_DILITHIUM_SECRETKEYBYTES \
-+ (2 * LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_TRBYTES + \
-+ LC_DILITHIUM_L * LC_DILITHIUM_POLYETA_PACKEDBYTES + \
-+ LC_DILITHIUM_K * LC_DILITHIUM_POLYETA_PACKEDBYTES + \
-+ LC_DILITHIUM_K * LC_DILITHIUM_POLYT0_PACKEDBYTES)
-+
-+#define LC_DILITHIUM_CRYPTO_BYTES \
-+ (LC_DILITHIUM_CTILDE_BYTES + \
-+ LC_DILITHIUM_L * LC_DILITHIUM_POLYZ_PACKEDBYTES + \
-+ LC_DILITHIUM_POLYVECH_PACKEDBYTES)
-+/// \endcond
-+
-+#ifndef __ASSEMBLER__
-+/**
-+ * @brief Dilithium secret key
-+ */
-+struct lc_dilithium_65_sk {
-+ uint8_t sk[LC_DILITHIUM_SECRETKEYBYTES];
-+};
-+
-+/**
-+ * @brief Dilithium public key
-+ */
-+struct lc_dilithium_65_pk {
-+ uint8_t pk[LC_DILITHIUM_PUBLICKEYBYTES];
-+};
-+
-+/**
-+ * @brief Dilithium signature
-+ */
-+struct lc_dilithium_65_sig {
-+ uint8_t sig[LC_DILITHIUM_CRYPTO_BYTES];
-+};
-+
-+#ifndef LC_DILITHIUM_CTX_ON_STACK
-+struct lc_dilithium_ctx {
-+ /**
-+ * @brief Hash context used internally to the library - it should not
-+ * be touched by the user
-+ */
-+ struct lc_hash_ctx dilithium_hash_ctx;
-+
-+ /**
-+ * @brief State memory of the hash context used internally to the
-+ * library - it should not be touched by the user
-+ */
-+ uint8_t shake_state[LC_SHA3_STATE_SIZE_ALIGN(LC_SHA3_256_CTX_SIZE)];
-+
-+ /**
-+ * @brief When using HashML-DSA, set the hash reference used for the
-+ * hash operation. Allowed values are lc_sha256, lc_sha512, lc_sha3_256,
-+ * lc_sha3_384, lc_sha3_512, lc_shake128 and lc_shake256. Note, the
-+ * actual message digest operation can be performed external to
-+ * leancrypto. This parameter only shall indicate the used hash
-+ * operation.
-+ *
-+ * \note Use \p lc_dilithium_ctx_hash or
-+ * \p lc_dilithium_ed25519_ctx_hash to set this value.
-+ */
-+ const struct lc_hash *dilithium_prehash_type;
-+
-+ /**
-+ * @brief length of the user context (allowed range between 0 and 255
-+ * bytes)
-+ *
-+ * \note Use \p lc_dilithium_ctx_userctx or
-+ * \p lc_dilithium_ed25519_ctx_userctx to set this value.
-+ */
-+ size_t userctxlen;
-+
-+ /**
-+ * @brief buffer with a caller-specified context string
-+ *
-+ * \note Use \p lc_dilithium_ctx_userctx or
-+ * \p lc_dilithium_ed25519_ctx_userctx to set this value.
-+ */
-+ const uint8_t *userctx;
-+
-+ /**
-+ * @brief Pointer to the AHat buffer. This can be provided by the caller
-+ * or it must be NULL otherwise.
-+ *
-+ * \note Use \p LC_DILITHIUM_CTX_ON_STACK_AHAT to provide memory for
-+ * storing AHat in the caller context and thus make the signature
-+ * operation much faster starting with the 2nd use of the key (pair).
-+ */
-+ void *ahat;
-+ unsigned short ahat_size;
-+
-+ /**
-+ * @brief Pointer to the external mu.
-+ *
-+ * If set, the signature operation will use the provided mu instead of
-+ * the message. In this case, the message pointer to the signature
-+ * generation or verification can be NULL.
-+ */
-+ const uint8_t *external_mu;
-+ size_t external_mu_len;
-+
-+ /**
-+ * @brief Pointer to the randomizer
-+ *
-+ * This is used for the Composite signature: For the discussion of the
-+ * randomizer, see https://lamps-wg.github.io/draft-composite-sigs/draft-ietf-lamps-pq-composite-sigs.html
-+ */
-+ const uint8_t *randomizer;
-+ size_t randomizerlen;
-+
-+ /**
-+ * @brief NIST category required for composite signatures
-+ *
-+ * The domain separation logic depends on the selection of the right
-+ * OID for the "Domain" data.
-+ */
-+ unsigned int nist_category;
-+
-+ /**
-+ * @brief When set to true, only the ML-DSA.Sign_internal or
-+ * ML-DSA.Verify_internal are performed (see FIPS 204 chapter 6).
-+ * Otherwise the ML-DSA.Sign / ML-DSA.Verify (see FIPS chapter 5) is
-+ * applied.
-+ *
-+ * \note Use \p lc_dilithium_ctx_internal or
-+ * \p lc_dilithium_ed25519_ctx_internal to set this value.
-+ *
-+ * \warning Only set this value to true if you exactly know what you are
-+ * doing!.
-+ */
-+ unsigned int ml_dsa_internal : 1;
-+
-+ /**
-+ * @brief Was aHat already filled? This is used and set internally.
-+ */
-+ unsigned int ahat_expanded : 1;
-+};
-+#endif
-+
-+/// \cond DO_NOT_DOCUMENT
-+
-+/*
-+ * The alignment is based on largest alignment of a polyvecl typedef - this is
-+ * the AVX2 definition.
-+ */
-+#define LC_DILITHIUM_AHAT_ALIGNMENT (32)
-+
-+/*
-+ * Padding between struct lc_dilithium_ctx and AHat buffer to ensure AHat buffer
-+ * is aligned to LC_DILITHIUM_AHAT_ALIGNMENT
-+ */
-+#define LC_DILITHIUM_65_AHAT_PAD \
-+ (LC_DILITHIUM_AHAT_ALIGNMENT - \
-+ (sizeof(struct lc_dilithium_ctx) % LC_DILITHIUM_AHAT_ALIGNMENT))
-+
-+/* Size of the AHat matrix for ML-DSA 87 */
-+#define LC_DILITHIUM_65_AHAT_SIZE \
-+ (256 * sizeof(int32_t) * LC_DILITHIUM_K * LC_DILITHIUM_L)
-+
-+#ifndef LC_DILITHIUM_CTX_ON_STACK
-+#define LC_DILITHIUM_CTX_SIZE sizeof(struct lc_dilithium_ctx)
-+
-+#define LC_DILITHIUM_CTX_INIT_HASH(name) \
-+ LC_SHAKE_256_CTX((&(name)->dilithium_hash_ctx))
-+
-+#define LC_DILITHIUM_SET_CTX(name) \
-+ LC_DILITHIUM_CTX_INIT_HASH(name); \
-+ (name)->dilithium_prehash_type = NULL; \
-+ (name)->ml_dsa_internal = 0; \
-+ (name)->userctxlen = 0; \
-+ (name)->userctx = NULL; \
-+ (name)->ahat = NULL; \
-+ (name)->ahat_size = 0; \
-+ (name)->external_mu = NULL; \
-+ (name)->external_mu_len = 0; \
-+ (name)->randomizer = NULL; \
-+ (name)->randomizerlen = 0; \
-+ (name)->nist_category = 0;
-+#endif
-+/// \endcond
-+
-+/**
-+ * @brief Allocate stack memory for the Dilithium stream context or additional
-+ * parameter relevant for the signature operation.
-+ *
-+ * @param [in] name Name of the stack variable
-+ */
-+#ifndef LC_DILITHIUM_CTX_ON_STACK
-+#define LC_DILITHIUM_CTX_ON_STACK(name) \
-+ _Pragma("GCC diagnostic push") _Pragma( \
-+ "GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \
-+ LC_ALIGNED_BUFFER(name##_ctx_buf, LC_DILITHIUM_CTX_SIZE, \
-+ LC_HASH_COMMON_ALIGNMENT); \
-+ struct lc_dilithium_ctx *name = \
-+ (struct lc_dilithium_ctx *)name##_ctx_buf; \
-+ LC_DILITHIUM_SET_CTX(name); \
-+ _Pragma("GCC diagnostic pop")
-+#endif
-+
-+/**
-+ * @brief Allocate stack memory for the Dilithium stream context and additional
-+ * parameter relevant for the signature operation.
-+ *
-+ * In addition, the memory buffer returned by this allocation contains the space
-+ * for an expanded representation of the public key which is required in both,
-+ * signature generation and verification. When using this memory, the first
-+ * signature operation expands the key and any subsequent operation using this
-+ * context will re-use the expanded key which improves performance of the
-+ * signature operation significantly.
-+ *
-+ * As the same expanded structure is used for signature generation and
-+ * verification and the structure can be expanded by either operation, it
-+ * is perfectly legal to use one context for both operations as the expanded
-+ * key can (a) be generated from either the public or the secret key and (b)
-+ * it applies to both operations and (c) is identical irrespective it was
-+ * generated from the public or secret key.
-+ *
-+ * \note: ML-DSA AVX2 signature operation uses a completely different
-+ * algorithm which does not use a pre-pcomputed expanded key. Thus, if you know
-+ * you have AVX2 support, you *may* not need this larger buffer and you *can*
-+ * use \p LC_DILITHIUM_CTX_ON_STACK instead.
-+ *
-+ * \note: The expanded representation only uses public key data. Even when
-+ * deriving the expanded representation from a secret key, this data is only
-+ * obtained from a part that is considered public. Thus, this memory does not
-+ * require special protections. See FIPS 204 section 3.6.3 on the properties
-+ * and handling requirements of the  matrix. Further, see the FIPS 204
-+ * ML-DSA.Sign_internal and ML-DSA.Verify_internal algorithm specification on
-+ * how this  matrix is generated and that the input to the generation is public
-+ * data.
-+ *
-+ * \warning: One instance of the expanded key representation can only ever apply
-+ * to one given key (pair). If you want to reuse the context with multiple keys,
-+ * you MUST invalidate the potentially present expanded key representation. Such
-+ * invalidation is invoked with the method \p lc_dilithium_ctx_drop_ahat. Only
-+ * after this invalidation you can use the context with a different key.
-+ *
-+ * @param [in] name Name of the stack variable
-+ */
-+#define LC_DILITHIUM_65_CTX_ON_STACK_AHAT(name) \
-+ _Pragma("GCC diagnostic push") _Pragma( \
-+ "GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \
-+ LC_ALIGNED_BUFFER(name##_ctx_buf, \
-+ LC_DILITHIUM_CTX_SIZE + \
-+ LC_DILITHIUM_65_AHAT_PAD + \
-+ LC_DILITHIUM_65_AHAT_SIZE, \
-+ LC_HASH_COMMON_ALIGNMENT); \
-+ struct lc_dilithium_ctx *name = \
-+ (struct lc_dilithium_ctx *)name##_ctx_buf; \
-+ LC_DILITHIUM_SET_CTX(name); \
-+ name->ahat = (uint8_t *)name + LC_DILITHIUM_CTX_SIZE + \
-+ LC_DILITHIUM_65_AHAT_PAD; \
-+ name->ahat_expanded = 0; \
-+ name->ahat_size = LC_DILITHIUM_65_AHAT_SIZE; \
-+ _Pragma("GCC diagnostic pop")
-+
-+/**
-+ * @brief Zeroize Dilithium context allocated with
-+ * LC_DILITHIUM_CTX_ON_STACK lc_dilithium_ed25519_alloc
-+ *
-+ * @param [in] ctx Dilithium context to be zeroized
-+ */
-+static inline void lc_dilithium_65_ctx_zero(struct lc_dilithium_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+ lc_hash_zero(&ctx->dilithium_hash_ctx);
-+ if (ctx->ahat) {
-+ lc_memset_secure(ctx->ahat, 0, ctx->ahat_size);
-+ ctx->ahat_expanded = 0;
-+ }
-+}
-+
-+/**
-+ * @brief Allocate Dilithium stream context on heap
-+ *
-+ * @param [out] ctx Allocated Dilithium stream context
-+ *
-+ * @return: 0 on success, < 0 on error
-+ */
-+int lc_dilithium_65_ctx_alloc(struct lc_dilithium_ctx **ctx);
-+
-+/**
-+ * @brief Allocate Dilithium stream context on heap including additional
-+ * parameter relevant for the signature operation.
-+ *
-+ * \note See \p LC_DILITHIUM_65_CTX_ON_STACK_AHAT for details.
-+ *
-+ * @param [out] ctx Allocated Dilithium stream context
-+ *
-+ * @return: 0 on success, < 0 on error
-+ */
-+int lc_dilithium_65_ctx_alloc_ahat(struct lc_dilithium_ctx **ctx);
-+
-+/**
-+ * @brief Zeroize and free Dilithium stream context
-+ *
-+ * @param [in] ctx Dilithium stream context to be zeroized and freed
-+ */
-+void lc_dilithium_65_ctx_zero_free(struct lc_dilithium_ctx *ctx);
-+
-+/**
-+ * @brief Return the size of the Dilithium secret key.
-+ */
-+LC_PURE
-+static inline unsigned int lc_dilithium_65_sk_size(void)
-+{
-+ return lc_member_size(struct lc_dilithium_65_sk, sk);
-+}
-+
-+/**
-+ * @brief Return the size of the Dilithium public key.
-+ */
-+LC_PURE
-+static inline unsigned int lc_dilithium_65_pk_size(void)
-+{
-+ return lc_member_size(struct lc_dilithium_65_pk, pk);
-+}
-+
-+/**
-+ * @brief Return the size of the Dilithium signature.
-+ */
-+LC_PURE
-+static inline unsigned int lc_dilithium_65_sig_size(void)
-+{
-+ return lc_member_size(struct lc_dilithium_65_sig, sig);
-+}
-+
-+/**
-+ * @brief Generates Dilithium public and private key.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] rng_ctx pointer to seeded random number generator context
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_65_keypair(struct lc_dilithium_65_pk *pk,
-+ struct lc_dilithium_65_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Generates Dilithium public and private key from a given seed.
-+ *
-+ * The idea of the function is the allowance of FIPS 204 to maintain the seed
-+ * used to generate a key pair in lieu of maintaining a private key or the
-+ * key pair (which used much more memory). The seed must be treated equally
-+ * sensitive as a private key.
-+ *
-+ * The seed is generated by simply obtaining 32 bytes from a properly seeded
-+ * DRNG, i.e. the same way as a symmetric key would be generated.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] seed buffer with the seed data which must be exactly 32 bytes
-+ * in size
-+ * @param [in] seedlen length of the seed buffer
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_65_keypair_from_seed(struct lc_dilithium_65_pk *pk,
-+ struct lc_dilithium_65_sk *sk,
-+ const uint8_t *seed, size_t seedlen);
-+
-+/**
-+ * @brief Computes ML-DSA signature in one shot
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_65_sign(struct lc_dilithium_65_sig *sig, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_65_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Computes signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_65_sign_ctx(struct lc_dilithium_65_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_65_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Initializes a signature operation
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_sign_update and lc_dilithium_sign_final.
-+ *
-+ * @param [in,out] ctx pointer to an allocated Dilithium context
-+ * @param [in] sk pointer to bit-packed secret key
-+ *
-+ * @return 0 (success) or < 0 on error; -EOPNOTSUPP is returned if a different
-+ * hash than lc_shake256 is used.
-+ */
-+int lc_dilithium_65_sign_init(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_65_sk *sk);
-+
-+/**
-+ * @brief Add more data to an already initialized signature state
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_sign_init and lc_dilithium_sign_final.
-+ *
-+ * @param [in] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_65_sign_update(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+
-+/**
-+ * @brief Computes signature
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init and filled with
-+ * lc_dilithium_sign_update
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_65_sign_final(struct lc_dilithium_65_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_65_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Verifies ML-DSA signature in one shot
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_65_verify(const struct lc_dilithium_65_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_65_pk *pk);
-+
-+/**
-+ * @brief Verifies signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_65_verify_ctx(const struct lc_dilithium_65_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen,
-+ const struct lc_dilithium_65_pk *pk);
-+
-+/**
-+ * @brief Initializes a signature verification operation
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_verify_update and
-+ * lc_dilithium_verify_final.
-+ *
-+ * @param [in,out] ctx pointer to an allocated Dilithium context
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 (success) or < 0 on error; -EOPNOTSUPP is returned if a different
-+ * hash than lc_shake256 is used.
-+ */
-+int lc_dilithium_65_verify_init(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_65_pk *pk);
-+
-+/**
-+ * @brief Add more data to an already initialized signature state
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_verify_init and
-+ * lc_dilithium_verify_final.
-+ *
-+ * @param [in,out] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_65_verify_update(struct lc_dilithium_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+
-+/**
-+ * @brief Verifies signature
-+ *
-+ * @param [in] sig pointer to output signature
-+ * @param [in] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init and filled with
-+ * lc_dilithium_sign_update
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_65_verify_final(const struct lc_dilithium_65_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_65_pk *pk);
-+
-+/****************************** Dilithium ED25510 *****************************/
-+/* Macro set during leancrypto compile time for target platform */
-+#undef LC_DILITHIUM_ED25519_SIG
-+#ifdef LC_DILITHIUM_ED25519_SIG
-+
-+#include "lc_ed25519.h"
-+
-+/**
-+ * @brief Dilithium secret key
-+ */
-+struct lc_dilithium_65_ed25519_sk {
-+ struct lc_dilithium_65_sk sk;
-+ struct lc_ed25519_sk sk_ed25519;
-+};
-+
-+/**
-+ * @brief Dilithium public key
-+ */
-+struct lc_dilithium_65_ed25519_pk {
-+ struct lc_dilithium_65_pk pk;
-+ struct lc_ed25519_pk pk_ed25519;
-+};
-+
-+/**
-+ * @brief Dilithium signature
-+ */
-+struct lc_dilithium_65_ed25519_sig {
-+ struct lc_dilithium_65_sig sig;
-+ struct lc_ed25519_sig sig_ed25519;
-+};
-+
-+/**
-+ * @brief Dilithium stream context
-+ *
-+ * This structure is used for the init/update/final operation of the
-+ * Dilithium-ED25519 hybrid.
-+ */
-+#ifndef LC_DILITHIUM_ED25519_CTX_ON_STACK
-+struct lc_dilithium_ed25519_ctx {
-+ struct lc_dilithium_ctx dilithium_ctx;
-+};
-+#endif
-+
-+/// \cond DO_NOT_DOCUMENT
-+#ifndef LC_DILITHIUM_ED25519_CTX_ON_STACK
-+#define LC_DILITHIUM_ED25519_CTX_SIZE sizeof(struct lc_dilithium_ed25519_ctx)
-+#endif
-+/// \endcond
-+
-+/**
-+ * @brief Allocate stack memory for the Dilithium-ED25519 stream context
-+ *
-+ * @param [in] name Name of the stack variable
-+ */
-+#ifndef LC_DILITHIUM_ED25519_CTX_ON_STACK
-+#define LC_DILITHIUM_ED25519_CTX_ON_STACK(name) \
-+ _Pragma("GCC diagnostic push") _Pragma( \
-+ "GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \
-+ LC_ALIGNED_BUFFER(name##_ctx_buf, \
-+ LC_DILITHIUM_ED25519_CTX_SIZE, \
-+ LC_HASH_COMMON_ALIGNMENT); \
-+ struct lc_dilithium_ed25519_ctx *name = \
-+ (struct lc_dilithium_ed25519_ctx *)name##_ctx_buf; \
-+ LC_DILITHIUM_SET_CTX(&(name)->dilithium_ctx); \
-+ _Pragma("GCC diagnostic pop")
-+#endif
-+
-+/**
-+ * @brief Zeroize Dilithium-ED25519 context allocated with
-+ * LC_DILITHIUM_ED25519_CTX_ON_STACK lc_dilithium_ed25519_alloc
-+ *
-+ * @param [in] ctx Dilithium-ED25519 context to be zeroized
-+ */
-+static inline void
-+lc_dilithium_65_ed25519_ctx_zero(struct lc_dilithium_ed25519_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+ lc_dilithium_65_ctx_zero(&ctx->dilithium_ctx);
-+}
-+
-+/**
-+ * @brief Allocate Dilithium-ED25519 stream context on heap
-+ *
-+ * @param [out] ctx Allocated Dilithium-ED25519 stream context
-+ *
-+ * @return: 0 on success, < 0 on error
-+ */
-+int lc_dilithium_65_ed25519_ctx_alloc(struct lc_dilithium_ed25519_ctx **ctx);
-+
-+/**
-+ * @brief Zeroize and free Dilithium-ED25519 stream context
-+ *
-+ * @param [in] ctx Dilithium-ED25519 stream context to be zeroized and freed
-+ */
-+void lc_dilithium_65_ed25519_ctx_zero_free(struct lc_dilithium_ed25519_ctx *ctx);
-+
-+/**
-+ * @brief Generates Dilithium public and private key.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] rng_ctx pointer to seeded random number generator context
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_65_ed25519_keypair(struct lc_dilithium_65_ed25519_pk *pk,
-+ struct lc_dilithium_65_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Computes signature in one shot
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_65_ed25519_sign(struct lc_dilithium_65_ed25519_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_65_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Computes signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_65_ed25519_sign_ctx(struct lc_dilithium_65_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_65_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+int lc_dilithium_65_ed25519_sign_init(
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_65_ed25519_sk *sk);
-+
-+int lc_dilithium_65_ed25519_sign_update(struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+
-+int lc_dilithium_65_ed25519_sign_final(
-+ struct lc_dilithium_65_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_65_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Verifies signature in one shot
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_65_ed25519_verify(const struct lc_dilithium_65_ed25519_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_65_ed25519_pk *pk);
-+
-+/**
-+ * @brief Verifies signature in one shot with Dilithium context
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_65_ed25519_verify_ctx(
-+ const struct lc_dilithium_65_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx, const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_65_ed25519_pk *pk);
-+
-+int lc_dilithium_65_ed25519_verify_init(
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_65_ed25519_pk *pk);
-+int lc_dilithium_65_ed25519_verify_update(struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+int lc_dilithium_65_ed25519_verify_final(
-+ const struct lc_dilithium_65_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_65_ed25519_pk *pk);
-+
-+#endif /* LC_DILITHIUM_ED25519_SIG */
-+
-+/****************************** Dilithium ED25510 *****************************/
-+/* Macro set during leancrypto compile time for target platform */
-+#undef LC_DILITHIUM_ED448_SIG
-+#ifdef LC_DILITHIUM_ED448_SIG
-+
-+#include "lc_ed448.h"
-+
-+/**
-+ * @brief Dilithium secret key
-+ */
-+struct lc_dilithium_65_ed448_sk {
-+ struct lc_dilithium_65_sk sk;
-+ struct lc_ed448_sk sk_ed448;
-+};
-+
-+/**
-+ * @brief Dilithium public key
-+ */
-+struct lc_dilithium_65_ed448_pk {
-+ struct lc_dilithium_65_pk pk;
-+ struct lc_ed448_pk pk_ed448;
-+};
-+
-+/**
-+ * @brief Dilithium signature
-+ */
-+struct lc_dilithium_65_ed448_sig {
-+ struct lc_dilithium_65_sig sig;
-+ struct lc_ed448_sig sig_ed448;
-+};
-+
-+/**
-+ * @brief Dilithium stream context
-+ *
-+ * This structure is used for the init/update/final operation of the
-+ * Dilithium-ED448 hybrid.
-+ */
-+#ifndef LC_DILITHIUM_ED448_CTX_ON_STACK
-+struct lc_dilithium_ed448_ctx {
-+ struct lc_dilithium_ctx dilithium_ctx;
-+};
-+#endif
-+
-+/// \cond DO_NOT_DOCUMENT
-+#ifndef LC_DILITHIUM_ED448_CTX_ON_STACK
-+#define LC_DILITHIUM_ED448_CTX_SIZE sizeof(struct lc_dilithium_ed448_ctx)
-+#endif
-+/// \endcond
-+
-+/**
-+ * @brief Allocate stack memory for the Dilithium-ED448 stream context
-+ *
-+ * @param [in] name Name of the stack variable
-+ */
-+#ifndef LC_DILITHIUM_ED448_CTX_ON_STACK
-+#define LC_DILITHIUM_ED448_CTX_ON_STACK(name) \
-+ _Pragma("GCC diagnostic push") _Pragma( \
-+ "GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \
-+ LC_ALIGNED_BUFFER(name##_ctx_buf, LC_DILITHIUM_ED448_CTX_SIZE, \
-+ LC_HASH_COMMON_ALIGNMENT); \
-+ struct lc_dilithium_ed448_ctx *name = \
-+ (struct lc_dilithium_ed448_ctx *)name##_ctx_buf; \
-+ LC_DILITHIUM_SET_CTX(&(name)->dilithium_ctx); \
-+ _Pragma("GCC diagnostic pop")
-+#endif
-+
-+/**
-+ * @brief Zeroize Dilithium-ED448 context allocated with
-+ * LC_DILITHIUM_ED448_CTX_ON_STACK lc_dilithium_ed448_alloc
-+ *
-+ * @param [in] ctx Dilithium-ED448 context to be zeroized
-+ */
-+static inline void
-+lc_dilithium_65_ed448_ctx_zero(struct lc_dilithium_ed448_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+ lc_dilithium_65_ctx_zero(&ctx->dilithium_ctx);
-+}
-+
-+/**
-+ * @brief Allocate Dilithium-ED448 stream context on heap
-+ *
-+ * @param [out] ctx Allocated Dilithium-ED448 stream context
-+ *
-+ * @return: 0 on success, < 0 on error
-+ */
-+int lc_dilithium_65_ed448_ctx_alloc(struct lc_dilithium_ed448_ctx **ctx);
-+
-+/**
-+ * @brief Zeroize and free Dilithium-ED448 stream context
-+ *
-+ * @param [in] ctx Dilithium-ED448 stream context to be zeroized and freed
-+ */
-+void lc_dilithium_65_ed448_ctx_zero_free(struct lc_dilithium_ed448_ctx *ctx);
-+
-+/**
-+ * @brief Generates Dilithium public and private key.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] rng_ctx pointer to seeded random number generator context
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_65_ed448_keypair(struct lc_dilithium_65_ed448_pk *pk,
-+ struct lc_dilithium_65_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Computes signature in one shot
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_65_ed448_sign(struct lc_dilithium_65_ed448_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_65_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Computes signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_65_ed448_sign_ctx(struct lc_dilithium_65_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_65_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+int lc_dilithium_65_ed448_sign_init(struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_65_ed448_sk *sk);
-+
-+int lc_dilithium_65_ed448_sign_update(struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+
-+int lc_dilithium_65_ed448_sign_final(struct lc_dilithium_65_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_65_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Verifies signature in one shot
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_65_ed448_verify(const struct lc_dilithium_65_ed448_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_65_ed448_pk *pk);
-+
-+/**
-+ * @brief Verifies signature in one shot with Dilithium context
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_65_ed448_verify_ctx(const struct lc_dilithium_65_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_65_ed448_pk *pk);
-+
-+int lc_dilithium_65_ed448_verify_init(struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_65_ed448_pk *pk);
-+int lc_dilithium_65_ed448_verify_update(struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+int lc_dilithium_65_ed448_verify_final(
-+ const struct lc_dilithium_65_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_65_ed448_pk *pk);
-+
-+#endif /* LC_DILITHIUM_ED448_SIG */
-+
-+#endif /* __ASSEMBLER__ */
-+
-+/*
-+ * To allow including the different lc_dilithium_*.h files, these macros need to
-+ * be undefined. Only during compilation of leancrypto, these macros remain
-+ * defined as this header file is not included multiple times.
-+ */
-+#ifndef LC_DILITHIUM_INTERNAL
-+#undef LC_DILITHIUM_MODE
-+#undef LC_DILITHIUM_NIST_CATEGORY
-+#undef LC_DILITHIUM_SEEDBYTES
-+#undef LC_DILITHIUM_CRHBYTES
-+#undef LC_DILITHIUM_TRBYTES
-+#undef LC_DILITHIUM_RNDBYTES
-+#undef LC_DILITHIUM_N
-+#undef LC_DILITHIUM_Q
-+#undef LC_DILITHIUM_D
-+#undef LC_DILITHIUM_ROOT_OF_UNITY
-+#undef LC_DILITHIUM_LAMBDA
-+#undef LC_DILITHIUM_K
-+#undef LC_DILITHIUM_L
-+#undef LC_DILITHIUM_ETA
-+#undef LC_DILITHIUM_TAU
-+#undef LC_DILITHIUM_BETA
-+#undef LC_DILITHIUM_GAMMA1
-+#undef LC_DILITHIUM_GAMMA2
-+#undef LC_DILITHIUM_OMEGA
-+#undef LC_DILITHIUM_CTILDE_BYTES
-+#undef LC_DILITHIUM_POLYT1_PACKEDBYTES
-+#undef LC_DILITHIUM_POLYT0_PACKEDBYTES
-+#undef LC_DILITHIUM_POLYVECH_PACKEDBYTES
-+#undef LC_DILITHIUM_POLYZ_PACKEDBYTES
-+#undef LC_DILITHIUM_POLYW1_PACKEDBYTES
-+#undef LC_DILITHIUM_POLYETA_PACKEDBYTES
-+#undef LC_DILITHIUM_PUBLICKEYBYTES
-+#undef LC_DILITHIUM_SECRETKEYBYTES
-+#undef LC_DILITHIUM_CRYPTO_BYTES
-+#endif /* LC_DILITHIUM_INTERNAL */
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* LC_DILITHIUM_65_H */
-diff --git a/lib/freebl/leancrypto/lc_dilithium_87.h b/lib/freebl/leancrypto/lc_dilithium_87.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/lc_dilithium_87.h
-@@ -0,0 +1,1135 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#ifndef LC_DILITHIUM_87_H
-+#define LC_DILITHIUM_87_H
-+
-+#ifndef __ASSEMBLER__
-+
-+#include "ext_headers.h"
-+#include "lc_hash.h"
-+#include "lc_rng.h"
-+#include "lc_sha3.h"
-+#include "lc_sha512.h"
-+
-+#endif /* __ASSEMBLER__ */
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/// \cond DO_NOT_DOCUMENT
-+/*
-+ * Dilithium Security Levels
-+ * 2 -> 192 bits of security strength
-+ * 3 -> 225 bits of security strength
-+ * 5 -> 257 bits of security strength
-+ */
-+#define LC_DILITHIUM_MODE 5
-+
-+#define LC_DILITHIUM_SEEDBYTES 32
-+#define LC_DILITHIUM_CRHBYTES 64
-+#define LC_DILITHIUM_TRBYTES 64
-+#define LC_DILITHIUM_RNDBYTES 32
-+#define LC_DILITHIUM_N 256
-+#define LC_DILITHIUM_Q 8380417
-+#define LC_DILITHIUM_D 13
-+#define LC_DILITHIUM_ROOT_OF_UNITY 1753
-+
-+#if LC_DILITHIUM_MODE == 2
-+#define LC_DILITHIUM_NIST_CATEGORY 1
-+#define LC_DILITHIUM_LAMBDA 128
-+#define LC_DILITHIUM_K 4
-+#define LC_DILITHIUM_L 4
-+#define LC_DILITHIUM_ETA 2
-+#define LC_DILITHIUM_TAU 39
-+#define LC_DILITHIUM_BETA 78
-+#define LC_DILITHIUM_GAMMA1 (1 << 17)
-+#define LC_DILITHIUM_GAMMA2 ((LC_DILITHIUM_Q - 1) / 88)
-+#define LC_DILITHIUM_OMEGA 80
-+
-+#elif LC_DILITHIUM_MODE == 3
-+#define LC_DILITHIUM_NIST_CATEGORY 3
-+#define LC_DILITHIUM_LAMBDA 192
-+#define LC_DILITHIUM_K 6
-+#define LC_DILITHIUM_L 5
-+#define LC_DILITHIUM_ETA 4
-+#define LC_DILITHIUM_TAU 49
-+#define LC_DILITHIUM_BETA 196
-+#define LC_DILITHIUM_GAMMA1 (1 << 19)
-+#define LC_DILITHIUM_GAMMA2 ((LC_DILITHIUM_Q - 1) / 32)
-+#define LC_DILITHIUM_OMEGA 55
-+
-+#elif LC_DILITHIUM_MODE == 5
-+#define LC_DILITHIUM_NIST_CATEGORY 5
-+#define LC_DILITHIUM_LAMBDA 256
-+#define LC_DILITHIUM_K 8
-+#define LC_DILITHIUM_L 7
-+#define LC_DILITHIUM_ETA 2
-+#define LC_DILITHIUM_TAU 60
-+#define LC_DILITHIUM_BETA 120
-+#define LC_DILITHIUM_GAMMA1 (1 << 19)
-+#define LC_DILITHIUM_GAMMA2 ((LC_DILITHIUM_Q - 1) / 32)
-+#define LC_DILITHIUM_OMEGA 75
-+
-+#endif
-+
-+#define LC_DILITHIUM_CTILDE_BYTES (LC_DILITHIUM_LAMBDA * 2 / 8)
-+#define LC_DILITHIUM_POLYT1_PACKEDBYTES 320
-+#define LC_DILITHIUM_POLYT0_PACKEDBYTES 416
-+#define LC_DILITHIUM_POLYVECH_PACKEDBYTES (LC_DILITHIUM_OMEGA + LC_DILITHIUM_K)
-+
-+#if LC_DILITHIUM_GAMMA1 == (1 << 17)
-+#define LC_DILITHIUM_POLYZ_PACKEDBYTES 576
-+#elif LC_DILITHIUM_GAMMA1 == (1 << 19)
-+#define LC_DILITHIUM_POLYZ_PACKEDBYTES 640
-+#endif
-+
-+#if LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 88
-+#define LC_DILITHIUM_POLYW1_PACKEDBYTES 192
-+#elif LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 32
-+#define LC_DILITHIUM_POLYW1_PACKEDBYTES 128
-+#endif
-+
-+#if LC_DILITHIUM_ETA == 2
-+#define LC_DILITHIUM_POLYETA_PACKEDBYTES 96
-+#elif LC_DILITHIUM_ETA == 4
-+#define LC_DILITHIUM_POLYETA_PACKEDBYTES 128
-+#endif
-+
-+/*
-+ * Sizes of the different Dilithium buffer types.
-+ *
-+ * WARNING: Do not use these defines in your code. If you need the sizes of
-+ * the different variable sizes, use sizeof of the different variable structs or
-+ * use the different *_size functions documented below to retrieve the data size
-+ * of a particular Dilithium component.
-+ */
-+#define LC_DILITHIUM_PUBLICKEYBYTES \
-+ (LC_DILITHIUM_SEEDBYTES + \
-+ LC_DILITHIUM_K * LC_DILITHIUM_POLYT1_PACKEDBYTES)
-+#define LC_DILITHIUM_SECRETKEYBYTES \
-+ (2 * LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_TRBYTES + \
-+ LC_DILITHIUM_L * LC_DILITHIUM_POLYETA_PACKEDBYTES + \
-+ LC_DILITHIUM_K * LC_DILITHIUM_POLYETA_PACKEDBYTES + \
-+ LC_DILITHIUM_K * LC_DILITHIUM_POLYT0_PACKEDBYTES)
-+
-+#define LC_DILITHIUM_CRYPTO_BYTES \
-+ (LC_DILITHIUM_CTILDE_BYTES + \
-+ LC_DILITHIUM_L * LC_DILITHIUM_POLYZ_PACKEDBYTES + \
-+ LC_DILITHIUM_POLYVECH_PACKEDBYTES)
-+/// \endcond
-+
-+#ifndef __ASSEMBLER__
-+/**
-+ * @brief Dilithium secret key
-+ */
-+struct lc_dilithium_87_sk {
-+ uint8_t sk[LC_DILITHIUM_SECRETKEYBYTES];
-+};
-+
-+/**
-+ * @brief Dilithium public key
-+ */
-+struct lc_dilithium_87_pk {
-+ uint8_t pk[LC_DILITHIUM_PUBLICKEYBYTES];
-+};
-+
-+/**
-+ * @brief Dilithium signature
-+ */
-+struct lc_dilithium_87_sig {
-+ uint8_t sig[LC_DILITHIUM_CRYPTO_BYTES];
-+};
-+
-+#ifndef LC_DILITHIUM_CTX_ON_STACK
-+struct lc_dilithium_ctx {
-+ /**
-+ * @brief Hash context used internally to the library - it should not
-+ * be touched by the user
-+ */
-+ struct lc_hash_ctx dilithium_hash_ctx;
-+
-+ /**
-+ * @brief State memory of the hash context used internally to the
-+ * library - it should not be touched by the user
-+ */
-+ uint8_t shake_state[LC_SHA3_STATE_SIZE_ALIGN(LC_SHA3_256_CTX_SIZE)];
-+
-+ /**
-+ * @brief When using HashML-DSA, set the hash reference used for the
-+ * hash operation. Allowed values are lc_sha256, lc_sha512, lc_sha3_256,
-+ * lc_sha3_384, lc_sha3_512, lc_shake128 and lc_shake256. Note, the
-+ * actual message digest operation can be performed external to
-+ * leancrypto. This parameter only shall indicate the used hash
-+ * operation.
-+ *
-+ * \note Use \p lc_dilithium_ctx_hash or
-+ * \p lc_dilithium_ed25519_ctx_hash to set this value.
-+ */
-+ const struct lc_hash *dilithium_prehash_type;
-+
-+ /**
-+ * @brief length of the user context (allowed range between 0 and 255
-+ * bytes)
-+ *
-+ * \note Use \p lc_dilithium_ctx_userctx or
-+ * \p lc_dilithium_ed25519_ctx_userctx to set this value.
-+ */
-+ size_t userctxlen;
-+
-+ /**
-+ * @brief buffer with a caller-specified context string
-+ *
-+ * \note Use \p lc_dilithium_ctx_userctx or
-+ * \p lc_dilithium_ed25519_ctx_userctx to set this value.
-+ */
-+ const uint8_t *userctx;
-+
-+ /**
-+ * @brief Pointer to the AHat buffer. This can be provided by the caller
-+ * or it must be NULL otherwise.
-+ *
-+ * \note Use \p LC_DILITHIUM_CTX_ON_STACK_AHAT to provide memory for
-+ * storing AHat in the caller context and thus make the signature
-+ * operation much faster starting with the 2nd use of the key (pair).
-+ */
-+ void *ahat;
-+ unsigned short ahat_size;
-+
-+ /**
-+ * @brief Pointer to the external mu.
-+ *
-+ * If set, the signature operation will use the provided mu instead of
-+ * the message. In this case, the message pointer to the signature
-+ * generation or verification can be NULL.
-+ */
-+ const uint8_t *external_mu;
-+ size_t external_mu_len;
-+
-+ /**
-+ * @brief Pointer to the randomizer
-+ *
-+ * This is used for the Composite signature: For the discussion of the
-+ * randomizer, see https://lamps-wg.github.io/draft-composite-sigs/draft-ietf-lamps-pq-composite-sigs.html
-+ */
-+ const uint8_t *randomizer;
-+ size_t randomizerlen;
-+
-+ /**
-+ * @brief NIST category required for composite signatures
-+ *
-+ * The domain separation logic depends on the selection of the right
-+ * OID for the "Domain" data.
-+ */
-+ unsigned int nist_category;
-+
-+ /**
-+ * @brief When set to true, only the ML-DSA.Sign_internal or
-+ * ML-DSA.Verify_internal are performed (see FIPS 204 chapter 6).
-+ * Otherwise the ML-DSA.Sign / ML-DSA.Verify (see FIPS chapter 5) is
-+ * applied.
-+ *
-+ * \note Use \p lc_dilithium_ctx_internal or
-+ * \p lc_dilithium_ed25519_ctx_internal to set this value.
-+ *
-+ * \warning Only set this value to true if you exactly know what you are
-+ * doing!.
-+ */
-+ unsigned int ml_dsa_internal : 1;
-+
-+ /**
-+ * @brief Was aHat already filled? This is used and set internally.
-+ */
-+ unsigned int ahat_expanded : 1;
-+};
-+#endif
-+
-+/// \cond DO_NOT_DOCUMENT
-+
-+/*
-+ * The alignment is based on largest alignment of a polyvecl typedef - this is
-+ * the AVX2 definition.
-+ */
-+#define LC_DILITHIUM_AHAT_ALIGNMENT (32)
-+
-+/*
-+ * Padding between struct lc_dilithium_ctx and AHat buffer to ensure AHat buffer
-+ * is aligned to LC_DILITHIUM_AHAT_ALIGNMENT
-+ */
-+#define LC_DILITHIUM_87_AHAT_PAD \
-+ (LC_DILITHIUM_AHAT_ALIGNMENT - \
-+ (sizeof(struct lc_dilithium_ctx) % LC_DILITHIUM_AHAT_ALIGNMENT))
-+
-+/* Size of the AHat matrix for ML-DSA 87 */
-+#define LC_DILITHIUM_87_AHAT_SIZE \
-+ (256 * sizeof(int32_t) * LC_DILITHIUM_K * LC_DILITHIUM_L)
-+
-+#ifndef LC_DILITHIUM_CTX_ON_STACK
-+#define LC_DILITHIUM_CTX_SIZE sizeof(struct lc_dilithium_ctx)
-+
-+#define LC_DILITHIUM_CTX_INIT_HASH(name) \
-+ LC_SHAKE_256_CTX((&(name)->dilithium_hash_ctx))
-+
-+#define LC_DILITHIUM_SET_CTX(name) \
-+ LC_DILITHIUM_CTX_INIT_HASH(name); \
-+ (name)->dilithium_prehash_type = NULL; \
-+ (name)->ml_dsa_internal = 0; \
-+ (name)->userctxlen = 0; \
-+ (name)->userctx = NULL; \
-+ (name)->ahat = NULL; \
-+ (name)->ahat_size = 0; \
-+ (name)->external_mu = NULL; \
-+ (name)->external_mu_len = 0; \
-+ (name)->randomizer = NULL; \
-+ (name)->randomizerlen = 0; \
-+ (name)->nist_category = 0;
-+#endif
-+/// \endcond
-+
-+/**
-+ * @brief Allocate stack memory for the Dilithium stream context or additional
-+ * parameter relevant for the signature operation.
-+ *
-+ * @param [in] name Name of the stack variable
-+ */
-+#ifndef LC_DILITHIUM_CTX_ON_STACK
-+#define LC_DILITHIUM_CTX_ON_STACK(name) \
-+ _Pragma("GCC diagnostic push") _Pragma( \
-+ "GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \
-+ LC_ALIGNED_BUFFER(name##_ctx_buf, LC_DILITHIUM_CTX_SIZE, \
-+ LC_HASH_COMMON_ALIGNMENT); \
-+ struct lc_dilithium_ctx *name = \
-+ (struct lc_dilithium_ctx *)name##_ctx_buf; \
-+ LC_DILITHIUM_SET_CTX(name); \
-+ _Pragma("GCC diagnostic pop")
-+#endif
-+
-+/**
-+ * @brief Allocate stack memory for the Dilithium stream context and additional
-+ * parameter relevant for the signature operation.
-+ *
-+ * In addition, the memory buffer returned by this allocation contains the space
-+ * for an expanded representation of the public key which is required in both,
-+ * signature generation and verification. When using this memory, the first
-+ * signature operation expands the key and any subsequent operation using this
-+ * context will re-use the expanded key which improves performance of the
-+ * signature operation significantly.
-+ *
-+ * As the same expanded structure is used for signature generation and
-+ * verification and the structure can be expanded by either operation, it
-+ * is perfectly legal to use one context for both operations as the expanded
-+ * key can (a) be generated from either the public or the secret key and (b)
-+ * it applies to both operations and (c) is identical irrespective it was
-+ * generated from the public or secret key.
-+ *
-+ * \note: ML-DSA AVX2 signature operation uses a completely different
-+ * algorithm which does not use a pre-pcomputed expanded key. Thus, if you know
-+ * you have AVX2 support, you *may* not need this larger buffer and you *can*
-+ * use \p LC_DILITHIUM_CTX_ON_STACK instead.
-+ *
-+ * \note: The expanded representation only uses public key data. Even when
-+ * deriving the expanded representation from a secret key, this data is only
-+ * obtained from a part that is considered public. Thus, this memory does not
-+ * require special protections. See FIPS 204 section 3.6.3 on the properties
-+ * and handling requirements of the  matrix. Further, see the FIPS 204
-+ * ML-DSA.Sign_internal and ML-DSA.Verify_internal algorithm specification on
-+ * how this  matrix is generated and that the input to the generation is public
-+ * data.
-+ *
-+ * \warning: One instance of the expanded key representation can only ever apply
-+ * to one given key (pair). If you want to reuse the context with multiple keys,
-+ * you MUST invalidate the potentially present expanded key representation. Such
-+ * invalidation is invoked with the method \p lc_dilithium_ctx_drop_ahat. Only
-+ * after this invalidation you can use the context with a different key.
-+ *
-+ * @param [in] name Name of the stack variable
-+ */
-+#define LC_DILITHIUM_87_CTX_ON_STACK_AHAT(name) \
-+ _Pragma("GCC diagnostic push") _Pragma( \
-+ "GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \
-+ LC_ALIGNED_BUFFER(name##_ctx_buf, \
-+ LC_DILITHIUM_CTX_SIZE + \
-+ LC_DILITHIUM_87_AHAT_PAD + \
-+ LC_DILITHIUM_87_AHAT_SIZE, \
-+ LC_HASH_COMMON_ALIGNMENT); \
-+ struct lc_dilithium_ctx *name = \
-+ (struct lc_dilithium_ctx *)name##_ctx_buf; \
-+ LC_DILITHIUM_SET_CTX(name); \
-+ name->ahat = (uint8_t *)name + LC_DILITHIUM_CTX_SIZE + \
-+ LC_DILITHIUM_87_AHAT_PAD; \
-+ name->ahat_expanded = 0; \
-+ name->ahat_size = LC_DILITHIUM_87_AHAT_SIZE; \
-+ _Pragma("GCC diagnostic pop")
-+
-+/**
-+ * @brief Zeroize Dilithium context allocated with
-+ * LC_DILITHIUM_CTX_ON_STACK lc_dilithium_ed25519_alloc
-+ *
-+ * @param [in] ctx Dilithium context to be zeroized
-+ */
-+static inline void lc_dilithium_87_ctx_zero(struct lc_dilithium_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+ lc_hash_zero(&ctx->dilithium_hash_ctx);
-+ if (ctx->ahat) {
-+ lc_memset_secure(ctx->ahat, 0, ctx->ahat_size);
-+ ctx->ahat_expanded = 0;
-+ }
-+}
-+
-+/**
-+ * @brief Allocate Dilithium stream context on heap
-+ *
-+ * @param [out] ctx Allocated Dilithium stream context
-+ *
-+ * @return: 0 on success, < 0 on error
-+ */
-+int lc_dilithium_87_ctx_alloc(struct lc_dilithium_ctx **ctx);
-+
-+/**
-+ * @brief Allocate Dilithium stream context on heap including additional
-+ * parameter relevant for the signature operation.
-+ *
-+ * \note See \p LC_DILITHIUM_87_CTX_ON_STACK_AHAT for details.
-+ *
-+ * @param [out] ctx Allocated Dilithium stream context
-+ *
-+ * @return: 0 on success, < 0 on error
-+ */
-+int lc_dilithium_87_ctx_alloc_ahat(struct lc_dilithium_ctx **ctx);
-+
-+/**
-+ * @brief Zeroize and free Dilithium stream context
-+ *
-+ * @param [in] ctx Dilithium stream context to be zeroized and freed
-+ */
-+void lc_dilithium_87_ctx_zero_free(struct lc_dilithium_ctx *ctx);
-+
-+/**
-+ * @brief Return the size of the Dilithium secret key.
-+ */
-+LC_PURE
-+static inline unsigned int lc_dilithium_87_sk_size(void)
-+{
-+ return lc_member_size(struct lc_dilithium_87_sk, sk);
-+}
-+
-+/**
-+ * @brief Return the size of the Dilithium public key.
-+ */
-+LC_PURE
-+static inline unsigned int lc_dilithium_87_pk_size(void)
-+{
-+ return lc_member_size(struct lc_dilithium_87_pk, pk);
-+}
-+
-+/**
-+ * @brief Return the size of the Dilithium signature.
-+ */
-+LC_PURE
-+static inline unsigned int lc_dilithium_87_sig_size(void)
-+{
-+ return lc_member_size(struct lc_dilithium_87_sig, sig);
-+}
-+
-+/**
-+ * @brief Generates Dilithium public and private key.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] rng_ctx pointer to seeded random number generator context
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_87_keypair(struct lc_dilithium_87_pk *pk,
-+ struct lc_dilithium_87_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Generates Dilithium public and private key from a given seed.
-+ *
-+ * The idea of the function is the allowance of FIPS 204 to maintain the seed
-+ * used to generate a key pair in lieu of maintaining a private key or the
-+ * key pair (which used much more memory). The seed must be treated equally
-+ * sensitive as a private key.
-+ *
-+ * The seed is generated by simply obtaining 32 bytes from a properly seeded
-+ * DRNG, i.e. the same way as a symmetric key would be generated.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] seed buffer with the seed data which must be exactly 32 bytes
-+ * in size
-+ * @param [in] seedlen length of the seed buffer
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_87_keypair_from_seed(struct lc_dilithium_87_pk *pk,
-+ struct lc_dilithium_87_sk *sk,
-+ const uint8_t *seed, size_t seedlen);
-+
-+/**
-+ * @brief Computes ML-DSA signature in one shot
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_87_sign(struct lc_dilithium_87_sig *sig, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_87_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Computes signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_87_sign_ctx(struct lc_dilithium_87_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_87_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Initializes a signature operation
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_sign_update and lc_dilithium_sign_final.
-+ *
-+ * @param [in,out] ctx pointer to an allocated Dilithium context
-+ * @param [in] sk pointer to bit-packed secret key
-+ *
-+ * @return 0 (success) or < 0 on error; -EOPNOTSUPP is returned if a different
-+ * hash than lc_shake256 is used.
-+ */
-+int lc_dilithium_87_sign_init(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_87_sk *sk);
-+
-+/**
-+ * @brief Add more data to an already initialized signature state
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_sign_init and lc_dilithium_sign_final.
-+ *
-+ * @param [in] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_87_sign_update(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+
-+/**
-+ * @brief Computes signature
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init and filled with
-+ * lc_dilithium_sign_update
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_87_sign_final(struct lc_dilithium_87_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_87_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Verifies ML-DSA signature in one shot
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_87_verify(const struct lc_dilithium_87_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_87_pk *pk);
-+
-+/**
-+ * @brief Verifies signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_87_verify_ctx(const struct lc_dilithium_87_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen,
-+ const struct lc_dilithium_87_pk *pk);
-+
-+/**
-+ * @brief Initializes a signature verification operation
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_verify_update and
-+ * lc_dilithium_verify_final.
-+ *
-+ * @param [in,out] ctx pointer to an allocated Dilithium context
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 (success) or < 0 on error; -EOPNOTSUPP is returned if a different
-+ * hash than lc_shake256 is used.
-+ */
-+int lc_dilithium_87_verify_init(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_87_pk *pk);
-+
-+/**
-+ * @brief Add more data to an already initialized signature state
-+ *
-+ * This call is intended to support messages that are located in non-contiguous
-+ * places and even becomes available at different times. This call is to be
-+ * used together with the lc_dilithium_verify_init and
-+ * lc_dilithium_verify_final.
-+ *
-+ * @param [in,out] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_87_verify_update(struct lc_dilithium_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+
-+/**
-+ * @brief Verifies signature
-+ *
-+ * @param [in] sig pointer to output signature
-+ * @param [in] ctx pointer to Dilithium context that was initialized with
-+ * lc_dilithium_sign_init and filled with
-+ * lc_dilithium_sign_update
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_87_verify_final(const struct lc_dilithium_87_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_87_pk *pk);
-+
-+/****************************** Dilithium ED25510 *****************************/
-+/* Macro set during leancrypto compile time for target platform */
-+#undef LC_DILITHIUM_ED25519_SIG
-+#ifdef LC_DILITHIUM_ED25519_SIG
-+
-+#include "lc_ed25519.h"
-+
-+/**
-+ * @brief Dilithium secret key
-+ */
-+struct lc_dilithium_87_ed25519_sk {
-+ struct lc_dilithium_87_sk sk;
-+ struct lc_ed25519_sk sk_ed25519;
-+};
-+
-+/**
-+ * @brief Dilithium public key
-+ */
-+struct lc_dilithium_87_ed25519_pk {
-+ struct lc_dilithium_87_pk pk;
-+ struct lc_ed25519_pk pk_ed25519;
-+};
-+
-+/**
-+ * @brief Dilithium signature
-+ */
-+struct lc_dilithium_87_ed25519_sig {
-+ struct lc_dilithium_87_sig sig;
-+ struct lc_ed25519_sig sig_ed25519;
-+};
-+
-+/**
-+ * @brief Dilithium stream context
-+ *
-+ * This structure is used for the init/update/final operation of the
-+ * Dilithium-ED25519 hybrid.
-+ */
-+#ifndef LC_DILITHIUM_ED25519_CTX_ON_STACK
-+struct lc_dilithium_ed25519_ctx {
-+ struct lc_dilithium_ctx dilithium_ctx;
-+};
-+#endif
-+
-+/// \cond DO_NOT_DOCUMENT
-+#ifndef LC_DILITHIUM_ED25519_CTX_ON_STACK
-+#define LC_DILITHIUM_ED25519_CTX_SIZE sizeof(struct lc_dilithium_ed25519_ctx)
-+#endif
-+/// \endcond
-+
-+/**
-+ * @brief Allocate stack memory for the Dilithium-ED25519 stream context
-+ *
-+ * @param [in] name Name of the stack variable
-+ */
-+#ifndef LC_DILITHIUM_ED25519_CTX_ON_STACK
-+#define LC_DILITHIUM_ED25519_CTX_ON_STACK(name) \
-+ _Pragma("GCC diagnostic push") _Pragma( \
-+ "GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \
-+ LC_ALIGNED_BUFFER(name##_ctx_buf, \
-+ LC_DILITHIUM_ED25519_CTX_SIZE, \
-+ LC_HASH_COMMON_ALIGNMENT); \
-+ struct lc_dilithium_ed25519_ctx *name = \
-+ (struct lc_dilithium_ed25519_ctx *)name##_ctx_buf; \
-+ LC_DILITHIUM_SET_CTX(&(name)->dilithium_ctx); \
-+ _Pragma("GCC diagnostic pop")
-+#endif
-+
-+/**
-+ * @brief Zeroize Dilithium-ED25519 context allocated with
-+ * LC_DILITHIUM_ED25519_CTX_ON_STACK lc_dilithium_ed25519_alloc
-+ *
-+ * @param [in] ctx Dilithium-ED25519 context to be zeroized
-+ */
-+static inline void
-+lc_dilithium_87_ed25519_ctx_zero(struct lc_dilithium_ed25519_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+ lc_dilithium_87_ctx_zero(&ctx->dilithium_ctx);
-+}
-+
-+/**
-+ * @brief Allocate Dilithium-ED25519 stream context on heap
-+ *
-+ * @param [out] ctx Allocated Dilithium-ED25519 stream context
-+ *
-+ * @return: 0 on success, < 0 on error
-+ */
-+int lc_dilithium_87_ed25519_ctx_alloc(struct lc_dilithium_ed25519_ctx **ctx);
-+
-+/**
-+ * @brief Zeroize and free Dilithium-ED25519 stream context
-+ *
-+ * @param [in] ctx Dilithium-ED25519 stream context to be zeroized and freed
-+ */
-+void lc_dilithium_87_ed25519_ctx_zero_free(struct lc_dilithium_ed25519_ctx *ctx);
-+
-+/**
-+ * @brief Generates Dilithium public and private key.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] rng_ctx pointer to seeded random number generator context
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_87_ed25519_keypair(struct lc_dilithium_87_ed25519_pk *pk,
-+ struct lc_dilithium_87_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Computes signature in one shot
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_87_ed25519_sign(struct lc_dilithium_87_ed25519_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_87_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Computes signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_87_ed25519_sign_ctx(struct lc_dilithium_87_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_87_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+int lc_dilithium_87_ed25519_sign_init(
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_87_ed25519_sk *sk);
-+
-+int lc_dilithium_87_ed25519_sign_update(struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+
-+int lc_dilithium_87_ed25519_sign_final(
-+ struct lc_dilithium_87_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_87_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Verifies signature in one shot
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_87_ed25519_verify(const struct lc_dilithium_87_ed25519_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_87_ed25519_pk *pk);
-+
-+/**
-+ * @brief Verifies signature in one shot with Dilithium context
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_87_ed25519_verify_ctx(
-+ const struct lc_dilithium_87_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx, const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_87_ed25519_pk *pk);
-+
-+int lc_dilithium_87_ed25519_verify_init(
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_87_ed25519_pk *pk);
-+int lc_dilithium_87_ed25519_verify_update(struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+int lc_dilithium_87_ed25519_verify_final(
-+ const struct lc_dilithium_87_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_87_ed25519_pk *pk);
-+
-+#endif /* LC_DILITHIUM_ED25519_SIG */
-+
-+/****************************** Dilithium ED25510 *****************************/
-+/* Macro set during leancrypto compile time for target platform */
-+#undef LC_DILITHIUM_ED448_SIG
-+#ifdef LC_DILITHIUM_ED448_SIG
-+
-+#include "lc_ed448.h"
-+
-+/**
-+ * @brief Dilithium secret key
-+ */
-+struct lc_dilithium_87_ed448_sk {
-+ struct lc_dilithium_87_sk sk;
-+ struct lc_ed448_sk sk_ed448;
-+};
-+
-+/**
-+ * @brief Dilithium public key
-+ */
-+struct lc_dilithium_87_ed448_pk {
-+ struct lc_dilithium_87_pk pk;
-+ struct lc_ed448_pk pk_ed448;
-+};
-+
-+/**
-+ * @brief Dilithium signature
-+ */
-+struct lc_dilithium_87_ed448_sig {
-+ struct lc_dilithium_87_sig sig;
-+ struct lc_ed448_sig sig_ed448;
-+};
-+
-+/**
-+ * @brief Dilithium stream context
-+ *
-+ * This structure is used for the init/update/final operation of the
-+ * Dilithium-ED448 hybrid.
-+ */
-+#ifndef LC_DILITHIUM_ED448_CTX_ON_STACK
-+struct lc_dilithium_ed448_ctx {
-+ struct lc_dilithium_ctx dilithium_ctx;
-+};
-+#endif
-+
-+/// \cond DO_NOT_DOCUMENT
-+#ifndef LC_DILITHIUM_ED448_CTX_ON_STACK
-+#define LC_DILITHIUM_ED448_CTX_SIZE sizeof(struct lc_dilithium_ed448_ctx)
-+#endif
-+/// \endcond
-+
-+/**
-+ * @brief Allocate stack memory for the Dilithium-ED448 stream context
-+ *
-+ * @param [in] name Name of the stack variable
-+ */
-+#ifndef LC_DILITHIUM_ED448_CTX_ON_STACK
-+#define LC_DILITHIUM_ED448_CTX_ON_STACK(name) \
-+ _Pragma("GCC diagnostic push") _Pragma( \
-+ "GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \
-+ LC_ALIGNED_BUFFER(name##_ctx_buf, LC_DILITHIUM_ED448_CTX_SIZE, \
-+ LC_HASH_COMMON_ALIGNMENT); \
-+ struct lc_dilithium_ed448_ctx *name = \
-+ (struct lc_dilithium_ed448_ctx *)name##_ctx_buf; \
-+ LC_DILITHIUM_SET_CTX(&(name)->dilithium_ctx); \
-+ _Pragma("GCC diagnostic pop")
-+#endif
-+
-+/**
-+ * @brief Zeroize Dilithium-ED448 context allocated with
-+ * LC_DILITHIUM_ED448_CTX_ON_STACK lc_dilithium_ed448_alloc
-+ *
-+ * @param [in] ctx Dilithium-ED448 context to be zeroized
-+ */
-+static inline void
-+lc_dilithium_87_ed448_ctx_zero(struct lc_dilithium_ed448_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+ lc_dilithium_87_ctx_zero(&ctx->dilithium_ctx);
-+}
-+
-+/**
-+ * @brief Allocate Dilithium-ED448 stream context on heap
-+ *
-+ * @param [out] ctx Allocated Dilithium-ED448 stream context
-+ *
-+ * @return: 0 on success, < 0 on error
-+ */
-+int lc_dilithium_87_ed448_ctx_alloc(struct lc_dilithium_ed448_ctx **ctx);
-+
-+/**
-+ * @brief Zeroize and free Dilithium-ED448 stream context
-+ *
-+ * @param [in] ctx Dilithium-ED448 stream context to be zeroized and freed
-+ */
-+void lc_dilithium_87_ed448_ctx_zero_free(struct lc_dilithium_ed448_ctx *ctx);
-+
-+/**
-+ * @brief Generates Dilithium public and private key.
-+ *
-+ * @param [out] pk pointer to allocated output public key
-+ * @param [out] sk pointer to allocated output private key
-+ * @param [in] rng_ctx pointer to seeded random number generator context
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_87_ed448_keypair(struct lc_dilithium_87_ed448_pk *pk,
-+ struct lc_dilithium_87_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Computes signature in one shot
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_87_ed448_sign(struct lc_dilithium_87_ed448_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_87_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Computes signature with Dilithium context in one shot
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [out] sig pointer to output signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message to be signed
-+ * @param [in] mlen length of message
-+ * @param [in] sk pointer to bit-packed secret key
-+ * @param [in] rng_ctx pointer to seeded random number generator context - when
-+ * pointer is non-NULL, perform a randomized signing.
-+ * Otherwise use deterministic signing.
-+ *
-+ * @return 0 (success) or < 0 on error
-+ */
-+int lc_dilithium_87_ed448_sign_ctx(struct lc_dilithium_87_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_87_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+int lc_dilithium_87_ed448_sign_init(struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_87_ed448_sk *sk);
-+
-+int lc_dilithium_87_ed448_sign_update(struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+
-+int lc_dilithium_87_ed448_sign_final(struct lc_dilithium_87_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_87_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+/**
-+ * @brief Verifies signature in one shot
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_87_ed448_verify(const struct lc_dilithium_87_ed448_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_87_ed448_pk *pk);
-+
-+/**
-+ * @brief Verifies signature in one shot with Dilithium context
-+ *
-+ * This API allows the caller to provide an arbitrary context buffer which
-+ * is hashed together with the message to form the message digest to be signed.
-+ *
-+ * @param [in] sig pointer to input signature
-+ * @param [in] ctx reference to the allocated Dilithium context handle
-+ * @param [in] m pointer to message
-+ * @param [in] mlen length of message
-+ * @param [in] pk pointer to bit-packed public key
-+ *
-+ * @return 0 if signature could be verified correctly and -EBADMSG when
-+ * signature cannot be verified, < 0 on other errors
-+ */
-+int lc_dilithium_87_ed448_verify_ctx(const struct lc_dilithium_87_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_87_ed448_pk *pk);
-+
-+int lc_dilithium_87_ed448_verify_init(struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_87_ed448_pk *pk);
-+int lc_dilithium_87_ed448_verify_update(struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *m, size_t mlen);
-+int lc_dilithium_87_ed448_verify_final(
-+ const struct lc_dilithium_87_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_87_ed448_pk *pk);
-+
-+#endif /* LC_DILITHIUM_ED448_SIG */
-+
-+#endif /* __ASSEMBLER__ */
-+
-+/*
-+ * To allow including the different lc_dilithium_*.h files, these macros need to
-+ * be undefined. Only during compilation of leancrypto, these macros remain
-+ * defined as this header file is not included multiple times.
-+ */
-+#ifndef LC_DILITHIUM_INTERNAL
-+#undef LC_DILITHIUM_MODE
-+#undef LC_DILITHIUM_NIST_CATEGORY
-+#undef LC_DILITHIUM_SEEDBYTES
-+#undef LC_DILITHIUM_CRHBYTES
-+#undef LC_DILITHIUM_TRBYTES
-+#undef LC_DILITHIUM_RNDBYTES
-+#undef LC_DILITHIUM_N
-+#undef LC_DILITHIUM_Q
-+#undef LC_DILITHIUM_D
-+#undef LC_DILITHIUM_ROOT_OF_UNITY
-+#undef LC_DILITHIUM_LAMBDA
-+#undef LC_DILITHIUM_K
-+#undef LC_DILITHIUM_L
-+#undef LC_DILITHIUM_ETA
-+#undef LC_DILITHIUM_TAU
-+#undef LC_DILITHIUM_BETA
-+#undef LC_DILITHIUM_GAMMA1
-+#undef LC_DILITHIUM_GAMMA2
-+#undef LC_DILITHIUM_OMEGA
-+#undef LC_DILITHIUM_CTILDE_BYTES
-+#undef LC_DILITHIUM_POLYT1_PACKEDBYTES
-+#undef LC_DILITHIUM_POLYT0_PACKEDBYTES
-+#undef LC_DILITHIUM_POLYVECH_PACKEDBYTES
-+#undef LC_DILITHIUM_POLYZ_PACKEDBYTES
-+#undef LC_DILITHIUM_POLYW1_PACKEDBYTES
-+#undef LC_DILITHIUM_POLYETA_PACKEDBYTES
-+#undef LC_DILITHIUM_PUBLICKEYBYTES
-+#undef LC_DILITHIUM_SECRETKEYBYTES
-+#undef LC_DILITHIUM_CRYPTO_BYTES
-+#endif /* LC_DILITHIUM_INTERNAL */
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* LC_DILITHIUM_87_H */
-diff --git a/lib/freebl/leancrypto/lc_hash.h b/lib/freebl/leancrypto/lc_hash.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/lc_hash.h
-@@ -0,0 +1,17 @@
-+#include "hasht.h"
-+#include "blapit.h"
-+#include "lc_memset_secure.h" /* sigh the original included it,
-+ * so some files expect it to be there already */
-+#include "lc_memory_support.h"
-+/* sigh Stephen doesn seem to believe in typedef, so
-+ * just stuff our context pointer into a struct */
-+#define LC_SHA3_256_CTX_SIZE (SHA3_256_BLOCK_LENGTH)
-+#define LC_SHA3_STATE_SIZE_ALIGN(x) (x)
-+
-+#define LC_SHA3_512_SIZE_DIGEST SHA3_512_LENGTH
-+
-+#ifndef LC_HASH_COMMON_ALIGNMENT
-+#define LC_HASH_COMMON_ALIGNMENT 64
-+#endif
-+
-+
-diff --git a/lib/freebl/leancrypto/lc_init.h b/lib/freebl/leancrypto/lc_init.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/lc_init.h
-@@ -0,0 +1,51 @@
-+/*
-+ * Copyright (C) 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef LC_INIT_H
-+#define LC_INIT_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/**
-+ * @brief Initialization of leancrypto
-+ *
-+ * This function invokes all necessary initialization functions required at
-+ * the loading time of leancrypto. However, this function is only needed for
-+ * environments without a constructor functionality such as the Linux kernel
-+ * or the EFI environment.
-+ *
-+ * For regular environments such as Linux, this function is not required to be
-+ * called. But it does not hurt to be called.
-+ *
-+ * \note If this function is called, no other leancrypto service must be offered
-+ * as this function may alter the global leancrypto state.
-+ *
-+ * @param [in] flags currently unused
-+ *
-+ * @return 0 on success, < 0 on error
-+ */
-+int lc_init(unsigned int flags);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* LC_INIT_H */
-diff --git a/lib/freebl/leancrypto/lc_memcmp_secure.h b/lib/freebl/leancrypto/lc_memcmp_secure.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/lc_memcmp_secure.h
-@@ -0,0 +1,45 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef MEMCMP_SECURE_H
-+#define MEMCMP_SECURE_H
-+
-+#include "ext_headers.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/**
-+ * @brief Constant-time memcmp implementation
-+ *
-+ * @param s1 First string
-+ * @param s1n Size of first string
-+ * @param s2 Second string
-+ * @param s2n Size of second string
-+ *
-+ * @return 0 on string match, != 0 when strings do not match
-+ */
-+int lc_memcmp_secure(const void *s1, size_t s1n, const void *s2, size_t s2n);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* MEMCMP_SECURE_H */
-diff --git a/lib/freebl/leancrypto/lc_memcpy_secure.h b/lib/freebl/leancrypto/lc_memcpy_secure.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/lc_memcpy_secure.h
-@@ -0,0 +1,43 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef MEMCPY_SECURE_H
-+#define MEMCPY_SECURE_H
-+
-+#include "ext_headers.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/**
-+ * @brief Leancrypto-internal memcpy
-+ *
-+ * @param d Destination buffer
-+ * @param dn Size of destination buffer
-+ * @param s Source buffer
-+ * @param sn Size of source buffer
-+ */
-+void *lc_memcpy_secure(void *d, size_t dn, const void *s, size_t sn);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* MEMCPY_SECURE_H */
-diff --git a/lib/freebl/leancrypto/lc_memory_support.h b/lib/freebl/leancrypto/lc_memory_support.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/lc_memory_support.h
-@@ -0,0 +1,184 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef LC_MEMORY_SUPPORT_H
-+#define LC_MEMORY_SUPPORT_H
-+
-+#include "ext_headers.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/* Default memory alignment */
-+#define LC_MEM_COMMON_ALIGNMENT (8)
-+
-+/**
-+ * @brief Allocate aligned stack memory
-+ *
-+ * The variable can be casted to any structure
-+ *
-+ * @param name variable name
-+ * @param size size of the buffer
-+ * @param alignment alignment of the buffer
-+ */
-+#define LC_ALIGNED_BUFFER(name, size, alignment) \
-+ uint64_t name[(size + sizeof(uint64_t) - 1) / sizeof(uint64_t)] \
-+ __attribute__((aligned(alignment)))
-+
-+/* Helpers to align a pointer */
-+#define LC_ALIGNMENT_MASK(alignment) (alignment - 1)
-+#define LC_ALIGN_APPLY(x, mask) (((x) + (mask)) & ~(mask))
-+#define LC_ALIGN(x, a) LC_ALIGN_APPLY((x), (uintptr_t)(a))
-+
-+/**
-+ * @brief Align pointer interpreted as 64 bit variable
-+ *
-+ * @param p pointer
-+ * @param a alignment
-+ */
-+#define LC_ALIGN_PTR_64(p, a) ((uint64_t *)LC_ALIGN((uintptr_t)(p), (a)));
-+
-+/**
-+ * @brief Align pointer interpreted as 32 bit variable
-+ *
-+ * @param p pointer
-+ * @param a alignment
-+ */
-+#define LC_ALIGN_PTR_32(p, a) ((uint32_t *)LC_ALIGN((uintptr_t)(p), (a)))
-+
-+/**
-+ * @brief Align pointer interpreted as 16 bit variable
-+ *
-+ * @param p pointer
-+ * @param a alignment
-+ */
-+#define LC_ALIGN_PTR_16(p, a) ((uint16_t *)LC_ALIGN((uintptr_t)(p), (a)))
-+
-+/**
-+ * @brief Align pointer interpreted as 8 bit variable
-+ *
-+ * @param p pointer
-+ * @param a alignment
-+ */
-+#define LC_ALIGN_PTR_8(p, a) ((uint8_t *)LC_ALIGN((uintptr_t)(p), (a)))
-+
-+/**
-+ * Proper memory alignment value when using XOR
-+ */
-+#define LC_XOR_MIN_ALIGNMENT(min, requested) \
-+ ((min < requested) ? (requested) : (min))
-+
-+/* Macros set during leancrypto compile time for target platform */
-+#define LC_DEF_HOST_X86_64
-+#undef LC_DEF_HOST_ARM32_NEON
-+#undef LC_DEF_HOST_AARCH64
-+
-+#ifdef LC_DEF_HOST_X86_64
-+
-+/*
-+ * The load of data into __m256i does not require alignment, the store
-+ * requires 64 bit alignment by using _mm_storel_pd / _mm_storeh_pd.
-+ */
-+#define LC_XOR_AVX2_ALIGNMENT (sizeof(uint64_t))
-+#define LC_XOR_ALIGNMENT(min) LC_XOR_MIN_ALIGNMENT(min, LC_XOR_AVX2_ALIGNMENT)
-+
-+#elif (defined(LC_DEF_HOST_ARM32_NEON) || defined(LC_DEF_HOST_AARCH64)) && \
-+ !defined(LINUX_KERNEL)
-+
-+/*
-+ * The load of data into uint64x2_t requires 64 bit alignment, the store
-+ * requires 64 bit alignment.
-+ */
-+#define LC_XOR_NEON_ALIGNMENT (sizeof(uint64_t))
-+#define LC_XOR_ALIGNMENT(min) LC_XOR_MIN_ALIGNMENT(min, LC_XOR_NEON_ALIGNMENT)
-+
-+#else
-+
-+#define LC_XOR_ALIGNMENT(min) LC_XOR_MIN_ALIGNMENT(min, (sizeof(uint64_t)))
-+
-+#endif
-+
-+/**
-+ * @brief allocate aligned memory up to 8 bytes alignment
-+ *
-+ * @param [out] memptr pointer to the newly allocated memory
-+ * @param [in] alignment alignment of the memory
-+ * @param [in] size size of the memory buffer
-+ */
-+int lc_alloc_aligned(void **memptr, size_t alignment, size_t size);
-+
-+/**
-+ * @brief allocate aligned memory up to 8 bytes alignment with additional
-+ * security precautions
-+ *
-+ * @param [out] memptr pointer to the newly allocated memory
-+ * @param [in] alignment alignment of the memory
-+ * @param [in] size size of the memory buffer
-+ */
-+int lc_alloc_aligned_secure(void **memptr, size_t alignment, size_t size);
-+
-+/**
-+ * @brief allocate aligned memory with arbitrary alignment
-+ *
-+ * @param [out] memptr pointer to the newly allocated memory
-+ * @param [in] alignment alignment of the memory
-+ * @param [in] size size of the memory buffer
-+ */
-+int lc_alloc_high_aligned(void **memptr, size_t alignment, size_t size);
-+
-+/**
-+ * @brief free the memory allocated with lc_alloc_aligned
-+ *
-+ * The memory is NOT zeroized.
-+ *
-+ * @param [in] ptr memory pointer to free
-+ */
-+void lc_free(void *ptr);
-+
-+/**
-+ * @brief free the memory allocated with lc_alloc_high_aligned
-+ *
-+ * The memory is NOT zeroized.
-+ *
-+ * @param [in] ptr memory pointer to free
-+ * @param [in] size size of the memory to free
-+ */
-+void lc_free_high_aligned(void *ptr, size_t size);
-+
-+/**
-+ * @brief Check if memory pointer is aligned to given alignment mask
-+ *
-+ * @param [in] ptr memory pointer to check
-+ * @param [in] alignmask alignment mask to check for
-+ *
-+ * @return 1 if pointer is aligned, 0 if not aligned
-+ */
-+static inline int lc_mem_aligned(const uint8_t *ptr, uint32_t alignmask)
-+{
-+ if ((uintptr_t)ptr & alignmask)
-+ return 0;
-+ return 1;
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* LC_MEMORY_SUPPORT_H */
-diff --git a/lib/freebl/leancrypto/lc_memset_secure.h b/lib/freebl/leancrypto/lc_memset_secure.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/lc_memset_secure.h
-@@ -0,0 +1,100 @@
-+/*
-+ * Copyright (C) 2018 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef LC_MEMSET_SECURE_H
-+#define LC_MEMSET_SECURE_H
-+
-+#include "ext_headers.h"
-+
-+/*
-+ * Tested following code:
-+ *
-+ * (1) __asm__ __volatile__("" : "=r" (s) : "0" (s));
-+ * (2) __asm__ __volatile__("": : :"memory");
-+ * (3) __asm__ __volatile__("" : "=r" (s) : "0" (s) : "memory");
-+ * (4) __asm__ __volatile__("" : : "r" (s) : "memory");
-+ *
-+ * Requred result:
-+ *
-+ * gcc -O3: objdump -d shows the following:
-+ *
-+ * 0000000000400440 :
-+ * ...
-+ * 400469: 48 c7 04 24 00 00 00 movq $0x0,(%rsp)
-+ * 400470: 00
-+ * 400471: 48 c7 44 24 08 00 00 movq $0x0,0x8(%rsp)
-+ * 400478: 00 00
-+ * 40047a: c7 44 24 10 00 00 00 movl $0x0,0x10(%rsp)
-+ * 400481: 00
-+ *
-+ * clang -O3: objdump -d shows the following:
-+ *
-+ * 0000000000400590 :
-+ * ...
-+ * 4005c3: c7 44 24 10 00 00 00 movl $0x0,0x10(%rsp)
-+ * 4005ca: 00
-+ *
-+ *
-+ * Test results:
-+ *
-+ * The following table marks an X when the aforementioned movq/movl code is
-+ * present (or an invocation of memset@plt) in the object code
-+ * (i.e. the code we want). Contrary, the table marks - where the code is not
-+ * present (i.e. the code we do not want):
-+ *
-+ * | BARRIER | (1) | (2) | (3) | (4)
-+ * ---------+----------+ | | |
-+ * Compiler | | | | |
-+ * =========+==========+=======================
-+ * | | | |
-+ * gcc -O0 | X | X | X | X
-+ * | | | |
-+ * gcc -O2 | - | X | X | X
-+ * | | | |
-+ * gcc -O3 | - | X | X | X
-+ * | | | |
-+ * clang -00 | X | X | X | X
-+ * | | | |
-+ * clang -02 | X | - | X | X
-+ * | | | |
-+ * clang -03 | - | - | X | X
-+ */
-+
-+static inline void lc_memset_secure(void *s, int c, size_t n)
-+{
-+ memset(s, c, n);
-+ __asm__ __volatile__("" : : "r"(s) : "memory");
-+}
-+
-+#if 0
-+#include
-+
-+int main(int argc, char *argv[])
-+{
-+ char buf[20];
-+
-+ snprintf(buf, sizeof(buf) - 1, "test");
-+ printf("%s\n", buf);
-+
-+ memset_secure(buf, 0, sizeof(buf));
-+ return 0;
-+}
-+#endif
-+
-+#endif /* LC_MEMSET_SECURE_H */
-diff --git a/lib/freebl/leancrypto/lc_rng.h b/lib/freebl/leancrypto/lc_rng.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/lc_rng.h
-@@ -0,0 +1,56 @@
-+#ifndef LC_RNG_H
-+#define LC_RNG_H 1
-+#include
-+#include
-+
-+struct lc_rng_ctx;
-+extern struct lc_rng_ctx *lc_seeded_rng;
-+
-+/* just enough of the rng_context to make the code happy.
-+ * in the end, we just use our NSS internal RNG */
-+struct lc_static_rng_data {
-+ const unsigned char *seed;
-+ size_t seedlen;
-+};
-+
-+struct lc_rng_ctx {
-+ struct lc_static_rng_data *dummy;
-+};
-+
-+static inline int lc_rng_generate(struct lc_rng_ctx *rng,
-+ unsigned char *addinput,
-+ size_t addlen,
-+ unsigned char *out,
-+ size_t outlen)
-+{
-+ size_t len;
-+ if (rng->dummy != NULL) {
-+ if (outlen > rng->dummy->seedlen) {
-+ return -1;
-+ }
-+ PORT_Memcpy(out, rng->dummy->seed, outlen);
-+ return 0;
-+ }
-+ if (addlen != 0) {
-+ RNG_RandomUpdate(addinput, addlen);
-+ }
-+ len= RNG_SystemRNG(out, outlen);
-+ if (len != outlen) {
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+#define lc_rng_seed(rng, seed, seedlen, pers, perslen) {\
-+ if (pers_len != 0) {\
-+ RNG_RandomUpdate(pers, perslen); \
-+ } \
-+ RNG_SystemRNG(seed, seedlen); \
-+}
-+#define lc_rng_check(rng)
-+
-+#define LC_STATIC_DRNG_ON_STACK(sdrng, state)\
-+ struct lc_rng_ctx sdrng; \
-+ sdrng.dummy = state;
-+
-+#endif
-diff --git a/lib/freebl/leancrypto/lc_sha256.h b/lib/freebl/leancrypto/lc_sha256.h
-new file mode 100644
-diff --git a/lib/freebl/leancrypto/lc_sha3.h b/lib/freebl/leancrypto/lc_sha3.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/lc_sha3.h
-@@ -0,0 +1,213 @@
-+// SPDX-License-Identifier: MIT
-+// NSS SHA3 bindings for ML-DSA leancrypto
-+
-+#ifndef LC_SHA3__H
-+#define LC_SHA3__H
-+#include
-+
-+#define LC_SHA3_SIZE_RATE(bits) ((1600 - 2 * bits) >> 3)
-+
-+#define LC_SHAKE_128_SIZE_BLOCK LC_SHA3_SIZE_RATE(128)
-+#define LC_SHAKE_256_SIZE_BLOCK LC_SHA3_SIZE_RATE(256)
-+
-+/*#define SHAKE128_RATE 168
-+#define shake128 SHAKE_128_HashBuf
-+
-+#define SHAKE256_RATE SHA3_256_BLOCK_LENGTH
-+#define shake256 SHAKE_256_HashBuf */
-+
-+#define LC_HASH_CTX_ON_STACK(name, type_) \
-+ struct lc_hash_ctx _##name ; \
-+ _##name.hash= type_; \
-+ _##name.buf= NULL; \
-+ _##name.stream = false; \
-+ _##name.u.ctx_ptr = NULL; \
-+ struct lc_hash_ctx *name= &_##name;
-+
-+#define LC_HASH_SET_CTX(name, type_) \
-+ name->hash= type_;
-+
-+#define LC_SHAKE_256_CTX(name) \
-+ LC_HASH_SET_CTX(name, lc_shake256);
-+
-+typedef enum {
-+ lc_shake128,
-+ lc_shake256,
-+} sha3Type;
-+
-+
-+/* sigh, we buffer eKEverything because we can't correctly do multiple
-+ * finals correctly. In cases where we know we are not going to
-+ * do multiple finals, set the streaming bool */
-+struct lc_hash_ctx {
-+ sha3Type hash;
-+ bool stream;
-+ union {
-+ SHAKE_256Context *shake256_ctx;
-+ SHAKE_128Context *shake128_ctx;
-+ void *ctx_ptr;
-+ }u;
-+ size_t digestSize;
-+ size_t current_input;
-+ size_t current_output;
-+ unsigned char *buf;
-+ size_t buf_size;
-+ unsigned char buf_space[2048];
-+ unsigned char buf2_space[2048];
-+};
-+
-+#define lc_xof(type, in, inlen, out, outlen) \
-+ switch(type) { \
-+ case lc_shake128: \
-+ SHAKE_128_HashBuf(out, outlen, in, inlen); \
-+ break; \
-+ case lc_shake256: \
-+ SHAKE_256_HashBuf(out, outlen, in, inlen); \
-+ break; \
-+ default: \
-+ assert(0); \
-+ }
-+
-+static inline void
-+lc_hash_init(struct lc_hash_ctx *ptr) {
-+ if (ptr->stream) {
-+ /* if we already have a context, just reset it, This is
-+ * what the caller wanted, saving a destroy and create */
-+ if (ptr->u.ctx_ptr == NULL) {
-+ switch (ptr->hash) {
-+ case lc_shake128:
-+ ptr->u.shake128_ctx = SHAKE_128_NewContext();
-+ break;
-+ case lc_shake256:
-+ ptr->u.shake256_ctx = SHAKE_256_NewContext();
-+ break;
-+ }
-+ }
-+ switch (ptr->hash) {
-+ case lc_shake128:
-+ SHAKE_128_Begin(ptr->u.shake128_ctx);
-+ break;
-+ case lc_shake256:
-+ SHAKE_256_Begin(ptr->u.shake256_ctx);
-+ break;
-+ }
-+ return;
-+ }
-+ /* we can be called with an active buffer, do and implicit reset here
-+ * and free that buffer before we set up the next one */
-+ if (ptr->buf && ptr->buf != ptr->buf_space) {
-+ memset(ptr->buf, 0, ptr->current_input);
-+ free(ptr->buf);
-+ }
-+ ptr->digestSize = 0;
-+ ptr->current_input = 0;
-+ ptr->current_output = 0;
-+ ptr->buf_size = sizeof(ptr->buf_space);
-+ ptr->buf = &ptr->buf_space[0];
-+}
-+
-+static inline void
-+lc_hash_update(struct lc_hash_ctx *ptr, const unsigned char *input, size_t inLen) {
-+ if (inLen ==0) { return; } /* why were we even called with a NULL buffer? */
-+ if (ptr->stream) {
-+ switch (ptr->hash) {
-+ case lc_shake128:
-+ SHAKE_128_Absorb(ptr->u.shake128_ctx, input, inLen);
-+ break;
-+ case lc_shake256:
-+ SHAKE_256_Absorb(ptr->u.shake256_ctx, input, inLen);
-+ break;
-+ }
-+ return;
-+ }
-+ if (ptr->current_input + inLen > ptr->buf_size) {
-+ int len = ptr->current_input + inLen + 2048;
-+ unsigned char *newBuf;
-+ if (ptr->buf_size == sizeof(ptr->buf_space)) {
-+ newBuf = calloc(1, len);
-+ if (newBuf) {
-+ memcpy(newBuf, ptr->buf, ptr->buf_size);
-+ memset(ptr->buf_space, 0, sizeof(ptr->buf_space));
-+ }
-+ } else {
-+ newBuf = reallocarray(ptr->buf, 1, len);
-+ }
-+ if (!newBuf) {
-+ return;
-+ }
-+ ptr->buf = newBuf;
-+ ptr->buf_size = len;
-+ }
-+ memcpy(ptr->buf + ptr->current_input, input, inLen);
-+ ptr->current_input+=inLen;
-+}
-+
-+#define lc_hash_set_digestsize(ptr, len) ((ptr)->digestSize = (len))
-+static inline void
-+lc_hash_final(struct lc_hash_ctx *ptr, unsigned char *output)
-+{
-+ size_t outLen= ptr->digestSize;
-+ if (ptr->stream) {
-+ switch (ptr->hash) {
-+ case lc_shake128:
-+ SHAKE_128_SqueezeEnd(ptr->u.shake128_ctx, output, outLen);
-+ break;
-+ case lc_shake256:
-+ SHAKE_256_SqueezeEnd(ptr->u.shake256_ctx, output, outLen);
-+ break;
-+ }
-+ return;
-+ }
-+ int len= ptr->current_output+outLen;
-+ if (ptr->current_output == 0) {
-+ lc_xof(ptr->hash, ptr->buf, ptr->current_input, output, outLen);
-+ ptr->current_output += outLen;
-+ return;
-+ }
-+ if (len > sizeof(ptr->buf2_space)) {
-+ unsigned char *newBuf = calloc(1,len);
-+ if (!newBuf) {
-+ memset(output, 0, outLen);
-+ return;
-+ }
-+ lc_xof(ptr->hash, ptr->buf, ptr->current_input, newBuf, len);
-+ memcpy(output, newBuf+ptr->current_output, outLen);
-+ memset(newBuf, 0, len);
-+ free(newBuf);
-+ ptr->current_output += outLen;
-+ return;
-+ }
-+ lc_xof(ptr->hash, ptr->buf, ptr->current_input, ptr->buf2_space, len);
-+ memcpy(output, &ptr->buf2_space[ptr->current_output], outLen);
-+ memset(ptr->buf2_space, 0,len);
-+ ptr->current_output += outLen;
-+ return;
-+}
-+
-+static inline void lc_hash_zero(struct lc_hash_ctx *ptr)
-+{
-+ if (ptr->stream) {
-+ if (ptr->u.ctx_ptr != NULL) {
-+ switch (ptr->hash) {
-+ case lc_shake128:
-+ SHAKE_128_DestroyContext(ptr->u.shake128_ctx, PR_TRUE);
-+ ptr->u.shake128_ctx = NULL;
-+ break;
-+ case lc_shake256:
-+ SHAKE_128_DestroyContext(ptr->u.shake256_ctx, PR_TRUE);
-+ ptr->u.shake256_ctx = NULL;
-+ break;
-+ }
-+ }
-+ return;
-+ }
-+ memset(ptr->buf2_space, 0, sizeof(ptr->buf2_space));
-+ memset(ptr->buf_space, 0, sizeof(ptr->buf_space));
-+ if (ptr->buf != ptr->buf_space) {
-+ memset(ptr->buf, 0, ptr->buf_size);
-+ free(ptr->buf);
-+ ptr->buf = NULL;
-+ }
-+ lc_hash_init(ptr);
-+}
-+#endif
-diff --git a/lib/freebl/leancrypto/lc_sha512.h b/lib/freebl/leancrypto/lc_sha512.h
-new file mode 100644
-diff --git a/lib/freebl/leancrypto/lc_status.h b/lib/freebl/leancrypto/lc_status.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/lc_status.h
-@@ -0,0 +1,55 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef LC_STATUS_H
-+#define LC_STATUS_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/**
-+ * @brief (Re-)run the self tests
-+ *
-+ * If the self tests were already executed for a given algorithm, they are
-+ * triggered again.
-+ */
-+void lc_rerun_selftests(void);
-+
-+/**
-+ * @brief Re-run the FIPS 140 integrity test
-+ *
-+ * \note This API is only present in the FIPS module instance of leancrypto.
-+ */
-+void lc_fips_integrity_checker(void);
-+
-+/**
-+ * @brief Status information about leancrypto
-+ *
-+ * @param [in] outbuf Buffer to be filled with status information, allocated by
-+ * caller
-+ * @param [in] outlen Size of the output buffer
-+ */
-+void lc_status(char *outbuf, size_t outlen);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* LC_STATUS_H */
-diff --git a/lib/freebl/leancrypto/leap_git_version.txt b/lib/freebl/leancrypto/leap_git_version.txt
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/leap_git_version.txt
-@@ -0,0 +1,1 @@
-+* master 70cabeec Poly1305: move function delcarations to internal header
-diff --git a/lib/freebl/leancrypto/left_encode.h b/lib/freebl/leancrypto/left_encode.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/left_encode.h
-@@ -0,0 +1,38 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef LEFT_ENCODE_H
-+#define LEFT_ENCODE_H
-+
-+#include "ext_headers.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/**
-+ * @brief - left_encode operation defined in SP800-185
-+ */
-+unsigned int lc_left_encode(uint8_t *buf, size_t val);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* LEFT_ENCODE_H */
-diff --git a/lib/freebl/leancrypto/math_helper.h b/lib/freebl/leancrypto/math_helper.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/math_helper.h
-@@ -0,0 +1,58 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef MATH_HELPER_H
-+#define MATH_HELPER_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#ifndef LINUX_KERNEL
-+
-+#define likely(x) __builtin_expect(!!(x), 1)
-+#define unlikely(x) __builtin_expect(!!(x), 0)
-+
-+#endif /* LINUX_KERNEL */
-+
-+static inline uint8_t min_uint8(uint8_t a, uint8_t b)
-+{
-+ return a < b ? a : b;
-+}
-+
-+static inline uint32_t min_uint32(uint32_t a, uint32_t b)
-+{
-+ return a < b ? a : b;
-+}
-+
-+static inline uint64_t min_uint64(uint64_t a, uint64_t b)
-+{
-+ return a < b ? a : b;
-+}
-+
-+static inline size_t min_size(size_t a, size_t b)
-+{
-+ return a < b ? a : b;
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* MATH_HELPER_H */
-diff --git a/lib/freebl/leancrypto/ml_dsa_44_debug.c b/lib/freebl/leancrypto/ml_dsa_44_debug.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_44_debug.c
-@@ -0,0 +1,92 @@
-+#define LC_DILITHIUM_TYPE_44 1
-+/*
-+ * Copyright (C) 2023 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#include "binhexbin.h"
-+
-+/* This code is only tuned to the C implementation */
-+#include "dilithium_type.h"
-+#include "dilithium_poly.h"
-+#include "dilithium_poly_common.h"
-+#include "dilithium_poly_c.h"
-+#include "dilithium_polyvec.h"
-+#include "dilithium_polyvec_c.h"
-+
-+#include "dilithium_debug.h"
-+
-+void dilithium_print_buffer(const uint8_t *buffer, const size_t bufferlen,
-+ const char *explanation)
-+{
-+ bin2print(buffer, bufferlen, stdout, explanation);
-+}
-+
-+void dilithium_print_polyvecl_k(polyvecl mat[LC_DILITHIUM_K],
-+ const char *explanation)
-+{
-+ unsigned int i, j, k;
-+
-+ printf("%s", explanation);
-+ for (i = 0; i < LC_DILITHIUM_K; i++) {
-+ for (j = 0; j < LC_DILITHIUM_L; j++) {
-+ printf("\nK(%u) x L(%u) x N: ", i, j);
-+ for (k = 0; k < LC_DILITHIUM_N; k++)
-+ printf("0x%.8x ", mat[i].vec[j].coeffs[k]);
-+ }
-+ }
-+ printf("\n");
-+}
-+
-+void dilithium_print_polyvecl(polyvecl *polyvec, const char *explanation)
-+{
-+ unsigned int i, j;
-+
-+ printf("%s", explanation);
-+ for (i = 0; i < LC_DILITHIUM_L; i++) {
-+ printf("\nL(%u) x N: ", i);
-+ for (j = 0; j < LC_DILITHIUM_N; j++) {
-+ printf("%d ", polyvec->vec[i].coeffs[j]);
-+ }
-+ }
-+ printf("\n");
-+}
-+
-+void dilithium_print_polyveck(polyveck *polyvec, const char *explanation)
-+{
-+ unsigned int i, j;
-+
-+ printf("%s", explanation);
-+ for (i = 0; i < LC_DILITHIUM_K; i++) {
-+ printf("\nK(%u) x N: ", i);
-+ for (j = 0; j < LC_DILITHIUM_N; j++) {
-+ printf("%d ", polyvec->vec[i].coeffs[j]);
-+ }
-+ }
-+ printf("\n");
-+}
-+
-+void dilithium_print_poly(poly *vec, const char *explanation)
-+{
-+ unsigned int i;
-+
-+ printf("%s", explanation);
-+ for (i = 0; i < LC_DILITHIUM_N; i++) {
-+ printf("%d ", vec->coeffs[i]);
-+ }
-+ printf("\n");
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_44_def_header.h b/lib/freebl/leancrypto/ml_dsa_44_def_header.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_44_def_header.h
-@@ -0,0 +1,1 @@
-+#define LC_DILITHIUM_TYPE_44 1
-diff --git a/lib/freebl/leancrypto/ml_dsa_44_ntt.c b/lib/freebl/leancrypto/ml_dsa_44_ntt.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_44_ntt.c
-@@ -0,0 +1,92 @@
-+#define LC_DILITHIUM_TYPE_44 1
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#include "dilithium_ntt.h"
-+#include "dilithium_reduce.h"
-+#include "dilithium_zetas.h"
-+
-+/**
-+ * @brief ntt - Forward NTT, in-place. No modular reduction is performed after
-+ * additions or subtractions. Output vector is in bitreversed
-+ * order.
-+ *
-+ * @param [in,out] p input/output coefficient array
-+ */
-+void ntt(int32_t a[LC_DILITHIUM_N])
-+{
-+ unsigned int len, start, j, k;
-+ int32_t zeta, t;
-+
-+ k = 0;
-+
-+ for (len = 128; len > 0; len >>= 1) {
-+ for (start = 0; start < LC_DILITHIUM_N; start = j + len) {
-+ zeta = dilithium_zetas[++k];
-+ for (j = start; j < start + len; ++j) {
-+ t = montgomery_reduce((int64_t)zeta *
-+ a[j + len]);
-+ a[j + len] = a[j] - t;
-+ a[j] = a[j] + t;
-+ }
-+ }
-+ }
-+}
-+
-+/**
-+ * @brief invntt_tomont - Inverse NTT and multiplication by Montgomery factor
-+ * 2^32. In-place. No modular reductions after additions
-+ * or subtractions; input coefficients need to be smaller
-+ * than Q in absolute value. Output coefficient are
-+ * smaller than Q in absolute value.
-+ *
-+ * @param [in,out] p input/output coefficient array
-+ */
-+void invntt_tomont(int32_t a[LC_DILITHIUM_N])
-+{
-+ unsigned int start, len, j, k;
-+ int32_t t, zeta;
-+ const int32_t f = 41978; // mont^2/256
-+
-+ k = 256;
-+
-+ for (len = 1; len < LC_DILITHIUM_N; len <<= 1) {
-+ for (start = 0; start < LC_DILITHIUM_N; start = j + len) {
-+ zeta = -dilithium_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] = montgomery_reduce((int64_t)zeta *
-+ a[j + len]);
-+ }
-+ }
-+ }
-+
-+ for (j = 0; j < LC_DILITHIUM_N; ++j)
-+ a[j] = montgomery_reduce((int64_t)f * a[j]);
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_44_poly.c b/lib/freebl/leancrypto/ml_dsa_44_poly.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_44_poly.c
-@@ -0,0 +1,595 @@
-+#define LC_DILITHIUM_TYPE_44 1
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#include "dilithium_poly.h"
-+#include "dilithium_poly_common.h"
-+#include "dilithium_service_helpers.h"
-+#include "lc_sha3.h"
-+#include "timecop.h"
-+
-+/**
-+ * @brief poly_chknorm - Check infinity norm of polynomial against given bound.
-+ * Assumes input coefficients were reduced by reduce32().
-+ *
-+ * @param [in] a pointer to polynomial
-+ * @param [in] B norm bound
-+ *
-+ * @return 0 if norm is strictly smaller than B <= (Q-1)/8 and 1 otherwise.
-+ */
-+int poly_chknorm(const poly *a, int32_t B)
-+{
-+ unsigned int i;
-+ int32_t t;
-+
-+ if (B > (LC_DILITHIUM_Q - 1) / 8)
-+ return 1;
-+
-+ /*
-+ * It is ok to leak which coefficient violates the bound since
-+ * the probability for each coefficient *is independent of secret
-+ * data but we must not leak the sign of the centralized representative.
-+ */
-+ for (i = 0; i < LC_DILITHIUM_N; ++i) {
-+ /* Absolute value */
-+ t = a->coeffs[i] >> 31;
-+ t = a->coeffs[i] - (t & 2 * a->coeffs[i]);
-+
-+ if (t >= B)
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * @brief poly_uniform - Sample polynomial with uniformly random coefficients
-+ * in [0,Q-1] by performing rejection sampling on the
-+ * output stream of SHAKE128(seed|nonce).
-+ *
-+ * @param [out] a pointer to output polynomial
-+ * @param [in] seed byte array with seed of length LC_DILITHIUM_SEEDBYTES
-+ * @param [in] nonce 2-byte nonce
-+ */
-+void poly_uniform(poly *a, const uint8_t seed[LC_DILITHIUM_SEEDBYTES],
-+ uint16_t nonce, void *ws_buf)
-+{
-+ unsigned int i, ctr, off;
-+ unsigned int buflen = POLY_UNIFORM_NBLOCKS * LC_SHAKE_128_SIZE_BLOCK;
-+ uint8_t *buf = ws_buf;
-+ LC_HASH_CTX_ON_STACK(hash_ctx, lc_shake128);
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, seed, LC_DILITHIUM_SEEDBYTES);
-+ lc_hash_update(hash_ctx, (uint8_t *)&nonce, sizeof(nonce));
-+ lc_hash_set_digestsize(hash_ctx, buflen);
-+ lc_hash_final(hash_ctx, buf);
-+
-+ lc_hash_set_digestsize(hash_ctx, LC_SHAKE_128_SIZE_BLOCK);
-+
-+ ctr = rej_uniform(a->coeffs, LC_DILITHIUM_N, buf, buflen);
-+
-+ while (ctr < LC_DILITHIUM_N) {
-+ off = buflen % 3;
-+ for (i = 0; i < off; ++i)
-+ buf[i] = buf[buflen - off + i];
-+
-+ lc_hash_final(hash_ctx, buf + off);
-+ buflen = LC_DILITHIUM_SEEDBYTES + off;
-+ ctr += rej_uniform(a->coeffs + ctr, LC_DILITHIUM_N - ctr, buf,
-+ buflen);
-+ }
-+
-+ lc_hash_zero(hash_ctx);
-+}
-+
-+/**
-+ * @brief poly_uniform_eta - Sample polynomial with uniformly random
-+ * coefficients in [-ETA,ETA] by performing rejection
-+ * sampling on the output stream from
-+ * SHAKE256(seed|nonce).
-+ *
-+ * @param [out] a pointer to output polynomial
-+ * @param [in] seed byte array with seed of length LC_DILITHIUM_CRHBYTES
-+ * @param [in] nonce 2-byte nonce
-+ */
-+void poly_uniform_eta(poly *a, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
-+ uint16_t nonce, void *ws_buf)
-+{
-+ unsigned int ctr;
-+ uint8_t *buf = ws_buf;
-+ LC_HASH_CTX_ON_STACK(hash_ctx, lc_shake256);
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, seed, LC_DILITHIUM_CRHBYTES);
-+ lc_hash_update(hash_ctx, (uint8_t *)&nonce, sizeof(nonce));
-+ lc_hash_set_digestsize(hash_ctx, POLY_UNIFORM_ETA_BYTES);
-+ lc_hash_final(hash_ctx, buf);
-+
-+ ctr = rej_eta(a->coeffs, LC_DILITHIUM_N, buf, POLY_UNIFORM_ETA_BYTES);
-+
-+ while (ctr < LC_DILITHIUM_N) {
-+ lc_hash_final(hash_ctx, buf);
-+
-+ ctr += rej_eta(a->coeffs + ctr, LC_DILITHIUM_N - ctr, buf,
-+ LC_SHAKE_256_SIZE_BLOCK);
-+ }
-+
-+ lc_hash_zero(hash_ctx);
-+}
-+
-+/**
-+ * @brief poly_uniform_gamma1 - Sample polynomial with uniformly random
-+ * coefficients in [-(GAMMA1 - 1), GAMMA1] by
-+ * unpacking output stream of
-+ * SHAKE256(seed|nonce).
-+ *
-+ * @param [out] a pointer to output polynomial
-+ * @param [in] seed: byte array with seed of length LC_DILITHIUM_CRHBYTES
-+ * @param nonce 16-bit nonce
-+ */
-+void poly_uniform_gamma1(poly *a, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
-+ uint16_t nonce, void *ws_buf)
-+{
-+ LC_HASH_CTX_ON_STACK(hash_ctx, lc_shake256);
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, seed, LC_DILITHIUM_CRHBYTES);
-+ lc_hash_update(hash_ctx, (uint8_t *)&nonce, sizeof(nonce));
-+ lc_hash_set_digestsize(hash_ctx, POLY_UNIFORM_GAMMA1_BYTES);
-+ lc_hash_final(hash_ctx, ws_buf);
-+ lc_hash_zero(hash_ctx);
-+
-+ polyz_unpack(a, ws_buf);
-+}
-+
-+/**
-+ * @brief poly_challenge - Implementation of H. Samples polynomial with TAU
-+ * nonzero coefficients in {-1,1} using the output
-+ * stream of SHAKE256(seed).
-+ *
-+ * @param [out] c pointer to output polynomial
-+ * @param [in] mu byte array containing seed of length LC_DILITHIUM_CTILDE_BYTES
-+ */
-+void poly_challenge(poly *c, const uint8_t seed[LC_DILITHIUM_CTILDE_BYTES],
-+ void *ws_buf)
-+{
-+ unsigned int i, b, pos;
-+ uint64_t signs;
-+ uint8_t *buf = ws_buf;
-+ LC_HASH_CTX_ON_STACK(hash_ctx, lc_shake256);
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, seed, LC_DILITHIUM_CTILDE_BYTES);
-+ lc_hash_set_digestsize(hash_ctx, POLY_CHALLENGE_BYTES);
-+ lc_hash_final(hash_ctx, buf);
-+
-+ signs = 0;
-+ for (i = 0; i < 8; ++i)
-+ signs |= (uint64_t)buf[i] << 8 * i;
-+ pos = 8;
-+
-+ for (i = 0; i < LC_DILITHIUM_N; ++i)
-+ c->coeffs[i] = 0;
-+
-+ for (i = LC_DILITHIUM_N - LC_DILITHIUM_TAU; i < LC_DILITHIUM_N; ++i) {
-+ do {
-+ if (pos >= LC_SHAKE_256_SIZE_BLOCK) {
-+ lc_hash_final(hash_ctx, buf);
-+ pos = 0;
-+ }
-+
-+ b = buf[pos++];
-+ } while (b > i);
-+
-+ c->coeffs[i] = c->coeffs[b];
-+ c->coeffs[b] = 1 - (int32_t)(2 * (signs & 1));
-+ signs >>= 1;
-+ }
-+
-+ lc_hash_zero(hash_ctx);
-+}
-+
-+/**
-+ * @brief polyeta_pack - Bit-pack polynomial with coefficients in [-ETA,ETA].
-+ *
-+ * @param [out] r pointer to output byte array with at least
-+ * LC_DILITHIUM_POLYETA_PACKEDBYTES bytes
-+ * @param [in] a pointer to input polynomial
-+ */
-+void polyeta_pack(uint8_t *r, const poly *a)
-+{
-+ unsigned int i;
-+ uint8_t t[8];
-+
-+#if LC_DILITHIUM_ETA == 2
-+ for (i = 0; i < LC_DILITHIUM_N / 8; ++i) {
-+ t[0] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 0]);
-+ t[1] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 1]);
-+ t[2] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 2]);
-+ t[3] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 3]);
-+ t[4] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 4]);
-+ t[5] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 5]);
-+ t[6] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 6]);
-+ t[7] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 7]);
-+
-+ r[3 * i + 0] =
-+ (uint8_t)((t[0] >> 0) | (t[1] << 3) | (t[2] << 6));
-+ r[3 * i + 1] = (uint8_t)((t[2] >> 2) | (t[3] << 1) |
-+ (t[4] << 4) | (t[5] << 7));
-+ r[3 * i + 2] =
-+ (uint8_t)((t[5] >> 1) | (t[6] << 2) | (t[7] << 5));
-+ }
-+#elif LC_DILITHIUM_ETA == 4
-+ for (i = 0; i < LC_DILITHIUM_N / 2; ++i) {
-+ t[0] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[2 * i + 0]);
-+ t[1] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[2 * i + 1]);
-+ r[i] = (uint8_t)(t[0] | (t[1] << 4));
-+ }
-+#else
-+#error "Undefined LC_DILITHIUM_ETA"
-+#endif
-+}
-+
-+/**
-+ * @brief polyeta_unpack - Unpack polynomial with coefficients in [-ETA,ETA].
-+ *
-+ * @param [out] r pointer to output polynomial
-+ * @param [in] a byte array with bit-packed polynomial
-+ */
-+void polyeta_unpack(poly *r, const uint8_t *a)
-+{
-+ unsigned int i;
-+
-+#if LC_DILITHIUM_ETA == 2
-+ for (i = 0; i < LC_DILITHIUM_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] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 0];
-+ r->coeffs[8 * i + 1] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 1];
-+ r->coeffs[8 * i + 2] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 2];
-+ r->coeffs[8 * i + 3] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 3];
-+ r->coeffs[8 * i + 4] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 4];
-+ r->coeffs[8 * i + 5] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 5];
-+ r->coeffs[8 * i + 6] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 6];
-+ r->coeffs[8 * i + 7] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 7];
-+ }
-+#elif LC_DILITHIUM_ETA == 4
-+ for (i = 0; i < LC_DILITHIUM_N / 2; ++i) {
-+ r->coeffs[2 * i + 0] = a[i] & 0x0F;
-+ r->coeffs[2 * i + 1] = a[i] >> 4;
-+ r->coeffs[2 * i + 0] = LC_DILITHIUM_ETA - r->coeffs[2 * i + 0];
-+ r->coeffs[2 * i + 1] = LC_DILITHIUM_ETA - r->coeffs[2 * i + 1];
-+ }
-+#else
-+#error "Undefined LC_DILITHIUM_ETA"
-+#endif
-+}
-+
-+/**
-+ * @brief polyt1_pack - Bit-pack polynomial t1 with coefficients fitting in 10
-+ * bits. Input coefficients are assumed to be standard
-+ * representatives.
-+ *
-+ * @param [out] r pointer to output byte array with at least
-+ * LC_DILITHIUM_POLYT1_PACKEDBYTES bytes
-+ * @param [in] a pointer to input polynomial
-+ */
-+void polyt1_pack(uint8_t *r, const poly *a)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N / 4; ++i) {
-+ r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0));
-+ r[5 * i + 1] = (uint8_t)((a->coeffs[4 * i + 0] >> 8) |
-+ (a->coeffs[4 * i + 1] << 2));
-+ r[5 * i + 2] = (uint8_t)((a->coeffs[4 * i + 1] >> 6) |
-+ (a->coeffs[4 * i + 2] << 4));
-+ r[5 * i + 3] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) |
-+ (a->coeffs[4 * i + 3] << 6));
-+ r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2));
-+ }
-+}
-+
-+/**
-+ * @brief polyt0_pack - Bit-pack polynomial t0 with coefficients in
-+ * ]-2^{D-1}, 2^{D-1}].
-+ *
-+ * @param [out] r pointer to output byte array with at least
-+ * LC_DILITHIUM_POLYT0_PACKEDBYTES bytes
-+ * @param [in] a pointer to input polynomial
-+ */
-+void polyt0_pack(uint8_t *r, const poly *a)
-+{
-+ unsigned int i;
-+ uint32_t t[8];
-+
-+ for (i = 0; i < LC_DILITHIUM_N / 8; ++i) {
-+ t[0] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 0]);
-+ t[1] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 1]);
-+ t[2] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 2]);
-+ t[3] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 3]);
-+ t[4] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 4]);
-+ t[5] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 5]);
-+ t[6] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 6]);
-+ t[7] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 7]);
-+
-+ r[13 * i + 0] = (uint8_t)(t[0]);
-+ r[13 * i + 1] = (uint8_t)(t[0] >> 8);
-+ r[13 * i + 1] |= (uint8_t)(t[1] << 5);
-+ r[13 * i + 2] = (uint8_t)(t[1] >> 3);
-+ r[13 * i + 3] = (uint8_t)(t[1] >> 11);
-+ r[13 * i + 3] |= (uint8_t)(t[2] << 2);
-+ r[13 * i + 4] = (uint8_t)(t[2] >> 6);
-+ r[13 * i + 4] |= (uint8_t)(t[3] << 7);
-+ r[13 * i + 5] = (uint8_t)(t[3] >> 1);
-+ r[13 * i + 6] = (uint8_t)(t[3] >> 9);
-+ r[13 * i + 6] |= (uint8_t)(t[4] << 4);
-+ r[13 * i + 7] = (uint8_t)(t[4] >> 4);
-+ r[13 * i + 8] = (uint8_t)(t[4] >> 12);
-+ r[13 * i + 8] |= (uint8_t)(t[5] << 1);
-+ r[13 * i + 9] = (uint8_t)(t[5] >> 7);
-+ r[13 * i + 9] |= (uint8_t)(t[6] << 6);
-+ r[13 * i + 10] = (uint8_t)(t[6] >> 2);
-+ r[13 * i + 11] = (uint8_t)(t[6] >> 10);
-+ r[13 * i + 11] |= (uint8_t)(t[7] << 3);
-+ r[13 * i + 12] = (uint8_t)(t[7] >> 5);
-+ }
-+
-+ lc_memset_secure(t, 0, sizeof(t));
-+}
-+
-+/**
-+ * @brief polyt0_unpack - Unpack polynomial t0 with coefficients in
-+ * ]-2^{D-1}, 2^{D-1}].
-+ *
-+ * @param [out] r pointer to output polynomial
-+ * @param [in] a byte array with bit-packed polynomial
-+ */
-+void polyt0_unpack(poly *r, const uint8_t *a)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N / 8; ++i) {
-+ r->coeffs[8 * i + 0] = a[13 * i + 0];
-+ r->coeffs[8 * i + 0] |= (int32_t)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] |= (int32_t)a[13 * i + 2] << 3;
-+ r->coeffs[8 * i + 1] |= (int32_t)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] |= (int32_t)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] |= (int32_t)a[13 * i + 5] << 1;
-+ r->coeffs[8 * i + 3] |= (int32_t)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] |= (int32_t)a[13 * i + 7] << 4;
-+ r->coeffs[8 * i + 4] |= (int32_t)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] |= (int32_t)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] |= (int32_t)a[13 * i + 10] << 2;
-+ r->coeffs[8 * i + 6] |= (int32_t)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] |= (int32_t)a[13 * i + 12] << 5;
-+ r->coeffs[8 * i + 7] &= 0x1FFF;
-+
-+ r->coeffs[8 * i + 0] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 0];
-+ r->coeffs[8 * i + 1] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 1];
-+ r->coeffs[8 * i + 2] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 2];
-+ r->coeffs[8 * i + 3] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 3];
-+ r->coeffs[8 * i + 4] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 4];
-+ r->coeffs[8 * i + 5] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 5];
-+ r->coeffs[8 * i + 6] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 6];
-+ r->coeffs[8 * i + 7] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 7];
-+ }
-+}
-+
-+/**
-+ * @param polyz_pack - Bit-pack polynomial with coefficients
-+ * in [-(GAMMA1 - 1), GAMMA1].
-+ *
-+ * @param [out] r pointer to output byte array with at least
-+ * LC_DILITHIUM_POLYZ_PACKEDBYTES bytes
-+ * @param [in] a pointer to input polynomial
-+ */
-+void polyz_pack(uint8_t *r, const poly *a)
-+{
-+ unsigned int i;
-+ uint32_t t[4];
-+
-+#if LC_DILITHIUM_GAMMA1 == (1 << 17)
-+ for (i = 0; i < LC_DILITHIUM_N / 4; ++i) {
-+ t[0] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[4 * i + 0]);
-+ t[1] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[4 * i + 1]);
-+ t[2] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[4 * i + 2]);
-+ t[3] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[4 * i + 3]);
-+
-+ r[9 * i + 0] = (uint8_t)(t[0]);
-+ r[9 * i + 1] = (uint8_t)(t[0] >> 8);
-+ r[9 * i + 2] = (uint8_t)(t[0] >> 16);
-+ r[9 * i + 2] |= (uint8_t)(t[1] << 2);
-+ r[9 * i + 3] = (uint8_t)(t[1] >> 6);
-+ r[9 * i + 4] = (uint8_t)(t[1] >> 14);
-+ r[9 * i + 4] |= (uint8_t)(t[2] << 4);
-+ r[9 * i + 5] = (uint8_t)(t[2] >> 4);
-+ r[9 * i + 6] = (uint8_t)(t[2] >> 12);
-+ r[9 * i + 6] |= (uint8_t)(t[3] << 6);
-+ r[9 * i + 7] = (uint8_t)(t[3] >> 2);
-+ r[9 * i + 8] = (uint8_t)(t[3] >> 10);
-+ }
-+#elif LC_DILITHIUM_GAMMA1 == (1 << 19)
-+ for (i = 0; i < LC_DILITHIUM_N / 2; ++i) {
-+ t[0] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[2 * i + 0]);
-+ t[1] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[2 * i + 1]);
-+
-+ r[5 * i + 0] = (uint8_t)(t[0]);
-+ r[5 * i + 1] = (uint8_t)(t[0] >> 8);
-+ r[5 * i + 2] = (uint8_t)(t[0] >> 16);
-+ r[5 * i + 2] |= (uint8_t)(t[1] << 4);
-+ r[5 * i + 3] = (uint8_t)(t[1] >> 4);
-+ r[5 * i + 4] = (uint8_t)(t[1] >> 12);
-+ }
-+#else
-+#error "Undefined Gamma"
-+#endif
-+
-+ lc_memset_secure(t, 0, sizeof(t));
-+}
-+
-+/**
-+ * @brief polyz_unpack - Unpack polynomial z with coefficients
-+ * in [-(GAMMA1 - 1), GAMMA1].
-+ *
-+ * @param [out] r pointer to output polynomial
-+ * @param [in] a byte array with bit-packed polynomial
-+ */
-+void polyz_unpack(poly *r, const uint8_t *a)
-+{
-+ unsigned int i;
-+
-+#if LC_DILITHIUM_GAMMA1 == (1 << 17)
-+ for (i = 0; i < LC_DILITHIUM_N / 4; ++i) {
-+ r->coeffs[4 * i + 0] = a[9 * i + 0];
-+ r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8;
-+ r->coeffs[4 * i + 0] |= (int32_t)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] |= (int32_t)a[9 * i + 3] << 6;
-+ r->coeffs[4 * i + 1] |= (int32_t)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] |= (int32_t)a[9 * i + 5] << 4;
-+ r->coeffs[4 * i + 2] |= (int32_t)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] |= (int32_t)a[9 * i + 7] << 2;
-+ r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10;
-+ r->coeffs[4 * i + 3] &= 0x3FFFF;
-+
-+ r->coeffs[4 * i + 0] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[4 * i + 0];
-+ r->coeffs[4 * i + 1] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[4 * i + 1];
-+ r->coeffs[4 * i + 2] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[4 * i + 2];
-+ r->coeffs[4 * i + 3] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[4 * i + 3];
-+ }
-+#elif LC_DILITHIUM_GAMMA1 == (1 << 19)
-+ for (i = 0; i < LC_DILITHIUM_N / 2; ++i) {
-+ r->coeffs[2 * i + 0] = a[5 * i + 0];
-+ r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8;
-+ r->coeffs[2 * i + 0] |= (int32_t)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] |= (int32_t)a[5 * i + 3] << 4;
-+ r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12;
-+ r->coeffs[2 * i + 1] &= 0xFFFFF;
-+
-+ r->coeffs[2 * i + 0] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[2 * i + 0];
-+ r->coeffs[2 * i + 1] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[2 * i + 1];
-+ }
-+#else
-+#error "Undefined Gamma"
-+#endif
-+}
-+
-+/**
-+ * @brief polyw1_pack - Bit-pack polynomial w1 with coefficients in [0,15] or
-+ * [0,43]. Input coefficients are assumed to be standard
-+ * representatives.
-+ *
-+ * @param [out] r pointer to output byte array with at least
-+ * LC_DILITHIUM_POLYW1_PACKEDBYTES bytes
-+ * @param [in] a pointer to input polynomial
-+ */
-+void polyw1_pack(uint8_t *r, const poly *a)
-+{
-+ unsigned int i;
-+
-+#if LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 88
-+ for (i = 0; i < LC_DILITHIUM_N / 4; ++i) {
-+ r[3 * i + 0] = (uint8_t)(a->coeffs[4 * i + 0]);
-+ r[3 * i + 0] |= (uint8_t)(a->coeffs[4 * i + 1] << 6);
-+ r[3 * i + 1] = (uint8_t)(a->coeffs[4 * i + 1] >> 2);
-+ r[3 * i + 1] |= (uint8_t)(a->coeffs[4 * i + 2] << 4);
-+ r[3 * i + 2] = (uint8_t)(a->coeffs[4 * i + 2] >> 4);
-+ r[3 * i + 2] |= (uint8_t)(a->coeffs[4 * i + 3] << 2);
-+ }
-+#elif LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 32
-+ for (i = 0; i < LC_DILITHIUM_N / 2; ++i)
-+ r[i] = (uint8_t)(a->coeffs[2 * i + 0] |
-+ (a->coeffs[2 * i + 1] << 4));
-+#else
-+#error "Undefined Gamma"
-+#endif
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_44_rounding.c b/lib/freebl/leancrypto/ml_dsa_44_rounding.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_44_rounding.c
-@@ -0,0 +1,130 @@
-+#define LC_DILITHIUM_TYPE_44 1
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#include "dilithium_rounding.h"
-+
-+/**
-+ * @brief power2round - For finite field element a, compute a0, a1 such that
-+ * a mod^+ Q = a1*2^D + a0 with -2^{D-1} < a0 <= 2^{D-1}.
-+ * Assumes a to be standard representative.
-+ *
-+ * @param [in] a input element
-+ * @param [out] a0 pointer to output element a0
-+ *
-+ * @return a1.
-+ */
-+int32_t power2round(int32_t *a0, int32_t a)
-+{
-+ int32_t a1;
-+
-+ a1 = (a + (1 << (LC_DILITHIUM_D - 1)) - 1) >> LC_DILITHIUM_D;
-+ *a0 = a - (a1 << LC_DILITHIUM_D);
-+ return a1;
-+}
-+
-+/**
-+ * @brief decompose - For finite field element a, compute high and low bits a0,
-+ * a1 such that a mod^+ Q = a1*ALPHA + a0 with
-+ * -ALPHA/2 < a0 <= ALPHA/2 except if a1 = (Q-1)/ALPHA where
-+ * we set a1 = 0 and -ALPHA/2 <= a0 = a mod^+ Q - Q < 0.
-+ * Assumes a to be standard representative.
-+ *
-+ * @param [in] a input element
-+ * @param [out] a0 pointer to output element a0
-+ *
-+ * @return a1.
-+ */
-+int32_t decompose(int32_t *a0, int32_t a)
-+{
-+ int32_t a1;
-+
-+ a1 = (a + 127) >> 7;
-+#if LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 32
-+ a1 = (a1 * 1025 + (1 << 21)) >> 22;
-+ a1 &= 15;
-+#elif LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 88
-+ a1 = (a1 * 11275 + (1 << 23)) >> 24;
-+ a1 ^= ((43 - a1) >> 31) & a1;
-+#else
-+#error "Uknown GAMMA2"
-+#endif
-+
-+ *a0 = a - a1 * 2 * LC_DILITHIUM_GAMMA2;
-+ *a0 -= (((LC_DILITHIUM_Q - 1) / 2 - *a0) >> 31) & LC_DILITHIUM_Q;
-+
-+ return a1;
-+}
-+
-+/**
-+ * @brief make_hint - Compute hint bit indicating whether the low bits of the
-+ * input element overflow into the high bits.
-+ *
-+ * @param a0 [in] low bits of input element
-+ * @param a1 [in] high bits of input element
-+ *
-+ * @return 1 if overflow.
-+ */
-+int32_t make_hint(int32_t a0, int32_t a1)
-+{
-+ if (a0 > LC_DILITHIUM_GAMMA2 || a0 < -LC_DILITHIUM_GAMMA2 ||
-+ (a0 == -LC_DILITHIUM_GAMMA2 && a1 != 0))
-+ return 1;
-+
-+ return 0;
-+}
-+
-+/**
-+ * @brief use_hint - Correct high bits according to hint.
-+ *
-+ * @param [in] a input element
-+ * @param [in] hint hint bit
-+ *
-+ * @return corrected high bits.
-+ */
-+int32_t use_hint(int32_t a, int32_t hint)
-+{
-+ int32_t a0, a1;
-+
-+ a1 = decompose(&a0, a);
-+ if (hint == 0)
-+ return a1;
-+
-+#if LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 32
-+ if (a0 > 0)
-+ return (a1 + 1) & 15;
-+ else
-+ return (a1 - 1) & 15;
-+#elif LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 88
-+ if (a0 > 0)
-+ return (a1 == 43) ? 0 : a1 + 1;
-+ else
-+ return (a1 == 0) ? 43 : a1 - 1;
-+#else
-+#error "Uknown GAMMA2"
-+#endif
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_44_signature_c.c b/lib/freebl/leancrypto/ml_dsa_44_signature_c.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_44_signature_c.c
-@@ -0,0 +1,131 @@
-+#define LC_DILITHIUM_TYPE_44 1
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#include "dilithium_signature_c.h"
-+#include "visibility.h"
-+
-+/* We need once the buffer size to handle the hashing */
-+#define LC_POLY_UNIFOR_BUF_SIZE_MULTIPLIER 1
-+
-+#include "dilithium_poly.h"
-+#include "dilithium_poly_common.h"
-+#include "dilithium_poly_c.h"
-+#include "dilithium_polyvec.h"
-+#include "dilithium_polyvec_c.h"
-+#include "dilithium_pack.h"
-+#include "dilithium_signature_impl.h"
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_keypair_from_seed_c,
-+ struct lc_dilithium_pk *pk, struct lc_dilithium_sk *sk,
-+ const uint8_t *seed, size_t seedlen)
-+{
-+ return lc_dilithium_keypair_from_seed_impl(pk, sk, seed, seedlen);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_keypair_c, struct lc_dilithium_pk *pk,
-+ struct lc_dilithium_sk *sk, struct lc_rng_ctx *rng_ctx)
-+{
-+ return lc_dilithium_keypair_impl(pk, sk, rng_ctx);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_c, struct lc_dilithium_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ return lc_dilithium_sign_impl(sig, m, mlen, sk, rng_ctx);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_ctx_c,
-+ struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ return lc_dilithium_sign_ctx_impl(sig, ctx, m, mlen, sk, rng_ctx);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_init_c,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_sk *sk)
-+{
-+ return lc_dilithium_sign_init_impl(ctx, sk);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_update_c,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen)
-+{
-+ return lc_dilithium_sign_update_impl(ctx, m, mlen);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_final_c,
-+ struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ return lc_dilithium_sign_final_impl(sig, ctx, sk, rng_ctx);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_c,
-+ const struct lc_dilithium_sig *sig, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_pk *pk)
-+{
-+ return lc_dilithium_verify_impl(sig, m, mlen, pk);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_ctx_c,
-+ const struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_pk *pk)
-+{
-+ return lc_dilithium_verify_ctx_impl(sig, ctx, m, mlen, pk);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_init_c,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_pk *pk)
-+{
-+ return lc_dilithium_verify_init_impl(ctx, pk);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_update_c,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen)
-+{
-+ return lc_dilithium_verify_update_impl(ctx, m, mlen);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_final_c,
-+ const struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_pk *pk)
-+{
-+ return lc_dilithium_verify_final_impl(sig, ctx, pk);
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_44_signature_helper.c b/lib/freebl/leancrypto/ml_dsa_44_signature_helper.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_44_signature_helper.c
-@@ -0,0 +1,103 @@
-+#define LC_DILITHIUM_TYPE_44 1
-+/*
-+ * Copyright (C) 2024 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#include "dilithium_type.h"
-+#include "visibility.h"
-+
-+#include "lc_sha3.h"
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ctx_alloc,
-+ struct lc_dilithium_ctx **ctx)
-+{
-+ struct lc_dilithium_ctx *out_ctx = NULL;
-+ int ret;
-+
-+ if (!ctx)
-+ return -EINVAL;
-+
-+ ret = lc_alloc_aligned((void **)&out_ctx, LC_HASH_COMMON_ALIGNMENT,
-+ LC_DILITHIUM_CTX_SIZE);
-+ if (ret)
-+ return -ret;
-+
-+ LC_DILITHIUM_SET_CTX(out_ctx);
-+
-+ *ctx = out_ctx;
-+
-+ return 0;
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ctx_alloc_ahat,
-+ struct lc_dilithium_ctx **ctx)
-+{
-+ struct lc_dilithium_ctx *out_ctx = NULL;
-+ int ret;
-+
-+ if (!ctx)
-+ return -EINVAL;
-+
-+#if LC_DILITHIUM_MODE == 2
-+ ret = lc_alloc_aligned((void **)&out_ctx, LC_HASH_COMMON_ALIGNMENT,
-+ LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_44_AHAT_PAD +
-+ LC_DILITHIUM_44_AHAT_SIZE);
-+ if (ret)
-+ return -ret;
-+ out_ctx->ahat = (uint8_t *)out_ctx + LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_44_AHAT_PAD;
-+ out_ctx->ahat_size = LC_DILITHIUM_44_AHAT_SIZE;
-+#elif LC_DILITHIUM_MODE == 3
-+ ret = lc_alloc_aligned((void **)&out_ctx, LC_HASH_COMMON_ALIGNMENT,
-+ LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_65_AHAT_PAD +
-+ LC_DILITHIUM_65_AHAT_SIZE);
-+ if (ret)
-+ return -ret;
-+ out_ctx->ahat = (uint8_t *)out_ctx + LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_65_AHAT_PAD;
-+ out_ctx->ahat_size = LC_DILITHIUM_65_AHAT_SIZE;
-+#elif LC_DILITHIUM_MODE == 5
-+ ret = lc_alloc_aligned((void **)&out_ctx, LC_HASH_COMMON_ALIGNMENT,
-+ LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_87_AHAT_PAD +
-+ LC_DILITHIUM_87_AHAT_SIZE);
-+ if (ret)
-+ return -ret;
-+ out_ctx->ahat = (uint8_t *)out_ctx + LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_87_AHAT_PAD;
-+ out_ctx->ahat_size = LC_DILITHIUM_87_AHAT_SIZE;
-+#endif
-+
-+ LC_SHAKE_256_CTX((&(out_ctx)->dilithium_hash_ctx));
-+
-+ *ctx = out_ctx;
-+
-+ return 0;
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ctx_zero_free,
-+ struct lc_dilithium_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+
-+ lc_dilithium_ctx_zero(ctx);
-+ lc_free(ctx);
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_65_debug.c b/lib/freebl/leancrypto/ml_dsa_65_debug.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_65_debug.c
-@@ -0,0 +1,92 @@
-+#define LC_DILITHIUM_TYPE_65 1
-+/*
-+ * Copyright (C) 2023 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#include "binhexbin.h"
-+
-+/* This code is only tuned to the C implementation */
-+#include "dilithium_type.h"
-+#include "dilithium_poly.h"
-+#include "dilithium_poly_common.h"
-+#include "dilithium_poly_c.h"
-+#include "dilithium_polyvec.h"
-+#include "dilithium_polyvec_c.h"
-+
-+#include "dilithium_debug.h"
-+
-+void dilithium_print_buffer(const uint8_t *buffer, const size_t bufferlen,
-+ const char *explanation)
-+{
-+ bin2print(buffer, bufferlen, stdout, explanation);
-+}
-+
-+void dilithium_print_polyvecl_k(polyvecl mat[LC_DILITHIUM_K],
-+ const char *explanation)
-+{
-+ unsigned int i, j, k;
-+
-+ printf("%s", explanation);
-+ for (i = 0; i < LC_DILITHIUM_K; i++) {
-+ for (j = 0; j < LC_DILITHIUM_L; j++) {
-+ printf("\nK(%u) x L(%u) x N: ", i, j);
-+ for (k = 0; k < LC_DILITHIUM_N; k++)
-+ printf("0x%.8x ", mat[i].vec[j].coeffs[k]);
-+ }
-+ }
-+ printf("\n");
-+}
-+
-+void dilithium_print_polyvecl(polyvecl *polyvec, const char *explanation)
-+{
-+ unsigned int i, j;
-+
-+ printf("%s", explanation);
-+ for (i = 0; i < LC_DILITHIUM_L; i++) {
-+ printf("\nL(%u) x N: ", i);
-+ for (j = 0; j < LC_DILITHIUM_N; j++) {
-+ printf("%d ", polyvec->vec[i].coeffs[j]);
-+ }
-+ }
-+ printf("\n");
-+}
-+
-+void dilithium_print_polyveck(polyveck *polyvec, const char *explanation)
-+{
-+ unsigned int i, j;
-+
-+ printf("%s", explanation);
-+ for (i = 0; i < LC_DILITHIUM_K; i++) {
-+ printf("\nK(%u) x N: ", i);
-+ for (j = 0; j < LC_DILITHIUM_N; j++) {
-+ printf("%d ", polyvec->vec[i].coeffs[j]);
-+ }
-+ }
-+ printf("\n");
-+}
-+
-+void dilithium_print_poly(poly *vec, const char *explanation)
-+{
-+ unsigned int i;
-+
-+ printf("%s", explanation);
-+ for (i = 0; i < LC_DILITHIUM_N; i++) {
-+ printf("%d ", vec->coeffs[i]);
-+ }
-+ printf("\n");
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_65_def_header.h b/lib/freebl/leancrypto/ml_dsa_65_def_header.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_65_def_header.h
-@@ -0,0 +1,1 @@
-+#define LC_DILITHIUM_TYPE_65 1
-diff --git a/lib/freebl/leancrypto/ml_dsa_65_ntt.c b/lib/freebl/leancrypto/ml_dsa_65_ntt.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_65_ntt.c
-@@ -0,0 +1,92 @@
-+#define LC_DILITHIUM_TYPE_65 1
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#include "dilithium_ntt.h"
-+#include "dilithium_reduce.h"
-+#include "dilithium_zetas.h"
-+
-+/**
-+ * @brief ntt - Forward NTT, in-place. No modular reduction is performed after
-+ * additions or subtractions. Output vector is in bitreversed
-+ * order.
-+ *
-+ * @param [in,out] p input/output coefficient array
-+ */
-+void ntt(int32_t a[LC_DILITHIUM_N])
-+{
-+ unsigned int len, start, j, k;
-+ int32_t zeta, t;
-+
-+ k = 0;
-+
-+ for (len = 128; len > 0; len >>= 1) {
-+ for (start = 0; start < LC_DILITHIUM_N; start = j + len) {
-+ zeta = dilithium_zetas[++k];
-+ for (j = start; j < start + len; ++j) {
-+ t = montgomery_reduce((int64_t)zeta *
-+ a[j + len]);
-+ a[j + len] = a[j] - t;
-+ a[j] = a[j] + t;
-+ }
-+ }
-+ }
-+}
-+
-+/**
-+ * @brief invntt_tomont - Inverse NTT and multiplication by Montgomery factor
-+ * 2^32. In-place. No modular reductions after additions
-+ * or subtractions; input coefficients need to be smaller
-+ * than Q in absolute value. Output coefficient are
-+ * smaller than Q in absolute value.
-+ *
-+ * @param [in,out] p input/output coefficient array
-+ */
-+void invntt_tomont(int32_t a[LC_DILITHIUM_N])
-+{
-+ unsigned int start, len, j, k;
-+ int32_t t, zeta;
-+ const int32_t f = 41978; // mont^2/256
-+
-+ k = 256;
-+
-+ for (len = 1; len < LC_DILITHIUM_N; len <<= 1) {
-+ for (start = 0; start < LC_DILITHIUM_N; start = j + len) {
-+ zeta = -dilithium_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] = montgomery_reduce((int64_t)zeta *
-+ a[j + len]);
-+ }
-+ }
-+ }
-+
-+ for (j = 0; j < LC_DILITHIUM_N; ++j)
-+ a[j] = montgomery_reduce((int64_t)f * a[j]);
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_65_poly.c b/lib/freebl/leancrypto/ml_dsa_65_poly.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_65_poly.c
-@@ -0,0 +1,595 @@
-+#define LC_DILITHIUM_TYPE_65 1
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#include "dilithium_poly.h"
-+#include "dilithium_poly_common.h"
-+#include "dilithium_service_helpers.h"
-+#include "lc_sha3.h"
-+#include "timecop.h"
-+
-+/**
-+ * @brief poly_chknorm - Check infinity norm of polynomial against given bound.
-+ * Assumes input coefficients were reduced by reduce32().
-+ *
-+ * @param [in] a pointer to polynomial
-+ * @param [in] B norm bound
-+ *
-+ * @return 0 if norm is strictly smaller than B <= (Q-1)/8 and 1 otherwise.
-+ */
-+int poly_chknorm(const poly *a, int32_t B)
-+{
-+ unsigned int i;
-+ int32_t t;
-+
-+ if (B > (LC_DILITHIUM_Q - 1) / 8)
-+ return 1;
-+
-+ /*
-+ * It is ok to leak which coefficient violates the bound since
-+ * the probability for each coefficient *is independent of secret
-+ * data but we must not leak the sign of the centralized representative.
-+ */
-+ for (i = 0; i < LC_DILITHIUM_N; ++i) {
-+ /* Absolute value */
-+ t = a->coeffs[i] >> 31;
-+ t = a->coeffs[i] - (t & 2 * a->coeffs[i]);
-+
-+ if (t >= B)
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * @brief poly_uniform - Sample polynomial with uniformly random coefficients
-+ * in [0,Q-1] by performing rejection sampling on the
-+ * output stream of SHAKE128(seed|nonce).
-+ *
-+ * @param [out] a pointer to output polynomial
-+ * @param [in] seed byte array with seed of length LC_DILITHIUM_SEEDBYTES
-+ * @param [in] nonce 2-byte nonce
-+ */
-+void poly_uniform(poly *a, const uint8_t seed[LC_DILITHIUM_SEEDBYTES],
-+ uint16_t nonce, void *ws_buf)
-+{
-+ unsigned int i, ctr, off;
-+ unsigned int buflen = POLY_UNIFORM_NBLOCKS * LC_SHAKE_128_SIZE_BLOCK;
-+ uint8_t *buf = ws_buf;
-+ LC_HASH_CTX_ON_STACK(hash_ctx, lc_shake128);
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, seed, LC_DILITHIUM_SEEDBYTES);
-+ lc_hash_update(hash_ctx, (uint8_t *)&nonce, sizeof(nonce));
-+ lc_hash_set_digestsize(hash_ctx, buflen);
-+ lc_hash_final(hash_ctx, buf);
-+
-+ lc_hash_set_digestsize(hash_ctx, LC_SHAKE_128_SIZE_BLOCK);
-+
-+ ctr = rej_uniform(a->coeffs, LC_DILITHIUM_N, buf, buflen);
-+
-+ while (ctr < LC_DILITHIUM_N) {
-+ off = buflen % 3;
-+ for (i = 0; i < off; ++i)
-+ buf[i] = buf[buflen - off + i];
-+
-+ lc_hash_final(hash_ctx, buf + off);
-+ buflen = LC_DILITHIUM_SEEDBYTES + off;
-+ ctr += rej_uniform(a->coeffs + ctr, LC_DILITHIUM_N - ctr, buf,
-+ buflen);
-+ }
-+
-+ lc_hash_zero(hash_ctx);
-+}
-+
-+/**
-+ * @brief poly_uniform_eta - Sample polynomial with uniformly random
-+ * coefficients in [-ETA,ETA] by performing rejection
-+ * sampling on the output stream from
-+ * SHAKE256(seed|nonce).
-+ *
-+ * @param [out] a pointer to output polynomial
-+ * @param [in] seed byte array with seed of length LC_DILITHIUM_CRHBYTES
-+ * @param [in] nonce 2-byte nonce
-+ */
-+void poly_uniform_eta(poly *a, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
-+ uint16_t nonce, void *ws_buf)
-+{
-+ unsigned int ctr;
-+ uint8_t *buf = ws_buf;
-+ LC_HASH_CTX_ON_STACK(hash_ctx, lc_shake256);
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, seed, LC_DILITHIUM_CRHBYTES);
-+ lc_hash_update(hash_ctx, (uint8_t *)&nonce, sizeof(nonce));
-+ lc_hash_set_digestsize(hash_ctx, POLY_UNIFORM_ETA_BYTES);
-+ lc_hash_final(hash_ctx, buf);
-+
-+ ctr = rej_eta(a->coeffs, LC_DILITHIUM_N, buf, POLY_UNIFORM_ETA_BYTES);
-+
-+ while (ctr < LC_DILITHIUM_N) {
-+ lc_hash_final(hash_ctx, buf);
-+
-+ ctr += rej_eta(a->coeffs + ctr, LC_DILITHIUM_N - ctr, buf,
-+ LC_SHAKE_256_SIZE_BLOCK);
-+ }
-+
-+ lc_hash_zero(hash_ctx);
-+}
-+
-+/**
-+ * @brief poly_uniform_gamma1 - Sample polynomial with uniformly random
-+ * coefficients in [-(GAMMA1 - 1), GAMMA1] by
-+ * unpacking output stream of
-+ * SHAKE256(seed|nonce).
-+ *
-+ * @param [out] a pointer to output polynomial
-+ * @param [in] seed: byte array with seed of length LC_DILITHIUM_CRHBYTES
-+ * @param nonce 16-bit nonce
-+ */
-+void poly_uniform_gamma1(poly *a, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
-+ uint16_t nonce, void *ws_buf)
-+{
-+ LC_HASH_CTX_ON_STACK(hash_ctx, lc_shake256);
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, seed, LC_DILITHIUM_CRHBYTES);
-+ lc_hash_update(hash_ctx, (uint8_t *)&nonce, sizeof(nonce));
-+ lc_hash_set_digestsize(hash_ctx, POLY_UNIFORM_GAMMA1_BYTES);
-+ lc_hash_final(hash_ctx, ws_buf);
-+ lc_hash_zero(hash_ctx);
-+
-+ polyz_unpack(a, ws_buf);
-+}
-+
-+/**
-+ * @brief poly_challenge - Implementation of H. Samples polynomial with TAU
-+ * nonzero coefficients in {-1,1} using the output
-+ * stream of SHAKE256(seed).
-+ *
-+ * @param [out] c pointer to output polynomial
-+ * @param [in] mu byte array containing seed of length LC_DILITHIUM_CTILDE_BYTES
-+ */
-+void poly_challenge(poly *c, const uint8_t seed[LC_DILITHIUM_CTILDE_BYTES],
-+ void *ws_buf)
-+{
-+ unsigned int i, b, pos;
-+ uint64_t signs;
-+ uint8_t *buf = ws_buf;
-+ LC_HASH_CTX_ON_STACK(hash_ctx, lc_shake256);
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, seed, LC_DILITHIUM_CTILDE_BYTES);
-+ lc_hash_set_digestsize(hash_ctx, POLY_CHALLENGE_BYTES);
-+ lc_hash_final(hash_ctx, buf);
-+
-+ signs = 0;
-+ for (i = 0; i < 8; ++i)
-+ signs |= (uint64_t)buf[i] << 8 * i;
-+ pos = 8;
-+
-+ for (i = 0; i < LC_DILITHIUM_N; ++i)
-+ c->coeffs[i] = 0;
-+
-+ for (i = LC_DILITHIUM_N - LC_DILITHIUM_TAU; i < LC_DILITHIUM_N; ++i) {
-+ do {
-+ if (pos >= LC_SHAKE_256_SIZE_BLOCK) {
-+ lc_hash_final(hash_ctx, buf);
-+ pos = 0;
-+ }
-+
-+ b = buf[pos++];
-+ } while (b > i);
-+
-+ c->coeffs[i] = c->coeffs[b];
-+ c->coeffs[b] = 1 - (int32_t)(2 * (signs & 1));
-+ signs >>= 1;
-+ }
-+
-+ lc_hash_zero(hash_ctx);
-+}
-+
-+/**
-+ * @brief polyeta_pack - Bit-pack polynomial with coefficients in [-ETA,ETA].
-+ *
-+ * @param [out] r pointer to output byte array with at least
-+ * LC_DILITHIUM_POLYETA_PACKEDBYTES bytes
-+ * @param [in] a pointer to input polynomial
-+ */
-+void polyeta_pack(uint8_t *r, const poly *a)
-+{
-+ unsigned int i;
-+ uint8_t t[8];
-+
-+#if LC_DILITHIUM_ETA == 2
-+ for (i = 0; i < LC_DILITHIUM_N / 8; ++i) {
-+ t[0] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 0]);
-+ t[1] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 1]);
-+ t[2] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 2]);
-+ t[3] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 3]);
-+ t[4] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 4]);
-+ t[5] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 5]);
-+ t[6] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 6]);
-+ t[7] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 7]);
-+
-+ r[3 * i + 0] =
-+ (uint8_t)((t[0] >> 0) | (t[1] << 3) | (t[2] << 6));
-+ r[3 * i + 1] = (uint8_t)((t[2] >> 2) | (t[3] << 1) |
-+ (t[4] << 4) | (t[5] << 7));
-+ r[3 * i + 2] =
-+ (uint8_t)((t[5] >> 1) | (t[6] << 2) | (t[7] << 5));
-+ }
-+#elif LC_DILITHIUM_ETA == 4
-+ for (i = 0; i < LC_DILITHIUM_N / 2; ++i) {
-+ t[0] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[2 * i + 0]);
-+ t[1] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[2 * i + 1]);
-+ r[i] = (uint8_t)(t[0] | (t[1] << 4));
-+ }
-+#else
-+#error "Undefined LC_DILITHIUM_ETA"
-+#endif
-+}
-+
-+/**
-+ * @brief polyeta_unpack - Unpack polynomial with coefficients in [-ETA,ETA].
-+ *
-+ * @param [out] r pointer to output polynomial
-+ * @param [in] a byte array with bit-packed polynomial
-+ */
-+void polyeta_unpack(poly *r, const uint8_t *a)
-+{
-+ unsigned int i;
-+
-+#if LC_DILITHIUM_ETA == 2
-+ for (i = 0; i < LC_DILITHIUM_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] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 0];
-+ r->coeffs[8 * i + 1] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 1];
-+ r->coeffs[8 * i + 2] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 2];
-+ r->coeffs[8 * i + 3] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 3];
-+ r->coeffs[8 * i + 4] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 4];
-+ r->coeffs[8 * i + 5] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 5];
-+ r->coeffs[8 * i + 6] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 6];
-+ r->coeffs[8 * i + 7] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 7];
-+ }
-+#elif LC_DILITHIUM_ETA == 4
-+ for (i = 0; i < LC_DILITHIUM_N / 2; ++i) {
-+ r->coeffs[2 * i + 0] = a[i] & 0x0F;
-+ r->coeffs[2 * i + 1] = a[i] >> 4;
-+ r->coeffs[2 * i + 0] = LC_DILITHIUM_ETA - r->coeffs[2 * i + 0];
-+ r->coeffs[2 * i + 1] = LC_DILITHIUM_ETA - r->coeffs[2 * i + 1];
-+ }
-+#else
-+#error "Undefined LC_DILITHIUM_ETA"
-+#endif
-+}
-+
-+/**
-+ * @brief polyt1_pack - Bit-pack polynomial t1 with coefficients fitting in 10
-+ * bits. Input coefficients are assumed to be standard
-+ * representatives.
-+ *
-+ * @param [out] r pointer to output byte array with at least
-+ * LC_DILITHIUM_POLYT1_PACKEDBYTES bytes
-+ * @param [in] a pointer to input polynomial
-+ */
-+void polyt1_pack(uint8_t *r, const poly *a)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N / 4; ++i) {
-+ r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0));
-+ r[5 * i + 1] = (uint8_t)((a->coeffs[4 * i + 0] >> 8) |
-+ (a->coeffs[4 * i + 1] << 2));
-+ r[5 * i + 2] = (uint8_t)((a->coeffs[4 * i + 1] >> 6) |
-+ (a->coeffs[4 * i + 2] << 4));
-+ r[5 * i + 3] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) |
-+ (a->coeffs[4 * i + 3] << 6));
-+ r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2));
-+ }
-+}
-+
-+/**
-+ * @brief polyt0_pack - Bit-pack polynomial t0 with coefficients in
-+ * ]-2^{D-1}, 2^{D-1}].
-+ *
-+ * @param [out] r pointer to output byte array with at least
-+ * LC_DILITHIUM_POLYT0_PACKEDBYTES bytes
-+ * @param [in] a pointer to input polynomial
-+ */
-+void polyt0_pack(uint8_t *r, const poly *a)
-+{
-+ unsigned int i;
-+ uint32_t t[8];
-+
-+ for (i = 0; i < LC_DILITHIUM_N / 8; ++i) {
-+ t[0] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 0]);
-+ t[1] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 1]);
-+ t[2] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 2]);
-+ t[3] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 3]);
-+ t[4] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 4]);
-+ t[5] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 5]);
-+ t[6] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 6]);
-+ t[7] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 7]);
-+
-+ r[13 * i + 0] = (uint8_t)(t[0]);
-+ r[13 * i + 1] = (uint8_t)(t[0] >> 8);
-+ r[13 * i + 1] |= (uint8_t)(t[1] << 5);
-+ r[13 * i + 2] = (uint8_t)(t[1] >> 3);
-+ r[13 * i + 3] = (uint8_t)(t[1] >> 11);
-+ r[13 * i + 3] |= (uint8_t)(t[2] << 2);
-+ r[13 * i + 4] = (uint8_t)(t[2] >> 6);
-+ r[13 * i + 4] |= (uint8_t)(t[3] << 7);
-+ r[13 * i + 5] = (uint8_t)(t[3] >> 1);
-+ r[13 * i + 6] = (uint8_t)(t[3] >> 9);
-+ r[13 * i + 6] |= (uint8_t)(t[4] << 4);
-+ r[13 * i + 7] = (uint8_t)(t[4] >> 4);
-+ r[13 * i + 8] = (uint8_t)(t[4] >> 12);
-+ r[13 * i + 8] |= (uint8_t)(t[5] << 1);
-+ r[13 * i + 9] = (uint8_t)(t[5] >> 7);
-+ r[13 * i + 9] |= (uint8_t)(t[6] << 6);
-+ r[13 * i + 10] = (uint8_t)(t[6] >> 2);
-+ r[13 * i + 11] = (uint8_t)(t[6] >> 10);
-+ r[13 * i + 11] |= (uint8_t)(t[7] << 3);
-+ r[13 * i + 12] = (uint8_t)(t[7] >> 5);
-+ }
-+
-+ lc_memset_secure(t, 0, sizeof(t));
-+}
-+
-+/**
-+ * @brief polyt0_unpack - Unpack polynomial t0 with coefficients in
-+ * ]-2^{D-1}, 2^{D-1}].
-+ *
-+ * @param [out] r pointer to output polynomial
-+ * @param [in] a byte array with bit-packed polynomial
-+ */
-+void polyt0_unpack(poly *r, const uint8_t *a)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N / 8; ++i) {
-+ r->coeffs[8 * i + 0] = a[13 * i + 0];
-+ r->coeffs[8 * i + 0] |= (int32_t)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] |= (int32_t)a[13 * i + 2] << 3;
-+ r->coeffs[8 * i + 1] |= (int32_t)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] |= (int32_t)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] |= (int32_t)a[13 * i + 5] << 1;
-+ r->coeffs[8 * i + 3] |= (int32_t)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] |= (int32_t)a[13 * i + 7] << 4;
-+ r->coeffs[8 * i + 4] |= (int32_t)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] |= (int32_t)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] |= (int32_t)a[13 * i + 10] << 2;
-+ r->coeffs[8 * i + 6] |= (int32_t)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] |= (int32_t)a[13 * i + 12] << 5;
-+ r->coeffs[8 * i + 7] &= 0x1FFF;
-+
-+ r->coeffs[8 * i + 0] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 0];
-+ r->coeffs[8 * i + 1] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 1];
-+ r->coeffs[8 * i + 2] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 2];
-+ r->coeffs[8 * i + 3] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 3];
-+ r->coeffs[8 * i + 4] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 4];
-+ r->coeffs[8 * i + 5] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 5];
-+ r->coeffs[8 * i + 6] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 6];
-+ r->coeffs[8 * i + 7] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 7];
-+ }
-+}
-+
-+/**
-+ * @param polyz_pack - Bit-pack polynomial with coefficients
-+ * in [-(GAMMA1 - 1), GAMMA1].
-+ *
-+ * @param [out] r pointer to output byte array with at least
-+ * LC_DILITHIUM_POLYZ_PACKEDBYTES bytes
-+ * @param [in] a pointer to input polynomial
-+ */
-+void polyz_pack(uint8_t *r, const poly *a)
-+{
-+ unsigned int i;
-+ uint32_t t[4];
-+
-+#if LC_DILITHIUM_GAMMA1 == (1 << 17)
-+ for (i = 0; i < LC_DILITHIUM_N / 4; ++i) {
-+ t[0] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[4 * i + 0]);
-+ t[1] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[4 * i + 1]);
-+ t[2] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[4 * i + 2]);
-+ t[3] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[4 * i + 3]);
-+
-+ r[9 * i + 0] = (uint8_t)(t[0]);
-+ r[9 * i + 1] = (uint8_t)(t[0] >> 8);
-+ r[9 * i + 2] = (uint8_t)(t[0] >> 16);
-+ r[9 * i + 2] |= (uint8_t)(t[1] << 2);
-+ r[9 * i + 3] = (uint8_t)(t[1] >> 6);
-+ r[9 * i + 4] = (uint8_t)(t[1] >> 14);
-+ r[9 * i + 4] |= (uint8_t)(t[2] << 4);
-+ r[9 * i + 5] = (uint8_t)(t[2] >> 4);
-+ r[9 * i + 6] = (uint8_t)(t[2] >> 12);
-+ r[9 * i + 6] |= (uint8_t)(t[3] << 6);
-+ r[9 * i + 7] = (uint8_t)(t[3] >> 2);
-+ r[9 * i + 8] = (uint8_t)(t[3] >> 10);
-+ }
-+#elif LC_DILITHIUM_GAMMA1 == (1 << 19)
-+ for (i = 0; i < LC_DILITHIUM_N / 2; ++i) {
-+ t[0] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[2 * i + 0]);
-+ t[1] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[2 * i + 1]);
-+
-+ r[5 * i + 0] = (uint8_t)(t[0]);
-+ r[5 * i + 1] = (uint8_t)(t[0] >> 8);
-+ r[5 * i + 2] = (uint8_t)(t[0] >> 16);
-+ r[5 * i + 2] |= (uint8_t)(t[1] << 4);
-+ r[5 * i + 3] = (uint8_t)(t[1] >> 4);
-+ r[5 * i + 4] = (uint8_t)(t[1] >> 12);
-+ }
-+#else
-+#error "Undefined Gamma"
-+#endif
-+
-+ lc_memset_secure(t, 0, sizeof(t));
-+}
-+
-+/**
-+ * @brief polyz_unpack - Unpack polynomial z with coefficients
-+ * in [-(GAMMA1 - 1), GAMMA1].
-+ *
-+ * @param [out] r pointer to output polynomial
-+ * @param [in] a byte array with bit-packed polynomial
-+ */
-+void polyz_unpack(poly *r, const uint8_t *a)
-+{
-+ unsigned int i;
-+
-+#if LC_DILITHIUM_GAMMA1 == (1 << 17)
-+ for (i = 0; i < LC_DILITHIUM_N / 4; ++i) {
-+ r->coeffs[4 * i + 0] = a[9 * i + 0];
-+ r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8;
-+ r->coeffs[4 * i + 0] |= (int32_t)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] |= (int32_t)a[9 * i + 3] << 6;
-+ r->coeffs[4 * i + 1] |= (int32_t)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] |= (int32_t)a[9 * i + 5] << 4;
-+ r->coeffs[4 * i + 2] |= (int32_t)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] |= (int32_t)a[9 * i + 7] << 2;
-+ r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10;
-+ r->coeffs[4 * i + 3] &= 0x3FFFF;
-+
-+ r->coeffs[4 * i + 0] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[4 * i + 0];
-+ r->coeffs[4 * i + 1] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[4 * i + 1];
-+ r->coeffs[4 * i + 2] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[4 * i + 2];
-+ r->coeffs[4 * i + 3] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[4 * i + 3];
-+ }
-+#elif LC_DILITHIUM_GAMMA1 == (1 << 19)
-+ for (i = 0; i < LC_DILITHIUM_N / 2; ++i) {
-+ r->coeffs[2 * i + 0] = a[5 * i + 0];
-+ r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8;
-+ r->coeffs[2 * i + 0] |= (int32_t)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] |= (int32_t)a[5 * i + 3] << 4;
-+ r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12;
-+ r->coeffs[2 * i + 1] &= 0xFFFFF;
-+
-+ r->coeffs[2 * i + 0] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[2 * i + 0];
-+ r->coeffs[2 * i + 1] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[2 * i + 1];
-+ }
-+#else
-+#error "Undefined Gamma"
-+#endif
-+}
-+
-+/**
-+ * @brief polyw1_pack - Bit-pack polynomial w1 with coefficients in [0,15] or
-+ * [0,43]. Input coefficients are assumed to be standard
-+ * representatives.
-+ *
-+ * @param [out] r pointer to output byte array with at least
-+ * LC_DILITHIUM_POLYW1_PACKEDBYTES bytes
-+ * @param [in] a pointer to input polynomial
-+ */
-+void polyw1_pack(uint8_t *r, const poly *a)
-+{
-+ unsigned int i;
-+
-+#if LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 88
-+ for (i = 0; i < LC_DILITHIUM_N / 4; ++i) {
-+ r[3 * i + 0] = (uint8_t)(a->coeffs[4 * i + 0]);
-+ r[3 * i + 0] |= (uint8_t)(a->coeffs[4 * i + 1] << 6);
-+ r[3 * i + 1] = (uint8_t)(a->coeffs[4 * i + 1] >> 2);
-+ r[3 * i + 1] |= (uint8_t)(a->coeffs[4 * i + 2] << 4);
-+ r[3 * i + 2] = (uint8_t)(a->coeffs[4 * i + 2] >> 4);
-+ r[3 * i + 2] |= (uint8_t)(a->coeffs[4 * i + 3] << 2);
-+ }
-+#elif LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 32
-+ for (i = 0; i < LC_DILITHIUM_N / 2; ++i)
-+ r[i] = (uint8_t)(a->coeffs[2 * i + 0] |
-+ (a->coeffs[2 * i + 1] << 4));
-+#else
-+#error "Undefined Gamma"
-+#endif
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_65_rounding.c b/lib/freebl/leancrypto/ml_dsa_65_rounding.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_65_rounding.c
-@@ -0,0 +1,130 @@
-+#define LC_DILITHIUM_TYPE_65 1
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#include "dilithium_rounding.h"
-+
-+/**
-+ * @brief power2round - For finite field element a, compute a0, a1 such that
-+ * a mod^+ Q = a1*2^D + a0 with -2^{D-1} < a0 <= 2^{D-1}.
-+ * Assumes a to be standard representative.
-+ *
-+ * @param [in] a input element
-+ * @param [out] a0 pointer to output element a0
-+ *
-+ * @return a1.
-+ */
-+int32_t power2round(int32_t *a0, int32_t a)
-+{
-+ int32_t a1;
-+
-+ a1 = (a + (1 << (LC_DILITHIUM_D - 1)) - 1) >> LC_DILITHIUM_D;
-+ *a0 = a - (a1 << LC_DILITHIUM_D);
-+ return a1;
-+}
-+
-+/**
-+ * @brief decompose - For finite field element a, compute high and low bits a0,
-+ * a1 such that a mod^+ Q = a1*ALPHA + a0 with
-+ * -ALPHA/2 < a0 <= ALPHA/2 except if a1 = (Q-1)/ALPHA where
-+ * we set a1 = 0 and -ALPHA/2 <= a0 = a mod^+ Q - Q < 0.
-+ * Assumes a to be standard representative.
-+ *
-+ * @param [in] a input element
-+ * @param [out] a0 pointer to output element a0
-+ *
-+ * @return a1.
-+ */
-+int32_t decompose(int32_t *a0, int32_t a)
-+{
-+ int32_t a1;
-+
-+ a1 = (a + 127) >> 7;
-+#if LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 32
-+ a1 = (a1 * 1025 + (1 << 21)) >> 22;
-+ a1 &= 15;
-+#elif LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 88
-+ a1 = (a1 * 11275 + (1 << 23)) >> 24;
-+ a1 ^= ((43 - a1) >> 31) & a1;
-+#else
-+#error "Uknown GAMMA2"
-+#endif
-+
-+ *a0 = a - a1 * 2 * LC_DILITHIUM_GAMMA2;
-+ *a0 -= (((LC_DILITHIUM_Q - 1) / 2 - *a0) >> 31) & LC_DILITHIUM_Q;
-+
-+ return a1;
-+}
-+
-+/**
-+ * @brief make_hint - Compute hint bit indicating whether the low bits of the
-+ * input element overflow into the high bits.
-+ *
-+ * @param a0 [in] low bits of input element
-+ * @param a1 [in] high bits of input element
-+ *
-+ * @return 1 if overflow.
-+ */
-+int32_t make_hint(int32_t a0, int32_t a1)
-+{
-+ if (a0 > LC_DILITHIUM_GAMMA2 || a0 < -LC_DILITHIUM_GAMMA2 ||
-+ (a0 == -LC_DILITHIUM_GAMMA2 && a1 != 0))
-+ return 1;
-+
-+ return 0;
-+}
-+
-+/**
-+ * @brief use_hint - Correct high bits according to hint.
-+ *
-+ * @param [in] a input element
-+ * @param [in] hint hint bit
-+ *
-+ * @return corrected high bits.
-+ */
-+int32_t use_hint(int32_t a, int32_t hint)
-+{
-+ int32_t a0, a1;
-+
-+ a1 = decompose(&a0, a);
-+ if (hint == 0)
-+ return a1;
-+
-+#if LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 32
-+ if (a0 > 0)
-+ return (a1 + 1) & 15;
-+ else
-+ return (a1 - 1) & 15;
-+#elif LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 88
-+ if (a0 > 0)
-+ return (a1 == 43) ? 0 : a1 + 1;
-+ else
-+ return (a1 == 0) ? 43 : a1 - 1;
-+#else
-+#error "Uknown GAMMA2"
-+#endif
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_65_signature_c.c b/lib/freebl/leancrypto/ml_dsa_65_signature_c.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_65_signature_c.c
-@@ -0,0 +1,131 @@
-+#define LC_DILITHIUM_TYPE_65 1
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#include "dilithium_signature_c.h"
-+#include "visibility.h"
-+
-+/* We need once the buffer size to handle the hashing */
-+#define LC_POLY_UNIFOR_BUF_SIZE_MULTIPLIER 1
-+
-+#include "dilithium_poly.h"
-+#include "dilithium_poly_common.h"
-+#include "dilithium_poly_c.h"
-+#include "dilithium_polyvec.h"
-+#include "dilithium_polyvec_c.h"
-+#include "dilithium_pack.h"
-+#include "dilithium_signature_impl.h"
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_keypair_from_seed_c,
-+ struct lc_dilithium_pk *pk, struct lc_dilithium_sk *sk,
-+ const uint8_t *seed, size_t seedlen)
-+{
-+ return lc_dilithium_keypair_from_seed_impl(pk, sk, seed, seedlen);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_keypair_c, struct lc_dilithium_pk *pk,
-+ struct lc_dilithium_sk *sk, struct lc_rng_ctx *rng_ctx)
-+{
-+ return lc_dilithium_keypair_impl(pk, sk, rng_ctx);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_c, struct lc_dilithium_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ return lc_dilithium_sign_impl(sig, m, mlen, sk, rng_ctx);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_ctx_c,
-+ struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ return lc_dilithium_sign_ctx_impl(sig, ctx, m, mlen, sk, rng_ctx);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_init_c,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_sk *sk)
-+{
-+ return lc_dilithium_sign_init_impl(ctx, sk);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_update_c,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen)
-+{
-+ return lc_dilithium_sign_update_impl(ctx, m, mlen);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_final_c,
-+ struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ return lc_dilithium_sign_final_impl(sig, ctx, sk, rng_ctx);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_c,
-+ const struct lc_dilithium_sig *sig, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_pk *pk)
-+{
-+ return lc_dilithium_verify_impl(sig, m, mlen, pk);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_ctx_c,
-+ const struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_pk *pk)
-+{
-+ return lc_dilithium_verify_ctx_impl(sig, ctx, m, mlen, pk);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_init_c,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_pk *pk)
-+{
-+ return lc_dilithium_verify_init_impl(ctx, pk);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_update_c,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen)
-+{
-+ return lc_dilithium_verify_update_impl(ctx, m, mlen);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_final_c,
-+ const struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_pk *pk)
-+{
-+ return lc_dilithium_verify_final_impl(sig, ctx, pk);
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_65_signature_helper.c b/lib/freebl/leancrypto/ml_dsa_65_signature_helper.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_65_signature_helper.c
-@@ -0,0 +1,103 @@
-+#define LC_DILITHIUM_TYPE_65 1
-+/*
-+ * Copyright (C) 2024 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#include "dilithium_type.h"
-+#include "visibility.h"
-+
-+#include "lc_sha3.h"
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ctx_alloc,
-+ struct lc_dilithium_ctx **ctx)
-+{
-+ struct lc_dilithium_ctx *out_ctx = NULL;
-+ int ret;
-+
-+ if (!ctx)
-+ return -EINVAL;
-+
-+ ret = lc_alloc_aligned((void **)&out_ctx, LC_HASH_COMMON_ALIGNMENT,
-+ LC_DILITHIUM_CTX_SIZE);
-+ if (ret)
-+ return -ret;
-+
-+ LC_DILITHIUM_SET_CTX(out_ctx);
-+
-+ *ctx = out_ctx;
-+
-+ return 0;
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ctx_alloc_ahat,
-+ struct lc_dilithium_ctx **ctx)
-+{
-+ struct lc_dilithium_ctx *out_ctx = NULL;
-+ int ret;
-+
-+ if (!ctx)
-+ return -EINVAL;
-+
-+#if LC_DILITHIUM_MODE == 2
-+ ret = lc_alloc_aligned((void **)&out_ctx, LC_HASH_COMMON_ALIGNMENT,
-+ LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_44_AHAT_PAD +
-+ LC_DILITHIUM_44_AHAT_SIZE);
-+ if (ret)
-+ return -ret;
-+ out_ctx->ahat = (uint8_t *)out_ctx + LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_44_AHAT_PAD;
-+ out_ctx->ahat_size = LC_DILITHIUM_44_AHAT_SIZE;
-+#elif LC_DILITHIUM_MODE == 3
-+ ret = lc_alloc_aligned((void **)&out_ctx, LC_HASH_COMMON_ALIGNMENT,
-+ LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_65_AHAT_PAD +
-+ LC_DILITHIUM_65_AHAT_SIZE);
-+ if (ret)
-+ return -ret;
-+ out_ctx->ahat = (uint8_t *)out_ctx + LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_65_AHAT_PAD;
-+ out_ctx->ahat_size = LC_DILITHIUM_65_AHAT_SIZE;
-+#elif LC_DILITHIUM_MODE == 5
-+ ret = lc_alloc_aligned((void **)&out_ctx, LC_HASH_COMMON_ALIGNMENT,
-+ LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_87_AHAT_PAD +
-+ LC_DILITHIUM_87_AHAT_SIZE);
-+ if (ret)
-+ return -ret;
-+ out_ctx->ahat = (uint8_t *)out_ctx + LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_87_AHAT_PAD;
-+ out_ctx->ahat_size = LC_DILITHIUM_87_AHAT_SIZE;
-+#endif
-+
-+ LC_SHAKE_256_CTX((&(out_ctx)->dilithium_hash_ctx));
-+
-+ *ctx = out_ctx;
-+
-+ return 0;
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ctx_zero_free,
-+ struct lc_dilithium_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+
-+ lc_dilithium_ctx_zero(ctx);
-+ lc_free(ctx);
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_87_debug.c b/lib/freebl/leancrypto/ml_dsa_87_debug.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_87_debug.c
-@@ -0,0 +1,92 @@
-+#define LC_DILITHIUM_TYPE_87 1
-+/*
-+ * Copyright (C) 2023 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#include "binhexbin.h"
-+
-+/* This code is only tuned to the C implementation */
-+#include "dilithium_type.h"
-+#include "dilithium_poly.h"
-+#include "dilithium_poly_common.h"
-+#include "dilithium_poly_c.h"
-+#include "dilithium_polyvec.h"
-+#include "dilithium_polyvec_c.h"
-+
-+#include "dilithium_debug.h"
-+
-+void dilithium_print_buffer(const uint8_t *buffer, const size_t bufferlen,
-+ const char *explanation)
-+{
-+ bin2print(buffer, bufferlen, stdout, explanation);
-+}
-+
-+void dilithium_print_polyvecl_k(polyvecl mat[LC_DILITHIUM_K],
-+ const char *explanation)
-+{
-+ unsigned int i, j, k;
-+
-+ printf("%s", explanation);
-+ for (i = 0; i < LC_DILITHIUM_K; i++) {
-+ for (j = 0; j < LC_DILITHIUM_L; j++) {
-+ printf("\nK(%u) x L(%u) x N: ", i, j);
-+ for (k = 0; k < LC_DILITHIUM_N; k++)
-+ printf("0x%.8x ", mat[i].vec[j].coeffs[k]);
-+ }
-+ }
-+ printf("\n");
-+}
-+
-+void dilithium_print_polyvecl(polyvecl *polyvec, const char *explanation)
-+{
-+ unsigned int i, j;
-+
-+ printf("%s", explanation);
-+ for (i = 0; i < LC_DILITHIUM_L; i++) {
-+ printf("\nL(%u) x N: ", i);
-+ for (j = 0; j < LC_DILITHIUM_N; j++) {
-+ printf("%d ", polyvec->vec[i].coeffs[j]);
-+ }
-+ }
-+ printf("\n");
-+}
-+
-+void dilithium_print_polyveck(polyveck *polyvec, const char *explanation)
-+{
-+ unsigned int i, j;
-+
-+ printf("%s", explanation);
-+ for (i = 0; i < LC_DILITHIUM_K; i++) {
-+ printf("\nK(%u) x N: ", i);
-+ for (j = 0; j < LC_DILITHIUM_N; j++) {
-+ printf("%d ", polyvec->vec[i].coeffs[j]);
-+ }
-+ }
-+ printf("\n");
-+}
-+
-+void dilithium_print_poly(poly *vec, const char *explanation)
-+{
-+ unsigned int i;
-+
-+ printf("%s", explanation);
-+ for (i = 0; i < LC_DILITHIUM_N; i++) {
-+ printf("%d ", vec->coeffs[i]);
-+ }
-+ printf("\n");
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_87_def_header.h b/lib/freebl/leancrypto/ml_dsa_87_def_header.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_87_def_header.h
-@@ -0,0 +1,1 @@
-+#define LC_DILITHIUM_TYPE_87 1
-diff --git a/lib/freebl/leancrypto/ml_dsa_87_ntt.c b/lib/freebl/leancrypto/ml_dsa_87_ntt.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_87_ntt.c
-@@ -0,0 +1,92 @@
-+#define LC_DILITHIUM_TYPE_87 1
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#include "dilithium_ntt.h"
-+#include "dilithium_reduce.h"
-+#include "dilithium_zetas.h"
-+
-+/**
-+ * @brief ntt - Forward NTT, in-place. No modular reduction is performed after
-+ * additions or subtractions. Output vector is in bitreversed
-+ * order.
-+ *
-+ * @param [in,out] p input/output coefficient array
-+ */
-+void ntt(int32_t a[LC_DILITHIUM_N])
-+{
-+ unsigned int len, start, j, k;
-+ int32_t zeta, t;
-+
-+ k = 0;
-+
-+ for (len = 128; len > 0; len >>= 1) {
-+ for (start = 0; start < LC_DILITHIUM_N; start = j + len) {
-+ zeta = dilithium_zetas[++k];
-+ for (j = start; j < start + len; ++j) {
-+ t = montgomery_reduce((int64_t)zeta *
-+ a[j + len]);
-+ a[j + len] = a[j] - t;
-+ a[j] = a[j] + t;
-+ }
-+ }
-+ }
-+}
-+
-+/**
-+ * @brief invntt_tomont - Inverse NTT and multiplication by Montgomery factor
-+ * 2^32. In-place. No modular reductions after additions
-+ * or subtractions; input coefficients need to be smaller
-+ * than Q in absolute value. Output coefficient are
-+ * smaller than Q in absolute value.
-+ *
-+ * @param [in,out] p input/output coefficient array
-+ */
-+void invntt_tomont(int32_t a[LC_DILITHIUM_N])
-+{
-+ unsigned int start, len, j, k;
-+ int32_t t, zeta;
-+ const int32_t f = 41978; // mont^2/256
-+
-+ k = 256;
-+
-+ for (len = 1; len < LC_DILITHIUM_N; len <<= 1) {
-+ for (start = 0; start < LC_DILITHIUM_N; start = j + len) {
-+ zeta = -dilithium_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] = montgomery_reduce((int64_t)zeta *
-+ a[j + len]);
-+ }
-+ }
-+ }
-+
-+ for (j = 0; j < LC_DILITHIUM_N; ++j)
-+ a[j] = montgomery_reduce((int64_t)f * a[j]);
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_87_poly.c b/lib/freebl/leancrypto/ml_dsa_87_poly.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_87_poly.c
-@@ -0,0 +1,595 @@
-+#define LC_DILITHIUM_TYPE_87 1
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#include "dilithium_poly.h"
-+#include "dilithium_poly_common.h"
-+#include "dilithium_service_helpers.h"
-+#include "lc_sha3.h"
-+#include "timecop.h"
-+
-+/**
-+ * @brief poly_chknorm - Check infinity norm of polynomial against given bound.
-+ * Assumes input coefficients were reduced by reduce32().
-+ *
-+ * @param [in] a pointer to polynomial
-+ * @param [in] B norm bound
-+ *
-+ * @return 0 if norm is strictly smaller than B <= (Q-1)/8 and 1 otherwise.
-+ */
-+int poly_chknorm(const poly *a, int32_t B)
-+{
-+ unsigned int i;
-+ int32_t t;
-+
-+ if (B > (LC_DILITHIUM_Q - 1) / 8)
-+ return 1;
-+
-+ /*
-+ * It is ok to leak which coefficient violates the bound since
-+ * the probability for each coefficient *is independent of secret
-+ * data but we must not leak the sign of the centralized representative.
-+ */
-+ for (i = 0; i < LC_DILITHIUM_N; ++i) {
-+ /* Absolute value */
-+ t = a->coeffs[i] >> 31;
-+ t = a->coeffs[i] - (t & 2 * a->coeffs[i]);
-+
-+ if (t >= B)
-+ return 1;
-+ }
-+
-+ return 0;
-+}
-+
-+/**
-+ * @brief poly_uniform - Sample polynomial with uniformly random coefficients
-+ * in [0,Q-1] by performing rejection sampling on the
-+ * output stream of SHAKE128(seed|nonce).
-+ *
-+ * @param [out] a pointer to output polynomial
-+ * @param [in] seed byte array with seed of length LC_DILITHIUM_SEEDBYTES
-+ * @param [in] nonce 2-byte nonce
-+ */
-+void poly_uniform(poly *a, const uint8_t seed[LC_DILITHIUM_SEEDBYTES],
-+ uint16_t nonce, void *ws_buf)
-+{
-+ unsigned int i, ctr, off;
-+ unsigned int buflen = POLY_UNIFORM_NBLOCKS * LC_SHAKE_128_SIZE_BLOCK;
-+ uint8_t *buf = ws_buf;
-+ LC_HASH_CTX_ON_STACK(hash_ctx, lc_shake128);
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, seed, LC_DILITHIUM_SEEDBYTES);
-+ lc_hash_update(hash_ctx, (uint8_t *)&nonce, sizeof(nonce));
-+ lc_hash_set_digestsize(hash_ctx, buflen);
-+ lc_hash_final(hash_ctx, buf);
-+
-+ lc_hash_set_digestsize(hash_ctx, LC_SHAKE_128_SIZE_BLOCK);
-+
-+ ctr = rej_uniform(a->coeffs, LC_DILITHIUM_N, buf, buflen);
-+
-+ while (ctr < LC_DILITHIUM_N) {
-+ off = buflen % 3;
-+ for (i = 0; i < off; ++i)
-+ buf[i] = buf[buflen - off + i];
-+
-+ lc_hash_final(hash_ctx, buf + off);
-+ buflen = LC_DILITHIUM_SEEDBYTES + off;
-+ ctr += rej_uniform(a->coeffs + ctr, LC_DILITHIUM_N - ctr, buf,
-+ buflen);
-+ }
-+
-+ lc_hash_zero(hash_ctx);
-+}
-+
-+/**
-+ * @brief poly_uniform_eta - Sample polynomial with uniformly random
-+ * coefficients in [-ETA,ETA] by performing rejection
-+ * sampling on the output stream from
-+ * SHAKE256(seed|nonce).
-+ *
-+ * @param [out] a pointer to output polynomial
-+ * @param [in] seed byte array with seed of length LC_DILITHIUM_CRHBYTES
-+ * @param [in] nonce 2-byte nonce
-+ */
-+void poly_uniform_eta(poly *a, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
-+ uint16_t nonce, void *ws_buf)
-+{
-+ unsigned int ctr;
-+ uint8_t *buf = ws_buf;
-+ LC_HASH_CTX_ON_STACK(hash_ctx, lc_shake256);
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, seed, LC_DILITHIUM_CRHBYTES);
-+ lc_hash_update(hash_ctx, (uint8_t *)&nonce, sizeof(nonce));
-+ lc_hash_set_digestsize(hash_ctx, POLY_UNIFORM_ETA_BYTES);
-+ lc_hash_final(hash_ctx, buf);
-+
-+ ctr = rej_eta(a->coeffs, LC_DILITHIUM_N, buf, POLY_UNIFORM_ETA_BYTES);
-+
-+ while (ctr < LC_DILITHIUM_N) {
-+ lc_hash_final(hash_ctx, buf);
-+
-+ ctr += rej_eta(a->coeffs + ctr, LC_DILITHIUM_N - ctr, buf,
-+ LC_SHAKE_256_SIZE_BLOCK);
-+ }
-+
-+ lc_hash_zero(hash_ctx);
-+}
-+
-+/**
-+ * @brief poly_uniform_gamma1 - Sample polynomial with uniformly random
-+ * coefficients in [-(GAMMA1 - 1), GAMMA1] by
-+ * unpacking output stream of
-+ * SHAKE256(seed|nonce).
-+ *
-+ * @param [out] a pointer to output polynomial
-+ * @param [in] seed: byte array with seed of length LC_DILITHIUM_CRHBYTES
-+ * @param nonce 16-bit nonce
-+ */
-+void poly_uniform_gamma1(poly *a, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
-+ uint16_t nonce, void *ws_buf)
-+{
-+ LC_HASH_CTX_ON_STACK(hash_ctx, lc_shake256);
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, seed, LC_DILITHIUM_CRHBYTES);
-+ lc_hash_update(hash_ctx, (uint8_t *)&nonce, sizeof(nonce));
-+ lc_hash_set_digestsize(hash_ctx, POLY_UNIFORM_GAMMA1_BYTES);
-+ lc_hash_final(hash_ctx, ws_buf);
-+ lc_hash_zero(hash_ctx);
-+
-+ polyz_unpack(a, ws_buf);
-+}
-+
-+/**
-+ * @brief poly_challenge - Implementation of H. Samples polynomial with TAU
-+ * nonzero coefficients in {-1,1} using the output
-+ * stream of SHAKE256(seed).
-+ *
-+ * @param [out] c pointer to output polynomial
-+ * @param [in] mu byte array containing seed of length LC_DILITHIUM_CTILDE_BYTES
-+ */
-+void poly_challenge(poly *c, const uint8_t seed[LC_DILITHIUM_CTILDE_BYTES],
-+ void *ws_buf)
-+{
-+ unsigned int i, b, pos;
-+ uint64_t signs;
-+ uint8_t *buf = ws_buf;
-+ LC_HASH_CTX_ON_STACK(hash_ctx, lc_shake256);
-+
-+ lc_hash_init(hash_ctx);
-+ lc_hash_update(hash_ctx, seed, LC_DILITHIUM_CTILDE_BYTES);
-+ lc_hash_set_digestsize(hash_ctx, POLY_CHALLENGE_BYTES);
-+ lc_hash_final(hash_ctx, buf);
-+
-+ signs = 0;
-+ for (i = 0; i < 8; ++i)
-+ signs |= (uint64_t)buf[i] << 8 * i;
-+ pos = 8;
-+
-+ for (i = 0; i < LC_DILITHIUM_N; ++i)
-+ c->coeffs[i] = 0;
-+
-+ for (i = LC_DILITHIUM_N - LC_DILITHIUM_TAU; i < LC_DILITHIUM_N; ++i) {
-+ do {
-+ if (pos >= LC_SHAKE_256_SIZE_BLOCK) {
-+ lc_hash_final(hash_ctx, buf);
-+ pos = 0;
-+ }
-+
-+ b = buf[pos++];
-+ } while (b > i);
-+
-+ c->coeffs[i] = c->coeffs[b];
-+ c->coeffs[b] = 1 - (int32_t)(2 * (signs & 1));
-+ signs >>= 1;
-+ }
-+
-+ lc_hash_zero(hash_ctx);
-+}
-+
-+/**
-+ * @brief polyeta_pack - Bit-pack polynomial with coefficients in [-ETA,ETA].
-+ *
-+ * @param [out] r pointer to output byte array with at least
-+ * LC_DILITHIUM_POLYETA_PACKEDBYTES bytes
-+ * @param [in] a pointer to input polynomial
-+ */
-+void polyeta_pack(uint8_t *r, const poly *a)
-+{
-+ unsigned int i;
-+ uint8_t t[8];
-+
-+#if LC_DILITHIUM_ETA == 2
-+ for (i = 0; i < LC_DILITHIUM_N / 8; ++i) {
-+ t[0] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 0]);
-+ t[1] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 1]);
-+ t[2] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 2]);
-+ t[3] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 3]);
-+ t[4] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 4]);
-+ t[5] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 5]);
-+ t[6] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 6]);
-+ t[7] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[8 * i + 7]);
-+
-+ r[3 * i + 0] =
-+ (uint8_t)((t[0] >> 0) | (t[1] << 3) | (t[2] << 6));
-+ r[3 * i + 1] = (uint8_t)((t[2] >> 2) | (t[3] << 1) |
-+ (t[4] << 4) | (t[5] << 7));
-+ r[3 * i + 2] =
-+ (uint8_t)((t[5] >> 1) | (t[6] << 2) | (t[7] << 5));
-+ }
-+#elif LC_DILITHIUM_ETA == 4
-+ for (i = 0; i < LC_DILITHIUM_N / 2; ++i) {
-+ t[0] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[2 * i + 0]);
-+ t[1] = (uint8_t)(LC_DILITHIUM_ETA - a->coeffs[2 * i + 1]);
-+ r[i] = (uint8_t)(t[0] | (t[1] << 4));
-+ }
-+#else
-+#error "Undefined LC_DILITHIUM_ETA"
-+#endif
-+}
-+
-+/**
-+ * @brief polyeta_unpack - Unpack polynomial with coefficients in [-ETA,ETA].
-+ *
-+ * @param [out] r pointer to output polynomial
-+ * @param [in] a byte array with bit-packed polynomial
-+ */
-+void polyeta_unpack(poly *r, const uint8_t *a)
-+{
-+ unsigned int i;
-+
-+#if LC_DILITHIUM_ETA == 2
-+ for (i = 0; i < LC_DILITHIUM_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] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 0];
-+ r->coeffs[8 * i + 1] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 1];
-+ r->coeffs[8 * i + 2] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 2];
-+ r->coeffs[8 * i + 3] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 3];
-+ r->coeffs[8 * i + 4] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 4];
-+ r->coeffs[8 * i + 5] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 5];
-+ r->coeffs[8 * i + 6] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 6];
-+ r->coeffs[8 * i + 7] = LC_DILITHIUM_ETA - r->coeffs[8 * i + 7];
-+ }
-+#elif LC_DILITHIUM_ETA == 4
-+ for (i = 0; i < LC_DILITHIUM_N / 2; ++i) {
-+ r->coeffs[2 * i + 0] = a[i] & 0x0F;
-+ r->coeffs[2 * i + 1] = a[i] >> 4;
-+ r->coeffs[2 * i + 0] = LC_DILITHIUM_ETA - r->coeffs[2 * i + 0];
-+ r->coeffs[2 * i + 1] = LC_DILITHIUM_ETA - r->coeffs[2 * i + 1];
-+ }
-+#else
-+#error "Undefined LC_DILITHIUM_ETA"
-+#endif
-+}
-+
-+/**
-+ * @brief polyt1_pack - Bit-pack polynomial t1 with coefficients fitting in 10
-+ * bits. Input coefficients are assumed to be standard
-+ * representatives.
-+ *
-+ * @param [out] r pointer to output byte array with at least
-+ * LC_DILITHIUM_POLYT1_PACKEDBYTES bytes
-+ * @param [in] a pointer to input polynomial
-+ */
-+void polyt1_pack(uint8_t *r, const poly *a)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N / 4; ++i) {
-+ r[5 * i + 0] = (uint8_t)((a->coeffs[4 * i + 0] >> 0));
-+ r[5 * i + 1] = (uint8_t)((a->coeffs[4 * i + 0] >> 8) |
-+ (a->coeffs[4 * i + 1] << 2));
-+ r[5 * i + 2] = (uint8_t)((a->coeffs[4 * i + 1] >> 6) |
-+ (a->coeffs[4 * i + 2] << 4));
-+ r[5 * i + 3] = (uint8_t)((a->coeffs[4 * i + 2] >> 4) |
-+ (a->coeffs[4 * i + 3] << 6));
-+ r[5 * i + 4] = (uint8_t)((a->coeffs[4 * i + 3] >> 2));
-+ }
-+}
-+
-+/**
-+ * @brief polyt0_pack - Bit-pack polynomial t0 with coefficients in
-+ * ]-2^{D-1}, 2^{D-1}].
-+ *
-+ * @param [out] r pointer to output byte array with at least
-+ * LC_DILITHIUM_POLYT0_PACKEDBYTES bytes
-+ * @param [in] a pointer to input polynomial
-+ */
-+void polyt0_pack(uint8_t *r, const poly *a)
-+{
-+ unsigned int i;
-+ uint32_t t[8];
-+
-+ for (i = 0; i < LC_DILITHIUM_N / 8; ++i) {
-+ t[0] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 0]);
-+ t[1] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 1]);
-+ t[2] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 2]);
-+ t[3] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 3]);
-+ t[4] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 4]);
-+ t[5] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 5]);
-+ t[6] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 6]);
-+ t[7] = (uint32_t)((1 << (LC_DILITHIUM_D - 1)) -
-+ a->coeffs[8 * i + 7]);
-+
-+ r[13 * i + 0] = (uint8_t)(t[0]);
-+ r[13 * i + 1] = (uint8_t)(t[0] >> 8);
-+ r[13 * i + 1] |= (uint8_t)(t[1] << 5);
-+ r[13 * i + 2] = (uint8_t)(t[1] >> 3);
-+ r[13 * i + 3] = (uint8_t)(t[1] >> 11);
-+ r[13 * i + 3] |= (uint8_t)(t[2] << 2);
-+ r[13 * i + 4] = (uint8_t)(t[2] >> 6);
-+ r[13 * i + 4] |= (uint8_t)(t[3] << 7);
-+ r[13 * i + 5] = (uint8_t)(t[3] >> 1);
-+ r[13 * i + 6] = (uint8_t)(t[3] >> 9);
-+ r[13 * i + 6] |= (uint8_t)(t[4] << 4);
-+ r[13 * i + 7] = (uint8_t)(t[4] >> 4);
-+ r[13 * i + 8] = (uint8_t)(t[4] >> 12);
-+ r[13 * i + 8] |= (uint8_t)(t[5] << 1);
-+ r[13 * i + 9] = (uint8_t)(t[5] >> 7);
-+ r[13 * i + 9] |= (uint8_t)(t[6] << 6);
-+ r[13 * i + 10] = (uint8_t)(t[6] >> 2);
-+ r[13 * i + 11] = (uint8_t)(t[6] >> 10);
-+ r[13 * i + 11] |= (uint8_t)(t[7] << 3);
-+ r[13 * i + 12] = (uint8_t)(t[7] >> 5);
-+ }
-+
-+ lc_memset_secure(t, 0, sizeof(t));
-+}
-+
-+/**
-+ * @brief polyt0_unpack - Unpack polynomial t0 with coefficients in
-+ * ]-2^{D-1}, 2^{D-1}].
-+ *
-+ * @param [out] r pointer to output polynomial
-+ * @param [in] a byte array with bit-packed polynomial
-+ */
-+void polyt0_unpack(poly *r, const uint8_t *a)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < LC_DILITHIUM_N / 8; ++i) {
-+ r->coeffs[8 * i + 0] = a[13 * i + 0];
-+ r->coeffs[8 * i + 0] |= (int32_t)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] |= (int32_t)a[13 * i + 2] << 3;
-+ r->coeffs[8 * i + 1] |= (int32_t)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] |= (int32_t)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] |= (int32_t)a[13 * i + 5] << 1;
-+ r->coeffs[8 * i + 3] |= (int32_t)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] |= (int32_t)a[13 * i + 7] << 4;
-+ r->coeffs[8 * i + 4] |= (int32_t)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] |= (int32_t)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] |= (int32_t)a[13 * i + 10] << 2;
-+ r->coeffs[8 * i + 6] |= (int32_t)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] |= (int32_t)a[13 * i + 12] << 5;
-+ r->coeffs[8 * i + 7] &= 0x1FFF;
-+
-+ r->coeffs[8 * i + 0] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 0];
-+ r->coeffs[8 * i + 1] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 1];
-+ r->coeffs[8 * i + 2] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 2];
-+ r->coeffs[8 * i + 3] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 3];
-+ r->coeffs[8 * i + 4] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 4];
-+ r->coeffs[8 * i + 5] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 5];
-+ r->coeffs[8 * i + 6] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 6];
-+ r->coeffs[8 * i + 7] =
-+ (1 << (LC_DILITHIUM_D - 1)) - r->coeffs[8 * i + 7];
-+ }
-+}
-+
-+/**
-+ * @param polyz_pack - Bit-pack polynomial with coefficients
-+ * in [-(GAMMA1 - 1), GAMMA1].
-+ *
-+ * @param [out] r pointer to output byte array with at least
-+ * LC_DILITHIUM_POLYZ_PACKEDBYTES bytes
-+ * @param [in] a pointer to input polynomial
-+ */
-+void polyz_pack(uint8_t *r, const poly *a)
-+{
-+ unsigned int i;
-+ uint32_t t[4];
-+
-+#if LC_DILITHIUM_GAMMA1 == (1 << 17)
-+ for (i = 0; i < LC_DILITHIUM_N / 4; ++i) {
-+ t[0] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[4 * i + 0]);
-+ t[1] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[4 * i + 1]);
-+ t[2] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[4 * i + 2]);
-+ t[3] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[4 * i + 3]);
-+
-+ r[9 * i + 0] = (uint8_t)(t[0]);
-+ r[9 * i + 1] = (uint8_t)(t[0] >> 8);
-+ r[9 * i + 2] = (uint8_t)(t[0] >> 16);
-+ r[9 * i + 2] |= (uint8_t)(t[1] << 2);
-+ r[9 * i + 3] = (uint8_t)(t[1] >> 6);
-+ r[9 * i + 4] = (uint8_t)(t[1] >> 14);
-+ r[9 * i + 4] |= (uint8_t)(t[2] << 4);
-+ r[9 * i + 5] = (uint8_t)(t[2] >> 4);
-+ r[9 * i + 6] = (uint8_t)(t[2] >> 12);
-+ r[9 * i + 6] |= (uint8_t)(t[3] << 6);
-+ r[9 * i + 7] = (uint8_t)(t[3] >> 2);
-+ r[9 * i + 8] = (uint8_t)(t[3] >> 10);
-+ }
-+#elif LC_DILITHIUM_GAMMA1 == (1 << 19)
-+ for (i = 0; i < LC_DILITHIUM_N / 2; ++i) {
-+ t[0] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[2 * i + 0]);
-+ t[1] = (uint32_t)(LC_DILITHIUM_GAMMA1 - a->coeffs[2 * i + 1]);
-+
-+ r[5 * i + 0] = (uint8_t)(t[0]);
-+ r[5 * i + 1] = (uint8_t)(t[0] >> 8);
-+ r[5 * i + 2] = (uint8_t)(t[0] >> 16);
-+ r[5 * i + 2] |= (uint8_t)(t[1] << 4);
-+ r[5 * i + 3] = (uint8_t)(t[1] >> 4);
-+ r[5 * i + 4] = (uint8_t)(t[1] >> 12);
-+ }
-+#else
-+#error "Undefined Gamma"
-+#endif
-+
-+ lc_memset_secure(t, 0, sizeof(t));
-+}
-+
-+/**
-+ * @brief polyz_unpack - Unpack polynomial z with coefficients
-+ * in [-(GAMMA1 - 1), GAMMA1].
-+ *
-+ * @param [out] r pointer to output polynomial
-+ * @param [in] a byte array with bit-packed polynomial
-+ */
-+void polyz_unpack(poly *r, const uint8_t *a)
-+{
-+ unsigned int i;
-+
-+#if LC_DILITHIUM_GAMMA1 == (1 << 17)
-+ for (i = 0; i < LC_DILITHIUM_N / 4; ++i) {
-+ r->coeffs[4 * i + 0] = a[9 * i + 0];
-+ r->coeffs[4 * i + 0] |= (int32_t)a[9 * i + 1] << 8;
-+ r->coeffs[4 * i + 0] |= (int32_t)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] |= (int32_t)a[9 * i + 3] << 6;
-+ r->coeffs[4 * i + 1] |= (int32_t)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] |= (int32_t)a[9 * i + 5] << 4;
-+ r->coeffs[4 * i + 2] |= (int32_t)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] |= (int32_t)a[9 * i + 7] << 2;
-+ r->coeffs[4 * i + 3] |= (int32_t)a[9 * i + 8] << 10;
-+ r->coeffs[4 * i + 3] &= 0x3FFFF;
-+
-+ r->coeffs[4 * i + 0] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[4 * i + 0];
-+ r->coeffs[4 * i + 1] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[4 * i + 1];
-+ r->coeffs[4 * i + 2] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[4 * i + 2];
-+ r->coeffs[4 * i + 3] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[4 * i + 3];
-+ }
-+#elif LC_DILITHIUM_GAMMA1 == (1 << 19)
-+ for (i = 0; i < LC_DILITHIUM_N / 2; ++i) {
-+ r->coeffs[2 * i + 0] = a[5 * i + 0];
-+ r->coeffs[2 * i + 0] |= (int32_t)a[5 * i + 1] << 8;
-+ r->coeffs[2 * i + 0] |= (int32_t)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] |= (int32_t)a[5 * i + 3] << 4;
-+ r->coeffs[2 * i + 1] |= (int32_t)a[5 * i + 4] << 12;
-+ r->coeffs[2 * i + 1] &= 0xFFFFF;
-+
-+ r->coeffs[2 * i + 0] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[2 * i + 0];
-+ r->coeffs[2 * i + 1] =
-+ LC_DILITHIUM_GAMMA1 - r->coeffs[2 * i + 1];
-+ }
-+#else
-+#error "Undefined Gamma"
-+#endif
-+}
-+
-+/**
-+ * @brief polyw1_pack - Bit-pack polynomial w1 with coefficients in [0,15] or
-+ * [0,43]. Input coefficients are assumed to be standard
-+ * representatives.
-+ *
-+ * @param [out] r pointer to output byte array with at least
-+ * LC_DILITHIUM_POLYW1_PACKEDBYTES bytes
-+ * @param [in] a pointer to input polynomial
-+ */
-+void polyw1_pack(uint8_t *r, const poly *a)
-+{
-+ unsigned int i;
-+
-+#if LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 88
-+ for (i = 0; i < LC_DILITHIUM_N / 4; ++i) {
-+ r[3 * i + 0] = (uint8_t)(a->coeffs[4 * i + 0]);
-+ r[3 * i + 0] |= (uint8_t)(a->coeffs[4 * i + 1] << 6);
-+ r[3 * i + 1] = (uint8_t)(a->coeffs[4 * i + 1] >> 2);
-+ r[3 * i + 1] |= (uint8_t)(a->coeffs[4 * i + 2] << 4);
-+ r[3 * i + 2] = (uint8_t)(a->coeffs[4 * i + 2] >> 4);
-+ r[3 * i + 2] |= (uint8_t)(a->coeffs[4 * i + 3] << 2);
-+ }
-+#elif LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 32
-+ for (i = 0; i < LC_DILITHIUM_N / 2; ++i)
-+ r[i] = (uint8_t)(a->coeffs[2 * i + 0] |
-+ (a->coeffs[2 * i + 1] << 4));
-+#else
-+#error "Undefined Gamma"
-+#endif
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_87_rounding.c b/lib/freebl/leancrypto/ml_dsa_87_rounding.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_87_rounding.c
-@@ -0,0 +1,130 @@
-+#define LC_DILITHIUM_TYPE_87 1
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#include "dilithium_rounding.h"
-+
-+/**
-+ * @brief power2round - For finite field element a, compute a0, a1 such that
-+ * a mod^+ Q = a1*2^D + a0 with -2^{D-1} < a0 <= 2^{D-1}.
-+ * Assumes a to be standard representative.
-+ *
-+ * @param [in] a input element
-+ * @param [out] a0 pointer to output element a0
-+ *
-+ * @return a1.
-+ */
-+int32_t power2round(int32_t *a0, int32_t a)
-+{
-+ int32_t a1;
-+
-+ a1 = (a + (1 << (LC_DILITHIUM_D - 1)) - 1) >> LC_DILITHIUM_D;
-+ *a0 = a - (a1 << LC_DILITHIUM_D);
-+ return a1;
-+}
-+
-+/**
-+ * @brief decompose - For finite field element a, compute high and low bits a0,
-+ * a1 such that a mod^+ Q = a1*ALPHA + a0 with
-+ * -ALPHA/2 < a0 <= ALPHA/2 except if a1 = (Q-1)/ALPHA where
-+ * we set a1 = 0 and -ALPHA/2 <= a0 = a mod^+ Q - Q < 0.
-+ * Assumes a to be standard representative.
-+ *
-+ * @param [in] a input element
-+ * @param [out] a0 pointer to output element a0
-+ *
-+ * @return a1.
-+ */
-+int32_t decompose(int32_t *a0, int32_t a)
-+{
-+ int32_t a1;
-+
-+ a1 = (a + 127) >> 7;
-+#if LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 32
-+ a1 = (a1 * 1025 + (1 << 21)) >> 22;
-+ a1 &= 15;
-+#elif LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 88
-+ a1 = (a1 * 11275 + (1 << 23)) >> 24;
-+ a1 ^= ((43 - a1) >> 31) & a1;
-+#else
-+#error "Uknown GAMMA2"
-+#endif
-+
-+ *a0 = a - a1 * 2 * LC_DILITHIUM_GAMMA2;
-+ *a0 -= (((LC_DILITHIUM_Q - 1) / 2 - *a0) >> 31) & LC_DILITHIUM_Q;
-+
-+ return a1;
-+}
-+
-+/**
-+ * @brief make_hint - Compute hint bit indicating whether the low bits of the
-+ * input element overflow into the high bits.
-+ *
-+ * @param a0 [in] low bits of input element
-+ * @param a1 [in] high bits of input element
-+ *
-+ * @return 1 if overflow.
-+ */
-+int32_t make_hint(int32_t a0, int32_t a1)
-+{
-+ if (a0 > LC_DILITHIUM_GAMMA2 || a0 < -LC_DILITHIUM_GAMMA2 ||
-+ (a0 == -LC_DILITHIUM_GAMMA2 && a1 != 0))
-+ return 1;
-+
-+ return 0;
-+}
-+
-+/**
-+ * @brief use_hint - Correct high bits according to hint.
-+ *
-+ * @param [in] a input element
-+ * @param [in] hint hint bit
-+ *
-+ * @return corrected high bits.
-+ */
-+int32_t use_hint(int32_t a, int32_t hint)
-+{
-+ int32_t a0, a1;
-+
-+ a1 = decompose(&a0, a);
-+ if (hint == 0)
-+ return a1;
-+
-+#if LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 32
-+ if (a0 > 0)
-+ return (a1 + 1) & 15;
-+ else
-+ return (a1 - 1) & 15;
-+#elif LC_DILITHIUM_GAMMA2 == (LC_DILITHIUM_Q - 1) / 88
-+ if (a0 > 0)
-+ return (a1 == 43) ? 0 : a1 + 1;
-+ else
-+ return (a1 == 0) ? 43 : a1 - 1;
-+#else
-+#error "Uknown GAMMA2"
-+#endif
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_87_signature_c.c b/lib/freebl/leancrypto/ml_dsa_87_signature_c.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_87_signature_c.c
-@@ -0,0 +1,131 @@
-+#define LC_DILITHIUM_TYPE_87 1
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#include "dilithium_signature_c.h"
-+#include "visibility.h"
-+
-+/* We need once the buffer size to handle the hashing */
-+#define LC_POLY_UNIFOR_BUF_SIZE_MULTIPLIER 1
-+
-+#include "dilithium_poly.h"
-+#include "dilithium_poly_common.h"
-+#include "dilithium_poly_c.h"
-+#include "dilithium_polyvec.h"
-+#include "dilithium_polyvec_c.h"
-+#include "dilithium_pack.h"
-+#include "dilithium_signature_impl.h"
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_keypair_from_seed_c,
-+ struct lc_dilithium_pk *pk, struct lc_dilithium_sk *sk,
-+ const uint8_t *seed, size_t seedlen)
-+{
-+ return lc_dilithium_keypair_from_seed_impl(pk, sk, seed, seedlen);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_keypair_c, struct lc_dilithium_pk *pk,
-+ struct lc_dilithium_sk *sk, struct lc_rng_ctx *rng_ctx)
-+{
-+ return lc_dilithium_keypair_impl(pk, sk, rng_ctx);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_c, struct lc_dilithium_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ return lc_dilithium_sign_impl(sig, m, mlen, sk, rng_ctx);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_ctx_c,
-+ struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ return lc_dilithium_sign_ctx_impl(sig, ctx, m, mlen, sk, rng_ctx);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_init_c,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_sk *sk)
-+{
-+ return lc_dilithium_sign_init_impl(ctx, sk);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_update_c,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen)
-+{
-+ return lc_dilithium_sign_update_impl(ctx, m, mlen);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_final_c,
-+ struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ return lc_dilithium_sign_final_impl(sig, ctx, sk, rng_ctx);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_c,
-+ const struct lc_dilithium_sig *sig, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_pk *pk)
-+{
-+ return lc_dilithium_verify_impl(sig, m, mlen, pk);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_ctx_c,
-+ const struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_pk *pk)
-+{
-+ return lc_dilithium_verify_ctx_impl(sig, ctx, m, mlen, pk);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_init_c,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_pk *pk)
-+{
-+ return lc_dilithium_verify_init_impl(ctx, pk);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_update_c,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen)
-+{
-+ return lc_dilithium_verify_update_impl(ctx, m, mlen);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_final_c,
-+ const struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_pk *pk)
-+{
-+ return lc_dilithium_verify_final_impl(sig, ctx, pk);
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_87_signature_helper.c b/lib/freebl/leancrypto/ml_dsa_87_signature_helper.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_87_signature_helper.c
-@@ -0,0 +1,103 @@
-+#define LC_DILITHIUM_TYPE_87 1
-+/*
-+ * Copyright (C) 2024 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#include "dilithium_type.h"
-+#include "visibility.h"
-+
-+#include "lc_sha3.h"
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ctx_alloc,
-+ struct lc_dilithium_ctx **ctx)
-+{
-+ struct lc_dilithium_ctx *out_ctx = NULL;
-+ int ret;
-+
-+ if (!ctx)
-+ return -EINVAL;
-+
-+ ret = lc_alloc_aligned((void **)&out_ctx, LC_HASH_COMMON_ALIGNMENT,
-+ LC_DILITHIUM_CTX_SIZE);
-+ if (ret)
-+ return -ret;
-+
-+ LC_DILITHIUM_SET_CTX(out_ctx);
-+
-+ *ctx = out_ctx;
-+
-+ return 0;
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ctx_alloc_ahat,
-+ struct lc_dilithium_ctx **ctx)
-+{
-+ struct lc_dilithium_ctx *out_ctx = NULL;
-+ int ret;
-+
-+ if (!ctx)
-+ return -EINVAL;
-+
-+#if LC_DILITHIUM_MODE == 2
-+ ret = lc_alloc_aligned((void **)&out_ctx, LC_HASH_COMMON_ALIGNMENT,
-+ LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_44_AHAT_PAD +
-+ LC_DILITHIUM_44_AHAT_SIZE);
-+ if (ret)
-+ return -ret;
-+ out_ctx->ahat = (uint8_t *)out_ctx + LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_44_AHAT_PAD;
-+ out_ctx->ahat_size = LC_DILITHIUM_44_AHAT_SIZE;
-+#elif LC_DILITHIUM_MODE == 3
-+ ret = lc_alloc_aligned((void **)&out_ctx, LC_HASH_COMMON_ALIGNMENT,
-+ LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_65_AHAT_PAD +
-+ LC_DILITHIUM_65_AHAT_SIZE);
-+ if (ret)
-+ return -ret;
-+ out_ctx->ahat = (uint8_t *)out_ctx + LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_65_AHAT_PAD;
-+ out_ctx->ahat_size = LC_DILITHIUM_65_AHAT_SIZE;
-+#elif LC_DILITHIUM_MODE == 5
-+ ret = lc_alloc_aligned((void **)&out_ctx, LC_HASH_COMMON_ALIGNMENT,
-+ LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_87_AHAT_PAD +
-+ LC_DILITHIUM_87_AHAT_SIZE);
-+ if (ret)
-+ return -ret;
-+ out_ctx->ahat = (uint8_t *)out_ctx + LC_DILITHIUM_CTX_SIZE +
-+ LC_DILITHIUM_87_AHAT_PAD;
-+ out_ctx->ahat_size = LC_DILITHIUM_87_AHAT_SIZE;
-+#endif
-+
-+ LC_SHAKE_256_CTX((&(out_ctx)->dilithium_hash_ctx));
-+
-+ *ctx = out_ctx;
-+
-+ return 0;
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ctx_zero_free,
-+ struct lc_dilithium_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+
-+ lc_dilithium_ctx_zero(ctx);
-+ lc_free(ctx);
-+}
-diff --git a/lib/freebl/leancrypto/ml_dsa_api.h b/lib/freebl/leancrypto/ml_dsa_api.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_api.h
-@@ -0,0 +1,71 @@
-+#ifndef ML_DSA_API_H
-+#define ML_DSA_API_H
-+// This is a generated file from the various XXX_sign.h files
-+#include
-+#include "ml_dsa_apit.h"
-+
-+// from ml_dsa_44_sign.h
-+int lc_dilithium_44_keypair_from_seed_c(struct lc_dilithium_44_pk *pk,
-+ struct lc_dilithium_44_sk *sk,
-+ const uint8_t *seed, size_t seedlen);
-+
-+int lc_dilithium_44_sign_init_c(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_44_sk *sk);
-+int lc_dilithium_44_sign_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+int lc_dilithium_44_sign_final_c(struct lc_dilithium_44_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_44_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+int lc_dilithium_44_verify_init_c(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_44_pk *pk);
-+int lc_dilithium_44_verify_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+int lc_dilithium_44_verify_final_c(const struct lc_dilithium_44_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_44_pk *pk);
-+
-+// from ml_dsa_65_sign.h
-+int lc_dilithium_65_keypair_from_seed_c(struct lc_dilithium_65_pk *pk,
-+ struct lc_dilithium_65_sk *sk,
-+ const uint8_t *seed, size_t seedlen);
-+
-+int lc_dilithium_65_sign_init_c(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_65_sk *sk);
-+int lc_dilithium_65_sign_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+int lc_dilithium_65_sign_final_c(struct lc_dilithium_65_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_65_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+int lc_dilithium_65_verify_init_c(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_65_pk *pk);
-+int lc_dilithium_65_verify_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+int lc_dilithium_65_verify_final_c(const struct lc_dilithium_65_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_65_pk *pk);
-+// from ml_dsa_87_sign.h
-+int lc_dilithium_87_keypair_from_seed_c(struct lc_dilithium_87_pk *pk,
-+ struct lc_dilithium_87_sk *sk,
-+ const uint8_t *seed, size_t seedlen);
-+
-+int lc_dilithium_87_sign_init_c(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_87_sk *sk);
-+int lc_dilithium_87_sign_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+int lc_dilithium_87_sign_final_c(struct lc_dilithium_87_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_87_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+int lc_dilithium_87_verify_init_c(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_87_pk *pk);
-+int lc_dilithium_87_verify_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+int lc_dilithium_87_verify_final_c(const struct lc_dilithium_87_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_87_pk *pk);
-+#endif /* ML_DSA_API_H */
-diff --git a/lib/freebl/leancrypto/ml_dsa_apit.h b/lib/freebl/leancrypto/ml_dsa_apit.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ml_dsa_apit.h
-@@ -0,0 +1,10 @@
-+// This is a generated file from the various XXX_sign.h files
-+#ifndef ML_DSA_APIT_H
-+#define ML_DSA_APIT_H
-+
-+// to make the function defines work
-+#ifndef RNDBYTES
-+#define RNDBYTES 32
-+#endif
-+
-+#endif /* ML_DSA_APIT_H */
-diff --git a/lib/freebl/leancrypto/mldsa_api.c b/lib/freebl/leancrypto/mldsa_api.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/mldsa_api.c
-@@ -0,0 +1,2535 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#include "ext_headers.h"
-+#include "lc_dilithium.h"
-+#include "dilithium_pct.h"
-+#include "visibility.h"
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ctx_alloc,
-+ struct lc_dilithium_ctx **ctx)
-+{
-+ if (!ctx)
-+ return -EINVAL;
-+
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ctx_alloc(ctx);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ return lc_dilithium_65_ctx_alloc(ctx);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ return lc_dilithium_44_ctx_alloc(ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ctx_alloc_ahat,
-+ struct lc_dilithium_ctx **ctx)
-+{
-+ if (!ctx)
-+ return -EINVAL;
-+
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ctx_alloc_ahat(ctx);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ return lc_dilithium_65_ctx_alloc_ahat(ctx);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ return lc_dilithium_44_ctx_alloc_ahat(ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ctx_zero_free,
-+ struct lc_dilithium_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ lc_dilithium_87_ctx_zero_free(ctx);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ lc_dilithium_65_ctx_zero_free(ctx);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ lc_dilithium_44_ctx_zero_free(ctx);
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ctx_zero, struct lc_dilithium_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ lc_dilithium_87_ctx_zero(ctx);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ lc_dilithium_65_ctx_zero(ctx);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ lc_dilithium_44_ctx_zero(ctx);
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ctx_internal,
-+ struct lc_dilithium_ctx *ctx)
-+{
-+ if (ctx)
-+ ctx->ml_dsa_internal = 1;
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ctx_hash, struct lc_dilithium_ctx *ctx,
-+ const struct lc_hash *hash)
-+{
-+ if (ctx)
-+ ctx->dilithium_prehash_type = hash;
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ctx_userctx,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *userctx,
-+ size_t userctxlen)
-+{
-+ if (ctx) {
-+ ctx->userctx = userctx;
-+ ctx->userctxlen = userctxlen;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ctx_external_mu,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *external_mu,
-+ size_t external_mu_len)
-+{
-+ if (ctx) {
-+ ctx->external_mu = external_mu;
-+ ctx->external_mu_len = external_mu_len;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ctx_drop_ahat,
-+ struct lc_dilithium_ctx *ctx)
-+{
-+ if (ctx)
-+ ctx->ahat_expanded = 0;
-+}
-+
-+LC_INTERFACE_FUNCTION(enum lc_dilithium_type, lc_dilithium_sk_type,
-+ const struct lc_dilithium_sk *sk)
-+{
-+ if (!sk)
-+ return LC_DILITHIUM_UNKNOWN;
-+ return sk->dilithium_type;
-+}
-+
-+LC_INTERFACE_FUNCTION(enum lc_dilithium_type, lc_dilithium_pk_type,
-+ const struct lc_dilithium_pk *pk)
-+{
-+ if (!pk)
-+ return LC_DILITHIUM_UNKNOWN;
-+ return pk->dilithium_type;
-+}
-+
-+LC_INTERFACE_FUNCTION(enum lc_dilithium_type, lc_dilithium_sig_type,
-+ const struct lc_dilithium_sig *sig)
-+{
-+ if (!sig)
-+ return LC_DILITHIUM_UNKNOWN;
-+ return sig->dilithium_type;
-+}
-+
-+LC_PURE LC_INTERFACE_FUNCTION(unsigned int, lc_dilithium_sk_size,
-+ enum lc_dilithium_type dilithium_type)
-+{
-+ switch (dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_member_size(struct lc_dilithium_sk, key.sk_87);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_member_size(struct lc_dilithium_sk, key.sk_65);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_member_size(struct lc_dilithium_sk, key.sk_44);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return 0;
-+ }
-+}
-+
-+LC_PURE LC_INTERFACE_FUNCTION(unsigned int, lc_dilithium_pk_size,
-+ enum lc_dilithium_type dilithium_type)
-+{
-+ switch (dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_member_size(struct lc_dilithium_pk, key.pk_87);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_member_size(struct lc_dilithium_pk, key.pk_65);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_member_size(struct lc_dilithium_pk, key.pk_44);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return 0;
-+ }
-+}
-+
-+LC_PURE LC_INTERFACE_FUNCTION(unsigned int, lc_dilithium_sig_size,
-+ enum lc_dilithium_type dilithium_type)
-+{
-+ switch (dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_member_size(struct lc_dilithium_sig, sig.sig_87);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_member_size(struct lc_dilithium_sig, sig.sig_65);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_member_size(struct lc_dilithium_sig, sig.sig_44);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return 0;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sk_load, struct lc_dilithium_sk *sk,
-+ const uint8_t *src_key, size_t src_key_len)
-+{
-+ if (!sk || !src_key || src_key_len == 0) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (src_key_len == lc_dilithium_sk_size(LC_DILITHIUM_87)) {
-+ struct lc_dilithium_87_sk *_sk = &sk->key.sk_87;
-+
-+ memcpy(_sk->sk, src_key, src_key_len);
-+ sk->dilithium_type = LC_DILITHIUM_87;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (src_key_len == lc_dilithium_sk_size(LC_DILITHIUM_65)) {
-+ struct lc_dilithium_65_sk *_sk = &sk->key.sk_65;
-+
-+ memcpy(_sk->sk, src_key, src_key_len);
-+ sk->dilithium_type = LC_DILITHIUM_65;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (src_key_len == lc_dilithium_sk_size(LC_DILITHIUM_44)) {
-+ struct lc_dilithium_44_sk *_sk = &sk->key.sk_44;
-+
-+ memcpy(_sk->sk, src_key, src_key_len);
-+ sk->dilithium_type = LC_DILITHIUM_44;
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_pk_load, struct lc_dilithium_pk *pk,
-+ const uint8_t *src_key, size_t src_key_len)
-+{
-+ if (!pk || !src_key || src_key_len == 0) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (src_key_len == lc_dilithium_pk_size(LC_DILITHIUM_87)) {
-+ struct lc_dilithium_87_pk *_pk = &pk->key.pk_87;
-+
-+ memcpy(_pk->pk, src_key, src_key_len);
-+ pk->dilithium_type = LC_DILITHIUM_87;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (src_key_len == lc_dilithium_pk_size(LC_DILITHIUM_65)) {
-+ struct lc_dilithium_65_pk *_pk = &pk->key.pk_65;
-+
-+ memcpy(_pk->pk, src_key, src_key_len);
-+ pk->dilithium_type = LC_DILITHIUM_65;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (src_key_len == lc_dilithium_pk_size(LC_DILITHIUM_44)) {
-+ struct lc_dilithium_44_pk *_pk = &pk->key.pk_44;
-+
-+ memcpy(_pk->pk, src_key, src_key_len);
-+ pk->dilithium_type = LC_DILITHIUM_44;
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sig_load, struct lc_dilithium_sig *sig,
-+ const uint8_t *src_sig, size_t src_sig_len)
-+{
-+ if (!sig || !src_sig || src_sig_len == 0) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (src_sig_len == lc_dilithium_sig_size(LC_DILITHIUM_87)) {
-+ struct lc_dilithium_87_sig *_sig = &sig->sig.sig_87;
-+
-+ memcpy(_sig->sig, src_sig, src_sig_len);
-+ sig->dilithium_type = LC_DILITHIUM_87;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (src_sig_len == lc_dilithium_sig_size(LC_DILITHIUM_65)) {
-+ struct lc_dilithium_65_sig *_sig = &sig->sig.sig_65;
-+
-+ memcpy(_sig->sig, src_sig, src_sig_len);
-+ sig->dilithium_type = LC_DILITHIUM_65;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (src_sig_len == lc_dilithium_sig_size(LC_DILITHIUM_44)) {
-+ struct lc_dilithium_44_sig *_sig = &sig->sig.sig_44;
-+
-+ memcpy(_sig->sig, src_sig, src_sig_len);
-+ sig->dilithium_type = LC_DILITHIUM_44;
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sk_ptr, uint8_t **dilithium_key,
-+ size_t *dilithium_key_len, struct lc_dilithium_sk *sk)
-+{
-+ if (!sk || !dilithium_key || !dilithium_key_len) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (sk->dilithium_type == LC_DILITHIUM_87) {
-+ struct lc_dilithium_87_sk *_sk = &sk->key.sk_87;
-+
-+ *dilithium_key = _sk->sk;
-+ *dilithium_key_len = lc_dilithium_sk_size(sk->dilithium_type);
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (sk->dilithium_type == LC_DILITHIUM_65) {
-+ struct lc_dilithium_65_sk *_sk = &sk->key.sk_65;
-+
-+ *dilithium_key = _sk->sk;
-+ *dilithium_key_len = lc_dilithium_sk_size(sk->dilithium_type);
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (sk->dilithium_type == LC_DILITHIUM_44) {
-+ struct lc_dilithium_44_sk *_sk = &sk->key.sk_44;
-+
-+ *dilithium_key = _sk->sk;
-+ *dilithium_key_len = lc_dilithium_sk_size(sk->dilithium_type);
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_pk_ptr, uint8_t **dilithium_key,
-+ size_t *dilithium_key_len, struct lc_dilithium_pk *pk)
-+{
-+ if (!pk || !dilithium_key || !dilithium_key_len) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (pk->dilithium_type == LC_DILITHIUM_87) {
-+ struct lc_dilithium_87_pk *_pk = &pk->key.pk_87;
-+
-+ *dilithium_key = _pk->pk;
-+ *dilithium_key_len = lc_dilithium_pk_size(pk->dilithium_type);
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (pk->dilithium_type == LC_DILITHIUM_65) {
-+ struct lc_dilithium_65_pk *_pk = &pk->key.pk_65;
-+
-+ *dilithium_key = _pk->pk;
-+ *dilithium_key_len = lc_dilithium_pk_size(pk->dilithium_type);
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (pk->dilithium_type == LC_DILITHIUM_44) {
-+ struct lc_dilithium_44_pk *_pk = &pk->key.pk_44;
-+
-+ *dilithium_key = _pk->pk;
-+ *dilithium_key_len = lc_dilithium_pk_size(pk->dilithium_type);
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sig_ptr, uint8_t **dilithium_sig,
-+ size_t *dilithium_sig_len, struct lc_dilithium_sig *sig)
-+{
-+ if (!sig || !dilithium_sig || !dilithium_sig_len) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (sig->dilithium_type == LC_DILITHIUM_87) {
-+ struct lc_dilithium_87_sig *_sig = &sig->sig.sig_87;
-+
-+ *dilithium_sig = _sig->sig;
-+ *dilithium_sig_len = lc_dilithium_sig_size(sig->dilithium_type);
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (sig->dilithium_type == LC_DILITHIUM_65) {
-+ struct lc_dilithium_65_sig *_sig = &sig->sig.sig_65;
-+
-+ *dilithium_sig = _sig->sig;
-+ *dilithium_sig_len = lc_dilithium_sig_size(sig->dilithium_type);
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (sig->dilithium_type == LC_DILITHIUM_44) {
-+ struct lc_dilithium_44_sig *_sig = &sig->sig.sig_44;
-+
-+ *dilithium_sig = _sig->sig;
-+ *dilithium_sig_len = lc_dilithium_sig_size(sig->dilithium_type);
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_keypair, struct lc_dilithium_pk *pk,
-+ struct lc_dilithium_sk *sk, struct lc_rng_ctx *rng_ctx,
-+ enum lc_dilithium_type dilithium_type)
-+{
-+ if (!pk || !sk)
-+ return -EINVAL;
-+
-+ switch (dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ pk->dilithium_type = dilithium_type;
-+ sk->dilithium_type = dilithium_type;
-+ return lc_dilithium_87_keypair(&pk->key.pk_87, &sk->key.sk_87,
-+ rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ pk->dilithium_type = dilithium_type;
-+ sk->dilithium_type = dilithium_type;
-+ return lc_dilithium_65_keypair(&pk->key.pk_65, &sk->key.sk_65,
-+ rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ pk->dilithium_type = dilithium_type;
-+ sk->dilithium_type = dilithium_type;
-+ return lc_dilithium_44_keypair(&pk->key.pk_44, &sk->key.sk_44,
-+ rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_keypair_from_seed,
-+ struct lc_dilithium_pk *pk, struct lc_dilithium_sk *sk,
-+ const uint8_t *seed, size_t seedlen,
-+ enum lc_dilithium_type dilithium_type)
-+{
-+ if (!pk || !sk)
-+ return -EINVAL;
-+
-+ switch (dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ pk->dilithium_type = dilithium_type;
-+ sk->dilithium_type = dilithium_type;
-+ return lc_dilithium_87_keypair_from_seed(
-+ &pk->key.pk_87, &sk->key.sk_87, seed, seedlen);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ pk->dilithium_type = dilithium_type;
-+ sk->dilithium_type = dilithium_type;
-+ return lc_dilithium_65_keypair_from_seed(
-+ &pk->key.pk_65, &sk->key.sk_65, seed, seedlen);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ pk->dilithium_type = dilithium_type;
-+ sk->dilithium_type = dilithium_type;
-+ return lc_dilithium_44_keypair_from_seed(
-+ &pk->key.pk_44, &sk->key.sk_44, seed, seedlen);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_pct, const struct lc_dilithium_pk *pk,
-+ const struct lc_dilithium_sk *sk)
-+{
-+ return _lc_dilithium_pct_fips(pk, sk);
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign, struct lc_dilithium_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ if (!sk || !sig)
-+ return -EINVAL;
-+
-+ switch (sk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_87;
-+ return lc_dilithium_87_sign(&sig->sig.sig_87, m, mlen,
-+ &sk->key.sk_87, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_65;
-+ return lc_dilithium_65_sign(&sig->sig.sig_65, m, mlen,
-+ &sk->key.sk_65, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_44;
-+ return lc_dilithium_44_sign(&sig->sig.sig_44, m, mlen,
-+ &sk->key.sk_44, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_ctx, struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ if (!sk || !sig)
-+ return -EINVAL;
-+
-+ switch (sk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_87;
-+ return lc_dilithium_87_sign_ctx(&sig->sig.sig_87, ctx, m, mlen,
-+ &sk->key.sk_87, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_65;
-+ return lc_dilithium_65_sign_ctx(&sig->sig.sig_65, ctx, m, mlen,
-+ &sk->key.sk_65, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_44;
-+ return lc_dilithium_44_sign_ctx(&sig->sig.sig_44, ctx, m, mlen,
-+ &sk->key.sk_44, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_init, struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_sk *sk)
-+{
-+ if (!sk)
-+ return -EINVAL;
-+
-+ switch (sk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_sign_init(ctx, &sk->key.sk_87);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_dilithium_65_sign_init(ctx, &sk->key.sk_65);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_dilithium_44_sign_init(ctx, &sk->key.sk_44);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_update,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen)
-+{
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_sign_update(ctx, m, mlen);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ return lc_dilithium_65_sign_update(ctx, m, mlen);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ return lc_dilithium_44_sign_update(ctx, m, mlen);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_final,
-+ struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ if (!sk || !sig)
-+ return -EINVAL;
-+
-+ switch (sk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_87;
-+ return lc_dilithium_87_sign_final(&sig->sig.sig_87, ctx,
-+ &sk->key.sk_87, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_65;
-+ return lc_dilithium_65_sign_final(&sig->sig.sig_65, ctx,
-+ &sk->key.sk_65, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_44;
-+ return lc_dilithium_44_sign_final(&sig->sig.sig_44, ctx,
-+ &sk->key.sk_44, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify,
-+ const struct lc_dilithium_sig *sig, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_pk *pk)
-+{
-+ if (!pk || !sig || sig->dilithium_type != pk->dilithium_type)
-+ return -EINVAL;
-+
-+ switch (pk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_verify(&sig->sig.sig_87, m, mlen,
-+ &pk->key.pk_87);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_dilithium_65_verify(&sig->sig.sig_65, m, mlen,
-+ &pk->key.pk_65);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_dilithium_44_verify(&sig->sig.sig_44, m, mlen,
-+ &pk->key.pk_44);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_ctx,
-+ const struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_pk *pk)
-+{
-+ if (!pk || !sig || sig->dilithium_type != pk->dilithium_type)
-+ return -EINVAL;
-+
-+ switch (pk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_verify_ctx(&sig->sig.sig_87, ctx, m,
-+ mlen, &pk->key.pk_87);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_dilithium_65_verify_ctx(&sig->sig.sig_65, ctx, m,
-+ mlen, &pk->key.pk_65);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_dilithium_44_verify_ctx(&sig->sig.sig_44, ctx, m,
-+ mlen, &pk->key.pk_44);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_init,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_pk *pk)
-+{
-+ if (!pk)
-+ return -EINVAL;
-+
-+ switch (pk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_verify_init(ctx, &pk->key.pk_87);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_dilithium_65_verify_init(ctx, &pk->key.pk_65);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_dilithium_44_verify_init(ctx, &pk->key.pk_44);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_update,
-+ struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen)
-+{
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_verify_update(ctx, m, mlen);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ return lc_dilithium_65_verify_update(ctx, m, mlen);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ return lc_dilithium_44_verify_update(ctx, m, mlen);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_final,
-+ const struct lc_dilithium_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_pk *pk)
-+{
-+ if (!pk || !sig || sig->dilithium_type != pk->dilithium_type)
-+ return -EINVAL;
-+
-+ switch (pk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_verify_final(&sig->sig.sig_87, ctx,
-+ &pk->key.pk_87);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_dilithium_65_verify_final(&sig->sig.sig_65, ctx,
-+ &pk->key.pk_65);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_dilithium_44_verify_final(&sig->sig.sig_44, ctx,
-+ &pk->key.pk_44);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+/****************************** Dilithium ED25510 *****************************/
-+
-+#ifdef LC_DILITHIUM_ED25519_SIG
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_ctx_alloc,
-+ struct lc_dilithium_ed25519_ctx **ctx)
-+{
-+ if (!ctx)
-+ return -EINVAL;
-+
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed25519_ctx_alloc(ctx);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ return lc_dilithium_65_ed25519_ctx_alloc(ctx);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ return lc_dilithium_44_ed25519_ctx_alloc(ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ed25519_ctx_zero_free,
-+ struct lc_dilithium_ed25519_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ lc_dilithium_87_ed25519_ctx_zero_free(ctx);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ lc_dilithium_65_ed25519_ctx_zero_free(ctx);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ lc_dilithium_44_ed25519_ctx_zero_free(ctx);
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ed25519_ctx_zero,
-+ struct lc_dilithium_ed25519_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ lc_dilithium_87_ed25519_ctx_zero(ctx);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ lc_dilithium_65_ed25519_ctx_zero(ctx);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ lc_dilithium_44_ed25519_ctx_zero(ctx);
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ed25519_ctx_hash,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_hash *hash)
-+{
-+ if (ctx)
-+ ctx->dilithium_ctx.dilithium_prehash_type = hash;
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ed25519_ctx_internal,
-+ struct lc_dilithium_ed25519_ctx *ctx)
-+{
-+ if (ctx)
-+ ctx->dilithium_ctx.ml_dsa_internal = 1;
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ed25519_ctx_userctx,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *userctx, size_t userctxlen)
-+{
-+ if (ctx) {
-+ ctx->dilithium_ctx.userctx = userctx;
-+ ctx->dilithium_ctx.userctxlen = userctxlen;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ed25519_ctx_randomizer,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const uint8_t *randomizer, size_t randomizerlen)
-+{
-+ if (ctx) {
-+ ctx->dilithium_ctx.randomizer = randomizer;
-+ ctx->dilithium_ctx.randomizerlen = randomizerlen;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(enum lc_dilithium_type, lc_dilithium_ed25519_sk_type,
-+ const struct lc_dilithium_ed25519_sk *sk)
-+{
-+ if (!sk)
-+ return LC_DILITHIUM_UNKNOWN;
-+ return sk->dilithium_type;
-+}
-+
-+LC_INTERFACE_FUNCTION(enum lc_dilithium_type, lc_dilithium_ed25519_pk_type,
-+ const struct lc_dilithium_ed25519_pk *pk)
-+{
-+ if (!pk)
-+ return LC_DILITHIUM_UNKNOWN;
-+ return pk->dilithium_type;
-+}
-+
-+LC_INTERFACE_FUNCTION(enum lc_dilithium_type, lc_dilithium_ed25519_sig_type,
-+ const struct lc_dilithium_ed25519_sig *sig)
-+{
-+ if (!sig)
-+ return LC_DILITHIUM_UNKNOWN;
-+ return sig->dilithium_type;
-+}
-+
-+LC_PURE LC_INTERFACE_FUNCTION(unsigned int, lc_dilithium_ed25519_sk_size,
-+ enum lc_dilithium_type dilithium_type)
-+{
-+ switch (dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed25519_sk,
-+ key.sk_87);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed25519_sk,
-+ key.sk_65);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed25519_sk,
-+ key.sk_44);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return 0;
-+ }
-+}
-+
-+LC_PURE LC_INTERFACE_FUNCTION(unsigned int, lc_dilithium_ed25519_pk_size,
-+ enum lc_dilithium_type dilithium_type)
-+{
-+ switch (dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed25519_pk,
-+ key.pk_87);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed25519_pk,
-+ key.pk_65);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed25519_pk,
-+ key.pk_44);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return 0;
-+ }
-+}
-+
-+LC_PURE LC_INTERFACE_FUNCTION(unsigned int, lc_dilithium_ed25519_sig_size,
-+ enum lc_dilithium_type dilithium_type)
-+{
-+ switch (dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed25519_sig,
-+ sig.sig_87);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed25519_sig,
-+ sig.sig_65);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed25519_sig,
-+ sig.sig_44);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return 0;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_sk_load,
-+ struct lc_dilithium_ed25519_sk *sk,
-+ const uint8_t *dilithium_src_key,
-+ size_t dilithium_src_key_len,
-+ const uint8_t *ed25519_src_key,
-+ size_t ed25519_src_key_len)
-+{
-+ if (!sk || !dilithium_src_key || !ed25519_src_key ||
-+ ed25519_src_key_len != LC_ED25519_SECRETKEYBYTES) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (dilithium_src_key_len ==
-+ lc_dilithium_sk_size(LC_DILITHIUM_87)) {
-+ struct lc_dilithium_87_ed25519_sk *_sk = &sk->key.sk_87;
-+
-+ memcpy(_sk->sk.sk, dilithium_src_key, dilithium_src_key_len);
-+ memcpy(_sk->sk_ed25519.sk, ed25519_src_key,
-+ ed25519_src_key_len);
-+ sk->dilithium_type = LC_DILITHIUM_87;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (dilithium_src_key_len ==
-+ lc_dilithium_sk_size(LC_DILITHIUM_65)) {
-+ struct lc_dilithium_65_ed25519_sk *_sk = &sk->key.sk_65;
-+
-+ memcpy(_sk->sk.sk, dilithium_src_key, dilithium_src_key_len);
-+ memcpy(_sk->sk_ed25519.sk, ed25519_src_key,
-+ ed25519_src_key_len);
-+ sk->dilithium_type = LC_DILITHIUM_65;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (dilithium_src_key_len ==
-+ lc_dilithium_sk_size(LC_DILITHIUM_44)) {
-+ struct lc_dilithium_44_ed25519_sk *_sk = &sk->key.sk_44;
-+
-+ memcpy(_sk->sk.sk, dilithium_src_key, dilithium_src_key_len);
-+ memcpy(_sk->sk_ed25519.sk, ed25519_src_key,
-+ ed25519_src_key_len);
-+ sk->dilithium_type = LC_DILITHIUM_44;
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_pk_load,
-+ struct lc_dilithium_ed25519_pk *pk,
-+ const uint8_t *dilithium_src_key,
-+ size_t dilithium_src_key_len,
-+ const uint8_t *ed25519_src_key,
-+ size_t ed25519_src_key_len)
-+{
-+ if (!pk || !dilithium_src_key || !ed25519_src_key ||
-+ ed25519_src_key_len != LC_ED25519_PUBLICKEYBYTES) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (dilithium_src_key_len ==
-+ lc_dilithium_pk_size(LC_DILITHIUM_87)) {
-+ struct lc_dilithium_87_ed25519_pk *_pk = &pk->key.pk_87;
-+
-+ memcpy(_pk->pk.pk, dilithium_src_key, dilithium_src_key_len);
-+ memcpy(_pk->pk_ed25519.pk, ed25519_src_key,
-+ ed25519_src_key_len);
-+ pk->dilithium_type = LC_DILITHIUM_87;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (dilithium_src_key_len ==
-+ lc_dilithium_pk_size(LC_DILITHIUM_65)) {
-+ struct lc_dilithium_65_ed25519_pk *_pk = &pk->key.pk_65;
-+
-+ memcpy(_pk->pk.pk, dilithium_src_key, dilithium_src_key_len);
-+ memcpy(_pk->pk_ed25519.pk, ed25519_src_key,
-+ ed25519_src_key_len);
-+ pk->dilithium_type = LC_DILITHIUM_65;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (dilithium_src_key_len ==
-+ lc_dilithium_pk_size(LC_DILITHIUM_44)) {
-+ struct lc_dilithium_44_ed25519_pk *_pk = &pk->key.pk_44;
-+
-+ memcpy(_pk->pk.pk, dilithium_src_key, dilithium_src_key_len);
-+ memcpy(_pk->pk_ed25519.pk, ed25519_src_key,
-+ ed25519_src_key_len);
-+ pk->dilithium_type = LC_DILITHIUM_44;
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_sig_load,
-+ struct lc_dilithium_ed25519_sig *sig,
-+ const uint8_t *dilithium_src_sig,
-+ size_t dilithium_src_sig_len,
-+ const uint8_t *ed25519_src_sig,
-+ size_t ed25519_src_sig_len)
-+{
-+ if (!sig || !dilithium_src_sig || !ed25519_src_sig ||
-+ ed25519_src_sig_len != LC_ED25519_SIGBYTES) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (dilithium_src_sig_len ==
-+ lc_dilithium_sig_size(LC_DILITHIUM_87)) {
-+ struct lc_dilithium_87_ed25519_sig *_sig = &sig->sig.sig_87;
-+
-+ memcpy(_sig->sig.sig, dilithium_src_sig, dilithium_src_sig_len);
-+ memcpy(_sig->sig_ed25519.sig, ed25519_src_sig,
-+ ed25519_src_sig_len);
-+ sig->dilithium_type = LC_DILITHIUM_87;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (dilithium_src_sig_len ==
-+ lc_dilithium_sig_size(LC_DILITHIUM_65)) {
-+ struct lc_dilithium_65_ed25519_sig *_sig = &sig->sig.sig_65;
-+
-+ memcpy(_sig->sig.sig, dilithium_src_sig, dilithium_src_sig_len);
-+ memcpy(_sig->sig_ed25519.sig, ed25519_src_sig,
-+ ed25519_src_sig_len);
-+ sig->dilithium_type = LC_DILITHIUM_65;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (dilithium_src_sig_len ==
-+ lc_dilithium_sig_size(LC_DILITHIUM_44)) {
-+ struct lc_dilithium_44_ed25519_sig *_sig = &sig->sig.sig_44;
-+
-+ memcpy(_sig->sig.sig, dilithium_src_sig, dilithium_src_sig_len);
-+ memcpy(_sig->sig_ed25519.sig, ed25519_src_sig,
-+ ed25519_src_sig_len);
-+ sig->dilithium_type = LC_DILITHIUM_44;
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_sk_ptr, uint8_t **dilithium_key,
-+ size_t *dilithium_key_len, uint8_t **ed25519_key,
-+ size_t *ed25519_key_len,
-+ struct lc_dilithium_ed25519_sk *sk)
-+{
-+ if (!sk || !dilithium_key || !dilithium_key_len || !ed25519_key ||
-+ !ed25519_key_len) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (sk->dilithium_type == LC_DILITHIUM_87) {
-+ struct lc_dilithium_87_ed25519_sk *_sk = &sk->key.sk_87;
-+
-+ *dilithium_key = _sk->sk.sk;
-+ *dilithium_key_len = lc_dilithium_sk_size(sk->dilithium_type);
-+ *ed25519_key = _sk->sk_ed25519.sk;
-+ *ed25519_key_len = LC_ED25519_SECRETKEYBYTES;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (sk->dilithium_type == LC_DILITHIUM_65) {
-+ struct lc_dilithium_65_ed25519_sk *_sk = &sk->key.sk_65;
-+
-+ *dilithium_key = _sk->sk.sk;
-+ *dilithium_key_len = lc_dilithium_sk_size(sk->dilithium_type);
-+ *ed25519_key = _sk->sk_ed25519.sk;
-+ *ed25519_key_len = LC_ED25519_SECRETKEYBYTES;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (sk->dilithium_type == LC_DILITHIUM_44) {
-+ struct lc_dilithium_44_ed25519_sk *_sk = &sk->key.sk_44;
-+
-+ *dilithium_key = _sk->sk.sk;
-+ *dilithium_key_len = lc_dilithium_sk_size(sk->dilithium_type);
-+ *ed25519_key = _sk->sk_ed25519.sk;
-+ *ed25519_key_len = LC_ED25519_SECRETKEYBYTES;
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_pk_ptr, uint8_t **dilithium_key,
-+ size_t *dilithium_key_len, uint8_t **ed25519_key,
-+ size_t *ed25519_key_len,
-+ struct lc_dilithium_ed25519_pk *pk)
-+{
-+ if (!pk || !dilithium_key || !dilithium_key_len || !ed25519_key ||
-+ !ed25519_key_len) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (pk->dilithium_type == LC_DILITHIUM_87) {
-+ struct lc_dilithium_87_ed25519_pk *_pk = &pk->key.pk_87;
-+
-+ *dilithium_key = _pk->pk.pk;
-+ *dilithium_key_len = lc_dilithium_pk_size(pk->dilithium_type);
-+ *ed25519_key = _pk->pk_ed25519.pk;
-+ *ed25519_key_len = LC_ED25519_PUBLICKEYBYTES;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (pk->dilithium_type == LC_DILITHIUM_65) {
-+ struct lc_dilithium_65_ed25519_pk *_pk = &pk->key.pk_65;
-+
-+ *dilithium_key = _pk->pk.pk;
-+ *dilithium_key_len = lc_dilithium_pk_size(pk->dilithium_type);
-+ *ed25519_key = _pk->pk_ed25519.pk;
-+ *ed25519_key_len = LC_ED25519_PUBLICKEYBYTES;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (pk->dilithium_type == LC_DILITHIUM_44) {
-+ struct lc_dilithium_44_ed25519_pk *_pk = &pk->key.pk_44;
-+
-+ *dilithium_key = _pk->pk.pk;
-+ *dilithium_key_len = lc_dilithium_pk_size(pk->dilithium_type);
-+ *ed25519_key = _pk->pk_ed25519.pk;
-+ *ed25519_key_len = LC_ED25519_PUBLICKEYBYTES;
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_sig_ptr,
-+ uint8_t **dilithium_sig, size_t *dilithium_sig_len,
-+ uint8_t **ed25519_sig, size_t *ed25519_sig_len,
-+ struct lc_dilithium_ed25519_sig *sig)
-+{
-+ if (!sig || !dilithium_sig || !dilithium_sig_len || !ed25519_sig ||
-+ !ed25519_sig_len) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (sig->dilithium_type == LC_DILITHIUM_87) {
-+ struct lc_dilithium_87_ed25519_sig *_sig = &sig->sig.sig_87;
-+
-+ *dilithium_sig = _sig->sig.sig;
-+ *dilithium_sig_len = lc_dilithium_sig_size(sig->dilithium_type);
-+ *ed25519_sig = _sig->sig_ed25519.sig;
-+ *ed25519_sig_len = LC_ED25519_SIGBYTES;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (sig->dilithium_type == LC_DILITHIUM_65) {
-+ struct lc_dilithium_65_ed25519_sig *_sig = &sig->sig.sig_65;
-+
-+ *dilithium_sig = _sig->sig.sig;
-+ *dilithium_sig_len = lc_dilithium_sig_size(sig->dilithium_type);
-+ *ed25519_sig = _sig->sig_ed25519.sig;
-+ *ed25519_sig_len = LC_ED25519_SIGBYTES;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (sig->dilithium_type == LC_DILITHIUM_44) {
-+ struct lc_dilithium_44_ed25519_sig *_sig = &sig->sig.sig_44;
-+
-+ *dilithium_sig = _sig->sig.sig;
-+ *dilithium_sig_len = lc_dilithium_sig_size(sig->dilithium_type);
-+ *ed25519_sig = _sig->sig_ed25519.sig;
-+ *ed25519_sig_len = LC_ED25519_SIGBYTES;
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_keypair,
-+ struct lc_dilithium_ed25519_pk *pk,
-+ struct lc_dilithium_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx,
-+ enum lc_dilithium_type dilithium_type)
-+{
-+ if (!pk || !sk)
-+ return -EINVAL;
-+
-+ switch (dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ pk->dilithium_type = dilithium_type;
-+ sk->dilithium_type = dilithium_type;
-+ return lc_dilithium_87_ed25519_keypair(&pk->key.pk_87,
-+ &sk->key.sk_87, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ pk->dilithium_type = dilithium_type;
-+ sk->dilithium_type = dilithium_type;
-+ return lc_dilithium_65_ed25519_keypair(&pk->key.pk_65,
-+ &sk->key.sk_65, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ pk->dilithium_type = dilithium_type;
-+ sk->dilithium_type = dilithium_type;
-+ return lc_dilithium_44_ed25519_keypair(&pk->key.pk_44,
-+ &sk->key.sk_44, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_sign,
-+ struct lc_dilithium_ed25519_sig *sig, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ if (!sk || !sig)
-+ return -EINVAL;
-+
-+ switch (sk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_87;
-+ return lc_dilithium_87_ed25519_sign(&sig->sig.sig_87, m, mlen,
-+ &sk->key.sk_87, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_65;
-+ return lc_dilithium_65_ed25519_sign(&sig->sig.sig_65, m, mlen,
-+ &sk->key.sk_65, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_44;
-+ return lc_dilithium_44_ed25519_sign(&sig->sig.sig_44, m, mlen,
-+ &sk->key.sk_44, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_sign_ctx,
-+ struct lc_dilithium_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ if (!sk || !sig)
-+ return -EINVAL;
-+
-+ switch (sk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_87;
-+ return lc_dilithium_87_ed25519_sign_ctx(&sig->sig.sig_87, ctx,
-+ m, mlen, &sk->key.sk_87,
-+ rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_65;
-+ return lc_dilithium_65_ed25519_sign_ctx(&sig->sig.sig_65, ctx,
-+ m, mlen, &sk->key.sk_65,
-+ rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_44;
-+ return lc_dilithium_44_ed25519_sign_ctx(&sig->sig.sig_44, ctx,
-+ m, mlen, &sk->key.sk_44,
-+ rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_sign_init,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_ed25519_sk *sk)
-+{
-+ if (!ctx || !sk)
-+ return -EINVAL;
-+
-+ switch (sk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed25519_sign_init(ctx, &sk->key.sk_87);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_dilithium_65_ed25519_sign_init(ctx, &sk->key.sk_65);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_dilithium_44_ed25519_sign_init(ctx, &sk->key.sk_44);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_sign_update,
-+ struct lc_dilithium_ed25519_ctx *ctx, const uint8_t *m,
-+ size_t mlen)
-+{
-+ if (!ctx)
-+ return -EINVAL;
-+
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed25519_sign_update(ctx, m, mlen);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ return lc_dilithium_65_ed25519_sign_update(ctx, m, mlen);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ return lc_dilithium_44_ed25519_sign_update(ctx, m, mlen);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_sign_final,
-+ struct lc_dilithium_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_ed25519_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ if (!sk || !sig || !ctx)
-+ return -EINVAL;
-+
-+ switch (sk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_87;
-+ return lc_dilithium_87_ed25519_sign_final(
-+ &sig->sig.sig_87, ctx, &sk->key.sk_87, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_65;
-+ return lc_dilithium_65_ed25519_sign_final(
-+ &sig->sig.sig_65, ctx, &sk->key.sk_65, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_44;
-+ return lc_dilithium_44_ed25519_sign_final(
-+ &sig->sig.sig_44, ctx, &sk->key.sk_44, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_verify,
-+ const struct lc_dilithium_ed25519_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_ed25519_pk *pk)
-+{
-+ if (!pk || !sig || sig->dilithium_type != pk->dilithium_type)
-+ return -EINVAL;
-+
-+ switch (pk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed25519_verify(&sig->sig.sig_87, m, mlen,
-+ &pk->key.pk_87);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_dilithium_65_ed25519_verify(&sig->sig.sig_65, m, mlen,
-+ &pk->key.pk_65);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_dilithium_44_ed25519_verify(&sig->sig.sig_44, m, mlen,
-+ &pk->key.pk_44);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_verify_ctx,
-+ const struct lc_dilithium_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_ed25519_pk *pk)
-+{
-+ if (!pk || !sig || sig->dilithium_type != pk->dilithium_type)
-+ return -EINVAL;
-+
-+ switch (pk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed25519_verify_ctx(
-+ &sig->sig.sig_87, ctx, m, mlen, &pk->key.pk_87);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_dilithium_65_ed25519_verify_ctx(
-+ &sig->sig.sig_65, ctx, m, mlen, &pk->key.pk_65);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_dilithium_44_ed25519_verify_ctx(
-+ &sig->sig.sig_44, ctx, m, mlen, &pk->key.pk_44);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_verify_init,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_ed25519_pk *pk)
-+{
-+ if (!pk || !ctx)
-+ return -EINVAL;
-+
-+ switch (pk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed25519_verify_init(ctx, &pk->key.pk_87);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_dilithium_65_ed25519_verify_init(ctx, &pk->key.pk_65);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_dilithium_44_ed25519_verify_init(ctx, &pk->key.pk_44);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_verify_update,
-+ struct lc_dilithium_ed25519_ctx *ctx, const uint8_t *m,
-+ size_t mlen)
-+{
-+ if (!ctx)
-+ return -EINVAL;
-+
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed25519_verify_update(ctx, m, mlen);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ return lc_dilithium_65_ed25519_verify_update(ctx, m, mlen);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ return lc_dilithium_44_ed25519_verify_update(ctx, m, mlen);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed25519_verify_final,
-+ const struct lc_dilithium_ed25519_sig *sig,
-+ struct lc_dilithium_ed25519_ctx *ctx,
-+ const struct lc_dilithium_ed25519_pk *pk)
-+{
-+ if (!ctx || !pk || !sig || sig->dilithium_type != pk->dilithium_type)
-+ return -EINVAL;
-+
-+ switch (pk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed25519_verify_final(
-+ &sig->sig.sig_87, ctx, &pk->key.pk_87);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_dilithium_65_ed25519_verify_final(
-+ &sig->sig.sig_65, ctx, &pk->key.pk_65);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_dilithium_44_ed25519_verify_final(
-+ &sig->sig.sig_44, ctx, &pk->key.pk_44);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+#endif /* LC_DILITHIUM_ED25519_SIG */
-+
-+/****************************** Dilithium ED25510 *****************************/
-+
-+#ifdef LC_DILITHIUM_ED448_SIG
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_ctx_alloc,
-+ struct lc_dilithium_ed448_ctx **ctx)
-+{
-+ if (!ctx)
-+ return -EINVAL;
-+
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed448_ctx_alloc(ctx);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ return lc_dilithium_65_ed448_ctx_alloc(ctx);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ return lc_dilithium_44_ed448_ctx_alloc(ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ed448_ctx_zero_free,
-+ struct lc_dilithium_ed448_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ lc_dilithium_87_ed448_ctx_zero_free(ctx);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ lc_dilithium_65_ed448_ctx_zero_free(ctx);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ lc_dilithium_44_ed448_ctx_zero_free(ctx);
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ed448_ctx_zero,
-+ struct lc_dilithium_ed448_ctx *ctx)
-+{
-+ if (!ctx)
-+ return;
-+
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ lc_dilithium_87_ed448_ctx_zero(ctx);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ lc_dilithium_65_ed448_ctx_zero(ctx);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ lc_dilithium_44_ed448_ctx_zero(ctx);
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ed448_ctx_hash,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_hash *hash)
-+{
-+ if (ctx)
-+ ctx->dilithium_ctx.dilithium_prehash_type = hash;
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ed448_ctx_internal,
-+ struct lc_dilithium_ed448_ctx *ctx)
-+{
-+ if (ctx)
-+ ctx->dilithium_ctx.ml_dsa_internal = 1;
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ed448_ctx_userctx,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *userctx, size_t userctxlen)
-+{
-+ if (ctx) {
-+ ctx->dilithium_ctx.userctx = userctx;
-+ ctx->dilithium_ctx.userctxlen = userctxlen;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(void, lc_dilithium_ed448_ctx_randomizer,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const uint8_t *randomizer, size_t randomizerlen)
-+{
-+ if (ctx) {
-+ ctx->dilithium_ctx.randomizer = randomizer;
-+ ctx->dilithium_ctx.randomizerlen = randomizerlen;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(enum lc_dilithium_type, lc_dilithium_ed448_sk_type,
-+ const struct lc_dilithium_ed448_sk *sk)
-+{
-+ if (!sk)
-+ return LC_DILITHIUM_UNKNOWN;
-+ return sk->dilithium_type;
-+}
-+
-+LC_INTERFACE_FUNCTION(enum lc_dilithium_type, lc_dilithium_ed448_pk_type,
-+ const struct lc_dilithium_ed448_pk *pk)
-+{
-+ if (!pk)
-+ return LC_DILITHIUM_UNKNOWN;
-+ return pk->dilithium_type;
-+}
-+
-+LC_INTERFACE_FUNCTION(enum lc_dilithium_type, lc_dilithium_ed448_sig_type,
-+ const struct lc_dilithium_ed448_sig *sig)
-+{
-+ if (!sig)
-+ return LC_DILITHIUM_UNKNOWN;
-+ return sig->dilithium_type;
-+}
-+
-+LC_PURE LC_INTERFACE_FUNCTION(unsigned int, lc_dilithium_ed448_sk_size,
-+ enum lc_dilithium_type dilithium_type)
-+{
-+ switch (dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed448_sk, key.sk_87);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed448_sk, key.sk_65);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed448_sk, key.sk_44);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return 0;
-+ }
-+}
-+
-+LC_PURE LC_INTERFACE_FUNCTION(unsigned int, lc_dilithium_ed448_pk_size,
-+ enum lc_dilithium_type dilithium_type)
-+{
-+ switch (dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed448_pk, key.pk_87);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed448_pk, key.pk_65);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed448_pk, key.pk_44);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return 0;
-+ }
-+}
-+
-+LC_PURE LC_INTERFACE_FUNCTION(unsigned int, lc_dilithium_ed448_sig_size,
-+ enum lc_dilithium_type dilithium_type)
-+{
-+ switch (dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed448_sig,
-+ sig.sig_87);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed448_sig,
-+ sig.sig_65);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_member_size(struct lc_dilithium_ed448_sig,
-+ sig.sig_44);
-+#else
-+ return 0;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return 0;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_sk_load,
-+ struct lc_dilithium_ed448_sk *sk,
-+ const uint8_t *dilithium_src_key,
-+ size_t dilithium_src_key_len,
-+ const uint8_t *ed448_src_key, size_t ed448_src_key_len)
-+{
-+ if (!sk || !dilithium_src_key || !ed448_src_key ||
-+ ed448_src_key_len != LC_ED448_SECRETKEYBYTES) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (dilithium_src_key_len ==
-+ lc_dilithium_sk_size(LC_DILITHIUM_87)) {
-+ struct lc_dilithium_87_ed448_sk *_sk = &sk->key.sk_87;
-+
-+ memcpy(_sk->sk.sk, dilithium_src_key, dilithium_src_key_len);
-+ memcpy(_sk->sk_ed448.sk, ed448_src_key, ed448_src_key_len);
-+ sk->dilithium_type = LC_DILITHIUM_87;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (dilithium_src_key_len ==
-+ lc_dilithium_sk_size(LC_DILITHIUM_65)) {
-+ struct lc_dilithium_65_ed448_sk *_sk = &sk->key.sk_65;
-+
-+ memcpy(_sk->sk.sk, dilithium_src_key, dilithium_src_key_len);
-+ memcpy(_sk->sk_ed448.sk, ed448_src_key, ed448_src_key_len);
-+ sk->dilithium_type = LC_DILITHIUM_65;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (dilithium_src_key_len ==
-+ lc_dilithium_sk_size(LC_DILITHIUM_44)) {
-+ struct lc_dilithium_44_ed448_sk *_sk = &sk->key.sk_44;
-+
-+ memcpy(_sk->sk.sk, dilithium_src_key, dilithium_src_key_len);
-+ memcpy(_sk->sk_ed448.sk, ed448_src_key, ed448_src_key_len);
-+ sk->dilithium_type = LC_DILITHIUM_44;
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_pk_load,
-+ struct lc_dilithium_ed448_pk *pk,
-+ const uint8_t *dilithium_src_key,
-+ size_t dilithium_src_key_len,
-+ const uint8_t *ed448_src_key, size_t ed448_src_key_len)
-+{
-+ if (!pk || !dilithium_src_key || !ed448_src_key ||
-+ ed448_src_key_len != LC_ED448_PUBLICKEYBYTES) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (dilithium_src_key_len ==
-+ lc_dilithium_pk_size(LC_DILITHIUM_87)) {
-+ struct lc_dilithium_87_ed448_pk *_pk = &pk->key.pk_87;
-+
-+ memcpy(_pk->pk.pk, dilithium_src_key, dilithium_src_key_len);
-+ memcpy(_pk->pk_ed448.pk, ed448_src_key, ed448_src_key_len);
-+ pk->dilithium_type = LC_DILITHIUM_87;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (dilithium_src_key_len ==
-+ lc_dilithium_pk_size(LC_DILITHIUM_65)) {
-+ struct lc_dilithium_65_ed448_pk *_pk = &pk->key.pk_65;
-+
-+ memcpy(_pk->pk.pk, dilithium_src_key, dilithium_src_key_len);
-+ memcpy(_pk->pk_ed448.pk, ed448_src_key, ed448_src_key_len);
-+ pk->dilithium_type = LC_DILITHIUM_65;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (dilithium_src_key_len ==
-+ lc_dilithium_pk_size(LC_DILITHIUM_44)) {
-+ struct lc_dilithium_44_ed448_pk *_pk = &pk->key.pk_44;
-+
-+ memcpy(_pk->pk.pk, dilithium_src_key, dilithium_src_key_len);
-+ memcpy(_pk->pk_ed448.pk, ed448_src_key, ed448_src_key_len);
-+ pk->dilithium_type = LC_DILITHIUM_44;
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_sig_load,
-+ struct lc_dilithium_ed448_sig *sig,
-+ const uint8_t *dilithium_src_sig,
-+ size_t dilithium_src_sig_len,
-+ const uint8_t *ed448_src_sig, size_t ed448_src_sig_len)
-+{
-+ if (!sig || !dilithium_src_sig || !ed448_src_sig ||
-+ ed448_src_sig_len != LC_ED448_SIGBYTES) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (dilithium_src_sig_len ==
-+ lc_dilithium_sig_size(LC_DILITHIUM_87)) {
-+ struct lc_dilithium_87_ed448_sig *_sig = &sig->sig.sig_87;
-+
-+ memcpy(_sig->sig.sig, dilithium_src_sig, dilithium_src_sig_len);
-+ memcpy(_sig->sig_ed448.sig, ed448_src_sig, ed448_src_sig_len);
-+ sig->dilithium_type = LC_DILITHIUM_87;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (dilithium_src_sig_len ==
-+ lc_dilithium_sig_size(LC_DILITHIUM_65)) {
-+ struct lc_dilithium_65_ed448_sig *_sig = &sig->sig.sig_65;
-+
-+ memcpy(_sig->sig.sig, dilithium_src_sig, dilithium_src_sig_len);
-+ memcpy(_sig->sig_ed448.sig, ed448_src_sig, ed448_src_sig_len);
-+ sig->dilithium_type = LC_DILITHIUM_65;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (dilithium_src_sig_len ==
-+ lc_dilithium_sig_size(LC_DILITHIUM_44)) {
-+ struct lc_dilithium_44_ed448_sig *_sig = &sig->sig.sig_44;
-+
-+ memcpy(_sig->sig.sig, dilithium_src_sig, dilithium_src_sig_len);
-+ memcpy(_sig->sig_ed448.sig, ed448_src_sig, ed448_src_sig_len);
-+ sig->dilithium_type = LC_DILITHIUM_44;
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_sk_ptr, uint8_t **dilithium_key,
-+ size_t *dilithium_key_len, uint8_t **ed448_key,
-+ size_t *ed448_key_len, struct lc_dilithium_ed448_sk *sk)
-+{
-+ if (!sk || !dilithium_key || !dilithium_key_len || !ed448_key ||
-+ !ed448_key_len) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (sk->dilithium_type == LC_DILITHIUM_87) {
-+ struct lc_dilithium_87_ed448_sk *_sk = &sk->key.sk_87;
-+
-+ *dilithium_key = _sk->sk.sk;
-+ *dilithium_key_len = lc_dilithium_sk_size(sk->dilithium_type);
-+ *ed448_key = _sk->sk_ed448.sk;
-+ *ed448_key_len = LC_ED448_SECRETKEYBYTES;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (sk->dilithium_type == LC_DILITHIUM_65) {
-+ struct lc_dilithium_65_ed448_sk *_sk = &sk->key.sk_65;
-+
-+ *dilithium_key = _sk->sk.sk;
-+ *dilithium_key_len = lc_dilithium_sk_size(sk->dilithium_type);
-+ *ed448_key = _sk->sk_ed448.sk;
-+ *ed448_key_len = LC_ED448_SECRETKEYBYTES;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (sk->dilithium_type == LC_DILITHIUM_44) {
-+ struct lc_dilithium_44_ed448_sk *_sk = &sk->key.sk_44;
-+
-+ *dilithium_key = _sk->sk.sk;
-+ *dilithium_key_len = lc_dilithium_sk_size(sk->dilithium_type);
-+ *ed448_key = _sk->sk_ed448.sk;
-+ *ed448_key_len = LC_ED448_SECRETKEYBYTES;
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_pk_ptr, uint8_t **dilithium_key,
-+ size_t *dilithium_key_len, uint8_t **ed448_key,
-+ size_t *ed448_key_len, struct lc_dilithium_ed448_pk *pk)
-+{
-+ if (!pk || !dilithium_key || !dilithium_key_len || !ed448_key ||
-+ !ed448_key_len) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (pk->dilithium_type == LC_DILITHIUM_87) {
-+ struct lc_dilithium_87_ed448_pk *_pk = &pk->key.pk_87;
-+
-+ *dilithium_key = _pk->pk.pk;
-+ *dilithium_key_len = lc_dilithium_pk_size(pk->dilithium_type);
-+ *ed448_key = _pk->pk_ed448.pk;
-+ *ed448_key_len = LC_ED448_PUBLICKEYBYTES;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (pk->dilithium_type == LC_DILITHIUM_65) {
-+ struct lc_dilithium_65_ed448_pk *_pk = &pk->key.pk_65;
-+
-+ *dilithium_key = _pk->pk.pk;
-+ *dilithium_key_len = lc_dilithium_pk_size(pk->dilithium_type);
-+ *ed448_key = _pk->pk_ed448.pk;
-+ *ed448_key_len = LC_ED448_PUBLICKEYBYTES;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (pk->dilithium_type == LC_DILITHIUM_44) {
-+ struct lc_dilithium_44_ed448_pk *_pk = &pk->key.pk_44;
-+
-+ *dilithium_key = _pk->pk.pk;
-+ *dilithium_key_len = lc_dilithium_pk_size(pk->dilithium_type);
-+ *ed448_key = _pk->pk_ed448.pk;
-+ *ed448_key_len = LC_ED448_PUBLICKEYBYTES;
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_sig_ptr, uint8_t **dilithium_sig,
-+ size_t *dilithium_sig_len, uint8_t **ed448_sig,
-+ size_t *ed448_sig_len, struct lc_dilithium_ed448_sig *sig)
-+{
-+ if (!sig || !dilithium_sig || !dilithium_sig_len || !ed448_sig ||
-+ !ed448_sig_len) {
-+ return -EINVAL;
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ } else if (sig->dilithium_type == LC_DILITHIUM_87) {
-+ struct lc_dilithium_87_ed448_sig *_sig = &sig->sig.sig_87;
-+
-+ *dilithium_sig = _sig->sig.sig;
-+ *dilithium_sig_len = lc_dilithium_sig_size(sig->dilithium_type);
-+ *ed448_sig = _sig->sig_ed448.sig;
-+ *ed448_sig_len = LC_ED448_SIGBYTES;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ } else if (sig->dilithium_type == LC_DILITHIUM_65) {
-+ struct lc_dilithium_65_ed448_sig *_sig = &sig->sig.sig_65;
-+
-+ *dilithium_sig = _sig->sig.sig;
-+ *dilithium_sig_len = lc_dilithium_sig_size(sig->dilithium_type);
-+ *ed448_sig = _sig->sig_ed448.sig;
-+ *ed448_sig_len = LC_ED448_SIGBYTES;
-+ return 0;
-+#endif
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ } else if (sig->dilithium_type == LC_DILITHIUM_44) {
-+ struct lc_dilithium_44_ed448_sig *_sig = &sig->sig.sig_44;
-+
-+ *dilithium_sig = _sig->sig.sig;
-+ *dilithium_sig_len = lc_dilithium_sig_size(sig->dilithium_type);
-+ *ed448_sig = _sig->sig_ed448.sig;
-+ *ed448_sig_len = LC_ED448_SIGBYTES;
-+ return 0;
-+#endif
-+ } else {
-+ return -EINVAL;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_keypair,
-+ struct lc_dilithium_ed448_pk *pk,
-+ struct lc_dilithium_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx,
-+ enum lc_dilithium_type dilithium_type)
-+{
-+ if (!pk || !sk)
-+ return -EINVAL;
-+
-+ switch (dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ pk->dilithium_type = dilithium_type;
-+ sk->dilithium_type = dilithium_type;
-+ return lc_dilithium_87_ed448_keypair(&pk->key.pk_87,
-+ &sk->key.sk_87, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ pk->dilithium_type = dilithium_type;
-+ sk->dilithium_type = dilithium_type;
-+ return lc_dilithium_65_ed448_keypair(&pk->key.pk_65,
-+ &sk->key.sk_65, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ pk->dilithium_type = dilithium_type;
-+ sk->dilithium_type = dilithium_type;
-+ return lc_dilithium_44_ed448_keypair(&pk->key.pk_44,
-+ &sk->key.sk_44, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_sign,
-+ struct lc_dilithium_ed448_sig *sig, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ if (!sk || !sig)
-+ return -EINVAL;
-+
-+ switch (sk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_87;
-+ return lc_dilithium_87_ed448_sign(&sig->sig.sig_87, m, mlen,
-+ &sk->key.sk_87, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_65;
-+ return lc_dilithium_65_ed448_sign(&sig->sig.sig_65, m, mlen,
-+ &sk->key.sk_65, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_44;
-+ return lc_dilithium_44_ed448_sign(&sig->sig.sig_44, m, mlen,
-+ &sk->key.sk_44, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_sign_ctx,
-+ struct lc_dilithium_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ if (!sk || !sig)
-+ return -EINVAL;
-+
-+ switch (sk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_87;
-+ return lc_dilithium_87_ed448_sign_ctx(&sig->sig.sig_87, ctx, m,
-+ mlen, &sk->key.sk_87,
-+ rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_65;
-+ return lc_dilithium_65_ed448_sign_ctx(&sig->sig.sig_65, ctx, m,
-+ mlen, &sk->key.sk_65,
-+ rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_44;
-+ return lc_dilithium_44_ed448_sign_ctx(&sig->sig.sig_44, ctx, m,
-+ mlen, &sk->key.sk_44,
-+ rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_sign_init,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_ed448_sk *sk)
-+{
-+ if (!ctx || !sk)
-+ return -EINVAL;
-+
-+ switch (sk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed448_sign_init(ctx, &sk->key.sk_87);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_dilithium_65_ed448_sign_init(ctx, &sk->key.sk_65);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_dilithium_44_ed448_sign_init(ctx, &sk->key.sk_44);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_sign_update,
-+ struct lc_dilithium_ed448_ctx *ctx, const uint8_t *m,
-+ size_t mlen)
-+{
-+ if (!ctx)
-+ return -EINVAL;
-+
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed448_sign_update(ctx, m, mlen);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ return lc_dilithium_65_ed448_sign_update(ctx, m, mlen);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ return lc_dilithium_44_ed448_sign_update(ctx, m, mlen);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_sign_final,
-+ struct lc_dilithium_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_ed448_sk *sk,
-+ struct lc_rng_ctx *rng_ctx)
-+{
-+ if (!sk || !sig || !ctx)
-+ return -EINVAL;
-+
-+ switch (sk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_87;
-+ return lc_dilithium_87_ed448_sign_final(
-+ &sig->sig.sig_87, ctx, &sk->key.sk_87, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_65;
-+ return lc_dilithium_65_ed448_sign_final(
-+ &sig->sig.sig_65, ctx, &sk->key.sk_65, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ sig->dilithium_type = LC_DILITHIUM_44;
-+ return lc_dilithium_44_ed448_sign_final(
-+ &sig->sig.sig_44, ctx, &sk->key.sk_44, rng_ctx);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_verify,
-+ const struct lc_dilithium_ed448_sig *sig,
-+ const uint8_t *m, size_t mlen,
-+ const struct lc_dilithium_ed448_pk *pk)
-+{
-+ if (!pk || !sig || sig->dilithium_type != pk->dilithium_type)
-+ return -EINVAL;
-+
-+ switch (pk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed448_verify(&sig->sig.sig_87, m, mlen,
-+ &pk->key.pk_87);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_dilithium_65_ed448_verify(&sig->sig.sig_65, m, mlen,
-+ &pk->key.pk_65);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_dilithium_44_ed448_verify(&sig->sig.sig_44, m, mlen,
-+ &pk->key.pk_44);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_verify_ctx,
-+ const struct lc_dilithium_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx, const uint8_t *m,
-+ size_t mlen, const struct lc_dilithium_ed448_pk *pk)
-+{
-+ if (!pk || !sig || sig->dilithium_type != pk->dilithium_type)
-+ return -EINVAL;
-+
-+ switch (pk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed448_verify_ctx(
-+ &sig->sig.sig_87, ctx, m, mlen, &pk->key.pk_87);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_dilithium_65_ed448_verify_ctx(
-+ &sig->sig.sig_65, ctx, m, mlen, &pk->key.pk_65);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_dilithium_44_ed448_verify_ctx(
-+ &sig->sig.sig_44, ctx, m, mlen, &pk->key.pk_44);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_verify_init,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_ed448_pk *pk)
-+{
-+ if (!pk || !ctx)
-+ return -EINVAL;
-+
-+ switch (pk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed448_verify_init(ctx, &pk->key.pk_87);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_dilithium_65_ed448_verify_init(ctx, &pk->key.pk_65);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_dilithium_44_ed448_verify_init(ctx, &pk->key.pk_44);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_verify_update,
-+ struct lc_dilithium_ed448_ctx *ctx, const uint8_t *m,
-+ size_t mlen)
-+{
-+ if (!ctx)
-+ return -EINVAL;
-+
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed448_verify_update(ctx, m, mlen);
-+#elif defined(LC_DILITHIUM_65_ENABLED)
-+ return lc_dilithium_65_ed448_verify_update(ctx, m, mlen);
-+#elif defined(LC_DILITHIUM_44_ENABLED)
-+ return lc_dilithium_44_ed448_verify_update(ctx, m, mlen);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+}
-+
-+LC_INTERFACE_FUNCTION(int, lc_dilithium_ed448_verify_final,
-+ const struct lc_dilithium_ed448_sig *sig,
-+ struct lc_dilithium_ed448_ctx *ctx,
-+ const struct lc_dilithium_ed448_pk *pk)
-+{
-+ if (!ctx || !pk || !sig || sig->dilithium_type != pk->dilithium_type)
-+ return -EINVAL;
-+
-+ switch (pk->dilithium_type) {
-+ case LC_DILITHIUM_87:
-+#ifdef LC_DILITHIUM_87_ENABLED
-+ return lc_dilithium_87_ed448_verify_final(&sig->sig.sig_87, ctx,
-+ &pk->key.pk_87);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_65:
-+#ifdef LC_DILITHIUM_65_ENABLED
-+ return lc_dilithium_65_ed448_verify_final(&sig->sig.sig_65, ctx,
-+ &pk->key.pk_65);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_44:
-+#ifdef LC_DILITHIUM_44_ENABLED
-+ return lc_dilithium_44_ed448_verify_final(&sig->sig.sig_44, ctx,
-+ &pk->key.pk_44);
-+#else
-+ return -EOPNOTSUPP;
-+#endif
-+ case LC_DILITHIUM_UNKNOWN:
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+}
-+
-+#endif /* LC_DILITHIUM_ED448_SIG */
-diff --git a/lib/freebl/leancrypto/mldsa_zetas.c b/lib/freebl/leancrypto/mldsa_zetas.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/mldsa_zetas.c
-@@ -0,0 +1,70 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/dilithium
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
-+ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
-+ */
-+
-+#include "dilithium_zetas.h"
-+#include "ext_headers.h"
-+
-+LC_FIPS_RODATA_SECTION
-+const int32_t dilithium_zetas[LC_DILITHIUM_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
-+};
-diff --git a/lib/freebl/leancrypto/mutex_w.h b/lib/freebl/leancrypto/mutex_w.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/mutex_w.h
-@@ -0,0 +1,159 @@
-+/*
-+ * Copyright (C) 2018 - 2025, Stephan Mueller
-+ *
-+ * License: see COPYING file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef _MUTEX_W_H
-+#define _MUTEX_W_H
-+
-+#include "atomic.h"
-+#include "atomic_bool.h"
-+
-+/**
-+ * @brief Writer mutex with a polling mechanism
-+ *
-+ * This mutex and its implementation below is intended to cover the needs of
-+ * leancrypto and having no dependencies whatsoever. Thus, the implementation
-+ * is below is not intended for general-purpose use! Yet, it serves its purpose
-+ * for leancrypto.
-+ */
-+typedef struct {
-+ atomic_bool_t lock;
-+ atomic_t writer_pending;
-+} mutex_w_t;
-+
-+/* 1 microsecond when using nanosleep */
-+#define MUTEX_DEFAULT_SLEEP_TIME_NS (1 << 10)
-+/** 1 << (MUTEX_DEFAULT_SLEEP_TIME_NS + MUTEX_MAX_INC_BITS) */
-+#define MUTEX_MAX_INC_BITS 14
-+
-+#define __MUTEX_W_INITIALIZER(locked) \
-+ { \
-+ .lock = ATOMIC_BOOL_INIT(locked), \
-+ .writer_pending = ATOMIC_INIT(0), \
-+ }
-+
-+#define DEFINE_MUTEX_W_UNLOCKED(name) \
-+ mutex_w_t name = __MUTEX_W_INITIALIZER(false)
-+
-+#define DEFINE_MUTEX_W_LOCKED(name) mutex_w_t name = __MUTEX_W_INITIALIZER(true)
-+
-+/*
-+ * Instead of using a environment-dependent nanosleep implementation, we use
-+ * a small busy-wait loop which should serve the purpose of the short-duration
-+ * contentions possible in leancrypto.
-+ */
-+#if 0
-+#include
-+static inline void mutex_w_sleep(mutex_w_t *mutex)
-+{
-+ struct timespec sleeptime = { .tv_sec = 0,
-+ .tv_nsec = MUTEX_DEFAULT_SLEEP_TIME_NS};
-+ int pending = atomic_read(&mutex->writer_pending);
-+
-+ /* Increase wait time exponentially depending on waiters */
-+ if (pending > MUTEX_MAX_INC_BITS)
-+ pending = MUTEX_MAX_INC_BITS;
-+ if (pending < 0)
-+ pending = 0;
-+ sleeptime.tv_nsec <<= pending;
-+ nanosleep(&sleeptime, NULL);
-+}
-+#else
-+static inline void mutex_w_sleep(mutex_w_t *mutex)
-+{
-+ uint64_t tv_nsec = MUTEX_DEFAULT_SLEEP_TIME_NS;
-+ /*
-+ * Use volatile to ensure the compiler does not optimize the busyloop
-+ * away.
-+ */
-+ volatile uint64_t i;
-+ int pending = atomic_read(&mutex->writer_pending);
-+
-+ /* Increase wait time exponentially depending on waiters */
-+ if (pending > MUTEX_MAX_INC_BITS)
-+ pending = MUTEX_MAX_INC_BITS;
-+ if (pending < 0)
-+ pending = 0;
-+ tv_nsec <<= pending;
-+
-+ /* Busy-loop for sleeping */
-+ for (i = 0; i < tv_nsec; i++)
-+ ;
-+}
-+#endif
-+
-+/**
-+ * @brief Initialize a mutex
-+ * @param mutex [in] Lock variable to initialize.
-+ * @param locked [in] Specify whether the lock shall already be locked (true)
-+ * or unlocked (false).
-+ */
-+static inline void mutex_w_init(mutex_w_t *mutex, bool locked)
-+{
-+ atomic_bool_set(locked, &mutex->lock);
-+ atomic_set(&mutex->writer_pending, 0);
-+}
-+
-+static inline void mutex_w_destroy(mutex_w_t *mutex)
-+{
-+ (void)mutex;
-+}
-+
-+/**
-+ * Mutual exclusion lock (covering also the reader lock use case).
-+ * @param mutex [in] lock variable to lock
-+ */
-+static inline void mutex_w_lock(mutex_w_t *mutex)
-+{
-+ atomic_inc(&mutex->writer_pending);
-+
-+ /* Take the writer lock only if no writer lock is taken. */
-+ while (!atomic_bool_cmpxchg(&mutex->lock, false, true))
-+ mutex_w_sleep(mutex);
-+
-+ atomic_dec(&mutex->writer_pending);
-+}
-+
-+/**
-+ * Mutual exclusion lock: Attempt to take the lock. The function will never
-+ * block but return whether the lock was successfully taken or not.
-+ *
-+ * @param mutex [in] lock variable to lock
-+ * @return true if lock was taken, false if lock was not taken
-+ */
-+static inline bool mutex_w_trylock(mutex_w_t *mutex)
-+{
-+ return atomic_bool_cmpxchg(&mutex->lock, false, true);
-+}
-+
-+static inline bool mutex_w_islocked(mutex_w_t *mutex)
-+{
-+ return atomic_bool_read(&mutex->lock);
-+}
-+
-+/**
-+ * Unlock the lock
-+ * @param mutex [in] lock variable to lock
-+ */
-+static inline void mutex_w_unlock(mutex_w_t *mutex)
-+{
-+ /* Release the writer lock. */
-+ atomic_bool_cmpxchg(&mutex->lock, true, false);
-+}
-+
-+#endif /* _MUTEX_W_H */
-diff --git a/lib/freebl/leancrypto/new_headers/lc_hash.h b/lib/freebl/leancrypto/new_headers/lc_hash.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/new_headers/lc_hash.h
-@@ -0,0 +1,17 @@
-+#include "hasht.h"
-+#include "blapit.h"
-+#include "lc_memset_secure.h" /* sigh the original included it,
-+ * so some files expect it to be there already */
-+#include "lc_memory_support.h"
-+/* sigh Stephen doesn seem to believe in typedef, so
-+ * just stuff our context pointer into a struct */
-+#define LC_SHA3_256_CTX_SIZE (SHA3_256_BLOCK_LENGTH)
-+#define LC_SHA3_STATE_SIZE_ALIGN(x) (x)
-+
-+#define LC_SHA3_512_SIZE_DIGEST SHA3_512_LENGTH
-+
-+#ifndef LC_HASH_COMMON_ALIGNMENT
-+#define LC_HASH_COMMON_ALIGNMENT 64
-+#endif
-+
-+
-diff --git a/lib/freebl/leancrypto/new_headers/lc_rng.h b/lib/freebl/leancrypto/new_headers/lc_rng.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/new_headers/lc_rng.h
-@@ -0,0 +1,56 @@
-+#ifndef LC_RNG_H
-+#define LC_RNG_H 1
-+#include
-+#include
-+
-+struct lc_rng_ctx;
-+extern struct lc_rng_ctx *lc_seeded_rng;
-+
-+/* just enough of the rng_context to make the code happy.
-+ * in the end, we just use our NSS internal RNG */
-+struct lc_static_rng_data {
-+ const unsigned char *seed;
-+ size_t seedlen;
-+};
-+
-+struct lc_rng_ctx {
-+ struct lc_static_rng_data *dummy;
-+};
-+
-+static inline int lc_rng_generate(struct lc_rng_ctx *rng,
-+ unsigned char *addinput,
-+ size_t addlen,
-+ unsigned char *out,
-+ size_t outlen)
-+{
-+ size_t len;
-+ if (rng->dummy != NULL) {
-+ if (outlen > rng->dummy->seedlen) {
-+ return -1;
-+ }
-+ PORT_Memcpy(out, rng->dummy->seed, outlen);
-+ return 0;
-+ }
-+ if (addlen != 0) {
-+ RNG_RandomUpdate(addinput, addlen);
-+ }
-+ len= RNG_SystemRNG(out, outlen);
-+ if (len != outlen) {
-+ return -1;
-+ }
-+ return 0;
-+}
-+
-+#define lc_rng_seed(rng, seed, seedlen, pers, perslen) {\
-+ if (pers_len != 0) {\
-+ RNG_RandomUpdate(pers, perslen); \
-+ } \
-+ RNG_SystemRNG(seed, seedlen); \
-+}
-+#define lc_rng_check(rng)
-+
-+#define LC_STATIC_DRNG_ON_STACK(sdrng, state)\
-+ struct lc_rng_ctx sdrng; \
-+ sdrng.dummy = state;
-+
-+#endif
-diff --git a/lib/freebl/leancrypto/new_headers/lc_sha3.h b/lib/freebl/leancrypto/new_headers/lc_sha3.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/new_headers/lc_sha3.h
-@@ -0,0 +1,213 @@
-+// SPDX-License-Identifier: MIT
-+// NSS SHA3 bindings for ML-DSA leancrypto
-+
-+#ifndef LC_SHA3__H
-+#define LC_SHA3__H
-+#include
-+
-+#define LC_SHA3_SIZE_RATE(bits) ((1600 - 2 * bits) >> 3)
-+
-+#define LC_SHAKE_128_SIZE_BLOCK LC_SHA3_SIZE_RATE(128)
-+#define LC_SHAKE_256_SIZE_BLOCK LC_SHA3_SIZE_RATE(256)
-+
-+/*#define SHAKE128_RATE 168
-+#define shake128 SHAKE_128_HashBuf
-+
-+#define SHAKE256_RATE SHA3_256_BLOCK_LENGTH
-+#define shake256 SHAKE_256_HashBuf */
-+
-+#define LC_HASH_CTX_ON_STACK(name, type_) \
-+ struct lc_hash_ctx _##name ; \
-+ _##name.hash= type_; \
-+ _##name.buf= NULL; \
-+ _##name.stream = false; \
-+ _##name.u.ctx_ptr = NULL; \
-+ struct lc_hash_ctx *name= &_##name;
-+
-+#define LC_HASH_SET_CTX(name, type_) \
-+ name->hash= type_;
-+
-+#define LC_SHAKE_256_CTX(name) \
-+ LC_HASH_SET_CTX(name, lc_shake256);
-+
-+typedef enum {
-+ lc_shake128,
-+ lc_shake256,
-+} sha3Type;
-+
-+
-+/* sigh, we buffer eKEverything because we can't correctly do multiple
-+ * finals correctly. In cases where we know we are not going to
-+ * do multiple finals, set the streaming bool */
-+struct lc_hash_ctx {
-+ sha3Type hash;
-+ bool stream;
-+ union {
-+ SHAKE_256Context *shake256_ctx;
-+ SHAKE_128Context *shake128_ctx;
-+ void *ctx_ptr;
-+ }u;
-+ size_t digestSize;
-+ size_t current_input;
-+ size_t current_output;
-+ unsigned char *buf;
-+ size_t buf_size;
-+ unsigned char buf_space[2048];
-+ unsigned char buf2_space[2048];
-+};
-+
-+#define lc_xof(type, in, inlen, out, outlen) \
-+ switch(type) { \
-+ case lc_shake128: \
-+ SHAKE_128_HashBuf(out, outlen, in, inlen); \
-+ break; \
-+ case lc_shake256: \
-+ SHAKE_256_HashBuf(out, outlen, in, inlen); \
-+ break; \
-+ default: \
-+ assert(0); \
-+ }
-+
-+static inline void
-+lc_hash_init(struct lc_hash_ctx *ptr) {
-+ if (ptr->stream) {
-+ /* if we already have a context, just reset it, This is
-+ * what the caller wanted, saving a destroy and create */
-+ if (ptr->u.ctx_ptr == NULL) {
-+ switch (ptr->hash) {
-+ case lc_shake128:
-+ ptr->u.shake128_ctx = SHAKE_128_NewContext();
-+ break;
-+ case lc_shake256:
-+ ptr->u.shake256_ctx = SHAKE_256_NewContext();
-+ break;
-+ }
-+ }
-+ switch (ptr->hash) {
-+ case lc_shake128:
-+ SHAKE_128_Begin(ptr->u.shake128_ctx);
-+ break;
-+ case lc_shake256:
-+ SHAKE_256_Begin(ptr->u.shake256_ctx);
-+ break;
-+ }
-+ return;
-+ }
-+ /* we can be called with an active buffer, do and implicit reset here
-+ * and free that buffer before we set up the next one */
-+ if (ptr->buf && ptr->buf != ptr->buf_space) {
-+ memset(ptr->buf, 0, ptr->current_input);
-+ free(ptr->buf);
-+ }
-+ ptr->digestSize = 0;
-+ ptr->current_input = 0;
-+ ptr->current_output = 0;
-+ ptr->buf_size = sizeof(ptr->buf_space);
-+ ptr->buf = &ptr->buf_space[0];
-+}
-+
-+static inline void
-+lc_hash_update(struct lc_hash_ctx *ptr, const unsigned char *input, size_t inLen) {
-+ if (inLen ==0) { return; } /* why were we even called with a NULL buffer? */
-+ if (ptr->stream) {
-+ switch (ptr->hash) {
-+ case lc_shake128:
-+ SHAKE_128_Absorb(ptr->u.shake128_ctx, input, inLen);
-+ break;
-+ case lc_shake256:
-+ SHAKE_256_Absorb(ptr->u.shake256_ctx, input, inLen);
-+ break;
-+ }
-+ return;
-+ }
-+ if (ptr->current_input + inLen > ptr->buf_size) {
-+ int len = ptr->current_input + inLen + 2048;
-+ unsigned char *newBuf;
-+ if (ptr->buf_size == sizeof(ptr->buf_space)) {
-+ newBuf = calloc(1, len);
-+ if (newBuf) {
-+ memcpy(newBuf, ptr->buf, ptr->buf_size);
-+ memset(ptr->buf_space, 0, sizeof(ptr->buf_space));
-+ }
-+ } else {
-+ newBuf = reallocarray(ptr->buf, 1, len);
-+ }
-+ if (!newBuf) {
-+ return;
-+ }
-+ ptr->buf = newBuf;
-+ ptr->buf_size = len;
-+ }
-+ memcpy(ptr->buf + ptr->current_input, input, inLen);
-+ ptr->current_input+=inLen;
-+}
-+
-+#define lc_hash_set_digestsize(ptr, len) ((ptr)->digestSize = (len))
-+static inline void
-+lc_hash_final(struct lc_hash_ctx *ptr, unsigned char *output)
-+{
-+ size_t outLen= ptr->digestSize;
-+ if (ptr->stream) {
-+ switch (ptr->hash) {
-+ case lc_shake128:
-+ SHAKE_128_SqueezeEnd(ptr->u.shake128_ctx, output, outLen);
-+ break;
-+ case lc_shake256:
-+ SHAKE_256_SqueezeEnd(ptr->u.shake256_ctx, output, outLen);
-+ break;
-+ }
-+ return;
-+ }
-+ int len= ptr->current_output+outLen;
-+ if (ptr->current_output == 0) {
-+ lc_xof(ptr->hash, ptr->buf, ptr->current_input, output, outLen);
-+ ptr->current_output += outLen;
-+ return;
-+ }
-+ if (len > sizeof(ptr->buf2_space)) {
-+ unsigned char *newBuf = calloc(1,len);
-+ if (!newBuf) {
-+ memset(output, 0, outLen);
-+ return;
-+ }
-+ lc_xof(ptr->hash, ptr->buf, ptr->current_input, newBuf, len);
-+ memcpy(output, newBuf+ptr->current_output, outLen);
-+ memset(newBuf, 0, len);
-+ free(newBuf);
-+ ptr->current_output += outLen;
-+ return;
-+ }
-+ lc_xof(ptr->hash, ptr->buf, ptr->current_input, ptr->buf2_space, len);
-+ memcpy(output, &ptr->buf2_space[ptr->current_output], outLen);
-+ memset(ptr->buf2_space, 0,len);
-+ ptr->current_output += outLen;
-+ return;
-+}
-+
-+static inline void lc_hash_zero(struct lc_hash_ctx *ptr)
-+{
-+ if (ptr->stream) {
-+ if (ptr->u.ctx_ptr != NULL) {
-+ switch (ptr->hash) {
-+ case lc_shake128:
-+ SHAKE_128_DestroyContext(ptr->u.shake128_ctx, PR_TRUE);
-+ ptr->u.shake128_ctx = NULL;
-+ break;
-+ case lc_shake256:
-+ SHAKE_128_DestroyContext(ptr->u.shake256_ctx, PR_TRUE);
-+ ptr->u.shake256_ctx = NULL;
-+ break;
-+ }
-+ }
-+ return;
-+ }
-+ memset(ptr->buf2_space, 0, sizeof(ptr->buf2_space));
-+ memset(ptr->buf_space, 0, sizeof(ptr->buf_space));
-+ if (ptr->buf != ptr->buf_space) {
-+ memset(ptr->buf, 0, ptr->buf_size);
-+ free(ptr->buf);
-+ ptr->buf = NULL;
-+ }
-+ lc_hash_init(ptr);
-+}
-+#endif
-diff --git a/lib/freebl/leancrypto/new_headers/lc_sha512.h b/lib/freebl/leancrypto/new_headers/lc_sha512.h
-new file mode 100644
-diff --git a/lib/freebl/leancrypto/new_headers/ml_dsa_api.h b/lib/freebl/leancrypto/new_headers/ml_dsa_api.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/new_headers/ml_dsa_api.h
-@@ -0,0 +1,71 @@
-+#ifndef ML_DSA_API_H
-+#define ML_DSA_API_H
-+// This is a generated file from the various XXX_sign.h files
-+#include
-+#include "ml_dsa_apit.h"
-+
-+// from ml_dsa_44_sign.h
-+int lc_dilithium_44_keypair_from_seed_c(struct lc_dilithium_44_pk *pk,
-+ struct lc_dilithium_44_sk *sk,
-+ const uint8_t *seed, size_t seedlen);
-+
-+int lc_dilithium_44_sign_init_c(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_44_sk *sk);
-+int lc_dilithium_44_sign_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+int lc_dilithium_44_sign_final_c(struct lc_dilithium_44_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_44_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+int lc_dilithium_44_verify_init_c(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_44_pk *pk);
-+int lc_dilithium_44_verify_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+int lc_dilithium_44_verify_final_c(const struct lc_dilithium_44_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_44_pk *pk);
-+
-+// from ml_dsa_65_sign.h
-+int lc_dilithium_65_keypair_from_seed_c(struct lc_dilithium_65_pk *pk,
-+ struct lc_dilithium_65_sk *sk,
-+ const uint8_t *seed, size_t seedlen);
-+
-+int lc_dilithium_65_sign_init_c(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_65_sk *sk);
-+int lc_dilithium_65_sign_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+int lc_dilithium_65_sign_final_c(struct lc_dilithium_65_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_65_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+int lc_dilithium_65_verify_init_c(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_65_pk *pk);
-+int lc_dilithium_65_verify_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+int lc_dilithium_65_verify_final_c(const struct lc_dilithium_65_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_65_pk *pk);
-+// from ml_dsa_87_sign.h
-+int lc_dilithium_87_keypair_from_seed_c(struct lc_dilithium_87_pk *pk,
-+ struct lc_dilithium_87_sk *sk,
-+ const uint8_t *seed, size_t seedlen);
-+
-+int lc_dilithium_87_sign_init_c(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_87_sk *sk);
-+int lc_dilithium_87_sign_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+int lc_dilithium_87_sign_final_c(struct lc_dilithium_87_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_87_sk *sk,
-+ struct lc_rng_ctx *rng_ctx);
-+
-+int lc_dilithium_87_verify_init_c(struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_87_pk *pk);
-+int lc_dilithium_87_verify_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
-+ size_t mlen);
-+int lc_dilithium_87_verify_final_c(const struct lc_dilithium_87_sig *sig,
-+ struct lc_dilithium_ctx *ctx,
-+ const struct lc_dilithium_87_pk *pk);
-+#endif /* ML_DSA_API_H */
-diff --git a/lib/freebl/leancrypto/new_headers/static_rng.h b/lib/freebl/leancrypto/new_headers/static_rng.h
-new file mode 100644
-diff --git a/lib/freebl/leancrypto/null_buffer.h b/lib/freebl/leancrypto/null_buffer.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/null_buffer.h
-@@ -0,0 +1,39 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef NULL_BUFFER_H
-+#define NULL_BUFFER_H
-+
-+#include "ext_headers.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#define LC_NULL_BUFFER_SIZE 64
-+extern const uint8_t null_buffer[];
-+
-+extern volatile int16_t optimization_blocker_int16;
-+extern volatile int8_t optimization_blocker_int8;
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* NULL_BUFFER_H */
-diff --git a/lib/freebl/leancrypto/randombytes.h b/lib/freebl/leancrypto/randombytes.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/randombytes.h
-@@ -0,0 +1,13 @@
-+// SPDX-License-Identifier: MIT
-+// NSS stub for liboqs randombytes.h
-+
-+#ifndef RANDOMBYTES_H
-+#define RANDOMBYTES_H
-+
-+// run the random number generator through our mldsa code so we can support
-+// CKA_SEED (both acquiring it and generating keys from it) and
-+// DETERMINISTIC signatures (by returning zeros from the RNG)
-+void mldsa_GetRandomBytes(unsigned char *rdn, int bytes);
-+#define randombytes mldsa_GetRandomBytes
-+
-+#endif
-diff --git a/lib/freebl/leancrypto/ret_checkers.h b/lib/freebl/leancrypto/ret_checkers.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/ret_checkers.h
-@@ -0,0 +1,82 @@
-+/*
-+ * Copyright (C) 2018 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef RET_CHECKERS_H
-+#define RET_CHECKERS_H
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+//#define ret_t int __attribute__((warn_unused_result))
-+
-+#ifdef LC_DEBUG
-+#define CKERROR_LOG \
-+ _Pragma("GCC diagnostic push") \
-+ _Pragma("GCC diagnostic ignored \"-Wpedantic\"") \
-+ printf("Error %d at %s:%s:%u\n", ret, __FILE__, \
-+ __FUNCTION__, __LINE__); \
-+ _Pragma("GCC diagnostic pop")
-+#else
-+#define CKERROR_LOG
-+#endif
-+
-+#define CKINT(x) \
-+ { \
-+ ret = x; \
-+ if (ret < 0) { \
-+ CKERROR_LOG \
-+ goto out; \
-+ } \
-+ }
-+
-+#define CKINT_LOG(x, ...) \
-+ { \
-+ ret = x; \
-+ if (ret < 0) { \
-+ CKERROR_LOG \
-+ printf(__VA_ARGS__); \
-+ goto out; \
-+ } \
-+ }
-+
-+#define CKNULL(v, r) \
-+ { \
-+ if (!v) { \
-+ ret = r; \
-+ CKERROR_LOG \
-+ goto out; \
-+ } \
-+ }
-+
-+#define CKNULL_LOG(v, r, ...) \
-+ { \
-+ if (!v) { \
-+ printf(__VA_ARGS__); \
-+ ret = r; \
-+ CKERROR_LOG \
-+ goto out; \
-+ } \
-+ }
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* RET_CHECKERS_H */
-diff --git a/lib/freebl/leancrypto/rotate.h b/lib/freebl/leancrypto/rotate.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/rotate.h
-@@ -0,0 +1,90 @@
-+/* Rotate left / right functions
-+ *
-+ * Copyright (C) 2015 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef ROTATE_H
-+#define ROTATE_H
-+
-+#include "ext_headers.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#ifndef LINUX_KERNEL
-+
-+/*
-+ * Rotate 8 bit unsigned integer X by N bits left/right
-+ */
-+static inline uint8_t rol8(uint16_t x, uint8_t n)
-+{
-+ return (uint8_t)((x << (n & (8 - 1))) | (x >> ((8 - n) & (8 - 1))));
-+}
-+
-+static inline uint8_t ror8(uint16_t x, uint8_t n)
-+{
-+ return (uint8_t)((x >> (n & (8 - 1))) | (x << ((8 - n) & (8 - 1))));
-+}
-+
-+/*
-+ * Rotate 16 bit unsigned integer X by N bits left/right
-+ */
-+static inline uint16_t rol16(uint16_t x, uint8_t n)
-+{
-+ return (uint16_t)((x << (n & (16 - 1))) | (x >> ((16 - n) & (16 - 1))));
-+}
-+
-+static inline uint16_t ror16(uint16_t x, uint8_t n)
-+{
-+ return (uint16_t)((x >> (n & (16 - 1))) | (x << ((16 - n) & (16 - 1))));
-+}
-+
-+/*
-+ * Rotate 32 bit unsigned integer X by N bits left/right
-+ */
-+static inline uint32_t rol32(uint32_t x, uint8_t n)
-+{
-+ return ((x << (n & (32 - 1))) | (x >> ((32 - n) & (32 - 1))));
-+}
-+
-+static inline uint32_t ror32(uint32_t x, uint8_t n)
-+{
-+ return ((x >> (n & (32 - 1))) | (x << ((32 - n) & (32 - 1))));
-+}
-+
-+/*
-+ * Rotate 64 bit unsigned integer X by N bits left/right
-+ */
-+static inline uint64_t rol64(uint64_t x, uint8_t n)
-+{
-+ return ((x << (n & (64 - 1))) | (x >> ((64 - n) & (64 - 1))));
-+}
-+
-+static inline uint64_t ror64(uint64_t x, uint8_t n)
-+{
-+ return ((x >> (n & (64 - 1))) | (x << ((64 - n) & (64 - 1))));
-+}
-+
-+#endif /* LINUX_KERNEL */
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* ROTATE_H */
-diff --git a/lib/freebl/leancrypto/sidechannel_resistantce.h b/lib/freebl/leancrypto/sidechannel_resistantce.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/sidechannel_resistantce.h
-@@ -0,0 +1,125 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived in parts from the code distribution provided with
-+ * https://github.com/pq-crystals/kyber
-+ *
-+ * That code is released under Public Domain
-+ * (https://creativecommons.org/share-your-work/public-domain/cc0/).
-+ */
-+
-+#ifndef SIDECHANNEL_RESISTANCE_H
-+#define SIDECHANNEL_RESISTANCE_H
-+
-+#include "ext_headers.h"
-+#include "null_buffer.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+/**
-+ * @brief cmov - Copy len bytes from x to r if b is 1;
-+ * don't modify x if b is 0. Requires b to be in {0,1};
-+ * assumes two's complement representation of negative integers.
-+ * Runs in constant time.
-+ *
-+ * @param [out] r pointer to output byte array
-+ * @param [in] x pointer to input byte array
-+ * @param [in] len Amount of bytes to be copied
-+ * @param [in] b Condition bit; has to be in {0,1}
-+ */
-+static inline void cmov(uint8_t *r, const uint8_t *x, size_t len, uint8_t b)
-+{
-+ size_t i;
-+ uint8_t opt_blocker;
-+
-+ /*
-+ * Goal: copy data only depending on a given condition without
-+ * the use of a branching operation which alters the timing behavior
-+ * depending on the condition. As the condition here depends on
-+ * secret data, the code has to ensure that no branching is used to have
-+ * time-invariant code. This solution below also shall ensure that the
-+ * compiler cannot optimize this code such that it brings back the
-+ * branching.
-+ *
-+ * (condition ^ opt_blocker) can be any value at run-time to the
-+ * compiler, making it impossible to skip the computation (except the
-+ * compiler would care to create a branch for opt_blocker to be either
-+ * 0 or 1, which would be extremely unlikely). Yet the volatile
-+ * variable has to be loaded only once at the beginning of the function
-+ * call.
-+ *
-+ * Note, the opt_blocker is not required in most instances, but in the
-+ * ARMv8 Neon implementation of SLH-DSA the compiler managed to still
-+ * create time-variant code without the optimization blocker.
-+ */
-+ opt_blocker = (uint8_t)optimization_blocker_int8;
-+
-+ b = -b;
-+ for (i = 0; i < len; i++)
-+ r[i] ^= (b & (r[i] ^ x[i])) ^ opt_blocker;
-+}
-+
-+/**
-+ * @brief cmov_int16 - Copy input v to *r if b is 1, don't modify *r if b is 0.
-+ * Requires b to be in {0,1}; Runs in constant time.
-+ *
-+ * @param [out] r pointer to output int16_t
-+ * @param [in] v input int16_t
-+ * @param [in] b Condition bit; has to be in {0,1}
-+ */
-+static inline void cmov_int16(int16_t *r, int16_t v, uint16_t b)
-+{
-+ b = -b;
-+ *r ^= (int16_t)(b & ((*r) ^ v));
-+}
-+
-+/**
-+ * @brief cmov_uint32 - Copy input v to *r if b is 1, don't modify *r if b is 0.
-+ * Requires b to be in {0,1}; Runs in constant time.
-+ *
-+ * @param [out] r pointer to output int16_t
-+ * @param [in] v input int16_t
-+ * @param [in] b Condition bit; has to be in {0,1}
-+ */
-+static inline void cmov_uint32(uint32_t *r, uint32_t v, uint32_t b)
-+{
-+ b = -b;
-+ *r ^= (uint32_t)(b & ((*r) ^ v));
-+}
-+
-+/**
-+ * @brief cmov_int - Copy input v to *r if b is 1, don't modify *r if b is 0.
-+ * Requires b to be in {0,1}; Runs in constant time.
-+ *
-+ * @param [out] r pointer to output int16_t
-+ * @param [in] v input int16_t
-+ * @param [in] b Condition bit; has to be in {0,1}
-+ */
-+static inline void cmov_int(int *r, int v, uint16_t b)
-+{
-+ b = -b;
-+ *r ^= (int)(b & ((*r) ^ v));
-+}
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* SIDECHANNEL_RESISTANCE_H */
-diff --git a/lib/freebl/leancrypto/signature_domain_separation.c b/lib/freebl/leancrypto/signature_domain_separation.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/signature_domain_separation.c
-@@ -0,0 +1,329 @@
-+/*
-+ * Copyright (C) 2024 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#include "signature_domain_separation.h"
-+#include "lc_sha256.h"
-+#include "lc_sha3.h"
-+#include "lc_sha512.h"
-+#include "ret_checkers.h"
-+
-+/* RFC4055 2.16.840.1.101.3.4.2.1 */
-+static const uint8_t sha256_oid_der[] __maybe_unused = { 0x06, 0x09, 0x60, 0x86,
-+ 0x48, 0x01, 0x65, 0x03,
-+ 0x04, 0x02, 0x01 };
-+/* RFC4055 2.16.840.1.101.3.4.2.2 */
-+static const uint8_t sha384_oid_der[] __maybe_unused = { 0x06, 0x09, 0x60, 0x86,
-+ 0x48, 0x01, 0x65, 0x03,
-+ 0x04, 0x02, 0x02 };
-+/* RFC4055 2.16.840.1.101.3.4.2.3 */
-+static const uint8_t sha512_oid_der[] __maybe_unused = { 0x06, 0x09, 0x60, 0x86,
-+ 0x48, 0x01, 0x65, 0x03,
-+ 0x04, 0x02, 0x03 };
-+
-+/*
-+ * https://lamps-wg.github.io/draft-composite-sigs/draft-ietf-lamps-pq-composite-sigs.html
-+ */
-+static const uint8_t sha3_256_oid_der[] __maybe_unused = {
-+ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x08
-+};
-+static const uint8_t sha3_384_oid_der[] __maybe_unused = {
-+ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x09
-+};
-+static const uint8_t sha3_512_oid_der[] __maybe_unused = {
-+ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0a
-+};
-+
-+/* RFC8692 2.16.840.1.101.3.4.2.11 */
-+static const uint8_t shake128_oid_der[] __maybe_unused = {
-+ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0B
-+};
-+
-+/* RFC8692 2.16.840.1.101.3.4.2.11 */
-+static const uint8_t shake256_oid_der[] __maybe_unused = {
-+ 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x0C
-+};
-+
-+/* OIDs from https://www.ietf.org/archive/id/draft-ietf-lamps-pq-composite-sigs-03.html */
-+const uint8_t lc_x509_composite_sig_prefix[] = {
-+ 0x43, 0x6F, 0x6D, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x65, 0x41, 0x6C,
-+ 0x67, 0x6F, 0x72, 0x69, 0x74, 0x68, 0x6D, 0x53, 0x69, 0x67, 0x6E,
-+ 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x32, 0x30, 0x32, 0x35
-+};
-+
-+static const uint8_t lc_x509_test_dom_sep[] = { 0x06, 0x0b, 0x60, 0x86, 0x48,
-+ 0x01, 0x86, 0xfa, 0x6b, 0x50,
-+ 0x09, 0x01, 0x08 };
-+
-+/* id-HashMLDSA44-Ed25519-SHA512 */
-+static const uint8_t lc_x509_mldsa44_ed25519_sha512_dom_sep[] = {
-+ 0x06, 0x0B, 0x60, 0x86, 0x48, 0x01, 0x86,
-+ 0xFA, 0x6B, 0x50, 0x09, 0x01, 0x02
-+};
-+
-+/* id-HashMLDSA65-Ed25519-SHA512 */
-+static const uint8_t lc_x509_mldsa65_ed25519_sha512_dom_sep[] = {
-+ 0x06, 0x0B, 0x60, 0x86, 0x48, 0x01, 0x86,
-+ 0xFA, 0x6B, 0x50, 0x09, 0x01, 0x0B
-+};
-+
-+/* id-HashMLDSA87-Ed448-SHAKE256 */
-+static const uint8_t lc_x509_mldsa87_ed448_sha512_dom_sep[] = {
-+ 0x06, 0x0B, 0x60, 0x86, 0x48, 0x01, 0x86,
-+ 0xFA, 0x6B, 0x50, 0x09, 0x01, 0x0E
-+};
-+
-+int signature_ph_oids(struct lc_hash_ctx *hash_ctx,
-+ const struct lc_hash *signature_prehash_type, size_t mlen,
-+ unsigned int nist_category)
-+{
-+ /* If no hash is supplied, we have no HashML-DSA */
-+ if (!signature_prehash_type)
-+ return 0;
-+
-+ /*
-+ * The signature init/update/final operation will not work with the
-+ * check of mlen, as only when _final is invoked, the message length
-+ * is known.
-+ *
-+ * As defined in FIPS 204, section 5.4 requires
-+ * "... the digest that is signed needs to be generated using an
-+ * approved hash function or XOF (e.g., from FIPS 180 or FIPS 202) that
-+ * provides at least λ bits of classical security strength against both
-+ * collision and second preimage attacks ... Obtaining at least λ bits
-+ * of classical security strength against collision attacks requires
-+ * that the digest to be signed be at least 2λ bits in length."
-+ * This requirement implies in the following definitions.
-+ */
-+ (void)mlen;
-+
-+ switch (nist_category) {
-+ case 1:
-+#ifdef LC_SHA2_256
-+ if (signature_prehash_type == lc_sha256) {
-+ // if (mlen != LC_SHA256_SIZE_DIGEST)
-+ // return -EOPNOTSUPP;
-+ lc_hash_update(hash_ctx, sha256_oid_der,
-+ sizeof(sha256_oid_der));
-+ return 0;
-+ }
-+#endif
-+#ifdef LC_SHA3
-+ if (signature_prehash_type == lc_sha3_256) {
-+ // if (mlen != LC_SHA3_256_SIZE_DIGEST)
-+ // return -EOPNOTSUPP;
-+ lc_hash_update(hash_ctx, sha3_256_oid_der,
-+ sizeof(sha3_256_oid_der));
-+ return 0;
-+ }
-+ if (signature_prehash_type == lc_shake128) {
-+ /* FIPS 204 section 5.4.1 */
-+ // if (mlen != 32)
-+ // return -EOPNOTSUPP;
-+ lc_hash_update(hash_ctx, shake128_oid_der,
-+ sizeof(shake128_oid_der));
-+ return 0;
-+ }
-+#endif
-+ /* FALLTHROUGH - Dilithium44 allows the following, too */
-+ fallthrough;
-+ case 3:
-+#ifdef LC_SHA3
-+ if (signature_prehash_type == lc_sha3_384) {
-+ // if (mlen != LC_SHA3_384_SIZE_DIGEST)
-+ // return -EOPNOTSUPP;
-+ lc_hash_update(hash_ctx, sha3_384_oid_der,
-+ sizeof(sha3_384_oid_der));
-+ return 0;
-+ }
-+#endif
-+#ifdef LC_SHA2_512
-+ if (signature_prehash_type == lc_sha384) {
-+ // if (mlen != LC_SHA384_SIZE_DIGEST)
-+ // return -EOPNOTSUPP;
-+ lc_hash_update(hash_ctx, sha384_oid_der,
-+ sizeof(sha384_oid_der));
-+ return 0;
-+ }
-+#endif
-+ /* FALLTHROUGH - Dilithium[44|65] allows the following, too */
-+ fallthrough;
-+ case 5:
-+#ifdef LC_SHA2_512
-+ if (signature_prehash_type == lc_sha512) {
-+ // if (mlen != LC_SHA512_SIZE_DIGEST)
-+ // return -EOPNOTSUPP;
-+ lc_hash_update(hash_ctx, sha512_oid_der,
-+ sizeof(sha512_oid_der));
-+ return 0;
-+ }
-+#endif
-+#ifdef LC_SHA3
-+ if (signature_prehash_type == lc_sha3_512) {
-+ // if (mlen != LC_SHA3_512_SIZE_DIGEST)
-+ // return -EOPNOTSUPP;
-+ lc_hash_update(hash_ctx, sha3_512_oid_der,
-+ sizeof(sha3_512_oid_der));
-+ return 0;
-+ } else if (signature_prehash_type == lc_shake256) {
-+ /* FIPS 204 section 5.4.1 */
-+ /*
-+ * TODO: mlen must be >= 64 to comply with the
-+ * aforementioned requirement - unfortunately we can
-+ * only check mlen at the end of the signature
-+ * operation - shall this be implemented?
-+ */
-+ // if (mlen != 64)
-+ // return -EOPNOTSUPP;
-+ lc_hash_update(hash_ctx, shake256_oid_der,
-+ sizeof(shake256_oid_der));
-+ return 0;
-+ }
-+#endif
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return -EOPNOTSUPP;
-+}
-+
-+static int composite_signature_set_domain(const uint8_t **domain,
-+ size_t *domainlen,
-+ unsigned int nist_category)
-+{
-+ /* Set Domain */
-+ switch (nist_category) {
-+ case 0:
-+ *domain = lc_x509_test_dom_sep;
-+ *domainlen = sizeof(lc_x509_test_dom_sep);
-+ break;
-+ case 1:
-+ *domain = lc_x509_mldsa44_ed25519_sha512_dom_sep;
-+ *domainlen = sizeof(lc_x509_mldsa44_ed25519_sha512_dom_sep);
-+ break;
-+ case 3:
-+ *domain = lc_x509_mldsa65_ed25519_sha512_dom_sep;
-+ *domainlen = sizeof(lc_x509_mldsa65_ed25519_sha512_dom_sep);
-+ break;
-+ case 5:
-+ *domain = lc_x509_mldsa87_ed448_sha512_dom_sep;
-+ *domainlen = sizeof(lc_x509_mldsa87_ed448_sha512_dom_sep);
-+ break;
-+ default:
-+ return -EOPNOTSUPP;
-+ }
-+
-+ return 0;
-+}
-+
-+int composite_signature_domain_separation(struct lc_hash_ctx *hash_ctx,
-+ const uint8_t *userctx,
-+ size_t userctxlen,
-+ const uint8_t *randomizer,
-+ size_t randomizerlen,
-+ unsigned int nist_category)
-+{
-+ const uint8_t *domain;
-+ size_t domainlen;
-+ uint8_t userctxlen_small = (uint8_t)userctxlen;
-+ int ret;
-+
-+ CKINT(composite_signature_set_domain(&domain, &domainlen,
-+ nist_category));
-+
-+ /*
-+ * M' = Prefix || Domain || len(ctx) || ctx || r
-+ *
-+ * See for details: https://lamps-wg.github.io/draft-composite-sigs/draft-ietf-lamps-pq-composite-sigs.html
-+ */
-+ lc_hash_update(hash_ctx, lc_x509_composite_sig_prefix,
-+ sizeof(lc_x509_composite_sig_prefix));
-+ lc_hash_update(hash_ctx, domain, domainlen);
-+ lc_hash_update(hash_ctx, &userctxlen_small, sizeof(userctxlen_small));
-+ lc_hash_update(hash_ctx, userctx, userctxlen);
-+ lc_hash_update(hash_ctx, randomizer, randomizerlen);
-+
-+out:
-+ return ret;
-+}
-+
-+static int standalone_signature_domain_separation(
-+ struct lc_hash_ctx *hash_ctx,
-+ const struct lc_hash *signature_prehash_type, const uint8_t *userctx,
-+ size_t userctxlen, size_t mlen, unsigned int nist_category)
-+{
-+ int ret;
-+ uint8_t domainseparation[2];
-+
-+ domainseparation[0] = signature_prehash_type ? 1 : 0;
-+ domainseparation[1] = (uint8_t)userctxlen;
-+
-+ lc_hash_update(hash_ctx, domainseparation, sizeof(domainseparation));
-+ lc_hash_update(hash_ctx, userctx, userctxlen);
-+
-+ CKINT(signature_ph_oids(hash_ctx, signature_prehash_type, mlen,
-+ nist_category));
-+
-+out:
-+ return ret;
-+}
-+
-+int signature_domain_separation(struct lc_hash_ctx *hash_ctx,
-+ unsigned int ml_dsa_internal,
-+ const struct lc_hash *signature_prehash_type,
-+ const uint8_t *userctx, size_t userctxlen,
-+ const uint8_t *m, size_t mlen,
-+ const uint8_t *randomizer, size_t randomizerlen,
-+ unsigned int nist_category)
-+{
-+ int ret = 0;
-+
-+ /* The internal operation skips the domain separation code */
-+ if (ml_dsa_internal)
-+ goto out;
-+
-+ if (userctxlen > 255)
-+ return -EINVAL;
-+
-+ /* If Composite ML-DSA is requested, use domain as userctx */
-+ if (randomizer) {
-+ const uint8_t *domain;
-+ size_t domainlen;
-+
-+ CKINT(composite_signature_set_domain(&domain, &domainlen,
-+ nist_category));
-+
-+ /* Add the composite signature domain as context */
-+ CKINT(standalone_signature_domain_separation(
-+ hash_ctx, signature_prehash_type, domain, domainlen,
-+ mlen, nist_category));
-+
-+ CKINT(composite_signature_domain_separation(
-+ hash_ctx, userctx, userctxlen, randomizer,
-+ randomizerlen, nist_category));
-+ } else {
-+ CKINT(standalone_signature_domain_separation(
-+ hash_ctx, signature_prehash_type, userctx, userctxlen,
-+ mlen, nist_category));
-+ }
-+
-+out:
-+ lc_hash_update(hash_ctx, m, mlen);
-+ return ret;
-+}
-diff --git a/lib/freebl/leancrypto/signature_domain_separation.h b/lib/freebl/leancrypto/signature_domain_separation.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/signature_domain_separation.h
-@@ -0,0 +1,52 @@
-+/*
-+ * Copyright (C) 2024 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef SIGNATURE_DOMAIN_SEPARATION_H
-+#define SIGNATURE_DOMAIN_SEPARATION_H
-+
-+#include "dilithium_type.h"
-+#include "helper.h"
-+#include "lc_hash.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+int signature_domain_separation(struct lc_hash_ctx *hash_ctx,
-+ unsigned int ml_dsa_internal,
-+ const struct lc_hash *signature_prehash_type,
-+ const uint8_t *userctx, size_t userctxlen,
-+ const uint8_t *m, size_t mlen,
-+ const uint8_t *randomizer, size_t randomizerlen,
-+ unsigned int nist_category);
-+int signature_ph_oids(struct lc_hash_ctx *hash_ctx,
-+ const struct lc_hash *signature_prehash_type, size_t mlen,
-+ unsigned int nist_category);
-+int composite_signature_domain_separation(struct lc_hash_ctx *hash_ctx,
-+ const uint8_t *userctx,
-+ size_t userctxlen,
-+ const uint8_t *randomizer,
-+ size_t randomizerlen,
-+ unsigned int nist_category);
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* SIGNATURE_DOMAIN_SEPARATION_H */
-diff --git a/lib/freebl/leancrypto/small_stack_support.h b/lib/freebl/leancrypto/small_stack_support.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/small_stack_support.h
-@@ -0,0 +1,84 @@
-+/*
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef SMALL_STACK_SUPPORT_H
-+#define SMALL_STACK_SUPPORT_H
-+
-+#include "ext_headers.h"
-+#include "lc_memory_support.h"
-+#include "lc_memset_secure.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#define LC_ALIGNED_BUFFER_ALIGNMENTSIZE(name, size, alignment) \
-+ uint64_t name[(size + sizeof(uint64_t) - 1) / sizeof(uint64_t)] \
-+ __attribute__((aligned(alignment)))
-+
-+/* Allocate memory on stack */
-+#define __LC_DECLARE_MEM_STACK(name, type, alignment) \
-+ LC_ALIGNED_BUFFER_ALIGNMENTSIZE(name##_buf, sizeof(type), alignment); \
-+ lc_memset_secure(name##_buf, 0, sizeof(type)); \
-+ type *name = (type *)name##_buf
-+#define __LC_RELEASE_MEM_STACK(name) lc_memset_secure(name, 0, sizeof(*name))
-+
-+/* Allocate memory on heap */
-+#define __LC_DECLARE_MEM_HEAP(name, type, alignment) \
-+ type *name = NULL; \
-+ int __ret = \
-+ lc_alloc_high_aligned((void *)&name, alignment, sizeof(type)); \
-+ if (__ret || !name) \
-+ return __ret; \
-+ lc_memset_secure(name, 0, sizeof(type))
-+
-+#define __LC_RELEASE_MEM_HEAP(name) \
-+ lc_memset_secure(name, 0, sizeof(*name)); \
-+ lc_free_high_aligned(name, sizeof(*name))
-+
-+/* Define macro LC_MEM_ON_HEAP if stack is less than 256KiB in size */
-+#ifdef LC_MEM_ON_HEAP
-+
-+#define noinline_stack noinline
-+
-+#define LC_DECLARE_MEM(name, type, alignment) \
-+ _Pragma("GCC diagnostic push") \
-+ _Pragma("GCC diagnostic ignored \"-Wcast-align\"") \
-+ __LC_DECLARE_MEM_HEAP(name, type, alignment); \
-+ _Pragma("GCC diagnostic pop")
-+#define LC_RELEASE_MEM(name) __LC_RELEASE_MEM_HEAP(name)
-+
-+#else
-+
-+#define noinline_stack
-+
-+#define LC_DECLARE_MEM(name, type, alignment) \
-+ _Pragma("GCC diagnostic push") \
-+ _Pragma("GCC diagnostic ignored \"-Wcast-align\"") \
-+ __LC_DECLARE_MEM_STACK(name, type, alignment); \
-+ _Pragma("GCC diagnostic pop")
-+#define LC_RELEASE_MEM(name) __LC_RELEASE_MEM_STACK(name)
-+
-+#endif
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* SMALL_STACK_SUPPORT_H */
-diff --git a/lib/freebl/leancrypto/static_rng.h b/lib/freebl/leancrypto/static_rng.h
-new file mode 100644
-diff --git a/lib/freebl/leancrypto/timecop.h b/lib/freebl/leancrypto/timecop.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/timecop.h
-@@ -0,0 +1,87 @@
-+/*
-+ * Copyright (C) 2024 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+/*
-+ * This code is derived from
-+ * https://www.post-apocalyptic-crypto.org/timecop/#source-code
-+ *
-+ * The license is: this code is released into the public domain
-+ */
-+
-+#ifndef TIMECOP_H
-+#define TIMECOP_H
-+
-+#if defined __has_include
-+#if __has_include()
-+#define LC_HAS_TIMECOP
-+#endif
-+#endif
-+
-+#if defined(LC_USE_TIMECOP) && !defined(LC_HAS_TIMECOP)
-+#error "Compilation with TIMECOP requested, but valgrind's memcheck.h missing."
-+#endif
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#ifdef LC_USE_TIMECOP
-+
-+/*
-+ * This code requires header files from valgrind. They can be installed with
-+ * packages like valgrind-client-headers.
-+ */
-+#include
-+
-+/**
-+ * Poisons a memory region of len bytes, starting at addr, indicating that
-+ * execution time must not depend on the content of this memory region.
-+ * Use this function to mark any memory regions containing secret data.
-+ */
-+#define poison(addr, len) VALGRIND_MAKE_MEM_UNDEFINED(addr, len)
-+
-+/**
-+ * Use this function to indicate that the specified memory region does no longer
-+ * contain data that must not affect execution time.
-+ */
-+#define unpoison(addr, len) VALGRIND_MAKE_MEM_DEFINED(addr, len)
-+
-+/**
-+ * Checks whether the memory region of len bytes, starting at addr,
-+ * contains any poisoned bits.
-+ * Returns 0 if the code is running natively, rather than within valgrind.
-+ * If valgrind is running, it returns the first address containing poisoned
-+ * data, or 0 if there is no poisoned data in the specified memory region.
-+ * You can use RUNNING_ON_VALGRIND from valgrind.h to check whether the code
-+ * is being executed within valgrind.
-+ */
-+#define is_poisoned(addr, len) VALGRIND_CHECK_MEM_IS_DEFINED(addr, len)
-+
-+#else /* LC_USE_TIMECOP */
-+
-+#define poison(addr, len)
-+#define unpoison(addr, len)
-+#define is_poisoned(addr, len)
-+
-+#endif /* LC_USE_TIMECOP */
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* TIMECOP_H */
-diff --git a/lib/freebl/leancrypto/visibility.h b/lib/freebl/leancrypto/visibility.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/visibility.h
-@@ -0,0 +1,107 @@
-+/*
-+ * see https://gcc.gnu.org/wiki/Visibility
-+ *
-+ * use -fvisibility=hidden to mark all symbols hidden per default
-+ *
-+ * It is sufficient to use the macros in the declarations only. The
-+ * definitions do not need to be instrumented.
-+ */
-+
-+#ifndef VISIBILITY_H
-+#define VISIBILITY_H
-+
-+#ifdef LINUX_KERNEL
-+
-+#pragma GCC diagnostic push
-+#pragma GCC diagnostic ignored "-Wvariadic-macros"
-+#define LC_INTERFACE_FUNCTION(ret, symbol, param...) \
-+ ret symbol(param); \
-+ EXPORT_SYMBOL(symbol); \
-+ ret symbol(param)
-+
-+#define LC_INIT_FUNCTION(ret, symbol, param...) \
-+ ret __init symbol(param); \
-+ ret __init symbol(param)
-+
-+#define LC_TEST_FUNC(ret, symbol, param...) \
-+ static ret symbol(param); \
-+ static int __init symbol##_init(void) \
-+ { \
-+ int __ret; \
-+ \
-+ pr_info("%s: Starting test case\n", KBUILD_MODNAME); \
-+ __ret = symbol(0, NULL); \
-+ pr_info("%s: Test case completed with return code %d\n", \
-+ KBUILD_MODNAME, __ret); \
-+ return __ret ? -EFAULT : 0; \
-+ } \
-+ static void __exit symbol##_exit(void) \
-+ { \
-+ } \
-+ module_init(symbol##_init); \
-+ module_exit(symbol##_exit); \
-+ MODULE_LICENSE("Dual BSD/GPL"); \
-+ MODULE_AUTHOR("Stephan Mueller "); \
-+ MODULE_DESCRIPTION("leancrypto test case"); \
-+ static ret symbol(param)
-+
-+#pragma GCC diagnostic pop
-+
-+#define LC_INTERFACE_SYMBOL(ret, symbol) \
-+ ret symbol; \
-+ EXPORT_SYMBOL(symbol); \
-+ ret symbol
-+
-+#define LC_CONSTRUCTOR(_func) \
-+ void __init _func(void); \
-+ void __init _func(void)
-+
-+#else /* LINUX_KERNEL */
-+
-+#define DSO_PUBLIC __attribute__((visibility("default")))
-+#define DSO_LOCAL __attribute__((visibility("hidden")))
-+
-+#pragma GCC diagnostic push
-+#pragma GCC diagnostic ignored "-Wvariadic-macros"
-+
-+#define LC_INTERFACE_FUNCTION(ret, symbol, param...) \
-+ DSO_PUBLIC ret symbol(param)
-+
-+#define LC_INIT_FUNCTION(ret, symbol, param...) DSO_PUBLIC ret symbol(param)
-+
-+#ifdef LC_STATIC
-+#define LC_TEST_FUNC(ret, symbol, param...) \
-+ int lc_init(unsigned int flags); \
-+ static ret __##symbol(param); \
-+ ret symbol(param) \
-+ { \
-+ lc_init(0); \
-+ return __##symbol(argc, argv); \
-+ } \
-+ static ret __##symbol(param)
-+#else
-+#define LC_TEST_FUNC(ret, symbol, param...) ret symbol(param)
-+#endif
-+
-+#pragma GCC diagnostic pop
-+
-+#define LC_INTERFACE_SYMBOL(ret, symbol) DSO_PUBLIC ret symbol
-+
-+#ifdef LC_EFI
-+/*
-+ * EFI does not have the constructor logic. Thus, mark the constructor functions
-+ * as regular non-static functions as they are intended to be called by lc_init.
-+ */
-+#define LC_CONSTRUCTOR(_func) \
-+ void _func(void); \
-+ void _func(void)
-+#else /* LC_EFI */
-+
-+#define LC_CONSTRUCTOR(_func) \
-+ void __attribute__((constructor)) _func(void); \
-+ void _func(void)
-+#endif /* LC_EFI */
-+
-+#endif /* LINUX_KERNEL */
-+
-+#endif /* VISIBILITY_H */
-diff --git a/lib/freebl/leancrypto/xor.h b/lib/freebl/leancrypto/xor.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/xor.h
-@@ -0,0 +1,189 @@
-+/* Efficient XOR implementation
-+ *
-+ * Copyright (C) 2022 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef XOR_H
-+#define XOR_H
-+
-+#include "alignment.h"
-+#include "ext_headers.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+static inline void xor_8(uint8_t *dst, const uint8_t *src, size_t size)
-+{
-+ for (; size; size--)
-+ *dst++ ^= *src++;
-+}
-+
-+static inline void xor_32_aligned(uint8_t *dst, const uint8_t *src, size_t size)
-+{
-+ /*
-+ * We can ignore the alignment warning as we checked
-+ * for proper alignment.
-+ */
-+#pragma GCC diagnostic push
-+#pragma GCC diagnostic ignored "-Wcast-align"
-+ uint32_t *dst_word = (uint32_t *)dst;
-+ uint32_t *src_word = (uint32_t *)src;
-+#pragma GCC diagnostic pop
-+
-+ for (; size >= sizeof(*src_word); size -= sizeof(*src_word))
-+ *dst_word++ ^= *src_word++;
-+
-+ xor_8((uint8_t *)dst_word, (uint8_t *)src_word, size);
-+}
-+
-+static inline void xor_32(uint8_t *dst, const uint8_t *src, size_t size)
-+{
-+ if (aligned(src, sizeof(uint32_t) - 1) &&
-+ aligned(dst, sizeof(uint32_t) - 1))
-+ xor_32_aligned(dst, src, size);
-+ else
-+ xor_8(dst, src, size);
-+}
-+
-+static inline void xor_64_aligned(uint8_t *dst, const uint8_t *src, size_t size)
-+{
-+ /*
-+ * We can ignore the alignment warning as we checked
-+ * for proper alignment.
-+ */
-+#pragma GCC diagnostic push
-+#pragma GCC diagnostic ignored "-Wcast-align"
-+ uint64_t *dst_dword = (uint64_t *)dst;
-+ uint64_t *src_dword = (uint64_t *)src;
-+#pragma GCC diagnostic pop
-+
-+#ifdef __LP64__
-+ for (; size >= sizeof(*src_dword); size -= sizeof(*src_dword))
-+ *dst_dword++ ^= *src_dword++;
-+#endif /* __LP64__ */
-+
-+ xor_32_aligned((uint8_t *)dst_dword, (uint8_t *)src_dword, size);
-+}
-+
-+/**
-+ * @brief Perform XOR operation efficiently
-+ *
-+ * @param [in,out] dst Data in which the source data is XORed into
-+ * @param [in] src Source data which is XORed into the destination
-+ * @param [in] size Buffer lengths of both, dst and src
-+ */
-+static inline void xor_64(uint8_t *dst, const uint8_t *src, size_t size)
-+{
-+#ifdef __LP64__
-+ if (aligned(src, sizeof(uint64_t) - 1) &&
-+ aligned(dst, sizeof(uint64_t) - 1))
-+ xor_64_aligned(dst, src, size);
-+ else
-+#endif
-+ xor_32(dst, src, size);
-+}
-+
-+static inline void xor_8_3(uint8_t *dst, const uint8_t *src1,
-+ const uint8_t *src2, size_t size)
-+{
-+ for (; size; size--)
-+ *dst++ = *src1++ ^ *src2++;
-+}
-+
-+static inline void xor_32_3_aligned(uint8_t *dst, const uint8_t *src1,
-+ const uint8_t *src2, size_t size)
-+{
-+ /*
-+ * We can ignore the alignment warning as we checked
-+ * for proper alignment.
-+ */
-+#pragma GCC diagnostic push
-+#pragma GCC diagnostic ignored "-Wcast-align"
-+ uint32_t *dst_word = (uint32_t *)dst;
-+ uint32_t *src1_word = (uint32_t *)src1;
-+ uint32_t *src2_word = (uint32_t *)src2;
-+#pragma GCC diagnostic pop
-+
-+ for (; size >= sizeof(*src1_word); size -= sizeof(*src1_word))
-+ *dst_word++ = *src1_word++ ^ *src2_word++;
-+
-+ xor_8_3((uint8_t *)dst_word, (uint8_t *)src1_word, (uint8_t *)src2_word,
-+ size);
-+}
-+
-+static inline void xor_32_3(uint8_t *dst, const uint8_t *src1,
-+ const uint8_t *src2, size_t size)
-+{
-+ if (aligned(src1, sizeof(uint32_t) - 1) &&
-+ aligned(src2, sizeof(uint32_t) - 1) &&
-+ aligned(dst, sizeof(uint32_t) - 1))
-+ xor_32_3_aligned(dst, src1, src2, size);
-+ else
-+ xor_8_3(dst, src1, src2, size);
-+}
-+
-+#ifdef __LP64__
-+static inline void xor_64_3_aligned(uint8_t *dst, const uint8_t *src1,
-+ const uint8_t *src2, size_t size)
-+{
-+ /*
-+ * We can ignore the alignment warning as we checked
-+ * for proper alignment.
-+ */
-+#pragma GCC diagnostic push
-+#pragma GCC diagnostic ignored "-Wcast-align"
-+ uint64_t *dst_dword = (uint64_t *)dst;
-+ uint64_t *src1_dword = (uint64_t *)src1;
-+ uint64_t *src2_dword = (uint64_t *)src2;
-+#pragma GCC diagnostic pop
-+
-+ for (; size >= sizeof(*src1_dword); size -= sizeof(*src1_dword))
-+ *dst_dword++ = *src1_dword++ ^ *src2_dword++;
-+
-+ xor_32_3_aligned((uint8_t *)dst_dword, (uint8_t *)src1_dword,
-+ (uint8_t *)src2_dword, size);
-+}
-+#endif
-+
-+/**
-+ * @brief Perform XOR operation efficiently
-+ *
-+ * @param [out] dst Data in which the source data is XORed into
-+ * @param [in] src1 1st source data which is XORed into the destination
-+ * @param [in] src2 2nd source data which is XORed into the destination
-+ * @param [in] size Buffer lengths all buffers dst, src1, and src2
-+ */
-+static inline void xor_64_3(uint8_t *dst, const uint8_t *src1,
-+ const uint8_t *src2, size_t size)
-+{
-+#ifdef __LP64__
-+ if (aligned(src1, sizeof(uint64_t) - 1) &&
-+ aligned(src2, sizeof(uint64_t) - 1) &&
-+ aligned(dst, sizeof(uint64_t) - 1))
-+ xor_64_3_aligned(dst, src1, src2, size);
-+ else
-+#endif
-+ xor_32_3(dst, src1, src2, size);
-+}
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* XOR_H */
-diff --git a/lib/freebl/leancrypto/xor256.h b/lib/freebl/leancrypto/xor256.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/leancrypto/xor256.h
-@@ -0,0 +1,182 @@
-+/*
-+ * Copyright (C) 2024 - 2025, Stephan Mueller
-+ *
-+ * License: see LICENSE file in root directory
-+ *
-+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
-+ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
-+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
-+ * DAMAGE.
-+ */
-+
-+#ifndef XOR256_H
-+#define XOR256_H
-+
-+#include "build_bug_on.h"
-+#include "cpufeatures.h"
-+#include "xor.h"
-+
-+#ifdef __cplusplus
-+extern "C" {
-+#endif
-+
-+#ifdef LC_HOST_X86_64
-+
-+/*
-+ * AVX2 implementation of XOR (processing 256 bit chunks)
-+ */
-+#include "ext_headers_x86.h"
-+static inline void xor_256_aligned(uint8_t *dst, const uint8_t *src,
-+ size_t size)
-+{
-+ __m256i dst_256, src_256;
-+
-+ LC_FPU_ENABLE;
-+ for (; size >= sizeof(src_256); size -= sizeof(src_256),
-+ dst += sizeof(dst_256),
-+ src += sizeof(src_256)) {
-+ __m128d t;
-+
-+#pragma GCC diagnostic push
-+#pragma GCC diagnostic ignored "-Wsign-conversion"
-+ dst_256 = _mm256_set_epi8(dst[31], dst[30], dst[29], dst[28],
-+ dst[27], dst[26], dst[25], dst[24],
-+ dst[23], dst[22], dst[21], dst[20],
-+ dst[19], dst[18], dst[17], dst[16],
-+ dst[15], dst[14], dst[13], dst[12],
-+ dst[11], dst[10], dst[9], dst[8],
-+ dst[7], dst[6], dst[5], dst[4],
-+ dst[3], dst[2], dst[1], dst[0]);
-+ src_256 = _mm256_set_epi8(src[31], src[30], src[29], src[28],
-+ src[27], src[26], src[25], src[24],
-+ src[23], src[22], src[21], src[20],
-+ src[19], src[18], src[17], src[16],
-+ src[15], src[14], src[13], src[12],
-+ src[11], src[10], src[9], src[8],
-+ src[7], src[6], src[5], src[4],
-+ src[3], src[2], src[1], src[0]);
-+#pragma GCC diagnostic pop
-+
-+ dst_256 = _mm256_xor_si256(dst_256, src_256);
-+
-+ /*
-+ * We can ignore the alignment warning as we checked
-+ * for proper alignment.
-+ */
-+#pragma GCC diagnostic push
-+#pragma GCC diagnostic ignored "-Wcast-align"
-+ t = _mm_castsi128_pd(_mm256_castsi256_si128(dst_256));
-+ _mm_storel_pd((__attribute__((__may_alias__)) double *)&dst[0],
-+ t);
-+ _mm_storeh_pd((__attribute__((__may_alias__)) double *)&dst[8],
-+ t);
-+ t = _mm_castsi128_pd(_mm256_extracti128_si256(dst_256, 1));
-+ _mm_storel_pd((__attribute__((__may_alias__)) double *)&dst[16],
-+ t);
-+ _mm_storeh_pd((__attribute__((__may_alias__)) double *)&dst[24],
-+ t);
-+#pragma GCC diagnostic pop
-+ }
-+ LC_FPU_DISABLE;
-+
-+ /*
-+ * As we skip the xor_64 alignment check, guarantee it at compile time.
-+ */
-+ BUILD_BUG_ON(LC_XOR_AVX2_ALIGNMENT < sizeof(uint64_t));
-+ xor_64_aligned(dst, src, size);
-+}
-+
-+static inline void xor_256(uint8_t *dst, const uint8_t *src, size_t size)
-+{
-+ enum lc_cpu_features feat =
-+ lc_cpu_feature_available() & LC_CPU_FEATURE_INTEL_AVX2;
-+
-+ if (!aligned(src, LC_XOR_AVX2_ALIGNMENT - 1) ||
-+ !aligned(dst, LC_XOR_AVX2_ALIGNMENT - 1) || !feat) {
-+ xor_64(dst, src, size);
-+ } else {
-+ xor_256_aligned(dst, src, size);
-+ }
-+}
-+
-+#elif (defined(LC_HOST_ARM32_NEON) || defined(LC_HOST_AARCH64)) && \
-+ !defined(LINUX_KERNEL)
-+
-+/*
-+ * ARM Neon implementation of XOR (processing 128 bit chunks)
-+ */
-+/* This code cannot be compiled for the Linux kernel as of now */
-+#include
-+#include "ext_headers_arm.h"
-+static inline void xor_256_aligned(uint8_t *dst, const uint8_t *src,
-+ size_t size)
-+{
-+ uint64x2_t dst_128, src_128;
-+
-+ if (!aligned(src, sizeof(uint64x2_t) - 1) ||
-+ !aligned(dst, sizeof(uint64x2_t) - 1)) {
-+ xor_64(dst, src, size);
-+ return;
-+ }
-+
-+ LC_NEON_ENABLE;
-+ for (; size >= sizeof(src_128); size -= sizeof(src_128),
-+ dst += sizeof(dst_128),
-+ src += sizeof(src_128)) {
-+#pragma GCC diagnostic push
-+#pragma GCC diagnostic ignored "-Wcast-align"
-+ src_128 = vld1q_u64((uint64_t *)src);
-+ dst_128 = vld1q_u64((uint64_t *)dst);
-+#pragma GCC diagnostic pop
-+
-+ dst_128 = veorq_u64(dst_128, src_128);
-+
-+#pragma GCC diagnostic push
-+#pragma GCC diagnostic ignored "-Wcast-align"
-+ vst1q_u64((uint64_t *)dst, dst_128);
-+#pragma GCC diagnostic pop
-+ }
-+ LC_NEON_DISABLE;
-+
-+ /*
-+ * As we skip the xor_64 alignment check, guarantee it at compile time.
-+ */
-+ BUILD_BUG_ON(LC_XOR_NEON_ALIGNMENT < sizeof(uint64_t));
-+ xor_64_aligned(dst, src, size);
-+}
-+
-+static inline void xor_256(uint8_t *dst, const uint8_t *src, size_t size)
-+{
-+ enum lc_cpu_features feat =
-+ lc_cpu_feature_available() & LC_CPU_FEATURE_ARM_NEON;
-+
-+ if (!aligned(src, LC_XOR_NEON_ALIGNMENT - 1) ||
-+ !aligned(dst, LC_XOR_NEON_ALIGNMENT - 1) || !feat) {
-+ xor_64(dst, src, size);
-+ } else {
-+ xor_256_aligned(dst, src, size);
-+ }
-+}
-+
-+#else /* LC_HOST_X86_64 */
-+
-+static inline void xor_256(uint8_t *dst, const uint8_t *src, size_t size)
-+{
-+ xor_64(dst, src, size);
-+}
-+
-+#endif
-+
-+#ifdef __cplusplus
-+}
-+#endif
-+
-+#endif /* XOR256_H */
-diff --git a/lib/freebl/loader.c b/lib/freebl/loader.c
---- a/lib/freebl/loader.c
-+++ b/lib/freebl/loader.c
-@@ -2897,8 +2897,59 @@ X25519_DerivePublicKey(const SECItem *pr
-
- SECStatus
- EC_DerivePublicKey(const SECItem *privateKey, const ECParams *ecParams, SECItem *publicKey)
- {
- if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
- return SECFailure;
- return (vector->p_EC_DerivePublicKey)(privateKey, ecParams, publicKey);
- }
-+
-+/* ============== New for 3.0031 =============================== */
-+
-+SECStatus MLDSA_NewKey(CK_ML_DSA_PARAMETER_SET_TYPE paramSet, SECItem *seed,
-+ MLDSAPrivateKey *privKey, MLDSAPublicKey *pubKey)
-+{
-+ if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
-+ return SECFailure;
-+ return (vector->p_MLDSA_NewKey)(paramSet, seed, privKey, pubKey);
-+}
-+SECStatus MLDSA_SignInit(MLDSAPrivateKey *key, CK_HEDGE_TYPE hedgeType,
-+ const SECItem *sgnCtx, MLDSAContext **ctx)
-+{
-+ if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
-+ return SECFailure;
-+ return (vector->p_MLDSA_SignInit)(key, hedgeType, sgnCtx, ctx);
-+}
-+SECStatus MLDSA_SignUpdate(MLDSAContext *ctx, const SECItem *data)
-+{
-+ if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
-+ return SECFailure;
-+ return (vector->p_MLDSA_SignUpdate)(ctx, data);
-+}
-+SECStatus MLDSA_SignFinal(MLDSAContext *ctx, SECItem *signature)
-+{
-+ if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
-+ return SECFailure;
-+ return (vector->p_MLDSA_SignFinal)(ctx, signature);
-+}
-+
-+SECStatus MLDSA_VerifyInit(MLDSAPublicKey *key, const SECItem *sgnCtx,
-+ MLDSAContext **ctx)
-+{
-+ if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
-+ return SECFailure;
-+ return (vector->p_MLDSA_VerifyInit)(key, sgnCtx, ctx);
-+}
-+SECStatus MLDSA_VerifyUpdate(MLDSAContext *ctx, const SECItem *data)
-+{
-+ if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
-+ return SECFailure;
-+ return (vector->p_MLDSA_VerifyUpdate)(ctx, data);
-+}
-+SECStatus MLDSA_VerifyFinal(MLDSAContext *ctx, const SECItem *signature)
-+{
-+ if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
-+ return SECFailure;
-+ return (vector->p_MLDSA_VerifyFinal)(ctx, signature);
-+}
-+
-+
-diff --git a/lib/freebl/loader.h b/lib/freebl/loader.h
---- a/lib/freebl/loader.h
-+++ b/lib/freebl/loader.h
-@@ -5,17 +5,17 @@
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
- #ifndef _LOADER_H_
- #define _LOADER_H_ 1
-
- #include "blapi.h"
-
--#define FREEBL_VERSION 0x0327
-+#define FREEBL_VERSION 0x0331
-
- struct FREEBLVectorStr {
-
- unsigned short length; /* of this struct in bytes */
- unsigned short version; /* of this struct. */
-
- RSAPrivateKey *(*p_RSA_NewKey)(int keySizeInBits,
- SECItem *publicExponent);
-@@ -926,16 +926,25 @@ struct FREEBLVectorStr {
- /* Version 3.028 came to here */
-
- SECStatus (*p_X25519_DerivePublicKey)(const SECItem *privateKey, SECItem *publicKey);
- /* Version 3.029 came to here */
-
- SECStatus (*p_EC_DerivePublicKey)(const SECItem *privateKey, const ECParams *ecParams, SECItem *publicKey);
- /* Version 3.030 came to here */
-
-+ SECStatus (*p_MLDSA_NewKey)(CK_ML_DSA_PARAMETER_SET_TYPE paramSet, SECItem *seed, MLDSAPrivateKey *privKey, MLDSAPublicKey *pubKey);
-+ SECStatus (*p_MLDSA_SignInit)(MLDSAPrivateKey *key, CK_HEDGE_TYPE hedgType, const SECItem *sgnCtx, MLDSAContext **ctx);
-+ SECStatus (*p_MLDSA_SignUpdate)(MLDSAContext *ctx, const SECItem *data);
-+ SECStatus (*p_MLDSA_SignFinal)(MLDSAContext *ctx, SECItem *signature);
-+ SECStatus (*p_MLDSA_VerifyInit)(MLDSAPublicKey *key, const SECItem *sgnCtx, MLDSAContext **ctx);
-+ SECStatus (*p_MLDSA_VerifyUpdate)(MLDSAContext *ctx, const SECItem *data) ;
-+ SECStatus (*p_MLDSA_VerifyFinal)(MLDSAContext *ctx, const SECItem *signature);
-+ /* Version 3.031 came to here */
-+
- /* Add new function pointers at the end of this struct and bump
- * FREEBL_VERSION at the beginning of this file. */
- };
-
- typedef struct FREEBLVectorStr FREEBLVector;
-
- #ifdef FREEBL_LOWHASH
- #include "nsslowhash.h"
-@@ -1034,8 +1043,11 @@ typedef SECStatus (*F_RC2_InitContext)(R
- typedef RC2Context *(*F_RC2_AllocateContext)(void);
- #endif
-
- typedef SECStatus (*F_Kyber_NewKey)(KyberParams params, const SECItem *seed, SECItem *privKey, SECItem *pubKey);
-
- typedef SECStatus (*F_Kyber_Encapsulate)(KyberParams params, const SECItem *seed, const SECItem *pubKey, SECItem *ciphertext, SECItem *secret);
-
- typedef SECStatus (*F_Kyber_Decapsulate)(KyberParams params, const SECItem *privKey, const SECItem *ciphertext, SECItem *secret);
-+
-+
-+
-diff --git a/lib/freebl/manifest.mn b/lib/freebl/manifest.mn
---- a/lib/freebl/manifest.mn
-+++ b/lib/freebl/manifest.mn
-@@ -82,16 +82,17 @@ DEFINES += -DKYBER_K=3
-
- REQUIRES =
-
- EXPORTS = \
- blapit.h \
- shsign.h \
- ecl-exp.h \
- $(LOWHASH_EXPORTS) \
-+ $(ML_DSA_EXPORTS) \
- $(NULL)
-
- PRIVATE_EXPORTS = \
- cmac.h \
- alghmac.h \
- blake2b.h \
- blapi.h \
- chacha20poly1305.h \
-@@ -108,16 +109,18 @@ MPI_HDRS = mpi-config.h mpi.h mpi-priv.h
- MPI_SRCS = mpprime.c mpmontg.c mplogic.c mpi.c mp_gf2m.c
-
-
- ECL_HDRS = ecl-exp.h ecl.h ecl-priv.h
- ECL_SRCS = ecp_25519.c ecp_secp256r1.c ecp_secp384r1.c ecp_secp521r1.c
- SHA_SRCS = sha_fast.c
- MPCPU_SRCS = mpcpucache.c
- VERIFIED_SRCS = $(NULL)
-+ML_DSA_SRCS = $(NULL)
-+
-
- CSRCS = \
- freeblver.c \
- ldvector.c \
- sysrand.c \
- $(SHA_SRCS) \
- md2.c \
- md5.c \
-@@ -152,21 +155,23 @@ CSRCS = \
- rsa.c \
- rsa_blind.c \
- rsapkcs.c \
- shvfy.c \
- tlsprfalg.c \
- jpake.c \
- secmpi.c \
- kyber.c \
-+ ml_dsa.c \
- $(KYBER_PQCRYSTALS) \
- $(MPI_SRCS) \
- $(MPCPU_SRCS) \
- $(ECL_SRCS) \
- $(VERIFIED_SRCS) \
-+ $(ML_DSA_SRCS) \
- $(STUBS_SRCS) \
- $(LOWHASH_SRCS) \
- $(EXTRA_SRCS) \
- $(NULL)
-
- ifndef NSS_DISABLE_DEPRECATED_SEED
- CSRCS += deprecated/seed.c
- endif
-diff --git a/lib/freebl/ml_dsa.c b/lib/freebl/ml_dsa.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/ml_dsa.c
-@@ -0,0 +1,552 @@
-+/*
-+ *
-+ * This Source Code Form is subject to the terms of the Mozilla Public
-+ * License, v. 2.0. If a copy of the MPL was not distributed with this
-+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-+
-+#ifdef FREEBL_NO_DEPEND
-+#include "stubs.h"
-+#endif
-+
-+#include "prerror.h"
-+#include "secerr.h"
-+
-+#include "prtypes.h"
-+#include "prinit.h"
-+#include "blapi.h"
-+#include "secitem.h"
-+#include "blapit.h"
-+#include "secport.h"
-+#include "nssilock.h"
-+#include "secrng.h"
-+
-+#include "lc_dilithium.h"
-+#include "ml_dsa_api.h"
-+
-+
-+/*
-+ * some missing utilities, just use the nss implementations
-+ */
-+int
-+lc_memcmp_secure(const void *s1, size_t s1n, const void *s2, size_t s2n)
-+{
-+ /* NSS's secure function takes on one len, get the min length
-+ * to pass to it the point here is to be constant time... so
-+ * we do the select checks in constant time: NOTE:this is really
-+ * only constant time is the min value is constant, but we can't
-+ * overrun the min buffer */
-+ PRUint32 s1n_, s2n_, min, res;
-+ s1n_ = s1n; s2n_= s2n;
-+ min = PORT_CT_SEL(PORT_CT_LT(s1n_,s2n_), s1n_, s2n_);
-+ res = NSS_SecureMemcmp(s1, s2, min);
-+ return (int)PORT_CT_SEL(PORT_CT_EQ(s1n_,s2n_), res, 1);
-+}
-+
-+#ifdef notdef
-+void bin2print(const unsigned char *bin, const size_t binlen, FILE *out,
-+ const char *explanation) {
-+ if (explanation)
-+ fprintf(out, "%s = ", explanation);
-+
-+ for (int i=0; i < binlen; i++)
-+ fprintf(out, "%02x",bin[i]);
-+ fprintf(out,"\n");
-+}
-+#endif
-+
-+struct MLDSAContextStr {
-+ PLArenaPool *arena;
-+ MLDSAPrivateKey *privKey;
-+ MLDSAPublicKey *pubKey;
-+ CK_HEDGE_TYPE hedgeType;
-+ CK_ML_DSA_PARAMETER_SET_TYPE paramSet;
-+ struct lc_dilithium_ctx lc_dilithium;
-+};
-+
-+#ifdef notdef
-+void
-+hexprint(const char *label, const unsigned char *buf,
-+ unsigned int len, unsigned int max)
-+{
-+ int i;
-+ fprintf(stderr,"%s(%d): ",label, len);
-+ len = len > max ? max : len;
-+ if (len == 0) {
-+ fprintf(stderr, "null\n");
-+ return;
-+ }
-+
-+ for (i=0; i < len; i++) {
-+ fprintf(stderr,"%02x",buf[i]);
-+ }
-+ fprintf(stderr, "\n");
-+}
-+#endif
-+
-+
-+#ifdef NSS_ENABLE_ML_DSA
-+static void
-+mldsa_DestroyContext(MLDSAContext *ctx)
-+{
-+ PLArenaPool *arena = ctx->arena;
-+
-+ /* free up any dangling hashes. Can happen in certain signature
-+ * failure cases */
-+ lc_hash_zero(&ctx->lc_dilithium.dilithium_hash_ctx);
-+
-+ /* this zeros out all the arena allocated data, so we don't have to
-+ * do any expicit freeing */
-+ PORT_FreeArena(arena, PR_TRUE);
-+}
-+
-+static MLDSAContext *
-+mldsa_NewContext(const MLDSAPrivateKey *privKey, const MLDSAPublicKey *pubKey)
-+{
-+ PLArenaPool *arena = NULL;
-+ MLDSAContext *ctx = NULL;
-+
-+ /* must have one and only one of the keys */
-+ if (!privKey && !pubKey) {
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ }
-+ if (privKey && pubKey) {
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ }
-+
-+ arena = PORT_NewArena(1024);
-+ if (arena == NULL) {
-+ return NULL;
-+ }
-+
-+ ctx = PORT_ArenaZNew(arena, MLDSAContext);
-+ if (!ctx) {
-+ goto loser;
-+ }
-+ ctx->arena = arena;
-+ ctx->lc_dilithium.dilithium_hash_ctx.hash = lc_shake256;
-+ ctx->lc_dilithium.dilithium_hash_ctx.stream = true;
-+ /* we ZNew'd the context, so this is not necessary, but
-+ * document it here or hashing won't work if we don't
-+ * have a zero'ed context:
-+ lctx->lc_dilithium.dilithium_hash_ctx.u.ctx_ptr = NULL; */
-+ if (privKey) {
-+ ctx->privKey = PORT_ArenaNew(arena, MLDSAPrivateKey);
-+ if (ctx->privKey == NULL) {
-+ goto loser;
-+ }
-+ PORT_Memcpy(ctx->privKey, privKey, sizeof(MLDSAPrivateKey));
-+ }
-+ if (pubKey) {
-+ ctx->pubKey = PORT_ArenaNew(arena, MLDSAPublicKey);
-+ if (ctx->pubKey == NULL) {
-+ goto loser;
-+ }
-+ PORT_Memcpy(ctx->pubKey, pubKey, sizeof(MLDSAPublicKey));
-+ }
-+ return ctx;
-+
-+loser:
-+ if (ctx) {
-+ arena = 0;
-+ mldsa_DestroyContext(ctx);
-+ }
-+ if (arena) {
-+ PORT_FreeArena(arena, PR_FALSE);
-+ }
-+ return NULL;
-+}
-+
-+static const MLDSAPrivateKey *
-+mldsa_ContextGetPrivateKey(const MLDSAContext *ctx)
-+{
-+ return ctx->privKey;
-+}
-+
-+static const MLDSAPublicKey *
-+mldsa_ContextGetPublicKey(const MLDSAContext *ctx)
-+{
-+ return ctx->pubKey;
-+}
-+#endif
-+
-+/*
-+** Generate and return a new DSA public and private key pair,
-+** both of which are encoded into a single DSAPrivateKey struct.
-+** "params" is a pointer to the PQG parameters for the domain
-+** Uses a random seed.
-+*/
-+SECStatus
-+MLDSA_NewKey(CK_ML_DSA_PARAMETER_SET_TYPE paramSet, SECItem *seed,
-+ MLDSAPrivateKey *privKey, MLDSAPublicKey *pubKey)
-+{
-+#ifndef NSS_ENABLE_ML_DSA
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ return SECFailure;
-+#else
-+ int ret = -1;
-+
-+ /* make sure we can set the keys first */
-+ if (!privKey || !pubKey) {
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ return SECFailure;
-+ }
-+
-+ privKey->seedLen = ML_DSA_SEED_LEN;
-+ privKey->paramSet = paramSet;
-+ pubKey->paramSet = paramSet;
-+ if (seed != NULL) {
-+ if ((seed->data == NULL) || (seed->len != ML_DSA_SEED_LEN)) {
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ goto loser;
-+ }
-+ PORT_Memcpy(privKey->seed, seed->data, ML_DSA_SEED_LEN);
-+ } else {
-+ RNG_SystemRNG(privKey->seed, ML_DSA_SEED_LEN);
-+ }
-+ privKey->seedLen = ML_DSA_SEED_LEN;
-+
-+ switch (paramSet) {
-+ case CKP_ML_DSA_44:
-+ ret = lc_dilithium_44_keypair_from_seed_c(
-+ (struct lc_dilithium_44_pk *)pubKey->keyVal,
-+ (struct lc_dilithium_44_sk *)privKey->keyVal,
-+ privKey->seed, privKey->seedLen);
-+ pubKey->keyValLen = ML_DSA_44_PUBLICKEY_LEN;
-+ privKey->keyValLen = ML_DSA_44_PRIVATEKEY_LEN;
-+ break;
-+ case CKP_ML_DSA_65:
-+ ret = lc_dilithium_65_keypair_from_seed_c(
-+ (struct lc_dilithium_65_pk *)pubKey->keyVal,
-+ (struct lc_dilithium_65_sk *)privKey->keyVal,
-+ privKey->seed, privKey->seedLen);
-+ pubKey->keyValLen = ML_DSA_65_PUBLICKEY_LEN;
-+ privKey->keyValLen = ML_DSA_65_PRIVATEKEY_LEN;
-+ break;
-+ case CKP_ML_DSA_87:
-+ ret = lc_dilithium_87_keypair_from_seed_c(
-+ (struct lc_dilithium_87_pk *)pubKey->keyVal,
-+ (struct lc_dilithium_87_sk *)privKey->keyVal,
-+ privKey->seed, privKey->seedLen);
-+ pubKey->keyValLen = ML_DSA_87_PUBLICKEY_LEN;
-+ privKey->keyValLen = ML_DSA_87_PRIVATEKEY_LEN;
-+ break;
-+ default:
-+ ret = -1;
-+ break;
-+ }
-+
-+ if (ret != 0 ) {
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ goto loser;
-+ }
-+ return SECSuccess;
-+
-+loser:
-+ PORT_SafeZero(privKey, sizeof(privKey));
-+ PORT_SafeZero(pubKey, sizeof(pubKey));
-+ return SECFailure;
-+#endif
-+}
-+
-+/*
-+ * we don't have a streaming interace, so use our own local context
-+ * to keep track of things */
-+SECStatus
-+MLDSA_SignInit(MLDSAPrivateKey *key, CK_HEDGE_TYPE hedgeType,
-+ const SECItem *sgnCtx, MLDSAContext **ctx)
-+{
-+#ifndef NSS_ENABLE_ML_DSA
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ return SECFailure;
-+#else
-+ int ret = -1;
-+ MLDSAContext *lctx = NULL;
-+ if (!ctx || !key || sgnCtx->len > 255) {
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ return SECFailure;
-+ }
-+ lctx = mldsa_NewContext(key, NULL);
-+ if (lctx == NULL ) {
-+ return SECFailure;
-+ }
-+ lctx->hedgeType = hedgeType;
-+ if (sgnCtx && sgnCtx->len != 0) {
-+ lctx->lc_dilithium.userctx = sgnCtx->data;
-+ lctx->lc_dilithium.userctxlen = sgnCtx->len;
-+ }
-+ lctx->paramSet = key->paramSet;
-+
-+ switch (key->paramSet) {
-+ case CKP_ML_DSA_44:
-+ ret = lc_dilithium_44_sign_init_c(&lctx->lc_dilithium,
-+ (struct lc_dilithium_44_sk *)key->keyVal);
-+ break;
-+ case CKP_ML_DSA_65:
-+ ret = lc_dilithium_65_sign_init_c(&lctx->lc_dilithium,
-+ (struct lc_dilithium_65_sk *)key->keyVal);
-+ break;
-+ case CKP_ML_DSA_87:
-+ ret = lc_dilithium_87_sign_init_c(&lctx->lc_dilithium,
-+ (struct lc_dilithium_87_sk *)key->keyVal);
-+ break;
-+ }
-+
-+ if (ret < 0) {
-+ mldsa_DestroyContext(lctx);
-+ return SECFailure;
-+ }
-+ *ctx = lctx;
-+ return SECSuccess;
-+#endif
-+}
-+
-+SECStatus
-+MLDSA_SignUpdate(MLDSAContext *ctx, const SECItem *data)
-+{
-+#ifndef NSS_ENABLE_ML_DSA
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ return SECFailure;
-+#else
-+ int ret = -1;
-+ switch (ctx->paramSet) {
-+ case CKP_ML_DSA_44:
-+ ret = lc_dilithium_44_sign_update_c(&ctx->lc_dilithium,
-+ data->data, data->len);
-+ break;
-+ case CKP_ML_DSA_65:
-+ ret = lc_dilithium_65_sign_update_c(&ctx->lc_dilithium,
-+ data->data, data->len);
-+ break;
-+ case CKP_ML_DSA_87:
-+ ret = lc_dilithium_87_sign_update_c(&ctx->lc_dilithium,
-+ data->data, data->len);
-+ break;
-+ }
-+
-+ if (ret < 0) {
-+ return SECFailure;
-+ }
-+ return SECSuccess;
-+#endif
-+}
-+
-+
-+SECStatus
-+MLDSA_SignFinal(MLDSAContext *ctx, SECItem *signature)
-+{
-+#ifndef NSS_ENABLE_ML_DSA
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ return SECFailure;
-+#else
-+ /* make sure we have all the parameters */
-+ if (!ctx || !signature) {
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ return SECFailure;
-+ }
-+ const MLDSAPrivateKey *key = mldsa_ContextGetPrivateKey(ctx);
-+ int ret = -1;
-+ size_t len = signature->len;
-+ struct lc_rng_ctx system_rng = {NULL};
-+ struct lc_rng_ctx *fake_rng = &system_rng;
-+
-+ if (!key) {
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ return SECFailure;
-+ }
-+ if (ctx->hedgeType == CKH_DETERMINISTIC_REQUIRED) {
-+ fake_rng = NULL;
-+ }
-+
-+ ret = -1;
-+ switch (key->paramSet) {
-+ case CKP_ML_DSA_44:
-+ /* handle the case where we are trying to get the signature length
-+ * or we supplied a length that was too short */
-+ len = ML_DSA_44_SIGNATURE_LEN;
-+ if (!signature->data ||
-+ (signature->len < len)) {
-+ signature->len = len;
-+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
-+ break;
-+ }
-+ ret = lc_dilithium_44_sign_final_c(
-+ (struct lc_dilithium_44_sig *)signature->data,
-+ &ctx->lc_dilithium,
-+ (struct lc_dilithium_44_sk *)key->keyVal,
-+ fake_rng);
-+ break;
-+ case CKP_ML_DSA_65:
-+ /* handle the case where we are trying to get the signature length
-+ * or we supplied a length that was too short */
-+ len = ML_DSA_65_SIGNATURE_LEN;
-+ if (!signature->data ||
-+ (signature->len < len)) {
-+ signature->len = len;
-+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
-+ break;
-+ }
-+ ret = lc_dilithium_65_sign_final_c(
-+ (struct lc_dilithium_65_sig *)signature->data,
-+ &ctx->lc_dilithium,
-+ (struct lc_dilithium_65_sk *)key->keyVal,
-+ fake_rng);
-+ break;
-+ case CKP_ML_DSA_87:
-+ /* handle the case where we are trying to get the signature length
-+ * or we supplied a length that was too short */
-+ len = ML_DSA_87_SIGNATURE_LEN;
-+ if (!signature->data ||
-+ (signature->len < len)) {
-+ signature->len = len;
-+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
-+ break;
-+ }
-+ ret = lc_dilithium_87_sign_final_c(
-+ (struct lc_dilithium_87_sig *)signature->data,
-+ &ctx->lc_dilithium,
-+ (struct lc_dilithium_87_sk *)key->keyVal,
-+ fake_rng);
-+ break;
-+ default:
-+ ret = -1;
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ break;
-+ }
-+ if (ret != 0 ) {
-+ /* error code already set */
-+ return SECFailure;
-+ }
-+ signature->len = len;
-+ mldsa_DestroyContext(ctx);
-+ return SECSuccess;
-+#endif
-+}
-+
-+/*
-+ * we don't have a streaming interace, so use our own local context
-+ * to keep track of things */
-+SECStatus
-+MLDSA_VerifyInit(MLDSAPublicKey *key, const SECItem *sgnCtx, MLDSAContext **ctx)
-+{
-+#ifndef NSS_ENABLE_ML_DSA
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ return SECFailure;
-+#else
-+ MLDSAContext *lctx;
-+ int ret = -1;
-+ if (!ctx || !key || sgnCtx->len > 255) {
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ return SECFailure;
-+ }
-+ lctx = mldsa_NewContext(NULL, key);
-+ if (!lctx) {
-+ return SECFailure;
-+ }
-+ if (sgnCtx && sgnCtx->len != 0) {
-+ lctx->lc_dilithium.userctx = sgnCtx->data;
-+ lctx->lc_dilithium.userctxlen = sgnCtx->len;
-+ }
-+ lctx->paramSet = key->paramSet;
-+
-+ switch (key->paramSet) {
-+ case CKP_ML_DSA_44:
-+ ret = lc_dilithium_44_verify_init_c(&lctx->lc_dilithium,
-+ (struct lc_dilithium_44_pk *)key->keyVal);
-+ break;
-+ case CKP_ML_DSA_65:
-+ ret = lc_dilithium_65_verify_init_c(&lctx->lc_dilithium,
-+ (struct lc_dilithium_65_pk *)key->keyVal);
-+ break;
-+ case CKP_ML_DSA_87:
-+ ret = lc_dilithium_87_verify_init_c(&lctx->lc_dilithium,
-+ (struct lc_dilithium_87_pk *)key->keyVal);
-+ break;
-+ }
-+
-+ if (ret < 0) {
-+ mldsa_DestroyContext(lctx);
-+ return SECFailure;
-+ }
-+ *ctx = lctx;
-+ return SECSuccess;
-+#endif
-+}
-+
-+SECStatus
-+MLDSA_VerifyUpdate(MLDSAContext *ctx, const SECItem *data)
-+{
-+#ifndef NSS_ENABLE_ML_DSA
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ return SECFailure;
-+#else
-+ int ret = -1;
-+ switch (ctx->paramSet) {
-+ case CKP_ML_DSA_44:
-+ ret = lc_dilithium_44_verify_update_c(&ctx->lc_dilithium,
-+ data->data, data->len);
-+ break;
-+ case CKP_ML_DSA_65:
-+ ret = lc_dilithium_65_verify_update_c(&ctx->lc_dilithium,
-+ data->data, data->len);
-+ break;
-+ case CKP_ML_DSA_87:
-+ ret = lc_dilithium_87_verify_update_c(&ctx->lc_dilithium,
-+ data->data, data->len);
-+ break;
-+ }
-+
-+ if (ret < 0) {
-+ return SECFailure;
-+ }
-+ return SECSuccess;
-+#endif
-+}
-+
-+SECStatus
-+MLDSA_VerifyFinal(MLDSAContext *ctx, const SECItem *signature)
-+{
-+#ifndef NSS_ENABLE_ML_DSA
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ return SECFailure;
-+#else
-+ const MLDSAPublicKey *key = mldsa_ContextGetPublicKey(ctx);
-+ int ret = -1;
-+
-+ if (key == NULL) {
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ return SECFailure;
-+ }
-+ ret = -1;
-+ switch (key->paramSet) {
-+ case CKP_ML_DSA_44:
-+ ret = lc_dilithium_44_verify_final_c(
-+ (struct lc_dilithium_44_sig *)signature->data,
-+ &ctx->lc_dilithium, (struct lc_dilithium_44_pk *)key->keyVal);
-+ break;
-+ case CKP_ML_DSA_65:
-+ ret = lc_dilithium_65_verify_final_c(
-+ (struct lc_dilithium_65_sig *)signature->data,
-+ &ctx->lc_dilithium, (struct lc_dilithium_65_pk *)key->keyVal);
-+ break;
-+ case CKP_ML_DSA_87:
-+ ret = lc_dilithium_87_verify_final_c(
-+ (struct lc_dilithium_87_sig *)signature->data,
-+ &ctx->lc_dilithium, (struct lc_dilithium_87_pk *)key->keyVal);
-+ break;
-+ default:
-+ ret = -1;
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ break;
-+ }
-+ if (ret != 0 ) {
-+ /* in Verify we close the context on an invalid signature as well
-+ * as success */
-+ mldsa_DestroyContext(ctx);
-+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
-+ return SECFailure;
-+ }
-+ mldsa_DestroyContext(ctx);
-+ return SECSuccess;
-+#endif
-+}
-+
-diff --git a/lib/freebl/stubs.c b/lib/freebl/stubs.c
---- a/lib/freebl/stubs.c
-+++ b/lib/freebl/stubs.c
-@@ -135,16 +135,17 @@
- if (fn) { \
- return fn(a1, a2, a3, a4, a5, a6); \
- }
- #endif
-
- STUB_DECLARE(void *, PORT_Alloc_Util, (size_t len));
- STUB_DECLARE(void *, PORT_ArenaAlloc_Util, (PLArenaPool * arena, size_t size));
- STUB_DECLARE(void *, PORT_ArenaZAlloc_Util, (PLArenaPool * arena, size_t size));
-+STUB_DECLARE(void *, PORT_ArenaGrow_Util, (PLArenaPool * arena, void *ptr, size_t oldsize, size_t newsize));
- STUB_DECLARE(void, PORT_Free_Util, (void *ptr));
- STUB_DECLARE(void, PORT_FreeArena_Util, (PLArenaPool * arena, PRBool zero));
- STUB_DECLARE(int, PORT_GetError_Util, (void));
- STUB_DECLARE(PLArenaPool *, PORT_NewArena_Util, (unsigned long chunksize));
- STUB_DECLARE(void, PORT_SafeZero, (void *p, size_t n));
- STUB_DECLARE(void, PORT_SetError_Util, (int value));
- STUB_DECLARE(void *, PORT_ZAlloc_Util, (size_t len));
- STUB_DECLARE(void *, PORT_ZAllocAligned_Util, (size_t bytes, size_t alignment, void **mem));
-@@ -326,16 +327,25 @@ extern void *
- PORT_ArenaZAlloc_stub(PLArenaPool *arena, size_t size)
- {
-
- STUB_SAFE_CALL2(PORT_ArenaZAlloc_Util, arena, size);
- abort();
- return NULL;
- }
-
-+extern void *
-+PORT_ArenaGrow_stub(PLArenaPool *arena, void *ptr, size_t oldsize, size_t newsize)
-+{
-+
-+ STUB_SAFE_CALL4(PORT_ArenaGrow_Util, arena, ptr, oldsize, newsize);
-+ abort();
-+ return NULL;
-+}
-+
- extern void
- PORT_FreeArena_stub(PLArenaPool *arena, PRBool zero)
- {
-
- STUB_SAFE_CALL2(PORT_FreeArena_Util, arena, zero);
- abort();
- }
-
-@@ -808,16 +818,17 @@ freebl_InitNSSUtil(void *lib)
- {
- STUB_FETCH_FUNCTION(PORT_Alloc_Util);
- STUB_FETCH_FUNCTION(PORT_Free_Util);
- STUB_FETCH_FUNCTION(PORT_ZAlloc_Util);
- STUB_FETCH_FUNCTION(PORT_ZFree_Util);
- STUB_FETCH_FUNCTION(PORT_NewArena_Util);
- STUB_FETCH_FUNCTION(PORT_ArenaAlloc_Util);
- STUB_FETCH_FUNCTION(PORT_ArenaZAlloc_Util);
-+ STUB_FETCH_FUNCTION(PORT_ArenaGrow_Util);
- STUB_FETCH_FUNCTION(PORT_FreeArena_Util);
- STUB_FETCH_FUNCTION(PORT_GetError_Util);
- STUB_FETCH_FUNCTION(PORT_SetError_Util);
- STUB_FETCH_FUNCTION(SECITEM_FreeItem_Util);
- STUB_FETCH_FUNCTION(SECITEM_AllocItem_Util);
- STUB_FETCH_FUNCTION(SECITEM_CompareItem_Util);
- STUB_FETCH_FUNCTION(SECITEM_CopyItem_Util);
- STUB_FETCH_FUNCTION(SECITEM_ZfreeItem_Util);
-diff --git a/lib/freebl/stubs.h b/lib/freebl/stubs.h
---- a/lib/freebl/stubs.h
-+++ b/lib/freebl/stubs.h
-@@ -18,16 +18,17 @@
- #endif
-
- /* hide libutil rename */
- #define _LIBUTIL_H_ 1
-
- #define PORT_Alloc PORT_Alloc_stub
- #define PORT_ArenaAlloc PORT_ArenaAlloc_stub
- #define PORT_ArenaZAlloc PORT_ArenaZAlloc_stub
-+#define PORT_ArenaGrow PORT_ArenaGrow_stub
- #define PORT_Free PORT_Free_stub
- #define PORT_FreeArena PORT_FreeArena_stub
- #define PORT_GetError PORT_GetError_stub
- #define PORT_NewArena PORT_NewArena_stub
- #define PORT_SafeZero PORT_SafeZero_stub
- #define PORT_SetError PORT_SetError_stub
- #define PORT_ZAlloc PORT_ZAlloc_stub
- #define PORT_ZFree PORT_ZFree_stub
-diff --git a/lib/pk11wrap/pk11akey.c b/lib/pk11wrap/pk11akey.c
---- a/lib/pk11wrap/pk11akey.c
-+++ b/lib/pk11wrap/pk11akey.c
-@@ -21,21 +21,21 @@
- #include "secasn1.h"
- #include "secoid.h"
- #include "secerr.h"
- #include "sechash.h"
-
- #include "secpkcs5.h"
- #include "blapit.h"
-
--static SECItem *
--pk11_MakeIDFromPublicKey(SECKEYPublicKey *pubKey)
-+const SECItem *
-+pk11_GetPublicKeyComponent(SECKEYPublicKey *pubKey)
- {
- /* set the ID to the public key so we can find it again */
-- SECItem *pubKeyIndex = NULL;
-+ const SECItem *pubKeyIndex = NULL;
- switch (pubKey->keyType) {
- case rsaKey:
- pubKeyIndex = &pubKey->u.rsa.modulus;
- break;
- case dsaKey:
- pubKeyIndex = &pubKey->u.dsa.publicValue;
- break;
- case dhKey:
-@@ -44,24 +44,67 @@ pk11_MakeIDFromPublicKey(SECKEYPublicKey
- case edKey:
- case ecKey:
- case ecMontKey:
- pubKeyIndex = &pubKey->u.ec.publicValue;
- break;
- case kyberKey:
- pubKeyIndex = &pubKey->u.kyber.publicValue;
- break;
-+ case mldsaKey:
-+ pubKeyIndex = &pubKey->u.mldsa.publicValue;
-+ break;
- default:
- return NULL;
- }
- PORT_Assert(pubKeyIndex != NULL);
-+ return pubKeyIndex;
-+}
-
-+static SECItem *
-+pk11_MakeIDFromPublicKey(SECKEYPublicKey *pubKey)
-+{
-+ const SECItem *pubKeyIndex = pk11_GetPublicKeyComponent(pubKey);
-+ if (pubKeyIndex == NULL) {
-+ return NULL;
-+ }
- return PK11_MakeIDFromPubKey(pubKeyIndex);
- }
-
-+KeyType
-+pk11_GetKeyTypeFromPKCS11KeyType(CK_KEY_TYPE pk11KeyType)
-+{
-+ switch (pk11KeyType) {
-+ case CKK_RSA:
-+ return rsaKey;
-+ case CKK_DSA:
-+ return dsaKey;
-+ case CKK_DH:
-+ return dhKey;
-+ case CKK_EC:
-+ return ecKey;
-+ case CKK_EC_MONTGOMERY:
-+ return ecMontKey;
-+ case CKK_EC_EDWARDS:
-+ return edKey;
-+#ifndef NSS_DISABLE_KYBER
-+ case CKK_NSS_KYBER:
-+#endif
-+ case CKK_NSS_ML_KEM:
-+ case CKK_ML_KEM:
-+ return kyberKey;
-+ case CKK_ML_DSA:
-+ return mldsaKey;
-+ default:
-+ break;
-+ }
-+ PORT_SetError(SEC_ERROR_BAD_KEY);
-+ return nullKey;
-+}
-+
- /*
- * import a public key into the desired slot
- *
- * This function takes a public key structure and creates a public key in a
- * given slot. If isToken is set, then a persistant public key is created.
- *
- * Note: it is possible for this function to return a handle for a key which
- * is persistant, even if isToken is not set.
-@@ -73,17 +116,17 @@ PK11_ImportPublicKey(PK11SlotInfo *slot,
- CK_BBOOL cktrue = CK_TRUE;
- CK_BBOOL ckfalse = CK_FALSE;
- CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
- CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
- CK_OBJECT_HANDLE objectID;
- CK_ATTRIBUTE theTemplate[11];
- CK_ATTRIBUTE *signedattr = NULL;
- CK_ATTRIBUTE *attrs = theTemplate;
-- CK_NSS_KEM_PARAMETER_SET_TYPE kemParams;
-+ CK_ULONG paramSet;
- SECItem *ckaId = NULL;
- SECItem *pubValue = NULL;
- int signedcount = 0;
- unsigned int templateCount = 0;
- SECStatus rv;
-
- /* if we already have an object in the desired slot, use it */
- if (!isToken && pubKey->pkcs11Slot == slot) {
-@@ -244,62 +287,74 @@ PK11_ImportPublicKey(PK11SlotInfo *slot,
- return CK_INVALID_HANDLE;
- }
- PK11_SETATTRS(attrs, CKA_EC_POINT,
- pubValue->data, pubValue->len);
- attrs++;
- }
- break;
- case kyberKey:
-- /*fprintf(stderr, "PK11_ImportPublic key kyber, params=%d\n",
-- pubKey->u.kyber.params);*/
- switch (pubKey->u.kyber.params) {
- #ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3:
- case params_kyber768_round3_test_mode:
- keyType = CKK_NSS_KYBER;
-- kemParams = CKP_NSS_KYBER_768_ROUND3;
-+ paramSet = CKP_NSS_KYBER_768_ROUND3;
- break;
- #endif
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
- keyType = CKK_ML_KEM;
-- kemParams = CKP_ML_KEM_768;
-+ paramSet = CKP_ML_KEM_768;
- break;
- case params_ml_kem1024:
- case params_ml_kem1024_test_mode:
- keyType = CKK_ML_KEM;
-- kemParams = CKP_ML_KEM_1024;
-+ paramSet = CKP_ML_KEM_1024;
- break;
- default:
-- kemParams = CKP_INVALID_ID;
-- break;
-+ PORT_SetError(SEC_ERROR_BAD_KEY);
-+ return CK_INVALID_HANDLE;
- }
-- /*fprintf(stderr, "PK11_ImportPublic KEY_TYPE=0x%08lx, kem_params=0x%08lxd\n",
-- keyType, kemParams); */
-
- PK11_SETATTRS(attrs, CKA_PARAMETER_SET,
-- &kemParams,
-+ ¶mSet,
- sizeof(CK_ML_KEM_PARAMETER_SET_TYPE));
- attrs++;
- PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.kyber.publicValue.data,
- pubKey->u.kyber.publicValue.len);
- attrs++;
- break;
-+ case mldsaKey:
-+ keyType = CKK_ML_DSA;
-+ paramSet = SECKEY_MLDSAOidParamsToPkcs11Params(pubKey->u.mldsa.params);
-+ if (paramSet == 0) {
-+ PORT_SetError(SEC_ERROR_BAD_KEY);
-+ return CK_INVALID_HANDLE;
-+ }
-+ PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));
-+ attrs++;
-+ PK11_SETATTRS(attrs, CKA_VALUE,
-+ pubKey->u.mldsa.publicValue.data,
-+ pubKey->u.mldsa.publicValue.len);
-+ attrs++;
-+ PK11_SETATTRS(attrs, CKA_PARAMETER_SET, ¶mSet,
-+ sizeof(CK_ML_DSA_PARAMETER_SET_TYPE));
-+ attrs++;
-+ break;
- default:
- if (ckaId) {
- SECITEM_FreeItem(ckaId, PR_TRUE);
- }
- PORT_SetError(SEC_ERROR_BAD_KEY);
- return CK_INVALID_HANDLE;
- }
- templateCount = attrs - theTemplate;
- PORT_Assert(templateCount <= (sizeof(theTemplate) / sizeof(CK_ATTRIBUTE)));
-- if (pubKey->keyType != ecKey && pubKey->keyType != kyberKey && pubKey->keyType != edKey &&
-- pubKey->keyType != ecMontKey) {
-+ if (signedattr) {
- PORT_Assert(signedattr);
- signedcount = attrs - signedattr;
- for (attrs = signedattr; signedcount; attrs++, signedcount--) {
- pk11_SignedToUnsigned(attrs);
- }
- }
- rv = PK11_CreateNewObject(slot, CK_INVALID_HANDLE, theTemplate,
- templateCount, isToken, &objectID);
-@@ -664,54 +719,28 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot
- PLArenaPool *tmp_arena;
- SECKEYPublicKey *pubKey;
- unsigned int templateCount = 0;
- CK_KEY_TYPE pk11KeyType;
- CK_RV crv;
- CK_ATTRIBUTE template[8];
- CK_ATTRIBUTE *attrs = template;
- CK_ATTRIBUTE *modulus, *exponent, *base, *prime, *subprime, *value;
-- CK_ATTRIBUTE *ecparams, *kemParams;
-+ CK_ATTRIBUTE *ecparams, *paramSet;
-
- /* if we didn't know the key type, get it */
- if (keyType == nullKey) {
-
- pk11KeyType = PK11_ReadULongAttribute(slot, id, CKA_KEY_TYPE);
- if (pk11KeyType == CK_UNAVAILABLE_INFORMATION) {
- return NULL;
- }
-- switch (pk11KeyType) {
-- case CKK_RSA:
-- keyType = rsaKey;
-- break;
-- case CKK_DSA:
-- keyType = dsaKey;
-- break;
-- case CKK_DH:
-- keyType = dhKey;
-- break;
-- case CKK_EC:
-- keyType = ecKey;
-- break;
-- case CKK_EC_MONTGOMERY:
-- keyType = ecMontKey;
-- break;
-- case CKK_EC_EDWARDS:
-- keyType = edKey;
-- break;
--#ifndef NSS_DISABLE_KYBER
-- case CKK_NSS_KYBER:
--#endif
-- case CKK_NSS_ML_KEM:
-- case CKK_ML_KEM:
-- keyType = kyberKey;
-- break;
-- default:
-- PORT_SetError(SEC_ERROR_BAD_KEY);
-- return NULL;
-+ keyType = pk11_GetKeyTypeFromPKCS11KeyType(pk11KeyType);
-+ if (keyType == nullKey) {
-+ return NULL;
- }
- }
-
- /* now we need to create space for the public key */
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
- if (arena == NULL)
- return NULL;
- tmp_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-@@ -862,27 +891,27 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot
- crv = pk11_get_Decoded_ECPoint(arena,
- &pubKey->u.ec.DEREncodedParams, value,
- &pubKey->u.ec.publicValue);
- break;
- case kyberKey:
- value = attrs;
- PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0);
- attrs++;
-- kemParams = attrs;
-+ paramSet = attrs;
- PK11_SETATTRS(attrs, CKA_PARAMETER_SET, NULL, 0);
- attrs++;
- templateCount = attrs - template;
- PR_ASSERT(templateCount <= sizeof(template) / sizeof(CK_ATTRIBUTE));
-
- crv = PK11_GetAttributes(arena, slot, id, template, templateCount);
- if (crv != CKR_OK) {
- /* try to fetch with the vendor specific
- * CKA_NSS_PARAMETER_SET */
-- kemParams->type = CKA_NSS_PARAMETER_SET;
-+ paramSet->type = CKA_NSS_PARAMETER_SET;
- crv = PK11_GetAttributes(arena, slot, id, template,
- templateCount);
- if (crv != CKR_OK) {
- break;
- }
- }
- if (keyClass != CKO_PUBLIC_KEY) {
- crv = CKR_OBJECT_HANDLE_INVALID;
-@@ -898,21 +927,21 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot
- default:
- crv = CKR_OBJECT_HANDLE_INVALID;
- break;
- }
- if (crv != CKR_OK) {
- break;
- }
-
-- if (kemParams->ulValueLen != sizeof(CK_ML_KEM_PARAMETER_SET_TYPE)) {
-+ if (paramSet->ulValueLen != sizeof(CK_ML_KEM_PARAMETER_SET_TYPE)) {
- crv = CKR_OBJECT_HANDLE_INVALID;
- break;
- }
-- CK_ML_KEM_PARAMETER_SET_TYPE *pPK11Params = kemParams->pValue;
-+ CK_ML_KEM_PARAMETER_SET_TYPE *pPK11Params = paramSet->pValue;
- switch (*pPK11Params) {
- #ifdef NSS_DISABLE_KYBER
- case CKP_NSS_KYBER_768_ROUND3:
- pubKey->u.kyber.params = params_kyber768_round3;
- break;
- #endif
- case CKP_NSS_ML_KEM_768:
- case CKP_ML_KEM_768:
-@@ -922,16 +951,43 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot
- pubKey->u.kyber.params = params_ml_kem1024;
- break;
- default:
- pubKey->u.kyber.params = params_kyber_invalid;
- break;
- }
- crv = pk11_Attr2SecItem(arena, value, &pubKey->u.kyber.publicValue);
- break;
-+ case mldsaKey:
-+ value = attrs;
-+ PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0);
-+ attrs++;
-+ paramSet = attrs;
-+ PK11_SETATTRS(attrs, CKA_PARAMETER_SET, NULL, 0);
-+ attrs++;
-+ templateCount = attrs - template;
-+ PR_ASSERT(templateCount <= sizeof(template) / sizeof(CK_ATTRIBUTE));
-+
-+ crv = PK11_GetAttributes(arena, slot, id, template, templateCount);
-+ if (crv != CKR_OK) {
-+ break;
-+ }
-+ if (keyClass != CKO_PUBLIC_KEY) {
-+ crv = CKR_OBJECT_HANDLE_INVALID;
-+ break;
-+ }
-+
-+ if (paramSet->ulValueLen != sizeof(CK_ML_DSA_PARAMETER_SET_TYPE)) {
-+ crv = CKR_OBJECT_HANDLE_INVALID;
-+ break;
-+ }
-+ pubKey->u.mldsa.params = SECKEY_MLDSAPkcs11ParamsToOidParams(
-+ *(CK_ML_DSA_PARAMETER_SET_TYPE *)paramSet->pValue);
-+ crv = pk11_Attr2SecItem(arena, value, &pubKey->u.mldsa.publicValue);
-+ break;
- case fortezzaKey:
- case nullKey:
- default:
- crv = CKR_OBJECT_HANDLE_INVALID;
- break;
- }
-
- PORT_FreeArena(tmp_arena, PR_FALSE);
-@@ -959,47 +1015,19 @@ PK11_MakePrivKey(PK11SlotInfo *slot, Key
- SECStatus rv;
-
- /* don't know? look it up */
- if (keyType == nullKey) {
- CK_KEY_TYPE pk11Type = CKK_RSA;
-
- pk11Type = PK11_ReadULongAttribute(slot, privID, CKA_KEY_TYPE);
- isTemp = (PRBool)!PK11_HasAttributeSet(slot, privID, CKA_TOKEN, PR_FALSE);
-- switch (pk11Type) {
-- case CKK_RSA:
-- keyType = rsaKey;
-- break;
-- case CKK_DSA:
-- keyType = dsaKey;
-- break;
-- case CKK_DH:
-- keyType = dhKey;
-- break;
-- case CKK_KEA:
-- keyType = fortezzaKey;
-- break;
-- case CKK_EC:
-- keyType = ecKey;
-- break;
-- case CKK_EC_MONTGOMERY:
-- keyType = ecMontKey;
-- break;
-- case CKK_EC_EDWARDS:
-- keyType = edKey;
-- break;
--#ifndef NSS_DISABLE_KYBER
-- case CKK_NSS_KYBER:
--#endif
-- case CKK_NSS_ML_KEM:
-- case CKK_ML_KEM:
-- keyType = kyberKey;
-- break;
-- default:
-- break;
-+ keyType = pk11_GetKeyTypeFromPKCS11KeyType(pk11Type);
-+ if (keyType == nullKey) {
-+ return NULL;
- }
- }
-
- /* if the key is private, make sure we are authenticated to the
- * token before we try to use it */
- isPrivate = (PRBool)PK11_HasAttributeSet(slot, privID, CKA_PRIVATE, PR_FALSE);
- if (isPrivate) {
- rv = PK11_Authenticate(slot, PR_TRUE, wincx);
-@@ -1105,16 +1133,17 @@ pk11_loadPrivKeyWithFlags(PK11SlotInfo *
- { CKA_EXPONENT_1, NULL, 0 },
- { CKA_EXPONENT_2, NULL, 0 },
- { CKA_COEFFICIENT, NULL, 0 },
- { CKA_DECRYPT, NULL, 0 },
- { CKA_DERIVE, NULL, 0 },
- { CKA_SIGN, NULL, 0 },
- { CKA_SIGN_RECOVER, NULL, 0 },
- { CKA_UNWRAP, NULL, 0 },
-+ { CKA_ENCAPSULATE, NULL, 0 },
- /* reserve space for the attributes that may be
- * specified in attrFlags */
- { CKA_TOKEN, NULL, 0 },
- { CKA_PRIVATE, NULL, 0 },
- { CKA_MODIFIABLE, NULL, 0 },
- { CKA_SENSITIVE, NULL, 0 },
- { CKA_EXTRACTABLE, NULL, 0 },
- #define NUM_RESERVED_ATTRS 5 /* number of reserved attributes above */
-@@ -1214,16 +1243,34 @@ pk11_loadPrivKeyWithFlags(PK11SlotInfo *
- extra_count++;
- }
-
- ap->type = CKA_SIGN;
- ap++;
- count++;
- extra_count++;
- break;
-+ case mldsaKey:
-+ ap->type = CKA_VALUE;
-+ ap++;
-+ count++;
-+ extra_count++;
-+ ap->type = CKA_SEED;
-+ ap++;
-+ count++;
-+ extra_count++;
-+ ap->type = CKA_PARAMETER_SET;
-+ ap++;
-+ count++;
-+ extra_count++;
-+ ap->type = CKA_SIGN;
-+ ap++;
-+ count++;
-+ extra_count++;
-+ break;
- default:
- count = 0;
- extra_count = 0;
- break;
- }
-
- if (count == 0) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-@@ -1400,17 +1447,17 @@ PK11_GenerateKeyPairWithOpFlags(PK11Slot
-
- /*CK_ULONG key_size = 0;*/
- CK_ATTRIBUTE *pubTemplate;
- int privCount = 0;
- int pubCount = 0;
- PK11RSAGenParams *rsaParams;
- SECKEYPQGParams *dsaParams;
- SECKEYDHParams *dhParams;
-- CK_NSS_KEM_PARAMETER_SET_TYPE *kemParams;
-+ CK_ULONG *paramSet;
- CK_MECHANISM mechanism;
- CK_MECHANISM test_mech;
- CK_MECHANISM test_mech2;
- CK_SESSION_HANDLE session_handle;
- CK_RV crv;
- CK_OBJECT_HANDLE privID, pubID;
- SECKEYPrivateKey *privKey;
- KeyType keyType;
-@@ -1610,25 +1657,36 @@ PK11_GenerateKeyPairWithOpFlags(PK11Slot
- goto ml_kem_gen;
- #endif
- case CKM_NSS_ML_KEM_KEY_PAIR_GEN:
- test_mech.mechanism = CKM_NSS_ML_KEM;
- goto ml_kem_gen;
- case CKM_ML_KEM_KEY_PAIR_GEN:
- test_mech.mechanism = CKM_ML_KEM;
- ml_kem_gen:
-- kemParams = (CK_NSS_KEM_PARAMETER_SET_TYPE *)param;
-+ paramSet = (CK_ULONG *)param;
- attrs = kyberPubTemplate;
-- PK11_SETATTRS(attrs, CKA_NSS_PARAMETER_SET,
-- kemParams,
-- sizeof(CK_NSS_KEM_PARAMETER_SET_TYPE));
-+ PK11_SETATTRS(attrs, CKA_PARAMETER_SET,
-+ paramSet,
-+ sizeof(CK_ML_KEM_PARAMETER_SET_TYPE));
- attrs++;
- pubTemplate = kyberPubTemplate;
- keyType = kyberKey;
- break;
-+ case CKM_ML_DSA_KEY_PAIR_GEN:
-+ test_mech.mechanism = CKM_ML_DSA;
-+ paramSet = (CK_ULONG *)param;
-+ attrs = kyberPubTemplate;
-+ PK11_SETATTRS(attrs, CKA_PARAMETER_SET,
-+ paramSet,
-+ sizeof(CK_ML_DSA_PARAMETER_SET_TYPE));
-+ attrs++;
-+ pubTemplate = kyberPubTemplate;
-+ keyType = mldsaKey;
-+ break;
- case CKM_EC_MONTGOMERY_KEY_PAIR_GEN:
- ecParams = (SECKEYECParams *)param;
- attrs = ecPubTemplate;
- PK11_SETATTRS(attrs, CKA_EC_PARAMS, ecParams->data,
- ecParams->len);
- attrs++;
- pubTemplate = ecPubTemplate;
- keyType = ecMontKey;
-@@ -1705,16 +1763,19 @@ ml_kem_gen:
- break;
- #ifndef NSS_DISABLE_KYBER
- case CKM_NSS_KYBER:
- #endif
- case CKM_NSS_ML_KEM:
- case CKM_ML_KEM:
- mechanism_info.flags = CKF_ENCAPSULATE|CKF_DECAPSULATE;
- break;
-+ case CKM_ML_DSA:
-+ mechanism_info.flags = CKF_SIGN|CKF_VERIFY;
-+ break;
- default:
- break;
- }
- }
- /* now adjust our flags according to the user's key usage passed to us */
- mechanism_info.flags = (mechanism_info.flags & (~opFlagsMask)) | opFlags;
- /* set the public key attributes */
- attrs += pk11_AttrFlagsToAttributes(pubKeyAttrFlags, attrs,
-@@ -1938,16 +1999,17 @@ PK11_MakeKEAPubKey(unsigned char *keyDat
- SECStatus
- SECKEY_SetPublicValue(SECKEYPrivateKey *privKey, SECItem *publicValue)
- {
- SECStatus rv;
- SECKEYPublicKey pubKey;
- PLArenaPool *arena;
- PK11SlotInfo *slot;
- CK_OBJECT_HANDLE privKeyID;
-+ CK_ULONG paramSet;
-
- if (privKey == NULL || publicValue == NULL ||
- publicValue->data == NULL || publicValue->len == 0) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
-
- pubKey.arena = NULL;
-@@ -2004,16 +2066,31 @@ SECKEY_SetPublicValue(SECKEYPrivateKey *
- case edKey:
- case ecMontKey:
- pubKey.u.ec.publicValue = *publicValue;
- pubKey.u.ec.encoding = ECPoint_Undefined;
- pubKey.u.ec.size = 0;
- rv = PK11_ReadAttribute(slot, privKeyID, CKA_EC_PARAMS,
- arena, &pubKey.u.ec.DEREncodedParams);
- break;
-+ case mldsaKey:
-+ pubKey.u.mldsa.publicValue = *publicValue;
-+ paramSet = PK11_ReadULongAttribute(slot, privKeyID,
-+ CKA_PARAMETER_SET);
-+ if (paramSet == CK_UNAVAILABLE_INFORMATION) {
-+ PORT_SetError(SEC_ERROR_BAD_KEY);
-+ break;
-+ }
-+ pubKey.u.mldsa.params = SECKEY_MLDSAPkcs11ParamsToOidParams(paramSet);
-+ if (pubKey.u.mldsa.params == SEC_OID_UNKNOWN) {
-+ PORT_SetError(SEC_ERROR_BAD_KEY);
-+ break;
-+ }
-+ rv = SECSuccess;
-+ break;
- }
- if (rv == SECSuccess) {
- rv = PK11_ImportPublicKey(slot, &pubKey, PR_TRUE);
- }
- /* Even though pubKey is stored on the stack, we've allocated
- * some of it's data from the arena. SECKEY_DestroyPublicKey
- * destroys keys by freeing the arena, so this will clean up all
- * the data we allocated specifically for the key above. It will
-@@ -2132,16 +2209,21 @@ PK11_ImportEncryptedPrivateKeyInfoAndRet
- usage = edUsage;
- usageCount = 1;
- break;
- case ecMontKey:
- key_type = CKK_EC_MONTGOMERY;
- usage = dhUsage;
- usageCount = 1;
- break;
-+ case mldsaKey:
-+ key_type = CKK_ML_DSA;
-+ usage = dsaUsage;
-+ usageCount = sizeof(dsaUsage) / sizeof(dsaUsage[0]);
-+ break;
- }
-
- try_faulty_3des:
-
- key = PK11_PBEKeyGen(slot, &epki->algorithm, pwitem, faulty3DES, wincx);
- if (key == NULL) {
- rv = SECFailure;
- goto done;
-@@ -2751,17 +2833,17 @@ PK11_FindKeyByKeyID(PK11SlotInfo *slot,
- }
-
- /*
- * Generate a CKA_ID from the relevant public key data. The CKA_ID is generated
- * from the pubKeyData by SHA1_Hashing it to produce a smaller CKA_ID (to make
- * smart cards happy.
- */
- SECItem *
--PK11_MakeIDFromPubKey(SECItem *pubKeyData)
-+PK11_MakeIDFromPubKey(const SECItem *pubKeyData)
- {
- PK11Context *context;
- SECItem *certCKA_ID;
- SECStatus rv;
-
- if (pubKeyData->len <= SHA1_LENGTH) {
- /* probably an already hashed value. The strongest known public
- * key values <= 160 bits would be less than 40 bit symetric in
-diff --git a/lib/pk11wrap/pk11cert.c b/lib/pk11wrap/pk11cert.c
---- a/lib/pk11wrap/pk11cert.c
-+++ b/lib/pk11wrap/pk11cert.c
-@@ -13,16 +13,17 @@
- #include "secmodi.h"
- #include "secmodti.h"
- #include "pkcs11.h"
- #include "pk11func.h"
- #include "cert.h"
- #include "certi.h"
- #include "secitem.h"
- #include "keyhi.h"
-+#include "keyi.h"
- #include "secoid.h"
- #include "pkcs7t.h"
- #include "cmsreclist.h"
-
- #include "certdb.h"
- #include "secerr.h"
- #include "sslerr.h"
-
-@@ -150,16 +151,17 @@ PK11_IsUserCert(PK11SlotInfo *slot, CERT
- SECKEYPublicKey *pubKey = CERT_ExtractPublicKey(cert);
- CK_ATTRIBUTE theTemplate;
-
- if (pubKey == NULL) {
- return PR_FALSE;
- }
-
- PK11_SETATTRS(&theTemplate, 0, NULL, 0);
-+
- switch (pubKey->keyType) {
- case rsaKey:
- case rsaPssKey:
- case rsaOaepKey:
- PK11_SETATTRS(&theTemplate, CKA_MODULUS, pubKey->u.rsa.modulus.data,
- pubKey->u.rsa.modulus.len);
- break;
- case dsaKey:
-@@ -172,16 +174,20 @@ PK11_IsUserCert(PK11SlotInfo *slot, CERT
- break;
- case ecKey:
- case edKey:
- case ecMontKey:
- PK11_SETATTRS(&theTemplate, CKA_EC_POINT,
- pubKey->u.ec.publicValue.data,
- pubKey->u.ec.publicValue.len);
- break;
-+ case mldsaKey:
-+ PK11_SETATTRS(&theTemplate, CKA_VALUE, pubKey->u.mldsa.publicValue.data,
-+ pubKey->u.mldsa.publicValue.len);
-+ break;
- case keaKey:
- case fortezzaKey:
- case kyberKey:
- case nullKey:
- /* fall through and return false */
- break;
- }
-
-@@ -1093,40 +1099,25 @@ PK11_FindCertsFromNickname(const char *n
- * extract a key ID for a certificate...
- * NOTE: We call this function from PKCS11.c If we ever use
- * pkcs11 to extract the public key (we currently do not), this will break.
- */
- SECItem *
- PK11_GetPubIndexKeyID(CERTCertificate *cert)
- {
- SECKEYPublicKey *pubk;
-+ const SECItem *oldItem;
- SECItem *newItem = NULL;
-
- pubk = CERT_ExtractPublicKey(cert);
- if (pubk == NULL)
- return NULL;
--
-- switch (pubk->keyType) {
-- case rsaKey:
-- newItem = SECITEM_DupItem(&pubk->u.rsa.modulus);
-- break;
-- case dsaKey:
-- newItem = SECITEM_DupItem(&pubk->u.dsa.publicValue);
-- break;
-- case dhKey:
-- newItem = SECITEM_DupItem(&pubk->u.dh.publicValue);
-- break;
-- case ecKey:
-- case edKey:
-- case ecMontKey:
-- newItem = SECITEM_DupItem(&pubk->u.ec.publicValue);
-- break;
-- case fortezzaKey:
-- default:
-- newItem = NULL; /* Fortezza Fix later... */
-+ oldItem = pk11_GetPublicKeyComponent(pubk);
-+ if (oldItem) {
-+ newItem = SECITEM_DupItem(oldItem);
- }
- SECKEY_DestroyPublicKey(pubk);
- /* make hash of it */
- return newItem;
- }
-
- /*
- * generate a CKA_ID from a certificate.
-diff --git a/lib/pk11wrap/pk11mech.c b/lib/pk11wrap/pk11mech.c
---- a/lib/pk11wrap/pk11mech.c
-+++ b/lib/pk11wrap/pk11mech.c
-@@ -1934,16 +1934,18 @@ PK11_MapSignKeyType(KeyType keyType)
- return CKM_RSA_PKCS;
- case fortezzaKey:
- case dsaKey:
- return CKM_DSA;
- case ecKey:
- return CKM_ECDSA;
- case edKey:
- return CKM_EDDSA;
-+ case mldsaKey:
-+ return CKM_ML_DSA;
- case dhKey:
- default:
- break;
- }
- return CKM_INVALID_MECHANISM;
- }
-
- CK_MECHANISM_TYPE
-diff --git a/lib/pk11wrap/pk11obj.c b/lib/pk11wrap/pk11obj.c
---- a/lib/pk11wrap/pk11obj.c
-+++ b/lib/pk11wrap/pk11obj.c
-@@ -11,16 +11,17 @@
- #include "secder.h"
- #include "secmod.h"
- #include "secmodi.h"
- #include "secmodti.h"
- #include "pkcs11.h"
- #include "pkcs11t.h"
- #include "pk11func.h"
- #include "keyhi.h"
-+#include "keyi.h"
- #include "secitem.h"
- #include "secerr.h"
- #include "sslerr.h"
-
- #define PK11_SEARCH_CHUNKSIZE 10
-
- /*
- * Build a block big enough to hold the data
-@@ -547,16 +548,17 @@ pk11_backupGetSignLength(SECKEYPrivateKe
- */
- int
- PK11_SignatureLen(SECKEYPrivateKey *key)
- {
- int val;
- SECItem attributeItem = { siBuffer, NULL, 0 };
- SECStatus rv;
- int length;
-+ SECOidTag paramSet;
-
- switch (key->keyType) {
- case rsaKey:
- case rsaPssKey:
- val = PK11_GetPrivateModulusLen(key);
- if (val == -1) {
- return pk11_backupGetSignLength(key);
- }
-@@ -585,16 +587,20 @@ PK11_SignatureLen(SECKEYPrivateKey *key)
- length = SECKEY_ECParamsToBasePointOrderLen(&attributeItem);
- PORT_Free(attributeItem.data);
- if (length != 0) {
- length = ((length + 7) / 8) * 2;
- return length;
- }
- }
- return pk11_backupGetSignLength(key);
-+ case mldsaKey:
-+ paramSet = SECKEY_GetParameterSet(key);
-+ return SECKEY_MLDSAOidParamsToLen(paramSet, SECKEYSignatureType);
-+
- default:
- break;
- }
- PORT_SetError(SEC_ERROR_INVALID_KEY);
- return 0;
- }
-
- /*
-diff --git a/lib/pk11wrap/pk11pars.c b/lib/pk11wrap/pk11pars.c
---- a/lib/pk11wrap/pk11pars.c
-+++ b/lib/pk11wrap/pk11pars.c
-@@ -472,16 +472,22 @@ static const oidValDef signOptList[] = {
- { CIPHER_NAME("RSA-PKCS"), SEC_OID_PKCS1_RSA_ENCRYPTION,
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
- { CIPHER_NAME("RSA-PSS"), SEC_OID_PKCS1_RSA_PSS_SIGNATURE,
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
- { CIPHER_NAME("ECDSA"), SEC_OID_ANSIX962_EC_PUBLIC_KEY,
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
- { CIPHER_NAME("ED25519"), SEC_OID_ED25519_PUBLIC_KEY,
- NSS_USE_ALG_IN_SIGNATURE },
-+ { CIPHER_NAME("ML-DSA-44"), SEC_OID_ML_DSA_44,
-+ NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
-+ { CIPHER_NAME("ML-DSA-65"), SEC_OID_ML_DSA_65,
-+ NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
-+ { CIPHER_NAME("ML-DSA-87"), SEC_OID_ML_DSA_87,
-+ NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
- };
-
- typedef struct {
- const oidValDef *list;
- PRUint32 entries;
- const char *description;
- PRBool allowEmpty;
- } algListsDef;
-diff --git a/lib/pk11wrap/pk11pk12.c b/lib/pk11wrap/pk11pk12.c
---- a/lib/pk11wrap/pk11pk12.c
-+++ b/lib/pk11wrap/pk11pk12.c
-@@ -12,16 +12,17 @@
- #include "secmod.h"
- #include "secmodi.h"
- #include "secmodti.h"
- #include "secmodt.h"
- #include "pkcs11.h"
- #include "pk11func.h"
- #include "secitem.h"
- #include "keyhi.h"
-+#include "keyi.h"
- #include "secoid.h"
- #include "secasn1.h"
- #include "secerr.h"
- #include "prerror.h"
-
- /* These data structures should move to a common .h file shared between the
- * wrappers and the pkcs 12 code. */
-
-@@ -74,27 +75,35 @@ struct SECKEYECPrivateKeyStr {
- PLArenaPool *arena;
- SECItem version;
- SECItem curveOID; /* optional/ignored */
- SECItem publicValue; /* required (for now) */
- SECItem privateValue;
- };
- typedef struct SECKEYECPrivateKeyStr SECKEYECPrivateKey;
-
-+struct SECKEYMLDSAPrivateKeyStr {
-+ SECOidTag params;
-+ SECItem privateValue;
-+ SECItem seed;
-+};
-+typedef struct SECKEYMLDSAPrivateKeyStr SECKEYMLDSAPrivateKey;
-+
- /*
- ** raw private key object
- */
- struct SECKEYRawPrivateKeyStr {
- PLArenaPool *arena;
- KeyType keyType;
- union {
- SECKEYRSAPrivateKey rsa;
- SECKEYDSAPrivateKey dsa;
- SECKEYDHPrivateKey dh;
- SECKEYECPrivateKey ec;
-+ SECKEYMLDSAPrivateKey mldsa;
- } u;
- };
- typedef struct SECKEYRawPrivateKeyStr SECKEYRawPrivateKey;
-
- SEC_ASN1_MKSUB(SEC_AnyTemplate)
- SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
-
- /* ASN1 Templates for new decoder/encoder */
-@@ -150,16 +159,38 @@ const SEC_ASN1Template SECKEY_DSAPrivate
- };
-
- const SEC_ASN1Template SECKEY_DHPrivateKeyExportTemplate[] = {
- { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dh.privateValue) },
- { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dh.base) },
- { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.dh.prime) },
- };
-
-+const SEC_ASN1Template SECKEY_MLDSAPrivateKeyBothExportTemplate[] = {
-+ { SEC_ASN1_CHOICE, 0, NULL, sizeof(SECKEYRawPrivateKey)},
-+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYRawPrivateKey) },
-+ { SEC_ASN1_OCTET_STRING, offsetof(SECKEYRawPrivateKey, u.mldsa.seed) },
-+ { SEC_ASN1_OCTET_STRING, offsetof(SECKEYRawPrivateKey, u.mldsa.privateValue) },
-+ { 0 }
-+};
-+
-+const SEC_ASN1Template SECKEY_MLDSAPrivateKeySeedExportTemplate[] = {
-+ { SEC_ASN1_CHOICE, 0, NULL, sizeof(SECKEYRawPrivateKey)},
-+ { SEC_ASN1_CONTEXT_SPECIFIC | 0,
-+ offsetof(SECKEYRawPrivateKey, u.mldsa.seed),
-+ SEC_ASN1_SUB(SEC_OctetStringTemplate) },
-+ { 0 }
-+};
-+
-+const SEC_ASN1Template SECKEY_MLDSAPrivateKeyKeyExportTemplate[] = {
-+ { SEC_ASN1_CHOICE, 0, NULL, sizeof(SECKEYRawPrivateKey)},
-+ { SEC_ASN1_OCTET_STRING, offsetof(SECKEYRawPrivateKey, u.mldsa.privateValue) },
-+ { 0 }
-+};
-+
- SEC_ASN1_MKSUB(SEC_BitStringTemplate)
- SEC_ASN1_MKSUB(SEC_ObjectIDTemplate)
-
- const SEC_ASN1Template SECKEY_ECPrivateKeyExportTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYRawPrivateKey) },
- { SEC_ASN1_INTEGER, offsetof(SECKEYRawPrivateKey, u.ec.version) },
- { SEC_ASN1_OCTET_STRING,
- offsetof(SECKEYRawPrivateKey, u.ec.privateValue) },
-@@ -330,16 +361,17 @@ PK11_ImportAndReturnPrivateKey(PK11SlotI
- CK_ATTRIBUTE theTemplate[20];
- int templateCount = 0;
- SECStatus rv = SECFailure;
- CK_ATTRIBUTE *attrs;
- CK_ATTRIBUTE *signedattr = NULL;
- int signedcount = 0;
- CK_ATTRIBUTE *ap;
- SECItem *ck_id = NULL;
-+ CK_ULONG paramSet;
-
- attrs = theTemplate;
-
- PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass));
- attrs++;
- PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType));
- attrs++;
- PK11_SETATTRS(attrs, CKA_TOKEN, isPerm ? &cktrue : &ckfalse,
-@@ -423,17 +455,17 @@ PK11_ImportAndReturnPrivateKey(PK11SlotI
- }
- if (PK11_IsInternal(slot)) {
- PK11_SETATTRS(attrs, CKA_NSS_DB,
- publicValue->data, publicValue->len);
- attrs++;
- }
- PK11_SETATTRS(attrs, CKA_SIGN, &cktrue, sizeof(CK_BBOOL));
- attrs++;
-- PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, &cktrue, sizeof(CK_BBOOL));
-+ PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, &ckfalse, sizeof(CK_BBOOL));
- attrs++;
- if (nickname) {
- PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
- attrs++;
- }
- ck_id = PK11_MakeIDFromPubKey(publicValue);
- if (ck_id == NULL) {
- goto loser;
-@@ -497,19 +529,17 @@ PK11_ImportAndReturnPrivateKey(PK11SlotI
- lpk->u.ec.publicValue.len);
- attrs++;
- }
- }
-
- PK11_SETATTRS(attrs, CKA_SIGN, (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue : &ckfalse,
- sizeof(CK_BBOOL));
- attrs++;
-- PK11_SETATTRS(attrs, CKA_SIGN_RECOVER,
-- (keyUsage & KU_DIGITAL_SIGNATURE) ? &cktrue
-- : &ckfalse,
-+ PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, &ckfalse,
- sizeof(CK_BBOOL));
- attrs++;
- PK11_SETATTRS(attrs, CKA_DERIVE, (keyUsage & KU_KEY_AGREEMENT) ? &cktrue : &ckfalse,
- sizeof(CK_BBOOL));
- attrs++;
- if (nickname) {
- PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
- attrs++;
-@@ -566,24 +596,76 @@ PK11_ImportAndReturnPrivateKey(PK11SlotI
- PK11_SETATTRS(attrs, CKA_EC_PARAMS, lpk->u.ec.curveOID.data,
- lpk->u.ec.curveOID.len);
- attrs++;
-
- PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.ec.privateValue.data,
- lpk->u.ec.privateValue.len);
- attrs++;
- break;
-+ case mldsaKey:
-+ keyType = CKK_ML_DSA;
-+ /* we need at least one of these to import into PKCS #11.
-+ * if we have only one, it may still fail, but that is up
-+ * to the token */
-+ if ((lpk->u.mldsa.seed.len == 0) &&
-+ (lpk->u.mldsa.privateValue.len == 0)) {
-+ PORT_SetError(SEC_ERROR_BAD_KEY);
-+ goto loser;
-+ }
-+ PK11_SETATTRS(attrs, CKA_SIGN, &cktrue, sizeof(CK_BBOOL));
-+ attrs++;
-+ PK11_SETATTRS(attrs, CKA_SIGN_RECOVER, &ckfalse, sizeof(CK_BBOOL));
-+ attrs++;
-+ /* if we have the public value, we can do more, without it
-+ * we won't be able to set the ck_id properly, which will make
-+ * this key effectively invisible. The application will need
-+ * to update the ID before it looses it's handle */
-+ if (publicValue != NULL) {
-+ if (PK11_IsInternal(slot)) {
-+ PK11_SETATTRS(attrs, CKA_NSS_DB,
-+ publicValue->data, publicValue->len);
-+ attrs++;
-+ }
-+ ck_id = PK11_MakeIDFromPubKey(publicValue);
-+ if (ck_id == NULL) {
-+ goto loser;
-+ }
-+ PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len);
-+ attrs++;
-+ }
-+ if (nickname) {
-+ PK11_SETATTRS(attrs, CKA_LABEL, nickname->data, nickname->len);
-+ attrs++;
-+ }
-+ paramSet = SECKEY_MLDSAOidParamsToPkcs11Params(lpk->u.mldsa.params);
-+ PK11_SETATTRS(attrs, CKA_PARAMETER_SET, (unsigned char *)¶mSet,
-+ sizeof(CK_ML_DSA_PARAMETER_SET_TYPE));
-+ attrs++;
-+ if (lpk->u.mldsa.seed.len) {
-+ PK11_SETATTRS(attrs, CKA_SEED, lpk->u.mldsa.seed.data,
-+ lpk->u.mldsa.seed.len);
-+ attrs++;
-+ }
-+ if (lpk->u.mldsa.privateValue.len) {
-+ PK11_SETATTRS(attrs, CKA_VALUE, lpk->u.mldsa.privateValue.data,
-+ lpk->u.mldsa.privateValue.len);
-+ attrs++;
-+ }
-+ break;
- default:
- PORT_SetError(SEC_ERROR_BAD_KEY);
- goto loser;
- }
- templateCount = attrs - theTemplate;
- PORT_Assert(templateCount <= sizeof(theTemplate) / sizeof(CK_ATTRIBUTE));
-- if (lpk->keyType != ecKey && lpk->keyType != edKey && lpk->keyType != ecMontKey) {
-- PORT_Assert(signedattr);
-+ /* we used to assert unless the key didn't need signedattrs, but that's
-+ * now true of almost all modern keys, so now if the key has signedattrs
-+ * the just need to set the value */
-+ if (signedattr) {
- signedcount = attrs - signedattr;
- for (ap = signedattr; signedcount; ap++, signedcount--) {
- pk11_SignedToUnsigned(ap);
- }
- }
-
- rv = PK11_CreateNewObject(slot, CK_INVALID_HANDLE,
- theTemplate, templateCount, isPerm, &objectID);
-@@ -608,31 +690,33 @@ PK11_ImportPrivateKeyInfoAndReturnKey(PK
- PRBool isPerm, PRBool isPrivate, unsigned int keyUsage,
- SECKEYPrivateKey **privk, void *wincx)
- {
- SECStatus rv = SECFailure;
- SECKEYRawPrivateKey *lpk = NULL;
- const SEC_ASN1Template *keyTemplate, *paramTemplate;
- void *paramDest = NULL;
- PLArenaPool *arena = NULL;
-+ SECOidTag algTag;
-
- arena = PORT_NewArena(2048);
- if (!arena) {
- return SECFailure;
- }
-
- /* need to change this to use RSA/DSA keys */
- lpk = (SECKEYRawPrivateKey *)PORT_ArenaZAlloc(arena,
- sizeof(SECKEYRawPrivateKey));
- if (lpk == NULL) {
- goto loser;
- }
- lpk->arena = arena;
-
-- switch (SECOID_GetAlgorithmTag(&pki->algorithm)) {
-+ algTag = SECOID_GetAlgorithmTag(&pki->algorithm);
-+ switch (algTag) {
- case SEC_OID_PKCS1_RSA_ENCRYPTION:
- prepare_rsa_priv_key_export_for_asn1(lpk);
- keyTemplate = SECKEY_RSAPrivateKeyExportTemplate;
- paramTemplate = NULL;
- paramDest = NULL;
- lpk->keyType = rsaKey;
- break;
- case SEC_OID_ANSIX9_DSA_SIGNATURE:
-@@ -666,17 +750,40 @@ PK11_ImportPrivateKeyInfoAndReturnKey(PK
- break;
- case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
- prepare_ec_priv_key_export_for_asn1(lpk);
- keyTemplate = SECKEY_ECPrivateKeyExportTemplate;
- paramTemplate = NULL;
- paramDest = NULL;
- lpk->keyType = ecKey;
- break;
--
-+ case SEC_OID_ML_DSA_44:
-+ case SEC_OID_ML_DSA_65:
-+ case SEC_OID_ML_DSA_87:
-+ /* choice */
-+ switch (pki->privateKey.data[0]) {
-+ case SEC_ASN1_CONTEXT_SPECIFIC|0:
-+ keyTemplate = SECKEY_MLDSAPrivateKeySeedExportTemplate;
-+ break;
-+ case SEC_ASN1_OCTET_STRING:
-+ keyTemplate = SECKEY_MLDSAPrivateKeyKeyExportTemplate;
-+ break;
-+ case SEC_ASN1_CONSTRUCTED|SEC_ASN1_SEQUENCE:
-+ keyTemplate = SECKEY_MLDSAPrivateKeyBothExportTemplate;
-+ break;
-+ default:
-+ keyTemplate = NULL;
-+ PORT_SetError(SEC_ERROR_BAD_DER);
-+ break;
-+ }
-+ paramTemplate = NULL;
-+ paramDest = NULL;
-+ lpk->keyType = mldsaKey;
-+ lpk->u.mldsa.params = algTag;
-+ break;
- default:
- keyTemplate = NULL;
- paramTemplate = NULL;
- paramDest = NULL;
- break;
- }
-
- if (!keyTemplate) {
-diff --git a/lib/pk11wrap/pk11pub.h b/lib/pk11wrap/pk11pub.h
---- a/lib/pk11wrap/pk11pub.h
-+++ b/lib/pk11wrap/pk11pub.h
-@@ -681,17 +681,17 @@ PK11SymKey *PK11_ConvertSessionSymKeyToT
- SECKEYPrivateKey *PK11_ConvertSessionPrivKeyToTokenPrivKey(
- SECKEYPrivateKey *privk, void *wincx);
- SECKEYPrivateKey *PK11_CopyTokenPrivKeyToSessionPrivKey(PK11SlotInfo *destSlot,
- SECKEYPrivateKey *privKey);
-
- /**********************************************************************
- * Certs
- **********************************************************************/
--SECItem *PK11_MakeIDFromPubKey(SECItem *pubKeyData);
-+SECItem *PK11_MakeIDFromPubKey(const SECItem *pubKeyData);
- SECStatus PK11_TraverseSlotCerts(
- SECStatus (*callback)(CERTCertificate *, SECItem *, void *),
- void *arg, void *wincx);
- CERTCertificate *PK11_FindCertFromNickname(const char *nickname, void *wincx);
- CERTCertificate *PK11_FindCertFromURI(const char *uri, void *wincx);
- CERTCertList *PK11_FindCertsFromURI(const char *uri, void *wincx);
- CERTCertList *PK11_FindCertsFromEmailAddress(const char *email, void *wincx);
- CERTCertList *PK11_FindCertsFromNickname(const char *nickname, void *wincx);
-diff --git a/lib/pk11wrap/pk11skey.c b/lib/pk11wrap/pk11skey.c
---- a/lib/pk11wrap/pk11skey.c
-+++ b/lib/pk11wrap/pk11skey.c
-@@ -2123,23 +2123,17 @@ PK11_PubDerive(SECKEYPrivateKey *privKey
- /* Message is or'd with a real Attribute (CKA_ENCRYPT, CKA_DECRYPT),
- * etc. Strip out the real attribute here */
- operation &= ~CKA_NSS_MESSAGE_MASK;
- }
-
- symKey->origin = PK11_OriginDerive;
-
- switch (privKey->keyType) {
-- case rsaKey:
-- case rsaPssKey:
-- case rsaOaepKey:
-- case kyberKey:
-- case nullKey:
-- case edKey:
-- case ecMontKey:
-+ default:
- PORT_SetError(SEC_ERROR_BAD_KEY);
- break;
- case dsaKey:
- case keaKey:
- case fortezzaKey: {
- static unsigned char rb_email[128] = { 0 };
- CK_KEA_DERIVE_PARAMS param;
- param.isSender = (CK_BBOOL)isSender;
-diff --git a/lib/pk11wrap/secmodi.h b/lib/pk11wrap/secmodi.h
---- a/lib/pk11wrap/secmodi.h
-+++ b/lib/pk11wrap/secmodi.h
-@@ -165,12 +165,13 @@ SECKEYPrivateKey *PK11_MakePrivKey(PK11S
- PRBool isTemp, CK_OBJECT_HANDLE privID, void *wincx);
- CERTCertificate *PK11_MakeCertFromHandle(PK11SlotInfo *slot,
- CK_OBJECT_HANDLE certID, CK_ATTRIBUTE *privateLabel);
-
- SECItem *pk11_GenerateNewParamWithKeyLen(CK_MECHANISM_TYPE type, int keyLen);
- SECItem *pk11_ParamFromIVWithLen(CK_MECHANISM_TYPE type,
- SECItem *iv, int keyLen);
- SECItem *pk11_mkcertKeyID(CERTCertificate *cert);
-+const SECItem *pk11_GetPublicKeyComponent(SECKEYPublicKey *pubKey);
-
- SEC_END_PROTOS
-
- #endif
-diff --git a/lib/pk11wrap/secmodti.h b/lib/pk11wrap/secmodti.h
---- a/lib/pk11wrap/secmodti.h
-+++ b/lib/pk11wrap/secmodti.h
-@@ -204,10 +204,13 @@ struct PK11GenericObjectStr {
-
- /*
- * private header file, so we can set real names for oids that aren't upstream
- * yet, so we applications don't try to use them and get hosed when they change
- */
- #define SEC_OID_X25519MLKEM768 SEC_OID_MLKEM768X25519
- #define SEC_OID_SECP256R1MLKEM768 SEC_OID_PRIVATE_1
- #define SEC_OID_SECP384R1MLKEM1024 SEC_OID_PRIVATE_2
-+#define SEC_OID_ML_DSA_44 SEC_OID_PRIVATE_3
-+#define SEC_OID_ML_DSA_65 SEC_OID_PRIVATE_4
-+#define SEC_OID_ML_DSA_87 SEC_OID_PRIVATE_5
-
- #endif /* _SECMODTI_H_ */
-diff --git a/lib/pkcs12/p12d.c b/lib/pkcs12/p12d.c
---- a/lib/pkcs12/p12d.c
-+++ b/lib/pkcs12/p12d.c
-@@ -2887,16 +2887,19 @@ sec_pkcs12_get_public_value_and_type(SEC
-
- if (!type || !pubKey) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return NULL;
- }
-
- *type = pubKey->keyType;
- switch (pubKey->keyType) {
-+ case mldsaKey:
-+ pubValue = &pubKey->u.mldsa.publicValue;
-+ break;
- case dsaKey:
- pubValue = &pubKey->u.dsa.publicValue;
- break;
- case dhKey:
- pubValue = &pubKey->u.dh.publicValue;
- break;
- case rsaKey:
- pubValue = &pubKey->u.rsa.modulus;
-diff --git a/lib/smime/cmssiginfo.c b/lib/smime/cmssiginfo.c
---- a/lib/smime/cmssiginfo.c
-+++ b/lib/smime/cmssiginfo.c
-@@ -136,16 +136,17 @@ NSS_CMSSignerInfo_GetSignatureAlgorithmO
- SECOidTag pubkAlgTag,
- SECOidTag signAlgTag)
- {
- switch (keyType) {
- case rsaKey:
- return pubkAlgTag;
- case rsaPssKey:
- case dsaKey:
-+ case mldsaKey: /* pubkAlgTag and signAlgTag are the same */
- case ecKey:
- return signAlgTag;
- default:
- return SEC_OID_UNKNOWN;
- }
- }
-
- /*
-diff --git a/lib/softoken/lowkey.c b/lib/softoken/lowkey.c
---- a/lib/softoken/lowkey.c
-+++ b/lib/softoken/lowkey.c
-@@ -87,16 +87,34 @@ const SEC_ASN1Template nsslowkey_RSAPriv
-
- const SEC_ASN1Template nsslowkey_DSAPrivateKeyTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) },
- { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dsa.publicValue) },
- { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dsa.privateValue) },
- { 0 }
- };
-
-+const SEC_ASN1Template nsslowkey_PQBothSeedAndPrivateKeyTemplate[] = {
-+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) },
-+ { SEC_ASN1_OCTET_STRING, offsetof(NSSLOWKEYPrivateKey, u.genpq.seedItem) },
-+ { SEC_ASN1_OCTET_STRING, offsetof(NSSLOWKEYPrivateKey, u.genpq.keyItem) },
-+ { 0 }
-+};
-+
-+const SEC_ASN1Template nsslowkey_PQSeedTemplate[] = {
-+ { SEC_ASN1_CONTEXT_SPECIFIC | 0,
-+ offsetof(NSSLOWKEYPrivateKey, u.genpq.seedItem),
-+ SEC_ASN1_SUB(SEC_OctetStringTemplate) },
-+ { 0 }
-+};
-+const SEC_ASN1Template nsslowkey_PQPrivateKeyTemplate[] = {
-+ { SEC_ASN1_OCTET_STRING, offsetof(NSSLOWKEYPrivateKey, u.genpq.keyItem) },
-+ { 0 }
-+};
-+
- const SEC_ASN1Template nsslowkey_DSAPrivateKeyExportTemplate[] = {
- { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dsa.privateValue) },
- };
-
- const SEC_ASN1Template nsslowkey_DHPrivateKeyTemplate[] = {
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWKEYPrivateKey) },
- { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dh.publicValue) },
- { SEC_ASN1_INTEGER, offsetof(NSSLOWKEYPrivateKey, u.dh.privateValue) },
-@@ -418,16 +436,56 @@ nsslowkey_ConvertToPublicKey(NSSLOWKEYPr
- pubk->u.ec.ecParams.arena = arena;
- /* Copy the rest of the params */
- rv = EC_CopyParams(arena, &(pubk->u.ec.ecParams),
- &(privk->u.ec.ecParams));
- if (rv == SECSuccess)
- return pubk;
- }
- break;
-+#ifdef NSS_ENABLE_ML_DSA
-+ case NSSLOWKEYMLDSAKey:
-+ pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena,
-+ sizeof(NSSLOWKEYPublicKey));
-+ if (pubk != NULL) {
-+ SECStatus rv;
-+ SECItem seed= {siBuffer, NULL, 0};
-+ MLDSAPrivateKey newPrivKey;
-+
-+ pubk->arena = arena;
-+ pubk->keyType = privk->keyType;
-+
-+ /* privatekey value is encoded (rho, K, tr, s1, s2, t0) */
-+ /* publickey value is encoded (rho, t1) */
-+ /* Future, we can calculate public key directly from
-+ * privatekey value as follows :
-+ * A^ = ExpandA(rho);
-+ * t = NTT-1(A& o NSS(s1)) + s2
-+ * (t1, t0) = Power2Round(t)
-+ * we now have rho and t1 so we can encode public key.
-+ * these functions are all specified in FIPS-204. For now
-+ * we just use the seed if it's a available and regenerate
-+ * both keys, and discard the private key. */
-+ if (privk->u.mldsa.seedLen == 0) {
-+ PORT_SetError(SEC_ERROR_PKCS11_FUNCTION_FAILED);
-+ rv = SECFailure;
-+ break;
-+ }
-+ seed.data = privk->u.mldsa.seed;
-+ seed.len = privk->u.mldsa.seedLen;
-+ rv = MLDSA_NewKey(privk->u.mldsa.paramSet, &seed,
-+ &newPrivKey, &pubk->u.mldsa);
-+ if (rv != SECSuccess) {
-+ break;
-+ }
-+ PORT_SafeZero(&newPrivKey, sizeof(newPrivKey));
-+ return pubk;
-+ }
-+ break;
-+#endif
- /* No Fortezza in Low Key implementations (Fortezza keys aren't
- * stored in our data base */
- default:
- break;
- }
-
- PORT_FreeArena(arena, PR_TRUE);
- return NULL;
-@@ -554,16 +612,22 @@ nsslowkey_CopyPrivateKey(NSSLOWKEYPrivat
- break;
- returnKey->u.ec.ecParams.arena = poolp;
- /* Copy the rest of the params */
- rv = EC_CopyParams(poolp, &(returnKey->u.ec.ecParams),
- &(privKey->u.ec.ecParams));
- if (rv != SECSuccess)
- break;
- break;
-+#ifdef NSS_ENABLE_ML_DSA
-+ case NSSLOWKEYMLDSAKey:
-+ returnKey->u.mldsa = privKey->u.mldsa;
-+ rv = SECSuccess;
-+ break;
-+#endif
- default:
- rv = SECFailure;
- }
-
- loser:
-
- if (rv != SECSuccess) {
- PORT_FreeArena(poolp, PR_TRUE);
-diff --git a/lib/softoken/lowkeyti.h b/lib/softoken/lowkeyti.h
---- a/lib/softoken/lowkeyti.h
-+++ b/lib/softoken/lowkeyti.h
-@@ -17,16 +17,19 @@
- extern const SEC_ASN1Template nsslowkey_PQGParamsTemplate[];
- extern const SEC_ASN1Template nsslowkey_RSAPrivateKeyTemplate[];
- extern const SEC_ASN1Template nsslowkey_DSAPrivateKeyTemplate[];
- extern const SEC_ASN1Template nsslowkey_DSAPrivateKeyExportTemplate[];
- extern const SEC_ASN1Template nsslowkey_DHPrivateKeyTemplate[];
- extern const SEC_ASN1Template nsslowkey_DHPrivateKeyExportTemplate[];
- #define NSSLOWKEY_EC_PRIVATE_KEY_VERSION 1 /* as per SECG 1 C.4 */
- extern const SEC_ASN1Template nsslowkey_ECPrivateKeyTemplate[];
-+extern const SEC_ASN1Template nsslowkey_PQBothSeedAndPrivateKeyTemplate[];
-+extern const SEC_ASN1Template nsslowkey_PQSeedTemplate[];
-+extern const SEC_ASN1Template nsslowkey_PQPrivateKeyTemplate[];
-
- extern const SEC_ASN1Template nsslowkey_PrivateKeyInfoTemplate[];
- extern const SEC_ASN1Template nsslowkey_EncryptedPrivateKeyInfoTemplate[];
- extern const SEC_ASN1Template nsslowkey_SubjectPublicKeyInfoTemplate[];
- extern const SEC_ASN1Template nsslowkey_RSAPublicKeyTemplate[];
-
- /*
- * PKCS #8 attributes
-@@ -57,44 +60,58 @@ struct NSSLOWKEYSubjectPublicKeyInfoStr
- };
- typedef struct NSSLOWKEYSubjectPublicKeyInfoStr NSSLOWKEYSubjectPublicKeyInfo;
-
- typedef enum {
- NSSLOWKEYNullKey = 0,
- NSSLOWKEYRSAKey = 1,
- NSSLOWKEYDSAKey = 2,
- NSSLOWKEYDHKey = 4,
-- NSSLOWKEYECKey = 5
-+ NSSLOWKEYECKey = 5,
-+ NSSLOWKEYMLDSAKey = 6,
- } NSSLOWKEYType;
-
- /*
- ** An RSA public key object.
- */
- struct NSSLOWKEYPublicKeyStr {
- PLArenaPool *arena;
- NSSLOWKEYType keyType;
- union {
- RSAPublicKey rsa;
- DSAPublicKey dsa;
- DHPublicKey dh;
- ECPublicKey ec;
-+#ifdef NSS_ENABLE_ML_DSA
-+ MLDSAPublicKey mldsa;
-+#endif
- } u;
- };
- typedef struct NSSLOWKEYPublicKeyStr NSSLOWKEYPublicKey;
-
-+typedef struct GenPostQuantumPrivateKeyStr GenPostQuantumPrivateKey;
-+struct GenPostQuantumPrivateKeyStr {
-+ SECItem seedItem;
-+ SECItem keyItem;
-+};
-+
- /*
- ** Low Level private key object
- ** This is only used by the raw Crypto engines (crypto), keydb (keydb),
- ** and PKCS #11. Everyone else uses the high level key structure.
- */
- struct NSSLOWKEYPrivateKeyStr {
- PLArenaPool *arena;
- NSSLOWKEYType keyType;
- union {
- RSAPrivateKey rsa;
- DSAPrivateKey dsa;
- DHPrivateKey dh;
- ECPrivateKey ec;
-+ GenPostQuantumPrivateKey genpq; /* used to decode post quantum keys */
-+#ifdef NSS_ENABLE_ML_DSA
-+ MLDSAPrivateKey mldsa;
-+#endif
- } u;
- };
- typedef struct NSSLOWKEYPrivateKeyStr NSSLOWKEYPrivateKey;
-
- #endif /* _LOWKEYTI_H_ */
-diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c
---- a/lib/softoken/pkcs11.c
-+++ b/lib/softoken/pkcs11.c
-@@ -653,16 +653,18 @@ static const struct mechanismList mechan
- #ifndef NSS_DISABLE_KYBER
- { CKM_NSS_KYBER_KEY_PAIR_GEN, { 0, 0, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
- { CKM_NSS_KYBER, { 0, 0, CKF_KEM }, PR_TRUE },
- #endif
- { CKM_NSS_ML_KEM_KEY_PAIR_GEN, { 0, 0, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
- { CKM_NSS_ML_KEM, { 0, 0, CKF_KEM }, PR_TRUE },
- { CKM_ML_KEM_KEY_PAIR_GEN, { 0, 0, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
- { CKM_ML_KEM, { 0, 0, CKF_KEM }, PR_TRUE },
-+ { CKM_ML_DSA_KEY_PAIR_GEN, { ML_DSA_44_PUBLICKEY_LEN, ML_DSA_87_PUBLICKEY_LEN, CKF_GENERATE }, PR_TRUE },
-+ { CKM_ML_DSA, { ML_DSA_44_PUBLICKEY_LEN, ML_DSA_87_PUBLICKEY_LEN, CKF_SN_VR }, PR_TRUE },
- };
- static const CK_ULONG mechanismCount = sizeof(mechanisms) / sizeof(mechanisms[0]);
-
- /* sigh global so fipstokn can read it */
- PRBool nsc_init = PR_FALSE;
-
- #if defined(CHECK_FORK_PTHREAD) || defined(CHECK_FORK_MIXED)
-
-@@ -1035,16 +1037,17 @@ sftk_handlePublicKeyObject(SFTKSession *
- CK_KEY_TYPE key_type)
- {
- CK_BBOOL encrypt = CK_TRUE;
- CK_BBOOL recover = CK_TRUE;
- CK_BBOOL wrap = CK_TRUE;
- CK_BBOOL derive = CK_FALSE;
- CK_BBOOL verify = CK_TRUE;
- CK_BBOOL encapsulate = CK_FALSE;
-+ CK_ULONG paramSet = 0;
- CK_RV crv;
-
- switch (key_type) {
- case CKK_RSA:
- crv = sftk_ConstrainAttribute(object, CKA_MODULUS,
- RSA_MIN_MODULUS_BITS, 0, 0);
- if (crv != CKR_OK) {
- return crv;
-@@ -1125,16 +1128,37 @@ sftk_handlePublicKeyObject(SFTKSession *
- }
- derive = CK_FALSE;
- verify = CK_FALSE;
- encrypt = CK_FALSE;
- recover = CK_FALSE;
- wrap = CK_FALSE;
- encapsulate = CK_TRUE;
- break;
-+#ifdef NSS_ENABLE_ML_DSA
-+ case CKK_ML_DSA:
-+ if (!sftk_hasAttribute(object, CKA_PARAMETER_SET)) {
-+ return CKR_TEMPLATE_INCOMPLETE;
-+ }
-+ crv = sftk_GetULongAttribute (object, CKA_PARAMETER_SET,
-+ ¶mSet);
-+ if (crv != CKR_OK) {
-+ return crv;
-+ }
-+ if (sftk_MLDSAGetSigLen(paramSet) == 0) {
-+ return CKR_ATTRIBUTE_VALUE_INVALID;
-+ }
-+ derive = CK_FALSE;
-+ verify = CK_TRUE;
-+ encrypt = CK_FALSE;
-+ recover = CK_FALSE;
-+ wrap = CK_FALSE;
-+ encapsulate = CK_FALSE;
-+ break;
-+#endif
- default:
- return CKR_ATTRIBUTE_VALUE_INVALID;
- }
-
- /* make sure the required fields exist */
- crv = sftk_defaultAttribute(object, CKA_SUBJECT, NULL, 0);
- if (crv != CKR_OK)
- return crv;
-@@ -1205,20 +1229,21 @@ static CK_RV
- sftk_handlePrivateKeyObject(SFTKSession *session, SFTKObject *object, CK_KEY_TYPE key_type)
- {
- CK_BBOOL cktrue = CK_TRUE;
- CK_BBOOL encrypt = CK_TRUE;
- CK_BBOOL sign = CK_FALSE;
- CK_BBOOL recover = CK_TRUE;
- CK_BBOOL wrap = CK_TRUE;
- CK_BBOOL derive = CK_TRUE;
-- CK_BBOOL encapsulate = CK_FALSE;
-+ CK_BBOOL decapsulate = CK_FALSE;
- CK_BBOOL ckfalse = CK_FALSE;
- PRBool createObjectInfo = PR_TRUE;
- PRBool fillPrivateKey = PR_FALSE;
-+ CK_ULONG paramSet = 0;
- int missing_rsa_mod_component = 0;
- int missing_rsa_exp_component = 0;
- int missing_rsa_crt_component = 0;
-
- SECItem mod;
- CK_RV crv;
- SECStatus rv;
-
-@@ -1350,18 +1375,97 @@ sftk_handlePrivateKeyObject(SFTKSession
- return CKR_TEMPLATE_INCOMPLETE;
- }
- if (!sftk_hasAttribute(object, CKA_PARAMETER_SET)) {
- if (!sftk_hasAttribute(object, CKA_NSS_PARAMETER_SET)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
- }
- encrypt = sign = recover = wrap = CK_FALSE;
-- encapsulate = CK_TRUE;
-+ decapsulate = CK_TRUE;
- break;
-+#ifdef NSS_ENABLE_ML_DSA
-+ case CKK_ML_DSA:
-+ if (!sftk_hasAttribute(object, CKA_KEY_TYPE)) {
-+ return CKR_TEMPLATE_INCOMPLETE;
-+ }
-+ /* make sure we have a CKA_PARAMETER_SET */
-+ if (!sftk_hasAttribute(object, CKA_PARAMETER_SET)) {
-+ return CKR_TEMPLATE_INCOMPLETE;
-+ }
-+ /* make sure it's one we understand */
-+ crv = sftk_GetULongAttribute (object, CKA_PARAMETER_SET,
-+ ¶mSet);
-+ if (crv != CKR_OK) {
-+ return crv;
-+ }
-+ if (sftk_MLDSAGetSigLen(paramSet) == 0) {
-+ return CKR_ATTRIBUTE_VALUE_INVALID;
-+ }
-+ /*
-+ * if we have a seed deal with making sure seed and
-+ * CKA_VALUE . We skip this step if the SEED and VALUE
-+ * was generated together by us. */
-+ if (sftk_hasAttribute(object, CKA_SEED)) {
-+ PRBool seedOK = sftk_hasAttribute(object, CKA_NSS_SEED_OK);
-+ SFTKAttribute *seedAttribute = sftk_FindAttribute(object,
-+ CKA_SEED);
-+ PORT_Assert(seedAttribute);
-+ crv = CKR_OK;
-+ if (seedAttribute->attrib.ulValueLen != 0) {
-+ SFTKAttribute *valueAttribute =
-+ sftk_FindAttribute(object, CKA_VALUE);
-+ unsigned int valueLen = valueAttribute ?
-+ valueAttribute->attrib.ulValueLen : 0;
-+ if (!seedOK || valueLen == 0) {
-+ MLDSAPrivateKey privKey;
-+ MLDSAPublicKey pubKey;
-+ SECItem seedItem;
-+
-+ seedItem.data = seedAttribute->attrib.pValue;
-+ seedItem.len = seedAttribute->attrib.ulValueLen;
-+ rv = MLDSA_NewKey(paramSet, &seedItem, &privKey,
-+ &pubKey);
-+ if (rv != SECSuccess) {
-+ crv = CKR_ATTRIBUTE_VALUE_INVALID;
-+ } else if (valueLen == 0) {
-+ crv = sftk_forceAttribute(object, CKA_VALUE,
-+ privKey.keyVal,
-+ privKey.keyValLen);
-+ } else {
-+ /* we have the value, so we must need to
-+ * verify it */
-+ PORT_Assert(!seedOK);
-+ if ((privKey.keyValLen != valueLen) ||
-+ (PORT_Memcmp(valueAttribute->attrib.pValue,
-+ privKey.keyVal, valueLen) != 0)){
-+ crv = CKR_ATTRIBUTE_VALUE_INVALID;
-+ }
-+ }
-+ PORT_SafeZero(&privKey, sizeof(privKey));
-+ PORT_SafeZero(&pubKey, sizeof(pubKey));
-+ }
-+ if (valueAttribute)
-+ sftk_FreeAttribute(valueAttribute);
-+ }
-+ sftk_FreeAttribute(seedAttribute);
-+ if (crv != CKR_OK) {
-+ return crv;
-+ }
-+ }
-+ sftk_DeleteAttributeType(object, CKA_NSS_SEED_OK);
-+ /* if we got this far, we should have a CKA_VALUE, either but
-+ * one given to us, or by it being generated above */
-+ if (!sftk_hasAttribute(object, CKA_VALUE)) {
-+ return CKR_TEMPLATE_INCOMPLETE;
-+ }
-+ encrypt = decapsulate = recover = wrap = CK_FALSE;
-+ sign = CK_TRUE;
-+ break;
-+#endif
- default:
- return CKR_ATTRIBUTE_VALUE_INVALID;
- }
- crv = sftk_defaultAttribute(object, CKA_SUBJECT, NULL, 0);
- if (crv != CKR_OK)
- return crv;
- crv = sftk_defaultAttribute(object, CKA_SENSITIVE, &cktrue, sizeof(CK_BBOOL));
- if (crv != CKR_OK)
-@@ -1380,17 +1484,17 @@ sftk_handlePrivateKeyObject(SFTKSession
- if (crv != CKR_OK)
- return crv;
- crv = sftk_defaultAttribute(object, CKA_UNWRAP, &wrap, sizeof(CK_BBOOL));
- if (crv != CKR_OK)
- return crv;
- crv = sftk_defaultAttribute(object, CKA_DERIVE, &derive, sizeof(CK_BBOOL));
- if (crv != CKR_OK)
- return crv;
-- crv = sftk_defaultAttribute(object, CKA_DECAPSULATE, &encapsulate, sizeof(CK_BBOOL));
-+ crv = sftk_defaultAttribute(object, CKA_DECAPSULATE, &decapsulate, sizeof(CK_BBOOL));
- if (crv != CKR_OK)
- return crv;
- /* the next two bits get modified only in the key gen and token cases */
- crv = sftk_forceAttribute(object, CKA_ALWAYS_SENSITIVE,
- &ckfalse, sizeof(CK_BBOOL));
- if (crv != CKR_OK)
- return crv;
- crv = sftk_forceAttribute(object, CKA_NEVER_EXTRACTABLE,
-@@ -2045,16 +2149,31 @@ sftk_GetPubKey(SFTKObject *object, CK_KE
- break;
- #ifndef NSS_DISABLE_KYBER
- case CKK_NSS_KYBER:
- #endif
- case CKK_NSS_ML_KEM:
- case CKK_ML_KEM:
- crv = CKR_OK;
- break;
-+#ifdef NSS_ENABLE_ML_DSA
-+ case CKK_ML_DSA:
-+ pubKey->keyType = NSSLOWKEYMLDSAKey;
-+ crv = sftk_ReadAttribute(object, CKA_VALUE,
-+ pubKey->u.mldsa.keyVal,
-+ sizeof(pubKey->u.mldsa.keyVal),
-+ &pubKey->u.mldsa.keyValLen);
-+ if (crv != CKR_OK) {
-+ break;
-+ }
-+ crv = sftk_GetULongAttribute (object, CKA_PARAMETER_SET,
-+ &pubKey->u.mldsa.paramSet);
-+
-+ break;
-+#endif
- default:
- crv = CKR_KEY_TYPE_INCONSISTENT;
- break;
- }
- *crvp = crv;
- if (crv != CKR_OK) {
- PORT_FreeArena(arena, PR_TRUE);
- return NULL;
-@@ -2218,16 +2337,41 @@ sftk_mkPrivKey(SFTKObject *object, CK_KE
-
- #ifndef NSS_DISABLE_KYBER
- case CKK_NSS_KYBER:
- #endif
- case CKK_NSS_ML_KEM:
- case CKK_ML_KEM:
- break;
-
-+#ifdef NSS_ENABLE_ML_DSA
-+ case CKK_ML_DSA:
-+ privKey->keyType = NSSLOWKEYMLDSAKey;
-+ crv = sftk_ReadAttribute(object, CKA_VALUE,
-+ privKey->u.mldsa.keyVal,
-+ sizeof(privKey->u.mldsa.keyVal),
-+ &privKey->u.mldsa.keyValLen);
-+ if (crv != CKR_OK) {
-+ break;
-+ }
-+ crv = sftk_ReadAttribute(object, CKA_SEED,
-+ privKey->u.mldsa.seed,
-+ sizeof(privKey->u.mldsa.seed),
-+ &privKey->u.mldsa.seedLen);
-+ if (crv != CKR_OK) {
-+ /* no seed value, just set it to zero. The seed
-+ * has been lost or discarded for this key */
-+ privKey->u.mldsa.seedLen = 0;
-+ }
-+ crv = sftk_GetULongAttribute(object, CKA_PARAMETER_SET,
-+ &privKey->u.mldsa.paramSet);
-+
-+ break;
-+#endif
-+
- default:
- crv = CKR_KEY_TYPE_INCONSISTENT;
- break;
- }
- if (crv == CKR_OK && itemTemplateCount != 0) {
- PORT_Assert(itemTemplateCount > 0);
- PORT_Assert(itemTemplateCount <= SFTK_MAX_ITEM_TEMPLATE);
- crv = sftk_MultipleAttribute2SecItem(arena, object, itemTemplate,
-@@ -2468,16 +2612,31 @@ sftk_PutPubKey(SFTKObject *publicKey, SF
- crv = sftk_AddAttributeType(publicKey, CKA_BASE,
- sftk_item_expand(&pubKey->u.dsa.params.base));
- if (crv != CKR_OK) {
- break;
- }
- crv = sftk_AddAttributeType(publicKey, CKA_VALUE,
- sftk_item_expand(&pubKey->u.dsa.publicValue));
- break;
-+#ifdef NSS_ENABLE_ML_DSA
-+ case CKK_ML_DSA:
-+ sftk_DeleteAttributeType(publicKey, CKA_VALUE);
-+ sftk_DeleteAttributeType(publicKey, CKA_PARAMETER_SET);
-+ crv = sftk_AddAttributeType(publicKey, CKA_VALUE,
-+ pubKey->u.mldsa.keyVal,
-+ pubKey->u.mldsa.keyValLen);
-+ if (crv != CKR_OK) {
-+ break;
-+ }
-+ crv = sftk_AddAttributeType(publicKey, CKA_PARAMETER_SET,
-+ (unsigned char *)&pubKey->u.mldsa.paramSet,
-+ sizeof(pubKey->u.mldsa.paramSet));
-+ break;
-+#endif
- case CKK_DH:
- sftk_DeleteAttributeType(publicKey, CKA_PRIME);
- sftk_DeleteAttributeType(publicKey, CKA_BASE);
- crv = sftk_AddAttributeType(publicKey, CKA_PRIME,
- sftk_item_expand(&pubKey->u.dh.prime));
- if (crv != CKR_OK) {
- break;
- }
-@@ -2532,16 +2691,22 @@ sftk_PutPubKey(SFTKObject *publicKey, SF
- }
- }
- if (sftk_isTrue(privateKey, CKA_SIGN_RECOVER)) {
- crv = sftk_forceAttribute(publicKey, CKA_VERIFY_RECOVER, &cktrue, sizeof(CK_BBOOL));
- if (crv != CKR_OK) {
- return crv;
- }
- }
-+ if (sftk_isTrue(privateKey, CKA_DECAPSULATE)) {
-+ crv = sftk_forceAttribute(publicKey, CKA_ENCAPSULATE, &cktrue, sizeof(CK_BBOOL));
-+ if (crv != CKR_OK) {
-+ return crv;
-+ }
-+ }
- if (sftk_isTrue(privateKey, CKA_DERIVE)) {
- crv = sftk_forceAttribute(publicKey, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));
- if (crv != CKR_OK) {
- return crv;
- }
- }
- return crv;
- }
-diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
---- a/lib/softoken/pkcs11c.c
-+++ b/lib/softoken/pkcs11c.c
-@@ -76,16 +76,25 @@ typedef struct {
- } SSL3RSAPreMasterSecret;
-
- static void
- sftk_Null(void *data, PRBool freeit)
- {
- return;
- }
-
-+/* fake hash end, the hashed data is already in the signature context,
-+ * return a NULL hash, which will be passed to the sign final and ignored */
-+void
-+sftk_NullHashEnd(void *info, unsigned char *data, unsigned int *lenp,
-+ unsigned int maxlen)
-+{
-+ *lenp = 0;
-+}
-+
- #ifdef EC_DEBUG
- #define SEC_PRINT(str1, str2, num, sitem) \
- printf("pkcs11c.c:%s:%s (keytype=%d) [len=%d]\n", \
- str1, str2, num, sitem->len); \
- for (i = 0; i < sitem->len; i++) { \
- printf("%02x:", sitem->data[i]); \
- } \
- printf("\n")
-@@ -2844,16 +2853,85 @@ nsc_EDDSASignStub(void *ctx, unsigned ch
- SECStatus rv = ED_SignMessage(&(key->u.ec), &signature, &digest);
- if (rv != SECSuccess && PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
- sftk_fatalError = PR_TRUE;
- }
- *sigLen = signature.len;
- return rv;
- }
-
-+#ifdef NSS_ENABLE_ML_DSA
-+void
-+sftk_MLDSASignUpdate(void *info, const unsigned char *data, unsigned int len)
-+{
-+ MLDSAContext *ctptr = (MLDSAContext *)info;
-+ const SECItem inData = {siBuffer, (unsigned char *)data, len};
-+ (void) MLDSA_SignUpdate(ctptr, &inData);
-+}
-+
-+void
-+sftk_MLDSAVerifyUpdate(void *info, const unsigned char *data, unsigned int len)
-+{
-+ MLDSAContext *ctptr = (MLDSAContext *)info;
-+ const SECItem inData = {siBuffer, (unsigned char *)data, len};
-+ (void) MLDSA_VerifyUpdate(ctptr, &inData);
-+}
-+
-+SECStatus
-+sftk_MLDSASignFinal(void *info, unsigned char *sig, unsigned int *sigLen,
-+ unsigned int maxLen, const unsigned char *data,
-+ unsigned int len)
-+{
-+ MLDSAContext *ctptr = (MLDSAContext *)info;
-+ SECItem sigOut = {siBuffer, sig, maxLen};
-+ SECStatus rv;
-+
-+ if (len !=0 ) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return SECFailure;
-+ }
-+
-+ rv = MLDSA_SignFinal(ctptr, &sigOut);
-+ *sigLen = sigOut.len;
-+ return rv;
-+}
-+
-+SECStatus
-+sftk_MLDSAVerifyFinal(void *info, const unsigned char *sig, unsigned int sigLen,
-+ const unsigned char *data, unsigned int len)
-+{
-+ MLDSAContext *ctptr = (MLDSAContext *)info;
-+ const SECItem sigIn= {siBuffer, (unsigned char *)sig, sigLen};
-+
-+ if (len !=0 ) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return SECFailure;
-+ }
-+
-+ return MLDSA_VerifyFinal(ctptr, &sigIn);
-+}
-+
-+unsigned int
-+sftk_MLDSAGetSigLen(CK_ML_DSA_PARAMETER_SET_TYPE paramSet)
-+{
-+ switch (paramSet) {
-+ case CKP_ML_DSA_44:
-+ return ML_DSA_44_SIGNATURE_LEN;
-+ case CKP_ML_DSA_65:
-+ return ML_DSA_65_SIGNATURE_LEN;
-+ case CKP_ML_DSA_87:
-+ return ML_DSA_87_SIGNATURE_LEN;
-+ }
-+ /* this is a programming error if we get a valid DSA key with an unknown
-+ * parmaSet */
-+ PORT_Assert( /* unknown param set */ 0);
-+ return 0;
-+}
-+#endif
-+
- /* NSC_SignInit setups up the signing operations. There are three basic
- * types of signing:
- * (1) the tradition single part, where "Raw RSA" or "Raw DSA" is applied
- * to data in a single Sign operation (which often looks a lot like an
- * encrypt, with data coming in and data going out).
- * (2) Hash based signing, where we continually hash the data, then apply
- * some sort of signature to the end.
- * (3) Block Encryption CBC MAC's, where the Data is encrypted with a key,
-@@ -3033,16 +3111,81 @@ NSC_SignInit(CK_SESSION_HANDLE hSession,
- }
- context->cipherInfo = privKey;
- context->update = nsc_DSA_Sign_Stub;
- context->destroy = (privKey == key->objectInfo) ? sftk_Null : sftk_FreePrivKey;
- context->maxLen = DSA_MAX_SIGNATURE_LEN;
-
- break;
-
-+#ifdef NSS_ENABLE_ML_DSA
-+ case CKM_ML_DSA:
-+ {
-+ /* set our defaults */
-+ CK_HEDGE_TYPE hedgeType = CKH_HEDGE_PREFERRED;
-+ SECItem signCtx = { siBuffer, NULL, 0 };
-+ MLDSAContext *ctptr = NULL;
-+ SECStatus rv;
-+
-+ /* make sure we have the right key type */
-+ if (key_type != CKK_ML_DSA) {
-+ crv = CKR_KEY_TYPE_INCONSISTENT;
-+ break;
-+ }
-+ /* fill in our parameters from the mechanism parameters if
-+ * supplied */
-+ if (pMechanism->ulParameterLen != 0) {
-+ CK_SIGN_ADDITIONAL_CONTEXT *param;
-+ if (pMechanism->ulParameterLen !=
-+ sizeof(CK_SIGN_ADDITIONAL_CONTEXT)) {
-+ crv = CKR_MECHANISM_PARAM_INVALID;
-+ break;
-+ }
-+ param = (CK_SIGN_ADDITIONAL_CONTEXT *)pMechanism->pParameter;
-+ hedgeType = param->hedgeVariant;
-+ signCtx.data = param->pContext;
-+ signCtx.len = param->ulContextLen;
-+ }
-+ /* fetch the key */
-+ privKey = sftk_GetPrivKey(key, key_type, &crv);
-+ if (privKey == NULL) {
-+ crv = CKR_HOST_MEMORY;
-+ break;
-+ }
-+ /* now initialize it the signature */
-+ rv = MLDSA_SignInit(&privKey->u.mldsa, hedgeType, &signCtx, &ctptr);
-+ if (rv != SECSuccess) {
-+ crv = sftk_MapCryptError(PORT_GetError());
-+ if (privKey != key->objectInfo) {
-+ nsslowkey_DestroyPrivateKey(privKey);
-+ }
-+ break;
-+ }
-+ /* set up our cipher info. MLDSA is only a combined hash/sign
-+ * so the hash update is our sign update, the hash end is a null
-+ * function returning a zero length value, and the final gets our
-+ * signature based on the context. Both the cipher context and the
-+ * hash Info is the same. The MLDSA_SignFinal frees the context,
-+ * so we don't have to */
-+ context->multi = PR_TRUE;
-+ context->cipherInfo = ctptr;
-+ context->hashInfo = ctptr;
-+ context->hashUpdate = sftk_MLDSASignUpdate;
-+ context->end = sftk_NullHashEnd;
-+ context->hashdestroy = sftk_Null;
-+ context->destroy = sftk_Null;
-+ context->update = sftk_MLDSASignFinal;
-+ context->maxLen = sftk_MLDSAGetSigLen(privKey->u.mldsa.paramSet);
-+ if (privKey != key->objectInfo) {
-+ nsslowkey_DestroyPrivateKey(privKey);
-+ }
-+ break;
-+ }
-+#endif
-+
- #define INIT_ECDSA_SIG_MECH(mmm) \
- case CKM_ECDSA_##mmm: \
- context->multi = PR_TRUE; \
- crv = sftk_doSub##mmm(context); \
- if (crv != CKR_OK) \
- break; \
- goto finish_ecdsa;
- INIT_ECDSA_SIG_MECH(SHA1)
-@@ -3840,16 +3983,73 @@ NSC_VerifyInit(CK_SESSION_HANDLE hSessio
- if (pubKey == NULL) {
- break;
- }
- context->cipherInfo = pubKey;
- context->verify = nsc_DSA_Verify_Stub;
- context->destroy = sftk_Null;
- break;
-
-+#ifdef NSS_ENABLE_ML_DSA
-+ case CKM_ML_DSA:
-+ {
-+ /* set our defaults */
-+ SECItem signCtx = { siBuffer, NULL, 0 };
-+ MLDSAContext *ctptr = NULL;
-+ SECStatus rv;
-+
-+ /* make sure we have the right key type */
-+ if (key_type != CKK_ML_DSA) {
-+ crv = CKR_KEY_TYPE_INCONSISTENT;
-+ break;
-+ }
-+ /* fill in our parameters from the mechanism parameters if
-+ * supplied */
-+ if (pMechanism->ulParameterLen != 0) {
-+ CK_SIGN_ADDITIONAL_CONTEXT *param;
-+ if (pMechanism->ulParameterLen !=
-+ sizeof(CK_SIGN_ADDITIONAL_CONTEXT)) {
-+ crv = CKR_MECHANISM_PARAM_INVALID;
-+ break;
-+ }
-+ param = (CK_SIGN_ADDITIONAL_CONTEXT *)pMechanism->pParameter;
-+ signCtx.data = param->pContext;
-+ signCtx.len = param->ulContextLen;
-+ }
-+ /* fetch the key */
-+ pubKey = sftk_GetPubKey(key, key_type, &crv);
-+ if (pubKey == NULL) {
-+ /* crv already set */
-+ break;
-+ }
-+ /* now initialize it the signature */
-+ rv = MLDSA_VerifyInit(&(pubKey->u.mldsa), &signCtx, &ctptr);
-+ if (rv != SECSuccess) {
-+ crv = sftk_MapVerifyError(PORT_GetError());
-+ break;
-+ }
-+ /* set up our cipher info. MLDSA is only a combined hash/sign
-+ * so the hash update is our sign update, the hash end is a null
-+ * function returning a zero length value, and the final gets our
-+ * signature based on the context. Both the cipher context and the
-+ * hash Info is the same. The MLDSA_VerifyFinal frees the context,
-+ * so we don't have to */
-+ context->multi = PR_TRUE;
-+ context->cipherInfo = ctptr;
-+ context->hashInfo = ctptr;
-+ context->hashUpdate = sftk_MLDSAVerifyUpdate;
-+ context->end = sftk_NullHashEnd;
-+ context->hashdestroy = sftk_Null;
-+ context->destroy = sftk_Null;
-+ context->verify = sftk_MLDSAVerifyFinal;
-+ context->maxLen = sftk_MLDSAGetSigLen(pubKey->u.mldsa.paramSet);
-+ break;
-+ }
-+#endif
-+
- INIT_ECDSA_SIG_MECH(SHA1)
- INIT_ECDSA_SIG_MECH(SHA224)
- INIT_ECDSA_SIG_MECH(SHA256)
- INIT_ECDSA_SIG_MECH(SHA384)
- INIT_ECDSA_SIG_MECH(SHA512)
- case CKM_ECDSA:
- finish_ecdsa:
- if (key_type != CKK_EC) {
-@@ -5309,16 +5509,20 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
- signature_length = DSA_MAX_SIGNATURE_LEN;
- pairwise_digest_length = subPrimeLen;
- mech.mechanism = CKM_DSA;
- break;
- case CKK_EC:
- signature_length = MAX_ECKEY_LEN * 2;
- mech.mechanism = CKM_ECDSA;
- break;
-+ case CKK_ML_DSA:
-+ signature_length = MAX_ML_DSA_SIGNATURE_LEN;
-+ mech.mechanism = CKM_ML_DSA;
-+ break;
- case CKK_EC_EDWARDS:
- signature_length = ED25519_SIGN_LEN;
- mech.mechanism = CKM_EDDSA;
- break;
- default:
- return CKR_DEVICE_ERROR;
- }
-
-@@ -5630,27 +5834,31 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
- int public_modulus_bits = 0;
- SECItem pubExp;
- RSAPrivateKey *rsaPriv;
-
- /* DSA */
- PQGParams pqgParam;
- DHParams dhParam;
- DSAPrivateKey *dsaPriv;
-+#ifdef NSS_ENABLE_ML_DSA
-+ MLDSAPrivateKey mldsaPriv;
-+ MLDSAPublicKey mldsaPub;
-+#endif
-
- /* Diffie Hellman */
- DHPrivateKey *dhPriv;
-
- /* Elliptic Curve Cryptography */
- SECItem ecEncodedParams; /* DER Encoded parameters */
- ECPrivateKey *ecPriv;
- ECParams *ecParams;
-
- /* Kyber */
-- CK_NSS_KEM_PARAMETER_SET_TYPE ckKyberParamSet;
-+ CK_ULONG ckParamSet;
-
- CHECK_FORK();
-
- if (!slot) {
- return CKR_SESSION_HANDLE_INVALID;
- }
- /*
- * now lets create an object to hang the attributes off of
-@@ -5665,21 +5873,21 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
- */
- for (i = 0; i < (int)ulPublicKeyAttributeCount; i++) {
- if (pPublicKeyTemplate[i].type == CKA_MODULUS_BITS) {
- public_modulus_bits = *(CK_ULONG *)pPublicKeyTemplate[i].pValue;
- continue;
- }
-
- if (pPublicKeyTemplate[i].type == CKA_NSS_PARAMETER_SET) {
-- ckKyberParamSet = *(CK_NSS_KEM_PARAMETER_SET_TYPE *)pPublicKeyTemplate[i].pValue;
-+ ckParamSet = *(CK_ULONG *)pPublicKeyTemplate[i].pValue;
- continue;
- }
- if (pPublicKeyTemplate[i].type == CKA_PARAMETER_SET) {
-- ckKyberParamSet = *(CK_ML_KEM_PARAMETER_SET_TYPE *)pPublicKeyTemplate[i].pValue;
-+ ckParamSet = *(CK_ULONG *)pPublicKeyTemplate[i].pValue;
- continue;
- }
-
- crv = sftk_AddAttributeType(publicKey,
- sftk_attr_expand(&pPublicKeyTemplate[i]));
- if (crv != CKR_OK)
- break;
- }
-@@ -6083,17 +6291,17 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
- goto generate_mlkem;
- case CKM_ML_KEM_KEY_PAIR_GEN:
- key_type = CKK_ML_KEM;
- generate_mlkem:
- sftk_DeleteAttributeType(privateKey, CKA_NSS_DB);
-
- SECItem privKey = { siBuffer, NULL, 0 };
- SECItem pubKey = { siBuffer, NULL, 0 };
-- KyberParams kyberParams = sftk_kyber_PK11ParamToInternal(ckKyberParamSet);
-+ KyberParams kyberParams = sftk_kyber_PK11ParamToInternal(ckParamSet);
- if (!sftk_kyber_AllocPrivKeyItem(kyberParams, &privKey)) {
- crv = CKR_HOST_MEMORY;
- goto kyber_done;
- }
- if (!sftk_kyber_AllocPubKeyItem(kyberParams, &pubKey)) {
- crv = CKR_HOST_MEMORY;
- goto kyber_done;
- }
-@@ -6103,37 +6311,117 @@ generate_mlkem:
- goto kyber_done;
- }
-
- crv = sftk_AddAttributeType(publicKey, CKA_VALUE, sftk_item_expand(&pubKey));
- if (crv != CKR_OK) {
- goto kyber_done;
- }
- crv = sftk_AddAttributeType(publicKey, CKA_PARAMETER_SET,
-- &ckKyberParamSet, sizeof(CK_ML_KEM_PARAMETER_SET_TYPE));
-+ &ckParamSet, sizeof(CK_ML_KEM_PARAMETER_SET_TYPE));
- if (crv != CKR_OK) {
- goto kyber_done;
- }
- crv = sftk_AddAttributeType(privateKey, CKA_VALUE,
- sftk_item_expand(&privKey));
- if (crv != CKR_OK) {
- goto kyber_done;
- }
-
- crv = sftk_AddAttributeType(privateKey, CKA_PARAMETER_SET,
-- &ckKyberParamSet, sizeof(CK_ML_KEM_PARAMETER_SET_TYPE));
-+ &ckParamSet, sizeof(CK_ML_KEM_PARAMETER_SET_TYPE));
- if (crv != CKR_OK) {
- goto kyber_done;
- }
- crv = sftk_AddAttributeType(privateKey, CKA_NSS_DB,
- sftk_item_expand(&pubKey));
- kyber_done:
- SECITEM_ZfreeItem(&privKey, PR_FALSE);
- SECITEM_FreeItem(&pubKey, PR_FALSE);
- break;
-+#ifdef NSS_ENABLE_ML_DSA
-+ case CKM_ML_DSA_KEY_PAIR_GEN:
-+ sftk_DeleteAttributeType(publicKey, CKA_VALUE);
-+ sftk_DeleteAttributeType(privateKey, CKA_NSS_DB);
-+ sftk_DeleteAttributeType(privateKey, CKA_SEED);
-+ key_type = CKK_ML_DSA;
-+
-+
-+ /*
-+ * the parameters are recognized by us
-+ */
-+ bitSize = sftk_MLDSAGetSigLen(ckParamSet);
-+ if (bitSize == 0) {
-+ crv = CKR_TEMPLATE_INCOMPLETE;
-+ break;
-+ }
-+
-+ /* Generate the key */
-+ rv = MLDSA_NewKey(ckParamSet, NULL, &mldsaPriv, &mldsaPub);
-+
-+ if (rv != SECSuccess) {
-+ if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
-+ sftk_fatalError = PR_TRUE;
-+ }
-+ crv = sftk_MapCryptError(PORT_GetError());
-+ break;
-+ }
-+
-+ /* store the generated key into the attributes */
-+ crv = sftk_AddAttributeType(publicKey, CKA_VALUE,
-+ mldsaPub.keyVal, mldsaPub.keyValLen);
-+ if (crv != CKR_OK)
-+ goto mldsagn_done;
-+ crv = sftk_AddAttributeType(publicKey, CKA_PARAMETER_SET,
-+ &ckParamSet, sizeof(CK_ML_DSA_PARAMETER_SET_TYPE));
-+ if (crv != CKR_OK) {
-+ goto mldsagn_done;
-+ }
-+
-+ /* now fill in the RSA dependent paramenters in the private key */
-+ crv = sftk_AddAttributeType(privateKey, CKA_NSS_DB,
-+ mldsaPub.keyVal, mldsaPub.keyValLen);
-+ if (crv != CKR_OK)
-+ goto mldsagn_done;
-+
-+ crv = sftk_AddAttributeType(privateKey, CKA_VALUE,
-+ mldsaPriv.keyVal,
-+ mldsaPriv.keyValLen);
-+ if (crv != CKR_OK)
-+ goto mldsagn_done;
-+ crv = sftk_AddAttributeType(privateKey, CKA_PARAMETER_SET,
-+ &ckParamSet, sizeof(CK_ML_DSA_PARAMETER_SET_TYPE));
-+ if (crv != CKR_OK) {
-+ goto mldsagn_done;
-+ }
-+
-+ if (mldsaPriv.seedLen != 0) {
-+ crv = sftk_AddAttributeType(privateKey, CKA_SEED,
-+ mldsaPriv.seed, mldsaPriv.seedLen);
-+ if (crv != CKR_OK) {
-+ goto mldsagn_done;
-+ }
-+ /* pseudo attribute that says the seed came with the key
-+ * so don't try to regenerate thekey in handleObject.
-+ * it will be removed before the object sees the light of
-+ * day. */
-+ crv = sftk_AddAttributeType(privateKey, CKA_NSS_SEED_OK,
-+ NULL, 0);
-+ /* it was either this or a comment 'fall through' which would
-+ * be cryptic to some users */
-+ if (crv != CKR_OK) {
-+ goto mldsagn_done;
-+ }
-+ }
-+ mldsagn_done:
-+ PORT_SafeZero(&mldsaPriv, sizeof(mldsaPriv));
-+ PORT_SafeZero(&mldsaPub, sizeof(mldsaPub));
-+ break;
-+#endif
-+
-
- case CKM_EC_MONTGOMERY_KEY_PAIR_GEN:
- case CKM_EC_EDWARDS_KEY_PAIR_GEN:
- sftk_DeleteAttributeType(privateKey, CKA_EC_PARAMS);
- sftk_DeleteAttributeType(privateKey, CKA_VALUE);
- sftk_DeleteAttributeType(privateKey, CKA_NSS_DB);
- key_type = (pMechanism->mechanism == CKM_EC_EDWARDS_KEY_PAIR_GEN) ? CKK_EC_EDWARDS : CKK_EC_MONTGOMERY;
-
-@@ -6444,16 +6732,77 @@ sftk_PackagePrivateKey(SFTKObject *key,
- SEC_PRINT("sftk_PackagePrivateKey()", "PrivateKey", lk->keyType,
- fordebug);
- #endif
-
- param = SECITEM_DupItem(&lk->u.ec.ecParams.DEREncoding);
-
- algorithm = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
- break;
-+ case NSSLOWKEYMLDSAKey:
-+ {
-+ SECItem seed = {siBuffer, NULL, 0};
-+ SECItem keyVal = {siBuffer, NULL, 0};
-+ dummy = NULL;
-+
-+ /* paramSet sets the algorithm */
-+ switch (lk->u.mldsa.paramSet) {
-+ case CKP_ML_DSA_44:
-+ algorithm = SEC_OID_ML_DSA_44;
-+ break;
-+ case CKP_ML_DSA_65:
-+ algorithm = SEC_OID_ML_DSA_65;
-+ break;
-+ case CKP_ML_DSA_87:
-+ algorithm = SEC_OID_ML_DSA_87;
-+ break;
-+ default:
-+ algorithm = SEC_OID_UNKNOWN;
-+ break;
-+ }
-+ if (algorithm == SEC_OID_UNKNOWN) {
-+ break;
-+ }
-+
-+ /* if we have the seed, copy it */
-+ if (lk->u.mldsa.seedLen != 0) {
-+ rv = SECITEM_MakeItem(arena, &seed, lk->u.mldsa.seed,
-+ lk->u.mldsa.seedLen);
-+ if (rv != SECSuccess) {
-+ break;
-+ }
-+ }
-+ rv = SECITEM_MakeItem(arena, &keyVal, lk->u.mldsa.keyVal,
-+ lk->u.mldsa.keyValLen);
-+ if (rv != SECSuccess) {
-+ break;
-+ }
-+ if (lk == key->objectInfo) {
-+ /* we are used a cached key, and we are about to
-+ * overwrite it, let's get a duplicate first */
-+ lk = nsslowkey_CopyPrivateKey(lk);
-+ if (lk == NULL) {
-+ break;
-+ }
-+ }
-+ /* this overwrites the mldsa data, but we don't need it any
-+ * more because we are discarding lk once we encode */
-+ lk->u.genpq.seedItem = seed;
-+ lk->u.genpq.keyItem = keyVal;
-+
-+ if (seed.len) {
-+ dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
-+ nsslowkey_PQBothSeedAndPrivateKeyTemplate);
-+ } else {
-+ dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk,
-+ nsslowkey_PQPrivateKeyTemplate);
-+ }
-+ }
-+ break;
-+
- case NSSLOWKEYDHKey:
- default:
- dummy = NULL;
- break;
- }
-
- if (!dummy || ((lk->keyType == NSSLOWKEYDSAKey) && !param)) {
- *crvp = CKR_DEVICE_ERROR; /* should map NSS SECError */
-@@ -6652,24 +7001,26 @@ NSC_WrapKey(CK_SESSION_HANDLE hSession,
-
- /*
- * import a pprivate key info into the desired slot
- */
- static SECStatus
- sftk_unwrapPrivateKey(SFTKObject *key, SECItem *bpki)
- {
- CK_BBOOL cktrue = CK_TRUE;
-+ CK_BBOOL ckfalse = CK_FALSE;
- CK_KEY_TYPE keyType = CKK_RSA;
- SECStatus rv = SECFailure;
- const SEC_ASN1Template *keyTemplate, *paramTemplate;
- void *paramDest = NULL;
- PLArenaPool *arena;
- NSSLOWKEYPrivateKey *lpk = NULL;
- NSSLOWKEYPrivateKeyInfo *pki = NULL;
- CK_RV crv = CKR_KEY_TYPE_INCONSISTENT;
-+ CK_ULONG paramSet = 0;
-
- arena = PORT_NewArena(2048);
- if (!arena) {
- return SECFailure;
- }
-
- pki = (NSSLOWKEYPrivateKeyInfo *)PORT_ArenaZAlloc(arena,
- sizeof(NSSLOWKEYPrivateKeyInfo));
-@@ -6711,16 +7062,45 @@ sftk_unwrapPrivateKey(SFTKObject *key, S
- case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
- keyTemplate = nsslowkey_ECPrivateKeyTemplate;
- paramTemplate = NULL;
- paramDest = &(lpk->u.ec.ecParams.DEREncoding);
- lpk->keyType = NSSLOWKEYECKey;
- prepare_low_ec_priv_key_for_asn1(lpk);
- prepare_low_ecparams_for_asn1(&lpk->u.ec.ecParams);
- break;
-+ case SEC_OID_ML_DSA_44:
-+ paramSet = CKP_ML_DSA_44;
-+ goto mldsa_next;
-+ case SEC_OID_ML_DSA_65:
-+ paramSet = CKP_ML_DSA_65;
-+ goto mldsa_next;
-+ case SEC_OID_ML_DSA_87:
-+ paramSet = CKP_ML_DSA_87;
-+mldsa_next:
-+ switch (pki->privateKey.data[0]) {
-+ case SEC_ASN1_CONTEXT_SPECIFIC|0:
-+ keyTemplate = nsslowkey_PQSeedTemplate;
-+ break;
-+ case SEC_ASN1_OCTET_STRING:
-+ keyTemplate = nsslowkey_PQPrivateKeyTemplate;
-+ break;
-+ case SEC_ASN1_CONSTRUCTED|SEC_ASN1_SEQUENCE:
-+ keyTemplate = nsslowkey_PQBothSeedAndPrivateKeyTemplate;
-+ break;
-+ default:
-+ keyTemplate = NULL;
-+ break;
-+ }
-+
-+ paramTemplate = NULL;
-+ paramDest = NULL;
-+ lpk->keyType = NSSLOWKEYMLDSAKey;
-+ /* genpq encodes ocect, not integer, so no need to prep it */
-+ break;
- default:
- keyTemplate = NULL;
- paramTemplate = NULL;
- paramDest = NULL;
- break;
- }
-
- if (!keyTemplate) {
-@@ -6819,17 +7199,17 @@ sftk_unwrapPrivateKey(SFTKObject *key, S
- crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType,
- sizeof(keyType));
- if (crv != CKR_OK)
- break;
- crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue,
- sizeof(CK_BBOOL));
- if (crv != CKR_OK)
- break;
-- crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue,
-+ crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &ckfalse,
- sizeof(CK_BBOOL));
- if (crv != CKR_OK)
- break;
- crv = sftk_AddAttributeType(key, CKA_PRIME,
- sftk_item_expand(&lpk->u.dsa.params.prime));
- if (crv != CKR_OK)
- break;
- crv = sftk_AddAttributeType(key, CKA_SUBPRIME,
-@@ -6840,16 +7220,58 @@ sftk_unwrapPrivateKey(SFTKObject *key, S
- sftk_item_expand(&lpk->u.dsa.params.base));
- if (crv != CKR_OK)
- break;
- crv = sftk_AddAttributeType(key, CKA_VALUE,
- sftk_item_expand(&lpk->u.dsa.privateValue));
- if (crv != CKR_OK)
- break;
- break;
-+#ifdef NSS_ENABLE_ML_DSA
-+ case NSSLOWKEYMLDSAKey:
-+ keyType = CKK_ML_DSA;
-+ crv = (sftk_hasAttribute(key, CKA_NSS_DB)) ? CKR_OK : CKR_KEY_TYPE_INCONSISTENT;
-+ if (crv != CKR_OK)
-+ break;
-+ crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType,
-+ sizeof(keyType));
-+ if (crv != CKR_OK)
-+ break;
-+ crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue,
-+ sizeof(CK_BBOOL));
-+ if (crv != CKR_OK)
-+ break;
-+ crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &ckfalse,
-+ sizeof(CK_BBOOL));
-+ if (crv != CKR_OK)
-+ break;
-+ crv = sftk_AddAttributeType(key, CKA_PARAMETER_SET, ¶mSet,
-+ sizeof(CK_ML_DSA_PARAMETER_SET_TYPE));
-+ if (crv != CKR_OK)
-+ break;
-+ if (lpk->u.genpq.seedItem.len != 0) {
-+ crv = sftk_AddAttributeType(key, CKA_SEED,
-+ sftk_item_expand(&lpk->u.genpq.seedItem));
-+ if (crv != CKR_OK)
-+ break;
-+ }
-+
-+ /* if we were given just the seed, we'll regenerate the key
-+ * from the seed in handleObject */
-+ if (lpk->u.genpq.keyItem.len != 0) {
-+ crv = sftk_AddAttributeType(key, CKA_VALUE,
-+ sftk_item_expand(&lpk->u.genpq.keyItem));
-+ /* I know, this is redundant, but it would be too easy
-+ * for someone to add another sftk_AddAttributeType after
-+ * this without adding this check back because of the if */
-+ if (crv != CKR_OK)
-+ break;
-+ }
-+ break;
-+#endif
- #ifdef notdef
- case NSSLOWKEYDHKey:
- template = dhTemplate;
- templateCount = sizeof(dhTemplate) / sizeof(CK_ATTRIBUTE);
- keyType = CKK_DH;
- break;
- #endif
- /* what about fortezza??? */
-@@ -6861,17 +7283,17 @@ sftk_unwrapPrivateKey(SFTKObject *key, S
- crv = sftk_AddAttributeType(key, CKA_KEY_TYPE, &keyType,
- sizeof(keyType));
- if (crv != CKR_OK)
- break;
- crv = sftk_AddAttributeType(key, CKA_SIGN, &cktrue,
- sizeof(CK_BBOOL));
- if (crv != CKR_OK)
- break;
-- crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &cktrue,
-+ crv = sftk_AddAttributeType(key, CKA_SIGN_RECOVER, &ckfalse,
- sizeof(CK_BBOOL));
- if (crv != CKR_OK)
- break;
- crv = sftk_AddAttributeType(key, CKA_DERIVE, &cktrue,
- sizeof(CK_BBOOL));
- if (crv != CKR_OK)
- break;
- crv = sftk_AddAttributeType(key, CKA_EC_PARAMS,
-diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h
---- a/lib/softoken/pkcs11i.h
-+++ b/lib/softoken/pkcs11i.h
-@@ -68,16 +68,20 @@
- #define TIME_ATTRIBUTE_HASH_SIZE 32
- #define TIME_SESSION_OBJECT_HASH_SIZE 1024
- #define TIME_SESSION_HASH_SIZE 1024
- #define MAX_OBJECT_LIST_SIZE 800
- /* how many objects to keep on the free list
- * before we start freeing them */
- #define MAX_KEY_LEN 256 /* maximum symmetric key length in bytes */
-
-+#define SEC_OID_ML_DSA_44 SEC_OID_PRIVATE_3
-+#define SEC_OID_ML_DSA_65 SEC_OID_PRIVATE_4
-+#define SEC_OID_ML_DSA_87 SEC_OID_PRIVATE_5
-+
- /*
- * LOG2_BUCKETS_PER_SESSION_LOCK must be a prime number.
- * With SESSION_HASH_SIZE=1024, LOG2 can be 9, 5, 1, or 0.
- * With SESSION_HASH_SIZE=4096, LOG2 can be 11, 9, 5, 1, or 0.
- *
- * HASH_SIZE LOG2_BUCKETS_PER BUCKETS_PER_LOCK NUMBER_OF_BUCKETS
- * 1024 9 512 2
- * 1024 5 32 32
-@@ -764,16 +768,19 @@ extern CK_RV sftk_Attribute2SSecItem(PLA
- CK_ATTRIBUTE_TYPE type);
- extern SFTKModifyType sftk_modifyType(CK_ATTRIBUTE_TYPE type,
- CK_OBJECT_CLASS inClass);
- extern PRBool sftk_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass);
- extern char *sftk_getString(SFTKObject *object, CK_ATTRIBUTE_TYPE type);
- extern void sftk_nullAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type);
- extern CK_RV sftk_GetULongAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
- CK_ULONG *longData);
-+extern CK_RV sftk_ReadAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
-+ unsigned char *data, unsigned int maxlen,
-+ unsigned int *lenp);
- extern CK_RV sftk_forceAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
- const void *value, unsigned int len);
- extern CK_RV sftk_defaultAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
- const void *value, unsigned int len);
- extern unsigned int sftk_MapTrust(CK_TRUST trust, PRBool clientAuth);
-
- extern SFTKObject *sftk_NewObject(SFTKSlot *slot);
- extern CK_RV sftk_CopyObject(SFTKObject *destObject, SFTKObject *srcObject);
-@@ -979,11 +986,15 @@ CK_FLAGS sftk_AttributeToFlags(CK_ATTRIB
- /* check the FIPS table to determine if this current operation is allowed by
- * FIPS security policy */
- PRBool sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech,
- CK_ATTRIBUTE_TYPE op, SFTKObject *source,
- CK_ULONG targetKeySize);
- /* add validation objects to the slot */
- CK_RV sftk_CreateValidationObjects(SFTKSlot *slot);
-
-+/* get the length of an MLDSASignature based on the PKCS #11 parameter set */
-+unsigned int sftk_MLDSAGetSigLen(CK_ML_DSA_PARAMETER_SET_TYPE paramSet);
-+
-+
- SEC_END_PROTOS
-
- #endif /* _PKCS11I_H_ */
-diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c
---- a/lib/softoken/pkcs11u.c
-+++ b/lib/softoken/pkcs11u.c
-@@ -742,16 +742,18 @@ sftk_modifyType(CK_ATTRIBUTE_TYPE type,
- case CKA_PRIME_2:
- case CKA_EXPONENT_1:
- case CKA_EXPONENT_2:
- case CKA_COEFFICIENT:
- case CKA_VALUE_LEN:
- case CKA_ALWAYS_SENSITIVE:
- case CKA_NEVER_EXTRACTABLE:
- case CKA_NSS_DB:
-+ case CKA_SEED:
-+ case CKA_PARAMETER_SET:
- mtype = SFTK_NEVER;
- break;
-
- /* ONCOPY */
- case CKA_TOKEN:
- case CKA_PRIVATE:
- case CKA_MODIFIABLE:
- mtype = SFTK_ONCOPY;
-@@ -809,16 +811,17 @@ sftk_isSensitive(CK_ATTRIBUTE_TYPE type,
- switch (type) {
- /* ALWAYS */
- case CKA_PRIVATE_EXPONENT:
- case CKA_PRIME_1:
- case CKA_PRIME_2:
- case CKA_EXPONENT_1:
- case CKA_EXPONENT_2:
- case CKA_COEFFICIENT:
-+ case CKA_SEED:
- return PR_TRUE;
-
- /* DEPENDS ON CLASS */
- case CKA_VALUE:
- /* PRIVATE and SECRET KEYS have SENSITIVE values */
- return (PRBool)((inClass == CKO_PRIVATE_KEY) || (inClass == CKO_SECRET_KEY));
-
- default:
-@@ -872,16 +875,38 @@ sftk_GetULongAttribute(SFTKObject *objec
- return CKR_ATTRIBUTE_VALUE_INVALID;
- }
-
- *longData = *(CK_ULONG *)attribute->attrib.pValue;
- sftk_FreeAttribute(attribute);
- return CKR_OK;
- }
-
-+CK_RV
-+sftk_ReadAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
-+ unsigned char *data, unsigned int maxLen, unsigned int *lenp)
-+{
-+ SFTKAttribute *attribute;
-+
-+ attribute = sftk_FindAttribute(object, type);
-+ if (attribute == NULL)
-+ return CKR_TEMPLATE_INCOMPLETE;
-+
-+ *lenp = attribute->attrib.ulValueLen;
-+ if (*lenp > maxLen) {
-+ /* normally would be CKR_BUFFER_TOO_SMALL, but
-+ * it used with internal buffers, so if the value is
-+ * to long, the original attribute was invalid */
-+ return CKR_ATTRIBUTE_VALUE_INVALID;
-+ }
-+ PORT_Memcpy(data, attribute->attrib.pValue, *lenp);
-+ sftk_FreeAttribute(attribute);
-+ return CKR_OK;
-+}
-+
- void
- sftk_DeleteAttributeType(SFTKObject *object, CK_ATTRIBUTE_TYPE type)
- {
- SFTKAttribute *attribute;
- attribute = sftk_FindAttribute(object, type);
- if (attribute == NULL)
- return;
- sftk_DeleteAttribute(object, attribute);
-@@ -1401,16 +1426,21 @@ static const CK_ATTRIBUTE_TYPE dhPubKeyA
- static const CK_ULONG dhPubKeyAttrsCount =
- sizeof(dhPubKeyAttrs) / sizeof(dhPubKeyAttrs[0]);
- static const CK_ATTRIBUTE_TYPE ecPubKeyAttrs[] = {
- CKA_EC_PARAMS, CKA_EC_POINT
- };
- static const CK_ULONG ecPubKeyAttrsCount =
- sizeof(ecPubKeyAttrs) / sizeof(ecPubKeyAttrs[0]);
-
-+static const CK_ATTRIBUTE_TYPE mldsaPubKeyAttrs[] = {
-+ CKA_PARAMETER_SET, CKA_VALUE
-+};
-+static const CK_ULONG mldsaPubKeyAttrsCount = PR_ARRAY_SIZE(mldsaPubKeyAttrs);
-+
- static const CK_ATTRIBUTE_TYPE commonPrivKeyAttrs[] = {
- CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER, CKA_UNWRAP, CKA_SUBJECT,
- CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_NSS_DB, CKA_PUBLIC_KEY_INFO
- };
- static const CK_ULONG commonPrivKeyAttrsCount =
- sizeof(commonPrivKeyAttrs) / sizeof(commonPrivKeyAttrs[0]);
-
- static const CK_ATTRIBUTE_TYPE rsaPrivKeyAttrs[] = {
-@@ -1438,16 +1468,21 @@ static const CK_ULONG ecPrivKeyAttrsCoun
- sizeof(ecPrivKeyAttrs) / sizeof(ecPrivKeyAttrs[0]);
-
- static const CK_ATTRIBUTE_TYPE certAttrs[] = {
- CKA_CERTIFICATE_TYPE, CKA_VALUE, CKA_SUBJECT, CKA_ISSUER, CKA_SERIAL_NUMBER
- };
- static const CK_ULONG certAttrsCount =
- sizeof(certAttrs) / sizeof(certAttrs[0]);
-
-+static const CK_ATTRIBUTE_TYPE mldsaPrivKeyAttrs[] = {
-+ CKA_PARAMETER_SET, CKA_VALUE, CKA_SEED
-+};
-+static const CK_ULONG mldsaPrivKeyAttrsCount = PR_ARRAY_SIZE(mldsaPrivKeyAttrs);
-+
- static const CK_ATTRIBUTE_TYPE trustAttrs[] = {
- CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
- CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_EMAIL_PROTECTION,
- CKA_TRUST_CODE_SIGNING, CKA_TRUST_STEP_UP_APPROVED
- };
- static const CK_ULONG trustAttrsCount =
- sizeof(trustAttrs) / sizeof(trustAttrs[0]);
-
-@@ -1531,16 +1566,22 @@ stfk_CopyTokenPrivateKey(SFTKObject *des
- case CKK_RSA:
- crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPrivKeyAttrs,
- rsaPrivKeyAttrsCount);
- break;
- case CKK_DSA:
- crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPrivKeyAttrs,
- dsaPrivKeyAttrsCount);
- break;
-+#ifdef NSS_ENABLE_ML_DSA
-+ case CKK_ML_DSA:
-+ crv = stfk_CopyTokenAttributes(destObject, src_to, mldsaPrivKeyAttrs,
-+ mldsaPrivKeyAttrsCount);
-+ break;
-+#endif
- case CKK_DH:
- crv = stfk_CopyTokenAttributes(destObject, src_to, dhPrivKeyAttrs,
- dhPrivKeyAttrsCount);
- break;
- case CKK_EC:
- crv = stfk_CopyTokenAttributes(destObject, src_to, ecPrivKeyAttrs,
- ecPrivKeyAttrsCount);
- break;
-@@ -1591,16 +1632,22 @@ stfk_CopyTokenPublicKey(SFTKObject *dest
- case CKK_RSA:
- crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPubKeyAttrs,
- rsaPubKeyAttrsCount);
- break;
- case CKK_DSA:
- crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPubKeyAttrs,
- dsaPubKeyAttrsCount);
- break;
-+#ifdef NSS_ENABLE_ML_DSA
-+ case CKK_ML_DSA:
-+ crv = stfk_CopyTokenAttributes(destObject, src_to, mldsaPubKeyAttrs,
-+ mldsaPubKeyAttrsCount);
-+ break;
-+#endif
- case CKK_DH:
- crv = stfk_CopyTokenAttributes(destObject, src_to, dhPubKeyAttrs,
- dhPubKeyAttrsCount);
- break;
- case CKK_EC:
- crv = stfk_CopyTokenAttributes(destObject, src_to, ecPubKeyAttrs,
- ecPubKeyAttrsCount);
- break;
-diff --git a/lib/softoken/sdb.c b/lib/softoken/sdb.c
---- a/lib/softoken/sdb.c
-+++ b/lib/softoken/sdb.c
-@@ -108,32 +108,32 @@ static const CK_ATTRIBUTE_TYPE known_att
- CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE,
- CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS,
- CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
- CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_HW_FEATURE_TYPE,
- CKA_RESET_ON_INIT, CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y,
- CKA_RESOLUTION, CKA_CHAR_ROWS, CKA_CHAR_COLUMNS, CKA_COLOR,
- CKA_BITS_PER_PIXEL, CKA_CHAR_SETS, CKA_ENCODING_METHODS, CKA_MIME_TYPES,
- CKA_MECHANISM_TYPE, CKA_REQUIRED_CMS_ATTRIBUTES,
-- CKA_ENCAPSULATE, CKA_DECAPSULATE, CKA_PARAMETER_SET,
-+ CKA_ENCAPSULATE, CKA_DECAPSULATE, CKA_PARAMETER_SET, CKA_SEED,
- CKA_DEFAULT_CMS_ATTRIBUTES, CKA_SUPPORTED_CMS_ATTRIBUTES,
- CKA_WRAP_TEMPLATE, CKA_UNWRAP_TEMPLATE, CKA_NSS_TRUST, CKA_NSS_URL,
- CKA_NSS_EMAIL, CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP,
- CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES,
- CKA_NSS_KRL, CKA_NSS_PQG_COUNTER, CKA_NSS_PQG_SEED,
- CKA_NSS_PQG_H, CKA_NSS_PQG_SEED_BITS, CKA_NSS_MODULE_SPEC,
- CKA_NSS_OVERRIDE_EXTENSIONS, CKA_NSS_SERVER_DISTRUST_AFTER,
- CKA_NSS_EMAIL_DISTRUST_AFTER, CKA_TRUST_DIGITAL_SIGNATURE,
- CKA_TRUST_NON_REPUDIATION, CKA_TRUST_KEY_ENCIPHERMENT,
- CKA_TRUST_DATA_ENCIPHERMENT, CKA_TRUST_KEY_AGREEMENT,
- CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN, CKA_TRUST_SERVER_AUTH,
- CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING, CKA_TRUST_EMAIL_PROTECTION,
- CKA_TRUST_IPSEC_END_SYSTEM, CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER,
- CKA_TRUST_TIME_STAMPING, CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH,
-- CKA_CERT_MD5_HASH, CKA_NSS_DB
-+ CKA_CERT_MD5_HASH, CKA_NSS_DB,
- };
-
- static const int known_attributes_size = PR_ARRAY_SIZE(known_attributes);
-
- /*
- * Note on use of sqlReadDB: Only one thread at a time may have an actual
- * operation going on given sqlite3 * database. An operation is defined as
- * the time from a sqlite3_prepare() until the sqlite3_finalize().
-@@ -1937,16 +1937,111 @@ sdb_attributeComparator(const void *a, c
- return -1;
- }
- if (*(CK_ATTRIBUTE_TYPE *)a > *(CK_ATTRIBUTE_TYPE *)b) {
- return 1;
- }
- return 0;
- }
-
-+static const char ADD_COLUMN_CMD[] = "ALTER TABLE %s ADD COLUMN %s";
-+static CK_RV
-+sdb_add_column(sqlite3 *sqlDB, const char *table, sdbDataType type,
-+ const char *typeString)
-+{
-+ char *newStr = sqlite3_mprintf(ADD_COLUMN_CMD, table, typeString);
-+ int sqlerr;
-+
-+ sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
-+ sqlite3_free(newStr);
-+ if (sqlerr != SQLITE_OK) {
-+ return sdb_mapSQLError(type, sqlerr);
-+ }
-+ return CKR_OK;
-+}
-+
-+static const char COLUMN_QUERY_CMD[] =
-+ "SELECT * FROM %s";
-+
-+/*
-+ * if our current database does not have all the attributes in the columns,
-+ * we need to add those columns or attempts to add objects with those
-+ * attributes will fail. We only need this on R/W databases because we only
-+ * add objects to R/W databases.
-+ */
-+static CK_RV
-+sdb_update_column(sqlite3 *sqlDB, const char *table, sdbDataType type)
-+{
-+ char *newStr = sqlite3_mprintf(COLUMN_QUERY_CMD, table);
-+ sqlite3_stmt *stmt;
-+ int columnCount;
-+ int sqlerr;
-+ CK_RV error;
-+
-+ if (!newStr) {
-+ return CKR_HOST_MEMORY;
-+ }
-+
-+ sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL);
-+ sqlite3_free(newStr);
-+ if (sqlerr != SQLITE_OK) {
-+ return sdb_mapSQLError(type, sqlerr);
-+ }
-+
-+ columnCount= sqlite3_column_count(stmt);
-+ /* columns include the first column, which is id, which is not
-+ * and attribute. check to make sure we have at least as many attributes
-+ * as there are id in out list. This assumes we never add some
-+ * attributes in some NSS version and not others, which is generally
-+ * true. */
-+ if (columnCount >= known_attributes_size+1) {
-+ sqlite3_finalize(stmt);
-+ return CKR_OK;
-+ }
-+ /* we have more attributes than in the database, so we know things
-+ * are missing, find what was missing */
-+ for (int i=0; i < known_attributes_size; i++) {
-+ char *typeString = sqlite3_mprintf("a%x", known_attributes[i]);
-+ PRBool found=PR_FALSE;
-+ /* this one index is important, we skip the first column (id), since
-+ * it will never match, starting at zero isn't a bug,
-+ * just inefficient */
-+ for (int j=1; j < columnCount; j++) {
-+ const char *columnName = sqlite3_column_name(stmt, j);
-+ if (columnName == NULL) {
-+ sqlite3_free(typeString);
-+ sqlite3_finalize(stmt);
-+ /* if we couldnt' get the colmun name, it's only because
-+ * we couldn't get the memory */
-+ return CKR_HOST_MEMORY;
-+ }
-+ if (PORT_Strcmp(typeString, columnName) == 0) {
-+ /* we found this one, no need to add it */
-+ found=PR_TRUE;
-+ break;
-+ }
-+ }
-+ if (found) {
-+ sqlite3_free(typeString);
-+ continue;
-+ }
-+ /* we didn't find the attribute, so now add it */
-+ error = sdb_add_column(sqlDB, table, type, typeString);
-+ if (error != CKR_OK) {
-+ sqlite3_free(typeString);
-+ sqlite3_finalize(stmt);
-+ return error;
-+ }
-+ sqlite3_free(typeString);
-+ }
-+ sqlite3_finalize(stmt);
-+ return CKR_OK;
-+}
-+
-+
- /*
- * initialize a single database
- */
- static const char INIT_CMD[] =
- "CREATE TABLE %s (id PRIMARY KEY UNIQUE ON CONFLICT ABORT%s)";
-
- CK_RV
- sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate,
-@@ -2081,17 +2176,26 @@ sdb_init(char *dbname, char *table, sdbD
- goto loser;
- }
- sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
- sqlite3_free(newStr);
- if (sqlerr != SQLITE_OK) {
- error = sdb_mapSQLError(type, sqlerr);
- goto loser;
- }
-+ } else if (flags != SDB_RDONLY) {
-+ /* check to see if we need to update the scheme, only need to
-+ * do this if we open r/w, since that's the only case where
-+ * it's a problem is attribute colmumn are missing */
-+ error = sdb_update_column(sqlDB, table, type);
-+ if (error != CKR_OK) {
-+ goto loser;
-+ }
- }
-+
- /*
- * detect the case where we have created the database, but have
- * not yet updated it.
- *
- * We only check the Key database because only the key database has
- * a metaData table. The metaData table is created when a password
- * is set, or in the case of update, when a password is supplied.
- * If no key database exists, then the update would have happened immediately
-diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c
---- a/lib/softoken/sftkdb.c
-+++ b/lib/softoken/sftkdb.c
-@@ -91,16 +91,17 @@ sftkdb_isPrivateAttribute(CK_ATTRIBUTE_T
- switch (type) {
- case CKA_VALUE:
- case CKA_PRIVATE_EXPONENT:
- case CKA_PRIME_1:
- case CKA_PRIME_2:
- case CKA_EXPONENT_1:
- case CKA_EXPONENT_2:
- case CKA_COEFFICIENT:
-+ case CKA_SEED:
- return PR_TRUE;
- default:
- break;
- }
- return PR_FALSE;
- }
-
- /* These attributes must be authenticated with an hmac. */
-diff --git a/lib/util/manifest.mn b/lib/util/manifest.mn
---- a/lib/util/manifest.mn
-+++ b/lib/util/manifest.mn
-@@ -5,16 +5,17 @@
- CORE_DEPTH = ../..
-
- EXPORTS = \
- base64.h \
- ciferfam.h \
- eccutil.h \
- hasht.h \
- kyber.h \
-+ ml_dsat.h \
- nssb64.h \
- nssb64t.h \
- nsshash.h \
- nsslocks.h \
- nssilock.h \
- nssilckt.h \
- nssrwlk.h \
- nssrwlkt.h \
-diff --git a/lib/util/ml_dsat.h b/lib/util/ml_dsat.h
-new file mode 100644
---- /dev/null
-+++ b/lib/util/ml_dsat.h
-@@ -0,0 +1,31 @@
-+/* This Source Code Form is subject to the terms of the Mozilla Public
-+ * License, v. 2.0. If a copy of the MPL was not distributed with this
-+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-+
-+#ifndef ML_DSAT_H
-+#define ML_DSAT_H
-+
-+// ML_DSA Key and signature sizes, independent of implementaion
-+
-+// ml_dsa_44
-+#define ML_DSA_44_PUBLICKEY_LEN 1312
-+#define ML_DSA_44_PRIVATEKEY_LEN 2560
-+#define ML_DSA_44_SIGNATURE_LEN 2420
-+
-+// ml_dsa_65
-+#define ML_DSA_65_PUBLICKEY_LEN 1952
-+#define ML_DSA_65_PRIVATEKEY_LEN 4032
-+#define ML_DSA_65_SIGNATURE_LEN 3309
-+
-+// ml_dsa_87
-+#define ML_DSA_87_PUBLICKEY_LEN 2592
-+#define ML_DSA_87_PRIVATEKEY_LEN 4896
-+#define ML_DSA_87_SIGNATURE_LEN 4627
-+
-+// the max defines and common defines
-+#define MAX_ML_DSA_PRIVATE_KEY_LEN ML_DSA_87_PRIVATEKEY_LEN
-+#define MAX_ML_DSA_PUBLIC_KEY_LEN ML_DSA_87_PUBLICKEY_LEN
-+#define MAX_ML_DSA_SIGNATURE_LEN ML_DSA_87_SIGNATURE_LEN
-+#define ML_DSA_SEED_LEN 32
-+
-+#endif /* ML_DSAT_H */
-diff --git a/lib/util/pkcs11n.h b/lib/util/pkcs11n.h
---- a/lib/util/pkcs11n.h
-+++ b/lib/util/pkcs11n.h
-@@ -108,16 +108,19 @@
- #define CKA_NSS_EMAIL_DISTRUST_AFTER (CKA_NSS + 36)
-
- #define CKA_NSS_VALIDATION_TYPE (CKA_NSS + 36)
- #define CKA_NSS_VALIDATION_VERSION (CKA_NSS + 37)
- #define CKA_NSS_VALIDATION_LEVEL (CKA_NSS + 38)
- #define CKA_NSS_VALIDATION_MODULE_ID (CKA_NSS + 39)
-
- #define CKA_NSS_PARAMETER_SET (CKA_NSS + 40)
-+/* this is an intern NSS signalling attribute, you'll
-+ * never see it in an application accessible object */
-+#define CKA_NSS_SEED_OK (CKA_NSS + 41)
-
- /*
- * Trust attributes:
- *
- * If trust goes standard, these probably will too. So I'll
- * put them all in one place.
- */
-
-diff --git a/lib/util/pkcs11t.h b/lib/util/pkcs11t.h
---- a/lib/util/pkcs11t.h
-+++ b/lib/util/pkcs11t.h
-@@ -764,16 +764,35 @@ typedef CK_ULONG CK_ML_KEM_PARAMETER_SET
- #define CKP_ML_KEM_512 0x00000001UL
- #define CKP_ML_KEM_768 0x00000002UL
- #define CKP_ML_KEM_1024 0x00000003UL
- #define CKA_PARAMETER_SET 0x0000061dUL
- #define CKA_ENCAPSULATE 0x00000633UL
- #define CKA_DECAPSULATE 0x00000634UL
- #define CKF_DECAPSULATE 0x20000000UL
- #define CKF_ENCAPSULATE 0x10000000UL
-+/* mldsa support */
-+#define CKK_ML_DSA 0x0000004aUL
-+#define CKM_ML_DSA_KEY_PAIR_GEN 0x0000001cUL
-+#define CKM_ML_DSA 0x0000001dUL
-+typedef CK_ULONG CK_ML_DSA_PARAMETER_SET_TYPE;
-+#define CKP_ML_DSA_44 0x00000001UL
-+#define CKP_ML_DSA_65 0x00000002UL
-+#define CKP_ML_DSA_87 0x00000003UL
-+#define CKA_SEED 0x00000637UL
-+typedef CK_ULONG CK_HEDGE_TYPE;
-+#define CKH_HEDGE_PREFERRED 0x00000000UL
-+#define CKH_HEDGE_REQUIRED 0x00000001UL
-+#define CKH_DETERMINISTIC_REQUIRED 0x00000002UL
-+typedef struct CK_SIGN_ADDITIONAL_CONTEXT {
-+ CK_HEDGE_TYPE hedgeVariant;
-+ CK_BYTE_PTR pContext;
-+ CK_ULONG ulContextLen;
-+} CK_SIGN_ADDITIONAL_CONTEXT;
-+
-
- #define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020UL
- #define CKM_DH_PKCS_DERIVE 0x00000021UL
-
- /* CKM_X9_42_DH_KEY_PAIR_GEN, CKM_X9_42_DH_DERIVE,
- * CKM_X9_42_DH_HYBRID_DERIVE, and CKM_X9_42_MQV_DERIVE are new for
- * v2.11 */
- #define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030UL
-diff --git a/lib/util/secoid.c b/lib/util/secoid.c
---- a/lib/util/secoid.c
-+++ b/lib/util/secoid.c
-@@ -34,17 +34,17 @@ const char __nss_util_version[] = "Versi
- #define MISSI_KEA_DSS MISSI, 0x14
- #define MISSI_DSS MISSI, 0x13
- #define MISSI_KEA MISSI, 0x0a
- #define MISSI_ALT_KEA MISSI, 0x16
-
- #define NISTALGS USGOV, 3, 4
- #define AES NISTALGS, 1
- #define SHAXXX NISTALGS, 2
--#define DSA2 NISTALGS, 3
-+#define NISTSIGALGS NISTALGS, 3
-
- /**
- ** The Netscape OID space is allocated by Terry Hayes. If you need
- ** a piece of the space, contact him at thayes@netscape.com.
- **/
-
- /* Netscape Communications Corporation Object ID space */
- /* { 2 16 840 1 113730 } */
-@@ -420,18 +420,21 @@ CONST_OID pkcs12V1SafeContentsBag[] = {
-
- /* The following encoding is INCORRECT, but correcting it would create a
- * duplicate OID in the table. So, we will leave it alone.
- */
- CONST_OID pkcs12KeyUsageAttr[] = { 2, 5, 29, 15 };
-
- CONST_OID ansix9DSASignature[] = { ANSI_X9_ALGORITHM, 0x01 };
- CONST_OID ansix9DSASignaturewithSHA1Digest[] = { ANSI_X9_ALGORITHM, 0x03 };
--CONST_OID nistDSASignaturewithSHA224Digest[] = { DSA2, 0x01 };
--CONST_OID nistDSASignaturewithSHA256Digest[] = { DSA2, 0x02 };
-+CONST_OID nistDSASignaturewithSHA224Digest[] = { NISTSIGALGS, 0x01 };
-+CONST_OID nistDSASignaturewithSHA256Digest[] = { NISTSIGALGS, 0x02 };
-+CONST_OID nistMLDSASignatureParm44[] = { NISTSIGALGS, 17 };
-+CONST_OID nistMLDSASignatureParm65[] = { NISTSIGALGS, 18 };
-+CONST_OID nistMLDSASignatureParm87[] = { NISTSIGALGS, 19 };
-
- /* verisign OIDs */
- CONST_OID verisignUserNotices[] = { VERISIGN, 1, 7, 1, 1 };
-
- /* pkix OIDs */
- CONST_OID pkixCPSPointerQualifier[] = { PKIX_POLICY_QUALIFIERS, 1 };
- CONST_OID pkixUserNoticeQualifier[] = { PKIX_POLICY_QUALIFIERS, 2 };
-
-@@ -1901,17 +1904,22 @@ const static SECOidData oids[SEC_OID_TOT
- ODE(SEC_OID_TLS_REQUIRE_EMS,
- "TLS Require EMS", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
- /* this will change upstream. for now apps shouldn't use it */
- /* we need it for the policy code. */
- ODE(SEC_OID_PRIVATE_1,
- "ML-KEM-768+SECP256 key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
- ODE(SEC_OID_PRIVATE_2,
- "ML-KEM-1024+SECP256 key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
--
-+ OD(nistMLDSASignatureParm44, SEC_OID_PRIVATE_3, "ML-DSA-44",
-+ CKM_ML_DSA, INVALID_CERT_EXTENSION),
-+ OD(nistMLDSASignatureParm65, SEC_OID_PRIVATE_4, "ML-DSA-65",
-+ CKM_ML_DSA, INVALID_CERT_EXTENSION),
-+ OD(nistMLDSASignatureParm87, SEC_OID_PRIVATE_5, "ML-DSA-87",
-+ CKM_ML_DSA, INVALID_CERT_EXTENSION),
- };
-
- /* PRIVATE EXTENDED SECOID Table
- * This table is private. Its structure is opaque to the outside.
- * It is indexed by the same SECOidTag as the oids table above.
- * Every member of this struct must have accessor functions (set, get)
- * and those functions must operate by value, not by reference.
- * The addresses of the contents of this table must not be exposed
-diff --git a/lib/util/secoidt.h b/lib/util/secoidt.h
---- a/lib/util/secoidt.h
-+++ b/lib/util/secoidt.h
-@@ -536,16 +536,19 @@ typedef enum {
-
- SEC_OID_TLS_REQUIRE_EMS = 390,
-
- /* these will change upstream. for now apps shouldn't use it */
- /* give it an obscure name here */
-
- SEC_OID_PRIVATE_1 = 391,
- SEC_OID_PRIVATE_2 = 392,
-+ SEC_OID_PRIVATE_3 = 393,
-+ SEC_OID_PRIVATE_4 = 394,
-+ SEC_OID_PRIVATE_5 = 395,
-
- SEC_OID_TOTAL
- } SECOidTag;
-
- #define SEC_OID_SECG_EC_SECP192R1 SEC_OID_ANSIX962_EC_PRIME192V1
- #define SEC_OID_SECG_EC_SECP256R1 SEC_OID_ANSIX962_EC_PRIME256V1
- #define SEC_OID_PKCS12_KEY_USAGE SEC_OID_X509_KEY_USAGE
-
diff --git a/nss-3.112-add-ml-dsa-ssl-support-dsa.patch b/nss-3.112-add-ml-dsa-ssl-support-dsa.patch
deleted file mode 100644
index 195bf03..0000000
--- a/nss-3.112-add-ml-dsa-ssl-support-dsa.patch
+++ /dev/null
@@ -1,4323 +0,0 @@
-diff --git a/cmd/certutil/certutil.c b/cmd/certutil/certutil.c
---- a/cmd/certutil/certutil.c
-+++ b/cmd/certutil/certutil.c
-@@ -298,20 +298,17 @@ CertReq(SECKEYPrivateKey *privk, SECKEYP
- if (rv != SECSuccess) {
- PORT_FreeArena(arena, PR_FALSE);
- SECU_PrintError(progName, "unable to set algorithm ID");
- return SECFailure;
- }
- } else {
- /* sigh, we need to create a new SEC_GetSignatureAlgorithOidTag()
- * that takes a public key and one that takes a private key */
-- if (keyType == mldsaKey) {
-- hashAlgTag = pubk->u.mldsa.params;
-- }
-- signAlgTag = SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag);
-+ signAlgTag = SECU_GetSignatureAlgorithmFromPublicKey(pubk, hashAlgTag);
- if (signAlgTag == SEC_OID_UNKNOWN) {
- PORT_FreeArena(arena, PR_FALSE);
- SECU_PrintError(progName, "unknown Key or Hash type");
- return SECFailure;
- }
- rv = SECOID_SetAlgorithmID(arena, &signAlg, signAlgTag, 0);
- if (rv != SECSuccess) {
- PORT_FreeArena(arena, PR_FALSE);
-@@ -2056,39 +2053,16 @@ MakeV1Cert(CERTCertDBHandle *handle,
- }
- if (issuerCert) {
- CERT_DestroyCertificate(issuerCert);
- }
-
- return (cert);
- }
-
--/* sigh look up the ml-dsa oid by string */
--static SECOidTag
--FindTagFromString(char *cipherString)
--{
-- SECOidTag tag;
-- SECOidData *oid;
--
-- /* future enhancement: accept dotted oid spec? */
--
-- for (tag = 1; (oid = SECOID_FindOIDByTag(tag)) != NULL; tag++) {
-- /* only interested in oids that we actually understand */
-- if (oid->mechanism == CKM_INVALID_MECHANISM) {
-- continue;
-- }
-- if (PORT_Strcasecmp(oid->desc, cipherString) != 0) {
-- continue;
-- }
-- return tag;
-- }
-- return SEC_OID_UNKNOWN;
--}
--
--
- static SECStatus
- SetSignatureAlgorithm(PLArenaPool *arena,
- SECAlgorithmID *signAlg,
- SECAlgorithmID *spkiAlg,
- SECOidTag hashAlgTag,
- SECKEYPrivateKey *privKey,
- PRBool pssSign)
- {
-@@ -2119,72 +2093,23 @@ SetSignatureAlgorithm(PLArenaPool *arena
- }
- rv = SECOID_SetAlgorithmID(arena, signAlg,
- SEC_OID_PKCS1_RSA_PSS_SIGNATURE,
- params);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "Could not set signature algorithm id.");
- return rv;
- }
-- } else if (privKey->keyType == mldsaKey) {
-- /* sigh, we need toexport SECKEY_GetParameterSet(), for now
-- * just do it inline */
-- /* this is temp code until we fix it correctly upstream. Don't
-- * push this upstream */
-- SECOidTag algID;
-- SECItem item;
-- CK_ULONG paramSet;
--
-- rv = PK11_ReadRawAttribute(PK11_TypePrivKey, privKey,
-- CKA_PARAMETER_SET, &item);
--
-- if (rv != SECSuccess) {
-- SECU_PrintError(progName, "missing parameter set for ml-dsa key.");
-- return SECFailure;
-- }
-- if (item.len != sizeof (paramSet)) {
-- SECU_PrintError(progName, "corrupted parameter set for ml-dsa key.");
-- PORT_Free(item.data);
-- return SECFailure;
-- }
-- paramSet = *(CK_ULONG *)item.data;
-- PORT_Free(item.data);
-- switch (paramSet) {
-- case CKP_ML_DSA_44:
-- algID = FindTagFromString("ML-DSA-44");
-- break;
-- case CKP_ML_DSA_65:
-- algID = FindTagFromString("ML-DSA-65");
-- break;
-- case CKP_ML_DSA_87:
-- algID = FindTagFromString("ML-DSA-87");
-- break;
-- default:
-- algID = SEC_OID_UNKNOWN;
-- break;
-- }
-- if (algID == SEC_OID_UNKNOWN) {
-- PORT_SetError(SEC_ERROR_INVALID_KEY);
-- SECU_PrintError(progName, "invalid parameter set for ml-dsa key.");
-- return SECFailure;
-- }
--
-- rv = SECOID_SetAlgorithmID(arena, signAlg, algID, 0);
-- if (rv != SECSuccess) {
-- SECU_PrintError(progName, "Could not set signature algorithm id.");
-- return rv;
-- }
- } else {
-- KeyType keyType = SECKEY_GetPrivateKeyType(privKey);
- SECOidTag algID;
-
- /* first, try to get the ParameterSet from the key, If the
- * key as a parameter set, use it, otherwise fall back to
- * SEC_GetSignatureAlgorithmoidTag */
-- algID = SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag);
-+ algID = SECU_GetSignatureAlgorithmFromPrivateKey(privKey, hashAlgTag);
- if (algID == SEC_OID_UNKNOWN) {
- SECU_PrintError(progName, "Unknown key or hash type for issuer.");
- return SECFailure;
- }
- rv = SECOID_SetAlgorithmID(arena, signAlg, algID, 0);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "Could not set signature algorithm id.");
- return rv;
-diff --git a/cmd/crmf-cgi/crmfcgi.c b/cmd/crmf-cgi/crmfcgi.c
---- a/cmd/crmf-cgi/crmfcgi.c
-+++ b/cmd/crmf-cgi/crmfcgi.c
-@@ -377,18 +377,17 @@ createNewCert(CERTCertificate **issuedCe
- rv = addExtensions(newCert, certReq);
- if (rv != NO_ERROR) {
- goto loser;
- }
- issuerPrivKey = PK11_FindKeyByAnyCert(issuerCert, varTable);
- if (issuerPrivKey == NULL) {
- rv = COULD_NOT_FIND_ISSUER_PRIVATE_KEY;
- }
-- signTag = SEC_GetSignatureAlgorithmOidTag(issuerPrivatekey->keytype,
-- SEC_OID_UNKNOWN);
-+ signTag = SECU_GetSignatureAlgorithmFromPrivateKey(issuerPrivatekey, SEC_OID_UNKNOWN);
- if (signTag == SEC_OID_UNKNOWN) {
- rv = UNSUPPORTED_SIGN_OPERATION_FOR_ISSUER;
- goto loser;
- }
- srv = SECOID_SetAlgorithmID(newCert->arena, &newCert->signature,
- signTag, 0);
- if (srv != SECSuccess) {
- rv = ERROR_SETTING_SIGN_ALG;
-diff --git a/cmd/lib/secutil.c b/cmd/lib/secutil.c
---- a/cmd/lib/secutil.c
-+++ b/cmd/lib/secutil.c
-@@ -3854,16 +3854,94 @@ SECU_StoreCRL(PK11SlotInfo *slot, SECIte
- }
- if (!outFile && !slot) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- return SECSuccess;
- }
-
-+/* look up the an oid by string */
-+SECOidTag
-+SECU_FindTagFromString(char *cipherString)
-+{
-+ SECOidTag tag;
-+ SECOidData *oid;
-+
-+ /* future enhancement: accept dotted oid spec? */
-+
-+ for (tag = 1; (oid = SECOID_FindOIDByTag(tag)) != NULL; tag++) {
-+ /* only interested in oids that we actually understand */
-+ if (oid->mechanism == CKM_INVALID_MECHANISM) {
-+ continue;
-+ }
-+ if (PORT_Strcasecmp(oid->desc, cipherString) != 0) {
-+ continue;
-+ }
-+ return tag;
-+ }
-+ return SEC_OID_UNKNOWN;
-+}
-+
-+
-+/* sigh, we need toexport SECKEY_GetParameterSet(), for now
-+ * just do it inline */
-+/* this is temp code until we fix it correctly upstream. Don't
-+ * push this upstream */
-+SECOidTag
-+SECU_GetSignatureAlgorithmFromPrivateKey(SECKEYPrivateKey *privKey, SECOidTag hashAlg)
-+{
-+ SECItem item;
-+ CK_ULONG paramSet;
-+ SECStatus rv;
-+
-+ /* don't modify hashAlg if we aren't a DSA key */
-+ if (privKey->keyType != mldsaKey) {
-+ return SEC_GetSignatureAlgorithmOidTag(privKey->keyType, hashAlg);
-+ }
-+
-+ rv = PK11_ReadRawAttribute(PK11_TypePrivKey, privKey,
-+ CKA_PARAMETER_SET, &item);
-+
-+ if (rv != SECSuccess) {
-+ return SEC_OID_UNKNOWN;
-+ }
-+ if (item.len != sizeof (paramSet)) {
-+ PORT_Free(item.data);
-+ PORT_SetError(SEC_ERROR_INVALID_KEY);
-+ return SEC_OID_UNKNOWN;
-+ }
-+ paramSet = *(CK_ULONG *)item.data;
-+ PORT_Free(item.data);
-+ switch (paramSet) {
-+ case CKP_ML_DSA_44:
-+ return SECU_FindTagFromString("ML-DSA-44");
-+ break;
-+ case CKP_ML_DSA_65:
-+ return SECU_FindTagFromString("ML-DSA-65");
-+ break;
-+ case CKP_ML_DSA_87:
-+ return SECU_FindTagFromString("ML-DSA-87");
-+ break;
-+ default:
-+ PORT_SetError(SEC_ERROR_INVALID_KEY);
-+ break;
-+ }
-+ return SEC_OID_UNKNOWN;
-+}
-+
-+SECOidTag
-+SECU_GetSignatureAlgorithmFromPublicKey(SECKEYPublicKey *pubKey, SECOidTag hashAlg)
-+{
-+ if (pubKey->keyType == mldsaKey) {
-+ return pubKey->u.mldsa.params;
-+ }
-+ return SEC_GetSignatureAlgorithmOidTag(pubKey->keyType, hashAlg);
-+}
-+
- SECStatus
- SECU_SignAndEncodeCRL(CERTCertificate *issuer, CERTSignedCrl *signCrl,
- SECOidTag hashAlgTag, SignAndEncodeFuncExitStat *resCode)
- {
- SECItem der;
- SECKEYPrivateKey *caPrivateKey = NULL;
- SECStatus rv;
- PLArenaPool *arena;
-@@ -3879,17 +3957,17 @@ SECU_SignAndEncodeCRL(CERTCertificate *i
- arena = signCrl->arena;
-
- caPrivateKey = PK11_FindKeyByAnyCert(issuer, NULL);
- if (caPrivateKey == NULL) {
- *resCode = noKeyFound;
- return SECFailure;
- }
-
-- algID = SEC_GetSignatureAlgorithmOidTag(caPrivateKey->keyType, hashAlgTag);
-+ algID = SECU_GetSignatureAlgorithmFromPrivateKey(caPrivateKey, hashAlgTag);
- if (algID == SEC_OID_UNKNOWN) {
- *resCode = noSignatureMatch;
- rv = SECFailure;
- goto done;
- }
-
- if (!signCrl->crl.signatureAlg.parameters.data) {
- rv = SECOID_SetAlgorithmID(arena, &signCrl->crl.signatureAlg, algID, 0);
-@@ -4379,16 +4457,19 @@ schemeNameToScheme(const char *name)
- compareScheme(ed448);
- compareScheme(rsa_pss_pss_sha256);
- compareScheme(rsa_pss_pss_sha384);
- compareScheme(rsa_pss_pss_sha512);
- compareScheme(dsa_sha1);
- compareScheme(dsa_sha256);
- compareScheme(dsa_sha384);
- compareScheme(dsa_sha512);
-+ compareScheme(mldsa44);
-+ compareScheme(mldsa65);
-+ compareScheme(mldsa87);
-
- #undef compareScheme
-
- return ssl_sig_none;
- }
-
- SECStatus
- parseSigSchemeList(const char *arg, const SSLSignatureScheme **enabledSigSchemes,
-diff --git a/cmd/lib/secutil.h b/cmd/lib/secutil.h
---- a/cmd/lib/secutil.h
-+++ b/cmd/lib/secutil.h
-@@ -457,12 +457,18 @@ extern int ffs(unsigned int i);
- #endif
-
- /* Finds certificate by searching it in the DB or by examinig file
- * in the local directory. */
- CERTCertificate *
- SECU_FindCertByNicknameOrFilename(CERTCertDBHandle *handle,
- char *name, PRBool ascii,
- void *pwarg);
-+
-+/* temparary libraries for ml-dsa support */
-+SECOidTag SECu_FindTagFromString(char *cipherString);
-+SECOidTag SECU_GetSignatureAlgorithmFromPrivateKey(SECKEYPrivateKey *privKey, SECOidTag hashAlg);
-+SECOidTag SECU_GetSignatureAlgorithmFromPublicKey(SECKEYPublicKey *privKey, SECOidTag hashAlg);
-+
- #include "secerr.h"
- #include "sslerr.h"
-
- #endif /* _SEC_UTIL_H_ */
-diff --git a/cmd/selfserv/selfserv.c b/cmd/selfserv/selfserv.c
---- a/cmd/selfserv/selfserv.c
-+++ b/cmd/selfserv/selfserv.c
-@@ -156,24 +156,25 @@ static PRLogModuleInfo *lm;
- fflush(stderr); \
- }
- #define VLOG(arg) PR_LOG(lm, PR_LOG_DEBUG, arg)
-
- static void
- PrintUsageHeader(const char *progName)
- {
- fprintf(stderr,
-- "Usage: %s -n rsa_nickname -p port [-BDENRZbjlmrsuvx] [-w password]\n"
-+ "Usage: %s -n cert_nickname -p port [-BDENRZbjlmrsuvx] [-w password]\n"
- " [-t threads] [-i pid_file] [-c ciphers] [-Y] [-d dbdir] [-g numblocks]\n"
- " [-f password_file] [-L [seconds]] [-M maxProcs] [-P dbprefix]\n"
- " [-V [min-version]:[max-version]] [-a sni_name]\n"
- " [ T ] [-A ca]\n"
-- " [-C SSLCacheEntries] [-S dsa_nickname] [-Q]\n"
-- " [-I groups] [-J signatureschemes] [-e ec_nickname]\n"
-+ " [-C SSLCacheEntries] [-S cert_nickname ] [-Q]\n"
-+ " [-I groups] [-J signatureschemes] [-e cer_nickname]\n"
- " -U [0|1] -H [0|1|2] -W [0|1] [-z externalPsk] -q\n"
-+ " -n is for the primary cert, -e are for additional certs -S is deprecated\n"
- "\n",
- progName);
- }
-
- static void
- PrintParameterUsage()
- {
- fputs(
-@@ -234,16 +235,17 @@ PrintParameterUsage()
- "x25519mlkem768, secp256r1mlkem768, secp384r1mlkem1024\n"
- "-J comma separated list of enabled signature schemes in preference order.\n"
- " The following values are valid:\n"
- " rsa_pkcs1_sha1, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,\n"
- " ecdsa_sha1, ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384,\n"
- " ecdsa_secp521r1_sha512,\n"
- " rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512,\n"
- " rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512,\n"
-+ " mldsa44, mldsa65, mldsa87\n"
- "-Z enable 0-RTT (for TLS 1.3; also use -u)\n"
- "-E enable post-handshake authentication\n"
- " (for TLS 1.3; only has an effect with 3 or more -r options)\n"
- "-x Export and print keying material after successful handshake\n"
- " The argument is a comma separated list of exporters in the form:\n"
- " LABEL[:OUTPUT-LENGTH[:CONTEXT]]\n"
- " where LABEL and CONTEXT can be either a free-form string or\n"
- " a hex string if it is preceded by \"0x\"; OUTPUT-LENGTH\n"
-@@ -2923,17 +2925,17 @@ main(int argc, char **argv)
- }
- if (listen_sock) {
- PR_Close(listen_sock);
- }
- exit(0);
- }
-
- if (certNicknameIndex == 0) {
-- fprintf(stderr, "Must specify at least one certificate nickname using '-n' (RSA), '-S' (DSA), or 'e' (EC).\n");
-+ fprintf(stderr, "Must specify at least one certificate nickname using '-n' or '-e' or '-S' (deprecated) \n");
- fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
- exit(6);
- }
-
- if (port == 0) {
- fprintf(stderr, "Required argument 'port' must be non-zero value\n");
- exit(7);
- }
-diff --git a/cmd/signtool/certgen.c b/cmd/signtool/certgen.c
---- a/cmd/signtool/certgen.c
-+++ b/cmd/signtool/certgen.c
-@@ -433,17 +433,17 @@ sign_cert(CERTCertificate *cert, SECKEYP
- {
- SECStatus rv;
-
- SECItem der2;
- SECItem *result2;
-
- SECOidTag alg = SEC_OID_UNKNOWN;
-
-- alg = SEC_GetSignatureAlgorithmOidTag(privk->keyType, SEC_OID_UNKNOWN);
-+ alg = SECU_GetSignatureAlgorithmFromPrivateKey(privk, SEC_OID_UNKNOWN);
- if (alg == SEC_OID_UNKNOWN) {
- FatalError("Unknown key type");
- }
-
- rv = SECOID_SetAlgorithmID(cert->arena, &cert->signature, alg, 0);
-
- if (rv != SECSuccess) {
- PR_fprintf(errorFD, "%s: unable to set signature alg id\n",
-diff --git a/cmd/strsclnt/strsclnt.c b/cmd/strsclnt/strsclnt.c
---- a/cmd/strsclnt/strsclnt.c
-+++ b/cmd/strsclnt/strsclnt.c
-@@ -169,17 +169,18 @@ Usage(void)
- " This takes a comma separated list of signature schemes in preference\n"
- " order.\n"
- " Possible values are:\n"
- " rsa_pkcs1_sha1, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,\n"
- " ecdsa_sha1, ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384,\n"
- " ecdsa_secp521r1_sha512,\n"
- " rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512,\n"
- " rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512,\n"
-- " dsa_sha1, dsa_sha256, dsa_sha384, dsa_sha512\n",
-+ " dsa_sha1, dsa_sha256, dsa_sha384, dsa_sha512\n"
-+ " mldsa44, mldsa65, mldsa87\n",
- progName);
- exit(1);
- }
-
- static void
- errWarn(char *funcString)
- {
- PRErrorCode perr = PR_GetError();
-diff --git a/cmd/tstclnt/tstclnt.c b/cmd/tstclnt/tstclnt.c
---- a/cmd/tstclnt/tstclnt.c
-+++ b/cmd/tstclnt/tstclnt.c
-@@ -136,16 +136,19 @@ signatureSchemeName(SSLSignatureScheme s
- strcase(ed448);
- strcase(rsa_pss_pss_sha256);
- strcase(rsa_pss_pss_sha384);
- strcase(rsa_pss_pss_sha512);
- strcase(dsa_sha1);
- strcase(dsa_sha256);
- strcase(dsa_sha384);
- strcase(dsa_sha512);
-+ strcase(mldsa44);
-+ strcase(mldsa65);
-+ strcase(mldsa87);
- #undef strcase
- case ssl_sig_rsa_pkcs1_sha1md5:
- return "RSA PKCS#1 SHA1+MD5";
- default:
- break;
- }
- return "Unknown Scheme";
- }
-@@ -318,17 +321,17 @@ PrintParameterUsage()
- "-I", "", "", "");
- fprintf(stderr, "%-20s Comma separated list of signature schemes in preference order.\n"
- "%-20s The following values are valid:\n"
- "%-20s rsa_pkcs1_sha1, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,\n"
- "%-20s ecdsa_sha1, ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384,\n"
- "%-20s ecdsa_secp521r1_sha512,\n"
- "%-20s rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512,\n"
- "%-20s rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512,\n"
-- "%-20s dsa_sha1, dsa_sha256, dsa_sha384, dsa_sha512\n",
-+ "%-20s dsa_sha1, dsa_sha256, dsa_sha384, dsa_sha512 mldsa44 mldsa65 mldsa87\n",
- "-J", "", "", "", "", "", "", "");
- fprintf(stderr, "%-20s Use DTLS\n", "-P {client, server}");
- fprintf(stderr, "%-20s Exit after handshake\n", "-Q");
- fprintf(stderr, "%-20s Use Encrypted Client Hello with the given Base64-encoded ECHConfigs\n", "-N");
- fprintf(stderr, "%-20s Enable Encrypted Client Hello GREASEing with the given padding size (0-255) \n", "-i");
- fprintf(stderr, "%-20s Enable post-handshake authentication\n"
- "%-20s for TLS 1.3; need to specify -n\n",
- "-E", "");
-diff --git a/doc/certutil.xml b/doc/certutil.xml
---- a/doc/certutil.xml
-+++ b/doc/certutil.xml
-@@ -271,17 +271,17 @@ Add one or multiple extensions that cert
- Pass an input file to the command. Depending on the command option, an input file can be a specific certificate, a certificate request file, or a batch file of commands.
-
-
-
- -k key-type-or-id
-
- Specify the type or specific ID of a key.
-
-- The valid key type options are rsa, dsa, ec, or all. The default
-+ The valid key type options are rsa, dsa, ec, mldsa or all. The default
- value is rsa. Specifying the type of key can avoid mistakes caused by
- duplicate nicknames. Giving a key type generates a new key pair;
- giving the ID of an existing key reuses that key pair (which is
- required to renew certificates).
-
-
-
-
-@@ -312,17 +312,17 @@ Add one or multiple extensions that cert
-
-
-
- -p phone
- Specify a contact telephone number to include in new certificates or certificate requests. Bracket this string with quotation marks if it contains spaces.
-
-
-
-- -q pqgfile or curve-name
-+ -q pqgfile or curve-name or ml-dsa-parameter-set
-
- Read an alternate PQG value from the specified file when generating DSA key pairs. If this argument is not used, certutil generates its own PQG value. PQG files are created with a separate DSA utility.
- Elliptic curve name is one of the ones from nistp256, nistp384, nistp521, curve25519.
-
- If a token is available that supports more curves, the foolowing curves are supported as well:
- sect163k1, nistk163, sect163r1, sect163r2,
- nistb163, sect193r1, sect193r2, sect233k1, nistk233,
- sect233r1, nistb233, sect239k1, sect283k1, nistk283,
-@@ -336,16 +336,17 @@ Add one or multiple extensions that cert
- c2pnb163v2, c2pnb163v3, c2pnb176v1, c2tnb191v1,
- c2tnb191v2, c2tnb191v3,
- c2pnb208w1, c2tnb239v1, c2tnb239v2, c2tnb239v3,
- c2pnb272w1, c2pnb304w1,
- c2tnb359w1, c2pnb368w1, c2tnb431r1, secp112r1,
- secp112r2, secp128r1, secp128r2, sect113r1, sect113r2,
- sect131r1, sect131r2
-
-+ ML-DSA parameter set is one of ml-dsa-44, ml-dsa-65, ml-dsa-87.
-
-
-
-
-
- -r
- Display a certificate's binary DER encoding when listing information about that certificate with the -L option.
-
-diff --git a/gtests/ssl_gtest/ssl_auth_unittest.cc b/gtests/ssl_gtest/ssl_auth_unittest.cc
---- a/gtests/ssl_gtest/ssl_auth_unittest.cc
-+++ b/gtests/ssl_gtest/ssl_auth_unittest.cc
-@@ -2289,9 +2289,31 @@ INSTANTIATE_TEST_SUITE_P(
- INSTANTIATE_TEST_SUITE_P(
- SignatureSchemeEcdsaSha1, TlsSignatureSchemeConfiguration,
- ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
- TlsConnectTestBase::kTlsV12,
- ::testing::Values(TlsAgent::kServerEcdsa256,
- TlsAgent::kServerEcdsa384),
- ::testing::Values(ssl_auth_ecdsa),
- ::testing::Values(ssl_sig_ecdsa_sha1)));
-+// ML-DSA is only allowed to be used in TLS 1.3 or greater
-+INSTANTIATE_TEST_SUITE_P(
-+ SignatureSchemeMlDsa44Tls13, TlsSignatureSchemeConfiguration,
-+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
-+ TlsConnectTestBase::kTlsV13,
-+ ::testing::Values(TlsAgent::kServerMlDsa44),
-+ ::testing::Values(ssl_auth_mldsa44),
-+ ::testing::Values(ssl_sig_mldsa44)));
-+INSTANTIATE_TEST_SUITE_P(
-+ SignatureSchemeMlDsa65Tls13, TlsSignatureSchemeConfiguration,
-+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
-+ TlsConnectTestBase::kTlsV13,
-+ ::testing::Values(TlsAgent::kServerMlDsa65),
-+ ::testing::Values(ssl_auth_mldsa65),
-+ ::testing::Values(ssl_sig_mldsa65)));
-+INSTANTIATE_TEST_SUITE_P(
-+ SignatureSchemeMlDsa87Tls13, TlsSignatureSchemeConfiguration,
-+ ::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
-+ TlsConnectTestBase::kTlsV13,
-+ ::testing::Values(TlsAgent::kServerMlDsa87),
-+ ::testing::Values(ssl_auth_mldsa87),
-+ ::testing::Values(ssl_sig_mldsa87)));
- } // namespace nss_test
-diff --git a/gtests/ssl_gtest/tls_agent.cc b/gtests/ssl_gtest/tls_agent.cc
---- a/gtests/ssl_gtest/tls_agent.cc
-+++ b/gtests/ssl_gtest/tls_agent.cc
-@@ -39,19 +39,25 @@ const std::string TlsAgent::kServerRsaSi
- const std::string TlsAgent::kServerRsaPss = "rsa_pss";
- const std::string TlsAgent::kServerRsaDecrypt = "rsa_decrypt";
- const std::string TlsAgent::kServerEcdsa256 = "ecdsa256";
- const std::string TlsAgent::kServerEcdsa384 = "ecdsa384";
- const std::string TlsAgent::kServerEcdsa521 = "ecdsa521";
- const std::string TlsAgent::kServerEcdhRsa = "ecdh_rsa";
- const std::string TlsAgent::kServerEcdhEcdsa = "ecdh_ecdsa";
- const std::string TlsAgent::kServerDsa = "dsa";
-+const std::string TlsAgent::kServerMlDsa44 = "mldsa44";
-+const std::string TlsAgent::kServerMlDsa65 = "mldsa65";
-+const std::string TlsAgent::kServerMlDsa87 = "mldsa87";
- const std::string TlsAgent::kDelegatorEcdsa256 = "delegator_ecdsa256";
- const std::string TlsAgent::kDelegatorRsae2048 = "delegator_rsae2048";
- const std::string TlsAgent::kDelegatorRsaPss2048 = "delegator_rsa_pss2048";
-+const std::string TlsAgent::kDelegatorMlDsa44 = "delegator_mldsa44";
-+const std::string TlsAgent::kDelegatorMlDsa65 = "delegator_mldsa65";
-+const std::string TlsAgent::kDelegatorMlDsa87 = "delegator_mldsa87";
-
- static const uint8_t kCannedTls13ServerHello[] = {
- 0x03, 0x03, 0x9c, 0xbc, 0x14, 0x9b, 0x0e, 0x2e, 0xfa, 0x0d, 0xf3,
- 0xf0, 0x5c, 0x70, 0x7a, 0xe0, 0xd1, 0x9b, 0x3e, 0x5a, 0x44, 0x6b,
- 0xdf, 0xe5, 0xc2, 0x28, 0x64, 0xf7, 0x00, 0xc1, 0x9c, 0x08, 0x76,
- 0x08, 0x00, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00, 0x24,
- 0x00, 0x1d, 0x00, 0x20, 0xc2, 0xcf, 0x23, 0x17, 0x64, 0x23, 0x03,
- 0xf0, 0xfb, 0x45, 0x98, 0x26, 0xd1, 0x65, 0x24, 0xa1, 0x6c, 0xa9,
-diff --git a/gtests/ssl_gtest/tls_agent.h b/gtests/ssl_gtest/tls_agent.h
---- a/gtests/ssl_gtest/tls_agent.h
-+++ b/gtests/ssl_gtest/tls_agent.h
-@@ -82,19 +82,25 @@ class TlsAgent : public PollTarget {
- static const std::string kServerRsaPss;
- static const std::string kServerRsaDecrypt;
- static const std::string kServerEcdsa256;
- static const std::string kServerEcdsa384;
- static const std::string kServerEcdsa521;
- static const std::string kServerEcdhEcdsa;
- static const std::string kServerEcdhRsa;
- static const std::string kServerDsa;
-+ static const std::string kServerMlDsa44;
-+ static const std::string kServerMlDsa65;
-+ static const std::string kServerMlDsa87;
- static const std::string kDelegatorEcdsa256; // draft-ietf-tls-subcerts
- static const std::string kDelegatorRsae2048; // draft-ietf-tls-subcerts
- static const std::string kDelegatorRsaPss2048; // draft-ietf-tls-subcerts
-+ static const std::string kDelegatorMlDsa44; // draft-ietf-tls-subcerts
-+ static const std::string kDelegatorMlDsa65; // draft-ietf-tls-subcerts
-+ static const std::string kDelegatorMlDsa87; // draft-ietf-tls-subcerts
-
- TlsAgent(const std::string& name, Role role, SSLProtocolVariant variant);
- virtual ~TlsAgent();
-
- void SetPeer(std::shared_ptr& peer) {
- adapter_->SetPeer(peer->adapter_);
- }
-
-diff --git a/gtests/ssl_gtest/tls_subcerts_unittest.cc b/gtests/ssl_gtest/tls_subcerts_unittest.cc
---- a/gtests/ssl_gtest/tls_subcerts_unittest.cc
-+++ b/gtests/ssl_gtest/tls_subcerts_unittest.cc
-@@ -19,21 +19,23 @@
-
- namespace nss_test {
-
- #ifndef LTO
- // sigh this construction breaks LTO
- const std::string kEcdsaDelegatorId = TlsAgent::kDelegatorEcdsa256;
- const std::string kRsaeDelegatorId = TlsAgent::kDelegatorRsae2048;
- const std::string kPssDelegatorId = TlsAgent::kDelegatorRsaPss2048;
-+const std::string kMlDsa65DelegatorId = TlsAgent::kDelegatorMlDsa65;
- const std::string kDCId = TlsAgent::kServerEcdsa256;
- #else
- #define kEcdsaDelegatorId TlsAgent::kDelegatorEcdsa256
- #define kRsaeDelegatorId TlsAgent::kDelegatorRsae2048
- #define kPssDelegatorId TlsAgent::kDelegatorRsaPss2048
-+#define kMlDsa65DelegatorId TlsAgent::kDelegatorMlDsa65
- #define kDCId TlsAgent::kServerEcdsa256
- #endif
- const SSLSignatureScheme kDCScheme = ssl_sig_ecdsa_secp256r1_sha256;
- const PRUint32 kDCValidFor = 60 * 60 * 24 * 7 /* 1 week (seconds) */;
-
- static void CheckPreliminaryPeerDelegCred(
- const std::shared_ptr& client, bool expected,
- PRUint32 key_bits = 0, SSLSignatureScheme sig_scheme = ssl_sig_none) {
-@@ -234,16 +236,63 @@ TEST_P(TlsConnectTls13, DCConnectEcdsaP2
- client_, ssl_delegated_credentials_xtn);
- Connect();
-
- EXPECT_TRUE(cfilter->captured());
- CheckPeerDelegCred(client_, true, 256);
- EXPECT_EQ(ssl_sig_ecdsa_secp256r1_sha256, client_->info().signatureScheme);
- }
-
-+// Connected with ML-DSA-65, using an ML-DSA-65 SKI and ML-DSA-65 delegation cert.
-+TEST_P(TlsConnectTls13, DCConnectMlDsa65MlDsa65) {
-+ Reset(kMlDsa65DelegatorId);
-+
-+ // Need to enable PSS-PSS, which is not on by default.
-+ static const SSLSignatureScheme kSchemes[] = {ssl_sig_ecdsa_secp256r1_sha256,
-+ ssl_sig_mldsa65};
-+ client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
-+ server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
-+
-+ client_->EnableDelegatedCredentials();
-+ server_->AddDelegatedCredential(
-+ TlsAgent::kServerMlDsa65, ssl_sig_mldsa65, kDCValidFor, now());
-+
-+ auto cfilter = MakeTlsFilter(
-+ client_, ssl_delegated_credentials_xtn);
-+ Connect();
-+
-+ EXPECT_TRUE(cfilter->captured());
-+ CheckPeerDelegCred(client_, true, ML_DSA_65_PUBLICKEY_LEN*8);
-+ EXPECT_EQ(ssl_sig_mldsa65, client_->info().signatureScheme);
-+}
-+
-+// Connected with ECDSA-P256 using a PSS delegation cert.
-+TEST_P(TlsConnectTls13, DCConnectEcdsaP256MlDsa65) {
-+ Reset(kMlDsa65DelegatorId);
-+
-+ // Need to enable PSS-PSS, which is not on by default.
-+ static const SSLSignatureScheme kSchemes[] = {ssl_sig_ecdsa_secp256r1_sha256,
-+ ssl_sig_mldsa65};
-+ client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
-+ server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
-+
-+ client_->EnableDelegatedCredentials();
-+ server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256,
-+ ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor,
-+ now());
-+
-+ auto cfilter = MakeTlsFilter(
-+ client_, ssl_delegated_credentials_xtn);
-+ Connect();
-+
-+ EXPECT_TRUE(cfilter->captured());
-+ CheckPeerDelegCred(client_, true, 256);
-+ EXPECT_EQ(ssl_sig_ecdsa_secp256r1_sha256, client_->info().signatureScheme);
-+}
-+
- // Simulate the client receiving a DC containing algorithms not advertised.
- // Do this by tweaking the client's supported sigSchemes after the CH.
- TEST_P(TlsConnectTls13, DCReceiveUnadvertisedScheme) {
- Reset(kEcdsaDelegatorId);
- static const SSLSignatureScheme kClientSchemes[] = {
- ssl_sig_ecdsa_secp256r1_sha256, ssl_sig_ecdsa_secp384r1_sha384};
- static const SSLSignatureScheme kServerSchemes[] = {
- ssl_sig_ecdsa_secp384r1_sha384, ssl_sig_ecdsa_secp256r1_sha256};
-@@ -733,11 +782,29 @@ TEST_F(DCDelegation, DCDelegations) {
- cert.get(), priv.get(), pub_ecdsa.get(),
- ssl_sig_rsa_pss_pss_sha256, kDCValidFor, now, &dc));
- EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError());
- EXPECT_EQ(SECFailure,
- SSL_DelegateCredential(cert.get(), priv.get(), pub_ecdsa.get(),
- ssl_sig_ecdsa_secp384r1_sha384, kDCValidFor,
- now, &dc));
- EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError());
-+ ScopedSECKEYPublicKey pub_mldsa;
-+ ScopedSECKEYPrivateKey priv_mldsa;
-+ ASSERT_TRUE(TlsAgent::LoadKeyPairFromCert(TlsAgent::kServerMlDsa65,
-+ &pub_mldsa, &priv_mldsa));
-+ EXPECT_EQ(SECFailure,
-+ SSL_DelegateCredential(cert.get(), priv.get(), pub_mldsa.get(),
-+ ssl_sig_rsa_pss_rsae_sha256, kDCValidFor,
-+ now, &dc));
-+ EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError());
-+ EXPECT_EQ(SECFailure, SSL_DelegateCredential(
-+ cert.get(), priv.get(), pub_mldsa.get(),
-+ ssl_sig_mldsa44, kDCValidFor, now, &dc));
-+ EXPECT_EQ(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, PORT_GetError());
-+ EXPECT_EQ(SECSuccess,
-+ SSL_DelegateCredential(cert.get(), priv.get(), pub_mldsa.get(),
-+ ssl_sig_mldsa65, kDCValidFor,
-+ now, &dc));
-+ dc.Reset();
- }
-
- } // namespace nss_test
-diff --git a/lib/cryptohi/secsign.c b/lib/cryptohi/secsign.c
---- a/lib/cryptohi/secsign.c
-+++ b/lib/cryptohi/secsign.c
-@@ -764,28 +764,24 @@ SEC_GetSignatureAlgorithmOidTag(KeyType
- return sigTag;
- }
-
- static SECItem *
- sec_CreateRSAPSSParameters(PLArenaPool *arena,
- SECItem *result,
- SECOidTag hashAlgTag,
- const SECItem *params,
-- const SECKEYPrivateKey *key)
-+ int modBytes)
- {
- SECKEYRSAPSSParams pssParams;
-- int modBytes, hashLength;
-+ int hashLength;
- unsigned long saltLength;
- PRBool defaultSHA1 = PR_FALSE;
- SECStatus rv;
-
-- if (key->keyType != rsaKey && key->keyType != rsaPssKey) {
-- PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
-- return NULL;
-- }
-
- PORT_Memset(&pssParams, 0, sizeof(pssParams));
-
- if (params && params->data) {
- /* The parameters field should either be empty or contain
- * valid RSA-PSS parameters */
- PORT_Assert(!(params->len == 2 &&
- params->data[0] == SEC_ASN1_NULL &&
-@@ -808,21 +804,28 @@ sec_CreateRSAPSSParameters(PLArenaPool *
- return NULL;
- }
- if (trailerField != 1) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return NULL;
- }
- }
-
-- modBytes = PK11_GetPrivateModulusLen((SECKEYPrivateKey *)key);
-
- /* Determine the hash algorithm to use, based on hashAlgTag and
-- * pssParams.hashAlg; there are four cases */
-- if (hashAlgTag != SEC_OID_UNKNOWN) {
-+ * pssParams.hashAlg; there are 6 cases.
-+ * case:
-+ * 1) we did not specify any parameters but we did specifi
-+ * a hashAlgTag. Use the specified hash algtag. This is the fall
-+ * through case (none of the if's trigger).
-+ * 2) We have params and we have a specified hashAlgTag from
-+ * the app and the hash alg is in the parameters, make sure that the
-+ * hashAlgTag specified by the appication matches.
-+ * 3) Same as 2 except the algorithm is not specified by the */
-+ if (params && (hashAlgTag != SEC_OID_UNKNOWN)) {
- SECOidTag tag = SEC_OID_UNKNOWN;
-
- if (pssParams.hashAlg) {
- tag = SECOID_GetAlgorithmTag(pssParams.hashAlg);
- } else if (defaultSHA1) {
- tag = SEC_OID_SHA1;
- }
-
-@@ -897,16 +900,18 @@ sec_CreateRSAPSSParameters(PLArenaPool *
- &saltLength);
- if (rv != SECSuccess) {
- return NULL;
- }
-
- /* The specified salt length is too long */
- if (saltLength > (unsigned long)(modBytes - hashLength - 2)) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+
-+
- return NULL;
- }
- } else if (defaultSHA1) {
- saltLength = 20;
- }
-
- /* Fill in the parameters */
- if (pssParams.hashAlg) {
-@@ -983,22 +988,57 @@ sec_CreateRSAPSSParameters(PLArenaPool *
- SECItem *
- SEC_CreateSignatureAlgorithmParameters(PLArenaPool *arena,
- SECItem *result,
- SECOidTag signAlgTag,
- SECOidTag hashAlgTag,
- const SECItem *params,
- const SECKEYPrivateKey *key)
- {
-+ int modBytes;
- switch (signAlgTag) {
- case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
-+ if (key->keyType != rsaKey && key->keyType != rsaPssKey) {
-+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
-+ return NULL;
-+ }
-+ modBytes = PK11_GetPrivateModulusLen((SECKEYPrivateKey *)key);
- return sec_CreateRSAPSSParameters(arena, result,
-- hashAlgTag, params, key);
-+ hashAlgTag, params, modBytes);
- default:
- if (params == NULL)
- return NULL;
- if (result == NULL)
- result = SECITEM_AllocItem(arena, NULL, 0);
- if (SECITEM_CopyItem(arena, result, params) != SECSuccess)
- return NULL;
- return result;
- }
- }
-+
-+SECItem *
-+SEC_CreateVerifySignatureAlgorithmParameters(PLArenaPool *arena,
-+ SECItem *result,
-+ SECOidTag signAlgTag,
-+ SECOidTag hashAlgTag,
-+ const SECItem *params,
-+ const SECKEYPublicKey *key)
-+{
-+ int modBytes;
-+ switch (signAlgTag) {
-+ case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
-+ if (key->keyType != rsaKey && key->keyType != rsaPssKey) {
-+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
-+ return NULL;
-+ }
-+ modBytes = key->u.rsa.modulus.len;
-+ return sec_CreateRSAPSSParameters(arena, result,
-+ hashAlgTag, params, modBytes);
-+ default:
-+ if (params == NULL)
-+ return NULL;
-+ if (result == NULL)
-+ result = SECITEM_AllocItem(arena, NULL, 0);
-+ if (SECITEM_CopyItem(arena, result, params) != SECSuccess)
-+ return NULL;
-+ return result;
-+ }
-+}
-diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c
---- a/lib/ssl/ssl3con.c
-+++ b/lib/ssl/ssl3con.c
-@@ -31,16 +31,17 @@
- #include "pratom.h"
- #include "prthread.h"
- #include "nss.h"
- #include "nssoptions.h"
-
- #include "pk11func.h"
- #include "secmod.h"
- #include "blapi.h"
-+#include "secmodti.h" /* for ML_DSA_OIDS, not needed upstream */
-
- #include
- #include
-
- static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec,
- PK11SlotInfo *serverKeySlot);
- static SECStatus ssl3_ComputeMasterSecret(sslSocket *ss, PK11SymKey *pms,
- PK11SymKey **msp);
-@@ -66,16 +67,17 @@ static SECStatus ssl3_HandlePostHelloHan
- PRUint32 length);
- static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
- static CK_MECHANISM_TYPE ssl3_GetHashMechanismByHashType(SSLHashType hashType);
- static CK_MECHANISM_TYPE ssl3_GetMgfMechanismByHashType(SSLHashType hash);
- PRBool ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme);
- PRBool ssl_IsRsaeSignatureScheme(SSLSignatureScheme scheme);
- PRBool ssl_IsRsaPkcs1SignatureScheme(SSLSignatureScheme scheme);
- PRBool ssl_IsDsaSignatureScheme(SSLSignatureScheme scheme);
-+PRBool ssl_IsMlDsaSignatureScheme(SSLSignatureScheme scheme);
- static SECStatus ssl3_UpdateDefaultHandshakeHashes(sslSocket *ss,
- const unsigned char *b,
- unsigned int l);
- const PRUint32 kSSLSigSchemePolicy =
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_ANY_SIGNATURE;
-
- const PRUint8 ssl_hello_retry_random[] = {
- 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
-@@ -200,17 +202,20 @@ static const SSLSignatureScheme defaultS
- ssl_sig_rsa_pss_rsae_sha512,
- ssl_sig_rsa_pkcs1_sha256,
- ssl_sig_rsa_pkcs1_sha384,
- ssl_sig_rsa_pkcs1_sha512,
- ssl_sig_rsa_pkcs1_sha1,
- ssl_sig_dsa_sha256,
- ssl_sig_dsa_sha384,
- ssl_sig_dsa_sha512,
-- ssl_sig_dsa_sha1
-+ ssl_sig_dsa_sha1,
-+ ssl_sig_mldsa44,
-+ ssl_sig_mldsa65,
-+ ssl_sig_mldsa87,
- };
- PR_STATIC_ASSERT(PR_ARRAY_SIZE(defaultSignatureSchemes) <=
- MAX_SIGNATURE_SCHEMES);
-
- /* Verify that SSL_ImplementedCiphers and cipherSuites are in consistent order.
- */
- #ifdef DEBUG
- void
-@@ -358,17 +363,20 @@ static const CK_MECHANISM_TYPE auth_alg_
- CKM_DSA, /* ? _SHA1 */ /* ssl_auth_dsa */
- CKM_INVALID_MECHANISM, /* ssl_auth_kea (unused) */
- CKM_ECDSA, /* ssl_auth_ecdsa */
- CKM_ECDH1_DERIVE, /* ssl_auth_ecdh_rsa */
- CKM_ECDH1_DERIVE, /* ssl_auth_ecdh_ecdsa */
- CKM_RSA_PKCS, /* ssl_auth_rsa_sign */
- CKM_RSA_PKCS_PSS, /* ssl_auth_rsa_pss */
- CKM_NSS_HKDF_SHA256, /* ssl_auth_psk (just check for HKDF) */
-- CKM_INVALID_MECHANISM /* ssl_auth_tls13_any */
-+ CKM_INVALID_MECHANISM, /* ssl_auth_tls13_any */
-+ CKM_ML_DSA, /* ssl_auth_mldsa (same mech for each) */
-+ CKM_ML_DSA, /* ssl_auth_mldsa (key determines the*/
-+ CKM_ML_DSA, /* ssl_auth_mldsa parameter set) */
- };
- PR_STATIC_ASSERT(PR_ARRAY_SIZE(auth_alg_defs) == ssl_auth_size);
-
- static const CK_MECHANISM_TYPE kea_alg_defs[] = {
- CKM_INVALID_MECHANISM, /* ssl_kea_null */
- CKM_RSA_PKCS, /* ssl_kea_rsa */
- CKM_DH_PKCS_DERIVE, /* ssl_kea_dh */
- CKM_INVALID_MECHANISM, /* ssl_kea_fortezza (unused) */
-@@ -758,16 +766,23 @@ ssl_KEAEnabled(const sslSocket *ss, SSLK
-
- static PRBool
- ssl_HasCert(const sslSocket *ss, PRUint16 maxVersion, SSLAuthType authType)
- {
- PRCList *cursor;
- if (authType == ssl_auth_null || authType == ssl_auth_psk || authType == ssl_auth_tls13_any) {
- return PR_TRUE;
- }
-+ /* mldsa is only supported in TLS 1.3 or greater */
-+ if (maxVersion < SSL_LIBRARY_VERSION_TLS_1_3 &&
-+ (authType == ssl_auth_mldsa44 ||
-+ authType == ssl_auth_mldsa65 ||
-+ authType == ssl_auth_mldsa87)) {
-+ return PR_FALSE;
-+ }
- for (cursor = PR_NEXT_LINK(&ss->serverCerts);
- cursor != &ss->serverCerts;
- cursor = PR_NEXT_LINK(cursor)) {
- sslServerCert *cert = (sslServerCert *)cursor;
- if (!cert->serverKeyPair ||
- !cert->serverKeyPair->privKey ||
- !cert->serverCertChain ||
- !SSL_CERT_IS(cert, authType)) {
-@@ -803,16 +818,21 @@ ssl_HasCert(const sslSocket *ss, PRUint1
- static PRBool
- ssl_SchemePolicyOK(SSLSignatureScheme scheme, PRUint32 require)
- {
- /* Hash policy. */
- PRUint32 policy;
- SECOidTag hashOID = ssl3_HashTypeToOID(ssl_SignatureSchemeToHashType(scheme));
- SECOidTag sigOID;
-
-+#ifndef NSS_ENABLE_ML_DSA
-+ if (ssl_IsMlDsaSignatureScheme(scheme)) {
-+ return PR_FALSE;
-+ }
-+#endif
- /* policy bits needed to enable a SignatureScheme */
- SECStatus rv = NSS_GetAlgorithmPolicy(hashOID, &policy);
- if (rv == SECSuccess &&
- (policy & require) != require) {
- return PR_FALSE;
- }
-
- /* ssl_SignatureSchemeToAuthType reports rsa for rsa_pss_rsae, but we
-@@ -830,17 +850,17 @@ ssl_SchemePolicyOK(SSLSignatureScheme sc
- return PR_FALSE;
- }
- return PR_TRUE;
- }
-
- /* Check that a signature scheme is accepted.
- * Both by policy and by having a token that supports it. */
- static PRBool
--ssl_SignatureSchemeAccepted(PRUint16 minVersion,
-+ssl_SignatureSchemeAccepted(PRUint16 minVersion, PRUint16 maxVersion,
- SSLSignatureScheme scheme,
- PRBool forCert)
- {
- /* Disable RSA-PSS schemes if there are no tokens to verify them. */
- if (ssl_IsRsaPssSignatureScheme(scheme)) {
- if (!PK11_TokenExists(auth_alg_defs[ssl_auth_rsa_pss])) {
- return PR_FALSE;
- }
-@@ -852,16 +872,21 @@ ssl_SignatureSchemeAccepted(PRUint16 min
- if (minVersion >= SSL_LIBRARY_VERSION_TLS_1_3) {
- return PR_FALSE;
- }
- } else if (ssl_IsDsaSignatureScheme(scheme)) {
- /* DSA: not in TLS 1.3, and check policy. */
- if (minVersion >= SSL_LIBRARY_VERSION_TLS_1_3) {
- return PR_FALSE;
- }
-+ } else if (ssl_IsMlDsaSignatureScheme(scheme)) {
-+ /* MLDSA: limit ml-dsa if we don't support TLS 1.3. */
-+ if (maxVersion < SSL_LIBRARY_VERSION_TLS_1_3) {
-+ return PR_FALSE;
-+ }
- }
-
- return ssl_SchemePolicyOK(scheme, kSSLSigSchemePolicy);
- }
-
- static SECStatus
- ssl_CheckSignatureSchemes(sslSocket *ss)
- {
-@@ -887,17 +912,17 @@ ssl_CheckSignatureSchemes(sslSocket *ss)
- if (!foundCert) {
- PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
- return SECFailure;
- }
- }
-
- /* Ensure that there is a signature scheme that can be accepted.*/
- for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
-- if (ssl_SignatureSchemeAccepted(ss->vrange.min,
-+ if (ssl_SignatureSchemeAccepted(ss->vrange.min, ss->vrange.max,
- ss->ssl3.signatureSchemes[i],
- PR_FALSE /* forCert */)) {
- return SECSuccess;
- }
- }
- PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
- return SECFailure;
- }
-@@ -918,17 +943,18 @@ ssl_HasSignatureScheme(const sslSocket *
- return PR_TRUE;
- }
- for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
- SSLSignatureScheme scheme = ss->ssl3.signatureSchemes[i];
- SSLAuthType schemeAuthType = ssl_SignatureSchemeToAuthType(scheme);
- PRBool acceptable = authType == schemeAuthType ||
- (schemeAuthType == ssl_auth_rsa_pss &&
- authType == ssl_auth_rsa_sign);
-- if (acceptable && ssl_SignatureSchemeAccepted(ss->version, scheme, PR_FALSE /* forCert */)) {
-+ if (acceptable && ssl_SignatureSchemeAccepted(ss->version,
-+ ss->version, scheme, PR_FALSE /* forCert */)) {
- return PR_TRUE;
- }
- }
- return PR_FALSE;
- }
-
- /* Initialize the suite->isPresent value for config_match
- * Returns count of enabled ciphers supported by extant tokens,
-@@ -1228,17 +1254,18 @@ ssl3_GetNewRandom(SSL3Random random)
-
- rv = PK11_GenerateRandom(random, SSL3_RANDOM_LENGTH);
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE);
- }
- return rv;
- }
-
--SECStatus
-+/* this only implements TLS 1.2 and earlier signatures */
-+static SECStatus
- ssl3_SignHashesWithPrivKey(SSL3Hashes *hash, SECKEYPrivateKey *key,
- SSLSignatureScheme scheme, PRBool isTls, SECItem *buf)
- {
- SECStatus rv = SECFailure;
- PRBool doDerEncode = PR_FALSE;
- PRBool useRsaPss = ssl_IsRsaPssSignatureScheme(scheme);
- SECItem hashItem;
-
-@@ -1289,18 +1316,19 @@ ssl3_SignHashesWithPrivKey(SSL3Hashes *h
- SECItem pssParamsItem = { siBuffer,
- (unsigned char *)&pssParams,
- sizeof(pssParams) };
-
- if (signatureLen <= 0) {
- PORT_SetError(SEC_ERROR_INVALID_KEY);
- goto done;
- }
-- /* since we are calling PK11_SignWithMechanism directly, we need to check the
-- * key policy ourselves (which is already checked in SGN_Digest */
-+ /* since we are calling PK11_SignWithMechanism directly, we need to
-+ * check the key policy ourselves (which is already checked in
-+ * SGN_Digest */
- rv = NSS_OptionGet(NSS_KEY_SIZE_POLICY_FLAGS, &optval);
- if ((rv == SECSuccess) &&
- ((optval & NSS_KEY_SIZE_POLICY_SIGN_FLAG) == NSS_KEY_SIZE_POLICY_SIGN_FLAG)) {
- rv = SECKEY_EnforceKeySize(key->keyType, SECKEY_PrivateKeyStrengthInBits(key),
- SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
- if (rv != SECSuccess) {
- goto done; /* error code already set */
- }
-@@ -1365,18 +1393,19 @@ ssl3_SignHashes(sslSocket *ss, SSL3Hashe
- if (ss->sec.isServer) {
- ss->sec.signatureScheme = scheme;
- ss->sec.authType = ssl_SignatureSchemeToAuthType(scheme);
- }
-
- return SECSuccess;
- }
-
--/* Called from ssl3_VerifySignedHashes and tls13_HandleCertificateVerify. */
--SECStatus
-+/* Called from ssl3_VerifySignedHashes */
-+/* this only implements TLS 1.2 and earlier signatures */
-+static SECStatus
- ssl_VerifySignedHashesWithPubKey(sslSocket *ss, SECKEYPublicKey *key,
- SSLSignatureScheme scheme,
- SSL3Hashes *hash, SECItem *buf)
- {
- SECItem *signature = NULL;
- SECStatus rv = SECFailure;
- SECItem hashItem;
- SECOidTag encAlg;
-@@ -3407,16 +3436,17 @@ ssl3_GetHashMechanismByHashType(SSLHashT
- case ssl_hash_sha384:
- return CKM_SHA384;
- case ssl_hash_sha256:
- case ssl_hash_none:
- /* ssl_hash_none is for pre-1.2 suites, which use SHA-256. */
- return CKM_SHA256;
- case ssl_hash_sha1:
- return CKM_SHA_1;
-+ /* don't return a mechansim for ml_dsa hashes */
- default:
- PORT_Assert(0);
- }
- return CKM_SHA256;
- }
-
- /* Function valid for >= TLS 1.2, only. */
- static CK_MECHANISM_TYPE
-@@ -4345,16 +4375,29 @@ ssl3_HashTypeToOID(SSLHashType hashType)
- case ssl_hash_sha1:
- return SEC_OID_SHA1;
- case ssl_hash_sha256:
- return SEC_OID_SHA256;
- case ssl_hash_sha384:
- return SEC_OID_SHA384;
- case ssl_hash_sha512:
- return SEC_OID_SHA512;
-+ /* ml-dsa has it's own has algorithm,
-+ * if we are using an external hash,
-+ * we need to fail (at least until
-+ * we get mu support). Fortunately
-+ * mldsa is only supported in TLS 1.3
-+ * and can do full hash and sign in
-+ * the TLS 1.3 protocol */
-+ case ssl_hash_mldsa44:
-+ return SEC_OID_ML_DSA_44;
-+ case ssl_hash_mldsa65:
-+ return SEC_OID_ML_DSA_65;
-+ case ssl_hash_mldsa87:
-+ return SEC_OID_ML_DSA_87;
- default:
- break;
- }
- return SEC_OID_UNKNOWN;
- }
-
- SECOidTag
- ssl3_AuthTypeToOID(SSLAuthType authType)
-@@ -4363,16 +4406,22 @@ ssl3_AuthTypeToOID(SSLAuthType authType)
- case ssl_auth_rsa_sign:
- return SEC_OID_PKCS1_RSA_ENCRYPTION;
- case ssl_auth_rsa_pss:
- return SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
- case ssl_auth_ecdsa:
- return SEC_OID_ANSIX962_EC_PUBLIC_KEY;
- case ssl_auth_dsa:
- return SEC_OID_ANSIX9_DSA_SIGNATURE;
-+ case ssl_auth_mldsa44:
-+ return SEC_OID_ML_DSA_44;
-+ case ssl_auth_mldsa65:
-+ return SEC_OID_ML_DSA_65;
-+ case ssl_auth_mldsa87:
-+ return SEC_OID_ML_DSA_87;
- default:
- break;
- }
- /* shouldn't ever get there */
- PORT_Assert(0);
- return SEC_OID_UNKNOWN;
- }
-
-@@ -4397,16 +4446,22 @@ ssl_SignatureSchemeToHashType(SSLSignatu
- case ssl_sig_dsa_sha384:
- return ssl_hash_sha384;
- case ssl_sig_rsa_pkcs1_sha512:
- case ssl_sig_ecdsa_secp521r1_sha512:
- case ssl_sig_rsa_pss_rsae_sha512:
- case ssl_sig_rsa_pss_pss_sha512:
- case ssl_sig_dsa_sha512:
- return ssl_hash_sha512;
-+ case ssl_sig_mldsa44:
-+ return ssl_hash_mldsa44;
-+ case ssl_sig_mldsa65:
-+ return ssl_hash_mldsa65;
-+ case ssl_sig_mldsa87:
-+ return ssl_hash_mldsa87;
- case ssl_sig_rsa_pkcs1_sha1md5:
- return ssl_hash_none; /* Special for TLS 1.0/1.1. */
- case ssl_sig_none:
- case ssl_sig_ed25519:
- case ssl_sig_ed448:
- break;
- }
- PORT_Assert(0);
-@@ -4451,16 +4506,20 @@ ssl_SignatureSchemeValid(SSLSignatureSch
- return PR_FALSE;
- }
- if (ssl_IsDsaSignatureScheme(scheme)) {
- return PR_FALSE;
- }
- /* With TLS 1.3, EC keys should have been selected based on calling
- * ssl_SignatureSchemeFromSpki(), reject them otherwise. */
- return spkiOid != SEC_OID_ANSIX962_EC_PUBLIC_KEY;
-+ } else {
-+ if (ssl_IsMlDsaSignatureScheme(scheme)) {
-+ return PR_FALSE;
-+ }
- }
- return PR_TRUE;
- }
-
- static SECStatus
- ssl_SignatureSchemeFromPssSpki(const CERTSubjectPublicKeyInfo *spki,
- SSLSignatureScheme *scheme)
- {
-@@ -4538,37 +4597,65 @@ ssl_SignatureSchemeFromEcSpki(const CERT
- return SECSuccess;
- default:
- break;
- }
- PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
- return SECFailure;
- }
-
-+
-+/* some schmemes match 1 for 1 to oids, for those schemes, we
-+ * can return the oid directly. If this function return ssl_sig_none,
-+ * it means the oid doen't match a scheme or matches more than one
-+ * scheme */
-+SSLSignatureScheme
-+ssl_SignatureSchemeFromPublicKeyOid(SECOidTag tag)
-+{
-+ switch (tag) {
-+ case SEC_OID_ML_DSA_44:
-+ return ssl_sig_mldsa44;
-+ case SEC_OID_ML_DSA_65:
-+ return ssl_sig_mldsa65;
-+ case SEC_OID_ML_DSA_87:
-+ return ssl_sig_mldsa87;
-+ default:
-+ break;
-+ }
-+ return ssl_sig_none;
-+}
-+
-+
- /* Newer signature schemes are designed so that a single SPKI can be used with
- * that scheme. This determines that scheme from the SPKI. If the SPKI doesn't
- * have a single scheme, |*scheme| is set to ssl_sig_none. */
- SECStatus
- ssl_SignatureSchemeFromSpki(const CERTSubjectPublicKeyInfo *spki,
- PRBool isTls13, SSLSignatureScheme *scheme)
- {
- SECOidTag spkiOid = SECOID_GetAlgorithmTag(&spki->algorithm);
-
-- if (spkiOid == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
-- return ssl_SignatureSchemeFromPssSpki(spki, scheme);
-- }
--
-- /* Only do this lookup for TLS 1.3, where the scheme can be determined from
-- * the SPKI alone because the ECDSA key size determines the hash. Earlier
-- * TLS versions allow the same EC key to be used with different hashes. */
-- if (isTls13 && spkiOid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) {
-- return ssl_SignatureSchemeFromEcSpki(spki, scheme);
-- }
--
-+ /* default */
- *scheme = ssl_sig_none;
-+ switch (spkiOid) {
-+ case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
-+ return ssl_SignatureSchemeFromPssSpki(spki, scheme);
-+ case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
-+ /* Only do this lookup for TLS 1.3, where the scheme can be
-+ * determined from the SPKI alone because the ECDSA key size
-+ * determines the hash. Earlier TLS versions allow the same
-+ * EC key to be used with different hashes. */
-+ if (isTls13) {
-+ return ssl_SignatureSchemeFromEcSpki(spki, scheme);
-+ }
-+ break;
-+ default:
-+ *scheme = ssl_SignatureSchemeFromPublicKeyOid(spkiOid);
-+ break;
-+ }
- return SECSuccess;
- }
-
- /* Check that a signature scheme is enabled by configuration. */
- PRBool
- ssl_SignatureSchemeEnabled(const sslSocket *ss, SSLSignatureScheme scheme)
- {
- unsigned int i;
-@@ -4664,16 +4751,19 @@ ssl_IsSupportedSignatureScheme(SSLSignat
- case ssl_sig_rsa_pss_rsae_sha384:
- case ssl_sig_rsa_pss_rsae_sha512:
- case ssl_sig_rsa_pss_pss_sha256:
- case ssl_sig_rsa_pss_pss_sha384:
- case ssl_sig_rsa_pss_pss_sha512:
- case ssl_sig_ecdsa_secp256r1_sha256:
- case ssl_sig_ecdsa_secp384r1_sha384:
- case ssl_sig_ecdsa_secp521r1_sha512:
-+ case ssl_sig_mldsa44:
-+ case ssl_sig_mldsa65:
-+ case ssl_sig_mldsa87:
- case ssl_sig_dsa_sha1:
- case ssl_sig_dsa_sha256:
- case ssl_sig_dsa_sha384:
- case ssl_sig_dsa_sha512:
- case ssl_sig_ecdsa_sha1:
- return ssl_SchemePolicyOK(scheme, kSSLSigSchemePolicy);
- break;
-
-@@ -4746,16 +4836,31 @@ ssl_IsDsaSignatureScheme(SSLSignatureSch
- return PR_TRUE;
-
- default:
- return PR_FALSE;
- }
- return PR_FALSE;
- }
-
-+PRBool
-+ssl_IsMlDsaSignatureScheme(SSLSignatureScheme scheme)
-+{
-+ switch (scheme) {
-+ case ssl_sig_mldsa44:
-+ case ssl_sig_mldsa65:
-+ case ssl_sig_mldsa87:
-+ return PR_TRUE;
-+
-+ default:
-+ return PR_FALSE;
-+ }
-+ return PR_FALSE;
-+}
-+
- SSLAuthType
- ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme)
- {
- switch (scheme) {
- case ssl_sig_rsa_pkcs1_sha1:
- case ssl_sig_rsa_pkcs1_sha1md5:
- case ssl_sig_rsa_pkcs1_sha256:
- case ssl_sig_rsa_pkcs1_sha384:
-@@ -4769,16 +4874,22 @@ ssl_SignatureSchemeToAuthType(SSLSignatu
- case ssl_sig_rsa_pss_pss_sha384:
- case ssl_sig_rsa_pss_pss_sha512:
- return ssl_auth_rsa_pss;
- case ssl_sig_ecdsa_secp256r1_sha256:
- case ssl_sig_ecdsa_secp384r1_sha384:
- case ssl_sig_ecdsa_secp521r1_sha512:
- case ssl_sig_ecdsa_sha1:
- return ssl_auth_ecdsa;
-+ case ssl_sig_mldsa44:
-+ return ssl_auth_mldsa44;
-+ case ssl_sig_mldsa65:
-+ return ssl_auth_mldsa65;
-+ case ssl_sig_mldsa87:
-+ return ssl_auth_mldsa87;
- case ssl_sig_dsa_sha1:
- case ssl_sig_dsa_sha256:
- case ssl_sig_dsa_sha384:
- case ssl_sig_dsa_sha512:
- return ssl_auth_dsa;
-
- default:
- PORT_Assert(0);
-@@ -5852,28 +5963,78 @@ ssl_FindIndexByWrapMechanism(CK_MECHANIS
- return SECSuccess;
- }
- }
- PORT_Assert(0);
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-
-+/* mldsa server private key cannot be used directly in
-+ * a key exchange. Instead we'll sign the fixed value
-+ * use it in a PBE. This will work with any signature scheme
-+ * with a deterministic signature */
-+#define SSL_SIG_KEY "NSS Session Cashe Ks Init String"
-+static PK11SymKey *
-+ssl_getSigKs(SECKEYPrivateKey *svrPrivKey, CK_MECHANISM_TYPE mechanism,
-+ CK_MECHANISM_TYPE masterWrapMech, void *pwArg)
-+{
-+ const char *sigKey = SSL_SIG_KEY;
-+ SECItem msg = { siBuffer, (unsigned char *)sigKey, sizeof(sigKey) };
-+ /* set to the the size of the largest signature supported. currently
-+ * ml_dsa. If This value is to small, PK11_SignWithMechanism will
-+ * safely fail below without generating the signature */
-+ unsigned char sigBuf[MAX_ML_DSA_SIGNATURE_LEN];
-+ SECItem sig = {siBuffer, sigBuf, sizeof(sigBuf)};
-+ /* can't use the default because we need to generate
-+ * deterministic signatures */
-+ CK_SIGN_ADDITIONAL_CONTEXT sig_context =
-+ { CKH_DETERMINISTIC_REQUIRED, NULL, 0 };
-+ SECItem sig_params={siBuffer, (unsigned char *)&sig_context,
-+ sizeof(sig_context)};
-+ PK11SymKey *Ks = NULL;
-+ SECStatus rv;
-+
-+ sig_context.hedgeVariant = CKH_DETERMINISTIC_REQUIRED;
-+ sig_context.pContext = NULL;
-+ sig_context.ulContextLen = 0;
-+
-+ rv = PK11_SignWithMechanism(svrPrivKey, mechanism, &sig_params,
-+ &sig, &msg);
-+ if (rv != SECSuccess) {
-+ return NULL;
-+ }
-+
-+ Ks = PK11_RawPBEKeyGen(svrPrivKey->pkcs11Slot, masterWrapMech, NULL,
-+ &sig, PR_FALSE, pwArg);
-+ /* sigBuf became a CSP when we turned it into a password for the
-+ * PBE */
-+ PORT_SafeZero(sigBuf, sizeof(sigBuf));
-+
-+ if (Ks == NULL) {
-+ return NULL;
-+ }
-+ return Ks;
-+}
-+
- /* Each process sharing the server session ID cache has its own array of SymKey
- * pointers for the symmetric wrapping keys that are used to wrap the master
- * secrets. There is one key for each authentication type. These Symkeys
- * correspond to the wrapped SymKeys kept in the server session cache.
- */
- const SSLAuthType ssl_wrap_key_auth_type[SSL_NUM_WRAP_KEYS] = {
- ssl_auth_rsa_decrypt,
- ssl_auth_rsa_sign,
- ssl_auth_rsa_pss,
- ssl_auth_ecdsa,
- ssl_auth_ecdh_rsa,
-- ssl_auth_ecdh_ecdsa
-+ ssl_auth_ecdh_ecdsa,
-+ ssl_auth_mldsa44,
-+ ssl_auth_mldsa65,
-+ ssl_auth_mldsa87
- };
-
- static SECStatus
- ssl_FindIndexByWrapKey(const sslServerCert *serverCert, unsigned int *wrapKeyIndex)
- {
- unsigned int i;
- for (i = 0; i < SSL_NUM_WRAP_KEYS; ++i) {
- if (SSL_CERT_IS(serverCert, ssl_wrap_key_auth_type[i])) {
-@@ -5958,29 +6119,46 @@ ssl_UnwrapSymWrappingKey(
-
- wrappedKey.len = ecWrapped->wrappedKeyLen;
- wrappedKey.data = ecWrapped->var + ecWrapped->encodedParamLen +
- ecWrapped->pubValueLen;
-
- /* Derive Ks using ECDH */
- Ks = PK11_PubDeriveWithKDF(svrPrivKey, &pubWrapKey, PR_FALSE, NULL,
- NULL, CKM_ECDH1_DERIVE, masterWrapMech,
-- CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
-+ CKA_DERIVE, 0, CKD_NULL, NULL, pwArg);
- if (Ks == NULL) {
- goto loser;
- }
-
- /* Use Ks to unwrap the wrapping key */
- unwrappedWrappingKey = PK11_UnwrapSymKey(Ks, masterWrapMech, NULL,
- &wrappedKey, masterWrapMech,
- CKA_UNWRAP, 0);
- PK11_FreeSymKey(Ks);
-
- break;
--
-+ case ssl_auth_mldsa44:
-+ case ssl_auth_mldsa65:
-+ case ssl_auth_mldsa87:
-+ /* Signature only algorithms can use a trick of signing a
-+ * constant with the private key and using that constant
-+ * as the password for a PBE. This only works if the
-+ * signature is deterministic */
-+ Ks = ssl_getSigKs(svrPrivKey, CKM_ML_DSA, masterWrapMech, pwArg);
-+ if (Ks == NULL) {
-+ goto loser;
-+ }
-+ /* Use Ks to unwrap the wrapping key */
-+ unwrappedWrappingKey = PK11_UnwrapSymKey(Ks, masterWrapMech, NULL,
-+ &wrappedKey, masterWrapMech,
-+ CKA_UNWRAP, 0);
-+ PK11_FreeSymKey(Ks);
-+ break;
-+ break;
- default:
- PORT_Assert(0);
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- goto loser;
- }
- loser:
- return unwrappedWrappingKey;
- }
-@@ -6244,16 +6422,33 @@ ssl3_GetWrappingKey(sslSocket *ss,
- if (privWrapKey)
- SECKEY_DestroyPrivateKey(privWrapKey);
- if (pubWrapKey)
- SECKEY_DestroyPublicKey(pubWrapKey);
- if (Ks)
- PK11_FreeSymKey(Ks);
- asymWrapMechanism = masterWrapMech;
- break;
-+ case ssl_auth_mldsa44:
-+ case ssl_auth_mldsa65:
-+ case ssl_auth_mldsa87:
-+ /* Signature only algorithms can use a trick of signing a
-+ * constant with the private key and using that constant
-+ * as the password for a PBE. This only works if the
-+ * signature is deterministic */
-+ Ks = ssl_getSigKs(svrPrivKey, CKM_ML_DSA, masterWrapMech, pwArg);
-+ if (Ks == NULL) {
-+ goto loser;
-+ }
-+ /* Use Ks to unwrap the wrapping key */
-+ rv = PK11_WrapSymKey(masterWrapMech, NULL,Ks,
-+ unwrappedWrappingKey, &wrappedKey);
-+ PK11_FreeSymKey(Ks);
-+ asymWrapMechanism = masterWrapMech;
-+ break;
-
- default:
- rv = SECFailure;
- break;
- }
-
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
-@@ -10334,23 +10529,25 @@ ssl3_SendServerKeyExchange(sslSocket *ss
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- break;
- }
-
- return SECFailure;
- }
-
- SECStatus
--ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool forCert,
-- PRBool grease, sslBuffer *buf)
-+ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion,
-+ PRUint16 maxVersion, PRBool forCert, PRBool grease,
-+ sslBuffer *buf)
- {
- SSLSignatureScheme filtered[MAX_SIGNATURE_SCHEMES] = { 0 };
- unsigned int filteredCount = 0;
-
-- SECStatus rv = ssl3_FilterSigAlgs(ss, minVersion, PR_FALSE, forCert,
-+ SECStatus rv = ssl3_FilterSigAlgs(ss, minVersion, maxVersion,
-+ PR_FALSE, forCert,
- PR_ARRAY_SIZE(filtered),
- filtered, &filteredCount);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- return ssl3_EncodeFilteredSigAlgs(ss, filtered, filteredCount, grease, buf);
- }
-
-@@ -10417,17 +10614,18 @@ ssl3_EncodeFilteredSigAlgs(const sslSock
- * that include PKCS#1. Hence, forCert is used to enable advertising
- * PKCS#1 support. Note that we include these in signature_algorithms
- * because we don't yet support signature_algorithms_cert. TLS 1.3
- * requires that PKCS#1 schemes are placed last in the list if they
- * are present. This sorting can be removed once we support
- * signature_algorithms_cert.
- */
- SECStatus
--ssl3_FilterSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool disableRsae,
-+ssl3_FilterSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRUint16 maxVersion,
-+ PRBool disableRsae,
- PRBool forCert,
- unsigned int maxSchemes, SSLSignatureScheme *filteredSchemes,
- unsigned int *numFilteredSchemes)
- {
- PORT_Assert(filteredSchemes);
- PORT_Assert(numFilteredSchemes);
- PORT_Assert(maxSchemes >= ss->ssl3.signatureSchemeCount);
- if (maxSchemes < ss->ssl3.signatureSchemeCount) {
-@@ -10435,31 +10633,31 @@ ssl3_FilterSigAlgs(const sslSocket *ss,
- }
-
- *numFilteredSchemes = 0;
- PRBool allowUnsortedPkcs1 = forCert && minVersion < SSL_LIBRARY_VERSION_TLS_1_3;
- for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
- if (disableRsae && ssl_IsRsaeSignatureScheme(ss->ssl3.signatureSchemes[i])) {
- continue;
- }
-- if (ssl_SignatureSchemeAccepted(minVersion,
-+ if (ssl_SignatureSchemeAccepted(minVersion, maxVersion,
- ss->ssl3.signatureSchemes[i],
- allowUnsortedPkcs1)) {
- filteredSchemes[(*numFilteredSchemes)++] = ss->ssl3.signatureSchemes[i];
- }
- }
- if (forCert && !allowUnsortedPkcs1) {
- for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
- if (disableRsae && ssl_IsRsaeSignatureScheme(ss->ssl3.signatureSchemes[i])) {
- continue;
- }
-- if (!ssl_SignatureSchemeAccepted(minVersion,
-+ if (!ssl_SignatureSchemeAccepted(minVersion, maxVersion,
- ss->ssl3.signatureSchemes[i],
- PR_FALSE) &&
-- ssl_SignatureSchemeAccepted(minVersion,
-+ ssl_SignatureSchemeAccepted(minVersion, maxVersion,
- ss->ssl3.signatureSchemes[i],
- PR_TRUE)) {
- filteredSchemes[(*numFilteredSchemes)++] = ss->ssl3.signatureSchemes[i];
- }
- }
- }
- return SECSuccess;
- }
-@@ -10492,17 +10690,18 @@ ssl3_SendCertificateRequest(sslSocket *s
- if (rv != SECSuccess) {
- return rv;
- }
- certTypes = certificate_types;
- certTypesLength = sizeof certificate_types;
-
- length = 1 + certTypesLength + 2 + calen;
- if (isTLS12) {
-- rv = ssl3_EncodeSigAlgs(ss, ss->version, PR_TRUE /* forCert */,
-+ rv = ssl3_EncodeSigAlgs(ss, ss->version, ss->version,
-+ PR_TRUE /* forCert */,
- PR_FALSE /* GREASE */, &sigAlgsBuf);
- if (rv != SECSuccess) {
- return rv;
- }
- length += SSL_BUFFER_LEN(&sigAlgsBuf);
- }
-
- rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_request, length);
-@@ -11196,21 +11395,19 @@ get_fake_cert(SECItem *pCertItem, int *p
- numBytes = PR_Read(cf, pCertItem->data, info.size);
- }
- PR_Close(cf);
- if (numBytes != info.size) {
- SECITEM_FreeItem(pCertItem, PR_FALSE);
- PORT_SetError(SEC_ERROR_IO);
- goto loser;
- }
-- fprintf(stderr, "using %s\n", cfn);
- return SECSuccess;
-
- loser:
-- fprintf(stderr, "failed to use %s\n", cfn);
- *pIndex = -1;
- return SECFailure;
- }
- #endif
-
- /*
- * Used by both client and server.
- * Called from HandleServerHelloDone and from SendServerHelloSequence.
-@@ -11698,16 +11895,21 @@ ssl_SetAuthKeyBits(sslSocket *ss, const
- if (rv == SECSuccess && optval > 0) {
- minKey = (PRUint32)optval;
- } else {
- /* Don't check EC strength here on the understanding that we
- * only support curves we like. */
- minKey = ss->sec.authKeyBits;
- }
- break;
-+ case mldsaKey:
-+ /* ML DSA has fixed sizes and are handled by separate oids
-+ * for each key */
-+ minKey = ss->sec.authKeyBits;
-+ break;
-
- default:
- FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
- return SECFailure;
- }
-
- /* Too small: not good enough. Send a fatal alert. */
- if (ss->sec.authKeyBits < minKey) {
-@@ -14059,16 +14261,17 @@ SSL_SignatureSchemePrefSet(PRFileDesc *f
- SSL_GETPID(), fd, schemes[i]));
- continue;
- }
-
- ss->ssl3.signatureSchemes[ss->ssl3.signatureSchemeCount++] = schemes[i];
- }
-
- if (ss->ssl3.signatureSchemeCount == 0) {
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
- PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
- return SECFailure;
- }
- return SECSuccess;
- }
-
- SECStatus
- SSL_SignaturePrefSet(PRFileDesc *fd, const SSLSignatureAndHashAlg *algorithms,
-diff --git a/lib/ssl/ssl3exthandle.c b/lib/ssl/ssl3exthandle.c
---- a/lib/ssl/ssl3exthandle.c
-+++ b/lib/ssl/ssl3exthandle.c
-@@ -1650,23 +1650,27 @@ SECStatus
- ssl3_SendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
- sslBuffer *buf, PRBool *added)
- {
- if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_2) {
- return SECSuccess;
- }
-
- PRUint16 minVersion;
-+ PRUint16 maxVersion;
- if (ss->sec.isServer) {
- minVersion = ss->version; /* CertificateRequest */
-+ maxVersion = ss->version;
- } else {
- minVersion = ss->vrange.min; /* ClientHello */
-+ maxVersion = ss->vrange.max; /* ClientHello */
- }
-
-- SECStatus rv = ssl3_EncodeSigAlgs(ss, minVersion, PR_TRUE /* forCert */,
-+ SECStatus rv = ssl3_EncodeSigAlgs(ss, minVersion, maxVersion,
-+ PR_TRUE /* forCert */,
- ss->opt.enableGrease, buf);
- if (rv != SECSuccess) {
- return SECFailure;
- }
-
- *added = PR_TRUE;
- return SECSuccess;
- }
-diff --git a/lib/ssl/sslcert.c b/lib/ssl/sslcert.c
---- a/lib/ssl/sslcert.c
-+++ b/lib/ssl/sslcert.c
-@@ -8,16 +8,17 @@
-
- #include "ssl.h"
- #include "sslimpl.h"
- #include "secoid.h" /* for SECOID_GetAlgorithmTag */
- #include "pk11func.h" /* for PK11_ReferenceSlot */
- #include "nss.h" /* for NSS_RegisterShutdown */
- #include "prinit.h" /* for PR_CallOnceWithArg */
- #include "tls13subcerts.h" /* for tls13_ReadDelegatedCredential */
-+#include "secmodti.h" /* for private OID defines, don't upstream */
-
- /* This global item is used only in servers. It is is initialized by
- * SSL_ConfigSecureServer(), and is used in ssl3_SendCertificateRequest().
- */
- static struct {
- PRCallOnceType setup;
- CERTDistNames *names;
- } ssl_server_ca_list;
-@@ -565,16 +566,34 @@ ssl_GetCertificateAuthTypes(CERTCertific
- authTypes |= 1 << ssl_auth_ecdsa;
- }
- /* Again, bad form to have dual usage and we don't prevent it. */
- if (cert->keyUsage & KU_KEY_ENCIPHERMENT) {
- authTypes |= 1 << ssl_GetEcdhAuthType(cert);
- }
- break;
-
-+ case SEC_OID_ML_DSA_44:
-+ if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
-+ authTypes |= 1 << ssl_auth_mldsa44;
-+ }
-+ break;
-+
-+ case SEC_OID_ML_DSA_65:
-+ if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
-+ authTypes |= 1 << ssl_auth_mldsa65;
-+ }
-+ break;
-+
-+ case SEC_OID_ML_DSA_87:
-+ if (cert->keyUsage & KU_DIGITAL_SIGNATURE) {
-+ authTypes |= 1 << ssl_auth_mldsa87;
-+ }
-+ break;
-+
- default:
- break;
- }
-
- /* Check that we successfully picked an authType */
- if (targetAuthType != ssl_auth_null) {
- authTypes &= 1 << targetAuthType;
- }
-@@ -726,16 +745,25 @@ ssl_CertSuitableForAuthType(CERTCertific
- case SEC_OID_ANSIX9_DSA_SIGNATURE:
- mask |= 1 << ssl_auth_dsa;
- break;
- case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
- mask |= 1 << ssl_auth_ecdsa;
- mask |= 1 << ssl_auth_ecdh_rsa;
- mask |= 1 << ssl_auth_ecdh_ecdsa;
- break;
-+ case SEC_OID_ML_DSA_44:
-+ mask |= 1 << ssl_auth_mldsa44;
-+ break;
-+ case SEC_OID_ML_DSA_65:
-+ mask |= 1 << ssl_auth_mldsa65;
-+ break;
-+ case SEC_OID_ML_DSA_87:
-+ mask |= 1 << ssl_auth_mldsa87;
-+ break;
- default:
- break;
- }
- PORT_Assert(authTypes);
- /* Simply test that no inappropriate auth types are set. */
- return (authTypes & ~mask) == 0;
- }
-
-diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h
---- a/lib/ssl/sslimpl.h
-+++ b/lib/ssl/sslimpl.h
-@@ -41,16 +41,17 @@ typedef struct sslNamedGroupDefStr sslNa
- typedef struct sslEchConfigStr sslEchConfig;
- typedef struct sslEchConfigContentsStr sslEchConfigContents;
- typedef struct sslEchCookieDataStr sslEchCookieData;
- typedef struct sslEchXtnStateStr sslEchXtnState;
- typedef struct sslPskStr sslPsk;
- typedef struct sslDelegatedCredentialStr sslDelegatedCredential;
- typedef struct sslEphemeralKeyPairStr sslEphemeralKeyPair;
- typedef struct TLS13KeyShareEntryStr TLS13KeyShareEntry;
-+typedef struct tlsSignOrVerifyContextStr tlsSignOrVerifyContext;
-
- #include "sslencode.h"
- #include "sslexp.h"
- #include "ssl3ext.h"
- #include "sslspec.h"
-
- #if defined(DEBUG) || defined(TRACE)
- #ifdef __cplusplus
-@@ -108,17 +109,17 @@ typedef enum { SSLAppOpRead = 0,
-
- #define SSL_MIN_CHALLENGE_BYTES 16
- #define SSL_MAX_CHALLENGE_BYTES 32
-
- #define SSL3_MASTER_SECRET_LENGTH 48
-
- /* number of wrap mechanisms potentially used to wrap master secrets. */
- #define SSL_NUM_WRAP_MECHS 15
--#define SSL_NUM_WRAP_KEYS 6
-+#define SSL_NUM_WRAP_KEYS 9
-
- /* This makes the cert cache entry exactly 4k. */
- #define SSL_MAX_CACHED_CERT_LEN 4060
-
- #ifndef BPB
- #define BPB 8 /* Bits Per Byte */
- #endif
-
-@@ -1689,30 +1690,39 @@ extern SECStatus ssl_CheckSignatureSchem
- sslSocket *ss, SSLSignatureScheme scheme, CERTSubjectPublicKeyInfo *spki);
- extern SECStatus ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena,
- SSLSignatureScheme **schemesOut,
- unsigned int *numSchemesOut,
- unsigned char **b,
- unsigned int *len);
- extern SECStatus ssl_ConsumeSignatureScheme(
- sslSocket *ss, PRUint8 **b, PRUint32 *length, SSLSignatureScheme *out);
--extern SECStatus ssl3_SignHashesWithPrivKey(SSL3Hashes *hash,
-- SECKEYPrivateKey *key,
-- SSLSignatureScheme scheme,
-- PRBool isTls,
-- SECItem *buf);
- extern SECStatus ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash,
- SECKEYPrivateKey *key, SECItem *buf);
--extern SECStatus ssl_VerifySignedHashesWithPubKey(sslSocket *ss,
-- SECKEYPublicKey *spki,
-- SSLSignatureScheme scheme,
-- SSL3Hashes *hash,
-- SECItem *buf);
- extern SECStatus ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme,
- SSL3Hashes *hash, SECItem *buf);
-+/* new signaure algorithms don't really have a 'sign hashes' interface,
-+ * TLS13 now supports proper signing, where, if we are signing hashes, we
-+ * will sign them with a proper hash and signed signature. Provide
-+ * an API for those places in tls 13 where we need to sign. This leverages
-+ * the work in secsign and secvfy, so we don't need to add a lot of
-+ * algorithm specific code. Once the sign/verify interfaces work, we can
-+ * just add the oid in tls13con.c and the ssl_sig_xxxx value and we are
-+ * good to go */
-+extern tlsSignOrVerifyContext * tls_SignOrVerifyGetNewContext(
-+ SECKEYPrivateKey *privKey,
-+ SECKEYPublicKey *pubKey,
-+ SSLSignatureScheme scheme, PRBool sign,
-+ SECItem *signature, void *pwArg);
-+SECStatus tls_SignOrVerifyUpdate(tlsSignOrVerifyContext *ctx,
-+ const unsigned char *buf, int len);
-+SECStatus tls_SignOrVerifyEnd(tlsSignOrVerifyContext *ctx, SECItem *sig);
-+void tls_DestroySignOrVerifyContext(tlsSignOrVerifyContext *ctx);
-+
-+
- extern SECStatus ssl3_CacheWrappedSecret(sslSocket *ss, sslSessionID *sid,
- PK11SymKey *secret);
- extern void ssl3_FreeSniNameArray(TLSExtensionData *xtnData);
-
- /* Hello Extension related routines. */
- extern void ssl3_SetSIDSessionTicket(sslSessionID *sid,
- /*in/out*/ NewSessionTicket *session_ticket);
- SECStatus ssl3_EncodeSessionTicket(sslSocket *ss,
-@@ -1789,22 +1799,24 @@ SECStatus ssl3_HandleNoCertificate(sslSo
- SECStatus ssl3_SendEmptyCertificate(sslSocket *ss);
- void ssl3_CleanupPeerCerts(sslSocket *ss);
- SECStatus ssl3_SendCertificateStatus(sslSocket *ss);
- SECStatus ssl_SetAuthKeyBits(sslSocket *ss, const SECKEYPublicKey *pubKey);
- SECStatus ssl3_HandleServerSpki(sslSocket *ss);
- SECStatus ssl3_AuthCertificate(sslSocket *ss);
- SECStatus ssl_ReadCertificateStatus(sslSocket *ss, PRUint8 *b,
- PRUint32 length);
--SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool forCert,
-+SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint16 minVersion,
-+ PRUint16 maxVersion, PRBool forCert,
- PRBool grease, sslBuffer *buf);
- SECStatus ssl3_EncodeFilteredSigAlgs(const sslSocket *ss,
- const SSLSignatureScheme *schemes,
- PRUint32 numSchemes, PRBool grease, sslBuffer *buf);
--SECStatus ssl3_FilterSigAlgs(const sslSocket *ss, PRUint16 minVersion, PRBool disableRsae, PRBool forCert,
-+SECStatus ssl3_FilterSigAlgs(const sslSocket *ss, PRUint16 minVersion,
-+ PRUint16 maxVersion, PRBool disableRsae, PRBool forCert,
- unsigned int maxSchemes, SSLSignatureScheme *filteredSchemes,
- unsigned int *numFilteredSchemes);
- SECStatus ssl_GetCertificateRequestCAs(const sslSocket *ss,
- unsigned int *calenp,
- const SECItem **namesp,
- unsigned int *nnamesp);
- SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b,
- PRUint32 *length, CERTDistNames *ca_list);
-@@ -1854,26 +1866,28 @@ SECStatus ssl_PickSignatureScheme(sslSoc
- SSLSignatureScheme *schemPtr);
- SECStatus ssl_PickClientSignatureScheme(sslSocket *ss,
- CERTCertificate *clientCertificate,
- SECKEYPrivateKey *privKey,
- const SSLSignatureScheme *schemes,
- unsigned int numSchemes,
- SSLSignatureScheme *schemePtr);
- SECOidTag ssl3_HashTypeToOID(SSLHashType hashType);
--SECOidTag ssl3_AuthTypeToOID(SSLAuthType hashType);
-+SECOidTag ssl3_AuthTypeToOID(SSLAuthType authType);
- SSLHashType ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme);
- SSLAuthType ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme);
-
- SECStatus ssl3_SetupCipherSuite(sslSocket *ss, PRBool initHashes);
- SECStatus ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
- SSLContentType contentType, sslBuffer *wrBuf,
- PRBool *needsLength);
- PRBool ssl_SignatureSchemeValid(SSLSignatureScheme scheme, SECOidTag spkiOid,
- PRBool isTls13);
-+SSLSignatureScheme ssl_SignatureSchemeFromPublicKeyOid(SECOidTag tag);
-+
-
- /* Pull in DTLS functions */
- #include "dtlscon.h"
-
- /* Pull in TLS 1.3 functions */
- #include "tls13con.h"
- #include "dtls13con.h"
-
-diff --git a/lib/ssl/sslt.h b/lib/ssl/sslt.h
---- a/lib/ssl/sslt.h
-+++ b/lib/ssl/sslt.h
-@@ -116,17 +116,20 @@ typedef enum {
- /* ssl_hash_none is used internally to mean the pre-1.2 combination of MD5
- * and SHA1. The other values are only used in TLS 1.2. */
- ssl_hash_none = 0,
- ssl_hash_md5 = 1,
- ssl_hash_sha1 = 2,
- ssl_hash_sha224 = 3,
- ssl_hash_sha256 = 4,
- ssl_hash_sha384 = 5,
-- ssl_hash_sha512 = 6
-+ ssl_hash_sha512 = 6,
-+ ssl_hash_mldsa44 = 7, /* these make sure mldsa works, */
-+ ssl_hash_mldsa65 = 8, /* but only for tls 1.3, attempts */
-+ ssl_hash_mldsa87 = 9, /* to hash will these will fail */
- } SSLHashType;
-
- /* Deprecated */
- typedef struct SSLSignatureAndHashAlgStr {
- SSLHashType hashAlg;
- SSLSignType sigAlg;
- } SSLSignatureAndHashAlg;
-
-@@ -151,16 +154,20 @@ typedef enum {
- ssl_sig_rsa_pss_pss_sha512 = 0x080b,
-
- ssl_sig_dsa_sha1 = 0x0202,
- ssl_sig_dsa_sha256 = 0x0402,
- ssl_sig_dsa_sha384 = 0x0502,
- ssl_sig_dsa_sha512 = 0x0602,
- ssl_sig_ecdsa_sha1 = 0x0203,
-
-+ ssl_sig_mldsa44 = 0x0904,
-+ ssl_sig_mldsa65 = 0x0905,
-+ ssl_sig_mldsa87 = 0x0906,
-+
- /* The following value (which can't be used in the protocol), represents
- * the RSA signature using SHA-1 and MD5 that is used in TLS 1.0 and 1.1.
- * This is reported as a signature scheme when TLS 1.0 or 1.1 is used.
- * This should not be passed to SSL_SignatureSchemePrefSet(); this
- * signature scheme is always used and cannot be disabled. */
- ssl_sig_rsa_pkcs1_sha1md5 = 0x10101,
- } SSLSignatureScheme;
-
-@@ -180,16 +187,19 @@ typedef enum {
- ssl_auth_kea = 3, /* unused */
- ssl_auth_ecdsa = 4,
- ssl_auth_ecdh_rsa = 5, /* ECDH cert with an RSA signature. */
- ssl_auth_ecdh_ecdsa = 6, /* ECDH cert with an ECDSA signature. */
- ssl_auth_rsa_sign = 7, /* RSA signing with an rsaEncryption key. */
- ssl_auth_rsa_pss = 8, /* RSA signing with a PSS key. */
- ssl_auth_psk = 9,
- ssl_auth_tls13_any = 10,
-+ ssl_auth_mldsa44 = 11, /* use separate auth for each paramset */
-+ ssl_auth_mldsa65 = 12, /* so we can properly identify the certs */
-+ ssl_auth_mldsa87 = 13,
- ssl_auth_size /* number of authentication types */
- } SSLAuthType;
-
- typedef enum {
- ssl_psk_none = 0,
- ssl_psk_resume = 1,
- ssl_psk_external = 2,
- } SSLPskType;
-diff --git a/lib/ssl/tls13con.c b/lib/ssl/tls13con.c
---- a/lib/ssl/tls13con.c
-+++ b/lib/ssl/tls13con.c
-@@ -10,16 +10,19 @@
- #include "stdarg.h"
- #include "cert.h"
- #include "ssl.h"
- #include "keyhi.h"
- #include "pk11func.h"
- #include "prerr.h"
- #include "secitem.h"
- #include "secmod.h"
-+#include "secmodti.h" /* don't upstream, to get private SEC_OID_ defines */
-+#include "cryptohi.h"
-+#include "sechash.h"
- #include "sslimpl.h"
- #include "sslproto.h"
- #include "sslerr.h"
- #include "ssl3exthandle.h"
- #include "tls13hkdf.h"
- #include "tls13con.h"
- #include "tls13err.h"
- #include "tls13ech.h"
-@@ -4494,76 +4497,368 @@ tls13_HandleCertificate(sslSocket *ss, P
-
- first = PR_FALSE;
- }
- SECKEY_UpdateCertPQG(ss->sec.peerCert);
-
- return ssl3_AuthCertificate(ss); /* sets ss->ssl3.hs.ws */
- }
-
-+/* this should be in cryptohi, but we need can't create a new API
-+ * for it which doesn't try to parse old parameters and select things
-+ * based on the privkey stuff */
-+static
-+SECItem *
-+tls_encodeRSAParams(PLArenaPool *arena, SECOidTag hashAlgTag)
-+{
-+ SECKEYRSAPSSParams pssParams;
-+ SECStatus rv;
-+ int saltLen;
-+ SECItem *hashAlgItem = NULL;
-+ SECItem *saltItem = NULL;
-+
-+ PORT_Memset(&pssParams, 0, sizeof(pssParams));
-+
-+ /* RSA PSS let's us default SHA1, but we know this can only be called
-+ * for TLS 1.3 and greater, and there isn't any SHA-1 in TLS 1.3, so
-+ * we can skip those checks */
-+ pssParams.hashAlg = PORT_ArenaZNew(arena, SECAlgorithmID);
-+ if (!pssParams.hashAlg) {
-+ return NULL;
-+ }
-+ rv = SECOID_SetAlgorithmID(arena, pssParams.hashAlg, hashAlgTag, NULL);
-+ if (rv != SECSuccess) {
-+ return NULL;
-+ }
-+ hashAlgItem = SEC_ASN1EncodeItem(arena, NULL, pssParams.hashAlg,
-+ SEC_ASN1_GET(SECOID_AlgorithmIDTemplate));
-+ if (!hashAlgItem) {
-+ return NULL;
-+ }
-+ pssParams.maskAlg = PORT_ArenaZNew(arena, SECAlgorithmID);
-+ if (!pssParams.maskAlg) {
-+ return NULL;
-+ }
-+ rv = SECOID_SetAlgorithmID(arena, pssParams.maskAlg,
-+ SEC_OID_PKCS1_MGF1, hashAlgItem);
-+ if (rv != SECSuccess) {
-+ return NULL;
-+ }
-+ saltLen = HASH_ResultLenByOidTag(hashAlgTag);
-+ if (saltLen == 0) {
-+ return NULL;
-+ }
-+ saltItem = SEC_ASN1EncodeInteger(arena, &pssParams.saltLength, saltLen);
-+ if (!saltItem) {
-+ return NULL;
-+ }
-+ return SEC_ASN1EncodeItem(arena, NULL, &pssParams, SECKEY_RSAPSSParamsTemplate);
-+}
-+
-+/* we put this here because it only affects TLS 1.3, TLS 1.2 and earlier
-+ * use the old sign hashes interface. TLS 1.3 is friendly to algorthims
-+ * that don't have a signed hashes interface */
-+/* we generate an algorithm ID rather than just use an OID to support RSAPSS.
-+ * It's generated completely from the scheme, without the key */
-+SECAlgorithmID *
-+tls_GetSignatureAlgorithmId(PLArenaPool *arena, SSLSignatureScheme scheme)
-+{
-+ SECAlgorithmID *newAlgID = PORT_ArenaZNew(arena, SECAlgorithmID);
-+ SECOidTag algTag = SEC_OID_UNKNOWN;
-+ SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
-+ SECItem *params = NULL;
-+ SECStatus rv;
-+
-+ switch (scheme) {
-+ /* do rsa PSS first because it needs to set the params
-+ * for the algTag the difference between rsa_pss_rsae and
-+ * rsa_pss_pss is in the selection an validation of the cert
-+ * At this stage, the signatures are the same, so for our
-+ * purposed they are equivalent */
-+ case ssl_sig_rsa_pss_rsae_sha256:
-+ case ssl_sig_rsa_pss_pss_sha256:
-+ hashAlgTag = SEC_OID_SHA256;
-+ goto rsa_pss_next;
-+ case ssl_sig_rsa_pss_rsae_sha384:
-+ case ssl_sig_rsa_pss_pss_sha384:
-+ hashAlgTag = SEC_OID_SHA384;
-+ goto rsa_pss_next;
-+ case ssl_sig_rsa_pss_rsae_sha512:
-+ case ssl_sig_rsa_pss_pss_sha512:
-+ hashAlgTag = SEC_OID_SHA512;
-+rsa_pss_next:
-+ params = tls_encodeRSAParams(arena, hashAlgTag);
-+ if (params == NULL) {
-+ break;
-+ }
-+ algTag = SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
-+ break;
-+ /* the curve comes from the key and should have already been
-+ * enforced at a different level */
-+ case ssl_sig_ecdsa_secp256r1_sha256:
-+ algTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE;
-+ break;
-+ case ssl_sig_ecdsa_secp384r1_sha384:
-+ algTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE;
-+ break;
-+ case ssl_sig_ecdsa_secp521r1_sha512:
-+ algTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE;
-+ break;
-+ case ssl_sig_mldsa44:
-+ algTag = SEC_OID_ML_DSA_44;
-+ break;
-+ case ssl_sig_mldsa65:
-+ algTag = SEC_OID_ML_DSA_65;
-+ break;
-+ case ssl_sig_mldsa87:
-+ algTag = SEC_OID_ML_DSA_87;
-+ break;
-+
-+ /* the following is unsupported in tls 1.3 and greater, just break.
-+ * We include them here explicitly so we get the compiler warning about
-+ * missing enums in the switch statement. default would be a break anyway.
-+ * That way we'll know to update this table when new algorithsm are
-+ * added */
-+
-+ /* as of now sig ed is not supported in NSS. That could change, and this
-+ * is part the code that would pick up the change (need OIDS for the
-+ * hash variants of these signature, and then add them here) */
-+ case ssl_sig_ed25519:
-+ case ssl_sig_ed448:
-+
-+ /* sha1 hashes in sigs are explicitly disallowed int TLS 1.3 or greater */
-+ case ssl_sig_ecdsa_sha1:
-+
-+ /* rsa pkcs1 sigs are explicitly disallowed in TLS 1.3 and greater */
-+ case ssl_sig_rsa_pkcs1_sha1:
-+ case ssl_sig_rsa_pkcs1_sha256:
-+ case ssl_sig_rsa_pkcs1_sha384:
-+ case ssl_sig_rsa_pkcs1_sha512:
-+
-+ /* dsa sigs are explicitly disallowed in TLS 1.3 and greater */
-+ case ssl_sig_dsa_sha1:
-+ case ssl_sig_dsa_sha256:
-+ case ssl_sig_dsa_sha384:
-+ case ssl_sig_dsa_sha512:
-+
-+ /* special sig variants that aren't supported in TLS 1.3 or greater */
-+ case ssl_sig_rsa_pkcs1_sha1md5:
-+ case ssl_sig_none:
-+ break;
-+ }
-+
-+ /* the earlier code should have made sure none of the unsupported
-+ * algorithms were accepted */
-+ PORT_Assert(algTag != SEC_OID_UNKNOWN);
-+ if (algTag == SEC_OID_UNKNOWN) {
-+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
-+ return NULL;
-+ }
-+
-+ rv = SECOID_SetAlgorithmID(arena, newAlgID, algTag, params);
-+ if (rv != SECSuccess) {
-+ return NULL;
-+ }
-+ return newAlgID;
-+}
-+
-+struct tlsSignOrVerifyContextStr {
-+ PRBool sign;
-+ union {
-+ SGNContext *sig;
-+ VFYContext *vfy;
-+ } u;
-+};
-+
-+tlsSignOrVerifyContext *
-+tls_SignOrVerifyGetNewContext(SECKEYPrivateKey *privKey,
-+ SECKEYPublicKey *pubKey,
-+ SSLSignatureScheme scheme, PRBool sign,
-+ SECItem *signature, void *pwArg)
-+{
-+ PLArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-+ SECAlgorithmID *sigAlgID = NULL;
-+ tlsSignOrVerifyContext *newCtx = PORT_ZNew(tlsSignOrVerifyContext);
-+ SECStatus rv;
-+
-+ if (!newCtx) {
-+ goto loser;
-+ }
-+
-+ if (!arena) {
-+ goto loser;
-+ }
-+
-+ if (sign) {
-+ PORT_Assert(privKey);
-+ } else {
-+ PORT_Assert(pubKey);
-+ }
-+
-+ if ((sign && !privKey) || (!sign && !pubKey)) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ goto loser;
-+ }
-+
-+ newCtx->sign = sign;
-+
-+ sigAlgID = tls_GetSignatureAlgorithmId(arena, scheme);
-+ if (sigAlgID == NULL) {
-+ goto loser;
-+ }
-+ if (sign) {
-+ newCtx->u.sig= SGN_NewContextWithAlgorithmID(sigAlgID, privKey);
-+ if (!newCtx->u.sig) {
-+ goto loser;
-+ }
-+ rv = SGN_Begin(newCtx->u.sig);
-+ } else {
-+ newCtx->u.vfy = VFY_CreateContextWithAlgorithmID(pubKey, signature,
-+ sigAlgID, NULL, pwArg);
-+ if (!newCtx->u.vfy) {
-+ goto loser;
-+ }
-+ rv = VFY_Begin(newCtx->u.vfy);
-+ }
-+ if (rv != SECSuccess) {
-+ goto loser;
-+ }
-+ PORT_FreeArena(arena, PR_FALSE);
-+ return (newCtx);
-+
-+loser:
-+ tls_DestroySignOrVerifyContext(newCtx);
-+ if (arena) {
-+ PORT_FreeArena(arena, PR_FALSE);
-+ }
-+ return NULL;
-+}
-+
-+
-+SECStatus
-+tls_SignOrVerifyUpdate(tlsSignOrVerifyContext *ctx, const unsigned char *buf,
-+ int len)
-+{
-+ SECStatus rv;
-+ if (ctx->sign) {
-+ rv = SGN_Update(ctx->u.sig, buf, len);
-+ } else {
-+ rv = VFY_Update(ctx->u.vfy, buf, len);
-+ }
-+ return rv;
-+}
-+
-+SECStatus
-+tls_SignOrVerifyEnd(tlsSignOrVerifyContext *ctx, SECItem *sig)
-+{
-+ SECStatus rv;
-+ if (ctx->sign) {
-+ rv = SGN_End(ctx->u.sig, sig);
-+ } else {
-+ /* sign is already set in the context */
-+ rv = VFY_End(ctx->u.vfy);
-+ }
-+ return rv;
-+}
-+
-+void
-+tls_DestroySignOrVerifyContext(tlsSignOrVerifyContext *ctx)
-+{
-+ if (!ctx) {
-+ return;
-+ }
-+ if (ctx->sign) {
-+ if (ctx->u.sig) {
-+ SGN_DestroyContext(ctx->u.sig, PR_TRUE);
-+ }
-+ } else {
-+ if (ctx->u.vfy) {
-+ VFY_DestroyContext(ctx->u.vfy, PR_TRUE);
-+ }
-+ }
-+ PORT_Free(ctx);
-+}
-+
-+
- /* Add context to the hash functions as described in
- [draft-ietf-tls-tls13; Section 4.9.1] */
- SECStatus
--tls13_AddContextToHashes(sslSocket *ss, const SSL3Hashes *hashes,
-- SSLHashType algorithm, PRBool sending,
-- SSL3Hashes *tbsHash)
-+tls13_SignOrVerifyHashWithContext(sslSocket *ss, const SSL3Hashes *hashes,
-+ SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey,
-+ SSLSignatureScheme scheme, PRBool sending,
-+ SECItem *signature)
- {
- SECStatus rv = SECSuccess;
-- PK11Context *ctx;
-+ tlsSignOrVerifyContext *ctx = NULL;
-+ void *pwArg = ss->pkcs11PinArg;
- const unsigned char context_padding[] = {
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
- };
-
- const char *client_cert_verify_string = "TLS 1.3, client CertificateVerify";
- const char *server_cert_verify_string = "TLS 1.3, server CertificateVerify";
- const char *context_string = (sending ^ ss->sec.isServer) ? client_cert_verify_string
- : server_cert_verify_string;
-- unsigned int hashlength;
-
- /* Double check that we are doing the same hash.*/
- PORT_Assert(hashes->len == tls13_GetHashSize(ss));
--
-- ctx = PK11_CreateDigestContext(ssl3_HashTypeToOID(algorithm));
-- if (!ctx) {
-- PORT_SetError(SEC_ERROR_NO_MEMORY);
-- goto loser;
-- }
--
-- PORT_Assert(SECFailure);
-- PORT_Assert(!SECSuccess);
-+ if (hashes->len != tls13_GetHashSize(ss)) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return SECFailure;
-+ }
-
- PRINT_BUF(50, (ss, "TLS 1.3 hash without context", hashes->u.raw, hashes->len));
- PRINT_BUF(50, (ss, "Context string", context_string, strlen(context_string)));
-- rv |= PK11_DigestBegin(ctx);
-- rv |= PK11_DigestOp(ctx, context_padding, sizeof(context_padding));
-- rv |= PK11_DigestOp(ctx, (unsigned char *)context_string,
-- strlen(context_string) + 1); /* +1 includes the terminating 0 */
-- rv |= PK11_DigestOp(ctx, hashes->u.raw, hashes->len);
-- /* Update the hash in-place */
-- rv |= PK11_DigestFinal(ctx, tbsHash->u.raw, &hashlength, sizeof(tbsHash->u.raw));
-- PK11_DestroyContext(ctx, PR_TRUE);
-- PRINT_BUF(50, (ss, "TLS 1.3 hash with context", tbsHash->u.raw, hashlength));
--
-- tbsHash->len = hashlength;
-- tbsHash->hashAlg = algorithm;
--
-+
-+ ctx = tls_SignOrVerifyGetNewContext(privKey, pubKey, scheme,
-+ sending, signature, pwArg);
-+ if (ctx == NULL) {
-+ goto loser;
-+ }
-+
-+ rv = tls_SignOrVerifyUpdate(ctx, context_padding, sizeof(context_padding));
-+ if (rv != SECSuccess) {
-+ goto loser;
-+ }
-+ rv = tls_SignOrVerifyUpdate(ctx, (const unsigned char *)context_string,
-+ /* +1 includes the terminating 0 */
-+ strlen(context_string) + 1);
-+ if (rv != SECSuccess) {
-+ goto loser;
-+ }
-+ rv = tls_SignOrVerifyUpdate(ctx, hashes->u.raw, hashes->len);
-+ if (rv != SECSuccess) {
-+ goto loser;
-+ }
-+ rv = tls_SignOrVerifyEnd(ctx, signature);
- if (rv) {
- ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
- goto loser;
- }
-+ tls_DestroySignOrVerifyContext(ctx);
-+
-+ /* if we are server & sending or !server & !sending, update the scheme */
-+ /* only update on server cert verify */
-+ if (((ss->sec.isServer) ^ sending) == 0){
-+ ss->sec.signatureScheme = scheme;
-+ ss->sec.authType = ssl_SignatureSchemeToAuthType(scheme);
-+ }
-+
- return SECSuccess;
-
- loser:
-+ tls_DestroySignOrVerifyContext(ctx);
-+
- return SECFailure;
- }
-
- /*
- * Derive-Secret(Secret, Label, Messages) =
- * HKDF-Expand-Label(Secret, Label,
- * Hash(Messages) + Hash(resumption_context), L))
- */
-@@ -5358,19 +5653,17 @@ loser:
- }
-
- SECStatus
- tls13_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey)
- {
- SECStatus rv = SECFailure;
- SECItem buf = { siBuffer, NULL, 0 };
- unsigned int len;
-- SSLHashType hashAlg;
- SSL3Hashes hash;
-- SSL3Hashes tbsHash; /* The hash "to be signed". */
-
- PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
- PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
-
- SSL_TRC(3, ("%d: TLS13[%d]: send certificate_verify handshake",
- SSL_GETPID(), ss->fd));
-
- PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_single);
-@@ -5381,41 +5674,37 @@ tls13_SendCertificateVerify(sslSocket *s
-
- /* We should have picked a signature scheme when we received a
- * CertificateRequest, or when we picked a server certificate. */
- PORT_Assert(ss->ssl3.hs.signatureScheme != ssl_sig_none);
- if (ss->ssl3.hs.signatureScheme == ssl_sig_none) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-- hashAlg = ssl_SignatureSchemeToHashType(ss->ssl3.hs.signatureScheme);
-- rv = tls13_AddContextToHashes(ss, &hash, hashAlg,
-- PR_TRUE, &tbsHash);
-- if (rv != SECSuccess) {
-- return SECFailure;
-- }
--
-- rv = ssl3_SignHashes(ss, &tbsHash, privKey, &buf);
-+
-+ rv = tls13_SignOrVerifyHashWithContext(ss, &hash, privKey, NULL,
-+ ss->ssl3.hs.signatureScheme,
-+ PR_TRUE, &buf);
- if (rv == SECSuccess && !ss->sec.isServer) {
- /* Remember the info about the slot that did the signing.
- * Later, when doing an SSL restart handshake, verify this.
- * These calls are mere accessors, and can't fail.
- */
- PK11SlotInfo *slot;
- sslSessionID *sid = ss->sec.ci.sid;
-
- slot = PK11_GetSlotFromPrivateKey(privKey);
- sid->u.ssl3.clAuthSeries = PK11_GetSlotSeries(slot);
- sid->u.ssl3.clAuthSlotID = PK11_GetSlotID(slot);
- sid->u.ssl3.clAuthModuleID = PK11_GetModuleID(slot);
- sid->u.ssl3.clAuthValid = PR_TRUE;
- PK11_FreeSlot(slot);
- }
- if (rv != SECSuccess) {
-- goto done; /* err code was set by ssl3_SignHashes */
-+ goto done; /* err code was set by tls13_SignOrVerifyHashWithContext */
- }
-
- len = buf.len + 2 + 2;
-
- rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_certificate_verify, len);
- if (rv != SECSuccess) {
- goto done; /* error code set by AppendHandshake */
- }
-@@ -5446,18 +5735,16 @@ SECStatus
- tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
- {
- sslDelegatedCredential *dc = ss->xtnData.peerDelegCred;
- CERTSubjectPublicKeyInfo *spki;
- SECKEYPublicKey *pubKey = NULL;
- SECItem signed_hash = { siBuffer, NULL, 0 };
- SECStatus rv;
- SSLSignatureScheme sigScheme;
-- SSLHashType hashAlg;
-- SSL3Hashes tbsHash;
- SSL3Hashes hashes;
-
- SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_verify handshake",
- SSL_GETPID(), ss->fd));
- PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
- PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
-
- rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY,
-@@ -5521,23 +5808,16 @@ tls13_HandleCertificateVerify(sslSocket
- }
-
- rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme, spki);
- if (rv != SECSuccess) {
- /* Error set already */
- FATAL_ERROR(ss, PORT_GetError(), illegal_parameter);
- return SECFailure;
- }
-- hashAlg = ssl_SignatureSchemeToHashType(sigScheme);
--
-- rv = tls13_AddContextToHashes(ss, &hashes, hashAlg, PR_FALSE, &tbsHash);
-- if (rv != SECSuccess) {
-- FATAL_ERROR(ss, SSL_ERROR_DIGEST_FAILURE, internal_error);
-- return SECFailure;
-- }
-
- rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length);
- if (rv != SECSuccess) {
- PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_VERIFY);
- return SECFailure;
- }
-
- if (length != 0) {
-@@ -5545,19 +5825,18 @@ tls13_HandleCertificateVerify(sslSocket
- return SECFailure;
- }
-
- pubKey = SECKEY_ExtractPublicKey(spki);
- if (pubKey == NULL) {
- ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
- return SECFailure;
- }
--
-- rv = ssl_VerifySignedHashesWithPubKey(ss, pubKey, sigScheme,
-- &tbsHash, &signed_hash);
-+ rv = tls13_SignOrVerifyHashWithContext(ss, &hashes, NULL, pubKey,
-+ sigScheme, PR_FALSE, &signed_hash);
- if (rv != SECSuccess) {
- FATAL_ERROR(ss, PORT_GetError(), decrypt_error);
- goto loser;
- }
-
- /* Set the auth type and verify it is what we captured in ssl3_AuthCertificate */
- if (!ss->sec.isServer) {
- ss->sec.authType = ssl_SignatureSchemeToAuthType(sigScheme);
-diff --git a/lib/ssl/tls13exthandle.c b/lib/ssl/tls13exthandle.c
---- a/lib/ssl/tls13exthandle.c
-+++ b/lib/ssl/tls13exthandle.c
-@@ -1467,17 +1467,17 @@ tls13_ClientSendDelegatedCredentialsXtn(
- }
-
- /* Filter the schemes that are enabled and acceptable. Save these in
- * the "advertised" list, then encode them to be sent. If we receive
- * a DC in response, validate that it matches one of the advertised
- * schemes. */
- SSLSignatureScheme filtered[MAX_SIGNATURE_SCHEMES] = { 0 };
- unsigned int filteredCount = 0;
-- SECStatus rv = ssl3_FilterSigAlgs(ss, ss->vrange.max,
-+ SECStatus rv = ssl3_FilterSigAlgs(ss, ss->vrange.min, ss->vrange.max,
- PR_TRUE /* disableRsae */,
- PR_FALSE /* forCert */,
- MAX_SIGNATURE_SCHEMES,
- filtered,
- &filteredCount);
- if (rv != SECSuccess) {
- return SECFailure;
- }
-diff --git a/lib/ssl/tls13subcerts.c b/lib/ssl/tls13subcerts.c
---- a/lib/ssl/tls13subcerts.c
-+++ b/lib/ssl/tls13subcerts.c
-@@ -281,30 +281,31 @@ tls13_AppendCredentialSignature(sslBuffe
- return SECFailure;
- }
-
- return SECSuccess;
- }
-
- /* Hashes the message used to sign/verify the DC. */
- static SECStatus
--tls13_HashCredentialSignatureMessage(SSL3Hashes *hash,
-- SSLSignatureScheme scheme,
-- const CERTCertificate *cert,
-- const sslBuffer *dcBuf)
-+tls13_HashCredentialAndSignOrVerifyMessage(SECKEYPrivateKey *privKey,
-+ SECKEYPublicKey *pubKey,
-+ SSLSignatureScheme scheme,
-+ PRBool signing,
-+ const CERTCertificate *cert,
-+ const sslBuffer *dcBuf,
-+ SECItem *signature, void *pwArg)
- {
- SECStatus rv;
-- PK11Context *ctx = NULL;
-- unsigned int hashLen;
-+ tlsSignOrVerifyContext *ctx = NULL;
-
-- /* Set up hash context. */
-- hash->hashAlg = ssl_SignatureSchemeToHashType(scheme);
-- ctx = PK11_CreateDigestContext(ssl3_HashTypeToOID(hash->hashAlg));
-+ /* Set up sign and hash context. */
-+ ctx = tls_SignOrVerifyGetNewContext(privKey, pubKey, scheme, signing,
-+ signature, pwArg);
- if (!ctx) {
-- PORT_SetError(SEC_ERROR_NO_MEMORY);
- goto loser;
- }
-
- static const PRUint8 kCtxStrPadding[64] = {
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-@@ -312,73 +313,62 @@ tls13_HashCredentialSignatureMessage(SSL
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
- };
-
- static const PRUint8 kCtxStr[] = "TLS, server delegated credentials";
-
- /* Hash the message signed by the peer. */
-- rv = SECSuccess;
-- rv |= PK11_DigestBegin(ctx);
-- rv |= PK11_DigestOp(ctx, kCtxStrPadding, sizeof kCtxStrPadding);
-- rv |= PK11_DigestOp(ctx, kCtxStr, 1 /* 0-byte */ + strlen((const char *)kCtxStr));
-- rv |= PK11_DigestOp(ctx, cert->derCert.data, cert->derCert.len);
-- rv |= PK11_DigestOp(ctx, dcBuf->buf, dcBuf->len);
-- rv |= PK11_DigestFinal(ctx, hash->u.raw, &hashLen, sizeof hash->u.raw);
-- if (rv != SECSuccess) {
-- PORT_SetError(SSL_ERROR_SHA_DIGEST_FAILURE);
-- goto loser;
-- }
--
-- hash->len = hashLen;
-- if (ctx) {
-- PK11_DestroyContext(ctx, PR_TRUE);
-- }
-+ rv = tls_SignOrVerifyUpdate(ctx, kCtxStrPadding, sizeof kCtxStrPadding);
-+ if (rv != SECSuccess) goto loser;
-+ rv = tls_SignOrVerifyUpdate(ctx, kCtxStr,
-+ 1 /* 0-byte */ + strlen((const char *)kCtxStr));
-+ if (rv != SECSuccess) goto loser;
-+ rv = tls_SignOrVerifyUpdate(ctx, cert->derCert.data, cert->derCert.len);
-+ if (rv != SECSuccess) goto loser;
-+ rv = tls_SignOrVerifyUpdate(ctx, dcBuf->buf, dcBuf->len);
-+ if (rv != SECSuccess) goto loser;
-+ rv = tls_SignOrVerifyEnd(ctx, signature);
-+ if (rv != SECSuccess) goto loser;
-+ tls_DestroySignOrVerifyContext(ctx);
- return SECSuccess;
-
- loser:
-- if (ctx) {
-- PK11_DestroyContext(ctx, PR_TRUE);
-- }
-+ tls_DestroySignOrVerifyContext(ctx);
- return SECFailure;
- }
-
- /* Verifies the DC signature. */
- static SECStatus
- tls13_VerifyCredentialSignature(sslSocket *ss, sslDelegatedCredential *dc)
- {
- SECStatus rv = SECSuccess;
-- SSL3Hashes hash;
- sslBuffer dcBuf = SSL_BUFFER_EMPTY;
- CERTCertificate *cert = ss->sec.peerCert;
- SECKEYPublicKey *pubKey = NULL;
-+ void *pwArg = ss->pkcs11PinArg;
-+
-
- /* Serialize the DC parameters. */
- rv = tls13_AppendCredentialParams(&dcBuf, dc);
- if (rv != SECSuccess) {
- goto loser; /* Error set by caller. */
- }
-
-- /* Hash the message that was signed by the delegator. */
-- rv = tls13_HashCredentialSignatureMessage(&hash, dc->alg, cert, &dcBuf);
-- if (rv != SECSuccess) {
-- FATAL_ERROR(ss, PORT_GetError(), internal_error);
-- goto loser;
-- }
--
- pubKey = SECKEY_ExtractPublicKey(&cert->subjectPublicKeyInfo);
- if (pubKey == NULL) {
- FATAL_ERROR(ss, SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE, internal_error);
- goto loser;
- }
-
-- /* Verify the signature of the message. */
-- rv = ssl_VerifySignedHashesWithPubKey(ss, pubKey, dc->alg,
-- &hash, &dc->signature);
-+ /* Verify the signature of the delegaor message. */
-+ rv = tls13_HashCredentialAndSignOrVerifyMessage(NULL, pubKey, dc->alg,
-+ PR_FALSE, cert, &dcBuf,
-+ &dc->signature, pwArg);
- if (rv != SECSuccess) {
- FATAL_ERROR(ss, SSL_ERROR_DC_BAD_SIGNATURE, illegal_parameter);
- goto loser;
- }
-
- SECOidTag spkiAlg = SECOID_GetAlgorithmTag(&(dc->spki->algorithm));
- if (spkiAlg == SEC_OID_PKCS1_RSA_ENCRYPTION) {
- FATAL_ERROR(ss, SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM, illegal_parameter);
-@@ -651,17 +641,23 @@ tls13_MakeDcSpki(const SECKEYPublicKey *
- return NULL;
- }
- if (keyScheme != dcCertVerifyAlg) {
- PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
- return NULL;
- }
- return SECKEY_CreateSubjectPublicKeyInfo(dcPub);
- }
--
-+ case mldsaKey:
-+ if (ssl_SignatureSchemeFromPublicKeyOid(dcPub->u.mldsa.params)
-+ != dcCertVerifyAlg) {
-+ PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
-+ return NULL;
-+ }
-+ return SECKEY_CreateSubjectPublicKeyInfo(dcPub);
- default:
- break;
- }
-
- PORT_SetError(SEC_ERROR_INVALID_KEY);
- return NULL;
- }
-
-@@ -683,19 +679,19 @@ SSLExp_DelegateCredential(const CERTCert
- const SECKEYPrivateKey *certPriv,
- const SECKEYPublicKey *dcPub,
- SSLSignatureScheme dcCertVerifyAlg,
- PRUint32 dcValidFor,
- PRTime now,
- SECItem *out)
- {
- SECStatus rv;
-- SSL3Hashes hash;
- CERTSubjectPublicKeyInfo *spki = NULL;
- SECKEYPrivateKey *tmpPriv = NULL;
-+ void *pwArg = certPriv->wincx;
- sslDelegatedCredential *dc = NULL;
- sslBuffer dcBuf = SSL_BUFFER_EMPTY;
-
- if (!cert || !certPriv || !dcPub || !out) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
-
-@@ -749,30 +745,27 @@ SSLExp_DelegateCredential(const CERTCert
- }
- PORT_Assert(dc->alg != ssl_sig_none);
-
- rv = tls13_AppendCredentialParams(&dcBuf, dc);
- if (rv != SECSuccess) {
- goto loser;
- }
-
-- /* Hash signature message. */
-- rv = tls13_HashCredentialSignatureMessage(&hash, dc->alg, cert, &dcBuf);
-- if (rv != SECSuccess) {
-- goto loser;
-- }
-
- /* Sign the hash with the delegation key.
- *
- * The PK11 API discards const qualifiers, so we have to make a copy of
-- * |certPriv| and pass the copy to |ssl3_SignHashesWithPrivKey|.
-+ * |certPriv| and pass the copy to
-+ * |tls3_HashCredentialAndSignOrVerifyMessage|.
- */
- tmpPriv = SECKEY_CopyPrivateKey(certPriv);
-- rv = ssl3_SignHashesWithPrivKey(&hash, tmpPriv, dc->alg,
-- PR_TRUE /* isTls */, &dc->signature);
-+ rv = tls13_HashCredentialAndSignOrVerifyMessage(tmpPriv, NULL, dc->alg,
-+ PR_TRUE, cert, &dcBuf,
-+ &dc->signature, pwArg);
- if (rv != SECSuccess) {
- goto loser;
- }
-
- /* Serialize the DC signature. */
- rv = tls13_AppendCredentialSignature(&dcBuf, dc);
- if (rv != SECSuccess) {
- goto loser;
-diff --git a/tests/cert/cert.sh b/tests/cert/cert.sh
---- a/tests/cert/cert.sh
-+++ b/tests/cert/cert.sh
-@@ -57,24 +57,16 @@ cert_init()
- Exit 5 "Fatal - Root certs module not found."
- else
- html_passed "Looking for root certs module."
- fi
-
- if [ "${OS_ARCH}" = "WINNT" -a "$OS_NAME" = "CYGWIN_NT" ]; then
- ROOTCERTSFILE=`cygpath -m ${ROOTCERTSFILE}`
- fi
--# only enable ml dsa certs if using the sql database. The dbm database does
--# not support ml_dsa certs
-- unset NSS_CERT_ENABLE_ML_DSA
-- if [ -n $"NSS_ENABLE_ML_DSA" ]; then
-- if using_sql ; then
-- export NSS_CERT_ENABLE_ML_DSA=1
-- fi
-- fi
- }
-
- cert_log() ###################### write the cert_status file
- {
- echo "$SCRIPTNAME $*"
- echo $* >>${CERT_LOG_FILE}
- }
-
-@@ -291,50 +283,51 @@ cert_create_cert()
-
- CU_ACTION="Import Root CA for $CERTNAME"
- certu -A -n "TestCA" -t "TC,TC,TC" -f "${R_PWFILE}" -d "${PROFILEDIR}" \
- -i "${R_CADIR}/TestCA.ca.cert" 2>&1
- if [ "$RET" -ne 0 ]; then
- return $RET
- fi
-
-+ if [ -z "$NSS_DISABLE_DSA" ]; then
- CU_ACTION="Import DSA Root CA for $CERTNAME"
- certu -A -n "TestCA-dsa" -t "TC,TC,TC" -f "${R_PWFILE}" \
- -d "${PROFILEDIR}" -i "${R_CADIR}/TestCA-dsa.ca.cert" 2>&1
- if [ "$RET" -ne 0 ]; then
- return $RET
- fi
--
-- if [ -n "$NSS_CERT_ENABLE_ML_DSA" ]; then
-- CU_ACTION="Import ML-DSA-44 Root CA for $CERTNAME"
-- certu -A -n "TestCA-ml-dsa-44" -t "TC,TC,TC" -f "${R_PWFILE}" \
-- -d "${PROFILEDIR}" -i "${R_CADIR}/TestCA-ml-dsa-44.ca.cert" 2>&1
-- if [ "$RET" -ne 0 ]; then
-- return $RET
-- fi
-- CU_ACTION="Import ML-DSA-65 Root CA for $CERTNAME"
-- certu -A -n "TestCA-ml-dsa-65" -t "TC,TC,TC" -f "${R_PWFILE}" \
-- -d "${PROFILEDIR}" -i "${R_CADIR}/TestCA-ml-dsa-65.ca.cert" 2>&1
-- if [ "$RET" -ne 0 ]; then
-+ fi
-+ if [ -n "$NSS_ENABLE_ML_DSA" ]; then
-+ CU_ACTION="Import ML-DSA-44 Root CA for $CERTNAME"
-+ certu -A -n "TestCA-ml-dsa-44" -t "TC,TC,TC" -f "${R_PWFILE}" \
-+ -d "${PROFILEDIR}" -i "${R_CADIR}/TestCA-ml-dsa-44.ca.cert" 2>&1
-+ if [ "$RET" -ne 0 ]; then
- return $RET
-- fi
-- CU_ACTION="Import ML-DSA-87 Root CA for $CERTNAME"
-- certu -A -n "TestCA-ml-dsa-87" -t "TC,TC,TC" -f "${R_PWFILE}" \
-- -d "${PROFILEDIR}" -i "${R_CADIR}/TestCA-ml-dsa-87.ca.cert" 2>&1
-- if [ "$RET" -ne 0 ]; then
-- return $RET
-- fi
-- fi
--
-- CU_ACTION="Import EC Root CA for $CERTNAME"
-- certu -A -n "TestCA-ec" -t "TC,TC,TC" -f "${R_PWFILE}" \
-- -d "${PROFILEDIR}" -i "${R_CADIR}/TestCA-ec.ca.cert" 2>&1
-+ fi
-+ CU_ACTION="Import ML-DSA-65 Root CA for $CERTNAME"
-+ certu -A -n "TestCA-ml-dsa-65" -t "TC,TC,TC" -f "${R_PWFILE}" \
-+ -d "${PROFILEDIR}" -i "${R_CADIR}/TestCA-ml-dsa-65.ca.cert" 2>&1
- if [ "$RET" -ne 0 ]; then
- return $RET
- fi
-+ CU_ACTION="Import ML-DSA-87 Root CA for $CERTNAME"
-+ certu -A -n "TestCA-ml-dsa-87" -t "TC,TC,TC" -f "${R_PWFILE}" \
-+ -d "${PROFILEDIR}" -i "${R_CADIR}/TestCA-ml-dsa-87.ca.cert" 2>&1
-+ if [ "$RET" -ne 0 ]; then
-+ return $RET
-+ fi
-+ fi
-+
-+ CU_ACTION="Import EC Root CA for $CERTNAME"
-+ certu -A -n "TestCA-ec" -t "TC,TC,TC" -f "${R_PWFILE}" \
-+ -d "${PROFILEDIR}" -i "${R_CADIR}/TestCA-ec.ca.cert" 2>&1
-+ if [ "$RET" -ne 0 ]; then
-+ return $RET
-+ fi
-
- cert_add_cert "$5"
- return $?
- }
-
- ############################# cert_add_cert ############################
- # local shell function to add client certs to an existing CERT DB
- # generate request
-@@ -365,16 +358,17 @@ cert_add_cert()
- return $RET
- fi
-
- cert_log "SUCCESS: $CERTNAME's Cert Created"
-
- #
- # Generate and add DSA cert
- #
-+ if [ -z "$NSS_DISABLE_DSA" ]; then
- CU_ACTION="Generate DSA Cert Request for $CERTNAME"
- CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-dsa@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
- certu -R -k dsa -d "${PROFILEDIR}" -f "${R_PWFILE}" \
- -z "${R_NOISE_FILE}" -o req 2>&1
- if [ "$RET" -ne 0 ]; then
- return $RET
- fi
-
-@@ -415,90 +409,89 @@ cert_add_cert()
-
- CU_ACTION="Import $CERTNAME's mixed DSA Cert"
- certu -A -n "${CERTNAME}-dsamixed" -t "u,u,u" -d "${PROFILEDIR}" \
- -f "${R_PWFILE}" -i "${CERTNAME}-dsamixed.cert" 2>&1
- if [ "$RET" -ne 0 ]; then
- return $RET
- fi
- cert_log "SUCCESS: $CERTNAME's mixed DSA Cert Created"
--
-- if [ -n "$NSS_CERT_ENABLE_ML_DSA" ]; then
-- CU_ACTION="Generate ML-DSA-44 Cert Request for $CERTNAME"
-- CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-ml-dsa-44@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-- certu -R -k mldsa -q ml-dsa-44 -d "${PROFILEDIR}" -f "${R_PWFILE}" \
-- -z "${R_NOISE_FILE}" -o req 2>&1
-- if [ "$RET" -ne 0 ]; then
-+ fi
-+ if [ -n "$NSS_ENABLE_ML_DSA" ]; then
-+ CU_ACTION="Generate ML-DSA-44 Cert Request for $CERTNAME"
-+ CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-ml-dsa-44@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-+ certu -R -k mldsa -q ml-dsa-44 -d "${PROFILEDIR}" -f "${R_PWFILE}" \
-+ -z "${R_NOISE_FILE}" -o req 2>&1
-+ if [ "$RET" -ne 0 ]; then
- return $RET
-- fi
--
-- CU_ACTION="Sign ${CERTNAME}'s ML-DSA-44 Request"
-- certu -C -c "TestCA-ml-dsa-44" -m "$CERTSERIAL" -v 60 -d "${P_R_CADIR}" \
-+ fi
-+
-+ CU_ACTION="Sign ${CERTNAME}'s ML-DSA-44 Request"
-+ certu -C -c "TestCA-ml-dsa-44" -m "$CERTSERIAL" -v 60 -d "${P_R_CADIR}" \
- -i req -o "${CERTNAME}-ml-dsa-44.cert" -f "${R_PWFILE}" "$1" 2>&1
-- if [ "$RET" -ne 0 ]; then
-+ if [ "$RET" -ne 0 ]; then
- return $RET
-- fi
--
-- CU_ACTION="Import $CERTNAME's ML-DSA-44 Cert"
-- certu -A -n "${CERTNAME}-ml-dsa-44" -t "u,u,u" -d "${PROFILEDIR}" \
-- -f "${R_PWFILE}" -i "${CERTNAME}-ml-dsa-44.cert" 2>&1
-- if [ "$RET" -ne 0 ]; then
-+ fi
-+
-+ CU_ACTION="Import $CERTNAME's ML-DSA-44 Cert"
-+ certu -A -n "${CERTNAME}-ml-dsa-44" -t "u,u,u" -d "${PROFILEDIR}" \
-+ -f "${R_PWFILE}" -i "${CERTNAME}-ml-dsa-44.cert" 2>&1
-+ if [ "$RET" -ne 0 ]; then
- return $RET
-- fi
-- cert_log "SUCCESS: $CERTNAME's ML-DSA-44 Cert Created"
--
-- CU_ACTION="Generate ML-DSA-65 Cert Request for $CERTNAME"
-- CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-ml-dsa-65@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-- certu -R -k mldsa -q ml-dsa-65 -d "${PROFILEDIR}" -f "${R_PWFILE}" \
-- -z "${R_NOISE_FILE}" -o req 2>&1
-- if [ "$RET" -ne 0 ]; then
-+ fi
-+ cert_log "SUCCESS: $CERTNAME's ML-DSA-44 Cert Created"
-+
-+ CU_ACTION="Generate ML-DSA-65 Cert Request for $CERTNAME"
-+ CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-ml-dsa-65@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-+ certu -R -k mldsa -q ml-dsa-65 -d "${PROFILEDIR}" -f "${R_PWFILE}" \
-+ -z "${R_NOISE_FILE}" -o req 2>&1
-+ if [ "$RET" -ne 0 ]; then
- return $RET
-- fi
--
-- CU_ACTION="Sign ${CERTNAME}'s ML-DSA-65 Request"
-- certu -C -c "TestCA-ml-dsa-65" -m "$CERTSERIAL" -v 60 -d "${P_R_CADIR}" \
-+ fi
-+
-+ CU_ACTION="Sign ${CERTNAME}'s ML-DSA-65 Request"
-+ certu -C -c "TestCA-ml-dsa-65" -m "$CERTSERIAL" -v 60 -d "${P_R_CADIR}" \
- -i req -o "${CERTNAME}-ml-dsa-65.cert" -f "${R_PWFILE}" "$1" 2>&1
-- if [ "$RET" -ne 0 ]; then
-- return $RET
-- fi
--
-- CU_ACTION="Import $CERTNAME's ML-DSA-65 Cert"
-- certu -A -n "${CERTNAME}-ml-dsa-65" -t "u,u,u" -d "${PROFILEDIR}" \
-- -f "${R_PWFILE}" -i "${CERTNAME}-ml-dsa-65.cert" 2>&1
-- if [ "$RET" -ne 0 ]; then
-+ if [ "$RET" -ne 0 ]; then
- return $RET
-- fi
-- cert_log "SUCCESS: $CERTNAME's ML-DSA-65 Cert Created"
--
-- CU_ACTION="Generate ML-DSA-87 Cert Request for $CERTNAME"
-- CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-ml-dsa-87@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-- cert_log "SUCCESS: $CERTNAME's ML-DSA-87 Cert Created"
-- certu -R -k mldsa -q ml-dsa-87 -d "${PROFILEDIR}" -f "${R_PWFILE}" \
-- -z "${R_NOISE_FILE}" -o req 2>&1
-- if [ "$RET" -ne 0 ]; then
-+ fi
-+
-+ CU_ACTION="Import $CERTNAME's ML-DSA-65 Cert"
-+ certu -A -n "${CERTNAME}-ml-dsa-65" -t "u,u,u" -d "${PROFILEDIR}" \
-+ -f "${R_PWFILE}" -i "${CERTNAME}-ml-dsa-65.cert" 2>&1
-+ if [ "$RET" -ne 0 ]; then
- return $RET
-- fi
--
-- CU_ACTION="Sign ${CERTNAME}'s ML-DSA-87 Request"
-- certu -C -c "TestCA-ml-dsa-87" -m "$CERTSERIAL" -v 60 -d "${P_R_CADIR}" \
-- -i req -o "${CERTNAME}-ml-dsa-87.cert" -f "${R_PWFILE}" "$1" 2>&1
-- if [ "$RET" -ne 0 ]; then
-+ fi
-+ cert_log "SUCCESS: $CERTNAME's ML-DSA-65 Cert Created"
-+
-+ CU_ACTION="Generate ML-DSA-87 Cert Request for $CERTNAME"
-+ CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-ml-dsa-87@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-+ cert_log "SUCCESS: $CERTNAME's ML-DSA-87 Cert Created"
-+ certu -R -k mldsa -q ml-dsa-87 -d "${PROFILEDIR}" -f "${R_PWFILE}" \
-+ -z "${R_NOISE_FILE}" -o req 2>&1
-+ if [ "$RET" -ne 0 ]; then
- return $RET
-- fi
--
-- CU_ACTION="Import $CERTNAME's ML-DSA-87 Cert"
-- certu -A -n "${CERTNAME}-ml-dsa-87" -t "u,u,u" -d "${PROFILEDIR}" \
-- -f "${R_PWFILE}" -i "${CERTNAME}-ml-dsa-87.cert" 2>&1
-- if [ "$RET" -ne 0 ]; then
-+ fi
-+
-+ CU_ACTION="Sign ${CERTNAME}'s ML-DSA-87 Request"
-+ certu -C -c "TestCA-ml-dsa-87" -m "$CERTSERIAL" -v 60 -d "${P_R_CADIR}" \
-+ -i req -o "${CERTNAME}-ml-dsa-87.cert" -f "${R_PWFILE}" "$1" 2>&1
-+ if [ "$RET" -ne 0 ]; then
- return $RET
-- fi
-- cert_log "SUCCESS: $CERTNAME's ML-DSA-87 Cert Created"
-+ fi
-+
-+ CU_ACTION="Import $CERTNAME's ML-DSA-87 Cert"
-+ certu -A -n "${CERTNAME}-ml-dsa-87" -t "u,u,u" -d "${PROFILEDIR}" \
-+ -f "${R_PWFILE}" -i "${CERTNAME}-ml-dsa-87.cert" 2>&1
-+ if [ "$RET" -ne 0 ]; then
-+ return $RET
-+ fi
-+ cert_log "SUCCESS: $CERTNAME's ML-DSA-87 Cert Created"
- fi
-
--
- #
- # Generate and add EC cert
- #
- CURVE="secp384r1"
- CU_ACTION="Generate EC Cert Request for $CERTNAME"
- CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-ec@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
- certu -R -k ec -q "${CURVE}" -d "${PROFILEDIR}" -f "${R_PWFILE}" \
- -z "${R_NOISE_FILE}" -o req 2>&1
-@@ -600,16 +593,17 @@ cert_all_CA()
- cert_CA $CLIENT_CADIR chain-2-clientCA "-c chain-1-clientCA" "u,u,u" ${D_CLIENT_CA} "7"
-
- rm $CLIENT_CADIR/root.cert $SERVER_CADIR/root.cert
-
- # root.cert in $CLIENT_CADIR and in $SERVER_CADIR is one of the last
- # in the chain
-
-
-+ if [ -z "$NSS_DISABLE_DSA" ]; then
- #
- # Create DSA version of TestCA
- ALL_CU_SUBJECT="CN=NSS Test CA (DSA), O=BOGUS NSS, L=Mountain View, ST=California, C=US"
- cert_dsa_CA $CADIR TestCA-dsa -x "CTu,CTu,CTu" ${D_CA} "1"
- #
- # Create DSA versions of the intermediate CA certs
- ALL_CU_SUBJECT="CN=NSS Server Test CA (DSA), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
- cert_dsa_CA $SERVER_CADIR serverCA-dsa -x "Cu,Cu,Cu" ${D_SERVER_CA} "2"
-@@ -623,51 +617,77 @@ cert_all_CA()
- ALL_CU_SUBJECT="CN=NSS Chain1 Client Test CA (DSA), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
- cert_dsa_CA $CLIENT_CADIR chain-1-clientCA-dsa "-c clientCA-dsa" "u,u,u" ${D_CLIENT_CA} "6"
- ALL_CU_SUBJECT="CN=NSS Chain2 Client Test CA (DSA), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
- cert_dsa_CA $CLIENT_CADIR chain-2-clientCA-dsa "-c chain-1-clientCA-dsa" "u,u,u" ${D_CLIENT_CA} "7"
-
- rm $CLIENT_CADIR/dsaroot.cert $SERVER_CADIR/dsaroot.cert
- # dsaroot.cert in $CLIENT_CADIR and in $SERVER_CADIR is one of the last
- # in the chain
--
-- if [ -n "$NSS_CERT_ENABLE_ML_DSA" ]; then
-+ fi
-+ if [ -n "$NSS_ENABLE_ML_DSA" ]; then
- #
- # Create ML-DSA-44 version of TestCA
-- ALL_CU_SUBJECT="CN=NSS Test CA (ML-DSA-44), O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-- cert_ml_dsa_CA ml-dsa-44 $CADIR TestCA-ml-dsa-44 -x "CTu,CTu,CTu" ${D_CA} "1"
-+ ALL_CU_SUBJECT="CN=NSS Test CA (ML-DSA-44), O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-44 $CADIR TestCA-ml-dsa-44 -x "CTu,CTu,CTu" ${D_CA} "1"
- #
- # Create ML-DSA-44 versions of the intermediate CA certs
-- ALL_CU_SUBJECT="CN=NSS Server Test CA (ML-DSA-44), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-- cert_ml_dsa_CA ml-dsa-44 $SERVER_CADIR serverCA-ml-dsa-44 -x "Cu,Cu,Cu" ${D_SERVER_CA} "2"
--
-- ALL_CU_SUBJECT="CN=NSS Client Test CA (ML-DSA-44), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-- cert_m_ldsa_CA ml-dsa-44 $CLIENT_CADIR clientCA-dsa -x "Tu,Cu,Cu" ${D_CLIENT_CA} "5"
-+ ALL_CU_SUBJECT="CN=NSS Server Test CA (ML-DSA-44), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-44 $SERVER_CADIR serverCA-ml-dsa-44 -x "Cu,Cu,Cu" ${D_SERVER_CA} "2"
-+ ALL_CU_SUBJECT="CN=NSS Chain1 Server Test CA (ML-DSA-44), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-44 $SERVER_CADIR chain-1-serverCA-ml-dsa-44 "-c serverCA-ml-dsa-44" "u,u,u" ${D_SERVER_CA} "3"
-+ ALL_CU_SUBJECT="CN=NSS Chain2 Server Test CA (ML-DSA-44), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-44 $SERVER_CADIR chain-2-serverCA-ml-dsa-44 "-c chain-1-serverCA-ml-dsa-44" "u,u,u" ${D_SERVER_CA} "4"
-+
-+ ALL_CU_SUBJECT="CN=NSS Client Test CA (ML-DSA-44), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-44 $CLIENT_CADIR clientCA-ml-dsa-44 -x "Tu,Cu,Cu" ${D_CLIENT_CA} "5"
-+ ALL_CU_SUBJECT="CN=NSS Chain1 Client Test CA (ML-DSA-44), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-44 $CLIENT_CADIR chain-1-clientCA-ml-dsa-44 "-c clientCA-ml-dsa-44" "u,u,u" ${D_CLIENT_CA} "6"
-+ ALL_CU_SUBJECT="CN=NSS Chain2 Client Test CA (ML-DSA-44), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-44 $CLIENT_CADIR chain-2-clientCA-ml-dsa-44 "-c chain-1-clientCA-ml-dsa-44" "u,u,u" ${D_CLIENT_CA} "7"
-+
- #
- # Create ML-DSA-65 version of TestCA
-- ALL_CU_SUBJECT="CN=NSS Test CA (ML-DSA-65), O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-- cert_ml_dsa_CA ml-dsa-65 $CADIR TestCA-ml-dsa-65 -x "CTu,CTu,CTu" ${D_CA} "1"
--#
-+ ALL_CU_SUBJECT="CN=NSS Test CA (ML-DSA-65), O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-65 $CADIR TestCA-ml-dsa-65 -x "CTu,CTu,CTu" ${D_CA} "1"
- # Create ML-DSA-65 versions of the intermediate CA certs
-- ALL_CU_SUBJECT="CN=NSS Server Test CA (ML-DSA-65), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-- cert_ml_dsa_CA ml-dsa-65 $SERVER_CADIR serverCA-ml-dsa-65 -x "Cu,Cu,Cu" ${D_SERVER_CA} "2"
--
-- ALL_CU_SUBJECT="CN=NSS Client Test CA (ML-DSA-65), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-- cert_m_ldsa_CA ml-dsa-44 $CLIENT_CADIR clientCA-dsa -x "Tu,Cu,Cu" ${D_CLIENT_CA} "5"
-+ ALL_CU_SUBJECT="CN=NSS Server Test CA (ML-DSA-65), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-65 $SERVER_CADIR serverCA-ml-dsa-65 -x "Cu,Cu,Cu" ${D_SERVER_CA} "2"
-+ ALL_CU_SUBJECT="CN=NSS Chain1 Server Test CA (ML-DSA-65), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-65 $SERVER_CADIR chain-1-serverCA-ml-dsa-65 "-c serverCA-ml-dsa-65" "u,u,u" ${D_SERVER_CA} "3"
-+ ALL_CU_SUBJECT="CN=NSS Chain2 Server Test CA (ML-DSA-65), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-65 $SERVER_CADIR chain-2-serverCA-ml-dsa-65 "-c chain-1-serverCA-ml-dsa-65" "u,u,u" ${D_SERVER_CA} "4"
-+#
-+
-+ ALL_CU_SUBJECT="CN=NSS Client Test CA (ML-DSA-65), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-65 $CLIENT_CADIR clientCA-ml-dsa-65 -x "Tu,Cu,Cu" ${D_CLIENT_CA} "5"
-+ ALL_CU_SUBJECT="CN=NSS Chain1 Client Test CA (ML-DSA-65), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-65 $CLIENT_CADIR chain-1-clientCA-ml-dsa-65 "-c clientCA-ml-dsa-65" "u,u,u" ${D_CLIENT_CA} "6"
-+ ALL_CU_SUBJECT="CN=NSS Chain2 Client Test CA (ML-DSA-65), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-65 $CLIENT_CADIR chain-2-clientCA-ml-dsa-65 "-c chain-1-clientCA-ml-dsa-65" "u,u,u" ${D_CLIENT_CA} "7"
- #
- # Create ML-DSA-87 version of TestCA
-- ALL_CU_SUBJECT="CN=NSS Test CA (ML-DSA-87), O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-- cert_ml_dsa_CA ml-dsa-87 $CADIR TestCA-ml-dsa-87 -x "CTu,CTu,CTu" ${D_CA} "1"
-+ ALL_CU_SUBJECT="CN=NSS Test CA (ML-DSA-87), O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-87 $CADIR TestCA-ml-dsa-87 -x "CTu,CTu,CTu" ${D_CA} "1"
- #
- # Create ML-DSA-87 versions of the intermediate CA certs
-- ALL_CU_SUBJECT="CN=NSS Server Test CA (ML-DSA-87), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-- cert_ml_dsa_CA ml-dsa-87 $SERVER_CADIR serverCA-ml-dsa-87 -x "Cu,Cu,Cu" ${D_SERVER_CA} "2"
--
-- ALL_CU_SUBJECT="CN=NSS Client Test CA (ML-DSA-87), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-- cert_m_ldsa_CA ml-dsa-87 $CLIENT_CADIR clientCA-dsa -x "Tu,Cu,Cu" ${D_CLIENT_CA} "5"
-+ ALL_CU_SUBJECT="CN=NSS Server Test CA (ML-DSA-87), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-87 $SERVER_CADIR serverCA-ml-dsa-87 -x "Cu,Cu,Cu" ${D_SERVER_CA} "2"
-+ ALL_CU_SUBJECT="CN=NSS Chain1 Server Test CA (ML-DSA-87), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-87 $SERVER_CADIR chain-1-serverCA-ml-dsa-87 "-c serverCA-ml-dsa-87" "u,u,u" ${D_SERVER_CA} "3"
-+ ALL_CU_SUBJECT="CN=NSS Chain2 Server Test CA (ML-DSA-87), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-87 $SERVER_CADIR chain-2-serverCA-ml-dsa-87 "-c chain-1-serverCA-ml-dsa-87" "u,u,u" ${D_SERVER_CA} "4"
-+#
-+
-+ ALL_CU_SUBJECT="CN=NSS Client Test CA (ML-DSA-87), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-87 $CLIENT_CADIR clientCA-ml-dsa-87 -x "Tu,Cu,Cu" ${D_CLIENT_CA} "5"
-+ ALL_CU_SUBJECT="CN=NSS Chain1 Client Test CA (ML-DSA-87), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-87 $CLIENT_CADIR chain-1-clientCA-ml-dsa-87 "-c clientCA-ml-dsa-87" "u,u,u" ${D_CLIENT_CA} "6"
-+ ALL_CU_SUBJECT="CN=NSS Chain2 Client Test CA (ML-DSA-87), O=BOGUS NSS, L=Santa Clara, ST=California, C=US"
-+ cert_ml_dsa_CA ml-dsa-87 $CLIENT_CADIR chain-2-clientCA-ml-dsa-87 "-c chain-1-clientCA-ml-dsa-87" "u,u,u" ${D_CLIENT_CA} "7"
-
- fi
-
- #
- # Create RSA-PSS version of TestCA
- ALL_CU_SUBJECT="CN=NSS Test CA (RSA-PSS), O=BOGUS NSS, L=Mountain View, ST=California, C=US"
- cert_rsa_pss_CA $CADIR TestCA-rsa-pss -x "CTu,CTu,CTu" ${D_CA} "1" SHA256
- rm $CADIR/rsapssroot.cert
-@@ -1184,16 +1204,17 @@ cert_extended_ssl()
- CU_ACTION="Import $CERTNAME's Cert -t u,u,u (ext)"
- certu -A -n "$CERTNAME" -t "u,u,u" -d "${PROFILEDIR}" -f "${R_PWFILE}" \
- -i "${CERTNAME}.cert" 2>&1
-
- CU_ACTION="Import Client Root CA -t T,, for $CERTNAME (ext.)"
- certu -A -n "clientCA" -t "T,," -f "${R_PWFILE}" -d "${PROFILEDIR}" \
- -i "${CLIENT_CADIR}/clientCA.ca.cert" 2>&1
-
-+ if [ -z "$NSS_DISABLE_DSA" ]; then
- #
- # Repeat the above for DSA certs
- #
- CU_ACTION="Generate DSA Cert Request for $CERTNAME (ext)"
- CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-dsa@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
- certu -R -d "${PROFILEDIR}" -k dsa -f "${R_PWFILE}" \
- -z "${R_NOISE_FILE}" -o req 2>&1
-
-@@ -1227,16 +1248,82 @@ cert_extended_ssl()
- CU_ACTION="Import $CERTNAME's mixed DSA Cert -t u,u,u (ext)"
- certu -A -n "${CERTNAME}-dsamixed" -t "u,u,u" -d "${PROFILEDIR}" \
- -f "${R_PWFILE}" -i "${CERTNAME}-dsamixed.cert" 2>&1
-
- # CU_ACTION="Import Client mixed DSA Root CA -t T,, for $CERTNAME (ext.)"
- # certu -A -n "clientCA-dsamixed" -t "T,," -f "${R_PWFILE}" \
- # -d "${PROFILEDIR}" -i "${CLIENT_CADIR}/clientCA-dsamixed.ca.cert" \
- # 2>&1
-+ fi
-+ if [ -n "$NSS_ENABLE_ML_DSA" ]; then
-+#
-+# Repeat the above for ML-DSA-44 certs
-+#
-+ CU_ACTION="Generate ML-DSA-44 Cert Request for $CERTNAME (ext)"
-+ CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-ml-dsa-44@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-+ certu -R -d "${PROFILEDIR}" -k mldsa -q ml-dsa-44 -f "${R_PWFILE}" \
-+ -z "${R_NOISE_FILE}" -o req 2>&1
-+
-+ CU_ACTION="Sign ${CERTNAME}'s ML-DSA-44 Request (ext)"
-+ cp ${CERTDIR}/req ${SERVER_CADIR}
-+ certu -C -c "chain-2-serverCA-ml-dsa-44" -m 200 -v 60 -d "${P_SERVER_CADIR}" \
-+ -i req -o "${CERTNAME}-ml-dsa-44.cert" -f "${R_PWFILE}" 2>&1
-+
-+ CU_ACTION="Import $CERTNAME's ML-DSA-44 Cert -t u,u,u (ext)"
-+ certu -A -n "${CERTNAME}-ml-dsa-44" -t "u,u,u" -d "${PROFILEDIR}" \
-+ -f "${R_PWFILE}" -i "${CERTNAME}-ml-dsa-44.cert" 2>&1
-+
-+ CU_ACTION="Import Client ML-DSA-44 Root CA -t T,, for $CERTNAME (ext.)"
-+ certu -A -n "clientCA-ml-dsa-44" -t "T,," -f "${R_PWFILE}" -d "${PROFILEDIR}" \
-+ -i "${CLIENT_CADIR}/clientCA-ml-dsa-44.ca.cert" 2>&1
-+#
-+# Repeat the above for ML-DSA-65 certs
-+#
-+ CU_ACTION="Generate ML-DSA-65 Cert Request for $CERTNAME (ext)"
-+ CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-ml-dsa-65@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-+ certu -R -d "${PROFILEDIR}" -k mldsa -q ml-dsa-65 -f "${R_PWFILE}" \
-+ -z "${R_NOISE_FILE}" -o req 2>&1
-+
-+ CU_ACTION="Sign ${CERTNAME}'s ML-DSA-65 Request (ext)"
-+ cp ${CERTDIR}/req ${SERVER_CADIR}
-+ certu -C -c "chain-2-serverCA-ml-dsa-65" -m 200 -v 60 -d "${P_SERVER_CADIR}" \
-+ -i req -o "${CERTNAME}-ml-dsa-65.cert" -f "${R_PWFILE}" 2>&1
-+
-+ CU_ACTION="Import $CERTNAME's ML-DSA-65 Cert -t u,u,u (ext)"
-+ certu -A -n "${CERTNAME}-ml-dsa-65" -t "u,u,u" -d "${PROFILEDIR}" \
-+ -f "${R_PWFILE}" -i "${CERTNAME}-ml-dsa-65.cert" 2>&1
-+
-+ CU_ACTION="Import Client ML-DSA-65 Root CA -t T,, for $CERTNAME (ext.)"
-+ certu -A -n "clientCA-ml-dsa-65" -t "T,," -f "${R_PWFILE}" -d "${PROFILEDIR}" \
-+ -i "${CLIENT_CADIR}/clientCA-ml-dsa-65.ca.cert" 2>&1
-+#
-+# Repeat the above for ML-DSA-87 certs
-+#
-+ CU_ACTION="Generate ML-DSA-87 Cert Request for $CERTNAME (ext)"
-+ CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-ml-dsa-87@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-+ certu -R -d "${PROFILEDIR}" -k mldsa -q ml-dsa-87 -f "${R_PWFILE}" \
-+ -z "${R_NOISE_FILE}" -o req 2>&1
-+
-+ CU_ACTION="Sign ${CERTNAME}'s ML-DSA-87 Request (ext)"
-+ cp ${CERTDIR}/req ${SERVER_CADIR}
-+ certu -C -c "chain-2-serverCA-ml-dsa-87" -m 200 -v 60 -d "${P_SERVER_CADIR}" \
-+ -i req -o "${CERTNAME}-ml-dsa-87.cert" -f "${R_PWFILE}" 2>&1
-+
-+ CU_ACTION="Import $CERTNAME's ML-DSA-87 Cert -t u,u,u (ext)"
-+ certu -A -n "${CERTNAME}-ml-dsa-87" -t "u,u,u" -d "${PROFILEDIR}" \
-+ -f "${R_PWFILE}" -i "${CERTNAME}-ml-dsa-87.cert" 2>&1
-+
-+ CU_ACTION="Import Client ML-DSA-87 Root CA -t T,, for $CERTNAME (ext.)"
-+ certu -A -n "clientCA-ml-dsa-87" -t "T,," -f "${R_PWFILE}" -d "${PROFILEDIR}" \
-+ -i "${CLIENT_CADIR}/clientCA-ml-dsa-87.ca.cert" 2>&1
-+#
-+# done with ML-DSA certs
-+#
-+ fi
-
- #
- # Repeat the above for EC certs
- #
- EC_CURVE="secp256r1"
- CU_ACTION="Generate EC Cert Request for $CERTNAME (ext)"
- CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-ec@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
- certu -R -d "${PROFILEDIR}" -k ec -q "${EC_CURVE}" -f "${R_PWFILE}" \
-@@ -1280,34 +1367,34 @@ cert_extended_ssl()
- # 2>&1
-
- # Check that a repeated import with a different nickname doesn't change the
- # nickname of the existing cert (bug 1458518).
- # We want to search for the results using grep, to avoid subset matches,
- # we'll use one of the longer nicknames for testing.
- # (Because "grep -w hostname" matches "grep -w hostname-dsamixed")
- MYDBPASS="-d ${PROFILEDIR} -f ${R_PWFILE}"
-- TESTNAME="Ensure there's exactly one match for ${CERTNAME}-dsamixed"
-- cert_check_nickname_exists "$MYDBPASS" "${CERTNAME}-dsamixed" 0 1 "${TESTNAME}"
--
-- CU_ACTION="Repeated import of $CERTNAME's mixed DSA Cert with different nickname"
-- certu -A -n "${CERTNAME}-repeated-dsamixed" -t "u,u,u" -d "${PROFILEDIR}" \
-- -f "${R_PWFILE}" -i "${CERTNAME}-dsamixed.cert" 2>&1
--
-- TESTNAME="Ensure there's still exactly one match for ${CERTNAME}-dsamixed"
-- cert_check_nickname_exists "$MYDBPASS" "${CERTNAME}-dsamixed" 0 1 "${TESTNAME}"
--
-- TESTNAME="Ensure there's zero matches for ${CERTNAME}-repeated-dsamixed"
-- cert_check_nickname_exists "$MYDBPASS" "${CERTNAME}-repeated-dsamixed" 0 0 "${TESTNAME}"
-+ TESTNAME="Ensure there's exactly one match for ${CERTNAME}-ecmixed"
-+ cert_check_nickname_exists "$MYDBPASS" "${CERTNAME}-ecmixed" 0 1 "${TESTNAME}"
-+
-+ CU_ACTION="Repeated import of $CERTNAME's mixed EC Cert with different nickname"
-+ certu -A -n "${CERTNAME}-repeated-ecmixed" -t "u,u,u" -d "${PROFILEDIR}" \
-+ -f "${R_PWFILE}" -i "${CERTNAME}-ecmixed.cert" 2>&1
-+
-+ TESTNAME="Ensure there's still exactly one match for ${CERTNAME}-ecmixed"
-+ cert_check_nickname_exists "$MYDBPASS" "${CERTNAME}-ecmixed" 0 1 "${TESTNAME}"
-+
-+ TESTNAME="Ensure there's zero matches for ${CERTNAME}-repeated-ecmixed"
-+ cert_check_nickname_exists "$MYDBPASS" "${CERTNAME}-repeated-ecmixed" 0 0 "${TESTNAME}"
-
- echo "Importing all the server's own CA chain into the servers DB"
- for CA in `find ${SERVER_CADIR} -name "?*.ca.cert"` ;
- do
- N=`basename $CA | sed -e "s/.ca.cert//"`
-- if [ $N = "serverCA" -o $N = "serverCA-ec" -o $N = "serverCA-dsa" ] ; then
-+ if [ $N = "serverCA" -o $N = "serverCA-ec" -o $N = "serverCA-dsa" -o $N = "serverCA-ml-dsa-44" -o $N = "serverCA-ml-dsa-65" -o $N = "serverCA-ml-dsa-87" ] ; then
- T="-t C,C,C"
- else
- T="-t u,u,u"
- fi
- CU_ACTION="Import $N CA $T for $CERTNAME (ext.) "
- certu -A -n $N $T -f "${R_PWFILE}" -d "${PROFILEDIR}" \
- -i "${CA}" 2>&1
- done
-@@ -1336,16 +1423,17 @@ cert_extended_ssl()
- -i "${CERTNAME}.cert" 2>&1
- CU_ACTION="Import Server Root CA -t C,C,C for $CERTNAME (ext.)"
- certu -A -n "serverCA" -t "C,C,C" -f "${R_PWFILE}" -d "${PROFILEDIR}" \
- -i "${SERVER_CADIR}/serverCA.ca.cert" 2>&1
-
- #
- # Repeat the above for DSA certs
- #
-+ if [ -z "$NSS_DISABLE_DSA" ]; then
- CU_ACTION="Generate DSA Cert Request for $CERTNAME (ext)"
- CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-dsa@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
- certu -R -d "${PROFILEDIR}" -k dsa -f "${R_PWFILE}" \
- -z "${R_NOISE_FILE}" -o req 2>&1
-
- CU_ACTION="Sign ${CERTNAME}'s DSA Request (ext)"
- cp ${CERTDIR}/req ${CLIENT_CADIR}
- certu -C -c "chain-2-clientCA-dsa" -m 300 -v 60 -d "${P_CLIENT_CADIR}" \
-@@ -1379,16 +1467,80 @@ cert_extended_ssl()
- -f "${R_PWFILE}" -i "${CERTNAME}-dsamixed.cert" 2>&1
-
- # CU_ACTION="Import Server DSA Root CA -t C,C,C for $CERTNAME (ext.)"
- # certu -A -n "serverCA-dsa" -t "C,C,C" -f "${R_PWFILE}" \
- # -d "${PROFILEDIR}" -i "${SERVER_CADIR}/serverCA-dsa.ca.cert" 2>&1
- #
- # done with mixed DSA certs
- #
-+ fi
-+#
-+# Repeat the above for ML-DSA certs
-+#
-+ if [ -n "$NSS_ENABLE_ML_DSA" ]; then
-+# ML-DSA-44 certs
-+ CU_ACTION="Generate ML-DSA-44 Cert Request for $CERTNAME (ext)"
-+ CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-ml-dsa-44@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-+ certu -R -d "${PROFILEDIR}" -k mldsa -q ml-dsa-44 -f "${R_PWFILE}" \
-+ -z "${R_NOISE_FILE}" -o req 2>&1
-+
-+ CU_ACTION="Sign ${CERTNAME}'s ML-DSA-44 Request (ext)"
-+ cp ${CERTDIR}/req ${CLIENT_CADIR}
-+ certu -C -c "chain-2-clientCA-ml-dsa-44" -m 300 -v 60 -d "${P_CLIENT_CADIR}" \
-+ -i req -o "${CERTNAME}-ml-dsa-44.cert" -f "${R_PWFILE}" 2>&1
-+
-+ CU_ACTION="Import $CERTNAME's ML-DSA-44 Cert -t u,u,u (ext)"
-+ certu -A -n "${CERTNAME}-ml-dsa-44" -t "u,u,u" -d "${PROFILEDIR}" \
-+ -f "${R_PWFILE}" -i "${CERTNAME}-ml-dsa-44.cert" 2>&1
-+
-+ CU_ACTION="Import Server ML-DSA-44 Root CA -t C,C,C for $CERTNAME (ext.)"
-+ certu -A -n "serverCA-ml-dsa-44" -t "C,C,C" -f "${R_PWFILE}" \
-+ -d "${PROFILEDIR}" -i "${SERVER_CADIR}/serverCA-ml-dsa-44.ca.cert" 2>&1
-+# ML-DSA-65 certs
-+ CU_ACTION="Generate ML-DSA-65 Cert Request for $CERTNAME (ext)"
-+ CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-ml-dsa-65@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-+ certu -R -d "${PROFILEDIR}" -k mldsa -q ml-dsa-65 -f "${R_PWFILE}" \
-+ -z "${R_NOISE_FILE}" -o req 2>&1
-+
-+ CU_ACTION="Sign ${CERTNAME}'s ML-DSA-65 Request (ext)"
-+ cp ${CERTDIR}/req ${CLIENT_CADIR}
-+ certu -C -c "chain-2-clientCA-ml-dsa-65" -m 300 -v 60 -d "${P_CLIENT_CADIR}" \
-+ -i req -o "${CERTNAME}-ml-dsa-65.cert" -f "${R_PWFILE}" 2>&1
-+
-+ CU_ACTION="Import $CERTNAME's ML-DSA-65 Cert -t u,u,u (ext)"
-+ certu -A -n "${CERTNAME}-ml-dsa-65" -t "u,u,u" -d "${PROFILEDIR}" \
-+ -f "${R_PWFILE}" -i "${CERTNAME}-ml-dsa-65.cert" 2>&1
-+
-+ CU_ACTION="Import Server ML-DSA-65 Root CA -t C,C,C for $CERTNAME (ext.)"
-+ certu -A -n "serverCA-ml-dsa-65" -t "C,C,C" -f "${R_PWFILE}" \
-+ -d "${PROFILEDIR}" -i "${SERVER_CADIR}/serverCA-ml-dsa-65.ca.cert" 2>&1
-+# ML-DSA-87 certs
-+ CU_ACTION="Generate ML-DSA-87 Cert Request for $CERTNAME (ext)"
-+ CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-ml-dsa-87@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
-+ certu -R -d "${PROFILEDIR}" -k mldsa -q ml-dsa-87 -f "${R_PWFILE}" \
-+ -z "${R_NOISE_FILE}" -o req 2>&1
-+
-+ CU_ACTION="Sign ${CERTNAME}'s ML-DSA-87 Request (ext)"
-+ cp ${CERTDIR}/req ${CLIENT_CADIR}
-+ certu -C -c "chain-2-clientCA-ml-dsa-87" -m 300 -v 60 -d "${P_CLIENT_CADIR}" \
-+ -i req -o "${CERTNAME}-ml-dsa-87.cert" -f "${R_PWFILE}" 2>&1
-+
-+ CU_ACTION="Import $CERTNAME's ML-DSA-87 Cert -t u,u,u (ext)"
-+ certu -A -n "${CERTNAME}-ml-dsa-87" -t "u,u,u" -d "${PROFILEDIR}" \
-+ -f "${R_PWFILE}" -i "${CERTNAME}-ml-dsa-87.cert" 2>&1
-+
-+ CU_ACTION="Import Server ML-DSA-87 Root CA -t C,C,C for $CERTNAME (ext.)"
-+ certu -A -n "serverCA-ml-dsa-87" -t "C,C,C" -f "${R_PWFILE}" \
-+ -d "${PROFILEDIR}" -i "${SERVER_CADIR}/serverCA-ml-dsa-87.ca.cert" 2>&1
-+#
-+# done with ML-DSA certs
-+#
-+#
-+ fi
-
- #
- # Repeat the above for EC certs
- #
- CU_ACTION="Generate EC Cert Request for $CERTNAME (ext)"
- CU_SUBJECT="CN=$CERTNAME, E=${CERTNAME}-ec@example.com, O=BOGUS NSS, L=Mountain View, ST=California, C=US"
- certu -R -d "${PROFILEDIR}" -k ec -q "${EC_CURVE}" -f "${R_PWFILE}" \
- -z "${R_NOISE_FILE}" -o req 2>&1
-@@ -1431,17 +1583,17 @@ cert_extended_ssl()
- #
- # done with mixed EC certs
- #
-
- echo "Importing all the client's own CA chain into the servers DB"
- for CA in `find ${CLIENT_CADIR} -name "?*.ca.cert"` ;
- do
- N=`basename $CA | sed -e "s/.ca.cert//"`
-- if [ $N = "clientCA" -o $N = "clientCA-ec" -o $N = "clientCA-dsa" ] ; then
-+ if [ $N = "clientCA" -o $N = "clientCA-ec" -o $N = "clientCA-dsa" -o $N = "clientCA-ml-dsa-44" -o $N = "clientCA-ml-dsa-65" -o $N = "clientCA-ml-dsa-87" ] ; then
- T="-t T,C,C"
- else
- T="-t u,u,u"
- fi
- CU_ACTION="Import $N CA $T for $CERTNAME (ext.)"
- certu -A -n $N $T -f "${R_PWFILE}" -d "${PROFILEDIR}" \
- -i "${CA}" 2>&1
- done
-@@ -1469,20 +1621,22 @@ cert_ssl()
- echo "$SCRIPTNAME: Creating Server CA Issued Certificate for \\"
- echo " ${HOSTADDR}-sni --------------------------------"
- CERTSERIAL=101
- CERTNAME="${HOST}-sni${sniCertCount}.${DOMSUF}"
- cert_add_cert
- CU_ACTION="Modify trust attributes of Root CA -t TC,TC,TC"
- certu -M -n "TestCA" -t "TC,TC,TC" -d ${PROFILEDIR} -f "${R_PWFILE}"
-
-+ if [ -z "$NSS_DISABLE_DSA" ]; then
- CU_ACTION="Modify trust attributes of DSA Root CA -t TC,TC,TC"
- certu -M -n "TestCA-dsa" -t "TC,TC,TC" -d ${PROFILEDIR} -f "${R_PWFILE}"
--
-- if [ -n "$NSS_CERT_ENABLE_ML_DSA" ]; then
-+ fi
-+
-+ if [ -n "$NSS_ENABLE_ML_DSA" ]; then
- CU_ACTION="Modify trust attributes of ML-DSA-44 Root CA -t TC,TC,TC"
- certu -M -n "TestCA-ml-dsa-44" -t "TC,TC,TC" -d ${PROFILEDIR} -f "${R_PWFILE}"
- CU_ACTION="Modify trust attributes of ML-DSA-65 Root CA -t TC,TC,TC"
- certu -M -n "TestCA-ml-dsa-65" -t "TC,TC,TC" -d ${PROFILEDIR} -f "${R_PWFILE}"
- CU_ACTION="Modify trust attributes of ML-DSA-87 Root CA -t TC,TC,TC"
- certu -M -n "TestCA-ml-dsa-87" -t "TC,TC,TC" -d ${PROFILEDIR} -f "${R_PWFILE}"
- fi
-
-@@ -1588,19 +1742,26 @@ MODSCRIPT
- RETEXPECTED=255
- certu -W -d "${PROFILEDIR}" -f "${R_FIPSPWFILE}" -@ "${R_FIPSBADPWFILE}" 2>&1
- CU_ACTION="Attempt to generate a key with exponent of 3 (too small)"
- certu -G -k rsa -g 2048 -y 3 -d "${PROFILEDIR}" -z ${R_NOISE_FILE} -f "${R_FIPSPWFILE}"
- CU_ACTION="Attempt to generate a key with exponent of 17 (too small)"
- certu -G -k rsa -g 2048 -y 17 -d "${PROFILEDIR}" -z ${R_NOISE_FILE} -f "${R_FIPSPWFILE}"
- RETEXPECTED=0
-
-+ if [ -z "$NSS_DISABLE_DSA" ]; then
-+ FIPS_KEY="-k dsa"
-+ elif [ -n "$NSS_ENABLE_ML_DSA" ]; then
-+ FIPS_KEY="-k mldsa -q ml-dsa-44"
-+ else
-+ FIPS_KEY="-k ec -q nistp256"
-+ fi
- CU_ACTION="Generate Certificate for ${CERTNAME}"
- CU_SUBJECT="CN=${CERTNAME}, E=fips@example.com, O=BOGUS NSS, OU=FIPS PUB 140, L=Mountain View, ST=California, C=US"
-- certu -S -n ${FIPSCERTNICK} -x -t "Cu,Cu,Cu" -d "${PROFILEDIR}" -f "${R_FIPSPWFILE}" -k dsa -v 600 -m 500 -z "${R_NOISE_FILE}" 2>&1
-+ certu -S -n ${FIPSCERTNICK} -x -t "Cu,Cu,Cu" -d "${PROFILEDIR}" -f "${R_FIPSPWFILE}" ${FIPS_KEY} -v 600 -m 500 -z "${R_NOISE_FILE}" 2>&1
- if [ "$RET" -eq 0 ]; then
- cert_log "SUCCESS: FIPS passed"
- fi
-
- }
-
- ########################## cert_rsa_exponent #################################
- # local shell function to verify small rsa exponent can be used (only
-@@ -2022,30 +2183,68 @@ addext reasonCode 0 4
- addext issuerAltNames 0 "rfc822Name:caemail@ca.com|dnsName:ca.com|directoryName:CN=NSS Test CA,O=BOGUS NSS,L=Mountain View,ST=California,C=US|URI:http://ca.com|ipAddress:192.168.0.1|registerID=reg CA"
- EOF_CRLINI
- # This extension should be added to the list, but currently nss has bug
- #addext authKeyId 0 "CN=NSS Test CA,O=BOGUS NSS,L=Mountain View,ST=California,C=US" 1
- CRL_GEN_RES=`expr $? + $CRL_GEN_RES`
- chmod 600 ${CRL_FILE_GRP_1}_or
-
-
-+ if [ -z "$NSS_DISABLE_DSA" ]; then
- CU_ACTION="Generating CRL (DSA) for range ${CRL_GRP_1_BEGIN}-${CRL_GRP_END} TestCA-dsa authority"
-
- # Until Bug 292285 is resolved, do not encode x400 Addresses. After
- # the bug is resolved, reintroduce "x400Address:x400Address" within
- # addext issuerAltNames ...
- crlu -q -d $CADIR -G -n "TestCA-dsa" -f ${R_PWFILE} \
- -o ${CRL_FILE_GRP_1}_or-dsa < ${SERVEROUTFILE} 2>&1 &
- RET=$?
- else
- ${PROFTOOL} ${BINDIR}/selfserv -D -p ${PORT} -d ${P_R_SERVERDIR} ${RSA_OPTIONS} ${SERVER_OPTIONS} \
-- ${ECC_OPTIONS} -S ${HOSTADDR}-dsa -w nss "$@" -i ${R_SERVERPID} -V ${SERVER_VMIN}:${SERVER_VMAX} $verbose -H 1 &
-+ ${ECC_OPTIONS}${DSA_OPTIONS}${ML_DSA_OPTIONS}-w nss "$@" -i ${R_SERVERPID} -V ${SERVER_VMIN}:${SERVER_VMAX} $verbose -H 1 &
- RET=$?
- fi
-
- # The PID $! returned by the MKS or Cygwin shell is not the PID of
- # the real background process, but rather the PID of a helper
- # process (sh.exe). MKS's kill command has a bug: invoking kill
- # on the helper process does not terminate the real background
- # process. Our workaround has been to have selfserv save its PID
-@@ -371,30 +386,36 @@ ssl_cov()
- # restart it to enable ssl3
- if [ "$VMAX" = "ssl3" -a "$VMIN" = "tls1.1" ]; then
- kill_selfserv
- start_selfserv $CIPHER_SUITES
- VMIN="ssl3"
- fi
-
- TLS_GROUPS=${CLIENT_GROUPS}
-+ TLS_SIG_SCHEMES=""
- if [ "$ectype" = "MLKEM256" ]; then
- TLS_GROUPS="secp256r1mlkem768"
-+ TLS_SIG_SCHEMES="-J mldsa65"
- elif [ "$ectype" = "MLKEM219" ]; then
- TLS_GROUPS="x25519mlkem768"
-+ TLS_SIG_SCHEMES="-J mldsa44"
- elif [ "$ectype" = "MLKEM384" ]; then
- TLS_GROUPS="secp384r1mlkem1024"
-+ TLS_SIG_SCHEMES="-J mldsa87"
-+ elif [ "$ectype" = "MLDSAECC" ]; then
-+ TLS_SIG_SCHEMES="-J mldsa44"
- fi
- echo "TLS_GROUPS=${TLS_GROUPS}"
-
-- echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -I \"${TLS_GROUPS}\" -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} \\"
-+ echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -I \"${TLS_GROUPS}\" ${TLS_SIG_SCHEMES} -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} \\"
- echo " -f -d ${P_R_CLIENTDIR} $verbose -w nss < ${REQUEST_FILE}"
-
- rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
-- ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -I "${TLS_GROUPS}" -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} -f \
-+ ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -I "${TLS_GROUPS}" ${TLS_SIG_SCHEMES} -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} -f \
- -d ${P_R_CLIENTDIR} $verbose -w nss < ${REQUEST_FILE} \
- >${TMP}/$HOST.tmp.$$ 2>&1
- ret=$?
- cat ${TMP}/$HOST.tmp.$$
- rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
- html_msg $ret 0 "${testname}" \
- "produced a returncode of $ret, expected is 0"
- done < ${SSL_COV_TMP}
-@@ -687,16 +708,22 @@ ssl_stress()
- if [ "$ectype" = "SNI" -a "$NORM_EXT" = "Extended Test" ] ; then
- echo "$SCRIPTNAME: skipping $testname for $NORM_EXT"
- elif [ "${CLIENT_MODE}" = "fips" -a "${CAUTH}" -ne 0 ] ; then
- echo "$SCRIPTNAME: skipping $testname (non-FIPS only)"
- elif [ "${NOLOGIN}" -eq 0 ] && \
- [ "${CLIENT_MODE}" = "fips" -o "$NORM_EXT" = "Extended Test" ] ; then
- echo "$SCRIPTNAME: skipping $testname for $NORM_EXT"
- else
-+ unset SERVER_VMIN
-+ unset SERVER_VMAX
-+ if [ "$ectype" = "MLDSA" ]; then
-+ SERVER_VMIN="tls1.1"
-+ SERVER_VMAX="tls1.3"
-+ fi
- cparam=`echo $cparam | sed -e 's;_; ;g' -e "s/TestUser/$USER_NICKNAME/g" `
- if [ "$ectype" = "SNI" ]; then
- cparam=`echo $cparam | sed -e "s/Host/$HOST/g" -e "s/Dom/$DOMSUF/g" `
- sparam=`echo $sparam | sed -e "s/Host/$HOST/g" -e "s/Dom/$DOMSUF/g" `
- fi
-
- start_selfserv `echo "$sparam" | sed -e 's,_, ,g'`
-
-@@ -707,20 +734,20 @@ ssl_stress()
-
- if [ "${NOLOGIN}" -eq 0 ] ; then
- dbdir=${P_R_NOLOGINDIR}
- else
- dbdir=${P_R_CLIENTDIR}
- fi
-
- echo "strsclnt -4 -q -p ${PORT} -d ${dbdir} ${CLIENT_OPTIONS} -w nss $cparam \\"
-- echo " -V ssl3:tls1.2 $verbose ${HOSTADDR}"
-+ echo " $verbose ${HOSTADDR}"
- echo "strsclnt started at `date`"
- ${PROFTOOL} ${BINDIR}/strsclnt -4 -q -p ${PORT} -d ${dbdir} ${CLIENT_OPTIONS} -w nss $cparam \
-- -V ssl3:tls1.2 $verbose ${HOSTADDR}
-+ $verbose ${HOSTADDR}
- ret=$?
- echo "strsclnt completed at `date`"
- html_msg $ret $value \
- "${testname}" \
- "produced a returncode of $ret, expected is $value. "
- if [ "`uname -n`" = "sjsu" ] ; then
- echo "debugging disapering selfserv... ps -ef | grep selfserv"
- ps -ef | grep selfserv
-@@ -983,19 +1010,18 @@ ssl_policy_pkix_ocsp()
- # 5961 reset by peer
- grep 5961 ${P_R_SERVERDIR}/vfy2.out
- GRET=$? ; echo "OCSP: RET=$RET GRET=$GRET"
- if [ $RET -ne 0 -o $GRET -eq 0 ]; then
- echo "$SCRIPTNAME: skipping Check that OCSP doesn't break if we disable sha1 $NORM_EXT - server $SERVER_MODE/client $CLIENT_MODE - can't reach external servers"
- return 0
- fi
-
-- PKIX_SAVE=${NSS_ENABLE_PKIX_VERIFY-"unset"}
-- NSS_ENABLE_PKIX_VERIFY="1"
-- export NSS_ENABLE_PKIX_VERIFY
-+ PKIX_SAVE=${NSS_DISABLE_LIBPKIX_VERIFY-"unset"}
-+ unset NSS_DISABLE_LIBPKIX_VERIFY
-
- testname=""
-
- if [ ! -f "${P_R_SERVERDIR}/pkcs11.txt" ] ; then
- html_failed "${SCRIPTNAME}: ${P_R_SERVERDIR} is not initialized"
- return 1;
- fi
-
-@@ -1010,22 +1036,20 @@ ssl_policy_pkix_ocsp()
- vfyserv -o wrong.host.badssl.com -d ${P_R_SERVERDIR} 2>&1 | tee ${P_R_SERVERDIR}/vfy.out
- # make sure we have the domain mismatch, not bad signature error
- echo "grep -E '12276|5961' ${P_R_SERVERDIR}/vfy.out"
- grep -E '12276|5961' ${P_R_SERVERDIR}/vfy.out
- RET=$?
- html_msg $RET $RET_EXP "${testname}" \
- "produced a returncode of $RET, expected is $RET_EXP"
-
-- if [ "${PKIX_SAVE}" = "unset" ]; then
-- unset NSS_ENABLE_PKIX_VERIFY
-- else
-- NSS_ENABLE_PKIX_VERIFY=${PKIX_SAVE}
-- export NSS_ENABLE_PKIX_VERIFY
-+ if [ "{PKIX_SAVE}" != "unset" ]; then
-+ export NSS_DISABLE_LIBPKIX_VERIFY=${PKIX_SAVE}
- fi
-+
- cp ${P_R_SERVERDIR}/pkcs11.txt.sav ${P_R_SERVERDIR}/pkcs11.txt
-
- html "
"
-
- }
-
- ############################## ssl_policy_selfserv #####################
- # local shell function to perform SSL Policy tests, using selfserv
-@@ -1050,17 +1074,17 @@ ssl_policy_selfserv()
- setup_policy "disallow=rsa/ssl-key-exchange" ${P_R_SERVERDIR}
-
- SAVE_SERVER_OPTIONS=${SERVER_OPTIONS}
- # make sure policy is working in the multiprocess case is working on
- # UNIX-like OS's. Other OS's can't properly clean up the child processes
- # when our test suite kills the parent, so just use the single process
- # self serve for them
- # if [ "${OS_ARCH}" != "WINNT" ]; then
-- # SERVER_OPTIONS="-M 3 ${SERVER_OPTIONS}"
-+ SERVER_OPTIONS="-M 3 ${SERVER_OPTIONS}"
- # fi
-
- start_selfserv $CIPHER_SUITES
-
- SERVER_OPTIONS="${SAVE_SERVER_OPTIONS}"
- VMIN="ssl3"
- VMAX="tls1.2"
-
-@@ -1641,20 +1665,20 @@ ssl_run_tests()
- ssl_iopr_run
- ;;
- *)
- SERVER_MODE=`echo "${SSL_TEST}" | cut -d_ -f1`
- CLIENT_MODE=`echo "${SSL_TEST}" | cut -d_ -f2`
-
- case "${SERVER_MODE}" in
- "normal")
-- SERVER_OPTIONS=
-+ SERVER_OPTIONS=""
- ;;
- "fips")
-- SERVER_OPTIONS=
-+ SERVER_OPTIONS=""
- ssl_set_fips server on
- ;;
- *)
- html_failed "${SCRIPTNAME}: Error: Unknown server mode ${SERVER_MODE}"
- return 1
- ;;
- esac
-
-diff --git a/tests/ssl/sslauth.txt b/tests/ssl/sslauth.txt
---- a/tests/ssl/sslauth.txt
-+++ b/tests/ssl/sslauth.txt
-@@ -77,8 +77,27 @@
- SNI 1 -r_-a_Host-sni.Dom -V_ssl3:tls1.2_-c_v_-w_nss_-n_TestUser_-a_Host-sni1.Dom TLS Server response with alert
- SNI 0 -r_-a_Host-sni.Dom -V_ssl3:ssl3_-w_nss_-n_TestUser SSL3 Server hello response without SNI
- SNI 1 -r_-a_Host-sni.Dom -V_ssl3:ssl3_-c_v_-w_nss_-n_TestUser_-a_Host-sni.Dom SSL3 Server hello response with SNI: SSL don't have SH extensions
- SNI 0 -r_-r_-r_-a_Host-sni.Dom -V_ssl3:tls1.2_-w_nss_-n_TestUser TLS Server hello response without SNI
- SNI 0 -r_-r_-r_-a_Host-sni.Dom -V_ssl3:tls1.2_-c_v_-w_nss_-n_TestUser_-a_Host-sni.Dom TLS Server hello response with SNI
- SNI 1 -r_-r_-r_-a_Host-sni.Dom -V_ssl3:tls1.2_-w_nss_-n_TestUser_-a_Host-sni.Dom_-a_Host.Dom TLS Server hello response with SNI: Change name on 2d HS
- SNI 1 -r_-r_-r_-a_Host-sni.Dom -V_ssl3:tls1.2_-c_v_-w_nss_-n_TestUser_-a_Host-sni.Dom_-a_Host-sni1.Dom TLS Server hello response with SNI: Change name to invalid 2d HS
- SNI 1 -r_-r_-r_-a_Host-sni.Dom -V_ssl3:tls1.2_-c_v_-w_nss_-n_TestUser_-a_Host-sni1.Dom TLS Server response with alert
-+
-+#
-+# ML-DSA Tests
-+#
-+MLDSA 0 -r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_TestUser-ml-dsa-44_-w_nss TLS 1.3 ML-DSA-44 Request don't require client auth on post hs (client auth)
-+MLDSA 0 -r_-r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_TestUser-ml-dsa-44_-w_nss TLS 1.3 ML-DSA-44 Require client auth on post hs (client auth)
-+MLDSA 0 -r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_none_-w_nss TLS 1.3 ML-DSA-44 Request don't require client auth on post hs (client does not provide auth)
-+MLDSA 1 -r_-r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_none_-w_nss TLS 1.3 ML-DSA-44 Require client auth on post hs (client does not provide auth)
-+MLDSA 0 -r_-r_-r_-E_-u -V_tls1.3:tls1.3_-E_-n_TestUser-ml-dsa-44_-w_nss TLS 1.3 ML-DSA-44 Request don't require client auth on post hs with session ticket (client auth)
-+MLDSA 0 -r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_TestUser-ml-dsa-65_-w_nss TLS 1.3 ML-DSA-65 Request don't require client auth on post hs (client auth)
-+MLDSA 0 -r_-r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_TestUser-ml-dsa-65_-w_nss TLS 1.3 ML-DSA-65 Require client auth on post hs (client auth)
-+MLDSA 0 -r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_none_-w_nss TLS 1.3 ML-DSA-65 Request don't require client auth on post hs (client does not provide auth)
-+MLDSA 1 -r_-r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_none_-w_nss TLS 1.3 ML-DSA-65 Require client auth on post hs (client does not provide auth)
-+MLDSA 0 -r_-r_-r_-E_-u -V_tls1.3:tls1.3_-E_-n_TestUser-ml-dsa-65_-w_nss TLS 1.3 ML-DSA-65 Request don't require client auth on post hs with session ticket (client auth)
-+MLDSA 0 -r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_TestUser-ml-dsa-44_-w_nss TLS 1.3 ML-DSA-44 Request don't require client auth on post hs (client auth)
-+MLDSA 0 -r_-r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_TestUser-ml-dsa-44_-w_nss TLS 1.3 ML-DSA-44 Require client auth on post hs (client auth)
-+MLDSA 0 -r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_none_-w_nss TLS 1.3 ML-DSA-44 Request don't require client auth on post hs (client does not provide auth)
-+MLDSA 1 -r_-r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_none_-w_nss TLS 1.3 ML-DSA-44 Require client auth on post hs (client does not provide auth)
-+MLDSA 0 -r_-r_-r_-E_-u -V_tls1.3:tls1.3_-E_-n_TestUser-ml-dsa-44_-w_nss TLS 1.3 ML-DSA-44 Request don't require client auth on post hs with session ticket (client auth)
-diff --git a/tests/ssl/sslcov.txt b/tests/ssl/sslcov.txt
---- a/tests/ssl/sslcov.txt
-+++ b/tests/ssl/sslcov.txt
-@@ -157,8 +157,9 @@ MLKEM384 TLS13 :1301 TLS13_MLKEM1024P38
- MLKEM384 TLS13 :1302 TLS13_MLKEM1024P384_WITH_AES_256_GCM_SHA384
- MLKEM384 TLS13 :1303 TLS13_MLKEM1024P384_WITH_CHACHA20_POLY1305_SHA256
- MLKEM256 TLS13 :1301 TLS13_MLKEM768P256_WITH_AES_128_GCM_SHA256
- MLKEM256 TLS13 :1302 TLS13_MLKEM768P256_WITH_AES_256_GCM_SHA384
- MLKEM256 TLS13 :1303 TLS13_MLKEM768P256_WITH_CHACHA20_POLY1305_SHA256
- MLKEM219 TLS13 :1301 TLS13_MLKEM768X25519_WITH_AES_128_GCM_SHA256
- MLKEM219 TLS13 :1302 TLS13_MLKEM768X25519_WITH_AES_256_GCM_SHA384
- MLKEM219 TLS13 :1303 TLS13_MLKEM768X25519_WITH_CHACHA20_POLY1305_SHA256
-+MLDSAECC TLS13 :1301 TLS13_ECDHE_WITH_AES_128_GCM_SHA256_WITH_MLDSA44
-diff --git a/tests/ssl_gtests/ssl_gtests.sh b/tests/ssl_gtests/ssl_gtests.sh
---- a/tests/ssl_gtests/ssl_gtests.sh
-+++ b/tests/ssl_gtests/ssl_gtests.sh
-@@ -52,16 +52,30 @@ ssl_gtest_certs() {
- make_cert ecdh_ecdsa p256 kex
- make_cert rsa_ca rsa_ca ca
- make_cert rsa_chain rsa_chain sign
- make_cert rsa_pss_ca rsapss_ca ca
- make_cert rsa_pss_chain rsapss_chain sign
- make_cert rsa_ca_rsa_pss_chain rsa_ca_rsapss_chain sign
- make_cert ecdh_rsa ecdh_rsa kex
- make_cert dsa dsa sign
-+ if [ -n "${NSS_ENABLE_ML_DSA}" ]; then
-+ make_cert mldsa44 mldsa44 sign
-+ make_cert mldsa44_ca mldsa44_ca ca
-+ make_cert mldsa44_chain mldsa44_chain sign
-+ make_cert delegator_mldsa44 delegator_mldsa44 sign
-+ make_cert mldsa65 mldsa65 sign
-+ make_cert mldsa65_ca mldsa65_ca ca
-+ make_cert mldsa65_chain mldsa65_chain sign
-+ make_cert delegator_mldsa65 delegator_mldsa65 sign
-+ make_cert mldsa87 mldsa87 sign
-+ make_cert mldsa87_ca mldsa87_ca ca
-+ make_cert mldsa87_chain mldsa87_chain sign
-+ make_cert delegator_mldsa87 delegator_mldsa87 sign
-+ fi
- make_cert delegator_ecdsa256 delegator_p256 sign
- make_cert delegator_rsae2048 delegator_rsae2048 sign
- make_cert delegator_rsa_pss2048 delegator_rsa_pss2048 sign
- }
-
- ############################## ssl_gtest_init ##########################
- # local shell function to initialize this script
- ########################################################################
-@@ -145,11 +159,15 @@ parallel_fallback()
- ssl_gtest_cleanup()
- {
- cd ${QADIR}
- . common/cleanup.sh
- }
-
- ################## main #################################################
- cd "$(dirname "$0")"
-+
-+if using_sql ; then
-+ echo "skipping ssl_gtests in dbm"
-+fi
- ssl_gtest_init
- ssl_gtest_start
- ssl_gtest_cleanup
diff --git a/nss-3.112-add-sec384r1-mlkem-1024.patch b/nss-3.112-add-sec384r1-mlkem-1024.patch
deleted file mode 100644
index fee8de9..0000000
--- a/nss-3.112-add-sec384r1-mlkem-1024.patch
+++ /dev/null
@@ -1,2149 +0,0 @@
-diff --git a/cmd/lib/secutil.c b/cmd/lib/secutil.c
---- a/cmd/lib/secutil.c
-+++ b/cmd/lib/secutil.c
-@@ -4212,17 +4212,21 @@ static const struct SSLNamedGroupString
- { NAME_AND_LEN("FF3072"), ssl_grp_ffdhe_3072 },
- { NAME_AND_LEN("FF4096"), ssl_grp_ffdhe_4096 },
- { NAME_AND_LEN("FF6144"), ssl_grp_ffdhe_6144 },
- { NAME_AND_LEN("FF8192"), ssl_grp_ffdhe_8192 },
- #ifndef NSS_DISABLE_KYBER
- { NAME_AND_LEN("xyber76800"), ssl_grp_kem_xyber768d00 },
- #endif
-+ { NAME_AND_LEN("x25519mlkem768"), ssl_grp_kem_mlkem768x25519 },
- { NAME_AND_LEN("mlkem768x25519"), ssl_grp_kem_mlkem768x25519 },
-+ { NAME_AND_LEN("secp256r1mlkem768"), ssl_grp_kem_secp256r1mlkem768 },
- { NAME_AND_LEN("mlkem768secp256r1"), ssl_grp_kem_secp256r1mlkem768 },
-+ { NAME_AND_LEN("secp384r1mlkem1024"), ssl_grp_kem_secp384r1mlkem1024 },
-+ { NAME_AND_LEN("mlkem1024secp384r1"), ssl_grp_kem_secp384r1mlkem1024},
- };
-
- static const size_t sslNamedGroupStringLen=PR_ARRAY_SIZE(sslNamedGroupStringArray);
-
- static SSLNamedGroup
- groupNameToNamedGroup(char *name)
- {
- int len = PL_strlen(name);
-@@ -4231,21 +4235,16 @@ groupNameToNamedGroup(char *name)
- for (i=0; i < sslNamedGroupStringLen; i++) {
- const struct SSLNamedGroupString *ngs = &sslNamedGroupStringArray[i];
- if (len == ngs->len) {
- if (!strncmp(name, ngs->name, len)) {
- return ngs->grp;
- }
- }
- }
-- if (PL_strlen(name) == 14) {
-- if (!strncmp(name, "mlkem768x25519", 14)) {
-- return ssl_grp_kem_mlkem768x25519;
-- }
-- }
-
- return ssl_grp_none;
- }
-
- static SECStatus
- countItems(const char *arg, unsigned int *numItems)
- {
- char *str = PORT_Strdup(arg);
-diff --git a/cmd/selfserv/selfserv.c b/cmd/selfserv/selfserv.c
---- a/cmd/selfserv/selfserv.c
-+++ b/cmd/selfserv/selfserv.c
-@@ -226,17 +226,17 @@ PrintParameterUsage()
- "-Q enables ALPN for HTTP/1.1 [RFC7301]\n"
- "-I comma separated list of enabled groups for TLS key exchange.\n"
- " The following values are valid:\n"
- " P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192,\n"
- " "
- #ifndef NSS_DISABLE_KYBER
- "xyber768d00, "
- #endif
-- "mlkem768x25519, mlkem768secp256r1\n"
-+ "x25519mlkem768, secp256r1mlkem768, secp384r1mlkem1024\n"
- "-J comma separated list of enabled signature schemes in preference order.\n"
- " The following values are valid:\n"
- " rsa_pkcs1_sha1, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,\n"
- " ecdsa_sha1, ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384,\n"
- " ecdsa_secp521r1_sha512,\n"
- " rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512,\n"
- " rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512,\n"
- "-Z enable 0-RTT (for TLS 1.3; also use -u)\n"
-diff --git a/cmd/tstclnt/tstclnt.c b/cmd/tstclnt/tstclnt.c
---- a/cmd/tstclnt/tstclnt.c
-+++ b/cmd/tstclnt/tstclnt.c
-@@ -309,17 +309,17 @@ PrintParameterUsage()
- fprintf(stderr, "%-20s Disconnect and reconnect up to N times total\n", "-L");
- fprintf(stderr, "%-20s Comma separated list of enabled groups for TLS key exchange.\n"
- "%-20s The following values are valid:\n"
- "%-20s P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n"
- "%-20s "
- #ifndef NSS_DISABLE_KYBER
- "xyber768d00, "
- #endif
-- "mlkem768x25519, mlkem768secp256r1\n",
-+ "x25519mlkem768, secp256r1mlkem768, secp384r1mlkem1024\n",
- "-I", "", "", "");
- fprintf(stderr, "%-20s Comma separated list of signature schemes in preference order.\n"
- "%-20s The following values are valid:\n"
- "%-20s rsa_pkcs1_sha1, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,\n"
- "%-20s ecdsa_sha1, ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384,\n"
- "%-20s ecdsa_secp521r1_sha512,\n"
- "%-20s rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512,\n"
- "%-20s rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512,\n"
-diff --git a/gtests/pk11_gtest/pk11_keygen.cc b/gtests/pk11_gtest/pk11_keygen.cc
---- a/gtests/pk11_gtest/pk11_keygen.cc
-+++ b/gtests/pk11_gtest/pk11_keygen.cc
-@@ -162,15 +162,20 @@ std::unique_ptr Pkcs11KeyPa
- return std::unique_ptr(
- new KyberParamHolder(CKP_NSS_KYBER_768_ROUND3));
-
- case CKM_NSS_ML_KEM_KEY_PAIR_GEN:
- std::cerr << "Generate ML-KEM768 pair" << std::endl;
- return std::unique_ptr(
- new KyberParamHolder(CKP_NSS_ML_KEM_768));
-
-+ case CKM_ML_KEM_KEY_PAIR_GEN:
-+ std::cerr << "Generate ML-KEM1024 pair" << std::endl;
-+ return std::unique_ptr(
-+ new KyberParamHolder(CKP_ML_KEM_1024));
-+
- default:
-- ADD_FAILURE() << "unknown OID " << mech_;
-+ ADD_FAILURE() << "unknown Mechanism " << mech_;
- }
- return nullptr;
- }
-
- } // namespace nss_test
-diff --git a/gtests/pk11_gtest/pk11_kem_unittest.cc b/gtests/pk11_gtest/pk11_kem_unittest.cc
---- a/gtests/pk11_gtest/pk11_kem_unittest.cc
-+++ b/gtests/pk11_gtest/pk11_kem_unittest.cc
-@@ -69,41 +69,50 @@ class Pkcs11KEMTest
- }
-
- CK_MECHANISM_TYPE keyGenMech() {
- switch (GetParam()) {
- case CKP_NSS_KYBER_768_ROUND3:
- return CKM_NSS_KYBER_KEY_PAIR_GEN;
- case CKP_NSS_ML_KEM_768:
- return CKM_NSS_ML_KEM_KEY_PAIR_GEN;
-+ case CKP_ML_KEM_768:
-+ case CKP_ML_KEM_1024:
-+ return CKM_ML_KEM_KEY_PAIR_GEN;
- default:
- EXPECT_TRUE(false);
- return 0;
- }
- }
-
- CK_MECHANISM_TYPE encapsMech() {
- switch (GetParam()) {
- case CKP_NSS_KYBER_768_ROUND3:
- return CKM_NSS_KYBER;
- case CKP_NSS_ML_KEM_768:
- return CKM_NSS_ML_KEM;
-+ case CKP_ML_KEM_768:
-+ case CKP_ML_KEM_1024:
-+ return CKM_ML_KEM;
- default:
- EXPECT_TRUE(false);
- return 0;
- }
- }
- };
-
- TEST_P(Pkcs11KEMTest, KemConsistencyTest) {
- Pkcs11KeyPairGenerator generator(keyGenMech());
- ScopedSECKEYPrivateKey priv;
- ScopedSECKEYPublicKey pub;
- generator.GenerateKey(&priv, &pub, false);
-
-+ ASSERT_NE(nullptr, pub);
-+ ASSERT_NE(nullptr, priv);
-+
- // Copy the public key to simulate receiving the key as an octet string
- ScopedSECKEYPublicKey pubCopy(SECKEY_CopyPublicKey(pub.get()));
- ASSERT_NE(nullptr, pubCopy);
-
- ScopedPK11SlotInfo slot(PK11_GetBestSlot(encapsMech(), nullptr));
- ASSERT_NE(nullptr, slot);
-
- ASSERT_NE((unsigned int)CK_INVALID_HANDLE,
-@@ -139,11 +148,13 @@ TEST_P(Pkcs11KEMTest, KemConsistencyTest
- EXPECT_EQ(0, SECITEM_CompareItem(item1, item2));
- }
-
- INSTANTIATE_TEST_SUITE_P(Pkcs11KEMTest, Pkcs11KEMTest,
- ::testing::Values(
- #ifndef NSS_DISABLE_KYBER
- CKP_NSS_KYBER_768_ROUND3,
- #endif
-+ CKP_ML_KEM_768,
-+ CKP_ML_KEM_1024,
- CKP_NSS_ML_KEM_768));
-
- } // namespace nss_test
-diff --git a/gtests/ssl_gtest/tls_agent.cc b/gtests/ssl_gtest/tls_agent.cc
---- a/gtests/ssl_gtest/tls_agent.cc
-+++ b/gtests/ssl_gtest/tls_agent.cc
-@@ -521,53 +521,57 @@ void TlsAgent::DisableAllCiphers() {
- const std::vector kAllDHEGroups = {
- ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
- ssl_grp_ec_secp521r1, ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072,
- ssl_grp_ffdhe_4096, ssl_grp_ffdhe_6144, ssl_grp_ffdhe_8192,
- #ifndef NSS_DISABLE_KYBER
- ssl_grp_kem_xyber768d00,
- #endif
- ssl_grp_kem_mlkem768x25519, ssl_grp_kem_secp256r1mlkem768,
-+ ssl_grp_kem_secp384r1mlkem1024,
- };
-
- const std::vector kNonPQDHEGroups = {
- ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
- ssl_grp_ec_secp521r1, ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072,
- ssl_grp_ffdhe_4096, ssl_grp_ffdhe_6144, ssl_grp_ffdhe_8192,
- };
-
- const std::vector kECDHEGroups = {
- ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
- ssl_grp_ec_secp521r1,
- #ifndef NSS_DISABLE_KYBER
- ssl_grp_kem_xyber768d00,
- #endif
-- ssl_grp_kem_mlkem768x25519, ssl_grp_kem_secp256r1mlkem768
-+ ssl_grp_kem_mlkem768x25519, ssl_grp_kem_secp256r1mlkem768,
-+ ssl_grp_kem_secp384r1mlkem1024,
- };
-
- const std::vector kFFDHEGroups = {
- ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072, ssl_grp_ffdhe_4096,
- ssl_grp_ffdhe_6144, ssl_grp_ffdhe_8192};
-
- // Defined because the big DHE groups are ridiculously slow.
- const std::vector kFasterDHEGroups = {
- ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
- ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072,
- #ifndef NSS_DISABLE_KYBER
- ssl_grp_kem_xyber768d00,
- #endif
- ssl_grp_kem_mlkem768x25519, ssl_grp_kem_secp256r1mlkem768,
-+ ssl_grp_kem_secp384r1mlkem1024,
- };
-
- const std::vector kEcdhHybridGroups = {
- #ifndef NSS_DISABLE_KYBER
- ssl_grp_kem_xyber768d00,
- #endif
- ssl_grp_kem_mlkem768x25519,
- ssl_grp_kem_secp256r1mlkem768,
-+ ssl_grp_kem_secp384r1mlkem1024,
- };
-
- void TlsAgent::EnableCiphersByKeyExchange(SSLKEAType kea) {
- EXPECT_TRUE(EnsureTlsSetup());
-
- for (size_t i = 0; i < SSL_NumImplementedCiphers; ++i) {
- SSLCipherSuiteInfo csinfo;
-
-@@ -735,16 +739,19 @@ void TlsAgent::CheckKEA(SSLKEAType kea,
- #endif
- case ssl_grp_kem_mlkem768x25519:
- kea_size = 255;
- break;
- case ssl_grp_ec_secp256r1:
- case ssl_grp_kem_secp256r1mlkem768:
- kea_size = 256;
- break;
-+ case ssl_grp_kem_secp384r1mlkem1024:
-+ kea_size = 384;
-+ break;
- case ssl_grp_ec_secp384r1:
- kea_size = 384;
- break;
- case ssl_grp_ffdhe_2048:
- kea_size = 2048;
- break;
- case ssl_grp_ffdhe_3072:
- kea_size = 3072;
-diff --git a/gtests/ssl_gtest/tls_mlkem_unittest.cc b/gtests/ssl_gtest/tls_mlkem_unittest.cc
---- a/gtests/ssl_gtest/tls_mlkem_unittest.cc
-+++ b/gtests/ssl_gtest/tls_mlkem_unittest.cc
-@@ -35,16 +35,25 @@ TEST_P(TlsKeyExchangeTest13, Mlkem768Sec
- EnsureKeyShareSetup();
- ConfigNamedGroups({ssl_grp_kem_secp256r1mlkem768});
-
- Connect();
- CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_secp256r1mlkem768,
- ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
- }
-
-+TEST_P(TlsKeyExchangeTest13, Mlkem1024Secp384r1Supported) {
-+ EnsureKeyShareSetup();
-+ ConfigNamedGroups({ssl_grp_kem_secp384r1mlkem1024});
-+
-+ Connect();
-+ CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_secp384r1mlkem1024,
-+ ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
-+}
-+
- TEST_P(TlsKeyExchangeTest, Tls12ClientMlkem768StartNotSupported) {
- EnsureKeyShareSetup();
- client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
- SSL_LIBRARY_VERSION_TLS_1_2);
- server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
- SSL_LIBRARY_VERSION_TLS_1_3);
- client_->DisableAllCiphers();
- client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
-@@ -53,16 +62,17 @@ TEST_P(TlsKeyExchangeTest, Tls12ClientMl
- client_->ssl_fd(),
- kECDHEGroups.size() + kEcdhHybridGroups.size()));
-
- Connect();
- std::vector groups = GetGroupDetails(groups_capture_);
- for (auto group : groups) {
- EXPECT_NE(group, ssl_grp_kem_mlkem768x25519);
- EXPECT_NE(group, ssl_grp_kem_secp256r1mlkem768);
-+ EXPECT_NE(group, ssl_grp_kem_secp384r1mlkem1024);
- }
- }
-
- TEST_P(TlsKeyExchangeTest13, Tls12ServerMlkem768x25519NotSupported) {
- EnsureKeyShareSetup();
-
- client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
- SSL_LIBRARY_VERSION_TLS_1_3);
-@@ -127,43 +137,63 @@ TEST_P(TlsKeyExchangeTest13, Mlkem768x25
-
- Connect();
- CheckKEXDetails({ssl_grp_kem_mlkem768x25519, ssl_grp_ec_secp256r1},
- {ssl_grp_kem_mlkem768x25519}, ssl_grp_ec_secp256r1);
- }
-
- TEST_P(TlsKeyExchangeTest13, Mlkem768Secp256r1ClientDisabledByPolicy) {
- EnsureKeyShareSetup();
-- client_->SetPolicy(SEC_OID_SECP256R1MLKEM768, 0, NSS_USE_ALG_IN_SSL_KX);
-+ client_->SetPolicy(SEC_OID_SECP256R1MLKEM768, 0, NSS_USE_ALG_IN_SSL_KX);
- ConfigNamedGroups({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1});
-
- Connect();
- CheckKEXDetails({ssl_grp_ec_secp256r1}, {ssl_grp_ec_secp256r1});
- }
-
- TEST_P(TlsKeyExchangeTest13, Mlkem768Secp256r1ServerDisabledByPolicy) {
- EnsureKeyShareSetup();
-- server_->SetPolicy(SEC_OID_SECP256R1MLKEM768, 0, NSS_USE_ALG_IN_SSL_KX);
-+ server_->SetPolicy(SEC_OID_SECP256R1MLKEM768, 0, NSS_USE_ALG_IN_SSL_KX);
- ConfigNamedGroups({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1});
-
- Connect();
- CheckKEXDetails({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1},
- {ssl_grp_kem_secp256r1mlkem768}, ssl_grp_ec_secp256r1);
- }
-
-+TEST_P(TlsKeyExchangeTest13, Secp384r1Mlkem1024ClientDisabledByPolicy) {
-+ EnsureKeyShareSetup();
-+ client_->SetPolicy(SEC_OID_SECP384R1MLKEM1024, 0, NSS_USE_ALG_IN_SSL_KX);
-+ ConfigNamedGroups({ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp256r1});
-+
-+ Connect();
-+ CheckKEXDetails({ssl_grp_ec_secp256r1}, {ssl_grp_ec_secp256r1});
-+}
-+
-+TEST_P(TlsKeyExchangeTest13, Secp384r1Mlkem1024ServerDisabledByPolicy) {
-+ EnsureKeyShareSetup();
-+ server_->SetPolicy(SEC_OID_SECP384R1MLKEM1024, 0, NSS_USE_ALG_IN_SSL_KX);
-+ ConfigNamedGroups({ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp256r1});
-+
-+ Connect();
-+ CheckKEXDetails({ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp256r1},
-+ {ssl_grp_kem_secp384r1mlkem1024}, ssl_grp_ec_secp256r1);
-+}
-+
- static void CheckECDHShareReuse(
- const std::shared_ptr& capture) {
- EXPECT_TRUE(capture->captured());
- const DataBuffer& ext = capture->extension();
-- DataBuffer hybrid_share[4];
-- DataBuffer ecdh_share[4];
-- int hybrid_offset[4];
-- SSLNamedGroup hybrid_ec_type[4];
-- SSLNamedGroup ec_type[4];
-- int ecdh_index[4];
-+ const int max_count=4;
-+ DataBuffer hybrid_share[max_count];
-+ DataBuffer ecdh_share[max_count];
-+ int hybrid_offset[max_count];
-+ SSLNamedGroup hybrid_ec_type[max_count];
-+ SSLNamedGroup ec_type[max_count];
-+ int ecdh_index[max_count];
- int nextHybrid = 0;
- int nextECDH = 0;
-
- size_t offset = 0;
- uint32_t ext_len;
- ext.Read(0, 2, &ext_len);
- EXPECT_EQ(ext.len() - 2, ext_len);
- offset += 2;
-@@ -180,30 +210,40 @@ static void CheckECDHShareReuse(
- hybrid_ec_type[nextHybrid] = ssl_grp_ec_curve25519;
- nextHybrid++;
- break;
- case ssl_grp_kem_secp256r1mlkem768:
- hybrid_share[nextHybrid] = DataBuffer(ext.data() + offset + 2 + 2, named_group_len);
- hybrid_offset[nextHybrid] = 0;
- hybrid_ec_type[nextHybrid] = ssl_grp_ec_secp256r1;
- nextHybrid++;
-+ break;
-+ case ssl_grp_kem_secp384r1mlkem1024:
-+ hybrid_share[nextHybrid] = DataBuffer(ext.data() + offset + 2 + 2, named_group_len);
-+ hybrid_offset[nextHybrid] = 0;
-+ hybrid_ec_type[nextHybrid] = ssl_grp_ec_secp384r1;
-+ nextHybrid++;
-+ break;
- case ssl_grp_ec_curve25519:
- case ssl_grp_ec_secp256r1:
-+ case ssl_grp_ec_secp384r1:
- ecdh_share[nextECDH] = DataBuffer(ext.data() + offset + 2 + 2, named_group_len);
- ec_type[nextECDH] = (SSLNamedGroup) named_group;
- nextECDH++;
- }
- offset += 2 + 2 + named_group_len;
- ext.Read(offset, 2, &named_group);
- ext.Read(offset + 2, 2, &named_group_len);
- }
- EXPECT_EQ(offset, ext.len());
-
- ASSERT_TRUE(nextECDH > 0);
- ASSERT_TRUE(nextHybrid > 0);
-+ ASSERT_TRUE(nextECDH <= max_count);
-+ ASSERT_TRUE(nextHybrid <= max_count);
- /* setup the hybrid ecdh indeces */
- for (int i=0; i < nextHybrid; i++) {
- ecdh_index[i] = -1;
- for (int j=0; j < nextECDH; j++) {
- if (hybrid_ec_type[i] == ec_type[j]) {
- ecdh_index[i] = j;
- break;
- }
-@@ -265,16 +305,40 @@ TEST_P(TlsKeyExchangeTest13, Mlkem768Sec
-
- Connect();
-
- CheckKEXDetails({ssl_grp_ec_secp256r1, ssl_grp_kem_secp256r1mlkem768},
- {ssl_grp_ec_secp256r1, ssl_grp_kem_secp256r1mlkem768});
- CheckECDHShareReuse(shares_capture_);
- }
-
-+TEST_P(TlsKeyExchangeTest13, Secp384r1Mlkem1024ShareReuseFirst) {
-+ EnsureKeyShareSetup();
-+ ConfigNamedGroups({ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp384r1});
-+ EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
-+
-+ Connect();
-+
-+ CheckKEXDetails({ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp384r1},
-+ {ssl_grp_kem_secp384r1mlkem1024, ssl_grp_ec_secp384r1});
-+ CheckECDHShareReuse(shares_capture_);
-+}
-+
-+TEST_P(TlsKeyExchangeTest13, Secp384r1Mlkem1024ShareReuseSecond) {
-+ EnsureKeyShareSetup();
-+ ConfigNamedGroups({ssl_grp_ec_secp384r1, ssl_grp_kem_secp384r1mlkem1024});
-+ EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
-+
-+ Connect();
-+
-+ CheckKEXDetails({ssl_grp_ec_secp384r1, ssl_grp_kem_secp384r1mlkem1024},
-+ {ssl_grp_ec_secp384r1, ssl_grp_kem_secp384r1mlkem1024});
-+ CheckECDHShareReuse(shares_capture_);
-+}
-+
- class Mlkem768x25519ShareDamager : public TlsExtensionFilter {
- public:
- typedef enum {
- downgrade,
- extend,
- truncate,
- zero_ecdh,
- modify_ecdh,
-diff --git a/lib/freebl/Makefile b/lib/freebl/Makefile
---- a/lib/freebl/Makefile
-+++ b/lib/freebl/Makefile
-@@ -594,17 +594,22 @@ ifndef NSS_DISABLE_CHACHAPOLY
- EXTRA_SRCS += Hacl_Poly1305_128.c Hacl_Chacha20_Vec128.c Hacl_Chacha20Poly1305_128.c
- DEFINES += -DHACL_CAN_COMPILE_VEC128
- endif
- endif # x86_64
-
- VERIFIED_SRCS += Hacl_Poly1305_32.c Hacl_Chacha20.c Hacl_Chacha20Poly1305_32.c
- endif # NSS_DISABLE_CHACHAPOLY
-
-+ifndef NSS_DISABLE_KYBER
-+KYBER_PQCRYSTALS = kyber-pqcrystals-ref.c
-+endif
-+
- VERIFIED_SRCS += Hacl_Hash_SHA3.c Hacl_P256.c Hacl_P384.c Hacl_P521.c libcrux_mlkem768_portable.c libcrux_mlkem_portable.c libcrux_core.c
-+VERIFIED_SRCS += libcrux_mlkem1024_portable.c
- VERIFIED_SRCS += Hacl_Ed25519.c
- VERIFIED_SRCS += Hacl_Curve25519_51.c
-
- # Bug 1918767 / Bug 1918711 - by setting KRML_MUSTINLINE=inline here, we
- # avoid it being defined to `inline __forceinline` (for msvc) or `inline
- # __attribute__((always_inline))` (for gcc/clang) in
- # verified/karamel/include/krml/internal/target.h. These other
- # configurations can cause excessive stack usage.
-diff --git a/lib/freebl/freebl_base.gypi b/lib/freebl/freebl_base.gypi
---- a/lib/freebl/freebl_base.gypi
-+++ b/lib/freebl/freebl_base.gypi
-@@ -27,17 +27,16 @@
- 'ecl/ecp_secp521r1.c',
- 'fipsfreebl.c',
- 'blinit.c',
- 'freeblver.c',
- 'gcm.c',
- 'hmacct.c',
- 'jpake.c',
- 'kyber.c',
-- 'kyber-pqcrystals-ref.c',
- 'ldvector.c',
- 'md2.c',
- 'md5.c',
- 'mpi/mp_gf2m.c',
- 'mpi/mpcpucache.c',
- 'mpi/mpi.c',
- 'mpi/mplogic.c',
- 'mpi/mpmontg.c',
-@@ -228,13 +227,25 @@
- 'MP_IS_LITTLE_ENDIAN',
- 'MPI_AMD64',
- 'MP_ASSEMBLY_MULTIPLY',
- 'NSS_USE_COMBA',
- ],
- }],
- ],
- }],
-+ [ 'no_kyber_support==0', {
-+ 'sources': [
-+ 'kyber-pqcrystals-ref.c',
-+ ],
-+ }]
-+ [ 'ml_kem_1024_support==1', {
-+ 'sources': [
-+ 'verified/libcrux_mlkem1024_portable.c',
-+ ],
-+ }]
-+
-+
- ],
- 'ldflags': [
- '-Wl,-Bsymbolic'
- ],
- }
-diff --git a/lib/freebl/kyber.c b/lib/freebl/kyber.c
---- a/lib/freebl/kyber.c
-+++ b/lib/freebl/kyber.c
-@@ -12,126 +12,168 @@
- #include "secerr.h"
- #include "secitem.h"
-
- #include "kyber-pqcrystals-ref.h"
- #include "kyber.h"
- #include "verified/internal/libcrux_core.h"
- #include "verified/libcrux_mlkem768_portable.h"
- #include "verified/libcrux_mlkem768.h"
-+#include "verified/libcrux_mlkem1024_portable.h"
-+#include "verified/libcrux_mlkem1024.h"
-
- /* Consistency check between kyber-pqcrystals-ref.h and kyber.h */
- PR_STATIC_ASSERT(KYBER768_PUBLIC_KEY_BYTES == pqcrystals_kyber768_PUBLICKEYBYTES);
- PR_STATIC_ASSERT(KYBER768_PRIVATE_KEY_BYTES == pqcrystals_kyber768_SECRETKEYBYTES);
- PR_STATIC_ASSERT(KYBER768_CIPHERTEXT_BYTES == pqcrystals_kyber768_CIPHERTEXTBYTES);
- PR_STATIC_ASSERT(KYBER_SHARED_SECRET_BYTES == pqcrystals_kyber768_BYTES);
- PR_STATIC_ASSERT(KYBER_KEYPAIR_COIN_BYTES == pqcrystals_kyber768_KEYPAIRCOINBYTES);
- PR_STATIC_ASSERT(KYBER_ENC_COIN_BYTES == pqcrystals_kyber768_ENCCOINBYTES);
-
- /* Consistency check between libcrux_mlkem768_portable.h and kyber.h */
- PR_STATIC_ASSERT(KYBER768_PUBLIC_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM768_CPA_PKE_PUBLIC_KEY_SIZE_768);
- PR_STATIC_ASSERT(KYBER768_PRIVATE_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM768_SECRET_KEY_SIZE_768);
- PR_STATIC_ASSERT(KYBER768_CIPHERTEXT_BYTES == LIBCRUX_ML_KEM_MLKEM768_CPA_PKE_CIPHERTEXT_SIZE_768);
- PR_STATIC_ASSERT(KYBER_SHARED_SECRET_BYTES == LIBCRUX_ML_KEM_CONSTANTS_SHARED_SECRET_SIZE);
-+
-+/* Consistency check between libcrux_mlkem1024_portable.h and kyber.h */
-+PR_STATIC_ASSERT(MLKEM1024_PUBLIC_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_PUBLIC_KEY_SIZE_1024);
-+PR_STATIC_ASSERT(MLKEM1024_PRIVATE_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM1024_SECRET_KEY_SIZE_1024);
-+PR_STATIC_ASSERT(MLKEM1024_CIPHERTEXT_BYTES == LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_CIPHERTEXT_SIZE_1024);
-+
- PR_STATIC_ASSERT(KYBER_KEYPAIR_COIN_BYTES == 64);
- PR_STATIC_ASSERT(KYBER_ENC_COIN_BYTES == 32);
-
- static bool
- valid_params(KyberParams params)
- {
- switch (params) {
-+#ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3:
- case params_kyber768_round3_test_mode:
-+#endif
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
-+ case params_ml_kem1024:
-+ case params_ml_kem1024_test_mode:
- return true;
- default:
- return false;
- }
- }
-
- static bool
- valid_pubkey(KyberParams params, const SECItem *pubkey)
- {
- switch (params) {
-+#ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3:
- case params_kyber768_round3_test_mode:
-+#endif
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
- return pubkey && pubkey->len == KYBER768_PUBLIC_KEY_BYTES;
-+ case params_ml_kem1024:
-+ case params_ml_kem1024_test_mode:
-+ return pubkey && pubkey->len ==MLKEM1024_PUBLIC_KEY_BYTES;
- default:
- return false;
- }
- }
-
- static bool
- valid_privkey(KyberParams params, const SECItem *privkey)
- {
- switch (params) {
-+#ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3:
- case params_kyber768_round3_test_mode:
-+#endif
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
- return privkey && privkey->len == KYBER768_PRIVATE_KEY_BYTES;
-+ case params_ml_kem1024:
-+ case params_ml_kem1024_test_mode:
-+ return privkey && privkey->len == MLKEM1024_PRIVATE_KEY_BYTES;
- default:
- return false;
- }
- }
-
- static bool
- valid_ciphertext(KyberParams params, const SECItem *ciphertext)
- {
- switch (params) {
-+#ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3:
- case params_kyber768_round3_test_mode:
-+#endif
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
- return ciphertext && ciphertext->len == KYBER768_CIPHERTEXT_BYTES;
-+ case params_ml_kem1024:
-+ case params_ml_kem1024_test_mode:
-+ return ciphertext && ciphertext->len == MLKEM1024_CIPHERTEXT_BYTES;
- default:
- return false;
- }
- }
-
- static bool
- valid_secret(KyberParams params, const SECItem *secret)
- {
- switch (params) {
-+#ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3:
- case params_kyber768_round3_test_mode:
-+#endif
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
-+ case params_ml_kem1024:
-+ case params_ml_kem1024_test_mode:
- return secret && secret->len == KYBER_SHARED_SECRET_BYTES;
- default:
- return false;
- }
- }
-
- static bool
- valid_keypair_seed(KyberParams params, const SECItem *seed)
- {
- switch (params) {
-+#ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3:
- case params_kyber768_round3_test_mode:
-+#endif
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
-+ case params_ml_kem1024:
-+ case params_ml_kem1024_test_mode:
- return !seed || seed->len == KYBER_KEYPAIR_COIN_BYTES;
- default:
- return false;
- }
- }
-
- static bool
- valid_enc_seed(KyberParams params, const SECItem *seed)
- {
- switch (params) {
-+#ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3:
-+#endif
- case params_ml_kem768:
-+ case params_ml_kem1024:
- return !seed;
-+#ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3_test_mode:
-+#endif
- case params_ml_kem768_test_mode:
-+ case params_ml_kem1024_test_mode:
-+ return !seed;
- return !seed || seed->len == KYBER_SHARED_SECRET_BYTES;
- default:
- return false;
- }
- }
-
- SECStatus
- Kyber_NewKey(KyberParams params, const SECItem *keypair_seed, SECItem *privkey, SECItem *pubkey)
-@@ -153,22 +195,28 @@ Kyber_NewKey(KyberParams params, const S
- } else {
- if (RNG_GenerateGlobalRandomBytes(randbuf, sizeof randbuf) != SECSuccess) {
- PORT_SetError(SEC_ERROR_NEED_RANDOM);
- return SECFailure;
- }
- coins = randbuf;
- }
- NSS_CLASSIFY(coins, KYBER_KEYPAIR_COIN_BYTES);
-- if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) {
-- pqcrystals_kyber768_ref_keypair_derand(pubkey->data, privkey->data, coins);
-- } else if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) {
-+ if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) {
- libcrux_ml_kem_mlkem768_MlKem768KeyPair keys = libcrux_ml_kem_mlkem768_portable_generate_key_pair(coins);
- memcpy(pubkey->data, keys.pk.value, KYBER768_PUBLIC_KEY_BYTES);
- memcpy(privkey->data, keys.sk.value, KYBER768_PRIVATE_KEY_BYTES);
-+ } else if (params == params_ml_kem1024 || params == params_ml_kem1024_test_mode) {
-+ libcrux_ml_kem_mlkem1024_MlKem1024KeyPair keys = libcrux_ml_kem_mlkem1024_portable_generate_key_pair(coins);
-+ memcpy(pubkey->data, keys.pk.value, MLKEM1024_PUBLIC_KEY_BYTES);
-+ memcpy(privkey->data, keys.sk.value, MLKEM1024_PRIVATE_KEY_BYTES);
-+#ifndef NSS_DISABLE_KYBER
-+ } else if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) {
-+ pqcrystals_kyber768_ref_keypair_derand(pubkey->data, privkey->data, coins);
-+#endif
- } else {
- /* unreachable */
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
- NSS_DECLASSIFY(pubkey->data, pubkey->len);
- return SECSuccess;
- }
-@@ -193,31 +241,48 @@ Kyber_Encapsulate(KyberParams params, co
- } else {
- if (RNG_GenerateGlobalRandomBytes(randbuf, sizeof randbuf) != SECSuccess) {
- PORT_SetError(SEC_ERROR_NEED_RANDOM);
- return SECFailure;
- }
- coins = randbuf;
- }
- NSS_CLASSIFY(coins, KYBER_ENC_COIN_BYTES);
-- if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) {
-- pqcrystals_kyber768_ref_enc_derand(ciphertext->data, secret->data, pubkey->data, coins);
-- } else if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) {
-+ if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) {
-+ /* shouldn't this just use the typedef im libcrux_mlkem768.h? */
- libcrux_ml_kem_types_MlKemPublicKey_15 pk_value;
- memcpy(pk_value.value, pubkey->data, KYBER768_PUBLIC_KEY_BYTES);
-
- bool valid_pk = libcrux_ml_kem_mlkem768_portable_validate_public_key(&pk_value);
- if (!valid_pk) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
-
- tuple_3c encap = libcrux_ml_kem_mlkem768_portable_encapsulate(&pk_value, coins);
- memcpy(ciphertext->data, encap.fst.value, KYBER768_CIPHERTEXT_BYTES);
- memcpy(secret->data, encap.snd, KYBER_SHARED_SECRET_BYTES);
-+ } else if (params == params_ml_kem1024 || params == params_ml_kem1024_test_mode) {
-+ /* shouldn't this just use the typedef im libcrux_mlkem1024.h? */
-+ libcrux_ml_kem_types_MlKemPublicKey_1f pk_value;
-+ memcpy(pk_value.value, pubkey->data, MLKEM1024_PUBLIC_KEY_BYTES);
-+
-+ bool valid_pk = libcrux_ml_kem_mlkem1024_portable_validate_public_key(&pk_value);
-+ if (!valid_pk) {
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ return SECFailure;
-+ }
-+
-+ tuple_21 encap = libcrux_ml_kem_mlkem1024_portable_encapsulate(&pk_value, coins);
-+ memcpy(ciphertext->data, encap.fst.value, MLKEM1024_CIPHERTEXT_BYTES);
-+ memcpy(secret->data, encap.snd, KYBER_SHARED_SECRET_BYTES);
-+#ifndef NSS_DISABLE_KYBER
-+ } else if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) {
-+ pqcrystals_kyber768_ref_enc_derand(ciphertext->data, secret->data, pubkey->data, coins);
-+#endif
- } else {
- /* unreachable */
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-
- return SECSuccess;
- }
-@@ -230,32 +295,48 @@ Kyber_Decapsulate(KyberParams params, co
- return SECFailure;
- }
-
- if (!(valid_privkey(params, privkey) && valid_ciphertext(params, ciphertext) && valid_secret(params, secret))) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
-
-- if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) {
-- pqcrystals_kyber768_ref_dec(secret->data, ciphertext->data, privkey->data);
-- } else if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) {
-+ if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) {
- libcrux_ml_kem_types_MlKemPrivateKey_55 private_key;
- memcpy(private_key.value, privkey->data, KYBER768_PRIVATE_KEY_BYTES);
-
- libcrux_ml_kem_mlkem768_MlKem768Ciphertext cipher_text;
- memcpy(cipher_text.value, ciphertext->data, KYBER768_CIPHERTEXT_BYTES);
-
- bool valid = libcrux_ml_kem_mlkem768_portable_validate_private_key(&private_key, &cipher_text);
- if (!valid) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
-
- libcrux_ml_kem_mlkem768_portable_decapsulate(&private_key, &cipher_text, secret->data);
-+ } else if (params == params_ml_kem1024 || params == params_ml_kem1024_test_mode) {
-+ libcrux_ml_kem_types_MlKemPrivateKey_95 private_key;
-+ memcpy(private_key.value, privkey->data, MLKEM1024_PRIVATE_KEY_BYTES);
-+
-+ libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext cipher_text;
-+ memcpy(cipher_text.value, ciphertext->data, MLKEM1024_CIPHERTEXT_BYTES);
-+
-+ bool valid = libcrux_ml_kem_mlkem1024_portable_validate_private_key(&private_key, &cipher_text);
-+ if (!valid) {
-+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ return SECFailure;
-+ }
-+
-+ libcrux_ml_kem_mlkem1024_portable_decapsulate(&private_key, &cipher_text, secret->data);
-+#ifndef NSS_DISABLE_KYBER
-+ } else if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) {
-+ pqcrystals_kyber768_ref_dec(secret->data, ciphertext->data, privkey->data);
-+#endif
- } else {
- // unreachable
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-
- return SECSuccess;
- }
-diff --git a/lib/freebl/manifest.mn b/lib/freebl/manifest.mn
---- a/lib/freebl/manifest.mn
-+++ b/lib/freebl/manifest.mn
-@@ -152,17 +152,17 @@ CSRCS = \
- rsa.c \
- rsa_blind.c \
- rsapkcs.c \
- shvfy.c \
- tlsprfalg.c \
- jpake.c \
- secmpi.c \
- kyber.c \
-- kyber-pqcrystals-ref.c \
-+ $(KYBER_PQCRYSTALS) \
- $(MPI_SRCS) \
- $(MPCPU_SRCS) \
- $(ECL_SRCS) \
- $(VERIFIED_SRCS) \
- $(STUBS_SRCS) \
- $(LOWHASH_SRCS) \
- $(EXTRA_SRCS) \
- $(NULL)
-diff --git a/lib/freebl/verified/libcrux_mlkem1024.h b/lib/freebl/verified/libcrux_mlkem1024.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/verified/libcrux_mlkem1024.h
-@@ -0,0 +1,94 @@
-+/*
-+ * SPDX-FileCopyrightText: 2024 Cryspen Sarl
-+ *
-+ * SPDX-License-Identifier: MIT or Apache-2.0
-+ *
-+ * This code was generated with the following revisions:
-+ * Charon: b351338f6a84c7a1afc27433eb0ffdc668b3581d
-+ * Eurydice: 7efec1624422fd5e94388ef06b9c76dfe7a48d46
-+ * Karamel: c96fb69d15693284644d6aecaa90afa37e4de8f0
-+ * F*: 58c915a86a2c07c8eca8d9deafd76cb7a91f0eb7
-+ * Libcrux: 6ff01fb3c57ff29ecb59bc62d9dc7fd231060cfb
-+ */
-+
-+#ifndef __libcrux_mlkem1024_H
-+#define __libcrux_mlkem1024_H
-+
-+#if defined(__cplusplus)
-+extern "C" {
-+#endif
-+
-+#include "eurydice_glue.h"
-+#include "libcrux_core.h"
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_VECTOR_U_COMPRESSION_FACTOR_1024 ((size_t)11U)
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_C1_BLOCK_SIZE_1024 \
-+ (LIBCRUX_ML_KEM_CONSTANTS_COEFFICIENTS_IN_RING_ELEMENT * \
-+ LIBCRUX_ML_KEM_MLKEM1024_VECTOR_U_COMPRESSION_FACTOR_1024 / (size_t)8U)
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_RANK_1024 ((size_t)4U)
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_C1_SIZE_1024 \
-+ (LIBCRUX_ML_KEM_MLKEM1024_C1_BLOCK_SIZE_1024 * \
-+ LIBCRUX_ML_KEM_MLKEM1024_RANK_1024)
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_VECTOR_V_COMPRESSION_FACTOR_1024 ((size_t)5U)
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_C2_SIZE_1024 \
-+ (LIBCRUX_ML_KEM_CONSTANTS_COEFFICIENTS_IN_RING_ELEMENT * \
-+ LIBCRUX_ML_KEM_MLKEM1024_VECTOR_V_COMPRESSION_FACTOR_1024 / (size_t)8U)
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_CIPHERTEXT_SIZE_1024 \
-+ (LIBCRUX_ML_KEM_MLKEM1024_C1_SIZE_1024 + \
-+ LIBCRUX_ML_KEM_MLKEM1024_C2_SIZE_1024)
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_T_AS_NTT_ENCODED_SIZE_1024 \
-+ (LIBCRUX_ML_KEM_MLKEM1024_RANK_1024 * \
-+ LIBCRUX_ML_KEM_CONSTANTS_COEFFICIENTS_IN_RING_ELEMENT * \
-+ LIBCRUX_ML_KEM_CONSTANTS_BITS_PER_COEFFICIENT / (size_t)8U)
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_PUBLIC_KEY_SIZE_1024 \
-+ (LIBCRUX_ML_KEM_MLKEM1024_T_AS_NTT_ENCODED_SIZE_1024 + (size_t)32U)
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_SECRET_KEY_SIZE_1024 \
-+ (LIBCRUX_ML_KEM_MLKEM1024_RANK_1024 * \
-+ LIBCRUX_ML_KEM_CONSTANTS_COEFFICIENTS_IN_RING_ELEMENT * \
-+ LIBCRUX_ML_KEM_CONSTANTS_BITS_PER_COEFFICIENT / (size_t)8U)
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_ETA1 ((size_t)2U)
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_ETA1_RANDOMNESS_SIZE \
-+ (LIBCRUX_ML_KEM_MLKEM1024_ETA1 * (size_t)64U)
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_ETA2 ((size_t)2U)
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_ETA2_RANDOMNESS_SIZE \
-+ (LIBCRUX_ML_KEM_MLKEM1024_ETA2 * (size_t)64U)
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_IMPLICIT_REJECTION_HASH_INPUT_SIZE \
-+ (LIBCRUX_ML_KEM_CONSTANTS_SHARED_SECRET_SIZE + \
-+ LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_CIPHERTEXT_SIZE_1024)
-+
-+typedef libcrux_ml_kem_types_MlKemPrivateKey_95
-+ libcrux_ml_kem_mlkem1024_MlKem1024PrivateKey;
-+
-+typedef libcrux_ml_kem_types_MlKemPublicKey_1f
-+ libcrux_ml_kem_mlkem1024_MlKem1024PublicKey;
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_RANKED_BYTES_PER_RING_ELEMENT_1024 \
-+ (LIBCRUX_ML_KEM_MLKEM1024_RANK_1024 * \
-+ LIBCRUX_ML_KEM_CONSTANTS_BITS_PER_RING_ELEMENT / (size_t)8U)
-+
-+#define LIBCRUX_ML_KEM_MLKEM1024_SECRET_KEY_SIZE_1024 \
-+ (LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_SECRET_KEY_SIZE_1024 + \
-+ LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_PUBLIC_KEY_SIZE_1024 + \
-+ LIBCRUX_ML_KEM_CONSTANTS_H_DIGEST_SIZE + \
-+ LIBCRUX_ML_KEM_CONSTANTS_SHARED_SECRET_SIZE)
-+
-+#if defined(__cplusplus)
-+}
-+#endif
-+
-+#define __libcrux_mlkem1024_H_DEFINED
-+#endif
-diff --git a/lib/freebl/verified/libcrux_mlkem1024_portable.c b/lib/freebl/verified/libcrux_mlkem1024_portable.c
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/verified/libcrux_mlkem1024_portable.c
-@@ -0,0 +1,192 @@
-+/*
-+ * SPDX-FileCopyrightText: 2024 Cryspen Sarl
-+ *
-+ * SPDX-License-Identifier: MIT or Apache-2.0
-+ *
-+ * This code was generated with the following revisions:
-+ * Charon: b351338f6a84c7a1afc27433eb0ffdc668b3581d
-+ * Eurydice: 7efec1624422fd5e94388ef06b9c76dfe7a48d46
-+ * Karamel: c96fb69d15693284644d6aecaa90afa37e4de8f0
-+ * F*: 58c915a86a2c07c8eca8d9deafd76cb7a91f0eb7
-+ * Libcrux: 6ff01fb3c57ff29ecb59bc62d9dc7fd231060cfb
-+ */
-+
-+#include "libcrux_mlkem1024_portable.h"
-+
-+#include "internal/libcrux_mlkem_portable.h"
-+
-+/**
-+ Portable decapsulate
-+*/
-+/**
-+A monomorphic instance of
-+libcrux_ml_kem.ind_cca.instantiations.portable.decapsulate with const generics
-+- K= 4
-+- SECRET_KEY_SIZE= 3168
-+- CPA_SECRET_KEY_SIZE= 1536
-+- PUBLIC_KEY_SIZE= 1568
-+- CIPHERTEXT_SIZE= 1568
-+- T_AS_NTT_ENCODED_SIZE= 1536
-+- C1_SIZE= 1408
-+- C2_SIZE= 160
-+- VECTOR_U_COMPRESSION_FACTOR= 11
-+- VECTOR_V_COMPRESSION_FACTOR= 5
-+- C1_BLOCK_SIZE= 352
-+- ETA1= 2
-+- ETA1_RANDOMNESS_SIZE= 128
-+- ETA2= 2
-+- ETA2_RANDOMNESS_SIZE= 128
-+- IMPLICIT_REJECTION_HASH_INPUT_SIZE= 1600
-+*/
-+static void decapsulate_671(
-+ libcrux_ml_kem_types_MlKemPrivateKey_95 *private_key,
-+ libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext *ciphertext,
-+ uint8_t ret[32U]) {
-+ libcrux_ml_kem_ind_cca_decapsulate_1f1(private_key, ciphertext, ret);
-+}
-+
-+/**
-+ Decapsulate ML-KEM 1024
-+
-+ Generates an [`MlKemSharedSecret`].
-+ The input is a reference to an [`MlKem1024PrivateKey`] and an
-+ [`MlKem1024Ciphertext`].
-+*/
-+void libcrux_ml_kem_mlkem1024_portable_decapsulate(
-+ libcrux_ml_kem_types_MlKemPrivateKey_95 *private_key,
-+ libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext *ciphertext,
-+ uint8_t ret[32U]) {
-+ decapsulate_671(private_key, ciphertext, ret);
-+}
-+
-+/**
-+A monomorphic instance of
-+libcrux_ml_kem.ind_cca.instantiations.portable.encapsulate with const generics
-+- K= 4
-+- CIPHERTEXT_SIZE= 1568
-+- PUBLIC_KEY_SIZE= 1568
-+- T_AS_NTT_ENCODED_SIZE= 1536
-+- C1_SIZE= 1408
-+- C2_SIZE= 160
-+- VECTOR_U_COMPRESSION_FACTOR= 11
-+- VECTOR_V_COMPRESSION_FACTOR= 5
-+- VECTOR_U_BLOCK_LEN= 352
-+- ETA1= 2
-+- ETA1_RANDOMNESS_SIZE= 128
-+- ETA2= 2
-+- ETA2_RANDOMNESS_SIZE= 128
-+*/
-+static tuple_21 encapsulate_021(
-+ libcrux_ml_kem_types_MlKemPublicKey_1f *public_key,
-+ uint8_t randomness[32U]) {
-+ libcrux_ml_kem_types_MlKemPublicKey_1f *uu____0 = public_key;
-+ /* Passing arrays by value in Rust generates a copy in C */
-+ uint8_t copy_of_randomness[32U];
-+ memcpy(copy_of_randomness, randomness, (size_t)32U * sizeof(uint8_t));
-+ return libcrux_ml_kem_ind_cca_encapsulate_eb1(uu____0, copy_of_randomness);
-+}
-+
-+/**
-+ Encapsulate ML-KEM 1024
-+
-+ Generates an ([`MlKem1024Ciphertext`], [`MlKemSharedSecret`]) tuple.
-+ The input is a reference to an [`MlKem1024PublicKey`] and
-+ [`SHARED_SECRET_SIZE`] bytes of `randomness`.
-+*/
-+tuple_21 libcrux_ml_kem_mlkem1024_portable_encapsulate(
-+ libcrux_ml_kem_types_MlKemPublicKey_1f *public_key,
-+ uint8_t randomness[32U]) {
-+ libcrux_ml_kem_types_MlKemPublicKey_1f *uu____0 = public_key;
-+ /* Passing arrays by value in Rust generates a copy in C */
-+ uint8_t copy_of_randomness[32U];
-+ memcpy(copy_of_randomness, randomness, (size_t)32U * sizeof(uint8_t));
-+ return encapsulate_021(uu____0, copy_of_randomness);
-+}
-+
-+/**
-+ Portable generate key pair.
-+*/
-+/**
-+A monomorphic instance of
-+libcrux_ml_kem.ind_cca.instantiations.portable.generate_keypair with const
-+generics
-+- K= 4
-+- CPA_PRIVATE_KEY_SIZE= 1536
-+- PRIVATE_KEY_SIZE= 3168
-+- PUBLIC_KEY_SIZE= 1568
-+- BYTES_PER_RING_ELEMENT= 1536
-+- ETA1= 2
-+- ETA1_RANDOMNESS_SIZE= 128
-+*/
-+static libcrux_ml_kem_mlkem1024_MlKem1024KeyPair generate_keypair_871(
-+ uint8_t randomness[64U]) {
-+ /* Passing arrays by value in Rust generates a copy in C */
-+ uint8_t copy_of_randomness[64U];
-+ memcpy(copy_of_randomness, randomness, (size_t)64U * sizeof(uint8_t));
-+ return libcrux_ml_kem_ind_cca_generate_keypair_f61(copy_of_randomness);
-+}
-+
-+/**
-+ Generate ML-KEM 1024 Key Pair
-+*/
-+libcrux_ml_kem_mlkem1024_MlKem1024KeyPair
-+libcrux_ml_kem_mlkem1024_portable_generate_key_pair(uint8_t randomness[64U]) {
-+ /* Passing arrays by value in Rust generates a copy in C */
-+ uint8_t copy_of_randomness[64U];
-+ memcpy(copy_of_randomness, randomness, (size_t)64U * sizeof(uint8_t));
-+ return generate_keypair_871(copy_of_randomness);
-+}
-+
-+/**
-+ Portable private key validation
-+*/
-+/**
-+A monomorphic instance of
-+libcrux_ml_kem.ind_cca.instantiations.portable.validate_private_key with const
-+generics
-+- K= 4
-+- SECRET_KEY_SIZE= 3168
-+- CIPHERTEXT_SIZE= 1568
-+*/
-+static KRML_MUSTINLINE bool validate_private_key_e81(
-+ libcrux_ml_kem_types_MlKemPrivateKey_95 *private_key,
-+ libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext *ciphertext) {
-+ return libcrux_ml_kem_ind_cca_validate_private_key_dc(private_key,
-+ ciphertext);
-+}
-+
-+/**
-+ Validate a private key.
-+
-+ Returns `true` if valid, and `false` otherwise.
-+*/
-+bool libcrux_ml_kem_mlkem1024_portable_validate_private_key(
-+ libcrux_ml_kem_types_MlKemPrivateKey_95 *private_key,
-+ libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext *ciphertext) {
-+ return validate_private_key_e81(private_key, ciphertext);
-+}
-+
-+/**
-+ Portable public key validation
-+*/
-+/**
-+A monomorphic instance of
-+libcrux_ml_kem.ind_cca.instantiations.portable.validate_public_key with const
-+generics
-+- K= 4
-+- RANKED_BYTES_PER_RING_ELEMENT= 1536
-+- PUBLIC_KEY_SIZE= 1568
-+*/
-+static KRML_MUSTINLINE bool validate_public_key_7d1(uint8_t *public_key) {
-+ return libcrux_ml_kem_ind_cca_validate_public_key_b71(public_key);
-+}
-+
-+/**
-+ Validate a public key.
-+
-+ Returns `true` if valid, and `false` otherwise.
-+*/
-+bool libcrux_ml_kem_mlkem1024_portable_validate_public_key(
-+ libcrux_ml_kem_types_MlKemPublicKey_1f *public_key) {
-+ return validate_public_key_7d1(public_key->value);
-+}
-diff --git a/lib/freebl/verified/libcrux_mlkem1024_portable.h b/lib/freebl/verified/libcrux_mlkem1024_portable.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/verified/libcrux_mlkem1024_portable.h
-@@ -0,0 +1,74 @@
-+/*
-+ * SPDX-FileCopyrightText: 2024 Cryspen Sarl
-+ *
-+ * SPDX-License-Identifier: MIT or Apache-2.0
-+ *
-+ * This code was generated with the following revisions:
-+ * Charon: b351338f6a84c7a1afc27433eb0ffdc668b3581d
-+ * Eurydice: 7efec1624422fd5e94388ef06b9c76dfe7a48d46
-+ * Karamel: c96fb69d15693284644d6aecaa90afa37e4de8f0
-+ * F*: 58c915a86a2c07c8eca8d9deafd76cb7a91f0eb7
-+ * Libcrux: 6ff01fb3c57ff29ecb59bc62d9dc7fd231060cfb
-+ */
-+
-+#ifndef __libcrux_mlkem1024_portable_H
-+#define __libcrux_mlkem1024_portable_H
-+
-+#if defined(__cplusplus)
-+extern "C" {
-+#endif
-+
-+#include "eurydice_glue.h"
-+#include "libcrux_core.h"
-+
-+/**
-+ Decapsulate ML-KEM 1024
-+
-+ Generates an [`MlKemSharedSecret`].
-+ The input is a reference to an [`MlKem1024PrivateKey`] and an
-+ [`MlKem1024Ciphertext`].
-+*/
-+void libcrux_ml_kem_mlkem1024_portable_decapsulate(
-+ libcrux_ml_kem_types_MlKemPrivateKey_95 *private_key,
-+ libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext *ciphertext, uint8_t ret[32U]);
-+
-+/**
-+ Encapsulate ML-KEM 1024
-+
-+ Generates an ([`MlKem1024Ciphertext`], [`MlKemSharedSecret`]) tuple.
-+ The input is a reference to an [`MlKem1024PublicKey`] and
-+ [`SHARED_SECRET_SIZE`] bytes of `randomness`.
-+*/
-+tuple_21 libcrux_ml_kem_mlkem1024_portable_encapsulate(
-+ libcrux_ml_kem_types_MlKemPublicKey_1f *public_key,
-+ uint8_t randomness[32U]);
-+
-+/**
-+ Generate ML-KEM 1024 Key Pair
-+*/
-+libcrux_ml_kem_mlkem1024_MlKem1024KeyPair
-+libcrux_ml_kem_mlkem1024_portable_generate_key_pair(uint8_t randomness[64U]);
-+
-+/**
-+ Validate a private key.
-+
-+ Returns `true` if valid, and `false` otherwise.
-+*/
-+bool libcrux_ml_kem_mlkem1024_portable_validate_private_key(
-+ libcrux_ml_kem_types_MlKemPrivateKey_95 *private_key,
-+ libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext *ciphertext);
-+
-+/**
-+ Validate a public key.
-+
-+ Returns `true` if valid, and `false` otherwise.
-+*/
-+bool libcrux_ml_kem_mlkem1024_portable_validate_public_key(
-+ libcrux_ml_kem_types_MlKemPublicKey_1f *public_key);
-+
-+#if defined(__cplusplus)
-+}
-+#endif
-+
-+#define __libcrux_mlkem1024_portable_H_DEFINED
-+#endif
-diff --git a/lib/pk11wrap/pk11akey.c b/lib/pk11wrap/pk11akey.c
---- a/lib/pk11wrap/pk11akey.c
-+++ b/lib/pk11wrap/pk11akey.c
-@@ -259,16 +259,21 @@ PK11_ImportPublicKey(PK11SlotInfo *slot,
- kemParams = CKP_NSS_KYBER_768_ROUND3;
- break;
- #endif
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
- keyType = CKK_ML_KEM;
- kemParams = CKP_ML_KEM_768;
- break;
-+ case params_ml_kem1024:
-+ case params_ml_kem1024_test_mode:
-+ keyType = CKK_ML_KEM;
-+ kemParams = CKP_ML_KEM_1024;
-+ break;
- default:
- kemParams = CKP_INVALID_ID;
- break;
- }
- /*fprintf(stderr, "PK11_ImportPublic KEY_TYPE=0x%08lx, kem_params=0x%08lxd\n",
- keyType, kemParams); */
-
- PK11_SETATTRS(attrs, CKA_PARAMETER_SET,
-@@ -908,16 +913,19 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot
- case CKP_NSS_KYBER_768_ROUND3:
- pubKey->u.kyber.params = params_kyber768_round3;
- break;
- #endif
- case CKP_NSS_ML_KEM_768:
- case CKP_ML_KEM_768:
- pubKey->u.kyber.params = params_ml_kem768;
- break;
-+ case CKP_ML_KEM_1024:
-+ pubKey->u.kyber.params = params_ml_kem1024;
-+ break;
- default:
- pubKey->u.kyber.params = params_kyber_invalid;
- break;
- }
- crv = pk11_Attr2SecItem(arena, value, &pubKey->u.kyber.publicValue);
- break;
- case fortezzaKey:
- case nullKey:
-diff --git a/lib/pk11wrap/pk11pars.c b/lib/pk11wrap/pk11pars.c
---- a/lib/pk11wrap/pk11pars.c
-+++ b/lib/pk11wrap/pk11pars.c
-@@ -244,17 +244,32 @@ static const oidValDef curveOptList[] =
- { CIPHER_NAME("SECP521R1"), SEC_OID_SECG_EC_SECP521R1,
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
- { CIPHER_NAME("CURVE25519"), SEC_OID_CURVE25519,
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
- { CIPHER_NAME("XYBER768D00"), SEC_OID_XYBER768D00,
- NSS_USE_ALG_IN_SSL_KX },
- { CIPHER_NAME("MLKEM768X25519"), SEC_OID_MLKEM768X25519,
- NSS_USE_ALG_IN_SSL_KX },
-- { CIPHER_NAME("MLKEM768SECP256R1"), SEC_OID_SECP256R1MLKEM768,
-+ { CIPHER_NAME("SECP256R1MLKEM768"), SEC_OID_SECP256R1MLKEM768,
-+ NSS_USE_ALG_IN_SSL_KX },
-+ { CIPHER_NAME("MLKEM1024SECP384R1"), SEC_OID_SECP384R1MLKEM1024,
-+ NSS_USE_ALG_IN_SSL_KX },
-+ { CIPHER_NAME("X25519MLKEM768"), SEC_OID_MLKEM768X25519,
-+ NSS_USE_ALG_IN_SSL_KX },
-+ { CIPHER_NAME("SECP256R1MLKEM768"), SEC_OID_SECP256R1MLKEM768,
-+ NSS_USE_ALG_IN_SSL_KX },
-+ { CIPHER_NAME("SECP384R1MLKEM1024"), SEC_OID_SECP384R1MLKEM1024,
-+ NSS_USE_ALG_IN_SSL_KX },
-+ /* aliases for old names */
-+ { CIPHER_NAME("MLKEM768X25519"), SEC_OID_MLKEM768X25519,
-+ NSS_USE_ALG_IN_SSL_KX },
-+ { CIPHER_NAME("SECP256R1MLKEM768"), SEC_OID_SECP256R1MLKEM768,
-+ NSS_USE_ALG_IN_SSL_KX },
-+ { CIPHER_NAME("MLKEM1024SECP384R1"), SEC_OID_SECP384R1MLKEM1024,
- NSS_USE_ALG_IN_SSL_KX },
- /* ANSI X9.62 named elliptic curves (characteristic two field) */
- { CIPHER_NAME("C2PNB163V1"), SEC_OID_ANSIX962_EC_C2PNB163V1,
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
- { CIPHER_NAME("C2PNB163V2"), SEC_OID_ANSIX962_EC_C2PNB163V2,
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
- { CIPHER_NAME("C2PNB163V3"), SEC_OID_ANSIX962_EC_C2PNB163V3,
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
-diff --git a/lib/pk11wrap/pk11skey.c b/lib/pk11wrap/pk11skey.c
---- a/lib/pk11wrap/pk11skey.c
-+++ b/lib/pk11wrap/pk11skey.c
-@@ -3083,16 +3083,19 @@ static CK_ULONG
- pk11_KyberCiphertextLength(SECKEYKyberPublicKey *pubKey)
- {
- switch (pubKey->params) {
- case params_kyber768_round3:
- case params_kyber768_round3_test_mode:
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
- return KYBER768_CIPHERTEXT_BYTES;
-+ case params_ml_kem1024:
-+ case params_ml_kem1024_test_mode:
-+ return MLKEM1024_CIPHERTEXT_BYTES;
- default:
- // unreachable
- return 0;
- }
- }
-
- static CK_ULONG
- pk11_KEMCiphertextLength(SECKEYPublicKey *pubKey)
-diff --git a/lib/pk11wrap/secmodti.h b/lib/pk11wrap/secmodti.h
---- a/lib/pk11wrap/secmodti.h
-+++ b/lib/pk11wrap/secmodti.h
-@@ -201,12 +201,13 @@ struct PK11GenericObjectStr {
-
- /* This mask includes all CK_FLAGs with an equivalent CKA_ attribute. */
- #define CKF_KEY_OPERATION_FLAGS 0x000e7b00UL
-
- /*
- * private header file, so we can set real names for oids that aren't upstream
- * yet, so we applications don't try to use them and get hosed when they change
- */
--#define SEC_OID_SECP256R1MLKEM768 SEC_OID_PRIVATE_1
--#define SEC_OID_MLKEM1024SECP256R1 SEC_OID_PRIVATE_2
-+#define SEC_OID_X25519MLKEM768 SEC_OID_MLKEM768X25519
-+#define SEC_OID_SECP256R1MLKEM768 SEC_OID_PRIVATE_1
-+#define SEC_OID_SECP384R1MLKEM1024 SEC_OID_PRIVATE_2
-
- #endif /* _SECMODTI_H_ */
-diff --git a/lib/softoken/kem.c b/lib/softoken/kem.c
---- a/lib/softoken/kem.c
-+++ b/lib/softoken/kem.c
-@@ -7,77 +7,90 @@
- #include "pkcs11i.h"
- #include "pkcs11n.h"
- #include "secerr.h"
- #include "secitem.h"
- #include "secport.h"
- #include "softoken.h"
-
- /* change to the largest KEM Secret Bytes value supported */
--#define MAX_SHARED_SECRET_BYTES KYBER_SHARED_SECRET_BYTES
-+/* currenly only mlkem is supported */
-+#define MAX_KEM_SHARED_SECRET_BYTES KYBER_SHARED_SECRET_BYTES
-
- KyberParams
- sftk_kyber_PK11ParamToInternal(CK_ML_KEM_PARAMETER_SET_TYPE pk11ParamSet)
- {
- switch (pk11ParamSet) {
- #ifndef NSS_DISABLE_KYBER
- case CKP_NSS_KYBER_768_ROUND3:
- return params_kyber768_round3;
- #endif
- case CKP_NSS_ML_KEM_768:
- case CKP_ML_KEM_768:
- return params_ml_kem768;
-+ case CKP_ML_KEM_1024:
-+ return params_ml_kem1024;
- default:
- return params_kyber_invalid;
- }
- }
-
- SECItem *
- sftk_kyber_AllocPubKeyItem(KyberParams params, SECItem *pubkey)
- {
- switch (params) {
- #ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3:
- case params_kyber768_round3_test_mode:
- #endif
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
- return SECITEM_AllocItem(NULL, pubkey, KYBER768_PUBLIC_KEY_BYTES);
-+ case params_ml_kem1024:
-+ case params_ml_kem1024_test_mode:
-+ return SECITEM_AllocItem(NULL, pubkey, MLKEM1024_PUBLIC_KEY_BYTES);
- default:
- return NULL;
- }
- }
-
- SECItem *
- sftk_kyber_AllocPrivKeyItem(KyberParams params, SECItem *privkey)
- {
- switch (params) {
- #ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3:
- case params_kyber768_round3_test_mode:
- #endif
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
- return SECITEM_AllocItem(NULL, privkey, KYBER768_PRIVATE_KEY_BYTES);
-+ case params_ml_kem1024:
-+ case params_ml_kem1024_test_mode:
-+ return SECITEM_AllocItem(NULL, privkey, MLKEM1024_PRIVATE_KEY_BYTES);
- default:
- return NULL;
- }
- }
-
- SECItem *
- sftk_kyber_AllocCiphertextItem(KyberParams params, SECItem *ciphertext)
- {
- switch (params) {
- #ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3:
- case params_kyber768_round3_test_mode:
- #endif
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
- return SECITEM_AllocItem(NULL, ciphertext, KYBER768_CIPHERTEXT_BYTES);
-+ case params_ml_kem1024:
-+ case params_ml_kem1024_test_mode:
-+ return SECITEM_AllocItem(NULL, ciphertext, MLKEM1024_CIPHERTEXT_BYTES);
-+
- default:
- return NULL;
- }
- }
-
- static PRBool
- sftk_kem_ValidateMechanism(CK_MECHANISM_PTR pMechanism)
- {
-@@ -147,16 +160,18 @@ sftk_kem_CiphertextLen(CK_MECHANISM_PTR
- case CKM_ML_KEM:
- switch (paramSet) {
- #ifndef NSS_DISABLE_KYBER
- case CKP_NSS_KYBER_768_ROUND3:
- #endif
- case CKP_NSS_ML_KEM_768:
- case CKP_ML_KEM_768:
- return KYBER768_CIPHERTEXT_BYTES;
-+ case CKP_ML_KEM_1024:
-+ return MLKEM1024_CIPHERTEXT_BYTES;
- default:
- break;
- }
- default:
- break;
- }
- return 0;
- }
-@@ -245,17 +260,17 @@ NSC_EncapsulateKey(CK_SESSION_HANDLE hSe
- goto cleanup;
- }
-
- SECItem ciphertext = { siBuffer, pCiphertext, ciphertextLen };
- SECItem pubKey = { siBuffer, encapsulationKey->attrib.pValue, encapsulationKey->attrib.ulValueLen };
-
- /* The length of secretBuf can be increased if we ever support other KEMs
- * by changing the define at the top of this file */
-- uint8_t secretBuf[MAX_SHARED_SECRET_BYTES] = { 0 };
-+ uint8_t secretBuf[MAX_KEM_SHARED_SECRET_BYTES] = { 0 };
- SECItem secret = { siBuffer, secretBuf, sizeof secretBuf };
-
- key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_ENCAPSULATE,
- key, 0);
- key->source = SFTK_SOURCE_KEA;
- switch (pMechanism->mechanism) {
- #ifndef NSS_DISABLE_KYBER
- case CKM_NSS_KYBER:
-@@ -394,17 +409,17 @@ NSC_DecapsulateKey(CK_SESSION_HANDLE hSe
- }
-
- SECItem privKey = { siBuffer, decapsulationKey->attrib.pValue,
- decapsulationKey->attrib.ulValueLen };
- SECItem ciphertext = { siBuffer, pCiphertext, ulCiphertextLen };
-
- /* The length of secretBuf can be increased if we ever support other KEMs
- * by changing the define at the top of this file */
-- uint8_t secretBuf[MAX_SHARED_SECRET_BYTES] = { 0 };
-+ uint8_t secretBuf[MAX_KEM_SHARED_SECRET_BYTES] = { 0 };
- SECItem secret = { siBuffer, secretBuf, sizeof secretBuf };
- key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_DECAPSULATE,
- key, 0);
- key->source = SFTK_SOURCE_KEA;
-
- switch (pMechanism->mechanism) {
- #ifndef NSS_DISABLE_KYBER
- case CKM_NSS_KYBER:
-diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
---- a/lib/softoken/pkcs11c.c
-+++ b/lib/softoken/pkcs11c.c
-@@ -5532,17 +5532,17 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
- CK_KEY_TYPE genType = CKO_SECRET_KEY;
- CK_ATTRIBUTE template = { CKA_KEY_TYPE, NULL, 0 };
-
- template.pValue = &genType;
- template.ulValueLen = sizeof(genType);
- crv = CKR_OK;
- switch (keyType) {
- case CKK_ML_KEM:
-- cipher_text_length = KYBER_SHARED_SECRET_BYTES;
-+ cipher_text_length = MAX_ML_KEM_CIPHER_LENGTH;
- mech.mechanism = CKM_ML_KEM;
- break;
- case CKK_RSA:
- if (!isEncryptable) {
- /* already handled the pairwise test, no need to
- * do it again */
- goto kem_done;
- }
-diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h
---- a/lib/ssl/sslimpl.h
-+++ b/lib/ssl/sslimpl.h
-@@ -128,19 +128,19 @@ typedef enum { SSLAppOpRead = 0,
- #define DTLS_RETRANSMIT_MAX_MS 10000
- /* Time to wait in FINISHED state for retransmissions. */
- #define DTLS_RETRANSMIT_FINISHED_MS 30000
-
- /* default number of entries in namedGroupPreferences */
- #ifndef NSS_DISABLE_KYBER
- /* this define is checked against the namedGroup table
- * and compile time asserts kick in if it doesn't match */
--#define SSL_NAMED_GROUP_COUNT 34
-+#define SSL_NAMED_GROUP_COUNT 35
- #else
--#define SSL_NAMED_GROUP_COUNT 33
-+#define SSL_NAMED_GROUP_COUNT 34
- #endif
-
- /* The maximum DH and RSA bit-length supported. */
- #define SSL_MAX_DH_KEY_BITS 8192
- #define SSL_MAX_RSA_KEY_BITS 8192
-
- /* Types and names of elliptic curves used in TLS */
- typedef enum {
-diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c
---- a/lib/ssl/sslsock.c
-+++ b/lib/ssl/sslsock.c
-@@ -156,25 +156,26 @@ static const PRUint16 srtpCiphers[] = {
- }
- #define FFGROUP(size) \
- { \
- ssl_grp_ffdhe_##size, size, ssl_kea_dh, \
- SEC_OID_TLS_FFDHE_##size, PR_TRUE \
- }
- #define HYGROUP(kem, ec, size, kem_oid, ec_oid, assumeSupported) \
- { \
-- ssl_grp_kem_##kem##ec, size, ssl_kea_ecdh_hybrid, \
-- SEC_OID_##kem_oid##ec_oid, assumeSupported \
-+ ssl_grp_kem_##ec##kem, size, ssl_kea_ecdh_hybrid, \
-+ SEC_OID_##ec_oid##kem_oid, assumeSupported \
- }
-
- const sslNamedGroupDef ssl_named_groups[] = {
- /* Note that 256 for 25519 and hybrid is a lie, but we only use it for
- * checking bit security and expect 256 bits there (not 255). */
- HYGROUP(mlkem768, x25519, 256, MLKEM768, X25519, PR_TRUE),
- HYGROUP(mlkem768, secp256r1, 256, MLKEM768, SECP256R1, PR_TRUE),
-+ HYGROUP(mlkem1024, secp384r1, 384, MLKEM1024, SECP384R1, PR_TRUE),
- { ssl_grp_ec_curve25519, 256, ssl_kea_ecdh, SEC_OID_CURVE25519, PR_TRUE },
- ECGROUP(secp256r1, 256, SECP256R1, PR_TRUE),
- ECGROUP(secp384r1, 384, SECP384R1, PR_TRUE),
- ECGROUP(secp521r1, 521, SECP521R1, PR_TRUE),
- #ifndef NSS_DISABLE_KYBER
- { ssl_grp_kem_xyber768d00, 256, ssl_kea_ecdh_hybrid, SEC_OID_XYBER768D00, PR_TRUE },
- #endif
- FFGROUP(2048),
-@@ -204,16 +205,17 @@ const sslNamedGroupDef ssl_named_groups[
- ECGROUP(sect409r1, 409, SECT409R1, PR_FALSE),
- ECGROUP(sect571k1, 571, SECT571K1, PR_FALSE),
- ECGROUP(sect571r1, 571, SECT571R1, PR_FALSE),
- };
- PR_STATIC_ASSERT(SSL_NAMED_GROUP_COUNT == PR_ARRAY_SIZE(ssl_named_groups));
-
- #undef ECGROUP
- #undef FFGROUP
-+#undef HYGROUP
-
- /* forward declarations. */
- static sslSocket *ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant variant);
- static SECStatus ssl_MakeLocks(sslSocket *ss);
- static PRStatus ssl_SetDefaultsFromEnvironmentCallOnce(void);
- static void ssl_SetDefaultsFromEnvironment(void);
- static PRStatus ssl_PushIOLayer(sslSocket *ns, PRFileDesc *stack,
- PRDescIdentity id);
-diff --git a/lib/ssl/sslt.h b/lib/ssl/sslt.h
---- a/lib/ssl/sslt.h
-+++ b/lib/ssl/sslt.h
-@@ -255,25 +255,29 @@ typedef enum {
- ssl_grp_ec_secp384r1 = 24,
- ssl_grp_ec_secp521r1 = 25,
- ssl_grp_ec_curve25519 = 29, /* RFC4492 */
- ssl_grp_ffdhe_2048 = 256, /* RFC7919 */
- ssl_grp_ffdhe_3072 = 257,
- ssl_grp_ffdhe_4096 = 258,
- ssl_grp_ffdhe_6144 = 259,
- ssl_grp_ffdhe_8192 = 260,
-- ssl_grp_kem_mlkem768x25519 = 4588,
-- ssl_grp_kem_secp256r1mlkem768 = 4587,
-+ ssl_grp_kem_x25519mlkem768 = 4588,
-+ ssl_grp_kem_secp256r1mlkem768 = 4587,
-+ ssl_grp_kem_secp384r1mlkem1024 = 4589,
- #ifndef NSS_DISABLE_KYBER
- ssl_grp_kem_xyber768d00 = 25497, /* draft-tls-westerbaan-xyber768d00-02 */
- #endif
- ssl_grp_none = 65537, /* special value */
- ssl_grp_ffdhe_custom = 65538 /* special value */
- } SSLNamedGroup;
-
-+/* alias old names */
-+#define ssl_grp_kem_mlkem768x25519 ssl_grp_kem_x25519mlkem768
-+#define ssl_grp_kem_mlkem768secp256r1 ssl_grp_kem_secp256r1mlkem768
- typedef struct SSLExtraServerCertDataStr {
- /* When this struct is passed to SSL_ConfigServerCert, and authType is set
- * to a value other than ssl_auth_null, this limits the use of the key to
- * the type defined; otherwise, the certificate is configured for all
- * compatible types. */
- SSLAuthType authType;
- /* The remainder of the certificate chain. */
- const CERTCertificateList* certChain;
-diff --git a/lib/ssl/tls13con.c b/lib/ssl/tls13con.c
---- a/lib/ssl/tls13con.c
-+++ b/lib/ssl/tls13con.c
-@@ -385,19 +385,23 @@ tls13_CreateKEMKeyPair(sslSocket *ss, co
- #ifndef NSS_DISABLE_KYBER
- case ssl_grp_kem_xyber768d00:
- mechanism = CKM_NSS_KYBER_KEY_PAIR_GEN;
- paramSet = CKP_NSS_KYBER_768_ROUND3;
- break;
- #endif
- case ssl_grp_kem_mlkem768x25519:
- case ssl_grp_kem_secp256r1mlkem768:
-- mechanism = CKM_NSS_ML_KEM_KEY_PAIR_GEN;
-+ mechanism = CKM_ML_KEM_KEY_PAIR_GEN;
- paramSet = CKP_ML_KEM_768;
- break;
-+ case ssl_grp_kem_secp384r1mlkem1024:
-+ mechanism = CKM_ML_KEM_KEY_PAIR_GEN;
-+ paramSet = CKP_ML_KEM_1024;
-+ break;
- default:
- PORT_Assert(0);
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-
- PK11SlotInfo *slot = PK11_GetBestSlot(mechanism, ss->pkcs11PinArg);
- if (!slot) {
-@@ -494,16 +498,20 @@ tls13_FindHybridKeyPair(sslSocket *ss, c
- {
- sslEphemeralKeyPair *hybridPair = NULL;
- switch (groupDef->name) {
- case ssl_grp_ec_secp256r1:
- /* future, this may be a loop to check multiple named groups */
- hybridPair = ssl_LookupEphemeralKeyPair(ss,
- ssl_LookupNamedGroup(ssl_grp_kem_secp256r1mlkem768));
- break;
-+ case ssl_grp_ec_secp384r1:
-+ hybridPair = ssl_LookupEphemeralKeyPair(ss,
-+ ssl_LookupNamedGroup(ssl_grp_kem_secp384r1mlkem1024));
-+ break;
- case ssl_grp_ec_curve25519:
- #ifndef NSS_DISABLE_KYBER
- /* a loop to check multiple named groups */
- SSLNamedGroup gnames[] = { ssl_grp_kem_xyber768d00,
- ssl_grp_kem_mlkem768x25519 };
- for (int i=0; i < PR_ARRAY_SIZE(gnames); i++) {
- hybridPair = ssl_LookupEphemeralKeyPair(ss,
- ssl_LookupNamedGroup(gnames[i]));
-@@ -563,16 +571,19 @@ tls13_CreateKeyShare(sslSocket *ss, cons
-
- PORT_Assert(groupDef);
- switch (groupDef->keaType) {
- case ssl_kea_ecdh_hybrid:
- switch (groupDef->name) {
- case ssl_grp_kem_secp256r1mlkem768:
- dhGroup = ssl_LookupNamedGroup(ssl_grp_ec_secp256r1);
- break;
-+ case ssl_grp_kem_secp384r1mlkem1024:
-+ dhGroup = ssl_LookupNamedGroup(ssl_grp_ec_secp384r1);
-+ break;
- #ifndef NSS_DISABLE_KYBER
- case ssl_grp_kem_xyber768d00:
- #endif
- case ssl_grp_kem_mlkem768x25519:
- dhGroup = ssl_LookupNamedGroup(ssl_grp_ec_curve25519);
- break;
- default:
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-@@ -832,16 +843,19 @@ tls13_ImportKEMKeyShare(SECKEYPublicKey
- break;
- #endif
- case ssl_grp_kem_mlkem768x25519:
- expected_len = X25519_PUBLIC_KEY_BYTES + KYBER768_PUBLIC_KEY_BYTES;
- break;
- case ssl_grp_kem_secp256r1mlkem768:
- expected_len = SECP256_PUBLIC_KEY_BYTES + KYBER768_PUBLIC_KEY_BYTES;
- break;
-+ case ssl_grp_kem_secp384r1mlkem1024:
-+ expected_len = SECP384_PUBLIC_KEY_BYTES + MLKEM1024_PUBLIC_KEY_BYTES;
-+ break;
- default:
- PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
- return SECFailure;
- }
-
- if (entry->key_exchange.len != expected_len) {
- PORT_SetError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
- return SECFailure;
-@@ -866,16 +880,23 @@ tls13_ImportKEMKeyShare(SECKEYPublicKey
- break;
- case ssl_grp_kem_secp256r1mlkem768:
- peerKey->keyType = kyberKey;
- peerKey->u.kyber.params = params_ml_kem768;
- /* key_exchange.data is `secp256 || mlkem768` */
- pk.data = entry->key_exchange.data + SECP256_PUBLIC_KEY_BYTES;
- pk.len = KYBER768_PUBLIC_KEY_BYTES;
- break;
-+ case ssl_grp_kem_secp384r1mlkem1024:
-+ peerKey->keyType = kyberKey;
-+ peerKey->u.kyber.params = params_ml_kem1024;
-+ /* key_exchange.data is `secp384 || mlkem1024` */
-+ pk.data = entry->key_exchange.data + SECP384_PUBLIC_KEY_BYTES;
-+ pk.len = MLKEM1024_PUBLIC_KEY_BYTES;
-+ break;
- default:
- PORT_Assert(0);
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-
- rv = SECITEM_CopyItem(peerKey->arena, &peerKey->u.kyber.publicValue, &pk);
- if (rv != SECSuccess) {
-@@ -914,16 +935,24 @@ tls13_HandleKEMCiphertext(sslSocket *ss,
- case ssl_grp_kem_secp256r1mlkem768:
- if (entry->key_exchange.len != SECP256_PUBLIC_KEY_BYTES + KYBER768_CIPHERTEXT_BYTES) {
- ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
- return SECFailure;
- }
- ct.data = entry->key_exchange.data + SECP256_PUBLIC_KEY_BYTES;
- ct.len = KYBER768_CIPHERTEXT_BYTES;
- break;
-+ case ssl_grp_kem_secp384r1mlkem1024:
-+ if (entry->key_exchange.len != SECP384_PUBLIC_KEY_BYTES + MLKEM1024_CIPHERTEXT_BYTES) {
-+ ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
-+ return SECFailure;
-+ }
-+ ct.data = entry->key_exchange.data + SECP384_PUBLIC_KEY_BYTES;
-+ ct.len = MLKEM1024_CIPHERTEXT_BYTES;
-+ break;
- default:
- PORT_Assert(0);
- ssl_MapLowLevelError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-
- rv = PK11_Decapsulate(keyPair->privKey, &ct, CKM_HKDF_DERIVE, PK11_ATTR_SESSION,
- CKF_DERIVE, outKey);
-@@ -1039,16 +1068,24 @@ tls13_HandleKeyShare(sslSocket *ss,
- case ssl_grp_kem_secp256r1mlkem768:
- dhLen = SECP256_PUBLIC_KEY_BYTES;
- /* secp256 share is at the beginning */
- ec_data = entry->key_exchange.len < dhLen
- ? NULL
- : entry->key_exchange.data;
- dhGroup = ssl_LookupNamedGroup(ssl_grp_ec_secp256r1);
- break;
-+ case ssl_grp_kem_secp384r1mlkem1024:
-+ dhLen = SECP384_PUBLIC_KEY_BYTES;
-+ /* secp256 share is at the beginning */
-+ ec_data = entry->key_exchange.len < dhLen
-+ ? NULL
-+ : entry->key_exchange.data;
-+ dhGroup = ssl_LookupNamedGroup(ssl_grp_ec_secp384r1);
-+ break;
- default:
- ec_data = NULL;
- break;
- }
- if (!ec_data) {
- PORT_SetError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
- goto loser;
- }
-@@ -2927,16 +2964,17 @@ tls13_HandleClientKeyShare(sslSocket *ss
- case ssl_grp_kem_xyber768d00:
- ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
- break;
- #endif
- case ssl_grp_kem_mlkem768x25519:
- ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(kemSecret, dheSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
- break;
- case ssl_grp_kem_secp256r1mlkem768:
-+ case ssl_grp_kem_secp384r1mlkem1024:
- ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
- break;
- default:
- PORT_Assert(0);
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- ss->ssl3.hs.dheSecret = NULL;
- break;
- }
-@@ -3791,16 +3829,17 @@ tls13_HandleServerKeyShare(sslSocket *ss
- case ssl_grp_kem_xyber768d00:
- ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
- break;
- #endif
- case ssl_grp_kem_mlkem768x25519:
- ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(kemSecret, dheSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
- break;
- case ssl_grp_kem_secp256r1mlkem768:
-+ case ssl_grp_kem_secp384r1mlkem1024:
- ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
- break;
- default:
- PORT_Assert(0);
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- ss->ssl3.hs.dheSecret = NULL;
- break;
- }
-diff --git a/lib/ssl/tls13exthandle.c b/lib/ssl/tls13exthandle.c
---- a/lib/ssl/tls13exthandle.c
-+++ b/lib/ssl/tls13exthandle.c
-@@ -80,70 +80,47 @@ tls13_SizeOfKeyShareEntry(const sslEphem
-
- if (keyPair->kemKeys) {
- PORT_Assert(!keyPair->kemCt);
- PORT_Assert(
- #ifndef NSS_DISABLE_KYBER
- keyPair->group->name == ssl_grp_kem_xyber768d00 ||
- #endif
- keyPair->group->name == ssl_grp_kem_mlkem768x25519 ||
-- keyPair->group->name == ssl_grp_kem_secp256r1mlkem768);
-+ keyPair->group->name == ssl_grp_kem_secp256r1mlkem768 ||
-+ keyPair->group->name == ssl_grp_kem_secp384r1mlkem1024);
- pubKey = keyPair->kemKeys->pubKey;
- size += pubKey->u.kyber.publicValue.len;
- }
- if (keyPair->kemCt) {
- PORT_Assert(!keyPair->kemKeys);
- PORT_Assert(
- #ifndef NSS_DISABLE_KYBER
- keyPair->group->name == ssl_grp_kem_xyber768d00 ||
- #endif
- keyPair->group->name == ssl_grp_kem_mlkem768x25519 ||
-- keyPair->group->name == ssl_grp_kem_secp256r1mlkem768);
-+ keyPair->group->name == ssl_grp_kem_secp256r1mlkem768 ||
-+ keyPair->group->name == ssl_grp_kem_secp384r1mlkem1024);
- size += keyPair->kemCt->len;
- }
-
- return size;
- }
-
-+static SECStatus
-+tls13_WriteECCFirstMLKEMKeyExchangeInfo(sslBuffer *buf, sslEphemeralKeyPair *keyPair)
-+ {
-+ PORT_Assert(keyPair->group->name == ssl_grp_kem_secp256r1mlkem768 ||
- #ifndef NSS_DISABLE_KYBER
--static SECStatus
--tls13_WriteXyber768D00KeyExchangeInfo(sslBuffer *buf, sslEphemeralKeyPair *keyPair)
--{
-- PORT_Assert(keyPair->group->name == ssl_grp_kem_xyber768d00);
-+ keyPair->group->name == ssl_grp_kem_xyber768d00 ||
-+#endif
-+ keyPair->group->name == ssl_grp_kem_secp384r1mlkem1024);
- PORT_Assert(keyPair->keys->pubKey->keyType == ecKey);
-
-- // Encode the X25519 share first, then the Kyber768 key or ciphertext.
-- SECStatus rv;
-- rv = sslBuffer_Append(buf, keyPair->keys->pubKey->u.ec.publicValue.data,
-- keyPair->keys->pubKey->u.ec.publicValue.len);
-- if (rv != SECSuccess) {
-- return rv;
-- }
--
-- if (keyPair->kemKeys) {
-- PORT_Assert(!keyPair->kemCt);
-- rv = sslBuffer_Append(buf, keyPair->kemKeys->pubKey->u.kyber.publicValue.data, keyPair->kemKeys->pubKey->u.kyber.publicValue.len);
-- } else if (keyPair->kemCt) {
-- rv = sslBuffer_Append(buf, keyPair->kemCt->data, keyPair->kemCt->len);
-- } else {
-- PORT_Assert(0);
-- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-- rv = SECFailure;
-- }
-- return rv;
--}
--#endif
--
--static SECStatus
--tls13_WriteMLKEM768Secp256r1KeyExchangeInfo(sslBuffer *buf, sslEphemeralKeyPair *keyPair)
-- {
-- PORT_Assert(keyPair->group->name == ssl_grp_kem_secp256r1mlkem768);
-- PORT_Assert(keyPair->keys->pubKey->keyType == ecKey);
--
-- // Encode the p256 key first, then the Kyber768 key or ciphertext.
-+ // Encode the ECC key first, then the ML-KEM key or ciphertext.
- SECStatus rv;
- rv = sslBuffer_Append(buf, keyPair->keys->pubKey->u.ec.publicValue.data,
- keyPair->keys->pubKey->u.ec.publicValue.len);
- if (rv != SECSuccess) {
- return rv;
- }
-
- if (keyPair->kemKeys) {
-@@ -155,22 +132,22 @@ tls13_WriteMLKEM768Secp256r1KeyExchangeI
- PORT_Assert(0);
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- rv = SECFailure;
- }
- return rv;
- }
-
- static SECStatus
--tls13_WriteMLKEM768X25519KeyExchangeInfo(sslBuffer *buf, sslEphemeralKeyPair *keyPair)
-+tls13_WriteMLKEMFirstKeyExchangeInfo(sslBuffer *buf, sslEphemeralKeyPair *keyPair)
- {
- PORT_Assert(keyPair->group->name == ssl_grp_kem_mlkem768x25519);
- PORT_Assert(keyPair->keys->pubKey->keyType == ecKey);
-
-- // Encode the ML-KEM-768 key or ciphertext first, then the X25519 share.
-+ // Encode the ML-KEM key or ciphertext first, then the ecc share.
- SECStatus rv;
- if (keyPair->kemKeys) {
- PORT_Assert(!keyPair->kemCt);
- rv = sslBuffer_Append(buf, keyPair->kemKeys->pubKey->u.kyber.publicValue.data, keyPair->kemKeys->pubKey->u.kyber.publicValue.len);
- } else if (keyPair->kemCt) {
- rv = sslBuffer_Append(buf, keyPair->kemCt->data, keyPair->kemCt->len);
- } else {
- PORT_Assert(0);
-@@ -223,26 +200,24 @@ tls13_EncodeKeyShareEntry(sslBuffer *buf
- rv = sslBuffer_AppendNumber(buf, size - 4, 2);
- if (rv != SECSuccess) {
- return rv;
- }
-
- switch (keyPair->group->name) {
- #ifndef NSS_DISABLE_KYBER
- case ssl_grp_kem_xyber768d00:
-- rv = tls13_WriteXyber768D00KeyExchangeInfo(buf, keyPair);
-+#endif
-+ case ssl_grp_kem_secp256r1mlkem768:
-+ case ssl_grp_kem_secp384r1mlkem1024:
-+ rv = tls13_WriteECCFirstMLKEMKeyExchangeInfo(buf, keyPair);
- break;
--#endif
- case ssl_grp_kem_mlkem768x25519:
-- rv = tls13_WriteMLKEM768X25519KeyExchangeInfo(buf, keyPair);
-+ rv = tls13_WriteMLKEMFirstKeyExchangeInfo(buf, keyPair);
- break;
-- case ssl_grp_kem_secp256r1mlkem768:
-- rv = tls13_WriteMLKEM768Secp256r1KeyExchangeInfo(buf, keyPair);
-- break;
--
- default:
- rv = tls13_WriteKeyExchangeInfo(buf, keyPair);
- break;
- }
- return rv;
- }
-
- SECStatus
-diff --git a/lib/util/eccutil.h b/lib/util/eccutil.h
---- a/lib/util/eccutil.h
-+++ b/lib/util/eccutil.h
-@@ -2,16 +2,17 @@
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
- #ifndef _FREEBL_H_
- #define _FREEBL_H_
-
- #define X25519_PUBLIC_KEY_BYTES 32U
- #define SECP256_PUBLIC_KEY_BYTES 65U
-+#define SECP384_PUBLIC_KEY_BYTES 97U
-
- /* deprecated */
- typedef enum {
- ECPoint_Uncompressed,
- ECPoint_XOnly,
- ECPoint_Undefined
- } ECPointEncoding;
-
-diff --git a/lib/util/kyber.h b/lib/util/kyber.h
---- a/lib/util/kyber.h
-+++ b/lib/util/kyber.h
-@@ -4,20 +4,28 @@
-
- #ifndef KYBER_UTIL_H
- #define KYBER_UTIL_H
-
- #define KYBER768_PUBLIC_KEY_BYTES 1184U
- #define KYBER768_PRIVATE_KEY_BYTES 2400U
- #define KYBER768_CIPHERTEXT_BYTES 1088U
-
-+#define MLKEM1024_PUBLIC_KEY_BYTES 1568U
-+#define MLKEM1024_PRIVATE_KEY_BYTES 3168U
-+#define MLKEM1024_CIPHERTEXT_BYTES 1568U
-+
- #define KYBER_SHARED_SECRET_BYTES 32U
- #define KYBER_KEYPAIR_COIN_BYTES 64U
- #define KYBER_ENC_COIN_BYTES 32U
-
-+#define MAX_ML_KEM_CIPHER_LENGTH MLKEM1024_CIPHERTEXT_BYTES
-+#define MAX_ML_KEM_PRIVATE_KEY_LENGTH MLKEM1024_PRIVATE_KEY_BYTES
-+#define MAX_ML_KEM_PUBLIC_KEY_LENGTH MLKEM1024_PUBLIC_KEY_BYTES
-+
- typedef enum {
- params_kyber_invalid,
-
- /*
- * The Kyber768 parameters specified in version 3.02 of the NIST submission
- * https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf
- */
- params_kyber768_round3,
-@@ -34,11 +42,24 @@ typedef enum {
- */
- params_ml_kem768,
-
- /*
- * Identical to params_ml_kem768 except that this parameter set allows
- * the use of a seed in `Kyber_Encapsulate` for testing.
- */
- params_ml_kem768_test_mode,
-+
-+ /*
-+ * The ML-KEM parameters specified in FIPS 203.
-+ * https://csrc.nist.gov/pubs/fips/203/final
-+ */
-+ params_ml_kem1024,
-+
-+ /*
-+ * Identical to params_ml_kem1024 except that this parameter set allows
-+ * the use of a seed in `Kyber_Encapsulate` for testing.
-+ */
-+ params_ml_kem1024_test_mode,
-+
- } KyberParams;
-
- #endif /* KYBER_UTIL_H */
-diff --git a/tests/ssl/ssl.sh b/tests/ssl/ssl.sh
---- a/tests/ssl/ssl.sh
-+++ b/tests/ssl/ssl.sh
-@@ -119,19 +119,19 @@ ssl_init()
-
- # List of cipher suites to test, including ECC cipher suites.
- CIPHER_SUITES="-c ${EC_SUITES}${NON_EC_SUITES}"
- TLS13_CIPHER_SUITES="-c ${TLS13_SUITES}${EC_SUITES}${NON_EC_SUITES}"
-
- # FIPS specific options for both clients and servers
- FIPS_OPTIONS=""
- # in fips mode, turn off curve25519 until it's NIST approved
-- ALL_GROUPS="P256,P384,P521,x25519,FF2048,FF3072,FF4096,FF6144,FF8192,mlkem768secp256r1,mlkem768x25519"
-+ ALL_GROUPS="P256,P384,P521,x25519,FF2048,FF3072,FF4096,FF6144,FF8192,secp256r1mlkem768,secp384r1mlkem1024, mlkem768x25519"
- NON_PQ_GROUPS="P256,P384,P521,x25519,FF2048,FF3072,FF4096,FF6144,FF8192"
-- FIPS_GROUPS="P256,P384,P521,FF2048,FF3072,FF4096,FF6144,FF8192,mlkem768secp256r1,mlkem768x25519"
-+ FIPS_GROUPS="P256,P384,P521,FF2048,FF3072,FF4096,FF6144,FF8192,secp256r1mlkem768,secp384r1mlkem1024,mlkem768x25519"
-
- # in non-fips mode, tstclnt may run without the db password in some
- # cases, but in fips mode it's always needed
- CLIENT_PW=""
- CLIENT_PW_FIPS="-w nss"
- CLIENT_PW_NORMAL=""
-
- if [ "${OS_ARCH}" != "WINNT" ]; then
-@@ -372,19 +372,21 @@ ssl_cov()
- if [ "$VMAX" = "ssl3" -a "$VMIN" = "tls1.1" ]; then
- kill_selfserv
- start_selfserv $CIPHER_SUITES
- VMIN="ssl3"
- fi
-
- TLS_GROUPS=${CLIENT_GROUPS}
- if [ "$ectype" = "MLKEM256" ]; then
-- TLS_GROUPS="mlkem768secp256r1"
-+ TLS_GROUPS="secp256r1mlkem768"
- elif [ "$ectype" = "MLKEM219" ]; then
-- TLS_GROUPS="mlkem768x25519"
-+ TLS_GROUPS="x25519mlkem768"
-+ elif [ "$ectype" = "MLKEM384" ]; then
-+ TLS_GROUPS="secp384r1mlkem1024"
- fi
- echo "TLS_GROUPS=${TLS_GROUPS}"
-
- echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -I \"${TLS_GROUPS}\" -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} \\"
- echo " -f -d ${P_R_CLIENTDIR} $verbose -w nss < ${REQUEST_FILE}"
-
- rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
- ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -I "${TLS_GROUPS}" -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} -f \
-diff --git a/tests/ssl/sslcov.txt b/tests/ssl/sslcov.txt
---- a/tests/ssl/sslcov.txt
-+++ b/tests/ssl/sslcov.txt
-@@ -148,14 +148,17 @@
- # Test against server with RSA-PSS server certificate
- #
- ECC TLS12 :C02F TLS12_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - RSA-PSS
- ECC TLS12 :C030 TLS12_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - RSA-PSS
- # test TLS 1.3
- ECC TLS13 :1301 TLS13_ECDHE_WITH_AES_128_GCM_SHA256
- ECC TLS13 :1302 TLS13_ECDHE_WITH_AES_256_GCM_SHA384
- ECC TLS13 :1303 TLS13_ECDHE_WITH_CHACHA20_POLY1305_SHA256
--MLKEM256 TLS13 :1301 TLS13_MLKEMP256_WITH_AES_128_GCM_SHA256
--MLKEM256 TLS13 :1302 TLS13_MLKEMP256_WITH_AES_256_GCM_SHA384
--MLKEM256 TLS13 :1303 TLS13_MLKEMP256_WITH_CHACHA20_POLY1305_SHA256
--MLKEM219 TLS13 :1301 TLS13_MLKEMX25519_WITH_AES_128_GCM_SHA256
--MLKEM219 TLS13 :1302 TLS13_MLKEMX25519_WITH_AES_256_GCM_SHA384
--MLKEM219 TLS13 :1303 TLS13_MLKEMX25519_WITH_CHACHA20_POLY1305_SHA256
-+MLKEM384 TLS13 :1301 TLS13_MLKEM1024P384_WITH_AES_128_GCM_SHA256
-+MLKEM384 TLS13 :1302 TLS13_MLKEM1024P384_WITH_AES_256_GCM_SHA384
-+MLKEM384 TLS13 :1303 TLS13_MLKEM1024P384_WITH_CHACHA20_POLY1305_SHA256
-+MLKEM256 TLS13 :1301 TLS13_MLKEM768P256_WITH_AES_128_GCM_SHA256
-+MLKEM256 TLS13 :1302 TLS13_MLKEM768P256_WITH_AES_256_GCM_SHA384
-+MLKEM256 TLS13 :1303 TLS13_MLKEM768P256_WITH_CHACHA20_POLY1305_SHA256
-+MLKEM219 TLS13 :1301 TLS13_MLKEM768X25519_WITH_AES_128_GCM_SHA256
-+MLKEM219 TLS13 :1302 TLS13_MLKEM768X25519_WITH_AES_256_GCM_SHA384
-+MLKEM219 TLS13 :1303 TLS13_MLKEM768X25519_WITH_CHACHA20_POLY1305_SHA256
diff --git a/nss-3.112-big-endian-compression-fix.patch b/nss-3.112-big-endian-compression-fix.patch
deleted file mode 100644
index 6f19821..0000000
--- a/nss-3.112-big-endian-compression-fix.patch
+++ /dev/null
@@ -1,71 +0,0 @@
-diff --git a/cmd/selfserv/selfserv.c b/cmd/selfserv/selfserv.c
---- a/cmd/selfserv/selfserv.c
-+++ b/cmd/selfserv/selfserv.c
-@@ -2078,13 +2078,13 @@
- if (!input || !input->data || input->len == 0 || !output || outputLen == 0) {
- PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
- return SECFailure;
- }
-
-- *usedLen = outputLen;
--
-- int ret = uncompress(output, (unsigned long *)usedLen, input->data, input->len);
-+ unsigned long outputLenUL = outputLen;
-+ int ret = uncompress(output, &outputLenUL, input->data, input->len);
-+ *usedLen = outputLenUL;
- if (ret != Z_OK) {
- PR_SetError(SEC_ERROR_BAD_DATA, 0);
- return SECFailure;
- }
-
-@@ -2100,11 +2100,13 @@
- }
-
- unsigned long maxCompressedLen = compressBound(input->len);
- SECITEM_AllocItem(NULL, output, maxCompressedLen);
-
-- int ret = compress(output->data, (unsigned long *)&output->len, input->data, input->len);
-+ unsigned long outputLenUL = output->len;
-+ int ret = compress(output->data, &outputLenUL, input->data, input->len);
-+ output->len = outputLenUL;
- if (ret != Z_OK) {
- PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
- return SECFailure;
- }
-
-diff --git a/cmd/tstclnt/tstclnt.c b/cmd/tstclnt/tstclnt.c
---- a/cmd/tstclnt/tstclnt.c
-+++ b/cmd/tstclnt/tstclnt.c
-@@ -1375,11 +1375,13 @@
- }
-
- unsigned long maxCompressedLen = compressBound(input->len);
- SECITEM_AllocItem(NULL, output, maxCompressedLen);
-
-- int ret = compress(output->data, (unsigned long *)&output->len, input->data, input->len);
-+ unsigned long outputLenUL = output->len;
-+ int ret = compress(output->data, &outputLenUL, input->data, input->len);
-+ output->len = outputLenUL;
- if (ret != Z_OK) {
- PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
- return SECFailure;
- }
-
-@@ -1394,13 +1396,13 @@
- if (!input || !input->data || input->len == 0 || !output || outputLen == 0) {
- PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
- return SECFailure;
- }
-
-- *usedLen = outputLen;
--
-- int ret = uncompress(output, (unsigned long *)usedLen, input->data, input->len);
-+ unsigned long outputLenUL = outputLen;
-+ int ret = uncompress(output, &outputLenUL, input->data, input->len);
-+ *usedLen = outputLenUL;
- if (ret != Z_OK) {
- PR_SetError(SEC_ERROR_BAD_DATA, 0);
- return SECFailure;
- }
-
-
diff --git a/nss-3.112-fips-and-fixes.patch b/nss-3.112-fips-and-fixes.patch
deleted file mode 100644
index accddd8..0000000
--- a/nss-3.112-fips-and-fixes.patch
+++ /dev/null
@@ -1,4069 +0,0 @@
-diff --git a/cmd/shlibsign/Makefile b/cmd/shlibsign/Makefile
---- a/cmd/shlibsign/Makefile
-+++ b/cmd/shlibsign/Makefile
-@@ -19,17 +19,39 @@ include $(CORE_DEPTH)/coreconf/config.mk
- #######################################################################
- # (3) Include "component" configuration information. (OPTIONAL) #
- #######################################################################
-
- #######################################################################
- # (4) Include "local" platform-dependent assignments (OPTIONAL). #
- #######################################################################
-
--include ../platlibs.mk
-+EXTRA_LIBS += \
-+ $(DIST)/lib/$(LIB_PREFIX)sectool.$(LIB_SUFFIX) \
-+ $(NULL)
-+
-+# SHLIBSign cannot depend on freebl or above as it's used to sign them.
-+# use a minimal set of required libraries to compile
-+ifeq ($(OS_ARCH), WINNT)
-+EXTRA_LIBS += \
-+ $(NSSUTIL_LIB_DIR)/$(LIB_PREFIX)nssutil3.$(LIB_SUFFIX) \
-+ $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plc4.$(LIB_SUFFIX) \
-+ $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plds4.$(LIB_SUFFIX) \
-+ $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4.$(LIB_SUFFIX) \
-+ $(NULL)
-+else
-+EXTRA_SHARED_LIBS += \
-+ -L$(NSSUTIL_LIB_DIR) \
-+ -lnssutil3 \
-+ -L$(NSPR_LIB_DIR) \
-+ -lplc4 \
-+ -lplds4 \
-+ -lnspr4 \
-+ $(NULL)
-+endif
-
- # sign any and all shared libraries that contain the word freebl
- ifeq ($(NSS_BUILD_WITHOUT_SOFTOKEN),1)
- CHECKLIBS =
- CHECKLOC =
- else
- CHECKLIBS = $(DIST)/lib/$(DLL_PREFIX)softokn3.$(DLL_SUFFIX)
- CHECKLIBS += $(wildcard $(DIST)/lib/$(DLL_PREFIX)freebl*3.$(DLL_SUFFIX))
-diff --git a/lib/freebl/fipsfreebl.c b/lib/freebl/fipsfreebl.c
---- a/lib/freebl/fipsfreebl.c
-+++ b/lib/freebl/fipsfreebl.c
-@@ -1791,16 +1791,255 @@ loser:
- if (dhStatus != SECSuccess) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return (SECFailure);
- }
- return (SECSuccess);
- }
-
- static SECStatus
-+freebl_ML_KEM_Test(KyberParams param_set,
-+ const unsigned char *seed, size_t seed_len,
-+ const unsigned char *enc_seed, size_t enc_seed_len,
-+ const unsigned char *pub_key, size_t pub_key_len,
-+ const unsigned char *priv_key, size_t priv_key_len,
-+ const unsigned char *cipher_text, size_t cipher_text_len,
-+ const unsigned char *key, size_t key_len)
-+{
-+ SECStatus rv;
-+ unsigned char cipher_text_buf[MAX_ML_KEM_CIPHER_LENGTH];
-+ unsigned char priv_key_buf[MAX_ML_KEM_PRIVATE_KEY_LENGTH];
-+ unsigned char pub_key_buf[MAX_ML_KEM_PUBLIC_KEY_LENGTH];
-+ unsigned char key_buf[KYBER_SHARED_SECRET_BYTES];
-+ unsigned char key2_buf[KYBER_SHARED_SECRET_BYTES];
-+ SECItem ct_item = { siBuffer, cipher_text_buf, cipher_text_len };
-+ SECItem priv_key_item = { siBuffer, priv_key_buf, priv_key_len };
-+ SECItem pub_key_item = { siBuffer, pub_key_buf, pub_key_len };
-+ SECItem key_item = { siBuffer, key_buf, sizeof(key_buf) };
-+ SECItem key2_item = { siBuffer, key2_buf, sizeof(key2_buf) };
-+ SECItem seed_item = { siBuffer, (unsigned char *)seed, seed_len };
-+ SECItem eseed_item = { siBuffer, (unsigned char *)enc_seed, enc_seed_len };
-+
-+ PORT_Assert(pub_key_len <= sizeof(pub_key_buf));
-+ PORT_Assert(priv_key_len <= sizeof(priv_key_buf));
-+ PORT_Assert(cipher_text_len <= sizeof(cipher_text_buf));
-+
-+ rv = Kyber_NewKey(param_set, &seed_item, &priv_key_item, &pub_key_item);
-+ if (rv != SECSuccess) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return rv;
-+ }
-+
-+ if ((priv_key_item.len != priv_key_len) ||
-+ (pub_key_item.len != pub_key_len) ||
-+ (PORT_Memcmp(priv_key_item.data, priv_key, priv_key_len) != 0) ||
-+ (PORT_Memcmp(pub_key_item.data, pub_key, pub_key_len) != 0)) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return rv;
-+ }
-+
-+ rv = Kyber_Encapsulate(param_set, &eseed_item, &pub_key_item,
-+ &ct_item, &key_item);
-+ if (rv != SECSuccess) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return rv;
-+ }
-+
-+ if ((ct_item.len != cipher_text_len) ||
-+ (key_item.len != key_len) ||
-+ (PORT_Memcmp(ct_item.data, cipher_text, cipher_text_len) != 0) ||
-+ (PORT_Memcmp(key_item.data, key, key_len) != 0)) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return rv;
-+ }
-+
-+ rv = Kyber_Decapsulate(param_set, &priv_key_item, &ct_item, &key2_item);
-+ if (rv != SECSuccess) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return rv;
-+ }
-+ if (SECITEM_CompareItem(&key2_item, &key_item) != 0) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return rv;
-+ }
-+ return SECSuccess;
-+}
-+
-+static SECStatus
-+freebl_fips_ML_KEM_PowerUpSelfTest()
-+{
-+ SECStatus rv;
-+
-+#include "ml_kem_fips_vectors.h"
-+ PORT_Assert(sizeof (ml_kem_key_seed) == KYBER_KEYPAIR_COIN_BYTES);
-+ PORT_Assert(sizeof (ml_kem_enc_seed) == KYBER_SHARED_SECRET_BYTES);
-+ PORT_Assert(sizeof (ml_kem768_pub_key) == KYBER768_PUBLIC_KEY_BYTES);
-+ PORT_Assert(sizeof (ml_kem768_priv_key) == KYBER768_PRIVATE_KEY_BYTES);
-+ PORT_Assert(sizeof (ml_kem768_cipher_text) == KYBER768_CIPHERTEXT_BYTES);
-+ PORT_Assert(sizeof (ml_kem768_key) == KYBER_SHARED_SECRET_BYTES);
-+ PORT_Assert(sizeof (ml_kem1024_pub_key) == MLKEM1024_PUBLIC_KEY_BYTES);
-+ PORT_Assert(sizeof (ml_kem1024_priv_key) == MLKEM1024_PRIVATE_KEY_BYTES);
-+ PORT_Assert(sizeof (ml_kem1024_cipher_text) == MLKEM1024_CIPHERTEXT_BYTES);
-+ PORT_Assert(sizeof (ml_kem1024_key) == KYBER_SHARED_SECRET_BYTES);
-+
-+ rv = freebl_ML_KEM_Test(params_ml_kem768_test_mode,
-+ ml_kem_key_seed, KYBER_KEYPAIR_COIN_BYTES,
-+ ml_kem_enc_seed, KYBER_SHARED_SECRET_BYTES,
-+ ml_kem768_pub_key, KYBER768_PUBLIC_KEY_BYTES,
-+ ml_kem768_priv_key, KYBER768_PRIVATE_KEY_BYTES,
-+ ml_kem768_cipher_text, KYBER768_CIPHERTEXT_BYTES,
-+ ml_kem768_key, KYBER_SHARED_SECRET_BYTES);
-+ if (rv != SECSuccess) {
-+ return SECFailure;
-+ }
-+ rv = freebl_ML_KEM_Test(params_ml_kem1024_test_mode,
-+ ml_kem_key_seed, KYBER_KEYPAIR_COIN_BYTES,
-+ ml_kem_enc_seed, KYBER_SHARED_SECRET_BYTES,
-+ ml_kem1024_pub_key, MLKEM1024_PUBLIC_KEY_BYTES,
-+ ml_kem1024_priv_key, MLKEM1024_PRIVATE_KEY_BYTES,
-+ ml_kem1024_cipher_text, MLKEM1024_CIPHERTEXT_BYTES,
-+ ml_kem1024_key, KYBER_SHARED_SECRET_BYTES);
-+ if (rv != SECSuccess) {
-+ return SECFailure;
-+ }
-+
-+ return SECSuccess;
-+}
-+
-+#ifdef NSS_ENABLE_ML_DSA
-+static SECStatus
-+freebl_ML_DSA_Test(CK_ML_DSA_PARAMETER_SET_TYPE param_set,
-+ const unsigned char *seed, size_t seed_len,
-+ const unsigned char *message, size_t message_len,
-+ const unsigned char *pub_key, size_t pub_key_len,
-+ const unsigned char *priv_key, size_t priv_key_len,
-+ const unsigned char *sig, size_t sig_len)
-+{
-+ SECStatus rv;
-+ MLDSAPrivateKey mldsa_priv_key;
-+ MLDSAPublicKey mldsa_pub_key;
-+ SECItem seed_item={ siBuffer, (unsigned char *)seed, seed_len};
-+ SECItem message_item={ siBuffer, (unsigned char *)message, message_len};
-+ unsigned char sig_buf[MAX_ML_DSA_SIGNATURE_LEN];
-+ SECItem sig_item={siBuffer, sig_buf, sizeof(sig_buf)};
-+ MLDSAContext *ctx = NULL;
-+
-+ /* generate the public and private key from the seed */
-+ rv = MLDSA_NewKey(param_set, &seed_item, &mldsa_priv_key, &mldsa_pub_key);
-+ if (rv != SECSuccess) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return rv;
-+ }
-+ /* verify that it was correct */
-+ if ((mldsa_priv_key.keyValLen != priv_key_len) ||
-+ (mldsa_pub_key.keyValLen != pub_key_len) ||
-+ (mldsa_priv_key.seedLen != seed_len) ||
-+ (PORT_Memcmp(mldsa_priv_key.keyVal, priv_key, priv_key_len) != 0) ||
-+ (PORT_Memcmp(mldsa_priv_key.seed, seed, seed_len) != 0) ||
-+ (PORT_Memcmp(mldsa_pub_key.keyVal, pub_key, pub_key_len) != 0)) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return (SECFailure);
-+ }
-+
-+ /* make a deterministic the signature and compare it to what was
-+ * passed in */
-+ rv = MLDSA_SignInit(&mldsa_priv_key, CKH_DETERMINISTIC_REQUIRED,
-+ NULL, &ctx);
-+ if (rv != SECSuccess) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return rv;
-+ }
-+ rv = MLDSA_SignUpdate(ctx, &message_item);
-+ if (rv != SECSuccess) {
-+ /* attempt to free the context */
-+ MLDSA_SignFinal(ctx, &sig_item);
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return rv;
-+ }
-+ rv = MLDSA_SignFinal(ctx, &sig_item);
-+ if (rv != SECSuccess) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return rv;
-+ }
-+ /* verify that it was correct */
-+ if ((sig_item.len != sig_len) ||
-+ (PORT_Memcmp(sig_item.data, sig, sig_len) != 0)) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return (SECFailure);
-+ }
-+
-+ /* now verify the signature with the public key */
-+ rv = MLDSA_VerifyInit(&mldsa_pub_key, NULL, &ctx);
-+ if (rv != SECSuccess) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return rv;
-+ }
-+ rv = MLDSA_VerifyUpdate(ctx, &message_item);
-+ if (rv != SECSuccess) {
-+ /* attempt to free the context */
-+ MLDSA_VerifyFinal(ctx, &sig_item);
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return rv;
-+ }
-+ rv = MLDSA_VerifyFinal(ctx, &sig_item);
-+ if (rv != SECSuccess) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return rv;
-+ }
-+
-+ return SECSuccess;
-+}
-+
-+static SECStatus
-+freebl_fips_ML_DSA_PowerUpSelfTest()
-+{
-+ SECStatus rv;
-+
-+#include "ml_dsa_fips_vectors.h"
-+ PORT_Assert(sizeof (ml_dsa_seed) == ML_DSA_SEED_LEN);
-+ PORT_Assert(sizeof (ml_dsa_44_pub_key) == ML_DSA_44_PUBLICKEY_LEN);
-+ PORT_Assert(sizeof (ml_dsa_44_priv_key) == ML_DSA_44_PRIVATEKEY_LEN);
-+ PORT_Assert(sizeof (ml_dsa_65_pub_key) == ML_DSA_65_PUBLICKEY_LEN);
-+ PORT_Assert(sizeof (ml_dsa_65_priv_key) == ML_DSA_65_PRIVATEKEY_LEN);
-+ PORT_Assert(sizeof (ml_dsa_87_pub_key) == ML_DSA_87_PUBLICKEY_LEN);
-+ PORT_Assert(sizeof (ml_dsa_87_priv_key) == ML_DSA_87_PRIVATEKEY_LEN);
-+ PORT_Assert(sizeof (ml_dsa_44_sig) == ML_DSA_44_SIGNATURE_LEN);
-+ PORT_Assert(sizeof (ml_dsa_65_sig) == ML_DSA_65_SIGNATURE_LEN);
-+ PORT_Assert(sizeof (ml_dsa_87_sig) == ML_DSA_87_SIGNATURE_LEN);
-+
-+ rv = freebl_ML_DSA_Test(CKP_ML_DSA_44, ml_dsa_seed, ML_DSA_SEED_LEN,
-+ ml_dsa_message, sizeof(ml_dsa_message),
-+ ml_dsa_44_pub_key, ML_DSA_44_PUBLICKEY_LEN,
-+ ml_dsa_44_priv_key, ML_DSA_44_PRIVATEKEY_LEN,
-+ ml_dsa_44_sig, ML_DSA_44_SIGNATURE_LEN);
-+ if (rv != SECSuccess) {
-+ return SECFailure;
-+ }
-+ rv = freebl_ML_DSA_Test(CKP_ML_DSA_65, ml_dsa_seed, ML_DSA_SEED_LEN,
-+ ml_dsa_message, sizeof(ml_dsa_message),
-+ ml_dsa_65_pub_key, ML_DSA_65_PUBLICKEY_LEN,
-+ ml_dsa_65_priv_key, ML_DSA_65_PRIVATEKEY_LEN,
-+ ml_dsa_65_sig, ML_DSA_65_SIGNATURE_LEN);
-+ if (rv != SECSuccess) {
-+ return SECFailure;
-+ }
-+ rv = freebl_ML_DSA_Test(CKP_ML_DSA_87, ml_dsa_seed, ML_DSA_SEED_LEN,
-+ ml_dsa_message, sizeof(ml_dsa_message),
-+ ml_dsa_87_pub_key, ML_DSA_87_PUBLICKEY_LEN,
-+ ml_dsa_87_priv_key, ML_DSA_87_PRIVATEKEY_LEN,
-+ ml_dsa_87_sig, ML_DSA_87_SIGNATURE_LEN);
-+ if (rv != SECSuccess) {
-+ return SECFailure;
-+ }
-+
-+ return (SECSuccess);
-+}
-+#endif
-+
-+static SECStatus
- freebl_fips_RNG_PowerUpSelfTest(void)
- {
- SECStatus rng_status = SECSuccess;
-
- /*******************************************/
- /* Run the SP 800-90 Health tests */
- /*******************************************/
- rng_status = PRNGTEST_RunHealthTests();
-@@ -1905,16 +2144,30 @@ freebl_fipsPowerUpSelfTest(unsigned int
- if (rv != SECSuccess)
- return rv;
-
- /* EC Power-Up SelfTest(s). */
- rv = freebl_fips_EC_PowerUpSelfTest();
-
- if (rv != SECSuccess)
- return rv;
-+
-+ /* ML_KEM Power-Up SelfTest(s). */
-+ rv = freebl_fips_ML_KEM_PowerUpSelfTest();
-+
-+ if (rv != SECSuccess)
-+ return rv;
-+
-+#ifdef NSS_ENABLE_ML_DSA
-+ /* ML_DSA Power-Up SelfTest(s). */
-+ rv = freebl_fips_ML_DSA_PowerUpSelfTest();
-+
-+ if (rv != SECSuccess)
-+ return rv;
-+#endif
- }
- /* Passed Power-Up SelfTest(s). */
- return (SECSuccess);
- }
-
- /*
- * state variables. NOTE: freebl has two uses: a standalone use which
- * provided limitted access to the hash functions throught the NSSLOWHASH_
-diff --git a/lib/freebl/kyber.c b/lib/freebl/kyber.c
---- a/lib/freebl/kyber.c
-+++ b/lib/freebl/kyber.c
-@@ -163,17 +163,16 @@ valid_enc_seed(KyberParams params, const
- case params_ml_kem768:
- case params_ml_kem1024:
- return !seed;
- #ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3_test_mode:
- #endif
- case params_ml_kem768_test_mode:
- case params_ml_kem1024_test_mode:
-- return !seed;
- return !seed || seed->len == KYBER_SHARED_SECRET_BYTES;
- default:
- return false;
- }
- }
-
- SECStatus
- Kyber_NewKey(KyberParams params, const SECItem *keypair_seed, SECItem *privkey, SECItem *pubkey)
-diff --git a/lib/freebl/ml_dsa.c b/lib/freebl/ml_dsa.c
---- a/lib/freebl/ml_dsa.c
-+++ b/lib/freebl/ml_dsa.c
-@@ -256,17 +256,17 @@ MLDSA_SignInit(MLDSAPrivateKey *key, CK_
- const SECItem *sgnCtx, MLDSAContext **ctx)
- {
- #ifndef NSS_ENABLE_ML_DSA
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- #else
- int ret = -1;
- MLDSAContext *lctx = NULL;
-- if (!ctx || !key || sgnCtx->len > 255) {
-+ if (!ctx || !key || (sgnCtx && sgnCtx->len > 255)) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- lctx = mldsa_NewContext(key, NULL);
- if (lctx == NULL ) {
- return SECFailure;
- }
- lctx->hedgeType = hedgeType;
-@@ -429,17 +429,17 @@ SECStatus
- MLDSA_VerifyInit(MLDSAPublicKey *key, const SECItem *sgnCtx, MLDSAContext **ctx)
- {
- #ifndef NSS_ENABLE_ML_DSA
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- #else
- MLDSAContext *lctx;
- int ret = -1;
-- if (!ctx || !key || sgnCtx->len > 255) {
-+ if (!ctx || !key || (sgnCtx && sgnCtx->len > 255)) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
- lctx = mldsa_NewContext(NULL, key);
- if (!lctx) {
- return SECFailure;
- }
- if (sgnCtx && sgnCtx->len != 0) {
-diff --git a/lib/freebl/ml_dsa_fips_vectors.h b/lib/freebl/ml_dsa_fips_vectors.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/ml_dsa_fips_vectors.h
-@@ -0,0 +1,2347 @@
-+/*
-+ *
-+ * This Source Code Form is subject to the terms of the Mozilla Public
-+ * License, v. 2.0. If a copy of the MPL was not distributed with this
-+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-+
-+/* put the ml_dsa vectors in their own file so that fipsfreebl can stay
-+ * readable since DSA keys and signatures are huge */
-+ static const unsigned char ml_dsa_seed[] = {
-+ 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
-+ };
-+ static const unsigned char ml_dsa_message[] = {
-+ 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
-+ };
-+ static const unsigned char ml_dsa_44_pub_key[] = {
-+ 0xd7, 0xb2, 0xb4, 0x72, 0x54, 0xaa, 0xe0, 0xdb, 0x45, 0xe7, 0x93, 0x0d,
-+ 0x4a, 0x98, 0xd2, 0xc9, 0x7d, 0x8f, 0x13, 0x97, 0xd1, 0x78, 0x9d, 0xaf,
-+ 0xa1, 0x70, 0x24, 0xb3, 0x16, 0xe9, 0xbe, 0xc9, 0x4f, 0xc9, 0x94, 0x6d,
-+ 0x42, 0xf1, 0x9b, 0x79, 0xa7, 0x41, 0x3b, 0xba, 0xa3, 0x3e, 0x71, 0x49,
-+ 0xcb, 0x42, 0xed, 0x51, 0x15, 0x69, 0x3a, 0xc0, 0x41, 0xfa, 0xcb, 0x98,
-+ 0x8a, 0xde, 0xb5, 0xfe, 0x0e, 0x1d, 0x86, 0x31, 0x18, 0x49, 0x95, 0xb5,
-+ 0x92, 0xc3, 0x97, 0xd2, 0x29, 0x4e, 0x2e, 0x14, 0xf9, 0x0a, 0xa4, 0x14,
-+ 0xba, 0x38, 0x26, 0x89, 0x9a, 0xc4, 0x3f, 0x4c, 0xcc, 0xac, 0xbc, 0x26,
-+ 0xe9, 0xa8, 0x32, 0xb9, 0x51, 0x18, 0xd5, 0xcb, 0x43, 0x3c, 0xbe, 0xf9,
-+ 0x66, 0x0b, 0x00, 0x13, 0x8e, 0x08, 0x17, 0xf6, 0x1e, 0x76, 0x2c, 0xa2,
-+ 0x74, 0xc3, 0x6a, 0xd5, 0x54, 0xeb, 0x22, 0xaa, 0xc1, 0x16, 0x2e, 0x4a,
-+ 0xb0, 0x1a, 0xcb, 0xa1, 0xe3, 0x8c, 0x4e, 0xfd, 0x8f, 0x80, 0xb6, 0x5b,
-+ 0x33, 0x3d, 0x0f, 0x72, 0xe5, 0x5d, 0xfe, 0x71, 0xce, 0x9c, 0x1e, 0xbb,
-+ 0x98, 0x89, 0xe7, 0xc5, 0x61, 0x06, 0xc0, 0xfd, 0x73, 0x80, 0x3a, 0x2a,
-+ 0xec, 0xfe, 0xaf, 0xde, 0xd7, 0xaa, 0x3c, 0xb2, 0xce, 0xda, 0x54, 0xd1,
-+ 0x2b, 0xd8, 0xcd, 0x36, 0xa7, 0x8c, 0xf9, 0x75, 0x94, 0x3b, 0x47, 0xab,
-+ 0xd2, 0x5e, 0x88, 0x0a, 0xc4, 0x52, 0xe5, 0x74, 0x2e, 0xd1, 0xe8, 0xd1,
-+ 0xa8, 0x2a, 0xfa, 0x86, 0xe5, 0x90, 0xc7, 0x58, 0xc1, 0x5a, 0xe4, 0xd2,
-+ 0x84, 0x0d, 0x92, 0xbc, 0xa1, 0xa5, 0x09, 0x0f, 0x40, 0x49, 0x65, 0x97,
-+ 0xfc, 0xa7, 0xd8, 0xb9, 0x51, 0x3f, 0x1a, 0x1b, 0xda, 0x6e, 0x95, 0x0a,
-+ 0xaa, 0x98, 0xde, 0x46, 0x75, 0x07, 0xd4, 0xa4, 0xf5, 0xa4, 0xf0, 0x59,
-+ 0x92, 0x16, 0x58, 0x2c, 0x35, 0x72, 0xf6, 0x2e, 0xda, 0x89, 0x05, 0xab,
-+ 0x35, 0x81, 0x67, 0x0c, 0x4a, 0x02, 0x77, 0x7a, 0x33, 0xe0, 0xca, 0x72,
-+ 0x95, 0xfd, 0x8f, 0x4f, 0xf6, 0xd1, 0xa0, 0xa3, 0xa7, 0x68, 0x3d, 0x65,
-+ 0xf5, 0xf5, 0xf7, 0xfc, 0x60, 0xda, 0x02, 0x3e, 0x82, 0x6c, 0x5f, 0x92,
-+ 0x14, 0x4c, 0x02, 0xf7, 0xd1, 0xba, 0x10, 0x75, 0x98, 0x75, 0x53, 0xea,
-+ 0x93, 0x67, 0xfc, 0xd7, 0x6d, 0x99, 0x0b, 0x7f, 0xa9, 0x9c, 0xd4, 0x5a,
-+ 0xfd, 0xb8, 0x83, 0x6d, 0x43, 0xe4, 0x59, 0xf5, 0x18, 0x7d, 0xf0, 0x58,
-+ 0x47, 0x97, 0x09, 0xa0, 0x1e, 0xa6, 0x83, 0x59, 0x35, 0xfa, 0x70, 0x46,
-+ 0x09, 0x90, 0xcd, 0x3d, 0xc1, 0xba, 0x40, 0x1b, 0xa9, 0x4b, 0xab, 0x1d,
-+ 0xde, 0x41, 0xac, 0x67, 0xab, 0x33, 0x19, 0xdc, 0xac, 0xa0, 0x60, 0x48,
-+ 0xd4, 0xc4, 0xee, 0xf2, 0x7e, 0xe1, 0x3a, 0x9c, 0x17, 0xd0, 0x53, 0x8f,
-+ 0x43, 0x0f, 0x2d, 0x64, 0x2d, 0xc2, 0x41, 0x56, 0x60, 0xde, 0x78, 0x87,
-+ 0x7d, 0x8d, 0x8a, 0xbc, 0x72, 0x52, 0x39, 0x78, 0xc0, 0x42, 0xe4, 0x28,
-+ 0x5f, 0x43, 0x19, 0x84, 0x6c, 0x44, 0x12, 0x62, 0x42, 0x97, 0x68, 0x44,
-+ 0xc1, 0x0e, 0x55, 0x6b, 0xa2, 0x15, 0xb5, 0xa7, 0x19, 0xe5, 0x9d, 0x0c,
-+ 0x6b, 0x2a, 0x96, 0xd3, 0x98, 0x59, 0x07, 0x1f, 0xdc, 0xc2, 0xcd, 0xe7,
-+ 0x52, 0x4a, 0x7b, 0xed, 0xae, 0x54, 0xe8, 0x5b, 0x31, 0x8e, 0x85, 0x4e,
-+ 0x8f, 0xe2, 0xb2, 0xf3, 0xed, 0xfa, 0xc9, 0x71, 0x91, 0x28, 0x27, 0x0a,
-+ 0xaf, 0xd1, 0xe5, 0x04, 0x4c, 0x3a, 0x4f, 0xda, 0xfd, 0x9f, 0xf3, 0x1f,
-+ 0x90, 0x78, 0x4b, 0x8e, 0x8e, 0x45, 0x96, 0x14, 0x4a, 0x0d, 0xaf, 0x58,
-+ 0x65, 0x11, 0xd3, 0xd9, 0x96, 0x2b, 0x9e, 0xa9, 0x5a, 0xf1, 0x97, 0xb4,
-+ 0xe5, 0xfc, 0x60, 0xf2, 0xb1, 0xed, 0x15, 0xde, 0x3a, 0x5b, 0xef, 0x5f,
-+ 0x89, 0xbd, 0xc7, 0x9d, 0x91, 0x05, 0x1d, 0x9b, 0x28, 0x16, 0xe7, 0x4f,
-+ 0xa5, 0x45, 0x31, 0xef, 0xdc, 0x1c, 0xbe, 0x74, 0xd4, 0x48, 0x85, 0x7f,
-+ 0x47, 0x6b, 0xcd, 0x58, 0xf2, 0x1c, 0x0b, 0x65, 0x3b, 0x3b, 0x76, 0xa4,
-+ 0xe0, 0x76, 0xa6, 0x55, 0x9a, 0x30, 0x27, 0x18, 0x55, 0x5c, 0xc6, 0x3f,
-+ 0x74, 0x85, 0x9a, 0xab, 0xab, 0x92, 0x5f, 0x02, 0x38, 0x61, 0xca, 0x8c,
-+ 0xd0, 0xf7, 0xba, 0xdb, 0x28, 0x71, 0xf6, 0x7d, 0x55, 0x32, 0x6d, 0x74,
-+ 0x51, 0x13, 0x5a, 0xd4, 0x5f, 0x4a, 0x1b, 0xa6, 0x91, 0x18, 0xfb, 0xb2,
-+ 0xc8, 0xa3, 0x0e, 0xec, 0x93, 0x92, 0xef, 0x3f, 0x97, 0x70, 0x66, 0xc9,
-+ 0xad, 0xd5, 0xc7, 0x10, 0xcc, 0x64, 0x7b, 0x15, 0x14, 0xd2, 0x17, 0xd9,
-+ 0x58, 0xc7, 0x01, 0x7c, 0x3e, 0x90, 0xfd, 0x20, 0xc0, 0x4e, 0x67, 0x4b,
-+ 0x90, 0x48, 0x6e, 0x93, 0x70, 0xa3, 0x1a, 0x00, 0x1d, 0x32, 0xf4, 0x73,
-+ 0x97, 0x9e, 0x49, 0x06, 0x74, 0x9e, 0x7e, 0x47, 0x7f, 0xa0, 0xb7, 0x45,
-+ 0x08, 0xf8, 0xa5, 0xf2, 0x37, 0x83, 0x12, 0xb8, 0x3c, 0x25, 0xbd, 0x38,
-+ 0x8c, 0xa0, 0xb0, 0xff, 0xf7, 0x47, 0x8b, 0xaf, 0x42, 0xb7, 0x16, 0x67,
-+ 0xed, 0xaa, 0xc9, 0x7c, 0x46, 0xb1, 0x29, 0x64, 0x3e, 0x58, 0x6e, 0x5b,
-+ 0x05, 0x5a, 0x0c, 0x21, 0x19, 0x46, 0xd4, 0xf3, 0x6e, 0x67, 0x5b, 0xed,
-+ 0x58, 0x60, 0xfa, 0x04, 0x2a, 0x31, 0x5d, 0x98, 0x26, 0x16, 0x4d, 0x6a,
-+ 0x92, 0x37, 0xc3, 0x5a, 0x5f, 0xbf, 0x49, 0x54, 0x90, 0xa5, 0xbd, 0x4d,
-+ 0xf2, 0x48, 0xb9, 0x5c, 0x4a, 0xae, 0x77, 0x84, 0xb6, 0x05, 0x67, 0x31,
-+ 0x66, 0xac, 0x42, 0x45, 0xb5, 0xb4, 0xb0, 0x82, 0xa0, 0x9e, 0x93, 0x23,
-+ 0xe6, 0x2f, 0x20, 0x78, 0xc5, 0xb7, 0x67, 0x83, 0x44, 0x6d, 0xef, 0xd7,
-+ 0x36, 0xad, 0x3a, 0x37, 0x02, 0xd4, 0x9b, 0x08, 0x98, 0x44, 0x90, 0x0a,
-+ 0x61, 0x83, 0x33, 0x97, 0xbc, 0x44, 0x19, 0xb3, 0x0d, 0x7a, 0x97, 0xa0,
-+ 0xb3, 0x87, 0xc1, 0x91, 0x14, 0x74, 0xc4, 0xd4, 0x1b, 0x53, 0xe3, 0x2a,
-+ 0x97, 0x7a, 0xcb, 0x6f, 0x0e, 0xa7, 0x5d, 0xb6, 0x5b, 0xb3, 0x9e, 0x59,
-+ 0xe7, 0x01, 0xe7, 0x69, 0x57, 0xde, 0xf6, 0xf2, 0xd4, 0x45, 0x59, 0xc3,
-+ 0x1a, 0x77, 0x12, 0x2b, 0x52, 0x04, 0xe3, 0xb5, 0xc2, 0x19, 0xf1, 0x68,
-+ 0x8b, 0x14, 0xed, 0x0b, 0xc0, 0xb8, 0x01, 0xb3, 0xe6, 0xe8, 0x2d, 0xcd,
-+ 0x43, 0xe9, 0xc0, 0xe9, 0xf4, 0x17, 0x44, 0xcd, 0x98, 0x15, 0xbd, 0x1b,
-+ 0xc8, 0x82, 0x0d, 0x8b, 0xb1, 0x23, 0xf0, 0x4f, 0xac, 0xd1, 0xb1, 0xb6,
-+ 0x85, 0xdd, 0x5a, 0x2b, 0x1b, 0x8d, 0xbb, 0xf3, 0xed, 0x93, 0x36, 0x70,
-+ 0xf0, 0x95, 0xa1, 0x80, 0xb4, 0xf1, 0x92, 0xd0, 0x8b, 0x10, 0xb8, 0xfa,
-+ 0xbb, 0xdf, 0xcc, 0x2b, 0x24, 0x51, 0x8e, 0x32, 0xee, 0xa0, 0xa5, 0xe0,
-+ 0xc9, 0x04, 0xca, 0x84, 0x47, 0x80, 0x08, 0x3f, 0x3b, 0x0c, 0xd2, 0xd0,
-+ 0xb8, 0xb6, 0xaf, 0x67, 0xbc, 0x35, 0x5b, 0x94, 0x94, 0x02, 0x5d, 0xc7,
-+ 0xb0, 0xa7, 0x8f, 0xa8, 0x0e, 0x3a, 0x2d, 0xbf, 0xeb, 0x51, 0x32, 0x88,
-+ 0x51, 0xd6, 0x07, 0x81, 0x98, 0xe9, 0x49, 0x36, 0x51, 0xae, 0x78, 0x7e,
-+ 0xc0, 0x25, 0x1f, 0x92, 0x2b, 0xa3, 0x0e, 0x9f, 0x51, 0xdf, 0x62, 0xa6,
-+ 0xd7, 0x27, 0x84, 0xcf, 0x3d, 0xd2, 0x05, 0x39, 0x31, 0x76, 0xdf, 0xa3,
-+ 0x24, 0xa5, 0x12, 0xbd, 0x94, 0x97, 0x0a, 0x36, 0xdd, 0x34, 0xa5, 0x14,
-+ 0xa8, 0x67, 0x91, 0xf0, 0xeb, 0x36, 0xf0, 0x14, 0x5b, 0x09, 0xab, 0x64,
-+ 0x65, 0x1b, 0x4a, 0x03, 0x13, 0xb2, 0x99, 0x61, 0x1a, 0x2a, 0x1c, 0x48,
-+ 0x89, 0x16, 0x27, 0x59, 0x87, 0x68, 0xa3, 0x11, 0x40, 0x60, 0xba, 0x44,
-+ 0x43, 0x48, 0x6d, 0xf5, 0x15, 0x22, 0xa1, 0xce, 0x88, 0xb3, 0x09, 0x85,
-+ 0xc2, 0x16, 0xf8, 0xe6, 0xed, 0x17, 0x8d, 0xd5, 0x67, 0xb3, 0x04, 0xa0,
-+ 0xd4, 0xca, 0xfb, 0xa8, 0x82, 0xa2, 0x83, 0x42, 0xf1, 0x7a, 0x9a, 0xa2,
-+ 0x6a, 0xe5, 0x8d, 0xb6, 0x30, 0x08, 0x3d, 0x2c, 0x35, 0x8f, 0xdf, 0x56,
-+ 0x6c, 0x3f, 0x5d, 0x62, 0xa4, 0x28, 0x56, 0x7b, 0xc9, 0xea, 0x8c, 0xe9,
-+ 0x5c, 0xaa, 0x0f, 0x35, 0x47, 0x4b, 0x0b, 0xfa, 0x8f, 0x33, 0x9a, 0x25,
-+ 0x0a, 0xb4, 0xdf, 0xcf, 0x20, 0x83, 0xbe, 0x8e, 0xef, 0xbc, 0x10, 0x55,
-+ 0xe1, 0x8f, 0xe1, 0x53, 0x70, 0xee, 0xcb, 0x26, 0x05, 0x66, 0xd8, 0x3f,
-+ 0xf0, 0x6b, 0x21, 0x1a, 0xae, 0xc4, 0x3c, 0xa2, 0x9b, 0x54, 0xcc, 0xd0,
-+ 0x0f, 0x88, 0x15, 0xa2, 0x46, 0x5e, 0xf0, 0xb4, 0x65, 0x15, 0xcc, 0x7e,
-+ 0x41, 0xf3, 0x12, 0x4f, 0x09, 0xef, 0xff, 0x73, 0x93, 0x09, 0xab, 0x58,
-+ 0xb2, 0x9a, 0x14, 0x59, 0xa0, 0x0b, 0xce, 0x50, 0x38, 0xe9, 0x38, 0xc9,
-+ 0x67, 0x8f, 0x72, 0xeb, 0x0e, 0x4e, 0xe5, 0xfd, 0xaa, 0xe6, 0x6d, 0x9f,
-+ 0x85, 0x73, 0xfc, 0x97, 0xfc, 0x42, 0xb4, 0x95, 0x9f, 0x4b, 0xf8, 0xb6,
-+ 0x1d, 0x78, 0x43, 0x3e, 0x86, 0xb0, 0x33, 0x5d, 0x6e, 0x91, 0x91, 0xc4,
-+ 0xd8, 0xbf, 0x48, 0x7b, 0x39, 0x05, 0xc1, 0x08, 0xcf, 0xd6, 0xac, 0x24,
-+ 0xb0, 0xce, 0xb7, 0xdc, 0xb7, 0xcf, 0x51, 0xf8, 0x4d, 0x0e, 0xd6, 0x87,
-+ 0xb9, 0x5e, 0xae, 0xb1, 0xc5, 0x33, 0xc0, 0x6f, 0x0d, 0x97, 0x02, 0x3d,
-+ 0x92, 0xa7, 0x08, 0x25, 0x83, 0x7b, 0x59, 0xba, 0x6c, 0xb7, 0xd4, 0xe5,
-+ 0x6b, 0x0a, 0x87, 0xc2, 0x03, 0x86, 0x2a, 0xe8, 0xf3, 0x15, 0xba, 0x59,
-+ 0x25, 0xe8, 0xed, 0xef, 0xa6, 0x79, 0x36, 0x9a, 0x22, 0x02, 0x76, 0x61,
-+ 0x51, 0xf1, 0x6a, 0x96, 0x5f, 0x9f, 0x81, 0xec, 0xe7, 0x6c, 0xc0, 0x70,
-+ 0xb5, 0x58, 0x69, 0xe4, 0xdb, 0x97, 0x84, 0xcf, 0x05, 0xc8, 0x30, 0xb3,
-+ 0x24, 0x2c, 0x83, 0x12,
-+ };
-+ static const unsigned char ml_dsa_44_priv_key[] = {
-+ 0xd7, 0xb2, 0xb4, 0x72, 0x54, 0xaa, 0xe0, 0xdb, 0x45, 0xe7, 0x93, 0x0d,
-+ 0x4a, 0x98, 0xd2, 0xc9, 0x7d, 0x8f, 0x13, 0x97, 0xd1, 0x78, 0x9d, 0xaf,
-+ 0xa1, 0x70, 0x24, 0xb3, 0x16, 0xe9, 0xbe, 0xc9, 0x39, 0xce, 0x0f, 0x7f,
-+ 0x77, 0xf8, 0xdb, 0x56, 0x44, 0xdc, 0xda, 0x36, 0x6b, 0xfe, 0x47, 0x34,
-+ 0xbd, 0x95, 0xf4, 0x35, 0xff, 0x9a, 0x61, 0x3a, 0xa5, 0x4a, 0xa4, 0x1c,
-+ 0x2c, 0x69, 0x4c, 0x04, 0x32, 0x9a, 0x07, 0xb1, 0xfa, 0xbb, 0x48, 0xf5,
-+ 0x2a, 0x30, 0x9f, 0x11, 0xa1, 0x89, 0x8f, 0x84, 0x8e, 0x23, 0x22, 0xff,
-+ 0xe6, 0x23, 0xec, 0x81, 0x0d, 0xb3, 0xbe, 0xe3, 0x36, 0x85, 0x85, 0x4a,
-+ 0x88, 0x26, 0x9d, 0xa3, 0x20, 0xd5, 0x12, 0x0b, 0xfc, 0xfe, 0x89, 0xa1,
-+ 0x8e, 0x30, 0xf7, 0x11, 0x4d, 0x83, 0xaa, 0x40, 0x4a, 0x64, 0x6b, 0x6c,
-+ 0x99, 0x73, 0x89, 0x86, 0x0d, 0x12, 0x52, 0x2e, 0xe0, 0x00, 0x6e, 0x23,
-+ 0x84, 0x81, 0x91, 0x86, 0x61, 0x9b, 0x26, 0x0d, 0x11, 0x86, 0x64, 0xd4,
-+ 0xa6, 0x28, 0x22, 0x18, 0x44, 0x82, 0x40, 0x28, 0x98, 0x14, 0x61, 0x48,
-+ 0xa6, 0x61, 0x4c, 0x42, 0x48, 0xa1, 0x92, 0x08, 0xc2, 0x38, 0x29, 0x51,
-+ 0x24, 0x48, 0x08, 0xa1, 0x25, 0xc2, 0x08, 0x31, 0x08, 0xc4, 0x71, 0x20,
-+ 0x14, 0x09, 0x14, 0x83, 0x6c, 0x18, 0xa7, 0x80, 0x84, 0x10, 0x6e, 0xc9,
-+ 0xc0, 0x70, 0x22, 0xb5, 0x64, 0x08, 0xb0, 0x61, 0x0c, 0x07, 0x04, 0x98,
-+ 0x12, 0x44, 0x51, 0x88, 0x69, 0x59, 0x00, 0x46, 0x22, 0x93, 0x20, 0x41,
-+ 0x06, 0x2e, 0x42, 0xb6, 0x4c, 0x01, 0x16, 0x49, 0x14, 0x28, 0x4c, 0x41,
-+ 0xa8, 0x51, 0x80, 0x46, 0x0a, 0x51, 0x16, 0x51, 0x5a, 0x08, 0x20, 0x02,
-+ 0x22, 0x44, 0xdc, 0x98, 0x49, 0xd1, 0x32, 0x51, 0xe1, 0x30, 0x65, 0xd3,
-+ 0xc0, 0x85, 0x92, 0xa8, 0x51, 0x12, 0xa1, 0x64, 0x00, 0x39, 0x22, 0x09,
-+ 0x46, 0x62, 0x1c, 0xc7, 0x0c, 0xd9, 0x08, 0x6d, 0xd0, 0x06, 0x26, 0x52,
-+ 0x40, 0x85, 0x80, 0x44, 0x30, 0x91, 0x06, 0x2c, 0x50, 0xc8, 0x09, 0x24,
-+ 0xc5, 0x84, 0x1a, 0x96, 0x6d, 0x4a, 0x98, 0x2c, 0x99, 0x06, 0x6d, 0xa4,
-+ 0x44, 0x32, 0x20, 0xa7, 0x64, 0x5a, 0x32, 0x6e, 0x11, 0xb5, 0x70, 0x20,
-+ 0x92, 0x61, 0x24, 0x13, 0x8e, 0x04, 0x85, 0x2c, 0x0a, 0x48, 0x72, 0xc8,
-+ 0xa0, 0x51, 0xd3, 0x08, 0x2a, 0x99, 0x20, 0x80, 0x58, 0x24, 0x20, 0x24,
-+ 0x07, 0x4e, 0x59, 0x14, 0x88, 0x10, 0xa4, 0x64, 0x60, 0xc0, 0x6d, 0xe0,
-+ 0xb2, 0x8d, 0x1b, 0x19, 0x09, 0x20, 0x34, 0x22, 0xc0, 0x24, 0x41, 0x09,
-+ 0x43, 0x71, 0x0a, 0x21, 0x20, 0x61, 0xa2, 0x01, 0x52, 0x22, 0x52, 0x1b,
-+ 0x80, 0x80, 0x9a, 0x34, 0x00, 0x13, 0x93, 0x4d, 0xd3, 0x32, 0x29, 0x22,
-+ 0x17, 0x0a, 0x98, 0x92, 0x69, 0x1a, 0x14, 0x51, 0x20, 0x27, 0x21, 0x9c,
-+ 0xc0, 0x20, 0x62, 0xa2, 0x81, 0x48, 0x18, 0x69, 0x1a, 0x85, 0x4d, 0x83,
-+ 0x44, 0x69, 0x5b, 0x20, 0x41, 0x03, 0x12, 0x42, 0xcb, 0x18, 0x46, 0x01,
-+ 0xa9, 0x0d, 0x0c, 0x02, 0x31, 0x83, 0xb0, 0x21, 0x5a, 0x22, 0x4a, 0xc8,
-+ 0x92, 0x05, 0xd9, 0x90, 0x69, 0x04, 0x30, 0x6a, 0x4b, 0x06, 0x4a, 0xd2,
-+ 0xb2, 0x01, 0x1c, 0x40, 0x40, 0x81, 0x42, 0x32, 0x52, 0x32, 0x72, 0x54,
-+ 0xa6, 0x40, 0x5a, 0x18, 0x10, 0x0c, 0x32, 0x12, 0x92, 0xc2, 0x80, 0x52,
-+ 0x12, 0x62, 0x5c, 0x82, 0x28, 0x0b, 0xb4, 0x6c, 0x03, 0x42, 0x8d, 0x53,
-+ 0x10, 0x0c, 0x14, 0x01, 0x0e, 0xe1, 0x36, 0x52, 0x88, 0x84, 0x24, 0x91,
-+ 0x02, 0x0a, 0x63, 0x46, 0x26, 0x20, 0x06, 0x29, 0x11, 0xc2, 0x28, 0xd0,
-+ 0x20, 0x48, 0x02, 0xb3, 0x6c, 0xa2, 0x36, 0x09, 0x5a, 0x86, 0x48, 0xcb,
-+ 0xb4, 0x61, 0x8b, 0x46, 0x62, 0xc4, 0x40, 0x82, 0x1a, 0x89, 0x09, 0x10,
-+ 0x02, 0x4d, 0x24, 0xb2, 0x45, 0x20, 0x12, 0x25, 0x24, 0xc9, 0x05, 0x88,
-+ 0x28, 0x8c, 0xc9, 0xc0, 0x4d, 0x59, 0x48, 0x22, 0x0a, 0x27, 0x6e, 0xc1,
-+ 0x34, 0x64, 0x4c, 0x90, 0x60, 0x5b, 0x44, 0x50, 0x82, 0x86, 0x49, 0x43,
-+ 0x88, 0x04, 0x43, 0xb2, 0x8c, 0x60, 0x30, 0x80, 0xa2, 0x88, 0x2d, 0x84,
-+ 0xa4, 0x6d, 0x8c, 0xa6, 0x29, 0xd0, 0xc6, 0x84, 0x42, 0x06, 0x46, 0x89,
-+ 0x88, 0x51, 0x00, 0xa9, 0x8d, 0x01, 0x49, 0x8d, 0xe4, 0x38, 0x0d, 0xa4,
-+ 0x06, 0x8d, 0xd3, 0x94, 0x71, 0x42, 0xb2, 0x6c, 0x1a, 0x84, 0x61, 0x1b,
-+ 0xa3, 0x28, 0x42, 0xb4, 0x28, 0x08, 0xa0, 0x71, 0x1a, 0xc5, 0x31, 0xe0,
-+ 0xa0, 0x4c, 0x01, 0x37, 0x65, 0x24, 0x28, 0x62, 0x14, 0x28, 0x90, 0x09,
-+ 0x10, 0x61, 0xd9, 0x40, 0x22, 0x1b, 0x33, 0x60, 0x09, 0x02, 0x92, 0xd0,
-+ 0x24, 0x81, 0x20, 0x04, 0x08, 0x49, 0x18, 0x44, 0xa3, 0x22, 0x2d, 0x5c,
-+ 0x88, 0x44, 0x14, 0x98, 0x08, 0xa4, 0x46, 0x61, 0x01, 0x95, 0x64, 0x0b,
-+ 0x39, 0x0a, 0x0c, 0x94, 0x50, 0xca, 0x40, 0x6a, 0xd2, 0xb2, 0x20, 0xc0,
-+ 0x38, 0x01, 0x82, 0x30, 0x8e, 0x13, 0xb9, 0x08, 0x91, 0x80, 0x84, 0x14,
-+ 0x88, 0x29, 0xc0, 0x18, 0x91, 0x12, 0x35, 0x0d, 0xa0, 0x24, 0x22, 0xe2,
-+ 0x04, 0x06, 0xd9, 0xc2, 0x85, 0x04, 0x28, 0x12, 0x1c, 0xc9, 0x89, 0x18,
-+ 0x02, 0x72, 0xd2, 0x40, 0x29, 0xc2, 0x08, 0x12, 0xd8, 0x06, 0x2a, 0x99,
-+ 0x94, 0x71, 0x9b, 0xb8, 0x68, 0x23, 0x84, 0x29, 0x1a, 0x22, 0x89, 0x14,
-+ 0x45, 0x11, 0xdc, 0x82, 0x44, 0x50, 0x96, 0x45, 0x0c, 0x44, 0x84, 0xc0,
-+ 0xb2, 0x04, 0x9a, 0xa6, 0x05, 0x43, 0x86, 0x2c, 0x44, 0x32, 0x6e, 0x88,
-+ 0x44, 0x21, 0x20, 0xa8, 0x4c, 0x9a, 0x30, 0x70, 0xe3, 0xb8, 0x2d, 0x63,
-+ 0x26, 0x88, 0x03, 0x25, 0x49, 0x03, 0x43, 0x8c, 0x48, 0xa8, 0x09, 0xca,
-+ 0x14, 0x72, 0x53, 0x34, 0x4e, 0x12, 0x43, 0x08, 0x1b, 0xa7, 0x04, 0x59,
-+ 0x30, 0x22, 0xd9, 0x94, 0x80, 0xe2, 0x34, 0x22, 0x81, 0x42, 0x12, 0x9c,
-+ 0x30, 0x2a, 0x94, 0x34, 0x26, 0x61, 0x04, 0x45, 0x24, 0x26, 0x28, 0x13,
-+ 0x46, 0x09, 0x4a, 0x32, 0x6d, 0x11, 0x28, 0x09, 0x18, 0xb8, 0x25, 0x62,
-+ 0x28, 0x11, 0x13, 0x41, 0x0d, 0x41, 0xb2, 0x11, 0x90, 0x84, 0x4c, 0x8b,
-+ 0x12, 0x12, 0xa2, 0xc6, 0x88, 0xc9, 0xc0, 0x30, 0x22, 0x06, 0x06, 0xd2,
-+ 0x18, 0x8e, 0x84, 0x86, 0x30, 0x90, 0x44, 0x52, 0x12, 0x88, 0x31, 0xd9,
-+ 0x20, 0x71, 0x13, 0xc5, 0x28, 0x43, 0x06, 0x0e, 0x03, 0x30, 0x60, 0xcc,
-+ 0xa6, 0x84, 0x58, 0x26, 0x52, 0x4c, 0x88, 0x01, 0x1e, 0xf7, 0x25, 0x62,
-+ 0xc8, 0x5f, 0xfa, 0x43, 0xac, 0xfa, 0x49, 0x21, 0x7f, 0x2b, 0x17, 0x2d,
-+ 0x7b, 0xbc, 0x14, 0x62, 0x0e, 0x6d, 0x98, 0x0a, 0x71, 0xaa, 0xbb, 0xdf,
-+ 0x0c, 0x45, 0xe9, 0xa2, 0x06, 0xec, 0xb1, 0x42, 0x3f, 0xee, 0x15, 0xde,
-+ 0xcc, 0x17, 0x60, 0x13, 0x00, 0x14, 0x9d, 0x92, 0x23, 0xcd, 0x6e, 0x6c,
-+ 0x6e, 0x1f, 0xa8, 0xe4, 0x1f, 0xc7, 0xc6, 0x49, 0x38, 0xab, 0x68, 0x90,
-+ 0x5f, 0xd3, 0xdc, 0xda, 0x50, 0xd8, 0x70, 0x82, 0xe7, 0xd0, 0xd7, 0x1d,
-+ 0x1b, 0xc9, 0xb2, 0xb8, 0x4c, 0x85, 0x52, 0x3c, 0xa8, 0xfe, 0x6c, 0xad,
-+ 0x29, 0x4a, 0xdf, 0x83, 0xbe, 0x15, 0xb1, 0x08, 0xff, 0x72, 0x1d, 0x0c,
-+ 0xc8, 0x7b, 0xc3, 0xdd, 0x3a, 0x75, 0x90, 0x18, 0x4b, 0x0e, 0x84, 0x56,
-+ 0x63, 0xa9, 0x1f, 0xc9, 0xe1, 0xc3, 0xc5, 0x3a, 0x61, 0xd8, 0x67, 0x42,
-+ 0x0b, 0x04, 0xf0, 0x92, 0x35, 0x57, 0x53, 0xbc, 0x65, 0xa0, 0x63, 0x68,
-+ 0xfd, 0x41, 0x29, 0x5f, 0xd0, 0x99, 0x24, 0x13, 0x2c, 0x6f, 0x91, 0xf6,
-+ 0x79, 0x64, 0xc1, 0x42, 0x67, 0x4a, 0x72, 0x5c, 0x34, 0x39, 0x14, 0xc4,
-+ 0xce, 0xcf, 0x58, 0xc0, 0x74, 0xbc, 0xaf, 0x45, 0x58, 0xc9, 0x7b, 0xf7,
-+ 0x91, 0x1e, 0x07, 0xaa, 0x6d, 0x09, 0x38, 0xf2, 0xee, 0x2b, 0xb3, 0xc1,
-+ 0xa8, 0xc5, 0x95, 0xd6, 0x35, 0xe8, 0x43, 0x42, 0xfd, 0xea, 0x01, 0xdc,
-+ 0x24, 0xb2, 0x11, 0xad, 0x2f, 0xc2, 0x81, 0xcf, 0x77, 0xe5, 0x91, 0x10,
-+ 0xc7, 0xab, 0xc5, 0x4b, 0xf0, 0xc8, 0x6d, 0x48, 0x0b, 0x9b, 0xe2, 0x76,
-+ 0x47, 0x1d, 0xc9, 0xd6, 0x03, 0xce, 0xe9, 0x8c, 0xfd, 0xab, 0x3e, 0x9f,
-+ 0xcf, 0xb7, 0x03, 0x79, 0x35, 0x60, 0x54, 0x9e, 0xa4, 0x45, 0x0f, 0xa7,
-+ 0xb3, 0x3f, 0xb9, 0x16, 0x9c, 0x44, 0xb4, 0xd2, 0x5f, 0xb9, 0xc4, 0x57,
-+ 0xf4, 0x97, 0x91, 0xcd, 0x3d, 0xa0, 0x3e, 0xac, 0x96, 0x09, 0x58, 0x13,
-+ 0xc1, 0x05, 0x13, 0x2c, 0xcd, 0xa4, 0xe6, 0x3e, 0x49, 0x22, 0x8c, 0xd2,
-+ 0x3d, 0x8a, 0x1f, 0x37, 0x85, 0x6f, 0x14, 0x2d, 0x93, 0xb9, 0x0d, 0xb0,
-+ 0x9f, 0x82, 0xaf, 0x89, 0x25, 0x8c, 0x63, 0xaa, 0xb8, 0x04, 0x7a, 0x80,
-+ 0xc0, 0x36, 0xc9, 0x35, 0x7e, 0xa2, 0x04, 0x6f, 0x8d, 0xc6, 0x35, 0x4f,
-+ 0x0c, 0x52, 0x95, 0xf3, 0x42, 0xbb, 0x41, 0x7d, 0x3c, 0xfe, 0xb0, 0xb1,
-+ 0xfd, 0x33, 0x62, 0x2c, 0x29, 0xe1, 0x4c, 0xbb, 0xd9, 0x2e, 0x13, 0x63,
-+ 0xc6, 0x5e, 0xbd, 0x45, 0x04, 0xb7, 0x51, 0x23, 0x29, 0xb9, 0x67, 0x0e,
-+ 0x32, 0xe1, 0xb2, 0xc6, 0x7a, 0x54, 0xe7, 0xf1, 0xa5, 0x5f, 0x8b, 0x9f,
-+ 0x9e, 0xa0, 0x4e, 0x8c, 0xa3, 0xa7, 0x05, 0xe6, 0x2a, 0x3c, 0x5e, 0x63,
-+ 0x73, 0x74, 0xaf, 0xb7, 0xae, 0xb6, 0xdd, 0xea, 0x61, 0x2c, 0xde, 0x28,
-+ 0xf0, 0x1a, 0x20, 0x2d, 0x7a, 0xa4, 0xe3, 0x47, 0x22, 0xd2, 0x7d, 0xd3,
-+ 0xf9, 0xb8, 0x98, 0x94, 0xd0, 0x19, 0xfd, 0x5d, 0x4d, 0x71, 0x19, 0xef,
-+ 0xe3, 0x72, 0x3b, 0xba, 0x10, 0x4c, 0xb8, 0xbb, 0x09, 0x81, 0xe0, 0x74,
-+ 0xde, 0x3a, 0xfe, 0x20, 0x0d, 0xaa, 0xae, 0xad, 0x82, 0x6c, 0xc4, 0x5f,
-+ 0x24, 0x4d, 0xbf, 0x43, 0x1a, 0xfa, 0xb3, 0x4e, 0xfb, 0xdf, 0x78, 0x24,
-+ 0x74, 0xd2, 0xfd, 0x57, 0x11, 0x8f, 0x64, 0x62, 0x14, 0x93, 0x4e, 0xd9,
-+ 0x9c, 0xba, 0x3b, 0x00, 0x3e, 0x8d, 0x67, 0xa3, 0x83, 0x6f, 0x6f, 0x19,
-+ 0xfc, 0x41, 0x91, 0x0c, 0xe5, 0x16, 0x3e, 0xe3, 0xae, 0x99, 0xeb, 0x84,
-+ 0xd5, 0x14, 0xeb, 0x76, 0x1e, 0x63, 0x68, 0x4e, 0xa5, 0x6f, 0x97, 0x91,
-+ 0xd2, 0xdd, 0x4a, 0xac, 0x6e, 0x61, 0x68, 0xb9, 0x48, 0xc8, 0x17, 0xf7,
-+ 0x5a, 0x22, 0x2a, 0xcb, 0x0e, 0x8c, 0xdc, 0x03, 0xcc, 0x4a, 0xfe, 0x8f,
-+ 0x67, 0x15, 0x7e, 0x1a, 0x36, 0x3b, 0x7f, 0xae, 0xff, 0x9f, 0x17, 0x2b,
-+ 0x98, 0x91, 0x36, 0x77, 0xc5, 0xa1, 0xdd, 0x08, 0x5e, 0x9e, 0xe4, 0xc2,
-+ 0x20, 0x52, 0xc1, 0xaf, 0x58, 0x19, 0x31, 0x16, 0x67, 0x3d, 0xcd, 0x3b,
-+ 0xfc, 0x5f, 0x34, 0xb8, 0x55, 0xdc, 0xc6, 0xc7, 0x78, 0x85, 0x64, 0x9e,
-+ 0x9e, 0x71, 0xf4, 0x3d, 0x4a, 0xea, 0x0f, 0x4b, 0x72, 0xca, 0x7e, 0xda,
-+ 0x05, 0x78, 0xba, 0x13, 0xd3, 0x1a, 0x65, 0x8d, 0x2d, 0x06, 0x0a, 0x9a,
-+ 0x66, 0xff, 0x69, 0xed, 0x1b, 0xe7, 0x99, 0x7a, 0x2f, 0xb1, 0xd2, 0x72,
-+ 0x3d, 0x38, 0xf9, 0xbf, 0xab, 0xe1, 0x8f, 0x8e, 0x7b, 0x3c, 0xda, 0x90,
-+ 0x6e, 0x4e, 0x9b, 0x5e, 0x94, 0x2c, 0x8e, 0xae, 0xb2, 0x96, 0x07, 0x0e,
-+ 0xbf, 0xd3, 0x64, 0x94, 0x7a, 0x94, 0x0c, 0xc9, 0x78, 0xbe, 0xd6, 0x6b,
-+ 0x37, 0x74, 0x9e, 0x6d, 0x5d, 0xcd, 0x7b, 0xe8, 0xc4, 0x94, 0x44, 0x0e,
-+ 0x2b, 0x84, 0xce, 0xcf, 0xef, 0xb9, 0x8c, 0x0b, 0xed, 0xfb, 0x3c, 0x41,
-+ 0xe3, 0x35, 0x9d, 0x2c, 0xd7, 0x19, 0x7f, 0xbe, 0x72, 0x0c, 0x48, 0xaa,
-+ 0x6c, 0x6b, 0x64, 0x65, 0xc1, 0xee, 0x63, 0xe3, 0x56, 0x9c, 0x2a, 0xdc,
-+ 0x74, 0x44, 0x91, 0x37, 0x0b, 0x7f, 0x78, 0x26, 0xfe, 0x0b, 0x77, 0xa1,
-+ 0xd1, 0x9d, 0x64, 0x10, 0x1d, 0x03, 0x2b, 0x91, 0x81, 0x06, 0xb4, 0x2d,
-+ 0x2e, 0xf7, 0x37, 0x47, 0xe5, 0x60, 0x1f, 0xe4, 0xba, 0x50, 0xf2, 0x3e,
-+ 0xde, 0x52, 0x1f, 0x03, 0x1a, 0x81, 0x7d, 0x15, 0x29, 0x4a, 0x43, 0x72,
-+ 0x2e, 0x83, 0x78, 0x78, 0x4b, 0x6d, 0xb0, 0xcf, 0x1b, 0xa9, 0xe8, 0xae,
-+ 0x91, 0x1d, 0x92, 0x01, 0xb9, 0xce, 0x9c, 0xc3, 0x01, 0x9c, 0x6f, 0x5c,
-+ 0x27, 0xcb, 0x98, 0xda, 0x26, 0x14, 0x4b, 0x64, 0x22, 0x5a, 0x7c, 0x93,
-+ 0x2b, 0x30, 0xf7, 0x61, 0xe7, 0x8a, 0x2d, 0x59, 0xa1, 0xd8, 0xb8, 0x3e,
-+ 0xc6, 0x34, 0x4a, 0x2f, 0x6d, 0xd4, 0x7e, 0x76, 0x57, 0x06, 0xd0, 0x0b,
-+ 0xf4, 0xa7, 0x9a, 0x6a, 0x92, 0x6c, 0x3b, 0xa9, 0x1d, 0x81, 0x2c, 0x8f,
-+ 0x2c, 0x79, 0x7a, 0xb1, 0x79, 0x67, 0x09, 0xe5, 0xd1, 0x68, 0x56, 0x77,
-+ 0x82, 0x93, 0x52, 0x9f, 0x02, 0x86, 0xd0, 0x15, 0xc3, 0xb5, 0x39, 0x96,
-+ 0x19, 0x64, 0x2a, 0x33, 0x3e, 0x9e, 0x59, 0x3d, 0x6e, 0x3f, 0x53, 0x53,
-+ 0x99, 0x42, 0x08, 0xe9, 0xe6, 0xa3, 0x32, 0x85, 0x1d, 0x7f, 0x65, 0x25,
-+ 0x22, 0xa9, 0x28, 0xb9, 0x17, 0xe2, 0x7e, 0x2d, 0x6d, 0x42, 0x13, 0x7d,
-+ 0xfe, 0x2e, 0xbf, 0xa6, 0xfb, 0x1c, 0x67, 0xb2, 0x6c, 0x02, 0x54, 0x52,
-+ 0x86, 0x85, 0xf7, 0xeb, 0xdb, 0xe3, 0x15, 0xa6, 0x8e, 0xaa, 0x2d, 0xa7,
-+ 0x69, 0xe8, 0xa9, 0xf4, 0x2d, 0x3e, 0x60, 0x00, 0x7c, 0x71, 0x33, 0x09,
-+ 0x26, 0xb2, 0xc0, 0x01, 0x2d, 0x83, 0xea, 0xd4, 0xe4, 0xfd, 0x1e, 0xd8,
-+ 0x72, 0xcc, 0xd1, 0x97, 0x22, 0x01, 0xd2, 0xb0, 0x27, 0xf3, 0x54, 0x5a,
-+ 0xc2, 0xd3, 0x0c, 0xd7, 0x8b, 0xc1, 0xd7, 0x40, 0xfe, 0xcc, 0xbc, 0x6f,
-+ 0xc2, 0xa0, 0x44, 0x6c, 0x6e, 0x30, 0xea, 0xc5, 0x1f, 0x5a, 0x69, 0x09,
-+ 0x8a, 0xa2, 0xd4, 0x47, 0xf2, 0x08, 0x5b, 0x4e, 0x4e, 0x4b, 0x92, 0xcc,
-+ 0xc2, 0x69, 0x21, 0xd2, 0xde, 0x47, 0x85, 0x18, 0xcd, 0x09, 0x0c, 0xe2,
-+ 0x67, 0xae, 0xa2, 0xd2, 0x7a, 0xda, 0x57, 0xfd, 0x88, 0xb4, 0x97, 0x6d,
-+ 0x89, 0xfb, 0x84, 0x3c, 0xdc, 0xcf, 0x49, 0xa7, 0x6c, 0xa2, 0x67, 0x9e,
-+ 0x68, 0x01, 0xbf, 0xa7, 0xfb, 0x03, 0x18, 0x96, 0xfb, 0x50, 0x62, 0x97,
-+ 0x04, 0xb9, 0x92, 0x39, 0x36, 0xbb, 0x5d, 0xd3, 0x85, 0x31, 0x11, 0x21,
-+ 0xca, 0xdf, 0xb1, 0x19, 0x95, 0xe5, 0x9b, 0x73, 0x03, 0x4c, 0xf6, 0x7e,
-+ 0xd0, 0x3a, 0xb8, 0x13, 0x86, 0x76, 0x48, 0xd0, 0x25, 0x82, 0x80, 0x87,
-+ 0xe9, 0x49, 0xa9, 0xaf, 0xd1, 0x6b, 0x95, 0xd7, 0x2d, 0x99, 0xb1, 0xed,
-+ 0xca, 0x25, 0x7a, 0xac, 0x13, 0x2f, 0xfb, 0x7a, 0x07, 0x09, 0xae, 0xd5,
-+ 0xa9, 0xc0, 0xff, 0x05, 0xfb, 0x0f, 0x2b, 0xbf, 0x28, 0x40, 0x9e, 0xed,
-+ 0x7b, 0x5f, 0x58, 0x01, 0xbe, 0x96, 0x4c, 0xed, 0x01, 0x9e, 0x1c, 0xb7,
-+ 0x85, 0x1d, 0x38, 0x51, 0xf1, 0x02, 0x90, 0x67, 0x4e, 0x19, 0xff, 0xb0,
-+ 0x08, 0xb3, 0x01, 0xc4, 0xac, 0xf6, 0x41, 0xa2, 0xbb, 0x14, 0x21, 0x6e,
-+ 0x1d, 0x69, 0xca, 0xbf, 0x52, 0xb5, 0xef, 0x22, 0x74, 0x96, 0xb0, 0xf3,
-+ 0x07, 0x99, 0xa8, 0x55, 0xd1, 0x17, 0xfa, 0xd3, 0x74, 0x4a, 0x6f, 0xa3,
-+ 0x35, 0x03, 0xea, 0x79, 0x8b, 0x52, 0xdd, 0xd7, 0xee, 0x54, 0x26, 0x60,
-+ 0x9d, 0xbf, 0xcd, 0x3f, 0x0c, 0x13, 0xb1, 0x64, 0xd6, 0xc0, 0x51, 0xf7,
-+ 0xed, 0x4a, 0x11, 0x97, 0x19, 0xa7, 0x12, 0xe3, 0x88, 0xd3, 0x28, 0x40,
-+ 0x20, 0x81, 0xff, 0x13, 0x54, 0xb5, 0x54, 0xd2, 0xc2, 0x37, 0xaf, 0xed,
-+ 0x3b, 0x15, 0x1c, 0x4b, 0xa8, 0xe9, 0xf4, 0xbd, 0xeb, 0x84, 0x99, 0xa3,
-+ 0x06, 0x6e, 0x26, 0xbb, 0xc6, 0x9e, 0x8a, 0xf0, 0x89, 0xde, 0xc7, 0x17,
-+ 0x31, 0xd1, 0xdc, 0x52, 0x9e, 0xab, 0x17, 0xef, 0x73, 0x74, 0x73, 0x4c,
-+ 0x0f, 0xe4, 0x75, 0x49, 0x4c, 0x83, 0x83, 0x6b, 0xdd, 0x34, 0xa0, 0x3b,
-+ 0x9b, 0xc8, 0x99, 0x14, 0x71, 0x60, 0x61, 0xbf, 0xb9, 0x8e, 0xc6, 0xe6,
-+ 0x1c, 0x3e, 0xd4, 0x43, 0x8e, 0xdc, 0xaf, 0x25, 0x24, 0x3c, 0x64, 0x70,
-+ 0x86, 0xb9, 0xea, 0x70, 0x18, 0xb0, 0xd9, 0xa8, 0xa0, 0xb0, 0x0c, 0xec,
-+ 0xb0, 0x0a, 0xbd, 0xe2, 0x49, 0x8d, 0x69, 0xc2, 0x33, 0x61, 0x01, 0xa7,
-+ 0x72, 0xcb, 0xe4, 0xf5, 0x71, 0x52, 0x3f, 0x51, 0xbd, 0x05, 0x88, 0x2c,
-+ 0xdf, 0x35, 0x8b, 0x84, 0x9c, 0xc1, 0x40, 0xaa, 0x1f, 0xaf, 0x22, 0x42,
-+ 0x3a, 0x12, 0x85, 0x1c, 0xe0, 0xe3, 0x3f, 0xd4, 0x89, 0x75, 0xa4, 0x95,
-+ 0x9f, 0xa5, 0xc5, 0xfe, 0x41, 0x8c, 0x93, 0x90, 0x81, 0x91, 0xab, 0x6e,
-+ 0x74, 0x1b, 0x77, 0xbf, 0xe0, 0x2c, 0xbd, 0x69, 0x8e, 0xe7, 0x95, 0xc4,
-+ 0x66, 0xd6, 0x15, 0x61, 0x9e, 0x64, 0x41, 0x38, 0x2c, 0x6e, 0xac, 0x01,
-+ 0x83, 0x4e, 0xe9, 0xab, 0x73, 0xce, 0xa8, 0x0b, 0xbe, 0x23, 0x5c, 0x78,
-+ 0xda, 0x91, 0xbd, 0x79, 0xb6, 0xf8, 0x2f, 0x89, 0x97, 0x85, 0xd6, 0x87,
-+ 0x00, 0xd3, 0x93, 0xe6, 0x75, 0xc2, 0x22, 0x4d, 0x6b, 0x7a, 0x1a, 0xd2,
-+ 0x13, 0x20, 0x49, 0x56, 0x79, 0xad, 0xae, 0xd7, 0x01, 0x67, 0xb5, 0x08,
-+ 0x66, 0x71, 0x3a, 0x53, 0x10, 0x9d, 0xb7, 0xb6, 0xf7, 0xd8, 0x13, 0x04,
-+ 0xec, 0xdf, 0xd8, 0x3b, 0x31, 0x9b, 0x1e, 0xf2, 0x48, 0x30, 0x6b, 0x45,
-+ 0xad, 0x29, 0xe7, 0xdd, 0xcc, 0x86, 0x3d, 0xac, 0x56, 0x04, 0x8b, 0x5d,
-+ 0x69, 0xea, 0x17, 0x50, 0x11, 0xf7, 0x61, 0x4c, 0x00, 0xa8, 0x6a, 0x86,
-+ 0x3c, 0xde, 0x18, 0x72, 0xa8, 0x93, 0x28, 0x78, 0xb9, 0xac, 0x7e, 0x1a,
-+ 0xc5, 0xbd, 0xa4, 0x99, 0x7b, 0x72, 0x06, 0x4f, 0x0c, 0xd7, 0x5f, 0x4c,
-+ 0x81, 0x4e, 0x03, 0x4d, 0xe1, 0x1a, 0xcb, 0x90, 0x13, 0xcf, 0x7e, 0xa9,
-+ 0x26, 0xb4, 0xe7, 0xea, 0xac, 0xe0, 0x70, 0xc7, 0xba, 0x21, 0x88, 0xef,
-+ 0xad, 0x2e, 0x43, 0x1e, 0x12, 0x23, 0xd4, 0x5d, 0xd0, 0x5c, 0x4d, 0x84,
-+ 0x03, 0xc2, 0xe4, 0x5c, 0xee, 0x64, 0x13, 0xec, 0xbe, 0x75, 0x27, 0xe8,
-+ 0x73, 0xe4, 0x55, 0xc4, 0xe6, 0x10, 0xa6, 0x18, 0x39, 0xaa, 0xcc, 0x0b,
-+ 0xd5, 0x6d, 0x24, 0x83, 0xe7, 0x8f, 0x29, 0x8b, 0x66, 0xa4, 0x78, 0xeb,
-+ 0x2f, 0x55, 0x8c, 0xba, 0xfc, 0xa8, 0x6b, 0xe8, 0x47, 0xba, 0xeb, 0x02,
-+ 0xc5, 0xb2, 0x16, 0xc8, 0xcd, 0x88, 0xfe, 0xa4, 0xdf, 0x24, 0x9b, 0x09,
-+ 0xe6, 0x70, 0xa2, 0x07, 0x03, 0xab, 0xac, 0x24, 0xb0, 0xa9, 0x1a, 0xbc,
-+ 0x4a, 0x56, 0x46, 0x60, 0x14, 0x42, 0xba, 0x10, 0xbe, 0xcf, 0xd3, 0x09,
-+ 0x93, 0x88, 0x00, 0x51, 0xd0, 0x7f, 0x56, 0xa0, 0x5a, 0x93, 0x79, 0xe7,
-+ 0xa8, 0xe6, 0xbe, 0xfe, 0xe3, 0xf2, 0x2f, 0xaa, 0x10, 0x63, 0x98, 0xf7,
-+ 0x70, 0x60, 0x06, 0xe4, 0x2e, 0x9b, 0xe1, 0xef, 0x89, 0xd2, 0x5c, 0x27,
-+ 0x2f, 0x11, 0xa9, 0x50, 0x95, 0xc5, 0x87, 0xd7, 0x13, 0x73, 0x22, 0x84,
-+ 0xde, 0x9d, 0xbd, 0x3c, 0x72, 0x17, 0xb0, 0x68, 0x9e, 0x21, 0xd8, 0xeb,
-+ 0x0f, 0xf6, 0x96, 0x68,
-+ };
-+ static const unsigned char ml_dsa_65_pub_key[] = {
-+ 0x48, 0x68, 0x3d, 0x91, 0x97, 0x8e, 0x31, 0xeb, 0x3d, 0xdd, 0xb8, 0xb0,
-+ 0x47, 0x34, 0x82, 0xd2, 0xb8, 0x8a, 0x5f, 0x62, 0x59, 0x49, 0xfd, 0x8f,
-+ 0x58, 0xa5, 0x61, 0xe6, 0x96, 0xbd, 0x4c, 0x27, 0xd0, 0x5b, 0x38, 0xdb,
-+ 0xb2, 0xed, 0xf0, 0x1e, 0x66, 0x4e, 0xfd, 0x81, 0xbe, 0x1e, 0xa8, 0x93,
-+ 0x68, 0x8c, 0xe6, 0x8a, 0xa2, 0xd5, 0x1c, 0x59, 0x58, 0xf8, 0xbb, 0xc6,
-+ 0xeb, 0x4e, 0x89, 0xee, 0x67, 0xd2, 0xc0, 0x32, 0x09, 0x54, 0xd5, 0x72,
-+ 0x12, 0xca, 0xc7, 0x22, 0x9f, 0xf1, 0xd6, 0xea, 0xf0, 0x39, 0x28, 0xbd,
-+ 0x51, 0x51, 0x1f, 0x8d, 0x88, 0xd8, 0x47, 0x73, 0x6c, 0x7d, 0xe2, 0x73,
-+ 0x0d, 0x59, 0x78, 0xe5, 0x41, 0x07, 0x13, 0x16, 0x09, 0x78, 0x86, 0x77,
-+ 0x11, 0xbf, 0x55, 0x39, 0xa0, 0xbf, 0xc4, 0xc3, 0x50, 0xc2, 0xbe, 0x57,
-+ 0x2b, 0xaf, 0x0e, 0xe2, 0xe2, 0xfb, 0x16, 0xcc, 0xfe, 0xa0, 0x80, 0x28,
-+ 0xd9, 0x9a, 0xc4, 0x9a, 0xeb, 0xb7, 0x59, 0x37, 0xdd, 0xce, 0x11, 0x1c,
-+ 0xda, 0xb6, 0x2f, 0xff, 0x3c, 0xea, 0x8b, 0xa2, 0x23, 0x3d, 0x1e, 0x56,
-+ 0xfb, 0xc5, 0xc5, 0xa1, 0xe7, 0x26, 0xde, 0x63, 0xfa, 0xdd, 0x2a, 0xf0,
-+ 0x16, 0xb1, 0x19, 0x17, 0x7f, 0xa3, 0xd9, 0x71, 0xa2, 0xd9, 0x27, 0x71,
-+ 0x73, 0xfc, 0xe5, 0x5b, 0x67, 0x74, 0x5a, 0xf0, 0xb7, 0xc2, 0x1d, 0x59,
-+ 0x7d, 0xbe, 0xb9, 0x3e, 0x6a, 0x32, 0xf3, 0x41, 0xc4, 0x9a, 0x5a, 0x8b,
-+ 0xe9, 0xe8, 0x25, 0x08, 0x8d, 0x1f, 0x2a, 0xa4, 0x51, 0x55, 0xd6, 0xc8,
-+ 0xae, 0x15, 0x36, 0x7e, 0x4e, 0xb0, 0x03, 0xb8, 0xfd, 0xf7, 0x85, 0x10,
-+ 0x71, 0x94, 0x97, 0x39, 0xf9, 0xff, 0xf0, 0x90, 0x23, 0xea, 0xf4, 0x51,
-+ 0x04, 0xd2, 0xa8, 0x4a, 0x45, 0x90, 0x6e, 0xed, 0x46, 0x71, 0xa4, 0x4d,
-+ 0xc2, 0x8d, 0x27, 0x98, 0x7b, 0xb5, 0x5d, 0xf6, 0x9e, 0x9e, 0x85, 0x61,
-+ 0xf6, 0x1a, 0x80, 0xa7, 0x26, 0x99, 0x50, 0x38, 0x65, 0xfe, 0xd9, 0xb7,
-+ 0xee, 0x72, 0xa8, 0xe1, 0x7a, 0x19, 0xc4, 0x08, 0x14, 0x4f, 0x4b, 0x29,
-+ 0xaf, 0xef, 0x70, 0x31, 0xc3, 0xa6, 0xd8, 0x57, 0x16, 0x10, 0xb4, 0x2c,
-+ 0x9f, 0x42, 0x12, 0x45, 0xa8, 0x8f, 0x19, 0x7e, 0x16, 0x81, 0x2b, 0x03,
-+ 0x11, 0x59, 0xb6, 0x5b, 0x96, 0x87, 0xe5, 0xb3, 0xe9, 0x34, 0xc5, 0x22,
-+ 0x5a, 0xe9, 0x8a, 0x79, 0xba, 0x73, 0xd2, 0xb3, 0x99, 0xd7, 0x35, 0x10,
-+ 0xef, 0xfa, 0xd1, 0x9e, 0x53, 0xb8, 0x45, 0x0f, 0x0b, 0xa8, 0xfc, 0xe1,
-+ 0x01, 0x2f, 0xd9, 0x8d, 0x26, 0x0a, 0x74, 0xaa, 0xaa, 0x13, 0xfa, 0xe2,
-+ 0x49, 0xa0, 0x06, 0xb1, 0xc3, 0x4f, 0x5b, 0xa0, 0xb8, 0x82, 0xf2, 0x63,
-+ 0x78, 0x22, 0x2f, 0xb3, 0x6f, 0x22, 0x83, 0xc2, 0x43, 0xf0, 0xff, 0xeb,
-+ 0x5f, 0x1b, 0xb4, 0x14, 0xa0, 0xa7, 0x0d, 0x55, 0xe3, 0xd4, 0x0a, 0x56,
-+ 0xb6, 0xcb, 0xc8, 0x8a, 0xe1, 0xf0, 0x3b, 0x7b, 0x28, 0x82, 0xd9, 0x8d,
-+ 0xee, 0xa2, 0x8e, 0x14, 0x5c, 0x9d, 0xed, 0xfd, 0x8e, 0xaf, 0x1c, 0xef,
-+ 0x2e, 0xd9, 0x4a, 0x8b, 0x05, 0x0f, 0x89, 0x64, 0xf4, 0x6d, 0x1e, 0xa0,
-+ 0xd0, 0xc2, 0xa4, 0x3e, 0x0d, 0xda, 0x61, 0x82, 0xad, 0xbf, 0x4f, 0x6e,
-+ 0xd1, 0x75, 0xb6, 0x74, 0x22, 0x57, 0x85, 0x9b, 0xf2, 0x2f, 0x3a, 0x41,
-+ 0x7e, 0xcf, 0x1f, 0x9d, 0x89, 0x31, 0x7b, 0x5e, 0x53, 0x9d, 0x58, 0x7a,
-+ 0xf1, 0x6b, 0x9e, 0x13, 0x13, 0xe0, 0x45, 0x14, 0xff, 0xa6, 0x4b, 0xa8,
-+ 0xb3, 0xff, 0x2b, 0x83, 0x21, 0xf8, 0x81, 0x1c, 0xb3, 0xfb, 0x02, 0x2c,
-+ 0x8f, 0x64, 0x4e, 0x70, 0xa4, 0xb8, 0x0a, 0x2f, 0xbf, 0xee, 0x60, 0x4a,
-+ 0xbb, 0x73, 0x79, 0x09, 0x1e, 0xa8, 0xe6, 0xc5, 0xc7, 0x4d, 0xfc, 0x02,
-+ 0x83, 0x66, 0x6b, 0x40, 0xc0, 0x79, 0x38, 0x70, 0x02, 0x82, 0x04, 0xa1,
-+ 0x36, 0xbf, 0x5d, 0xa9, 0x56, 0x8e, 0xb7, 0x98, 0xd3, 0x49, 0x03, 0x8b,
-+ 0xdb, 0x0c, 0x11, 0xe0, 0x34, 0x45, 0xe7, 0x84, 0x7c, 0xb5, 0x06, 0x9c,
-+ 0x75, 0xcf, 0x28, 0xac, 0x60, 0x1c, 0x77, 0x99, 0xd9, 0x58, 0x21, 0x0d,
-+ 0xdb, 0xcb, 0x22, 0x6e, 0x51, 0xaf, 0xef, 0x9f, 0x1d, 0xe4, 0x7b, 0x07,
-+ 0x38, 0x73, 0xd6, 0xd3, 0xf9, 0x74, 0x56, 0xbe, 0xde, 0x08, 0x50, 0x82,
-+ 0xe7, 0x4a, 0x29, 0x8b, 0x2c, 0xd4, 0x8f, 0x4b, 0x30, 0x93, 0x15, 0x5f,
-+ 0x36, 0x6c, 0x8f, 0xa6, 0x01, 0xc6, 0xaf, 0x85, 0x8d, 0xfa, 0x32, 0xc0,
-+ 0x84, 0x91, 0xb2, 0xa2, 0x98, 0x87, 0xf9, 0x03, 0x35, 0x94, 0x9a, 0x5d,
-+ 0x6e, 0xda, 0xa6, 0x79, 0x88, 0x2a, 0x3a, 0x95, 0xd6, 0xbf, 0x6d, 0x97,
-+ 0x0a, 0x22, 0x1f, 0x4b, 0x9d, 0x3d, 0x8c, 0xbf, 0x38, 0x4a, 0xf8, 0x1a,
-+ 0xac, 0x95, 0xe2, 0xb3, 0x29, 0x4e, 0x04, 0x78, 0x9a, 0xc8, 0x37, 0x27,
-+ 0xa5, 0xdc, 0x04, 0x55, 0x9f, 0x96, 0xaf, 0x41, 0xd8, 0xa0, 0x53, 0x51,
-+ 0x6f, 0xee, 0xee, 0xbc, 0x52, 0x74, 0x6e, 0xb6, 0xab, 0x28, 0x19, 0xe0,
-+ 0x91, 0x08, 0x71, 0x0d, 0x83, 0x5f, 0x01, 0x1f, 0xa6, 0x30, 0x65, 0x87,
-+ 0x2a, 0xd3, 0x34, 0xd5, 0xcd, 0xff, 0xb2, 0xb2, 0x31, 0x05, 0x07, 0xe9,
-+ 0x2f, 0xc9, 0x93, 0xae, 0x31, 0x7d, 0xa9, 0x7f, 0x4f, 0x30, 0x9c, 0xda,
-+ 0xf0, 0xf6, 0x7e, 0xd9, 0x9d, 0x90, 0x21, 0x55, 0x76, 0x08, 0x38, 0x49,
-+ 0xf9, 0x53, 0xb2, 0x46, 0xd7, 0xfe, 0xdb, 0x3f, 0xdb, 0x67, 0x67, 0x98,
-+ 0x50, 0xa5, 0xad, 0x40, 0x4e, 0x64, 0x14, 0x7f, 0xb7, 0xcf, 0x4f, 0x6a,
-+ 0xed, 0xdd, 0x05, 0xaf, 0xb4, 0xb8, 0x34, 0x96, 0x8d, 0x1f, 0xe8, 0x80,
-+ 0x14, 0x96, 0x0d, 0xce, 0x5d, 0x94, 0x22, 0x36, 0x52, 0x6e, 0x12, 0xa4,
-+ 0x78, 0xd6, 0x9e, 0x5f, 0xbe, 0x69, 0x70, 0x31, 0x0b, 0x30, 0x8c, 0x06,
-+ 0x84, 0x50, 0x18, 0xcf, 0xc7, 0xb2, 0xab, 0x43, 0x0a, 0x13, 0xa6, 0xb1,
-+ 0xac, 0x7b, 0xb0, 0x2c, 0xcc, 0xbb, 0x3d, 0x91, 0x1a, 0xc2, 0xf1, 0x10,
-+ 0x68, 0x61, 0x3f, 0xbe, 0x02, 0x9b, 0xfd, 0xce, 0x02, 0xcf, 0x5c, 0xd3,
-+ 0x89, 0x50, 0xed, 0x72, 0xc8, 0x39, 0x44, 0xed, 0xfb, 0xc7, 0x56, 0x15,
-+ 0xaf, 0x87, 0xf8, 0x64, 0xc0, 0x51, 0xf3, 0xc5, 0x54, 0x56, 0xc5, 0x41,
-+ 0x28, 0x63, 0xa4, 0x0c, 0x06, 0xd1, 0xda, 0xb5, 0x62, 0xbd, 0xff, 0x05,
-+ 0x71, 0xb8, 0xd3, 0xc3, 0x91, 0x7b, 0xbd, 0x30, 0x08, 0x80, 0xbb, 0xa5,
-+ 0xe9, 0x98, 0x23, 0x9b, 0x95, 0xfa, 0x91, 0xb7, 0xd6, 0x41, 0x6d, 0x4f,
-+ 0x39, 0x8b, 0x3a, 0xdb, 0xcd, 0x30, 0x98, 0x3e, 0xd3, 0x59, 0x2b, 0x4d,
-+ 0x9e, 0xf7, 0xd4, 0x23, 0x6f, 0xd0, 0x0f, 0x50, 0xd9, 0x8a, 0xa5, 0x3a,
-+ 0x23, 0x5a, 0xc4, 0x17, 0x27, 0x20, 0xf7, 0x7d, 0x96, 0x17, 0x26, 0x72,
-+ 0x98, 0x0c, 0xfe, 0x8f, 0xf7, 0xa5, 0xa7, 0x02, 0x78, 0x3e, 0xdc, 0x2b,
-+ 0xa3, 0x1b, 0x22, 0x59, 0x01, 0x5a, 0x11, 0x2f, 0xc7, 0xf4, 0x68, 0xa9,
-+ 0xc2, 0xf9, 0x46, 0x40, 0x39, 0x00, 0x2d, 0x30, 0xef, 0x67, 0x8b, 0x4c,
-+ 0xb7, 0x98, 0xbc, 0x11, 0x62, 0x16, 0xbf, 0x7a, 0x9a, 0x7c, 0x18, 0xba,
-+ 0x03, 0xb7, 0xb5, 0x8f, 0xd0, 0x75, 0x15, 0xd3, 0x11, 0x50, 0x49, 0xd3,
-+ 0x61, 0x4b, 0xe7, 0xa0, 0x7e, 0x74, 0x43, 0x00, 0x75, 0x0d, 0xf1, 0xd2,
-+ 0xc5, 0x87, 0x53, 0x38, 0x90, 0x59, 0xea, 0xfc, 0x3d, 0x78, 0x5c, 0xcd,
-+ 0xd3, 0x1c, 0x07, 0x64, 0x8b, 0xed, 0xc0, 0x3a, 0x5c, 0x3b, 0x8a, 0xd4,
-+ 0x6d, 0x06, 0x4d, 0x59, 0xc1, 0x3d, 0x57, 0x37, 0x47, 0x29, 0xfc, 0x4e,
-+ 0x29, 0x53, 0x62, 0xe2, 0xa5, 0x19, 0x12, 0x04, 0x53, 0x04, 0x28, 0xbc,
-+ 0x15, 0x22, 0xaf, 0xa2, 0x8f, 0xf5, 0xfe, 0x16, 0x55, 0xe3, 0x04, 0xca,
-+ 0x5b, 0xc8, 0xc2, 0x7a, 0xd0, 0xe0, 0xc6, 0xa3, 0x9d, 0xd4, 0xdf, 0x28,
-+ 0x95, 0x6c, 0x14, 0xb3, 0x8c, 0xc9, 0x36, 0x82, 0xce, 0xfe, 0x40, 0x2b,
-+ 0xbd, 0x5e, 0x82, 0xd2, 0x9c, 0x46, 0x4e, 0x44, 0xeb, 0x5d, 0x37, 0xb4,
-+ 0x8f, 0xc5, 0x68, 0xdf, 0xe0, 0xcc, 0x6e, 0x8e, 0x16, 0xba, 0xea, 0x05,
-+ 0xe5, 0x13, 0x55, 0x90, 0xf1, 0x92, 0x94, 0xe7, 0x3e, 0x83, 0x67, 0xb0,
-+ 0x21, 0x6d, 0xbb, 0x81, 0x50, 0x30, 0xb9, 0xde, 0x55, 0x91, 0x3f, 0x08,
-+ 0x03, 0x9c, 0x42, 0x35, 0x1c, 0x59, 0xe5, 0x51, 0x5d, 0xd5, 0xaf, 0x8e,
-+ 0x08, 0x9a, 0x15, 0xe6, 0x25, 0xe8, 0xf6, 0xde, 0xe6, 0x39, 0x38, 0x6c,
-+ 0x46, 0x49, 0x7d, 0x7a, 0x26, 0x32, 0x88, 0x77, 0x4d, 0xe5, 0x81, 0xa7,
-+ 0xde, 0x96, 0x29, 0xb4, 0x1b, 0x44, 0x24, 0x14, 0x1f, 0x97, 0x8f, 0xb8,
-+ 0x33, 0x12, 0x08, 0xef, 0xde, 0xc3, 0xc6, 0xe0, 0xde, 0x39, 0xbc, 0x57,
-+ 0x06, 0x3f, 0x3d, 0xcd, 0x6c, 0x47, 0x03, 0x73, 0xc0, 0x88, 0x91, 0xea,
-+ 0x29, 0xcb, 0xc7, 0xcc, 0x6d, 0x64, 0x83, 0xb8, 0x88, 0x90, 0x83, 0xac,
-+ 0xe8, 0x6a, 0xa7, 0xb5, 0x1b, 0x1c, 0x2c, 0xfe, 0x6e, 0x2a, 0xd1, 0x8d,
-+ 0x97, 0xce, 0x36, 0xfb, 0xc5, 0x6e, 0xa4, 0x2f, 0xae, 0x97, 0xe6, 0xa7,
-+ 0xac, 0x11, 0x48, 0x64, 0x47, 0x8c, 0x36, 0x6d, 0xf1, 0xeb, 0xb1, 0xe7,
-+ 0xb1, 0x1a, 0x90, 0x98, 0x50, 0x4f, 0xd5, 0x97, 0x5b, 0xdf, 0x1f, 0x49,
-+ 0xdc, 0x70, 0x00, 0x2b, 0x63, 0xc1, 0x73, 0x9a, 0x9d, 0x26, 0x3f, 0xba,
-+ 0xd4, 0x07, 0x3f, 0x6a, 0x9f, 0x6c, 0x2b, 0x8a, 0xf4, 0xb4, 0xc3, 0x32,
-+ 0xa1, 0x03, 0xa0, 0xcf, 0xfa, 0x5d, 0xee, 0xb2, 0xd0, 0x62, 0xca, 0x3c,
-+ 0x21, 0x5f, 0xd3, 0x60, 0x02, 0x6b, 0xe7, 0xc5, 0x16, 0x4f, 0x4a, 0x44,
-+ 0x24, 0xef, 0x74, 0x94, 0x88, 0x04, 0xd6, 0x6f, 0x46, 0x48, 0x77, 0x32,
-+ 0xc8, 0x20, 0x2c, 0x79, 0x54, 0x78, 0x64, 0x7b, 0x4e, 0xa7, 0x1d, 0x62,
-+ 0x7c, 0x08, 0x60, 0x24, 0xcc, 0xa3, 0x54, 0xa4, 0x1f, 0x08, 0x77, 0xb3,
-+ 0x8f, 0x19, 0xb3, 0x77, 0x4a, 0xd2, 0x09, 0x5c, 0x8d, 0xa5, 0x3b, 0x06,
-+ 0x9e, 0x21, 0xc7, 0x6a, 0xe2, 0xd2, 0x00, 0x7e, 0x16, 0x71, 0x9e, 0xd4,
-+ 0x00, 0x80, 0xd3, 0x34, 0xf7, 0xda, 0x52, 0xe9, 0xf5, 0xa5, 0x99, 0x04,
-+ 0x39, 0xca, 0xf0, 0x83, 0xa9, 0x5b, 0x83, 0x3f, 0x02, 0xad, 0x10, 0xa0,
-+ 0x8c, 0x1a, 0x6d, 0x0f, 0x26, 0x0c, 0x00, 0x72, 0x85, 0xbd, 0x4a, 0x2f,
-+ 0x47, 0x70, 0x3a, 0x5a, 0xef, 0x46, 0x52, 0x87, 0xd2, 0x53, 0xb1, 0x8a,
-+ 0xc2, 0x25, 0x14, 0x31, 0x62, 0x10, 0xff, 0x56, 0x68, 0x14, 0xb1, 0x0f,
-+ 0x87, 0xa2, 0x93, 0xd6, 0xf1, 0x99, 0xd3, 0xc3, 0x95, 0x99, 0x90, 0xd0,
-+ 0xc1, 0x26, 0x8b, 0x4f, 0x50, 0xd5, 0xf9, 0xfc, 0xef, 0xbb, 0xf2, 0x37,
-+ 0xbd, 0x0c, 0x28, 0xb8, 0x01, 0x82, 0xd6, 0x65, 0x97, 0x41, 0xf1, 0x4f,
-+ 0x10, 0xbf, 0xbb, 0x21, 0xbb, 0xa1, 0x2a, 0xb6, 0x20, 0xaa, 0x23, 0x96,
-+ 0xf5, 0x6c, 0x06, 0x86, 0xb4, 0xea, 0x90, 0x17, 0x99, 0x02, 0x24, 0x21,
-+ 0x6b, 0x2f, 0xe8, 0xad, 0x76, 0xc4, 0xa9, 0x14, 0x8e, 0xef, 0x9a, 0x86,
-+ 0xa3, 0x63, 0x5a, 0x6a, 0xa7, 0x7b, 0xc1, 0xdc, 0xfb, 0x6f, 0xba, 0x59,
-+ 0xa7, 0x7d, 0xfd, 0xa9, 0xb7, 0x53, 0x0d, 0xc0, 0xca, 0x86, 0x48, 0xc8,
-+ 0xd9, 0x73, 0x73, 0x8e, 0x01, 0xba, 0xb8, 0xf0, 0x8b, 0x49, 0x05, 0xe8,
-+ 0x4a, 0xa4, 0x64, 0x1b, 0xd6, 0x02, 0x41, 0x0c, 0xd9, 0x75, 0x20, 0x26,
-+ 0x5f, 0x2f, 0x23, 0x1f, 0x2b, 0x35, 0xe1, 0x5e, 0xb2, 0xfa, 0x04, 0xd2,
-+ 0xbd, 0x94, 0xd5, 0xa7, 0x7a, 0xba, 0xf1, 0xe0, 0xe1, 0x61, 0x01, 0x0a,
-+ 0x99, 0x00, 0x87, 0xf5, 0xb4, 0x6e, 0xa9, 0x88, 0xb2, 0xbc, 0x05, 0x12,
-+ 0xfd, 0xa0, 0xfa, 0x92, 0x3d, 0xad, 0xd6, 0xc4, 0x5c, 0x53, 0x01, 0xd0,
-+ 0x94, 0x83, 0x67, 0x32, 0x65, 0xb5, 0xab, 0x2e, 0x10, 0xf4, 0xba, 0x52,
-+ 0x0f, 0x6b, 0xba, 0xd5, 0x64, 0xa5, 0xc3, 0xd5, 0xe2, 0x7b, 0xdb, 0x08,
-+ 0x0f, 0x7d, 0x20, 0xe1, 0x32, 0x96, 0xa3, 0x18, 0x19, 0x54, 0xc3, 0x9c,
-+ 0x64, 0x9c, 0x94, 0x3e, 0xbe, 0x17, 0xdf, 0x5c, 0x1f, 0x7a, 0xae, 0x0a,
-+ 0x8f, 0xe1, 0x26, 0xc4, 0x77, 0x58, 0x5a, 0x5d, 0x4d, 0x64, 0x8a, 0x0d,
-+ 0x00, 0x8b, 0x6a, 0xf5, 0xe8, 0xcd, 0x31, 0xbe, 0x69, 0xa9, 0x29, 0x6d,
-+ 0x4f, 0x3f, 0xd2, 0x5e, 0xd8, 0x6f, 0x22, 0x1e, 0x4b, 0x93, 0xf6, 0x5f,
-+ 0x59, 0x29, 0x96, 0x75, 0x33, 0x62, 0x4b, 0x92, 0x35, 0x75, 0x0c, 0x30,
-+ 0x70, 0x75, 0x50, 0xb5, 0x85, 0x36, 0xd1, 0x09, 0xa7, 0x13, 0x1c, 0x5a,
-+ 0x5b, 0xbe, 0x4a, 0x57, 0x15, 0x56, 0x7c, 0x12, 0x53, 0x4a, 0xec, 0x76,
-+ 0x60, 0x76, 0x1e, 0xeb, 0xb9, 0xfa, 0xe2, 0x89, 0x1c, 0x77, 0x45, 0x89,
-+ 0xb8, 0x0e, 0x56, 0x6a, 0xd5, 0x57, 0xdd, 0xef, 0x73, 0x67, 0x19, 0x6b,
-+ 0x72, 0x27, 0xea, 0x98, 0x70, 0xef, 0x09, 0xdd, 0xfe, 0xc7, 0x9d, 0x6b,
-+ 0x93, 0x19, 0xa6, 0x87, 0x9b, 0x52, 0x05, 0xd7, 0x6b, 0xf7, 0xab, 0xa5,
-+ 0xac, 0xf3, 0x3a, 0xfb, 0x59, 0xd1, 0x7f, 0xc5, 0x4e, 0x68, 0x38, 0x3d,
-+ 0x6b, 0xe5, 0xa0, 0x8e, 0x9b, 0x66, 0xda, 0x53, 0xdc, 0xde, 0x00, 0x8b,
-+ 0xb2, 0x94, 0xb8, 0x58, 0x2b, 0xd1, 0x32, 0xcd, 0xcc, 0x49, 0x95, 0x9f,
-+ 0xdb, 0xc2, 0x1e, 0x52, 0x72, 0x18, 0x80, 0xc8, 0xad, 0x03, 0x52, 0xc7,
-+ 0x9f, 0x03, 0xa4, 0x3b, 0xbd, 0x84, 0xc4, 0xcd, 0xfd, 0xc6, 0xc5, 0x29,
-+ 0x00, 0x5e, 0x1e, 0x7c, 0xd9, 0xa3, 0x49, 0xa7, 0x16, 0x8a, 0x35, 0x56,
-+ 0x9b, 0xa5, 0xde, 0xa8, 0x18, 0x96, 0x8d, 0x5a, 0x91, 0x46, 0x6b, 0xd6,
-+ 0xe6, 0x4e, 0x20, 0xbf, 0x62, 0x41, 0x71, 0x98, 0xaf, 0xc4, 0xe8, 0x1c,
-+ 0x28, 0xdd, 0x77, 0xed, 0x40, 0x28, 0x23, 0x23, 0x98, 0xb5, 0x2f, 0xbd,
-+ 0xe8, 0x6b, 0xc8, 0x4f, 0x47, 0x5b, 0x90, 0x16, 0x71, 0x0c, 0xe2, 0xaa,
-+ 0xbc, 0x11, 0xa0, 0x6b, 0x4d, 0xba, 0xc9, 0x01, 0xec, 0x16, 0xcf, 0x36,
-+ 0x5c, 0xa3, 0xf2, 0xd5, 0x38, 0x13, 0x94, 0x8a, 0x69, 0x3a, 0x0f, 0x93,
-+ 0xe7, 0x9c, 0x46, 0xca, 0x5d, 0x5a, 0x6d, 0xca, 0x3d, 0x28, 0xca, 0x50,
-+ 0xad, 0x18, 0xbd, 0x13, 0xfc, 0xa5, 0x50, 0x59, 0xdd, 0x9b, 0x18, 0x5f,
-+ 0x79, 0xf9, 0xc4, 0x71, 0x96, 0xa4, 0xe8, 0x1b, 0x21, 0x04, 0xbc, 0x46,
-+ 0x0a, 0x05, 0x1e, 0x02, 0xf2, 0xe8, 0x44, 0x4f,
-+ };
-+ static const unsigned char ml_dsa_65_priv_key[] = {
-+ 0x48, 0x68, 0x3d, 0x91, 0x97, 0x8e, 0x31, 0xeb, 0x3d, 0xdd, 0xb8, 0xb0,
-+ 0x47, 0x34, 0x82, 0xd2, 0xb8, 0x8a, 0x5f, 0x62, 0x59, 0x49, 0xfd, 0x8f,
-+ 0x58, 0xa5, 0x61, 0xe6, 0x96, 0xbd, 0x4c, 0x27, 0xd8, 0x53, 0xfa, 0x69,
-+ 0xb8, 0x19, 0x90, 0x23, 0xe8, 0xcd, 0x67, 0x8d, 0xd9, 0xfa, 0xbf, 0x90,
-+ 0x47, 0x64, 0x6f, 0xfd, 0x0c, 0xb3, 0xcc, 0x7f, 0x79, 0x58, 0x05, 0xa7,
-+ 0x1e, 0x70, 0xd2, 0x37, 0x1b, 0x05, 0x63, 0xe3, 0xcd, 0x33, 0x46, 0x14,
-+ 0x9c, 0x8c, 0x9e, 0xbc, 0xf2, 0x3b, 0x0a, 0x4e, 0x5a, 0x90, 0x0e, 0xea,
-+ 0x9c, 0x65, 0x62, 0x79, 0x0a, 0x7c, 0x63, 0xe3, 0x86, 0x63, 0xda, 0xa2,
-+ 0xdd, 0xdb, 0x6e, 0x48, 0x0d, 0xc4, 0x05, 0xa1, 0xe7, 0x01, 0x94, 0x8b,
-+ 0x74, 0x84, 0x1e, 0xf5, 0xcc, 0x1c, 0x3f, 0x2b, 0xf3, 0x27, 0x97, 0x2e,
-+ 0x95, 0x10, 0x51, 0x0c, 0xd5, 0x37, 0x5e, 0xcc, 0x08, 0x55, 0x71, 0x77,
-+ 0x11, 0x87, 0x22, 0x21, 0x86, 0x23, 0x81, 0x00, 0x04, 0x24, 0x77, 0x80,
-+ 0x61, 0x47, 0x50, 0x07, 0x50, 0x17, 0x17, 0x03, 0x55, 0x04, 0x51, 0x51,
-+ 0x25, 0x47, 0x18, 0x38, 0x04, 0x61, 0x75, 0x72, 0x22, 0x44, 0x10, 0x88,
-+ 0x68, 0x60, 0x86, 0x46, 0x01, 0x27, 0x47, 0x56, 0x71, 0x80, 0x87, 0x06,
-+ 0x66, 0x86, 0x43, 0x32, 0x44, 0x41, 0x22, 0x04, 0x36, 0x38, 0x66, 0x75,
-+ 0x02, 0x82, 0x36, 0x34, 0x24, 0x43, 0x22, 0x05, 0x73, 0x64, 0x10, 0x64,
-+ 0x55, 0x54, 0x77, 0x22, 0x75, 0x56, 0x81, 0x43, 0x36, 0x14, 0x62, 0x55,
-+ 0x08, 0x20, 0x64, 0x37, 0x68, 0x54, 0x68, 0x75, 0x43, 0x53, 0x75, 0x10,
-+ 0x68, 0x71, 0x83, 0x33, 0x80, 0x54, 0x75, 0x05, 0x25, 0x80, 0x75, 0x28,
-+ 0x18, 0x84, 0x38, 0x11, 0x08, 0x72, 0x60, 0x20, 0x20, 0x08, 0x58, 0x83,
-+ 0x01, 0x83, 0x61, 0x13, 0x82, 0x82, 0x12, 0x06, 0x17, 0x11, 0x57, 0x87,
-+ 0x68, 0x78, 0x88, 0x78, 0x64, 0x37, 0x54, 0x60, 0x16, 0x57, 0x15, 0x50,
-+ 0x84, 0x71, 0x88, 0x66, 0x07, 0x27, 0x32, 0x88, 0x06, 0x64, 0x74, 0x18,
-+ 0x56, 0x76, 0x21, 0x80, 0x31, 0x82, 0x76, 0x64, 0x15, 0x78, 0x24, 0x50,
-+ 0x25, 0x64, 0x66, 0x43, 0x11, 0x35, 0x04, 0x36, 0x47, 0x80, 0x12, 0x66,
-+ 0x73, 0x14, 0x30, 0x11, 0x66, 0x06, 0x55, 0x86, 0x47, 0x18, 0x36, 0x88,
-+ 0x63, 0x50, 0x38, 0x47, 0x86, 0x11, 0x01, 0x20, 0x23, 0x56, 0x11, 0x61,
-+ 0x37, 0x86, 0x07, 0x85, 0x32, 0x12, 0x40, 0x07, 0x54, 0x78, 0x82, 0x30,
-+ 0x43, 0x66, 0x61, 0x16, 0x60, 0x42, 0x55, 0x41, 0x82, 0x85, 0x60, 0x53,
-+ 0x67, 0x78, 0x56, 0x38, 0x43, 0x44, 0x30, 0x63, 0x26, 0x10, 0x77, 0x07,
-+ 0x31, 0x78, 0x42, 0x72, 0x14, 0x11, 0x16, 0x53, 0x03, 0x85, 0x27, 0x68,
-+ 0x67, 0x46, 0x01, 0x50, 0x82, 0x37, 0x35, 0x32, 0x07, 0x66, 0x10, 0x75,
-+ 0x04, 0x68, 0x12, 0x48, 0x06, 0x66, 0x03, 0x03, 0x26, 0x52, 0x31, 0x24,
-+ 0x45, 0x40, 0x88, 0x00, 0x31, 0x80, 0x88, 0x76, 0x72, 0x17, 0x30, 0x71,
-+ 0x82, 0x47, 0x21, 0x51, 0x27, 0x80, 0x11, 0x65, 0x44, 0x74, 0x86, 0x61,
-+ 0x72, 0x23, 0x33, 0x80, 0x86, 0x60, 0x64, 0x46, 0x83, 0x52, 0x15, 0x84,
-+ 0x20, 0x36, 0x80, 0x11, 0x80, 0x21, 0x18, 0x18, 0x33, 0x17, 0x73, 0x54,
-+ 0x53, 0x48, 0x81, 0x00, 0x44, 0x86, 0x53, 0x67, 0x43, 0x70, 0x57, 0x72,
-+ 0x58, 0x83, 0x34, 0x60, 0x38, 0x42, 0x32, 0x85, 0x68, 0x10, 0x06, 0x04,
-+ 0x26, 0x04, 0x25, 0x84, 0x56, 0x02, 0x35, 0x68, 0x20, 0x51, 0x83, 0x86,
-+ 0x38, 0x43, 0x24, 0x21, 0x22, 0x42, 0x45, 0x64, 0x58, 0x58, 0x67, 0x71,
-+ 0x45, 0x72, 0x85, 0x04, 0x78, 0x87, 0x17, 0x18, 0x06, 0x18, 0x83, 0x60,
-+ 0x86, 0x86, 0x41, 0x56, 0x50, 0x81, 0x16, 0x50, 0x26, 0x46, 0x70, 0x06,
-+ 0x08, 0x26, 0x62, 0x27, 0x38, 0x31, 0x72, 0x40, 0x72, 0x57, 0x30, 0x07,
-+ 0x27, 0x28, 0x86, 0x20, 0x66, 0x75, 0x88, 0x68, 0x26, 0x07, 0x06, 0x40,
-+ 0x20, 0x33, 0x03, 0x43, 0x66, 0x31, 0x55, 0x46, 0x42, 0x45, 0x34, 0x56,
-+ 0x67, 0x18, 0x73, 0x45, 0x65, 0x83, 0x70, 0x22, 0x50, 0x84, 0x68, 0x56,
-+ 0x28, 0x80, 0x70, 0x36, 0x70, 0x84, 0x62, 0x37, 0x17, 0x10, 0x06, 0x57,
-+ 0x17, 0x58, 0x47, 0x78, 0x70, 0x86, 0x55, 0x53, 0x78, 0x22, 0x35, 0x14,
-+ 0x46, 0x77, 0x28, 0x56, 0x73, 0x03, 0x22, 0x87, 0x00, 0x14, 0x33, 0x20,
-+ 0x61, 0x71, 0x58, 0x45, 0x52, 0x66, 0x32, 0x50, 0x26, 0x51, 0x33, 0x47,
-+ 0x77, 0x38, 0x03, 0x55, 0x16, 0x43, 0x13, 0x47, 0x35, 0x10, 0x66, 0x27,
-+ 0x51, 0x75, 0x74, 0x02, 0x46, 0x88, 0x81, 0x70, 0x67, 0x43, 0x46, 0x81,
-+ 0x86, 0x01, 0x76, 0x52, 0x45, 0x33, 0x30, 0x87, 0x21, 0x04, 0x34, 0x34,
-+ 0x01, 0x03, 0x22, 0x87, 0x63, 0x51, 0x55, 0x26, 0x50, 0x81, 0x30, 0x77,
-+ 0x45, 0x44, 0x41, 0x68, 0x15, 0x41, 0x83, 0x63, 0x64, 0x11, 0x20, 0x40,
-+ 0x26, 0x87, 0x30, 0x43, 0x67, 0x77, 0x12, 0x80, 0x88, 0x46, 0x35, 0x54,
-+ 0x53, 0x00, 0x62, 0x45, 0x81, 0x04, 0x58, 0x36, 0x51, 0x24, 0x84, 0x27,
-+ 0x80, 0x34, 0x51, 0x66, 0x63, 0x58, 0x43, 0x78, 0x56, 0x01, 0x46, 0x51,
-+ 0x15, 0x74, 0x23, 0x21, 0x43, 0x66, 0x85, 0x22, 0x47, 0x77, 0x31, 0x34,
-+ 0x50, 0x17, 0x83, 0x62, 0x42, 0x05, 0x50, 0x00, 0x64, 0x84, 0x47, 0x12,
-+ 0x34, 0x40, 0x88, 0x00, 0x60, 0x47, 0x35, 0x40, 0x57, 0x83, 0x33, 0x63,
-+ 0x08, 0x21, 0x06, 0x15, 0x22, 0x52, 0x07, 0x24, 0x88, 0x51, 0x34, 0x86,
-+ 0x37, 0x06, 0x76, 0x22, 0x58, 0x85, 0x71, 0x26, 0x56, 0x73, 0x47, 0x68,
-+ 0x16, 0x46, 0x46, 0x84, 0x25, 0x87, 0x08, 0x12, 0x27, 0x05, 0x50, 0x08,
-+ 0x38, 0x32, 0x00, 0x23, 0x20, 0x80, 0x66, 0x34, 0x53, 0x36, 0x00, 0x33,
-+ 0x46, 0x85, 0x72, 0x47, 0x06, 0x35, 0x54, 0x00, 0x35, 0x77, 0x12, 0x27,
-+ 0x52, 0x30, 0x71, 0x42, 0x53, 0x68, 0x74, 0x37, 0x45, 0x70, 0x05, 0x66,
-+ 0x43, 0x22, 0x44, 0x82, 0x85, 0x20, 0x72, 0x18, 0x33, 0x30, 0x20, 0x53,
-+ 0x37, 0x33, 0x40, 0x77, 0x27, 0x80, 0x55, 0x25, 0x30, 0x63, 0x52, 0x50,
-+ 0x40, 0x67, 0x33, 0x46, 0x13, 0x18, 0x07, 0x28, 0x07, 0x17, 0x24, 0x83,
-+ 0x77, 0x63, 0x45, 0x73, 0x18, 0x58, 0x51, 0x60, 0x23, 0x33, 0x44, 0x36,
-+ 0x25, 0x16, 0x43, 0x38, 0x16, 0x08, 0x58, 0x77, 0x34, 0x62, 0x42, 0x88,
-+ 0x30, 0x07, 0x03, 0x65, 0x85, 0x37, 0x55, 0x00, 0x75, 0x52, 0x31, 0x50,
-+ 0x37, 0x02, 0x13, 0x24, 0x63, 0x04, 0x37, 0x08, 0x68, 0x06, 0x36, 0x15,
-+ 0x03, 0x03, 0x00, 0x43, 0x58, 0x63, 0x57, 0x08, 0x02, 0x11, 0x06, 0x64,
-+ 0x73, 0x46, 0x35, 0x22, 0x62, 0x03, 0x30, 0x43, 0x80, 0x21, 0x08, 0x52,
-+ 0x87, 0x57, 0x83, 0x21, 0x07, 0x88, 0x67, 0x48, 0x08, 0x56, 0x34, 0x74,
-+ 0x36, 0x73, 0x42, 0x84, 0x05, 0x84, 0x66, 0x84, 0x14, 0x37, 0x00, 0x55,
-+ 0x10, 0x87, 0x34, 0x26, 0x44, 0x77, 0x21, 0x12, 0x73, 0x84, 0x73, 0x65,
-+ 0x26, 0x47, 0x25, 0x77, 0x14, 0x47, 0x04, 0x17, 0x86, 0x44, 0x26, 0x02,
-+ 0x47, 0x11, 0x87, 0x40, 0x81, 0x22, 0x16, 0x60, 0x58, 0x47, 0x17, 0x81,
-+ 0x37, 0x06, 0x76, 0x80, 0x81, 0x70, 0x58, 0x18, 0x55, 0x85, 0x47, 0x13,
-+ 0x63, 0x42, 0x10, 0x75, 0x58, 0x01, 0x63, 0x58, 0x35, 0x85, 0x18, 0x44,
-+ 0x03, 0x84, 0x71, 0x10, 0x33, 0x87, 0x42, 0x62, 0x82, 0x47, 0x74, 0x13,
-+ 0x65, 0x54, 0x42, 0x70, 0x73, 0x46, 0x35, 0x77, 0x75, 0x00, 0x66, 0x25,
-+ 0x62, 0x68, 0x42, 0x02, 0x12, 0x46, 0x83, 0x86, 0x46, 0x16, 0x64, 0x60,
-+ 0x31, 0x22, 0x53, 0x88, 0x84, 0x54, 0x00, 0x84, 0x57, 0x34, 0x46, 0x47,
-+ 0x54, 0x47, 0x25, 0x60, 0x54, 0x61, 0x66, 0x84, 0x66, 0x30, 0x88, 0x06,
-+ 0x38, 0x27, 0x15, 0x63, 0x28, 0x71, 0x83, 0x84, 0x06, 0x52, 0x24, 0x76,
-+ 0x81, 0x16, 0x06, 0x62, 0x13, 0x03, 0x30, 0x18, 0x68, 0x02, 0x80, 0x13,
-+ 0x84, 0x63, 0x05, 0x05, 0x65, 0x72, 0x38, 0x75, 0x83, 0x65, 0x72, 0x32,
-+ 0x30, 0x68, 0x80, 0x46, 0x12, 0x26, 0x06, 0x65, 0x16, 0x75, 0x57, 0x05,
-+ 0x32, 0x41, 0x32, 0x27, 0x67, 0x35, 0x17, 0x08, 0x01, 0x53, 0x00, 0x16,
-+ 0x28, 0x46, 0x01, 0x34, 0x88, 0x77, 0x01, 0x11, 0x88, 0x15, 0x57, 0x13,
-+ 0x15, 0x46, 0x43, 0x11, 0x70, 0x47, 0x32, 0x88, 0x28, 0x56, 0x36, 0x82,
-+ 0x34, 0x55, 0x50, 0x41, 0x86, 0x27, 0x65, 0x63, 0x11, 0x11, 0x68, 0x75,
-+ 0x05, 0x10, 0x42, 0x54, 0x41, 0x44, 0x27, 0x85, 0x22, 0x11, 0x17, 0x17,
-+ 0x88, 0x15, 0x36, 0x85, 0x15, 0x74, 0x47, 0x16, 0x62, 0x55, 0x36, 0x55,
-+ 0x83, 0x63, 0x02, 0x50, 0x28, 0x55, 0x76, 0x87, 0x53, 0x27, 0x13, 0x71,
-+ 0x03, 0x72, 0x37, 0x05, 0x71, 0x47, 0x61, 0x71, 0x36, 0x51, 0x84, 0x12,
-+ 0x42, 0x36, 0x64, 0x44, 0x66, 0x41, 0x43, 0x52, 0x05, 0x21, 0x08, 0x51,
-+ 0x57, 0x03, 0x33, 0x63, 0x86, 0x02, 0x58, 0x42, 0x66, 0x28, 0x14, 0x81,
-+ 0x10, 0x54, 0x62, 0x68, 0x17, 0x30, 0x38, 0x75, 0x64, 0x33, 0x21, 0x65,
-+ 0x88, 0x56, 0x86, 0x63, 0x63, 0x28, 0x13, 0x40, 0x62, 0x54, 0x01, 0x20,
-+ 0x40, 0x88, 0x65, 0x47, 0x88, 0x61, 0x71, 0x65, 0x76, 0x23, 0x72, 0x62,
-+ 0x34, 0x86, 0x70, 0x30, 0x11, 0x51, 0x15, 0x63, 0x20, 0x50, 0x75, 0x35,
-+ 0x02, 0x12, 0x21, 0x08, 0x42, 0x65, 0x31, 0x43, 0x55, 0x67, 0x11, 0x15,
-+ 0x25, 0x72, 0x01, 0x06, 0x85, 0x36, 0x30, 0x15, 0x05, 0x57, 0x58, 0x60,
-+ 0x58, 0x78, 0x43, 0x14, 0x31, 0x32, 0x78, 0x78, 0x80, 0x87, 0x38, 0x47,
-+ 0x88, 0x63, 0x78, 0x81, 0x81, 0x38, 0x73, 0x42, 0x61, 0x78, 0x38, 0x85,
-+ 0x24, 0x66, 0x77, 0x33, 0x50, 0x60, 0x21, 0x15, 0x14, 0x64, 0x23, 0x82,
-+ 0x32, 0x68, 0x01, 0x35, 0x44, 0x07, 0x83, 0x47, 0x53, 0x85, 0x53, 0x57,
-+ 0x52, 0x83, 0x23, 0x35, 0x18, 0x76, 0x01, 0x15, 0x21, 0x34, 0x32, 0x57,
-+ 0x73, 0x33, 0x36, 0x55, 0x18, 0x86, 0x15, 0x81, 0x61, 0x68, 0x24, 0x18,
-+ 0x42, 0x21, 0x22, 0x30, 0x84, 0x14, 0x48, 0x15, 0x12, 0x01, 0x10, 0x30,
-+ 0x24, 0x77, 0x72, 0x42, 0x54, 0x43, 0x66, 0x06, 0x77, 0x17, 0x70, 0x76,
-+ 0x03, 0x01, 0x45, 0x25, 0x40, 0x35, 0x00, 0x18, 0x38, 0x73, 0x23, 0x77,
-+ 0x35, 0x26, 0x50, 0x86, 0x35, 0x71, 0x13, 0x73, 0x44, 0x81, 0x60, 0x52,
-+ 0x77, 0x45, 0x65, 0x53, 0x73, 0x00, 0x85, 0x83, 0x77, 0x85, 0x03, 0x51,
-+ 0x21, 0x11, 0x54, 0x80, 0x62, 0x88, 0x50, 0x18, 0x02, 0x68, 0x13, 0x86,
-+ 0x52, 0x05, 0x34, 0x68, 0x01, 0x32, 0x07, 0x24, 0x18, 0x03, 0x21, 0x30,
-+ 0x05, 0x72, 0x38, 0x64, 0x07, 0x64, 0x27, 0x11, 0x41, 0x01, 0x83, 0x85,
-+ 0x25, 0x51, 0x06, 0x32, 0x60, 0x71, 0x04, 0x86, 0x51, 0x76, 0x83, 0x38,
-+ 0x28, 0x57, 0x27, 0x62, 0x35, 0x45, 0x18, 0x73, 0x50, 0x83, 0x13, 0x28,
-+ 0x86, 0x37, 0x66, 0x61, 0x42, 0x63, 0x11, 0x67, 0x50, 0x33, 0x11, 0x25,
-+ 0x53, 0x76, 0x41, 0x76, 0x03, 0x14, 0x33, 0x17, 0x72, 0x12, 0x23, 0x44,
-+ 0x18, 0xa8, 0x2e, 0x4f, 0x5c, 0x9e, 0xa0, 0xfa, 0xf9, 0x9e, 0xb0, 0x4d,
-+ 0x78, 0xa7, 0x33, 0x27, 0x11, 0x11, 0x7c, 0x33, 0xf1, 0x8e, 0xca, 0x21,
-+ 0xf8, 0x74, 0x33, 0x76, 0xad, 0xa5, 0x21, 0x98, 0x04, 0xa7, 0xed, 0x9a,
-+ 0x55, 0x57, 0xfc, 0xd6, 0x7a, 0x35, 0x50, 0xb3, 0xa4, 0xb8, 0xc5, 0x88,
-+ 0x62, 0x9c, 0x02, 0x14, 0x75, 0xfa, 0x3d, 0x56, 0xd5, 0xd6, 0xcf, 0xbb,
-+ 0x1a, 0x09, 0xbd, 0xa8, 0xd1, 0x4d, 0xe6, 0x22, 0xdd, 0xff, 0x16, 0xd8,
-+ 0xbc, 0x99, 0xb1, 0x42, 0x78, 0xa8, 0xaf, 0x1d, 0x76, 0xbe, 0xd1, 0x57,
-+ 0x67, 0x2d, 0xd9, 0xc3, 0x23, 0x16, 0xf9, 0x7e, 0x8d, 0xaa, 0xde, 0xf8,
-+ 0xd9, 0xda, 0x69, 0x58, 0x67, 0x25, 0x56, 0x7f, 0xb9, 0x6b, 0x59, 0x99,
-+ 0x0d, 0x4b, 0xf0, 0xbc, 0x9c, 0x19, 0x5b, 0x90, 0xb7, 0x42, 0x95, 0xf5,
-+ 0x67, 0x5b, 0x24, 0x25, 0x7c, 0x27, 0x10, 0xc1, 0x75, 0xb0, 0x15, 0x3f,
-+ 0x29, 0x11, 0x32, 0x8c, 0x2e, 0xb7, 0xab, 0xb9, 0xad, 0x46, 0xe7, 0x0a,
-+ 0x8b, 0x53, 0xc3, 0x9e, 0xa6, 0x42, 0xce, 0xe4, 0xb3, 0xcb, 0x42, 0x62,
-+ 0x0e, 0x86, 0x3c, 0xe8, 0xb6, 0x50, 0xce, 0x8a, 0xdc, 0xd9, 0x23, 0x72,
-+ 0x1a, 0x16, 0x87, 0x02, 0x3c, 0x67, 0x3a, 0x8c, 0xbb, 0x6b, 0x03, 0xd5,
-+ 0x1c, 0xd1, 0x97, 0xe8, 0xc3, 0x46, 0xeb, 0xad, 0xce, 0x93, 0x95, 0x0f,
-+ 0x88, 0xce, 0xe2, 0x01, 0xdb, 0x9e, 0x32, 0x08, 0x43, 0xe2, 0x9f, 0x30,
-+ 0x0d, 0x9a, 0x19, 0x50, 0x0d, 0x70, 0xa4, 0xca, 0xf2, 0x72, 0xc6, 0x9e,
-+ 0x4e, 0xef, 0x69, 0xfb, 0xb8, 0xa5, 0x5e, 0xfd, 0x7c, 0xa2, 0xbe, 0xd9,
-+ 0x90, 0xd2, 0xd3, 0xb5, 0x82, 0x84, 0x8f, 0x9c, 0x45, 0xc2, 0xab, 0xc5,
-+ 0x4c, 0xfc, 0x47, 0xd3, 0x4f, 0x06, 0xc0, 0xff, 0xa5, 0x6f, 0xcd, 0x76,
-+ 0x2a, 0xb9, 0xcb, 0xa9, 0x14, 0x6d, 0x77, 0x25, 0x21, 0x89, 0x63, 0xb2,
-+ 0x40, 0xd7, 0x2b, 0x6d, 0x22, 0xc9, 0x31, 0x71, 0xfb, 0xd4, 0x77, 0x88,
-+ 0xb7, 0x6e, 0x72, 0x04, 0x2d, 0xef, 0x08, 0x78, 0xd2, 0x3d, 0xf6, 0x31,
-+ 0xa1, 0xa1, 0xe5, 0xa6, 0x02, 0x76, 0x86, 0xde, 0x5b, 0x4a, 0x10, 0xe9,
-+ 0x10, 0x69, 0xc8, 0xf2, 0xba, 0x02, 0x59, 0xb0, 0x4d, 0x64, 0x09, 0xda,
-+ 0x96, 0x56, 0x7c, 0xa5, 0x2d, 0xa4, 0x97, 0x02, 0x6e, 0x58, 0x3a, 0x0e,
-+ 0xce, 0xfc, 0x1f, 0x01, 0xe6, 0xb9, 0x88, 0xe2, 0x1f, 0x97, 0x67, 0xa2,
-+ 0xb7, 0xe1, 0x67, 0x2d, 0xeb, 0x9a, 0x1e, 0x2a, 0x3f, 0xcc, 0x86, 0x3a,
-+ 0xa9, 0x15, 0x17, 0xc3, 0x34, 0x62, 0x06, 0x01, 0xb4, 0xfe, 0x79, 0x73,
-+ 0x0e, 0x93, 0x49, 0x35, 0xf4, 0xb6, 0xfb, 0xc4, 0xe3, 0x26, 0x95, 0x14,
-+ 0x5c, 0x2b, 0x5f, 0x6a, 0x12, 0x7f, 0xec, 0xc0, 0xa2, 0x77, 0x45, 0x1e,
-+ 0xbc, 0x3f, 0xd5, 0x23, 0x44, 0x4f, 0x9e, 0xe7, 0xc9, 0xc3, 0x45, 0x34,
-+ 0xf3, 0x56, 0xdb, 0x54, 0x4f, 0xc3, 0x1c, 0x1b, 0xfd, 0xe5, 0xf6, 0x5c,
-+ 0x77, 0xea, 0x2f, 0x7c, 0x2e, 0xae, 0x4c, 0x55, 0xeb, 0xaf, 0x10, 0x42,
-+ 0x71, 0xc5, 0x66, 0xfd, 0x4e, 0xba, 0xc7, 0x1c, 0x7a, 0x62, 0xc7, 0x49,
-+ 0x52, 0x81, 0x7a, 0xe6, 0x75, 0x50, 0x4d, 0x95, 0x99, 0xb1, 0xb7, 0x62,
-+ 0xb6, 0xac, 0xa1, 0x68, 0xa8, 0x32, 0x48, 0xc9, 0xd9, 0xad, 0xb0, 0xce,
-+ 0xb1, 0x55, 0x6e, 0x57, 0x59, 0x49, 0x0b, 0xbc, 0x0c, 0x79, 0x00, 0x79,
-+ 0x5a, 0xd7, 0x21, 0x23, 0x03, 0x8b, 0x66, 0x2f, 0x64, 0xf1, 0x06, 0xa9,
-+ 0x99, 0x36, 0x81, 0xa2, 0x5d, 0x59, 0xaf, 0x7b, 0xc9, 0x7a, 0x23, 0x5b,
-+ 0xe9, 0x28, 0x4c, 0x5b, 0xc4, 0x5a, 0x6c, 0x90, 0xcb, 0x1c, 0x29, 0x99,
-+ 0xc6, 0x63, 0xd9, 0x6b, 0x47, 0x8e, 0x23, 0x07, 0xf8, 0x55, 0x48, 0x95,
-+ 0x7d, 0x65, 0x74, 0x0e, 0x26, 0x73, 0xe9, 0xeb, 0xd1, 0x35, 0x28, 0x29,
-+ 0x03, 0x8f, 0x46, 0x2b, 0x8f, 0xd3, 0xb5, 0x68, 0x1d, 0xa5, 0x5c, 0x02,
-+ 0x52, 0x52, 0x38, 0x53, 0x52, 0x5e, 0xa0, 0xad, 0x64, 0x7e, 0x71, 0xac,
-+ 0x2c, 0x5a, 0x88, 0x93, 0xe6, 0x03, 0xac, 0x97, 0xe5, 0x6c, 0x04, 0xce,
-+ 0xb2, 0xf2, 0x6f, 0x5c, 0x5b, 0x4b, 0x6d, 0x94, 0xab, 0x81, 0x13, 0x80,
-+ 0xfd, 0x00, 0xf2, 0x20, 0x8f, 0xe8, 0x65, 0x35, 0x08, 0x6a, 0xeb, 0xfd,
-+ 0x35, 0xc2, 0x91, 0x20, 0x62, 0x4c, 0x04, 0xfb, 0xb6, 0x11, 0x39, 0x29,
-+ 0xd9, 0xc5, 0x56, 0x35, 0x02, 0x53, 0x76, 0x6c, 0x20, 0x9f, 0xdb, 0xa8,
-+ 0x3c, 0x95, 0xfc, 0xcd, 0x34, 0x2a, 0x28, 0x09, 0x93, 0x55, 0xd0, 0x0b,
-+ 0xc8, 0x63, 0xf4, 0xee, 0xf5, 0x96, 0xeb, 0x0b, 0x42, 0xeb, 0xcc, 0x7c,
-+ 0x79, 0x49, 0x1c, 0xce, 0xae, 0x20, 0x5e, 0xa0, 0xb8, 0x05, 0x9f, 0xbb,
-+ 0x8a, 0x57, 0x26, 0xc5, 0x94, 0x9d, 0x2b, 0x15, 0xe7, 0xe2, 0x9c, 0x51,
-+ 0xfc, 0x9b, 0x02, 0xee, 0x1a, 0x4f, 0xc3, 0x57, 0xb5, 0xf1, 0xbe, 0xf9,
-+ 0xc4, 0xad, 0xd4, 0x6a, 0x2a, 0x92, 0x0c, 0x2f, 0xbf, 0x08, 0xa3, 0x7e,
-+ 0xb1, 0x51, 0x4b, 0xfa, 0x15, 0x11, 0x0a, 0x43, 0x92, 0xa7, 0x4c, 0x6f,
-+ 0x13, 0xc5, 0x0c, 0x5c, 0xff, 0xd9, 0x75, 0x31, 0x09, 0x8d, 0x7c, 0xd2,
-+ 0x3b, 0x60, 0xeb, 0x35, 0xc4, 0xa4, 0x28, 0xb4, 0x6c, 0x55, 0x38, 0x6e,
-+ 0x10, 0x10, 0xc4, 0xba, 0x7f, 0x70, 0xe4, 0xc7, 0xec, 0xb7, 0x57, 0x5f,
-+ 0x30, 0x63, 0xa7, 0x1e, 0x84, 0xdf, 0xdc, 0xf0, 0x9a, 0x58, 0xb2, 0xcd,
-+ 0xb0, 0xf9, 0x9f, 0x27, 0xed, 0x37, 0x86, 0x10, 0xd2, 0x5c, 0xba, 0xd7,
-+ 0xbf, 0xa6, 0xba, 0x0d, 0x59, 0x18, 0x9c, 0xfe, 0x88, 0xea, 0xb9, 0xb4,
-+ 0x6d, 0x7e, 0x6d, 0xb0, 0x30, 0x7e, 0xab, 0xe4, 0x19, 0x8e, 0x99, 0xbd,
-+ 0x71, 0xf7, 0x79, 0xab, 0x66, 0x58, 0x1e, 0x09, 0x12, 0xfc, 0x7b, 0x1d,
-+ 0x25, 0x85, 0x24, 0x5e, 0x9a, 0x12, 0x68, 0x7a, 0x97, 0x5c, 0xd5, 0xe8,
-+ 0xe1, 0xdc, 0xc0, 0x45, 0xd5, 0xf8, 0x91, 0xc4, 0xc6, 0x85, 0xdb, 0x07,
-+ 0xcf, 0x81, 0xe7, 0x73, 0x89, 0xb3, 0x63, 0xeb, 0x6b, 0xdf, 0xe3, 0x9b,
-+ 0x27, 0xff, 0x84, 0xc9, 0x7e, 0xef, 0xee, 0x16, 0x2e, 0x3b, 0x45, 0x1f,
-+ 0xe6, 0x91, 0x47, 0x19, 0xcb, 0x64, 0x36, 0xd8, 0x55, 0x96, 0x0f, 0xf9,
-+ 0x15, 0xd7, 0xce, 0xa6, 0xad, 0xea, 0xfd, 0xfc, 0x1c, 0x05, 0x78, 0x6c,
-+ 0x49, 0xf9, 0x23, 0xa4, 0x74, 0xff, 0xdf, 0xc3, 0x15, 0x3a, 0x06, 0xe6,
-+ 0xed, 0x0b, 0x0a, 0xd2, 0x20, 0xd7, 0x25, 0x24, 0x43, 0x4d, 0x52, 0x73,
-+ 0xc0, 0xaa, 0xb6, 0xdd, 0xe4, 0xe9, 0x14, 0x76, 0xd5, 0x81, 0xa2, 0x69,
-+ 0x5a, 0x60, 0xde, 0x6d, 0x9f, 0x44, 0xd7, 0x7a, 0xa0, 0x82, 0x66, 0xe9,
-+ 0x38, 0xee, 0xb4, 0xa9, 0x59, 0x7c, 0x9b, 0x64, 0x98, 0x60, 0x59, 0xe4,
-+ 0x92, 0x62, 0xa4, 0xea, 0xb2, 0x45, 0x4e, 0x14, 0x01, 0x5a, 0xd0, 0x53,
-+ 0x6c, 0x42, 0x73, 0x3a, 0x5d, 0x77, 0xd7, 0x99, 0x5c, 0x2a, 0x20, 0x44,
-+ 0x60, 0x09, 0xeb, 0xfe, 0x56, 0x32, 0xc8, 0x0c, 0x08, 0xed, 0x2b, 0x97,
-+ 0xaf, 0x35, 0x06, 0x64, 0x89, 0xf5, 0x97, 0xeb, 0x1b, 0x1f, 0x11, 0xf0,
-+ 0x4f, 0x60, 0xe0, 0xc9, 0x04, 0x01, 0x59, 0xc4, 0x4a, 0xb3, 0xe6, 0x0e,
-+ 0x0a, 0x15, 0x22, 0x9d, 0x19, 0x12, 0x28, 0xbe, 0xd1, 0x7b, 0xbc, 0x3a,
-+ 0xc9, 0x39, 0xb3, 0xc6, 0x7c, 0xee, 0x13, 0x5f, 0x35, 0x2c, 0x27, 0x21,
-+ 0x6c, 0x9c, 0x31, 0xf7, 0x2a, 0x3e, 0x87, 0x04, 0x0c, 0x5f, 0x61, 0x93,
-+ 0x06, 0xeb, 0x0b, 0x6c, 0xca, 0x2a, 0x9c, 0xe7, 0xb2, 0x2a, 0x16, 0x94,
-+ 0xd0, 0x0c, 0xa9, 0xc0, 0x5e, 0x31, 0x51, 0x26, 0x45, 0x7f, 0x26, 0xce,
-+ 0x84, 0xf9, 0x61, 0x72, 0x41, 0x86, 0x07, 0x82, 0xf8, 0x64, 0xb4, 0x73,
-+ 0xd8, 0x40, 0x17, 0x49, 0x19, 0x02, 0xb1, 0xbd, 0xc8, 0xcd, 0xc5, 0x80,
-+ 0x0d, 0xd4, 0x61, 0x27, 0xfb, 0x80, 0xa7, 0x1c, 0x09, 0x5b, 0x47, 0x3a,
-+ 0x56, 0x25, 0x29, 0xb3, 0xb1, 0xe7, 0xe4, 0x37, 0xe1, 0x58, 0xa5, 0xf6,
-+ 0x66, 0x6e, 0x99, 0x74, 0xd0, 0x05, 0xb0, 0x62, 0xc2, 0x30, 0x9e, 0x6d,
-+ 0xce, 0x98, 0xf9, 0xb6, 0x58, 0xc6, 0xe3, 0xf9, 0xa2, 0x16, 0xd5, 0x8c,
-+ 0x8c, 0x91, 0x42, 0xbd, 0x1c, 0x8c, 0x85, 0xa9, 0xda, 0x87, 0x2e, 0xbb,
-+ 0xfa, 0xd3, 0xfe, 0xa9, 0xd9, 0xab, 0xa2, 0xb6, 0x8c, 0x0e, 0x8f, 0x19,
-+ 0xc6, 0xff, 0x5f, 0x00, 0x58, 0x4d, 0x45, 0xda, 0xf9, 0xd6, 0xc9, 0xd6,
-+ 0x9e, 0xd0, 0x4b, 0x8d, 0xa8, 0xd6, 0x87, 0x25, 0x8b, 0x77, 0x80, 0x79,
-+ 0x27, 0x61, 0x2c, 0x53, 0x04, 0x46, 0xfe, 0xa7, 0x69, 0x7a, 0xe3, 0xf9,
-+ 0x26, 0x69, 0x89, 0x29, 0xbc, 0x6a, 0x5a, 0x8c, 0xf3, 0xe2, 0x02, 0x4c,
-+ 0x0f, 0x0c, 0x5e, 0xe5, 0x7b, 0x58, 0x69, 0xbf, 0x98, 0x18, 0x81, 0xca,
-+ 0xf9, 0xe3, 0x66, 0x5f, 0xc7, 0xf7, 0xef, 0xc6, 0x78, 0x92, 0x9f, 0x87,
-+ 0xa5, 0x6e, 0xaa, 0x42, 0xea, 0x4d, 0x1f, 0xf6, 0x69, 0x18, 0x22, 0xdd,
-+ 0x79, 0xa4, 0x70, 0x96, 0xb7, 0x76, 0xd1, 0xd8, 0xf0, 0x14, 0x56, 0xe5,
-+ 0x87, 0x3b, 0x07, 0x38, 0x40, 0x6c, 0x38, 0x2c, 0x57, 0x3a, 0xe9, 0xcd,
-+ 0xe2, 0xd9, 0xe7, 0xf2, 0x31, 0xb6, 0xcc, 0x5c, 0x67, 0x6e, 0x7c, 0xf4,
-+ 0x39, 0x63, 0x37, 0x30, 0x13, 0xa5, 0x80, 0x75, 0x38, 0x1f, 0xf0, 0x94,
-+ 0x9b, 0xe0, 0x84, 0x54, 0x6d, 0x72, 0xe4, 0xf8, 0xa3, 0xe5, 0xfe, 0x4a,
-+ 0xa5, 0x09, 0x1a, 0xdd, 0x23, 0x4e, 0x2a, 0xfe, 0x00, 0x30, 0xb1, 0xb6,
-+ 0x63, 0xae, 0x9d, 0x2d, 0x32, 0x41, 0x09, 0x86, 0xb9, 0x40, 0x2a, 0xaa,
-+ 0xf2, 0x46, 0x5b, 0x74, 0xa5, 0xe2, 0xd0, 0xbc, 0x38, 0xe3, 0xa9, 0x2b,
-+ 0xbd, 0xdd, 0x8a, 0x1f, 0xed, 0x7b, 0x94, 0x8c, 0x23, 0xcc, 0xe6, 0xf8,
-+ 0xc0, 0x8f, 0xe3, 0x56, 0x83, 0x5b, 0xa6, 0x5b, 0x0f, 0x98, 0x40, 0x68,
-+ 0x61, 0x6e, 0xf4, 0x81, 0x38, 0xef, 0xd8, 0x9b, 0xf3, 0x57, 0xa5, 0x4d,
-+ 0x2e, 0xbb, 0xf3, 0x76, 0xcb, 0xdc, 0xc6, 0x9c, 0x5f, 0x1f, 0x61, 0xc6,
-+ 0x4d, 0x27, 0x94, 0xbc, 0x06, 0xcc, 0xb9, 0xab, 0xdf, 0x66, 0xe2, 0x50,
-+ 0x85, 0xd8, 0xc8, 0x30, 0xe2, 0xae, 0x3b, 0x0f, 0xe0, 0xf0, 0x7a, 0x7a,
-+ 0xf8, 0xb9, 0x32, 0x0b, 0xf3, 0x42, 0x97, 0x09, 0x97, 0xd6, 0x7d, 0x7c,
-+ 0x12, 0x59, 0x3a, 0x8f, 0xbf, 0xad, 0xe6, 0x35, 0xaa, 0xc5, 0x30, 0x83,
-+ 0xa7, 0x02, 0x2c, 0x47, 0xd5, 0xf7, 0x7a, 0x52, 0xb5, 0x7b, 0x59, 0x8d,
-+ 0xa9, 0x39, 0x2a, 0xe6, 0xd8, 0x6a, 0xfc, 0x46, 0xfc, 0x06, 0x45, 0x51,
-+ 0x81, 0xb9, 0xc7, 0x5a, 0x64, 0x6d, 0xc2, 0x1f, 0x81, 0xe4, 0xbf, 0x21,
-+ 0x37, 0x53, 0xde, 0x73, 0x7f, 0xd2, 0xa1, 0x40, 0x02, 0x79, 0x20, 0xad,
-+ 0xd3, 0x5a, 0x22, 0x3f, 0x9f, 0x5f, 0x44, 0x65, 0xce, 0xb6, 0x0c, 0x03,
-+ 0xed, 0x04, 0x55, 0xa3, 0x33, 0xa5, 0xcc, 0x83, 0xad, 0xbf, 0x43, 0xf1,
-+ 0xf4, 0x2c, 0x2c, 0xcb, 0x83, 0x28, 0xc2, 0x1c, 0x7a, 0xb7, 0xfa, 0xed,
-+ 0x2b, 0x21, 0xcf, 0xad, 0xe2, 0xda, 0x55, 0x22, 0x3a, 0xaa, 0xb2, 0xaf,
-+ 0x9b, 0x41, 0xc7, 0x33, 0x23, 0x41, 0x74, 0x63, 0x41, 0xb3, 0x9a, 0xa2,
-+ 0xf4, 0x38, 0x15, 0x65, 0x0f, 0x54, 0x80, 0x51, 0x14, 0x24, 0xcf, 0xa6,
-+ 0x90, 0x17, 0x79, 0xc4, 0xd1, 0x8b, 0x63, 0x8c, 0xc0, 0x28, 0x7a, 0xaa,
-+ 0xf3, 0x16, 0x80, 0x33, 0x8d, 0x20, 0xb1, 0x7c, 0x74, 0x49, 0xfd, 0xc6,
-+ 0xa2, 0x78, 0xa8, 0xd9, 0x6a, 0x82, 0xee, 0x4c, 0x4e, 0xca, 0x40, 0x12,
-+ 0x5e, 0x2d, 0x65, 0x29, 0x00, 0x71, 0xc7, 0xae, 0xf1, 0xbe, 0x6a, 0x99,
-+ 0x15, 0x98, 0xfb, 0x9d, 0x59, 0x51, 0x25, 0x23, 0xbc, 0xd4, 0xb3, 0x8c,
-+ 0x56, 0x6b, 0x8e, 0x80, 0xa7, 0x3a, 0xe3, 0x33, 0xe1, 0x34, 0x41, 0x43,
-+ 0x27, 0xef, 0x1d, 0x83, 0xc4, 0x7c, 0x49, 0xdf, 0xe7, 0x93, 0x6d, 0xf1,
-+ 0x33, 0x8a, 0x5e, 0x24, 0x77, 0x87, 0x86, 0x8f, 0xc8, 0x4f, 0xdc, 0xb9,
-+ 0x5a, 0xc8, 0x9c, 0x18, 0x5c, 0x4b, 0xb5, 0xfd, 0x57, 0xb2, 0x33, 0x8a,
-+ 0xc4, 0x2b, 0x41, 0xc1, 0x0a, 0x82, 0x3d, 0xf3, 0x96, 0x24, 0xf3, 0x6b,
-+ 0x15, 0xa2, 0xf0, 0x67, 0x58, 0x4e, 0x06, 0xca, 0x2e, 0x08, 0xcc, 0xaf,
-+ 0xf1, 0x61, 0x8f, 0xe0, 0x1d, 0xd0, 0x6d, 0xf3, 0x51, 0x2e, 0x0b, 0x72,
-+ 0x4d, 0xec, 0x85, 0x06, 0xda, 0x24, 0x21, 0x5a, 0xca, 0xcc, 0x2c, 0x51,
-+ 0xb8, 0x2a, 0xd8, 0xd3, 0x02, 0x00, 0x2f, 0xb4, 0x10, 0x68, 0xb1, 0xda,
-+ 0x4f, 0x8b, 0xb1, 0x47, 0x98, 0x7b, 0x35, 0x16, 0xba, 0xd5, 0xdb, 0xdd,
-+ 0xf0, 0x13, 0x18, 0xfd, 0x3f, 0xa9, 0xbc, 0x43, 0x70, 0x2a, 0xc4, 0x98,
-+ 0xc7, 0x19, 0xd9, 0x5f, 0x2e, 0x84, 0x1b, 0x62, 0x2a, 0x5e, 0x48, 0x48,
-+ 0xa3, 0xc5, 0xc2, 0x62, 0x95, 0x99, 0x92, 0xea, 0x7a, 0x7d, 0x72, 0xca,
-+ 0x8a, 0x36, 0x80, 0x28, 0xf4, 0x97, 0xdf, 0xad, 0x93, 0x35, 0x5c, 0xbb,
-+ 0x1b, 0xb9, 0x78, 0x6d, 0x14, 0xff, 0x2c, 0xf5, 0x90, 0x31, 0x78, 0x48,
-+ 0xf9, 0x58, 0x56, 0x42, 0x71, 0x10, 0xdd, 0xa3, 0x6f, 0x51, 0x92, 0xa8,
-+ 0x16, 0xce, 0x9c, 0x88, 0x16, 0xcc, 0x7b, 0xbf, 0xc8, 0x04, 0xef, 0xc4,
-+ 0x00, 0x85, 0xa3, 0x85, 0x0b, 0x89, 0xf1, 0xe7, 0xfe, 0x56, 0x56, 0xdb,
-+ 0xa4, 0x10, 0xf9, 0x06, 0xa9, 0x7c, 0x32, 0x33, 0x6c, 0x1a, 0xe7, 0xe8,
-+ 0x17, 0x37, 0xa8, 0x3e, 0x08, 0x73, 0x54, 0xe4, 0x28, 0xda, 0x85, 0x38,
-+ 0xd9, 0x48, 0xdb, 0xf5, 0xdf, 0xac, 0xb5, 0x9d, 0xd2, 0xb5, 0xfd, 0x3b,
-+ 0xc8, 0x03, 0xf4, 0xba, 0x43, 0x2c, 0x9a, 0x73, 0x9d, 0xf2, 0xcf, 0xa9,
-+ 0xed, 0x94, 0x84, 0x32, 0x0f, 0x97, 0xed, 0xff, 0x1a, 0x48, 0xc6, 0xb8,
-+ 0x6b, 0x30, 0x02, 0xcf, 0xb7, 0x72, 0xdd, 0x5e, 0x56, 0x2b, 0xc4, 0xc3,
-+ 0xd6, 0x83, 0xed, 0x96, 0x4b, 0x61, 0x99, 0xfa, 0x05, 0x14, 0xb0, 0x79,
-+ 0x0d, 0x95, 0x80, 0x95, 0xb7, 0xb8, 0x5c, 0x6b, 0xe8, 0x75, 0xfb, 0xb5,
-+ 0x59, 0xe1, 0x93, 0x01, 0x46, 0xcc, 0xea, 0x63, 0xa3, 0x88, 0xa1, 0x94,
-+ 0xfe, 0x09, 0xc3, 0xde, 0xa0, 0x3b, 0xe5, 0x2d, 0xe2, 0x7e, 0x90, 0x10,
-+ 0x17, 0xaf, 0xe8, 0x09, 0xaf, 0x63, 0x0a, 0x73, 0x82, 0xbf, 0x5c, 0x4c,
-+ 0xd4, 0xd1, 0xb8, 0xf4, 0x15, 0x79, 0xfb, 0x43, 0x48, 0xed, 0xe4, 0xca,
-+ 0x05, 0xf4, 0xcd, 0x3f, 0x13, 0x9a, 0x31, 0xb2, 0x54, 0x4e, 0x51, 0x6d,
-+ 0xbe, 0x40, 0x86, 0xb9, 0xbb, 0x4b, 0x2b, 0xed, 0x47, 0xe2, 0xd2, 0x30,
-+ 0x98, 0x2d, 0xd5, 0x19, 0x24, 0x29, 0xd3, 0x77, 0xb7, 0xc0, 0x74, 0x5c,
-+ 0xc0, 0x68, 0xe2, 0xf5, 0xa4, 0xaa, 0x04, 0xc7, 0xff, 0x87, 0x20, 0x9e,
-+ 0xd1, 0x25, 0x99, 0x76, 0xa0, 0xfc, 0x9b, 0x25, 0xe9, 0xe8, 0x51, 0xd4,
-+ 0xe3, 0x50, 0x2c, 0x02, 0xc8, 0x5d, 0x6d, 0xff, 0x02, 0x9e, 0x21, 0x1d,
-+ 0x01, 0xeb, 0xf0, 0xe9, 0xe7, 0x18, 0x8d, 0x56, 0x8f, 0x84, 0x37, 0xd8,
-+ 0x13, 0xb0, 0xf1, 0x22, 0xf2, 0xfb, 0x17, 0x60, 0x3b, 0x69, 0x3e, 0xd9,
-+ 0xc3, 0x8f, 0x17, 0xcf, 0xd5, 0x0b, 0x81, 0x5e, 0x6d, 0x9d, 0xfc, 0x0e,
-+ 0xd2, 0xcc, 0xf1, 0x9f, 0x63, 0x99, 0x27, 0x4a, 0x14, 0x20, 0xf2, 0x35,
-+ 0xa5, 0x9d, 0x8b, 0xf7, 0x24, 0x34, 0x5e, 0x14, 0xe4, 0x5d, 0x9e, 0x4b,
-+ 0xe8, 0x93, 0x4d, 0xfc, 0x3f, 0xa9, 0x26, 0x78, 0xdb, 0x61, 0xd7, 0x11,
-+ 0x8b, 0xf5, 0x3c, 0xb8, 0xa2, 0x22, 0x5b, 0x33, 0x5f, 0x7e, 0xae, 0x50,
-+ 0xe3, 0xf9, 0x41, 0x23, 0x76, 0x28, 0xdb, 0x76, 0xd8, 0xea, 0x38, 0xf7,
-+ 0x7a, 0x72, 0xaf, 0x3a, 0x26, 0xc8, 0x1f, 0xe4, 0x35, 0x23, 0xb3, 0x35,
-+ 0x53, 0x5a, 0x5d, 0x1d, 0xb7, 0xc3, 0x8f, 0x34, 0x10, 0x82, 0xbb, 0x57,
-+ 0x34, 0xd0, 0x89, 0xe8, 0xae, 0x30, 0x9c, 0xfd, 0xa3, 0xa0, 0xbc, 0xb5,
-+ 0xcd, 0x5b, 0x09, 0x71, 0x13, 0xc8, 0xed, 0xf9, 0x61, 0x6a, 0xa4, 0xf6,
-+ 0xe6, 0x63, 0x1b, 0x91, 0x25, 0x27, 0x6f, 0xb3, 0xf6, 0x80, 0xa3, 0x43,
-+ 0x41, 0xc3, 0xdb, 0x66, 0x8d, 0xc6, 0xca, 0xd4, 0x5f, 0xc9, 0x3b, 0x27,
-+ 0x08, 0xca, 0x2a, 0xf7, 0x5c, 0xcc, 0xe7, 0x34, 0xfd, 0x19, 0x1c, 0x50,
-+ 0x08, 0x9d, 0xad, 0x53, 0x98, 0x2f, 0xdd, 0xae, 0x02, 0x53, 0x1f, 0xf9,
-+ 0x3e, 0x1f, 0x21, 0xff, 0x39, 0x5f, 0xc0, 0xa1, 0x28, 0x74, 0xed, 0xf0,
-+ 0x6b, 0x6f, 0x96, 0x47, 0xe9, 0x5a, 0x73, 0x24, 0x58, 0x6c, 0x71, 0xdf,
-+ 0xd9, 0x1d, 0x90, 0x1d, 0x62, 0x18, 0x58, 0x19, 0x0f, 0xec, 0xd0, 0x0c,
-+ 0xcd, 0x11, 0x0b, 0xba, 0xc5, 0x9f, 0x96, 0xcb, 0x88, 0x4c, 0x3c, 0x93,
-+ 0x99, 0x47, 0x48, 0xa5, 0x6f, 0x41, 0x28, 0x3b, 0xfc, 0x41, 0xfb, 0x89,
-+ 0x05, 0x21, 0x53, 0xa8, 0x94, 0x58, 0x8c, 0x3c, 0xb9, 0x01, 0x7f, 0x3d,
-+ 0x66, 0x32, 0x6c, 0x98, 0x56, 0x37, 0xe5, 0x75, 0xac, 0xb8, 0x12, 0x34,
-+ 0x63, 0x42, 0x65, 0x40, 0x25, 0xd6, 0x02, 0xde, 0x3b, 0xa9, 0x40, 0xc1,
-+ 0x9a, 0xc1, 0xa6, 0x33, 0xdf, 0xfd, 0xa9, 0x77, 0xb5, 0x29, 0xb8, 0x01,
-+ 0x3e, 0x19, 0xc1, 0xd6, 0xd0, 0x68, 0x0f, 0x4d, 0xae, 0x62, 0xc9, 0x24,
-+ 0x45, 0x0a, 0xe6, 0x6a, 0xab, 0x82, 0xf2, 0x14, 0x73, 0x06, 0x1d, 0xab,
-+ 0x3d, 0x62, 0xb2, 0x47, 0xf9, 0x07, 0xe3, 0x55, 0x19, 0x39, 0xad, 0x3f,
-+ 0x54, 0x65, 0xe9, 0xd0, 0x8a, 0x82, 0xbf, 0xea, 0x17, 0xee, 0xa1, 0xb6,
-+ 0xb2, 0xb9, 0x23, 0x75, 0x74, 0x77, 0xf9, 0x93, 0x00, 0x0b, 0x2f, 0x43,
-+ 0xb7, 0x0f, 0x28, 0xaa, 0xab, 0x1f, 0xe9, 0xa2, 0x6a, 0xd1, 0xfd, 0x33,
-+ 0x61, 0x61, 0x6c, 0x0b, 0x0e, 0x24, 0x2f, 0xe7, 0x66, 0x04, 0xb7, 0x03,
-+ 0x3a, 0x1f, 0x30, 0xe9, 0x7e, 0x28, 0xf5, 0x26, 0xca, 0x3c, 0x88, 0x0f,
-+ 0xe2, 0xb8, 0xd9, 0xd1, 0xb0, 0xc9, 0xff, 0x18, 0x8b, 0x31, 0xcb, 0x9d,
-+ 0x97, 0x42, 0x5a, 0xca, 0xb9, 0xb2, 0x16, 0xd9, 0x8a, 0x6a, 0xe3, 0x55,
-+ 0xe5, 0x83, 0xda, 0x71, 0xe8, 0x86, 0x4e, 0xe3, 0xd1, 0x6b, 0x07, 0x59,
-+ 0x79, 0x61, 0x90, 0xef, 0x54, 0x5c, 0x1e, 0x62, 0xbf, 0xef, 0x92, 0xaf,
-+ 0x6c, 0xa1, 0x47, 0xb1, 0x32, 0x44, 0xd6, 0xc8, 0x92, 0xfc, 0x8e, 0xf2,
-+ 0x23, 0xab, 0x3f, 0x43, 0xf9, 0x24, 0xc2, 0xf4, 0x66, 0x09, 0x7e, 0xe8,
-+ };
-+ static const unsigned char ml_dsa_87_pub_key[] = {
-+ 0x97, 0x92, 0xbc, 0xec, 0x2f, 0x24, 0x30, 0x68, 0x6a, 0x82, 0xfc, 0xcf,
-+ 0x3c, 0x2f, 0x5f, 0xf6, 0x65, 0xe7, 0x71, 0xd7, 0xab, 0x41, 0xb9, 0x02,
-+ 0x58, 0xcf, 0xa7, 0xe9, 0x0e, 0xc9, 0x71, 0x24, 0xa7, 0x3b, 0x32, 0x3b,
-+ 0x9b, 0xa2, 0x1a, 0xb6, 0x4d, 0x76, 0x7c, 0x43, 0x3f, 0x5a, 0x52, 0x1e,
-+ 0xff, 0xe1, 0x8f, 0x86, 0xe4, 0x6a, 0x18, 0x89, 0x52, 0xc4, 0x46, 0x7e,
-+ 0x04, 0x8b, 0x72, 0x9e, 0x7f, 0xc4, 0xd1, 0x15, 0xe7, 0xe4, 0x8d, 0xa1,
-+ 0x89, 0x6d, 0x5f, 0xe1, 0x19, 0xb1, 0x0d, 0xcd, 0xde, 0xf6, 0x2c, 0xb3,
-+ 0x07, 0x95, 0x40, 0x74, 0xb4, 0x23, 0x36, 0xe5, 0x28, 0x36, 0xde, 0x61,
-+ 0xda, 0x94, 0x1f, 0x8d, 0x37, 0xea, 0x68, 0xac, 0x81, 0x06, 0xfa, 0xbe,
-+ 0x19, 0x07, 0x06, 0x79, 0xaf, 0x60, 0x08, 0x53, 0x71, 0x20, 0xf7, 0x07,
-+ 0x93, 0xb8, 0xea, 0x9c, 0xc0, 0xe6, 0xe7, 0xb7, 0xb4, 0xc9, 0xa5, 0xc7,
-+ 0x42, 0x1c, 0x60, 0xf2, 0x44, 0x51, 0xba, 0x1e, 0x93, 0x3d, 0xb1, 0xa2,
-+ 0xee, 0x16, 0xc7, 0x95, 0x59, 0xf2, 0x1b, 0x3d, 0x1b, 0x83, 0x05, 0x85,
-+ 0x0a, 0xa4, 0x2a, 0xfb, 0xb1, 0x3f, 0x1f, 0x4d, 0x5b, 0x9f, 0x48, 0x35,
-+ 0xf9, 0xd8, 0x7d, 0xfc, 0xeb, 0x16, 0x2d, 0x0e, 0xf4, 0xa7, 0xfd, 0xc4,
-+ 0xcb, 0xa1, 0x74, 0x3c, 0xd1, 0xc8, 0x7b, 0xb4, 0x96, 0x7d, 0xa1, 0x6c,
-+ 0xc8, 0x76, 0x4b, 0x65, 0x69, 0xdf, 0x8e, 0xe5, 0xbd, 0xcb, 0xff, 0xe9,
-+ 0xa4, 0xe0, 0x57, 0x48, 0xe6, 0xfd, 0xf2, 0x25, 0xaf, 0x9e, 0x4e, 0xeb,
-+ 0x77, 0x73, 0xb6, 0x2e, 0x8f, 0x85, 0xf9, 0xb5, 0x6b, 0x54, 0x89, 0x45,
-+ 0x55, 0x18, 0x44, 0xfb, 0xd8, 0x98, 0x06, 0xa4, 0xac, 0x36, 0x9b, 0xed,
-+ 0x2d, 0x25, 0x61, 0x00, 0xf6, 0x88, 0xa6, 0xad, 0x5e, 0x0a, 0x70, 0x98,
-+ 0x26, 0xdc, 0x44, 0x49, 0xe9, 0x1e, 0x23, 0xc5, 0x50, 0x6e, 0x64, 0x23,
-+ 0x61, 0xef, 0x5a, 0x31, 0x37, 0x12, 0xf7, 0x9b, 0xc4, 0xb3, 0x18, 0x68,
-+ 0x61, 0xca, 0x85, 0xa4, 0xba, 0xb1, 0x7e, 0x7f, 0x94, 0x3d, 0x1b, 0x8a,
-+ 0x33, 0x3a, 0xa3, 0xae, 0x7c, 0xe1, 0x6b, 0x44, 0x0d, 0x60, 0x18, 0xf9,
-+ 0xe0, 0x4d, 0xaf, 0x57, 0x25, 0xc7, 0xf1, 0xa9, 0x3f, 0xad, 0x1a, 0x5a,
-+ 0x27, 0xb6, 0x78, 0x95, 0xbd, 0x24, 0x9a, 0xa9, 0x16, 0x85, 0xde, 0x20,
-+ 0xaf, 0x32, 0xc8, 0xb7, 0xe2, 0x68, 0xc7, 0xf9, 0x68, 0x77, 0xd0, 0xc8,
-+ 0x50, 0x01, 0x13, 0x5a, 0x4f, 0x0a, 0x8f, 0x1b, 0x82, 0x64, 0xfa, 0x6e,
-+ 0xbe, 0x5a, 0x34, 0x9d, 0x8a, 0xec, 0xad, 0x1a, 0x16, 0x29, 0x9c, 0xcf,
-+ 0x2f, 0xd9, 0xc7, 0xb8, 0x5b, 0xac, 0xe2, 0xce, 0xd3, 0xaa, 0x12, 0x76,
-+ 0xba, 0x61, 0xee, 0x78, 0xed, 0x7e, 0x5c, 0xa5, 0xb6, 0x7c, 0xdd, 0x45,
-+ 0x8a, 0x93, 0x54, 0x03, 0x0e, 0x6a, 0xbb, 0xba, 0xbf, 0x56, 0xa0, 0xa2,
-+ 0x31, 0x6f, 0xec, 0x9d, 0xba, 0x83, 0xb5, 0x1d, 0x42, 0xfd, 0x31, 0x67,
-+ 0xf1, 0xe0, 0xf9, 0x08, 0x55, 0xd5, 0xc6, 0x65, 0x09, 0xb2, 0x10, 0x26,
-+ 0x5d, 0xc1, 0xe5, 0x4e, 0xc4, 0x4b, 0x43, 0xba, 0x7c, 0xf9, 0xae, 0xf1,
-+ 0x18, 0xb4, 0x4d, 0x80, 0x91, 0x2c, 0xe7, 0x51, 0x66, 0xa6, 0x65, 0x1e,
-+ 0x11, 0x6c, 0xeb, 0xe4, 0x92, 0x29, 0xa7, 0x06, 0x2c, 0x09, 0x93, 0x1f,
-+ 0x71, 0xab, 0xd2, 0x29, 0x3f, 0x76, 0xf7, 0xef, 0xc3, 0x21, 0x5b, 0xa9,
-+ 0x78, 0x00, 0x03, 0x7e, 0x58, 0xe4, 0x70, 0xbd, 0xbb, 0xb4, 0x3c, 0x1b,
-+ 0x04, 0x39, 0xea, 0xf7, 0x9c, 0x54, 0xd9, 0x3b, 0x44, 0xaa, 0xc9, 0xef,
-+ 0xe9, 0xfb, 0xe1, 0x51, 0x87, 0x4c, 0xfb, 0x2a, 0x64, 0xcb, 0xee, 0x28,
-+ 0xcc, 0x4c, 0x0f, 0xe7, 0x77, 0x5e, 0x5d, 0x87, 0x0f, 0x1c, 0x02, 0xe5,
-+ 0xb2, 0xe3, 0xc5, 0x00, 0x4c, 0x99, 0x5f, 0x24, 0xc9, 0xb7, 0x79, 0xcb,
-+ 0x75, 0x3a, 0x27, 0x7d, 0x0e, 0x71, 0xfd, 0x42, 0x5e, 0xb6, 0xbc, 0x2c,
-+ 0xa5, 0x6c, 0xe1, 0x29, 0xdb, 0x51, 0xf7, 0x07, 0x40, 0xf3, 0x1e, 0x63,
-+ 0x97, 0x6b, 0x50, 0xc7, 0x31, 0x2e, 0x97, 0x97, 0xd7, 0x8c, 0x5b, 0x1a,
-+ 0xc2, 0x4a, 0x5f, 0xa3, 0x47, 0xcc, 0x91, 0x6e, 0x0a, 0x83, 0xf5, 0xc3,
-+ 0xb6, 0x75, 0xcd, 0x30, 0xb8, 0x1e, 0x3f, 0xa1, 0x0b, 0x93, 0x44, 0x4e,
-+ 0x07, 0x39, 0x75, 0x71, 0xcc, 0xe9, 0x8b, 0x28, 0xda, 0x51, 0xdb, 0x90,
-+ 0x56, 0xbc, 0x72, 0x8c, 0x5b, 0x0b, 0x11, 0x81, 0xe2, 0xfb, 0xd3, 0x87,
-+ 0xb4, 0xc7, 0x9a, 0xb1, 0xa5, 0xfe, 0xfe, 0xce, 0x37, 0x16, 0x7a, 0xf7,
-+ 0x72, 0xdd, 0xad, 0x14, 0xeb, 0x4c, 0x39, 0x82, 0xda, 0x5a, 0x59, 0xd0,
-+ 0xe9, 0xeb, 0x17, 0x3e, 0xc6, 0x31, 0x50, 0x91, 0x17, 0x00, 0x27, 0xa3,
-+ 0xab, 0x5e, 0xf6, 0xaa, 0x12, 0x9c, 0xb8, 0x58, 0x57, 0x27, 0xb9, 0x35,
-+ 0x8a, 0x28, 0x50, 0x1d, 0x71, 0x3a, 0x72, 0xf3, 0xf1, 0xdb, 0x31, 0x71,
-+ 0x42, 0x86, 0xf9, 0xb6, 0x40, 0x80, 0x13, 0xaf, 0x06, 0x04, 0x5d, 0x75,
-+ 0x59, 0x2f, 0xc0, 0xb7, 0xdd, 0x47, 0xc7, 0x3e, 0xd9, 0xc7, 0x5b, 0x11,
-+ 0xe9, 0xd7, 0xc6, 0x9f, 0x7c, 0xad, 0xfc, 0x32, 0x80, 0xa9, 0x06, 0x2c,
-+ 0x52, 0x73, 0xc4, 0x3b, 0xe1, 0xc3, 0x4f, 0x87, 0x44, 0x88, 0x64, 0xce,
-+ 0xa7, 0xb5, 0xc9, 0x7d, 0x6d, 0x32, 0xf5, 0x9b, 0xd5, 0xf2, 0x53, 0x84,
-+ 0x65, 0x3b, 0xb5, 0xc4, 0xfa, 0xa4, 0x5b, 0xea, 0x8b, 0x89, 0x40, 0x28,
-+ 0x43, 0xe6, 0x45, 0xb6, 0xb9, 0x26, 0x9e, 0x2b, 0xd9, 0x88, 0xdd, 0xac,
-+ 0xb0, 0x33, 0x32, 0x8f, 0xfb, 0x06, 0x04, 0x50, 0xf7, 0xdf, 0x08, 0x00,
-+ 0x53, 0xe6, 0x96, 0x9b, 0x25, 0x1e, 0x87, 0x5e, 0xce, 0xc3, 0x2c, 0xfc,
-+ 0x59, 0x28, 0x40, 0xd6, 0x9a, 0xb6, 0x9a, 0x75, 0xe0, 0x6b, 0x37, 0x9c,
-+ 0x53, 0x5d, 0x95, 0x26, 0x6b, 0x08, 0x2f, 0x4f, 0x09, 0xc9, 0x31, 0x62,
-+ 0xb3, 0x3b, 0x0d, 0x9f, 0x73, 0x07, 0xa4, 0xea, 0xaa, 0x52, 0x10, 0x44,
-+ 0x37, 0xfe, 0xd6, 0x6f, 0x8e, 0xe3, 0xea, 0xbb, 0xd4, 0x5d, 0x67, 0xb2,
-+ 0x5a, 0x81, 0x33, 0xf4, 0x96, 0x46, 0x8b, 0x52, 0xba, 0xff, 0xdb, 0xfa,
-+ 0xd9, 0x3e, 0xef, 0x1a, 0x98, 0x18, 0xb5, 0xe4, 0x2e, 0xc7, 0x22, 0x78,
-+ 0x8a, 0x3d, 0x8d, 0x35, 0x29, 0xfc, 0x77, 0x7d, 0x2b, 0xa5, 0x70, 0x80,
-+ 0x1d, 0xfa, 0xe0, 0x1e, 0xc8, 0x83, 0x02, 0x83, 0x7c, 0x1f, 0xb9, 0xe0,
-+ 0x35, 0x57, 0x27, 0x64, 0x5e, 0xe1, 0x04, 0x6c, 0x3f, 0x91, 0x5f, 0x6a,
-+ 0xe8, 0x2d, 0xad, 0x4f, 0xb6, 0xb0, 0x35, 0x6a, 0x46, 0x51, 0x8f, 0xfc,
-+ 0x83, 0x41, 0x55, 0xc3, 0xb4, 0xfe, 0x6d, 0xaf, 0xa6, 0xcc, 0x8a, 0x5c,
-+ 0xcf, 0x53, 0xc7, 0x3a, 0x08, 0x49, 0xd8, 0xd4, 0x4f, 0x7d, 0xcf, 0x72,
-+ 0x75, 0x4e, 0x70, 0xe1, 0xb7, 0xdf, 0xb4, 0x47, 0xbb, 0x4e, 0xf4, 0x9d,
-+ 0x1a, 0x71, 0x8f, 0x61, 0x71, 0xbb, 0xce, 0x20, 0x09, 0x50, 0xe0, 0xce,
-+ 0x92, 0x61, 0x06, 0xb1, 0x51, 0xa3, 0xe8, 0x71, 0xd5, 0xce, 0x49, 0x73,
-+ 0x1b, 0xd6, 0x65, 0x0a, 0x9b, 0x0c, 0xa9, 0x72, 0xda, 0x1c, 0x5f, 0x13,
-+ 0x6d, 0x44, 0x82, 0x0e, 0xa6, 0x38, 0x3c, 0x08, 0xf3, 0xb3, 0x84, 0xcf,
-+ 0x23, 0x38, 0xe7, 0x89, 0xc5, 0x13, 0xf6, 0x18, 0xcc, 0x56, 0x94, 0xa6,
-+ 0xf0, 0xce, 0xe1, 0x04, 0x51, 0x1e, 0x1e, 0xd7, 0xc5, 0xf2, 0x3a, 0x1e,
-+ 0xbf, 0xd8, 0xa0, 0xdb, 0x84, 0x24, 0x55, 0x32, 0x40, 0x15, 0x6d, 0xbf,
-+ 0x62, 0x28, 0x31, 0xb0, 0xc6, 0x43, 0xd1, 0xc5, 0x51, 0xb6, 0xf3, 0xf7,
-+ 0xa9, 0x8d, 0x29, 0xb8, 0x5c, 0x2d, 0xe0, 0x5a, 0x65, 0xfa, 0x61, 0x5e,
-+ 0xee, 0x16, 0x49, 0x5b, 0xd9, 0x07, 0x37, 0x67, 0x21, 0x15, 0xb5, 0x3e,
-+ 0x91, 0xc5, 0xd9, 0x00, 0x28, 0xcf, 0x3f, 0x1a, 0x93, 0x95, 0x3a, 0x15,
-+ 0x3d, 0xe5, 0x3b, 0x44, 0x08, 0x4e, 0x9c, 0xcf, 0xf6, 0xb7, 0x36, 0x69,
-+ 0x39, 0x26, 0xda, 0xef, 0xeb, 0xb2, 0xd7, 0x7a, 0xa5, 0xad, 0x68, 0x9b,
-+ 0x92, 0xf3, 0x16, 0x86, 0x66, 0x9d, 0xf1, 0x6d, 0x17, 0x15, 0xcc, 0x58,
-+ 0xf7, 0xa2, 0xcf, 0xb7, 0x2d, 0xd1, 0xa5, 0x1e, 0x92, 0xf8, 0x25, 0x99,
-+ 0x3a, 0x74, 0x02, 0x2b, 0xe7, 0xe9, 0xeb, 0x60, 0x54, 0x65, 0x44, 0x57,
-+ 0x09, 0x4d, 0x14, 0x92, 0x8f, 0x20, 0x21, 0x5e, 0x7b, 0x22, 0x2a, 0xc5,
-+ 0x6b, 0x51, 0xad, 0xbe, 0xc8, 0xd8, 0xbd, 0xb6, 0x98, 0x39, 0x79, 0xa7,
-+ 0xe3, 0xa2, 0x1b, 0x44, 0xb5, 0xd1, 0x51, 0x8c, 0xa9, 0x7d, 0x0b, 0x51,
-+ 0x95, 0xf5, 0x1e, 0xd6, 0xa2, 0x43, 0x50, 0xc8, 0x97, 0x47, 0xe1, 0xed,
-+ 0xea, 0x51, 0xb4, 0x48, 0xe3, 0xe9, 0x14, 0x70, 0x54, 0xce, 0x92, 0x78,
-+ 0x73, 0xc9, 0x0d, 0xb3, 0x94, 0xd8, 0x68, 0x88, 0xe0, 0x7d, 0xff, 0x17,
-+ 0x75, 0x93, 0xd6, 0xf7, 0x9e, 0x15, 0x23, 0x02, 0x20, 0x4a, 0xeb, 0x03,
-+ 0xbe, 0x23, 0x86, 0xaf, 0x3e, 0x24, 0x07, 0x8b, 0xd0, 0x28, 0xb1, 0x68,
-+ 0x9f, 0x5e, 0x14, 0x7c, 0x9f, 0x45, 0x2c, 0x8c, 0xeb, 0x02, 0xec, 0x59,
-+ 0xcc, 0x9d, 0xb6, 0x3a, 0x03, 0x57, 0x6c, 0xee, 0xaf, 0xe9, 0x82, 0x39,
-+ 0x02, 0x38, 0x97, 0xda, 0x02, 0x36, 0x63, 0x0a, 0x53, 0xc0, 0xde, 0x7f,
-+ 0x43, 0x5a, 0x19, 0x86, 0x97, 0x92, 0xfa, 0xb3, 0x6e, 0x7b, 0x9e, 0x63,
-+ 0x57, 0x60, 0xf0, 0x90, 0x69, 0xe6, 0x43, 0x2e, 0x70, 0x00, 0x35, 0xac,
-+ 0x2a, 0x02, 0x87, 0x9f, 0xff, 0x0a, 0x1e, 0x1b, 0xec, 0x52, 0x20, 0x47,
-+ 0x19, 0x3d, 0x94, 0xeb, 0x5d, 0xf1, 0xef, 0xd5, 0x3e, 0xea, 0x11, 0x44,
-+ 0xca, 0x78, 0x94, 0x08, 0x52, 0xf5, 0xec, 0x97, 0x27, 0x90, 0x4b, 0x36,
-+ 0x6e, 0xde, 0x4f, 0x5e, 0x2d, 0x33, 0x1f, 0xad, 0x5f, 0xc2, 0x82, 0xea,
-+ 0x2c, 0x47, 0xe9, 0x23, 0x14, 0x27, 0x71, 0xc3, 0xdd, 0x75, 0xa8, 0x73,
-+ 0x57, 0x48, 0x7d, 0xef, 0x99, 0xe5, 0xf1, 0x8e, 0x9d, 0x9e, 0xd6, 0x23,
-+ 0xc1, 0x75, 0xd0, 0x28, 0x88, 0xc5, 0x1f, 0x82, 0xc0, 0x7a, 0x80, 0xd5,
-+ 0x47, 0x16, 0xb3, 0xc3, 0xc2, 0xbd, 0xbe, 0x2e, 0x9f, 0x0a, 0x9b, 0xba,
-+ 0xae, 0xbe, 0xb4, 0xd5, 0x29, 0x36, 0x87, 0x64, 0x06, 0xf5, 0xc0, 0x0e,
-+ 0x8e, 0x4b, 0xbd, 0x0a, 0x5e, 0xc0, 0x57, 0x97, 0xe6, 0x20, 0x7c, 0x5a,
-+ 0xb6, 0xc8, 0x8f, 0x1a, 0x68, 0x84, 0x21, 0xbd, 0x05, 0xa1, 0x14, 0xf4,
-+ 0xd7, 0xde, 0x2a, 0xc2, 0x41, 0xfa, 0x0e, 0x8b, 0xed, 0xff, 0x47, 0xf7,
-+ 0x62, 0xdd, 0xcb, 0xea, 0xa9, 0x10, 0x04, 0xf8, 0xd3, 0x1e, 0x85, 0x09,
-+ 0x5c, 0x81, 0x05, 0x49, 0x94, 0xad, 0x38, 0x26, 0xe3, 0x44, 0xba, 0x96,
-+ 0x04, 0x08, 0x10, 0xfc, 0x0b, 0x2a, 0xd1, 0xde, 0x48, 0xcf, 0xad, 0xe0,
-+ 0x02, 0xc6, 0x2e, 0x5a, 0x49, 0xa0, 0x73, 0x1a, 0xb3, 0x83, 0x44, 0xbc,
-+ 0x16, 0x36, 0xdf, 0x16, 0xbf, 0x60, 0x7d, 0x56, 0x85, 0x5e, 0x56, 0xd6,
-+ 0x84, 0x00, 0x3c, 0x71, 0x8e, 0x4b, 0xad, 0x9e, 0x5a, 0x09, 0x99, 0x79,
-+ 0xfc, 0xdd, 0xee, 0xb1, 0xc4, 0xa7, 0x77, 0x6c, 0xd3, 0x7a, 0x34, 0x17,
-+ 0xcb, 0x0e, 0x18, 0x4e, 0x29, 0xef, 0x9b, 0xc0, 0xe8, 0x74, 0x75, 0xba,
-+ 0x66, 0x3b, 0xe0, 0x9e, 0x00, 0xab, 0x56, 0x2e, 0xb7, 0xc0, 0xf7, 0x16,
-+ 0x5f, 0x96, 0x9a, 0x9b, 0x42, 0x41, 0x41, 0x98, 0xcc, 0xf1, 0xbf, 0xf2,
-+ 0xa2, 0xc8, 0xd6, 0x89, 0xa4, 0x14, 0xec, 0xe7, 0x66, 0x29, 0x27, 0x66,
-+ 0x56, 0x89, 0xe9, 0x4d, 0xb9, 0x61, 0xeb, 0xae, 0xc5, 0x61, 0x5c, 0xbc,
-+ 0x1a, 0x78, 0x95, 0xc6, 0x85, 0x1a, 0xc9, 0x61, 0x43, 0x2f, 0xf1, 0x11,
-+ 0x8d, 0x46, 0x07, 0xd3, 0x2e, 0xf9, 0xdc, 0x73, 0x2d, 0x51, 0x33, 0x3b,
-+ 0xe4, 0xb4, 0xd0, 0xe3, 0x0d, 0xde, 0xa7, 0x84, 0xec, 0xa8, 0xbe, 0x47,
-+ 0xe7, 0x41, 0xbe, 0x9c, 0x19, 0x63, 0x1d, 0xc4, 0x70, 0xa5, 0x2e, 0xf4,
-+ 0xdc, 0x13, 0xa4, 0xf3, 0x63, 0x3f, 0xd4, 0x34, 0xd7, 0x87, 0xc1, 0x70,
-+ 0x97, 0x7b, 0x41, 0x7d, 0xf5, 0x98, 0xe1, 0xd0, 0xdd, 0xe5, 0x06, 0xbb,
-+ 0x71, 0xd6, 0xf0, 0xbc, 0x17, 0xec, 0x70, 0xe3, 0xb0, 0x3c, 0xdc, 0x19,
-+ 0x65, 0xcb, 0x36, 0x99, 0x3f, 0x63, 0x3b, 0x04, 0x72, 0xe5, 0x0d, 0x09,
-+ 0x23, 0xac, 0x6c, 0x66, 0xfd, 0xf1, 0xd3, 0xe6, 0x45, 0x9c, 0xc1, 0x21,
-+ 0xf0, 0xf5, 0xf9, 0x4d, 0x09, 0xe9, 0xdb, 0xcf, 0x5d, 0x69, 0x0e, 0x23,
-+ 0x23, 0x38, 0x38, 0xa0, 0xba, 0xcb, 0x7c, 0x63, 0x8d, 0x1b, 0x26, 0x50,
-+ 0xa4, 0x30, 0x8c, 0xd1, 0x71, 0xb6, 0x85, 0x51, 0x26, 0xd1, 0xda, 0x67,
-+ 0x2a, 0x6e, 0xd8, 0x5a, 0x8d, 0x78, 0xc2, 0x86, 0xfb, 0x56, 0xf4, 0xab,
-+ 0x3d, 0x21, 0x49, 0x75, 0x28, 0x04, 0x5c, 0x63, 0x26, 0x2c, 0x8a, 0x42,
-+ 0xaf, 0x2f, 0x98, 0x02, 0xc5, 0x3b, 0x7b, 0xb8, 0xbe, 0x28, 0xe7, 0x8f,
-+ 0xe0, 0xb5, 0xce, 0x45, 0xfb, 0xb7, 0xa1, 0xaf, 0x1a, 0x3b, 0x28, 0xa8,
-+ 0xd9, 0x4b, 0x78, 0x90, 0xe3, 0xc8, 0x82, 0xe3, 0x9b, 0xc9, 0x8e, 0x9f,
-+ 0x0a, 0xd7, 0x60, 0x25, 0xbf, 0x0d, 0xd2, 0xf0, 0x02, 0x98, 0xe7, 0x14,
-+ 0x1a, 0x22, 0x6b, 0x3d, 0x7c, 0xee, 0x41, 0x4f, 0x60, 0x4d, 0x1e, 0x0b,
-+ 0xa5, 0x4d, 0x11, 0xd5, 0xfe, 0x58, 0xbc, 0xce, 0xa6, 0xad, 0x77, 0xad,
-+ 0x2e, 0x8c, 0x1c, 0xaa, 0xcf, 0x32, 0x45, 0x90, 0x14, 0xb7, 0xb9, 0x10,
-+ 0x01, 0xb1, 0xef, 0xa8, 0xad, 0x17, 0x2a, 0x52, 0x3f, 0xb8, 0xe3, 0x65,
-+ 0xb5, 0x77, 0x12, 0x1b, 0xf9, 0xfd, 0x88, 0xa2, 0xc6, 0x0c, 0x21, 0xe8,
-+ 0x21, 0xd7, 0xb6, 0xac, 0xb4, 0x7a, 0x5a, 0x99, 0x5e, 0x40, 0xca, 0xce,
-+ 0xd5, 0xc2, 0x23, 0xb8, 0xfe, 0x6d, 0xe5, 0xe1, 0x8e, 0x9d, 0x2e, 0x58,
-+ 0x93, 0xae, 0xfe, 0xbb, 0x7a, 0xae, 0x7f, 0xf1, 0xa1, 0x46, 0x26, 0x0e,
-+ 0x2f, 0x11, 0x0e, 0x93, 0x95, 0x28, 0x21, 0x3a, 0x00, 0x25, 0xa3, 0x8e,
-+ 0xc7, 0x9a, 0xab, 0xc8, 0x61, 0xb2, 0x5e, 0xbc, 0x50, 0x9a, 0x46, 0x74,
-+ 0xc1, 0x32, 0xaa, 0xac, 0xb7, 0xe0, 0x14, 0x6f, 0x14, 0xef, 0xd1, 0x1c,
-+ 0xfc, 0xaf, 0x4c, 0xaa, 0x4f, 0x77, 0x5a, 0x71, 0x6c, 0xe3, 0x25, 0xe0,
-+ 0xa4, 0x35, 0xa4, 0xd3, 0x49, 0xd7, 0x20, 0xbc, 0xf1, 0x37, 0x45, 0x0a,
-+ 0xfc, 0x45, 0x04, 0x6f, 0xc1, 0xa1, 0xf8, 0x3a, 0x9d, 0x32, 0x97, 0x77,
-+ 0xa7, 0x08, 0x4e, 0x4a, 0xad, 0xae, 0x71, 0x22, 0xce, 0x97, 0x00, 0x59,
-+ 0x30, 0x52, 0x8e, 0xb3, 0xc7, 0xf7, 0xf1, 0x12, 0x9b, 0x37, 0x28, 0x87,
-+ 0xa3, 0x71, 0x15, 0x5a, 0x3b, 0xa2, 0x01, 0xa2, 0x5c, 0xbf, 0x1d, 0xcb,
-+ 0x64, 0xe7, 0xcd, 0xee, 0x09, 0x2c, 0x31, 0x41, 0xfb, 0x55, 0x50, 0xfe,
-+ 0x3d, 0x0d, 0xd8, 0x2e, 0x87, 0x0e, 0x57, 0x8b, 0x2b, 0x46, 0x50, 0x08,
-+ 0x18, 0x11, 0x3b, 0x8f, 0x65, 0x69, 0x77, 0x3c, 0x67, 0x73, 0x85, 0xb6,
-+ 0x9a, 0x42, 0xb7, 0x7d, 0xcb, 0xa7, 0xac, 0xff, 0xd9, 0x5f, 0xd4, 0x45,
-+ 0x2e, 0x23, 0xaa, 0xa1, 0xd3, 0x7e, 0x1d, 0xa2, 0x15, 0x1e, 0xa6, 0x58,
-+ 0xd4, 0x0a, 0x35, 0x96, 0xb2, 0x7a, 0xc9, 0xf8, 0x12, 0x9d, 0xc6, 0xcf,
-+ 0x06, 0x43, 0x77, 0x26, 0x24, 0xb5, 0x9f, 0x4f, 0x46, 0x12, 0x30, 0xdf,
-+ 0x47, 0x1c, 0xa2, 0x60, 0x87, 0xc3, 0x94, 0x2d, 0x5c, 0x66, 0x87, 0xdf,
-+ 0x60, 0x82, 0x83, 0x59, 0x35, 0xa3, 0xf8, 0x7c, 0xb7, 0x62, 0xb0, 0xc3,
-+ 0xb1, 0xd0, 0xdd, 0xa4, 0xa6, 0x53, 0x39, 0x65, 0xbe, 0xf1, 0xb7, 0xb8,
-+ 0x29, 0x2e, 0x25, 0x4c, 0x01, 0x4d, 0x09, 0x0f, 0xed, 0x85, 0x7c, 0x44,
-+ 0xc1, 0x83, 0x9c, 0x69, 0x4c, 0x0a, 0x64, 0xe3, 0xfa, 0xd9, 0x0a, 0x11,
-+ 0xf5, 0x34, 0x72, 0x2b, 0x6e, 0xe1, 0x57, 0x4f, 0x2e, 0x14, 0x9d, 0x55,
-+ 0xd7, 0x44, 0xde, 0x48, 0x87, 0x02, 0x4e, 0x08, 0x51, 0x14, 0x31, 0xc0,
-+ 0x62, 0x75, 0x0e, 0x16, 0xc7, 0x4a, 0xb9, 0xf3, 0x24, 0x2f, 0x2d, 0xb3,
-+ 0xff, 0xb1, 0x2a, 0x8d, 0x61, 0x07, 0xfa, 0xa2, 0x29, 0xd6, 0xf6, 0x37,
-+ 0x3b, 0x07, 0xf3, 0x6d, 0x39, 0x32, 0xb3, 0xbd, 0xb0, 0x4c, 0x19, 0xdd,
-+ 0x64, 0xea, 0xdd, 0x7f, 0x93, 0xc3, 0xc5, 0x64, 0xc3, 0x58, 0xa1, 0xc8,
-+ 0x1d, 0xcf, 0x1c, 0x9c, 0x31, 0xe5, 0xb0, 0x65, 0x68, 0xf9, 0x75, 0x44,
-+ 0xc1, 0x7d, 0xc1, 0x56, 0x98, 0xc5, 0xcb, 0x38, 0x98, 0x3a, 0x9a, 0xfc,
-+ 0x42, 0x78, 0x3f, 0xaa, 0x77, 0x3a, 0x52, 0xc9, 0xd8, 0x26, 0x06, 0x90,
-+ 0xbe, 0x9e, 0x31, 0x56, 0xaa, 0x5b, 0xc1, 0x50, 0x9d, 0xea, 0x3f, 0x69,
-+ 0x58, 0x76, 0x95, 0xcd, 0x6f, 0xf1, 0x72, 0xba, 0x83, 0xe6, 0xa6, 0xd8,
-+ 0xa7, 0xd6, 0xbb, 0xeb, 0xbb, 0xcd, 0xa3, 0x67, 0x27, 0x31, 0x98, 0x3f,
-+ 0x89, 0xbc, 0x58, 0x31, 0xdc, 0x37, 0xc3, 0xf3, 0xc5, 0xc5, 0x6f, 0xac,
-+ 0xc6, 0x97, 0xf3, 0xcb, 0x20, 0xbd, 0x5d, 0xba, 0xdb, 0xd7, 0x02, 0xe5,
-+ 0x48, 0x44, 0xac, 0x2f, 0x62, 0x69, 0x01, 0xfe, 0x15, 0x9d, 0xb9, 0x3d,
-+ 0xfd, 0x47, 0x73, 0xd8, 0xfe, 0x73, 0x56, 0x2b, 0x84, 0x6c, 0x1f, 0xc8,
-+ 0x56, 0xd1, 0x80, 0x27, 0x62, 0x84, 0x0e, 0xbc, 0x72, 0xd7, 0x98, 0x8b,
-+ 0xde, 0x75, 0xcb, 0xca, 0x70, 0xd3, 0x19, 0xd3, 0x2c, 0xe0, 0xcc, 0x02,
-+ 0x53, 0xbb, 0x2a, 0xd4, 0x55, 0x72, 0x3e, 0xe0, 0xc7, 0xf4, 0x73, 0x6c,
-+ 0xe6, 0xe6, 0x66, 0x5c, 0x5a, 0xca, 0x32, 0xa4, 0x81, 0xc5, 0x38, 0x39,
-+ 0xbc, 0x25, 0x91, 0x67, 0xb0, 0x13, 0xd0, 0x42, 0x33, 0x95, 0xee, 0xb9,
-+ 0xaa, 0xae, 0xe3, 0x20, 0x61, 0x49, 0xa7, 0xd5, 0x50, 0xd6, 0x7f, 0xc5,
-+ 0xfd, 0xfe, 0x4a, 0x8a, 0x5c, 0x35, 0xd2, 0x51, 0x0b, 0x66, 0x43, 0x79,
-+ 0xab, 0x8f, 0x72, 0x85, 0x5a, 0x2a, 0xf4, 0x7a, 0xbc, 0xe2, 0xa6, 0x32,
-+ 0x04, 0x8e, 0xaf, 0x89, 0xe5, 0xcb, 0x4a, 0x88, 0xde, 0xbc, 0x53, 0xa5,
-+ 0x95, 0x10, 0x3a, 0xcc, 0xe4, 0xf1, 0xcf, 0xf1, 0x8a, 0xcf, 0xf0, 0x7a,
-+ 0xfe, 0x1e, 0xb5, 0x71, 0x6a, 0xa1, 0xe4, 0x0b, 0x63, 0x13, 0x4c, 0x3a,
-+ 0x3a, 0xe9, 0x57, 0x9f, 0xa8, 0x7f, 0x51, 0x5b, 0xe0, 0x93, 0xc2, 0xd2,
-+ 0x9d, 0xb6, 0xd6, 0xb6, 0x5c, 0x93, 0x66, 0x1e, 0x00, 0x63, 0x6b, 0x59,
-+ 0x27, 0x04, 0xd0, 0x93, 0xcc, 0x67, 0x16, 0xc2, 0x34, 0x2e, 0xb1, 0x85,
-+ 0x3d, 0x48, 0xc8, 0x5c, 0x63, 0xac, 0x8a, 0x28, 0x54, 0x46, 0x2c, 0x7b,
-+ 0x77, 0xe7, 0xe3, 0xbd, 0x1e, 0xac, 0x5b, 0xca, 0x28, 0xff, 0xaa, 0x00,
-+ 0xb5, 0xd3, 0x49, 0xf8, 0xa5, 0x47, 0xad, 0x87, 0x5b, 0x96, 0xa8, 0xc2,
-+ 0xb2, 0x91, 0x0c, 0x93, 0x01, 0x30, 0x9a, 0x3f, 0x91, 0x38, 0xa5, 0x69,
-+ 0x31, 0x11, 0xf5, 0x5b, 0x3c, 0x00, 0x9c, 0xa9, 0x47, 0xc3, 0x9d, 0xfc,
-+ 0x82, 0xd9, 0x8e, 0xb1, 0xca, 0xa4, 0xa9, 0xcb, 0xe8, 0x85, 0xf7, 0x86,
-+ 0xfa, 0x86, 0xe5, 0x5b, 0xe0, 0x62, 0x22, 0x2f, 0x8b, 0xa9, 0x0a, 0x97,
-+ 0x40, 0x73, 0x32, 0x6b, 0x31, 0x21, 0x2a, 0xec, 0xe0, 0xa3, 0x4a, 0x60,
-+ };
-+ static const unsigned char ml_dsa_87_priv_key[] = {
-+ 0x97, 0x92, 0xbc, 0xec, 0x2f, 0x24, 0x30, 0x68, 0x6a, 0x82, 0xfc, 0xcf,
-+ 0x3c, 0x2f, 0x5f, 0xf6, 0x65, 0xe7, 0x71, 0xd7, 0xab, 0x41, 0xb9, 0x02,
-+ 0x58, 0xcf, 0xa7, 0xe9, 0x0e, 0xc9, 0x71, 0x24, 0xd8, 0xe9, 0xee, 0x4e,
-+ 0x90, 0xa1, 0x6c, 0x60, 0x2f, 0x5e, 0xc9, 0xbc, 0x38, 0x51, 0x7d, 0xc3,
-+ 0x0e, 0x32, 0x9d, 0x5a, 0xb2, 0x76, 0x73, 0xbd, 0x85, 0xf4, 0xc9, 0xb0,
-+ 0x30, 0x0f, 0x77, 0x63, 0x89, 0x88, 0x67, 0x50, 0xb5, 0x7c, 0x24, 0xdb,
-+ 0x3f, 0xc0, 0x12, 0xe6, 0x1e, 0xde, 0x59, 0x75, 0x33, 0x37, 0x37, 0x4f,
-+ 0xa7, 0x12, 0x49, 0x91, 0x54, 0x9a, 0xf2, 0x43, 0x49, 0x6d, 0x06, 0x37,
-+ 0xcb, 0x3b, 0xe0, 0x5a, 0x59, 0x48, 0x23, 0x5b, 0xf7, 0x98, 0x75, 0xf8,
-+ 0x96, 0xd8, 0xfe, 0x0c, 0xab, 0x30, 0xc8, 0x49, 0x48, 0xdb, 0x4d, 0x63,
-+ 0x15, 0xaa, 0xaf, 0x16, 0x0a, 0xc6, 0x24, 0x36, 0x64, 0x22, 0x01, 0x48,
-+ 0x16, 0x11, 0x09, 0x11, 0x2c, 0x94, 0x02, 0x89, 0x22, 0x45, 0x2c, 0x62,
-+ 0xb8, 0x45, 0x00, 0x45, 0x2a, 0x08, 0x96, 0x70, 0x90, 0x12, 0x6e, 0x14,
-+ 0x93, 0x70, 0xd4, 0x46, 0x10, 0x84, 0x44, 0x51, 0x58, 0x96, 0x91, 0x0c,
-+ 0xa9, 0x29, 0x82, 0xb2, 0x41, 0xc9, 0x08, 0x71, 0xc4, 0x28, 0x68, 0x04,
-+ 0x96, 0x89, 0x48, 0x40, 0x85, 0x9b, 0x22, 0x6d, 0x1c, 0x28, 0x64, 0x59,
-+ 0x12, 0x41, 0x9c, 0xb8, 0x91, 0x84, 0x04, 0x89, 0x44, 0x90, 0x05, 0xcb,
-+ 0x34, 0x62, 0xa0, 0x86, 0x90, 0x40, 0x26, 0x92, 0x20, 0x99, 0x29, 0x13,
-+ 0x05, 0x69, 0x5c, 0x34, 0x68, 0xa4, 0x32, 0x8e, 0x19, 0x26, 0x92, 0x59,
-+ 0x46, 0x10, 0x09, 0xa4, 0x49, 0x23, 0x42, 0x4d, 0x12, 0x36, 0x61, 0x58,
-+ 0x10, 0x65, 0x01, 0x28, 0x90, 0x1a, 0x33, 0x4c, 0x99, 0x86, 0x31, 0xd3,
-+ 0xa2, 0x49, 0x09, 0x82, 0x25, 0x43, 0x14, 0x28, 0xc0, 0x38, 0x81, 0x03,
-+ 0x15, 0x4d, 0x5b, 0x28, 0x86, 0x08, 0x87, 0x48, 0x23, 0x31, 0x52, 0x94,
-+ 0x22, 0x25, 0xc3, 0xc0, 0x4d, 0xa4, 0x98, 0x21, 0x98, 0x40, 0x20, 0xd1,
-+ 0x42, 0x86, 0xcb, 0x40, 0x70, 0x5b, 0xb0, 0x71, 0x9c, 0x96, 0x2c, 0xc1,
-+ 0x12, 0x06, 0x53, 0x46, 0x09, 0x0c, 0x45, 0x02, 0x14, 0x46, 0x6e, 0x91,
-+ 0xb4, 0x21, 0x54, 0xb0, 0x8c, 0xe4, 0x46, 0x42, 0x9a, 0x20, 0x8c, 0x01,
-+ 0x21, 0x25, 0x13, 0x41, 0x05, 0x5a, 0x40, 0x22, 0x13, 0xc9, 0x0c, 0xa0,
-+ 0x18, 0x40, 0x52, 0xc2, 0x30, 0xcb, 0x34, 0x2c, 0x4b, 0xc8, 0x68, 0x1b,
-+ 0xa4, 0x60, 0x49, 0x84, 0x84, 0x63, 0x30, 0x29, 0x4a, 0xa0, 0x69, 0x5b,
-+ 0x80, 0x04, 0xd2, 0x38, 0x0a, 0x14, 0x26, 0x4c, 0xe2, 0xb2, 0x44, 0x8b,
-+ 0xa2, 0x11, 0x24, 0x46, 0x49, 0xc4, 0x14, 0x52, 0x0b, 0x42, 0x71, 0x03,
-+ 0xb2, 0x10, 0x92, 0x28, 0x80, 0x01, 0x24, 0x88, 0xe3, 0x08, 0x11, 0x0a,
-+ 0x05, 0x28, 0x19, 0xc4, 0x81, 0x00, 0x20, 0x22, 0xdc, 0x44, 0x68, 0x42,
-+ 0x12, 0x22, 0x44, 0x00, 0x2a, 0xc9, 0x26, 0x6a, 0x0c, 0x87, 0x31, 0xe0,
-+ 0xc0, 0x44, 0x99, 0x14, 0x84, 0x18, 0x36, 0x0d, 0x11, 0x37, 0x42, 0x22,
-+ 0x18, 0x8c, 0x63, 0xb2, 0x91, 0x0c, 0x98, 0x08, 0xa1, 0xa0, 0x01, 0x08,
-+ 0x92, 0x44, 0x04, 0x13, 0x24, 0x5c, 0x98, 0x71, 0x82, 0x84, 0x71, 0x84,
-+ 0x32, 0x52, 0x51, 0xb0, 0x31, 0x9c, 0x42, 0x2e, 0x1a, 0xa8, 0x28, 0x02,
-+ 0x08, 0x91, 0x01, 0xc0, 0x89, 0x0b, 0xc7, 0x05, 0x8a, 0x24, 0x65, 0x22,
-+ 0xc2, 0x64, 0x4c, 0x88, 0x91, 0x5c, 0x82, 0x68, 0x13, 0xa5, 0x64, 0x50,
-+ 0x20, 0x86, 0x21, 0x04, 0x02, 0x91, 0x94, 0x44, 0x48, 0x22, 0x30, 0x22,
-+ 0x39, 0x4a, 0x02, 0x98, 0x84, 0x09, 0xa2, 0x88, 0x19, 0x19, 0x29, 0x44,
-+ 0x48, 0x8c, 0x22, 0x95, 0x0c, 0xa1, 0x04, 0x72, 0x04, 0x87, 0x70, 0x12,
-+ 0x21, 0x10, 0x42, 0x06, 0x84, 0x1b, 0x49, 0x85, 0x89, 0x06, 0x4a, 0xd3,
-+ 0x36, 0x08, 0xdb, 0xc0, 0x40, 0x58, 0xb6, 0x51, 0x0c, 0xa7, 0x09, 0x8c,
-+ 0x24, 0x61, 0x99, 0x90, 0x64, 0x8c, 0xc2, 0x90, 0x5b, 0x24, 0x90, 0x10,
-+ 0xa3, 0x49, 0x03, 0x25, 0x61, 0x43, 0x32, 0x8a, 0x11, 0x98, 0x44, 0xc8,
-+ 0xb2, 0x20, 0x04, 0x38, 0x41, 0x10, 0x47, 0x2c, 0x19, 0xc6, 0x44, 0x1c,
-+ 0x25, 0x2c, 0x04, 0x88, 0x30, 0xd9, 0x46, 0x69, 0x9b, 0x20, 0x00, 0x1b,
-+ 0x46, 0x82, 0x5a, 0xa4, 0x80, 0x5b, 0xa0, 0x49, 0x18, 0x90, 0x25, 0x00,
-+ 0x26, 0x80, 0x0b, 0xc2, 0x31, 0x5a, 0x40, 0x72, 0x54, 0xc6, 0x20, 0xc1,
-+ 0xb0, 0x31, 0x24, 0xb1, 0x4d, 0x10, 0x95, 0x28, 0x14, 0x00, 0x0a, 0xa0,
-+ 0xc8, 0x4d, 0x54, 0xa2, 0x88, 0x23, 0x98, 0x81, 0x60, 0x90, 0x04, 0x02,
-+ 0x16, 0x2c, 0x13, 0x21, 0x40, 0x91, 0x86, 0x8d, 0x08, 0xc2, 0x91, 0x91,
-+ 0x14, 0x26, 0xd0, 0xb4, 0x0c, 0x09, 0xc6, 0x60, 0x51, 0x44, 0x2e, 0x04,
-+ 0x11, 0x26, 0x00, 0x29, 0x11, 0x93, 0xc2, 0x08, 0x63, 0xa4, 0x31, 0x22,
-+ 0x00, 0x28, 0xc1, 0x14, 0x08, 0x0c, 0x40, 0x2c, 0x41, 0x14, 0x06, 0x9c,
-+ 0x20, 0x72, 0x54, 0x22, 0x06, 0x8b, 0x08, 0x4d, 0xa1, 0x48, 0x69, 0x10,
-+ 0x30, 0x41, 0x1c, 0x28, 0x49, 0x44, 0x18, 0x8e, 0xcc, 0x96, 0x48, 0xd9,
-+ 0x42, 0x50, 0x1b, 0x06, 0x49, 0x0c, 0x45, 0x88, 0x23, 0x04, 0x0d, 0x20,
-+ 0x30, 0x2e, 0x23, 0x85, 0x2c, 0x14, 0x07, 0x30, 0x40, 0xb6, 0x85, 0x4c,
-+ 0xc0, 0x20, 0x44, 0x86, 0x20, 0x19, 0x00, 0x6c, 0x54, 0x02, 0x48, 0xcc,
-+ 0x88, 0x6c, 0x59, 0x06, 0x32, 0x49, 0x14, 0x84, 0x04, 0xc7, 0x50, 0x13,
-+ 0x49, 0x28, 0xe4, 0x06, 0x09, 0xd3, 0xc6, 0x10, 0xc8, 0x28, 0x4c, 0x23,
-+ 0x39, 0x44, 0x52, 0xa4, 0x64, 0xcc, 0xa8, 0x49, 0x44, 0x38, 0x32, 0x0a,
-+ 0x89, 0x84, 0x00, 0x34, 0x2c, 0x22, 0x85, 0x8d, 0x10, 0x31, 0x09, 0x09,
-+ 0x32, 0x65, 0x1c, 0x89, 0x8c, 0x40, 0x40, 0x29, 0x21, 0x85, 0x00, 0x09,
-+ 0xa1, 0x6d, 0x84, 0xc0, 0x64, 0xe2, 0x02, 0x2d, 0x48, 0x04, 0x40, 0x12,
-+ 0x09, 0x8e, 0xe0, 0x42, 0x2e, 0x93, 0x44, 0x08, 0x12, 0x10, 0x6a, 0x01,
-+ 0x84, 0x05, 0x92, 0x30, 0x8a, 0xcb, 0x34, 0x8e, 0xa2, 0x26, 0x2e, 0x5c,
-+ 0x86, 0x11, 0x0b, 0x35, 0x08, 0x18, 0x10, 0x00, 0x02, 0x34, 0x26, 0x24,
-+ 0x23, 0x89, 0xd1, 0x84, 0x00, 0x24, 0x46, 0x60, 0x13, 0xb2, 0x49, 0x24,
-+ 0x28, 0x46, 0x18, 0x02, 0x71, 0xa0, 0x38, 0x90, 0x89, 0x14, 0x44, 0xd3,
-+ 0x96, 0x2d, 0xa3, 0x18, 0x40, 0x23, 0x27, 0x21, 0xc0, 0x18, 0x50, 0x43,
-+ 0xc8, 0x04, 0x41, 0x42, 0x8d, 0x5c, 0x26, 0x41, 0x44, 0xa2, 0x6d, 0x48,
-+ 0x12, 0x0e, 0x40, 0x32, 0x25, 0x0b, 0x14, 0x82, 0x0a, 0x48, 0x2e, 0xcb,
-+ 0x82, 0x88, 0x03, 0xa3, 0x60, 0x1b, 0x25, 0x26, 0x8c, 0xb8, 0x20, 0x24,
-+ 0xb0, 0x85, 0x98, 0x04, 0x21, 0x08, 0xa7, 0x2c, 0x83, 0x38, 0x64, 0x54,
-+ 0x32, 0x89, 0x01, 0x04, 0x01, 0x23, 0x49, 0x84, 0x02, 0x95, 0x69, 0xd1,
-+ 0xa4, 0x4d, 0x13, 0xa4, 0x0c, 0x91, 0x46, 0x0d, 0x61, 0x94, 0x80, 0x90,
-+ 0x38, 0x45, 0x5c, 0xc6, 0x50, 0x01, 0x17, 0x20, 0x53, 0xc6, 0x28, 0x9b,
-+ 0x18, 0x10, 0x41, 0x12, 0x68, 0x90, 0x12, 0x21, 0xc0, 0x10, 0x84, 0x42,
-+ 0x16, 0x92, 0x53, 0x82, 0x29, 0x81, 0x26, 0x49, 0xd8, 0xa4, 0x05, 0x9a,
-+ 0x26, 0x24, 0x24, 0x03, 0x29, 0xe0, 0x40, 0x26, 0xd2, 0x02, 0x48, 0x11,
-+ 0x24, 0x68, 0x11, 0x99, 0x89, 0x98, 0x14, 0x85, 0xc9, 0x20, 0x0d, 0x50,
-+ 0x12, 0x8c, 0x1c, 0x08, 0x10, 0x02, 0x10, 0x00, 0x00, 0x95, 0x28, 0xc1,
-+ 0x28, 0x90, 0x59, 0xb4, 0x85, 0xd3, 0x14, 0x65, 0x0a, 0x40, 0x6e, 0x11,
-+ 0x29, 0x65, 0x18, 0xc2, 0x4c, 0x21, 0x34, 0x65, 0xd8, 0x30, 0x69, 0x10,
-+ 0x30, 0x52, 0x19, 0x31, 0x66, 0x8c, 0x18, 0x8a, 0xc8, 0xc0, 0x08, 0x4c,
-+ 0x98, 0x30, 0xa3, 0xa6, 0x20, 0x41, 0x16, 0x22, 0x18, 0x05, 0x2e, 0x22,
-+ 0x25, 0x2a, 0x64, 0xb8, 0x25, 0x0a, 0xb3, 0x01, 0x63, 0x20, 0x84, 0x09,
-+ 0x80, 0x09, 0x19, 0x28, 0x0e, 0x02, 0x11, 0x01, 0xa3, 0x94, 0x11, 0xe3,
-+ 0x98, 0x6c, 0x58, 0x20, 0x21, 0x09, 0x41, 0x10, 0x60, 0x36, 0x22, 0x08,
-+ 0x06, 0x71, 0x12, 0xc2, 0x85, 0x5a, 0xa0, 0x85, 0xc0, 0xc6, 0x84, 0x5c,
-+ 0x38, 0x06, 0xcb, 0xb6, 0x69, 0x14, 0x84, 0x84, 0x53, 0x22, 0x82, 0xa1,
-+ 0xa6, 0x40, 0xcc, 0x86, 0x00, 0xc4, 0x26, 0x22, 0xa0, 0xa8, 0x08, 0x98,
-+ 0x34, 0x72, 0xd4, 0x20, 0x41, 0x43, 0xc4, 0x90, 0x48, 0x16, 0x68, 0x1b,
-+ 0x16, 0x52, 0x1a, 0x37, 0x02, 0x50, 0x20, 0x42, 0x48, 0x48, 0x8a, 0x20,
-+ 0x11, 0x41, 0xe2, 0x00, 0x6c, 0xc0, 0xc2, 0x0c, 0x14, 0x06, 0x49, 0x11,
-+ 0x31, 0x4d, 0x19, 0x06, 0x0a, 0x89, 0x46, 0x09, 0x1b, 0x81, 0x65, 0x44,
-+ 0xc8, 0x00, 0x82, 0x06, 0x70, 0x00, 0x16, 0x72, 0xcc, 0x24, 0x50, 0x8a,
-+ 0x42, 0x89, 0x9c, 0x96, 0x90, 0x64, 0x28, 0x70, 0x92, 0xb2, 0x68, 0x98,
-+ 0x26, 0x62, 0x61, 0x94, 0x40, 0xc1, 0x16, 0x89, 0xd8, 0x42, 0x64, 0x1a,
-+ 0x21, 0x4e, 0x62, 0x90, 0x64, 0x21, 0xc8, 0x24, 0x8b, 0x28, 0x6d, 0x5c,
-+ 0x42, 0x92, 0xa0, 0xc6, 0x4d, 0x0c, 0x85, 0x80, 0xcc, 0x88, 0x4d, 0xd4,
-+ 0x42, 0x8d, 0x42, 0x34, 0x8a, 0x0b, 0x04, 0x51, 0xc3, 0x26, 0x86, 0x24,
-+ 0x25, 0x81, 0x12, 0x35, 0x06, 0xa0, 0x44, 0x04, 0xc8, 0x94, 0x81, 0x5b,
-+ 0xb4, 0x31, 0x1c, 0x08, 0x06, 0x5c, 0x24, 0x08, 0x03, 0x27, 0x6a, 0x20,
-+ 0xc2, 0x25, 0xe1, 0x80, 0x90, 0x19, 0xb4, 0x6d, 0xa3, 0x46, 0x0c, 0x4b,
-+ 0x18, 0x60, 0x50, 0xc6, 0x2c, 0x1b, 0x92, 0x2d, 0x11, 0x15, 0x04, 0xa2,
-+ 0x00, 0x04, 0x21, 0x48, 0x2e, 0xd8, 0x16, 0x06, 0xd2, 0x10, 0x8a, 0x83,
-+ 0xa2, 0x25, 0x08, 0x31, 0x0d, 0x09, 0x38, 0x51, 0xd9, 0x48, 0x49, 0x0b,
-+ 0x16, 0x4c, 0x23, 0x32, 0x25, 0x19, 0x19, 0x02, 0x4a, 0x44, 0x09, 0xd1,
-+ 0xb2, 0x21, 0x0b, 0x83, 0x2c, 0x23, 0x25, 0x85, 0x93, 0x16, 0x85, 0x44,
-+ 0xa0, 0x44, 0x1b, 0x83, 0x50, 0x02, 0x22, 0x72, 0x4b, 0x04, 0x80, 0x9b,
-+ 0x14, 0x65, 0x21, 0x93, 0x60, 0x18, 0x13, 0x0a, 0xd9, 0x46, 0x0d, 0x22,
-+ 0x45, 0x61, 0xc8, 0xb4, 0x40, 0xa1, 0x42, 0x2d, 0x02, 0xb8, 0x09, 0x00,
-+ 0x14, 0x44, 0x9b, 0xb6, 0x11, 0x0b, 0x97, 0x8c, 0x40, 0x10, 0x4a, 0x82,
-+ 0x14, 0x6a, 0xda, 0x90, 0x05, 0x1c, 0x02, 0x8e, 0x0c, 0x19, 0x72, 0xa3,
-+ 0xb4, 0x8d, 0x24, 0x30, 0x50, 0x11, 0x87, 0x09, 0x64, 0xc6, 0x28, 0xe4,
-+ 0x18, 0x92, 0x98, 0xb4, 0x6c, 0x61, 0x16, 0x51, 0x40, 0x46, 0x0e, 0x1c,
-+ 0x32, 0x48, 0xda, 0x20, 0x51, 0x88, 0x36, 0x8a, 0x23, 0xb1, 0x21, 0x82,
-+ 0x90, 0x28, 0x1a, 0x15, 0x32, 0xe2, 0x18, 0x61, 0x92, 0x04, 0x8e, 0x13,
-+ 0xb6, 0x90, 0x13, 0x13, 0x68, 0xc9, 0x84, 0x68, 0x4c, 0x40, 0x6d, 0x0b,
-+ 0x33, 0x00, 0x81, 0x46, 0x4d, 0xd2, 0x38, 0x0c, 0x04, 0x96, 0x81, 0xa4,
-+ 0x88, 0x50, 0x02, 0x90, 0x85, 0x22, 0xb0, 0x04, 0xd3, 0xa4, 0x71, 0xd2,
-+ 0x80, 0x10, 0xca, 0x96, 0x40, 0x51, 0xa6, 0x41, 0xa4, 0x84, 0x28, 0xe0,
-+ 0x08, 0x52, 0x0b, 0x30, 0x8c, 0xd2, 0x38, 0x0a, 0x0c, 0x29, 0x51, 0xc3,
-+ 0x82, 0x09, 0xca, 0x20, 0x91, 0xd8, 0x36, 0x92, 0xa3, 0xa6, 0x28, 0x92,
-+ 0x42, 0x22, 0xa2, 0x16, 0x01, 0x1a, 0x34, 0x86, 0x37, 0xd9, 0xa6, 0x59,
-+ 0x16, 0x98, 0x81, 0xec, 0x21, 0xcf, 0x48, 0x11, 0x86, 0x9d, 0x1d, 0x7f,
-+ 0x13, 0x9f, 0x05, 0x37, 0xe9, 0x6f, 0x11, 0x84, 0x58, 0x54, 0x05, 0xfd,
-+ 0x17, 0x80, 0x8a, 0xf1, 0xe0, 0x62, 0x39, 0xd3, 0xb3, 0x4e, 0x5a, 0xca,
-+ 0x8b, 0xf1, 0x36, 0x96, 0x77, 0xb4, 0x47, 0xac, 0x71, 0x8a, 0xc4, 0x7d,
-+ 0x85, 0x0c, 0x4d, 0x77, 0xb0, 0xbe, 0x31, 0xdc, 0x9f, 0x50, 0x8e, 0x39,
-+ 0x78, 0xf2, 0x42, 0x74, 0xab, 0x01, 0x85, 0xf7, 0x27, 0xab, 0xdf, 0xf5,
-+ 0x9f, 0x44, 0x90, 0x37, 0x1b, 0xf0, 0x46, 0x10, 0xe3, 0x64, 0xe6, 0x4e,
-+ 0xc8, 0x75, 0xef, 0x9d, 0x20, 0xdc, 0x94, 0x07, 0x7e, 0x1e, 0x16, 0x63,
-+ 0x27, 0xa8, 0x79, 0xb8, 0xab, 0x51, 0x61, 0x60, 0xb2, 0xa3, 0xf7, 0x74,
-+ 0x37, 0xb9, 0xb3, 0xcc, 0x7d, 0x17, 0xae, 0xad, 0xdc, 0x84, 0xdb, 0x62,
-+ 0x74, 0x6a, 0x35, 0xac, 0x09, 0x6f, 0x78, 0x2f, 0x62, 0xa7, 0xf0, 0x1a,
-+ 0xa6, 0xd6, 0x69, 0x3d, 0xee, 0xc9, 0x0b, 0x23, 0xc6, 0x69, 0x85, 0xa0,
-+ 0x23, 0x07, 0xe0, 0xa1, 0xca, 0xe5, 0x98, 0xa6, 0x73, 0x24, 0xdb, 0xa0,
-+ 0xf5, 0x2f, 0x22, 0x43, 0x22, 0x75, 0xe9, 0x32, 0x57, 0x06, 0x5c, 0x3b,
-+ 0x7e, 0x5e, 0x1c, 0xfe, 0x1d, 0xfd, 0x4d, 0x0d, 0xf0, 0x86, 0xdf, 0x21,
-+ 0x24, 0x34, 0x14, 0xa2, 0xd2, 0x7e, 0x20, 0x23, 0x0a, 0x82, 0x9b, 0xe4,
-+ 0xeb, 0x4c, 0x82, 0xc1, 0x6d, 0x35, 0xf7, 0x8b, 0x0e, 0x5e, 0x19, 0x83,
-+ 0x32, 0xe0, 0x00, 0x74, 0xbb, 0x64, 0x61, 0x2f, 0xab, 0x17, 0xd4, 0xc8,
-+ 0x97, 0x1c, 0xb6, 0x8e, 0x5e, 0xda, 0xb0, 0x36, 0x9f, 0x11, 0x57, 0xb3,
-+ 0x46, 0x9a, 0xbd, 0x83, 0x84, 0xe2, 0xd9, 0x55, 0x3f, 0x1b, 0x78, 0xe7,
-+ 0x86, 0xe1, 0xee, 0x9d, 0x0b, 0x98, 0xd3, 0x9f, 0x83, 0xcc, 0xec, 0xf3,
-+ 0x7d, 0x1e, 0xbd, 0x3a, 0x9d, 0x63, 0xae, 0xc7, 0x66, 0x16, 0x4a, 0x10,
-+ 0x17, 0x1a, 0x4f, 0xd8, 0xc6, 0x3d, 0xaf, 0x18, 0x2c, 0x42, 0x12, 0x58,
-+ 0xc5, 0xf5, 0x29, 0xaa, 0x55, 0xcb, 0x7e, 0xba, 0xe2, 0xe1, 0x65, 0x23,
-+ 0x15, 0xe1, 0xf7, 0x1e, 0x8a, 0x74, 0x13, 0x14, 0x10, 0xd0, 0x32, 0x47,
-+ 0xed, 0xe1, 0x1d, 0x34, 0xdb, 0x91, 0xf6, 0xf0, 0x8a, 0xa2, 0x47, 0x8f,
-+ 0xd7, 0x89, 0x67, 0x9c, 0x04, 0x94, 0x9f, 0x71, 0xbc, 0x01, 0x71, 0xe0,
-+ 0x7e, 0x3a, 0x8b, 0xb5, 0x75, 0x3d, 0xbb, 0xda, 0xa4, 0x11, 0xa6, 0x35,
-+ 0x0a, 0xb4, 0x6e, 0xef, 0xbf, 0x86, 0xfc, 0x55, 0x1c, 0x29, 0xef, 0xe4,
-+ 0xcd, 0xd7, 0x66, 0x1d, 0x5c, 0xf6, 0xc3, 0xdb, 0x22, 0xd0, 0xce, 0xdd,
-+ 0xe5, 0x99, 0x85, 0x44, 0x59, 0xd9, 0x7f, 0x20, 0xdf, 0x74, 0x55, 0xbd,
-+ 0xf3, 0x56, 0xa1, 0x98, 0xd0, 0xf7, 0xeb, 0x6d, 0x34, 0x11, 0x1f, 0xc9,
-+ 0x40, 0xb2, 0x5c, 0x05, 0x43, 0xb7, 0x88, 0xed, 0xda, 0x9d, 0x26, 0x81,
-+ 0x0e, 0xac, 0x3d, 0x6c, 0xc9, 0xc5, 0x13, 0x27, 0xc2, 0xcf, 0x83, 0xe8,
-+ 0x87, 0xd4, 0x08, 0x9e, 0x19, 0x69, 0x5e, 0x11, 0xad, 0xd8, 0x37, 0xf6,
-+ 0xf4, 0x40, 0xcc, 0x36, 0x0f, 0x93, 0xf3, 0x2f, 0xee, 0x8a, 0x96, 0x63,
-+ 0x71, 0x2c, 0x6b, 0xbd, 0x38, 0xc8, 0x4a, 0xb7, 0xb5, 0x48, 0x23, 0xec,
-+ 0x36, 0x3e, 0xb7, 0xe4, 0x2e, 0xb5, 0x9f, 0xc1, 0xfc, 0xe6, 0x0f, 0xbd,
-+ 0x55, 0x30, 0x7b, 0x3e, 0xc8, 0x5f, 0xd9, 0xda, 0xf3, 0x20, 0x6d, 0x7b,
-+ 0x4b, 0x39, 0x17, 0xf1, 0xc8, 0xb7, 0xa9, 0x2e, 0x3c, 0x67, 0xd8, 0x98,
-+ 0x80, 0xfd, 0xf2, 0xe4, 0x7f, 0x5a, 0x0c, 0x99, 0x45, 0x95, 0xdb, 0x17,
-+ 0x0a, 0xf4, 0x1b, 0xab, 0xf5, 0xa2, 0x5b, 0x4d, 0xc1, 0xc4, 0x2d, 0xd6,
-+ 0xa9, 0xdb, 0x27, 0x1e, 0x76, 0x4d, 0xe2, 0xfb, 0x01, 0x5a, 0x49, 0xa8,
-+ 0x50, 0xc7, 0x91, 0x9b, 0xe4, 0x70, 0x06, 0xa3, 0x36, 0xe2, 0xe3, 0x25,
-+ 0xfd, 0xe5, 0x3a, 0xc5, 0x99, 0x55, 0x4d, 0x0a, 0x7d, 0xe4, 0xef, 0x45,
-+ 0xec, 0x40, 0xc3, 0x9d, 0x6b, 0xaf, 0xf3, 0x11, 0xbe, 0xee, 0x75, 0xd8,
-+ 0x9e, 0x02, 0xad, 0x31, 0xf4, 0xbe, 0x4b, 0xd2, 0x0a, 0xe9, 0x19, 0x4f,
-+ 0x5e, 0xdd, 0xda, 0xa6, 0x65, 0x07, 0x76, 0x11, 0x6e, 0x9f, 0x27, 0x0f,
-+ 0x77, 0x71, 0x4a, 0xd7, 0xa8, 0xe8, 0x9a, 0xce, 0xf7, 0x4b, 0x7f, 0xf7,
-+ 0xd8, 0xdb, 0xec, 0x27, 0xf8, 0x02, 0x0a, 0x98, 0x52, 0x47, 0xe2, 0xcd,
-+ 0xac, 0xef, 0x48, 0x94, 0xa4, 0xd6, 0x8b, 0xa3, 0x7c, 0xa9, 0x12, 0xd6,
-+ 0xbe, 0x73, 0x50, 0x1c, 0x99, 0x51, 0x81, 0xe5, 0xb7, 0x77, 0x23, 0x35,
-+ 0x0b, 0x36, 0x31, 0xda, 0x37, 0x00, 0xe1, 0x3f, 0xd3, 0x66, 0xe1, 0x31,
-+ 0xbf, 0x06, 0xb3, 0x6e, 0xb6, 0xb0, 0x34, 0x50, 0x93, 0x20, 0x9f, 0x0a,
-+ 0x7b, 0xef, 0xfa, 0xe1, 0xfd, 0xd8, 0x75, 0xb0, 0x06, 0x87, 0xc1, 0x16,
-+ 0x3c, 0x35, 0x3d, 0x7d, 0x2a, 0xc9, 0x09, 0x37, 0xb3, 0x4e, 0x97, 0x8e,
-+ 0x92, 0xf8, 0x21, 0xad, 0xc9, 0x66, 0x22, 0x02, 0xec, 0xe8, 0x9a, 0x17,
-+ 0xe7, 0xbb, 0x65, 0xae, 0x17, 0xd8, 0x3b, 0x90, 0xdb, 0xbe, 0x6a, 0x50,
-+ 0x1a, 0x4e, 0x13, 0x45, 0xbe, 0xe4, 0xe5, 0xa5, 0xb5, 0x3a, 0xf2, 0xe5,
-+ 0xba, 0x3d, 0x1e, 0xf3, 0xf4, 0xe0, 0x5a, 0xdf, 0x0b, 0x3a, 0x4c, 0xf2,
-+ 0xe5, 0x30, 0x36, 0x0f, 0xee, 0x64, 0x92, 0x99, 0x02, 0xb5, 0x71, 0xf6,
-+ 0xfd, 0x2e, 0x30, 0x56, 0x52, 0xa4, 0xcb, 0x01, 0x0f, 0x79, 0xf8, 0x15,
-+ 0xe1, 0x8f, 0x2b, 0xbb, 0x8c, 0xc8, 0x9f, 0xa6, 0xfc, 0x76, 0xf7, 0x7c,
-+ 0x89, 0xe2, 0x93, 0xcf, 0x17, 0x5a, 0x0b, 0x19, 0x58, 0x00, 0xfe, 0x72,
-+ 0xd2, 0xcc, 0xdd, 0x7d, 0x75, 0xe5, 0xbd, 0x90, 0xbc, 0x6a, 0xc4, 0x35,
-+ 0xd6, 0xa4, 0x40, 0xef, 0x85, 0x2e, 0x9a, 0x1c, 0x8c, 0x53, 0xde, 0x03,
-+ 0xbf, 0x19, 0x33, 0x65, 0xd7, 0x35, 0xaa, 0xf2, 0x9c, 0x51, 0x62, 0xa6,
-+ 0x17, 0xe3, 0x64, 0xe7, 0xf9, 0x44, 0x16, 0x8d, 0x0f, 0xb4, 0x8f, 0xef,
-+ 0x40, 0x55, 0x8f, 0x45, 0x42, 0x97, 0xcc, 0x3d, 0xd5, 0x08, 0x66, 0x2c,
-+ 0xf2, 0x3f, 0xb8, 0x8e, 0x19, 0x54, 0xaa, 0x45, 0xd1, 0xc5, 0xe1, 0x15,
-+ 0xbc, 0xc3, 0x6f, 0x05, 0xb3, 0xe0, 0x98, 0xd5, 0x55, 0x22, 0x0f, 0x40,
-+ 0xbe, 0x26, 0x29, 0xb3, 0x45, 0x07, 0xb8, 0x46, 0x4c, 0x54, 0xc2, 0x7b,
-+ 0x5d, 0xec, 0x78, 0xda, 0x8f, 0x22, 0x65, 0x05, 0x14, 0x79, 0x7a, 0xf8,
-+ 0x6a, 0x25, 0x12, 0xbc, 0xb7, 0xe2, 0x92, 0x33, 0x79, 0xef, 0x6d, 0x73,
-+ 0xc1, 0x37, 0x00, 0x6c, 0x1b, 0x38, 0xf5, 0x1e, 0x37, 0xf9, 0x35, 0x85,
-+ 0xe2, 0x90, 0x41, 0xa3, 0xe4, 0xe3, 0xaf, 0x46, 0x00, 0x7c, 0xe1, 0x3b,
-+ 0x8b, 0x5f, 0x7b, 0x17, 0xd5, 0xd6, 0x5d, 0x7d, 0x56, 0x68, 0xe4, 0x27,
-+ 0xbc, 0xbe, 0x7e, 0xc1, 0xd7, 0xc4, 0x08, 0xc0, 0x54, 0xa4, 0x8c, 0x1a,
-+ 0xe7, 0x97, 0xbf, 0x99, 0xac, 0xbc, 0x8d, 0x26, 0x07, 0x52, 0x29, 0x35,
-+ 0xfd, 0x66, 0x5e, 0xa7, 0x82, 0x2d, 0x93, 0x0f, 0x23, 0xea, 0xbf, 0xf7,
-+ 0x83, 0xbb, 0x23, 0x69, 0x75, 0x69, 0xe2, 0x04, 0xb9, 0x43, 0x14, 0x1e,
-+ 0x00, 0xc0, 0x88, 0x10, 0x95, 0x6b, 0xe0, 0x52, 0x53, 0x65, 0xdb, 0xab,
-+ 0x54, 0xed, 0x48, 0xcb, 0x76, 0x96, 0x4c, 0xcd, 0xf5, 0xcb, 0xd3, 0xae,
-+ 0xe7, 0x28, 0x2d, 0x4a, 0x00, 0x00, 0xd2, 0x78, 0x4d, 0x7b, 0x8f, 0xab,
-+ 0x16, 0xb2, 0xf7, 0xf0, 0xd5, 0x22, 0x57, 0x32, 0xb1, 0xef, 0xbc, 0x4e,
-+ 0xb1, 0xcf, 0xed, 0xeb, 0x43, 0xfd, 0xe7, 0x9b, 0x69, 0xec, 0xc0, 0xfb,
-+ 0xea, 0xa1, 0xe6, 0xb4, 0x07, 0x28, 0x67, 0x3b, 0xd4, 0xb2, 0xe9, 0x8a,
-+ 0x0d, 0x4a, 0x8f, 0x02, 0xf8, 0x53, 0x95, 0x07, 0x30, 0xf2, 0x8d, 0x35,
-+ 0xeb, 0x12, 0xfc, 0xc7, 0x97, 0x68, 0xb8, 0xe1, 0x8e, 0x4b, 0xda, 0x0e,
-+ 0x58, 0xa3, 0x31, 0xa2, 0xf7, 0x1d, 0x7c, 0xcc, 0x2d, 0x45, 0x1b, 0x32,
-+ 0xb1, 0xc6, 0x5c, 0x31, 0x2a, 0xcf, 0x47, 0xee, 0x51, 0x3b, 0x21, 0x95,
-+ 0x4c, 0x41, 0xc0, 0x0c, 0x87, 0x38, 0x72, 0xee, 0x94, 0xcf, 0x14, 0xf4,
-+ 0x60, 0x37, 0x42, 0x53, 0x61, 0xf4, 0xbd, 0xb5, 0x48, 0x21, 0xf7, 0x11,
-+ 0x46, 0x0c, 0xeb, 0xae, 0x8c, 0x07, 0x50, 0x8a, 0x92, 0x19, 0xf8, 0x8f,
-+ 0xa6, 0xbe, 0xda, 0xa6, 0x78, 0xee, 0xd5, 0x01, 0x94, 0x4a, 0x16, 0xae,
-+ 0x6f, 0x7b, 0x5b, 0xb7, 0xa2, 0xe1, 0xe3, 0x57, 0xe7, 0x0d, 0x7b, 0x98,
-+ 0x46, 0x1a, 0x2c, 0x71, 0xcb, 0x0f, 0xa7, 0x62, 0xd6, 0xad, 0x98, 0x24,
-+ 0x08, 0x1d, 0x37, 0xf2, 0x92, 0xfd, 0x4b, 0xe8, 0xb8, 0x4c, 0x36, 0x11,
-+ 0x0d, 0xc7, 0x44, 0x36, 0x02, 0x01, 0xbe, 0xeb, 0xe0, 0xbd, 0x6c, 0x9d,
-+ 0x05, 0xe8, 0x69, 0x25, 0x6d, 0x2f, 0xf3, 0xf9, 0x95, 0x17, 0xb7, 0xef,
-+ 0xd2, 0xa3, 0x37, 0x74, 0x05, 0x6c, 0xb5, 0x67, 0x16, 0x75, 0xa8, 0xb4,
-+ 0x92, 0xe9, 0xf5, 0xf2, 0x62, 0x0e, 0xb8, 0xef, 0x93, 0x81, 0xd3, 0xd1,
-+ 0xdf, 0x19, 0x93, 0x8b, 0x7b, 0x5f, 0xfa, 0xac, 0x59, 0xbc, 0x81, 0x10,
-+ 0xfa, 0x87, 0xba, 0x8d, 0x7a, 0x3d, 0x01, 0x65, 0xf8, 0xe4, 0x1d, 0xd0,
-+ 0xf8, 0x04, 0xf1, 0x1b, 0x9d, 0xed, 0x0f, 0x35, 0x2a, 0x59, 0x78, 0x35,
-+ 0xd0, 0x63, 0x07, 0xa8, 0xe0, 0xc6, 0xef, 0x4d, 0x21, 0x90, 0x43, 0x39,
-+ 0xe1, 0xcf, 0x45, 0x89, 0x23, 0xa3, 0xe8, 0x9e, 0x02, 0x5d, 0x94, 0x53,
-+ 0x47, 0x36, 0x6c, 0x02, 0xf3, 0xdd, 0x63, 0x68, 0xd4, 0xe4, 0x7e, 0x85,
-+ 0xd3, 0xd2, 0xa9, 0x70, 0x5b, 0xd5, 0x79, 0x61, 0x85, 0x2e, 0x5a, 0x57,
-+ 0x9f, 0x93, 0xb1, 0xc5, 0x14, 0xc5, 0x39, 0xf4, 0x9e, 0xa1, 0x16, 0x3a,
-+ 0x2a, 0x49, 0x3b, 0x0e, 0xfc, 0xb4, 0x7f, 0x47, 0x48, 0xf6, 0xa9, 0x9e,
-+ 0x10, 0xbf, 0x70, 0x78, 0x28, 0x2e, 0x4a, 0xce, 0x18, 0x13, 0x6e, 0x2a,
-+ 0x8b, 0x3e, 0xe0, 0xa3, 0x80, 0xdc, 0xd3, 0xb3, 0xef, 0x3e, 0x65, 0xe1,
-+ 0xb8, 0x15, 0x72, 0x89, 0xd6, 0x24, 0x67, 0xad, 0x48, 0x8b, 0xa0, 0x39,
-+ 0x2b, 0x2e, 0x90, 0xa1, 0xed, 0xed, 0xcb, 0xdc, 0x93, 0x1d, 0xc1, 0x72,
-+ 0x98, 0xcc, 0xef, 0x76, 0x64, 0x5c, 0x7d, 0x33, 0x0a, 0x05, 0xc2, 0xce,
-+ 0x40, 0xf8, 0x9b, 0x85, 0x46, 0x8f, 0x35, 0x7a, 0x21, 0x77, 0x51, 0xe1,
-+ 0x54, 0x63, 0x13, 0x04, 0xec, 0x4e, 0x04, 0xbb, 0x45, 0xb3, 0x67, 0x89,
-+ 0x09, 0xc7, 0x4a, 0xf5, 0x1c, 0xe3, 0x70, 0x36, 0x4d, 0x8f, 0x4f, 0x7e,
-+ 0xb1, 0xe6, 0x1e, 0x00, 0x28, 0x74, 0x29, 0xc9, 0x96, 0x1d, 0xe8, 0x32,
-+ 0x2c, 0xa9, 0xa2, 0x62, 0x9b, 0x13, 0x09, 0xd8, 0x00, 0xe9, 0x2b, 0xc1,
-+ 0xdc, 0x50, 0x55, 0xdc, 0xc7, 0x97, 0xf3, 0x38, 0x66, 0xeb, 0x0c, 0xfd,
-+ 0x8d, 0x49, 0x02, 0x50, 0xd4, 0x8f, 0xfc, 0xa8, 0x02, 0x2f, 0x49, 0x29,
-+ 0x0e, 0x2d, 0x53, 0x76, 0x16, 0x2f, 0xba, 0xa9, 0x82, 0xd1, 0x64, 0x53,
-+ 0xc8, 0x25, 0xb3, 0x5f, 0x65, 0x15, 0x63, 0x5e, 0xa9, 0x2b, 0xea, 0x72,
-+ 0x36, 0x7b, 0xaa, 0x54, 0xde, 0x3f, 0x9e, 0xae, 0xa6, 0x95, 0x42, 0xa8,
-+ 0x1a, 0x41, 0x27, 0xf7, 0x1c, 0xba, 0xa2, 0x57, 0xf3, 0x24, 0xfe, 0xfe,
-+ 0xf1, 0x4f, 0x08, 0xfb, 0xd6, 0x5a, 0x04, 0x9c, 0xd2, 0xfb, 0x36, 0x25,
-+ 0x94, 0xa8, 0xe2, 0x3f, 0xf1, 0xa2, 0x61, 0x7d, 0xb5, 0xb1, 0x58, 0xf6,
-+ 0xf0, 0x1c, 0xf5, 0x0a, 0xb0, 0xed, 0x95, 0xc6, 0xe7, 0x09, 0x84, 0x11,
-+ 0x64, 0x10, 0x8b, 0x06, 0xe1, 0xb4, 0x0a, 0xb0, 0xab, 0x11, 0xc4, 0x08,
-+ 0x30, 0x1d, 0x3d, 0x9d, 0x8e, 0xa6, 0x9e, 0x96, 0x8a, 0x96, 0x00, 0xb3,
-+ 0xd1, 0x7f, 0x38, 0x01, 0x1c, 0xe2, 0x80, 0x74, 0xe2, 0xc2, 0xe1, 0x0b,
-+ 0xf6, 0x19, 0x7c, 0x60, 0x2d, 0x8d, 0x0c, 0xe7, 0xd3, 0xa3, 0xef, 0x2d,
-+ 0x89, 0x62, 0x3b, 0xc9, 0xf1, 0x2e, 0xa3, 0x38, 0x79, 0x1e, 0x92, 0x66,
-+ 0xbb, 0x8c, 0xe0, 0x2b, 0x12, 0x4c, 0x6c, 0x79, 0x29, 0xba, 0xea, 0x69,
-+ 0x32, 0x44, 0x09, 0x84, 0x54, 0xa0, 0x80, 0xeb, 0x75, 0x23, 0xe1, 0x3b,
-+ 0xb1, 0xb7, 0xc5, 0xb6, 0x77, 0x5f, 0xab, 0xab, 0xab, 0xbe, 0x90, 0x75,
-+ 0xfe, 0x56, 0x87, 0xaa, 0x45, 0x13, 0x97, 0xbb, 0x9c, 0xfc, 0xcd, 0x05,
-+ 0x12, 0x43, 0xe9, 0xbf, 0x5a, 0xef, 0x24, 0x06, 0x2d, 0x33, 0x5d, 0xe5,
-+ 0xfc, 0xe2, 0x4e, 0x9d, 0xdb, 0xde, 0x11, 0x91, 0x05, 0x2d, 0x80, 0xc3,
-+ 0x6d, 0xf9, 0xf8, 0x43, 0x48, 0x72, 0xf2, 0x77, 0xed, 0x4f, 0x5a, 0x1c,
-+ 0xe8, 0xeb, 0xd3, 0xb9, 0x60, 0x82, 0x4a, 0x4e, 0x4f, 0x10, 0x01, 0xb0,
-+ 0x4c, 0xb6, 0x85, 0xf9, 0xbe, 0xe4, 0xd0, 0xdd, 0xb0, 0xc5, 0x71, 0x59,
-+ 0x8a, 0xc2, 0x02, 0x1a, 0x66, 0x06, 0xfd, 0x23, 0x34, 0x5c, 0x6f, 0xbb,
-+ 0x84, 0xf0, 0xce, 0x05, 0xfe, 0x52, 0x73, 0x45, 0x21, 0xb7, 0xb0, 0x7c,
-+ 0x63, 0x88, 0xd3, 0xa3, 0xb9, 0x93, 0x18, 0xbf, 0x01, 0x31, 0x50, 0x4a,
-+ 0xa9, 0xdf, 0xba, 0xf5, 0x48, 0xf9, 0xd3, 0x2a, 0x9c, 0xd4, 0xc6, 0x89,
-+ 0x35, 0x24, 0xb1, 0x13, 0x30, 0xa2, 0xd3, 0xaa, 0xd3, 0xed, 0x2a, 0x58,
-+ 0x96, 0x6e, 0xbb, 0x01, 0x34, 0x46, 0x5d, 0x54, 0x3f, 0xd7, 0x79, 0x7a,
-+ 0xf5, 0x49, 0xf5, 0x68, 0xea, 0xeb, 0xe9, 0x57, 0xf6, 0x4f, 0xec, 0x85,
-+ 0x46, 0x74, 0x90, 0x2b, 0x97, 0x55, 0x87, 0x56, 0x98, 0x69, 0x46, 0xea,
-+ 0x3a, 0xb7, 0xa2, 0x51, 0xcb, 0xbe, 0xa1, 0x1a, 0x68, 0x7b, 0xd4, 0x3f,
-+ 0x5d, 0x0b, 0xd8, 0x9c, 0xd2, 0xca, 0xba, 0x61, 0xd5, 0x21, 0x83, 0x74,
-+ 0x99, 0x0e, 0xe8, 0xb9, 0x22, 0x19, 0xed, 0x25, 0xdc, 0xa0, 0x11, 0xc6,
-+ 0x8a, 0x97, 0x57, 0xc0, 0x13, 0xbd, 0x83, 0x7b, 0x2d, 0xd7, 0x34, 0xe3,
-+ 0x75, 0x1f, 0x64, 0xfc, 0xb4, 0xb2, 0x3d, 0xcd, 0x6b, 0xc5, 0x7e, 0xa5,
-+ 0x67, 0xf5, 0x71, 0x6e, 0x17, 0x36, 0x72, 0x44, 0x75, 0x1e, 0x23, 0x03,
-+ 0xb2, 0x2a, 0x95, 0x3e, 0x77, 0x27, 0x56, 0x95, 0x6c, 0xdc, 0xc0, 0x13,
-+ 0xff, 0xd2, 0xc3, 0x24, 0x90, 0x75, 0x44, 0x22, 0xa5, 0x72, 0x52, 0x9d,
-+ 0x4c, 0x92, 0xf1, 0xeb, 0xb1, 0x9f, 0x1d, 0xad, 0x4d, 0x03, 0x6f, 0x2f,
-+ 0xdf, 0x31, 0xca, 0x91, 0x01, 0xbd, 0xf8, 0x1a, 0xea, 0x94, 0x8a, 0xed,
-+ 0xcf, 0x21, 0x7a, 0xa8, 0xfc, 0xcd, 0x7a, 0x07, 0x71, 0xaa, 0x27, 0x53,
-+ 0xe1, 0xa8, 0x23, 0xbf, 0x41, 0xc9, 0x53, 0x77, 0xa2, 0xff, 0xa6, 0x1b,
-+ 0x22, 0x65, 0x13, 0x81, 0x53, 0xce, 0x86, 0xd2, 0xc8, 0x7d, 0xd0, 0x7a,
-+ 0x4b, 0x32, 0xd2, 0x7f, 0x5f, 0x28, 0x72, 0x64, 0x14, 0x31, 0xce, 0x9a,
-+ 0x18, 0xa5, 0x02, 0xaa, 0xef, 0xd9, 0xaf, 0xc5, 0xb0, 0xd1, 0x3c, 0xd4,
-+ 0x6c, 0x35, 0x7e, 0x38, 0xe6, 0x9e, 0x1e, 0xe9, 0x45, 0xad, 0xd1, 0x99,
-+ 0x29, 0x32, 0xa5, 0xb1, 0xe5, 0xc5, 0x62, 0x9c, 0x9f, 0x48, 0xf7, 0x66,
-+ 0x18, 0x53, 0xda, 0x00, 0x78, 0x7c, 0x9d, 0x78, 0xfb, 0x92, 0x55, 0x53,
-+ 0xbf, 0x07, 0xa5, 0x0d, 0xd5, 0xb9, 0xd9, 0x35, 0x85, 0x34, 0x20, 0xe4,
-+ 0xd1, 0xa7, 0x1a, 0xe6, 0x2f, 0xf9, 0x0c, 0xa1, 0x93, 0xcd, 0xd6, 0xc2,
-+ 0xf4, 0xbe, 0xd2, 0x63, 0x41, 0x5a, 0xaf, 0x9a, 0x35, 0x09, 0x4b, 0xc2,
-+ 0xa2, 0x2e, 0x2a, 0x66, 0x3c, 0x76, 0x45, 0x00, 0x1c, 0xd1, 0x90, 0xb7,
-+ 0xbc, 0x17, 0xc7, 0x5f, 0xea, 0xdf, 0x8e, 0x87, 0xce, 0x5c, 0x24, 0xb7,
-+ 0x63, 0xb6, 0x58, 0x4e, 0xd3, 0x2e, 0x71, 0xb0, 0x26, 0x81, 0x42, 0xea,
-+ 0x3e, 0xd6, 0x89, 0x81, 0x57, 0xbf, 0x92, 0x3b, 0xeb, 0xf0, 0x19, 0x2d,
-+ 0x1b, 0xf5, 0xee, 0x30, 0xa7, 0xd3, 0x51, 0x63, 0x4a, 0x60, 0xb5, 0x04,
-+ 0xdd, 0xe3, 0x8a, 0x2e, 0x11, 0x4f, 0x7a, 0xe9, 0xbf, 0x17, 0x6d, 0x4a,
-+ 0x18, 0xba, 0x28, 0x95, 0xa7, 0xbb, 0x4b, 0x47, 0x44, 0x4a, 0x9b, 0xa8,
-+ 0xdb, 0xb4, 0xc1, 0x24, 0xcd, 0x41, 0xbb, 0xb3, 0x2f, 0x4b, 0xcb, 0x1d,
-+ 0xe4, 0x8c, 0x4a, 0xbb, 0x51, 0x06, 0x07, 0xa0, 0x01, 0xb5, 0xa0, 0x00,
-+ 0xbb, 0xa4, 0x36, 0x18, 0xb6, 0xc1, 0x9e, 0x43, 0x51, 0x7b, 0x45, 0xb4,
-+ 0x24, 0x05, 0x92, 0x8b, 0x67, 0xc7, 0x13, 0x88, 0x18, 0x58, 0xba, 0xd3,
-+ 0xa4, 0x25, 0x11, 0xc2, 0x71, 0x6f, 0xf9, 0xcd, 0x33, 0x20, 0x34, 0xb6,
-+ 0x72, 0xb5, 0x2f, 0xf1, 0x66, 0x10, 0x80, 0x5c, 0xdb, 0xe7, 0x54, 0x4a,
-+ 0x8a, 0x84, 0xb6, 0x6e, 0x1c, 0x74, 0x5a, 0x73, 0xc1, 0xb6, 0xbc, 0xda,
-+ 0x5b, 0x77, 0xb9, 0x51, 0xf3, 0x6c, 0x0f, 0x7a, 0x53, 0x72, 0xde, 0x9e,
-+ 0x5d, 0x1f, 0x9b, 0xbc, 0xde, 0x88, 0x43, 0xc6, 0x90, 0x90, 0x02, 0xdd,
-+ 0xa4, 0x87, 0x5e, 0x67, 0x57, 0x1a, 0xf0, 0xbe, 0xc5, 0x81, 0x85, 0x6c,
-+ 0x32, 0xc0, 0x9c, 0x24, 0x0e, 0x66, 0x4e, 0x76, 0x1e, 0x57, 0xcd, 0x0d,
-+ 0x8d, 0xc8, 0xa7, 0x1c, 0xb9, 0x18, 0xa5, 0x76, 0x2d, 0x11, 0x12, 0x85,
-+ 0xcd, 0x8b, 0x56, 0x13, 0xdd, 0xbd, 0x0c, 0xa0, 0x8a, 0xc0, 0x34, 0x2b,
-+ 0x2b, 0xde, 0xe3, 0x8f, 0x96, 0xfa, 0x75, 0x4b, 0xb2, 0xb0, 0x87, 0x17,
-+ 0x9c, 0x11, 0x3c, 0x93, 0x98, 0x6a, 0x81, 0x03, 0x56, 0xeb, 0x94, 0x54,
-+ 0x0b, 0x93, 0xcb, 0x9d, 0xec, 0x4a, 0xa9, 0x29, 0x0f, 0xf1, 0x2e, 0xc1,
-+ 0xaa, 0x2e, 0x65, 0x6c, 0x9b, 0xe3, 0xd5, 0x90, 0x75, 0x3c, 0x36, 0x6c,
-+ 0x60, 0x14, 0x06, 0xc0, 0x61, 0xbc, 0x22, 0x03, 0x3a, 0x1f, 0xd1, 0xf4,
-+ 0xe1, 0x11, 0x1d, 0x03, 0x9b, 0x88, 0x13, 0xb9, 0x83, 0xcb, 0x50, 0x6c,
-+ 0x3e, 0xa7, 0xff, 0x30, 0x57, 0x98, 0x3e, 0x8b, 0xf0, 0x16, 0x82, 0xfb,
-+ 0xb0, 0x0f, 0x43, 0x00, 0x53, 0x13, 0xc8, 0x2c, 0x13, 0x92, 0x91, 0x8a,
-+ 0x61, 0x65, 0xa1, 0x33, 0x38, 0xff, 0xe1, 0x1a, 0x99, 0x2c, 0x1f, 0xb3,
-+ 0xd1, 0x03, 0x2a, 0xa6, 0x79, 0xa4, 0x18, 0xc8, 0xba, 0x4f, 0x8a, 0x0b,
-+ 0xc1, 0x99, 0xe1, 0x0c, 0xf6, 0xbd, 0x77, 0xa1, 0x4f, 0xdd, 0x6a, 0x06,
-+ 0x09, 0x35, 0x14, 0x34, 0x8e, 0x3a, 0x89, 0x74, 0x43, 0x4a, 0xe8, 0xa3,
-+ 0x67, 0x63, 0x69, 0xc6, 0xbe, 0x2c, 0xf9, 0x0e, 0x67, 0x2b, 0x34, 0x3f,
-+ 0xce, 0x04, 0xac, 0x6b, 0x22, 0xe0, 0xcf, 0x47, 0x56, 0x8b, 0xc4, 0x5d,
-+ 0x70, 0xa6, 0x8e, 0x68, 0xc6, 0x49, 0xa4, 0x83, 0x0a, 0xe2, 0x18, 0x59,
-+ 0x0c, 0x1a, 0x43, 0x7e, 0x7a, 0x23, 0xa5, 0x4e, 0xfe, 0x44, 0xf6, 0x70,
-+ 0x86, 0xeb, 0x69, 0x7b, 0x9f, 0xa5, 0x78, 0x35, 0xf0, 0xb8, 0xf7, 0x0f,
-+ 0x0a, 0x92, 0x92, 0x26, 0xef, 0xb3, 0x36, 0xc0, 0xe2, 0x18, 0x33, 0xa0,
-+ 0x28, 0x21, 0x8c, 0xd6, 0x37, 0x32, 0xc8, 0x0a, 0xa4, 0x77, 0xe6, 0x2d,
-+ 0x14, 0x1d, 0xba, 0x81, 0x85, 0x4f, 0x70, 0xda, 0x68, 0xda, 0xff, 0x4a,
-+ 0x84, 0xcb, 0x6d, 0xe7, 0x79, 0x25, 0x4e, 0x8a, 0x97, 0xe7, 0x35, 0x65,
-+ 0x37, 0x4a, 0xf4, 0x09, 0x2a, 0xf0, 0x5c, 0xbd, 0x66, 0x54, 0xaf, 0xc3,
-+ 0xfd, 0x72, 0xf0, 0xae, 0x23, 0x26, 0x95, 0xcb, 0x66, 0x68, 0xea, 0xfe,
-+ 0xcc, 0x40, 0x69, 0xbd, 0x90, 0xbb, 0x52, 0x8b, 0x83, 0xef, 0xa2, 0xfb,
-+ 0xcd, 0xbd, 0x93, 0xb2, 0x89, 0x92, 0x96, 0x21, 0xed, 0x74, 0xd8, 0x08,
-+ 0x73, 0x8f, 0xc1, 0x03, 0xee, 0xb1, 0x05, 0x51, 0x08, 0x51, 0xfc, 0x93,
-+ 0x19, 0xf1, 0x71, 0xea, 0x0c, 0xed, 0x0b, 0x97, 0xb5, 0xb9, 0xfb, 0x5e,
-+ 0xf9, 0x85, 0x18, 0x6b, 0xc5, 0x20, 0x98, 0xf9, 0xeb, 0x47, 0x6f, 0x67,
-+ 0xb7, 0xcc, 0x76, 0x65, 0xd4, 0x75, 0x87, 0x97, 0x5c, 0xb4, 0x5a, 0x50,
-+ 0xfc, 0x64, 0x10, 0x07, 0x19, 0xbf, 0x76, 0x34, 0x5f, 0x0f, 0xdf, 0x1e,
-+ 0x09, 0xef, 0xe9, 0xfb, 0x80, 0x0d, 0xc1, 0x14, 0xe4, 0x6b, 0xe0, 0x87,
-+ 0x9a, 0x19, 0x5c, 0xc0, 0x68, 0x70, 0xe2, 0x3d, 0x26, 0x31, 0xda, 0xe7,
-+ 0x1c, 0x39, 0x94, 0x48, 0x1c, 0x87, 0x61, 0xc4, 0x0d, 0x07, 0xc5, 0xbf,
-+ 0xca, 0x95, 0xe7, 0x18, 0xb7, 0xb2, 0x25, 0x85, 0xaf, 0x03, 0xed, 0x34,
-+ 0x17, 0x5a, 0x46, 0xd5, 0x7a, 0xf3, 0x51, 0x8e, 0x32, 0xa7, 0xfc, 0x1a,
-+ 0xa4, 0x48, 0x27, 0x32, 0xa8, 0x1a, 0x87, 0xf7, 0x24, 0xf8, 0xd2, 0xe7,
-+ 0x80, 0xb3, 0xa3, 0x9d, 0x45, 0x1a, 0x38, 0x0f, 0x75, 0xc2, 0xd6, 0x80,
-+ 0xcc, 0x72, 0x13, 0xea, 0xb1, 0xd4, 0xa5, 0x9d, 0x39, 0x4a, 0xe3, 0x81,
-+ 0x0a, 0x1c, 0x90, 0x81, 0x8d, 0x52, 0xf9, 0x3f, 0xb2, 0x03, 0xe2, 0xd8,
-+ 0xb1, 0xb5, 0xfa, 0x8f, 0x60, 0xb2, 0xd5, 0x85, 0xd9, 0x13, 0x5d, 0x64,
-+ 0x88, 0x46, 0xf1, 0x38, 0xb8, 0x69, 0x53, 0x24, 0x2d, 0x2b, 0xb1, 0xf2,
-+ 0xec, 0xdf, 0x38, 0x9b, 0x4d, 0xe7, 0x65, 0x18, 0x17, 0xb8, 0xe4, 0xe6,
-+ 0x4b, 0x33, 0x3f, 0x1a, 0xac, 0x52, 0x3a, 0x93, 0xf2, 0x74, 0x8a, 0x9c,
-+ 0x38, 0xff, 0xbc, 0x29, 0xce, 0xd4, 0x57, 0xb6, 0xf9, 0x78, 0x1b, 0x08,
-+ 0xa6, 0x7a, 0x19, 0x75, 0xd0, 0x31, 0xcc, 0xd7, 0x15, 0x45, 0xc0, 0x03,
-+ 0x74, 0x34, 0x05, 0x6c, 0x24, 0x34, 0xd1, 0x3e, 0x6c, 0x4b, 0xee, 0xbf,
-+ 0x46, 0xfc, 0x12, 0x22, 0x2c, 0x0b, 0x2e, 0xcc, 0xd6, 0x15, 0x9d, 0x5a,
-+ 0xea, 0x8e, 0x55, 0x4d, 0x7a, 0x09, 0x65, 0x2b, 0x06, 0xbf, 0x7c, 0xa6,
-+ 0x99, 0xa7, 0x19, 0x9e, 0x71, 0x6d, 0x05, 0xdd, 0x55, 0x30, 0x41, 0xa8,
-+ 0xf2, 0xb3, 0x03, 0xd2, 0x36, 0xa9, 0xba, 0xba, 0xaf, 0xb9, 0xfa, 0x52,
-+ 0x8f, 0x28, 0xa2, 0xca, 0x2a, 0xa7, 0x80, 0xb9, 0x40, 0x38, 0x3c, 0x09,
-+ 0x9a, 0xa6, 0x5a, 0x00, 0x74, 0xb8, 0x3f, 0xd1, 0xf0, 0xbc, 0x5b, 0x7b,
-+ 0x5e, 0x46, 0xc2, 0x5e, 0x54, 0x83, 0x8b, 0x3c, 0xbc, 0xfc, 0x95, 0xf8,
-+ 0x7f, 0x1d, 0x47, 0x1b, 0x3b, 0xa8, 0x94, 0x43, 0x4f, 0xa5, 0x89, 0x52,
-+ 0xfd, 0xcb, 0x77, 0xf1, 0x61, 0x37, 0x26, 0x93, 0x30, 0x6d, 0xba, 0x4e,
-+ 0x8f, 0x21, 0x6d, 0x1c, 0x8e, 0x5c, 0xaf, 0xf0, 0xfe, 0x83, 0x60, 0xa5,
-+ 0x1c, 0x60, 0x76, 0x36, 0x44, 0x16, 0x9f, 0xdc, 0x6a, 0x82, 0x67, 0xf2,
-+ 0xe3, 0xf9, 0x09, 0xa6, 0x1b, 0x2a, 0x67, 0x8b, 0xce, 0x6a, 0xe9, 0x04,
-+ 0x03, 0xa8, 0x36, 0xb1, 0xa7, 0xb7, 0xe8, 0xcd, 0x8b, 0x54, 0xc3, 0x70,
-+ 0x87, 0xa9, 0xe1, 0x44, 0x46, 0xd9, 0x5e, 0x69, 0x08, 0xd2, 0xee, 0xdb,
-+ 0xfc, 0xc6, 0x53, 0xe0, 0x2f, 0xdf, 0x77, 0x1f, 0x70, 0x1a, 0x79, 0xb9,
-+ 0xe5, 0xa2, 0x6e, 0xd0, 0xa9, 0x47, 0x84, 0x20, 0x70, 0xf3, 0xb5, 0x70,
-+ 0x17, 0x42, 0x21, 0x12, 0x19, 0xe7, 0x61, 0x76, 0x2c, 0x37, 0xf0, 0xd0,
-+ 0xa1, 0xd1, 0xb9, 0x75, 0x0f, 0xee, 0x57, 0x7e, 0x12, 0x08, 0x11, 0x5c,
-+ 0x66, 0xac, 0x07, 0xec, 0x09, 0x1e, 0x6a, 0x3f, 0xc4, 0xaa, 0x6a, 0x25,
-+ 0x3b, 0xcb, 0xa8, 0x68, 0xed, 0xd3, 0x15, 0x4d, 0xca, 0xf5, 0x16, 0x2f,
-+ 0x61, 0x5e, 0x85, 0x49, 0x0a, 0x6c, 0xa3, 0x42, 0xf3, 0x4c, 0x43, 0xac,
-+ 0x61, 0xa3, 0xea, 0x6b, 0xfe, 0xef, 0xd8, 0x50, 0xe1, 0x90, 0xeb, 0x1d,
-+ 0x8d, 0xa4, 0xd2, 0x8b, 0x5e, 0xce, 0xeb, 0x16, 0x78, 0xc0, 0x24, 0x33,
-+ 0xec, 0xd5, 0xd4, 0x8b, 0x25, 0x36, 0x40, 0x42, 0x57, 0xe8, 0xca, 0x7b,
-+ 0xef, 0x58, 0x55, 0xf2, 0xb8, 0x13, 0xed, 0x2f, 0x4c, 0x40, 0x94, 0x45,
-+ 0xa3, 0x31, 0x7c, 0x9b, 0xe1, 0xa3, 0x5a, 0xe2, 0xfb, 0x4d, 0x2b, 0x87,
-+ 0x92, 0x1b, 0x90, 0x4b, 0xf2, 0xc1, 0x4d, 0xb5, 0x14, 0xce, 0xe0, 0x45,
-+ 0x25, 0x1c, 0xfc, 0x27, 0x63, 0x74, 0xdb, 0x15, 0xc9, 0x9d, 0xea, 0x15,
-+ 0xac, 0xde, 0x19, 0x7c, 0x6e, 0xb5, 0x24, 0x98, 0x8e, 0x39, 0xb6, 0x32,
-+ 0x87, 0xbe, 0xb8, 0x67, 0x68, 0x65, 0xaa, 0xa3, 0xba, 0xd1, 0xb4, 0x3b,
-+ 0x8c, 0xab, 0x15, 0xcb, 0xf2, 0x7a, 0x49, 0x87, 0x59, 0xe3, 0x20, 0x3a,
-+ 0xbf, 0x36, 0x9e, 0x97, 0x24, 0x2f, 0x0b, 0x01, 0x54, 0x14, 0x9f, 0x14,
-+ 0xac, 0x23, 0x3c, 0xdb, 0x73, 0xa2, 0x2b, 0x7f, 0xb8, 0xf0, 0x93, 0x25,
-+ 0xbf, 0x2a, 0xce, 0x83, 0xbb, 0x6b, 0x5d, 0xb8, 0xa1, 0x21, 0xa2, 0xb6,
-+ 0x82, 0x14, 0x9a, 0x69, 0x13, 0x1c, 0xcc, 0xe5, 0x22, 0x29, 0x84, 0x0b,
-+ 0x11, 0x3f, 0xc7, 0xb0, 0xbc, 0xc5, 0x84, 0x05, 0xbf, 0xe8, 0x7f, 0x1f,
-+ 0x95, 0xff, 0xc2, 0xe9, 0x6f, 0xc5, 0x59, 0x65, 0x67, 0xe9, 0x43, 0x64,
-+ 0xdf, 0xaa, 0x6d, 0x9d, 0x5a, 0x6e, 0xb9, 0x9a, 0xe4, 0xdd, 0xf4, 0x24,
-+ };
-+ static const unsigned char ml_dsa_44_sig[]= {
-+ 0xe5, 0xc9, 0x93, 0xb8, 0xac, 0x28, 0x9b, 0x77, 0xda, 0x22, 0x2c, 0x41,
-+ 0xb2, 0x17, 0x78, 0x3f, 0x16, 0xdd, 0x3a, 0x3e, 0xd5, 0x87, 0xd0, 0x56,
-+ 0xc6, 0x10, 0xda, 0xf5, 0x80, 0x50, 0x94, 0x6a, 0x69, 0xcd, 0xe3, 0xad,
-+ 0x8a, 0xf5, 0xee, 0x3f, 0xac, 0x7e, 0xc4, 0xa1, 0x78, 0xd2, 0x8b, 0xc4,
-+ 0x08, 0x23, 0x42, 0x6e, 0xd3, 0xec, 0x56, 0x1a, 0xaa, 0xd2, 0xc1, 0x1a,
-+ 0x2d, 0xad, 0x1a, 0xfa, 0xb4, 0x2e, 0x79, 0xd6, 0x19, 0x0a, 0xdd, 0x6b,
-+ 0x78, 0x51, 0x58, 0xfa, 0x5f, 0xbd, 0x23, 0x84, 0x22, 0x6d, 0xc3, 0xba,
-+ 0xe9, 0x07, 0x26, 0x58, 0x5f, 0x28, 0x1c, 0x60, 0x04, 0xe0, 0x07, 0x9b,
-+ 0xc6, 0xd5, 0xc4, 0x45, 0x96, 0x6c, 0xa5, 0xd1, 0x19, 0x80, 0xe7, 0x60,
-+ 0x7c, 0x43, 0x41, 0xb0, 0xdd, 0xb6, 0x8f, 0x9a, 0xc3, 0xa3, 0x60, 0x18,
-+ 0x45, 0xdf, 0x54, 0x09, 0x35, 0x39, 0xe8, 0x03, 0x30, 0x12, 0x32, 0x82,
-+ 0xe2, 0x9f, 0x7f, 0xf5, 0x52, 0x26, 0x6d, 0x01, 0xaa, 0xaf, 0xc4, 0x2b,
-+ 0x99, 0x64, 0x82, 0xf5, 0xe3, 0x76, 0x9f, 0xd4, 0x1e, 0x05, 0xed, 0xdd,
-+ 0x20, 0x4e, 0x7a, 0x2e, 0xb4, 0x3b, 0xb1, 0xb1, 0x29, 0x17, 0xf3, 0x2a,
-+ 0xf0, 0xf7, 0xd3, 0xf6, 0xe0, 0x53, 0xa2, 0x0f, 0x46, 0x68, 0x30, 0x45,
-+ 0xb9, 0x33, 0x81, 0x01, 0x45, 0x43, 0x85, 0xa6, 0x77, 0xb8, 0xf5, 0xbd,
-+ 0x42, 0x00, 0x96, 0x8d, 0x0b, 0xf2, 0xa8, 0x6b, 0x64, 0x60, 0x5b, 0xee,
-+ 0xa0, 0x82, 0xd5, 0xf5, 0x31, 0x75, 0x38, 0x5c, 0x8a, 0xa3, 0x77, 0x0f,
-+ 0x6d, 0x81, 0x2b, 0x0f, 0xb9, 0xf6, 0xea, 0xb4, 0x0f, 0x48, 0x18, 0x98,
-+ 0x46, 0x83, 0x89, 0xb0, 0x98, 0xce, 0x1d, 0xc6, 0x1d, 0x10, 0xa3, 0xa4,
-+ 0x9c, 0x04, 0x0c, 0xa0, 0x3b, 0x61, 0x44, 0x2e, 0x0c, 0x71, 0x91, 0xb6,
-+ 0x89, 0x6d, 0x50, 0x6d, 0x4f, 0xb9, 0x4f, 0x3c, 0xa6, 0x16, 0x3e, 0x1b,
-+ 0x0a, 0x0c, 0x03, 0xa3, 0xaf, 0x82, 0x22, 0x75, 0xac, 0x8d, 0xe2, 0xf3,
-+ 0x61, 0x61, 0x85, 0x39, 0x66, 0x96, 0x3e, 0x56, 0xad, 0x64, 0x16, 0x56,
-+ 0x2b, 0x03, 0x44, 0xf7, 0xf3, 0xee, 0xb6, 0xc0, 0x10, 0xbb, 0x99, 0xd6,
-+ 0x13, 0x0a, 0xc2, 0xd6, 0xf6, 0x87, 0x57, 0x2a, 0x48, 0x23, 0x42, 0xb8,
-+ 0xed, 0x0a, 0x47, 0x9b, 0x83, 0xee, 0x6a, 0x7d, 0xf4, 0x9c, 0x02, 0xfc,
-+ 0x9c, 0x3b, 0x4d, 0x00, 0x66, 0x0d, 0x24, 0x10, 0x3c, 0x3f, 0x34, 0xc7,
-+ 0x94, 0xc1, 0x3f, 0x04, 0xec, 0xd5, 0xa8, 0xa0, 0x28, 0x6d, 0x01, 0x9d,
-+ 0xb9, 0x80, 0xac, 0x87, 0xb6, 0x09, 0xd9, 0xd7, 0x2a, 0xa9, 0x3e, 0x02,
-+ 0xf1, 0xf0, 0x24, 0x50, 0x8d, 0x5f, 0x41, 0x8d, 0x7d, 0x08, 0xe6, 0xbb,
-+ 0x86, 0x5d, 0x44, 0xfe, 0x3e, 0x72, 0xe9, 0x56, 0x06, 0xec, 0xa1, 0x98,
-+ 0xda, 0xcb, 0x3f, 0x31, 0xcf, 0x16, 0x5d, 0x57, 0x20, 0x6f, 0x62, 0xcb,
-+ 0xf2, 0x2c, 0xa6, 0x12, 0x7f, 0x17, 0x3d, 0xeb, 0xef, 0xbc, 0xe1, 0x7b,
-+ 0x6f, 0x84, 0x3c, 0x7b, 0x75, 0x72, 0x94, 0x6d, 0xf1, 0xf3, 0x68, 0x1b,
-+ 0xdb, 0x55, 0x67, 0xd0, 0x4f, 0xfb, 0x1b, 0xbb, 0x1e, 0x53, 0xba, 0xdc,
-+ 0x26, 0x70, 0xf4, 0x22, 0xee, 0xf8, 0x67, 0xdb, 0xfc, 0xcb, 0xda, 0xa3,
-+ 0x1a, 0xc7, 0xc4, 0x5e, 0x21, 0x80, 0x78, 0x15, 0x01, 0xb4, 0x35, 0x16,
-+ 0x2e, 0x0c, 0x14, 0x2f, 0x19, 0xe8, 0x9d, 0x0b, 0x96, 0x25, 0x2d, 0xeb,
-+ 0x2c, 0xb3, 0x16, 0x4f, 0xe2, 0xc1, 0x42, 0x76, 0xc3, 0x5a, 0xc0, 0x5e,
-+ 0x47, 0x71, 0x23, 0x7f, 0xd0, 0xf8, 0x1d, 0xcd, 0x25, 0xc7, 0xd8, 0x1e,
-+ 0x15, 0x7a, 0xdd, 0x68, 0x88, 0x98, 0xc0, 0x3c, 0xac, 0xa4, 0x79, 0x81,
-+ 0x61, 0x44, 0x93, 0x2a, 0xd2, 0x4c, 0x0b, 0x28, 0x8f, 0xf3, 0x81, 0x49,
-+ 0xc3, 0xdf, 0xa5, 0xa4, 0x78, 0x35, 0x3a, 0x21, 0xaa, 0x2a, 0x01, 0xdf,
-+ 0xa8, 0x48, 0x89, 0xe5, 0xb0, 0x77, 0xe8, 0x62, 0x75, 0x2d, 0x91, 0x55,
-+ 0x05, 0xed, 0x40, 0x23, 0x66, 0x6a, 0xee, 0x3a, 0xb3, 0x1b, 0x6c, 0x56,
-+ 0x68, 0xfa, 0x81, 0x92, 0x05, 0xc9, 0xbb, 0x36, 0x7b, 0xc9, 0xf9, 0x42,
-+ 0x0e, 0x99, 0x1d, 0xe6, 0xc4, 0xbc, 0x59, 0x8d, 0x99, 0x24, 0x78, 0xc1,
-+ 0x26, 0x82, 0x09, 0xbd, 0x68, 0xca, 0xb6, 0xe6, 0xb5, 0xd4, 0x48, 0x8f,
-+ 0xa1, 0x0c, 0x62, 0xa4, 0x51, 0x13, 0xdd, 0xf1, 0x2a, 0xf6, 0xc1, 0xda,
-+ 0x75, 0x16, 0x76, 0x5c, 0xfa, 0x7a, 0x9b, 0x03, 0x3e, 0x0c, 0x4e, 0xd6,
-+ 0xfb, 0xba, 0x67, 0xee, 0x34, 0x56, 0x6f, 0xb4, 0x57, 0x1b, 0x95, 0x06,
-+ 0xf0, 0xb5, 0x92, 0x90, 0x69, 0x77, 0x23, 0xfa, 0x5b, 0xfb, 0xba, 0x8a,
-+ 0xb7, 0x36, 0x98, 0x6c, 0x1e, 0xb5, 0xbb, 0x7e, 0x24, 0x8f, 0x00, 0x27,
-+ 0x6f, 0x75, 0xa6, 0xd9, 0x66, 0x07, 0xa6, 0x96, 0x5d, 0x41, 0xac, 0x58,
-+ 0x2f, 0xfb, 0xa0, 0x3e, 0x3a, 0x2d, 0x81, 0xe8, 0x9f, 0x45, 0x13, 0x58,
-+ 0x1f, 0x83, 0x0b, 0x04, 0x19, 0x51, 0xb8, 0x2d, 0x96, 0xaa, 0xad, 0x63,
-+ 0x4f, 0x02, 0xd8, 0xfa, 0xb6, 0xc4, 0x61, 0xb5, 0xfd, 0xa8, 0xa7, 0xd5,
-+ 0x8f, 0xfc, 0x4a, 0x80, 0x46, 0x49, 0x68, 0x3c, 0xd4, 0xed, 0xfc, 0x92,
-+ 0x6e, 0xaf, 0xc4, 0x8f, 0x9c, 0xdc, 0x7b, 0x4b, 0x4b, 0x9f, 0x8b, 0x66,
-+ 0xbc, 0x80, 0xa4, 0xa2, 0xde, 0xb7, 0xc4, 0xeb, 0xfc, 0x72, 0x42, 0x3d,
-+ 0x2f, 0x56, 0x5c, 0x69, 0xe9, 0xf4, 0xa2, 0x41, 0x3b, 0x1a, 0xe9, 0x69,
-+ 0x96, 0xbf, 0xfb, 0xd3, 0x4d, 0x0b, 0xea, 0xe2, 0x85, 0xc0, 0x56, 0xc3,
-+ 0x09, 0x25, 0x84, 0xc4, 0x0f, 0xbc, 0x3b, 0xdb, 0x15, 0x5b, 0x10, 0xa4,
-+ 0x1f, 0xc6, 0x9a, 0x05, 0x63, 0xf2, 0xa5, 0x39, 0xd3, 0x2c, 0xf7, 0x03,
-+ 0x6b, 0x16, 0xf9, 0xc4, 0xa4, 0x2f, 0x41, 0xe3, 0x90, 0x1a, 0x4e, 0xd8,
-+ 0xb9, 0x78, 0x2f, 0xda, 0x03, 0x2f, 0xa6, 0x5e, 0x94, 0xfc, 0x41, 0xdd,
-+ 0xf6, 0xdc, 0xa3, 0xe1, 0x6d, 0x64, 0x36, 0xaf, 0x34, 0x01, 0xf0, 0x97,
-+ 0x09, 0xd0, 0x79, 0x6a, 0xe4, 0x44, 0x40, 0x0f, 0x6b, 0x64, 0xd2, 0x8c,
-+ 0xe0, 0xe9, 0xe7, 0x4a, 0x45, 0x08, 0x54, 0x0f, 0x23, 0x0d, 0xc2, 0x67,
-+ 0xec, 0xd1, 0xa8, 0x4e, 0xb5, 0xba, 0x02, 0x22, 0xcb, 0xe6, 0x0f, 0x8a,
-+ 0xb7, 0xbf, 0x75, 0xba, 0xdf, 0xee, 0x11, 0x3f, 0xf6, 0x38, 0xc5, 0x8e,
-+ 0x10, 0xce, 0xb2, 0x0c, 0x63, 0x00, 0x6f, 0x6d, 0x87, 0x96, 0xb4, 0x97,
-+ 0x45, 0xf6, 0x99, 0xbc, 0xb2, 0x94, 0x76, 0xb6, 0x69, 0x80, 0xe7, 0xcf,
-+ 0x03, 0x74, 0xb1, 0x64, 0xcf, 0x6a, 0x31, 0xbc, 0x23, 0xd7, 0x1d, 0x43,
-+ 0x6c, 0x87, 0x09, 0x44, 0x9c, 0xa5, 0x2b, 0x67, 0x83, 0x24, 0xb5, 0x4d,
-+ 0xcc, 0xc8, 0xd2, 0x63, 0x24, 0x94, 0x15, 0x7a, 0xd6, 0xcc, 0xba, 0x0c,
-+ 0x7b, 0x10, 0x7d, 0x5b, 0xe3, 0x7a, 0x47, 0xfa, 0x89, 0x8a, 0x74, 0x2f,
-+ 0x0a, 0x29, 0xaf, 0xbe, 0xec, 0xcd, 0x00, 0x5b, 0x5c, 0xb7, 0x0f, 0x60,
-+ 0xa9, 0x94, 0x1c, 0x56, 0x69, 0x5b, 0x78, 0xde, 0x9c, 0x37, 0x1a, 0xf4,
-+ 0xcf, 0xd3, 0xa9, 0xa1, 0xb9, 0x3f, 0xb7, 0x58, 0x0f, 0xee, 0xfe, 0x31,
-+ 0xef, 0xe2, 0xdc, 0x82, 0x85, 0x35, 0x54, 0x41, 0x17, 0x6d, 0xd7, 0x31,
-+ 0x6f, 0x67, 0x71, 0x2e, 0xbc, 0x62, 0x06, 0xeb, 0x6c, 0x48, 0xcb, 0xb2,
-+ 0x0c, 0xfb, 0x8e, 0x8c, 0x6a, 0xfd, 0xc7, 0x83, 0x33, 0xe2, 0x8b, 0x2f,
-+ 0x79, 0x8d, 0xea, 0xa2, 0x83, 0x3e, 0xc1, 0x18, 0x62, 0xa8, 0xce, 0xfa,
-+ 0x6c, 0x0a, 0x5a, 0xbd, 0xf5, 0x57, 0x07, 0xde, 0x88, 0x0b, 0x45, 0xd4,
-+ 0xbc, 0x81, 0x3b, 0x40, 0xce, 0x78, 0xea, 0x96, 0xec, 0xae, 0xb7, 0x4a,
-+ 0xc3, 0xd5, 0xc1, 0x1e, 0xff, 0xea, 0x6c, 0xad, 0xf9, 0xee, 0x54, 0xc2,
-+ 0x85, 0x8d, 0xfa, 0xcf, 0x83, 0x95, 0xa6, 0x93, 0x72, 0xae, 0x2b, 0x27,
-+ 0x5f, 0x5f, 0x21, 0x06, 0xde, 0xf8, 0xc7, 0x00, 0x5a, 0xb4, 0xaa, 0xa1,
-+ 0x5f, 0x9d, 0x81, 0xe0, 0xcb, 0x54, 0x91, 0x02, 0x63, 0x24, 0x41, 0xdc,
-+ 0x9e, 0x34, 0xb1, 0x8d, 0x2c, 0x0e, 0x4e, 0xae, 0x5e, 0xfd, 0x2c, 0x0a,
-+ 0x95, 0x27, 0xf1, 0x48, 0x74, 0x24, 0x09, 0xeb, 0x42, 0x08, 0x7e, 0xc0,
-+ 0x2a, 0xab, 0xea, 0xb9, 0xe4, 0x6f, 0xf4, 0x35, 0x3b, 0x2c, 0x2e, 0x7e,
-+ 0xb7, 0xb3, 0xe1, 0x02, 0x6f, 0x29, 0xd1, 0xc0, 0xf4, 0x9d, 0xfd, 0x2f,
-+ 0xd5, 0x9d, 0xb7, 0x03, 0x77, 0x6e, 0x84, 0x4a, 0x6e, 0x92, 0x53, 0x92,
-+ 0xf9, 0x87, 0xc0, 0xb1, 0x36, 0x39, 0x4d, 0x5f, 0x70, 0x59, 0x35, 0xcb,
-+ 0x2a, 0x1e, 0x87, 0xd0, 0x95, 0x93, 0x80, 0xce, 0xd3, 0x84, 0x33, 0xfe,
-+ 0x8d, 0xbf, 0xe2, 0x2d, 0xba, 0x63, 0xd5, 0xb0, 0x5e, 0x0a, 0x28, 0x03,
-+ 0x90, 0x4c, 0xfb, 0xf0, 0xbb, 0x55, 0x34, 0x27, 0xd0, 0x70, 0x35, 0xca,
-+ 0x90, 0x4f, 0xb9, 0xfd, 0x97, 0x4c, 0x7a, 0x8d, 0xd2, 0xd8, 0x9e, 0xde,
-+ 0x11, 0x5a, 0x60, 0x5f, 0xba, 0xa2, 0x8e, 0x93, 0xbf, 0xd2, 0x76, 0xdb,
-+ 0x92, 0x3d, 0xa0, 0x59, 0x28, 0x5b, 0xbe, 0x3f, 0x66, 0x18, 0xb5, 0x17,
-+ 0xeb, 0xf8, 0xeb, 0x5d, 0x0d, 0xd7, 0x5f, 0x90, 0x56, 0x6c, 0x81, 0x4f,
-+ 0xdb, 0x38, 0x30, 0x9b, 0x87, 0x06, 0x85, 0xf1, 0xbb, 0x17, 0xce, 0x4d,
-+ 0x38, 0x9c, 0xbc, 0xe8, 0x51, 0xa0, 0xb0, 0x18, 0xaf, 0xc2, 0x97, 0xbb,
-+ 0x91, 0x89, 0x0d, 0x33, 0x06, 0x04, 0xc2, 0xa4, 0x83, 0xc6, 0xc5, 0xeb,
-+ 0x59, 0x09, 0xbd, 0x34, 0x50, 0x82, 0xc2, 0x8f, 0xd7, 0x5d, 0x07, 0x55,
-+ 0x5c, 0x08, 0xc2, 0xc9, 0x21, 0x40, 0xaa, 0xb7, 0x17, 0x8a, 0x48, 0xf1,
-+ 0x86, 0x87, 0xa6, 0x62, 0x87, 0xb8, 0x79, 0x9a, 0xb7, 0xa2, 0xc8, 0x8e,
-+ 0xdb, 0x4c, 0x6a, 0xc5, 0x58, 0x33, 0x16, 0xfd, 0xb7, 0xa7, 0x2e, 0x72,
-+ 0x40, 0x70, 0x61, 0x9e, 0x1e, 0xcd, 0x4b, 0x84, 0x6d, 0x5d, 0x6f, 0x33,
-+ 0xdb, 0x42, 0x00, 0xcd, 0xb4, 0x45, 0x85, 0x62, 0xcd, 0x9f, 0x6b, 0xff,
-+ 0x37, 0x3e, 0x0d, 0xf6, 0x86, 0x29, 0xca, 0x98, 0x6e, 0xeb, 0x81, 0x3b,
-+ 0xd3, 0xc5, 0xd5, 0x4a, 0xf9, 0x63, 0x18, 0x5b, 0x42, 0xdb, 0xd9, 0x61,
-+ 0x47, 0x60, 0xac, 0x3d, 0x09, 0x7d, 0x10, 0x75, 0x40, 0xbb, 0x24, 0xd9,
-+ 0x0d, 0xe2, 0x92, 0x7a, 0x3c, 0xd9, 0x8f, 0xc5, 0xa4, 0x2f, 0x9d, 0xf2,
-+ 0x2b, 0x3b, 0x61, 0x65, 0x45, 0xdd, 0x19, 0x8b, 0xcc, 0x2e, 0x7f, 0xa6,
-+ 0x1d, 0x18, 0xc1, 0xae, 0x4c, 0x0f, 0xd8, 0xd4, 0xa0, 0x6b, 0x68, 0x68,
-+ 0xda, 0x4b, 0x00, 0x71, 0x5e, 0x27, 0x76, 0x4a, 0x48, 0x74, 0xe0, 0x6e,
-+ 0xd1, 0x10, 0x14, 0x1f, 0x12, 0xa4, 0xe9, 0xc6, 0xb5, 0x10, 0x16, 0xf8,
-+ 0xf6, 0x76, 0x59, 0xe9, 0xfd, 0x01, 0xe8, 0xc8, 0x7a, 0x50, 0xfd, 0x5a,
-+ 0xd6, 0x8e, 0xc8, 0xda, 0x76, 0x63, 0x1c, 0xa8, 0x3f, 0x99, 0xfc, 0x9f,
-+ 0x43, 0x80, 0x12, 0xc9, 0x1a, 0xcf, 0xb1, 0x94, 0x07, 0x8d, 0x04, 0x39,
-+ 0xc1, 0x3b, 0xb4, 0xe5, 0x3a, 0xe3, 0xa7, 0x7a, 0x62, 0x2a, 0x34, 0xad,
-+ 0x98, 0x29, 0x58, 0x96, 0x50, 0xff, 0x99, 0xe0, 0x23, 0x22, 0x6d, 0xc5,
-+ 0x8e, 0x1f, 0x4b, 0x7c, 0xb8, 0x59, 0xce, 0xa3, 0x67, 0xd7, 0x7e, 0xf4,
-+ 0x69, 0x7e, 0x80, 0x6b, 0xf6, 0xc0, 0xd6, 0xd0, 0xba, 0x12, 0xb8, 0x39,
-+ 0xfc, 0x06, 0x1d, 0xf5, 0x4c, 0x17, 0xce, 0xaa, 0xc8, 0x64, 0x7e, 0x0d,
-+ 0xb2, 0x4c, 0x9c, 0xf6, 0xaf, 0xe1, 0xd1, 0xbf, 0xc3, 0x43, 0x15, 0x42,
-+ 0x5b, 0xe8, 0x89, 0xfd, 0x2d, 0x09, 0xd4, 0x4f, 0xf2, 0x05, 0x6f, 0x4d,
-+ 0x8f, 0xd3, 0x1e, 0x0c, 0x54, 0x8e, 0xe4, 0x60, 0x99, 0xb4, 0x3d, 0x47,
-+ 0xb4, 0x23, 0x2e, 0x86, 0xac, 0x28, 0x1a, 0x6a, 0x46, 0xb5, 0x96, 0xeb,
-+ 0x38, 0xa5, 0x30, 0x73, 0x1a, 0xc2, 0x7c, 0x99, 0xe2, 0x16, 0x36, 0x5f,
-+ 0xf8, 0x4b, 0xf6, 0xf4, 0xc6, 0xfd, 0xc7, 0xde, 0xef, 0xbe, 0x44, 0xb8,
-+ 0x11, 0x13, 0x12, 0x1c, 0x9c, 0xfe, 0x3f, 0xd6, 0xc1, 0x09, 0xb7, 0x28,
-+ 0xf0, 0x6b, 0x7a, 0x0f, 0xdf, 0x32, 0x80, 0x6f, 0x9d, 0x69, 0x61, 0xab,
-+ 0x9a, 0xed, 0x53, 0xe5, 0x9d, 0x9a, 0x39, 0x85, 0x65, 0x8c, 0xf1, 0x62,
-+ 0x83, 0x17, 0x91, 0xba, 0x60, 0xe1, 0x41, 0x30, 0x15, 0x51, 0x50, 0x79,
-+ 0x6a, 0xc4, 0xf2, 0x89, 0x3d, 0xc5, 0x08, 0x33, 0xa2, 0x51, 0x19, 0xac,
-+ 0x38, 0xcd, 0x50, 0xb6, 0x63, 0xdd, 0xa8, 0x2a, 0xcd, 0x7f, 0x86, 0x1f,
-+ 0x60, 0x3f, 0xc2, 0x8e, 0x33, 0xce, 0xa0, 0xcb, 0x21, 0xa4, 0x22, 0xdb,
-+ 0x0c, 0xba, 0xd4, 0x99, 0xf5, 0x61, 0x4d, 0xb5, 0xd2, 0x1f, 0xa0, 0xb4,
-+ 0x6c, 0xbb, 0x4f, 0x8a, 0x6f, 0xfc, 0x16, 0x03, 0x75, 0x1e, 0xb1, 0x94,
-+ 0xe4, 0x34, 0x09, 0x89, 0x61, 0x1d, 0x5b, 0x82, 0x4a, 0xed, 0x05, 0xde,
-+ 0xb8, 0x5a, 0x7f, 0x06, 0x2d, 0x80, 0x88, 0xc6, 0x7b, 0x8f, 0xb8, 0x1e,
-+ 0xb6, 0xaf, 0x5a, 0x84, 0xbb, 0x6b, 0x0f, 0xa0, 0xf9, 0x4e, 0xea, 0x7c,
-+ 0xc2, 0x63, 0x85, 0x22, 0x70, 0x96, 0x86, 0x49, 0x57, 0x69, 0x26, 0xd7,
-+ 0xef, 0x8c, 0x03, 0x2e, 0xfc, 0x3c, 0x80, 0xab, 0x17, 0xf8, 0x26, 0x7d,
-+ 0xf4, 0x08, 0x91, 0x25, 0xe8, 0x36, 0x45, 0xee, 0x46, 0xb9, 0x7a, 0x0a,
-+ 0x84, 0xd9, 0x95, 0x69, 0x0c, 0x19, 0x46, 0x88, 0xa1, 0x05, 0x9d, 0x0e,
-+ 0x36, 0x97, 0x49, 0x8f, 0xbe, 0x7a, 0x40, 0x75, 0x33, 0x38, 0x33, 0x48,
-+ 0xa7, 0x6a, 0xd1, 0x56, 0x6e, 0x08, 0x35, 0xa7, 0xb4, 0x83, 0xdf, 0x23,
-+ 0xe1, 0xe8, 0xc9, 0x15, 0xa2, 0x8d, 0xac, 0xe1, 0x8a, 0x09, 0x19, 0x9f,
-+ 0x9a, 0x14, 0x0d, 0x65, 0xe4, 0x94, 0x05, 0x2e, 0x9b, 0x5c, 0x97, 0xd0,
-+ 0x0b, 0x75, 0xf5, 0xa3, 0x43, 0x68, 0x12, 0xf5, 0xd8, 0x0d, 0x6a, 0x39,
-+ 0x60, 0x63, 0x9c, 0x15, 0x38, 0xbe, 0x43, 0xac, 0xc1, 0xf6, 0x20, 0x6e,
-+ 0x40, 0xa2, 0x2a, 0xdb, 0x32, 0xd8, 0x7f, 0xc7, 0xe3, 0x64, 0x89, 0x5b,
-+ 0x47, 0x31, 0xb9, 0x0b, 0xff, 0x2b, 0x4c, 0x6e, 0xbf, 0xa9, 0x57, 0x40,
-+ 0x5b, 0x81, 0xf2, 0xe5, 0xc1, 0x96, 0xf2, 0x14, 0xbf, 0x89, 0xfa, 0xbc,
-+ 0x22, 0x8e, 0xd8, 0xa7, 0x78, 0xce, 0xe9, 0xe7, 0x25, 0xf6, 0x93, 0x14,
-+ 0x03, 0xf6, 0x3a, 0xe2, 0xc8, 0x1e, 0xee, 0xa1, 0x73, 0x69, 0x9c, 0x51,
-+ 0x2e, 0x3e, 0xbf, 0x2c, 0x1e, 0xb8, 0x16, 0x67, 0x05, 0x4b, 0x57, 0xee,
-+ 0x60, 0xb8, 0xcd, 0xcf, 0xf1, 0x5e, 0xc5, 0xb4, 0x6a, 0x1b, 0x90, 0x79,
-+ 0xe8, 0x49, 0xa4, 0x85, 0x33, 0xc8, 0x6d, 0x22, 0xcb, 0x05, 0x78, 0xe0,
-+ 0xfe, 0xcf, 0x89, 0xac, 0x42, 0x80, 0x44, 0x0b, 0x9a, 0xfc, 0x7b, 0x09,
-+ 0x6d, 0xb4, 0xfa, 0xc5, 0xe5, 0x2e, 0x39, 0x7f, 0x74, 0xbf, 0xb8, 0xe2,
-+ 0xd2, 0x42, 0xbf, 0xdf, 0x5f, 0x49, 0x20, 0xb3, 0x22, 0xd8, 0xac, 0xd8,
-+ 0x0a, 0xa9, 0x52, 0x58, 0x6f, 0xe4, 0xf7, 0xc2, 0xae, 0xdb, 0xf7, 0x14,
-+ 0x25, 0xcb, 0x3f, 0x4e, 0xd9, 0x8f, 0xbc, 0x1c, 0xae, 0xcf, 0x3a, 0x0a,
-+ 0x1b, 0x7a, 0xfe, 0x25, 0x32, 0x00, 0x7b, 0x82, 0xc3, 0xbe, 0x4c, 0x77,
-+ 0x66, 0xee, 0xa8, 0x58, 0xc4, 0xff, 0x0d, 0x33, 0x70, 0xb3, 0x97, 0x8f,
-+ 0x22, 0xd9, 0x3e, 0xa2, 0x93, 0x5c, 0xd8, 0x78, 0x15, 0x02, 0x4e, 0x8e,
-+ 0x80, 0x90, 0x3f, 0x18, 0xfd, 0x36, 0xd0, 0xc4, 0xe1, 0x34, 0x89, 0x62,
-+ 0x64, 0x0a, 0xc4, 0x20, 0x0f, 0x3d, 0x0b, 0xfc, 0xf3, 0x9c, 0x35, 0x0d,
-+ 0x1d, 0x9a, 0xc3, 0xb4, 0x51, 0x26, 0x68, 0x92, 0x0c, 0x70, 0xd3, 0x4e,
-+ 0x7a, 0xcd, 0x85, 0xc5, 0x4f, 0xb9, 0x11, 0x8c, 0x33, 0x35, 0xb9, 0x87,
-+ 0x9d, 0x40, 0x47, 0xe4, 0x38, 0x22, 0x62, 0x48, 0x90, 0x4f, 0x2f, 0x36,
-+ 0x91, 0x76, 0x6c, 0x20, 0x0a, 0xce, 0x09, 0xd6, 0xbe, 0x08, 0xa6, 0x85,
-+ 0x64, 0x8a, 0x95, 0x2b, 0x0d, 0x75, 0x5d, 0x6f, 0x45, 0x5e, 0x21, 0x0f,
-+ 0x69, 0x26, 0xf4, 0x5a, 0x76, 0x43, 0xc9, 0x99, 0xf7, 0xa5, 0x73, 0x69,
-+ 0x8d, 0x94, 0xcd, 0x73, 0x74, 0xd2, 0xc0, 0xb2, 0x54, 0xb9, 0xc1, 0x82,
-+ 0x07, 0xd1, 0x8a, 0x9b, 0x51, 0x0b, 0x7f, 0xf2, 0x22, 0x10, 0xb6, 0x0d,
-+ 0x7d, 0x8b, 0x81, 0x8b, 0x5a, 0x87, 0xfb, 0x16, 0xc4, 0xa2, 0xfc, 0x9c,
-+ 0x5f, 0x7d, 0x71, 0xf1, 0x74, 0x69, 0x15, 0x91, 0xfd, 0x5b, 0xdc, 0xc6,
-+ 0xde, 0xff, 0x77, 0x03, 0x8a, 0xab, 0xc7, 0xdb, 0x84, 0xce, 0x78, 0x27,
-+ 0xde, 0xfb, 0x79, 0xc5, 0x5b, 0x7d, 0x25, 0x27, 0xe8, 0x87, 0xca, 0x94,
-+ 0xe3, 0xcd, 0xc2, 0x72, 0x36, 0x0f, 0xce, 0x7d, 0xb9, 0x45, 0xa6, 0xd9,
-+ 0xdb, 0x72, 0x95, 0xe9, 0xb0, 0x4c, 0x13, 0x0b, 0xdd, 0x8a, 0x15, 0x7d,
-+ 0x14, 0x71, 0xe7, 0x7f, 0x6f, 0x31, 0x7d, 0x0e, 0x16, 0x22, 0xf2, 0x82,
-+ 0x75, 0x6a, 0x04, 0x44, 0x82, 0x07, 0x18, 0xfe, 0xf1, 0x4c, 0x93, 0x57,
-+ 0xd7, 0x14, 0x92, 0x75, 0x72, 0xb8, 0xac, 0x46, 0x03, 0x97, 0xe2, 0xd1,
-+ 0xf3, 0xb0, 0x20, 0x78, 0x83, 0x1f, 0xe0, 0x7e, 0xf2, 0x76, 0xd3, 0x3e,
-+ 0xbe, 0xca, 0x44, 0x9d, 0x69, 0xb0, 0xc2, 0xe4, 0x69, 0xac, 0x26, 0x48,
-+ 0x56, 0x14, 0x1e, 0xed, 0x28, 0x9c, 0xbb, 0x7a, 0x10, 0x17, 0x19, 0x26,
-+ 0x3f, 0x5a, 0x62, 0x65, 0x8c, 0x9a, 0xa2, 0xaf, 0xb3, 0xb9, 0xba, 0xc5,
-+ 0xcd, 0xd5, 0xde, 0xf2, 0x05, 0x08, 0x2c, 0x2e, 0x4f, 0x6d, 0x72, 0x81,
-+ 0x85, 0x94, 0x98, 0xb1, 0xba, 0xc0, 0xfc, 0x19, 0x21, 0x29, 0x33, 0x37,
-+ 0x39, 0x3f, 0x56, 0x6b, 0x70, 0x83, 0xa8, 0xaa, 0xc2, 0xcb, 0xdb, 0xee,
-+ 0x0d, 0x15, 0x18, 0x1c, 0x43, 0x49, 0x50, 0x68, 0x6c, 0x6f, 0x71, 0x73,
-+ 0x96, 0xa0, 0xcc, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x14, 0x23, 0x34, 0x44,
-+ };
-+ static const unsigned char ml_dsa_65_sig[]= {
-+ 0x16, 0x95, 0x22, 0xcb, 0xad, 0xbb, 0xce, 0x7e, 0x77, 0x11, 0xe2, 0x51,
-+ 0x5e, 0xba, 0x56, 0x1c, 0x4c, 0x8f, 0x6a, 0x9f, 0xd9, 0x0d, 0x99, 0xbe,
-+ 0x8d, 0x44, 0x76, 0x15, 0xa0, 0x63, 0x84, 0x92, 0x88, 0x42, 0x1b, 0x64,
-+ 0x95, 0x0b, 0x04, 0x50, 0x26, 0xec, 0x46, 0x71, 0xef, 0x5c, 0x50, 0xbb,
-+ 0xe0, 0x56, 0xff, 0xc6, 0x03, 0xbb, 0x1f, 0x1d, 0x68, 0xe4, 0x8e, 0x87,
-+ 0x87, 0x49, 0xcd, 0xf5, 0x92, 0xe4, 0x55, 0x30, 0x9f, 0x59, 0x02, 0xe8,
-+ 0xec, 0xe6, 0xef, 0x86, 0x45, 0x36, 0x27, 0xfa, 0x71, 0x41, 0x86, 0x4c,
-+ 0xe0, 0xb9, 0x99, 0xe6, 0x54, 0xae, 0x7c, 0x94, 0x6e, 0xe5, 0xa6, 0x89,
-+ 0x9d, 0xde, 0x38, 0x97, 0x26, 0x35, 0x64, 0x39, 0x6d, 0x7f, 0x2b, 0x84,
-+ 0xd1, 0x6f, 0x39, 0x7a, 0x05, 0x2c, 0x40, 0xc3, 0x90, 0xbc, 0x5d, 0xeb,
-+ 0x11, 0x1a, 0xbd, 0x43, 0x11, 0x3a, 0xfc, 0x2e, 0xf1, 0x8b, 0x88, 0xe8,
-+ 0x26, 0x79, 0xb2, 0x4f, 0x5e, 0xf5, 0x09, 0xa8, 0xa4, 0xb8, 0x9e, 0xcb,
-+ 0xa5, 0xeb, 0xac, 0x29, 0xa7, 0x40, 0x73, 0x70, 0x72, 0xa7, 0x66, 0xce,
-+ 0x2d, 0x82, 0xe5, 0x0a, 0x2c, 0x37, 0x03, 0xd4, 0x0d, 0x53, 0xb4, 0x4c,
-+ 0x24, 0x23, 0x1c, 0x5c, 0x73, 0x6f, 0x06, 0x0d, 0x9b, 0x3f, 0x4d, 0xf1,
-+ 0xb6, 0x32, 0x47, 0xfc, 0x96, 0xb9, 0x1d, 0x2e, 0xf0, 0xa1, 0x2c, 0x6b,
-+ 0x30, 0x1f, 0x63, 0x9c, 0x09, 0xca, 0x44, 0x07, 0x01, 0x96, 0x3b, 0xac,
-+ 0xdd, 0x30, 0xef, 0x40, 0x6a, 0x7e, 0xf4, 0xa4, 0x5e, 0x1c, 0x80, 0x44,
-+ 0x1c, 0x9e, 0x90, 0x4d, 0x0e, 0x5e, 0x16, 0x45, 0x0c, 0x46, 0x6a, 0xcb,
-+ 0xd0, 0xf1, 0x08, 0x76, 0x7a, 0x4e, 0xa1, 0xd9, 0x0e, 0xfd, 0xe9, 0xb7,
-+ 0x8d, 0x79, 0x14, 0xa3, 0xe0, 0x1c, 0x99, 0xf4, 0xee, 0x07, 0xc5, 0x04,
-+ 0x8f, 0x35, 0xac, 0x35, 0x0e, 0x6e, 0x56, 0xf6, 0xf6, 0xb3, 0x71, 0x2b,
-+ 0x33, 0x03, 0xb6, 0xc7, 0x79, 0x72, 0xef, 0x8d, 0x39, 0x85, 0xeb, 0x0e,
-+ 0x53, 0x7b, 0x99, 0xda, 0x92, 0x8a, 0xf7, 0x5b, 0xec, 0x8b, 0xf0, 0x72,
-+ 0xcf, 0x69, 0x79, 0xb5, 0xff, 0x01, 0x9c, 0xa3, 0xb8, 0xaa, 0x69, 0x6c,
-+ 0x5f, 0x25, 0x7d, 0x09, 0x67, 0xf9, 0x75, 0xa2, 0x3d, 0xd6, 0xb6, 0x6a,
-+ 0x67, 0xae, 0x86, 0xc6, 0x17, 0x33, 0x6a, 0xea, 0xda, 0xbf, 0xf1, 0x8f,
-+ 0x6b, 0xb2, 0x5c, 0x75, 0x0b, 0xf8, 0x4a, 0x68, 0xfa, 0x4d, 0xeb, 0x1f,
-+ 0xd3, 0xaa, 0x1e, 0xe6, 0x10, 0x8c, 0x55, 0x60, 0xb4, 0x72, 0x97, 0x0c,
-+ 0xac, 0xe9, 0xe4, 0x7d, 0x87, 0xdd, 0xb8, 0x10, 0x3e, 0x4e, 0x9d, 0x88,
-+ 0x5b, 0xb9, 0x4d, 0xd7, 0xe2, 0x0c, 0x31, 0xe0, 0x2a, 0xa8, 0xa3, 0x31,
-+ 0xb3, 0x99, 0x65, 0x4d, 0x1c, 0xd5, 0x30, 0x76, 0x50, 0xf1, 0x67, 0x8d,
-+ 0x05, 0xd0, 0x65, 0x19, 0x27, 0xd3, 0x77, 0xc2, 0xc8, 0x4a, 0x08, 0x14,
-+ 0xdd, 0x3a, 0x5b, 0x31, 0xcd, 0xa4, 0x31, 0x7f, 0x01, 0x8f, 0xd1, 0x26,
-+ 0x10, 0xde, 0x36, 0xbb, 0xa1, 0xf1, 0x82, 0xec, 0x83, 0xb8, 0xd2, 0xa3,
-+ 0x25, 0xe2, 0x09, 0xfe, 0xaf, 0x16, 0x33, 0xc7, 0xc5, 0xe9, 0xe5, 0xc6,
-+ 0xce, 0xc8, 0xb0, 0xc4, 0x68, 0x75, 0x09, 0x43, 0xa2, 0x58, 0x8d, 0xde,
-+ 0xf7, 0xff, 0x41, 0x63, 0xf5, 0xce, 0xd8, 0x6c, 0x9a, 0x44, 0x48, 0x77,
-+ 0x69, 0x2a, 0x5e, 0x3d, 0xa0, 0x22, 0xbc, 0xfc, 0xc0, 0xbe, 0x46, 0x07,
-+ 0x5c, 0xb6, 0xa0, 0x2c, 0x5d, 0x64, 0xf6, 0x33, 0x4a, 0x5e, 0x91, 0x9e,
-+ 0x1e, 0x5c, 0x93, 0x68, 0x3c, 0x76, 0xcf, 0xda, 0xbb, 0x94, 0x38, 0x31,
-+ 0xda, 0x03, 0x83, 0x28, 0xd0, 0x0d, 0x7e, 0x5b, 0x9d, 0x35, 0x27, 0xfc,
-+ 0x74, 0x5b, 0x53, 0x75, 0x84, 0x81, 0x9f, 0x60, 0xbc, 0xef, 0xd7, 0x3c,
-+ 0x12, 0x52, 0xba, 0xa9, 0x67, 0x62, 0x49, 0x41, 0x22, 0xcd, 0x84, 0xd5,
-+ 0xef, 0x18, 0x4d, 0x30, 0x5a, 0xb0, 0x7d, 0xc6, 0x0d, 0x5f, 0x0f, 0x3e,
-+ 0x26, 0x89, 0x63, 0x3a, 0x11, 0xc2, 0xc1, 0x56, 0x34, 0x7b, 0x5d, 0x5e,
-+ 0x39, 0x2d, 0x63, 0x2f, 0xdb, 0x1e, 0x78, 0x72, 0x85, 0x58, 0x57, 0x5b,
-+ 0x00, 0xea, 0xfd, 0x8b, 0xc6, 0x37, 0xd9, 0xfb, 0x50, 0x42, 0x23, 0x9f,
-+ 0x3f, 0x87, 0xb5, 0x12, 0x31, 0x92, 0xda, 0x1c, 0x15, 0x38, 0xc1, 0x9b,
-+ 0xf7, 0x64, 0xde, 0x1f, 0x99, 0xc0, 0x1c, 0x1b, 0xa7, 0x27, 0xcc, 0x60,
-+ 0x61, 0x9a, 0x94, 0x7f, 0xe0, 0xd0, 0x71, 0xd0, 0x4e, 0xe3, 0xc0, 0x72,
-+ 0xc1, 0x1c, 0x0a, 0xa5, 0x7b, 0x5a, 0x52, 0x16, 0xc4, 0x91, 0xa4, 0x3b,
-+ 0x18, 0x85, 0xaf, 0xc8, 0x5f, 0x5f, 0xad, 0x75, 0x63, 0xb1, 0x51, 0xd9,
-+ 0x58, 0xe0, 0x4d, 0x72, 0x2b, 0x3b, 0x99, 0xfd, 0x36, 0xa3, 0xe1, 0x03,
-+ 0x18, 0x5c, 0xdc, 0xed, 0xa3, 0x7a, 0x41, 0x8a, 0x35, 0x78, 0xba, 0x58,
-+ 0x1a, 0xe5, 0xd8, 0xee, 0x47, 0xb3, 0xbe, 0x4a, 0xbc, 0x8b, 0x1d, 0x89,
-+ 0xe1, 0x5c, 0xc2, 0x6d, 0x81, 0xe8, 0x05, 0x9b, 0xbc, 0x6a, 0x8c, 0xef,
-+ 0x0f, 0xac, 0xf1, 0xd9, 0xaa, 0xce, 0x79, 0x61, 0x73, 0x5b, 0xa4, 0x0e,
-+ 0xb0, 0x5d, 0x29, 0x21, 0xfd, 0xd2, 0xb2, 0xe8, 0x3b, 0x70, 0xa2, 0xba,
-+ 0xae, 0x71, 0xef, 0x5b, 0x3e, 0xfd, 0x44, 0x8f, 0x4c, 0x10, 0x49, 0xa8,
-+ 0x33, 0xee, 0xc5, 0xab, 0x00, 0x32, 0x6b, 0x4a, 0x5d, 0xfa, 0xd0, 0x7d,
-+ 0x72, 0x7f, 0xae, 0x63, 0x11, 0x2e, 0x11, 0x6e, 0xc7, 0xa4, 0xef, 0x07,
-+ 0xf1, 0xf9, 0x06, 0x01, 0xe6, 0x77, 0x6c, 0x25, 0x0e, 0xe9, 0xc3, 0x61,
-+ 0x4e, 0x6c, 0x03, 0xde, 0x54, 0x6c, 0x86, 0x76, 0xbc, 0xd9, 0xa8, 0x0d,
-+ 0x33, 0xbb, 0x28, 0x23, 0xdb, 0x78, 0x70, 0xc9, 0xac, 0xd3, 0x94, 0x92,
-+ 0x98, 0xc1, 0x94, 0xac, 0x5d, 0x2a, 0x12, 0xe1, 0xeb, 0x34, 0xcf, 0x99,
-+ 0xdc, 0xac, 0xf1, 0x08, 0xd8, 0x5c, 0x65, 0xd5, 0x13, 0xb2, 0xfe, 0x59,
-+ 0xe2, 0x8c, 0x9a, 0x63, 0xb6, 0x00, 0x04, 0x6f, 0xf5, 0xbd, 0xa8, 0x25,
-+ 0x45, 0x20, 0x0d, 0x15, 0xd4, 0x7f, 0xc2, 0xa2, 0x37, 0x36, 0x98, 0xf9,
-+ 0xf4, 0xad, 0x8a, 0x80, 0x38, 0xd5, 0xba, 0x7c, 0x97, 0xa5, 0x12, 0xd5,
-+ 0x1e, 0xab, 0x7f, 0xa6, 0x9c, 0x90, 0xb7, 0x6f, 0xe4, 0xcd, 0xc6, 0x5c,
-+ 0x67, 0xf1, 0x7c, 0xce, 0x0e, 0xca, 0xc2, 0xbe, 0x95, 0x9f, 0x36, 0x56,
-+ 0x32, 0x32, 0xdc, 0x78, 0xed, 0x3d, 0xb9, 0xbc, 0x49, 0x9d, 0x77, 0xae,
-+ 0xff, 0x29, 0x71, 0x72, 0x7b, 0x44, 0x1a, 0x76, 0x00, 0x1e, 0xaa, 0xdc,
-+ 0xfc, 0x5c, 0xe6, 0x8b, 0xe5, 0x81, 0x99, 0xde, 0xb5, 0xbf, 0x63, 0x26,
-+ 0x21, 0x05, 0x8f, 0x1e, 0xbc, 0x89, 0x47, 0xc3, 0x17, 0x70, 0x32, 0x96,
-+ 0x37, 0x34, 0xbf, 0xeb, 0x39, 0x1a, 0x05, 0xd1, 0x2a, 0xd8, 0xed, 0x91,
-+ 0xbd, 0x58, 0xae, 0xef, 0x29, 0xf9, 0x10, 0x9e, 0xae, 0xbd, 0x2f, 0x53,
-+ 0xd2, 0x66, 0x33, 0x12, 0x6f, 0xbd, 0xf4, 0xf3, 0x2a, 0x06, 0x3d, 0xc7,
-+ 0x63, 0x06, 0x9e, 0x96, 0xe6, 0x84, 0x79, 0x72, 0xbc, 0x98, 0xfd, 0x35,
-+ 0xc5, 0x82, 0xd3, 0xee, 0x6c, 0xc7, 0xce, 0x3b, 0x35, 0x4c, 0x7b, 0x77,
-+ 0x5b, 0x1d, 0x97, 0xd6, 0x96, 0x06, 0xf0, 0x58, 0x27, 0xb2, 0x88, 0x66,
-+ 0x51, 0xf5, 0x70, 0xa1, 0x56, 0x3a, 0xef, 0x39, 0x3d, 0x6d, 0x15, 0xed,
-+ 0x94, 0xe5, 0xaf, 0x41, 0x70, 0xf9, 0xb5, 0xa0, 0x15, 0x3d, 0xa3, 0x0e,
-+ 0xf6, 0x13, 0x58, 0x8b, 0xbe, 0x85, 0xac, 0x17, 0xf2, 0x1d, 0x41, 0xec,
-+ 0xed, 0x39, 0x3d, 0x82, 0x82, 0xd2, 0x91, 0xf1, 0xc6, 0xb7, 0x35, 0x66,
-+ 0x00, 0x26, 0xd6, 0x82, 0x9b, 0xe2, 0x96, 0x65, 0xfa, 0xde, 0x33, 0xc8,
-+ 0xa1, 0x34, 0x6f, 0x75, 0xb3, 0xd1, 0x44, 0xbf, 0xe5, 0xd3, 0x34, 0xaa,
-+ 0x28, 0x73, 0xbd, 0xc1, 0x97, 0x1a, 0xf3, 0x47, 0x8b, 0x3c, 0xa5, 0x54,
-+ 0xaa, 0x14, 0x5a, 0xf5, 0xb3, 0x86, 0x86, 0x33, 0xa3, 0xd1, 0xee, 0x97,
-+ 0x2e, 0x16, 0x37, 0x70, 0x9f, 0x50, 0x5d, 0x1a, 0xfe, 0x40, 0xe7, 0xfb,
-+ 0x0b, 0x25, 0x7e, 0x4f, 0xcc, 0x1c, 0x2f, 0x9b, 0x92, 0xa1, 0x99, 0x49,
-+ 0x3a, 0x84, 0xa0, 0x78, 0xb7, 0xe0, 0x18, 0xbc, 0x50, 0x6b, 0x1d, 0x39,
-+ 0xd5, 0x70, 0xca, 0x0d, 0xf3, 0xd3, 0x45, 0x4d, 0x43, 0xe5, 0xce, 0x91,
-+ 0x0d, 0xca, 0xf8, 0x0b, 0x20, 0xab, 0x24, 0xdf, 0x97, 0x51, 0x57, 0x42,
-+ 0xcf, 0xc3, 0x6b, 0x89, 0xfb, 0xad, 0x0b, 0x48, 0xc1, 0x5b, 0x0b, 0x8c,
-+ 0xce, 0xfa, 0x26, 0xda, 0x63, 0xc2, 0x65, 0x4b, 0x2d, 0xd0, 0xb6, 0xea,
-+ 0x01, 0x14, 0xae, 0x24, 0xb5, 0x82, 0x5b, 0x06, 0x2c, 0xab, 0x53, 0x17,
-+ 0xa7, 0x39, 0x31, 0x5a, 0xd3, 0x5c, 0xff, 0x47, 0x7a, 0x81, 0x58, 0x04,
-+ 0xa4, 0xaf, 0x43, 0x44, 0x21, 0x91, 0x73, 0x2e, 0xa4, 0xff, 0x20, 0x68,
-+ 0x24, 0xa7, 0xd3, 0x20, 0xe6, 0x9e, 0x3a, 0x0c, 0xa1, 0x30, 0x1c, 0xde,
-+ 0xa3, 0x81, 0xdf, 0xe1, 0x73, 0xd3, 0x8e, 0xb5, 0xca, 0x93, 0x91, 0xcd,
-+ 0x09, 0x60, 0xac, 0x52, 0x5c, 0x24, 0xd2, 0xba, 0xd4, 0x7c, 0x9c, 0x7d,
-+ 0x1b, 0x65, 0xe8, 0xd9, 0xb7, 0x0b, 0x96, 0x1a, 0x7c, 0x9c, 0x80, 0x45,
-+ 0xbe, 0x14, 0xd0, 0xf6, 0x80, 0x2e, 0x09, 0x52, 0x2c, 0xe4, 0x6e, 0x5f,
-+ 0x2b, 0x22, 0x62, 0xad, 0xea, 0x73, 0xb7, 0x5f, 0x5c, 0x6b, 0xb3, 0xd8,
-+ 0xee, 0x7c, 0x82, 0xe3, 0x34, 0x2c, 0xac, 0x80, 0x45, 0xf0, 0x8c, 0xc7,
-+ 0x74, 0xc0, 0x8e, 0xe9, 0x9b, 0xf9, 0xe1, 0x10, 0xe5, 0x96, 0xdc, 0x7a,
-+ 0x7d, 0x8d, 0xaf, 0x94, 0x2c, 0x44, 0xe0, 0xef, 0x49, 0x94, 0x84, 0xd5,
-+ 0x77, 0x86, 0x31, 0x06, 0x98, 0x1a, 0xb7, 0x6f, 0xb6, 0x6b, 0xe1, 0x60,
-+ 0xd7, 0x49, 0x97, 0xbd, 0xa7, 0x7c, 0x78, 0xdf, 0xf8, 0x3d, 0x96, 0x72,
-+ 0x3f, 0xfe, 0x53, 0xd9, 0xeb, 0xdf, 0x49, 0xc8, 0x64, 0xd4, 0x00, 0x64,
-+ 0xf1, 0x49, 0x2b, 0x20, 0xe2, 0x41, 0x4a, 0xeb, 0xb6, 0x0a, 0x8f, 0x05,
-+ 0xaa, 0x51, 0x7d, 0x87, 0x38, 0xb1, 0x80, 0x91, 0x9e, 0x34, 0x2b, 0x77,
-+ 0x38, 0x64, 0x20, 0x60, 0x2e, 0xee, 0x95, 0xae, 0xd9, 0x1d, 0x99, 0x6b,
-+ 0x44, 0xb8, 0x27, 0x68, 0x15, 0x3e, 0xfd, 0x14, 0xf9, 0x2f, 0x73, 0x40,
-+ 0x5f, 0x73, 0x61, 0x72, 0x7b, 0xf9, 0x08, 0x8a, 0xc6, 0x6a, 0x38, 0xc2,
-+ 0xb1, 0xd7, 0xd4, 0xe9, 0x8c, 0xc3, 0x4b, 0x36, 0x37, 0xeb, 0xee, 0x55,
-+ 0x95, 0x67, 0x84, 0xf8, 0x2c, 0xe1, 0xc1, 0xbd, 0x98, 0x03, 0xe8, 0x78,
-+ 0x51, 0xcc, 0x2c, 0x08, 0x5c, 0x69, 0x7f, 0x25, 0xd2, 0xb1, 0x90, 0xb8,
-+ 0x77, 0x9a, 0x29, 0xcd, 0x04, 0xef, 0x44, 0xb2, 0x2e, 0x3e, 0x3f, 0xe4,
-+ 0x37, 0x55, 0x12, 0x05, 0x39, 0xac, 0x9c, 0xfe, 0x8a, 0x68, 0xb4, 0xb0,
-+ 0x82, 0x34, 0xa2, 0x0c, 0xf0, 0x20, 0xe1, 0x08, 0x47, 0x33, 0x5e, 0x46,
-+ 0xba, 0xe7, 0x8f, 0x88, 0x80, 0x17, 0x4a, 0xb6, 0xcf, 0xfe, 0xd8, 0xe4,
-+ 0x37, 0xae, 0x93, 0xf3, 0xd6, 0x23, 0x0d, 0xdf, 0xb9, 0x15, 0x3f, 0xe0,
-+ 0x2e, 0x93, 0xaa, 0xe3, 0xeb, 0x1a, 0xc1, 0x47, 0xc7, 0x5a, 0x29, 0xd5,
-+ 0x18, 0xa2, 0x5d, 0x16, 0xaf, 0xe8, 0xbc, 0x15, 0x98, 0x4d, 0xa5, 0x4e,
-+ 0x14, 0xae, 0xfd, 0xf1, 0x98, 0xc3, 0x84, 0xd6, 0x72, 0xcc, 0xb2, 0xe5,
-+ 0x06, 0xc9, 0xcd, 0xa5, 0x66, 0x51, 0xe0, 0x26, 0x95, 0x7d, 0xa5, 0x57,
-+ 0x81, 0x0e, 0x5d, 0x6d, 0x9b, 0x7a, 0x6f, 0x2a, 0x28, 0xaf, 0x34, 0xa8,
-+ 0x68, 0xb1, 0x7e, 0x3e, 0xa3, 0x47, 0xf6, 0xf3, 0x0e, 0x37, 0x36, 0x62,
-+ 0xbf, 0x99, 0xcc, 0x7a, 0xa1, 0x8a, 0x32, 0x80, 0x49, 0x89, 0x2b, 0x7b,
-+ 0xfa, 0xaa, 0xb4, 0xa6, 0x99, 0xf2, 0x01, 0xe8, 0xe6, 0x80, 0xb6, 0x03,
-+ 0x59, 0x05, 0xe9, 0x3a, 0xc7, 0xd0, 0x9b, 0x44, 0xcd, 0x5b, 0x47, 0x9c,
-+ 0x52, 0xd1, 0x62, 0x56, 0x5d, 0x24, 0x0e, 0xb5, 0x8e, 0x12, 0x88, 0x0a,
-+ 0xe4, 0x0e, 0xed, 0xfb, 0xaf, 0xae, 0x15, 0xf4, 0x7b, 0xcd, 0xdd, 0x8a,
-+ 0x97, 0xc5, 0xd4, 0xcb, 0x33, 0x33, 0x8e, 0xec, 0x82, 0xcd, 0x02, 0x55,
-+ 0x62, 0xc9, 0xeb, 0xbf, 0x86, 0x74, 0x98, 0xfd, 0xad, 0x89, 0xc7, 0x30,
-+ 0x85, 0xc8, 0xec, 0xe2, 0x37, 0x9d, 0x86, 0x0c, 0x94, 0x23, 0x2e, 0x73,
-+ 0xbf, 0xe4, 0x15, 0x9b, 0xca, 0x3a, 0x75, 0x41, 0x57, 0x76, 0x5b, 0xf3,
-+ 0xca, 0x6f, 0xf6, 0xb5, 0x7b, 0xe7, 0x2a, 0x5a, 0x62, 0x27, 0x71, 0x93,
-+ 0x5c, 0x0c, 0x88, 0xcb, 0x17, 0x44, 0x57, 0xe9, 0x03, 0x2e, 0x3a, 0x69,
-+ 0xa2, 0x6e, 0x23, 0xec, 0xaa, 0xcc, 0x12, 0x9c, 0xd9, 0x85, 0x99, 0x5e,
-+ 0x8d, 0xd1, 0x05, 0xc0, 0xb5, 0x4f, 0xa7, 0x53, 0xba, 0xe6, 0x00, 0x0f,
-+ 0xc7, 0x49, 0xcc, 0xb2, 0x61, 0x66, 0x23, 0xf5, 0xa1, 0x5d, 0x25, 0xff,
-+ 0x75, 0x96, 0x95, 0x1d, 0xc2, 0x6d, 0x82, 0xd0, 0x0a, 0x8c, 0xd9, 0xa9,
-+ 0xd1, 0x52, 0x31, 0x96, 0xd7, 0x53, 0x6c, 0x3b, 0xd5, 0x03, 0x8c, 0x7d,
-+ 0x16, 0xb5, 0x46, 0x25, 0x7b, 0x0d, 0xc4, 0xf9, 0x1d, 0xca, 0x24, 0x6a,
-+ 0x8f, 0xbe, 0x0a, 0x47, 0xa6, 0x26, 0xeb, 0xe9, 0x21, 0xcd, 0x54, 0x18,
-+ 0x9d, 0x7b, 0x2f, 0x5e, 0x3a, 0x58, 0x23, 0x6f, 0xcd, 0x25, 0x1c, 0xac,
-+ 0xeb, 0x23, 0x81, 0xa1, 0x1c, 0xf6, 0x75, 0x9b, 0x9c, 0x86, 0x66, 0xde,
-+ 0xaa, 0x6b, 0x63, 0xbb, 0x1e, 0x09, 0x32, 0x4b, 0xaa, 0xa3, 0x02, 0x2b,
-+ 0x1d, 0x71, 0xe2, 0xc7, 0x79, 0x39, 0x25, 0x8d, 0x47, 0x26, 0x70, 0x49,
-+ 0x60, 0xcb, 0xec, 0x78, 0x3d, 0x57, 0x83, 0xf4, 0x1b, 0xe1, 0x7b, 0xb1,
-+ 0x56, 0x24, 0xe9, 0x7e, 0x38, 0xc2, 0x41, 0x16, 0x04, 0xc4, 0xcb, 0x82,
-+ 0xa7, 0x58, 0xcb, 0x87, 0x72, 0xba, 0xfc, 0x46, 0x1a, 0x1d, 0x15, 0x72,
-+ 0xb3, 0x04, 0x8c, 0x54, 0x44, 0x9c, 0x3d, 0x33, 0x49, 0x90, 0x14, 0x1d,
-+ 0x5c, 0x94, 0x9f, 0x1f, 0x82, 0x5a, 0x26, 0xbd, 0xc2, 0x78, 0xa4, 0x6e,
-+ 0xb8, 0x5d, 0xd3, 0xfd, 0x33, 0xc4, 0xdd, 0x7d, 0x17, 0xc9, 0x7e, 0x2d,
-+ 0x13, 0x16, 0xeb, 0x90, 0x14, 0xe1, 0x5e, 0xa1, 0x86, 0x3d, 0x81, 0x25,
-+ 0xf9, 0xee, 0x8a, 0x70, 0x56, 0x43, 0x03, 0x30, 0x88, 0xd4, 0xdd, 0x0d,
-+ 0x2b, 0x85, 0x32, 0x9d, 0x6d, 0x79, 0x76, 0x0f, 0x4a, 0x2c, 0x95, 0x80,
-+ 0x01, 0xe3, 0x77, 0x83, 0x56, 0x3b, 0x82, 0xcd, 0xd5, 0x5c, 0x5b, 0x22,
-+ 0xc7, 0x52, 0xb2, 0x06, 0xc4, 0x50, 0xc0, 0xf0, 0xab, 0x89, 0xd8, 0x1c,
-+ 0x76, 0x20, 0x39, 0x1f, 0xb9, 0x28, 0x44, 0xf2, 0xc3, 0x0e, 0x2d, 0xbb,
-+ 0x99, 0xdf, 0x19, 0x05, 0xd7, 0x34, 0x93, 0x7a, 0x1a, 0xff, 0x68, 0x3d,
-+ 0x86, 0x95, 0x3a, 0xcf, 0x1e, 0x70, 0x31, 0xdd, 0xee, 0x9f, 0x3b, 0xa9,
-+ 0x41, 0xd5, 0x70, 0xfe, 0xab, 0x1b, 0x01, 0x95, 0xeb, 0xfe, 0xdc, 0x8d,
-+ 0x09, 0x13, 0xe8, 0x10, 0x51, 0x2b, 0xbc, 0x38, 0x09, 0x27, 0xdc, 0x1b,
-+ 0x31, 0x64, 0xfd, 0xa1, 0x62, 0x0c, 0xe0, 0x5a, 0xa9, 0xb3, 0x9b, 0x4e,
-+ 0x45, 0x7b, 0x72, 0x30, 0x76, 0xbd, 0xb1, 0xb9, 0x8d, 0xe3, 0x23, 0xd8,
-+ 0x47, 0x22, 0xd2, 0x76, 0x4e, 0x4b, 0x9b, 0x74, 0x92, 0x1e, 0xe5, 0x59,
-+ 0x80, 0xe5, 0x83, 0x08, 0x96, 0xfd, 0x6b, 0x99, 0x61, 0x6e, 0x73, 0x09,
-+ 0x16, 0xdf, 0xa9, 0x8c, 0x70, 0x50, 0x92, 0x52, 0x30, 0xc5, 0x5f, 0x3f,
-+ 0x21, 0xd1, 0x49, 0x6b, 0xe0, 0x81, 0xb6, 0x1e, 0xf9, 0xfc, 0xa5, 0x49,
-+ 0xb2, 0xca, 0x09, 0x03, 0x7d, 0x32, 0x6b, 0x52, 0x50, 0xb1, 0xfc, 0xcf,
-+ 0xfd, 0x43, 0xbf, 0xc5, 0x68, 0x2f, 0x06, 0xde, 0x62, 0xca, 0xd3, 0xba,
-+ 0x91, 0x65, 0x28, 0xf1, 0xa8, 0xeb, 0x1f, 0x04, 0x64, 0x03, 0xf7, 0x13,
-+ 0x84, 0x81, 0x22, 0x40, 0xf4, 0x05, 0x1d, 0xf5, 0xa2, 0xa3, 0x95, 0x25,
-+ 0xf8, 0x6a, 0x48, 0x89, 0xea, 0x60, 0x9a, 0x86, 0xf2, 0xde, 0x09, 0xd0,
-+ 0x4f, 0x3e, 0xfc, 0xfc, 0x37, 0x43, 0x45, 0x90, 0x96, 0x73, 0x41, 0xc4,
-+ 0xe4, 0xff, 0x07, 0x7f, 0x81, 0x9a, 0xd3, 0x01, 0xd7, 0x1d, 0xd0, 0x96,
-+ 0xd2, 0xe0, 0x83, 0xe3, 0xd6, 0xbe, 0x2c, 0xdb, 0xdc, 0x76, 0x01, 0x97,
-+ 0xd3, 0x2e, 0x30, 0x66, 0x24, 0x42, 0x08, 0xd6, 0xb4, 0x92, 0x4e, 0xcc,
-+ 0xca, 0x88, 0xaf, 0xa2, 0x99, 0xee, 0x34, 0x6a, 0x2b, 0x68, 0xc9, 0x47,
-+ 0x7b, 0x32, 0x83, 0x56, 0x6f, 0x7f, 0xd3, 0x77, 0x06, 0xfa, 0xc8, 0x32,
-+ 0xf7, 0x65, 0x7a, 0x52, 0xb5, 0xcf, 0x2b, 0x61, 0x20, 0xc1, 0xe7, 0x3d,
-+ 0xa5, 0xad, 0x3e, 0xaf, 0x28, 0x94, 0xf1, 0x12, 0xa4, 0x1e, 0x9c, 0x44,
-+ 0xef, 0x63, 0x45, 0x8c, 0xaf, 0xfc, 0xf7, 0x06, 0x43, 0x94, 0x71, 0x13,
-+ 0xc3, 0x16, 0x6c, 0xd5, 0x1a, 0x1e, 0x1f, 0xc7, 0x65, 0xc7, 0x74, 0x34,
-+ 0xa4, 0x6f, 0x06, 0x8e, 0x33, 0x76, 0xeb, 0x33, 0x38, 0x4a, 0x86, 0x61,
-+ 0xd2, 0x8d, 0xa6, 0x44, 0x1c, 0xc3, 0x73, 0xa1, 0xb4, 0x63, 0xd6, 0x34,
-+ 0x4f, 0x4c, 0xc3, 0x1e, 0xc2, 0x52, 0x78, 0x20, 0x10, 0x0e, 0xde, 0x9a,
-+ 0x64, 0x04, 0xf5, 0xbc, 0x71, 0xb4, 0x4b, 0x32, 0x32, 0x0a, 0xe2, 0x0d,
-+ 0x8a, 0xda, 0x67, 0xe0, 0xf5, 0x8f, 0x0b, 0xe0, 0xe2, 0x3c, 0x8d, 0x27,
-+ 0x64, 0x09, 0xaa, 0xcc, 0x0d, 0x30, 0x78, 0x0c, 0xda, 0x7d, 0x39, 0xd7,
-+ 0xd6, 0x3a, 0x9e, 0xc5, 0xf5, 0x52, 0x94, 0x3c, 0x66, 0xd4, 0x05, 0x0c,
-+ 0x22, 0x64, 0x98, 0xd7, 0x61, 0xfb, 0x24, 0xbc, 0xeb, 0x6f, 0x62, 0xb0,
-+ 0xd6, 0xf2, 0xcd, 0xb1, 0xa1, 0x35, 0x51, 0xa9, 0x78, 0x75, 0xc8, 0xd7,
-+ 0xf2, 0x37, 0x8f, 0x5b, 0x6e, 0xad, 0x9a, 0x5d, 0x61, 0x72, 0x76, 0x67,
-+ 0x53, 0x23, 0x8c, 0xe0, 0xec, 0x6b, 0x66, 0x2e, 0x53, 0x42, 0xb0, 0x0c,
-+ 0xd6, 0xef, 0xaa, 0x5b, 0xc1, 0xd8, 0x3d, 0x9c, 0xaa, 0x19, 0x03, 0x9d,
-+ 0xe4, 0x84, 0x46, 0x66, 0xcd, 0xeb, 0x27, 0xb2, 0x60, 0x59, 0xa9, 0xa1,
-+ 0xb0, 0xc5, 0x9d, 0x72, 0xc4, 0x8f, 0x8f, 0xbf, 0x9d, 0x44, 0xb6, 0x20,
-+ 0x27, 0x3b, 0x3a, 0x10, 0x7b, 0xe8, 0xb4, 0x89, 0x55, 0x82, 0x94, 0x94,
-+ 0x3c, 0xce, 0x51, 0x49, 0x13, 0x52, 0x5d, 0x3a, 0xdf, 0x4a, 0xbf, 0xcb,
-+ 0x2b, 0xb1, 0x70, 0xb9, 0xb5, 0x14, 0x6a, 0xe7, 0x9a, 0x6a, 0x31, 0xac,
-+ 0xd7, 0x93, 0x0b, 0x69, 0xa6, 0x43, 0xac, 0xa8, 0xef, 0xf6, 0x29, 0x16,
-+ 0x87, 0x5e, 0x20, 0xe1, 0xef, 0x80, 0xce, 0xf0, 0x53, 0x27, 0x36, 0x9e,
-+ 0x03, 0x5f, 0x41, 0x4a, 0x62, 0xa5, 0x1e, 0xba, 0xba, 0x8f, 0x14, 0x53,
-+ 0x19, 0x25, 0x13, 0x70, 0x6b, 0x6f, 0x6a, 0xd7, 0xe0, 0x02, 0xfa, 0x38,
-+ 0x4e, 0x38, 0x22, 0xc3, 0x4c, 0xf1, 0xea, 0xe7, 0xc8, 0x8c, 0xe8, 0x38,
-+ 0x0a, 0x54, 0xa0, 0x4c, 0x76, 0xb9, 0xe8, 0x3c, 0x39, 0x46, 0xf3, 0x48,
-+ 0x89, 0xc9, 0x5a, 0xbe, 0x12, 0x3a, 0x1d, 0x75, 0x90, 0x0c, 0x81, 0xf9,
-+ 0x76, 0xca, 0x79, 0x26, 0x94, 0x96, 0xd7, 0x0e, 0x0f, 0xa0, 0x9d, 0xa1,
-+ 0xe4, 0x16, 0x6d, 0x3b, 0xbb, 0x8a, 0x7c, 0x34, 0xaa, 0xaf, 0x77, 0x51,
-+ 0x6a, 0xca, 0x70, 0xc7, 0x87, 0x19, 0x19, 0x48, 0xa8, 0x5c, 0x24, 0x97,
-+ 0x3e, 0x03, 0xee, 0x01, 0xee, 0x97, 0xf0, 0x82, 0xd7, 0x56, 0x9e, 0x29,
-+ 0xe8, 0xc1, 0x0e, 0x21, 0x68, 0xc1, 0xb7, 0x79, 0x40, 0xca, 0xa0, 0xce,
-+ 0x2b, 0x18, 0xd5, 0xeb, 0x2d, 0x05, 0xb5, 0x95, 0x73, 0x6d, 0xb3, 0x12,
-+ 0x67, 0x4f, 0x13, 0xdf, 0xe1, 0x45, 0xf7, 0xed, 0x11, 0x82, 0xbc, 0xc6,
-+ 0x83, 0xbf, 0x87, 0x11, 0x6c, 0x57, 0x8f, 0xa5, 0x11, 0x48, 0x35, 0xef,
-+ 0xc3, 0x13, 0xdc, 0x41, 0x88, 0x14, 0xdd, 0x94, 0x54, 0xe7, 0x07, 0x9b,
-+ 0xed, 0x78, 0xd3, 0xd9, 0x55, 0x8d, 0x83, 0x05, 0x16, 0x7e, 0x90, 0x0b,
-+ 0x0a, 0x7a, 0xa7, 0xe6, 0xd2, 0x62, 0xb6, 0xf6, 0xd6, 0x44, 0x6c, 0x81,
-+ 0x8f, 0x32, 0x9c, 0xdf, 0x5d, 0x8c, 0xbf, 0xb7, 0x2c, 0x96, 0xc0, 0x29,
-+ 0xca, 0xe0, 0xdf, 0x7d, 0xa1, 0xdc, 0xfb, 0x63, 0x94, 0x41, 0xfb, 0xed,
-+ 0xe9, 0x68, 0x3f, 0xea, 0x10, 0x9f, 0x91, 0x22, 0xf2, 0x7e, 0x50, 0x80,
-+ 0x69, 0xad, 0xe0, 0x65, 0x8b, 0x36, 0xb9, 0x9e, 0x7f, 0x59, 0x1a, 0xd0,
-+ 0x30, 0x0f, 0x8a, 0x5e, 0x7f, 0xa5, 0x1e, 0xa6, 0x15, 0x6c, 0xe3, 0x1b,
-+ 0x83, 0x52, 0x74, 0x62, 0x74, 0xc7, 0xd1, 0x81, 0xcf, 0x1d, 0x16, 0x97,
-+ 0x65, 0x30, 0x15, 0x35, 0x1e, 0xec, 0x96, 0x50, 0x3c, 0x04, 0xc5, 0xe4,
-+ 0x66, 0xd6, 0x8e, 0xf6, 0xbd, 0x3e, 0x8c, 0x32, 0x6e, 0xdf, 0x6a, 0xd3,
-+ 0xe3, 0x54, 0x80, 0x1f, 0xe2, 0x0b, 0xe6, 0x6f, 0xdb, 0x2f, 0x29, 0xe5,
-+ 0x55, 0x56, 0x3e, 0x49, 0x2c, 0x6f, 0x51, 0x04, 0x1c, 0x0d, 0x80, 0xae,
-+ 0x6b, 0xf4, 0x7b, 0xa5, 0xc7, 0xeb, 0x64, 0x92, 0xc9, 0x61, 0xb2, 0xfb,
-+ 0xdb, 0x86, 0x99, 0xde, 0x97, 0x43, 0xca, 0xd5, 0x60, 0x8d, 0x60, 0x39,
-+ 0x4d, 0xfc, 0xa5, 0x67, 0xc5, 0x46, 0xdb, 0xc0, 0xe8, 0x9e, 0xa8, 0x2c,
-+ 0x61, 0x58, 0xd1, 0xfb, 0xf1, 0xac, 0x7f, 0x3c, 0x6a, 0x3d, 0xad, 0xd4,
-+ 0x7c, 0x22, 0x2d, 0x09, 0xed, 0x2e, 0xe8, 0x14, 0x30, 0xf2, 0xb5, 0xe6,
-+ 0xfc, 0x0a, 0x8f, 0xe7, 0x9a, 0xb5, 0x6d, 0xb4, 0x3e, 0x69, 0xdc, 0x78,
-+ 0x52, 0x70, 0x59, 0x74, 0x40, 0x0c, 0x5d, 0x0f, 0x85, 0x9b, 0xd1, 0xc8,
-+ 0x08, 0xe5, 0x3c, 0x82, 0xd0, 0xdd, 0x0d, 0x5a, 0xc2, 0xab, 0xc6, 0xab,
-+ 0x2d, 0x91, 0x98, 0xa6, 0x66, 0xcd, 0xde, 0x73, 0xa1, 0x69, 0xdb, 0x01,
-+ 0xf2, 0x43, 0x0f, 0xd3, 0x60, 0xd1, 0x5e, 0x5e, 0xf3, 0xab, 0x18, 0x0c,
-+ 0x50, 0x59, 0xd0, 0x24, 0x27, 0xb5, 0xa7, 0x12, 0xcd, 0x0b, 0xf2, 0x06,
-+ 0xb5, 0x39, 0xb2, 0x86, 0x09, 0x7c, 0x83, 0xa8, 0xe3, 0xd0, 0x75, 0x8d,
-+ 0xa7, 0x9e, 0x9e, 0xbe, 0x4e, 0x7c, 0x87, 0x8e, 0x32, 0x9b, 0xc4, 0x34,
-+ 0xf8, 0x28, 0x01, 0xef, 0x18, 0xfe, 0x00, 0xe3, 0xd4, 0x3f, 0x02, 0x6a,
-+ 0x01, 0x7f, 0x2d, 0xbf, 0xfd, 0x68, 0xea, 0xd8, 0x84, 0xd8, 0xce, 0xa1,
-+ 0xb9, 0x1e, 0x58, 0xe8, 0x01, 0x0c, 0xb5, 0x8a, 0xc1, 0x92, 0x97, 0xab,
-+ 0x52, 0x19, 0xd8, 0xfd, 0x6e, 0x2d, 0xeb, 0xc2, 0x72, 0x77, 0x74, 0x7a,
-+ 0xae, 0xfe, 0x77, 0x4e, 0xdf, 0x85, 0xbd, 0x28, 0xd1, 0xb0, 0x4d, 0x62,
-+ 0x17, 0x87, 0x18, 0x17, 0xc3, 0x3e, 0x1c, 0xef, 0xd1, 0xdd, 0xf8, 0xd3,
-+ 0x68, 0x4e, 0x7f, 0x84, 0xca, 0x33, 0x4a, 0x7d, 0x24, 0x83, 0x7e, 0x6c,
-+ 0x46, 0xa4, 0xc7, 0xe9, 0xf8, 0xe3, 0x5e, 0xd9, 0x31, 0xba, 0x3c, 0xea,
-+ 0x95, 0x25, 0x4e, 0xc2, 0xca, 0xae, 0xa7, 0x56, 0xe1, 0xe4, 0x49, 0xcb,
-+ 0x9a, 0x93, 0xfc, 0x53, 0x53, 0x60, 0x15, 0xce, 0xfd, 0x55, 0xac, 0xd3,
-+ 0x20, 0xc9, 0x4e, 0x62, 0x97, 0x0e, 0x27, 0x07, 0x60, 0x6b, 0x0c, 0x60,
-+ 0x44, 0xde, 0x85, 0x92, 0x7f, 0x78, 0xd7, 0xc7, 0xb9, 0x9a, 0xb9, 0x98,
-+ 0x40, 0x28, 0xdc, 0x31, 0x0e, 0x5e, 0x01, 0xb3, 0x26, 0x7d, 0xbc, 0x7c,
-+ 0x5e, 0x17, 0x66, 0x70, 0x55, 0x57, 0x1a, 0x8c, 0x7f, 0x26, 0x44, 0x28,
-+ 0xdc, 0x9a, 0xbd, 0x39, 0x6f, 0xe6, 0xae, 0x8f, 0x41, 0xcb, 0xc7, 0x59,
-+ 0xd1, 0x97, 0x37, 0x59, 0x10, 0x8e, 0x1c, 0xa1, 0x0e, 0x74, 0x39, 0xfe,
-+ 0x6b, 0x97, 0xe3, 0x05, 0xb4, 0x32, 0x33, 0x5e, 0x93, 0x6a, 0xed, 0xfe,
-+ 0x3d, 0xdf, 0xf2, 0x3b, 0xd6, 0x55, 0x6a, 0x0b, 0x28, 0x43, 0x0f, 0x7c,
-+ 0x55, 0xfd, 0x70, 0xc3, 0xee, 0x3a, 0x66, 0xb5, 0xa6, 0xe9, 0x7f, 0x47,
-+ 0x5b, 0xca, 0x04, 0x91, 0x32, 0x74, 0xd9, 0x13, 0x7b, 0x73, 0x32, 0xb6,
-+ 0xbd, 0x5a, 0xf0, 0x4c, 0x27, 0x2e, 0x1b, 0x44, 0x16, 0xfe, 0x08, 0x98,
-+ 0x36, 0x7f, 0xd7, 0xbc, 0x2d, 0xec, 0xad, 0xf5, 0x85, 0x6b, 0xad, 0xd3,
-+ 0x01, 0x08, 0xd9, 0xab, 0xde, 0x3b, 0x2b, 0xe2, 0x17, 0x18, 0x2b, 0x3e,
-+ 0x6f, 0x7b, 0xa9, 0xc3, 0x2c, 0x4f, 0xe1, 0xfc, 0x49, 0x86, 0x88, 0x95,
-+ 0xb5, 0xb7, 0xd9, 0xe2, 0x33, 0x60, 0xa5, 0xbf, 0xcf, 0x0c, 0x12, 0x3e,
-+ 0x68, 0x6d, 0xc8, 0xf1, 0x08, 0x0d, 0x0e, 0x1d, 0x30, 0x32, 0x34, 0x37,
-+ 0x8a, 0x96, 0x98, 0x9d, 0x9f, 0xca, 0xf6, 0xf8, 0x00, 0x00, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x08, 0x0c, 0x14, 0x19, 0x20, 0x30,
-+ };
-+ static const unsigned char ml_dsa_87_sig[]= {
-+ 0x22, 0x0e, 0xbd, 0x95, 0x83, 0xf6, 0x26, 0xdb, 0x16, 0xb4, 0x95, 0x28,
-+ 0x6f, 0xbe, 0xc9, 0x9f, 0xbd, 0xd8, 0x0a, 0xc8, 0xd9, 0xb7, 0x75, 0x87,
-+ 0xef, 0x06, 0x6f, 0xe7, 0xb0, 0x00, 0x0a, 0xb4, 0x63, 0xd3, 0xff, 0xa2,
-+ 0x05, 0xd8, 0x7c, 0x4e, 0x53, 0x8f, 0x73, 0xc3, 0x20, 0xc5, 0x3b, 0x0f,
-+ 0x37, 0xf8, 0x3f, 0xb1, 0xfa, 0x62, 0x47, 0xe8, 0x1f, 0x94, 0x27, 0x36,
-+ 0x40, 0x98, 0x4f, 0x17, 0xa5, 0x58, 0xe6, 0x6f, 0x72, 0x2a, 0xd5, 0x26,
-+ 0x5d, 0xe2, 0x24, 0x3a, 0xee, 0xf1, 0x11, 0xc2, 0x1b, 0x35, 0x2a, 0x4c,
-+ 0x03, 0x0a, 0x86, 0x7f, 0xff, 0xbf, 0x74, 0x25, 0x0b, 0x6d, 0xd2, 0x26,
-+ 0x0f, 0x7d, 0xf3, 0xdd, 0xa6, 0x56, 0x30, 0xff, 0x02, 0xa9, 0x51, 0x36,
-+ 0x6f, 0x64, 0x9c, 0xd3, 0x47, 0xa4, 0x49, 0x0d, 0x3e, 0x69, 0xd5, 0x24,
-+ 0xb4, 0xf0, 0x8f, 0x9f, 0x43, 0x32, 0x09, 0x2e, 0xdf, 0xc2, 0x06, 0x24,
-+ 0xd8, 0xf1, 0xd6, 0x26, 0x8a, 0xd2, 0x65, 0x02, 0x08, 0x2e, 0xe1, 0x8c,
-+ 0x1a, 0xe0, 0x82, 0x2a, 0x3d, 0xf5, 0xb6, 0x18, 0xf8, 0xc5, 0x94, 0x62,
-+ 0x9c, 0x63, 0x58, 0xda, 0x35, 0xe5, 0x70, 0x0b, 0x17, 0x60, 0xdf, 0x5a,
-+ 0x62, 0x58, 0x3a, 0x56, 0x9f, 0x1d, 0xa8, 0x80, 0xe7, 0x15, 0xf8, 0xd2,
-+ 0x05, 0x80, 0x51, 0xea, 0x7a, 0x65, 0xfb, 0x7b, 0xc7, 0x95, 0x58, 0x30,
-+ 0x5d, 0x8c, 0x4a, 0x84, 0x82, 0x2f, 0x26, 0x66, 0x88, 0xc8, 0x1d, 0x89,
-+ 0xb2, 0x02, 0x23, 0x9c, 0xc3, 0x99, 0xbe, 0x03, 0x69, 0x1d, 0x5e, 0x5f,
-+ 0xcf, 0xa0, 0x2b, 0x15, 0xda, 0x4c, 0xef, 0xaf, 0xc2, 0x32, 0xe8, 0x33,
-+ 0xf0, 0xef, 0xe3, 0x36, 0x96, 0x57, 0x4d, 0x3b, 0xa8, 0x65, 0x64, 0x02,
-+ 0x9a, 0x8b, 0x58, 0x70, 0x66, 0x51, 0x76, 0x85, 0xc4, 0xb8, 0x8b, 0xfc,
-+ 0x26, 0x8b, 0xce, 0xfb, 0x5e, 0xf5, 0xd6, 0x75, 0xc1, 0x8c, 0x0c, 0x3f,
-+ 0x63, 0xef, 0x99, 0x41, 0x88, 0x85, 0x95, 0x6d, 0xa4, 0x36, 0xf2, 0x54,
-+ 0xfa, 0xd0, 0x06, 0x02, 0x5c, 0x14, 0xb4, 0x8c, 0xc6, 0x8f, 0xaa, 0xe8,
-+ 0xa5, 0x10, 0x25, 0x6a, 0x97, 0xf3, 0x6c, 0x2e, 0x80, 0xba, 0x10, 0x7a,
-+ 0x40, 0x11, 0x2d, 0x8b, 0x2d, 0x0f, 0xde, 0x66, 0x0c, 0x98, 0xd3, 0xf0,
-+ 0x69, 0xf9, 0xa6, 0xcb, 0xef, 0x6f, 0x66, 0xa7, 0x8e, 0xc7, 0x09, 0xdd,
-+ 0x1b, 0xdd, 0x26, 0xa5, 0x3f, 0xca, 0xb8, 0x6a, 0x59, 0xa5, 0xe3, 0x0d,
-+ 0x9c, 0xfd, 0xbd, 0x1e, 0x89, 0xb4, 0x01, 0xe2, 0xc6, 0x87, 0x2c, 0x99,
-+ 0xfb, 0x16, 0x04, 0x2b, 0xf7, 0x9b, 0x62, 0xfb, 0xac, 0x3f, 0x7b, 0x15,
-+ 0x22, 0x44, 0xf8, 0x62, 0x34, 0x61, 0xec, 0xb6, 0x35, 0x7c, 0xce, 0x3f,
-+ 0x68, 0x55, 0x53, 0x5a, 0x53, 0x59, 0x8b, 0xae, 0x93, 0xb3, 0x27, 0x16,
-+ 0x67, 0xc1, 0xf7, 0x1c, 0x0b, 0x52, 0x18, 0x79, 0xde, 0x6c, 0x08, 0xc0,
-+ 0x70, 0xe1, 0x75, 0x2e, 0xea, 0x44, 0xcb, 0x25, 0xc2, 0x89, 0x6c, 0x59,
-+ 0x73, 0x39, 0xf8, 0xbb, 0xa7, 0x68, 0xf9, 0x73, 0x0f, 0x47, 0xfc, 0xf7,
-+ 0xf5, 0x9e, 0x20, 0xb3, 0xce, 0xdb, 0x12, 0x33, 0x59, 0x02, 0x7b, 0x45,
-+ 0xdb, 0x05, 0x18, 0xac, 0x2e, 0x70, 0x8e, 0xbb, 0x13, 0xd6, 0xf0, 0xfb,
-+ 0x53, 0x94, 0x1b, 0xc0, 0xab, 0xfd, 0x58, 0x91, 0x68, 0xaf, 0x68, 0x21,
-+ 0x08, 0x92, 0x8b, 0x92, 0xa6, 0x14, 0x57, 0xc9, 0x73, 0xa3, 0x88, 0x6f,
-+ 0x2f, 0x8b, 0x51, 0xc0, 0xbd, 0xa8, 0x39, 0x32, 0x08, 0x91, 0x77, 0x8a,
-+ 0x7d, 0x01, 0xdc, 0x40, 0xf0, 0x99, 0x95, 0x05, 0x04, 0x3b, 0xb0, 0x59,
-+ 0x13, 0xa4, 0x40, 0x30, 0xc0, 0xde, 0xf2, 0x2e, 0x57, 0x6f, 0x0f, 0x97,
-+ 0x5b, 0x7c, 0x9b, 0x54, 0x46, 0x55, 0x7c, 0x61, 0x21, 0x95, 0x35, 0x8c,
-+ 0x8c, 0x8f, 0x7c, 0xc4, 0xeb, 0xe0, 0x3d, 0xe3, 0x15, 0x2c, 0x4b, 0xb5,
-+ 0x77, 0x42, 0xe0, 0x99, 0xe0, 0x4c, 0x51, 0x8d, 0xc4, 0x82, 0xd1, 0xcb,
-+ 0xef, 0xd6, 0xa4, 0x32, 0x44, 0x80, 0x19, 0x54, 0x1d, 0xee, 0x29, 0x4a,
-+ 0xae, 0x61, 0x6a, 0x3c, 0x5a, 0x48, 0x91, 0x88, 0x1d, 0xa1, 0x32, 0x06,
-+ 0x4c, 0x2d, 0x93, 0x65, 0x81, 0x5a, 0xeb, 0xcc, 0x3a, 0x48, 0xc8, 0x30,
-+ 0x0a, 0x15, 0x86, 0x37, 0x35, 0xea, 0x56, 0xee, 0x4d, 0x0a, 0x21, 0xd7,
-+ 0x0d, 0xd6, 0x2d, 0xac, 0x7d, 0x59, 0xe4, 0x69, 0x99, 0xf2, 0x5b, 0xf3,
-+ 0x3f, 0xee, 0xbc, 0xc3, 0xc4, 0x86, 0x9e, 0x65, 0xbc, 0xb9, 0x42, 0xe5,
-+ 0xdc, 0xe4, 0x9c, 0x54, 0x0b, 0xb0, 0xa0, 0x9b, 0x21, 0x71, 0x66, 0xbd,
-+ 0x0c, 0x42, 0x3f, 0xb9, 0xd6, 0x8b, 0x74, 0x76, 0x10, 0x70, 0xaf, 0xd1,
-+ 0x73, 0xf8, 0x7f, 0xdf, 0xed, 0xb5, 0xb3, 0x0c, 0xc6, 0x89, 0xa2, 0x1c,
-+ 0x55, 0x50, 0x55, 0xc0, 0xda, 0x75, 0x07, 0xed, 0xca, 0x8e, 0xdb, 0xef,
-+ 0x88, 0x43, 0xd1, 0x25, 0xcd, 0x1f, 0xce, 0x35, 0x66, 0x8f, 0xc9, 0xcb,
-+ 0x2c, 0x7a, 0x2d, 0xc8, 0x3c, 0xf7, 0x82, 0xc3, 0xae, 0x54, 0xc3, 0x29,
-+ 0x2b, 0x3c, 0xed, 0xd9, 0x7d, 0x8d, 0x9d, 0x97, 0x0b, 0x69, 0xc9, 0xf0,
-+ 0xcd, 0xd2, 0xd2, 0x30, 0x70, 0x37, 0xeb, 0x33, 0xe4, 0xa4, 0x44, 0x38,
-+ 0xba, 0x9f, 0x3f, 0x7d, 0x86, 0x07, 0x8d, 0x0f, 0xe0, 0xe8, 0x8d, 0xf7,
-+ 0x62, 0x2e, 0x09, 0x05, 0x80, 0xd9, 0x4f, 0xc2, 0x16, 0x34, 0x6a, 0x6a,
-+ 0x43, 0x26, 0xcd, 0x6d, 0xd3, 0xb1, 0x62, 0xc3, 0xbb, 0x3c, 0x31, 0xa7,
-+ 0x3f, 0xc3, 0x72, 0x03, 0xf0, 0x56, 0x28, 0xc1, 0x94, 0xae, 0x8e, 0xa0,
-+ 0x4f, 0x50, 0x57, 0x47, 0xc3, 0x22, 0x0d, 0x63, 0xe5, 0x25, 0x71, 0xf4,
-+ 0x10, 0xf8, 0xd6, 0x56, 0xc4, 0x71, 0xb3, 0xba, 0x65, 0x29, 0x14, 0x6c,
-+ 0x06, 0x11, 0x70, 0x0d, 0x1c, 0x9a, 0x89, 0x54, 0x6d, 0x36, 0x21, 0xae,
-+ 0x22, 0x1b, 0x1c, 0xb7, 0x8a, 0xda, 0xc7, 0x9b, 0xb0, 0xdf, 0xec, 0x7b,
-+ 0x2d, 0x6a, 0x90, 0xda, 0x61, 0x59, 0x2e, 0xff, 0xa8, 0x6f, 0xd6, 0xa9,
-+ 0xce, 0xac, 0xf5, 0x8f, 0xd3, 0xa3, 0x75, 0xcd, 0xc7, 0xa7, 0x4a, 0x2c,
-+ 0x3d, 0x77, 0xe7, 0xe2, 0xdc, 0x5d, 0x86, 0xbe, 0x9f, 0x29, 0x0a, 0x60,
-+ 0x33, 0x7d, 0xf5, 0x15, 0xed, 0x5f, 0x6b, 0xf0, 0x99, 0x2a, 0x30, 0xf7,
-+ 0x21, 0x61, 0x55, 0xa2, 0xb3, 0x79, 0x4e, 0xb7, 0xa7, 0x93, 0x3e, 0x7e,
-+ 0x63, 0x10, 0xb9, 0x4b, 0xf0, 0x57, 0xf2, 0xf9, 0x54, 0x73, 0xd6, 0xbf,
-+ 0x80, 0xd2, 0xf9, 0xbe, 0xd5, 0x9e, 0x74, 0x2d, 0x37, 0xd9, 0x24, 0xf9,
-+ 0x52, 0x3d, 0x0e, 0xaf, 0xfb, 0x29, 0x2a, 0x1e, 0x4b, 0x80, 0x22, 0xb1,
-+ 0x75, 0x07, 0x6c, 0xbf, 0xc0, 0x98, 0x40, 0xe7, 0xdb, 0x19, 0x31, 0xf6,
-+ 0x6b, 0x34, 0xa2, 0x58, 0xe2, 0xfb, 0x43, 0x39, 0x44, 0x11, 0xf0, 0xb3,
-+ 0x37, 0x68, 0x96, 0x6f, 0xf1, 0x80, 0x14, 0x8e, 0xd4, 0xd6, 0xfb, 0xdc,
-+ 0xbe, 0x06, 0xd7, 0xd9, 0x25, 0x5d, 0x8c, 0x46, 0x83, 0x9e, 0x22, 0xcb,
-+ 0xb0, 0xa3, 0x14, 0x76, 0x4d, 0x82, 0x9a, 0x1e, 0x5e, 0x68, 0x87, 0xb4,
-+ 0x63, 0x9d, 0x8e, 0xa5, 0x4d, 0xd6, 0x8b, 0xc5, 0x06, 0xb5, 0x71, 0xd1,
-+ 0x72, 0x98, 0x63, 0xe3, 0xc6, 0x14, 0x4a, 0xfa, 0x6d, 0xe7, 0x4a, 0xba,
-+ 0x08, 0x5b, 0x92, 0xdc, 0x19, 0x9c, 0xdd, 0xfe, 0x0c, 0xdc, 0xc4, 0xc2,
-+ 0x8d, 0x1f, 0x6f, 0xf9, 0x93, 0xbb, 0xd2, 0x92, 0x5f, 0xe0, 0xcc, 0xbe,
-+ 0x0b, 0xd5, 0xdf, 0x99, 0x57, 0x27, 0x9e, 0x01, 0x7c, 0x65, 0x70, 0x2c,
-+ 0x56, 0x86, 0xc4, 0x7b, 0x25, 0x96, 0xb7, 0xc9, 0x5f, 0x08, 0x25, 0x6a,
-+ 0x85, 0xbe, 0x3e, 0x7f, 0x6b, 0xe6, 0x26, 0xd6, 0x50, 0x82, 0x24, 0xc2,
-+ 0x06, 0xf7, 0x20, 0x2c, 0x63, 0xfd, 0x94, 0x24, 0x5e, 0x61, 0x5c, 0x59,
-+ 0xac, 0xdb, 0x69, 0xd8, 0x3a, 0xd2, 0x67, 0x25, 0x41, 0xa2, 0x94, 0xe5,
-+ 0x3b, 0x36, 0x99, 0x08, 0xac, 0x27, 0x36, 0xd1, 0x35, 0x08, 0x7d, 0x3a,
-+ 0xd1, 0x5b, 0xb1, 0xd9, 0xae, 0xed, 0xbc, 0x55, 0x72, 0xf4, 0x2c, 0xa8,
-+ 0x0a, 0x2e, 0xfd, 0x33, 0x6f, 0xd2, 0x65, 0xe2, 0xef, 0x38, 0x5b, 0xc4,
-+ 0xca, 0xb2, 0x4c, 0xeb, 0xd4, 0xd5, 0x74, 0x9b, 0x0b, 0x4b, 0x74, 0xc1,
-+ 0x3c, 0xc7, 0x2a, 0xdb, 0x8c, 0x0f, 0x91, 0x1c, 0x4b, 0x79, 0xc1, 0xba,
-+ 0xcf, 0x86, 0x1e, 0x71, 0xcb, 0x43, 0xc0, 0xbf, 0x62, 0x03, 0x5c, 0xad,
-+ 0xbd, 0x00, 0x60, 0x97, 0x71, 0x2e, 0x4c, 0x6b, 0x81, 0x55, 0x04, 0x52,
-+ 0x79, 0xbd, 0x08, 0x92, 0x6d, 0xb6, 0x78, 0x6d, 0x25, 0xd2, 0xa9, 0xf5,
-+ 0x34, 0x9c, 0xc3, 0x44, 0xdc, 0xdd, 0xd0, 0xe3, 0x44, 0x2c, 0xf0, 0xc2,
-+ 0x01, 0x51, 0x70, 0x12, 0x46, 0x6d, 0x7c, 0x6c, 0x1b, 0xca, 0x33, 0xcc,
-+ 0x53, 0xa1, 0xb2, 0x4c, 0x0e, 0x01, 0xc0, 0xae, 0xf0, 0x8e, 0xb4, 0x8f,
-+ 0x13, 0x9a, 0xf2, 0x98, 0x98, 0x6f, 0x0f, 0xaa, 0x8e, 0x97, 0x4f, 0x7e,
-+ 0x69, 0x70, 0x6a, 0xc2, 0x9f, 0xab, 0xdf, 0xe0, 0xe5, 0x4b, 0x9c, 0xf5,
-+ 0xa0, 0xa8, 0xbc, 0x17, 0x3f, 0x29, 0x4d, 0xe1, 0x2c, 0x6f, 0xdf, 0xa1,
-+ 0x85, 0xb4, 0xd1, 0x61, 0xfe, 0x3f, 0x56, 0x7a, 0xf4, 0x9a, 0xc5, 0xc7,
-+ 0xa1, 0x07, 0x87, 0x9b, 0x19, 0x31, 0xda, 0x59, 0xb0, 0xaa, 0x19, 0x86,
-+ 0xfc, 0x05, 0x74, 0x7c, 0x2d, 0xd5, 0xb5, 0x18, 0x15, 0xa3, 0xd0, 0x77,
-+ 0x5a, 0x82, 0xbc, 0xeb, 0x49, 0x7b, 0x91, 0xfd, 0x18, 0x28, 0x2d, 0x81,
-+ 0x7b, 0xf1, 0x33, 0xfc, 0x9f, 0xb4, 0x63, 0x33, 0x30, 0x09, 0x3b, 0xf2,
-+ 0x35, 0xf7, 0x5f, 0x12, 0x21, 0xbc, 0x19, 0xf7, 0xd9, 0x06, 0x16, 0x72,
-+ 0x3d, 0x16, 0xba, 0x89, 0x05, 0xe0, 0x22, 0x91, 0x83, 0x5d, 0xd8, 0x47,
-+ 0x67, 0x08, 0x25, 0x05, 0xe0, 0x3c, 0xd9, 0xe2, 0xa0, 0x86, 0x76, 0xf7,
-+ 0xcb, 0xa6, 0x10, 0x80, 0xbd, 0x01, 0x9a, 0xc0, 0xcf, 0x62, 0x02, 0x45,
-+ 0xf0, 0x3c, 0x78, 0x22, 0x3c, 0xae, 0xdb, 0x50, 0xec, 0x23, 0xae, 0x49,
-+ 0x2f, 0x03, 0x77, 0x52, 0x44, 0x07, 0xeb, 0xf5, 0x09, 0xfd, 0x83, 0x63,
-+ 0xbc, 0x31, 0x90, 0x1b, 0x2d, 0x2c, 0x6a, 0xe1, 0x4b, 0x35, 0xa2, 0x7d,
-+ 0xb4, 0x1f, 0x30, 0x2d, 0x2e, 0x64, 0x13, 0x6b, 0x0d, 0x41, 0xed, 0xf7,
-+ 0x65, 0x90, 0x0a, 0x4d, 0xcc, 0x5d, 0x00, 0x74, 0x34, 0xbf, 0x23, 0xad,
-+ 0x58, 0x42, 0x37, 0xce, 0x65, 0xe6, 0x85, 0x22, 0x60, 0xf4, 0x79, 0x58,
-+ 0x3f, 0x05, 0x2a, 0xd8, 0xd8, 0xa3, 0x04, 0x8d, 0x31, 0x63, 0x7d, 0x12,
-+ 0xab, 0xa6, 0x0f, 0xad, 0x6b, 0x5c, 0x5e, 0x0a, 0xd7, 0xdc, 0x60, 0xb1,
-+ 0x83, 0x79, 0x2e, 0xe3, 0x3e, 0xca, 0x16, 0x83, 0x12, 0x12, 0xb0, 0xf5,
-+ 0x9a, 0x7e, 0x18, 0xce, 0xb0, 0x05, 0x8a, 0x43, 0x37, 0xb2, 0xbf, 0xc3,
-+ 0x70, 0xc9, 0x74, 0x16, 0xaa, 0xac, 0xc0, 0x23, 0x1f, 0xbb, 0xd5, 0xe9,
-+ 0x2a, 0xd2, 0xc5, 0x6a, 0x88, 0x1a, 0x65, 0xdc, 0xb6, 0x93, 0xad, 0xf2,
-+ 0xff, 0x9b, 0xd5, 0x3b, 0x39, 0xee, 0xa4, 0x6c, 0x4e, 0x3b, 0x81, 0x24,
-+ 0x19, 0x18, 0xbf, 0x4d, 0x9b, 0x04, 0x4d, 0x2f, 0x1c, 0x93, 0x50, 0xd5,
-+ 0x98, 0xd9, 0x09, 0xd4, 0xfd, 0xc8, 0x82, 0x4a, 0x06, 0xcd, 0xa0, 0xb6,
-+ 0x11, 0xbf, 0xcd, 0x88, 0x5b, 0x90, 0x24, 0x4d, 0x0e, 0xb0, 0x09, 0x23,
-+ 0x77, 0xa3, 0x13, 0x94, 0x5b, 0xf2, 0x95, 0x5e, 0xbe, 0xe5, 0x90, 0x30,
-+ 0x64, 0xbf, 0x52, 0x14, 0x5a, 0xe3, 0x09, 0x08, 0xa3, 0xd0, 0x9f, 0xf5,
-+ 0x32, 0x22, 0x41, 0x1b, 0x6d, 0x4a, 0xa3, 0x07, 0x3f, 0xfd, 0xe1, 0x0c,
-+ 0xfe, 0xe9, 0x16, 0xc5, 0x46, 0xb4, 0x4c, 0xeb, 0xf2, 0x25, 0xac, 0xef,
-+ 0x5f, 0xe4, 0xef, 0xe9, 0xa3, 0xb0, 0x98, 0x27, 0xc7, 0xb2, 0x53, 0xed,
-+ 0xcb, 0xd1, 0x68, 0x76, 0x36, 0x6a, 0x22, 0x45, 0x33, 0x7d, 0xb4, 0xb9,
-+ 0x9c, 0xb5, 0xcf, 0x56, 0x8d, 0x05, 0x71, 0x26, 0xfe, 0x4c, 0x9e, 0x3d,
-+ 0x37, 0xfd, 0xdc, 0x50, 0x62, 0x21, 0x0e, 0x62, 0x04, 0x0c, 0x25, 0x36,
-+ 0x89, 0x06, 0x29, 0xf7, 0x80, 0x89, 0x6c, 0x20, 0x92, 0xbb, 0x8a, 0x01,
-+ 0xa2, 0xf1, 0x71, 0x18, 0x6f, 0x2a, 0x09, 0x98, 0x6a, 0x94, 0xae, 0xd6,
-+ 0x66, 0x40, 0xba, 0x14, 0x66, 0x2c, 0xb9, 0x18, 0x5e, 0xda, 0xc3, 0x13,
-+ 0x5e, 0xec, 0xac, 0xb0, 0x4e, 0xbd, 0x1c, 0xbd, 0xb3, 0xc3, 0x7e, 0x58,
-+ 0x3e, 0x86, 0xc0, 0xae, 0x6d, 0x7d, 0xac, 0xcc, 0x2f, 0xef, 0xec, 0x02,
-+ 0x33, 0x60, 0xb3, 0xc8, 0xb4, 0x22, 0x03, 0xe0, 0xfb, 0xb9, 0x3a, 0x6f,
-+ 0x45, 0xfc, 0xff, 0x72, 0x08, 0x10, 0xbf, 0xb4, 0x24, 0x8e, 0xfb, 0x52,
-+ 0xf9, 0xa3, 0xdf, 0xca, 0xdb, 0x8e, 0x2c, 0xde, 0x41, 0x9f, 0x6b, 0xba,
-+ 0x08, 0x16, 0xe0, 0xe9, 0x07, 0x3f, 0x00, 0x90, 0xf2, 0xb0, 0x62, 0xc4,
-+ 0x14, 0x9f, 0x47, 0xfc, 0xcd, 0x94, 0xb2, 0xc6, 0xd1, 0xf2, 0x9a, 0xc5,
-+ 0xcc, 0x55, 0xf6, 0xfc, 0x17, 0x50, 0x39, 0x54, 0xea, 0x68, 0xff, 0xbe,
-+ 0x7f, 0x0a, 0x54, 0x45, 0xb3, 0xc8, 0x89, 0x57, 0xaa, 0xfd, 0x5d, 0x41,
-+ 0x32, 0x47, 0x4d, 0x88, 0xe0, 0xfd, 0xe1, 0xe9, 0xf8, 0xe2, 0x6b, 0xc2,
-+ 0xb8, 0xa1, 0x10, 0xa5, 0x5f, 0x51, 0x2c, 0x67, 0x1a, 0xf9, 0xdc, 0x88,
-+ 0xf1, 0x23, 0x3d, 0x09, 0x41, 0x99, 0xd3, 0xfa, 0xdf, 0xa4, 0x9b, 0x60,
-+ 0xc8, 0xb7, 0x70, 0x6d, 0xbe, 0x47, 0x72, 0x1a, 0xfc, 0x17, 0x6f, 0x0a,
-+ 0x35, 0x5e, 0x02, 0x0a, 0x74, 0x4b, 0xbf, 0xa0, 0x22, 0xca, 0xbf, 0x10,
-+ 0x7f, 0xf8, 0x8e, 0x5e, 0xd5, 0x19, 0xa2, 0x77, 0xd3, 0xc8, 0x3b, 0x74,
-+ 0x5a, 0xcd, 0x43, 0x0e, 0x50, 0xb4, 0x40, 0x28, 0x8f, 0xd2, 0x65, 0xb5,
-+ 0xb9, 0x00, 0x94, 0xfb, 0x45, 0xca, 0xfd, 0x03, 0xac, 0x3d, 0xa7, 0x64,
-+ 0x37, 0xc3, 0xc4, 0xf2, 0xf5, 0x71, 0xd7, 0x4a, 0xcf, 0xfe, 0x23, 0xdc,
-+ 0x1f, 0x52, 0x40, 0xec, 0xca, 0x13, 0x42, 0x5d, 0x7f, 0xef, 0x11, 0xcf,
-+ 0x4c, 0xac, 0xfa, 0xd7, 0xb4, 0xf5, 0x2d, 0xfa, 0xb7, 0x3e, 0xdd, 0xd9,
-+ 0x42, 0x6f, 0x5a, 0xbd, 0xcf, 0x84, 0x70, 0x8b, 0x9e, 0xeb, 0x89, 0xa7,
-+ 0x1c, 0xaa, 0xcf, 0xc8, 0xa5, 0xe5, 0x4a, 0x85, 0xf4, 0x7b, 0x87, 0x77,
-+ 0xbd, 0xcd, 0x87, 0x0d, 0xa8, 0xbc, 0xe9, 0x1a, 0x2b, 0x04, 0x49, 0x8a,
-+ 0xee, 0xb9, 0xe5, 0xd6, 0xb7, 0x71, 0xbd, 0x10, 0x3a, 0x7a, 0xbc, 0xca,
-+ 0xdc, 0x1d, 0x02, 0x81, 0x6a, 0x59, 0x49, 0x30, 0x4b, 0x5b, 0xf0, 0x8d,
-+ 0x28, 0x5a, 0x05, 0x06, 0x97, 0x66, 0xd4, 0x0b, 0x44, 0x65, 0x4e, 0x6e,
-+ 0x91, 0x5a, 0x62, 0x6c, 0x0a, 0x30, 0xe5, 0xf1, 0x66, 0x41, 0x04, 0xf3,
-+ 0xf8, 0xa6, 0xc5, 0x6a, 0xb7, 0x88, 0x88, 0xaf, 0x70, 0x9b, 0xc1, 0x98,
-+ 0x08, 0x31, 0xb6, 0xf5, 0xd6, 0x1a, 0x20, 0x7d, 0x25, 0x5e, 0xee, 0x36,
-+ 0x27, 0x8d, 0xc1, 0x06, 0xef, 0x2b, 0x22, 0xbf, 0x22, 0xc3, 0x0c, 0xf8,
-+ 0x38, 0xbc, 0xcf, 0x1d, 0x3c, 0x9c, 0x0d, 0x0b, 0xd7, 0xd9, 0xf8, 0x1a,
-+ 0xf0, 0x97, 0x0e, 0xb3, 0x1f, 0xf8, 0x8d, 0x56, 0x85, 0xca, 0x68, 0x4e,
-+ 0xc2, 0x2b, 0xe2, 0x84, 0x1c, 0xb4, 0x56, 0xeb, 0x99, 0xf4, 0x16, 0xc8,
-+ 0x45, 0xec, 0x3e, 0x2b, 0x97, 0x25, 0xa8, 0x7d, 0xfc, 0x97, 0xff, 0x8c,
-+ 0x96, 0x77, 0x6e, 0x30, 0x92, 0x0e, 0x7a, 0x19, 0xc0, 0x98, 0x54, 0x1d,
-+ 0x16, 0x8e, 0x74, 0xaf, 0x2e, 0x17, 0x0a, 0xcf, 0xc3, 0x69, 0xd2, 0x60,
-+ 0x1a, 0xb6, 0x5a, 0x5f, 0x5d, 0x29, 0x1f, 0x89, 0x0e, 0xf6, 0xdf, 0x9d,
-+ 0x50, 0xc1, 0x09, 0x43, 0xe5, 0xe0, 0xfd, 0x95, 0x32, 0xd9, 0xbb, 0x18,
-+ 0x8e, 0xa3, 0x6c, 0xf7, 0x64, 0xb4, 0x66, 0x5e, 0x83, 0xf2, 0x81, 0x38,
-+ 0xd6, 0x42, 0xec, 0xb4, 0x64, 0x35, 0x14, 0xf0, 0x0f, 0x97, 0x56, 0xf1,
-+ 0x1e, 0xbb, 0x20, 0x1c, 0xb7, 0x3f, 0x95, 0x73, 0x15, 0x23, 0x6a, 0x1d,
-+ 0xf7, 0x66, 0x4f, 0xca, 0x64, 0x60, 0x6f, 0x49, 0x7c, 0x49, 0x66, 0x9d,
-+ 0x2a, 0x1d, 0x15, 0x69, 0x29, 0x3f, 0x3a, 0x67, 0x92, 0xde, 0x95, 0x37,
-+ 0xe2, 0x0e, 0x39, 0xf8, 0x5f, 0x1b, 0x3f, 0x00, 0x09, 0x19, 0xc6, 0x64,
-+ 0x0b, 0xe1, 0x5e, 0xc8, 0x2a, 0x91, 0x73, 0xed, 0x5c, 0x22, 0x56, 0x9c,
-+ 0x8d, 0xcb, 0x15, 0xd3, 0xc9, 0xa3, 0xb4, 0xa3, 0x96, 0xa5, 0xfb, 0xd0,
-+ 0x7f, 0xdb, 0xe3, 0x98, 0x65, 0x62, 0xb0, 0xe3, 0x18, 0x99, 0x97, 0xfc,
-+ 0xef, 0xa5, 0xc8, 0x69, 0xf8, 0x3b, 0x1d, 0xc8, 0xbe, 0xdd, 0xa8, 0xc6,
-+ 0x2b, 0x23, 0xe6, 0x8e, 0x43, 0x65, 0x87, 0xae, 0xfc, 0xb5, 0xf0, 0x0b,
-+ 0xb6, 0x4e, 0x72, 0xf7, 0x37, 0x94, 0x08, 0x46, 0x99, 0xe8, 0x41, 0x9c,
-+ 0xe9, 0x54, 0xb8, 0xfb, 0x0c, 0x54, 0xf7, 0x22, 0xea, 0x27, 0x8c, 0x9b,
-+ 0x8c, 0x6b, 0x3d, 0x6b, 0xf8, 0x37, 0x61, 0x50, 0x60, 0xf9, 0x48, 0x0f,
-+ 0xd2, 0xdc, 0xa5, 0xa0, 0x16, 0x97, 0xe7, 0xbe, 0x86, 0x63, 0xdc, 0x3d,
-+ 0x76, 0x75, 0xea, 0xdc, 0xea, 0x9a, 0x14, 0x05, 0xcd, 0x13, 0x84, 0x85,
-+ 0xdd, 0x70, 0x01, 0x0e, 0x6f, 0xff, 0x00, 0x7d, 0xcd, 0x24, 0xd4, 0x60,
-+ 0x08, 0xdf, 0x27, 0x3d, 0x7f, 0x3a, 0xa5, 0xec, 0x11, 0xbf, 0x7e, 0x2e,
-+ 0xe6, 0xf8, 0x08, 0xe0, 0xee, 0x25, 0x7e, 0x5c, 0xb7, 0x5b, 0x0f, 0x58,
-+ 0xac, 0x5b, 0x73, 0xf9, 0x26, 0x2c, 0xd4, 0x0f, 0x58, 0x8f, 0x7a, 0x07,
-+ 0x5b, 0x19, 0xc3, 0xf3, 0x86, 0xc7, 0x81, 0x3f, 0xbb, 0xfa, 0x2c, 0x84,
-+ 0xc0, 0xc5, 0x78, 0xf8, 0x0e, 0xf7, 0x03, 0xea, 0xaf, 0xe0, 0x58, 0xcd,
-+ 0xba, 0x90, 0x3c, 0xa7, 0x7c, 0x13, 0x73, 0x79, 0xbf, 0x20, 0x1b, 0xc8,
-+ 0xc5, 0xb5, 0xa2, 0xaf, 0xa4, 0x00, 0xb3, 0xc0, 0xf8, 0xe8, 0x58, 0x4c,
-+ 0x48, 0xaf, 0xeb, 0x59, 0x76, 0x3b, 0x33, 0xe5, 0xef, 0xf9, 0xbe, 0xc2,
-+ 0x8b, 0x0b, 0x5b, 0x2c, 0x1f, 0xf6, 0x46, 0xe4, 0xb7, 0xe2, 0x33, 0x81,
-+ 0x59, 0xfe, 0x18, 0x6a, 0x17, 0x03, 0x24, 0x5e, 0x93, 0xf8, 0x18, 0x4c,
-+ 0x25, 0x67, 0x78, 0xbd, 0x14, 0xb1, 0x55, 0x81, 0x0c, 0x86, 0x5b, 0x44,
-+ 0xeb, 0xc0, 0x2d, 0x28, 0x53, 0x67, 0xc2, 0x1b, 0xc9, 0xa7, 0x97, 0x49,
-+ 0x80, 0xbd, 0x4c, 0x1a, 0xd3, 0xe7, 0x13, 0x2c, 0xe8, 0xb4, 0x14, 0x1b,
-+ 0x8a, 0xbe, 0x6a, 0xa3, 0xb9, 0x67, 0x52, 0xf2, 0x3f, 0x0c, 0xd7, 0xef,
-+ 0xd3, 0xba, 0x25, 0xbd, 0x95, 0x75, 0x08, 0xa6, 0xe0, 0x50, 0x98, 0xe5,
-+ 0x41, 0x98, 0xcc, 0x08, 0x86, 0xf8, 0x47, 0xfe, 0x3f, 0x01, 0x1c, 0xe8,
-+ 0xbc, 0xa2, 0xf8, 0x86, 0x48, 0x09, 0x12, 0x94, 0x74, 0x18, 0xbd, 0x5d,
-+ 0x45, 0x7e, 0x53, 0xd3, 0x97, 0xcd, 0xd2, 0xa8, 0xae, 0x84, 0xac, 0xe9,
-+ 0x98, 0xaa, 0x5c, 0xe3, 0x2e, 0xc2, 0xfa, 0xcb, 0xaa, 0x8f, 0x05, 0xf2,
-+ 0xd9, 0xfa, 0xb2, 0x4c, 0xc4, 0xca, 0x77, 0x62, 0xb5, 0x76, 0xcf, 0xc6,
-+ 0xe0, 0x8e, 0xfd, 0x53, 0x3b, 0xca, 0xc6, 0x9b, 0xc3, 0x99, 0xa7, 0x8d,
-+ 0x8b, 0x68, 0x2d, 0xd1, 0x4b, 0x76, 0x22, 0x2d, 0x2b, 0x16, 0xea, 0xfe,
-+ 0xe6, 0x1a, 0x4c, 0x0b, 0x7b, 0x3c, 0xfc, 0x16, 0x98, 0x62, 0x71, 0x5d,
-+ 0xfe, 0x17, 0x03, 0x27, 0xbf, 0xc0, 0xc8, 0x21, 0x6d, 0xbd, 0xb3, 0x98,
-+ 0x58, 0x11, 0xdc, 0xda, 0xb8, 0x46, 0x56, 0xe0, 0x42, 0xd0, 0xbf, 0x46,
-+ 0x62, 0xa3, 0x4b, 0x4b, 0x95, 0x72, 0x0e, 0x59, 0x05, 0x41, 0x87, 0xc9,
-+ 0x4f, 0xc9, 0x36, 0x4f, 0x4e, 0xf3, 0x0d, 0xac, 0xd8, 0x8d, 0xba, 0x8f,
-+ 0x46, 0x49, 0x40, 0xdb, 0x58, 0xeb, 0xf3, 0xb5, 0x90, 0x49, 0x64, 0xf7,
-+ 0x5d, 0xfd, 0xf4, 0xc4, 0x41, 0x21, 0x05, 0xb1, 0x0f, 0xae, 0x3d, 0x20,
-+ 0xf0, 0xe8, 0x81, 0x4b, 0x95, 0x77, 0xee, 0x8f, 0xb0, 0x20, 0xfe, 0xb8,
-+ 0x23, 0x9c, 0xf4, 0xdc, 0x72, 0x2d, 0x9b, 0x13, 0xfd, 0x6f, 0x6c, 0xed,
-+ 0x18, 0x32, 0xe8, 0x20, 0xa2, 0x93, 0x26, 0x7d, 0x97, 0xa5, 0x24, 0x15,
-+ 0x76, 0x61, 0x3c, 0xd9, 0xa3, 0xcf, 0x7b, 0xf2, 0xaa, 0x8e, 0x73, 0xc8,
-+ 0x0b, 0x6d, 0x78, 0x37, 0xbe, 0x73, 0xc1, 0x28, 0x1b, 0x2f, 0xf0, 0x61,
-+ 0x6f, 0xb8, 0xd7, 0x1a, 0xeb, 0x02, 0xd5, 0xa6, 0x70, 0x48, 0xdb, 0x64,
-+ 0xb3, 0x1f, 0xdd, 0xbe, 0xfe, 0xee, 0xf1, 0x6c, 0xc2, 0x23, 0x4a, 0x70,
-+ 0x2c, 0x5a, 0x55, 0xf7, 0x6b, 0x4b, 0xa5, 0x43, 0x50, 0x3e, 0x33, 0xa0,
-+ 0x5a, 0x92, 0x37, 0xa2, 0x42, 0x43, 0xe9, 0xda, 0x34, 0x1e, 0x4b, 0x57,
-+ 0x47, 0x71, 0x16, 0xb9, 0x9b, 0x28, 0xe4, 0xc0, 0xa6, 0x9e, 0x46, 0xef,
-+ 0x8e, 0x63, 0x4c, 0x5f, 0x47, 0xe1, 0xf7, 0xee, 0xce, 0x57, 0x08, 0xf3,
-+ 0x15, 0x35, 0x16, 0x1f, 0xc6, 0x99, 0x64, 0x16, 0x7f, 0x07, 0xf4, 0x52,
-+ 0xc1, 0x46, 0x7e, 0x27, 0xc0, 0xef, 0x0f, 0xd6, 0x73, 0x6a, 0xa5, 0x0b,
-+ 0x72, 0x9a, 0xcf, 0x9a, 0xd8, 0x0d, 0x41, 0xdb, 0xbe, 0xb9, 0x7e, 0x8f,
-+ 0x45, 0xab, 0x47, 0x0e, 0x32, 0x51, 0xf9, 0xbd, 0xcb, 0xd1, 0xe8, 0xc1,
-+ 0xcd, 0x7d, 0x38, 0x7e, 0xc9, 0x6f, 0x60, 0x7e, 0xd7, 0x32, 0xa6, 0x0b,
-+ 0xa6, 0xd2, 0xed, 0x05, 0x8b, 0xf3, 0x27, 0xc9, 0xf6, 0x24, 0x01, 0x12,
-+ 0x0d, 0x8b, 0x0d, 0x36, 0x95, 0x05, 0x11, 0x8c, 0xfe, 0x7a, 0xca, 0xa9,
-+ 0x87, 0xfb, 0x7d, 0xea, 0x1a, 0xcf, 0xa0, 0xa8, 0x56, 0xff, 0x3d, 0xfc,
-+ 0xb0, 0x76, 0x09, 0xcc, 0xa4, 0x01, 0x4c, 0x80, 0xc7, 0x4d, 0x96, 0xda,
-+ 0x33, 0x3f, 0x64, 0x19, 0xc6, 0x94, 0x2e, 0x67, 0xd0, 0x87, 0xeb, 0xa0,
-+ 0xbe, 0xf8, 0x41, 0x31, 0x00, 0x04, 0x2e, 0x59, 0x28, 0x90, 0xf6, 0xaf,
-+ 0x69, 0x4e, 0x7a, 0xa6, 0x0f, 0xaf, 0xdf, 0x98, 0xcf, 0x73, 0xb2, 0x6a,
-+ 0x43, 0x58, 0xe2, 0xfe, 0x2a, 0xa8, 0x75, 0x8c, 0x75, 0x46, 0x37, 0x93,
-+ 0x24, 0x48, 0xb0, 0xf8, 0x78, 0xed, 0xc1, 0x82, 0x33, 0xf0, 0xa3, 0x17,
-+ 0x36, 0x42, 0x2e, 0x4b, 0x5d, 0x63, 0xe4, 0x65, 0x1f, 0xb4, 0x42, 0xe7,
-+ 0x71, 0x0a, 0xbe, 0x49, 0xaf, 0xd1, 0xc8, 0xed, 0x59, 0x8f, 0xe3, 0xd5,
-+ 0x70, 0xc5, 0x1b, 0xea, 0x7a, 0xac, 0xa2, 0x7e, 0x28, 0xc9, 0x44, 0x42,
-+ 0x10, 0x69, 0xc1, 0xb0, 0x92, 0x82, 0x57, 0xe6, 0x5d, 0xe4, 0x9d, 0xf3,
-+ 0xcc, 0x59, 0x95, 0x1f, 0xf9, 0x0b, 0x72, 0x60, 0x2b, 0x9f, 0xa7, 0x75,
-+ 0xa2, 0x87, 0xc9, 0x87, 0x2f, 0xe3, 0x0f, 0x36, 0x19, 0x40, 0x98, 0x86,
-+ 0x7a, 0x53, 0x83, 0x32, 0xb4, 0x62, 0x73, 0xb5, 0x49, 0x90, 0x29, 0x5d,
-+ 0xcd, 0xd1, 0x67, 0xc8, 0x66, 0xe4, 0x9b, 0xa1, 0x1f, 0xb2, 0x65, 0xb4,
-+ 0x8c, 0xae, 0xc0, 0xa9, 0xc0, 0x68, 0x5f, 0x3c, 0x46, 0xbf, 0xd9, 0xcc,
-+ 0xa6, 0x55, 0x5f, 0xfe, 0x9f, 0x2d, 0x5a, 0x37, 0x8f, 0x4e, 0x0b, 0x34,
-+ 0xa0, 0x0e, 0x5f, 0xcc, 0x3f, 0x53, 0x82, 0x32, 0x01, 0x7d, 0x0a, 0x2b,
-+ 0xb8, 0xd4, 0x98, 0xd8, 0x49, 0x30, 0x7b, 0x51, 0x24, 0x2b, 0xd3, 0x1d,
-+ 0x6d, 0x7b, 0x89, 0x20, 0xee, 0xb6, 0x67, 0x98, 0xd2, 0xa9, 0x28, 0xae,
-+ 0x6c, 0x88, 0x7a, 0x77, 0x55, 0x28, 0x33, 0xe9, 0x30, 0x1a, 0xf2, 0x93,
-+ 0xea, 0xfd, 0x2a, 0xb5, 0x14, 0x4c, 0x89, 0x9f, 0x56, 0xb9, 0x6e, 0x8a,
-+ 0xb0, 0xd8, 0xfc, 0xbe, 0x4e, 0xba, 0x24, 0xc7, 0x40, 0xaf, 0xec, 0xb2,
-+ 0x51, 0x04, 0x7c, 0xea, 0x35, 0x19, 0x3d, 0x03, 0x39, 0x05, 0x8a, 0xa1,
-+ 0x60, 0xaf, 0x5e, 0xb0, 0x54, 0x2f, 0x2f, 0x93, 0x66, 0x07, 0x3b, 0xa8,
-+ 0x87, 0x01, 0xa5, 0xe8, 0xef, 0xcf, 0x71, 0xde, 0x80, 0xb4, 0x92, 0x91,
-+ 0x4f, 0x0f, 0x77, 0xce, 0x70, 0xce, 0xce, 0xbd, 0xa1, 0x0a, 0x7a, 0xb7,
-+ 0x55, 0xbf, 0xa7, 0xc7, 0x27, 0x05, 0xfe, 0xfa, 0x41, 0xc9, 0xec, 0x66,
-+ 0x47, 0x8b, 0xe4, 0x26, 0x32, 0x83, 0x5f, 0x2c, 0xea, 0x95, 0xd7, 0xf0,
-+ 0x79, 0x37, 0xf1, 0x76, 0xa2, 0xf3, 0xad, 0x92, 0x0e, 0x18, 0x25, 0xaf,
-+ 0xd4, 0x24, 0xda, 0x05, 0x8a, 0xbf, 0x3b, 0xa6, 0x58, 0x81, 0xaf, 0x19,
-+ 0xed, 0xa8, 0x2e, 0x15, 0x71, 0xd8, 0x8b, 0x4e, 0xf6, 0x52, 0x6f, 0xdd,
-+ 0x4f, 0x8e, 0xe1, 0x46, 0x2f, 0x2a, 0x99, 0xaf, 0x32, 0x51, 0x52, 0xbc,
-+ 0x48, 0x04, 0xa3, 0xa9, 0x30, 0x49, 0x49, 0x43, 0x35, 0xed, 0xef, 0xd6,
-+ 0x1f, 0xcb, 0x23, 0xd7, 0x2e, 0xea, 0xf0, 0x18, 0x4f, 0xc8, 0x2b, 0x4b,
-+ 0x98, 0x66, 0xd4, 0xb4, 0x9e, 0x88, 0x94, 0x5f, 0x20, 0x08, 0x6c, 0x55,
-+ 0x18, 0x1a, 0x62, 0xe6, 0x6d, 0x34, 0xa9, 0x6a, 0x3e, 0x31, 0x89, 0x3b,
-+ 0xc0, 0xcf, 0x39, 0xed, 0x49, 0xc7, 0x48, 0x4d, 0x32, 0x49, 0x79, 0xa8,
-+ 0x38, 0x24, 0xf3, 0xb5, 0xb6, 0x45, 0x8e, 0x4a, 0x29, 0x00, 0x46, 0xfc,
-+ 0x99, 0x01, 0x38, 0x65, 0x2b, 0x25, 0xcc, 0x67, 0xce, 0x6f, 0xfe, 0xf1,
-+ 0xc3, 0xa5, 0x8f, 0x18, 0x00, 0xd9, 0x7e, 0x1b, 0xc9, 0x59, 0xff, 0x0d,
-+ 0x54, 0x03, 0x47, 0x82, 0xb7, 0x0b, 0xf0, 0x45, 0x49, 0x81, 0xb7, 0x86,
-+ 0xac, 0x43, 0xc4, 0xf9, 0xfe, 0xd2, 0xd1, 0x69, 0xff, 0xea, 0x61, 0xc1,
-+ 0xe7, 0xbb, 0x8f, 0xa0, 0x25, 0xd6, 0x49, 0x12, 0x60, 0x74, 0xb5, 0x33,
-+ 0x58, 0x0d, 0xc5, 0xe8, 0xf5, 0xa5, 0x39, 0x50, 0x24, 0x37, 0x37, 0x93,
-+ 0x0c, 0xe9, 0x4f, 0x00, 0xce, 0xe9, 0xf2, 0xa2, 0x65, 0x34, 0x16, 0x10,
-+ 0x93, 0x08, 0xc8, 0xa4, 0xbe, 0xc0, 0xed, 0x06, 0xe9, 0xe4, 0x88, 0x7d,
-+ 0xb2, 0x81, 0x42, 0x7e, 0xb8, 0xa2, 0xcb, 0xf1, 0xac, 0x76, 0xe9, 0xce,
-+ 0x2f, 0x74, 0xd6, 0x90, 0x22, 0x5e, 0xe4, 0x4c, 0x2d, 0xf0, 0x76, 0xa9,
-+ 0x15, 0x97, 0xb0, 0x2a, 0x55, 0x64, 0x2e, 0x2c, 0x33, 0x21, 0xcb, 0xd6,
-+ 0x7a, 0xed, 0x65, 0xb9, 0x3b, 0xdc, 0x54, 0x2e, 0xec, 0x95, 0x9f, 0xec,
-+ 0x0c, 0xcb, 0x75, 0xf7, 0x03, 0xe0, 0x54, 0xa4, 0x03, 0x47, 0x76, 0xcd,
-+ 0x1a, 0x28, 0xe1, 0x93, 0x56, 0xec, 0x4e, 0xd4, 0x98, 0x29, 0x62, 0xca,
-+ 0x44, 0x85, 0x8b, 0x45, 0x1c, 0xa3, 0x6d, 0x42, 0x7e, 0x9b, 0xa3, 0x0f,
-+ 0x1b, 0x10, 0x1b, 0xb9, 0x24, 0x1b, 0xde, 0x04, 0x62, 0x30, 0xaa, 0xdd,
-+ 0x2c, 0x49, 0xf8, 0x67, 0xdf, 0x9b, 0xb1, 0xf3, 0xfa, 0x3c, 0x6b, 0x88,
-+ 0xe2, 0x8b, 0x0d, 0x4c, 0x2f, 0xf2, 0x63, 0x8e, 0x4e, 0xe3, 0xaf, 0xd0,
-+ 0xb8, 0x1a, 0x71, 0x85, 0x6a, 0x60, 0x3c, 0x3f, 0x34, 0x87, 0x09, 0x2b,
-+ 0xec, 0x1c, 0xb5, 0xc1, 0x4f, 0x03, 0x82, 0x3e, 0xc3, 0xa9, 0xb4, 0xeb,
-+ 0x62, 0x7e, 0x54, 0x0a, 0xd7, 0x54, 0x94, 0x95, 0x71, 0x76, 0x65, 0x4c,
-+ 0x80, 0x12, 0xb5, 0x6a, 0x2f, 0xf6, 0x9e, 0x17, 0x50, 0x0a, 0xbc, 0xe3,
-+ 0xdb, 0x84, 0x8e, 0x92, 0x20, 0xd6, 0x24, 0x87, 0xda, 0xe4, 0xa9, 0x4e,
-+ 0xb2, 0x15, 0xab, 0xa0, 0xc3, 0x2c, 0x39, 0xd1, 0x86, 0x03, 0xa6, 0x58,
-+ 0x69, 0x6e, 0x88, 0xab, 0x21, 0xe6, 0x63, 0xd2, 0x21, 0x17, 0x00, 0x2a,
-+ 0x20, 0x31, 0x4e, 0x92, 0x11, 0x7f, 0x6d, 0x79, 0xc7, 0x60, 0x74, 0x0c,
-+ 0x7f, 0xda, 0xcb, 0xd2, 0x82, 0xf7, 0xbd, 0x25, 0x19, 0xa8, 0xef, 0x97,
-+ 0x25, 0x7e, 0xb5, 0xe7, 0x98, 0x83, 0xe9, 0xba, 0x6b, 0xfb, 0xdb, 0x65,
-+ 0xa0, 0x7d, 0x08, 0xab, 0xc6, 0x52, 0xa3, 0x5b, 0x11, 0xe7, 0xec, 0x28,
-+ 0xf3, 0x55, 0xe7, 0x26, 0xfc, 0x57, 0xe7, 0xfc, 0xcf, 0xac, 0xac, 0x7d,
-+ 0x7f, 0xa3, 0xd7, 0x97, 0x9d, 0x71, 0x48, 0x67, 0xf2, 0x24, 0xbd, 0x52,
-+ 0x85, 0xc9, 0x23, 0xed, 0x16, 0xdb, 0x15, 0xa1, 0x97, 0x83, 0xd8, 0x82,
-+ 0xed, 0xd1, 0xda, 0x90, 0xdc, 0x34, 0x3d, 0xd6, 0x4b, 0x4d, 0x17, 0xc1,
-+ 0xdf, 0x50, 0xd0, 0x9d, 0x8b, 0x5c, 0x88, 0xa0, 0x65, 0x8e, 0x91, 0xbb,
-+ 0x37, 0x3f, 0xd5, 0x36, 0x8e, 0x7c, 0x17, 0xb2, 0xe1, 0x37, 0x96, 0xa2,
-+ 0x5c, 0x69, 0xf4, 0x44, 0x6b, 0x27, 0x56, 0xb6, 0xb7, 0x56, 0x71, 0x3b,
-+ 0xc1, 0x2a, 0xbc, 0x0f, 0x35, 0xa8, 0x17, 0x4e, 0xa4, 0xc0, 0xc5, 0xf2,
-+ 0x77, 0x9b, 0x21, 0x78, 0x55, 0x1c, 0xd2, 0xb2, 0x28, 0x45, 0x54, 0xa7,
-+ 0x42, 0x27, 0x1f, 0xd4, 0xc9, 0xaa, 0x1c, 0xb7, 0x26, 0xa5, 0xd4, 0xe0,
-+ 0x9f, 0x1f, 0x69, 0x9e, 0xdf, 0xb9, 0xc4, 0x78, 0xd0, 0x8b, 0xd2, 0xb7,
-+ 0xf1, 0x05, 0x8c, 0x41, 0xcb, 0x34, 0x43, 0x7f, 0x69, 0x01, 0x0e, 0xef,
-+ 0x35, 0x02, 0x12, 0xf1, 0x0b, 0x24, 0xe9, 0x0e, 0x89, 0x69, 0x9b, 0xc5,
-+ 0x78, 0x49, 0x91, 0xb6, 0x16, 0x7f, 0xcc, 0xe5, 0x5c, 0x0a, 0x5e, 0x75,
-+ 0xbf, 0xcf, 0x50, 0x7d, 0x05, 0x29, 0xdb, 0x55, 0x67, 0x6b, 0xac, 0xf8,
-+ 0x20, 0xd6, 0x13, 0xeb, 0xc0, 0x27, 0x3d, 0xef, 0x6f, 0x9a, 0x5c, 0x30,
-+ 0xbb, 0xfd, 0xa8, 0xc1, 0x1a, 0x99, 0x33, 0x62, 0xef, 0xb9, 0x2b, 0x12,
-+ 0xc6, 0x21, 0x84, 0x6a, 0xa1, 0xfd, 0x40, 0xfa, 0x12, 0x5c, 0x8a, 0x2b,
-+ 0x6e, 0xce, 0xcd, 0x91, 0x0d, 0xa5, 0xd2, 0x2e, 0x6b, 0xc3, 0x5b, 0x14,
-+ 0xe1, 0x43, 0x8a, 0x06, 0x58, 0x04, 0xc5, 0x83, 0xcf, 0xd7, 0x87, 0x92,
-+ 0x0d, 0x47, 0x97, 0x99, 0xf7, 0x40, 0xea, 0xc6, 0x3a, 0xe1, 0x4a, 0xfd,
-+ 0xe9, 0x71, 0x56, 0x5f, 0x6e, 0x55, 0xdd, 0xf0, 0xab, 0x57, 0xba, 0xf5,
-+ 0x1c, 0xc5, 0xdd, 0x8d, 0xb9, 0xa5, 0xa7, 0x89, 0xf7, 0xe5, 0x7a, 0x6c,
-+ 0x6e, 0x88, 0x35, 0x4e, 0x0a, 0xff, 0x88, 0xb0, 0xfc, 0x9d, 0x05, 0xc1,
-+ 0xc4, 0xc8, 0x30, 0x13, 0xa0, 0xa6, 0xa7, 0x03, 0x20, 0x45, 0xf6, 0x65,
-+ 0x92, 0xf0, 0x61, 0x8e, 0x7d, 0xf1, 0x18, 0x2e, 0x45, 0x55, 0x0c, 0x12,
-+ 0xe3, 0xb7, 0xa3, 0xce, 0xcc, 0x0e, 0x5b, 0x0c, 0x28, 0x28, 0xfa, 0xc0,
-+ 0xe6, 0x45, 0xdd, 0x86, 0xcb, 0x49, 0xa7, 0x43, 0x49, 0xe4, 0xcb, 0x9f,
-+ 0xce, 0xa9, 0x3d, 0x52, 0xed, 0x98, 0x14, 0x17, 0x4c, 0xf3, 0x59, 0x48,
-+ 0xc1, 0x14, 0x10, 0xa8, 0x78, 0x83, 0x62, 0xf3, 0x71, 0x5d, 0x03, 0x11,
-+ 0xa9, 0xdd, 0x5e, 0x86, 0xcb, 0xdb, 0xd8, 0xf7, 0x5a, 0x20, 0xb8, 0xd0,
-+ 0xcb, 0x18, 0xfa, 0x46, 0x43, 0xdd, 0xa6, 0xcc, 0x5a, 0xb4, 0x82, 0x03,
-+ 0x4c, 0x81, 0x0e, 0xfe, 0xcd, 0x90, 0xb1, 0x91, 0x28, 0xc1, 0xa6, 0x42,
-+ 0x97, 0x7e, 0x4d, 0x01, 0xdc, 0x46, 0xf5, 0x40, 0x4e, 0x1c, 0xf4, 0x24,
-+ 0x30, 0xfd, 0x96, 0x05, 0x76, 0x7f, 0x56, 0xcb, 0x37, 0x80, 0x00, 0x64,
-+ 0xab, 0x7b, 0xd1, 0x62, 0x1f, 0x35, 0x20, 0x86, 0xeb, 0xe5, 0x00, 0x63,
-+ 0xe0, 0x6b, 0x13, 0xbf, 0x46, 0xd5, 0x1d, 0x37, 0xaa, 0x5b, 0x84, 0x07,
-+ 0x1b, 0xad, 0x9d, 0xab, 0xb3, 0x32, 0x9d, 0x6f, 0x64, 0x5a, 0xfe, 0xa6,
-+ 0x1b, 0x5c, 0xa6, 0xe7, 0x45, 0xe1, 0x44, 0xf3, 0x4d, 0x86, 0xf8, 0x78,
-+ 0xef, 0x93, 0x88, 0x66, 0x7d, 0x29, 0xa1, 0x7f, 0xe4, 0xe7, 0x26, 0x2f,
-+ 0x04, 0xa1, 0x2e, 0x9a, 0xc7, 0xeb, 0x7d, 0x19, 0xc5, 0x3c, 0x45, 0x54,
-+ 0x41, 0x42, 0x8c, 0x1d, 0x62, 0x18, 0xeb, 0x88, 0x4a, 0x14, 0x25, 0x1a,
-+ 0xde, 0xee, 0xf2, 0xf7, 0x46, 0xb3, 0x02, 0x09, 0x5d, 0x05, 0x0e, 0x3e,
-+ 0x86, 0xc3, 0x12, 0xb4, 0xdf, 0x68, 0x54, 0xfd, 0x5b, 0x20, 0x14, 0xc8,
-+ 0x9f, 0x79, 0x36, 0x67, 0x49, 0xfe, 0xf4, 0xeb, 0xae, 0xa7, 0x20, 0x3c,
-+ 0x0d, 0xf3, 0x64, 0x11, 0x3f, 0xc6, 0xea, 0x66, 0x46, 0xd7, 0x2d, 0xce,
-+ 0x23, 0x86, 0x72, 0xf2, 0x1d, 0x99, 0x84, 0xad, 0x3f, 0xf3, 0x8d, 0xbe,
-+ 0xb7, 0x25, 0xea, 0xd8, 0x1e, 0x6d, 0x44, 0xa2, 0x5f, 0x0f, 0x2c, 0xe9,
-+ 0x36, 0x93, 0xa8, 0xac, 0x38, 0x82, 0xcf, 0xcb, 0xb8, 0x79, 0x7b, 0x0f,
-+ 0x0c, 0x42, 0xf9, 0x11, 0x6c, 0xbd, 0x8b, 0x8b, 0xb6, 0x8c, 0x09, 0x3e,
-+ 0x07, 0xf0, 0xa0, 0xbd, 0xeb, 0xbb, 0xcd, 0xa5, 0xd7, 0x06, 0x3f, 0x63,
-+ 0xc3, 0x10, 0xd1, 0x71, 0xfa, 0x1f, 0x8a, 0x23, 0x70, 0xad, 0x45, 0xc3,
-+ 0xc2, 0xb5, 0x8f, 0x21, 0x36, 0xc7, 0x7c, 0x28, 0xe8, 0x65, 0x29, 0x65,
-+ 0x92, 0x11, 0xbb, 0xbd, 0x77, 0xbc, 0xfe, 0x6c, 0x83, 0x92, 0x18, 0x6c,
-+ 0x1d, 0xe8, 0xdf, 0x63, 0x63, 0x81, 0x71, 0xd8, 0x5b, 0x0a, 0x89, 0x1b,
-+ 0x2f, 0x7b, 0xb6, 0xe5, 0x96, 0x5e, 0xf2, 0x2b, 0xab, 0x26, 0x77, 0xe0,
-+ 0x73, 0xe8, 0xe9, 0x1c, 0x66, 0xa1, 0x97, 0x1e, 0x84, 0x95, 0x1c, 0xc5,
-+ 0x67, 0x9a, 0x9a, 0x62, 0xc2, 0xcb, 0xac, 0x9a, 0x63, 0x61, 0xd6, 0x46,
-+ 0x0e, 0xd9, 0xdf, 0x12, 0x26, 0xf5, 0x39, 0x0e, 0x6d, 0x64, 0x41, 0x30,
-+ 0xe9, 0x27, 0xa8, 0x4e, 0x78, 0x9c, 0x92, 0x5d, 0xb2, 0x96, 0x76, 0x74,
-+ 0xe1, 0x24, 0x63, 0x96, 0x3e, 0xac, 0x9a, 0x2a, 0x02, 0x4f, 0x99, 0x26,
-+ 0xdf, 0xe8, 0xad, 0x5a, 0x85, 0xed, 0x9d, 0x76, 0x2e, 0xdc, 0x59, 0xe6,
-+ 0x2e, 0x88, 0x70, 0xca, 0x64, 0xb2, 0xcb, 0xcf, 0x0c, 0xd1, 0x3b, 0xf3,
-+ 0x6b, 0x93, 0xa6, 0xd6, 0x50, 0x84, 0x84, 0x01, 0x5a, 0x10, 0x7a, 0xfb,
-+ 0x34, 0xfe, 0xa1, 0x3a, 0x40, 0xff, 0x87, 0x26, 0xa4, 0x93, 0x73, 0x16,
-+ 0xb8, 0x30, 0x08, 0x75, 0xc0, 0x80, 0x50, 0xc7, 0x4b, 0xf1, 0xfa, 0x3d,
-+ 0x01, 0x46, 0xc2, 0x8f, 0x5b, 0xb0, 0x59, 0x3a, 0x8c, 0xa2, 0x6f, 0x67,
-+ 0x86, 0x1b, 0x37, 0x80, 0xd5, 0xaf, 0x44, 0xa5, 0xb9, 0x01, 0x92, 0x18,
-+ 0x26, 0x59, 0xf6, 0x8f, 0x85, 0xff, 0x66, 0xd8, 0xf7, 0x92, 0xbe, 0x7e,
-+ 0x9a, 0x6c, 0x50, 0x2a, 0x7f, 0x35, 0x45, 0x06, 0x21, 0x2f, 0x42, 0x4e,
-+ 0x8c, 0x8d, 0x90, 0x02, 0x09, 0x2f, 0x38, 0x53, 0x5a, 0xac, 0xd7, 0x26,
-+ 0x2b, 0x7e, 0xa6, 0xdb, 0xdf, 0xf4, 0x19, 0x20, 0x23, 0x43, 0x68, 0x9f,
-+ 0xc4, 0x46, 0x8d, 0x93, 0x9d, 0xfd, 0x01, 0x1c, 0x1d, 0x22, 0x23, 0x40,
-+ 0x91, 0xa3, 0xb5, 0xb8, 0xcd, 0xe2, 0xe5, 0xea, 0x19, 0x1c, 0x61, 0xe6,
-+ 0x05, 0x36, 0x4c, 0x53, 0x7e, 0x88, 0xa6, 0xb0, 0xcb, 0xea, 0x00, 0x00,
-+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
-+ 0x0f, 0x16, 0x1d, 0x22, 0x30, 0x34, 0x3e,
-+ };
-diff --git a/lib/freebl/ml_kem_fips_vectors.h b/lib/freebl/ml_kem_fips_vectors.h
-new file mode 100644
---- /dev/null
-+++ b/lib/freebl/ml_kem_fips_vectors.h
-@@ -0,0 +1,959 @@
-+/*
-+ *
-+ * This Source Code Form is subject to the terms of the Mozilla Public
-+ * License, v. 2.0. If a copy of the MPL was not distributed with this
-+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-+
-+/* put the ml_kem vectors in their own file so that fipsfreebl can stay
-+ * readable since DSA keys and signatures are huge */
-+ static const unsigned char ml_kem_key_seed[] = {
-+ 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, 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
-+ };
-+ static const unsigned char ml_kem_enc_seed[] = {
-+ 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
-+ };
-+ static const unsigned char ml_kem768_pub_key[] = {
-+ 0x29, 0x8a, 0xa1, 0x0d, 0x42, 0x3c, 0x8d, 0xda, 0x06, 0x9d, 0x02, 0xbc,
-+ 0x59, 0xe6, 0xcd, 0xf0, 0x3a, 0x09, 0x6b, 0x8b, 0x3d, 0xa4, 0xca, 0xb9,
-+ 0xb8, 0x0c, 0xa4, 0xa1, 0x49, 0x07, 0x67, 0x2c, 0xce, 0xf1, 0xec, 0x4f,
-+ 0xaf, 0x23, 0x4a, 0x0b, 0xc5, 0xb7, 0xe9, 0xd4, 0x73, 0xf2, 0xb3, 0x13,
-+ 0x3b, 0x3b, 0x26, 0xa1, 0xd1, 0x75, 0xcb, 0x67, 0xa7, 0x80, 0x59, 0x19,
-+ 0x69, 0x9c, 0x02, 0xf7, 0x65, 0x31, 0xb9, 0x9c, 0x5f, 0x89, 0x18, 0x07,
-+ 0x04, 0xbb, 0x4c, 0xa4, 0x53, 0x5c, 0x5b, 0x89, 0x72, 0x67, 0x9c, 0x66,
-+ 0x0a, 0x07, 0xc5, 0xe5, 0x14, 0xb8, 0x70, 0x09, 0xc8, 0x62, 0xeb, 0x8f,
-+ 0x51, 0x57, 0x69, 0x5e, 0xfb, 0x3f, 0xc4, 0x0a, 0x9d, 0xef, 0x6b, 0x81,
-+ 0xc1, 0xcc, 0x02, 0xa2, 0x49, 0xae, 0x4f, 0x09, 0x4a, 0xd0, 0xd9, 0xbd,
-+ 0x34, 0x85, 0xc1, 0xc1, 0xc6, 0x80, 0x80, 0x52, 0x0a, 0x7c, 0x8c, 0x63,
-+ 0x20, 0x32, 0xce, 0xe7, 0x38, 0x15, 0x4e, 0x5c, 0x51, 0x76, 0xc0, 0x7d,
-+ 0xa5, 0x60, 0x24, 0x77, 0x6a, 0x43, 0x0f, 0xe7, 0x6e, 0xac, 0xf6, 0x65,
-+ 0xa3, 0xf7, 0xb8, 0x32, 0x10, 0x22, 0x15, 0xbc, 0x82, 0xf1, 0x09, 0x39,
-+ 0xc8, 0x35, 0x57, 0x04, 0x33, 0x6a, 0x8f, 0xac, 0x1d, 0x81, 0xe4, 0xbb,
-+ 0x04, 0x85, 0xaa, 0x5d, 0x7c, 0x74, 0xd6, 0xb5, 0x9b, 0xbe, 0x5c, 0x5e,
-+ 0x97, 0x2a, 0x0d, 0x8b, 0xac, 0x41, 0x1b, 0x55, 0xb5, 0xd5, 0x55, 0x7c,
-+ 0xd6, 0x80, 0xa1, 0xa8, 0xf7, 0x1b, 0x4e, 0xb8, 0x6b, 0xc4, 0x8c, 0x9a,
-+ 0x05, 0x09, 0x73, 0x1a, 0x54, 0xbd, 0x9d, 0x72, 0x90, 0xb2, 0x79, 0x63,
-+ 0xe4, 0x37, 0x2d, 0xc9, 0xb1, 0x99, 0xcf, 0xdc, 0xac, 0x0b, 0x01, 0xac,
-+ 0xd2, 0x8a, 0x62, 0x39, 0x51, 0x12, 0xe4, 0xc4, 0x36, 0x48, 0xd6, 0x22,
-+ 0xc4, 0x8c, 0x82, 0x34, 0xd0, 0x14, 0x40, 0xe8, 0xcc, 0x37, 0x6c, 0x92,
-+ 0x7f, 0x23, 0xa5, 0xaf, 0xc9, 0xac, 0x04, 0x74, 0xc6, 0x62, 0x27, 0x4e,
-+ 0x42, 0x45, 0x25, 0xc8, 0x55, 0x2e, 0xce, 0x3b, 0x3f, 0xe2, 0x65, 0x16,
-+ 0xde, 0x90, 0x1b, 0xc7, 0xd5, 0x15, 0xbd, 0xe8, 0x95, 0x58, 0xe6, 0x26,
-+ 0xc9, 0x5c, 0x80, 0xb9, 0x33, 0x42, 0xf8, 0x01, 0x00, 0x04, 0xf3, 0x9e,
-+ 0x6c, 0x6c, 0x94, 0x87, 0x1c, 0x5e, 0x34, 0x4c, 0xab, 0x39, 0x66, 0xc8,
-+ 0x35, 0xf9, 0xa9, 0x6a, 0x59, 0xaf, 0xd3, 0x1c, 0x40, 0x28, 0x6b, 0x38,
-+ 0xb1, 0xc1, 0xa7, 0x84, 0x70, 0xba, 0xb9, 0x47, 0x51, 0x89, 0x34, 0x45,
-+ 0x3c, 0xe8, 0x67, 0x36, 0xa9, 0x19, 0xf1, 0xf5, 0xa6, 0xd5, 0x10, 0xa8,
-+ 0x6f, 0x54, 0x54, 0xfc, 0x39, 0x80, 0xcb, 0x5c, 0x76, 0x5b, 0xd2, 0xbd,
-+ 0x5f, 0x7b, 0x36, 0xb1, 0x41, 0x0d, 0x66, 0x35, 0xc8, 0xce, 0xb4, 0x7c,
-+ 0x4d, 0xda, 0x0d, 0x76, 0xa2, 0x8e, 0xac, 0x93, 0x9c, 0x71, 0xc3, 0x02,
-+ 0x48, 0x04, 0x86, 0x6c, 0x71, 0x62, 0x66, 0x58, 0x44, 0x21, 0x63, 0xc2,
-+ 0xc2, 0x21, 0x17, 0xe5, 0x0a, 0xce, 0xfc, 0xe6, 0x37, 0x8a, 0x98, 0x56,
-+ 0x52, 0x30, 0x2a, 0x4e, 0xf0, 0xc2, 0xce, 0x0c, 0xc7, 0x16, 0xb7, 0x79,
-+ 0x6e, 0x2b, 0x6b, 0x2e, 0x37, 0x77, 0xdf, 0xa1, 0xac, 0x3d, 0xa2, 0x59,
-+ 0xa3, 0x1b, 0x5a, 0x9b, 0x53, 0x0f, 0x8c, 0xb6, 0x38, 0xa8, 0x1a, 0x62,
-+ 0xac, 0x30, 0x18, 0x49, 0xab, 0xaf, 0x95, 0xa7, 0x30, 0x1b, 0xda, 0x30,
-+ 0x06, 0x89, 0x09, 0xbf, 0xdb, 0x7e, 0x67, 0xdb, 0xcc, 0xbb, 0x38, 0xa5,
-+ 0x55, 0x1a, 0x25, 0xb1, 0xa3, 0xa0, 0xf6, 0x85, 0x74, 0x8a, 0xd5, 0x75,
-+ 0x3d, 0x88, 0x80, 0xf0, 0x01, 0x6c, 0x62, 0x74, 0x86, 0x16, 0x63, 0x84,
-+ 0xc5, 0x57, 0x1f, 0xe2, 0x36, 0x59, 0x00, 0x36, 0x4d, 0x03, 0x83, 0x11,
-+ 0xe2, 0xd8, 0x75, 0xdb, 0x36, 0x66, 0x86, 0x93, 0x2b, 0x5e, 0xc6, 0x02,
-+ 0x43, 0x0a, 0x36, 0x9e, 0x87, 0xa6, 0xef, 0x5c, 0x33, 0x87, 0x86, 0x65,
-+ 0x78, 0x25, 0xbd, 0x4c, 0x05, 0x7a, 0xce, 0xb9, 0x23, 0xeb, 0x09, 0x35,
-+ 0xe6, 0x90, 0x5e, 0x63, 0xb4, 0xce, 0xd7, 0xf8, 0x08, 0x57, 0xa7, 0x73,
-+ 0xdd, 0x64, 0xb1, 0x50, 0xd2, 0x66, 0x12, 0xea, 0x9a, 0xc1, 0x20, 0x52,
-+ 0xdb, 0x20, 0x17, 0xbf, 0x18, 0x43, 0xcc, 0xb4, 0xb3, 0x28, 0x1b, 0x69,
-+ 0x0d, 0xc7, 0x28, 0xad, 0xfa, 0x85, 0xc0, 0x02, 0x81, 0xb8, 0xe3, 0xc0,
-+ 0x92, 0x87, 0x33, 0x5f, 0x85, 0x6b, 0x4f, 0xc2, 0x89, 0x2f, 0x69, 0xa2,
-+ 0xf5, 0x79, 0x21, 0xad, 0xa0, 0x19, 0x14, 0xc4, 0x09, 0x88, 0x66, 0x2d,
-+ 0x57, 0x76, 0x96, 0x62, 0xa7, 0x86, 0x35, 0x1b, 0x9b, 0x66, 0x49, 0x3d,
-+ 0xab, 0x79, 0x59, 0x4d, 0x98, 0x6d, 0xe2, 0x10, 0x0d, 0x65, 0xba, 0x0f,
-+ 0xf4, 0xea, 0x58, 0xb8, 0x15, 0x38, 0xd2, 0x4a, 0x44, 0x35, 0xa2, 0x58,
-+ 0xfa, 0xc2, 0x54, 0x04, 0xaa, 0x7f, 0x41, 0xf6, 0x58, 0xb1, 0x38, 0x50,
-+ 0x65, 0xe1, 0x58, 0xdc, 0xb6, 0x01, 0x15, 0x73, 0x27, 0x20, 0xf4, 0x04,
-+ 0x59, 0xaa, 0xac, 0x15, 0xe4, 0x06, 0x95, 0x3a, 0x90, 0xac, 0x52, 0x99,
-+ 0x7d, 0x1c, 0xcd, 0x07, 0x00, 0x60, 0xef, 0xc6, 0x5d, 0xb9, 0xe6, 0x53,
-+ 0x35, 0x44, 0x67, 0xfa, 0xd5, 0x6e, 0xc7, 0x13, 0xc8, 0x6e, 0x75, 0x40,
-+ 0xc4, 0x23, 0xac, 0xf2, 0x66, 0x9f, 0x52, 0xfa, 0x6f, 0x4a, 0xc6, 0x88,
-+ 0x8d, 0x87, 0x1e, 0xf3, 0xe8, 0x47, 0xc0, 0x29, 0xa8, 0xaa, 0xfb, 0xb9,
-+ 0x2e, 0x17, 0xb2, 0x4a, 0xa0, 0x79, 0xb1, 0xf4, 0x19, 0xba, 0x61, 0x75,
-+ 0xb4, 0x42, 0xaf, 0xb1, 0x19, 0x09, 0xd4, 0xa5, 0x6b, 0x70, 0xa0, 0x33,
-+ 0x5b, 0x28, 0x73, 0x92, 0x18, 0xaa, 0x7c, 0x93, 0x48, 0xe2, 0xc3, 0xc2,
-+ 0xf3, 0xeb, 0x3d, 0x15, 0xa4, 0x1e, 0x64, 0x17, 0xc0, 0xdd, 0x94, 0xbf,
-+ 0xeb, 0x21, 0x41, 0x9b, 0x31, 0x1a, 0x7b, 0xb1, 0x3a, 0x18, 0x0b, 0xbe,
-+ 0x83, 0x32, 0x18, 0xa9, 0xa6, 0xb1, 0x74, 0x47, 0xcc, 0x85, 0xf2, 0x25,
-+ 0x85, 0x95, 0x87, 0xa7, 0x30, 0x77, 0x04, 0x9a, 0xcb, 0xcf, 0xd4, 0x4d,
-+ 0x0f, 0x02, 0x54, 0x38, 0xe1, 0x5d, 0x15, 0x38, 0x27, 0x0d, 0x58, 0x6e,
-+ 0x1b, 0xf8, 0x31, 0x92, 0xa9, 0x45, 0x9c, 0xf6, 0x3c, 0x0e, 0x97, 0x2f,
-+ 0x85, 0x29, 0x76, 0x79, 0x83, 0x1e, 0xcf, 0x12, 0x15, 0x09, 0x85, 0x1c,
-+ 0xb8, 0x34, 0x0f, 0x6f, 0x10, 0x7b, 0x0f, 0xa1, 0xa0, 0xef, 0xd1, 0xb3,
-+ 0x6a, 0x81, 0x89, 0xbc, 0x08, 0x5c, 0x4f, 0x5c, 0xb7, 0x84, 0xe5, 0x53,
-+ 0xf4, 0x1b, 0x91, 0x8f, 0x80, 0x39, 0x7c, 0xe1, 0x95, 0x6f, 0x78, 0x5b,
-+ 0xee, 0x37, 0x7c, 0xa9, 0xaa, 0x8b, 0xe6, 0x99, 0x8a, 0xda, 0x30, 0xc2,
-+ 0x6b, 0x7c, 0x3d, 0x8c, 0x6b, 0x55, 0x25, 0x4c, 0xc9, 0x62, 0x03, 0xb2,
-+ 0x0c, 0x42, 0xae, 0xe0, 0xac, 0x4e, 0x1e, 0xbb, 0x40, 0x8e, 0x49, 0xa9,
-+ 0xe3, 0xf8, 0x79, 0xd0, 0xab, 0x07, 0x85, 0xeb, 0x70, 0x25, 0x42, 0x5d,
-+ 0x13, 0x05, 0xa2, 0x29, 0x9c, 0x01, 0x5e, 0x12, 0x0d, 0x16, 0x3b, 0x0e,
-+ 0x19, 0x49, 0x4c, 0xe5, 0x72, 0x53, 0xd0, 0x24, 0x6d, 0x18, 0x27, 0x45,
-+ 0xcb, 0x81, 0x97, 0xab, 0x74, 0x38, 0xb3, 0xc1, 0xbb, 0x79, 0x72, 0xbe,
-+ 0xc5, 0xa3, 0x06, 0xeb, 0xa3, 0x56, 0x78, 0x55, 0xc0, 0x14, 0x69, 0x9f,
-+ 0xef, 0x65, 0xae, 0x54, 0xc7, 0x70, 0xa0, 0xd8, 0x5c, 0x18, 0x40, 0x0c,
-+ 0xf6, 0x42, 0xae, 0xdc, 0x66, 0x07, 0x77, 0xba, 0x4b, 0x13, 0x85, 0x02,
-+ 0xbd, 0x5a, 0x78, 0x12, 0xf6, 0x21, 0xf8, 0x4a, 0x48, 0x29, 0x6b, 0x98,
-+ 0xdd, 0x43, 0x22, 0xb6, 0xf1, 0x58, 0x28, 0xb8, 0xa8, 0xf0, 0xe0, 0x0a,
-+ 0x8b, 0xa4, 0x4a, 0x53, 0xc3, 0xa8, 0xb1, 0x43, 0x57, 0x1b, 0x07, 0x40,
-+ 0xab, 0xd5, 0x67, 0xda, 0xf1, 0xcd, 0xe9, 0xc7, 0x9c, 0x20, 0x4b, 0x6d,
-+ 0x5e, 0x25, 0x9d, 0x17, 0x66, 0xa3, 0x1b, 0xbb, 0xcb, 0x4e, 0x6a, 0x05,
-+ 0xcf, 0x45, 0x02, 0x17, 0x6b, 0x30, 0x1c, 0x1c, 0x2f, 0x41, 0x24, 0x77,
-+ 0x50, 0x15, 0x7b, 0xce, 0xc8, 0x5e, 0x80, 0x9b, 0x30, 0xa4, 0xd6, 0x0d,
-+ 0x77, 0x47, 0xcd, 0xd0, 0xf5, 0xb9, 0x9a, 0xa8, 0xc8, 0x26, 0x98, 0x75,
-+ 0x17, 0x79, 0x3a, 0xaa, 0x80, 0x80, 0xa0, 0xb1, 0x24, 0xa8, 0x55, 0x8d,
-+ 0xf7, 0x2b, 0xbe, 0x37, 0xb7, 0x5f, 0x4e, 0xdb, 0xb6, 0xbe, 0x82, 0x16,
-+ 0xd6, 0xc6, 0x33, 0xfb, 0x2b, 0x22, 0x80, 0xe2, 0x51, 0x13, 0xd8, 0x69,
-+ 0x5e, 0x43, 0x48, 0x1c, 0x3e, 0xeb, 0x39, 0x7e, 0xb1, 0x92, 0x50, 0x52,
-+ 0x29, 0xb6, 0x7a, 0x20, 0x1e, 0xa8, 0x93, 0xc3, 0xe2, 0xcb, 0x32, 0xda,
-+ 0x8b, 0xc3, 0x42, 0xfa, 0x4d, 0xea, 0x05, 0x78,
-+ };
-+ static const unsigned char ml_kem768_priv_key[] = {
-+ 0x27, 0xd2, 0xa7, 0x7f, 0x33, 0x75, 0x6f, 0x61, 0x20, 0x8e, 0xf1, 0x13,
-+ 0xab, 0xe8, 0x25, 0x95, 0x87, 0x3d, 0x4a, 0xbc, 0x73, 0x0e, 0x5b, 0x5d,
-+ 0x67, 0x95, 0x29, 0xbf, 0x6a, 0x4c, 0xeb, 0x63, 0x83, 0x42, 0x72, 0x31,
-+ 0xa8, 0x61, 0x2f, 0x41, 0x55, 0x05, 0x15, 0xac, 0xba, 0x52, 0xe4, 0x8e,
-+ 0xad, 0x8b, 0x94, 0x28, 0x33, 0xbb, 0xe6, 0x86, 0x5d, 0x13, 0xd1, 0x4a,
-+ 0x79, 0xd2, 0xc5, 0xc3, 0xe0, 0x7f, 0x0a, 0x05, 0x6d, 0x8d, 0xe7, 0xaa,
-+ 0xdf, 0xca, 0xba, 0x05, 0x8c, 0x49, 0x3c, 0x80, 0xb3, 0x7c, 0xab, 0x8c,
-+ 0x56, 0x27, 0x53, 0xbb, 0x3b, 0xa6, 0xb6, 0xec, 0x82, 0x97, 0xf8, 0x85,
-+ 0xea, 0xa7, 0x54, 0x0d, 0x53, 0x00, 0x15, 0xa8, 0x44, 0x06, 0xe5, 0x5b,
-+ 0x13, 0x66, 0xb5, 0x77, 0xe2, 0x36, 0xce, 0x58, 0xa2, 0x6d, 0x8a, 0x1e,
-+ 0xb5, 0xa4, 0x4d, 0x54, 0x23, 0x23, 0xc2, 0x16, 0x7d, 0x9b, 0xf4, 0xa4,
-+ 0x7f, 0x98, 0x56, 0x99, 0xca, 0x05, 0xba, 0xe4, 0x3b, 0x8d, 0xec, 0x61,
-+ 0x7f, 0x02, 0x38, 0x0a, 0x38, 0x90, 0xaf, 0xd4, 0xb8, 0xc7, 0xec, 0x7e,
-+ 0xde, 0x26, 0x55, 0x3a, 0x02, 0x5f, 0x3c, 0xe5, 0xbc, 0x5d, 0x7a, 0x62,
-+ 0x13, 0x03, 0x04, 0x23, 0x5c, 0xb1, 0xad, 0x48, 0x36, 0xb5, 0x66, 0xb5,
-+ 0xb8, 0x63, 0xbd, 0x9b, 0xdb, 0x45, 0xa2, 0x84, 0x4a, 0x70, 0x47, 0xb6,
-+ 0xc8, 0xd3, 0x83, 0xe4, 0x48, 0x52, 0x5e, 0x04, 0x0b, 0x4d, 0xc8, 0xa2,
-+ 0xb4, 0x8c, 0x6c, 0x37, 0xc9, 0x6d, 0x62, 0xd4, 0x3f, 0x3f, 0xd8, 0x8e,
-+ 0x28, 0x81, 0xc4, 0x0a, 0x20, 0x5c, 0x9e, 0x24, 0x8f, 0x65, 0x2b, 0x59,
-+ 0x27, 0x81, 0xa7, 0x79, 0xf8, 0x68, 0x80, 0xf2, 0xa1, 0x47, 0xb6, 0x78,
-+ 0x63, 0xf3, 0x91, 0xcc, 0x1a, 0x5a, 0x90, 0x8c, 0x00, 0x95, 0xe0, 0x72,
-+ 0x12, 0x29, 0x1e, 0x2e, 0xf8, 0xa3, 0x6e, 0xb9, 0xa9, 0xc0, 0xc6, 0x07,
-+ 0x32, 0x25, 0xb3, 0x47, 0x03, 0xa4, 0xaf, 0x04, 0x93, 0x82, 0xc4, 0x75,
-+ 0x73, 0xda, 0x68, 0xfd, 0xe9, 0x24, 0x5a, 0xd4, 0x44, 0xe3, 0x1b, 0x1f,
-+ 0xbd, 0xb5, 0x21, 0xf1, 0xf6, 0x1f, 0x37, 0xbc, 0x0c, 0xef, 0x29, 0x20,
-+ 0x67, 0xe6, 0x70, 0xd2, 0x8a, 0x1f, 0xfd, 0x90, 0x4f, 0x6f, 0x11, 0x90,
-+ 0xa9, 0x96, 0x91, 0x8a, 0x13, 0x03, 0x7a, 0x6c, 0xab, 0xf3, 0xc3, 0x73,
-+ 0xbf, 0x82, 0x96, 0xcd, 0x37, 0xab, 0x33, 0xba, 0x77, 0x46, 0x80, 0x9c,
-+ 0xc3, 0xf8, 0xad, 0xe1, 0xb3, 0x63, 0x9b, 0xd5, 0x7b, 0xfc, 0xc6, 0x96,
-+ 0x50, 0xaa, 0xaf, 0x1d, 0xe1, 0x98, 0xfc, 0x4c, 0x04, 0x63, 0x29, 0x9e,
-+ 0x52, 0xc4, 0x61, 0x78, 0x0c, 0xc4, 0x28, 0xfc, 0x5d, 0x04, 0xa5, 0xc5,
-+ 0x18, 0x50, 0xcb, 0xa6, 0xc2, 0xa5, 0x27, 0x43, 0x40, 0x67, 0x57, 0x93,
-+ 0xdd, 0xa0, 0x9b, 0xe4, 0x4c, 0x29, 0xe6, 0x39, 0x5c, 0x65, 0xf8, 0x5d,
-+ 0x2a, 0x0a, 0x7c, 0x6d, 0xf4, 0x11, 0xe6, 0x91, 0x1b, 0x1f, 0x2c, 0xb6,
-+ 0xc3, 0x51, 0xcd, 0x2e, 0x87, 0x5f, 0x51, 0xb6, 0x38, 0xbe, 0x77, 0x60,
-+ 0x97, 0xe9, 0x3e, 0x2f, 0x2b, 0x2f, 0x83, 0xda, 0x0b, 0xee, 0xf4, 0xaa,
-+ 0x85, 0xba, 0x9e, 0x76, 0x3a, 0xb6, 0x45, 0x02, 0xa0, 0xca, 0x52, 0x22,
-+ 0xe9, 0xea, 0xb5, 0xb3, 0xb7, 0x08, 0x8e, 0xd5, 0x20, 0x60, 0xe8, 0xc8,
-+ 0x26, 0x9b, 0x94, 0x3a, 0x71, 0xab, 0x0a, 0xe1, 0xc5, 0xb1, 0xb6, 0x87,
-+ 0xd2, 0xe0, 0x19, 0xcf, 0x80, 0x36, 0xbc, 0xf9, 0xbf, 0x6e, 0x7b, 0xac,
-+ 0x3a, 0xaa, 0x36, 0xe4, 0x16, 0x60, 0xfa, 0xa4, 0x54, 0x0f, 0x26, 0x48,
-+ 0xcd, 0x93, 0xa1, 0x89, 0xec, 0x5c, 0x2d, 0xea, 0x70, 0xba, 0xca, 0xaa,
-+ 0x4f, 0xfc, 0x90, 0x6f, 0x90, 0x81, 0x0e, 0xa1, 0xb6, 0x7b, 0xf2, 0x4f,
-+ 0x2c, 0x78, 0xcf, 0x6b, 0xa8, 0x81, 0xaa, 0xea, 0x61, 0xc0, 0x65, 0x2b,
-+ 0xff, 0x95, 0xb1, 0xba, 0xe4, 0x42, 0x6d, 0x17, 0x73, 0xb9, 0xcc, 0x2c,
-+ 0xa8, 0x2c, 0x21, 0xe3, 0x8c, 0x63, 0x6e, 0x3b, 0x1c, 0x52, 0x32, 0x44,
-+ 0x98, 0x6b, 0x0b, 0xe8, 0xa8, 0x3f, 0x5d, 0xd5, 0xcf, 0x2d, 0x54, 0x76,
-+ 0x2f, 0xb3, 0xc5, 0xeb, 0xf5, 0x9b, 0x8e, 0x88, 0x53, 0x02, 0xb1, 0xce,
-+ 0x47, 0x03, 0x3e, 0xdf, 0x76, 0x0f, 0x4e, 0x02, 0x9b, 0xe4, 0x0b, 0x6d,
-+ 0x56, 0x6b, 0x19, 0xdd, 0x75, 0x8a, 0xcd, 0x5c, 0x74, 0x12, 0x87, 0x81,
-+ 0x31, 0x24, 0x4f, 0x90, 0x17, 0x2c, 0x53, 0xf2, 0x66, 0x63, 0xc2, 0x1d,
-+ 0x90, 0x53, 0x01, 0xd4, 0x8b, 0xaf, 0x91, 0xc9, 0x17, 0xcc, 0x77, 0x79,
-+ 0xe9, 0xd8, 0x80, 0x2c, 0xc1, 0x0d, 0x89, 0xa3, 0x70, 0x50, 0x99, 0xa2,
-+ 0xad, 0x3a, 0x3a, 0x88, 0x96, 0x74, 0x3c, 0x11, 0x44, 0x69, 0x80, 0x93,
-+ 0xbe, 0x25, 0x7d, 0xac, 0xb6, 0x6d, 0xc7, 0x85, 0x22, 0x8b, 0x91, 0x2c,
-+ 0x8d, 0x96, 0x5d, 0x14, 0xaa, 0x28, 0x34, 0x2c, 0x3a, 0xc4, 0xa9, 0x3f,
-+ 0xef, 0xa5, 0x32, 0xb2, 0x09, 0x45, 0xdd, 0xc1, 0x02, 0x01, 0x39, 0xc1,
-+ 0x4d, 0x63, 0x8b, 0x90, 0x8c, 0x4d, 0xdd, 0xe9, 0xa0, 0x64, 0x5b, 0x95,
-+ 0xb2, 0xe4, 0x41, 0x4d, 0x40, 0xbb, 0x79, 0xf0, 0x44, 0x13, 0x83, 0x0f,
-+ 0x15, 0xa8, 0x73, 0xc2, 0x8b, 0xb7, 0x05, 0x9c, 0x27, 0x41, 0x00, 0x20,
-+ 0x15, 0xf2, 0x04, 0x08, 0xf0, 0x58, 0xe7, 0x15, 0xb0, 0xbf, 0x99, 0x5b,
-+ 0x53, 0x80, 0xb7, 0xdd, 0x32, 0x5a, 0x05, 0x6a, 0xb9, 0x7e, 0x65, 0x9a,
-+ 0x2b, 0xe0, 0xcd, 0xf6, 0xc3, 0x37, 0x31, 0xc6, 0x83, 0xa6, 0x34, 0xb7,
-+ 0x71, 0xe8, 0xc9, 0x2a, 0x13, 0x9a, 0xee, 0x4b, 0xb0, 0xe4, 0x9c, 0x70,
-+ 0x77, 0x32, 0x1d, 0x42, 0xfc, 0x19, 0x9f, 0x7c, 0x1f, 0x29, 0x8c, 0xa6,
-+ 0x25, 0xd2, 0x23, 0xa5, 0xc2, 0x63, 0xa0, 0x3c, 0xc4, 0x81, 0x59, 0xb7,
-+ 0x81, 0x26, 0x65, 0xb7, 0x86, 0x37, 0xe4, 0xe1, 0x87, 0x20, 0xb2, 0xc2,
-+ 0x9a, 0x6b, 0x99, 0xf4, 0x27, 0x66, 0xa4, 0xcb, 0xc4, 0xdc, 0x50, 0x8b,
-+ 0xa9, 0x4b, 0xa8, 0x3b, 0x89, 0xc3, 0xa5, 0xc7, 0x8f, 0x8b, 0xb2, 0x6b,
-+ 0xbd, 0x9b, 0x79, 0xbe, 0xb8, 0xc8, 0x18, 0x24, 0x90, 0xf5, 0x79, 0x3e,
-+ 0xe5, 0xb9, 0x60, 0x13, 0xb7, 0x4b, 0x7e, 0x16, 0x9e, 0x29, 0xd1, 0x62,
-+ 0xf1, 0x31, 0x54, 0x64, 0xea, 0x7d, 0x72, 0x43, 0x6d, 0x89, 0xb7, 0x55,
-+ 0x16, 0x11, 0x92, 0xc8, 0x1c, 0xc2, 0xdd, 0x1c, 0x8b, 0x8b, 0xba, 0x79,
-+ 0x5e, 0xf4, 0x26, 0xee, 0x1c, 0xc0, 0x1c, 0x37, 0xaa, 0xa3, 0x7b, 0x2c,
-+ 0xff, 0x8b, 0x0a, 0x37, 0x8b, 0x47, 0xcb, 0xd0, 0xb4, 0xd4, 0x93, 0x98,
-+ 0xcf, 0xc2, 0x71, 0x29, 0x59, 0x69, 0x9f, 0xa0, 0xbd, 0x8c, 0xd8, 0x46,
-+ 0x66, 0xac, 0xc6, 0x1f, 0x54, 0x1b, 0x84, 0xfa, 0x96, 0xb9, 0xc8, 0x54,
-+ 0xe4, 0xe7, 0x5e, 0x91, 0x44, 0xad, 0xdb, 0x44, 0xb8, 0x56, 0x6a, 0x57,
-+ 0xdf, 0xbb, 0x54, 0x5c, 0xe4, 0x23, 0xc0, 0x33, 0x46, 0xf2, 0xb2, 0xc1,
-+ 0xa9, 0x17, 0x80, 0xd1, 0x52, 0xa8, 0xde, 0x1a, 0x4d, 0x4c, 0x9c, 0xac,
-+ 0xde, 0x73, 0x92, 0xc9, 0x96, 0x88, 0x8c, 0xc2, 0x39, 0x9c, 0x02, 0xc3,
-+ 0x8b, 0x33, 0x53, 0xad, 0xf8, 0xac, 0xab, 0x28, 0x39, 0x24, 0xda, 0x00,
-+ 0xa0, 0x5b, 0x76, 0xe7, 0x38, 0xc7, 0x2c, 0x93, 0x0d, 0x6c, 0xba, 0x09,
-+ 0xae, 0x16, 0x89, 0x90, 0xfa, 0xa1, 0xfe, 0xf2, 0x22, 0x6e, 0x78, 0x08,
-+ 0x61, 0xd4, 0x16, 0xef, 0xf4, 0x02, 0xf4, 0xf7, 0x59, 0xfc, 0x64, 0x8a,
-+ 0xb1, 0xf9, 0x71, 0x00, 0x10, 0x90, 0x87, 0xf9, 0x6e, 0x4b, 0x14, 0x8d,
-+ 0x2c, 0xb3, 0x1e, 0x48, 0x05, 0x31, 0x4e, 0xa0, 0xcd, 0x95, 0xfb, 0x02,
-+ 0x3e, 0xac, 0x0d, 0x98, 0x94, 0x74, 0xba, 0x42, 0x01, 0xd7, 0xb4, 0x1d,
-+ 0x26, 0xf5, 0x39, 0x4b, 0x21, 0x7e, 0xea, 0x5b, 0x34, 0xb7, 0x1a, 0x8b,
-+ 0x37, 0x93, 0x1c, 0x0e, 0x59, 0x42, 0x71, 0xe0, 0xb7, 0xc7, 0x33, 0x25,
-+ 0x72, 0x40, 0x23, 0x3e, 0x7b, 0xa7, 0x35, 0x60, 0x3e, 0x42, 0x5a, 0x87,
-+ 0xde, 0xe7, 0x70, 0x79, 0xe3, 0x7c, 0xb2, 0x8a, 0x21, 0x76, 0x45, 0x94,
-+ 0xce, 0x53, 0x50, 0xd8, 0xda, 0x2b, 0x62, 0xa0, 0x71, 0x74, 0x94, 0x30,
-+ 0x32, 0xec, 0x89, 0xc9, 0x88, 0x09, 0xc7, 0x3b, 0x64, 0x23, 0xd3, 0x0c,
-+ 0x1d, 0x28, 0x3a, 0x76, 0x6a, 0x64, 0xd8, 0x97, 0x03, 0xc3, 0xd6, 0x29,
-+ 0xb4, 0x97, 0x82, 0x8d, 0x48, 0x32, 0x0c, 0x34, 0x62, 0x10, 0x79, 0x7a,
-+ 0x29, 0x8a, 0xa1, 0x0d, 0x42, 0x3c, 0x8d, 0xda, 0x06, 0x9d, 0x02, 0xbc,
-+ 0x59, 0xe6, 0xcd, 0xf0, 0x3a, 0x09, 0x6b, 0x8b, 0x3d, 0xa4, 0xca, 0xb9,
-+ 0xb8, 0x0c, 0xa4, 0xa1, 0x49, 0x07, 0x67, 0x2c, 0xce, 0xf1, 0xec, 0x4f,
-+ 0xaf, 0x23, 0x4a, 0x0b, 0xc5, 0xb7, 0xe9, 0xd4, 0x73, 0xf2, 0xb3, 0x13,
-+ 0x3b, 0x3b, 0x26, 0xa1, 0xd1, 0x75, 0xcb, 0x67, 0xa7, 0x80, 0x59, 0x19,
-+ 0x69, 0x9c, 0x02, 0xf7, 0x65, 0x31, 0xb9, 0x9c, 0x5f, 0x89, 0x18, 0x07,
-+ 0x04, 0xbb, 0x4c, 0xa4, 0x53, 0x5c, 0x5b, 0x89, 0x72, 0x67, 0x9c, 0x66,
-+ 0x0a, 0x07, 0xc5, 0xe5, 0x14, 0xb8, 0x70, 0x09, 0xc8, 0x62, 0xeb, 0x8f,
-+ 0x51, 0x57, 0x69, 0x5e, 0xfb, 0x3f, 0xc4, 0x0a, 0x9d, 0xef, 0x6b, 0x81,
-+ 0xc1, 0xcc, 0x02, 0xa2, 0x49, 0xae, 0x4f, 0x09, 0x4a, 0xd0, 0xd9, 0xbd,
-+ 0x34, 0x85, 0xc1, 0xc1, 0xc6, 0x80, 0x80, 0x52, 0x0a, 0x7c, 0x8c, 0x63,
-+ 0x20, 0x32, 0xce, 0xe7, 0x38, 0x15, 0x4e, 0x5c, 0x51, 0x76, 0xc0, 0x7d,
-+ 0xa5, 0x60, 0x24, 0x77, 0x6a, 0x43, 0x0f, 0xe7, 0x6e, 0xac, 0xf6, 0x65,
-+ 0xa3, 0xf7, 0xb8, 0x32, 0x10, 0x22, 0x15, 0xbc, 0x82, 0xf1, 0x09, 0x39,
-+ 0xc8, 0x35, 0x57, 0x04, 0x33, 0x6a, 0x8f, 0xac, 0x1d, 0x81, 0xe4, 0xbb,
-+ 0x04, 0x85, 0xaa, 0x5d, 0x7c, 0x74, 0xd6, 0xb5, 0x9b, 0xbe, 0x5c, 0x5e,
-+ 0x97, 0x2a, 0x0d, 0x8b, 0xac, 0x41, 0x1b, 0x55, 0xb5, 0xd5, 0x55, 0x7c,
-+ 0xd6, 0x80, 0xa1, 0xa8, 0xf7, 0x1b, 0x4e, 0xb8, 0x6b, 0xc4, 0x8c, 0x9a,
-+ 0x05, 0x09, 0x73, 0x1a, 0x54, 0xbd, 0x9d, 0x72, 0x90, 0xb2, 0x79, 0x63,
-+ 0xe4, 0x37, 0x2d, 0xc9, 0xb1, 0x99, 0xcf, 0xdc, 0xac, 0x0b, 0x01, 0xac,
-+ 0xd2, 0x8a, 0x62, 0x39, 0x51, 0x12, 0xe4, 0xc4, 0x36, 0x48, 0xd6, 0x22,
-+ 0xc4, 0x8c, 0x82, 0x34, 0xd0, 0x14, 0x40, 0xe8, 0xcc, 0x37, 0x6c, 0x92,
-+ 0x7f, 0x23, 0xa5, 0xaf, 0xc9, 0xac, 0x04, 0x74, 0xc6, 0x62, 0x27, 0x4e,
-+ 0x42, 0x45, 0x25, 0xc8, 0x55, 0x2e, 0xce, 0x3b, 0x3f, 0xe2, 0x65, 0x16,
-+ 0xde, 0x90, 0x1b, 0xc7, 0xd5, 0x15, 0xbd, 0xe8, 0x95, 0x58, 0xe6, 0x26,
-+ 0xc9, 0x5c, 0x80, 0xb9, 0x33, 0x42, 0xf8, 0x01, 0x00, 0x04, 0xf3, 0x9e,
-+ 0x6c, 0x6c, 0x94, 0x87, 0x1c, 0x5e, 0x34, 0x4c, 0xab, 0x39, 0x66, 0xc8,
-+ 0x35, 0xf9, 0xa9, 0x6a, 0x59, 0xaf, 0xd3, 0x1c, 0x40, 0x28, 0x6b, 0x38,
-+ 0xb1, 0xc1, 0xa7, 0x84, 0x70, 0xba, 0xb9, 0x47, 0x51, 0x89, 0x34, 0x45,
-+ 0x3c, 0xe8, 0x67, 0x36, 0xa9, 0x19, 0xf1, 0xf5, 0xa6, 0xd5, 0x10, 0xa8,
-+ 0x6f, 0x54, 0x54, 0xfc, 0x39, 0x80, 0xcb, 0x5c, 0x76, 0x5b, 0xd2, 0xbd,
-+ 0x5f, 0x7b, 0x36, 0xb1, 0x41, 0x0d, 0x66, 0x35, 0xc8, 0xce, 0xb4, 0x7c,
-+ 0x4d, 0xda, 0x0d, 0x76, 0xa2, 0x8e, 0xac, 0x93, 0x9c, 0x71, 0xc3, 0x02,
-+ 0x48, 0x04, 0x86, 0x6c, 0x71, 0x62, 0x66, 0x58, 0x44, 0x21, 0x63, 0xc2,
-+ 0xc2, 0x21, 0x17, 0xe5, 0x0a, 0xce, 0xfc, 0xe6, 0x37, 0x8a, 0x98, 0x56,
-+ 0x52, 0x30, 0x2a, 0x4e, 0xf0, 0xc2, 0xce, 0x0c, 0xc7, 0x16, 0xb7, 0x79,
-+ 0x6e, 0x2b, 0x6b, 0x2e, 0x37, 0x77, 0xdf, 0xa1, 0xac, 0x3d, 0xa2, 0x59,
-+ 0xa3, 0x1b, 0x5a, 0x9b, 0x53, 0x0f, 0x8c, 0xb6, 0x38, 0xa8, 0x1a, 0x62,
-+ 0xac, 0x30, 0x18, 0x49, 0xab, 0xaf, 0x95, 0xa7, 0x30, 0x1b, 0xda, 0x30,
-+ 0x06, 0x89, 0x09, 0xbf, 0xdb, 0x7e, 0x67, 0xdb, 0xcc, 0xbb, 0x38, 0xa5,
-+ 0x55, 0x1a, 0x25, 0xb1, 0xa3, 0xa0, 0xf6, 0x85, 0x74, 0x8a, 0xd5, 0x75,
-+ 0x3d, 0x88, 0x80, 0xf0, 0x01, 0x6c, 0x62, 0x74, 0x86, 0x16, 0x63, 0x84,
-+ 0xc5, 0x57, 0x1f, 0xe2, 0x36, 0x59, 0x00, 0x36, 0x4d, 0x03, 0x83, 0x11,
-+ 0xe2, 0xd8, 0x75, 0xdb, 0x36, 0x66, 0x86, 0x93, 0x2b, 0x5e, 0xc6, 0x02,
-+ 0x43, 0x0a, 0x36, 0x9e, 0x87, 0xa6, 0xef, 0x5c, 0x33, 0x87, 0x86, 0x65,
-+ 0x78, 0x25, 0xbd, 0x4c, 0x05, 0x7a, 0xce, 0xb9, 0x23, 0xeb, 0x09, 0x35,
-+ 0xe6, 0x90, 0x5e, 0x63, 0xb4, 0xce, 0xd7, 0xf8, 0x08, 0x57, 0xa7, 0x73,
-+ 0xdd, 0x64, 0xb1, 0x50, 0xd2, 0x66, 0x12, 0xea, 0x9a, 0xc1, 0x20, 0x52,
-+ 0xdb, 0x20, 0x17, 0xbf, 0x18, 0x43, 0xcc, 0xb4, 0xb3, 0x28, 0x1b, 0x69,
-+ 0x0d, 0xc7, 0x28, 0xad, 0xfa, 0x85, 0xc0, 0x02, 0x81, 0xb8, 0xe3, 0xc0,
-+ 0x92, 0x87, 0x33, 0x5f, 0x85, 0x6b, 0x4f, 0xc2, 0x89, 0x2f, 0x69, 0xa2,
-+ 0xf5, 0x79, 0x21, 0xad, 0xa0, 0x19, 0x14, 0xc4, 0x09, 0x88, 0x66, 0x2d,
-+ 0x57, 0x76, 0x96, 0x62, 0xa7, 0x86, 0x35, 0x1b, 0x9b, 0x66, 0x49, 0x3d,
-+ 0xab, 0x79, 0x59, 0x4d, 0x98, 0x6d, 0xe2, 0x10, 0x0d, 0x65, 0xba, 0x0f,
-+ 0xf4, 0xea, 0x58, 0xb8, 0x15, 0x38, 0xd2, 0x4a, 0x44, 0x35, 0xa2, 0x58,
-+ 0xfa, 0xc2, 0x54, 0x04, 0xaa, 0x7f, 0x41, 0xf6, 0x58, 0xb1, 0x38, 0x50,
-+ 0x65, 0xe1, 0x58, 0xdc, 0xb6, 0x01, 0x15, 0x73, 0x27, 0x20, 0xf4, 0x04,
-+ 0x59, 0xaa, 0xac, 0x15, 0xe4, 0x06, 0x95, 0x3a, 0x90, 0xac, 0x52, 0x99,
-+ 0x7d, 0x1c, 0xcd, 0x07, 0x00, 0x60, 0xef, 0xc6, 0x5d, 0xb9, 0xe6, 0x53,
-+ 0x35, 0x44, 0x67, 0xfa, 0xd5, 0x6e, 0xc7, 0x13, 0xc8, 0x6e, 0x75, 0x40,
-+ 0xc4, 0x23, 0xac, 0xf2, 0x66, 0x9f, 0x52, 0xfa, 0x6f, 0x4a, 0xc6, 0x88,
-+ 0x8d, 0x87, 0x1e, 0xf3, 0xe8, 0x47, 0xc0, 0x29, 0xa8, 0xaa, 0xfb, 0xb9,
-+ 0x2e, 0x17, 0xb2, 0x4a, 0xa0, 0x79, 0xb1, 0xf4, 0x19, 0xba, 0x61, 0x75,
-+ 0xb4, 0x42, 0xaf, 0xb1, 0x19, 0x09, 0xd4, 0xa5, 0x6b, 0x70, 0xa0, 0x33,
-+ 0x5b, 0x28, 0x73, 0x92, 0x18, 0xaa, 0x7c, 0x93, 0x48, 0xe2, 0xc3, 0xc2,
-+ 0xf3, 0xeb, 0x3d, 0x15, 0xa4, 0x1e, 0x64, 0x17, 0xc0, 0xdd, 0x94, 0xbf,
-+ 0xeb, 0x21, 0x41, 0x9b, 0x31, 0x1a, 0x7b, 0xb1, 0x3a, 0x18, 0x0b, 0xbe,
-+ 0x83, 0x32, 0x18, 0xa9, 0xa6, 0xb1, 0x74, 0x47, 0xcc, 0x85, 0xf2, 0x25,
-+ 0x85, 0x95, 0x87, 0xa7, 0x30, 0x77, 0x04, 0x9a, 0xcb, 0xcf, 0xd4, 0x4d,
-+ 0x0f, 0x02, 0x54, 0x38, 0xe1, 0x5d, 0x15, 0x38, 0x27, 0x0d, 0x58, 0x6e,
-+ 0x1b, 0xf8, 0x31, 0x92, 0xa9, 0x45, 0x9c, 0xf6, 0x3c, 0x0e, 0x97, 0x2f,
-+ 0x85, 0x29, 0x76, 0x79, 0x83, 0x1e, 0xcf, 0x12, 0x15, 0x09, 0x85, 0x1c,
-+ 0xb8, 0x34, 0x0f, 0x6f, 0x10, 0x7b, 0x0f, 0xa1, 0xa0, 0xef, 0xd1, 0xb3,
-+ 0x6a, 0x81, 0x89, 0xbc, 0x08, 0x5c, 0x4f, 0x5c, 0xb7, 0x84, 0xe5, 0x53,
-+ 0xf4, 0x1b, 0x91, 0x8f, 0x80, 0x39, 0x7c, 0xe1, 0x95, 0x6f, 0x78, 0x5b,
-+ 0xee, 0x37, 0x7c, 0xa9, 0xaa, 0x8b, 0xe6, 0x99, 0x8a, 0xda, 0x30, 0xc2,
-+ 0x6b, 0x7c, 0x3d, 0x8c, 0x6b, 0x55, 0x25, 0x4c, 0xc9, 0x62, 0x03, 0xb2,
-+ 0x0c, 0x42, 0xae, 0xe0, 0xac, 0x4e, 0x1e, 0xbb, 0x40, 0x8e, 0x49, 0xa9,
-+ 0xe3, 0xf8, 0x79, 0xd0, 0xab, 0x07, 0x85, 0xeb, 0x70, 0x25, 0x42, 0x5d,
-+ 0x13, 0x05, 0xa2, 0x29, 0x9c, 0x01, 0x5e, 0x12, 0x0d, 0x16, 0x3b, 0x0e,
-+ 0x19, 0x49, 0x4c, 0xe5, 0x72, 0x53, 0xd0, 0x24, 0x6d, 0x18, 0x27, 0x45,
-+ 0xcb, 0x81, 0x97, 0xab, 0x74, 0x38, 0xb3, 0xc1, 0xbb, 0x79, 0x72, 0xbe,
-+ 0xc5, 0xa3, 0x06, 0xeb, 0xa3, 0x56, 0x78, 0x55, 0xc0, 0x14, 0x69, 0x9f,
-+ 0xef, 0x65, 0xae, 0x54, 0xc7, 0x70, 0xa0, 0xd8, 0x5c, 0x18, 0x40, 0x0c,
-+ 0xf6, 0x42, 0xae, 0xdc, 0x66, 0x07, 0x77, 0xba, 0x4b, 0x13, 0x85, 0x02,
-+ 0xbd, 0x5a, 0x78, 0x12, 0xf6, 0x21, 0xf8, 0x4a, 0x48, 0x29, 0x6b, 0x98,
-+ 0xdd, 0x43, 0x22, 0xb6, 0xf1, 0x58, 0x28, 0xb8, 0xa8, 0xf0, 0xe0, 0x0a,
-+ 0x8b, 0xa4, 0x4a, 0x53, 0xc3, 0xa8, 0xb1, 0x43, 0x57, 0x1b, 0x07, 0x40,
-+ 0xab, 0xd5, 0x67, 0xda, 0xf1, 0xcd, 0xe9, 0xc7, 0x9c, 0x20, 0x4b, 0x6d,
-+ 0x5e, 0x25, 0x9d, 0x17, 0x66, 0xa3, 0x1b, 0xbb, 0xcb, 0x4e, 0x6a, 0x05,
-+ 0xcf, 0x45, 0x02, 0x17, 0x6b, 0x30, 0x1c, 0x1c, 0x2f, 0x41, 0x24, 0x77,
-+ 0x50, 0x15, 0x7b, 0xce, 0xc8, 0x5e, 0x80, 0x9b, 0x30, 0xa4, 0xd6, 0x0d,
-+ 0x77, 0x47, 0xcd, 0xd0, 0xf5, 0xb9, 0x9a, 0xa8, 0xc8, 0x26, 0x98, 0x75,
-+ 0x17, 0x79, 0x3a, 0xaa, 0x80, 0x80, 0xa0, 0xb1, 0x24, 0xa8, 0x55, 0x8d,
-+ 0xf7, 0x2b, 0xbe, 0x37, 0xb7, 0x5f, 0x4e, 0xdb, 0xb6, 0xbe, 0x82, 0x16,
-+ 0xd6, 0xc6, 0x33, 0xfb, 0x2b, 0x22, 0x80, 0xe2, 0x51, 0x13, 0xd8, 0x69,
-+ 0x5e, 0x43, 0x48, 0x1c, 0x3e, 0xeb, 0x39, 0x7e, 0xb1, 0x92, 0x50, 0x52,
-+ 0x29, 0xb6, 0x7a, 0x20, 0x1e, 0xa8, 0x93, 0xc3, 0xe2, 0xcb, 0x32, 0xda,
-+ 0x8b, 0xc3, 0x42, 0xfa, 0x4d, 0xea, 0x05, 0x78, 0xa2, 0x4e, 0x16, 0xd8,
-+ 0xf8, 0xf9, 0x38, 0x3a, 0x95, 0xb7, 0x70, 0x50, 0xf4, 0xd9, 0xfd, 0x2f,
-+ 0x57, 0x33, 0xee, 0xc1, 0xd6, 0x3e, 0xf3, 0xc2, 0x3e, 0xbf, 0x99, 0x18,
-+ 0x17, 0x36, 0x69, 0xa7, 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,
-+ };
-+ static const unsigned char ml_kem768_cipher_text[] = {
-+ 0x71, 0x49, 0x61, 0xae, 0xc8, 0x8b, 0xb0, 0x62, 0x3e, 0xb5, 0xb0, 0x03,
-+ 0x45, 0x1c, 0xa3, 0xe4, 0xce, 0xfe, 0x69, 0xc9, 0xf3, 0xd6, 0xa3, 0x8d,
-+ 0x9c, 0x15, 0x38, 0x06, 0x78, 0xa7, 0x17, 0x3d, 0x74, 0x34, 0x58, 0x69,
-+ 0x3b, 0x75, 0x02, 0xc5, 0xf3, 0x27, 0xbe, 0x84, 0xab, 0xef, 0x32, 0xae,
-+ 0xb4, 0x73, 0x5c, 0x96, 0xb1, 0x72, 0x4d, 0x2b, 0x47, 0xca, 0xa9, 0x43,
-+ 0xcf, 0xe8, 0x5a, 0xc2, 0xee, 0x65, 0x15, 0x13, 0x83, 0x5e, 0xc1, 0xda,
-+ 0x07, 0x95, 0xc9, 0xdc, 0x3d, 0x4e, 0xf7, 0xb4, 0x7d, 0xf0, 0xa1, 0xc1,
-+ 0x12, 0x7e, 0x22, 0xba, 0xde, 0xd8, 0xec, 0xeb, 0xf1, 0xb8, 0xdb, 0xff,
-+ 0x37, 0x7f, 0x1d, 0x1c, 0xb3, 0xb2, 0x43, 0xce, 0xde, 0xe1, 0xaa, 0x0f,
-+ 0xe7, 0x85, 0xb0, 0x61, 0x6d, 0xe6, 0x46, 0x7c, 0x53, 0x45, 0x6d, 0xd2,
-+ 0x27, 0x5b, 0xd4, 0xe1, 0x3d, 0x59, 0xa7, 0x7b, 0x7b, 0x6c, 0x59, 0x1e,
-+ 0x0b, 0xba, 0x01, 0x2a, 0x81, 0x4c, 0x3a, 0x7d, 0x47, 0xe5, 0xd2, 0x7e,
-+ 0xfa, 0x6e, 0x91, 0x96, 0xfa, 0x6d, 0xc0, 0x77, 0xd8, 0x6b, 0xe8, 0xfb,
-+ 0x3f, 0x23, 0xaa, 0xd9, 0x2c, 0xb6, 0xa5, 0x0a, 0x83, 0x94, 0x6f, 0xcb,
-+ 0xfd, 0xa4, 0x94, 0xd6, 0x62, 0x7f, 0x8c, 0xff, 0x4c, 0x4a, 0xe3, 0x0c,
-+ 0x53, 0x63, 0x7d, 0xfd, 0xed, 0x4d, 0x65, 0xd0, 0xf2, 0xc0, 0x2f, 0x8a,
-+ 0x7a, 0xcc, 0x91, 0x3d, 0x65, 0xad, 0x33, 0xd4, 0xdd, 0x88, 0x10, 0x0f,
-+ 0x61, 0x44, 0xba, 0x58, 0xe2, 0xc5, 0x43, 0xfb, 0xb0, 0x21, 0x7e, 0x82,
-+ 0x42, 0x08, 0x74, 0xb9, 0x81, 0x45, 0x8a, 0x1b, 0x79, 0xba, 0x72, 0x25,
-+ 0xef, 0xea, 0x5b, 0xce, 0x36, 0x6d, 0x8f, 0xaa, 0x3d, 0x16, 0x7e, 0x55,
-+ 0x6f, 0xf3, 0xce, 0x93, 0x78, 0x48, 0xfd, 0xf1, 0xf5, 0x4b, 0xe6, 0x1e,
-+ 0x46, 0x93, 0xdd, 0xf5, 0xf1, 0xe8, 0xac, 0x04, 0x4f, 0xd2, 0x88, 0x60,
-+ 0x33, 0xcb, 0xcf, 0xba, 0x8a, 0x13, 0xd5, 0x36, 0x63, 0xb2, 0x78, 0x15,
-+ 0xcf, 0x7d, 0x2e, 0x88, 0x60, 0x49, 0x15, 0x4f, 0xc8, 0x23, 0x45, 0x86,
-+ 0x13, 0x71, 0xb8, 0x6e, 0x65, 0x30, 0x3f, 0x74, 0x36, 0xd9, 0x45, 0x40,
-+ 0x07, 0x99, 0x9d, 0x95, 0xbb, 0x13, 0xaa, 0x85, 0x61, 0xc5, 0x71, 0x6b,
-+ 0x66, 0xe0, 0x74, 0xe1, 0x3b, 0x0a, 0x2f, 0x65, 0x89, 0xcc, 0x23, 0x8d,
-+ 0x39, 0x8b, 0xd7, 0xea, 0xeb, 0x40, 0xd9, 0x7c, 0xec, 0x8c, 0x46, 0x04,
-+ 0xfd, 0x84, 0x27, 0x8e, 0x2c, 0xe2, 0x5b, 0x50, 0x53, 0x2d, 0xa0, 0x66,
-+ 0xcf, 0x73, 0xc1, 0x1b, 0xce, 0x6b, 0xa6, 0x33, 0xf6, 0xe1, 0x84, 0xa3,
-+ 0xec, 0x62, 0x24, 0x99, 0x2b, 0x55, 0x77, 0xdd, 0xc3, 0x0e, 0x26, 0xde,
-+ 0xd2, 0xcd, 0xc3, 0x45, 0x0a, 0xdc, 0x08, 0x95, 0xd6, 0xbb, 0xad, 0xf8,
-+ 0x26, 0x48, 0xaa, 0x2a, 0x96, 0xd5, 0x42, 0xc3, 0xb3, 0x23, 0x55, 0x88,
-+ 0x5f, 0x78, 0x80, 0x79, 0x25, 0xd3, 0x81, 0x27, 0x44, 0x13, 0x08, 0x29,
-+ 0x28, 0xb5, 0x09, 0xfc, 0x1b, 0xb4, 0x28, 0x41, 0xc5, 0xb3, 0xe1, 0xa9,
-+ 0xea, 0x87, 0xdb, 0x4e, 0xc4, 0x80, 0x2b, 0x42, 0xfc, 0x43, 0x66, 0xef,
-+ 0xea, 0x7e, 0x76, 0xad, 0x80, 0x8f, 0xdc, 0x8b, 0x74, 0xfd, 0xca, 0x3c,
-+ 0xa2, 0x9f, 0xbc, 0x9e, 0x16, 0xa3, 0x4b, 0x7d, 0x76, 0x3a, 0x02, 0x21,
-+ 0xfe, 0x95, 0x9a, 0x95, 0x84, 0xb5, 0x37, 0xe1, 0x91, 0x1b, 0x7e, 0xf2,
-+ 0xdb, 0x43, 0xaa, 0x7b, 0xe9, 0xa0, 0x5b, 0xdc, 0xa5, 0xbc, 0x28, 0x03,
-+ 0x26, 0xf9, 0xb5, 0x57, 0x91, 0x2a, 0x7f, 0x66, 0x3d, 0x89, 0xa6, 0x33,
-+ 0x54, 0xef, 0xd0, 0xa0, 0xbd, 0xec, 0x3e, 0x94, 0x5d, 0x05, 0x76, 0xfc,
-+ 0x03, 0xc6, 0xef, 0x00, 0xa5, 0x99, 0x44, 0x4a, 0x4f, 0xc7, 0x73, 0x38,
-+ 0x19, 0x06, 0xfa, 0xea, 0x4a, 0x59, 0x4f, 0x0c, 0x6c, 0xb5, 0x4f, 0xcd,
-+ 0x91, 0x58, 0x47, 0x25, 0x53, 0x22, 0xb3, 0xf7, 0x3d, 0xcc, 0xa2, 0x82,
-+ 0xbc, 0xed, 0x5b, 0xf1, 0x36, 0xc5, 0x68, 0xfd, 0xaa, 0xd8, 0x6b, 0x5e,
-+ 0x1f, 0xf0, 0x35, 0x03, 0xa4, 0x1e, 0x72, 0x26, 0xb1, 0x81, 0x1d, 0x69,
-+ 0xf0, 0xfe, 0x47, 0x6a, 0x84, 0xc8, 0xc9, 0xbc, 0x15, 0xb3, 0xc3, 0x39,
-+ 0x50, 0xcd, 0xee, 0x8f, 0xd4, 0x1c, 0xe4, 0x85, 0xc7, 0x54, 0x98, 0x2f,
-+ 0xff, 0xf2, 0x7d, 0x7a, 0x1f, 0xa3, 0x72, 0xac, 0xd9, 0xb0, 0xeb, 0xf4,
-+ 0xef, 0x11, 0x20, 0x11, 0xab, 0x10, 0x7f, 0x7c, 0x46, 0xd8, 0x06, 0x6a,
-+ 0xd8, 0x63, 0x51, 0x9a, 0x0d, 0x2f, 0x89, 0x4e, 0xa5, 0xae, 0xe0, 0x55,
-+ 0x67, 0xe7, 0x60, 0xbf, 0xb1, 0x07, 0x9f, 0x68, 0xb4, 0xe7, 0xee, 0xdc,
-+ 0x1b, 0xf2, 0x2b, 0x4a, 0x6a, 0xbd, 0x4b, 0x4f, 0x15, 0x67, 0x74, 0x25,
-+ 0xba, 0xc6, 0x06, 0xf6, 0xf6, 0x4e, 0x4a, 0xc7, 0x53, 0xe5, 0xc9, 0x96,
-+ 0xfa, 0x49, 0xf7, 0xb4, 0x38, 0xa9, 0x51, 0x1a, 0x15, 0x50, 0x7b, 0x70,
-+ 0xe6, 0x79, 0x87, 0x7d, 0xef, 0x96, 0xd3, 0x5a, 0x61, 0xcf, 0x53, 0xf0,
-+ 0xab, 0x2e, 0xce, 0xae, 0xd6, 0x6d, 0xac, 0xd8, 0xe7, 0x3b, 0x2d, 0xfd,
-+ 0x7e, 0x00, 0x29, 0x7f, 0xb9, 0xad, 0x11, 0x72, 0x3a, 0xd5, 0x34, 0xe6,
-+ 0x52, 0xef, 0x3d, 0xfe, 0x0c, 0xf1, 0x37, 0x2e, 0x98, 0xff, 0x42, 0x99,
-+ 0x03, 0x73, 0xa7, 0x80, 0x00, 0x87, 0xf3, 0xe7, 0x30, 0x06, 0x11, 0xcc,
-+ 0xce, 0xd0, 0x38, 0x75, 0x59, 0x68, 0xff, 0x0a, 0x70, 0xff, 0x03, 0x97,
-+ 0x76, 0xaf, 0xcc, 0x8f, 0xfc, 0xd9, 0xcc, 0x2a, 0x23, 0x4c, 0x99, 0x5b,
-+ 0x8d, 0xb9, 0xb8, 0x7c, 0xc7, 0xa9, 0x58, 0xae, 0x13, 0xa7, 0xd8, 0xae,
-+ 0x50, 0x55, 0xe6, 0x2c, 0x9b, 0xb7, 0xb6, 0x98, 0x31, 0x8f, 0xf1, 0x29,
-+ 0x2a, 0x74, 0xf3, 0x60, 0x2f, 0x83, 0x88, 0x55, 0xc7, 0xc4, 0x01, 0x6c,
-+ 0x1b, 0x57, 0xdc, 0x5b, 0x34, 0x5d, 0x9c, 0xd6, 0x09, 0x45, 0x9a, 0x34,
-+ 0x88, 0x95, 0x76, 0xdc, 0xb1, 0x62, 0x06, 0x36, 0xbb, 0x40, 0x63, 0x36,
-+ 0x1a, 0x6c, 0x2b, 0xa5, 0x86, 0x60, 0xaa, 0xca, 0xf3, 0x64, 0xe2, 0x17,
-+ 0x94, 0x69, 0xc9, 0x36, 0x87, 0xfe, 0x6e, 0x2d, 0x74, 0xc0, 0x1b, 0xc4,
-+ 0x50, 0x69, 0xf7, 0xa5, 0x9f, 0xa7, 0xe1, 0x1a, 0x93, 0xdb, 0x99, 0x88,
-+ 0xb9, 0x3b, 0x82, 0xc3, 0xf7, 0x1f, 0xcf, 0xca, 0x67, 0xdb, 0x40, 0x8a,
-+ 0x01, 0x66, 0xb4, 0xc4, 0x6c, 0xb1, 0x44, 0x16, 0x79, 0xed, 0x6a, 0x0c,
-+ 0xe0, 0x31, 0x70, 0x78, 0x31, 0xe5, 0x8b, 0x9d, 0x32, 0x3c, 0xc0, 0xe6,
-+ 0x96, 0xea, 0xe9, 0x85, 0x65, 0x36, 0xae, 0xcf, 0xfa, 0x1d, 0x9f, 0x0a,
-+ 0xb6, 0x29, 0xcf, 0x24, 0x2d, 0xdc, 0xa3, 0x28, 0x69, 0xe5, 0xdb, 0x59,
-+ 0xe0, 0x49, 0xd8, 0xe7, 0xef, 0xa6, 0x04, 0xb3, 0xe8, 0x59, 0xe1, 0xaa,
-+ 0xd6, 0xcc, 0xc2, 0x08, 0x90, 0x79, 0x47, 0x21, 0x09, 0x28, 0xf9, 0x27,
-+ 0x68, 0xee, 0xfc, 0x6f, 0xde, 0x3a, 0x30, 0x88, 0xde, 0xc6, 0x33, 0x19,
-+ 0xc0, 0x2f, 0x76, 0x88, 0xfd, 0xb6, 0x4d, 0x3c, 0x89, 0x78, 0x78, 0x05,
-+ 0x08, 0x9c, 0x3e, 0x68, 0xf2, 0xd5, 0xca, 0xde, 0xd4, 0x56, 0xb5, 0xd7,
-+ 0xb9, 0x76, 0x6b, 0x6e, 0x4f, 0xbd, 0x41, 0x43, 0x54, 0xba, 0xf3, 0xe0,
-+ 0x75, 0x9d, 0xab, 0x24, 0x7b, 0x9f, 0x82, 0x71, 0xc3, 0x8e, 0xc6, 0xe0,
-+ 0x1d, 0x36, 0x49, 0xa6, 0x2c, 0x29, 0x7b, 0x5c, 0xd9, 0xaa, 0x75, 0x7e,
-+ 0xc7, 0x70, 0x1a, 0x0f, 0x2b, 0xfd, 0x4e, 0x15, 0xb0, 0x33, 0x1b, 0xbc,
-+ 0xb6, 0xb0, 0xbb, 0x91, 0x96, 0x87, 0x5e, 0x26, 0x5c, 0x86, 0xbd, 0x14,
-+ 0x2b, 0xea, 0xd1, 0xca, 0xdd, 0xa9, 0x97, 0x12, 0xde, 0x3f, 0x3d, 0x0d,
-+ 0xfa, 0xc9, 0xa0, 0xdf, 0xe4, 0x3c, 0x76, 0x64, 0x98, 0x79, 0x49, 0x7f,
-+ 0x4c, 0xfd, 0x4e, 0x1c, 0x5e, 0x68, 0x4e, 0x8f, 0xf3, 0x7b, 0xac, 0xc8,
-+ 0xd6, 0x18, 0xf6, 0x5a, 0x70, 0x0b, 0x41, 0xf0, 0x17, 0x08, 0x67, 0x98,
-+ 0x2f, 0x5a, 0x68, 0xc7, 0x5c, 0x65, 0x15, 0x0e,
-+ };
-+ static const unsigned char ml_kem768_key[] = {
-+ 0x42, 0xf5, 0x58, 0xb0, 0xbc, 0x5d, 0x70, 0x0a, 0x91, 0x1b, 0x0f, 0xc6,
-+ 0x7f, 0x62, 0x37, 0x6f, 0x7a, 0xee, 0x46, 0x67, 0xf1, 0x96, 0x9e, 0x03,
-+ 0xf1, 0x8b, 0xdf, 0xdf, 0x3c, 0x59, 0xfb, 0xdc,
-+ };
-+ static const unsigned char ml_kem1024_pub_key[] = {
-+ 0x4b, 0x94, 0xc2, 0x94, 0x50, 0x11, 0x11, 0x91, 0x82, 0x3b, 0x35, 0x14,
-+ 0xc9, 0xac, 0x1e, 0xa3, 0xd9, 0x82, 0x5c, 0xcb, 0x86, 0x39, 0x3a, 0x2d,
-+ 0xfb, 0x04, 0x65, 0x4f, 0xa2, 0x19, 0x2d, 0x37, 0xbf, 0xad, 0x1c, 0x49,
-+ 0x7c, 0x65, 0x02, 0xee, 0xe5, 0xca, 0x80, 0xa7, 0x3b, 0xfc, 0xe0, 0xba,
-+ 0xf5, 0xa5, 0x4a, 0x88, 0x58, 0x5a, 0x40, 0x13, 0x97, 0xa3, 0xd2, 0x32,
-+ 0xf4, 0x26, 0xa7, 0xaf, 0xb0, 0x82, 0xbc, 0x21, 0xa4, 0x43, 0x17, 0x09,
-+ 0x0e, 0xaa, 0xc7, 0x59, 0x2c, 0x2e, 0xa8, 0x8a, 0x65, 0x3c, 0x44, 0x91,
-+ 0xea, 0x19, 0x39, 0x31, 0x33, 0x5f, 0x52, 0xe9, 0x89, 0xa3, 0xc4, 0xcc,
-+ 0x56, 0xd9, 0xc5, 0x53, 0x73, 0x2d, 0x57, 0xc4, 0x70, 0xfb, 0x41, 0xab,
-+ 0x75, 0x9b, 0x65, 0xd2, 0xd0, 0x44, 0x45, 0x38, 0x2f, 0xcd, 0x9c, 0x4e,
-+ 0x34, 0x4a, 0x11, 0x28, 0xfa, 0x9e, 0x11, 0xe0, 0x43, 0x58, 0xe1, 0x92,
-+ 0xed, 0x01, 0x4b, 0x23, 0x23, 0x2a, 0x7e, 0xe2, 0xb2, 0x2e, 0x23, 0x71,
-+ 0x7f, 0x44, 0x11, 0x1e, 0xe3, 0x35, 0x75, 0x39, 0x9c, 0x37, 0x64, 0x6d,
-+ 0xa9, 0x81, 0x3e, 0xc9, 0xb2, 0x12, 0xaf, 0xe9, 0x4e, 0x5d, 0xc5, 0xc2,
-+ 0x33, 0x0a, 0x72, 0x94, 0xcc, 0x1f, 0x42, 0x34, 0xa6, 0xd3, 0xfb, 0xb4,
-+ 0xf1, 0x68, 0x5a, 0xb8, 0x89, 0x2c, 0x04, 0xac, 0xb1, 0x7c, 0xd1, 0xc1,
-+ 0x70, 0xd7, 0xb0, 0x61, 0x1b, 0x6a, 0x71, 0x76, 0xc7, 0x94, 0xcc, 0x8c,
-+ 0x67, 0xf5, 0x5f, 0xc9, 0x23, 0xc2, 0xad, 0x20, 0x31, 0x00, 0xf3, 0x65,
-+ 0x99, 0x18, 0x82, 0xc3, 0x02, 0x43, 0xd7, 0x78, 0x13, 0x84, 0x3b, 0x5e,
-+ 0xc7, 0xc9, 0x64, 0x03, 0x22, 0x63, 0x70, 0x60, 0x92, 0xec, 0xf0, 0x0c,
-+ 0x75, 0x16, 0xbe, 0x64, 0xe4, 0x59, 0x8c, 0xa4, 0x22, 0x6c, 0x06, 0x9b,
-+ 0xb5, 0xe6, 0x7e, 0x41, 0x75, 0xcf, 0x22, 0x86, 0xc8, 0xdd, 0x5c, 0x48,
-+ 0x8a, 0x6c, 0x58, 0x61, 0xf3, 0x1b, 0xaa, 0x0b, 0xd0, 0x26, 0x94, 0x70,
-+ 0xe8, 0xb5, 0x51, 0xdd, 0x3b, 0xcd, 0x38, 0xc8, 0x6c, 0x12, 0xf9, 0xcd,
-+ 0xb1, 0x76, 0xc7, 0x7d, 0xc8, 0xb6, 0xc0, 0x2a, 0x70, 0x1f, 0x47, 0x89,
-+ 0x02, 0xc8, 0x55, 0x3f, 0x69, 0x4c, 0x0d, 0x82, 0x72, 0x7b, 0x4c, 0x4a,
-+ 0x5c, 0x2c, 0x10, 0x41, 0x21, 0x2a, 0xa1, 0x27, 0x48, 0x08, 0xb8, 0x21,
-+ 0x11, 0xb3, 0x77, 0xec, 0x75, 0x21, 0x4e, 0x9b, 0x19, 0x78, 0xf7, 0x60,
-+ 0x04, 0xd4, 0x13, 0x9d, 0x98, 0x61, 0x3f, 0x4b, 0x8e, 0x98, 0xd2, 0x0a,
-+ 0xf7, 0xb5, 0x34, 0x07, 0x3a, 0x50, 0x9a, 0x95, 0x9b, 0x7a, 0x75, 0x64,
-+ 0xf9, 0xb4, 0x0c, 0xa2, 0x18, 0xbf, 0x61, 0x82, 0x93, 0x20, 0xa8, 0x50,
-+ 0x20, 0x17, 0x95, 0x4d, 0x32, 0x8d, 0x7a, 0xc6, 0xc7, 0x69, 0xec, 0x29,
-+ 0x70, 0x07, 0x56, 0xe7, 0xb0, 0x68, 0x5b, 0x34, 0x0d, 0x5e, 0x11, 0x80,
-+ 0x59, 0x50, 0x4a, 0x49, 0xa9, 0xa5, 0x0a, 0x10, 0x19, 0x8e, 0xb1, 0x0a,
-+ 0x57, 0x84, 0x67, 0x8e, 0xb4, 0x27, 0xd7, 0xb4, 0xba, 0xbb, 0x95, 0x52,
-+ 0x93, 0x3b, 0x06, 0x28, 0x97, 0x97, 0x3e, 0x13, 0x18, 0xea, 0xf0, 0xa0,
-+ 0xea, 0xc3, 0x75, 0x84, 0xa6, 0x54, 0x01, 0xb1, 0x70, 0x3e, 0x04, 0x2a,
-+ 0xcc, 0xd8, 0x37, 0x53, 0x14, 0x83, 0xf2, 0x41, 0xca, 0xdc, 0xd1, 0xc1,
-+ 0xd3, 0x78, 0x11, 0x9e, 0x69, 0x44, 0x29, 0xdb, 0x19, 0x9a, 0xc8, 0x91,
-+ 0xe4, 0xc5, 0x34, 0x37, 0x57, 0x08, 0x5b, 0xb3, 0xae, 0x78, 0x36, 0x67,
-+ 0x35, 0x0c, 0x44, 0x58, 0xd9, 0x76, 0x72, 0xe8, 0x61, 0xe8, 0x0b, 0x1d,
-+ 0x26, 0x79, 0x51, 0x0e, 0xa3, 0xa6, 0xf2, 0x36, 0x0c, 0x77, 0xa4, 0x69,
-+ 0x42, 0xc7, 0xa0, 0x6a, 0x55, 0x4d, 0x22, 0x80, 0x80, 0xc8, 0x4b, 0x47,
-+ 0xae, 0xf1, 0x4d, 0xb1, 0x76, 0x20, 0xcb, 0x16, 0xc0, 0x6a, 0xb3, 0x0a,
-+ 0x1b, 0xe4, 0xcd, 0xa7, 0x08, 0x2b, 0xe9, 0xf8, 0x7e, 0x9c, 0x21, 0x1c,
-+ 0x46, 0x91, 0x63, 0x49, 0xa5, 0xba, 0x8e, 0xaa, 0x52, 0x01, 0xc7, 0x29,
-+ 0x4a, 0x3c, 0x08, 0x85, 0xb5, 0x3b, 0x65, 0x74, 0x52, 0x10, 0x88, 0x25,
-+ 0xec, 0x64, 0x6c, 0x90, 0xa0, 0x46, 0x12, 0x32, 0x4e, 0xe7, 0xd0, 0x31,
-+ 0xaf, 0xe5, 0x34, 0x31, 0x32, 0xcb, 0xef, 0x67, 0xb6, 0xef, 0xb1, 0xa5,
-+ 0xec, 0x28, 0x09, 0xb7, 0x73, 0x53, 0x8c, 0xe7, 0x7b, 0x3d, 0x8b, 0x04,
-+ 0xeb, 0x0b, 0x3c, 0x22, 0x56, 0x01, 0x1e, 0x4c, 0x71, 0x6c, 0x19, 0xa8,
-+ 0xba, 0x07, 0x52, 0xbf, 0x71, 0x49, 0x21, 0x17, 0x64, 0x9f, 0x06, 0x15,
-+ 0xc3, 0x29, 0x0f, 0xc2, 0x9a, 0x46, 0xfd, 0xe4, 0xbd, 0x52, 0xdb, 0x92,
-+ 0x86, 0xd6, 0x03, 0x38, 0x82, 0x44, 0x25, 0x9c, 0x15, 0xa7, 0xac, 0x2b,
-+ 0x64, 0x0a, 0x60, 0xcc, 0x03, 0x37, 0x6a, 0x58, 0x41, 0xa3, 0xfb, 0x8a,
-+ 0x47, 0x35, 0x68, 0xfa, 0x9b, 0x1a, 0x26, 0x72, 0x15, 0xf3, 0x4c, 0x01,
-+ 0x69, 0x7b, 0x0f, 0x0e, 0x62, 0x71, 0x75, 0xd7, 0x21, 0x05, 0xb7, 0x70,
-+ 0x7c, 0x29, 0xb9, 0xe6, 0x14, 0xbd, 0xc3, 0x3a, 0x6f, 0x6c, 0x81, 0x8a,
-+ 0x95, 0x37, 0x0b, 0x42, 0x78, 0x82, 0xd7, 0xb4, 0x76, 0x79, 0x6a, 0x9e,
-+ 0xc6, 0xeb, 0x99, 0x32, 0x74, 0xcd, 0x9b, 0x23, 0x91, 0xa8, 0x2b, 0xa4,
-+ 0x5e, 0x33, 0x93, 0xd2, 0xe9, 0xae, 0x97, 0x21, 0xca, 0x9d, 0x6c, 0x1b,
-+ 0x98, 0x8b, 0x58, 0x27, 0x71, 0x3f, 0x90, 0xa6, 0x58, 0x5d, 0xe9, 0x43,
-+ 0x35, 0x28, 0xc0, 0x2b, 0x03, 0xce, 0x10, 0xbb, 0x5f, 0x72, 0x01, 0x38,
-+ 0xd0, 0xfb, 0xb4, 0xc3, 0x0c, 0x12, 0x66, 0xb9, 0x18, 0xe5, 0x29, 0x25,
-+ 0xdf, 0xe1, 0x7b, 0x37, 0xf9, 0x5d, 0x22, 0xbc, 0xa5, 0x4f, 0x47, 0x59,
-+ 0x19, 0xac, 0x85, 0x90, 0x98, 0xc0, 0xf0, 0xd0, 0x8a, 0xc5, 0x87, 0x5e,
-+ 0xf2, 0x9b, 0x56, 0xfd, 0x14, 0x1e, 0x6e, 0xf1, 0x5f, 0x70, 0x0a, 0x0b,
-+ 0x66, 0xf3, 0x95, 0x95, 0xc5, 0x88, 0x17, 0x73, 0x73, 0xc4, 0x66, 0x9b,
-+ 0x21, 0xbc, 0x07, 0x1e, 0x4c, 0x3a, 0xa5, 0xf0, 0xb4, 0xa3, 0x1b, 0x62,
-+ 0x58, 0xf3, 0x5d, 0xa2, 0x4a, 0xc3, 0xcd, 0x29, 0xc7, 0xf2, 0x09, 0x24,
-+ 0x10, 0xc5, 0x07, 0x83, 0x55, 0xb1, 0x38, 0xfb, 0x53, 0xa6, 0xb9, 0xae,
-+ 0x6e, 0x0b, 0x9c, 0x08, 0x24, 0x3e, 0x7b, 0xaa, 0x45, 0xc4, 0x73, 0x76,
-+ 0xeb, 0x8c, 0x7f, 0x13, 0xd4, 0xcf, 0x51, 0xaa, 0x73, 0x6f, 0xa3, 0x15,
-+ 0x40, 0xc9, 0x24, 0x1f, 0x37, 0x0d, 0xa5, 0x44, 0xbf, 0x9f, 0x9c, 0x28,
-+ 0xd9, 0xa5, 0x7e, 0x2f, 0x2a, 0x7c, 0xa9, 0x5a, 0x4e, 0x4b, 0x46, 0x6e,
-+ 0x64, 0x1a, 0xb3, 0xbc, 0xc7, 0x6a, 0xdf, 0x11, 0x39, 0xd5, 0x67, 0xa6,
-+ 0xf1, 0x2b, 0x52, 0xf3, 0xa6, 0x5e, 0x7e, 0xc0, 0xaa, 0xe2, 0x6b, 0xca,
-+ 0xa8, 0xc5, 0x58, 0x33, 0xb0, 0x4e, 0x59, 0x99, 0x8e, 0xbc, 0x9a, 0x19,
-+ 0x30, 0xfb, 0xb6, 0xd2, 0x23, 0x3c, 0x53, 0xd2, 0xc1, 0xf8, 0xb9, 0x51,
-+ 0x8e, 0x3c, 0x2d, 0xe7, 0x3a, 0x19, 0xde, 0xe6, 0xb3, 0x80, 0xa5, 0xb3,
-+ 0x29, 0x71, 0xcf, 0x64, 0xe1, 0x29, 0xfd, 0x6c, 0x1f, 0xa6, 0xe7, 0x5d,
-+ 0x4a, 0x23, 0x45, 0x01, 0xe9, 0x66, 0xdd, 0x3a, 0x54, 0x0a, 0xf5, 0xc8,
-+ 0xf4, 0xf3, 0x4a, 0x6b, 0x4a, 0x25, 0x3e, 0xe2, 0x84, 0x92, 0x56, 0x6d,
-+ 0x5e, 0x67, 0xc6, 0xf5, 0x58, 0x55, 0xfc, 0xb0, 0x50, 0x6f, 0xb0, 0x6c,
-+ 0x15, 0x67, 0x44, 0xd9, 0xa0, 0x3a, 0x31, 0xa2, 0x6f, 0xa9, 0x4c, 0xad,
-+ 0x14, 0xf1, 0x57, 0xb7, 0xf3, 0x03, 0xd0, 0x7a, 0x69, 0xc7, 0x73, 0x76,
-+ 0x8f, 0xcb, 0x4d, 0x07, 0x9c, 0x09, 0x05, 0x97, 0x03, 0xa0, 0xc3, 0xa9,
-+ 0x4d, 0xe4, 0xb9, 0x9e, 0xa3, 0xa2, 0xf1, 0x65, 0x83, 0xd0, 0xf9, 0x17,
-+ 0x0a, 0x39, 0x50, 0xdb, 0x07, 0xb4, 0xf0, 0xbc, 0x30, 0x80, 0x29, 0x27,
-+ 0xf9, 0xf7, 0x96, 0x1b, 0x62, 0x59, 0x89, 0x26, 0x36, 0xa9, 0x50, 0x2a,
-+ 0x27, 0x05, 0x30, 0x36, 0x37, 0x79, 0x9d, 0xd3, 0x44, 0xda, 0x45, 0x1c,
-+ 0x1c, 0xf7, 0xbf, 0x67, 0x84, 0x0c, 0xeb, 0x30, 0x79, 0xab, 0x8c, 0x6b,
-+ 0x8c, 0x19, 0x27, 0xf6, 0x40, 0x53, 0xc6, 0x12, 0x45, 0x0c, 0x45, 0xc9,
-+ 0xe6, 0x03, 0xbc, 0x16, 0x66, 0x6e, 0x59, 0x6b, 0x34, 0x71, 0xe1, 0x03,
-+ 0xb6, 0xf1, 0x54, 0x47, 0x42, 0x4d, 0x17, 0x02, 0x20, 0x48, 0x11, 0x1f,
-+ 0xfb, 0xd3, 0x7e, 0x1c, 0x67, 0x0f, 0x64, 0xf1, 0x4b, 0x8a, 0x7b, 0x32,
-+ 0xb9, 0x4c, 0x1a, 0x49, 0xb4, 0x5d, 0xd2, 0xfc, 0x38, 0xcd, 0x52, 0x89,
-+ 0xd9, 0x10, 0xad, 0x63, 0x60, 0x2c, 0xf5, 0xe1, 0x30, 0x42, 0xc6, 0x4a,
-+ 0xc6, 0x79, 0x7b, 0x89, 0xfb, 0x55, 0x1a, 0xd0, 0x8e, 0x05, 0xa9, 0x2d,
-+ 0x20, 0x0c, 0xcc, 0xb7, 0xe7, 0x12, 0xef, 0x23, 0xc9, 0x31, 0x2c, 0xb3,
-+ 0x50, 0xf0, 0x29, 0xab, 0x53, 0x7e, 0x28, 0x73, 0x47, 0xfd, 0x30, 0x75,
-+ 0xac, 0x10, 0x90, 0x6a, 0x78, 0x3f, 0x1c, 0x6c, 0x07, 0xcc, 0xb8, 0x8f,
-+ 0x41, 0x22, 0x8c, 0x4b, 0xe1, 0xc6, 0x40, 0xf7, 0x90, 0xb5, 0xc3, 0xa5,
-+ 0xd5, 0xd3, 0xca, 0x79, 0x24, 0x95, 0xd7, 0x4b, 0xc4, 0x61, 0x56, 0x26,
-+ 0x58, 0xc0, 0x7a, 0xc6, 0x00, 0x27, 0x6b, 0x92, 0x4a, 0xb5, 0xbc, 0x9b,
-+ 0xe1, 0xf0, 0x49, 0x4c, 0xb7, 0x6f, 0x82, 0xf4, 0x60, 0xa7, 0x48, 0x09,
-+ 0x72, 0x66, 0x33, 0x81, 0xe1, 0x69, 0x99, 0x60, 0x61, 0xd7, 0x99, 0x85,
-+ 0x9e, 0xc5, 0x4d, 0x4f, 0x5c, 0xa5, 0xc4, 0x11, 0xc0, 0x1d, 0xb1, 0x59,
-+ 0x7b, 0x16, 0x59, 0x77, 0x66, 0x9d, 0xe1, 0x3a, 0x92, 0x8a, 0x34, 0xaf,
-+ 0xba, 0xc2, 0x58, 0xfe, 0xa8, 0xc4, 0x76, 0x42, 0x39, 0xc9, 0x42, 0x1d,
-+ 0xc3, 0x11, 0x9b, 0xf5, 0xb4, 0x76, 0x99, 0x20, 0x69, 0x78, 0x32, 0x7b,
-+ 0x1c, 0x53, 0x45, 0xef, 0x74, 0x6a, 0x79, 0x83, 0x84, 0x1f, 0x05, 0x6e,
-+ 0x25, 0x34, 0x10, 0x0a, 0xb2, 0x4d, 0x4e, 0x9a, 0xbb, 0xd0, 0xb1, 0x7c,
-+ 0x6a, 0x95, 0xbd, 0x4c, 0x3c, 0x0e, 0x40, 0xf6, 0x9e, 0x16, 0x12, 0xac,
-+ 0xee, 0xb2, 0x8b, 0x99, 0x08, 0x6c, 0x95, 0x11, 0x6e, 0x72, 0x04, 0x27,
-+ 0x38, 0x93, 0x39, 0x0b, 0xf4, 0x6b, 0x89, 0x9b, 0x36, 0x28, 0x6b, 0x0e,
-+ 0xbf, 0x19, 0x47, 0xbb, 0x98, 0x84, 0xf7, 0x32, 0xca, 0x27, 0xda, 0x82,
-+ 0xb1, 0x9b, 0x5d, 0xc0, 0xcc, 0x7f, 0x88, 0x85, 0x71, 0x49, 0x10, 0x88,
-+ 0x8b, 0x23, 0x10, 0xc4, 0xf9, 0x31, 0x9d, 0x41, 0x0b, 0x34, 0xe6, 0x43,
-+ 0x3b, 0x90, 0x03, 0xe2, 0x17, 0x6b, 0xb9, 0x95, 0x25, 0x74, 0x56, 0x10,
-+ 0x6e, 0x89, 0x52, 0x16, 0x3b, 0x8b, 0xa5, 0x92, 0x53, 0x0c, 0xc5, 0xaa,
-+ 0x0a, 0xeb, 0x43, 0xad, 0x39, 0x8f, 0xe9, 0xe9, 0x7b, 0xaa, 0x52, 0x3d,
-+ 0x7a, 0x44, 0x31, 0x67, 0x7c, 0x3d, 0x3a, 0xf0, 0x71, 0x9e, 0x47, 0x5d,
-+ 0xb8, 0x5c, 0xa9, 0x5a, 0xf5, 0x08, 0x9b, 0xea, 0xbe, 0xb0, 0x5b, 0x2f,
-+ 0xaa, 0xb4, 0x89, 0x6b, 0xa6, 0x0f, 0x81, 0xc8, 0x84, 0x72, 0xa5, 0x7b,
-+ 0x46, 0xa8, 0x28, 0x82, 0x6a, 0x0c, 0xdf, 0xb4, 0x46, 0xf8, 0x18, 0x91,
-+ 0x82, 0xd2, 0xbf, 0x5e, 0xac, 0x4e, 0xc1, 0xcc, 0x5d, 0xea, 0xf5, 0x99,
-+ 0xc8, 0xa1, 0x3e, 0x48, 0x23, 0x54, 0x06, 0xd1, 0x7f, 0xfd, 0xdc, 0x83,
-+ 0x44, 0xb6, 0xc6, 0x69, 0x84, 0xa8, 0x68, 0xaa, 0x92, 0xfa, 0x02, 0x22,
-+ 0x7a, 0x08, 0x69, 0x50, 0xeb, 0x0c, 0x87, 0x01, 0xed, 0x58, 0xdc, 0x62,
-+ 0x87, 0x76, 0xb9, 0x83, 0x88, 0x2e, 0x11, 0x75,
-+ };
-+ static const unsigned char ml_kem1024_priv_key[] = {
-+ 0xf7, 0x7b, 0x7f, 0x6b, 0x15, 0xc7, 0x3f, 0xe2, 0xcc, 0x54, 0x6b, 0x67,
-+ 0xfb, 0x77, 0x4c, 0xa1, 0x9b, 0x42, 0xcd, 0x46, 0x3e, 0xa9, 0xfb, 0xb9,
-+ 0x84, 0xca, 0x47, 0x7a, 0x77, 0xb6, 0xc7, 0x10, 0x87, 0xcb, 0xf0, 0x51,
-+ 0xab, 0xe4, 0x73, 0x6a, 0x90, 0x72, 0xc6, 0xe8, 0x70, 0xc8, 0x31, 0x1c,
-+ 0x55, 0x96, 0x3f, 0x50, 0x0a, 0x3c, 0x7b, 0x1b, 0x8f, 0x2a, 0x58, 0x55,
-+ 0x8f, 0x49, 0xc6, 0x25, 0x27, 0xb6, 0xc5, 0x94, 0xb5, 0xe7, 0xac, 0xb3,
-+ 0xbc, 0xf5, 0x97, 0x27, 0x3a, 0x57, 0x43, 0x51, 0x7d, 0x15, 0x12, 0x08,
-+ 0xbd, 0x4a, 0xa6, 0x1e, 0x75, 0xba, 0x67, 0xb0, 0xbd, 0x59, 0x4a, 0x99,
-+ 0x49, 0x19, 0x62, 0x7a, 0xc0, 0xa8, 0x04, 0xd4, 0x89, 0xe1, 0x71, 0x33,
-+ 0x6b, 0xc3, 0x39, 0xf4, 0x66, 0x67, 0x06, 0xe5, 0x13, 0x44, 0x12, 0xb3,
-+ 0x66, 0x82, 0x3d, 0x50, 0x31, 0x8c, 0x8b, 0xf2, 0x61, 0xab, 0x12, 0x0a,
-+ 0x28, 0xa0, 0x4f, 0xec, 0x01, 0xcc, 0x15, 0xf2, 0xb7, 0x19, 0x12, 0xce,
-+ 0xe5, 0x4a, 0xa8, 0xee, 0xd8, 0x54, 0x69, 0x4b, 0x6b, 0xa8, 0x86, 0xb5,
-+ 0xeb, 0x76, 0x61, 0xe6, 0xd5, 0x6a, 0xac, 0x21, 0x3c, 0xc1, 0xd8, 0x14,
-+ 0xd5, 0x92, 0xb3, 0x95, 0x55, 0x4f, 0xae, 0x74, 0x47, 0x6d, 0x34, 0x37,
-+ 0x11, 0x63, 0x12, 0x9b, 0xf8, 0x64, 0x52, 0x72, 0x50, 0x60, 0x6c, 0xc2,
-+ 0x1a, 0x53, 0x74, 0x6b, 0x20, 0x99, 0x70, 0x77, 0xbb, 0xa1, 0x55, 0x73,
-+ 0x3b, 0x28, 0xa4, 0xe7, 0xfa, 0x07, 0x76, 0x39, 0x95, 0x24, 0x76, 0x3e,
-+ 0xb4, 0x81, 0xce, 0xaa, 0x11, 0x36, 0x6c, 0x34, 0x74, 0xa0, 0x46, 0x85,
-+ 0xf4, 0x0c, 0x3f, 0x08, 0xb0, 0x42, 0x4f, 0x40, 0xbf, 0xf9, 0x49, 0xa0,
-+ 0xac, 0x92, 0x70, 0x4c, 0x3b, 0xa0, 0xc6, 0xeb, 0x36, 0xf1, 0xf5, 0xb6,
-+ 0x21, 0xd8, 0xbf, 0x2b, 0x63, 0x27, 0xbe, 0xb5, 0x7c, 0xd3, 0xfa, 0xcb,
-+ 0x94, 0x18, 0x6f, 0xe3, 0xfc, 0x9a, 0xb0, 0xa1, 0x43, 0x4b, 0xb2, 0x91,
-+ 0xd2, 0xc9, 0xbb, 0x70, 0x72, 0x30, 0x57, 0xe2, 0x25, 0x40, 0x59, 0x65,
-+ 0x6f, 0x56, 0x59, 0x19, 0xa3, 0x2c, 0xf7, 0x45, 0x79, 0xde, 0x89, 0x68,
-+ 0x1c, 0xd2, 0xc5, 0xa9, 0x35, 0xa5, 0x2b, 0x4a, 0xaa, 0x2d, 0x24, 0xcb,
-+ 0x5d, 0x5c, 0x9e, 0x20, 0x72, 0x9e, 0xc5, 0x49, 0x2e, 0xc3, 0x69, 0x61,
-+ 0xef, 0xb8, 0xa2, 0x8c, 0xbc, 0x00, 0xac, 0x30, 0x35, 0x23, 0x29, 0x5f,
-+ 0x3d, 0x80, 0x36, 0xab, 0xc1, 0x60, 0x33, 0x07, 0xce, 0x70, 0xd7, 0x84,
-+ 0x8a, 0x35, 0x65, 0x7a, 0x56, 0x87, 0xdd, 0x58, 0x99, 0x27, 0xea, 0x63,
-+ 0x73, 0x16, 0x26, 0xab, 0xb2, 0x6e, 0xc4, 0xe4, 0x31, 0xb8, 0xeb, 0x6b,
-+ 0x3b, 0x0b, 0xc1, 0xe8, 0x25, 0x73, 0xee, 0x73, 0xb1, 0xa0, 0x21, 0x18,
-+ 0x31, 0x83, 0x52, 0x81, 0x08, 0xae, 0x2e, 0xac, 0xad, 0xdb, 0x95, 0xb4,
-+ 0x64, 0xa0, 0xb9, 0x84, 0x69, 0xc3, 0x19, 0xcc, 0x27, 0xbf, 0xa0, 0x1b,
-+ 0xc3, 0x10, 0x54, 0xa6, 0x8c, 0x05, 0x50, 0x2b, 0x16, 0x62, 0xb8, 0x79,
-+ 0xfe, 0x98, 0xa1, 0x71, 0x1c, 0x34, 0x26, 0xf6, 0x43, 0x6c, 0xb0, 0x21,
-+ 0x4c, 0xea, 0x37, 0x9a, 0xc3, 0xa7, 0xe5, 0xfb, 0x60, 0x18, 0x4a, 0x37,
-+ 0xc1, 0xda, 0x1e, 0xda, 0x61, 0xc6, 0xc3, 0x9c, 0x1d, 0xd4, 0xe8, 0x47,
-+ 0x84, 0x58, 0x11, 0xf2, 0xa3, 0x58, 0xa4, 0x37, 0x31, 0x52, 0x85, 0x36,
-+ 0xd4, 0xa3, 0x29, 0x1b, 0x04, 0x15, 0x8c, 0x2c, 0x3d, 0xc6, 0x41, 0x62,
-+ 0x48, 0x82, 0x67, 0x8b, 0xc7, 0x80, 0x5f, 0x58, 0xa9, 0xd9, 0x4c, 0x71,
-+ 0x04, 0x56, 0x78, 0x46, 0xa2, 0x04, 0x4e, 0x65, 0xae, 0xce, 0x2a, 0x22,
-+ 0x53, 0x72, 0xb6, 0x02, 0x47, 0x99, 0xa5, 0x47, 0x7d, 0x60, 0x23, 0x75,
-+ 0x04, 0xaa, 0x5c, 0x0a, 0xc5, 0x7b, 0xc7, 0x0a, 0x35, 0x58, 0xc0, 0x8c,
-+ 0x4d, 0xe6, 0x87, 0xef, 0x13, 0x02, 0xb4, 0xfc, 0xb5, 0x59, 0x44, 0x13,
-+ 0xd2, 0x2c, 0xb9, 0x59, 0xbc, 0x31, 0xbe, 0x42, 0x34, 0x50, 0x40, 0x3c,
-+ 0x6b, 0xc5, 0x7d, 0xc4, 0x11, 0xb3, 0xfe, 0xfa, 0xc1, 0x05, 0x2a, 0xc4,
-+ 0xbb, 0x16, 0x2c, 0x44, 0x54, 0x5a, 0x4c, 0xa8, 0x08, 0x92, 0x65, 0x7f,
-+ 0xa1, 0x3a, 0x0b, 0x2c, 0x48, 0x2c, 0xed, 0x62, 0x9c, 0xc4, 0x99, 0x9d,
-+ 0x96, 0x9c, 0x59, 0x3d, 0x4a, 0xad, 0xf0, 0x73, 0xcc, 0x3e, 0x3a, 0x45,
-+ 0x8e, 0x78, 0xa8, 0xaa, 0x03, 0x94, 0x08, 0xe6, 0x52, 0xbe, 0x93, 0xb2,
-+ 0x0c, 0x8b, 0x42, 0xec, 0x5b, 0x0e, 0x50, 0x23, 0x9d, 0xac, 0x72, 0x60,
-+ 0x52, 0x85, 0x1a, 0x6d, 0x15, 0x31, 0x2e, 0xc3, 0x9e, 0xd2, 0x08, 0xb7,
-+ 0x22, 0x09, 0xa5, 0x77, 0xc6, 0xb2, 0x77, 0x01, 0x12, 0x89, 0x57, 0x49,
-+ 0xd5, 0x26, 0x0e, 0x7d, 0xd4, 0x46, 0xc0, 0xb0, 0x11, 0x8c, 0x10, 0x00,
-+ 0xbe, 0x68, 0x01, 0xd2, 0x61, 0x1f, 0xcf, 0x00, 0x79, 0x2a, 0x9c, 0xc4,
-+ 0xf4, 0xb4, 0x99, 0x22, 0xf9, 0xa2, 0xd4, 0xb9, 0xc8, 0xfa, 0x5a, 0x5d,
-+ 0x0d, 0x60, 0x50, 0x66, 0x31, 0xa7, 0xe9, 0x71, 0xce, 0xe8, 0x40, 0xb0,
-+ 0x8f, 0xa6, 0x3c, 0x13, 0x72, 0x9d, 0x7e, 0xa5, 0xaa, 0xc7, 0x03, 0x52,
-+ 0xa9, 0x84, 0xcd, 0xb6, 0x69, 0x33, 0x1c, 0xba, 0x75, 0x8f, 0xe8, 0x7e,
-+ 0xc3, 0x93, 0x1b, 0x3e, 0x31, 0x61, 0xfc, 0xc7, 0x47, 0xaa, 0x74, 0x94,
-+ 0x24, 0x68, 0x9f, 0xea, 0xe1, 0x4b, 0xf7, 0xc9, 0xa2, 0xff, 0xba, 0x13,
-+ 0x02, 0xb2, 0x12, 0xb8, 0x03, 0x72, 0xd8, 0xe9, 0x04, 0x9d, 0xb6, 0x9a,
-+ 0x3a, 0x12, 0x61, 0xd0, 0xa2, 0x85, 0x9a, 0x9b, 0x4d, 0x57, 0x89, 0x9e,
-+ 0x0b, 0xa4, 0x16, 0x07, 0xa1, 0xb6, 0x7a, 0x7c, 0x0e, 0x12, 0x92, 0x36,
-+ 0x89, 0xf8, 0xc6, 0x39, 0x53, 0x77, 0xd9, 0x70, 0xc7, 0x49, 0x0a, 0x41,
-+ 0x29, 0x61, 0x1a, 0x1d, 0x05, 0xc3, 0xb7, 0x81, 0x3b, 0xed, 0x94, 0x54,
-+ 0x20, 0x72, 0x3f, 0x7f, 0x95, 0x25, 0xa8, 0x77, 0x93, 0xfa, 0xfb, 0xbf,
-+ 0xca, 0x98, 0x2e, 0x66, 0xbb, 0x80, 0x68, 0x1c, 0x83, 0x24, 0x8a, 0x89,
-+ 0xda, 0x08, 0x4c, 0x19, 0x88, 0x2f, 0x48, 0xf3, 0x1e, 0x7f, 0xc0, 0x90,
-+ 0x93, 0xa4, 0x9e, 0x9f, 0xd0, 0x96, 0x91, 0xb0, 0x21, 0xed, 0xf4, 0x63,
-+ 0xaf, 0xc5, 0x19, 0xb6, 0x28, 0x53, 0x81, 0x61, 0x18, 0x34, 0x61, 0x15,
-+ 0xfb, 0x0b, 0x88, 0x2c, 0xc6, 0x48, 0x2f, 0x3c, 0x5c, 0xbc, 0xc1, 0xc1,
-+ 0x89, 0x46, 0x97, 0xe1, 0x23, 0x95, 0x98, 0xb3, 0x4b, 0x2a, 0x9a, 0x7a,
-+ 0xcd, 0x15, 0x24, 0x4d, 0x06, 0x90, 0xc8, 0x81, 0x94, 0x09, 0x7a, 0x9b,
-+ 0xed, 0xa5, 0x85, 0xe8, 0x7c, 0x43, 0x71, 0x24, 0x62, 0x4c, 0x21, 0x07,
-+ 0x68, 0xe6, 0x21, 0x5d, 0x37, 0x64, 0x82, 0x65, 0x3e, 0xb8, 0x99, 0x47,
-+ 0x87, 0x7c, 0x11, 0x8d, 0x37, 0x0c, 0x69, 0x6a, 0x6f, 0xfc, 0xc1, 0x01,
-+ 0x8a, 0xe4, 0x13, 0xa0, 0x8a, 0x8d, 0x0f, 0xfa, 0xa8, 0x19, 0x94, 0x5d,
-+ 0xa7, 0xa1, 0x67, 0xc2, 0x29, 0x91, 0x32, 0x90, 0xca, 0xd1, 0xc8, 0x0a,
-+ 0x36, 0x92, 0x58, 0x76, 0x26, 0x10, 0xea, 0x25, 0x3e, 0x62, 0xdc, 0x24,
-+ 0x22, 0x6a, 0x30, 0xc8, 0x92, 0xc1, 0x21, 0x36, 0xc3, 0x26, 0xf1, 0x3f,
-+ 0x44, 0x46, 0x66, 0x47, 0x12, 0xb0, 0xb9, 0x0b, 0xc0, 0x63, 0xb4, 0x02,
-+ 0x85, 0x93, 0xcb, 0xde, 0x06, 0xcd, 0xc2, 0x22, 0x89, 0xe2, 0x40, 0xc7,
-+ 0xe2, 0x96, 0xb5, 0x91, 0x72, 0xc1, 0xae, 0xda, 0x8c, 0x99, 0xe0, 0x51,
-+ 0x2d, 0x1a, 0x01, 0x63, 0xa9, 0x42, 0xea, 0x33, 0x14, 0x8e, 0x69, 0x37,
-+ 0xc0, 0x26, 0x02, 0x94, 0x24, 0xb8, 0x1b, 0x99, 0x6b, 0x1d, 0xf2, 0x2e,
-+ 0xa0, 0x62, 0x3e, 0xc6, 0x5c, 0x6b, 0xf0, 0x93, 0x50, 0x0c, 0xf3, 0xbf,
-+ 0x35, 0x37, 0x4a, 0xdc, 0x39, 0x20, 0x35, 0xca, 0x7c, 0x58, 0x3b, 0x99,
-+ 0x68, 0x5b, 0xca, 0x54, 0x1a, 0x08, 0x07, 0xb1, 0x63, 0xac, 0xd0, 0x88,
-+ 0x8b, 0xe0, 0x38, 0x5d, 0xea, 0x82, 0x0d, 0xa4, 0x6e, 0x4d, 0xbb, 0x44,
-+ 0xd2, 0xe4, 0x62, 0xc7, 0x34, 0xb8, 0x3a, 0x47, 0x3f, 0xed, 0x13, 0x64,
-+ 0x27, 0x31, 0x59, 0x25, 0x7c, 0xc2, 0x59, 0xa8, 0xc5, 0x67, 0x6c, 0x1c,
-+ 0x76, 0xd4, 0x1d, 0x56, 0xb9, 0x90, 0x7e, 0xc1, 0xc3, 0x59, 0x9c, 0x9e,
-+ 0x89, 0x07, 0x40, 0x3a, 0x27, 0xa7, 0x05, 0xe3, 0x61, 0x9b, 0x04, 0xb0,
-+ 0xad, 0x04, 0x6e, 0x8e, 0xc8, 0x16, 0x9c, 0x17, 0xb4, 0x60, 0xd4, 0x4c,
-+ 0x0c, 0x0c, 0x44, 0x64, 0xd0, 0x44, 0xc9, 0x46, 0x18, 0x6b, 0xc7, 0x25,
-+ 0x96, 0x50, 0x83, 0xa8, 0x92, 0xbc, 0xc4, 0x95, 0xc0, 0x54, 0x03, 0x11,
-+ 0xff, 0x9b, 0x3e, 0x51, 0x92, 0xc3, 0x03, 0xd8, 0x8f, 0x8b, 0xa4, 0x6a,
-+ 0x90, 0x1c, 0x78, 0x2e, 0xf0, 0x23, 0x88, 0xf1, 0xb2, 0xad, 0xda, 0xb6,
-+ 0xa5, 0x35, 0x0f, 0xc3, 0x63, 0x97, 0x00, 0xe3, 0x15, 0x43, 0x37, 0x33,
-+ 0x7e, 0x4a, 0x17, 0x8d, 0x35, 0x1c, 0xd2, 0xb5, 0x6e, 0xe1, 0xf0, 0xbf,
-+ 0xea, 0x34, 0xaa, 0xcf, 0xa3, 0x3d, 0x2e, 0xc7, 0x91, 0xe5, 0x07, 0x52,
-+ 0xd4, 0xd0, 0x34, 0xcb, 0x1c, 0x95, 0x15, 0x72, 0xca, 0xaa, 0x5c, 0x4d,
-+ 0x90, 0x94, 0x7b, 0x6b, 0x17, 0x5a, 0x6d, 0xd3, 0xc6, 0x2a, 0x77, 0xbb,
-+ 0x8f, 0x7a, 0xc9, 0xae, 0x24, 0x71, 0x9b, 0x53, 0xc2, 0xb1, 0x20, 0xa2,
-+ 0x87, 0x69, 0x86, 0xe2, 0x17, 0xb7, 0x2b, 0xd7, 0xce, 0xe4, 0x4a, 0x72,
-+ 0x65, 0xb1, 0x1c, 0xee, 0x1a, 0xb2, 0x26, 0x17, 0x62, 0xb3, 0x1a, 0x37,
-+ 0x38, 0x38, 0x69, 0x69, 0xc0, 0x82, 0x5f, 0xb7, 0x94, 0x52, 0xe6, 0x52,
-+ 0xe1, 0x14, 0x2f, 0xc7, 0x3c, 0x9d, 0xf6, 0xfb, 0xa4, 0x11, 0x79, 0x5b,
-+ 0x47, 0x17, 0x92, 0x2b, 0x29, 0xba, 0x2d, 0x53, 0xab, 0xe5, 0xa8, 0xc0,
-+ 0xdc, 0xc1, 0x60, 0x1b, 0x09, 0x6c, 0x96, 0xd7, 0x93, 0x8f, 0xd5, 0xa6,
-+ 0x8a, 0x87, 0x97, 0xc7, 0xb9, 0x47, 0x7a, 0x86, 0xa4, 0x72, 0xeb, 0x5d,
-+ 0xa2, 0x50, 0xcb, 0x2f, 0xec, 0x31, 0x8d, 0x83, 0xc8, 0xf4, 0x3b, 0xbe,
-+ 0x8e, 0x11, 0xc3, 0x5e, 0x37, 0x7d, 0x34, 0x93, 0x66, 0xc8, 0x5c, 0x43,
-+ 0x82, 0x59, 0x7f, 0x6f, 0xc2, 0x7a, 0x00, 0x51, 0xc0, 0xfb, 0x00, 0xb0,
-+ 0x2c, 0x01, 0xca, 0x20, 0xf9, 0xa4, 0x27, 0xf1, 0x72, 0x59, 0x94, 0x77,
-+ 0xca, 0x69, 0x0c, 0xc1, 0x32, 0x7e, 0x0f, 0x02, 0x5f, 0x80, 0xec, 0x33,
-+ 0x8a, 0x80, 0xa1, 0x59, 0xe3, 0x08, 0xc1, 0x2a, 0x27, 0xdb, 0x1a, 0x7e,
-+ 0x1b, 0x96, 0x0a, 0x99, 0xd3, 0x7d, 0xfc, 0x22, 0x87, 0x2e, 0x51, 0x93,
-+ 0x0f, 0x28, 0xc6, 0x51, 0xab, 0x22, 0x1f, 0x53, 0xab, 0xae, 0xe2, 0x0b,
-+ 0xad, 0x9a, 0x3e, 0xab, 0xcb, 0xab, 0x91, 0x32, 0x51, 0xbf, 0x13, 0x5b,
-+ 0xeb, 0x29, 0x61, 0x7b, 0x57, 0x54, 0x33, 0x3c, 0x4d, 0xaa, 0xdb, 0x22,
-+ 0x38, 0x34, 0x1c, 0x2a, 0xd9, 0x37, 0x81, 0x86, 0x28, 0x0f, 0x64, 0x49,
-+ 0x44, 0x0b, 0x78, 0x4b, 0xa7, 0x8f, 0x5d, 0xac, 0x44, 0xd8, 0xf6, 0x5b,
-+ 0x3b, 0x74, 0x21, 0x95, 0x03, 0x97, 0xc3, 0x91, 0x3a, 0x2d, 0xd2, 0x3e,
-+ 0xc6, 0xd1, 0xcb, 0x71, 0x7b, 0x36, 0xa5, 0xfc, 0x95, 0xaf, 0x19, 0x1e,
-+ 0x27, 0x82, 0x96, 0x94, 0x8c, 0x12, 0x54, 0xea, 0x86, 0xb4, 0xec, 0x00,
-+ 0x4b, 0x94, 0xc2, 0x94, 0x50, 0x11, 0x11, 0x91, 0x82, 0x3b, 0x35, 0x14,
-+ 0xc9, 0xac, 0x1e, 0xa3, 0xd9, 0x82, 0x5c, 0xcb, 0x86, 0x39, 0x3a, 0x2d,
-+ 0xfb, 0x04, 0x65, 0x4f, 0xa2, 0x19, 0x2d, 0x37, 0xbf, 0xad, 0x1c, 0x49,
-+ 0x7c, 0x65, 0x02, 0xee, 0xe5, 0xca, 0x80, 0xa7, 0x3b, 0xfc, 0xe0, 0xba,
-+ 0xf5, 0xa5, 0x4a, 0x88, 0x58, 0x5a, 0x40, 0x13, 0x97, 0xa3, 0xd2, 0x32,
-+ 0xf4, 0x26, 0xa7, 0xaf, 0xb0, 0x82, 0xbc, 0x21, 0xa4, 0x43, 0x17, 0x09,
-+ 0x0e, 0xaa, 0xc7, 0x59, 0x2c, 0x2e, 0xa8, 0x8a, 0x65, 0x3c, 0x44, 0x91,
-+ 0xea, 0x19, 0x39, 0x31, 0x33, 0x5f, 0x52, 0xe9, 0x89, 0xa3, 0xc4, 0xcc,
-+ 0x56, 0xd9, 0xc5, 0x53, 0x73, 0x2d, 0x57, 0xc4, 0x70, 0xfb, 0x41, 0xab,
-+ 0x75, 0x9b, 0x65, 0xd2, 0xd0, 0x44, 0x45, 0x38, 0x2f, 0xcd, 0x9c, 0x4e,
-+ 0x34, 0x4a, 0x11, 0x28, 0xfa, 0x9e, 0x11, 0xe0, 0x43, 0x58, 0xe1, 0x92,
-+ 0xed, 0x01, 0x4b, 0x23, 0x23, 0x2a, 0x7e, 0xe2, 0xb2, 0x2e, 0x23, 0x71,
-+ 0x7f, 0x44, 0x11, 0x1e, 0xe3, 0x35, 0x75, 0x39, 0x9c, 0x37, 0x64, 0x6d,
-+ 0xa9, 0x81, 0x3e, 0xc9, 0xb2, 0x12, 0xaf, 0xe9, 0x4e, 0x5d, 0xc5, 0xc2,
-+ 0x33, 0x0a, 0x72, 0x94, 0xcc, 0x1f, 0x42, 0x34, 0xa6, 0xd3, 0xfb, 0xb4,
-+ 0xf1, 0x68, 0x5a, 0xb8, 0x89, 0x2c, 0x04, 0xac, 0xb1, 0x7c, 0xd1, 0xc1,
-+ 0x70, 0xd7, 0xb0, 0x61, 0x1b, 0x6a, 0x71, 0x76, 0xc7, 0x94, 0xcc, 0x8c,
-+ 0x67, 0xf5, 0x5f, 0xc9, 0x23, 0xc2, 0xad, 0x20, 0x31, 0x00, 0xf3, 0x65,
-+ 0x99, 0x18, 0x82, 0xc3, 0x02, 0x43, 0xd7, 0x78, 0x13, 0x84, 0x3b, 0x5e,
-+ 0xc7, 0xc9, 0x64, 0x03, 0x22, 0x63, 0x70, 0x60, 0x92, 0xec, 0xf0, 0x0c,
-+ 0x75, 0x16, 0xbe, 0x64, 0xe4, 0x59, 0x8c, 0xa4, 0x22, 0x6c, 0x06, 0x9b,
-+ 0xb5, 0xe6, 0x7e, 0x41, 0x75, 0xcf, 0x22, 0x86, 0xc8, 0xdd, 0x5c, 0x48,
-+ 0x8a, 0x6c, 0x58, 0x61, 0xf3, 0x1b, 0xaa, 0x0b, 0xd0, 0x26, 0x94, 0x70,
-+ 0xe8, 0xb5, 0x51, 0xdd, 0x3b, 0xcd, 0x38, 0xc8, 0x6c, 0x12, 0xf9, 0xcd,
-+ 0xb1, 0x76, 0xc7, 0x7d, 0xc8, 0xb6, 0xc0, 0x2a, 0x70, 0x1f, 0x47, 0x89,
-+ 0x02, 0xc8, 0x55, 0x3f, 0x69, 0x4c, 0x0d, 0x82, 0x72, 0x7b, 0x4c, 0x4a,
-+ 0x5c, 0x2c, 0x10, 0x41, 0x21, 0x2a, 0xa1, 0x27, 0x48, 0x08, 0xb8, 0x21,
-+ 0x11, 0xb3, 0x77, 0xec, 0x75, 0x21, 0x4e, 0x9b, 0x19, 0x78, 0xf7, 0x60,
-+ 0x04, 0xd4, 0x13, 0x9d, 0x98, 0x61, 0x3f, 0x4b, 0x8e, 0x98, 0xd2, 0x0a,
-+ 0xf7, 0xb5, 0x34, 0x07, 0x3a, 0x50, 0x9a, 0x95, 0x9b, 0x7a, 0x75, 0x64,
-+ 0xf9, 0xb4, 0x0c, 0xa2, 0x18, 0xbf, 0x61, 0x82, 0x93, 0x20, 0xa8, 0x50,
-+ 0x20, 0x17, 0x95, 0x4d, 0x32, 0x8d, 0x7a, 0xc6, 0xc7, 0x69, 0xec, 0x29,
-+ 0x70, 0x07, 0x56, 0xe7, 0xb0, 0x68, 0x5b, 0x34, 0x0d, 0x5e, 0x11, 0x80,
-+ 0x59, 0x50, 0x4a, 0x49, 0xa9, 0xa5, 0x0a, 0x10, 0x19, 0x8e, 0xb1, 0x0a,
-+ 0x57, 0x84, 0x67, 0x8e, 0xb4, 0x27, 0xd7, 0xb4, 0xba, 0xbb, 0x95, 0x52,
-+ 0x93, 0x3b, 0x06, 0x28, 0x97, 0x97, 0x3e, 0x13, 0x18, 0xea, 0xf0, 0xa0,
-+ 0xea, 0xc3, 0x75, 0x84, 0xa6, 0x54, 0x01, 0xb1, 0x70, 0x3e, 0x04, 0x2a,
-+ 0xcc, 0xd8, 0x37, 0x53, 0x14, 0x83, 0xf2, 0x41, 0xca, 0xdc, 0xd1, 0xc1,
-+ 0xd3, 0x78, 0x11, 0x9e, 0x69, 0x44, 0x29, 0xdb, 0x19, 0x9a, 0xc8, 0x91,
-+ 0xe4, 0xc5, 0x34, 0x37, 0x57, 0x08, 0x5b, 0xb3, 0xae, 0x78, 0x36, 0x67,
-+ 0x35, 0x0c, 0x44, 0x58, 0xd9, 0x76, 0x72, 0xe8, 0x61, 0xe8, 0x0b, 0x1d,
-+ 0x26, 0x79, 0x51, 0x0e, 0xa3, 0xa6, 0xf2, 0x36, 0x0c, 0x77, 0xa4, 0x69,
-+ 0x42, 0xc7, 0xa0, 0x6a, 0x55, 0x4d, 0x22, 0x80, 0x80, 0xc8, 0x4b, 0x47,
-+ 0xae, 0xf1, 0x4d, 0xb1, 0x76, 0x20, 0xcb, 0x16, 0xc0, 0x6a, 0xb3, 0x0a,
-+ 0x1b, 0xe4, 0xcd, 0xa7, 0x08, 0x2b, 0xe9, 0xf8, 0x7e, 0x9c, 0x21, 0x1c,
-+ 0x46, 0x91, 0x63, 0x49, 0xa5, 0xba, 0x8e, 0xaa, 0x52, 0x01, 0xc7, 0x29,
-+ 0x4a, 0x3c, 0x08, 0x85, 0xb5, 0x3b, 0x65, 0x74, 0x52, 0x10, 0x88, 0x25,
-+ 0xec, 0x64, 0x6c, 0x90, 0xa0, 0x46, 0x12, 0x32, 0x4e, 0xe7, 0xd0, 0x31,
-+ 0xaf, 0xe5, 0x34, 0x31, 0x32, 0xcb, 0xef, 0x67, 0xb6, 0xef, 0xb1, 0xa5,
-+ 0xec, 0x28, 0x09, 0xb7, 0x73, 0x53, 0x8c, 0xe7, 0x7b, 0x3d, 0x8b, 0x04,
-+ 0xeb, 0x0b, 0x3c, 0x22, 0x56, 0x01, 0x1e, 0x4c, 0x71, 0x6c, 0x19, 0xa8,
-+ 0xba, 0x07, 0x52, 0xbf, 0x71, 0x49, 0x21, 0x17, 0x64, 0x9f, 0x06, 0x15,
-+ 0xc3, 0x29, 0x0f, 0xc2, 0x9a, 0x46, 0xfd, 0xe4, 0xbd, 0x52, 0xdb, 0x92,
-+ 0x86, 0xd6, 0x03, 0x38, 0x82, 0x44, 0x25, 0x9c, 0x15, 0xa7, 0xac, 0x2b,
-+ 0x64, 0x0a, 0x60, 0xcc, 0x03, 0x37, 0x6a, 0x58, 0x41, 0xa3, 0xfb, 0x8a,
-+ 0x47, 0x35, 0x68, 0xfa, 0x9b, 0x1a, 0x26, 0x72, 0x15, 0xf3, 0x4c, 0x01,
-+ 0x69, 0x7b, 0x0f, 0x0e, 0x62, 0x71, 0x75, 0xd7, 0x21, 0x05, 0xb7, 0x70,
-+ 0x7c, 0x29, 0xb9, 0xe6, 0x14, 0xbd, 0xc3, 0x3a, 0x6f, 0x6c, 0x81, 0x8a,
-+ 0x95, 0x37, 0x0b, 0x42, 0x78, 0x82, 0xd7, 0xb4, 0x76, 0x79, 0x6a, 0x9e,
-+ 0xc6, 0xeb, 0x99, 0x32, 0x74, 0xcd, 0x9b, 0x23, 0x91, 0xa8, 0x2b, 0xa4,
-+ 0x5e, 0x33, 0x93, 0xd2, 0xe9, 0xae, 0x97, 0x21, 0xca, 0x9d, 0x6c, 0x1b,
-+ 0x98, 0x8b, 0x58, 0x27, 0x71, 0x3f, 0x90, 0xa6, 0x58, 0x5d, 0xe9, 0x43,
-+ 0x35, 0x28, 0xc0, 0x2b, 0x03, 0xce, 0x10, 0xbb, 0x5f, 0x72, 0x01, 0x38,
-+ 0xd0, 0xfb, 0xb4, 0xc3, 0x0c, 0x12, 0x66, 0xb9, 0x18, 0xe5, 0x29, 0x25,
-+ 0xdf, 0xe1, 0x7b, 0x37, 0xf9, 0x5d, 0x22, 0xbc, 0xa5, 0x4f, 0x47, 0x59,
-+ 0x19, 0xac, 0x85, 0x90, 0x98, 0xc0, 0xf0, 0xd0, 0x8a, 0xc5, 0x87, 0x5e,
-+ 0xf2, 0x9b, 0x56, 0xfd, 0x14, 0x1e, 0x6e, 0xf1, 0x5f, 0x70, 0x0a, 0x0b,
-+ 0x66, 0xf3, 0x95, 0x95, 0xc5, 0x88, 0x17, 0x73, 0x73, 0xc4, 0x66, 0x9b,
-+ 0x21, 0xbc, 0x07, 0x1e, 0x4c, 0x3a, 0xa5, 0xf0, 0xb4, 0xa3, 0x1b, 0x62,
-+ 0x58, 0xf3, 0x5d, 0xa2, 0x4a, 0xc3, 0xcd, 0x29, 0xc7, 0xf2, 0x09, 0x24,
-+ 0x10, 0xc5, 0x07, 0x83, 0x55, 0xb1, 0x38, 0xfb, 0x53, 0xa6, 0xb9, 0xae,
-+ 0x6e, 0x0b, 0x9c, 0x08, 0x24, 0x3e, 0x7b, 0xaa, 0x45, 0xc4, 0x73, 0x76,
-+ 0xeb, 0x8c, 0x7f, 0x13, 0xd4, 0xcf, 0x51, 0xaa, 0x73, 0x6f, 0xa3, 0x15,
-+ 0x40, 0xc9, 0x24, 0x1f, 0x37, 0x0d, 0xa5, 0x44, 0xbf, 0x9f, 0x9c, 0x28,
-+ 0xd9, 0xa5, 0x7e, 0x2f, 0x2a, 0x7c, 0xa9, 0x5a, 0x4e, 0x4b, 0x46, 0x6e,
-+ 0x64, 0x1a, 0xb3, 0xbc, 0xc7, 0x6a, 0xdf, 0x11, 0x39, 0xd5, 0x67, 0xa6,
-+ 0xf1, 0x2b, 0x52, 0xf3, 0xa6, 0x5e, 0x7e, 0xc0, 0xaa, 0xe2, 0x6b, 0xca,
-+ 0xa8, 0xc5, 0x58, 0x33, 0xb0, 0x4e, 0x59, 0x99, 0x8e, 0xbc, 0x9a, 0x19,
-+ 0x30, 0xfb, 0xb6, 0xd2, 0x23, 0x3c, 0x53, 0xd2, 0xc1, 0xf8, 0xb9, 0x51,
-+ 0x8e, 0x3c, 0x2d, 0xe7, 0x3a, 0x19, 0xde, 0xe6, 0xb3, 0x80, 0xa5, 0xb3,
-+ 0x29, 0x71, 0xcf, 0x64, 0xe1, 0x29, 0xfd, 0x6c, 0x1f, 0xa6, 0xe7, 0x5d,
-+ 0x4a, 0x23, 0x45, 0x01, 0xe9, 0x66, 0xdd, 0x3a, 0x54, 0x0a, 0xf5, 0xc8,
-+ 0xf4, 0xf3, 0x4a, 0x6b, 0x4a, 0x25, 0x3e, 0xe2, 0x84, 0x92, 0x56, 0x6d,
-+ 0x5e, 0x67, 0xc6, 0xf5, 0x58, 0x55, 0xfc, 0xb0, 0x50, 0x6f, 0xb0, 0x6c,
-+ 0x15, 0x67, 0x44, 0xd9, 0xa0, 0x3a, 0x31, 0xa2, 0x6f, 0xa9, 0x4c, 0xad,
-+ 0x14, 0xf1, 0x57, 0xb7, 0xf3, 0x03, 0xd0, 0x7a, 0x69, 0xc7, 0x73, 0x76,
-+ 0x8f, 0xcb, 0x4d, 0x07, 0x9c, 0x09, 0x05, 0x97, 0x03, 0xa0, 0xc3, 0xa9,
-+ 0x4d, 0xe4, 0xb9, 0x9e, 0xa3, 0xa2, 0xf1, 0x65, 0x83, 0xd0, 0xf9, 0x17,
-+ 0x0a, 0x39, 0x50, 0xdb, 0x07, 0xb4, 0xf0, 0xbc, 0x30, 0x80, 0x29, 0x27,
-+ 0xf9, 0xf7, 0x96, 0x1b, 0x62, 0x59, 0x89, 0x26, 0x36, 0xa9, 0x50, 0x2a,
-+ 0x27, 0x05, 0x30, 0x36, 0x37, 0x79, 0x9d, 0xd3, 0x44, 0xda, 0x45, 0x1c,
-+ 0x1c, 0xf7, 0xbf, 0x67, 0x84, 0x0c, 0xeb, 0x30, 0x79, 0xab, 0x8c, 0x6b,
-+ 0x8c, 0x19, 0x27, 0xf6, 0x40, 0x53, 0xc6, 0x12, 0x45, 0x0c, 0x45, 0xc9,
-+ 0xe6, 0x03, 0xbc, 0x16, 0x66, 0x6e, 0x59, 0x6b, 0x34, 0x71, 0xe1, 0x03,
-+ 0xb6, 0xf1, 0x54, 0x47, 0x42, 0x4d, 0x17, 0x02, 0x20, 0x48, 0x11, 0x1f,
-+ 0xfb, 0xd3, 0x7e, 0x1c, 0x67, 0x0f, 0x64, 0xf1, 0x4b, 0x8a, 0x7b, 0x32,
-+ 0xb9, 0x4c, 0x1a, 0x49, 0xb4, 0x5d, 0xd2, 0xfc, 0x38, 0xcd, 0x52, 0x89,
-+ 0xd9, 0x10, 0xad, 0x63, 0x60, 0x2c, 0xf5, 0xe1, 0x30, 0x42, 0xc6, 0x4a,
-+ 0xc6, 0x79, 0x7b, 0x89, 0xfb, 0x55, 0x1a, 0xd0, 0x8e, 0x05, 0xa9, 0x2d,
-+ 0x20, 0x0c, 0xcc, 0xb7, 0xe7, 0x12, 0xef, 0x23, 0xc9, 0x31, 0x2c, 0xb3,
-+ 0x50, 0xf0, 0x29, 0xab, 0x53, 0x7e, 0x28, 0x73, 0x47, 0xfd, 0x30, 0x75,
-+ 0xac, 0x10, 0x90, 0x6a, 0x78, 0x3f, 0x1c, 0x6c, 0x07, 0xcc, 0xb8, 0x8f,
-+ 0x41, 0x22, 0x8c, 0x4b, 0xe1, 0xc6, 0x40, 0xf7, 0x90, 0xb5, 0xc3, 0xa5,
-+ 0xd5, 0xd3, 0xca, 0x79, 0x24, 0x95, 0xd7, 0x4b, 0xc4, 0x61, 0x56, 0x26,
-+ 0x58, 0xc0, 0x7a, 0xc6, 0x00, 0x27, 0x6b, 0x92, 0x4a, 0xb5, 0xbc, 0x9b,
-+ 0xe1, 0xf0, 0x49, 0x4c, 0xb7, 0x6f, 0x82, 0xf4, 0x60, 0xa7, 0x48, 0x09,
-+ 0x72, 0x66, 0x33, 0x81, 0xe1, 0x69, 0x99, 0x60, 0x61, 0xd7, 0x99, 0x85,
-+ 0x9e, 0xc5, 0x4d, 0x4f, 0x5c, 0xa5, 0xc4, 0x11, 0xc0, 0x1d, 0xb1, 0x59,
-+ 0x7b, 0x16, 0x59, 0x77, 0x66, 0x9d, 0xe1, 0x3a, 0x92, 0x8a, 0x34, 0xaf,
-+ 0xba, 0xc2, 0x58, 0xfe, 0xa8, 0xc4, 0x76, 0x42, 0x39, 0xc9, 0x42, 0x1d,
-+ 0xc3, 0x11, 0x9b, 0xf5, 0xb4, 0x76, 0x99, 0x20, 0x69, 0x78, 0x32, 0x7b,
-+ 0x1c, 0x53, 0x45, 0xef, 0x74, 0x6a, 0x79, 0x83, 0x84, 0x1f, 0x05, 0x6e,
-+ 0x25, 0x34, 0x10, 0x0a, 0xb2, 0x4d, 0x4e, 0x9a, 0xbb, 0xd0, 0xb1, 0x7c,
-+ 0x6a, 0x95, 0xbd, 0x4c, 0x3c, 0x0e, 0x40, 0xf6, 0x9e, 0x16, 0x12, 0xac,
-+ 0xee, 0xb2, 0x8b, 0x99, 0x08, 0x6c, 0x95, 0x11, 0x6e, 0x72, 0x04, 0x27,
-+ 0x38, 0x93, 0x39, 0x0b, 0xf4, 0x6b, 0x89, 0x9b, 0x36, 0x28, 0x6b, 0x0e,
-+ 0xbf, 0x19, 0x47, 0xbb, 0x98, 0x84, 0xf7, 0x32, 0xca, 0x27, 0xda, 0x82,
-+ 0xb1, 0x9b, 0x5d, 0xc0, 0xcc, 0x7f, 0x88, 0x85, 0x71, 0x49, 0x10, 0x88,
-+ 0x8b, 0x23, 0x10, 0xc4, 0xf9, 0x31, 0x9d, 0x41, 0x0b, 0x34, 0xe6, 0x43,
-+ 0x3b, 0x90, 0x03, 0xe2, 0x17, 0x6b, 0xb9, 0x95, 0x25, 0x74, 0x56, 0x10,
-+ 0x6e, 0x89, 0x52, 0x16, 0x3b, 0x8b, 0xa5, 0x92, 0x53, 0x0c, 0xc5, 0xaa,
-+ 0x0a, 0xeb, 0x43, 0xad, 0x39, 0x8f, 0xe9, 0xe9, 0x7b, 0xaa, 0x52, 0x3d,
-+ 0x7a, 0x44, 0x31, 0x67, 0x7c, 0x3d, 0x3a, 0xf0, 0x71, 0x9e, 0x47, 0x5d,
-+ 0xb8, 0x5c, 0xa9, 0x5a, 0xf5, 0x08, 0x9b, 0xea, 0xbe, 0xb0, 0x5b, 0x2f,
-+ 0xaa, 0xb4, 0x89, 0x6b, 0xa6, 0x0f, 0x81, 0xc8, 0x84, 0x72, 0xa5, 0x7b,
-+ 0x46, 0xa8, 0x28, 0x82, 0x6a, 0x0c, 0xdf, 0xb4, 0x46, 0xf8, 0x18, 0x91,
-+ 0x82, 0xd2, 0xbf, 0x5e, 0xac, 0x4e, 0xc1, 0xcc, 0x5d, 0xea, 0xf5, 0x99,
-+ 0xc8, 0xa1, 0x3e, 0x48, 0x23, 0x54, 0x06, 0xd1, 0x7f, 0xfd, 0xdc, 0x83,
-+ 0x44, 0xb6, 0xc6, 0x69, 0x84, 0xa8, 0x68, 0xaa, 0x92, 0xfa, 0x02, 0x22,
-+ 0x7a, 0x08, 0x69, 0x50, 0xeb, 0x0c, 0x87, 0x01, 0xed, 0x58, 0xdc, 0x62,
-+ 0x87, 0x76, 0xb9, 0x83, 0x88, 0x2e, 0x11, 0x75, 0x61, 0x34, 0x9e, 0x5c,
-+ 0x13, 0x1a, 0x7e, 0x11, 0x6a, 0x04, 0x63, 0x86, 0x1d, 0x7d, 0x18, 0x66,
-+ 0x3c, 0x56, 0x27, 0xc3, 0x8c, 0x71, 0x47, 0xdd, 0xaa, 0xdf, 0xd4, 0x8a,
-+ 0xcd, 0x7a, 0x45, 0x35, 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,
-+ };
-+ static const unsigned char ml_kem1024_cipher_text[] = {
-+ 0x37, 0xd1, 0x5e, 0x8a, 0x30, 0xca, 0xda, 0x6d, 0xf6, 0xa3, 0x6e, 0x40,
-+ 0xce, 0x44, 0x5e, 0x6d, 0x18, 0xec, 0xb8, 0xf8, 0x1c, 0x3b, 0xf7, 0x7f,
-+ 0xef, 0xae, 0x73, 0xb1, 0x66, 0x23, 0x90, 0xf6, 0x03, 0xee, 0x45, 0xcc,
-+ 0x70, 0x31, 0x23, 0xc5, 0x0f, 0x59, 0xf1, 0x16, 0x8c, 0xac, 0xcc, 0x56,
-+ 0x5d, 0x43, 0x16, 0xe2, 0x2c, 0x15, 0x94, 0x0f, 0xaa, 0x69, 0x9a, 0x6b,
-+ 0xd6, 0x9a, 0x01, 0xcf, 0xc0, 0xaa, 0xad, 0x5f, 0xb0, 0x33, 0xe8, 0x3c,
-+ 0xb6, 0x78, 0x71, 0x29, 0x53, 0xda, 0x97, 0xd2, 0xb6, 0xfb, 0xc8, 0xd9,
-+ 0xb5, 0x1e, 0xe5, 0x19, 0xa3, 0x3d, 0x11, 0x41, 0xe5, 0x42, 0x2c, 0x7b,
-+ 0x44, 0xf8, 0x6f, 0x2f, 0x96, 0x8a, 0xe8, 0xcd, 0x50, 0xbd, 0xaa, 0x0c,
-+ 0x66, 0x7a, 0x93, 0x5b, 0x09, 0x8b, 0x09, 0x11, 0xf6, 0x7d, 0x4b, 0x52,
-+ 0x96, 0x32, 0xbb, 0x86, 0xea, 0xf0, 0x36, 0xee, 0xb0, 0xe2, 0xea, 0xf9,
-+ 0x93, 0xa4, 0x73, 0x25, 0x78, 0x70, 0x9d, 0x86, 0xac, 0x6f, 0xe1, 0x12,
-+ 0x2b, 0x68, 0x81, 0x30, 0xc5, 0x92, 0xb1, 0xe7, 0x79, 0x42, 0x2c, 0xe1,
-+ 0xc0, 0x98, 0x7f, 0x9b, 0x3d, 0xc4, 0x92, 0x46, 0x45, 0x2b, 0x76, 0xc4,
-+ 0x5e, 0x2d, 0x4d, 0x52, 0x2f, 0x06, 0xa6, 0x21, 0x99, 0x07, 0x93, 0xf9,
-+ 0xea, 0x41, 0xa1, 0x7f, 0xc1, 0xb3, 0x7a, 0x60, 0xd6, 0x67, 0xe6, 0x02,
-+ 0x4a, 0x83, 0x98, 0x3c, 0x38, 0x0d, 0x95, 0x5c, 0x7a, 0xb8, 0x55, 0x67,
-+ 0xd9, 0x28, 0x30, 0x44, 0xbc, 0xf5, 0x9e, 0xe6, 0x01, 0x18, 0x0b, 0x92,
-+ 0x51, 0x91, 0xb6, 0x61, 0xfa, 0xb2, 0x26, 0x84, 0x64, 0xd7, 0x6c, 0x71,
-+ 0x9c, 0x6b, 0xb1, 0x0a, 0x98, 0x8f, 0x41, 0x22, 0x42, 0x3e, 0xe7, 0xe6,
-+ 0xf7, 0x25, 0x88, 0x95, 0xcd, 0x99, 0xb5, 0x06, 0xcc, 0xe9, 0x9d, 0x76,
-+ 0x84, 0x22, 0xfe, 0xc0, 0x25, 0x90, 0xa9, 0xd0, 0xbf, 0x38, 0x36, 0xf7,
-+ 0x61, 0x0e, 0xc4, 0x6b, 0xd4, 0xa0, 0xe0, 0x35, 0x76, 0x53, 0x66, 0xe5,
-+ 0x8c, 0x25, 0x21, 0x35, 0x32, 0x3f, 0x4a, 0x4f, 0xd8, 0xc0, 0xb3, 0xd7,
-+ 0xc9, 0xaf, 0x62, 0x70, 0xed, 0x3e, 0xb8, 0xa4, 0x85, 0x7a, 0x92, 0x41,
-+ 0xef, 0x2f, 0x41, 0x9f, 0x97, 0xf1, 0xc3, 0x0e, 0xa2, 0xa3, 0x1c, 0xf9,
-+ 0x49, 0x53, 0x34, 0x3f, 0xf6, 0x40, 0x23, 0xb1, 0xca, 0xb5, 0x90, 0x1a,
-+ 0x6c, 0xbb, 0x55, 0xcb, 0x42, 0x6e, 0x57, 0x37, 0x5b, 0x4c, 0x40, 0x6a,
-+ 0x5b, 0x63, 0x8f, 0xe2, 0x40, 0xa9, 0xc5, 0xf1, 0x30, 0x85, 0xf3, 0xdd,
-+ 0x32, 0x26, 0x46, 0x7e, 0x6e, 0xda, 0x22, 0x2c, 0x53, 0xcf, 0x81, 0x30,
-+ 0x8e, 0x16, 0x3a, 0x45, 0x6a, 0x6b, 0x12, 0x4e, 0xbc, 0x28, 0x2d, 0xdc,
-+ 0x90, 0xc1, 0x79, 0x10, 0x7e, 0x78, 0xf9, 0xcd, 0x31, 0x77, 0x42, 0xf8,
-+ 0x4e, 0x6d, 0x79, 0xc8, 0xc9, 0x6f, 0xe5, 0x3e, 0x3c, 0xd1, 0x11, 0x87,
-+ 0xe1, 0x49, 0x95, 0x50, 0x48, 0x6e, 0xdc, 0x61, 0xbf, 0x9a, 0xb1, 0xcd,
-+ 0x5d, 0x5c, 0xe4, 0xd4, 0xfd, 0x16, 0xbd, 0x4d, 0xec, 0x42, 0xeb, 0x82,
-+ 0x2c, 0x11, 0xb0, 0x93, 0x68, 0xe6, 0x70, 0xd0, 0xf9, 0xab, 0xd2, 0xca,
-+ 0xb6, 0x4f, 0xd6, 0x3c, 0x71, 0x18, 0x3f, 0xd1, 0x5d, 0xc9, 0x28, 0x41,
-+ 0x6b, 0x14, 0x2a, 0x25, 0xb5, 0x55, 0x6d, 0xf3, 0x43, 0x0d, 0x37, 0x20,
-+ 0xd6, 0x94, 0xd8, 0xa3, 0xae, 0x61, 0x89, 0x94, 0x93, 0x2c, 0x74, 0x10,
-+ 0x94, 0xd1, 0x99, 0x9a, 0x14, 0x73, 0x35, 0xe7, 0x05, 0x24, 0x6f, 0x44,
-+ 0x9c, 0x56, 0x26, 0x7e, 0xfb, 0x31, 0x2a, 0x78, 0x30, 0x3b, 0xc5, 0xba,
-+ 0x34, 0x86, 0x70, 0xd7, 0x50, 0x2f, 0x2c, 0xc6, 0x37, 0xdf, 0xeb, 0xf7,
-+ 0x80, 0xf3, 0xd2, 0xcb, 0x48, 0xa8, 0xe9, 0xf4, 0xb7, 0xe2, 0xf8, 0x5a,
-+ 0x27, 0xc7, 0xcd, 0xb7, 0x2c, 0x1c, 0x0e, 0x32, 0x1f, 0x73, 0x96, 0x5b,
-+ 0x61, 0x3e, 0xe3, 0x9c, 0xf5, 0x6e, 0xdc, 0xe0, 0x66, 0x5e, 0x79, 0x7e,
-+ 0x15, 0x7c, 0x62, 0x2d, 0xab, 0xfa, 0xe0, 0xa2, 0xeb, 0xe2, 0xd6, 0x6e,
-+ 0x10, 0xde, 0xd5, 0xe4, 0xa0, 0x7b, 0x98, 0xfd, 0x2c, 0x0a, 0x9f, 0x55,
-+ 0x03, 0x2d, 0x1d, 0x0c, 0x8c, 0x44, 0xf9, 0xcd, 0xe8, 0xfd, 0x36, 0xd2,
-+ 0x88, 0x7b, 0x70, 0xa0, 0x88, 0xba, 0xa2, 0x89, 0xee, 0x26, 0x8a, 0x2e,
-+ 0xac, 0xa8, 0xe4, 0xff, 0x89, 0xed, 0x99, 0x30, 0xa0, 0x23, 0x70, 0x51,
-+ 0x52, 0xbb, 0xa6, 0xd5, 0xbf, 0xf1, 0xbe, 0x36, 0xf8, 0x42, 0x7a, 0xfe,
-+ 0xa3, 0xfe, 0x54, 0x8c, 0x9b, 0x84, 0xc3, 0x6a, 0xcd, 0x67, 0x72, 0x7f,
-+ 0x3c, 0xc7, 0x4c, 0x35, 0x55, 0xc5, 0x17, 0xaa, 0xed, 0x46, 0x87, 0x3a,
-+ 0xdb, 0xb0, 0xd9, 0x31, 0x7d, 0xcc, 0x6d, 0xf7, 0xf2, 0x32, 0x78, 0x1a,
-+ 0x70, 0x69, 0x5d, 0x19, 0xb1, 0xfd, 0x6c, 0x00, 0xd1, 0x9b, 0xf9, 0xb4,
-+ 0x4e, 0x6f, 0x9e, 0x9b, 0x30, 0x69, 0x03, 0x12, 0xed, 0x76, 0x91, 0x42,
-+ 0xfe, 0x1b, 0x84, 0xb1, 0x79, 0xeb, 0x3a, 0x76, 0x10, 0x51, 0x5c, 0x72,
-+ 0x99, 0x39, 0x47, 0x38, 0x77, 0x82, 0x59, 0x5c, 0xb3, 0x0f, 0xed, 0x12,
-+ 0x28, 0x03, 0xae, 0x3f, 0x3d, 0x51, 0xd8, 0xf9, 0x90, 0xd6, 0x68, 0x76,
-+ 0xe9, 0x84, 0x5f, 0xf5, 0x64, 0x15, 0xc5, 0x20, 0x55, 0x49, 0x04, 0xf8,
-+ 0x37, 0xc4, 0x50, 0x98, 0x76, 0x59, 0xc6, 0x2a, 0xd7, 0x45, 0x97, 0x1c,
-+ 0xf4, 0x4e, 0x8f, 0x66, 0xd3, 0x4b, 0x92, 0xba, 0x49, 0x86, 0x7a, 0x02,
-+ 0x4b, 0xa5, 0xc8, 0x15, 0xdd, 0x32, 0xe9, 0x2c, 0x3d, 0xfb, 0x9d, 0x99,
-+ 0x95, 0x26, 0xd5, 0x53, 0xdc, 0x1a, 0x94, 0x24, 0x5d, 0xc7, 0xed, 0x71,
-+ 0xc0, 0x09, 0xfe, 0x37, 0x9f, 0xe4, 0x00, 0xe0, 0x35, 0xa7, 0x0f, 0xe6,
-+ 0x4c, 0xb7, 0x78, 0xf4, 0x95, 0x94, 0x51, 0x0d, 0x40, 0x19, 0xf9, 0xd4,
-+ 0x04, 0x90, 0xb7, 0x47, 0xb6, 0x26, 0x93, 0xf3, 0xb4, 0x53, 0x61, 0xe9,
-+ 0x2c, 0xb8, 0x24, 0x2d, 0x3b, 0x74, 0xc1, 0x63, 0x12, 0xb4, 0x85, 0xb3,
-+ 0xc1, 0xd4, 0x65, 0x65, 0x5f, 0x71, 0x69, 0xd2, 0x23, 0xef, 0xcf, 0x3a,
-+ 0xe7, 0xd0, 0x39, 0x6e, 0xcc, 0xb9, 0x7e, 0xdc, 0xf5, 0x78, 0xbc, 0x9e,
-+ 0xa9, 0xb5, 0xc4, 0x68, 0xe9, 0xc6, 0xa0, 0x08, 0x11, 0xe8, 0x5d, 0xc5,
-+ 0x1b, 0x32, 0x05, 0xd1, 0xe3, 0x2a, 0x11, 0x12, 0xc7, 0x04, 0xcb, 0x00,
-+ 0x70, 0xcf, 0x9e, 0x27, 0xd7, 0xc7, 0x88, 0xf4, 0xa3, 0xd2, 0xf8, 0x1c,
-+ 0x0d, 0xfd, 0x9b, 0x52, 0xb9, 0x36, 0xa9, 0x19, 0x5c, 0x5c, 0xd8, 0x66,
-+ 0x04, 0x93, 0xff, 0xc6, 0xfe, 0x5b, 0x2e, 0xc4, 0xb8, 0xe4, 0xd2, 0x2d,
-+ 0xb3, 0xc8, 0x06, 0xde, 0xdc, 0xe1, 0x54, 0x63, 0x59, 0x47, 0x1a, 0x71,
-+ 0xb5, 0x7d, 0x4b, 0x38, 0x54, 0xca, 0x06, 0x19, 0x67, 0x34, 0xce, 0x81,
-+ 0xa6, 0x2f, 0x8b, 0xa4, 0x22, 0x9a, 0x93, 0x0b, 0x61, 0xcb, 0x17, 0x60,
-+ 0x62, 0xf8, 0x92, 0x6d, 0x06, 0xce, 0xe5, 0x65, 0xd7, 0xcf, 0xf7, 0xd2,
-+ 0x3e, 0x90, 0x17, 0xba, 0x1a, 0x84, 0x08, 0xcd, 0xd1, 0xa3, 0x71, 0xfa,
-+ 0x08, 0x31, 0x03, 0x48, 0x97, 0xd6, 0xa8, 0xc3, 0x35, 0x21, 0xf3, 0x26,
-+ 0x05, 0x6d, 0x72, 0x31, 0x05, 0x5f, 0xc8, 0xb6, 0x37, 0x93, 0xd0, 0xfa,
-+ 0xd9, 0x96, 0x3d, 0xcf, 0x62, 0xfb, 0xf4, 0x5a, 0x1c, 0x33, 0xec, 0x1d,
-+ 0x7e, 0x1a, 0x40, 0x2e, 0xd8, 0x63, 0x09, 0x58, 0x57, 0x81, 0x34, 0xec,
-+ 0x2b, 0x8f, 0x50, 0xed, 0xa1, 0xf3, 0xba, 0xf1, 0xe0, 0x32, 0x52, 0xf5,
-+ 0xb8, 0x7b, 0x88, 0x8a, 0x24, 0x12, 0x33, 0xcc, 0x86, 0xb8, 0x58, 0x36,
-+ 0xc1, 0x74, 0xb9, 0x58, 0x77, 0x61, 0x9a, 0x2e, 0x79, 0x2a, 0x0e, 0xb0,
-+ 0xfb, 0x93, 0xa3, 0x1c, 0x44, 0xde, 0xfc, 0xec, 0x79, 0x46, 0xdf, 0xc7,
-+ 0x0a, 0x5f, 0xe2, 0xfd, 0xc3, 0xe5, 0x86, 0x9f, 0x89, 0x43, 0x4f, 0x9c,
-+ 0x9d, 0x4d, 0x86, 0xce, 0x24, 0x81, 0x37, 0x56, 0xe5, 0xfa, 0xde, 0x43,
-+ 0xa3, 0x90, 0xee, 0xbb, 0x65, 0x64, 0x61, 0x6c, 0xc4, 0xf0, 0xd2, 0x33,
-+ 0x71, 0x65, 0x14, 0xd8, 0x3d, 0x70, 0x52, 0x45, 0xe8, 0x64, 0x46, 0x70,
-+ 0xe9, 0xaa, 0x26, 0xfa, 0xf6, 0x12, 0xe1, 0x9a, 0x24, 0x9a, 0xa5, 0xd7,
-+ 0x0c, 0x4d, 0xa5, 0x26, 0x74, 0x6f, 0xf9, 0x7a, 0x53, 0x41, 0xc9, 0x5c,
-+ 0xde, 0xbd, 0xda, 0xea, 0x19, 0x33, 0x70, 0xf5, 0xd2, 0xaf, 0x25, 0x11,
-+ 0x2a, 0x03, 0xda, 0x16, 0x03, 0x0d, 0xa3, 0x93, 0x3e, 0x69, 0x4c, 0x91,
-+ 0xa0, 0x7f, 0x87, 0x15, 0x24, 0xc2, 0x38, 0xbe, 0xd7, 0xed, 0x25, 0x0c,
-+ 0xbd, 0x94, 0x6d, 0x7c, 0x45, 0x19, 0x0b, 0x5e, 0x50, 0xa9, 0xca, 0x4b,
-+ 0x0d, 0xb4, 0x72, 0x73, 0xd4, 0x22, 0xc4, 0x0d, 0xbb, 0xe7, 0xcc, 0x60,
-+ 0xea, 0x42, 0xc3, 0xc4, 0xb3, 0x59, 0xe7, 0xf1, 0xa8, 0x40, 0xfa, 0x12,
-+ 0xb4, 0xac, 0x85, 0x1f, 0xdc, 0xec, 0xe0, 0x1f, 0x0b, 0x03, 0xe5, 0x03,
-+ 0xd1, 0x3d, 0x70, 0x36, 0x50, 0xdb, 0x89, 0xb6, 0xf6, 0xf5, 0x3c, 0x92,
-+ 0x6d, 0x2e, 0x5d, 0x7b, 0xe7, 0xbb, 0x5d, 0x51, 0x45, 0x70, 0xc3, 0x1e,
-+ 0xc3, 0xbb, 0x48, 0x9c, 0xf6, 0x29, 0xb7, 0x43, 0xe3, 0xcd, 0x3a, 0xcd,
-+ 0xc8, 0xc9, 0x7c, 0xe2, 0xfe, 0xf4, 0x66, 0xef, 0x27, 0x3c, 0xd0, 0x04,
-+ 0xcd, 0x21, 0xe0, 0xff, 0xe6, 0x5e, 0x04, 0xed, 0x88, 0x6f, 0x7c, 0xa8,
-+ 0x58, 0x1c, 0x36, 0x3b, 0xed, 0x93, 0x6e, 0xbb, 0x2c, 0x6b, 0x77, 0x26,
-+ 0x54, 0x09, 0x8b, 0x3c, 0xdf, 0xfd, 0x18, 0xa9, 0xeb, 0x2e, 0xf3, 0xbf,
-+ 0x81, 0xc6, 0xf5, 0x9b, 0xd9, 0x8d, 0xa8, 0x6e, 0x55, 0xb7, 0xd1, 0x54,
-+ 0x6d, 0xa3, 0xdf, 0x9f, 0x1d, 0xe7, 0xf5, 0x0e, 0x10, 0xe7, 0xce, 0xab,
-+ 0x66, 0x5e, 0xbd, 0xa5, 0x6f, 0x85, 0x49, 0xa1, 0x35, 0x24, 0xa4, 0xdd,
-+ 0x1b, 0x66, 0x5c, 0x9a, 0xfb, 0x92, 0xa1, 0x79, 0xc4, 0x51, 0x21, 0xe7,
-+ 0xce, 0x8c, 0x60, 0x27, 0xa4, 0x7c, 0x6e, 0x66, 0x50, 0x0e, 0xa9, 0xc2,
-+ 0xf4, 0xf2, 0x8a, 0x60, 0x90, 0x75, 0x04, 0xb0, 0x7a, 0x5c, 0x4a, 0x0d,
-+ 0x41, 0xac, 0x4b, 0x67, 0xe1, 0x56, 0x4d, 0x12, 0xac, 0xc7, 0x3a, 0xe2,
-+ 0xdb, 0x1b, 0x0f, 0x74, 0xd4, 0xae, 0x35, 0x0b, 0x39, 0x00, 0xa5, 0xd8,
-+ 0x15, 0x1a, 0xd0, 0xe7, 0x27, 0x06, 0xbd, 0x0a, 0x8f, 0x0d, 0x91, 0xe6,
-+ 0xf2, 0x71, 0xe3, 0xff, 0x30, 0xc7, 0xa9, 0x5f, 0xcd, 0x54, 0x24, 0x2e,
-+ 0x51, 0xfd, 0x45, 0xd1, 0x0e, 0xdb, 0xbf, 0x7c, 0xa7, 0x9d, 0x2f, 0x95,
-+ 0xa1, 0x66, 0x17, 0x34, 0xe5, 0x02, 0xea, 0x7a, 0x2b, 0x89, 0x61, 0x41,
-+ 0x14, 0xb1, 0x9f, 0xa1, 0xf0, 0xc2, 0x59, 0xd1, 0x80, 0xd0, 0xd8, 0x20,
-+ 0x75, 0xf6, 0x17, 0x78, 0xc5, 0xd6, 0x4a, 0x52, 0xe0, 0x7b, 0xfd, 0x31,
-+ 0x11, 0xb6, 0x8a, 0x29, 0x52, 0x23, 0xbe, 0x88, 0x7c, 0xe6, 0x22, 0x66,
-+ 0x9f, 0x29, 0xf2, 0xf5, 0xd0, 0xa1, 0x41, 0x8f, 0x14, 0xaa, 0xd9, 0xd7,
-+ 0xd3, 0x17, 0x59, 0xca, 0x63, 0x00, 0x98, 0xe2, 0x01, 0xf2, 0x0f, 0x84,
-+ 0x82, 0x40, 0x93, 0x89, 0x06, 0xc1, 0x8d, 0xbf, 0xfe, 0xe7, 0x07, 0x24,
-+ 0x99, 0x24, 0xcf, 0x86, 0xbe, 0x28, 0xd8, 0x71, 0x9d, 0xd3, 0x33, 0xd4,
-+ 0xbf, 0xfa, 0xe1, 0x5d, 0xe9, 0x4e, 0xc4, 0x7c, 0x2d, 0x91, 0x66, 0x8e,
-+ 0x95, 0x14, 0x57, 0x2f, 0xa2, 0x03, 0x47, 0x0c, 0x08, 0x5a, 0x19, 0x9e,
-+ 0x3b, 0xaf, 0x03, 0xad, 0xf1, 0xab, 0x8f, 0x86, 0xea, 0x46, 0x28, 0xf8,
-+ 0x53, 0x80, 0xee, 0x89, 0x53, 0xd4, 0xa1, 0xad,
-+ };
-+ static const unsigned char ml_kem1024_key[] = {
-+ 0x73, 0x8a, 0x88, 0xcd, 0x9a, 0x25, 0x86, 0x1e, 0x9a, 0x37, 0xc6, 0x5a,
-+ 0x67, 0xec, 0x1b, 0x39, 0xf0, 0x69, 0xae, 0xd9, 0x64, 0x6e, 0xde, 0x89,
-+ 0x41, 0x0a, 0xce, 0x47, 0xa9, 0x6a, 0x9b, 0x57,
-+ };
-diff --git a/lib/freebl/rsa.c b/lib/freebl/rsa.c
---- a/lib/freebl/rsa.c
-+++ b/lib/freebl/rsa.c
-@@ -314,18 +314,22 @@ RSA_NewKey(int keySizeInBits, SECItem *p
- MP_DIGITS(&e) = 0;
- CHECK_MPI_OK(mp_init(&e));
- SECITEM_TO_MPINT(*publicExponent, &e);
- if (mp_iseven(&e) || !(mp_cmp_d(&e, 2) > 0)) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- goto cleanup;
- }
- #ifndef NSS_FIPS_DISABLED
-- /* Check that the exponent is not smaller than 65537 */
-- if (mp_cmp_d(&e, 0x10001) < 0) {
-+ /* Check that the exponent is not smaller than 65537, and not larger
-+ * the the max digit (which is between 2^33-1 and 2^65-1 all of which is less thant
-+ * the FIPS max of 2^256. NSS level code already limits this value to 2^33-1,
-+ * so we aren't adding any new requirements on real code. We use
-+ * MP_DIGIT_MAX because it allows us to easily use mp_cmp_d */
-+ if ((mp_cmp_d(&e, 0x10001) == MP_LT) || (mp_cmp_d(&e, MP_DIGIT_MAX) == MP_GT)) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- goto cleanup;
- }
- #endif
-
- /* 2. Allocate arena & key */
- arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE);
- if (!arena) {
-diff --git a/lib/pk11wrap/pk11pars.c b/lib/pk11wrap/pk11pars.c
---- a/lib/pk11wrap/pk11pars.c
-+++ b/lib/pk11wrap/pk11pars.c
-@@ -242,32 +242,26 @@ static const oidValDef curveOptList[] =
- { CIPHER_NAME("SECP384R1"), SEC_OID_SECG_EC_SECP384R1,
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
- { CIPHER_NAME("SECP521R1"), SEC_OID_SECG_EC_SECP521R1,
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
- { CIPHER_NAME("CURVE25519"), SEC_OID_CURVE25519,
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
- { CIPHER_NAME("XYBER768D00"), SEC_OID_XYBER768D00,
- NSS_USE_ALG_IN_SSL_KX },
-- { CIPHER_NAME("MLKEM768X25519"), SEC_OID_MLKEM768X25519,
-- NSS_USE_ALG_IN_SSL_KX },
-- { CIPHER_NAME("SECP256R1MLKEM768"), SEC_OID_SECP256R1MLKEM768,
-- NSS_USE_ALG_IN_SSL_KX },
-- { CIPHER_NAME("MLKEM1024SECP384R1"), SEC_OID_SECP384R1MLKEM1024,
-- NSS_USE_ALG_IN_SSL_KX },
- { CIPHER_NAME("X25519MLKEM768"), SEC_OID_MLKEM768X25519,
- NSS_USE_ALG_IN_SSL_KX },
- { CIPHER_NAME("SECP256R1MLKEM768"), SEC_OID_SECP256R1MLKEM768,
- NSS_USE_ALG_IN_SSL_KX },
- { CIPHER_NAME("SECP384R1MLKEM1024"), SEC_OID_SECP384R1MLKEM1024,
- NSS_USE_ALG_IN_SSL_KX },
- /* aliases for old names */
- { CIPHER_NAME("MLKEM768X25519"), SEC_OID_MLKEM768X25519,
- NSS_USE_ALG_IN_SSL_KX },
-- { CIPHER_NAME("SECP256R1MLKEM768"), SEC_OID_SECP256R1MLKEM768,
-+ { CIPHER_NAME("MLKEM768SECP256R1"), SEC_OID_SECP256R1MLKEM768,
- NSS_USE_ALG_IN_SSL_KX },
- { CIPHER_NAME("MLKEM1024SECP384R1"), SEC_OID_SECP384R1MLKEM1024,
- NSS_USE_ALG_IN_SSL_KX },
- /* ANSI X9.62 named elliptic curves (characteristic two field) */
- { CIPHER_NAME("C2PNB163V1"), SEC_OID_ANSIX962_EC_C2PNB163V1,
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
- { CIPHER_NAME("C2PNB163V2"), SEC_OID_ANSIX962_EC_C2PNB163V2,
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
-diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
---- a/lib/softoken/pkcs11c.c
-+++ b/lib/softoken/pkcs11c.c
-@@ -5268,42 +5268,41 @@ loser:
- }
- if (att2) {
- sftk_FreeAttribute(att2);
- }
- return result;
- }
-
-
--#define PAIRWISE_DIGEST_LENGTH SHA1_LENGTH /* 160-bits */
- #define PAIRWISE_MESSAGE_LENGTH 20 /* 160-bits */
-
- /*
-- * FIPS 140-2 pairwise consistency check utilized to validate key pair.
-+ * FIPS 140-3 pairwise consistency check utilized to validate key pair.
- *
- * This function returns
- * CKR_OK if pairwise consistency check passed
- * CKR_GENERAL_ERROR if pairwise consistency check failed
- * other error codes if paiswise consistency check could not be
- * performed, for example, CKR_HOST_MEMORY.
- */
- static CK_RV
- sftk_PairwiseConsistencyCheck(CK_SESSION_HANDLE hSession, SFTKSlot *slot,
- SFTKObject *publicKey, SFTKObject *privateKey,
- CK_KEY_TYPE keyType)
- {
- /*
- * Key type Mechanism type
- * --------------------------------
-- * For encrypt/decrypt: CKK_RSA => CKM_RSA_PKCS
-+ * For encrypt/decrypt: CKK_RSA => CKM_RSA_PKCS_OAEP
- * others => CKM_INVALID_MECHANISM
- *
-- * For sign/verify: CKK_RSA => CKM_RSA_PKCS
-- * CKK_DSA => CKM_DSA
-- * CKK_EC => CKM_ECDSA
-+ * For sign/verify: CKK_RSA => CKM_SHA256_RSA_PKCS_PSS
-+ * CKK_DSA => CKM_DSA_SHA256
-+ * CKK_EC => CKM_ECDSA_SHA256
- * others => CKM_INVALID_MECHANISM
- *
- * None of these mechanisms has a parameter.
- *
- * For derive: regenerate public key from the private key
- * CKK_DH => DH_Derive
- * CKK_EC => EC_NewKeyFromSeed
- * CKK_EC_MONTGOMERY => EC_NewKeyFromSeed
-@@ -5327,37 +5326,42 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
- /* Variables used for Encrypt/Decrypt functions. */
- unsigned char *known_message = (unsigned char *)"Known Crypto Message";
- unsigned char plaintext[PAIRWISE_MESSAGE_LENGTH];
- CK_ULONG bytes_decrypted;
- unsigned char *ciphertext;
- unsigned char *text_compared;
- CK_ULONG bytes_encrypted;
- CK_ULONG bytes_compared;
-- CK_ULONG pairwise_digest_length = PAIRWISE_DIGEST_LENGTH;
-
- /* Variables used for Signature/Verification functions. */
-- /* Must be at least 256 bits for DSA2 digest */
-- unsigned char *known_digest = (unsigned char *)"Mozilla Rules the World through NSS!";
- unsigned char *signature;
- CK_ULONG signature_length;
- SFTKAttribute *attribute;
-
- switch (keyType) {
- case CKK_RSA:
- /* Get modulus length of private key. */
- attribute = sftk_FindAttribute(privateKey, CKA_MODULUS);
- if (attribute == NULL) {
- return CKR_DEVICE_ERROR;
- }
- modulusLen = attribute->attrib.ulValueLen;
- if (*(unsigned char *)attribute->attrib.pValue == 0) {
- modulusLen--;
- }
- sftk_FreeAttribute(attribute);
-+#if RSA_MIN_MODULUS_BITS < 1023
-+ /* if we allow weak RSA keys, and this is a weak RSA key and
-+ * we aren't in FIPS mode, skip the tests, These keys are
-+ * factorable anyway, the pairwise test doen't matter. */
-+ if ((modulusLen < 1023) && !sftk_isFIPS(slot->slotID)) {
-+ return CKR_OK;
-+ }
-+#endif
- break;
- case CKK_DSA:
- /* Get subprime length of private key. */
- attribute = sftk_FindAttribute(privateKey, CKA_SUBPRIME);
- if (attribute == NULL) {
- return CKR_DEVICE_ERROR;
- }
- subPrimeLen = attribute->attrib.ulValueLen;
-@@ -5385,17 +5389,25 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
- * If the decryption attribute is set, attempt to encrypt
- * with the public key and decrypt with the private key.
- */
- if (isEncryptable) {
- if (keyType != CKK_RSA) {
- return CKR_DEVICE_ERROR;
- }
- bytes_encrypted = modulusLen;
-- mech.mechanism = CKM_RSA_PKCS;
-+ mech.mechanism = CKM_RSA_PKCS_OAEP;
-+ CK_RSA_PKCS_OAEP_PARAMS oaepParams;
-+ oaepParams.hashAlg = CKM_SHA256;
-+ oaepParams.mgf = CKG_MGF1_SHA256;
-+ oaepParams.source = CKZ_DATA_SPECIFIED;
-+ oaepParams.pSourceData = NULL;
-+ oaepParams.ulSourceDataLen = 0;
-+ mech.pParameter = &oaepParams;
-+ mech.ulParameterLen = sizeof(oaepParams);
-
- /* Allocate space for ciphertext. */
- ciphertext = (unsigned char *)PORT_ZAlloc(bytes_encrypted);
- if (ciphertext == NULL) {
- return CKR_HOST_MEMORY;
- }
-
- /* Prepare for encryption using the public key. */
-@@ -5494,30 +5506,35 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
- if (canSignVerify && keyType == CKK_EC) {
- NSSLOWKEYPrivateKey *privKey = sftk_GetPrivKey(privateKey, CKK_EC, &crv);
- if (privKey && privKey->u.ec.ecParams.name == ECCurve25519) {
- canSignVerify = PR_FALSE;
- }
- }
-
- if (canSignVerify) {
-+ CK_RSA_PKCS_PSS_PARAMS pssParams;
- /* Determine length of signature. */
- switch (keyType) {
- case CKK_RSA:
- signature_length = modulusLen;
-- mech.mechanism = CKM_RSA_PKCS;
-+ mech.mechanism = CKM_SHA256_RSA_PKCS_PSS;
-+ pssParams.hashAlg = CKM_SHA256;
-+ pssParams.mgf = CKG_MGF1_SHA256;
-+ pssParams.sLen = 0;
-+ mech.pParameter = &pssParams;
-+ mech.ulParameterLen = sizeof(pssParams);
- break;
- case CKK_DSA:
- signature_length = DSA_MAX_SIGNATURE_LEN;
-- pairwise_digest_length = subPrimeLen;
-- mech.mechanism = CKM_DSA;
-+ mech.mechanism = CKM_DSA_SHA256;
- break;
- case CKK_EC:
- signature_length = MAX_ECKEY_LEN * 2;
-- mech.mechanism = CKM_ECDSA;
-+ mech.mechanism = CKM_ECDSA_SHA256;
- break;
- case CKK_ML_DSA:
- signature_length = MAX_ML_DSA_SIGNATURE_LEN;
- mech.mechanism = CKM_ML_DSA;
- break;
- case CKK_EC_EDWARDS:
- signature_length = ED25519_SIGN_LEN;
- mech.mechanism = CKM_EDDSA;
-@@ -5535,42 +5552,42 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
- /* Sign the known hash using the private key. */
- crv = NSC_SignInit(hSession, &mech, privateKey->handle);
- if (crv != CKR_OK) {
- PORT_Free(signature);
- return crv;
- }
-
- crv = NSC_Sign(hSession,
-- known_digest,
-- pairwise_digest_length,
-+ known_message,
-+ PAIRWISE_MESSAGE_LENGTH,
- signature,
- &signature_length);
- if (crv != CKR_OK) {
- PORT_Free(signature);
- return crv;
- }
-
- /* detect trivial signing transforms */
-- if ((signature_length >= pairwise_digest_length) &&
-- (PORT_Memcmp(known_digest, signature + (signature_length - pairwise_digest_length), pairwise_digest_length) == 0)) {
-+ if ((signature_length >= PAIRWISE_MESSAGE_LENGTH) &&
-+ (PORT_Memcmp(known_message, signature + (signature_length - PAIRWISE_MESSAGE_LENGTH), PAIRWISE_MESSAGE_LENGTH) == 0)) {
- PORT_Free(signature);
- return CKR_GENERAL_ERROR;
- }
-
- /* Verify the known hash using the public key. */
- crv = NSC_VerifyInit(hSession, &mech, publicKey->handle);
- if (crv != CKR_OK) {
- PORT_Free(signature);
- return crv;
- }
-
- crv = NSC_Verify(hSession,
-- known_digest,
-- pairwise_digest_length,
-+ known_message,
-+ PAIRWISE_MESSAGE_LENGTH,
- signature,
- signature_length);
-
- /* Free signature data. */
- PORT_Free(signature);
-
- if ((crv == CKR_SIGNATURE_LEN_RANGE) ||
- (crv == CKR_SIGNATURE_INVALID)) {
-diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c
---- a/lib/softoken/pkcs11u.c
-+++ b/lib/softoken/pkcs11u.c
-@@ -2454,18 +2454,16 @@ sftk_getKeyLength(SFTKObject *source)
- }
-
- PRBool
- sftk_checkFIPSHash(CK_MECHANISM_TYPE hash, PRBool allowSmall, PRBool allowCMAC)
- {
- switch (hash) {
- case CKM_AES_CMAC:
- return allowCMAC;
-- case CKM_SHA_1:
-- case CKM_SHA_1_HMAC:
- case CKM_SHA224:
- case CKM_SHA224_HMAC:
- return allowSmall;
- case CKM_SHA256:
- case CKM_SHA256_HMAC:
- case CKM_SHA384:
- case CKM_SHA384_HMAC:
- case CKM_SHA512:
-@@ -2591,16 +2589,23 @@ sftk_handleSpecial(SFTKSlot *slot, CK_ME
- return PR_FALSE;
- }
- if (pbkdf2->ulSaltSourceDataLen < 16) {
- return PR_FALSE;
- }
- if (*(pbkdf2->ulPasswordLen) < SFTKFIPS_PBKDF2_MIN_PW_LEN) {
- return PR_FALSE;
- }
-+ /* sigh pbKDF2 defines it's own prf, just reject SHA-1 here. Future
-+ * make the mapping switch in nsc_SetupPBEKeyGen into a generic function
-+ * that return a hashType or a mechanism and then we can use
-+ * sftk_checkFIPSHash */
-+ if (pbkdf2->prf == CKP_PKCS5_PBKD2_HMAC_SHA1) {
-+ return PR_FALSE;
-+ }
- return PR_TRUE;
- }
- /* check the hash mechanisms to make sure they themselves are FIPS */
- case SFTKFIPSChkHashSp800:
- allowCMAC = PR_TRUE;
- case SFTKFIPSChkHash:
- allowSmall = PR_TRUE;
- case SFTKFIPSChkHashTls:
-diff --git a/lib/ssl/tls13con.c b/lib/ssl/tls13con.c
---- a/lib/ssl/tls13con.c
-+++ b/lib/ssl/tls13con.c
-@@ -724,20 +724,29 @@ tls13_SetupClientHello(sslSocket *ss, ss
- if (rv != SECSuccess) {
- return SECFailure;
- }
-
- /* Select the first enabled group.
- * TODO(ekr@rtfm.com): be smarter about offering the group
- * that the other side negotiated if we are resuming. */
- PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs));
-+ PRBool has_hybrid = PR_FALSE;
- for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
- if (!ss->namedGroupPreferences[i]) {
- continue;
- }
-+ /* only send one hybrid key share no matter how many key
-+ * shares we send */
-+ if (ss->namedGroupPreferences[i]->keaType == ssl_kea_ecdh_hybrid) {
-+ if (has_hybrid) {
-+ continue; /* already have one skip*/
-+ }
-+ has_hybrid = PR_TRUE;
-+ }
- rv = tls13_AddKeyShare(ss, ss->namedGroupPreferences[i]);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- if (++numShares > ss->additionalShares) {
- break;
- }
- }
diff --git a/nss-3.112-fips.patch b/nss-3.112-fips.patch
deleted file mode 100644
index 2cedc92..0000000
--- a/nss-3.112-fips.patch
+++ /dev/null
@@ -1,888 +0,0 @@
-diff --git a/lib/freebl/stubs.c b/lib/freebl/stubs.c
---- a/lib/freebl/stubs.c
-+++ b/lib/freebl/stubs.c
-@@ -485,17 +485,17 @@ PR_GetLibraryFilePathname_stub(const cha
- extern int
- PORT_GetError_stub(void)
- {
- STUB_SAFE_CALL0(PORT_GetError_Util);
- return errno;
- }
-
- extern void
--PORT_SafeZero(void *p, size_t n)
-+PORT_SafeZero_stub(void *p, size_t n)
- {
- STUB_SAFE_CALL2(PORT_SafeZero, p, n);
- /* just use a generic call in the case where we are running
- * standalone freebl */
- if (p != NULL) {
- volatile unsigned char *__vl = (unsigned char *)p;
- size_t __nl = n;
- while (__nl--)
-diff --git a/lib/freebl/stubs.h b/lib/freebl/stubs.h
---- a/lib/freebl/stubs.h
-+++ b/lib/freebl/stubs.h
-@@ -22,17 +22,17 @@
-
- #define PORT_Alloc PORT_Alloc_stub
- #define PORT_ArenaAlloc PORT_ArenaAlloc_stub
- #define PORT_ArenaZAlloc PORT_ArenaZAlloc_stub
- #define PORT_Free PORT_Free_stub
- #define PORT_FreeArena PORT_FreeArena_stub
- #define PORT_GetError PORT_GetError_stub
- #define PORT_NewArena PORT_NewArena_stub
--#define PORT_SaveZero PORT_SaveZero_stub
-+#define PORT_SafeZero PORT_SafeZero_stub
- #define PORT_SetError PORT_SetError_stub
- #define PORT_ZAlloc PORT_ZAlloc_stub
- #define PORT_ZFree PORT_ZFree_stub
- #define PORT_ZAllocAligned PORT_ZAllocAligned_stub
- #define PORT_ZAllocAlignedOffset PORT_ZAllocAlignedOffset_stub
-
- #define SECITEM_AllocItem SECITEM_AllocItem_stub
- #define SECITEM_CompareItem SECITEM_CompareItem_stub
-diff --git a/lib/freebl/unix_fips140_3.c b/lib/freebl/unix_fips140_3.c
---- a/lib/freebl/unix_fips140_3.c
-+++ b/lib/freebl/unix_fips140_3.c
-@@ -25,17 +25,17 @@ RNG_SystemInfoForRNG(void)
- {
- PRUint8 bytes[SYSTEM_RNG_SEED_COUNT];
- size_t numBytes = RNG_SystemRNG(bytes, SYSTEM_RNG_SEED_COUNT);
- if (!numBytes) {
- /* error is set */
- return;
- }
- RNG_RandomUpdate(bytes, numBytes);
-- PORT_SaveZero(bytes, sizeof(bytes));
-+ PORT_SafeZero(bytes, sizeof(bytes));
- }
-
- static unsigned int rng_grndFlags = 0;
- static PRCallOnceType rng_KernelFips;
-
- static PRStatus
- rng_getKernelFips()
- {
-diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
---- a/lib/softoken/pkcs11c.c
-+++ b/lib/softoken/pkcs11c.c
-@@ -535,17 +535,17 @@ sftk_InitGeneric(SFTKSession *session, C
- context->cipherInfo = NULL;
- context->hashInfo = NULL;
- context->doPad = PR_FALSE;
- context->padDataLength = 0;
- context->key = key;
- context->blockSize = 0;
- context->maxLen = 0;
- context->isFIPS = sftk_operationIsFIPS(session->slot, pMechanism,
-- operation, key);
-+ operation, key, 0);
- *contextPtr = context;
- return CKR_OK;
- }
-
- static int
- sftk_aes_mode(CK_MECHANISM_TYPE mechanism)
- {
- switch (mechanism) {
-@@ -4794,16 +4794,17 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSessi
- goto loser;
- }
-
- /* make sure we don't have any class, key_type, or value fields */
- sftk_DeleteAttributeType(key, CKA_CLASS);
- sftk_DeleteAttributeType(key, CKA_KEY_TYPE);
- sftk_DeleteAttributeType(key, CKA_VALUE);
-
-+
- /* Now Set up the parameters to generate the key (based on mechanism) */
- key_gen_type = nsc_bulk; /* bulk key by default */
- switch (pMechanism->mechanism) {
- case CKM_CDMF_KEY_GEN:
- case CKM_DES_KEY_GEN:
- case CKM_DES2_KEY_GEN:
- case CKM_DES3_KEY_GEN:
- checkWeak = PR_TRUE;
-@@ -4990,16 +4991,20 @@ NSC_GenerateKey(CK_SESSION_HANDLE hSessi
- crv = CKR_SESSION_HANDLE_INVALID;
- goto loser;
- }
-
- /*
- * handle the base object stuff
- */
- crv = sftk_handleObject(key, session);
-+ /* we need to do this check at the end, so we can check the generated key length against
-+ * fips requirements */
-+ key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_NSS_GENERATE, key, 0);
-+ session->lastOpWasFIPS = key->isFIPS;
- sftk_FreeSession(session);
- if (crv == CKR_OK && sftk_isTrue(key, CKA_SENSITIVE)) {
- crv = sftk_forceAttribute(key, CKA_ALWAYS_SENSITIVE, &cktrue, sizeof(CK_BBOOL));
- }
- if (crv == CKR_OK && !sftk_isTrue(key, CKA_EXTRACTABLE)) {
- crv = sftk_forceAttribute(key, CKA_NEVER_EXTRACTABLE, &cktrue, sizeof(CK_BBOOL));
- }
- if (crv == CKR_OK) {
-@@ -6077,18 +6082,18 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
- }
-
- /*
- * handle the base object cleanup for the private Key
- * If we have any problems, we destroy the public Key we've
- * created and linked.
- */
- crv = sftk_handleObject(publicKey, session);
-- sftk_FreeSession(session);
- if (crv != CKR_OK) {
-+ sftk_FreeSession(session);
- sftk_FreeObject(publicKey);
- NSC_DestroyObject(hSession, privateKey->handle);
- sftk_FreeObject(privateKey);
- return crv;
- }
- if (sftk_isTrue(privateKey, CKA_SENSITIVE)) {
- crv = sftk_forceAttribute(privateKey, CKA_ALWAYS_SENSITIVE,
- &cktrue, sizeof(CK_BBOOL));
-@@ -6120,22 +6125,29 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
- (PRUint32)hSession, (PRUint32)pMechanism->mechanism,
- (PRUint32)crv);
- sftk_LogAuditMessage(NSS_AUDIT_ERROR, NSS_AUDIT_SELF_TEST, msg);
- }
- }
- }
-
- if (crv != CKR_OK) {
-+ sftk_FreeSession(session);
- NSC_DestroyObject(hSession, publicKey->handle);
- sftk_FreeObject(publicKey);
- NSC_DestroyObject(hSession, privateKey->handle);
- sftk_FreeObject(privateKey);
- return crv;
- }
-+ /* we need to do this check at the end to make sure the generated key meets the key length requirements */
-+ privateKey->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_NSS_GENERATE_KEY_PAIR, privateKey, 0);
-+ publicKey->isFIPS = privateKey->isFIPS;
-+ session->lastOpWasFIPS = privateKey->isFIPS;
-+
-+ sftk_FreeSession(session);
- *phPrivateKey = privateKey->handle;
- *phPublicKey = publicKey->handle;
- sftk_FreeObject(publicKey);
- sftk_FreeObject(privateKey);
-
- return CKR_OK;
- }
-
-@@ -7321,30 +7333,35 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
- return CKR_MECHANISM_PARAM_INVALID;
- }
- if ((params->bExpand && keySize == 0) ||
- (!params->bExpand && keySize > hashLen) ||
- (params->bExpand && keySize > 255 * hashLen)) {
- return CKR_TEMPLATE_INCONSISTENT;
- }
-
-+ if (!params->bExpand) {
-+ keySize = hashLen;
-+ }
-+
- /* sourceKey is NULL if we are called from the POST, skip the
- * sensitiveCheck */
- if (sourceKey != NULL) {
- crv = sftk_DeriveSensitiveCheck(sourceKey, key, canBeData);
- if (crv != CKR_OK)
- return crv;
- }
-
- /* HKDF-Extract(salt, base key value) */
- if (params->bExtract) {
- CK_BYTE *salt;
- CK_ULONG saltLen;
- HMACContext *hmac;
- unsigned int bufLen;
-+ SFTKSource saltKeySource = SFTK_SOURCE_DEFAULT;
-
- switch (params->ulSaltType) {
- case CKF_HKDF_SALT_NULL:
- saltLen = hashLen;
- salt = hashbuf;
- memset(salt, 0, saltLen);
- break;
- case CKF_HKDF_SALT_DATA:
-@@ -7369,31 +7386,57 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
- /* if the base key is not fips, but the salt key is, the
- * resulting key can be fips */
- if (isFIPS && (key->isFIPS == 0) && (saltKey->isFIPS == 1)) {
- CK_MECHANISM mech;
- mech.mechanism = CKM_HKDF_DERIVE;
- mech.pParameter = params;
- mech.ulParameterLen = sizeof(*params);
- key->isFIPS = sftk_operationIsFIPS(saltKey->slot, &mech,
-- CKA_DERIVE, saltKey);
-+ CKA_DERIVE, saltKey,
-+ keySize*PR_BITS_PER_BYTE);
- }
-+ saltKeySource = saltKey->source;
- saltKey_att = sftk_FindAttribute(saltKey, CKA_VALUE);
- if (saltKey_att == NULL) {
- sftk_FreeObject(saltKey);
- return CKR_KEY_HANDLE_INVALID;
- }
- /* save the resulting salt */
- salt = saltKey_att->attrib.pValue;
- saltLen = saltKey_att->attrib.ulValueLen;
- break;
- default:
- return CKR_MECHANISM_PARAM_INVALID;
- break;
- }
-+ /* only TLS style usage is FIPS approved,
-+ * turn off the FIPS indicator for other usages */
-+ if (isFIPS && key && sourceKey) {
-+ PRBool fipsOK = PR_FALSE;
-+ /* case one: mix the kea with a previous or default
-+ * salt */
-+ if ((sourceKey->source == SFTK_SOURCE_KEA) &&
-+ (saltKeySource == SFTK_SOURCE_HKDF_EXPAND) &&
-+ (saltLen == rawHash->length)) {
-+ fipsOK = PR_TRUE;
-+ }
-+ /* case two: restart, remix the previous secret as a salt */
-+ if ((sourceKey->objclass == CKO_DATA) &&
-+ (NSS_SecureMemcmpZero(sourceKeyBytes, sourceKeyLen) == 0) &&
-+ (sourceKeyLen == rawHash->length) &&
-+ (saltKeySource == SFTK_SOURCE_HKDF_EXPAND) &&
-+ (saltLen == rawHash->length)) {
-+ fipsOK = PR_TRUE;
-+ }
-+ if (!fipsOK) {
-+ key->isFIPS = PR_FALSE;
-+ }
-+ }
-+ if (key) key->source = SFTK_SOURCE_HKDF_EXTRACT;
-
- hmac = HMAC_Create(rawHash, salt, saltLen, isFIPS);
- if (saltKey_att) {
- sftk_FreeAttribute(saltKey_att);
- }
- if (saltKey) {
- sftk_FreeObject(saltKey);
- }
-@@ -7411,26 +7454,50 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
- /* PRK = base key value */
- prk = sourceKeyBytes;
- prkLen = sourceKeyLen;
- }
-
- /* HKDF-Expand */
- if (!params->bExpand) {
- okm = prk;
-- keySize = genLen = hashLen;
-+ genLen = hashLen;
- } else {
- /* T(1) = HMAC-Hash(prk, "" | info | 0x01)
- * T(n) = HMAC-Hash(prk, T(n-1) | info | n
- * key material = T(1) | ... | T(n)
- */
- HMACContext *hmac;
- CK_BYTE bi;
- unsigned iterations;
-
-+ /* only TLS style usage is FIPS approved,
-+ * turn off the FIPS indicator for other usages */
-+ if (isFIPS && key && key->isFIPS && sourceKey) {
-+ unsigned char *info=¶ms->pInfo[3];
-+ /* only one case,
-+ * 1) Expand only
-+ * 2) with a key whose source was
-+ * SFTK_SOURCE_HKDF_EXPAND or SFTK_SOURCE_HKDF_EXTRACT
-+ * 3) source key length == rawHash->length
-+ * 4) Info has tls or dtls
-+ * If any of those conditions aren't met, then we turn
-+ * off the fips indicator */
-+ if (params->bExtract ||
-+ ((sourceKey->source != SFTK_SOURCE_HKDF_EXTRACT) &&
-+ (sourceKey->source != SFTK_SOURCE_HKDF_EXPAND)) ||
-+ (sourceKeyLen != rawHash->length) ||
-+ (params->ulInfoLen < 7) ||
-+ ((PORT_Memcmp(info,"tls",3) != 0) &&
-+ (PORT_Memcmp(info,"dtls",4) != 0))) {
-+ key->isFIPS = PR_FALSE;
-+ }
-+ }
-+ if (key) key->source = SFTK_SOURCE_HKDF_EXPAND;
-+
- genLen = PR_ROUNDUP(keySize, hashLen);
- iterations = genLen / hashLen;
-
- if (genLen > sizeof(keyBlock)) {
- keyBlockAlloc = PORT_Alloc(genLen);
- if (keyBlockAlloc == NULL) {
- return CKR_HOST_MEMORY;
- }
-@@ -7635,17 +7702,18 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
- /* get the value of the base key */
- att = sftk_FindAttribute(sourceKey, CKA_VALUE);
- if (att == NULL) {
- sftk_FreeObject(key);
- sftk_FreeObject(sourceKey);
- return CKR_KEY_HANDLE_INVALID;
- }
- }
-- key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_DERIVE, sourceKey);
-+ key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_DERIVE, sourceKey,
-+ keySize*PR_BITS_PER_BYTE);
-
- switch (mechanism) {
- /* get a public key from a private key. nsslowkey_ConvertToPublickey()
- * will generate the public portion if it doesn't already exist. */
- case CKM_NSS_PUB_FROM_PRIV: {
- NSSLOWKEYPrivateKey *privKey;
- NSSLOWKEYPublicKey *pubKey;
- int error;
-@@ -8797,16 +8865,17 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
-
- /* calculate private value - oct */
- rv = DH_Derive(&dhPublic, &dhPrime, &dhValue, &derived, keySize);
-
- SECITEM_ZfreeItem(&dhPrime, PR_FALSE);
- SECITEM_ZfreeItem(&dhValue, PR_FALSE);
-
- if (rv == SECSuccess) {
-+ key->source = SFTK_SOURCE_KEA;
- sftk_forceAttribute(key, CKA_VALUE, derived.data, derived.len);
- SECITEM_ZfreeItem(&derived, PR_FALSE);
- crv = CKR_OK;
- } else
- crv = CKR_HOST_MEMORY;
-
- break;
- }
-@@ -8894,16 +8963,17 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
- * tmp is the raw data created by ECDH_Derive,
- * secret and secretlen are the values we will
- * eventually pass as our generated key.
- */
- secret = tmp.data;
- secretlen = tmp.len;
- } else {
- secretlen = keySize;
-+ key->isFIPS = PR_FALSE;
- crv = sftk_ANSI_X9_63_kdf(&secret, keySize,
- &tmp, mechParams->pSharedData,
- mechParams->ulSharedDataLen, mechParams->kdf);
- PORT_ZFree(tmp.data, tmp.len);
- if (crv != CKR_OK) {
- break;
- }
- tmp.data = secret;
-@@ -8927,16 +8997,17 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
- }
- PORT_Memcpy(&keyData[keySize - secretlen], secret, secretlen);
- secret = keyData;
- } else {
- secret += (secretlen - keySize);
- }
- secretlen = keySize;
- }
-+ key->source = SFTK_SOURCE_KEA;
-
- sftk_forceAttribute(key, CKA_VALUE, secret, secretlen);
- PORT_ZFree(tmp.data, tmp.len);
- if (keyData) {
- PORT_ZFree(keyData, keySize);
- }
- break;
-
-diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h
---- a/lib/softoken/pkcs11i.h
-+++ b/lib/softoken/pkcs11i.h
-@@ -147,16 +147,26 @@ typedef enum {
- */
- typedef enum {
- SFTK_DestroyFailure,
- SFTK_Destroyed,
- SFTK_Busy
- } SFTKFreeStatus;
-
- /*
-+ * Source of various objects
-+ */
-+typedef enum {
-+ SFTK_SOURCE_DEFAULT=0,
-+ SFTK_SOURCE_KEA,
-+ SFTK_SOURCE_HKDF_EXPAND,
-+ SFTK_SOURCE_HKDF_EXTRACT
-+} SFTKSource;
-+
-+/*
- * attribute values of an object.
- */
- struct SFTKAttributeStr {
- SFTKAttribute *next;
- SFTKAttribute *prev;
- PRBool freeAttr;
- PRBool freeData;
- /*must be called handle to make sftkqueue_find work */
-@@ -189,16 +199,17 @@ struct SFTKObjectStr {
- CK_OBJECT_CLASS objclass;
- CK_OBJECT_HANDLE handle;
- int refCount;
- PZLock *refLock;
- SFTKSlot *slot;
- void *objectInfo;
- SFTKFree infoFree;
- PRBool isFIPS;
-+ SFTKSource source;
- };
-
- struct SFTKTokenObjectStr {
- SFTKObject obj;
- SECItem dbKey;
- };
-
- struct SFTKSessionObjectStr {
-@@ -963,15 +974,16 @@ char **NSC_ModuleDBFunc(unsigned long fu
- const SECItem *sftk_VerifyDH_Prime(SECItem *dhPrime, SECItem *generator, PRBool isFIPS);
- /* check if dhSubPrime claims dhPrime is a safe prime. */
- SECStatus sftk_IsSafePrime(SECItem *dhPrime, SECItem *dhSubPrime, PRBool *isSafe);
- /* map an operation Attribute to a Mechanism flag */
- CK_FLAGS sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE op);
- /* check the FIPS table to determine if this current operation is allowed by
- * FIPS security policy */
- PRBool sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech,
-- CK_ATTRIBUTE_TYPE op, SFTKObject *source);
-+ CK_ATTRIBUTE_TYPE op, SFTKObject *source,
-+ CK_ULONG targetKeySize);
- /* add validation objects to the slot */
- CK_RV sftk_CreateValidationObjects(SFTKSlot *slot);
-
- SEC_END_PROTOS
-
- #endif /* _PKCS11I_H_ */
-diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c
---- a/lib/softoken/pkcs11u.c
-+++ b/lib/softoken/pkcs11u.c
-@@ -1098,16 +1098,17 @@ sftk_NewObject(SFTKSlot *slot)
- sessObject->attrList[i].freeData = PR_FALSE;
- }
- sessObject->optimizeSpace = slot->optimizeSpace;
-
- object->handle = 0;
- object->next = object->prev = NULL;
- object->slot = slot;
- object->isFIPS = sftk_isFIPS(slot->slotID);
-+ object->source = SFTK_SOURCE_DEFAULT;
-
- object->refCount = 1;
- sessObject->sessionList.next = NULL;
- sessObject->sessionList.prev = NULL;
- sessObject->sessionList.parent = object;
- sessObject->session = NULL;
- sessObject->wasDerived = PR_FALSE;
- if (!hasLocks)
-@@ -1683,16 +1684,17 @@ fail:
- CK_RV
- sftk_CopyObject(SFTKObject *destObject, SFTKObject *srcObject)
- {
- SFTKAttribute *attribute;
- SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject);
- unsigned int i;
-
- destObject->isFIPS = srcObject->isFIPS;
-+ destObject->source = srcObject->source;
- if (src_so == NULL) {
- return sftk_CopyTokenObject(destObject, srcObject);
- }
-
- PZ_Lock(src_so->attributeLock);
- for (i = 0; i < src_so->hashSize; i++) {
- attribute = src_so->head[i];
- do {
-@@ -2068,16 +2070,17 @@ sftk_NewTokenObject(SFTKSlot *slot, SECI
- /* every object must have a class, if we can't get it, the object
- * doesn't exist */
- crv = handleToClass(slot, handle, &object->objclass);
- if (crv != CKR_OK) {
- goto loser;
- }
- object->slot = slot;
- object->isFIPS = sftk_isFIPS(slot->slotID);
-+ object->source = SFTK_SOURCE_DEFAULT;
- object->objectInfo = NULL;
- object->infoFree = NULL;
- if (!hasLocks) {
- object->refLock = PZ_NewLock(nssILockRefLock);
- }
- if (object->refLock == NULL) {
- goto loser;
- }
-@@ -2234,16 +2237,25 @@ sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE
- break;
- case CKA_DERIVE:
- flags = CKF_DERIVE;
- break;
- /* fake attribute to select digesting */
- case CKA_DIGEST:
- flags = CKF_DIGEST;
- break;
-+ /* fake attribute to select key gen */
-+ case CKA_NSS_GENERATE:
-+ flags = CKF_GENERATE;
-+ break;
-+ /* fake attribute to select key pair gen */
-+ case CKA_NSS_GENERATE_KEY_PAIR:
-+ flags = CKF_GENERATE_KEY_PAIR;
-+ break;
-+ /* fake attributes to to handle MESSAGE* flags */
- case CKA_NSS_MESSAGE | CKA_ENCRYPT:
- flags = CKF_MESSAGE_ENCRYPT;
- break;
- case CKA_NSS_MESSAGE | CKA_DECRYPT:
- flags = CKF_MESSAGE_DECRYPT;
- break;
- case CKA_NSS_MESSAGE | CKA_SIGN:
- flags = CKF_MESSAGE_SIGN;
-@@ -2319,20 +2331,20 @@ sftk_quickGetECCCurveOid(SFTKObject *sou
- }
-
- /* This function currently only returns valid lengths for
- * FIPS approved ECC curves. If we want to make this generic
- * in the future, that Curve determination can be done in
- * the sftk_handleSpecial. Since it's currently only used
- * in FIPS indicators, it's currently only compiled with
- * the FIPS indicator code */
--static int
-+static CK_ULONG
- sftk_getKeyLength(SFTKObject *source)
- {
-- CK_KEY_TYPE keyType = CK_INVALID_HANDLE;
-+ CK_KEY_TYPE keyType = CKK_INVALID_KEY_TYPE;
- CK_ATTRIBUTE_TYPE keyAttribute;
- CK_ULONG keyLength = 0;
- SFTKAttribute *attribute;
- CK_RV crv;
-
- /* If we don't have a key, then it doesn't have a length.
- * this may be OK (say we are hashing). The mech info will
- * sort this out because algorithms which expect no keys
-@@ -2342,17 +2354,17 @@ sftk_getKeyLength(SFTKObject *source)
- }
-
- crv = sftk_GetULongAttribute(source, CKA_KEY_TYPE, &keyType);
- if (crv != CKR_OK) {
- /* sometimes we're passed a data object, in that case the
- * key length is CKA_VALUE, which is the default */
- keyType = CKK_INVALID_KEY_TYPE;
- }
-- if (keyType == CKK_EC) {
-+ if (keyType == CKK_EC || keyType == CKK_EC_EDWARDS || keyType == CKK_EC_MONTGOMERY) {
- SECOidTag curve = sftk_quickGetECCCurveOid(source);
- switch (curve) {
- case SEC_OID_CURVE25519:
- /* change when we start algorithm testing on curve25519 */
- return 0;
- case SEC_OID_SECG_EC_SECP256R1:
- return 256;
- case SEC_OID_SECG_EC_SECP384R1:
-@@ -2384,24 +2396,65 @@ sftk_getKeyLength(SFTKObject *source)
- attribute = sftk_FindAttribute(source, keyAttribute);
- if (attribute) {
- keyLength = attribute->attrib.ulValueLen * 8;
- sftk_FreeAttribute(attribute);
- }
- return keyLength;
- }
-
-+PRBool
-+sftk_checkFIPSHash(CK_MECHANISM_TYPE hash, PRBool allowSmall, PRBool allowCMAC)
-+{
-+ switch (hash) {
-+ case CKM_AES_CMAC:
-+ return allowCMAC;
-+ case CKM_SHA_1:
-+ case CKM_SHA_1_HMAC:
-+ case CKM_SHA224:
-+ case CKM_SHA224_HMAC:
-+ return allowSmall;
-+ case CKM_SHA256:
-+ case CKM_SHA256_HMAC:
-+ case CKM_SHA384:
-+ case CKM_SHA384_HMAC:
-+ case CKM_SHA512:
-+ case CKM_SHA512_HMAC:
-+ return PR_TRUE;
-+ }
-+ return PR_FALSE;
-+}
-+
-+PRBool
-+sftk_checkKeyLength(CK_ULONG keyLength, CK_ULONG min,
-+ CK_ULONG max, CK_ULONG step)
-+{
-+ if (keyLength > max) {
-+ return PR_FALSE;
-+ }
-+ if (keyLength < min ) {
-+ return PR_FALSE;
-+ }
-+ if (((keyLength - min) % step) != 0) {
-+ return PR_FALSE;
-+ }
-+ return PR_TRUE;
-+}
-+
- /*
- * handle specialized FIPS semantics that are too complicated to
- * handle with just a table. NOTE: this means any additional semantics
- * would have to be coded here before they can be added to the table */
- static PRBool
- sftk_handleSpecial(SFTKSlot *slot, CK_MECHANISM *mech,
-- SFTKFIPSAlgorithmList *mechInfo, SFTKObject *source)
-+ SFTKFIPSAlgorithmList *mechInfo, SFTKObject *source,
-+ CK_ULONG keyLength, CK_ULONG targetKeyLength)
- {
-+ PRBool allowSmall = PR_FALSE;
-+ PRBool allowCMAC = PR_FALSE;
- switch (mechInfo->special) {
- case SFTKFIPSDH: {
- SECItem dhPrime;
- SECItem dhBase;
- SECItem dhGenerator;
- PRBool fipsOk = PR_FALSE;
- const SECItem *dhSubPrime;
- CK_RV crv = sftk_Attribute2SecItem(NULL, &dhPrime,
-@@ -2451,32 +2504,97 @@ sftk_handleSpecial(SFTKSlot *slot, CK_ME
- }
- /* we use the existing hash utilities to find the length of
- * the hash */
- hashObj = HASH_GetRawHashObject(sftk_GetHashTypeFromMechanism(
- pss->hashAlg));
- if (hashObj == NULL) {
- return PR_FALSE;
- }
-+ /* cap the salt for legacy keys */
-+ if ((keyLength <= 1024) && (pss->sLen > 63)) {
-+ return PR_FALSE;
-+ }
-+ /* cap the salt for based on the hash */
- if (pss->sLen > hashObj->length) {
- return PR_FALSE;
- }
-+ /* Our code makes sure pss->hashAlg matches the explicit
-+ * hash in the mechanism, and only mechanisms with approved
-+ * hashes are included, so no need to check pss->hashAlg
-+ * here */
-+ return PR_TRUE;
-+ }
-+ case SFTKFIPSPBKDF2: {
-+ /* PBKDF2 must have the following addition restrictions
-+ * (independent of keysize).
-+ * 1. iteration count must be at least 1000.
-+ * 2. salt must be at least 128 bits (16 bytes).
-+ * 3. password must match the length specified in the SP
-+ */
-+ CK_PKCS5_PBKD2_PARAMS *pbkdf2 = (CK_PKCS5_PBKD2_PARAMS *)
-+ mech->pParameter;
-+ if (mech->ulParameterLen != sizeof(*pbkdf2)) {
-+ return PR_FALSE;
-+ }
-+ if (pbkdf2->iterations < 1000) {
-+ return PR_FALSE;
-+ }
-+ if (pbkdf2->ulSaltSourceDataLen < 16) {
-+ return PR_FALSE;
-+ }
-+ if (*(pbkdf2->ulPasswordLen) < SFTKFIPS_PBKDF2_MIN_PW_LEN) {
-+ return PR_FALSE;
-+ }
- return PR_TRUE;
- }
-+ /* check the hash mechanisms to make sure they themselves are FIPS */
-+ case SFTKFIPSChkHashSp800:
-+ allowCMAC = PR_TRUE;
-+ case SFTKFIPSChkHash:
-+ allowSmall = PR_TRUE;
-+ case SFTKFIPSChkHashTls:
-+ if (mech->ulParameterLen < mechInfo->offset +sizeof(CK_ULONG)) {
-+ return PR_FALSE;
-+ }
-+ return sftk_checkFIPSHash(*(CK_ULONG *)(((char *)mech->pParameter)
-+ + mechInfo->offset), allowSmall, allowCMAC);
-+ case SFTKFIPSTlsKeyCheck:
-+ if (mech->mechanism != CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256) {
-+ /* unless the mechnism has a built-in hash, check the hash */
-+ if (mech->ulParameterLen < mechInfo->offset +sizeof(CK_ULONG)) {
-+ return PR_FALSE;
-+ }
-+ if (!sftk_checkFIPSHash(*(CK_ULONG *)(((char *)mech->pParameter)
-+ + mechInfo->offset), PR_FALSE, PR_FALSE)) {
-+ return PR_FALSE;
-+ }
-+ }
-+ return sftk_checkKeyLength(targetKeyLength, 112, 512, 1);
-+ case SFTKFIPSRSAOAEP:;
-+ CK_RSA_PKCS_OAEP_PARAMS *rsaoaep = (CK_RSA_PKCS_OAEP_PARAMS *)
-+ mech->pParameter;
-+
-+ HASH_HashType hash_msg = sftk_GetHashTypeFromMechanism(rsaoaep->hashAlg);
-+ HASH_HashType hash_pad = sftk_GetHashTypeFromMechanism(rsaoaep->mgf);
-+ /* message hash and mask generation function must be the same */
-+ if (hash_pad != hash_msg) return PR_FALSE;
-+
-+ return sftk_checkFIPSHash(rsaoaep->hashAlg, PR_FALSE, PR_FALSE);
- default:
- break;
- }
- /* if we didn't understand the special processing, mark it non-fips */
- return PR_FALSE;
- }
- #endif
-
- PRBool
- sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech, CK_ATTRIBUTE_TYPE op,
-- SFTKObject *source)
-+ SFTKObject *source, CK_ULONG targetKeyLength)
- {
- #ifndef NSS_HAS_FIPS_INDICATORS
- return PR_FALSE;
- #else
- int i;
- CK_FLAGS opFlags;
- CK_ULONG keyLength;
-
-@@ -2498,23 +2616,25 @@ sftk_operationIsFIPS(SFTKSlot *slot, CK_
- }
- keyLength = sftk_getKeyLength(source);
-
- /* check against our algorithm array */
- for (i = 0; i < SFTK_NUMBER_FIPS_ALGORITHMS; i++) {
- SFTKFIPSAlgorithmList *mechs = &sftk_fips_mechs[i];
- /* if we match the number of records exactly, then we are an
- * approved algorithm in the approved mode with an approved key */
-- if (((mech->mechanism == mechs->type) &&
-- (opFlags == (mechs->info.flags & opFlags)) &&
-- (keyLength <= mechs->info.ulMaxKeySize) &&
-- (keyLength >= mechs->info.ulMinKeySize) &&
-- ((keyLength - mechs->info.ulMinKeySize) % mechs->step) == 0) &&
-- ((mechs->special == SFTKFIPSNone) ||
-- sftk_handleSpecial(slot, mech, mechs, source))) {
-+ if ((mech->mechanism == mechs->type) &&
-+ (opFlags == (mechs->info.flags & opFlags)) &&
-+ sftk_checkKeyLength(keyLength, mechs->info.ulMinKeySize,
-+ mechs->info.ulMaxKeySize, mechs->step) &&
-+ ((targetKeyLength == 0) || (mechs->special == SFTKFIPSTlsKeyCheck)
-+ || sftk_checkKeyLength(targetKeyLength, mechs->info.ulMinKeySize,
-+ mechs->info.ulMaxKeySize, mechs->step)) &&
-+ ((mechs->special == SFTKFIPSNone) ||
-+ sftk_handleSpecial(slot, mech, mechs, source, keyLength, targetKeyLength))) {
- return PR_TRUE;
- }
- }
- return PR_FALSE;
- #endif
- }
-
- /*
-diff --git a/lib/softoken/sftkike.c b/lib/softoken/sftkike.c
---- a/lib/softoken/sftkike.c
-+++ b/lib/softoken/sftkike.c
-@@ -511,16 +511,22 @@ sftk_ike_prf(CK_SESSION_HANDLE hSession,
- }
- /* key as the data */
- crv = prf_update(&context, inKey->attrib.pValue,
- inKey->attrib.ulValueLen);
- if (crv != CKR_OK) {
- goto fail;
- }
- } else {
-+ /* ikev1 isn't validated, if we use this function in ikev1 mode,
-+ * mark the resulting key as not FIPS */
-+ if (!params->bRekey) {
-+ outKey->isFIPS = PR_FALSE;
-+ }
-+
- crv = prf_init(&context, inKey->attrib.pValue,
- inKey->attrib.ulValueLen);
- if (crv != CKR_OK) {
- goto fail;
- }
- if (newKeyValue) {
- crv = prf_update(&context, newKeyValue->attrib.pValue,
- newKeyValue->attrib.ulValueLen);
-diff --git a/lib/softoken/sftkmessage.c b/lib/softoken/sftkmessage.c
---- a/lib/softoken/sftkmessage.c
-+++ b/lib/softoken/sftkmessage.c
-@@ -178,16 +178,48 @@ sftk_CryptMessage(CK_SESSION_HANDLE hSes
-
- CHECK_FORK();
-
- /* make sure we're legal */
- crv = sftk_GetContext(hSession, &context, contextType, PR_TRUE, NULL);
- if (crv != CKR_OK)
- return crv;
-
-+ if (context->isFIPS && (contextType == SFTK_MESSAGE_ENCRYPT)) {
-+ if ((pParameter == NULL) || (ulParameterLen != sizeof(CK_GCM_MESSAGE_PARAMS))) {
-+ context->isFIPS = PR_FALSE;
-+ } else {
-+ CK_GCM_MESSAGE_PARAMS *p = (CK_GCM_MESSAGE_PARAMS *)pParameter;
-+ switch (p->ivGenerator) {
-+ default:
-+ case CKG_NO_GENERATE:
-+ context->isFIPS = PR_FALSE;
-+ break;
-+ case CKG_GENERATE_RANDOM:
-+ if ((p->ulIvLen < 96/PR_BITS_PER_BYTE) ||
-+ (p->ulIvFixedBits != 0)) {
-+ context->isFIPS = PR_FALSE;
-+ }
-+ break;
-+ case CKG_GENERATE_COUNTER_XOR:
-+ if ((p->ulIvLen != 96/PR_BITS_PER_BYTE) ||
-+ (p->ulIvFixedBits != 32)) {
-+ context->isFIPS = PR_FALSE;
-+ }
-+ break;
-+ case CKG_GENERATE_COUNTER:
-+ if ((p->ulIvFixedBits < 32) ||
-+ ((p->ulIvLen*PR_BITS_PER_BYTE - p->ulIvFixedBits) < 32)) {
-+ context->isFIPS = PR_FALSE;
-+ }
-+ break;
-+ }
-+ }
-+ }
-+
- if (!pOuttext) {
- *pulOuttextLen = ulIntextLen;
- return CKR_OK;
- }
- rv = (*context->aeadUpdate)(context->cipherInfo, pOuttext, &outlen,
- maxout, pIntext, ulIntextLen,
- pParameter, ulParameterLen,
- pAssociatedData, ulAssociatedDataLen);
-diff --git a/lib/util/pkcs11n.h b/lib/util/pkcs11n.h
---- a/lib/util/pkcs11n.h
-+++ b/lib/util/pkcs11n.h
-@@ -148,16 +148,18 @@
- /*
- * NSS-defined certificate types
- *
- */
- #define CKC_NSS (CKC_VENDOR_DEFINED | NSSCK_VENDOR_NSS)
-
- /* FAKE PKCS #11 defines */
- #define CKA_DIGEST 0x81000000L
-+#define CKA_NSS_GENERATE 0x81000001L
-+#define CKA_NSS_GENERATE_KEY_PAIR 0x81000002L
- #define CKA_NSS_MESSAGE 0x82000000L
- #define CKA_NSS_MESSAGE_MASK 0xff000000L
- #define CKA_FLAGS_ONLY 0 /* CKA_CLASS */
-
- /*
- * NSS-defined object attributes
- *
- */
diff --git a/nss-3.112-fix-get-interface.patch b/nss-3.112-fix-get-interface.patch
deleted file mode 100644
index 3d8e95e..0000000
--- a/nss-3.112-fix-get-interface.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-diff --git a/lib/softoken/fipstokn.c b/lib/softoken/fipstokn.c
---- a/lib/softoken/fipstokn.c
-+++ b/lib/softoken/fipstokn.c
-@@ -244,17 +244,17 @@ fc_getAttribute(CK_ATTRIBUTE_PTR pTempla
-
- #define CK_PKCS11_FUNCTION_INFO(name) CK_RV __PASTE(F, name)
- #define CK_NEED_ARG_LIST 1
-
- #include "pkcs11f.h"
-
- /* ------------- build the CK_CRYPTO_TABLE ------------------------- */
- static CK_FUNCTION_LIST_3_0 sftk_fipsTable = {
-- { CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR },
-+ { 3, 0 },
-
- #undef CK_NEED_ARG_LIST
- #undef CK_PKCS11_FUNCTION_INFO
-
- #define CK_PKCS11_FUNCTION_INFO(name) \
- __PASTE(F, name) \
- ,
-
-diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c
---- a/lib/softoken/pkcs11.c
-+++ b/lib/softoken/pkcs11.c
-@@ -107,17 +107,17 @@ static PRIntervalTime loginWaitTime;
- #define CK_PKCS11_FUNCTION_INFO(name) CK_RV __PASTE(F, name)
- #define CK_NEED_ARG_LIST 1
-
- #include "pkcs11f.h"
- #endif
-
- /* build the crypto module table */
- static CK_FUNCTION_LIST_3_0 sftk_funcList = {
-- { CRYPTOKI_VERSION_MAJOR, CRYPTOKI_VERSION_MINOR },
-+ { 3, 0 },
-
- #undef CK_PKCS11_FUNCTION_INFO
- #undef CK_NEED_ARG_LIST
-
- #define CK_PKCS11_FUNCTION_INFO(func) \
- __PASTE(NS, func) \
- ,
- #include "pkcs11f.h"
diff --git a/nss-3.112-mlkem-fips-update.patch b/nss-3.112-mlkem-fips-update.patch
deleted file mode 100644
index 8e2a103..0000000
--- a/nss-3.112-mlkem-fips-update.patch
+++ /dev/null
@@ -1,704 +0,0 @@
-# HG changeset patch
-# User Robert Relyea
-# Date 1761684967 25200
-# Tue Oct 28 13:56:07 2025 -0700
-# Branch RHEL10
-# Node ID 41c115659ed4c65119d97e4be6bdc3030c9a4586
-# Parent a2ec761c754f728b669dc32ea94e260362b43b5b
-nss-3.112-mlkem-fips-update.patch
-
-diff --git a/lib/freebl/fipsfreebl.c b/lib/freebl/fipsfreebl.c
---- a/lib/freebl/fipsfreebl.c
-+++ b/lib/freebl/fipsfreebl.c
-@@ -1797,29 +1797,34 @@ loser:
-
- static SECStatus
- freebl_ML_KEM_Test(KyberParams param_set,
- const unsigned char *seed, size_t seed_len,
- const unsigned char *enc_seed, size_t enc_seed_len,
- const unsigned char *pub_key, size_t pub_key_len,
- const unsigned char *priv_key, size_t priv_key_len,
- const unsigned char *cipher_text, size_t cipher_text_len,
-- const unsigned char *key, size_t key_len)
-+ const unsigned char *key, size_t key_len,
-+ const unsigned char *rej_key, size_t rej_key_len)
- {
- SECStatus rv;
- unsigned char cipher_text_buf[MAX_ML_KEM_CIPHER_LENGTH];
-+ unsigned char zero_text_buf[MAX_ML_KEM_CIPHER_LENGTH] = { 0 };
- unsigned char priv_key_buf[MAX_ML_KEM_PRIVATE_KEY_LENGTH];
- unsigned char pub_key_buf[MAX_ML_KEM_PUBLIC_KEY_LENGTH];
- unsigned char key_buf[KYBER_SHARED_SECRET_BYTES];
- unsigned char key2_buf[KYBER_SHARED_SECRET_BYTES];
-+ unsigned char key3_buf[KYBER_SHARED_SECRET_BYTES];
- SECItem ct_item = { siBuffer, cipher_text_buf, cipher_text_len };
-+ SECItem zt_item = { siBuffer, zero_text_buf, cipher_text_len };
- SECItem priv_key_item = { siBuffer, priv_key_buf, priv_key_len };
- SECItem pub_key_item = { siBuffer, pub_key_buf, pub_key_len };
- SECItem key_item = { siBuffer, key_buf, sizeof(key_buf) };
- SECItem key2_item = { siBuffer, key2_buf, sizeof(key2_buf) };
-+ SECItem key3_item = { siBuffer, key3_buf, sizeof(key3_buf) };
- SECItem seed_item = { siBuffer, (unsigned char *)seed, seed_len };
- SECItem eseed_item = { siBuffer, (unsigned char *)enc_seed, enc_seed_len };
-
- PORT_Assert(pub_key_len <= sizeof(pub_key_buf));
- PORT_Assert(priv_key_len <= sizeof(priv_key_buf));
- PORT_Assert(cipher_text_len <= sizeof(cipher_text_buf));
-
- rv = Kyber_NewKey(param_set, &seed_item, &priv_key_item, &pub_key_item);
-@@ -1828,43 +1833,53 @@ freebl_ML_KEM_Test(KyberParams param_set
- return rv;
- }
-
- if ((priv_key_item.len != priv_key_len) ||
- (pub_key_item.len != pub_key_len) ||
- (PORT_Memcmp(priv_key_item.data, priv_key, priv_key_len) != 0) ||
- (PORT_Memcmp(pub_key_item.data, pub_key, pub_key_len) != 0)) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-- return rv;
-+ return SECFailure;
- }
-
- rv = Kyber_Encapsulate(param_set, &eseed_item, &pub_key_item,
- &ct_item, &key_item);
- if (rv != SECSuccess) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return rv;
- }
-
- if ((ct_item.len != cipher_text_len) ||
- (key_item.len != key_len) ||
- (PORT_Memcmp(ct_item.data, cipher_text, cipher_text_len) != 0) ||
- (PORT_Memcmp(key_item.data, key, key_len) != 0)) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-- return rv;
-+ return SECFailure;
- }
-
- rv = Kyber_Decapsulate(param_set, &priv_key_item, &ct_item, &key2_item);
- if (rv != SECSuccess) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return rv;
- }
- if (SECITEM_CompareItem(&key2_item, &key_item) != 0) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return SECFailure;
-+ }
-+ rv = Kyber_Decapsulate(param_set, &priv_key_item, &zt_item, &key3_item);
-+ if (rv != SECSuccess) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return rv;
- }
-+ if ((key3_item.len != rej_key_len) ||
-+ (PORT_Memcmp(key3_item.data, rej_key, rej_key_len) != 0)) {
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return SECFailure;
-+ }
- return SECSuccess;
- }
-
- static SECStatus
- freebl_fips_ML_KEM_PowerUpSelfTest()
- {
- SECStatus rv;
-
-@@ -1881,27 +1896,29 @@ freebl_fips_ML_KEM_PowerUpSelfTest()
- PORT_Assert(sizeof (ml_kem1024_key) == KYBER_SHARED_SECRET_BYTES);
-
- rv = freebl_ML_KEM_Test(params_ml_kem768_test_mode,
- ml_kem_key_seed, KYBER_KEYPAIR_COIN_BYTES,
- ml_kem_enc_seed, KYBER_SHARED_SECRET_BYTES,
- ml_kem768_pub_key, KYBER768_PUBLIC_KEY_BYTES,
- ml_kem768_priv_key, KYBER768_PRIVATE_KEY_BYTES,
- ml_kem768_cipher_text, KYBER768_CIPHERTEXT_BYTES,
-- ml_kem768_key, KYBER_SHARED_SECRET_BYTES);
-+ ml_kem768_key, KYBER_SHARED_SECRET_BYTES,
-+ ml_kem768_rej_key, KYBER_SHARED_SECRET_BYTES);
- if (rv != SECSuccess) {
- return SECFailure;
- }
- rv = freebl_ML_KEM_Test(params_ml_kem1024_test_mode,
- ml_kem_key_seed, KYBER_KEYPAIR_COIN_BYTES,
- ml_kem_enc_seed, KYBER_SHARED_SECRET_BYTES,
- ml_kem1024_pub_key, MLKEM1024_PUBLIC_KEY_BYTES,
- ml_kem1024_priv_key, MLKEM1024_PRIVATE_KEY_BYTES,
- ml_kem1024_cipher_text, MLKEM1024_CIPHERTEXT_BYTES,
-- ml_kem1024_key, KYBER_SHARED_SECRET_BYTES);
-+ ml_kem1024_key, KYBER_SHARED_SECRET_BYTES,
-+ ml_kem1024_rej_key, KYBER_SHARED_SECRET_BYTES);
- if (rv != SECSuccess) {
- return SECFailure;
- }
-
- return SECSuccess;
- }
-
- #ifdef NSS_ENABLE_ML_DSA
-diff --git a/lib/freebl/kyber.c b/lib/freebl/kyber.c
---- a/lib/freebl/kyber.c
-+++ b/lib/freebl/kyber.c
-@@ -4,16 +4,17 @@
-
- #ifdef FREEBL_NO_DEPEND
- #include "stubs.h"
- #endif
-
- #include
-
- #include "blapi.h"
-+#include "blapii.h"
- #include "secerr.h"
- #include "secitem.h"
-
- #include "kyber-pqcrystals-ref.h"
- #include "kyber.h"
- #include "verified/internal/libcrux_core.h"
- #include "verified/libcrux_mlkem768_portable.h"
- #include "verified/libcrux_mlkem768.h"
-@@ -198,29 +199,39 @@ Kyber_NewKey(KyberParams params, const S
- }
- coins = randbuf;
- }
- NSS_CLASSIFY(coins, KYBER_KEYPAIR_COIN_BYTES);
- if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) {
- libcrux_ml_kem_mlkem768_MlKem768KeyPair keys = libcrux_ml_kem_mlkem768_portable_generate_key_pair(coins);
- memcpy(pubkey->data, keys.pk.value, KYBER768_PUBLIC_KEY_BYTES);
- memcpy(privkey->data, keys.sk.value, KYBER768_PRIVATE_KEY_BYTES);
-+ PORT_SafeZero(&keys, sizeof(keys));
- } else if (params == params_ml_kem1024 || params == params_ml_kem1024_test_mode) {
- libcrux_ml_kem_mlkem1024_MlKem1024KeyPair keys = libcrux_ml_kem_mlkem1024_portable_generate_key_pair(coins);
- memcpy(pubkey->data, keys.pk.value, MLKEM1024_PUBLIC_KEY_BYTES);
- memcpy(privkey->data, keys.sk.value, MLKEM1024_PRIVATE_KEY_BYTES);
-+ PORT_SafeZero(&keys, sizeof(keys));
- #ifndef NSS_DISABLE_KYBER
- } else if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) {
- pqcrystals_kyber768_ref_keypair_derand(pubkey->data, privkey->data, coins);
- #endif
- } else {
- /* unreachable */
-+ if (coins == randbuf) {
-+ PORT_SafeZero(randbuf, sizeof(randbuf));
-+ }
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-+ /* manual max stack count 68000 */
-+ BLAPI_CLEAR_STACK(70000);
-+ if (coins == randbuf) {
-+ PORT_SafeZero(randbuf, sizeof(randbuf));
-+ }
- NSS_DECLASSIFY(pubkey->data, pubkey->len);
- return SECSuccess;
- }
-
- SECStatus
- Kyber_Encapsulate(KyberParams params, const SECItem *enc_seed, const SECItem *pubkey, SECItem *ciphertext, SECItem *secret)
- {
- if (!valid_params(params)) {
-@@ -239,103 +250,133 @@ Kyber_Encapsulate(KyberParams params, co
- coins = enc_seed->data;
- } else {
- if (RNG_GenerateGlobalRandomBytes(randbuf, sizeof randbuf) != SECSuccess) {
- PORT_SetError(SEC_ERROR_NEED_RANDOM);
- return SECFailure;
- }
- coins = randbuf;
- }
-+ SECStatus rv = SECSuccess;
- NSS_CLASSIFY(coins, KYBER_ENC_COIN_BYTES);
- if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) {
- /* shouldn't this just use the typedef im libcrux_mlkem768.h? */
- libcrux_ml_kem_types_MlKemPublicKey_15 pk_value;
- memcpy(pk_value.value, pubkey->data, KYBER768_PUBLIC_KEY_BYTES);
-
- bool valid_pk = libcrux_ml_kem_mlkem768_portable_validate_public_key(&pk_value);
- if (!valid_pk) {
-+ PORT_SafeZero(&pk_value, sizeof(pk_value));
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
-- return SECFailure;
-+ rv = SECFailure;
-+ goto loser;
- }
-
- tuple_3c encap = libcrux_ml_kem_mlkem768_portable_encapsulate(&pk_value, coins);
- memcpy(ciphertext->data, encap.fst.value, KYBER768_CIPHERTEXT_BYTES);
- memcpy(secret->data, encap.snd, KYBER_SHARED_SECRET_BYTES);
-+ PORT_SafeZero(&pk_value, sizeof(pk_value));
-+ PORT_SafeZero(&encap, sizeof(encap));
- } else if (params == params_ml_kem1024 || params == params_ml_kem1024_test_mode) {
- /* shouldn't this just use the typedef im libcrux_mlkem1024.h? */
- libcrux_ml_kem_types_MlKemPublicKey_1f pk_value;
- memcpy(pk_value.value, pubkey->data, MLKEM1024_PUBLIC_KEY_BYTES);
-
- bool valid_pk = libcrux_ml_kem_mlkem1024_portable_validate_public_key(&pk_value);
- if (!valid_pk) {
-+ PORT_SafeZero(&pk_value, sizeof(pk_value));
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
-- return SECFailure;
-+ rv = SECFailure;
-+ goto loser;
- }
-
- tuple_21 encap = libcrux_ml_kem_mlkem1024_portable_encapsulate(&pk_value, coins);
- memcpy(ciphertext->data, encap.fst.value, MLKEM1024_CIPHERTEXT_BYTES);
- memcpy(secret->data, encap.snd, KYBER_SHARED_SECRET_BYTES);
-+ PORT_SafeZero(&pk_value, sizeof(pk_value));
-+ PORT_SafeZero(&encap, sizeof(encap));
- #ifndef NSS_DISABLE_KYBER
- } else if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) {
- pqcrystals_kyber768_ref_enc_derand(ciphertext->data, secret->data, pubkey->data, coins);
- #endif
- } else {
- /* unreachable */
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-- return SECFailure;
-+ rv = SECFailure;
-+ goto loser;
- }
-+loser:
-+ if (coins == randbuf) {
-+ PORT_SafeZero(randbuf, sizeof(randbuf));
-+ }
-+ /* manual max stack count 6700 */
-+ BLAPI_CLEAR_STACK(10000);
-
-- return SECSuccess;
-+ return rv;
- }
-
- SECStatus
- Kyber_Decapsulate(KyberParams params, const SECItem *privkey, const SECItem *ciphertext, SECItem *secret)
- {
- if (!valid_params(params)) {
- PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
- return SECFailure;
- }
-
- if (!(valid_privkey(params, privkey) && valid_ciphertext(params, ciphertext) && valid_secret(params, secret))) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
- }
-
-+ SECStatus rv = SECSuccess;
- if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) {
- libcrux_ml_kem_types_MlKemPrivateKey_55 private_key;
- memcpy(private_key.value, privkey->data, KYBER768_PRIVATE_KEY_BYTES);
-
- libcrux_ml_kem_mlkem768_MlKem768Ciphertext cipher_text;
- memcpy(cipher_text.value, ciphertext->data, KYBER768_CIPHERTEXT_BYTES);
-
- bool valid = libcrux_ml_kem_mlkem768_portable_validate_private_key(&private_key, &cipher_text);
- if (!valid) {
-+ PORT_SafeZero(&private_key, sizeof(private_key));
-+ PORT_SafeZero(&cipher_text, sizeof(cipher_text));
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
-- return SECFailure;
-+ rv = SECFailure;
-+ goto loser;
- }
-
- libcrux_ml_kem_mlkem768_portable_decapsulate(&private_key, &cipher_text, secret->data);
-+ PORT_SafeZero(&private_key, sizeof(private_key));
-+ PORT_SafeZero(&cipher_text, sizeof(cipher_text));
- } else if (params == params_ml_kem1024 || params == params_ml_kem1024_test_mode) {
- libcrux_ml_kem_types_MlKemPrivateKey_95 private_key;
- memcpy(private_key.value, privkey->data, MLKEM1024_PRIVATE_KEY_BYTES);
-
- libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext cipher_text;
- memcpy(cipher_text.value, ciphertext->data, MLKEM1024_CIPHERTEXT_BYTES);
-
- bool valid = libcrux_ml_kem_mlkem1024_portable_validate_private_key(&private_key, &cipher_text);
- if (!valid) {
-+ PORT_SafeZero(&private_key, sizeof(private_key));
-+ PORT_SafeZero(&cipher_text, sizeof(cipher_text));
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
-- return SECFailure;
-+ rv = SECFailure;
-+ goto loser;
- }
-
- libcrux_ml_kem_mlkem1024_portable_decapsulate(&private_key, &cipher_text, secret->data);
-+ PORT_SafeZero(&private_key, sizeof(private_key));
-+ PORT_SafeZero(&cipher_text, sizeof(cipher_text));
- #ifndef NSS_DISABLE_KYBER
- } else if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) {
- pqcrystals_kyber768_ref_dec(secret->data, ciphertext->data, privkey->data);
- #endif
- } else {
- // unreachable
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-+loser:
-+ /* manual max stack count 8200 */
-+ BLAPI_CLEAR_STACK(10000);
-
-- return SECSuccess;
-+ return rv;
- }
-diff --git a/lib/freebl/ml_kem_fips_vectors.h b/lib/freebl/ml_kem_fips_vectors.h
---- a/lib/freebl/ml_kem_fips_vectors.h
-+++ b/lib/freebl/ml_kem_fips_vectors.h
-@@ -415,16 +415,21 @@
- 0xd6, 0x18, 0xf6, 0x5a, 0x70, 0x0b, 0x41, 0xf0, 0x17, 0x08, 0x67, 0x98,
- 0x2f, 0x5a, 0x68, 0xc7, 0x5c, 0x65, 0x15, 0x0e,
- };
- static const unsigned char ml_kem768_key[] = {
- 0x42, 0xf5, 0x58, 0xb0, 0xbc, 0x5d, 0x70, 0x0a, 0x91, 0x1b, 0x0f, 0xc6,
- 0x7f, 0x62, 0x37, 0x6f, 0x7a, 0xee, 0x46, 0x67, 0xf1, 0x96, 0x9e, 0x03,
- 0xf1, 0x8b, 0xdf, 0xdf, 0x3c, 0x59, 0xfb, 0xdc,
- };
-+ static const unsigned char ml_kem768_rej_key[] = {
-+ 0x6b, 0x24, 0x6e, 0xb1, 0x8b, 0x55, 0x3a, 0xb4, 0xcc, 0x4a, 0x57, 0x04,
-+ 0x4d, 0x8d, 0x15, 0x34, 0xa8, 0x85, 0xd1, 0xd3, 0x42, 0x14, 0xc9, 0x87,
-+ 0x78, 0x96, 0x19, 0xcb, 0x73, 0xe6, 0x12, 0x9a,
-+ };
- static const unsigned char ml_kem1024_pub_key[] = {
- 0x4b, 0x94, 0xc2, 0x94, 0x50, 0x11, 0x11, 0x91, 0x82, 0x3b, 0x35, 0x14,
- 0xc9, 0xac, 0x1e, 0xa3, 0xd9, 0x82, 0x5c, 0xcb, 0x86, 0x39, 0x3a, 0x2d,
- 0xfb, 0x04, 0x65, 0x4f, 0xa2, 0x19, 0x2d, 0x37, 0xbf, 0xad, 0x1c, 0x49,
- 0x7c, 0x65, 0x02, 0xee, 0xe5, 0xca, 0x80, 0xa7, 0x3b, 0xfc, 0xe0, 0xba,
- 0xf5, 0xa5, 0x4a, 0x88, 0x58, 0x5a, 0x40, 0x13, 0x97, 0xa3, 0xd2, 0x32,
- 0xf4, 0x26, 0xa7, 0xaf, 0xb0, 0x82, 0xbc, 0x21, 0xa4, 0x43, 0x17, 0x09,
- 0x0e, 0xaa, 0xc7, 0x59, 0x2c, 0x2e, 0xa8, 0x8a, 0x65, 0x3c, 0x44, 0x91,
-@@ -952,8 +957,13 @@
- 0x3b, 0xaf, 0x03, 0xad, 0xf1, 0xab, 0x8f, 0x86, 0xea, 0x46, 0x28, 0xf8,
- 0x53, 0x80, 0xee, 0x89, 0x53, 0xd4, 0xa1, 0xad,
- };
- static const unsigned char ml_kem1024_key[] = {
- 0x73, 0x8a, 0x88, 0xcd, 0x9a, 0x25, 0x86, 0x1e, 0x9a, 0x37, 0xc6, 0x5a,
- 0x67, 0xec, 0x1b, 0x39, 0xf0, 0x69, 0xae, 0xd9, 0x64, 0x6e, 0xde, 0x89,
- 0x41, 0x0a, 0xce, 0x47, 0xa9, 0x6a, 0x9b, 0x57,
- };
-+ static const unsigned char ml_kem1024_rej_key[] = {
-+ 0x6a, 0x58, 0xe1, 0xc5, 0x96, 0x86, 0xc9, 0xfc, 0x32, 0x2e, 0xc2, 0x6b,
-+ 0x6e, 0xa0, 0xd5, 0x27, 0x22, 0x67, 0x29, 0x2c, 0xe9, 0xa4, 0x0f, 0x12,
-+ 0x75, 0x13, 0x96, 0xbc, 0x53, 0x22, 0x72, 0x46,
-+ };
-diff --git a/lib/softoken/kem.c b/lib/softoken/kem.c
---- a/lib/softoken/kem.c
-+++ b/lib/softoken/kem.c
-@@ -198,16 +198,18 @@ NSC_EncapsulateKey(CK_SESSION_HANDLE hSe
- SFTKAttribute *encapsulationKey = NULL;
-
- CK_RV crv;
- SFTKFreeStatus status;
- CK_ULONG paramSet = 0; /* use a generic U_LONG so we can handle
- * different param set types based on the
- * Mechanism value */
- KyberParams kyberParams;
-+ CK_OBJECT_CLASS ckclass = CKO_SECRET_KEY;
-+ CK_KEY_TYPE ckkeyType = CKK_GENERIC_SECRET;
-
- CHECK_FORK();
-
- if (!pMechanism || !phKey || !pulCiphertextLen) {
- return CKR_ARGUMENTS_BAD;
- }
-
- if (!sftk_kem_ValidateMechanism(pMechanism)) {
-@@ -232,16 +234,25 @@ NSC_EncapsulateKey(CK_SESSION_HANDLE hSe
- }
- for (unsigned long int i = 0; i < ulAttributeCount; i++) {
- crv = sftk_AddAttributeType(key, sftk_attr_expand(&pTemplate[i]));
- if (crv != CKR_OK) {
- goto cleanup;
- }
- }
-
-+ crv = sftk_defaultAttribute(key, CKA_CLASS, &ckclass, sizeof(ckclass));
-+ if (crv != CKR_OK) {
-+ goto cleanup;
-+ }
-+ crv = sftk_defaultAttribute(key, CKA_KEY_TYPE, &ckkeyType, sizeof(ckkeyType));
-+ if (crv != CKR_OK) {
-+ goto cleanup;
-+ }
-+
- encapsulationKeyObject = sftk_ObjectFromHandle(hPublicKey, session);
- if (encapsulationKeyObject == NULL) {
- crv = CKR_KEY_HANDLE_INVALID;
- goto cleanup;
- }
- encapsulationKey = sftk_FindAttribute(encapsulationKeyObject, CKA_VALUE);
- if (encapsulationKey == NULL) {
- crv = CKR_KEY_HANDLE_INVALID;
-@@ -264,17 +275,17 @@ NSC_EncapsulateKey(CK_SESSION_HANDLE hSe
- SECItem pubKey = { siBuffer, encapsulationKey->attrib.pValue, encapsulationKey->attrib.ulValueLen };
-
- /* The length of secretBuf can be increased if we ever support other KEMs
- * by changing the define at the top of this file */
- uint8_t secretBuf[MAX_KEM_SHARED_SECRET_BYTES] = { 0 };
- SECItem secret = { siBuffer, secretBuf, sizeof secretBuf };
-
- key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_ENCAPSULATE,
-- key, 0);
-+ encapsulationKeyObject, 0);
- key->source = SFTK_SOURCE_KEA;
- switch (pMechanism->mechanism) {
- #ifndef NSS_DISABLE_KYBER
- case CKM_NSS_KYBER:
- #endif
- case CKM_NSS_ML_KEM:
- case CKM_ML_KEM:
- PORT_Assert(secret.len >= KYBER_SHARED_SECRET_BYTES);
-@@ -347,16 +358,18 @@ NSC_DecapsulateKey(CK_SESSION_HANDLE hSe
- SFTKAttribute *decapsulationKey = NULL;
- CK_ULONG paramSet = 0; /* use a generic U_LONG so we can handle
- * different param set types based on the
- * Mechanism value */
-
- CK_RV crv;
- SFTKFreeStatus status;
- KyberParams kyberParams;
-+ CK_OBJECT_CLASS ckclass = CKO_SECRET_KEY;
-+ CK_KEY_TYPE ckkeyType = CKK_GENERIC_SECRET;
-
- CHECK_FORK();
-
- if (!pMechanism || !pCiphertext || !pTemplate || !phKey) {
- return CKR_ARGUMENTS_BAD;
- }
-
- if (!sftk_kem_ValidateMechanism(pMechanism)) {
-@@ -381,16 +394,25 @@ NSC_DecapsulateKey(CK_SESSION_HANDLE hSe
- }
- for (unsigned long int i = 0; i < ulAttributeCount; i++) {
- crv = sftk_AddAttributeType(key, sftk_attr_expand(&pTemplate[i]));
- if (crv != CKR_OK) {
- goto cleanup;
- }
- }
-
-+ crv = sftk_defaultAttribute(key, CKA_CLASS, &ckclass, sizeof(ckclass));
-+ if (crv != CKR_OK) {
-+ goto cleanup;
-+ }
-+ crv = sftk_defaultAttribute(key, CKA_KEY_TYPE, &ckkeyType, sizeof(ckkeyType));
-+ if (crv != CKR_OK) {
-+ goto cleanup;
-+ }
-+
- decapsulationKeyObject = sftk_ObjectFromHandle(hPrivateKey, session);
- if (decapsulationKeyObject == NULL) {
- crv = CKR_KEY_HANDLE_INVALID;
- goto cleanup;
- }
- decapsulationKey = sftk_FindAttribute(decapsulationKeyObject, CKA_VALUE);
- if (decapsulationKey == NULL) {
- crv = CKR_KEY_HANDLE_INVALID;
-@@ -412,17 +434,17 @@ NSC_DecapsulateKey(CK_SESSION_HANDLE hSe
- decapsulationKey->attrib.ulValueLen };
- SECItem ciphertext = { siBuffer, pCiphertext, ulCiphertextLen };
-
- /* The length of secretBuf can be increased if we ever support other KEMs
- * by changing the define at the top of this file */
- uint8_t secretBuf[MAX_KEM_SHARED_SECRET_BYTES] = { 0 };
- SECItem secret = { siBuffer, secretBuf, sizeof secretBuf };
- key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_DECAPSULATE,
-- key, 0);
-+ decapsulationKeyObject, 0);
- key->source = SFTK_SOURCE_KEA;
-
- switch (pMechanism->mechanism) {
- #ifndef NSS_DISABLE_KYBER
- case CKM_NSS_KYBER:
- #endif
- case CKM_NSS_ML_KEM:
- case CKM_ML_KEM:
-diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
---- a/lib/softoken/pkcs11c.c
-+++ b/lib/softoken/pkcs11c.c
-@@ -5236,17 +5236,17 @@ sftk_compareKeysEqual(CK_SESSION_HANDLE
- SFTKObject *key1obj = NULL;
- SFTKObject *key2obj = NULL;
- SFTKAttribute *att1 = NULL;
- SFTKAttribute *att2 = NULL;
-
- /* fetch the pkcs11 objects from the handles */
- session = sftk_SessionFromHandle(hSession);
- if (session == NULL) {
-- return CKR_SESSION_HANDLE_INVALID;
-+ return PR_FALSE;
- }
-
- key1obj = sftk_ObjectFromHandle(key1, session);
- key2obj = sftk_ObjectFromHandle(key2, session);
- sftk_FreeSession(session);
- if ((key1obj == NULL) || (key2obj == NULL)) {
- goto loser;
- }
-@@ -5268,17 +5268,17 @@ sftk_compareKeysEqual(CK_SESSION_HANDLE
- goto loser;
- }
- result = PR_TRUE;
- loser:
- if (key1obj) {
- sftk_FreeObject(key1obj);
- }
- if (key2obj) {
-- sftk_FreeObject(key1obj);
-+ sftk_FreeObject(key2obj);
- }
- if (att1) {
- sftk_FreeAttribute(att1);
- }
- if (att2) {
- sftk_FreeAttribute(att2);
- }
- return result;
-@@ -5758,24 +5758,24 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
- SECITEM_ZfreeItem(&prime, PR_FALSE);
- }
- /* clean up before we return */
- sftk_FreeAttribute(pubAttribute);
- if (crv != CKR_OK) {
- return crv;
- }
- }
-- isKEM = sftk_isTrue(privateKey, CKA_ENCAPSULATE);
-+ isKEM = sftk_isTrue(privateKey, CKA_DECAPSULATE);
- if (isKEM) {
- unsigned char *cipher_text = NULL;
- CK_ULONG cipher_text_length = 0;
- CK_OBJECT_HANDLE key1 = CK_INVALID_HANDLE;
- CK_OBJECT_HANDLE key2 = CK_INVALID_HANDLE;
- CK_KEY_TYPE genType = CKO_SECRET_KEY;
-- CK_ATTRIBUTE template = { CKA_KEY_TYPE, NULL, 0 };
-+ CK_ATTRIBUTE template = { CKA_CLASS, NULL, 0 };
-
- template.pValue = &genType;
- template.ulValueLen = sizeof(genType);
- crv = CKR_OK;
- switch (keyType) {
- case CKK_ML_KEM:
- cipher_text_length = MAX_ML_KEM_CIPHER_LENGTH;
- mech.mechanism = CKM_ML_KEM;
-@@ -5828,17 +5828,17 @@ kem_done:
- PORT_Free(cipher_text);
- if (key1 != CK_INVALID_HANDLE) {
- NSC_DestroyObject(hSession, key1);
- }
- if (key2 != CK_INVALID_HANDLE) {
- NSC_DestroyObject(hSession, key2);
- }
- if (crv != CKR_OK) {
-- return CKR_DEVICE_ERROR;
-+ return crv;
- }
- }
-
- return CKR_OK;
- }
-
- /* NSC_GenerateKeyPair generates a public-key/private-key pair,
- * creating new key objects. */
-@@ -7905,16 +7905,17 @@ sftk_DeriveEncrypt(SFTKCipher encrypt, v
- return crv;
- }
-
- crv = sftk_forceAttribute(key, CKA_VALUE, tmpdata, keySize);
- PORT_Memset(tmpdata, 0, sizeof tmpdata);
- return crv;
- }
-
-+
- CK_RV
- sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_SESSION_HANDLE hSession,
- SFTKObject *sourceKey, const unsigned char *sourceKeyBytes,
- int sourceKeyLen, SFTKObject *key, unsigned char *outKeyBytes,
- int keySize, PRBool canBeData, PRBool isFIPS)
- {
- SFTKSession *session;
- SFTKAttribute *saltKey_att = NULL;
-@@ -7958,16 +7959,21 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
- }
-
- /* sourceKey is NULL if we are called from the POST, skip the
- * sensitiveCheck */
- if (sourceKey != NULL) {
- crv = sftk_DeriveSensitiveCheck(sourceKey, key, canBeData);
- if (crv != CKR_OK)
- return crv;
-+ /* if the source key is data, clear the FIPS flag
-+ * and only get the FIPS state from the salt */
-+ if (sourceKey->objclass == CKO_DATA) {
-+ key->isFIPS = PR_FALSE;
-+ }
- }
-
- /* HKDF-Extract(salt, base key value) */
- if (params->bExtract) {
- CK_BYTE *salt;
- CK_ULONG saltLen;
- HMACContext *hmac;
- unsigned int bufLen;
-@@ -7988,16 +7994,17 @@ sftk_HKDF(CK_HKDF_PARAMS_PTR params, CK_
- break;
- case CKF_HKDF_SALT_KEY:
- /* lookup key */
- session = sftk_SessionFromHandle(hSession);
- if (session == NULL) {
- return CKR_SESSION_HANDLE_INVALID;
- }
-
-+
- saltKey = sftk_ObjectFromHandle(params->hSaltKey, session);
- sftk_FreeSession(session);
- if (saltKey == NULL) {
- return CKR_KEY_HANDLE_INVALID;
- }
- /* if the base key is not fips, but the salt key is, the
- * resulting key can be fips */
- if (isFIPS && (key->isFIPS == 0) && (saltKey->isFIPS == 1)) {
-@@ -9190,17 +9197,23 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
-
- PORT_Memcpy(buf, att->attrib.pValue, att->attrib.ulValueLen);
- PORT_Memcpy(buf + att->attrib.ulValueLen,
- att2->attrib.pValue, att2->attrib.ulValueLen);
-
- crv = sftk_forceAttribute(key, CKA_VALUE, buf, keySize);
- PORT_ZFree(buf, tmpKeySize);
- /* preserve the source of the original base key */
-- /* key->source = sourceKey->source; */
-+ key->source = sourceKey->source;
-+
-+ /* make sure this is fully fips approved, and mark it
-+ * unapproved if not */
-+ if (key->isFIPS) {
-+ key->isFIPS = paramKey->isFIPS;
-+ }
- sftk_FreeAttribute(att2);
- sftk_FreeObject(paramKey);
- break;
- }
-
- case CKM_CONCATENATE_BASE_AND_DATA:
- crv = sftk_DeriveSensitiveCheck(sourceKey, key, PR_FALSE);
- if (crv != CKR_OK)
-diff --git a/lib/softoken/pkcs11u.c b/lib/softoken/pkcs11u.c
---- a/lib/softoken/pkcs11u.c
-+++ b/lib/softoken/pkcs11u.c
-@@ -2285,16 +2285,22 @@ sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE
- flags = CKF_VERIFY;
- break;
- case CKA_VERIFY_RECOVER:
- flags = CKF_VERIFY_RECOVER;
- break;
- case CKA_DERIVE:
- flags = CKF_DERIVE;
- break;
-+ case CKA_ENCAPSULATE:
-+ flags = CKF_ENCAPSULATE;
-+ break;
-+ case CKA_DECAPSULATE:
-+ flags = CKF_DECAPSULATE;
-+ break;
- /* fake attribute to select digesting */
- case CKA_DIGEST:
- flags = CKF_DIGEST;
- break;
- /* fake attribute to select key gen */
- case CKA_NSS_GENERATE:
- flags = CKF_GENERATE;
- break;
diff --git a/nss-3.112-no-p12-smime-policy.patch b/nss-3.112-no-p12-smime-policy.patch
deleted file mode 100644
index 9856781..0000000
--- a/nss-3.112-no-p12-smime-policy.patch
+++ /dev/null
@@ -1,151 +0,0 @@
-diff --git a/lib/pkcs12/p12plcy.c b/lib/pkcs12/p12plcy.c
---- a/lib/pkcs12/p12plcy.c
-+++ b/lib/pkcs12/p12plcy.c
-@@ -32,27 +32,31 @@ static pkcs12SuiteMap pkcs12SuiteMaps[]
- { SEC_OID_UNKNOWN, 0, PKCS12_NULL, PR_FALSE, PR_FALSE },
- { SEC_OID_UNKNOWN, 0, 0L, PR_FALSE, PR_FALSE }
- };
-
- /* determine if algid is an algorithm which is allowed */
- static PRBool
- sec_PKCS12Allowed(SECOidTag alg, PRUint32 needed)
- {
-+#ifdef notdef
- PRUint32 policy;
- SECStatus rv;
-
- rv = NSS_GetAlgorithmPolicy(alg, &policy);
- if (rv != SECSuccess) {
- return PR_FALSE;
- }
- if ((policy & needed) == needed) {
- return PR_TRUE;
- }
- return PR_FALSE;
-+#else
-+ return PR_TRUE;
-+#endif
- }
-
- PRBool
- SEC_PKCS12CipherAllowed(SECOidTag pbeAlg, SECOidTag hmacAlg)
- {
- SECOidTag cipherAlg = SEC_PKCS5GetCryptoFromAlgTag(pbeAlg);
- SECOidTag hashAlg = SEC_PKCS5GetHashFromAlgTag(pbeAlg);
- if (cipherAlg == SEC_OID_UNKNOWN) {
-diff --git a/lib/smime/smimeutil.c b/lib/smime/smimeutil.c
---- a/lib/smime/smimeutil.c
-+++ b/lib/smime/smimeutil.c
-@@ -197,16 +197,17 @@ smime_get_policy_tag_from_key_length(SEC
- return SEC_OID_UNKNOWN;
- }
- return algtag;
- }
-
- PRBool
- smime_allowed_by_policy(SECOidTag algtag, PRUint32 neededPolicy)
- {
-+#ifdef notdef
- PRUint32 policyFlags;
-
- /* some S/MIME algs map to the same underlying KEA mechanism,
- * collaps them here */
- if ((neededPolicy & (NSS_USE_ALG_IN_SMIME_KX | NSS_USE_ALG_IN_SMIME_KX_LEGACY)) != 0) {
- CK_MECHANISM_TYPE mechType = PK11_AlgtagToMechanism(algtag);
- switch (mechType) {
- case CKM_ECDH1_DERIVE:
-@@ -216,16 +217,17 @@ smime_allowed_by_policy(SECOidTag algtag
- }
- }
-
- if ((NSS_GetAlgorithmPolicy(algtag, &policyFlags) == SECFailure) ||
- ((policyFlags & neededPolicy) != neededPolicy)) {
- PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM);
- return PR_FALSE;
- }
-+#endif
- return PR_TRUE;
- }
-
- /*
- * We'll need this for the fake policy oids for RC2, but the
- * rest of these should be moved to pk11wrap for generic
- * algtag to key size values. We already need this for
- * sec_pkcs5v2_key_length_by oid.
-@@ -480,28 +482,34 @@ smime_init_once(void *arg)
- return PR_FAILURE;
- }
- algorithm_list_lock = PZ_NewLock(nssILockCache);
- if (algorithm_list_lock == NULL) {
- *error = PORT_GetError();
- return PR_FAILURE;
- }
-
-+#ifdef notdef
- /* At initialization time, we need to set up the defaults. We first
- * look to see if the system or application has set up certain algorithms
- * by policy. If they have set up values by policy we'll only allow those
- * algorithms. We'll then look to see if any algorithms are enabled by
- * the application. */
- rv = NSS_GetAlgorithmPolicyAll(NSS_USE_ALG_IN_SMIME_LEGACY,
- NSS_USE_ALG_IN_SMIME_LEGACY,
- &tags, &tagCount);
- if (tags) {
- PORT_Free(tags);
- tags = NULL;
- }
-+#else
-+ /* just initialize the old maps */
-+ rv = SECSuccess;
-+ tagCount = 0;
-+#endif
- if ((rv != SECSuccess) || (tagCount == 0)) {
- /* No algorithms have been enabled by policy (either by the system
- * or by the application, we then will use the traditional default
- * algorithms from the policy map */
- for (i = smime_legacy_map_count - 1; i >= 0; i--) {
- SECOidTag policytag = smime_legacy_map[i].policytag;
- /* this enables the algorithm by policy. We need this or
- * the policy code will reject attempts to use it */
-diff --git a/tests/smime/smime.sh b/tests/smime/smime.sh
---- a/tests/smime/smime.sh
-+++ b/tests/smime/smime.sh
-@@ -867,13 +867,13 @@ smime_cleanup()
- }
-
- ################## main #################################################
-
- smime_init
- smime_main
- smime_data_tb
- smime_p7
--if using_sql ; then
-- smime_policy
--fi
-+#if using_sql ; then
-+# smime_policy
-+#fi
- smime_cleanup
-
-diff --git a/tests/tools/tools.sh b/tests/tools/tools.sh
---- a/tests/tools/tools.sh
-+++ b/tests/tools/tools.sh
-@@ -590,17 +590,17 @@ tools_p12()
- tools_p12_export_list_import_most_ciphers
- fi
- tools_p12_export_with_none_ciphers
- tools_p12_export_with_invalid_ciphers
- tools_p12_import_old_files
- tools_p12_import_pbmac1_samples
- if using_sql; then
- tools_p12_import_rsa_pss_private_key
-- tools_p12_policy
-+# tools_p12_policy
- fi
- }
-
- ############################## tools_sign ##############################
- # local shell function pk12util uses a hardcoded tmp file, if this exists
- # and is owned by another user we don't get reasonable errormessages
- ########################################################################
- check_tmpfile()
diff --git a/nss-3.112-partial-pub-key-validate.patch b/nss-3.112-partial-pub-key-validate.patch
deleted file mode 100644
index ab36f1a..0000000
--- a/nss-3.112-partial-pub-key-validate.patch
+++ /dev/null
@@ -1,1501 +0,0 @@
-# HG changeset patch
-# User Robert Relyea
-# Date 1763508464 28800
-# Tue Nov 18 15:27:44 2025 -0800
-# Branch RHEL10
-# Node ID d7226ed21acc227df5dfb0a73b99a31640fddcba
-# Parent 6949dbcd6631ec0db3f53b3cf8957fac3a80da25
-nss-3.112-partial-pub-key-validate.patch
-
-diff --git a/cmd/bltest/blapitest.c b/cmd/bltest/blapitest.c
---- a/cmd/bltest/blapitest.c
-+++ b/cmd/bltest/blapitest.c
-@@ -27,28 +27,30 @@
-
- SECStatus EC_DecodeParams(const SECItem *encodedParams,
- ECParams **ecparams);
- SECStatus EC_CopyParams(PLArenaPool *arena, ECParams *dstParams,
- const ECParams *srcParams);
-
- char *progName;
- char *testdir = NULL;
-+PRBool strictOAEP = PR_FALSE;
-
- #define BLTEST_DEFAULT_CHUNKSIZE 4096
-
- #define WORDSIZE sizeof(unsigned long)
-
--#define CHECKERROR(rv, ln) \
-- if (rv) { \
-+#define CHECKERROR(rv, erv, ln) \
-+ if (rv != erv) { \
- PRErrorCode prerror = PR_GetError(); \
- PR_fprintf(PR_STDERR, "%s: ERR %d (%s) at line %d.\n", progName, \
- prerror, PORT_ErrorToString(prerror), ln); \
- exit(-1); \
-- }
-+ } \
-+ rv = SECSuccess
-
- /* Macros for performance timing. */
- #define TIMESTART() \
- time1 = PR_IntervalNow();
-
- #define TIMEFINISH(time, reps) \
- time2 = (PRIntervalTime)(PR_IntervalNow() - time1); \
- time1 = PR_IntervalToMilliseconds(time2); \
-@@ -112,16 +114,19 @@ Usage()
- PRINTUSAGE("", "-m", "cipher mode to use");
- PRINTUSAGE("", "-i", "file which contains input buffer");
- PRINTUSAGE("", "-o", "file for output buffer");
- PRINTUSAGE("", "-k", "file which contains key");
- PRINTUSAGE("", "-v", "file which contains initialization vector");
- PRINTUSAGE("", "-p", "do performance test");
- PRINTUSAGE("", "-4", "run test in multithread mode. th_num number of parallel threads");
- PRINTUSAGE("", "-5", "run test for specified time interval(in seconds)");
-+ PRINTUSAGE("", "-6", "hash algorithm for RSA PSS or OAEP");
-+ PRINTUSAGE("", "-7", "mask hash algorithm for RSA PSS or OAEP");
-+ PRINTUSAGE("", "-8", "validate the public key for RSAOAEP Encrypt");
- PRINTUSAGE("", "--aad", "File with contains additional auth data");
- fprintf(stderr, "\n");
- PRINTUSAGE(progName, "-H -m mode", "Hash a buffer");
- PRINTUSAGE("", "", "[-i plaintext] [-o hash]");
- PRINTUSAGE("", "", "[-b bufsize]");
- PRINTUSAGE("", "", "[-p repetitions | -5 time_interval] [-4 th_num]");
- PRINTUSAGE("", "-m", "cipher mode to use");
- PRINTUSAGE("", "-i", "file which contains input buffer");
-@@ -370,23 +375,23 @@ eckey_from_filedata(PLArenaPool *arena,
- ECPrivateKey *key;
- SECStatus rv;
- ECParams *tmpECParams = NULL;
- key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey));
- /* read and convert params */
- key->ecParams.arena = arena;
- key_from_filedata(arena, &key->ecParams.DEREncoding, 0, 1, filedata);
- rv = SECOID_Init();
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, SECSuccess, __LINE__);
- rv = EC_DecodeParams(&key->ecParams.DEREncoding, &tmpECParams);
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, SECSuccess, __LINE__);
- rv = EC_CopyParams(key->ecParams.arena, &key->ecParams, tmpECParams);
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, SECSuccess, __LINE__);
- rv = SECOID_Shutdown();
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, SECSuccess, __LINE__);
- PORT_FreeArena(tmpECParams->arena, PR_TRUE);
- /* read key */
- key_from_filedata(arena, &key->publicValue, 1, 3, filedata);
- return key;
- }
-
- typedef struct curveNameTagPairStr {
- char *curveName;
-@@ -799,16 +804,17 @@ struct bltestCipherInfoStr {
- } cipher;
- /* performance testing */
- int repetitionsToPerfom;
- int seconds;
- int repetitions;
- int cxreps;
- double cxtime;
- double optime;
-+ SECStatus expect;
- };
-
- PRBool
- is_symmkeyCipher(bltestCipherMode mode)
- {
- /* change as needed! */
- if (mode >= bltestDES_ECB && mode <= bltestCHACHA20_CTR)
- return PR_TRUE;
-@@ -836,16 +842,29 @@ is_authCipher(bltestCipherMode mode)
- case bltestCHACHA20:
- return PR_TRUE;
- default:
- return PR_FALSE;
- }
- }
-
- PRBool
-+is_rsaV2(bltestCipherMode mode)
-+{
-+ /* change as needed! */
-+ switch (mode) {
-+ case bltestRSA_OAEP:
-+ case bltestRSA_PSS:
-+ return PR_TRUE;
-+ default:
-+ return PR_FALSE;
-+ }
-+}
-+
-+PRBool
- is_singleShotCipher(bltestCipherMode mode)
- {
- /* change as needed! */
- switch (mode) {
- case bltestAES_GCM:
- case bltestAES_CTS:
- case bltestCHACHA20_CTR:
- case bltestCHACHA20:
-@@ -1748,16 +1767,18 @@ bltest_rsa_init(bltestCipherInfo *cipher
- /* Have to convert private key to public key. Memory
- * is freed with private key's arena */
- pubKey = (RSAPublicKey *)PORT_ArenaAlloc(privKey->arena,
- sizeof(RSAPublicKey));
- pubKey->modulus.len = privKey->modulus.len;
- pubKey->modulus.data = privKey->modulus.data;
- pubKey->publicExponent.len = privKey->publicExponent.len;
- pubKey->publicExponent.data = privKey->publicExponent.data;
-+ /* if structOAEP is set, exercise the oaep verify tests */
-+ pubKey->needVerify = strictOAEP;
- asymk->pubKey = (void *)pubKey;
- }
- switch (cipherInfo->mode) {
- case bltestRSA:
- cipherInfo->cipher.pubkeyCipher = encrypt ? rsa_PublicKeyOp
- : rsa_PrivateKeyOp;
- break;
- case bltestRSA_PSS:
-@@ -1785,20 +1806,20 @@ blapi_pqg_param_gen(unsigned int keysize
- }
-
- SECStatus
- bltest_pqg_init(bltestDSAParams *dsap)
- {
- SECStatus rv, res;
- PQGVerify *vfy = NULL;
- rv = blapi_pqg_param_gen(dsap->keysize, &dsap->pqg, &vfy);
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, SECSuccess, __LINE__);
- rv = PQG_VerifyParams(dsap->pqg, vfy, &res);
-- CHECKERROR(res, __LINE__);
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(res, SECSuccess, __LINE__);
-+ CHECKERROR(rv, SECSuccess, __LINE__);
- return rv;
- }
-
- SECStatus
- bltest_dsa_init(bltestCipherInfo *cipherInfo, PRBool encrypt)
- {
- int i;
- DSAPrivateKey **dummyKey;
-@@ -2247,48 +2268,48 @@ pubkeyInitKey(bltestCipherInfo *cipherIn
- case bltestDSA:
- dsap = &asymk->cipherParams.dsa;
- dsaKey = (DSAPrivateKey **)&asymk->privKey;
- if (keysize > 0) {
- dsap->keysize = keysize * 8;
- if (!dsap->pqg)
- bltest_pqg_init(dsap);
- rv = DSA_NewKey(dsap->pqg, dsaKey);
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, cipherInfo->expect, __LINE__);
- serialize_key(&(*dsaKey)->params.prime, 5, file);
- } else {
- setupIO(cipherInfo->arena, &asymk->key, file, NULL, 0);
- *dsaKey = dsakey_from_filedata(cipherInfo->arena, &asymk->key.buf);
- dsap->keysize = (*dsaKey)->params.prime.len * 8;
- }
- break;
- case bltestECDSA:
- ecKey = (ECPrivateKey **)&asymk->privKey;
- if (curveName != NULL) {
- tmpECParamsDER = getECParams(curveName);
- rv = SECOID_Init();
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, SECSuccess, __LINE__);
- rv = EC_DecodeParams(tmpECParamsDER, &tmpECParams) == SECFailure;
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, SECSuccess, __LINE__);
- rv = EC_NewKey(tmpECParams, ecKey);
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, cipherInfo->expect, __LINE__);
- ecSerialize[0].type = tmpECParamsDER->type;
- ecSerialize[0].data = tmpECParamsDER->data;
- ecSerialize[0].len = tmpECParamsDER->len;
- ecSerialize[1].type = (*ecKey)->publicValue.type;
- ecSerialize[1].data = (*ecKey)->publicValue.data;
- ecSerialize[1].len = (*ecKey)->publicValue.len;
- ecSerialize[2].type = (*ecKey)->privateValue.type;
- ecSerialize[2].data = (*ecKey)->privateValue.data;
- ecSerialize[2].len = (*ecKey)->privateValue.len;
- serialize_key(&(ecSerialize[0]), 3, file);
- SECITEM_FreeItem(tmpECParamsDER, PR_TRUE);
- PORT_FreeArena(tmpECParams->arena, PR_TRUE);
- rv = SECOID_Shutdown();
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, SECSuccess, __LINE__);
- } else {
- setupIO(cipherInfo->arena, &asymk->key, file, NULL, 0);
- *ecKey = eckey_from_filedata(cipherInfo->arena, &asymk->key.buf);
- }
- break;
- default:
- return SECFailure;
- }
-@@ -2494,42 +2515,42 @@ cipherDoOp(bltestCipherInfo *cipherInfo)
- : PR_MIN(cipherInfo->input.pBuf.len, 16);
- unsigned char *output = cipherInfo->output.pBuf.data;
- unsigned int outputLen = maxLen;
- unsigned int totalOutputLen = 0;
- TIMESTART();
- rv = (*cipherInfo->cipher.symmkeyCipher)(cipherInfo->cx,
- output, &len, outputLen,
- input, inputLen);
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, cipherInfo->expect, __LINE__);
- totalOutputLen += len;
- if (cipherInfo->input.pBuf.len > inputLen) {
- input += inputLen;
- inputLen = cipherInfo->input.pBuf.len - inputLen;
- output += len;
- outputLen -= len;
- rv = (*cipherInfo->cipher.symmkeyCipher)(cipherInfo->cx,
- output, &len, outputLen,
- input, inputLen);
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, cipherInfo->expect, __LINE__);
- totalOutputLen += len;
- }
- cipherInfo->output.pBuf.len = totalOutputLen;
- TIMEFINISH(cipherInfo->optime, 1.0);
- cipherInfo->repetitions = 0;
- if (cipherInfo->repetitionsToPerfom != 0) {
- TIMESTART();
- for (i = 0; i < cipherInfo->repetitionsToPerfom; i++,
- cipherInfo->repetitions++) {
- (*cipherInfo->cipher.symmkeyCipher)(cipherInfo->cx, dummyOut,
- &len, maxLen,
- cipherInfo->input.pBuf.data,
- cipherInfo->input.pBuf.len);
-
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, cipherInfo->expect, __LINE__);
- }
- } else {
- int opsBetweenChecks = 0;
- TIMEMARK(cipherInfo->seconds);
- while (!(TIMETOFINISH())) {
- int j = 0;
- for (; j < opsBetweenChecks; j++) {
- (*cipherInfo->cipher.symmkeyCipher)(
-@@ -2551,32 +2572,32 @@ cipherDoOp(bltestCipherInfo *cipherInfo)
-
- TIMESTART();
- rv = (*cipherInfo->cipher.aeadCipher)(
- cipherInfo->cx,
- output, &outputLen, maxLen,
- input, inputLen,
- sk->iv.buf.data, sk->iv.buf.len,
- ask->aad.buf.data, ask->aad.buf.len);
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, cipherInfo->expect, __LINE__);
- cipherInfo->output.pBuf.len = outputLen;
- TIMEFINISH(cipherInfo->optime, 1.0);
-
- cipherInfo->repetitions = 0;
- if (cipherInfo->repetitionsToPerfom != 0) {
- TIMESTART();
- for (i = 0; i < cipherInfo->repetitionsToPerfom; i++,
- cipherInfo->repetitions++) {
- rv = (*cipherInfo->cipher.aeadCipher)(
- cipherInfo->cx,
- output, &outputLen, maxLen,
- input, inputLen,
- sk->iv.buf.data, sk->iv.buf.len,
- ask->aad.buf.data, ask->aad.buf.len);
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, cipherInfo->expect, __LINE__);
- }
- } else {
- int opsBetweenChecks = 0;
- TIMEMARK(cipherInfo->seconds);
- while (!(TIMETOFINISH())) {
- int j = 0;
- for (; j < opsBetweenChecks; j++) {
- (*cipherInfo->cipher.aeadCipher)(
-@@ -2591,74 +2612,74 @@ cipherDoOp(bltestCipherInfo *cipherInfo)
- }
- TIMEFINISH(cipherInfo->optime, 1.0);
- } else if (is_pubkeyCipher(cipherInfo->mode)) {
- TIMESTART();
- rv = (*cipherInfo->cipher.pubkeyCipher)(cipherInfo->cx,
- &cipherInfo->output.pBuf,
- &cipherInfo->input.pBuf);
- TIMEFINISH(cipherInfo->optime, 1.0);
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, cipherInfo->expect, __LINE__);
- cipherInfo->repetitions = 0;
- if (cipherInfo->repetitionsToPerfom != 0) {
- TIMESTART();
- for (i = 0; i < cipherInfo->repetitionsToPerfom;
- i++, cipherInfo->repetitions++) {
- SECItem dummy;
- dummy.data = dummyOut;
- dummy.len = maxLen;
-- (*cipherInfo->cipher.pubkeyCipher)(cipherInfo->cx, &dummy,
-- &cipherInfo->input.pBuf);
-- CHECKERROR(rv, __LINE__);
-+ rv = (*cipherInfo->cipher.pubkeyCipher)(cipherInfo->cx, &dummy,
-+ &cipherInfo->input.pBuf);
-+ CHECKERROR(rv, cipherInfo->expect, __LINE__);
- }
- } else {
- int opsBetweenChecks = 0;
- TIMEMARK(cipherInfo->seconds);
- while (!(TIMETOFINISH())) {
- int j = 0;
- for (; j < opsBetweenChecks; j++) {
- SECItem dummy;
- dummy.data = dummyOut;
- dummy.len = maxLen;
-- (*cipherInfo->cipher.pubkeyCipher)(cipherInfo->cx, &dummy,
-- &cipherInfo->input.pBuf);
-- CHECKERROR(rv, __LINE__);
-+ rv = (*cipherInfo->cipher.pubkeyCipher)(cipherInfo->cx, &dummy,
-+ &cipherInfo->input.pBuf);
-+ CHECKERROR(rv, cipherInfo->expect, __LINE__);
- }
- cipherInfo->repetitions += j;
- }
- }
- TIMEFINISH(cipherInfo->optime, 1.0);
- } else if (is_hashCipher(cipherInfo->mode)) {
- TIMESTART();
- rv = (*cipherInfo->cipher.hashCipher)(cipherInfo->output.pBuf.data,
- cipherInfo->input.pBuf.data,
- cipherInfo->input.pBuf.len);
- TIMEFINISH(cipherInfo->optime, 1.0);
-- CHECKERROR(rv, __LINE__);
-+ CHECKERROR(rv, cipherInfo->expect, __LINE__);
- cipherInfo->repetitions = 0;
- if (cipherInfo->repetitionsToPerfom != 0) {
- TIMESTART();
- for (i = 0; i < cipherInfo->repetitionsToPerfom;
- i++, cipherInfo->repetitions++) {
-- (*cipherInfo->cipher.hashCipher)(dummyOut,
-- cipherInfo->input.pBuf.data,
-- cipherInfo->input.pBuf.len);
-- CHECKERROR(rv, __LINE__);
-+ rv = (*cipherInfo->cipher.hashCipher)(dummyOut,
-+ cipherInfo->input.pBuf.data,
-+ cipherInfo->input.pBuf.len);
-+ CHECKERROR(rv, cipherInfo->expect, __LINE__);
- }
- } else {
- int opsBetweenChecks = 0;
- TIMEMARK(cipherInfo->seconds);
- while (!(TIMETOFINISH())) {
- int j = 0;
- for (; j < opsBetweenChecks; j++) {
- bltestIO *input = &cipherInfo->input;
-- (*cipherInfo->cipher.hashCipher)(dummyOut,
-- input->pBuf.data,
-- input->pBuf.len);
-- CHECKERROR(rv, __LINE__);
-+ rv = (*cipherInfo->cipher.hashCipher)(dummyOut,
-+ input->pBuf.data,
-+ input->pBuf.len);
-+ CHECKERROR(rv, cipherInfo->expect, __LINE__);
- }
- cipherInfo->repetitions += j;
- }
- }
- TIMEFINISH(cipherInfo->optime, 1.0);
- }
- PORT_Free(dummyOut);
- return rv;
-@@ -2996,29 +3017,20 @@ load_file_data(PLArenaPool *arena, bltes
- file = PR_Open(fn, PR_RDONLY, 00660);
- if (file) {
- setupIO(arena, data, file, NULL, 0);
- PR_Close(file);
- }
- }
-
- HASH_HashType
--mode_str_to_hash_alg(const SECItem *modeStr)
-+mode_string_to_hash_alg(const char *modeString)
- {
- bltestCipherMode mode;
-- char *tempModeStr = NULL;
-- if (!modeStr || modeStr->len == 0)
-- return HASH_AlgNULL;
-- tempModeStr = PORT_Alloc(modeStr->len + 1);
-- if (!tempModeStr)
-- return HASH_AlgNULL;
-- memcpy(tempModeStr, modeStr->data, modeStr->len);
-- tempModeStr[modeStr->len] = '\0';
-- mode = get_mode(tempModeStr);
-- PORT_Free(tempModeStr);
-+ mode = get_mode(modeString);
- switch (mode) {
- case bltestMD2:
- return HASH_AlgMD2;
- case bltestMD5:
- return HASH_AlgMD5;
- case bltestSHA1:
- return HASH_AlgSHA1;
- case bltestSHA224:
-@@ -3029,16 +3041,33 @@ mode_str_to_hash_alg(const SECItem *mode
- return HASH_AlgSHA384;
- case bltestSHA512:
- return HASH_AlgSHA512;
- default:
- return HASH_AlgNULL;
- }
- }
-
-+HASH_HashType
-+mode_str_to_hash_alg(const SECItem *modeStr)
-+{
-+ HASH_HashType hashType;
-+ char *tempModeStr = NULL;
-+ if (!modeStr || modeStr->len == 0)
-+ return HASH_AlgNULL;
-+ tempModeStr = PORT_Alloc(modeStr->len + 1);
-+ if (!tempModeStr)
-+ return HASH_AlgNULL;
-+ memcpy(tempModeStr, modeStr->data, modeStr->len);
-+ tempModeStr[modeStr->len] = '\0';
-+ hashType = mode_string_to_hash_alg(tempModeStr);
-+ PORT_Free(tempModeStr);
-+ return hashType;
-+}
-+
- void
- get_params(PLArenaPool *arena, bltestParams *params,
- bltestCipherMode mode, int j)
- {
- char filename[256];
- char *modestr = mode_strings[mode];
- bltestIO tempIO;
-
-@@ -3259,16 +3288,17 @@ blapi_selftest(bltestCipherMode *modes,
- char filename[256];
- PLArenaPool *arena;
- SECItem item;
- SECStatus rv = SECSuccess, srv;
-
- PORT_Memset(&cipherInfo, 0, sizeof(cipherInfo));
- arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE);
- cipherInfo.arena = arena;
-+ cipherInfo.expect = SECSuccess;
-
- nummodes = (numModes == 0) ? NUMMODES : numModes;
- for (i = 0; i < nummodes; i++) {
- if (numModes > 0)
- mode = modes[i];
- else
- mode = i;
- if (mode == bltestINVALID) {
-@@ -3299,31 +3329,41 @@ blapi_selftest(bltestCipherMode *modes,
- "plaintext", j);
- load_file_data(arena, &pt, filename,
- is_sigCipher(mode) ? bltestBase64Encoded
- : bltestBinary);
- snprintf(filename, sizeof(filename), "%s/tests/%s/%s%d", testdir, modestr,
- "ciphertext", j);
- load_file_data(arena, &ct, filename, bltestBase64Encoded);
-
-+ snprintf(filename, sizeof(filename), "%s/tests/%s/%s%s%s%d", testdir, modestr,
-+ "result", encrypt? "-encrypt" : "-decrypt", strictOAEP ? "-strict":"", j);
-+
-+ cipherInfo.expect = SECSuccess;
-+ if (PR_Access(filename, PR_ACCESS_EXISTS) == PR_SUCCESS) {
-+ cipherInfo.expect = SECFailure;
-+ }
-+
- get_params(arena, params, mode, j);
- /* Forward Operation (Encrypt/Sign/Hash)
- ** Align the input buffer (plaintext) according to request
- ** then perform operation and compare to ciphertext
- */
- if (encrypt) {
- rv |= bltestCopyIO(arena, &cipherInfo.input, &pt);
- misalignBuffer(arena, &cipherInfo.input, inoff);
- memset(&cipherInfo.output.buf, 0, sizeof cipherInfo.output.buf);
- rv |= cipherInit(&cipherInfo, PR_TRUE);
- misalignBuffer(arena, &cipherInfo.output, outoff);
- rv |= cipherDoOp(&cipherInfo);
- rv |= cipherFinish(&cipherInfo);
-- rv |= verify_self_test(&cipherInfo.output,
-- &ct, mode, PR_TRUE, SECSuccess);
-+ if (cipherInfo.expect == SECSuccess) {
-+ rv |= verify_self_test(&cipherInfo.output,
-+ &ct, mode, PR_TRUE, SECSuccess);
-+ }
- /* If testing hash, only one op to test */
- if (is_hashCipher(mode))
- continue;
- if (is_sigCipher(mode)) {
- /* Verify operations support detached signature files. For
- ** consistency between tests that run Sign/Verify back to
- ** back (eg: self-tests) and tests that are only running
- ** verify operations, copy the output into the sig buf,
-@@ -3332,16 +3372,22 @@ blapi_selftest(bltestCipherMode *modes,
- ** verify-only operations, this ensures that the output
- ** buffer is properly configured
- */
- rv |= bltestCopyIO(arena, ¶ms->asymk.sig, &cipherInfo.output);
- }
- }
- if (!decrypt)
- continue;
-+
-+ /* If we expect the encrypt to fail, then don't do the decrypt */
-+ if (cipherInfo.expect == SECFailure) {
-+ continue;
-+ }
-+
- /* Reverse Operation (Decrypt/Verify)
- ** Align the input buffer (ciphertext) according to request
- ** then perform operation and compare to plaintext
- */
- if (is_sigCipher(mode)) {
- rv |= bltestCopyIO(arena, &cipherInfo.input, &pt);
- rv |= bltestCopyIO(arena, &cipherInfo.output, ¶ms->asymk.sig);
- } else {
-@@ -3692,16 +3738,19 @@ enum {
- opt_UseSigSeed,
- opt_SeedFile,
- opt_AAD,
- opt_InputOffset,
- opt_OutputOffset,
- opt_MonteCarlo,
- opt_ThreadNum,
- opt_SecondsToRun,
-+ opt_RSAHash,
-+ opt_MaskHash,
-+ opt_OAEPStrict,
- opt_CmdLine
- };
-
- static secuCommandFlag bltest_commands[] = {
- { /* cmd_Decrypt */ 'D', PR_FALSE, 0, PR_FALSE },
- { /* cmd_Encrypt */ 'E', PR_FALSE, 0, PR_FALSE },
- { /* cmd_FIPS */ 'F', PR_FALSE, 0, PR_FALSE },
- { /* cmd_Hash */ 'H', PR_FALSE, 0, PR_FALSE },
-@@ -3742,19 +3791,29 @@ static secuCommandFlag bltest_options[]
- { /* opt_UseSigSeed */ 'y', PR_FALSE, 0, PR_FALSE },
- { /* opt_SeedFile */ 'z', PR_FALSE, 0, PR_FALSE },
- { /* opt_AAD */ 0, PR_TRUE, 0, PR_FALSE, "aad" },
- { /* opt_InputOffset */ '1', PR_TRUE, 0, PR_FALSE },
- { /* opt_OutputOffset */ '2', PR_TRUE, 0, PR_FALSE },
- { /* opt_MonteCarlo */ '3', PR_FALSE, 0, PR_FALSE },
- { /* opt_ThreadNum */ '4', PR_TRUE, 0, PR_FALSE },
- { /* opt_SecondsToRun */ '5', PR_TRUE, 0, PR_FALSE },
-+ { /* opt_RSAHash */ '6', PR_TRUE, 0, PR_FALSE },
-+ { /* opt_MaskHash */ '7', PR_TRUE, 0, PR_FALSE },
-+ { /* opt_OAEPStrict */ '8', PR_FALSE, 0, PR_FALSE },
- { /* opt_CmdLine */ '-', PR_FALSE, 0, PR_FALSE }
- };
-
-+unsigned int
-+HashLen(HASH_HashType type)
-+{
-+ const SECHashObject *hashObj = HASH_GetRawHashObject(type);
-+ return hashObj->length;
-+}
-+
- int
- main(int argc, char **argv)
- {
- SECStatus rv = SECFailure;
-
- double totalTime = 0.0;
- PRIntervalTime time1, time2;
- PRFileDesc *outfile = NULL;
-@@ -3832,16 +3891,17 @@ main(int argc, char **argv)
- if (bltest.options[opt_InputOffset].activated)
- inoff = PORT_Atoi(bltest.options[opt_InputOffset].arg);
- if (bltest.options[opt_OutputOffset].activated)
- outoff = PORT_Atoi(bltest.options[opt_OutputOffset].arg);
-
- testdir = (bltest.options[opt_SelfTestDir].activated) ? strdup(bltest.options[opt_SelfTestDir].arg)
- : ".";
-
-+ strictOAEP= bltest.options[opt_OAEPStrict].activated;
- /*
- * Handle three simple cases first
- */
-
- /* test the RSA_PopulatePrivateKey function with known vectors */
- if (bltest.commands[cmd_RSAPopulateKV].activated) {
- PORT_Free(cipherInfo);
- return doRSAPopulateTestKV();
-@@ -4145,16 +4205,84 @@ main(int argc, char **argv)
- }
- memset(&askp->aad, 0, sizeof askp->aad);
- askp->aad.mode = ioMode;
- setupIO(cipherInfo->arena, &askp->aad, file, aadstr, 0);
- if (file) {
- PR_Close(file);
- }
- }
-+ /* set up rsaoaep and pss values */
-+ if (is_rsaV2(cipherInfo->mode)) {
-+ char *seedstr = NULL;
-+ bltestRSAParams *rsakp;
-+ bltestIO tempIO;
-+ rsakp = ¶ms->asymk.cipherParams.rsa;
-+
-+ /* hash */
-+ if (bltest.options[opt_RSAHash].activated) {
-+ if (bltest.options[opt_CmdLine].activated) {
-+ rsakp->hashAlg = mode_string_to_hash_alg(
-+ bltest.options[opt_RSAHash].arg);
-+ } else {
-+ load_file_data(arena, &tempIO,
-+ bltest.options[opt_RSAHash].arg,
-+ bltestBinary);
-+ rsakp->hashAlg = mode_str_to_hash_alg(&tempIO.buf);
-+ }
-+ } else {
-+ /* save the random iv for reference */
-+ file = PR_Open("tmp.hash", PR_WRONLY | PR_CREATE_FILE, 00660);
-+ PR_Write(file, "sha256\n", sizeof("sha256\n")-1);
-+ rsakp->hashAlg = HASH_AlgSHA256;
-+ PR_Close(file);
-+
-+ }
-+ /* mask */
-+ if (bltest.options[opt_RSAHash].activated) {
-+ if (bltest.options[opt_CmdLine].activated) {
-+ rsakp->maskHashAlg = mode_string_to_hash_alg(
-+ bltest.options[opt_MaskHash].arg);
-+ } else {
-+ load_file_data(arena, &tempIO,
-+ bltest.options[opt_MaskHash].arg,
-+ bltestBinary);
-+ rsakp->maskHashAlg = mode_str_to_hash_alg(&tempIO.buf);
-+ }
-+ } else {
-+ /* save the random iv for reference */
-+ file = PR_Open("tmp.maskhash", PR_WRONLY | PR_CREATE_FILE,
-+ 00660);
-+ PR_Write(file, "sha256\n", sizeof("sha256\n")-1);
-+ rsakp->maskHashAlg = HASH_AlgSHA256;
-+ PR_Close(file);
-+
-+ }
-+ /* seed salt */
-+ file = NULL;
-+ if (bltest.options[opt_Seed].activated) {
-+ if (bltest.options[opt_CmdLine].activated) {
-+ seedstr = bltest.options[opt_Seed].arg;
-+ } else {
-+ file = PR_Open(bltest.options[opt_Seed].arg,
-+ PR_RDONLY, 00660);
-+ }
-+ } else {
-+ /* save the random seed for reference */
-+ file = PR_Open("tmp.seed", PR_WRONLY | PR_CREATE_FILE, 00660);
-+ }
-+ memset(&rsakp->seed, 0, sizeof rsakp->seed);
-+ rsakp->seed.mode = ioMode;
-+ setupIO(cipherInfo->arena, &rsakp->seed, file, seedstr,
-+ HashLen(rsakp->hashAlg));
-+ if (file) {
-+ PR_Close(file);
-+ }
-+ file = NULL;
-+ }
-
- if (bltest.commands[cmd_Verify].activated) {
- file = PR_Open(bltest.options[opt_SigFile].arg, PR_RDONLY, 00660);
- if (is_sigCipher(cipherInfo->mode)) {
- memset(¶ms->asymk.sig, 0, sizeof(bltestIO));
- params->asymk.sig.mode = ioMode;
- setupIO(cipherInfo->arena, ¶ms->asymk.sig, file, NULL, 0);
- }
-diff --git a/cmd/bltest/tests/rsa_oaep/ciphertext18 b/cmd/bltest/tests/rsa_oaep/ciphertext18
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/ciphertext18
-@@ -0,0 +1,6 @@
-+m8ZlOZEwDf3oapXT/tuBWS5Boa9rS08M/pFz1N2Y1GU0sYC4zcv79zxmjk2RjYLe
-+VjCAM8gAGoVdpV7P53NvAwEZcEpXd/ewhCz1sopc19o96pEYqC01Ik9TW0H/41Rh
-+O/KvWvVEoJ8s0TS6z+ViCK5iBjdxLhF7SKxwJXfcwZvOua3lr9yjgkljVzIYf7XA
-+1ZkkuxB0PDPw6ud022rn/xKhjhL9GJObY9rNYZwyS6hSpUEM+ZV106X+7nISVgOr
-+vP93jbTwg0ndqn3XJKOduJVZVTR/dEebqSuBnWW4TIGE3Tq84Xf+ySGpMtD3vRbG
-+C5P6A7EyqXJOOwUvvZzAcw==
-diff --git a/cmd/bltest/tests/rsa_oaep/ciphertext19 b/cmd/bltest/tests/rsa_oaep/ciphertext19
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/ciphertext19
-@@ -0,0 +1,6 @@
-+eNIFlfXIih5XqUTcmFUeW3WQdlrO8yeLkGBgYZcHkFCNXeEze26osWLzIpuRc+vY
-+kdHVVxDWhcp4Q/3AWL8Ib67BYfZk/AQn+IJCDsd2tdVxg3/ifCtYYm+09KY8oNy/
-+uWudjMEiS1FR7l+wb2QNHcQH6UjJqt5+z19nCcwyBfHH6E3u+U+Pq6uDdhSODu3e
-+s0UxYjiDl0UUW5m7uJVq7MCrqAHgTkH3h+wWOMJaORZ7tk9tfCnvUt9AiAToyv0Y
-+G9Ylbkll5bM+UO7R6JsXqm25cM6pshP5jy+aXbw+KqXLjxbgrDdZQZ1MXup7QT/z
-+znUkc0USufg5BmymMoPP/A==
-diff --git a/cmd/bltest/tests/rsa_oaep/ciphertext20 b/cmd/bltest/tests/rsa_oaep/ciphertext20
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/ciphertext20
-@@ -0,0 +1,6 @@
-+Ll4/kyqhXiKtf+rgK8vNrVpfqV+YOiARW1vCX5Mo28OEbUQHNeetPdpbQ8gnlkFa
-+xWdVrUmeVSY4A3Nkv8f3ZvC2m08A1OCvSxhgTKUJvO8eW5DErFdj0irT4FKt4nsO
-+G86+cOiEr5OuWNfZv+UI36TJaadgGXHNAD/keCl/tq65tiiw6EwWYSm3kypA5MN+
-+2e5eBtdwZfFM+kouQZf75AUitcYYGCbnZLWIyZc8OfTyEgtcR8ERTz+BrT0Ub8va
-+ML0MEc3+nIMApdXU9SWbyr/WA8Sz/wh5kyA+Yr6Xww0j36chjRgSh3Dn3ykZkYZX
-+gwWtxqWTY6mWaatQXCfnHA==
-diff --git a/cmd/bltest/tests/rsa_oaep/ciphertext21 b/cmd/bltest/tests/rsa_oaep/ciphertext21
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/ciphertext21
-@@ -0,0 +1,6 @@
-+gsKckbXuYtoxoGMVpkVsd1Nb2BMTqMuThlUXbzQB1qzJ1/PTbdpRWFtcDKsW202f
-+tO4NPt7sCIHdiqdqwXVQxcTabrbwaUZICtwphbLUQDKMU/pwhicKHSH8hD0/FbwU
-+4iYUgYKxkjsQUlW4Eq4Yh+2Vfk2+ae6PFAvdQE0EHEWsNUkbbbv5tNweLH0JmQGp
-+W4k2MKm2LUu4+v+n8aQ4FwkuQKS2ZqddTjR+QRjM+hzsSVNPpvvCu4kK4xU3G0ru
-+JWLCtmdmVGXpLlwiLUn0FomRUa1fqQOhp3W4/WvJf1kdcj2pPLzgHPKgivb+03o+
-+4pHctkSM4dgC9vhMOLc8Tg==
-diff --git a/cmd/bltest/tests/rsa_oaep/ciphertext22 b/cmd/bltest/tests/rsa_oaep/ciphertext22
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/ciphertext22
-@@ -0,0 +1,6 @@
-+agf+F8PWGOKXgZYUpqPZ2NT17bkElsyzUNXbmcuZKd1YHSo6TZZj+Jdd48QhlDHK
-+fUIch1+QIgRnTWZ9Jpw6d7Agk1jz0yjg2ywrEmdT1aRwBonVn1r1rK3q2giCZLEd
-+YhQ2fz/Iz89b084w7yjLDI2mbOi0Pbizn6IB6whkJYIKPjMLgekvwQ6EM4VvrsM6
-+gHT9BGmICIpO+ipHYYwNhZiePpnZSck5p7lxmHLa/WWFeGrFJzNzab+8ToRw12hR
-+oL4DBLfob5wvychGSkjGeWWRbFhbujalHOI8fOg92bUxSeaks3XDhRhv8eZmX1c6
-+hpKbNFNI99e20O5riigz7Q==
-diff --git a/cmd/bltest/tests/rsa_oaep/hash18 b/cmd/bltest/tests/rsa_oaep/hash18
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/hash18
-@@ -0,0 +1,1 @@
-+sha256
-diff --git a/cmd/bltest/tests/rsa_oaep/hash19 b/cmd/bltest/tests/rsa_oaep/hash19
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/hash19
-@@ -0,0 +1,1 @@
-+sha256
-diff --git a/cmd/bltest/tests/rsa_oaep/hash20 b/cmd/bltest/tests/rsa_oaep/hash20
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/hash20
-@@ -0,0 +1,1 @@
-+sha256
-diff --git a/cmd/bltest/tests/rsa_oaep/hash21 b/cmd/bltest/tests/rsa_oaep/hash21
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/hash21
-@@ -0,0 +1,1 @@
-+sha256
-diff --git a/cmd/bltest/tests/rsa_oaep/hash22 b/cmd/bltest/tests/rsa_oaep/hash22
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/hash22
-@@ -0,0 +1,1 @@
-+sha256
-diff --git a/cmd/bltest/tests/rsa_oaep/key18 b/cmd/bltest/tests/rsa_oaep/key18
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/key18
-@@ -0,0 +1,1 @@
-+AAAAAQAAAAEA5UUoEM5A1qttdY2GGJiJ5ypWHjr6o+CISs8S+zs2npypQiFLjSaf37nacs1Vz7J5mSHwJhTRXm2uzUYPckEuN1TA/88v4zl3O20RY2IBvI+T9Gqb/ir8KmH+/xQivsBaN2qIu0u/ZNzHyDpQlB3rJu4iqJhTQC/CdKN19o3Ex9QRdSC4xAITKnMooImWbLlBcqx0M6G0DMraD9DRaKntHhYabmtI8ly3wbldjHXlLc4YFEm+/Mk5kzNZAUCQ/gZrU/C6ue45cHhiqJpJ2Wx4X+3EQveTh9+emJMtOz4sogvy67ow+0/0f3svgbiycwe4HL5gu4yOCsH6l6asfqIYdwAAAAMBAAEAAAEAdDQ+H256vJN80kUd/19pHgp+Rao9GUyXp9sW0tFrWK8stsDrayp1g87OYruiT7g1G6Fw98w7ZjIPlCl7cLyKsS66961Kp0+cGDmqw4WMPcdEBXD3iba9wrmSpjTNe4NA9q9/h/bXlka0185+wuP7KOswE+XI5FKQq8+h3Ypzf5kEFCq2m1o13qEpqVyzKn4nJvkzmGvQN1+lcLi1OuhNr58iXG7yNS07Uewi9ytWMoYv/DB4peVT0kEHTrQsCSS1x4DPE6gj4taRosU4wwPQa0a23/5d/1MfLlQCa/GSa7vEryfa5bXbxbVpGcXEZLs33RG9M7IE2H0DB1RKP5Dm9wAAAQDlRSgQzkDWq211jYYYmInnKlYeOvqj4IhKzxL7OzaenKlCIUuNJp/fudpyzVXPsnmZIfAmFNFeba7NRg9yQS43VMD/zy/jOXc7bRFjYgG8j5P0apv+KvwqYf7/FCK+wFo3aoi7S79k3MfIOlCUHesm7iKomFNAL8J0o3X2jcTH1BF1ILjEAhMqcyigiZZsuUFyrHQzobQMytoP0NFoqe0eFhpua0jyXLfBuV2MdeUtzhgUSb78yTmTM1kBQJD+BmtT8Lq57jlweGKomknZbHhf7cRC95OH356Yky07PiyiC/LrujD7T/R/ey+BuLJzB7gcvmC7jI4KwfqXpqx+ohh3AAAAAQEAAAEAdDQ+H256vJN80kUd/19pHgp+Rao9GUyXp9sW0tFrWK8stsDrayp1g87OYruiT7g1G6Fw98w7ZjIPlCl7cLyKsS66961Kp0+cGDmqw4WMPcdEBXD3iba9wrmSpjTNe4NA9q9/h/bXlka0185+wuP7KOswE+XI5FKQq8+h3Ypzf5kEFCq2m1o13qEpqVyzKn4nJvkzmGvQN1+lcLi1OuhNr58iXG7yNS07Uewi9ytWMoYv/DB4peVT0kEHTrQsCSS1x4DPE6gj4taRosU4wwPQa0a23/5d/1MfLlQCa/GSa7vEryfa5bXbxbVpGcXEZLs33RG9M7IE2H0DB1RKP5Dm9wAAAAEBAAAAAQE=
-\ No newline at end of file
-diff --git a/cmd/bltest/tests/rsa_oaep/key19 b/cmd/bltest/tests/rsa_oaep/key19
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/key19
-@@ -0,0 +1,1 @@
-+AAAAAQAAAAEAiEv3eeAtf4akF4xEo9sRDLbrulalIBrTmzTYl7Twlk18eUU2CvamKx03Ls8YRdJsJ+73F+03e5gXQuqaq3IArYzy3P09rghqgPW52/Sux49ajDLfWsOUbWa4bQSAHxLHi45ZipyPnWgqHqzE7tq5OL4XpN0JVEg/wvm4c8FBIt91Qq5xQFdFkr5WpsnCyLTvvpDtaFCzIAoN2LY2ijH13V3dMuN1dKhCj2L9INEHgxRIqq5iKmBrRqZMhXdvZAh83lOc8aBgAkZ7Puvjz2fSSHlVNb9xfl+JUxOoHy6uUw66ZA5P1yacOlqwra/9gbe1GjuU0GJJQS8sVtt0MgHcjQAAAAMBAAEAAAEAYYSKMAbXKeVK5YXVTz3hYM+w7zbmkWqCN+Gnn8wjUHDx5HUlJtxXV2sDRxxtv42rbRAm+67DhWugnOF/oVM2I/jMz1xCUTFp0VZwIMnSeIgl4AjgM3Fad6E9M+rWfaQnAAKekyT8okGLHGjRqJWC5xYenjSNq4LLCDOToz00RbYQu0GaHXawG26AJbarYRaZLeG1zWUSSVIWnL+F4mMVh0huiSlS9TWTe2YQrkKqFzslyJ3DCqXQDz1gyuOm7E/3zeNAmGFZXrzCwLJuTpFQY66Ohmt25rDQdTvPR/V+Lnev3acLdTvwuFyT4MYsZeqCJ6b5ocUy5sW6WzwntsGg0QAAAAAAAAAAAAAAAAAAAAAAAAAA
-\ No newline at end of file
-diff --git a/cmd/bltest/tests/rsa_oaep/key20 b/cmd/bltest/tests/rsa_oaep/key20
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/key20
-@@ -0,0 +1,1 @@
-+AAAAAQAAAAEAxpqCGNigv6qOWXo2iOvLLM35bPnp5JgaB3XnnbWOUqF0vbvvRP85giGkYYDj4poPGT0NRshTkz7fKbAVCHCs7HBFzzaxXisQsFd9mno+x+62nERyJ8Jx6XASVxN9IoyhE7xXS1eDPjccG9XlXktwaRsvC3HCxlqEPxNCE+l9RM8re859xMesjtML2Ww6U5tKci//84f/dKjAD5Hbdoj2JIwRhRl+2ACUml2rWrglSjKH19ZzJkbWFFJhecrt1FD/CFsx+hFAtZQtuqs7PFQvZSwU1OoVTyf/jMEXwhsDoRyf3+QQp8wAm4GztJxXTclXk2jNA+g9/UJ91ZxUwrIYoQAAAAMBAAEAAAEAi59wOvuA9352mR08XcI3koY0BpMkBhuQoRIZBVzwc9MieYk4S6+KxJvWLt4oV9SrLLkpLkwDxY774RjzkH12dCYsOzNs9nL23raqQ9xX1EZnJfdIlyoGJmeUJMYPTtH6ANYnlPoxozyJStPtr1wZGs/3X30XieVrd68yrMGedhZ6tej11vJS/a22DWG57NjZC7/enzBkYHtzVCFnDRk08Qxzcss85IF8khG8NpLz1tl4+9vKKkwa08d++SC3EAs2/d9y9RCxiYTcXEgaWTmINT6JpWBXwdJAUIjOr1ujequixnapB351UZODHGKBieU1hpc52NuKz/SCLuCQmxkM0QAAAAAAAAAAAAAAAAAAAAAAAAAA
-\ No newline at end of file
-diff --git a/cmd/bltest/tests/rsa_oaep/key21 b/cmd/bltest/tests/rsa_oaep/key21
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/key21
-@@ -0,0 +1,1 @@
-+AAAAAQAAAAEAhxOfLwr3NUmZUE50aKLO+KHw8Y4yOLd9wZKJq/9WcuHnOJJJw0uV35ugsUvaXAcRwszCOJTtu+cZ1zMvRoEB/EQGcltmULHF9ViHkK5b7gcaSP2ALIrZyF9/IN5vnUGqsg1719WmgAOee6Zo1nytdbq5+cJGmAC8a6CorCM68eR1UsdoB7RfVQpqzc9fjG+HZ2wv58mk/OEhJAHUJRf7xjbrbF9jZ3DeiMd8f/dxK+bEKCXt2XsYZoOquylOdNVxCBylGSelzJqFwUvHUeJzSsz3PvXHB3YBH0cABVufoMOjwRYaNJvryhRICmbnH0Gw9ai90A/lotbprv2bzuGKUQAAAAMBAAEAAAEAGLqQ4+3gABNvS/JxAU79ESukjrR3oUaGcU/AgIqIaxPMXuD5PBW0ZHF7Y7n9SefJap5N2En7k/DlHC60svWfRVCy955YhJ4NVYHwVwcWsOGFtFkVb/fLERuydu6t3m7ucrxk/tEuxgCEZSuO/kAHBD3ltlCDLQv2KYzP7kfzJEllSDVplfcSfIxi5VQTcHuLZFScYQSeeWdjprWZ1Bv/fyFzqioqyNb/3SyFEMnXubDR0KH5yAWfeRRNLCje+DDUa41ZGiyBzlVf8eRtoh8CUNfDq6MtbfBvzjyswVV4M/h2RCO7nGAaJ8OkpCjzW04czzR/hwA2SbzP49OPD+fj1QAAAAAAAAAAAAAAAAAAAAAAAAAA
-\ No newline at end of file
-diff --git a/cmd/bltest/tests/rsa_oaep/key22 b/cmd/bltest/tests/rsa_oaep/key22
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/key22
-@@ -0,0 +1,1 @@
-+AAAAAQAAAAEAgu9i5HnjEXoGUpZ1SMf6auSlz7+X6N4hQ6Yiicq4BC66QIyjY3IjEyhlJKHsX3//GzWd+6NCerSWb23j54IrFcLGNH1oWylxZXJtCIn2+gVDsw4D+RwbG/cY6B3U4Qs1HnlSqgxKVVYAQmQyeIKshXldD86aC5OnfDlguZBN3Qe641oqoAshOzAPzBQU0fo4dey5SVXftIKm4YE2+rVK7UmbQsNBCPYonT3obsGqspnx5MghuP1MMV2HkTyL4GJk/MwTFKlsd8Nq9PrrPfpbEtpITV57lTvRcKMqW/8WaaY7YfNKtIE/TppFyw5WcxP+iPffXA+s3/kZNn4/zEGowQAAAAMBAAEAAAEAVjyMiaatoykXWPW3sYPkrtqBSt8Jkloa1o9pWA+oOzj7euAmDK1z5H5Kf2IWaJ/IyYb60m2or2CZZDKgVC4rafexMGNlvguk9Ku6ETfjA09lizPg3NQEgn06oVNYy5xurEnXNGQEcys8Pkos+GOxHBv+eMd5msV0d4lSTsi2CkJHnKuwFphjYdCTQTBZK8zlKDkY6El6Dyfmy9lrg/T5NC6kE2eeCss2/hkWzIGMbDcE3UVZGhJJhrca9SUkUHbGwbicGYUOnEGlQho9IBCpHt7CP1XWSNwZFJkRcmBFKomghAaLSXM/bfm8tghsnqI+zAL6bTdAaZkDgw5Pc0Cr+QAAAAAAAAAAAAAAAAAAAAAAAAAA
-\ No newline at end of file
-diff --git a/cmd/bltest/tests/rsa_oaep/maskhash18 b/cmd/bltest/tests/rsa_oaep/maskhash18
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/maskhash18
-@@ -0,0 +1,1 @@
-+sha256
-diff --git a/cmd/bltest/tests/rsa_oaep/maskhash19 b/cmd/bltest/tests/rsa_oaep/maskhash19
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/maskhash19
-@@ -0,0 +1,1 @@
-+sha256
-diff --git a/cmd/bltest/tests/rsa_oaep/maskhash20 b/cmd/bltest/tests/rsa_oaep/maskhash20
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/maskhash20
-@@ -0,0 +1,1 @@
-+sha256
-diff --git a/cmd/bltest/tests/rsa_oaep/maskhash21 b/cmd/bltest/tests/rsa_oaep/maskhash21
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/maskhash21
-@@ -0,0 +1,1 @@
-+sha256
-diff --git a/cmd/bltest/tests/rsa_oaep/maskhash22 b/cmd/bltest/tests/rsa_oaep/maskhash22
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/maskhash22
-@@ -0,0 +1,1 @@
-+sha256
-diff --git a/cmd/bltest/tests/rsa_oaep/numtests b/cmd/bltest/tests/rsa_oaep/numtests
---- a/cmd/bltest/tests/rsa_oaep/numtests
-+++ b/cmd/bltest/tests/rsa_oaep/numtests
-@@ -1,1 +1,1 @@
--18
-+23
-diff --git a/cmd/bltest/tests/rsa_oaep/plaintext18 b/cmd/bltest/tests/rsa_oaep/plaintext18
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/plaintext18
-@@ -0,0 +1,1 @@
-+i”fÅ2¶Hà&:É?LžØ·Žš8Ï(’¥Öª
-\ No newline at end of file
-diff --git a/cmd/bltest/tests/rsa_oaep/plaintext19 b/cmd/bltest/tests/rsa_oaep/plaintext19
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/plaintext19
-@@ -0,0 +1,1 @@
-+¤ ü†^=Åò.‚ Fñ—-‚T/4<Ç/.öOÉ2%
-\ No newline at end of file
-diff --git a/cmd/bltest/tests/rsa_oaep/plaintext20 b/cmd/bltest/tests/rsa_oaep/plaintext20
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/plaintext20
-@@ -0,0 +1,1 @@
-+g§º¥éíὃ8ðÚ8Íød£Å¯d3“„ÄG‹
-\ No newline at end of file
-diff --git a/cmd/bltest/tests/rsa_oaep/plaintext21 b/cmd/bltest/tests/rsa_oaep/plaintext21
-new file mode 100644
---- /dev/null
-+++ b/cmd/bltest/tests/rsa_oaep/plaintext21
-@@ -0,0 +1,1 @@
-+)¾7 1 , copy g-> factor, return MP_COMPOSITE */
-+ if (mp_cmp_d(&g, 1) > 0) {
-+ if (factor) {
-+ mp_copy(&g, factor);
-+ }
-+ res = MP_COMPOSITE;
-+ goto CLEANUP;
-+ }
-+
-+ /* Compute z = (x ** m) mod a */
-+ MP_CHECKOK(mp_exptmod(&x, &m, a, &z));
-+
-+ if (mp_cmp_d(&z, 1) == 0 || mp_cmp(&z, &amo) == 0) {
-+ res = MP_PRIME;
-+ continue;
-+ }
-+
-+ res = MP_NOT_POWER; /* just in case the following for loop never executes. */
-+ for (jx = 1; jx < b; jx++) {
-+ /* xp = z */
-+ MP_CHECKOK(mp_copy(&z, &xp));
-+ /* z = z^2 (mod a) */
-+ MP_CHECKOK(mp_sqrmod(&z, a, &z));
-+ res = MP_NOT_POWER; /* previous line set res to MP_PRIME */
-+
-+ if (mp_cmp_d(&z, 1) == 0) {
-+ res = MP_COMPOSITE;
-+ break;
-+ }
-+ if (mp_cmp(&z, &amo) == 0) {
-+ res = MP_PRIME;
-+ break;
-+ }
-+ } /* end testing loop */
-+
-+ /* If the test passes, we will continue iterating, but a failed
-+ test means the candidate is definitely NOT prime, so we will
-+ immediately break out of this loop
-+ */
-+ if (res != MP_PRIME)
-+ break;
-+ } /* end iterations loop */
-+
-+ if (res == MP_PRIME) {
-+ goto CLEANUP;
-+ }
-+
-+ if (res == MP_NOT_POWER) {
-+ /* xp = z */
-+ MP_CHECKOK(mp_copy(&z, &xp));
-+ /* z = z^2 (mod a) */
-+ MP_CHECKOK(mp_sqrmod(&z, a, &z));
-+ /* if z != 1 xp=z */
-+ if (mp_cmp_d(&z, 1) != 0) {
-+ MP_CHECKOK(mp_copy(&z, &xp));
-+ }
-+ }
-+ res = MP_NOT_POWER;
-+
-+ /* g = GCD(xp-1,a) */
-+ MP_CHECKOK(mp_sub_d(&xp, 1, &xp));
-+ MP_CHECKOK(mp_gcd(&xp, a, &g));
-+ /* if g > 1 , copy g-> factor, return MP_COMPOSITE */
-+ if (mp_cmp_d(&g, 1) > 0) {
-+ if (factor) {
-+ mp_copy(&g, factor);
-+ }
-+ res = MP_COMPOSITE;
-+ goto CLEANUP;
-+ }
-+ res = MP_NOT_POWER;
-+
-+CLEANUP:
-+ mp_clear(&m);
-+ mp_clear(&z);
-+ mp_clear(&g);
-+ mp_clear(&xp);
-+ mp_clear(&x);
-+ mp_clear(&amo);
-+ return res;
-+
-+} /* end mpp_pprime() */
-+
- /* }}} */
-
- /* Produce table of composites from list of primes and trial value.
- ** trial must be odd. List of primes must not include 2.
- ** sieve should have dimension >= MAXPRIME/2, where MAXPRIME is largest
- ** prime in list of primes. After this function is finished,
- ** if sieve[i] is non-zero, then (trial + 2*i) is composite.
- ** Each prime used in the sieve costs one division of trial, and eliminates
-diff --git a/lib/freebl/mpi/mpprime.h b/lib/freebl/mpi/mpprime.h
---- a/lib/freebl/mpi/mpprime.h
-+++ b/lib/freebl/mpi/mpprime.h
-@@ -30,19 +30,21 @@ mp_err mpp_random_size(mp_int *a, mp_siz
- typedef mp_err (*mpp_random_fn)(mp_int *);
-
- /* Pseudo-primality testing */
- mp_err mpp_divis_vector(mp_int *a, const mp_digit *vec, int size, int *which);
- mp_err mpp_divis_primes(mp_int *a, mp_digit *np);
- mp_err mpp_fermat(mp_int *a, mp_digit w);
- mp_err mpp_fermat_list(mp_int *a, const mp_digit *primes, mp_size nPrimes);
- mp_err mpp_pprime(mp_int *a, int nt);
-+mp_err mpp_pprime_or_power(mp_int *a, mp_int *factor, int nt);
- mp_err mpp_sieve(mp_int *trial, const mp_digit *primes, mp_size nPrimes,
- unsigned char *sieve, mp_size nSieve);
- mp_err mpp_make_prime(mp_int *start, mp_size nBits, mp_size strong);
-
- /* Pseudo-primality tests using a user-provided mpp_random implementation */
- mp_err mpp_pprime_ext_random(mp_int *a, int nt, mpp_random_fn random);
-+mp_err mpp_pprime_or_power_ext_random(mp_int *a, mp_int *f, int nt, mpp_random_fn random);
- mp_err mpp_make_prime_ext_random(mp_int *start, mp_size nBits, mp_size strong, mpp_random_fn random);
-
- SEC_END_PROTOS
-
- #endif /* end _H_MP_PRIME_ */
-diff --git a/lib/freebl/rsapkcs.c b/lib/freebl/rsapkcs.c
---- a/lib/freebl/rsapkcs.c
-+++ b/lib/freebl/rsapkcs.c
-@@ -10,16 +10,17 @@
- #include "stubs.h"
- #endif
-
- #include "secerr.h"
-
- #include "blapi.h"
- #include "secitem.h"
- #include "blapii.h"
-+#include "secmpi.h"
-
- #define RSA_BLOCK_MIN_PAD_LEN 8
- #define RSA_BLOCK_FIRST_OCTET 0x00
- #define RSA_BLOCK_PRIVATE_PAD_OCTET 0xff
- #define RSA_BLOCK_AFTER_PAD_OCTET 0x00
-
- /*
- * RSA block types
-@@ -795,16 +796,86 @@ eme_oaep_encode(unsigned char *em,
- for (i = 0; i < hash->length; ++i)
- em[1 + i] ^= mask[i];
-
- PORT_ZFree(mask, dbMaskLen);
- return SECSuccess;
- }
-
- SECStatus
-+RSA_PartialVerify(RSAPublicKey *key)
-+{
-+ mp_int n, e, fact;
-+ mp_err err;
-+ SECStatus rv = SECSuccess;
-+ mp_int small_primes_product;
-+ /* this string is the NIST string *751, since the requirement is to detect up to prime 751
-+ * inclusive */
-+ const char *primes_product_decimal_string ="1090367704589007566035202161494385722019383400119651874476478760664145697976533387343668263403266024900638505861980470638958322454581550203448421495842767449796261170069732921897400657944793163960886418313690808872680411646815934535605444102983629208422567461571568587963766123806881456648026733413053968363611105";
-+
-+ /* modulus length check done by the FIPS indicator code */
-+ /* validate public exponent this test only succeeds if the exponent e is
-+ * 2^16 <= e < 2^256. e = 2^16 will be rejected below byte the iseven check */
-+ if (!key->publicExponent.data[0] || (key->publicExponent.len < 3) || (key->publicExponent.len > 32)) {
-+ PORT_SetError(SEC_ERROR_INVALID_KEY);
-+ return SECFailure;
-+ }
-+ /* convert to mpi for more detailed tests */
-+ MP_DIGITS(&n) = 0;
-+ MP_DIGITS(&e) = 0;
-+ MP_DIGITS(&fact) = 0;
-+ MP_DIGITS(&small_primes_product) = 0;
-+ CHECK_MPI_OK(mp_init(&n));
-+ CHECK_MPI_OK(mp_init(&e));
-+ CHECK_MPI_OK(mp_init(&small_primes_product));
-+ CHECK_MPI_OK(mp_init(&fact));
-+ SECITEM_TO_MPINT(key->modulus, &n);
-+ SECITEM_TO_MPINT(key->publicExponent, &e);
-+
-+ /* reject even exponents and moduluses */
-+ if (mp_iseven(&e) || mp_iseven(&n)) {
-+ err = MP_BADARG;
-+ goto cleanup;
-+ }
-+ /* check for componsite or power */
-+ err = mpp_pprime_or_power_secure(&n, NULL, 4);
-+ if (err != MP_NOT_POWER) {
-+ /* prime check succeeded, therefore modulus is not composite */
-+ /* or we found a factor, indicating that the modulus is probably
-+ * a power of a prime */
-+ err = MP_BADARG;
-+ goto cleanup;
-+ }
-+ /* check for small factors using gcd */
-+ CHECK_MPI_OK(mp_read_radix(&small_primes_product,
-+ primes_product_decimal_string, 10));
-+ CHECK_MPI_OK(mp_gcd(&n,&small_primes_product, &fact));
-+ if (mp_cmp_d(&fact, 1) != 0) {
-+ /* factor found, not a good modulus */
-+ err = MP_BADARG;
-+ goto cleanup;
-+ }
-+
-+cleanup:
-+ mp_clear(&n);
-+ mp_clear(&e);
-+ mp_clear(&small_primes_product);
-+ mp_clear(&fact);
-+ if (err) {
-+ PORT_SetError(SEC_ERROR_INVALID_KEY);
-+ rv = SECFailure;
-+ } else {
-+ /* if we are called again with this key, no need to verify
-+ * again */
-+ key->needVerify = PR_FALSE;
-+ }
-+ return rv;
-+}
-+
-+SECStatus
- RSA_EncryptOAEP(RSAPublicKey *key,
- HASH_HashType hashAlg,
- HASH_HashType maskHashAlg,
- const unsigned char *label,
- unsigned int labelLen,
- const unsigned char *seed,
- unsigned int seedLen,
- unsigned char *output,
-@@ -827,16 +898,25 @@ RSA_EncryptOAEP(RSAPublicKey *key,
- return SECFailure;
- }
-
- if ((labelLen == 0 && label != NULL) ||
- (labelLen > 0 && label == NULL)) {
- PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
- return SECFailure;
- }
-+ /* we only need to verify public keys once, and only in FIPS mode
-+ */
-+ if (key->needVerify) {
-+ rv = RSA_PartialVerify(key);
-+ if (rv != SECSuccess) {
-+ /* error code set by RSA_PartialVerify() */
-+ return rv;
-+ }
-+ }
-
- oaepEncoded = (unsigned char *)PORT_Alloc(modulusLen);
- if (oaepEncoded == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return SECFailure;
- }
- rv = eme_oaep_encode(oaepEncoded, modulusLen, input, inputLen,
- hashAlg, maskHashAlg, label, labelLen, seed, seedLen);
-diff --git a/lib/freebl/secmpi.c b/lib/freebl/secmpi.c
---- a/lib/freebl/secmpi.c
-+++ b/lib/freebl/secmpi.c
-@@ -17,12 +17,18 @@ mpp_random_secure(mp_int *a)
-
- mp_err
- mpp_pprime_secure(mp_int *a, int nt)
- {
- return mpp_pprime_ext_random(a, nt, &mpp_random_secure);
- }
-
- mp_err
-+mpp_pprime_or_power_secure(mp_int *a, mp_int *fact, int nt)
-+{
-+ return mpp_pprime_or_power_ext_random(a, fact, nt, &mpp_random_secure);
-+}
-+
-+mp_err
- mpp_make_prime_secure(mp_int *start, mp_size nBits, mp_size strong)
- {
- return mpp_make_prime_ext_random(start, nBits, strong, &mpp_random_secure);
- }
-diff --git a/lib/freebl/secmpi.h b/lib/freebl/secmpi.h
---- a/lib/freebl/secmpi.h
-+++ b/lib/freebl/secmpi.h
-@@ -54,10 +54,13 @@
- }
-
- /* Fill the `used` digits of an mp_int with random bits */
- mp_err mpp_random_secure(mp_int *a);
-
- /* Pseudo-primality testing using `mpp_random_secure` to choose Miller-Rabin base */
- mp_err mpp_pprime_secure(mp_int *a, int nt);
-
-+/* Pseudo-primality testing using `mpp_random_secure` to choose extended Miller-Rabin base */
-+mp_err mpp_pprime_or_power_secure(mp_int *a, mp_int *fact, int nt);
-+
- /* Variant of `mpp_make_prime` using `mpp_random_secure` to choose Miller-Rabin base */
- mp_err mpp_make_prime_secure(mp_int *start, mp_size nBits, mp_size strong);
-diff --git a/lib/softoken/fipstest.c b/lib/softoken/fipstest.c
---- a/lib/softoken/fipstest.c
-+++ b/lib/softoken/fipstest.c
-@@ -470,17 +470,18 @@ sftk_fips_RSA_PowerUpSelfTest(void)
- 0x66, 0xa6, 0x5e, 0x30, 0x0c, 0x82, 0xd5, 0x81
- };
-
- static const RSAPublicKey bl_public_key = {
- NULL,
- { FIPS_RSA_TYPE, (unsigned char *)rsa_modulus,
- FIPS_RSA_MODULUS_LENGTH },
- { FIPS_RSA_TYPE, (unsigned char *)rsa_public_exponent,
-- FIPS_RSA_PUBLIC_EXPONENT_LENGTH }
-+ FIPS_RSA_PUBLIC_EXPONENT_LENGTH },
-+ PR_FALSE,
- };
- static const RSAPrivateKey bl_private_key = {
- NULL,
- { FIPS_RSA_TYPE, (unsigned char *)rsa_version,
- FIPS_RSA_PRIVATE_VERSION_LENGTH },
- { FIPS_RSA_TYPE, (unsigned char *)rsa_modulus,
- FIPS_RSA_MODULUS_LENGTH },
- { FIPS_RSA_TYPE, (unsigned char *)rsa_public_exponent,
-diff --git a/lib/softoken/lowkey.c b/lib/softoken/lowkey.c
---- a/lib/softoken/lowkey.c
-+++ b/lib/softoken/lowkey.c
-@@ -309,16 +309,18 @@ nsslowkey_ConvertToPublicKey(NSSLOWKEYPr
- rv = SECITEM_CopyItem(arena, &pubk->u.rsa.modulus,
- &privk->u.rsa.modulus);
- if (rv == SECSuccess) {
- rv = SECITEM_CopyItem(arena, &pubk->u.rsa.publicExponent,
- &privk->u.rsa.publicExponent);
- if (rv == SECSuccess)
- return pubk;
- }
-+ /* this key was already verified fully as a private key */
-+ pubk->u.rsa.needVerify = PR_FALSE;
- } else {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- }
- break;
- case NSSLOWKEYDSAKey:
- pubk = (NSSLOWKEYPublicKey *)PORT_ArenaZAlloc(arena,
- sizeof(NSSLOWKEYPublicKey));
- if (pubk != NULL) {
-diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c
---- a/lib/softoken/pkcs11.c
-+++ b/lib/softoken/pkcs11.c
-@@ -2030,16 +2030,19 @@ sftk_GetPubKey(SFTKObject *object, CK_KE
- return NULL;
- }
-
- /* fill in the structure */
- pubKey->arena = arena;
- switch (key_type) {
- case CKK_RSA:
- pubKey->keyType = NSSLOWKEYRSAKey;
-+ /* if we claim the object is fix, then make sure it's verified
-+ * before we do an OAEP operation */
-+ pubKey->u.rsa.needVerify = object->isFIPS;
- crv = sftk_Attribute2SSecItem(arena, &pubKey->u.rsa.modulus,
- object, CKA_MODULUS);
- if (crv != CKR_OK)
- break;
- crv = sftk_Attribute2SSecItem(arena, &pubKey->u.rsa.publicExponent,
- object, CKA_PUBLIC_EXPONENT);
- break;
- case CKK_DSA:
-diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
---- a/lib/softoken/pkcs11c.c
-+++ b/lib/softoken/pkcs11c.c
-@@ -7370,16 +7370,18 @@ mldsa_next:
- crv = CKR_HOST_MEMORY;
- goto loser;
- }
- rv = SECITEM_CopyItem(arena, &pubk.u.rsa.publicExponent, &lpk->u.rsa.publicExponent);
- if (rv != SECSuccess) {
- crv = CKR_HOST_MEMORY;
- goto loser;
- }
-+ pubk.u.rsa.needVerify = PR_FALSE; /* We're just encoding the key from the
-+ * private key */
-
- if (SEC_ASN1EncodeItem(arena, &spki.subjectPublicKey,
- &pubk, nsslowkey_RSAPublicKeyTemplate) == NULL) {
- crv = CKR_HOST_MEMORY;
- goto loser;
- }
-
- publicKeyInfo = SEC_ASN1EncodeItem(arena, NULL,
-diff --git a/tests/cipher/cipher.sh b/tests/cipher/cipher.sh
---- a/tests/cipher/cipher.sh
-+++ b/tests/cipher/cipher.sh
-@@ -87,18 +87,18 @@ cipher_main()
- cipher_without_offset
- else
- inOff=0
- while [ $inOff -lt 8 ]
- do
- outOff=0
- while [ $outOff -lt 8 ]
- do
-- echo "bltest -T -m $PARAM -d $CIPHERTESTDIR -1 $inOff -2 $outOff"
-- ${PROFTOOL} ${BINDIR}/bltest${PROG_SUFFIX} -T -m $PARAM -d $CIPHERTESTDIR -1 $inOff -2 $outOff
-+ echo "bltest -T -m $PARAM -d $CIPHERTESTDIR -1 $inOff -2 $outOff -8"
-+ ${PROFTOOL} ${BINDIR}/bltest${PROG_SUFFIX} -T -m $PARAM -d $CIPHERTESTDIR -1 $inOff -2 $outOff -8
- if [ $? -ne 0 ]; then
- failedStr="$failedStr[$inOff:$outOff]"
- fi
- outOff=`expr $outOff + 1`
- done
- inOff=`expr $inOff + 1`
- done
- if [ -n "$failedStr" ]; then
diff --git a/nss-3.112-pkcs12-ml-dsa-crash-fix.patch b/nss-3.112-pkcs12-ml-dsa-crash-fix.patch
deleted file mode 100644
index 038dbc8..0000000
--- a/nss-3.112-pkcs12-ml-dsa-crash-fix.patch
+++ /dev/null
@@ -1,202 +0,0 @@
-# HG changeset patch
-# User Robert Relyea
-# Date 1767992040 28800
-# Fri Jan 09 12:54:00 2026 -0800
-# Branch RHEL10
-# Node ID 15f1129c29c037cce7913eb62c0eca06b5aa51d1
-# Parent 4bfb87c6e863957fc933e6dd5af8eae8a5cd0469
-nss-3.112-pkcs12-ml-dsa-crash-fix.patch
-
-diff --git a/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc b/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc
---- a/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc
-+++ b/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc
-@@ -7,16 +7,17 @@
- #include
- #include
- #include "nss.h"
- #include "pk11pub.h"
- #include "secutil.h"
-
- #include "gtest/gtest.h"
- #include "nss_scoped_ptrs.h"
-+#define SEC_OID_ML_DSA_44 SEC_OID_PRIVATE_3
-
- namespace nss_test {
-
- const std::vector kValidP256Key = {
- 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
- 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
- 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20,
- 0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57,
-@@ -133,16 +134,69 @@ class DERPrivateKeyImportTest : public :
- // no cert. This is expected, so clear it.
- if (PORT_GetError() == SSL_ERROR_NO_CERTIFICATE) {
- PORT_SetError(0);
- }
- }
-
- return rv == SECSuccess;
- }
-+
-+ SECStatus BuildPrivateKeyInfoAndImportIt(SECOidTag algTag) {
-+ ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
-+ EXPECT_TRUE(slot);
-+ if (!slot) {
-+ return SECFailure;
-+ }
-+
-+ ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
-+ EXPECT_TRUE(arena);
-+ if (!arena) {
-+ return SECFailure;
-+ }
-+
-+ SECKEYPrivateKeyInfo* pki = (SECKEYPrivateKeyInfo*)PORT_ArenaZAlloc(
-+ arena.get(), sizeof(SECKEYPrivateKeyInfo));
-+ EXPECT_TRUE(pki);
-+ if (!pki) {
-+ return SECFailure;
-+ }
-+
-+ pki->version.data = (unsigned char*)PORT_ArenaAlloc(arena.get(), 1);
-+ EXPECT_TRUE(pki->version.data);
-+ if (!pki->version.data) {
-+ return SECFailure;
-+ }
-+
-+ pki->version.data[0] = 0x00;
-+ pki->version.len = 1;
-+
-+ EXPECT_EQ(
-+ SECOID_SetAlgorithmID(arena.get(), &pki->algorithm, algTag, nullptr),
-+ SECSuccess);
-+
-+ // Empty private key
-+ pki->privateKey.data = (unsigned char*)PORT_ArenaAlloc(arena.get(), 1);
-+ EXPECT_TRUE(pki->privateKey.data);
-+ if (!pki->privateKey.data) {
-+ return SECFailure;
-+ }
-+ pki->privateKey.len = 0;
-+
-+ SECKEYPrivateKey* privk = nullptr;
-+ PORT_SetError(0);
-+ SECStatus rv = PK11_ImportPrivateKeyInfoAndReturnKey(
-+ slot.get(), pki, nullptr, nullptr, PR_FALSE, PR_FALSE, KU_ALL, &privk,
-+ nullptr);
-+
-+ if (privk) {
-+ SECKEY_DestroyPrivateKey(privk);
-+ }
-+ return rv;
-+ }
- };
-
- TEST_F(DERPrivateKeyImportTest, ImportPrivateRSAKey) {
- EXPECT_TRUE(ParsePrivateKey(kValidRSAKey, true));
- EXPECT_FALSE(PORT_GetError()) << PORT_GetError();
- }
-
- TEST_F(DERPrivateKeyImportTest, ImportEcdsaKey) {
-@@ -155,9 +209,15 @@ TEST_F(DERPrivateKeyImportTest, ImportIn
- EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_DER) << PORT_GetError();
- }
-
- TEST_F(DERPrivateKeyImportTest, ImportZeroLengthPrivateKey) {
- EXPECT_FALSE(ParsePrivateKey(kInvalidZeroLengthKey, false));
- EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_KEY) << PORT_GetError();
- }
-
-+TEST_F(DERPrivateKeyImportTest,
-+ ImportZeroLengthMLDSAPrivateKey) {
-+ EXPECT_EQ(BuildPrivateKeyInfoAndImportIt(SEC_OID_ML_DSA_44), SECFailure);
-+ EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_KEY);
-+}
-+
- } // namespace nss_test
-diff --git a/lib/pk11wrap/pk11pk12.c b/lib/pk11wrap/pk11pk12.c
---- a/lib/pk11wrap/pk11pk12.c
-+++ b/lib/pk11wrap/pk11pk12.c
-@@ -323,17 +323,17 @@ PK11_ImportDERPrivateKeyInfoAndReturnKey
- derPKI);
- if (rv != SECSuccess) {
- /* If SEC_ASN1DecodeItem fails, we cannot assume anything about the
- * validity of the data in pki. The best we can do is free the arena
- * and return. */
- PORT_FreeArena(temparena, PR_TRUE);
- return rv;
- }
-- if (pki->privateKey.data == NULL) {
-+ if (pki->privateKey.data == NULL || pki->privateKey.len == 0) {
- /* If SEC_ASN1DecodeItems succeeds but SECKEYPrivateKeyInfo.privateKey
- * is a zero-length octet string, free the arena and return a failure
- * to avoid trying to zero the corresponding SECItem in
- * SECKEY_DestroyPrivateKeyInfo(). */
- PORT_FreeArena(temparena, PR_TRUE);
- PORT_SetError(SEC_ERROR_BAD_KEY);
- return SECFailure;
- }
-@@ -753,16 +753,20 @@ PK11_ImportPrivateKeyInfoAndReturnKey(PK
- keyTemplate = SECKEY_ECPrivateKeyExportTemplate;
- paramTemplate = NULL;
- paramDest = NULL;
- lpk->keyType = ecKey;
- break;
- case SEC_OID_ML_DSA_44:
- case SEC_OID_ML_DSA_65:
- case SEC_OID_ML_DSA_87:
-+ if (pki->privateKey.data == NULL || pki->privateKey.len == 0) {
-+ PORT_SetError(SEC_ERROR_BAD_KEY);
-+ goto loser;
-+ }
- /* choice */
- switch (pki->privateKey.data[0]) {
- case SEC_ASN1_CONTEXT_SPECIFIC|0:
- keyTemplate = SECKEY_MLDSAPrivateKeySeedExportTemplate;
- break;
- case SEC_ASN1_OCTET_STRING:
- keyTemplate = SECKEY_MLDSAPrivateKeyKeyExportTemplate;
- break;
-diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
---- a/lib/softoken/pkcs11c.c
-+++ b/lib/softoken/pkcs11c.c
-@@ -5815,17 +5815,17 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
- }
- crv = NSC_Decapsulate(hSession, &mech, privateKey->handle,
- cipher_text, cipher_text_length, &template, 1,
- &key2);
- if (crv != CKR_OK) {
- goto kem_done;
- }
- if (!sftk_compareKeysEqual(hSession, key1, key2)) {
-- crv = CKR_DEVICE_ERROR;
-+ crv = CKR_GENERAL_ERROR;
- goto kem_done;
- }
- kem_done:
- /* PORT_Free already checks for NULL */
- PORT_Free(cipher_text);
- if (key1 != CK_INVALID_HANDLE) {
- NSC_DestroyObject(hSession, key1);
- }
-@@ -7105,16 +7105,20 @@ sftk_unwrapPrivateKey(SFTKObject *key, S
- paramSet = CKP_ML_DSA_44;
- goto mldsa_next;
- case SEC_OID_ML_DSA_65:
- paramSet = CKP_ML_DSA_65;
- goto mldsa_next;
- case SEC_OID_ML_DSA_87:
- paramSet = CKP_ML_DSA_87;
- mldsa_next:
-+ if (pki->privateKey.data == NULL || pki->privateKey.len == 0) {
-+ PORT_SetError(SEC_ERROR_BAD_KEY);
-+ goto loser;
-+ }
- switch (pki->privateKey.data[0]) {
- case SEC_ASN1_CONTEXT_SPECIFIC|0:
- keyTemplate = nsslowkey_PQSeedTemplate;
- break;
- case SEC_ASN1_OCTET_STRING:
- keyTemplate = nsslowkey_PQPrivateKeyTemplate;
- break;
- case SEC_ASN1_CONSTRUCTED|SEC_ASN1_SEQUENCE:
diff --git a/nss-3.112-replace-xyber-with-mlkem-256.patch b/nss-3.112-replace-xyber-with-mlkem-256.patch
deleted file mode 100644
index 49f8015..0000000
--- a/nss-3.112-replace-xyber-with-mlkem-256.patch
+++ /dev/null
@@ -1,4027 +0,0 @@
-diff -up ./cmd/lib/secutil.c.mlkem_p256 ./cmd/lib/secutil.c
---- ./cmd/lib/secutil.c.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./cmd/lib/secutil.c 2025-06-25 16:47:19.374362915 -0700
-@@ -4198,43 +4198,42 @@ SECU_ParseSSLVersionRangeString(const ch
- return SECSuccess;
- }
-
-+#define NAME_AND_LEN(s) sizeof(s)-1,s
-+static const struct SSLNamedGroupString {
-+ int len;
-+ char *name;
-+ SSLNamedGroup grp;
-+} sslNamedGroupStringArray[] = {
-+ { NAME_AND_LEN("P256"), ssl_grp_ec_secp256r1 },
-+ { NAME_AND_LEN("P384"), ssl_grp_ec_secp384r1 },
-+ { NAME_AND_LEN("P521"), ssl_grp_ec_secp521r1 },
-+ { NAME_AND_LEN("x25519"), ssl_grp_ec_curve25519 },
-+ { NAME_AND_LEN("FF2048"), ssl_grp_ffdhe_2048 },
-+ { NAME_AND_LEN("FF3072"), ssl_grp_ffdhe_3072 },
-+ { NAME_AND_LEN("FF4096"), ssl_grp_ffdhe_4096 },
-+ { NAME_AND_LEN("FF6144"), ssl_grp_ffdhe_6144 },
-+ { NAME_AND_LEN("FF8192"), ssl_grp_ffdhe_8192 },
-+#ifndef NSS_DISABLE_KYBER
-+ { NAME_AND_LEN("xyber76800"), ssl_grp_kem_xyber768d00 },
-+#endif
-+ { NAME_AND_LEN("mlkem768x25519"), ssl_grp_kem_mlkem768x25519 },
-+ { NAME_AND_LEN("mlkem768secp256r1"), ssl_grp_kem_secp256r1mlkem768 },
-+};
-+
-+static const size_t sslNamedGroupStringLen=PR_ARRAY_SIZE(sslNamedGroupStringArray);
-+
- static SSLNamedGroup
- groupNameToNamedGroup(char *name)
- {
-- if (PL_strlen(name) == 4) {
-- if (!strncmp(name, "P256", 4)) {
-- return ssl_grp_ec_secp256r1;
-- }
-- if (!strncmp(name, "P384", 4)) {
-- return ssl_grp_ec_secp384r1;
-- }
-- if (!strncmp(name, "P521", 4)) {
-- return ssl_grp_ec_secp521r1;
-- }
-- }
-- if (PL_strlen(name) == 6) {
-- if (!strncmp(name, "x25519", 6)) {
-- return ssl_grp_ec_curve25519;
-- }
-- if (!strncmp(name, "FF2048", 6)) {
-- return ssl_grp_ffdhe_2048;
-- }
-- if (!strncmp(name, "FF3072", 6)) {
-- return ssl_grp_ffdhe_3072;
-- }
-- if (!strncmp(name, "FF4096", 6)) {
-- return ssl_grp_ffdhe_4096;
-- }
-- if (!strncmp(name, "FF6144", 6)) {
-- return ssl_grp_ffdhe_6144;
-- }
-- if (!strncmp(name, "FF8192", 6)) {
-- return ssl_grp_ffdhe_8192;
-- }
-- }
-- if (PL_strlen(name) == 11) {
-- if (!strncmp(name, "xyber768d00", 11)) {
-- return ssl_grp_kem_xyber768d00;
-+ int len = PL_strlen(name);
-+ int i;
-+
-+ for (i=0; i < sslNamedGroupStringLen; i++) {
-+ const struct SSLNamedGroupString *ngs = &sslNamedGroupStringArray[i];
-+ if (len == ngs->len) {
-+ if (!strncmp(name, ngs->name, len)) {
-+ return ngs->grp;
-+ }
- }
- }
- if (PL_strlen(name) == 14) {
-@@ -4309,6 +4308,26 @@ done:
- return SECSuccess;
- }
-
-+const char *
-+SECU_NamedGroupToGroupName(SSLNamedGroup grp) {
-+ int i;
-+ static char unknownBuf[32];
-+
-+ if (grp == ssl_grp_none) {
-+ return "None";
-+ }
-+
-+ for (i=0; i < sslNamedGroupStringLen; i++) {
-+ const struct SSLNamedGroupString *ngs = &sslNamedGroupStringArray[i];
-+ if (grp == ngs->grp) {
-+ return ngs->name;
-+ }
-+ }
-+ snprintf(unknownBuf, sizeof(unknownBuf), "Unknown %d\n", grp);
-+
-+ return unknownBuf;
-+}
-+
- SSLSignatureScheme
- schemeNameToScheme(const char *name)
- {
-diff -up ./cmd/lib/secutil.h.mlkem_p256 ./cmd/lib/secutil.h
---- ./cmd/lib/secutil.h.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./cmd/lib/secutil.h 2025-06-25 16:47:19.374362915 -0700
-@@ -425,6 +425,8 @@ SECStatus parseGroupList(const char *arg
- SECStatus parseSigSchemeList(const char *arg,
- const SSLSignatureScheme **enabledSigSchemes,
- unsigned int *enabledSigSchemeCount);
-+const char *SECU_NamedGroupToGroupName(SSLNamedGroup grp);
-+
- typedef struct {
- SECItem label;
- PRBool hasContext;
-diff -up ./cmd/selfserv/selfserv.c.mlkem_p256 ./cmd/selfserv/selfserv.c
---- ./cmd/selfserv/selfserv.c.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./cmd/selfserv/selfserv.c 2025-06-25 16:47:19.374362915 -0700
-@@ -227,7 +227,11 @@ PrintParameterUsage()
- "-I comma separated list of enabled groups for TLS key exchange.\n"
- " The following values are valid:\n"
- " P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192,\n"
-- " xyber768d00, mlkem768x25519\n"
-+ " "
-+#ifndef NSS_DISABLE_KYBER
-+ "xyber768d00, "
-+#endif
-+ "mlkem768x25519, mlkem768secp256r1\n"
- "-J comma separated list of enabled signature schemes in preference order.\n"
- " The following values are valid:\n"
- " rsa_pkcs1_sha1, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,\n"
-@@ -410,9 +414,11 @@ printSecurityInfo(PRFileDesc *fd)
- channel.isFIPS ? " FIPS" : "");
- FPRINTF(stderr,
- "selfserv: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
-+ " Key Exchange Group:%s\n"
- " Compression: %s, Extended Master Secret: %s\n",
- channel.authKeyBits, suite.authAlgorithmName,
- channel.keaKeyBits, suite.keaTypeName,
-+ SECU_NamedGroupToGroupName(channel.keaGroup),
- channel.compressionMethodName,
- channel.extendedMasterSecretUsed ? "Yes" : "No");
- }
-diff -up ./cmd/strsclnt/strsclnt.c.mlkem_p256 ./cmd/strsclnt/strsclnt.c
---- ./cmd/strsclnt/strsclnt.c.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./cmd/strsclnt/strsclnt.c 2025-06-25 16:47:19.374362915 -0700
-@@ -298,9 +298,11 @@ printSecurityInfo(PRFileDesc *fd)
- channel.isFIPS ? " FIPS" : "");
- FPRINTF(stderr,
- "strsclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
-+ " Key Exchange Group:%s\n"
- " Compression: %s\n",
- channel.authKeyBits, suite.authAlgorithmName,
- channel.keaKeyBits, suite.keaTypeName,
-+ SECU_NamedGroupToGroupName(channel.keaGroup),
- channel.compressionMethodName);
- }
- }
-diff -up ./cmd/tstclnt/tstclnt.c.mlkem_p256 ./cmd/tstclnt/tstclnt.c
---- ./cmd/tstclnt/tstclnt.c.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./cmd/tstclnt/tstclnt.c 2025-06-25 16:47:19.374362915 -0700
-@@ -176,10 +176,12 @@ printSecurityInfo(PRFileDesc *fd)
- channel.isFIPS ? " FIPS" : "");
- FPRINTF(stderr,
- "tstclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
-+ " Key Exchange Group:%s\n"
- " Compression: %s, Extended Master Secret: %s\n"
- " Signature Scheme: %s\n",
- channel.authKeyBits, suite.authAlgorithmName,
- channel.keaKeyBits, suite.keaTypeName,
-+ SECU_NamedGroupToGroupName(channel.keaGroup),
- channel.compressionMethodName,
- channel.extendedMasterSecretUsed ? "Yes" : "No",
- signatureSchemeName(channel.signatureScheme));
-@@ -308,7 +310,11 @@ PrintParameterUsage()
- fprintf(stderr, "%-20s Comma separated list of enabled groups for TLS key exchange.\n"
- "%-20s The following values are valid:\n"
- "%-20s P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n"
-- "%-20s xyber768d00, mlkem768x25519\n",
-+ "%-20s "
-+#ifndef NSS_DISABLE_KYBER
-+ "xyber768d00, "
-+#endif
-+ "mlkem768x25519, mlkem768secp256r1\n",
- "-I", "", "", "");
- fprintf(stderr, "%-20s Comma separated list of signature schemes in preference order.\n"
- "%-20s The following values are valid:\n"
-diff -up ./coreconf/config.mk.mlkem_p256 ./coreconf/config.mk
---- ./coreconf/config.mk.mlkem_p256 2025-06-25 16:47:19.375362928 -0700
-+++ ./coreconf/config.mk 2025-06-25 16:51:23.790507978 -0700
-@@ -179,6 +179,10 @@ ifdef NSS_DISABLE_LIBPKIX
- DEFINES += -DNSS_DISABLE_LIBPKIX
- endif
-
-+ifdef NSS_DISABLE_KYBER
-+DEFINES += -DNSS_DISABLE_KYBER
-+endif
-+
- ifdef NSS_DISABLE_DBM
- DEFINES += -DNSS_DISABLE_DBM
- endif
-diff -up ./gtests/nss_bogo_shim/nss_bogo_shim.cc.mlkem_p256 ./gtests/nss_bogo_shim/nss_bogo_shim.cc
---- ./gtests/nss_bogo_shim/nss_bogo_shim.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/nss_bogo_shim/nss_bogo_shim.cc 2025-06-25 16:47:19.375362928 -0700
-@@ -435,6 +435,7 @@ class TestAgent {
- if (rv != SECSuccess) {
- return false;
- }
-+#ifndef NSS_DISABLE_KYBER
- // Xyber768 is disabled by policy by default, so if it's requested
- // we need to update the policy flags as well.
- for (auto group : groups) {
-@@ -442,6 +443,7 @@ class TestAgent {
- NSS_SetAlgorithmPolicy(SEC_OID_XYBER768D00, NSS_USE_ALG_IN_SSL_KX, 0);
- }
- }
-+#endif
- }
-
- return true;
-diff -up ./gtests/pk11_gtest/pk11_kem_unittest.cc.mlkem_p256 ./gtests/pk11_gtest/pk11_kem_unittest.cc
---- ./gtests/pk11_gtest/pk11_kem_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/pk11_gtest/pk11_kem_unittest.cc 2025-06-25 16:47:19.375362928 -0700
-@@ -140,7 +140,10 @@ TEST_P(Pkcs11KEMTest, KemConsistencyTest
- }
-
- INSTANTIATE_TEST_SUITE_P(Pkcs11KEMTest, Pkcs11KEMTest,
-- ::testing::Values(CKP_NSS_KYBER_768_ROUND3,
-- CKP_NSS_ML_KEM_768));
-+ ::testing::Values(
-+#ifndef NSS_DISABLE_KYBER
-+ CKP_NSS_KYBER_768_ROUND3,
-+#endif
-+ CKP_NSS_ML_KEM_768));
-
- } // namespace nss_test
-diff -up ./gtests/ssl_gtest/Makefile.mlkem_p256 ./gtests/ssl_gtest/Makefile
---- ./gtests/ssl_gtest/Makefile.mlkem_p256 2025-06-26 08:11:04.554368549 -0700
-+++ ./gtests/ssl_gtest/Makefile 2025-06-26 08:12:08.993988976 -0700
-@@ -42,6 +42,13 @@ else
- SSLKEYLOGFILE_FILES = $(NULL)
- endif
-
-+ifndef NSS_DISABLE_KYBER
-+XYBER_FILES = tls_xyber_unittest.cc
-+else
-+XYBER_FILES = $(NULL)
-+endif
-+
-+
- #######################################################################
- # (5) Execute "global" rules. (OPTIONAL) #
- #######################################################################
-diff -up ./gtests/ssl_gtest/manifest.mn.mlkem_p256 ./gtests/ssl_gtest/manifest.mn
---- ./gtests/ssl_gtest/manifest.mn.mlkem_p256 2025-06-25 16:47:19.358362709 -0700
-+++ ./gtests/ssl_gtest/manifest.mn 2025-06-25 16:53:27.033093823 -0700
-@@ -62,6 +62,6 @@ CPPSRCS = \
- tls_psk_unittest.cc \
- tls_subcerts_unittest.cc \
-- tls_xyber_unittest.cc \
-+ $(XYBER_FILES) \
- $(SSLKEYLOGFILE_FILES) \
- $(NULL)
-
-diff -up ./gtests/ssl_gtest/ssl_0rtt_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_0rtt_unittest.cc
---- ./gtests/ssl_gtest/ssl_0rtt_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/ssl_0rtt_unittest.cc 2025-06-25 16:47:19.375362928 -0700
-@@ -197,8 +197,9 @@ TEST_P(TlsZeroRttReplayTest, ZeroRttRepl
- TEST_P(TlsConnectTls13, ZeroRttOptionsSetLate) {
- ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
- Connect();
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- SendReceive(); // Need to read so that we absorb the session ticket.
-- CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
-+ CheckKeys();
- Reset();
- StartConnect();
- // Now turn on 0-RTT but too late for the ticket.
-diff -up ./gtests/ssl_gtest/ssl_auth_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_auth_unittest.cc
---- ./gtests/ssl_gtest/ssl_auth_unittest.cc.mlkem_p256 2025-06-25 16:47:19.368362838 -0700
-+++ ./gtests/ssl_gtest/ssl_auth_unittest.cc 2025-06-25 16:47:19.375362928 -0700
-@@ -54,6 +54,7 @@ TEST_P(TlsConnectTls12Plus, ServerAuthRs
- PR_ARRAY_SIZE(kSignatureSchemePss));
- server_->SetSignatureSchemes(kSignatureSchemePss,
- PR_ARRAY_SIZE(kSignatureSchemePss));
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- Connect();
- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_pss,
- ssl_sig_rsa_pss_pss_sha256);
-@@ -84,6 +85,7 @@ TEST_P(TlsConnectTls12Plus, ServerAuthRs
- PR_ARRAY_SIZE(kSignatureSchemePss));
- server_->SetSignatureSchemes(kSignatureSchemePss,
- PR_ARRAY_SIZE(kSignatureSchemePss));
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- Connect();
- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_pss,
- ssl_sig_rsa_pss_pss_sha256);
-@@ -947,7 +949,7 @@ TEST_P(TlsConnectClientAuth, ClientAuthE
- client_->SetupClientAuth(std::get<2>(GetParam()), true);
- server_->RequestClientAuth(true);
- Connect();
-- CheckKeys(ssl_kea_ecdh, ssl_auth_ecdsa);
-+ CheckKeys(ssl_auth_ecdsa);
- }
-
- TEST_P(TlsConnectClientAuth, ClientAuthWithEch) {
-@@ -960,7 +962,7 @@ TEST_P(TlsConnectClientAuth, ClientAuthW
- client_->SetupClientAuth(std::get<2>(GetParam()), true);
- server_->RequestClientAuth(true);
- Connect();
-- CheckKeys(ssl_kea_ecdh, ssl_auth_ecdsa);
-+ CheckKeys(ssl_auth_ecdsa);
- }
-
- TEST_P(TlsConnectClientAuth, ClientAuthBigRsa) {
-@@ -1304,14 +1306,14 @@ static const SSLSignatureScheme kSignatu
- static const SSLSignatureScheme kSignatureSchemeRsaSha256[] = {
- ssl_sig_rsa_pkcs1_sha256};
-
--static SSLNamedGroup NamedGroupForEcdsa384(uint16_t version) {
-+static SSLNamedGroup NamedGroupForEcdsa384(const TlsConnectTestBase *ctbase) {
- // NSS tries to match the group size to the symmetric cipher. In TLS 1.1 and
- // 1.0, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA is the highest priority suite, so
- // we use P-384. With TLS 1.2 on we pick AES-128 GCM so use x25519.
-- if (version <= SSL_LIBRARY_VERSION_TLS_1_1) {
-+ if (ctbase->GetVersion() <= SSL_LIBRARY_VERSION_TLS_1_1) {
- return ssl_grp_ec_secp384r1;
- }
-- return ssl_grp_ec_curve25519;
-+ return ctbase->GetDefaultGroupFromKEA(ctbase->GetDefaultKEA());
- }
-
- // When signature algorithms match up, this should connect successfully; even
-@@ -1323,7 +1325,7 @@ TEST_P(TlsConnectGeneric, SignatureAlgor
- server_->SetSignatureSchemes(kSignatureSchemeEcdsaSha384,
- PR_ARRAY_SIZE(kSignatureSchemeEcdsaSha384));
- Connect();
-- CheckKeys(ssl_kea_ecdh, NamedGroupForEcdsa384(version_), ssl_auth_ecdsa,
-+ CheckKeys(GetDefaultKEA(), NamedGroupForEcdsa384(this), ssl_auth_ecdsa,
- ssl_sig_ecdsa_secp384r1_sha384);
- }
-
-@@ -1342,7 +1344,7 @@ TEST_P(TlsConnectGeneric, SignatureAlgor
- SSL_SignaturePrefSet(client_->ssl_fd(), clientAlgorithms,
- PR_ARRAY_SIZE(clientAlgorithms)));
- Connect();
-- CheckKeys(ssl_kea_ecdh, NamedGroupForEcdsa384(version_), ssl_auth_ecdsa,
-+ CheckKeys(GetDefaultKEA(), NamedGroupForEcdsa384(this), ssl_auth_ecdsa,
- ssl_sig_ecdsa_secp384r1_sha384);
- }
-
-@@ -1353,7 +1355,7 @@ TEST_P(TlsConnectGeneric, SignatureAlgor
- server_->SetSignatureSchemes(kSignatureSchemeEcdsaSha384,
- PR_ARRAY_SIZE(kSignatureSchemeEcdsaSha384));
- Connect();
-- CheckKeys(ssl_kea_ecdh, NamedGroupForEcdsa384(version_), ssl_auth_ecdsa,
-+ CheckKeys(GetDefaultKEA(), NamedGroupForEcdsa384(this), ssl_auth_ecdsa,
- ssl_sig_ecdsa_secp384r1_sha384);
- }
-
-@@ -1445,6 +1447,7 @@ TEST_P(TlsConnectTls12, SignatureAlgorit
-
- TEST_P(TlsConnectTls13, UnsupportedSignatureSchemeAlert) {
- EnsureTlsSetup();
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- auto filter =
- MakeTlsFilter(server_, ssl_sig_none);
- filter->EnableDecryption();
-@@ -1456,6 +1459,8 @@ TEST_P(TlsConnectTls13, UnsupportedSigna
-
- TEST_P(TlsConnectTls13, InconsistentSignatureSchemeAlert) {
- EnsureTlsSetup();
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
-
- // This won't work because we use an RSA cert by default.
- auto filter = MakeTlsFilter(
-@@ -1603,6 +1608,7 @@ static SECStatus AuthCompleteBlock(TlsAg
- // processed by the client, SSL_AuthCertificateComplete() is called.
- TEST_F(TlsConnectDatagram13, AuthCompleteBeforeFinished) {
- client_->SetAuthCertificateCallback(AuthCompleteBlock);
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- MakeTlsFilter(server_, client_, [this]() {
- EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(), 0));
- });
-@@ -2036,8 +2042,7 @@ class TlsSignatureSchemeConfiguration
- EnsureTlsSetup();
- configPeer->SetSignatureSchemes(&signature_scheme_, 1);
- Connect();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, auth_type_,
-- signature_scheme_);
-+ CheckKeys(auth_type_, signature_scheme_);
- }
-
- std::string certificate_;
-@@ -2071,7 +2076,7 @@ TEST_P(TlsSignatureSchemeConfiguration,
- client_->SetSignatureSchemes(&signature_scheme_, 1);
- server_->SetSignatureSchemes(&signature_scheme_, 1);
- Connect();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, auth_type_, signature_scheme_);
-+ CheckKeys(auth_type_, signature_scheme_);
- }
-
- class Tls12CertificateRequestReplacer : public TlsHandshakeFilter {
-diff -up ./gtests/ssl_gtest/ssl_ciphersuite_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_ciphersuite_unittest.cc
---- ./gtests/ssl_gtest/ssl_ciphersuite_unittest.cc.mlkem_p256 2025-06-25 16:47:19.368362838 -0700
-+++ ./gtests/ssl_gtest/ssl_ciphersuite_unittest.cc 2025-06-25 16:47:19.375362928 -0700
-@@ -42,6 +42,7 @@ class TlsCipherSuiteTestBase : public Tl
- EXPECT_EQ(SECSuccess, rv);
- if (rv == SECSuccess) {
- std::cerr << "Cipher suite: " << csinfo_.cipherSuiteName << std::endl;
-+ std::cerr << "KEA: " << csinfo_.keaType << std::endl;
- }
- auth_type_ = csinfo_.authType;
- kea_type_ = csinfo_.keaType;
-diff -up ./gtests/ssl_gtest/ssl_damage_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_damage_unittest.cc
---- ./gtests/ssl_gtest/ssl_damage_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/ssl_damage_unittest.cc 2025-06-25 16:47:19.375362928 -0700
-@@ -60,6 +60,8 @@ TEST_F(TlsConnectTest, DamageSecretHandl
-
- TEST_P(TlsConnectGenericPre13, DamageServerSignature) {
- EnsureTlsSetup();
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- auto filter = MakeTlsFilter(
- server_, kTlsHandshakeServerKeyExchange);
- ExpectAlert(client_, kTlsAlertDecryptError);
-@@ -70,6 +72,8 @@ TEST_P(TlsConnectGenericPre13, DamageSer
-
- TEST_P(TlsConnectTls13, DamageServerSignature) {
- EnsureTlsSetup();
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- auto filter = MakeTlsFilter(
- server_, kTlsHandshakeCertificateVerify);
- filter->EnableDecryption();
-diff -up ./gtests/ssl_gtest/ssl_dhe_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_dhe_unittest.cc
---- ./gtests/ssl_gtest/ssl_dhe_unittest.cc.mlkem_p256 2025-06-25 16:47:19.368362838 -0700
-+++ ./gtests/ssl_gtest/ssl_dhe_unittest.cc 2025-06-25 16:47:19.375362928 -0700
-@@ -29,7 +29,7 @@ TEST_P(TlsConnectGeneric, ConnectDhe) {
-
- TEST_P(TlsConnectTls13, SharesForBothEcdheAndDhe) {
- EnsureTlsSetup();
-- client_->ConfigNamedGroups(kAllDHEGroups);
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-
- auto groups_capture =
- std::make_shared(client_, ssl_supported_groups_xtn);
-@@ -41,7 +41,7 @@ TEST_P(TlsConnectTls13, SharesForBothEcd
-
- Connect();
-
-- CheckKeys();
-+ CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
-
- bool ec, dh;
- auto track_group_type = [&ec, &dh](SSLNamedGroup group) {
-diff -up ./gtests/ssl_gtest/ssl_drop_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_drop_unittest.cc
---- ./gtests/ssl_gtest/ssl_drop_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/ssl_drop_unittest.cc 2025-06-25 16:47:19.375362928 -0700
-@@ -201,6 +201,8 @@ class TlsDropDatagram13 : public TlsConn
- // ACKs
- TEST_P(TlsDropDatagram13, DropClientFirstFlightOnce) {
- client_filters_.drop_->Reset({0});
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- StartConnect();
- client_->Handshake();
- server_->Handshake();
-@@ -210,6 +212,8 @@ TEST_P(TlsDropDatagram13, DropClientFirs
-
- TEST_P(TlsDropDatagram13, DropServerFirstFlightOnce) {
- server_filters_.drop_->Reset(0xff);
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- StartConnect();
- client_->Handshake();
- // Send the first flight, all dropped.
-@@ -224,6 +228,8 @@ TEST_P(TlsDropDatagram13, DropServerFirs
- // TODO(ekr@rtfm.com): We should generate an empty ACK.
- TEST_P(TlsDropDatagram13, DropServerFirstRecordOnce) {
- server_filters_.drop_->Reset({0});
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- StartConnect();
- client_->Handshake();
- server_->Handshake();
-@@ -236,6 +242,8 @@ TEST_P(TlsDropDatagram13, DropServerFirs
- // produce an ACK.
- TEST_P(TlsDropDatagram13, DropServerSecondRecordOnce) {
- server_filters_.drop_->Reset({1});
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- StartConnect();
- client_->Handshake();
- server_->Handshake();
-@@ -299,6 +307,8 @@ TEST_P(TlsDropDatagram13, DropClientCert
- // Shrink the MTU down so that certs get split and drop the first piece.
- TEST_P(TlsDropDatagram13, DropFirstHalfOfServerCertificate) {
- server_filters_.drop_->Reset({2});
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- StartConnect();
- ShrinkPostServerHelloMtu();
- client_->Handshake();
-@@ -326,6 +336,8 @@ TEST_P(TlsDropDatagram13, DropFirstHalfO
- // Shrink the MTU down so that certs get split and drop the second piece.
- TEST_P(TlsDropDatagram13, DropSecondHalfOfServerCertificate) {
- server_filters_.drop_->Reset({3});
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- StartConnect();
- ShrinkPostServerHelloMtu();
- client_->Handshake();
-@@ -414,6 +426,8 @@ class TlsFragmentationAndRecoveryTest :
-
- private:
- void FirstFlightDropCertificate() {
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- StartConnect();
- client_->Handshake();
-
-@@ -561,6 +575,8 @@ TEST_P(TlsDropDatagram13, NoDropsDuringZ
-
- TEST_P(TlsDropDatagram13, DropEEDuringZeroRtt) {
- SetupForZeroRtt();
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- SetFilters();
- std::cerr << "Starting second handshake" << std::endl;
- client_->Set0RttEnabled(true);
-@@ -606,6 +622,8 @@ class TlsReorderDatagram13 : public TlsD
- // of the flight and will still produce an ACK.
- TEST_P(TlsDropDatagram13, ReorderServerEE) {
- server_filters_.drop_->Reset({1});
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- StartConnect();
- client_->Handshake();
- server_->Handshake();
-@@ -684,6 +702,8 @@ TEST_F(TlsConnectDatagram13, SendOutOfOr
- // Shrink the MTU down so that certs get split and then swap the first and
- // second pieces of the server certificate.
- TEST_P(TlsReorderDatagram13, ReorderServerCertificate) {
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- StartConnect();
- ShrinkPostServerHelloMtu();
- client_->Handshake();
-diff -up ./gtests/ssl_gtest/ssl_ecdh_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_ecdh_unittest.cc
---- ./gtests/ssl_gtest/ssl_ecdh_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/ssl_ecdh_unittest.cc 2025-06-25 16:47:19.376362941 -0700
-@@ -490,7 +490,7 @@ TEST_P(TlsKeyExchangeTest13, EqualPriori
-
- Connect();
-
-- CheckKeys();
-+ CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
- const std::vector shares = {ssl_grp_ec_curve25519};
- CheckKEXDetails(client_groups, shares);
- }
-diff -up ./gtests/ssl_gtest/ssl_exporter_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_exporter_unittest.cc
---- ./gtests/ssl_gtest/ssl_exporter_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/ssl_exporter_unittest.cc 2025-06-25 16:47:19.376362941 -0700
-@@ -82,8 +82,11 @@ TEST_P(TlsConnectGenericPre13, ExporterC
- 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF};
-
- EnsureTlsSetup();
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- Connect();
-- CheckKeys();
-+ CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
-+
-
- static const size_t exporter_len = 10;
- uint8_t client_value[exporter_len] = {0};
-diff -up ./gtests/ssl_gtest/ssl_extension_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_extension_unittest.cc
---- ./gtests/ssl_gtest/ssl_extension_unittest.cc.mlkem_p256 2025-06-25 16:47:19.368362838 -0700
-+++ ./gtests/ssl_gtest/ssl_extension_unittest.cc 2025-06-25 16:47:19.376362941 -0700
-@@ -1314,6 +1314,9 @@ TEST_P(TlsDisallowedUnadvertisedExtensio
-
- TEST_P(TlsConnectStream, IncludePadding) {
- EnsureTlsSetup();
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
-+
- SSL_EnableTls13GreaseEch(client_->ssl_fd(), PR_FALSE); // Don't GREASE
-
- // This needs to be long enough to push a TLS 1.0 ClientHello over 255, but
-@@ -1372,7 +1375,7 @@ TEST_F(TlsConnectStreamTls13, ClientHell
- PR_TRUE) == SECSuccess);
- Connect();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
-+ CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_mlkem768x25519, ssl_auth_psk, ssl_sig_none);
- }
-
- /* This test checks that the ClientHello extension order is actually permuted
-diff -up ./gtests/ssl_gtest/ssl_gtest.gyp.mlkem_p256 ./gtests/ssl_gtest/ssl_gtest.gyp
---- ./gtests/ssl_gtest/ssl_gtest.gyp.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/ssl_gtest.gyp 2025-06-25 16:47:19.376362941 -0700
-@@ -63,7 +63,6 @@
- 'tls_protect.cc',
- 'tls_psk_unittest.cc',
- 'tls_subcerts_unittest.cc',
-- 'tls_xyber_unittest.cc',
- ],
- 'dependencies': [
- '<(DEPTH)/exports.gyp:nss_exports',
-diff -up ./gtests/ssl_gtest/ssl_hrr_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_hrr_unittest.cc
---- ./gtests/ssl_gtest/ssl_hrr_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/ssl_hrr_unittest.cc 2025-06-25 16:47:19.376362941 -0700
-@@ -22,6 +22,7 @@ TEST_P(TlsConnectTls13, HelloRetryReques
- const PRInt32 k0RttDataLen = static_cast(strlen(k0RttData));
-
- SetupForZeroRtt(); // initial handshake as normal
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-
- static const std::vector groups = {ssl_grp_ec_secp384r1,
- ssl_grp_ec_secp521r1};
-@@ -107,6 +108,7 @@ TEST_P(TlsConnectTls13, SecondClientHell
- auto orig_client =
- std::make_shared(client_->name(), TlsAgent::CLIENT, variant_);
- client_.swap(orig_client);
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_1,
- SSL_LIBRARY_VERSION_TLS_1_3);
- client_->ConfigureSessionCache(RESUME_BOTH);
-@@ -370,6 +372,7 @@ TEST_P(TlsConnectTls13, RetryCallbackRet
- size_t cb_called = 0;
- EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(server_->ssl_fd(),
- RetryHello, &cb_called));
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-
- // Do the first message exchange.
- StartConnect();
-@@ -417,6 +420,7 @@ TEST_P(TlsConnectTls13, RetryCallbackRet
- size_t cb_called = 0;
- EXPECT_EQ(SECSuccess, SSL_HelloRetryRequestCallback(server_->ssl_fd(),
- RetryHello, &cb_called));
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-
- // Do the first message exchange.
- StartConnect();
-@@ -950,7 +954,7 @@ TEST_P(TlsKeyExchange13, ConnectEcdhePre
- client_->ConfigNamedGroups(client_groups);
- server_->ConfigNamedGroups(server_groups);
- Connect();
-- CheckKeys();
-+ CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519);
- static const std::vector expectedShares = {
- ssl_grp_ec_secp384r1};
- CheckKEXDetails(client_groups, expectedShares, ssl_grp_ec_curve25519);
-@@ -997,7 +1001,7 @@ TEST_P(TlsKeyExchange13, ConnectEcdhePre
- EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
-
- Connect();
-- CheckKeys();
-+ CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519);
- CheckKEXDetails(client_groups, client_groups);
- }
-
-@@ -1043,7 +1047,7 @@ TEST_P(TlsKeyExchange13,
- EXPECT_EQ(2U, cb_called);
- EXPECT_TRUE(shares_capture2_->captured()) << "client should send shares";
-
-- CheckKeys();
-+ CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519);
- static const std::vector client_shares(
- client_groups.begin(), client_groups.begin() + 2);
- CheckKEXDetails(client_groups, client_shares, server_groups[0]);
-diff -up ./gtests/ssl_gtest/ssl_keyupdate_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_keyupdate_unittest.cc
---- ./gtests/ssl_gtest/ssl_keyupdate_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/ssl_keyupdate_unittest.cc 2025-06-25 16:47:19.376362941 -0700
-@@ -1180,6 +1180,8 @@ TEST_F(TlsConnectDatagram13, DTLSKU_Wron
-
- TEST_F(TlsConnectDatagram13, DTLSKU_DamagedLength) {
- EnsureTlsSetup();
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- // Filter replacing the length value with 0.
- auto filter = MakeTlsFilter(client_, 3, 0);
- filter->EnableDecryption();
-@@ -1217,6 +1219,8 @@ TEST_F(TlsConnectDatagram13, DTLSKU_Dama
-
- TEST_F(TlsConnectDatagram13, DTLSKU_DamagedFragmentLength) {
- EnsureTlsSetup();
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- // Filter replacing the fragment length with 1.
- auto filter = MakeTlsFilter(client_, 10, 1);
- filter->EnableDecryption();
-@@ -1498,4 +1502,4 @@ TEST_F(TlsConnectDatagram13, DTLSKU_TooE
- client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
- }
-
--} // namespace nss_test
-\ No newline at end of file
-+} // namespace nss_test
-diff -up ./gtests/ssl_gtest/ssl_loopback_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_loopback_unittest.cc
---- ./gtests/ssl_gtest/ssl_loopback_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/ssl_loopback_unittest.cc 2025-06-25 16:47:19.376362941 -0700
-@@ -37,7 +37,7 @@ TEST_P(TlsConnectGeneric, ConnectEcdsa)
- SetExpectedVersion(std::get<1>(GetParam()));
- Reset(TlsAgent::kServerEcdsa256);
- Connect();
-- CheckKeys(ssl_kea_ecdh, ssl_auth_ecdsa);
-+ CheckKeys(ssl_auth_ecdsa);
- }
-
- TEST_P(TlsConnectGeneric, CipherSuiteMismatch) {
-diff -up ./gtests/ssl_gtest/ssl_recordsep_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_recordsep_unittest.cc
---- ./gtests/ssl_gtest/ssl_recordsep_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/ssl_recordsep_unittest.cc 2025-06-25 16:47:19.376362941 -0700
-@@ -344,6 +344,8 @@ static void SendForwardReceive(std::shar
- }
-
- TEST_P(TlsConnectStream, ReplaceRecordLayer) {
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- StartConnect();
- client_->SetServerKeyBits(server_->server_key_bits());
-
-@@ -387,7 +389,7 @@ TEST_P(TlsConnectStream, ReplaceRecordLa
- client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTED);
- server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTED);
- }
-- CheckKeys();
-+ CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign); // why?
-
- // Reading and writing application data should work.
- SendForwardReceive(client_, client_stage, server_);
-@@ -445,6 +447,8 @@ static SECStatus AuthCompleteBlock(TlsAg
- }
-
- TEST_P(TlsConnectStream, ReplaceRecordLayerAsyncLateAuth) {
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- StartConnect();
- client_->SetServerKeyBits(server_->server_key_bits());
-
-@@ -494,7 +498,7 @@ TEST_P(TlsConnectStream, ReplaceRecordLa
- client_stage.ForwardAll(server_, TlsAgent::STATE_CONNECTED);
- server_stage.ForwardAll(client_, TlsAgent::STATE_CONNECTED);
- }
-- CheckKeys();
-+ CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign); // why?
-
- // Reading and writing application data should work.
- SendForwardReceive(client_, client_stage, server_);
-diff -up ./gtests/ssl_gtest/ssl_recordsize_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_recordsize_unittest.cc
---- ./gtests/ssl_gtest/ssl_recordsize_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/ssl_recordsize_unittest.cc 2025-06-25 16:47:19.376362941 -0700
-@@ -275,6 +275,7 @@ TEST_F(TlsConnectStreamTls13, ClientHell
- auto filter =
- MakeTlsFilter(client_, kTlsHandshakeClientHello);
-
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- // Add PSK with label long enough to push CH length into [256, 511].
- std::vector label(100);
- EXPECT_EQ(SECSuccess,
-@@ -723,4 +724,4 @@ TEST_P(TlsConnectGeneric, RecordSizeLimi
- }
- }
-
--} // namespace nss_test
-\ No newline at end of file
-+} // namespace nss_test
-diff -up ./gtests/ssl_gtest/ssl_resumption_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_resumption_unittest.cc
---- ./gtests/ssl_gtest/ssl_resumption_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/ssl_resumption_unittest.cc 2025-06-25 16:47:19.376362941 -0700
-@@ -175,11 +175,15 @@ TEST_P(TlsConnectGenericResumption, Conn
- TEST_P(TlsConnectGenericPre13, ResumeWithHigherVersionTls13) {
- uint16_t lower_version = version_;
- ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- Connect();
- SendReceive();
- CheckKeys();
-
- Reset();
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
- EnsureTlsSetup();
- auto psk_ext = std::make_shared(
-@@ -244,6 +248,8 @@ TEST_P(TlsConnectGenericPre13, ResumeWit
- // connection. This looks like compatibility mode, we just want to ensure
- // that we get TLS 1.3 rather than 1.2 (and no resumption).
- Reset();
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- auto client_sid = MakeTlsFilter(client_);
- auto server_sid = MakeTlsFilter(server_);
- ConfigureSessionCache(RESUME_SESSIONID, RESUME_SESSIONID);
-@@ -359,12 +365,14 @@ TEST_P(TlsConnectGenericResumption, Conn
- TEST_P(TlsConnectGeneric, ConnectWithExpiredTicketAtServer) {
- // This causes a ticket resumption.
- ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- Connect();
- SendReceive();
-
- Reset();
- ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
- ExpectResumption(RESUME_NONE);
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-
- SSLExtensionType xtn = (version_ >= SSL_LIBRARY_VERSION_TLS_1_3)
- ? ssl_tls13_pre_shared_key_xtn
-@@ -453,7 +461,7 @@ TEST_P(TlsConnectGeneric, ServerSNICertT
- Connect();
- ScopedCERTCertificate cert2(SSL_PeerCertificate(client_->ssl_fd()));
- ASSERT_NE(nullptr, cert2.get());
-- CheckKeys(ssl_kea_ecdh, ssl_auth_ecdsa);
-+ CheckKeys(ssl_auth_ecdsa);
- EXPECT_TRUE(SECITEM_ItemsAreEqual(&cert1->derCert, &cert2->derCert));
- }
-
-@@ -613,7 +621,7 @@ TEST_P(TlsConnectGenericResumption, Resu
- client_->EnableSingleCipher(ChooseOneCipher(version_));
- Connect();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
-+ CheckKeys(ssl_auth_rsa_sign);
-
- Reset();
- ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
-@@ -628,7 +636,7 @@ TEST_P(TlsConnectGenericResumption, Resu
- auto ticket_capture =
- MakeTlsFilter(client_, ticket_extension);
- Connect();
-- CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
-+ CheckKeys(ssl_auth_rsa_sign);
- EXPECT_EQ(0U, ticket_capture->extension().len());
- }
-
-@@ -655,7 +663,7 @@ TEST_P(TlsConnectStream, ResumptionOverr
- server_->EnableSingleCipher(ChooseOneCipher(version_));
- Connect();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
-+ CheckKeys();
-
- Reset();
- ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
-@@ -793,8 +801,7 @@ TEST_F(TlsConnectTest, TestTls13Resumpti
- MakeTlsFilter(client_, ssl_tls13_pre_shared_key_xtn);
- Connect();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
-- ssl_sig_rsa_pss_rsae_sha256);
-+ CheckKeys(ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
- // The filter will go away when we reset, so save the captured extension.
- DataBuffer initialTicket(c1->extension());
- ASSERT_LT(0U, initialTicket.len());
-@@ -811,8 +818,7 @@ TEST_F(TlsConnectTest, TestTls13Resumpti
- ExpectResumption(RESUME_TICKET);
- Connect();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
-- ssl_sig_rsa_pss_rsae_sha256);
-+ CheckKeys(ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
- ASSERT_LT(0U, c2->extension().len());
-
- ScopedCERTCertificate cert2(SSL_PeerCertificate(client_->ssl_fd()));
-@@ -1089,7 +1095,7 @@ TEST_F(TlsConnectTest, TestTls13Resumpti
- Handshake();
-
- SendReceive();
-- CheckKeys();
-+ CheckKeys(ssl_kea_ecdh);
- }
-
- TEST_F(TlsConnectTest, TestTls13ResumptionForcedDowngrade) {
-@@ -1144,15 +1150,15 @@ TEST_P(TlsConnectGenericResumption, ReCo
- server_->EnableSingleCipher(ChooseOneCipher(version_));
- Connect();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
-- ssl_sig_rsa_pss_rsae_sha256);
-+ CheckKeys(ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
- // Resume
- Reset();
- ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
- ExpectResumption(RESUME_TICKET);
- Connect();
- // Only the client knows this.
-- CheckKeysResumption(ssl_kea_ecdh, ssl_grp_none, ssl_grp_ec_curve25519,
-+ CheckKeysResumption(GetDefaultKEA(), ssl_grp_none,
-+ GetDefaultGroupFromKEA(GetDefaultKEA()),
- ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
- }
-
-@@ -1161,13 +1167,13 @@ TEST_P(TlsConnectGenericPre13, ReConnect
- server_->EnableSingleCipher(ChooseOneCipher(version_));
- Connect();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
-- ssl_sig_rsa_pss_rsae_sha256);
-+ CheckKeys(ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
- // Resume
- Reset();
- ExpectResumption(RESUME_SESSIONID);
- Connect();
-- CheckKeysResumption(ssl_kea_ecdh, ssl_grp_none, ssl_grp_ec_curve25519,
-+ CheckKeysResumption(GetDefaultKEA(), ssl_grp_none,
-+ GetDefaultGroupFromKEA(GetDefaultKEA()),
- ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
- }
-
-@@ -1176,15 +1182,15 @@ TEST_P(TlsConnectGenericResumption, ReCo
- server_->EnableSingleCipher(ChooseOneCipher(version_));
- Connect();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
-- ssl_sig_rsa_pss_rsae_sha256);
-+ CheckKeys(ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
- // Resume
- Reset();
- ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
- ExpectResumption(RESUME_TICKET);
- Connect();
- // Only the client knows this.
-- CheckKeysResumption(ssl_kea_ecdh, ssl_grp_none, ssl_grp_ec_curve25519,
-+ CheckKeysResumption(GetDefaultKEA(), ssl_grp_none,
-+ GetDefaultGroupFromKEA(GetDefaultKEA()),
- ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
- // Resume connection again
- Reset();
-@@ -1192,7 +1198,8 @@ TEST_P(TlsConnectGenericResumption, ReCo
- ExpectResumption(RESUME_TICKET, 2);
- Connect();
- // Only the client knows this.
-- CheckKeysResumption(ssl_kea_ecdh, ssl_grp_none, ssl_grp_ec_curve25519,
-+ CheckKeysResumption(GetDefaultKEA(), ssl_grp_none,
-+ GetDefaultGroupFromKEA(GetDefaultKEA()),
- ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
- }
-
-@@ -1219,11 +1226,15 @@ void CheckGetInfoResult(PRTime now, uint
- // when resuming using an external token.
- TEST_P(TlsConnectGenericResumptionToken, CheckSessionId) {
- ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- auto original_sid = MakeTlsFilter(client_);
- Connect();
- SendReceive();
-
- Reset();
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
- ExpectResumption(RESUME_TICKET);
-
-diff -up ./gtests/ssl_gtest/ssl_skip_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_skip_unittest.cc
---- ./gtests/ssl_gtest/ssl_skip_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/ssl_skip_unittest.cc 2025-06-25 16:47:19.376362941 -0700
-@@ -114,6 +114,9 @@ class Tls13SkipTest : public TlsConnectT
- void SetUp() override {
- TlsConnectTestBase::SetUp();
- EnsureTlsSetup();
-+ // until we can fix filters to work with MLKEM
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
-+ server_->ConfigNamedGroups(kNonPQDHEGroups);
- }
-
- void ServerSkipTest(std::shared_ptr filter, int32_t error) {
-diff -up ./gtests/ssl_gtest/ssl_tls13compat_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_tls13compat_unittest.cc
---- ./gtests/ssl_gtest/ssl_tls13compat_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/ssl_tls13compat_unittest.cc 2025-06-25 16:47:19.377362953 -0700
-@@ -482,6 +482,7 @@ TEST_F(TlsConnectDatagram13, CompatModeD
- client_->SetOption(SSL_ENABLE_TLS13_COMPAT_MODE, PR_TRUE);
- auto client_records = MakeTlsFilter(client_);
- auto server_records = MakeTlsFilter(server_);
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- Connect();
-
- ASSERT_EQ(2U, client_records->count()); // CH, Fin
-@@ -522,6 +523,7 @@ class AddSessionIdFilter : public TlsHan
- // mode. It should be ignored instead.
- TEST_F(TlsConnectDatagram13, CompatModeDtlsServer) {
- EnsureTlsSetup();
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- auto client_records = std::make_shared(client_);
- client_->SetFilter(
- std::make_shared(ChainedPacketFilterInit(
-diff -up ./gtests/ssl_gtest/ssl_version_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/ssl_version_unittest.cc
---- ./gtests/ssl_gtest/ssl_version_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/ssl_version_unittest.cc 2025-06-25 16:47:19.377362953 -0700
-@@ -370,6 +370,7 @@ TEST_F(DtlsConnectTest, DtlsSupportedVer
- SSL_LIBRARY_VERSION_TLS_1_3);
- auto capture = MakeTlsFilter(
- client_, ssl_tls13_supported_versions_xtn);
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- Connect();
-
- ASSERT_EQ(7U, capture->extension().len());
-@@ -393,6 +394,7 @@ TEST_F(DtlsConnectTest, Dtls13VersionWor
-
- // Toggle the workaround, then verify both encodings are present.
- EnsureTlsSetup();
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- SSL_SetDtls13VersionWorkaround(client_->ssl_fd(), PR_TRUE);
- SSL_SetDtls13VersionWorkaround(client_->ssl_fd(), PR_FALSE);
- SSL_SetDtls13VersionWorkaround(client_->ssl_fd(), PR_TRUE);
-diff -up ./gtests/ssl_gtest/tls_agent.cc.mlkem_p256 ./gtests/ssl_gtest/tls_agent.cc
---- ./gtests/ssl_gtest/tls_agent.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/tls_agent.cc 2025-06-25 16:47:19.377362953 -0700
-@@ -522,12 +522,25 @@ const std::vector kAllDHE
- ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
- ssl_grp_ec_secp521r1, ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072,
- ssl_grp_ffdhe_4096, ssl_grp_ffdhe_6144, ssl_grp_ffdhe_8192,
-- ssl_grp_kem_xyber768d00, ssl_grp_kem_mlkem768x25519,
-+#ifndef NSS_DISABLE_KYBER
-+ ssl_grp_kem_xyber768d00,
-+#endif
-+ ssl_grp_kem_mlkem768x25519, ssl_grp_kem_secp256r1mlkem768,
-+};
-+
-+const std::vector kNonPQDHEGroups = {
-+ ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
-+ ssl_grp_ec_secp521r1, ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072,
-+ ssl_grp_ffdhe_4096, ssl_grp_ffdhe_6144, ssl_grp_ffdhe_8192,
- };
-
- const std::vector kECDHEGroups = {
- ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
-- ssl_grp_ec_secp521r1, ssl_grp_kem_xyber768d00, ssl_grp_kem_mlkem768x25519,
-+ ssl_grp_ec_secp521r1,
-+#ifndef NSS_DISABLE_KYBER
-+ ssl_grp_kem_xyber768d00,
-+#endif
-+ ssl_grp_kem_mlkem768x25519, ssl_grp_kem_secp256r1mlkem768
- };
-
- const std::vector kFFDHEGroups = {
-@@ -537,13 +550,19 @@ const std::vector kFFDHEG
- // Defined because the big DHE groups are ridiculously slow.
- const std::vector kFasterDHEGroups = {
- ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
-- ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072, ssl_grp_kem_xyber768d00,
-- ssl_grp_kem_mlkem768x25519,
-+ ssl_grp_ffdhe_2048, ssl_grp_ffdhe_3072,
-+#ifndef NSS_DISABLE_KYBER
-+ ssl_grp_kem_xyber768d00,
-+#endif
-+ ssl_grp_kem_mlkem768x25519, ssl_grp_kem_secp256r1mlkem768,
- };
-
- const std::vector kEcdhHybridGroups = {
-+#ifndef NSS_DISABLE_KYBER
- ssl_grp_kem_xyber768d00,
-+#endif
- ssl_grp_kem_mlkem768x25519,
-+ ssl_grp_kem_secp256r1mlkem768,
- };
-
- void TlsAgent::EnableCiphersByKeyExchange(SSLKEAType kea) {
-@@ -711,11 +730,14 @@ void TlsAgent::CheckKEA(SSLKEAType kea,
- if (kea_size == 0) {
- switch (kea_group) {
- case ssl_grp_ec_curve25519:
-+#ifndef NSS_DISABLE_KYBER
- case ssl_grp_kem_xyber768d00:
-+#endif
- case ssl_grp_kem_mlkem768x25519:
- kea_size = 255;
- break;
- case ssl_grp_ec_secp256r1:
-+ case ssl_grp_kem_secp256r1mlkem768:
- kea_size = 256;
- break;
- case ssl_grp_ec_secp384r1:
-@@ -1344,6 +1366,10 @@ void TlsAgentTestBase::Reset(const std::
- if (version_) {
- agent_->SetVersionRange(version_, version_);
- }
-+ const std::vector groups = {
-+ ssl_grp_ec_curve25519, ssl_grp_ec_secp256r1, ssl_grp_ec_secp384r1,
-+ ssl_grp_ffdhe_2048};
-+ agent_->ConfigNamedGroups(groups);
- agent_->adapter()->SetPeer(sink_adapter_);
- agent_->StartConnect();
- }
-diff -up ./gtests/ssl_gtest/tls_agent.h.mlkem_p256 ./gtests/ssl_gtest/tls_agent.h
---- ./gtests/ssl_gtest/tls_agent.h.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/tls_agent.h 2025-06-25 16:47:19.377362953 -0700
-@@ -52,6 +52,7 @@ class TlsCipherSpec;
- struct TlsRecord;
-
- const extern std::vector kAllDHEGroups;
-+const extern std::vector kNonPQDHEGroups;
- const extern std::vector kECDHEGroups;
- const extern std::vector kFFDHEGroups;
- const extern std::vector kFasterDHEGroups;
-diff -up ./gtests/ssl_gtest/tls_connect.cc.mlkem_p256 ./gtests/ssl_gtest/tls_connect.cc
---- ./gtests/ssl_gtest/tls_connect.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/tls_connect.cc 2025-06-25 16:47:19.377362953 -0700
-@@ -505,21 +505,23 @@ void TlsConnectTestBase::CheckEarlyDataL
- EXPECT_EQ(expected_size, static_cast(preinfo.maxEarlyDataSize));
- }
-
--void TlsConnectTestBase::CheckKeys(SSLKEAType kea_type, SSLNamedGroup kea_group,
-- SSLAuthType auth_type,
-- SSLSignatureScheme sig_scheme) const {
-- if (kea_group != ssl_grp_none) {
-- client_->CheckKEA(kea_type, kea_group);
-- server_->CheckKEA(kea_type, kea_group);
-+SSLKEAType TlsConnectTestBase::GetDefaultKEA(void) const {
-+ if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
-+ return ssl_kea_ecdh_hybrid;
- }
-- server_->CheckAuthType(auth_type, sig_scheme);
-- client_->CheckAuthType(auth_type, sig_scheme);
-+ return ssl_kea_ecdh;
- }
-
--void TlsConnectTestBase::CheckKeys(SSLKEAType kea_type,
-- SSLAuthType auth_type) const {
-+SSLAuthType TlsConnectTestBase::GetDefaultAuth(void) const {
-+ return ssl_auth_rsa_sign;
-+}
-+
-+SSLNamedGroup TlsConnectTestBase::GetDefaultGroupFromKEA(SSLKEAType kea_type) const {
- SSLNamedGroup group;
- switch (kea_type) {
-+ case ssl_kea_ecdh_hybrid:
-+ group = ssl_grp_kem_mlkem768x25519;
-+ break;
- case ssl_kea_ecdh:
- group = ssl_grp_ec_curve25519;
- break;
-@@ -534,7 +536,10 @@ void TlsConnectTestBase::CheckKeys(SSLKE
- group = ssl_grp_none;
- break;
- }
-+ return group;
-+}
-
-+SSLSignatureScheme TlsConnectTestBase::GetDefaultSchemeFromAuth(SSLAuthType auth_type) const {
- SSLSignatureScheme scheme;
- switch (auth_type) {
- case ssl_auth_rsa_decrypt:
-@@ -561,11 +566,54 @@ void TlsConnectTestBase::CheckKeys(SSLKE
- scheme = static_cast(0x0100);
- break;
- }
-+ return scheme;
-+}
-+void TlsConnectTestBase::CheckKeys(SSLKEAType kea_type, SSLNamedGroup kea_group,
-+ SSLAuthType auth_type,
-+ SSLSignatureScheme sig_scheme) const {
-+ if (kea_group != ssl_grp_none) {
-+ client_->CheckKEA(kea_type, kea_group);
-+ server_->CheckKEA(kea_type, kea_group);
-+ }
-+ server_->CheckAuthType(auth_type, sig_scheme);
-+ client_->CheckAuthType(auth_type, sig_scheme);
-+}
-+
-+void TlsConnectTestBase::CheckKeys(SSLKEAType kea_type,
-+ SSLNamedGroup kea_group) const {
-+ SSLAuthType auth_type = GetDefaultAuth();
-+ SSLSignatureScheme scheme = GetDefaultSchemeFromAuth(auth_type);
-+ CheckKeys(kea_type, kea_group, auth_type, scheme);
-+}
-+
-+void TlsConnectTestBase::CheckKeys( SSLAuthType auth_type,
-+ SSLSignatureScheme sig_scheme) const {
-+ SSLKEAType kea_type = GetDefaultKEA();
-+ SSLNamedGroup group = GetDefaultGroupFromKEA(kea_type);
-+ CheckKeys(kea_type, group, auth_type, sig_scheme);
-+}
-+
-+void TlsConnectTestBase::CheckKeys(SSLKEAType kea_type,
-+ SSLAuthType auth_type) const {
-+ SSLNamedGroup group = GetDefaultGroupFromKEA(kea_type);
-+ SSLSignatureScheme scheme = GetDefaultSchemeFromAuth(auth_type);
- CheckKeys(kea_type, group, auth_type, scheme);
- }
-
-+void TlsConnectTestBase::CheckKeys(SSLKEAType kea_type) const {
-+ SSLAuthType auth_type = GetDefaultAuth();
-+ CheckKeys(kea_type, auth_type);
-+}
-+
-+void TlsConnectTestBase::CheckKeys(SSLAuthType auth_type) const {
-+ SSLKEAType kea_type = GetDefaultKEA();
-+ CheckKeys(kea_type, auth_type);
-+}
-+
- void TlsConnectTestBase::CheckKeys() const {
-- CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
-+ SSLKEAType kea_type = GetDefaultKEA();
-+ SSLAuthType auth_type = GetDefaultAuth();
-+ CheckKeys(kea_type, auth_type);
- }
-
- void TlsConnectTestBase::CheckKeysResumption(SSLKEAType kea_type,
-diff -up ./gtests/ssl_gtest/tls_connect.h.mlkem_p256 ./gtests/ssl_gtest/tls_connect.h
---- ./gtests/ssl_gtest/tls_connect.h.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/tls_connect.h 2025-06-25 16:47:19.377362953 -0700
-@@ -83,11 +83,23 @@ class TlsConnectTestBase : public ::test
- void ConnectWithCipherSuite(uint16_t cipher_suite);
- void CheckEarlyDataLimit(const std::shared_ptr& agent,
- size_t expected_size);
-+ // Get the default KEA for our tls version
-+ SSLKEAType GetDefaultKEA(void) const;
-+ // Get the default auth for our tls version
-+ SSLAuthType GetDefaultAuth(void) const;
-+ // Find the default group for a given KEA
-+ SSLNamedGroup GetDefaultGroupFromKEA(SSLKEAType kea_type) const;
-+ // Find the default scheam for a given auth
-+ SSLSignatureScheme GetDefaultSchemeFromAuth(SSLAuthType auth_type) const;
- // Check that the keys used in the handshake match expectations.
- void CheckKeys(SSLKEAType kea_type, SSLNamedGroup kea_group,
- SSLAuthType auth_type, SSLSignatureScheme sig_scheme) const;
-- // This version guesses some of the values.
-+ // These version guesses some of the values.
-+ void CheckKeys(SSLKEAType kea_type, SSLNamedGroup kea_group) const;
-+ void CheckKeys(SSLAuthType auth_type, SSLSignatureScheme sig_scheme) const;
- void CheckKeys(SSLKEAType kea_type, SSLAuthType auth_type) const;
-+ void CheckKeys(SSLKEAType kea_type) const;
-+ void CheckKeys(SSLAuthType auth_type) const;
- // This version assumes defaults.
- void CheckKeys() const;
- // Check that keys on resumed sessions.
-@@ -103,6 +115,7 @@ class TlsConnectTestBase : public ::test
-
- void ConfigureVersion(uint16_t version);
- void SetExpectedVersion(uint16_t version);
-+ uint16_t GetVersion(void) const { return version_; };
- // Expect resumption of a particular type.
- void ExpectResumption(SessionResumptionMode expected,
- uint8_t num_resumed = 1);
-diff -up ./gtests/ssl_gtest/tls_ech_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/tls_ech_unittest.cc
---- ./gtests/ssl_gtest/tls_ech_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/tls_ech_unittest.cc 2025-06-25 16:47:19.377362953 -0700
-@@ -1106,7 +1106,7 @@ TEST_F(TlsConnectStreamTls13, EchAcceptW
- Handshake();
- CheckConnected();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
-+ CheckKeys(ssl_auth_psk, ssl_sig_none);
- // The PSK extension is present in CHOuter.
- ASSERT_TRUE(filter->captured());
-
-diff -up ./gtests/ssl_gtest/tls_mlkem_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/tls_mlkem_unittest.cc
---- ./gtests/ssl_gtest/tls_mlkem_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/tls_mlkem_unittest.cc 2025-06-25 16:47:19.377362953 -0700
-@@ -7,6 +7,7 @@
- #include "ssl.h"
- #include "sslerr.h"
- #include "sslproto.h"
-+#include "secmodti.h" /* for SEC_OID_SECP256R1MLKEM768, remove when shipped upstream */
-
- extern "C" {
- // This is not something that should make you happy.
-@@ -30,7 +31,16 @@ TEST_P(TlsKeyExchangeTest13, Mlkem768x25
- ssl_sig_rsa_pss_rsae_sha256);
- }
-
--TEST_P(TlsKeyExchangeTest, Tls12ClientMlkem768x25519NotSupported) {
-+TEST_P(TlsKeyExchangeTest13, Mlkem768Secp256r1Supported) {
-+ EnsureKeyShareSetup();
-+ ConfigNamedGroups({ssl_grp_kem_secp256r1mlkem768});
-+
-+ Connect();
-+ CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_secp256r1mlkem768,
-+ ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
-+}
-+
-+TEST_P(TlsKeyExchangeTest, Tls12ClientMlkem768StartNotSupported) {
- EnsureKeyShareSetup();
- client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
- SSL_LIBRARY_VERSION_TLS_1_2);
-@@ -47,6 +57,7 @@ TEST_P(TlsKeyExchangeTest, Tls12ClientMl
- std::vector groups = GetGroupDetails(groups_capture_);
- for (auto group : groups) {
- EXPECT_NE(group, ssl_grp_kem_mlkem768x25519);
-+ EXPECT_NE(group, ssl_grp_kem_secp256r1mlkem768);
- }
- }
-
-@@ -75,6 +86,31 @@ TEST_P(TlsKeyExchangeTest13, Tls12Server
- ssl_sig_rsa_pss_rsae_sha256);
- }
-
-+TEST_P(TlsKeyExchangeTest13, Tls12ServerMlkem768Secp256r1NotSupported) {
-+ EnsureKeyShareSetup();
-+
-+ client_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
-+ SSL_LIBRARY_VERSION_TLS_1_3);
-+ server_->SetVersionRange(SSL_LIBRARY_VERSION_TLS_1_2,
-+ SSL_LIBRARY_VERSION_TLS_1_2);
-+
-+ client_->DisableAllCiphers();
-+ client_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
-+ client_->EnableCiphersByKeyExchange(ssl_kea_ecdh_hybrid);
-+ client_->ConfigNamedGroups(
-+ {ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1});
-+ EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
-+
-+ server_->EnableCiphersByKeyExchange(ssl_kea_ecdh);
-+ server_->EnableCiphersByKeyExchange(ssl_kea_ecdh_hybrid);
-+ server_->ConfigNamedGroups(
-+ {ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1});
-+
-+ Connect();
-+ CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
-+ ssl_sig_rsa_pss_rsae_sha256);
-+}
-+
- TEST_P(TlsKeyExchangeTest13, Mlkem768x25519ClientDisabledByPolicy) {
- EnsureKeyShareSetup();
- client_->SetPolicy(SEC_OID_MLKEM768X25519, 0, NSS_USE_ALG_IN_SSL_KX);
-@@ -94,12 +130,37 @@ TEST_P(TlsKeyExchangeTest13, Mlkem768x25
- {ssl_grp_kem_mlkem768x25519}, ssl_grp_ec_secp256r1);
- }
-
-+TEST_P(TlsKeyExchangeTest13, Mlkem768Secp256r1ClientDisabledByPolicy) {
-+ EnsureKeyShareSetup();
-+ client_->SetPolicy(SEC_OID_SECP256R1MLKEM768, 0, NSS_USE_ALG_IN_SSL_KX);
-+ ConfigNamedGroups({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1});
-+
-+ Connect();
-+ CheckKEXDetails({ssl_grp_ec_secp256r1}, {ssl_grp_ec_secp256r1});
-+}
-+
-+TEST_P(TlsKeyExchangeTest13, Mlkem768Secp256r1ServerDisabledByPolicy) {
-+ EnsureKeyShareSetup();
-+ server_->SetPolicy(SEC_OID_SECP256R1MLKEM768, 0, NSS_USE_ALG_IN_SSL_KX);
-+ ConfigNamedGroups({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1});
-+
-+ Connect();
-+ CheckKEXDetails({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1},
-+ {ssl_grp_kem_secp256r1mlkem768}, ssl_grp_ec_secp256r1);
-+}
-+
- static void CheckECDHShareReuse(
- const std::shared_ptr& capture) {
- EXPECT_TRUE(capture->captured());
- const DataBuffer& ext = capture->extension();
-- DataBuffer hybrid_share;
-- DataBuffer x25519_share;
-+ DataBuffer hybrid_share[4];
-+ DataBuffer ecdh_share[4];
-+ int hybrid_offset[4];
-+ SSLNamedGroup hybrid_ec_type[4];
-+ SSLNamedGroup ec_type[4];
-+ int ecdh_index[4];
-+ int nextHybrid = 0;
-+ int nextECDH = 0;
-
- size_t offset = 0;
- uint32_t ext_len;
-@@ -112,11 +173,23 @@ static void CheckECDHShareReuse(
- ext.Read(offset, 2, &named_group);
- ext.Read(offset + 2, 2, &named_group_len);
- while (offset < ext.len()) {
-- if (named_group == ssl_grp_kem_mlkem768x25519) {
-- hybrid_share = DataBuffer(ext.data() + offset + 2 + 2, named_group_len);
-- }
-- if (named_group == ssl_grp_ec_curve25519) {
-- x25519_share = DataBuffer(ext.data() + offset + 2 + 2, named_group_len);
-+ switch (named_group) {
-+ case ssl_grp_kem_mlkem768x25519:
-+ hybrid_share[nextHybrid] = DataBuffer(ext.data() + offset + 2 + 2, named_group_len);
-+ hybrid_offset[nextHybrid] = KYBER768_PUBLIC_KEY_BYTES;
-+ hybrid_ec_type[nextHybrid] = ssl_grp_ec_curve25519;
-+ nextHybrid++;
-+ break;
-+ case ssl_grp_kem_secp256r1mlkem768:
-+ hybrid_share[nextHybrid] = DataBuffer(ext.data() + offset + 2 + 2, named_group_len);
-+ hybrid_offset[nextHybrid] = 0;
-+ hybrid_ec_type[nextHybrid] = ssl_grp_ec_secp256r1;
-+ nextHybrid++;
-+ case ssl_grp_ec_curve25519:
-+ case ssl_grp_ec_secp256r1:
-+ ecdh_share[nextECDH] = DataBuffer(ext.data() + offset + 2 + 2, named_group_len);
-+ ec_type[nextECDH] = (SSLNamedGroup) named_group;
-+ nextECDH++;
- }
- offset += 2 + 2 + named_group_len;
- ext.Read(offset, 2, &named_group);
-@@ -124,11 +197,29 @@ static void CheckECDHShareReuse(
- }
- EXPECT_EQ(offset, ext.len());
-
-- ASSERT_TRUE(hybrid_share.data());
-- ASSERT_TRUE(x25519_share.data());
-- ASSERT_GT(hybrid_share.len(), x25519_share.len());
-- EXPECT_EQ(0, memcmp(hybrid_share.data() + KYBER768_PUBLIC_KEY_BYTES,
-- x25519_share.data(), x25519_share.len()));
-+ ASSERT_TRUE(nextECDH > 0);
-+ ASSERT_TRUE(nextHybrid > 0);
-+ /* setup the hybrid ecdh indeces */
-+ for (int i=0; i < nextHybrid; i++) {
-+ ecdh_index[i] = -1;
-+ for (int j=0; j < nextECDH; j++) {
-+ if (hybrid_ec_type[i] == ec_type[j]) {
-+ ecdh_index[i] = j;
-+ break;
-+ }
-+ }
-+ ASSERT_TRUE(ecdh_index[i] != -1);
-+ }
-+ for (int i=0; i < nextECDH; i++) {
-+ ASSERT_TRUE(ecdh_share[i].data());
-+ }
-+ for (int i=0; i < nextHybrid; i++) {
-+ int j = ecdh_index[i];
-+ ASSERT_TRUE(hybrid_share[i].data());
-+ ASSERT_GT(hybrid_share[i].len(), ecdh_share[j].len());
-+ EXPECT_EQ(0, memcmp(hybrid_share[i].data() + hybrid_offset[i],
-+ ecdh_share[j].data(), ecdh_share[j].len()));
-+ }
- }
-
- TEST_P(TlsKeyExchangeTest13, Mlkem768x25519ShareReuseFirst) {
-@@ -155,6 +246,30 @@ TEST_P(TlsKeyExchangeTest13, Mlkem768x25
- CheckECDHShareReuse(shares_capture_);
- }
-
-+TEST_P(TlsKeyExchangeTest13, Mlkem768Secp256r1ShareReuseFirst) {
-+ EnsureKeyShareSetup();
-+ ConfigNamedGroups({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1});
-+ EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
-+
-+ Connect();
-+
-+ CheckKEXDetails({ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1},
-+ {ssl_grp_kem_secp256r1mlkem768, ssl_grp_ec_secp256r1});
-+ CheckECDHShareReuse(shares_capture_);
-+}
-+
-+TEST_P(TlsKeyExchangeTest13, Mlkem768Secp256r1ShareReuseSecond) {
-+ EnsureKeyShareSetup();
-+ ConfigNamedGroups({ssl_grp_ec_secp256r1, ssl_grp_kem_secp256r1mlkem768});
-+ EXPECT_EQ(SECSuccess, SSL_SendAdditionalKeyShares(client_->ssl_fd(), 1));
-+
-+ Connect();
-+
-+ CheckKEXDetails({ssl_grp_ec_secp256r1, ssl_grp_kem_secp256r1mlkem768},
-+ {ssl_grp_ec_secp256r1, ssl_grp_kem_secp256r1mlkem768});
-+ CheckECDHShareReuse(shares_capture_);
-+}
-+
- class Mlkem768x25519ShareDamager : public TlsExtensionFilter {
- public:
- typedef enum {
-diff -up ./gtests/ssl_gtest/tls_psk_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/tls_psk_unittest.cc
---- ./gtests/ssl_gtest/tls_psk_unittest.cc.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./gtests/ssl_gtest/tls_psk_unittest.cc 2025-06-25 16:47:19.377362953 -0700
-@@ -68,7 +68,7 @@ TEST_P(Tls13PskTest, NormalExternal) {
- AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
- Connect();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
-+ CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_mlkem768x25519, ssl_auth_psk, ssl_sig_none);
- client_->RemovePsk(kPskDummyLabel_);
- server_->RemovePsk(kPskDummyLabel_);
-
-@@ -91,7 +91,7 @@ TEST_P(Tls13PskTest, KeyTooLarge) {
- AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
- Connect();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
-+ CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_mlkem768x25519, ssl_auth_psk, ssl_sig_none);
- }
-
- // Attempt to use a PSK with the wrong PRF hash.
-@@ -117,7 +117,7 @@ TEST_P(Tls13PskTest, LabelMismatch) {
- client_->AddPsk(scoped_psk_, std::string("foo"), kPskHash_);
- server_->AddPsk(scoped_psk_, std::string("bar"), kPskHash_);
- Connect();
-- CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
-+ CheckKeys();
- }
-
- SSLHelloRetryRequestAction RetryFirstHello(
-@@ -148,7 +148,7 @@ TEST_P(Tls13PskTest, ResPskRetryStateles
- Handshake();
- CheckConnected();
- EXPECT_EQ(2U, cb_called);
-- CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
-+ CheckKeys();
- SendReceive();
- }
-
-@@ -174,7 +174,7 @@ TEST_P(Tls13PskTest, ExtPskRetryStateles
- Handshake();
- CheckConnected();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
-+ CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_mlkem768x25519, ssl_auth_psk, ssl_sig_none);
- }
-
- // Server not configured with PSK and sends a certificate instead of
-@@ -182,7 +182,7 @@ TEST_P(Tls13PskTest, ExtPskRetryStateles
- TEST_P(Tls13PskTest, ClientOnly) {
- client_->AddPsk(scoped_psk_, kPskDummyLabel_, kPskHash_);
- Connect();
-- CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
-+ CheckKeys();
- }
-
- // Set a PSK, remove psk_key_exchange_modes.
-@@ -247,7 +247,7 @@ TEST_P(Tls13PskTest, PreferEpsk) {
- Handshake();
- CheckConnected();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
-+ CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_mlkem768x25519, ssl_auth_psk, ssl_sig_none);
- }
-
- // Enable resumption, but connect (initially) with an EPSK.
-@@ -260,7 +260,7 @@ TEST_P(Tls13PskTest, SuppressNewSessionT
- nst_capture->EnableDecryption();
- Connect();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
-+ CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_mlkem768x25519, ssl_auth_psk, ssl_sig_none);
- EXPECT_EQ(SECFailure, SSL_SendSessionTicket(server_->ssl_fd(), nullptr, 0));
- EXPECT_EQ(0U, nst_capture->buffer().len());
- if (variant_ == ssl_variant_stream) {
-@@ -275,7 +275,7 @@ TEST_P(Tls13PskTest, SuppressNewSessionT
- ExpectResumption(RESUME_NONE);
- Connect();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
-+ CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_mlkem768x25519, ssl_auth_psk, ssl_sig_none);
- }
-
- TEST_P(Tls13PskTest, BadConfigValues) {
-@@ -314,7 +314,7 @@ TEST_P(Tls13PskTest, FallbackUnsupported
- client_->EnableSingleCipher(TLS_AES_128_GCM_SHA256);
- Connect();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_auth_rsa_sign);
-+ CheckKeys();
- }
-
- // That fallback should not occur if there is no cipher overlap.
-@@ -342,7 +342,7 @@ TEST_P(Tls13PskTest, SuppressHandshakeCe
-
- Connect();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
-+ CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_mlkem768x25519, ssl_auth_psk, ssl_sig_none);
- EXPECT_EQ(0U, cr_cert_capture->buffer().len());
- }
-
-@@ -422,7 +422,7 @@ TEST_P(Tls13PskTestWithCiphers, 0RttCiph
- ExpectEarlyDataAccepted(true);
- CheckConnected();
- SendReceive();
-- CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_psk, ssl_sig_none);
-+ CheckKeys(ssl_kea_ecdh_hybrid, ssl_grp_kem_mlkem768x25519, ssl_auth_psk, ssl_sig_none);
- }
-
- TEST_P(Tls13PskTestWithCiphers, 0RttMaxEarlyData) {
-diff -up ./gtests/ssl_gtest/tls_subcerts_unittest.cc.mlkem_p256 ./gtests/ssl_gtest/tls_subcerts_unittest.cc
---- ./gtests/ssl_gtest/tls_subcerts_unittest.cc.mlkem_p256 2025-06-25 16:47:19.357362696 -0700
-+++ ./gtests/ssl_gtest/tls_subcerts_unittest.cc 2025-06-25 16:47:19.378362966 -0700
-@@ -449,6 +449,7 @@ class ReplaceDCSigScheme : public TlsHan
- // Aborted because of incorrect DC signature algorithm indication.
- TEST_P(TlsConnectTls13, DCAbortBadExpectedCertVerifyAlg) {
- Reset(kEcdsaDelegatorId);
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- client_->EnableDelegatedCredentials();
- server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256,
- ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor,
-@@ -569,6 +570,7 @@ TEST_P(TlsConnectTls13, DCConnectClientN
- // Connected without DC because server doesn't support TLS 1.3.
- TEST_P(TlsConnectTls13, DCConnectServerNoTls13) {
- Reset(kEcdsaDelegatorId);
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- client_->EnableDelegatedCredentials();
- server_->AddDelegatedCredential(kDCId, kDCScheme, kDCValidFor, now());
-
-@@ -613,6 +615,7 @@ TEST_P(TlsConnectTls13, DCConnectExpecte
- TEST_P(TlsConnectTls13, DCCheckPreliminaryInfo) {
- Reset(kEcdsaDelegatorId);
- EnsureTlsSetup();
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- client_->EnableDelegatedCredentials();
- server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256,
- ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor,
-@@ -638,6 +641,7 @@ TEST_P(TlsConnectTls13, DCCheckPrelimina
- TEST_P(TlsConnectTls13, DCCheckPreliminaryInfoNoDC) {
- Reset(kEcdsaDelegatorId);
- EnsureTlsSetup();
-+ client_->ConfigNamedGroups(kNonPQDHEGroups);
- client_->EnableDelegatedCredentials();
- auto filter = MakeTlsFilter(server_);
- filter->SetHandshakeTypes(
-diff -up ./lib/pk11wrap/pk11akey.c.mlkem_p256 ./lib/pk11wrap/pk11akey.c
---- ./lib/pk11wrap/pk11akey.c.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/pk11wrap/pk11akey.c 2025-06-25 16:47:19.378362966 -0700
-@@ -249,24 +249,31 @@ PK11_ImportPublicKey(PK11SlotInfo *slot,
- }
- break;
- case kyberKey:
-+ /*fprintf(stderr, "PK11_ImportPublic key kyber, params=%d\n",
-+ pubKey->u.kyber.params);*/
- switch (pubKey->u.kyber.params) {
-+#ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3:
- case params_kyber768_round3_test_mode:
- keyType = CKK_NSS_KYBER;
- kemParams = CKP_NSS_KYBER_768_ROUND3;
- break;
-+#endif
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
-- keyType = CKK_NSS_ML_KEM;
-- kemParams = CKP_NSS_ML_KEM_768;
-+ keyType = CKK_ML_KEM;
-+ kemParams = CKP_ML_KEM_768;
- break;
- default:
- kemParams = CKP_INVALID_ID;
- break;
- }
-- PK11_SETATTRS(attrs, CKA_NSS_PARAMETER_SET,
-+ /*fprintf(stderr, "PK11_ImportPublic KEY_TYPE=0x%08lx, kem_params=0x%08lxd\n",
-+ keyType, kemParams); */
-+
-+ PK11_SETATTRS(attrs, CKA_PARAMETER_SET,
- &kemParams,
-- sizeof(CK_NSS_KEM_PARAMETER_SET_TYPE));
-+ sizeof(CK_ML_KEM_PARAMETER_SET_TYPE));
- attrs++;
- PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.kyber.publicValue.data,
- pubKey->u.kyber.publicValue.len);
-@@ -298,6 +305,7 @@ PK11_ImportPublicKey(PK11SlotInfo *slot,
- SECITEM_FreeItem(pubValue, PR_TRUE);
- }
- if (rv != SECSuccess) {
-+ /* fprintf(stderr, "PK11_CreatNewObject failed %d\n", PORT_GetError()); */
- return CK_INVALID_HANDLE;
- }
- }
-@@ -684,8 +692,11 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot
- case CKK_EC_EDWARDS:
- keyType = edKey;
- break;
-+#ifndef NSS_DISABLE_KYBER
- case CKK_NSS_KYBER:
-+#endif
- case CKK_NSS_ML_KEM:
-+ case CKK_ML_KEM:
- keyType = kyberKey;
- break;
- default:
-@@ -852,35 +863,54 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot
- PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0);
- attrs++;
- kemParams = attrs;
-- PK11_SETATTRS(attrs, CKA_NSS_PARAMETER_SET, NULL, 0);
-+ PK11_SETATTRS(attrs, CKA_PARAMETER_SET, NULL, 0);
- attrs++;
- templateCount = attrs - template;
- PR_ASSERT(templateCount <= sizeof(template) / sizeof(CK_ATTRIBUTE));
-
- crv = PK11_GetAttributes(arena, slot, id, template, templateCount);
-- if (crv != CKR_OK)
-- break;
--
-+ if (crv != CKR_OK) {
-+ /* try to fetch with the vendor specific
-+ * CKA_NSS_PARAMETER_SET */
-+ kemParams->type = CKA_NSS_PARAMETER_SET;
-+ crv = PK11_GetAttributes(arena, slot, id, template,
-+ templateCount);
-+ if (crv != CKR_OK) {
-+ break;
-+ }
-+ }
- if (keyClass != CKO_PUBLIC_KEY) {
- crv = CKR_OBJECT_HANDLE_INVALID;
- break;
- }
--
-- if (pk11KeyType != CKK_NSS_KYBER && pk11KeyType != CKK_NSS_ML_KEM) {
-- crv = CKR_OBJECT_HANDLE_INVALID;
-+ switch (pk11KeyType) {
-+#ifndef NSS_DISABLE_KYBER
-+ case CKK_NSS_KYBER:
-+#endif
-+ case CKK_NSS_ML_KEM:
-+ case CKK_ML_KEM:
-+ break;
-+ default:
-+ crv = CKR_OBJECT_HANDLE_INVALID;
-+ break;
-+ }
-+ if (crv != CKR_OK) {
- break;
- }
-
-- if (kemParams->ulValueLen != sizeof(CK_NSS_KEM_PARAMETER_SET_TYPE)) {
-+ if (kemParams->ulValueLen != sizeof(CK_ML_KEM_PARAMETER_SET_TYPE)) {
- crv = CKR_OBJECT_HANDLE_INVALID;
- break;
- }
-- CK_NSS_KEM_PARAMETER_SET_TYPE *pPK11Params = kemParams->pValue;
-+ CK_ML_KEM_PARAMETER_SET_TYPE *pPK11Params = kemParams->pValue;
- switch (*pPK11Params) {
-+#ifdef NSS_DISABLE_KYBER
- case CKP_NSS_KYBER_768_ROUND3:
- pubKey->u.kyber.params = params_kyber768_round3;
- break;
-+#endif
- case CKP_NSS_ML_KEM_768:
-+ case CKP_ML_KEM_768:
- pubKey->u.kyber.params = params_ml_kem768;
- break;
- default:
-@@ -948,8 +978,11 @@ PK11_MakePrivKey(PK11SlotInfo *slot, Key
- case CKK_EC_EDWARDS:
- keyType = edKey;
- break;
-+#ifndef NSS_DISABLE_KYBER
- case CKK_NSS_KYBER:
-+#endif
- case CKK_NSS_ML_KEM:
-+ case CKK_ML_KEM:
- keyType = kyberKey;
- break;
- default:
-@@ -1293,6 +1326,7 @@ PK11_GenerateKeyPairWithOpFlags(PK11Slot
- { CKA_DECRYPT, NULL, 0 },
- { CKA_EXTRACTABLE, NULL, 0 },
- { CKA_MODIFIABLE, NULL, 0 },
-+ { CKA_DECAPSULATE, NULL, 0 },
- };
- CK_ATTRIBUTE rsaPubTemplate[] = {
- { CKA_MODULUS_BITS, NULL, 0 },
-@@ -1304,6 +1338,7 @@ PK11_GenerateKeyPairWithOpFlags(PK11Slot
- { CKA_VERIFY_RECOVER, NULL, 0 },
- { CKA_ENCRYPT, NULL, 0 },
- { CKA_MODIFIABLE, NULL, 0 },
-+ { CKA_ENCAPSULATE, NULL, 0 },
- };
- CK_ATTRIBUTE dsaPubTemplate[] = {
- { CKA_PRIME, NULL, 0 },
-@@ -1316,6 +1351,7 @@ PK11_GenerateKeyPairWithOpFlags(PK11Slot
- { CKA_VERIFY_RECOVER, NULL, 0 },
- { CKA_ENCRYPT, NULL, 0 },
- { CKA_MODIFIABLE, NULL, 0 },
-+ { CKA_ENCAPSULATE, NULL, 0 },
- };
- CK_ATTRIBUTE dhPubTemplate[] = {
- { CKA_PRIME, NULL, 0 },
-@@ -1327,6 +1363,7 @@ PK11_GenerateKeyPairWithOpFlags(PK11Slot
- { CKA_VERIFY_RECOVER, NULL, 0 },
- { CKA_ENCRYPT, NULL, 0 },
- { CKA_MODIFIABLE, NULL, 0 },
-+ { CKA_ENCAPSULATE, NULL, 0 },
- };
- CK_ATTRIBUTE ecPubTemplate[] = {
- { CKA_EC_PARAMS, NULL, 0 },
-@@ -1337,6 +1374,7 @@ PK11_GenerateKeyPairWithOpFlags(PK11Slot
- { CKA_VERIFY_RECOVER, NULL, 0 },
- { CKA_ENCRYPT, NULL, 0 },
- { CKA_MODIFIABLE, NULL, 0 },
-+ { CKA_ENCAPSULATE, NULL, 0 },
- };
- SECKEYECParams *ecParams;
-
-@@ -1349,6 +1387,7 @@ PK11_GenerateKeyPairWithOpFlags(PK11Slot
- { CKA_VERIFY_RECOVER, NULL, 0 },
- { CKA_ENCRYPT, NULL, 0 },
- { CKA_MODIFIABLE, NULL, 0 },
-+ { CKA_ENCAPSULATE, NULL, 0 },
- };
-
- /*CK_ULONG key_size = 0;*/
-@@ -1557,18 +1596,17 @@ PK11_GenerateKeyPairWithOpFlags(PK11Slot
- test_mech2.mechanism = CKM_ECDSA;
- }
- break;
-+#ifndef NSS_DISABLE_KYBER
- case CKM_NSS_KYBER_KEY_PAIR_GEN:
-- kemParams = (CK_NSS_KEM_PARAMETER_SET_TYPE *)param;
-- attrs = kyberPubTemplate;
-- PK11_SETATTRS(attrs, CKA_NSS_PARAMETER_SET,
-- kemParams,
-- sizeof(CK_NSS_KEM_PARAMETER_SET_TYPE));
-- attrs++;
-- pubTemplate = kyberPubTemplate;
-- keyType = kyberKey;
- test_mech.mechanism = CKM_NSS_KYBER;
-- break;
-+ goto ml_kem_gen;
-+#endif
- case CKM_NSS_ML_KEM_KEY_PAIR_GEN:
-+ test_mech.mechanism = CKM_NSS_ML_KEM;
-+ goto ml_kem_gen;
-+ case CKM_ML_KEM_KEY_PAIR_GEN:
-+ test_mech.mechanism = CKM_ML_KEM;
-+ml_kem_gen:
- kemParams = (CK_NSS_KEM_PARAMETER_SET_TYPE *)param;
- attrs = kyberPubTemplate;
- PK11_SETATTRS(attrs, CKA_NSS_PARAMETER_SET,
-@@ -1577,7 +1615,6 @@ PK11_GenerateKeyPairWithOpFlags(PK11Slot
- attrs++;
- pubTemplate = kyberPubTemplate;
- keyType = kyberKey;
-- test_mech.mechanism = CKM_NSS_ML_KEM;
- break;
- case CKM_EC_MONTGOMERY_KEY_PAIR_GEN:
- ecParams = (SECKEYECParams *)param;
-@@ -1658,7 +1695,13 @@ PK11_GenerateKeyPairWithOpFlags(PK11Slot
- case CKM_EDDSA:
- mechanism_info.flags = CKF_SIGN | CKF_VERIFY;
- break;
--
-+#ifndef NSS_DISABLE_KYBER
-+ case CKM_NSS_KYBER:
-+#endif
-+ case CKM_NSS_ML_KEM:
-+ case CKM_ML_KEM:
-+ mechanism_info.flags = CKF_ENCAPSULATE|CKF_DECAPSULATE;
-+ break;
- default:
- break;
- }
-@@ -1688,6 +1731,12 @@ PK11_GenerateKeyPairWithOpFlags(PK11Slot
- mechanism_info.flags & CKF_ENCRYPT ? &cktrue : &ckfalse,
- sizeof(CK_BBOOL));
- attrs++;
-+ /* only set encapsulate if it's requested and shows up in the mechanism
-+ * list, that way we don't confuse pre-3.2 PKCS #11 modules */
-+ if (mechanism_info.flags & CKF_ENCAPSULATE) {
-+ PK11_SETATTRS(attrs, CKA_ENCAPSULATE, &cktrue, sizeof(CK_BBOOL));
-+ attrs++;
-+ }
- /* set the private key attributes */
- PK11_SETATTRS(privattrs, CKA_DERIVE,
- mechanism_info.flags & CKF_DERIVE ? &cktrue : &ckfalse,
-@@ -1705,6 +1754,10 @@ PK11_GenerateKeyPairWithOpFlags(PK11Slot
- mechanism_info.flags & CKF_DECRYPT ? &cktrue : &ckfalse,
- sizeof(CK_BBOOL));
- privattrs++;
-+ if (mechanism_info.flags & CKF_DECAPSULATE) {
-+ PK11_SETATTRS(privattrs, CKA_DECAPSULATE, &cktrue, sizeof(CK_BBOOL));
-+ privattrs++;
-+ }
-
- if (token) {
- session_handle = PK11_GetRWSession(slot);
-diff -up ./lib/pk11wrap/pk11pars.c.mlkem_p256 ./lib/pk11wrap/pk11pars.c
---- ./lib/pk11wrap/pk11pars.c.mlkem_p256 2025-06-25 16:47:19.354362658 -0700
-+++ ./lib/pk11wrap/pk11pars.c 2025-06-25 16:47:19.378362966 -0700
-@@ -245,8 +245,12 @@ static const oidValDef curveOptList[] =
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
- { CIPHER_NAME("CURVE25519"), SEC_OID_CURVE25519,
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
-- { CIPHER_NAME("XYBER768D00"), SEC_OID_XYBER768D00, 0 },
-- { CIPHER_NAME("MLKEM768X25519"), SEC_OID_MLKEM768X25519, 0 },
-+ { CIPHER_NAME("XYBER768D00"), SEC_OID_XYBER768D00,
-+ NSS_USE_ALG_IN_SSL_KX },
-+ { CIPHER_NAME("MLKEM768X25519"), SEC_OID_MLKEM768X25519,
-+ NSS_USE_ALG_IN_SSL_KX },
-+ { CIPHER_NAME("MLKEM768SECP256R1"), SEC_OID_SECP256R1MLKEM768,
-+ NSS_USE_ALG_IN_SSL_KX },
- /* ANSI X9.62 named elliptic curves (characteristic two field) */
- { CIPHER_NAME("C2PNB163V1"), SEC_OID_ANSIX962_EC_C2PNB163V1,
- NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
-diff -up ./lib/pk11wrap/pk11skey.c.mlkem_p256 ./lib/pk11wrap/pk11skey.c
---- ./lib/pk11wrap/pk11skey.c.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/pk11wrap/pk11skey.c 2025-06-25 16:47:19.378362966 -0700
-@@ -3107,6 +3107,30 @@ pk11_KEMCiphertextLength(SECKEYPublicKey
- }
- }
-
-+/* only one of privKey and pubKey is set. */
-+static SECStatus
-+pk11_GetKEMMechanism(KeyType keyType, CK_MECHANISM_PTR mechp,
-+ SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey)
-+{
-+ switch (keyType) {
-+ case kyberKey:
-+ /* we don't need to set the parameter set for the official
-+ * mlkem interface, it can it it from the key. If we have
-+ * kyber support, this still works because CKM_ML_KEM
-+ * will see the CP_NSS_KYBER_786_ROUND3 parameter and use
-+ * kyber.*/
-+ mechp->mechanism = CKM_ML_KEM;
-+ mechp->pParameter = NULL;
-+ mechp->ulParameterLen = 0;
-+ break;
-+ /* add other kems here */
-+ default:
-+ PORT_SetError(SEC_ERROR_INVALID_KEY);
-+ return SECFailure;
-+ }
-+ return SECSuccess;
-+}
-+
- SECStatus
- PK11_Encapsulate(SECKEYPublicKey *pubKey, CK_MECHANISM_TYPE target, PK11AttrFlags attrFlags, CK_FLAGS opFlags, PK11SymKey **outKey, SECItem **outCiphertext)
- {
-@@ -3138,20 +3162,11 @@ PK11_Encapsulate(SECKEYPublicKey *pubKey
- *outKey = NULL;
- *outCiphertext = NULL;
-
-- CK_MECHANISM_TYPE kemType;
-- CK_NSS_KEM_PARAMETER_SET_TYPE kemParameterSet = PK11_ReadULongAttribute(slot, pubKey->pkcs11ID, CKA_NSS_PARAMETER_SET);
-- switch (kemParameterSet) {
-- case CKP_NSS_KYBER_768_ROUND3:
-- kemType = CKM_NSS_KYBER;
-- break;
-- case CKP_NSS_ML_KEM_768:
-- kemType = CKM_NSS_ML_KEM;
-- break;
-- default:
-- PORT_SetError(SEC_ERROR_INVALID_KEY);
-- return SECFailure;
-+ CK_MECHANISM mech;
-+ SECStatus rv = pk11_GetKEMMechanism(pubKey->keyType, &mech, NULL, pubKey);
-+ if (rv != SECSuccess) {
-+ return rv;
- }
-- CK_MECHANISM mech = { kemType, &kemParameterSet, sizeof(kemParameterSet) };
-
- sharedSecret = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, NULL);
- if (sharedSecret == NULL) {
-@@ -3243,20 +3258,11 @@ PK11_Decapsulate(SECKEYPrivateKey *privK
-
- *outKey = NULL;
-
-- CK_MECHANISM_TYPE kemType;
-- CK_NSS_KEM_PARAMETER_SET_TYPE kemParameterSet = PK11_ReadULongAttribute(slot, privKey->pkcs11ID, CKA_NSS_PARAMETER_SET);
-- switch (kemParameterSet) {
-- case CKP_NSS_KYBER_768_ROUND3:
-- kemType = CKM_NSS_KYBER;
-- break;
-- case CKP_NSS_ML_KEM_768:
-- kemType = CKM_NSS_ML_KEM;
-- break;
-- default:
-- PORT_SetError(SEC_ERROR_INVALID_KEY);
-- return SECFailure;
-+ CK_MECHANISM mech;
-+ SECStatus rv = pk11_GetKEMMechanism(privKey->keyType, &mech, privKey, NULL);
-+ if (rv != SECSuccess) {
-+ return rv;
- }
-- CK_MECHANISM mech = { kemType, &kemParameterSet, sizeof(kemParameterSet) };
-
- sharedSecret = pk11_CreateSymKey(slot, target, PR_TRUE, PR_TRUE, NULL);
- if (sharedSecret == NULL) {
-diff -up ./lib/pk11wrap/pk11slot.c.mlkem_p256 ./lib/pk11wrap/pk11slot.c
---- ./lib/pk11wrap/pk11slot.c.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/pk11wrap/pk11slot.c 2025-06-25 16:47:19.378362966 -0700
-@@ -54,6 +54,7 @@ const PK11DefaultArrayEntry PK11_Default
- { "MD2", SECMOD_MD2_FLAG, CKM_MD2 },
- { "SSL", SECMOD_SSL_FLAG, CKM_SSL3_PRE_MASTER_KEY_GEN },
- { "TLS", SECMOD_TLS_FLAG, CKM_TLS_MASTER_KEY_DERIVE },
-+ { "MLKEM", SECMOD_MLKEM_FLAG, CKM_ML_KEM },
- { "SKIPJACK", SECMOD_FORTEZZA_FLAG, CKM_SKIPJACK_CBC64 },
- { "Publicly-readable certs", SECMOD_FRIENDLY_FLAG, CKM_INVALID_MECHANISM },
- { "Random Num Generator", SECMOD_RANDOM_FLAG, CKM_FAKE_RANDOM },
-@@ -89,6 +90,7 @@ static PK11SlotList
- pk11_dsaSlotList,
- pk11_dhSlotList,
- pk11_ecSlotList,
-+ pk11_mlkemSlotList,
- pk11_ideaSlotList,
- pk11_sslSlotList,
- pk11_tlsSlotList,
-@@ -843,6 +845,7 @@ PK11_InitSlotLists(void)
- pk11_InitSlotListStatic(&pk11_dsaSlotList);
- pk11_InitSlotListStatic(&pk11_dhSlotList);
- pk11_InitSlotListStatic(&pk11_ecSlotList);
-+ pk11_InitSlotListStatic(&pk11_mlkemSlotList);
- pk11_InitSlotListStatic(&pk11_ideaSlotList);
- pk11_InitSlotListStatic(&pk11_sslSlotList);
- pk11_InitSlotListStatic(&pk11_tlsSlotList);
-@@ -869,6 +872,7 @@ PK11_DestroySlotLists(void)
- pk11_FreeSlotListStatic(&pk11_dsaSlotList);
- pk11_FreeSlotListStatic(&pk11_dhSlotList);
- pk11_FreeSlotListStatic(&pk11_ecSlotList);
-+ pk11_FreeSlotListStatic(&pk11_mlkemSlotList);
- pk11_FreeSlotListStatic(&pk11_ideaSlotList);
- pk11_FreeSlotListStatic(&pk11_sslSlotList);
- pk11_FreeSlotListStatic(&pk11_tlsSlotList);
-@@ -945,11 +949,14 @@ PK11_GetSlotList(CK_MECHANISM_TYPE type)
- case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */
- case CKM_NSS_ECDHE_NO_PAIRWISE_CHECK_KEY_PAIR_GEN:
- case CKM_ECDH1_DERIVE:
-+ return &pk11_ecSlotList;
- case CKM_NSS_KYBER_KEY_PAIR_GEN: /* Bug 1893029 */
- case CKM_NSS_KYBER:
- case CKM_NSS_ML_KEM_KEY_PAIR_GEN: /* Bug 1893029 */
- case CKM_NSS_ML_KEM:
-- return &pk11_ecSlotList;
-+ case CKM_ML_KEM_KEY_PAIR_GEN: /* Bug 1893029 */
-+ case CKM_ML_KEM:
-+ return &pk11_mlkemSlotList;
- case CKM_SSL3_PRE_MASTER_KEY_GEN:
- case CKM_SSL3_MASTER_KEY_DERIVE:
- case CKM_SSL3_SHA1_MAC:
-diff -up ./lib/pk11wrap/secmodti.h.mlkem_p256 ./lib/pk11wrap/secmodti.h
---- ./lib/pk11wrap/secmodti.h.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/pk11wrap/secmodti.h 2025-06-25 16:47:19.378362966 -0700
-@@ -202,4 +202,11 @@ struct PK11GenericObjectStr {
- /* This mask includes all CK_FLAGs with an equivalent CKA_ attribute. */
- #define CKF_KEY_OPERATION_FLAGS 0x000e7b00UL
-
-+/*
-+ * private header file, so we can set real names for oids that aren't upstream
-+ * yet, so we applications don't try to use them and get hosed when they change
-+ */
-+#define SEC_OID_SECP256R1MLKEM768 SEC_OID_PRIVATE_1
-+#define SEC_OID_MLKEM1024SECP256R1 SEC_OID_PRIVATE_2
-+
- #endif /* _SECMODTI_H_ */
-diff -up ./lib/softoken/fipsaudt.c.mlkem_p256 ./lib/softoken/fipsaudt.c
---- ./lib/softoken/fipsaudt.c.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/softoken/fipsaudt.c 2025-06-25 16:47:19.378362966 -0700
-@@ -319,3 +319,51 @@ sftk_AuditDigestKey(CK_SESSION_HANDLE hS
- (PRUint32)hSession, (PRUint32)hKey, (PRUint32)rv);
- sftk_LogAuditMessage(severity, NSS_AUDIT_DIGEST_KEY, msg);
- }
-+
-+void
-+sftk_AuditEncapsulate(CK_SESSION_HANDLE hSession,
-+ CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hPublicKey,
-+ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
-+ CK_OBJECT_HANDLE_PTR phKey, CK_BYTE_PTR pCiphertext,
-+ CK_ULONG_PTR pulCiphertextLen, CK_RV rv)
-+{
-+ char msg[256];
-+ char mech[MECHANISM_BUFSIZE];
-+ char shKey[32];
-+ NSSAuditSeverity severity = (rv == CKR_OK) ? NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
-+
-+ sftk_PrintMechanism(mech, sizeof mech, pMechanism);
-+ sftk_PrintReturnedObjectHandle(shKey, sizeof shKey, "phKey", phKey, rv);
-+ PR_snprintf(msg, sizeof msg,
-+ "C_Encapsulate(hSession=0x%08lX, pMechanism=%s, "
-+ "hPublicKey=0x%08lX, pTemplate=%p, ulAttributeCount=%lu, "
-+ "phKey=%p pCipherText=%p, pulCiphertextLen=%p)=0x%08lX%s",
-+ (PRUint32)hSession, mech,
-+ (PRUint32)hPublicKey, pTemplate, (PRUint32)ulAttributeCount,
-+ phKey, pCiphertext, pulCiphertextLen, (PRUint32)rv, shKey);
-+ sftk_LogAuditMessage(severity, NSS_AUDIT_ENCAPSULATE_KEY, msg);
-+}
-+
-+void
-+sftk_AuditDecapsulate(CK_SESSION_HANDLE hSession,
-+ CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hPrivateKey,
-+ CK_BYTE_PTR pCiphertext, CK_ULONG ulCiphertextLen,
-+ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
-+ CK_OBJECT_HANDLE_PTR phKey, CK_RV rv)
-+{
-+ char msg[256];
-+ char mech[MECHANISM_BUFSIZE];
-+ char shKey[32];
-+ NSSAuditSeverity severity = (rv == CKR_OK) ? NSS_AUDIT_INFO : NSS_AUDIT_ERROR;
-+
-+ sftk_PrintMechanism(mech, sizeof mech, pMechanism);
-+ sftk_PrintReturnedObjectHandle(shKey, sizeof shKey, "phKey", phKey, rv);
-+ PR_snprintf(msg, sizeof msg,
-+ "C_Decapsulate(hSession=0x%08lX, pMechanism=%s, "
-+ "hPrivateKey=0x%08lX, pCipherText=%p, ulCiphertextLen=%lu,",
-+ "pTemplate=%p, ulAttributeCount=%lu, phKey=%p)=0x%08lX%s",
-+ (PRUint32)hSession, mech,
-+ (PRUint32)hPrivateKey, pCiphertext, (PRUint32)ulCiphertextLen,
-+ pTemplate, (PRUint32)ulAttributeCount, phKey, (PRUint32)rv, shKey);
-+ sftk_LogAuditMessage(severity, NSS_AUDIT_DECAPSULATE_KEY, msg);
-+}
-diff -up ./lib/softoken/fipstokn.c.mlkem_p256 ./lib/softoken/fipstokn.c
---- ./lib/softoken/fipstokn.c.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/softoken/fipstokn.c 2025-06-25 16:47:19.379362979 -0700
-@@ -24,6 +24,7 @@
- #include "pkcs11i.h"
- #include "prenv.h"
- #include "prprf.h"
-+#include "kem.h"
-
- #include
-
-@@ -261,6 +262,30 @@ static CK_FUNCTION_LIST_3_0 sftk_fipsTab
-
- };
-
-+CK_RV FC_Encapsulate(CK_SESSION_HANDLE hSession,
-+ CK_MECHANISM_PTR pMechanism,
-+ CK_OBJECT_HANDLE hPublicKey,
-+ CK_ATTRIBUTE_PTR pTemplate,
-+ CK_ULONG ulAttributeCount,
-+ CK_OBJECT_HANDLE_PTR phKey,
-+ CK_BYTE_PTR pCiphertext,
-+ CK_ULONG_PTR pulCiphertextLen);
-+
-+CK_RV FC_Decapsulate(CK_SESSION_HANDLE hSession,
-+ CK_MECHANISM_PTR pMechanism,
-+ CK_OBJECT_HANDLE hPrivateKey,
-+ CK_BYTE_PTR pCiphertext,
-+ CK_ULONG ulCiphertextLen,
-+ CK_ATTRIBUTE_PTR pTemplate,
-+ CK_ULONG ulAttributeCount,
-+ CK_OBJECT_HANDLE_PTR phKey);
-+
-+CK_NSS_KEM_FUNCTIONS sftk_fips_kem_funcList = {
-+ { 1, 0 },
-+ FC_Encapsulate,
-+ FC_Decapsulate
-+};
-+
- /* forward declaration of special GetInfo functions */
- CK_RV FC_GetInfoV2(CK_INFO_PTR pInfo);
- CK_RV NSC_GetInfoV2(CK_INFO_PTR pInfo);
-@@ -302,10 +327,11 @@ static CK_INTERFACE fips_interfaces[] =
- { (CK_UTF8CHAR_PTR) "PKCS 11", &sftk_fipsTable, NSS_INTERFACE_FLAGS },
- { (CK_UTF8CHAR_PTR) "PKCS 11", &sftk_fipsTable_v2, NSS_INTERFACE_FLAGS },
- { (CK_UTF8CHAR_PTR) "Vendor NSS Module Interface", &sftk_module_funcList, NSS_INTERFACE_FLAGS },
-- { (CK_UTF8CHAR_PTR) "Vendor NSS FIPS Interface", &sftk_fips_funcList, NSS_INTERFACE_FLAGS }
-+ { (CK_UTF8CHAR_PTR) "Vendor NSS FIPS Interface", &sftk_fips_funcList, NSS_INTERFACE_FLAGS },
-+ { (CK_UTF8CHAR_PTR) "Vendor NSS KEM Interface", &sftk_fips_kem_funcList, NSS_INTERFACE_FLAGS }
- };
- /* must match the count of interfaces in fips_interfaces above*/
--#define FIPS_INTERFACE_COUNT 4
-+#define FIPS_INTERFACE_COUNT PR_ARRAY_SIZE(fips_interfaces)
-
- /* CKO_NOT_A_KEY can be any object class that's not a key object. */
- #define CKO_NOT_A_KEY CKO_DATA
-@@ -350,6 +376,8 @@ sftk_mapLinuxAuditType(NSSAuditSeverity
- case NSS_AUDIT_LOAD_KEY:
- case NSS_AUDIT_UNWRAP_KEY:
- case NSS_AUDIT_WRAP_KEY:
-+ case NSS_AUDIT_ENCAPSULATE_KEY:
-+ case NSS_AUDIT_DECAPSULATE_KEY:
- return AUDIT_CRYPTO_KEY_USER;
- case NSS_AUDIT_CRYPT:
- return (severity == NSS_AUDIT_ERROR) ? AUDIT_CRYPTO_FAILURE_USER : AUDIT_CRYPTO_KEY_USER;
-@@ -2078,3 +2106,75 @@ FC_MessageVerifyFinal(CK_SESSION_HANDLE
- CHECK_FORK();
- return NSC_MessageVerifyFinal(hSession);
- }
-+
-+/*
-+ * vendor specific encapsulate/decapsulate
-+ */
-+CK_RV
-+FC_Encapsulate(CK_SESSION_HANDLE hSession,
-+ CK_MECHANISM_PTR pMechanism,
-+ CK_OBJECT_HANDLE hPublicKey,
-+ CK_ATTRIBUTE_PTR pTemplate,
-+ CK_ULONG ulAttributeCount,
-+ CK_OBJECT_HANDLE_PTR phKey,
-+ CK_BYTE_PTR pCiphertext,
-+ CK_ULONG_PTR pulCiphertextLen)
-+{
-+ CK_BBOOL *boolptr;
-+ SFTK_FIPSCHECK();
-+ CHECK_FORK();
-+
-+ /* all secret keys must be sensitive, if the upper level code tries to say
-+ * otherwise, reject it. */
-+ boolptr = (CK_BBOOL *)fc_getAttribute(pTemplate,
-+ ulAttributeCount, CKA_SENSITIVE);
-+ if (boolptr != NULL) {
-+ if (!(*boolptr)) {
-+ return CKR_ATTRIBUTE_VALUE_INVALID;
-+ }
-+ }
-+
-+ rv = NSC_Encapsulate(hSession, pMechanism, hPublicKey, pTemplate,
-+ ulAttributeCount, phKey, pCiphertext,
-+ pulCiphertextLen);
-+ if (sftk_audit_enabled) {
-+ sftk_AuditEncapsulate(hSession, pMechanism, hPublicKey, pTemplate,
-+ ulAttributeCount, phKey, pCiphertext,
-+ pulCiphertextLen, rv);
-+ }
-+ return rv;
-+}
-+
-+CK_RV
-+FC_Decapsulate(CK_SESSION_HANDLE hSession,
-+ CK_MECHANISM_PTR pMechanism,
-+ CK_OBJECT_HANDLE hPrivateKey,
-+ CK_BYTE_PTR pCiphertext,
-+ CK_ULONG ulCiphertextLen,
-+ CK_ATTRIBUTE_PTR pTemplate,
-+ CK_ULONG ulAttributeCount,
-+ CK_OBJECT_HANDLE_PTR phKey)
-+{
-+ CK_BBOOL *boolptr;
-+ SFTK_FIPSCHECK();
-+ CHECK_FORK();
-+
-+ /* all secret keys must be sensitive, if the upper level code tries to say
-+ * otherwise, reject it. */
-+ boolptr = (CK_BBOOL *)fc_getAttribute(pTemplate,
-+ ulAttributeCount, CKA_SENSITIVE);
-+ if (boolptr != NULL) {
-+ if (!(*boolptr)) {
-+ return CKR_ATTRIBUTE_VALUE_INVALID;
-+ }
-+ }
-+
-+ rv = NSC_Decapsulate(hSession, pMechanism, hPrivateKey, pCiphertext,
-+ ulCiphertextLen, pTemplate, ulAttributeCount, phKey);
-+ if (sftk_audit_enabled) {
-+ sftk_AuditDecapsulate(hSession, pMechanism, hPrivateKey, pCiphertext,
-+ ulCiphertextLen, pTemplate, ulAttributeCount,
-+ phKey, rv);
-+ }
-+ return rv;
-+}
-diff -up ./lib/softoken/kem.c.mlkem_p256 ./lib/softoken/kem.c
---- ./lib/softoken/kem.c.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/softoken/kem.c 2025-06-25 16:56:05.884129793 -0700
-@@ -11,13 +11,19 @@
- #include "secport.h"
- #include "softoken.h"
-
-+/* change to the largest KEM Secret Bytes value supported */
-+#define MAX_SHARED_SECRET_BYTES KYBER_SHARED_SECRET_BYTES
-+
- KyberParams
--sftk_kyber_PK11ParamToInternal(CK_NSS_KEM_PARAMETER_SET_TYPE pk11ParamSet)
-+sftk_kyber_PK11ParamToInternal(CK_ML_KEM_PARAMETER_SET_TYPE pk11ParamSet)
- {
- switch (pk11ParamSet) {
-+#ifndef NSS_DISABLE_KYBER
- case CKP_NSS_KYBER_768_ROUND3:
- return params_kyber768_round3;
-+#endif
- case CKP_NSS_ML_KEM_768:
-+ case CKP_ML_KEM_768:
- return params_ml_kem768;
- default:
- return params_kyber_invalid;
-@@ -28,8 +34,10 @@ SECItem *
- sftk_kyber_AllocPubKeyItem(KyberParams params, SECItem *pubkey)
- {
- switch (params) {
-+#ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3:
- case params_kyber768_round3_test_mode:
-+#endif
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
- return SECITEM_AllocItem(NULL, pubkey, KYBER768_PUBLIC_KEY_BYTES);
-@@ -42,8 +50,10 @@ SECItem *
- sftk_kyber_AllocPrivKeyItem(KyberParams params, SECItem *privkey)
- {
- switch (params) {
-+#ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3:
- case params_kyber768_round3_test_mode:
-+#endif
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
- return SECITEM_AllocItem(NULL, privkey, KYBER768_PRIVATE_KEY_BYTES);
-@@ -56,8 +66,10 @@ SECItem *
- sftk_kyber_AllocCiphertextItem(KyberParams params, SECItem *ciphertext)
- {
- switch (params) {
-+#ifndef NSS_DISABLE_KYBER
- case params_kyber768_round3:
- case params_kyber768_round3_test_mode:
-+#endif
- case params_ml_kem768:
- case params_ml_kem768_test_mode:
- return SECITEM_AllocItem(NULL, ciphertext, KYBER768_CIPHERTEXT_BYTES);
-@@ -67,70 +79,100 @@ sftk_kyber_AllocCiphertextItem(KyberPara
- }
-
- static PRBool
--sftk_kyber_ValidateParams(const CK_NSS_KEM_PARAMETER_SET_TYPE *params)
-+sftk_kem_ValidateMechanism(CK_MECHANISM_PTR pMechanism)
- {
-- if (!params) {
-+ if (!pMechanism) {
- return PR_FALSE;
- }
-- switch (*params) {
-- case CKP_NSS_KYBER_768_ROUND3:
-- case CKP_NSS_ML_KEM_768:
-+ switch (pMechanism->mechanism) {
-+#ifndef NSS_DISABLE_KYBER
-+ case CKM_NSS_KYBER:
-+#endif
-+ case CKM_NSS_ML_KEM:
-+ case CKM_ML_KEM:
- return PR_TRUE;
- default:
- return PR_FALSE;
- }
- }
-
--static PRBool
--sftk_kem_ValidateMechanism(CK_MECHANISM_PTR pMechanism)
-+/* this is a generic call the returns the paramSet as a CKU_LONG. if the
-+ * param set is in a different attribute or mechanism structure, that would
-+ * be based on the mechanism. The meaning of the paramter set is alway
-+ * mechanism specific */
-+static CK_RV
-+sftk_kem_getParamSet(CK_MECHANISM_PTR pMechanism, SFTKObject *key,
-+ CK_ULONG *paramSet)
- {
-- if (!pMechanism) {
-- return PR_FALSE;
-- }
-+ CK_RV crv = CKR_MECHANISM_INVALID;
-+
- switch (pMechanism->mechanism) {
-+#ifndef NSS_DISABLE_KYBER
- case CKM_NSS_KYBER:
-+#endif
- case CKM_NSS_ML_KEM:
-- return pMechanism->ulParameterLen == sizeof(CK_NSS_KEM_PARAMETER_SET_TYPE) && sftk_kyber_ValidateParams(pMechanism->pParameter);
-+ if ((pMechanism->pParameter) &&
-+ pMechanism->ulParameterLen == sizeof(CK_ML_KEM_PARAMETER_SET_TYPE)) {
-+ PR_STATIC_ASSERT(sizeof(CK_ML_KEM_PARAMETER_SET_TYPE) == sizeof(CK_LONG));
-+ *paramSet = *(CK_ULONG *)pMechanism->pParameter;
-+ crv = CKR_OK;
-+ break;
-+ }
-+ crv = sftk_GetULongAttribute(key, CKA_NSS_PARAMETER_SET, paramSet);
-+ if (crv == CKR_OK) {
-+ break;
-+ }
-+ case CKM_ML_KEM:
-+ crv = sftk_GetULongAttribute(key, CKA_PARAMETER_SET, paramSet);
-+ break;
- default:
-- return PR_FALSE;
-+ break;
- }
-+ return crv;
- }
-
- static CK_ULONG
--sftk_kem_CiphertextLen(CK_MECHANISM_PTR pMechanism)
-+sftk_kem_CiphertextLen(CK_MECHANISM_PTR pMechanism, CK_ULONG paramSet)
- {
--#ifdef DEBUG
-- if (!sftk_kem_ValidateMechanism(pMechanism)) {
-- PORT_Assert(0);
-- return 0;
-- }
-+ /* the switch here is redundant now, but we will eventually have
-+ * other unrelated KEM operations and the meaning of paramSet
-+ * is dependent of the mechanism type (in general). Since there
-+ * is not overlap between the Vendor specific mechanisms here
-+ * and the stand ones, we'll just accept them all here. */
-+ switch (pMechanism->mechanism) {
-+#ifndef NSS_DISABLE_KYBER
-+ case CKM_NSS_KYBER:
- #endif
--
-- /* Assumes pMechanism has been validated with sftk_kem_ValidateMechanism */
-- CK_NSS_KEM_PARAMETER_SET_TYPE *pParameterSet = pMechanism->pParameter;
-- switch (*pParameterSet) {
-- case CKP_NSS_KYBER_768_ROUND3:
-- case CKP_NSS_ML_KEM_768:
-- return KYBER768_CIPHERTEXT_BYTES;
-+ case CKM_NSS_ML_KEM:
-+ case CKM_ML_KEM:
-+ switch (paramSet) {
-+#ifndef NSS_DISABLE_KYBER
-+ case CKP_NSS_KYBER_768_ROUND3:
-+#endif
-+ case CKP_NSS_ML_KEM_768:
-+ case CKP_ML_KEM_768:
-+ return KYBER768_CIPHERTEXT_BYTES;
-+ default:
-+ break;
-+ }
- default:
-- /* unreachable if pMechanism has been validated */
-- PORT_Assert(0);
-- return 0;
-+ break;
- }
-+ return 0;
- }
-
- /* C_Encapsulate takes a public encapsulation key hPublicKey, a secret
- * phKey, and outputs a ciphertext (i.e. encapsulaton) of this secret in
- * pCiphertext. */
- CK_RV
--NSC_Encapsulate(CK_SESSION_HANDLE hSession,
-- CK_MECHANISM_PTR pMechanism,
-- CK_OBJECT_HANDLE hPublicKey,
-- CK_ATTRIBUTE_PTR pTemplate,
-- CK_ULONG ulAttributeCount,
-- /* out */ CK_OBJECT_HANDLE_PTR phKey,
-- /* out */ CK_BYTE_PTR pCiphertext,
-- /* out */ CK_ULONG_PTR pulCiphertextLen)
-+NSC_EncapsulateKey(CK_SESSION_HANDLE hSession,
-+ CK_MECHANISM_PTR pMechanism,
-+ CK_OBJECT_HANDLE hPublicKey,
-+ CK_ATTRIBUTE_PTR pTemplate,
-+ CK_ULONG ulAttributeCount,
-+ /* out */ CK_BYTE_PTR pCiphertext,
-+ /* out */ CK_ULONG_PTR pulCiphertextLen,
-+ /* out */ CK_OBJECT_HANDLE_PTR phKey)
- {
- SFTKSession *session = NULL;
- SFTKSlot *slot = NULL;
-@@ -142,6 +184,10 @@ NSC_Encapsulate(CK_SESSION_HANDLE hSessi
-
- CK_RV crv;
- SFTKFreeStatus status;
-+ CK_ULONG paramSet = 0; /* use a generic U_LONG so we can handle
-+ * different param set types based on the
-+ * Mechanism value */
-+ KyberParams kyberParams;
-
- CHECK_FORK();
-
-@@ -152,12 +198,6 @@ NSC_Encapsulate(CK_SESSION_HANDLE hSessi
- if (!sftk_kem_ValidateMechanism(pMechanism)) {
- return CKR_MECHANISM_INVALID;
- }
--
-- CK_ULONG ciphertextLen = sftk_kem_CiphertextLen(pMechanism);
-- if (!pCiphertext || *pulCiphertextLen < ciphertextLen) {
-- *pulCiphertextLen = ciphertextLen;
-- return CKR_KEY_SIZE_RANGE;
-- }
- *phKey = CK_INVALID_HANDLE;
-
- session = sftk_SessionFromHandle(hSession);
-@@ -193,20 +233,39 @@ NSC_Encapsulate(CK_SESSION_HANDLE hSessi
- goto cleanup;
- }
-
-+ crv = sftk_kem_getParamSet(pMechanism, encapsulationKeyObject, ¶mSet);
-+ if (crv != CKR_OK) {
-+ goto cleanup;
-+ }
-+
-+ CK_ULONG ciphertextLen = sftk_kem_CiphertextLen(pMechanism, paramSet);
-+ if (!pCiphertext || *pulCiphertextLen < ciphertextLen || ciphertextLen == 0) {
-+ *pulCiphertextLen = ciphertextLen;
-+ crv = CKR_KEY_SIZE_RANGE;
-+ goto cleanup;
-+ }
-+
- SECItem ciphertext = { siBuffer, pCiphertext, ciphertextLen };
- SECItem pubKey = { siBuffer, encapsulationKey->attrib.pValue, encapsulationKey->attrib.ulValueLen };
-
-- /* The length of secretBuf can be increased if we ever support other KEMs */
-- uint8_t secretBuf[KYBER_SHARED_SECRET_BYTES] = { 0 };
-+ /* The length of secretBuf can be increased if we ever support other KEMs
-+ * by changing the define at the top of this file */
-+ uint8_t secretBuf[MAX_SHARED_SECRET_BYTES] = { 0 };
- SECItem secret = { siBuffer, secretBuf, sizeof secretBuf };
-
-+ key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_ENCAPSULATE,
-+ key, 0);
-+ key->source = SFTK_SOURCE_KEA;
- switch (pMechanism->mechanism) {
-+#ifndef NSS_DISABLE_KYBER
- case CKM_NSS_KYBER:
-+#endif
- case CKM_NSS_ML_KEM:
-- PORT_Assert(secret.len == KYBER_SHARED_SECRET_BYTES);
-- CK_NSS_KEM_PARAMETER_SET_TYPE *pParameter = pMechanism->pParameter;
-- KyberParams kyberParams = sftk_kyber_PK11ParamToInternal(*pParameter);
-- SECStatus rv = Kyber_Encapsulate(kyberParams, /* seed */ NULL, &pubKey, &ciphertext, &secret);
-+ case CKM_ML_KEM:
-+ PORT_Assert(secret.len >= KYBER_SHARED_SECRET_BYTES);
-+ kyberParams = sftk_kyber_PK11ParamToInternal(paramSet);
-+ SECStatus rv = Kyber_Encapsulate(kyberParams, /* seed */ NULL,
-+ &pubKey, &ciphertext, &secret);
- if (rv != SECSuccess) {
- crv = (PORT_GetError() == SEC_ERROR_INVALID_ARGS) ? CKR_ARGUMENTS_BAD : CKR_FUNCTION_FAILED;
- goto cleanup;
-@@ -232,6 +291,7 @@ NSC_Encapsulate(CK_SESSION_HANDLE hSessi
- }
-
- cleanup:
-+ PORT_SafeZero(secretBuf, sizeof(secretBuf));
- if (session) {
- sftk_FreeSession(session);
- }
-@@ -254,14 +314,14 @@ cleanup:
- }
-
- CK_RV
--NSC_Decapsulate(CK_SESSION_HANDLE hSession,
-- CK_MECHANISM_PTR pMechanism,
-- CK_OBJECT_HANDLE hPrivateKey,
-- CK_BYTE_PTR pCiphertext,
-- CK_ULONG ulCiphertextLen,
-- CK_ATTRIBUTE_PTR pTemplate,
-- CK_ULONG ulAttributeCount,
-- /* out */ CK_OBJECT_HANDLE_PTR phKey)
-+NSC_DecapsulateKey(CK_SESSION_HANDLE hSession,
-+ CK_MECHANISM_PTR pMechanism,
-+ CK_OBJECT_HANDLE hPrivateKey,
-+ CK_ATTRIBUTE_PTR pTemplate,
-+ CK_ULONG ulAttributeCount,
-+ CK_BYTE_PTR pCiphertext,
-+ CK_ULONG ulCiphertextLen,
-+ /* out */ CK_OBJECT_HANDLE_PTR phKey)
- {
- SFTKSession *session = NULL;
- SFTKSlot *slot = NULL;
-@@ -270,9 +330,13 @@ NSC_Decapsulate(CK_SESSION_HANDLE hSessi
-
- SFTKObject *decapsulationKeyObject = NULL;
- SFTKAttribute *decapsulationKey = NULL;
-+ CK_ULONG paramSet = 0; /* use a generic U_LONG so we can handle
-+ * different param set types based on the
-+ * Mechanism value */
-
- CK_RV crv;
- SFTKFreeStatus status;
-+ KyberParams kyberParams;
-
- CHECK_FORK();
-
-@@ -283,11 +347,6 @@ NSC_Decapsulate(CK_SESSION_HANDLE hSessi
- if (!sftk_kem_ValidateMechanism(pMechanism)) {
- return CKR_MECHANISM_INVALID;
- }
--
-- CK_ULONG ciphertextLen = sftk_kem_CiphertextLen(pMechanism);
-- if (ulCiphertextLen < ciphertextLen) {
-- return CKR_ARGUMENTS_BAD;
-- }
- *phKey = CK_INVALID_HANDLE;
-
- session = sftk_SessionFromHandle(hSession);
-@@ -323,20 +382,39 @@ NSC_Decapsulate(CK_SESSION_HANDLE hSessi
- goto cleanup;
- }
-
-- SECItem privKey = { siBuffer, decapsulationKey->attrib.pValue, decapsulationKey->attrib.ulValueLen };
-+ crv = sftk_kem_getParamSet(pMechanism, decapsulationKeyObject, ¶mSet);
-+ if (crv != CKR_OK) {
-+ goto cleanup;
-+ }
-+
-+ CK_ULONG ciphertextLen = sftk_kem_CiphertextLen(pMechanism, paramSet);
-+ if (!pCiphertext || ulCiphertextLen != ciphertextLen || ciphertextLen == 0) {
-+ crv = CKR_ARGUMENTS_BAD;
-+ goto cleanup;
-+ }
-+
-+ SECItem privKey = { siBuffer, decapsulationKey->attrib.pValue,
-+ decapsulationKey->attrib.ulValueLen };
- SECItem ciphertext = { siBuffer, pCiphertext, ulCiphertextLen };
-
-- /* The length of secretBuf can be increased if we ever support other KEMs */
-- uint8_t secretBuf[KYBER_SHARED_SECRET_BYTES] = { 0 };
-+ /* The length of secretBuf can be increased if we ever support other KEMs
-+ * by changing the define at the top of this file */
-+ uint8_t secretBuf[MAX_SHARED_SECRET_BYTES] = { 0 };
- SECItem secret = { siBuffer, secretBuf, sizeof secretBuf };
-+ key->isFIPS = sftk_operationIsFIPS(slot, pMechanism, CKA_DECAPSULATE,
-+ key, 0);
-+ key->source = SFTK_SOURCE_KEA;
-
- switch (pMechanism->mechanism) {
-+#ifndef NSS_DISABLE_KYBER
- case CKM_NSS_KYBER:
-+#endif
- case CKM_NSS_ML_KEM:
-- PORT_Assert(secret.len == KYBER_SHARED_SECRET_BYTES);
-- CK_NSS_KEM_PARAMETER_SET_TYPE *pParameter = pMechanism->pParameter;
-- KyberParams kyberParams = sftk_kyber_PK11ParamToInternal(*pParameter);
-- SECStatus rv = Kyber_Decapsulate(kyberParams, &privKey, &ciphertext, &secret);
-+ case CKM_ML_KEM:
-+ kyberParams = sftk_kyber_PK11ParamToInternal(paramSet);
-+ PORT_Assert(secret.len >= KYBER_SHARED_SECRET_BYTES);
-+ SECStatus rv = Kyber_Decapsulate(kyberParams, &privKey,
-+ &ciphertext, &secret);
- if (rv != SECSuccess) {
- crv = (PORT_GetError() == SEC_ERROR_INVALID_ARGS) ? CKR_ARGUMENTS_BAD : CKR_FUNCTION_FAILED;
- goto cleanup;
-@@ -359,6 +437,7 @@ NSC_Decapsulate(CK_SESSION_HANDLE hSessi
- }
-
- cleanup:
-+ PORT_SafeZero(secretBuf, sizeof(secretBuf));
- if (session) {
- sftk_FreeSession(session);
- }
-@@ -379,3 +458,36 @@ cleanup:
- }
- return crv;
- }
-+
-+/* PKCS #11 final spec moved som the the arguments around (to make
-+ * NSC_EncapsulateKey and NSC_DecapsulateKey match, keep the old version for
-+ * the vendor defined for backward compatibility */
-+CK_RV
-+NSC_Encapsulate(CK_SESSION_HANDLE hSession,
-+ CK_MECHANISM_PTR pMechanism,
-+ CK_OBJECT_HANDLE hPublicKey,
-+ CK_ATTRIBUTE_PTR pTemplate,
-+ CK_ULONG ulAttributeCount,
-+ /* out */ CK_OBJECT_HANDLE_PTR phKey,
-+ /* out */ CK_BYTE_PTR pCiphertext,
-+ /* out */ CK_ULONG_PTR pulCiphertextLen)
-+{
-+ return NSC_EncapsulateKey(hSession, pMechanism, hPublicKey,
-+ pTemplate, ulAttributeCount,
-+ pCiphertext, pulCiphertextLen, phKey);
-+}
-+
-+CK_RV
-+NSC_Decapsulate(CK_SESSION_HANDLE hSession,
-+ CK_MECHANISM_PTR pMechanism,
-+ CK_OBJECT_HANDLE hPrivateKey,
-+ CK_BYTE_PTR pCiphertext,
-+ CK_ULONG ulCiphertextLen,
-+ CK_ATTRIBUTE_PTR pTemplate,
-+ CK_ULONG ulAttributeCount,
-+ /* out */ CK_OBJECT_HANDLE_PTR phKey)
-+{
-+ return NSC_DecapsulateKey(hSession, pMechanism, hPrivateKey, pTemplate,
-+ ulAttributeCount, pCiphertext, ulCiphertextLen,
-+ phKey);
-+}
-diff -up ./lib/softoken/pkcs11c.c.mlkem_p256 ./lib/softoken/pkcs11c.c
---- ./lib/softoken/pkcs11c.c.mlkem_p256 2025-06-25 16:47:19.369362850 -0700
-+++ ./lib/softoken/pkcs11c.c 2025-06-25 16:47:19.380362992 -0700
-@@ -5029,6 +5029,64 @@ loser:
- return crv;
- }
-
-+PRBool
-+sftk_compareKeysEqual(CK_SESSION_HANDLE hSession,
-+ CK_OBJECT_HANDLE key1, CK_OBJECT_HANDLE key2)
-+{
-+ PRBool result = PR_FALSE;
-+ SFTKSession *session;
-+ SFTKObject *key1obj = NULL;
-+ SFTKObject *key2obj = NULL;
-+ SFTKAttribute *att1 = NULL;
-+ SFTKAttribute *att2 = NULL;
-+
-+ /* fetch the pkcs11 objects from the handles */
-+ session = sftk_SessionFromHandle(hSession);
-+ if (session == NULL) {
-+ return CKR_SESSION_HANDLE_INVALID;
-+ }
-+
-+ key1obj = sftk_ObjectFromHandle(key1, session);
-+ key2obj = sftk_ObjectFromHandle(key2, session);
-+ sftk_FreeSession(session);
-+ if ((key1obj == NULL) || (key2obj == NULL)) {
-+ goto loser;
-+ }
-+ /* fetch the value attributes */
-+ att1 = sftk_FindAttribute(key1obj, CKA_VALUE);
-+ if (att1 == NULL) {
-+ goto loser;
-+ }
-+ att2 = sftk_FindAttribute(key2obj, CKA_VALUE);
-+ if (att2 == NULL) {
-+ goto loser;
-+ }
-+ /* make sure that they are equal */
-+ if (att1->attrib.ulValueLen != att2->attrib.ulValueLen) {
-+ goto loser;
-+ }
-+ if (PORT_Memcmp(att1->attrib.pValue, att2->attrib.pValue,
-+ att1->attrib.ulValueLen) != 0) {
-+ goto loser;
-+ }
-+ result = PR_TRUE;
-+loser:
-+ if (key1obj) {
-+ sftk_FreeObject(key1obj);
-+ }
-+ if (key2obj) {
-+ sftk_FreeObject(key1obj);
-+ }
-+ if (att1) {
-+ sftk_FreeAttribute(att1);
-+ }
-+ if (att2) {
-+ sftk_FreeAttribute(att2);
-+ }
-+ return result;
-+}
-+
-+
- #define PAIRWISE_DIGEST_LENGTH SHA1_LENGTH /* 160-bits */
- #define PAIRWISE_MESSAGE_LENGTH 20 /* 160-bits */
-
-@@ -5043,7 +5101,8 @@ loser:
- */
- static CK_RV
- sftk_PairwiseConsistencyCheck(CK_SESSION_HANDLE hSession, SFTKSlot *slot,
-- SFTKObject *publicKey, SFTKObject *privateKey, CK_KEY_TYPE keyType)
-+ SFTKObject *publicKey, SFTKObject *privateKey,
-+ CK_KEY_TYPE keyType)
- {
- /*
- * Key type Mechanism type
-@@ -5058,11 +5117,15 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
- *
- * None of these mechanisms has a parameter.
- *
-- * For derive CKK_DH => CKM_DH_PKCS_DERIVE
-- * CKK_EC => CKM_ECDH1_DERIVE
-- * CKK_EC_MONTGOMERY => CKM_ECDH1_DERIVE
-+ * For derive: regenerate public key from the private key
-+ * CKK_DH => DH_Derive
-+ * CKK_EC => EC_NewKeyFromSeed
-+ * CKK_EC_MONTGOMERY => EC_NewKeyFromSeed
- * others => CKM_INVALID_MECHANISM
- *
-+ * For KEM mechanisms:
-+ * CKK_NSS_KYBER => don't
-+ *
- * The parameters for these mechanisms is the public key.
- */
- CK_MECHANISM mech = { 0, NULL, 0 };
-@@ -5072,6 +5135,7 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
- PRBool isEncryptable = PR_FALSE;
- PRBool canSignVerify = PR_FALSE;
- PRBool isDerivable = PR_FALSE;
-+ PRBool isKEM = PR_FALSE;
- CK_RV crv;
-
- /* Variables used for Encrypt/Decrypt functions. */
-@@ -5089,35 +5153,42 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
- unsigned char *known_digest = (unsigned char *)"Mozilla Rules the World through NSS!";
- unsigned char *signature;
- CK_ULONG signature_length;
-+ SFTKAttribute *attribute;
-
-- if (keyType == CKK_RSA) {
-- SFTKAttribute *attribute;
--
-- /* Get modulus length of private key. */
-- attribute = sftk_FindAttribute(privateKey, CKA_MODULUS);
-- if (attribute == NULL) {
-- return CKR_DEVICE_ERROR;
-- }
-- modulusLen = attribute->attrib.ulValueLen;
-- if (*(unsigned char *)attribute->attrib.pValue == 0) {
-- modulusLen--;
-- }
-- sftk_FreeAttribute(attribute);
-- } else if (keyType == CKK_DSA) {
-- SFTKAttribute *attribute;
--
-- /* Get subprime length of private key. */
-- attribute = sftk_FindAttribute(privateKey, CKA_SUBPRIME);
-- if (attribute == NULL) {
-- return CKR_DEVICE_ERROR;
-- }
-- subPrimeLen = attribute->attrib.ulValueLen;
-- if (subPrimeLen > 1 && *(unsigned char *)attribute->attrib.pValue == 0) {
-- subPrimeLen--;
-- }
-- sftk_FreeAttribute(attribute);
-+ switch (keyType) {
-+ case CKK_RSA:
-+ /* Get modulus length of private key. */
-+ attribute = sftk_FindAttribute(privateKey, CKA_MODULUS);
-+ if (attribute == NULL) {
-+ return CKR_DEVICE_ERROR;
-+ }
-+ modulusLen = attribute->attrib.ulValueLen;
-+ if (*(unsigned char *)attribute->attrib.pValue == 0) {
-+ modulusLen--;
-+ }
-+ sftk_FreeAttribute(attribute);
-+ break;
-+ case CKK_DSA:
-+ /* Get subprime length of private key. */
-+ attribute = sftk_FindAttribute(privateKey, CKA_SUBPRIME);
-+ if (attribute == NULL) {
-+ return CKR_DEVICE_ERROR;
-+ }
-+ subPrimeLen = attribute->attrib.ulValueLen;
-+ if (subPrimeLen > 1 &&
-+ *(unsigned char *)attribute->attrib.pValue == 0) {
-+ subPrimeLen--;
-+ }
-+ break;
-+ case CKK_NSS_KYBER:
-+ case CKK_NSS_ML_KEM:
-+ /* these aren't fips. we use them to generate key without a
-+ * pairwise consistency check */
-+ return CKR_OK;
- }
-
-+
-+
- /**************************************************/
- /* Pairwise Consistency Check of Encrypt/Decrypt. */
- /**************************************************/
-@@ -5473,6 +5544,79 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
- return crv;
- }
- }
-+ isKEM = sftk_isTrue(privateKey, CKA_ENCAPSULATE);
-+ if (isKEM) {
-+ unsigned char *cipher_text = NULL;
-+ CK_ULONG cipher_text_length = 0;
-+ CK_OBJECT_HANDLE key1 = CK_INVALID_HANDLE;
-+ CK_OBJECT_HANDLE key2 = CK_INVALID_HANDLE;
-+ CK_KEY_TYPE genType = CKO_SECRET_KEY;
-+ CK_ATTRIBUTE template = { CKA_KEY_TYPE, NULL, 0 };
-+
-+ template.pValue = &genType;
-+ template.ulValueLen = sizeof(genType);
-+ crv = CKR_OK;
-+ switch (keyType) {
-+ case CKK_ML_KEM:
-+ cipher_text_length = KYBER_SHARED_SECRET_BYTES;
-+ mech.mechanism = CKM_ML_KEM;
-+ break;
-+ case CKK_RSA:
-+ if (!isEncryptable) {
-+ /* already handled the pairwise test, no need to
-+ * do it again */
-+ goto kem_done;
-+ }
-+ cipher_text_length = modulusLen;
-+ mech.mechanism = CKM_RSA_PKCS;
-+ break;
-+ case CKK_EC:
-+ case CKK_EC_MONTGOMERY:
-+ if (!isDerivable) {
-+ /* again, already handled above, no need to check again
-+ */
-+ goto kem_done;
-+ }
-+ cipher_text_length = MAX_ECKEY_LEN;
-+ mech.mechanism = CKM_ECDH1_DERIVE;
-+ break;
-+ default:
-+ return CKR_DEVICE_ERROR;
-+ }
-+
-+ /* Allocate space for signature data. */
-+ cipher_text = (unsigned char *)PORT_ZAlloc(cipher_text_length);
-+ if (cipher_text == NULL) {
-+ return CKR_HOST_MEMORY;
-+ }
-+ crv = NSC_Encapsulate(hSession, &mech, publicKey->handle, &template, 1,
-+ &key1, cipher_text, &cipher_text_length);
-+ if (crv != CKR_OK) {
-+ goto kem_done;
-+ }
-+ crv = NSC_Decapsulate(hSession, &mech, privateKey->handle,
-+ cipher_text, cipher_text_length, &template, 1,
-+ &key2);
-+ if (crv != CKR_OK) {
-+ goto kem_done;
-+ }
-+ if (!sftk_compareKeysEqual(hSession, key1, key2)) {
-+ crv = CKR_DEVICE_ERROR;
-+ goto kem_done;
-+ }
-+kem_done:
-+ /* PORT_Free already checks for NULL */
-+ PORT_Free(cipher_text);
-+ if (key1 != CK_INVALID_HANDLE) {
-+ NSC_DestroyObject(hSession, key1);
-+ }
-+ if (key2 != CK_INVALID_HANDLE) {
-+ NSC_DestroyObject(hSession, key2);
-+ }
-+ if (crv != CKR_OK) {
-+ return CKR_DEVICE_ERROR;
-+ }
-+ }
-
- return CKR_OK;
- }
-@@ -5547,6 +5691,10 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
- ckKyberParamSet = *(CK_NSS_KEM_PARAMETER_SET_TYPE *)pPublicKeyTemplate[i].pValue;
- continue;
- }
-+ if (pPublicKeyTemplate[i].type == CKA_PARAMETER_SET) {
-+ ckKyberParamSet = *(CK_ML_KEM_PARAMETER_SET_TYPE *)pPublicKeyTemplate[i].pValue;
-+ continue;
-+ }
-
- crv = sftk_AddAttributeType(publicKey,
- sftk_attr_expand(&pPublicKeyTemplate[i]));
-@@ -5883,8 +6031,9 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
- /* extract the necessary parameters and copy them to private keys */
- crv = sftk_Attribute2SSecItem(NULL, &ecEncodedParams, publicKey,
- CKA_EC_PARAMS);
-- if (crv != CKR_OK)
-+ if (crv != CKR_OK) {
- break;
-+ }
-
- crv = sftk_AddAttributeType(privateKey, CKA_EC_PARAMS,
- sftk_item_expand(&ecEncodedParams));
-@@ -5895,11 +6044,12 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
-
- /* Decode ec params before calling EC_NewKey */
- rv = EC_DecodeParams(&ecEncodedParams, &ecParams);
-- SECITEM_ZfreeItem(&ecEncodedParams, PR_FALSE);
- if (rv != SECSuccess) {
- crv = sftk_MapCryptError(PORT_GetError());
-+ SECITEM_ZfreeItem(&ecEncodedParams, PR_FALSE);
- break;
- }
-+ SECITEM_ZfreeItem(&ecEncodedParams, PR_FALSE);
- rv = EC_NewKey(ecParams, &ecPriv);
- if (rv != SECSuccess) {
- if (PORT_GetError() == SEC_ERROR_LIBRARY_FAILURE) {
-@@ -5943,10 +6093,18 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
- PORT_FreeArena(ecPriv->ecParams.arena, PR_TRUE);
- break;
-
-+#ifndef NSS_DISABLE_KYBER
- case CKM_NSS_KYBER_KEY_PAIR_GEN:
-+ key_type = CKK_NSS_KYBER;
-+ goto generate_mlkem;
-+#endif
- case CKM_NSS_ML_KEM_KEY_PAIR_GEN:
-+ key_type = CKK_NSS_ML_KEM;
-+ goto generate_mlkem;
-+ case CKM_ML_KEM_KEY_PAIR_GEN:
-+ key_type = CKK_ML_KEM;
-+generate_mlkem:
- sftk_DeleteAttributeType(privateKey, CKA_NSS_DB);
-- key_type = CKK_NSS_KYBER;
-
- SECItem privKey = { siBuffer, NULL, 0 };
- SECItem pubKey = { siBuffer, NULL, 0 };
-@@ -5969,8 +6127,8 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
- if (crv != CKR_OK) {
- goto kyber_done;
- }
-- crv = sftk_AddAttributeType(publicKey, CKA_NSS_PARAMETER_SET,
-- &ckKyberParamSet, sizeof(CK_NSS_KEM_PARAMETER_SET_TYPE));
-+ crv = sftk_AddAttributeType(publicKey, CKA_PARAMETER_SET,
-+ &ckKyberParamSet, sizeof(CK_ML_KEM_PARAMETER_SET_TYPE));
- if (crv != CKR_OK) {
- goto kyber_done;
- }
-@@ -5979,8 +6137,9 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
- if (crv != CKR_OK) {
- goto kyber_done;
- }
-- crv = sftk_AddAttributeType(privateKey, CKA_NSS_PARAMETER_SET,
-- &ckKyberParamSet, sizeof(CK_NSS_KEM_PARAMETER_SET_TYPE));
-+
-+ crv = sftk_AddAttributeType(privateKey, CKA_PARAMETER_SET,
-+ &ckKyberParamSet, sizeof(CK_ML_KEM_PARAMETER_SET_TYPE));
- if (crv != CKR_OK) {
- goto kyber_done;
- }
-@@ -6130,7 +6289,8 @@ NSC_GenerateKeyPair(CK_SESSION_HANDLE hS
- &cktrue, sizeof(CK_BBOOL));
- }
-
-- if (crv == CKR_OK && pMechanism->mechanism != CKM_NSS_ECDHE_NO_PAIRWISE_CHECK_KEY_PAIR_GEN && key_type != CKK_NSS_KYBER) {
-+ if (crv == CKR_OK &&
-+ pMechanism->mechanism != CKM_NSS_ECDHE_NO_PAIRWISE_CHECK_KEY_PAIR_GEN) {
- /* Perform FIPS 140-2 pairwise consistency check. */
- crv = sftk_PairwiseConsistencyCheck(hSession, slot,
- publicKey, privateKey, key_type);
-@@ -8598,6 +8758,8 @@ NSC_DeriveKey(CK_SESSION_HANDLE hSession
-
- crv = sftk_forceAttribute(key, CKA_VALUE, buf, keySize);
- PORT_ZFree(buf, tmpKeySize);
-+ /* preserve the source of the original base key */
-+ /* key->source = sourceKey->source; */
- sftk_FreeAttribute(att2);
- sftk_FreeObject(paramKey);
- break;
-diff -up ./lib/softoken/pkcs11.c.mlkem_p256 ./lib/softoken/pkcs11.c
---- ./lib/softoken/pkcs11.c.mlkem_p256 2025-06-25 16:47:19.369362850 -0700
-+++ ./lib/softoken/pkcs11.c 2025-06-25 16:47:19.379362979 -0700
-@@ -302,6 +302,7 @@ struct mechanismList {
- #define CKF_SN_VR CKF_SIGN | CKF_VERIFY
- #define CKF_SN_RE CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER
- #define CKF_EN_DE_MSG CKF_ENCRYPT | CKF_DECRYPT | CKF_MESSAGE_ENCRYPT | CKF_MESSAGE_DECRYPT
-+#define CKF_KEM CKF_ENCAPSULATE | CKF_DECAPSULATE
-
- #define CKF_EN_DE_WR_UN CKF_EN_DE | CKF_WR_UN
- #define CKF_SN_VR_RE CKF_SN_VR | CKF_SN_RE
-@@ -651,10 +652,14 @@ static const struct mechanismList mechan
- { CKM_NSS_IKE1_PRF_DERIVE, { 8, 64, CKF_DERIVE }, PR_TRUE },
- { CKM_NSS_IKE1_APP_B_PRF_DERIVE, { 8, 255 * 64, CKF_DERIVE }, PR_TRUE },
- /* -------------------- Kyber Operations ----------------------- */
-+#ifndef NSS_DISABLE_KYBER
- { CKM_NSS_KYBER_KEY_PAIR_GEN, { 0, 0, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
-- { CKM_NSS_KYBER, { 0, 0, 0 }, PR_TRUE },
-+ { CKM_NSS_KYBER, { 0, 0, CKF_KEM }, PR_TRUE },
-+#endif
- { CKM_NSS_ML_KEM_KEY_PAIR_GEN, { 0, 0, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
-- { CKM_NSS_ML_KEM, { 0, 0, 0 }, PR_TRUE },
-+ { CKM_NSS_ML_KEM, { 0, 0, CKF_KEM }, PR_TRUE },
-+ { CKM_ML_KEM_KEY_PAIR_GEN, { 0, 0, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
-+ { CKM_ML_KEM, { 0, 0, CKF_KEM }, PR_TRUE },
- };
- static const CK_ULONG mechanismCount = sizeof(mechanisms) / sizeof(mechanisms[0]);
-
-@@ -1036,6 +1041,7 @@ sftk_handlePublicKeyObject(SFTKSession *
- CK_BBOOL wrap = CK_TRUE;
- CK_BBOOL derive = CK_FALSE;
- CK_BBOOL verify = CK_TRUE;
-+ CK_BBOOL encapsulate = CK_FALSE;
- CK_RV crv;
-
- switch (key_type) {
-@@ -1109,16 +1115,22 @@ sftk_handlePublicKeyObject(SFTKSession *
- recover = CK_FALSE;
- wrap = CK_FALSE;
- break;
-+#ifndef NSS_DISABLE_KYBER
- case CKK_NSS_KYBER:
-+#endif
- case CKK_NSS_ML_KEM:
-- if (!sftk_hasAttribute(object, CKA_NSS_PARAMETER_SET)) {
-- return CKR_TEMPLATE_INCOMPLETE;
-+ case CKK_ML_KEM:
-+ if (!sftk_hasAttribute(object, CKA_PARAMETER_SET)) {
-+ if (!sftk_hasAttribute(object, CKA_NSS_PARAMETER_SET)) {
-+ return CKR_TEMPLATE_INCOMPLETE;
-+ }
- }
- derive = CK_FALSE;
- verify = CK_FALSE;
- encrypt = CK_FALSE;
- recover = CK_FALSE;
- wrap = CK_FALSE;
-+ encapsulate = CK_TRUE;
- break;
- default:
- return CKR_ATTRIBUTE_VALUE_INVALID;
-@@ -1144,6 +1156,10 @@ sftk_handlePublicKeyObject(SFTKSession *
- crv = sftk_defaultAttribute(object, CKA_DERIVE, &derive, sizeof(CK_BBOOL));
- if (crv != CKR_OK)
- return crv;
-+ crv = sftk_defaultAttribute(object, CKA_ENCAPSULATE, &encapsulate,
-+ sizeof(CK_BBOOL));
-+ if (crv != CKR_OK)
-+ return crv;
-
- object->objectInfo = sftk_GetPubKey(object, key_type, &crv);
- if (object->objectInfo == NULL) {
-@@ -1196,6 +1212,7 @@ sftk_handlePrivateKeyObject(SFTKSession
- CK_BBOOL recover = CK_TRUE;
- CK_BBOOL wrap = CK_TRUE;
- CK_BBOOL derive = CK_TRUE;
-+ CK_BBOOL encapsulate = CK_FALSE;
- CK_BBOOL ckfalse = CK_FALSE;
- PRBool createObjectInfo = PR_TRUE;
- PRBool fillPrivateKey = PR_FALSE;
-@@ -1323,15 +1340,24 @@ sftk_handlePrivateKeyObject(SFTKSession
- derive = CK_TRUE;
- createObjectInfo = PR_FALSE;
- break;
-+#ifndef NSS_DISABLE_KYBER
- case CKK_NSS_KYBER:
-+#endif
- case CKK_NSS_ML_KEM:
-+ case CKK_ML_KEM:
- if (!sftk_hasAttribute(object, CKA_KEY_TYPE)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
- if (!sftk_hasAttribute(object, CKA_VALUE)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
-+ if (!sftk_hasAttribute(object, CKA_PARAMETER_SET)) {
-+ if (!sftk_hasAttribute(object, CKA_NSS_PARAMETER_SET)) {
-+ return CKR_TEMPLATE_INCOMPLETE;
-+ }
-+ }
- encrypt = sign = recover = wrap = CK_FALSE;
-+ encapsulate = CK_TRUE;
- break;
- default:
- return CKR_ATTRIBUTE_VALUE_INVALID;
-@@ -1361,6 +1387,9 @@ sftk_handlePrivateKeyObject(SFTKSession
- crv = sftk_defaultAttribute(object, CKA_DERIVE, &derive, sizeof(CK_BBOOL));
- if (crv != CKR_OK)
- return crv;
-+ crv = sftk_defaultAttribute(object, CKA_DECAPSULATE, &encapsulate, sizeof(CK_BBOOL));
-+ if (crv != CKR_OK)
-+ return crv;
- /* the next two bits get modified only in the key gen and token cases */
- crv = sftk_forceAttribute(object, CKA_ALWAYS_SENSITIVE,
- &ckfalse, sizeof(CK_BBOOL));
-@@ -1372,7 +1401,6 @@ sftk_handlePrivateKeyObject(SFTKSession
- return crv;
-
- /* should we check the non-token RSA private keys? */
--
- if (sftk_isTrue(object, CKA_TOKEN)) {
- SFTKSlot *slot = session->slot;
- SFTKDBHandle *keyHandle = sftk_getKeyDB(slot);
-@@ -2017,8 +2045,11 @@ sftk_GetPubKey(SFTKObject *object, CK_KE
- crv = CKR_ATTRIBUTE_VALUE_INVALID;
- }
- break;
-+#ifndef NSS_DISABLE_KYBER
- case CKK_NSS_KYBER:
-+#endif
- case CKK_NSS_ML_KEM:
-+ case CKK_ML_KEM:
- crv = CKR_OK;
- break;
- default:
-@@ -2187,8 +2218,11 @@ sftk_mkPrivKey(SFTKObject *object, CK_KE
- }
- break;
-
-+#ifndef NSS_DISABLE_KYBER
- case CKK_NSS_KYBER:
-+#endif
- case CKK_NSS_ML_KEM:
-+ case CKK_ML_KEM:
- break;
-
- default:
-diff -up ./lib/softoken/pkcs11u.c.mlkem_p256 ./lib/softoken/pkcs11u.c
---- ./lib/softoken/pkcs11u.c.mlkem_p256 2025-06-25 16:47:19.361362747 -0700
-+++ ./lib/softoken/pkcs11u.c 2025-06-25 16:47:19.380362992 -0700
-@@ -555,6 +555,11 @@ sftk_isTrue(SFTKObject *object, CK_ATTRI
- if (attribute == NULL) {
- return PR_FALSE;
- }
-+ if ((attribute->attrib.pValue == NULL) ||
-+ (attribute->attrib.ulValueLen != sizeof(CK_BBOOL))) {
-+ return PR_FALSE;
-+ }
-+
- tok = (PRBool)(*(CK_BBOOL *)attribute->attrib.pValue);
- sftk_FreeAttribute(attribute);
-
-diff -up ./lib/softoken/sdb.c.mlkem_p256 ./lib/softoken/sdb.c
---- ./lib/softoken/sdb.c.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/softoken/sdb.c 2025-06-25 16:47:19.380362992 -0700
-@@ -113,6 +113,7 @@ static const CK_ATTRIBUTE_TYPE known_att
- CKA_RESOLUTION, CKA_CHAR_ROWS, CKA_CHAR_COLUMNS, CKA_COLOR,
- CKA_BITS_PER_PIXEL, CKA_CHAR_SETS, CKA_ENCODING_METHODS, CKA_MIME_TYPES,
- CKA_MECHANISM_TYPE, CKA_REQUIRED_CMS_ATTRIBUTES,
-+ CKA_ENCAPSULATE, CKA_DECAPSULATE, CKA_PARAMETER_SET,
- CKA_DEFAULT_CMS_ATTRIBUTES, CKA_SUPPORTED_CMS_ATTRIBUTES,
- CKA_WRAP_TEMPLATE, CKA_UNWRAP_TEMPLATE, CKA_NSS_TRUST, CKA_NSS_URL,
- CKA_NSS_EMAIL, CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP,
-diff -up ./lib/softoken/sftkdb.c.mlkem_p256 ./lib/softoken/sftkdb.c
---- ./lib/softoken/sftkdb.c.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/softoken/sftkdb.c 2025-06-25 16:47:19.380362992 -0700
-@@ -1763,6 +1763,7 @@ static const CK_ATTRIBUTE_TYPE known_att
- CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS,
- CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE,
- CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES,
-+ CKA_ENCAPSULATE, CKA_DECAPSULATE, CKA_PARAMETER_SET,
- CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NSS_URL, CKA_NSS_EMAIL,
- CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP,
- CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES,
-diff -up ./lib/softoken/softoken.h.mlkem_p256 ./lib/softoken/softoken.h
---- ./lib/softoken/softoken.h.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/softoken/softoken.h 2025-06-25 16:47:19.380362992 -0700
-@@ -137,6 +137,24 @@ extern void sftk_AuditDeriveKey(CK_SESSI
- extern void sftk_AuditDigestKey(CK_SESSION_HANDLE hSession,
- CK_OBJECT_HANDLE hKey, CK_RV rv);
-
-+extern void sftk_AuditEncapsulate(CK_SESSION_HANDLE hSession,
-+ CK_MECHANISM_PTR pMechanism,
-+ CK_OBJECT_HANDLE hPublicKey,
-+ CK_ATTRIBUTE_PTR pTemplate,
-+ CK_ULONG ulAttributeCount,
-+ CK_OBJECT_HANDLE_PTR phKey,
-+ CK_BYTE_PTR pCiphertext,
-+ CK_ULONG_PTR pulCiphertextLen, CK_RV rv);
-+
-+extern void sftk_AuditDecapsulate(CK_SESSION_HANDLE hSession,
-+ CK_MECHANISM_PTR pMechanism,
-+ CK_OBJECT_HANDLE hPrivateKey,
-+ CK_BYTE_PTR pCiphertext,
-+ CK_ULONG ulCiphertextLen,
-+ CK_ATTRIBUTE_PTR pTemplate,
-+ CK_ULONG ulAttributeCount,
-+ CK_OBJECT_HANDLE_PTR phKey, CK_RV rv);
-+
- /*
- ** FIPS 140-2 Error state
- */
-diff -up ./lib/softoken/softoknt.h.mlkem_p256 ./lib/softoken/softoknt.h
---- ./lib/softoken/softoknt.h.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/softoken/softoknt.h 2025-06-25 16:47:19.380362992 -0700
-@@ -40,7 +40,9 @@ typedef enum {
- NSS_AUDIT_SELF_TEST,
- NSS_AUDIT_SET_PIN,
- NSS_AUDIT_UNWRAP_KEY,
-- NSS_AUDIT_WRAP_KEY
-+ NSS_AUDIT_WRAP_KEY,
-+ NSS_AUDIT_ENCAPSULATE_KEY,
-+ NSS_AUDIT_DECAPSULATE_KEY
- } NSSAuditType;
-
- #endif /* _SOFTOKNT_H_ */
-diff -up ./lib/ssl/sslimpl.h.mlkem_p256 ./lib/ssl/sslimpl.h
---- ./lib/ssl/sslimpl.h.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/ssl/sslimpl.h 2025-06-25 16:47:19.381363005 -0700
-@@ -130,7 +130,13 @@ typedef enum { SSLAppOpRead = 0,
- #define DTLS_RETRANSMIT_FINISHED_MS 30000
-
- /* default number of entries in namedGroupPreferences */
-+#ifndef NSS_DISABLE_KYBER
-+/* this define is checked against the namedGroup table
-+ * and compile time asserts kick in if it doesn't match */
-+#define SSL_NAMED_GROUP_COUNT 34
-+#else
- #define SSL_NAMED_GROUP_COUNT 33
-+#endif
-
- /* The maximum DH and RSA bit-length supported. */
- #define SSL_MAX_DH_KEY_BITS 8192
-diff -up ./lib/ssl/sslsock.c.mlkem_p256 ./lib/ssl/sslsock.c
---- ./lib/ssl/sslsock.c.mlkem_p256 2025-06-25 16:47:19.358362709 -0700
-+++ ./lib/ssl/sslsock.c 2025-06-25 16:47:19.381363005 -0700
-@@ -22,6 +22,7 @@
- #include "tls13ech.h"
- #include "tls13psk.h"
- #include "tls13subcerts.h"
-+#include "secmodti.h" /* until SEC_OID_SECP256R1MLKEM768 is upstream */
-
- static const sslSocketOps ssl_default_ops = { /* No SSL. */
- ssl_DefConnect,
-@@ -158,16 +159,24 @@ static const PRUint16 srtpCiphers[] = {
- ssl_grp_ffdhe_##size, size, ssl_kea_dh, \
- SEC_OID_TLS_FFDHE_##size, PR_TRUE \
- }
-+#define HYGROUP(kem, ec, size, kem_oid, ec_oid, assumeSupported) \
-+ { \
-+ ssl_grp_kem_##kem##ec, size, ssl_kea_ecdh_hybrid, \
-+ SEC_OID_##kem_oid##ec_oid, assumeSupported \
-+ }
-
- const sslNamedGroupDef ssl_named_groups[] = {
-- /* Note that 256 for 25519 is a lie, but we only use it for checking bit
-- * security and expect 256 bits there (not 255). */
-+ /* Note that 256 for 25519 and hybrid is a lie, but we only use it for
-+ * checking bit security and expect 256 bits there (not 255). */
-+ HYGROUP(mlkem768, x25519, 256, MLKEM768, X25519, PR_TRUE),
-+ HYGROUP(mlkem768, secp256r1, 256, MLKEM768, SECP256R1, PR_TRUE),
- { ssl_grp_ec_curve25519, 256, ssl_kea_ecdh, SEC_OID_CURVE25519, PR_TRUE },
- ECGROUP(secp256r1, 256, SECP256R1, PR_TRUE),
- ECGROUP(secp384r1, 384, SECP384R1, PR_TRUE),
- ECGROUP(secp521r1, 521, SECP521R1, PR_TRUE),
-+#ifndef NSS_DISABLE_KYBER
- { ssl_grp_kem_xyber768d00, 256, ssl_kea_ecdh_hybrid, SEC_OID_XYBER768D00, PR_TRUE },
-- { ssl_grp_kem_mlkem768x25519, 256, ssl_kea_ecdh_hybrid, SEC_OID_MLKEM768X25519, PR_TRUE },
-+#endif
- FFGROUP(2048),
- FFGROUP(3072),
- FFGROUP(4096),
-diff -up ./lib/ssl/sslt.h.mlkem_p256 ./lib/ssl/sslt.h
---- ./lib/ssl/sslt.h.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/ssl/sslt.h 2025-06-25 16:47:19.381363005 -0700
-@@ -261,7 +261,10 @@ typedef enum {
- ssl_grp_ffdhe_6144 = 259,
- ssl_grp_ffdhe_8192 = 260,
- ssl_grp_kem_mlkem768x25519 = 4588,
-+ ssl_grp_kem_secp256r1mlkem768 = 4587,
-+#ifndef NSS_DISABLE_KYBER
- ssl_grp_kem_xyber768d00 = 25497, /* draft-tls-westerbaan-xyber768d00-02 */
-+#endif
- ssl_grp_none = 65537, /* special value */
- ssl_grp_ffdhe_custom = 65538 /* special value */
- } SSLNamedGroup;
-diff -up ./lib/ssl/tls13con.c.mlkem_p256 ./lib/ssl/tls13con.c
---- ./lib/ssl/tls13con.c.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/ssl/tls13con.c 2025-06-25 16:47:19.382363018 -0700
-@@ -382,13 +382,16 @@ tls13_CreateKEMKeyPair(sslSocket *ss, co
- CK_NSS_KEM_PARAMETER_SET_TYPE paramSet;
-
- switch (groupDef->name) {
-+#ifndef NSS_DISABLE_KYBER
- case ssl_grp_kem_xyber768d00:
- mechanism = CKM_NSS_KYBER_KEY_PAIR_GEN;
- paramSet = CKP_NSS_KYBER_768_ROUND3;
- break;
-+#endif
- case ssl_grp_kem_mlkem768x25519:
-+ case ssl_grp_kem_secp256r1mlkem768:
- mechanism = CKM_NSS_ML_KEM_KEY_PAIR_GEN;
-- paramSet = CKP_NSS_ML_KEM_768;
-+ paramSet = CKP_ML_KEM_768;
- break;
- default:
- PORT_Assert(0);
-@@ -400,15 +403,33 @@ tls13_CreateKEMKeyPair(sslSocket *ss, co
- if (!slot) {
- goto loser;
- }
-+ /* avoid pairwise check in non-FIPS mode */
-+ /* the only difference between CKM_ML_KEM_KEY_PAIR_GEN and
-+ * CKM_NSS_ML_KEM_KEY_PAIR_GEN is the latter skips the pairwise consistency
-+ * check and is only supported by softoken */
-+ if ((mechanism == CKM_ML_KEM_KEY_PAIR_GEN) && !PK11_IsFIPS() &&
-+ PK11_DoesMechanism(slot, CKM_NSS_ML_KEM_KEY_PAIR_GEN)) {
-+ mechanism = CKM_NSS_ML_KEM_KEY_PAIR_GEN;
-+ }
-
- privKey = PK11_GenerateKeyPairWithOpFlags(slot, mechanism,
-- ¶mSet, &pubKey, PK11_ATTR_SESSION | PK11_ATTR_INSENSITIVE | PK11_ATTR_PUBLIC,
-- CKF_DERIVE, CKF_DERIVE, ss->pkcs11PinArg);
-+ ¶mSet, &pubKey,
-+ PK11_ATTR_SESSION |
-+ PK11_ATTR_INSENSITIVE |
-+ PK11_ATTR_PUBLIC,
-+ CKF_ENCAPSULATE|CKF_DECAPSULATE,
-+ CKF_ENCAPSULATE|CKF_DECAPSULATE,
-+ ss->pkcs11PinArg);
-
- if (!privKey) {
- privKey = PK11_GenerateKeyPairWithOpFlags(slot, mechanism,
-- ¶mSet, &pubKey, PK11_ATTR_SESSION | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE,
-- CKF_DERIVE, CKF_DERIVE, ss->pkcs11PinArg);
-+ ¶mSet, &pubKey,
-+ PK11_ATTR_SESSION |
-+ PK11_ATTR_SENSITIVE |
-+ PK11_ATTR_PRIVATE,
-+ CKF_ENCAPSULATE|CKF_DECAPSULATE,
-+ CKF_ENCAPSULATE|CKF_DECAPSULATE,
-+ ss->pkcs11PinArg);
- }
-
- PK11_FreeSlot(slot);
-@@ -448,6 +469,89 @@ loser:
- return SECFailure;
- }
-
-+/* only copy the ECDh component of an ephemeral KeyPair */
-+sslEphemeralKeyPair *
-+tls13_CopyDHEphemeralKeyPair(sslEphemeralKeyPair *copyKeyPair,
-+ const sslNamedGroupDef *groupDef) {
-+ /* We could use ssl_CopyEphemeralKeyPair here, but we would need to free
-+ * the KEM components. So we only copy the ECDH keys */
-+ sslEphemeralKeyPair *keyPair = PORT_ZNew(sslEphemeralKeyPair);
-+ if (!keyPair) {
-+ return NULL;
-+ }
-+ PR_INIT_CLIST(&keyPair->link);
-+ keyPair->group = groupDef;
-+ keyPair->keys = ssl_GetKeyPairRef(copyKeyPair->keys);
-+ return keyPair;
-+}
-+
-+/*
-+ * find a hybrid key Pair they might contain the same ecdh key so we
-+ * can reuse them. Each ec group can map to more than one hybrid Pair
-+ */
-+sslEphemeralKeyPair *
-+tls13_FindHybridKeyPair(sslSocket *ss, const sslNamedGroupDef *groupDef)
-+{
-+ sslEphemeralKeyPair *hybridPair = NULL;
-+ switch (groupDef->name) {
-+ case ssl_grp_ec_secp256r1:
-+ /* future, this may be a loop to check multiple named groups */
-+ hybridPair = ssl_LookupEphemeralKeyPair(ss,
-+ ssl_LookupNamedGroup(ssl_grp_kem_secp256r1mlkem768));
-+ break;
-+ case ssl_grp_ec_curve25519:
-+#ifndef NSS_DISABLE_KYBER
-+ /* a loop to check multiple named groups */
-+ SSLNamedGroup gnames[] = { ssl_grp_kem_xyber768d00,
-+ ssl_grp_kem_mlkem768x25519 };
-+ for (int i=0; i < PR_ARRAY_SIZE(gnames); i++) {
-+ hybridPair = ssl_LookupEphemeralKeyPair(ss,
-+ ssl_LookupNamedGroup(gnames[i]));
-+ if (hybridPair != NULL) {
-+ break;
-+ }
-+ }
-+#else
-+ /* future, this will be a loop to check multiple named groups */
-+ hybridPair = ssl_LookupEphemeralKeyPair(ss,
-+ ssl_LookupNamedGroup(ssl_grp_kem_mlkem768x25519));
-+#endif
-+ break;
-+ default:
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return NULL;
-+ }
-+ return hybridPair;
-+}
-+
-+/*
-+ * Find a corresponding KEM form another hybrid key
-+ */
-+#ifdef notdef
-+sslKeyPair *
-+tls13_FindKEMKeyPairFromHybrid(sslSocket *ss, const sslNamedGroupDef *groupDef)
-+{
-+ sslEphemeralKeyPair *hybridPair = NULL;
-+ switch (groupDef->name) {
-+ case ssl_grp_kem_mlkem768x25519:
-+ /* future, this may be a loop to check multiple named groups */
-+ hybridPair = ssl_LookupEphemeralKeyPair(ss,
-+ ssl_LookupNamedGroup(ssl_grp_kem_secp256r1mlkem768));
-+ break;
-+ case ssl_grp_kem_secp256r1mlkem768:
-+ /* future, this will be a loop to check multiple named groups */
-+ hybridPair = ssl_LookupEphemeralKeyPair(ss,
-+ ssl_LookupNamedGroup(ssl_grp_kem_mlkem768x25519));
-+ break;
-+ default:
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return NULL;
-+ }
-+ return hybridPair->kemKeys;
-+}
-+#endif
-+
-+
- SECStatus
- tls13_CreateKeyShare(sslSocket *ss, const sslNamedGroupDef *groupDef,
- sslEphemeralKeyPair **outKeyPair)
-@@ -455,21 +559,35 @@ tls13_CreateKeyShare(sslSocket *ss, cons
- SECStatus rv;
- const ssl3DHParams *params;
- sslEphemeralKeyPair *keyPair = NULL;
-+ const sslNamedGroupDef *dhGroup = NULL;
-
- PORT_Assert(groupDef);
- switch (groupDef->keaType) {
- case ssl_kea_ecdh_hybrid:
-- if (groupDef->name != ssl_grp_kem_xyber768d00 && groupDef->name != ssl_grp_kem_mlkem768x25519) {
-+ switch (groupDef->name) {
-+ case ssl_grp_kem_secp256r1mlkem768:
-+ dhGroup = ssl_LookupNamedGroup(ssl_grp_ec_secp256r1);
-+ break;
-+#ifndef NSS_DISABLE_KYBER
-+ case ssl_grp_kem_xyber768d00:
-+#endif
-+ case ssl_grp_kem_mlkem768x25519:
-+ dhGroup = ssl_LookupNamedGroup(ssl_grp_ec_curve25519);
-+ break;
-+ default:
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ return SECFailure;
-+ }
-+ if (dhGroup == NULL) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-- const sslNamedGroupDef *x25519 = ssl_LookupNamedGroup(ssl_grp_ec_curve25519);
-- sslEphemeralKeyPair *x25519Pair = ssl_LookupEphemeralKeyPair(ss, x25519);
-- if (x25519Pair) {
-- keyPair = ssl_CopyEphemeralKeyPair(x25519Pair);
-+ keyPair = ssl_LookupEphemeralKeyPair(ss, dhGroup);
-+ if (keyPair) {
-+ keyPair= ssl_CopyEphemeralKeyPair(keyPair);
- }
- if (!keyPair) {
-- rv = ssl_CreateECDHEphemeralKeyPair(ss, x25519, &keyPair);
-+ rv = ssl_CreateECDHEphemeralKeyPair(ss, dhGroup, &keyPair);
- if (rv != SECSuccess) {
- return SECFailure;
- }
-@@ -477,23 +595,9 @@ tls13_CreateKeyShare(sslSocket *ss, cons
- keyPair->group = groupDef;
- break;
- case ssl_kea_ecdh:
-- if (groupDef->name == ssl_grp_ec_curve25519) {
-- sslEphemeralKeyPair *hybridPair = ssl_LookupEphemeralKeyPair(ss, ssl_LookupNamedGroup(ssl_grp_kem_mlkem768x25519));
-- if (!hybridPair) {
-- hybridPair = ssl_LookupEphemeralKeyPair(ss, ssl_LookupNamedGroup(ssl_grp_kem_xyber768d00));
-- }
-- if (hybridPair) {
-- // We could use ssl_CopyEphemeralKeyPair here, but we would need to free
-- // the KEM components. We should pull this out into a utility function when
-- // we refactor to support multiple hybrid mechanisms.
-- keyPair = PORT_ZNew(sslEphemeralKeyPair);
-- if (!keyPair) {
-- return SECFailure;
-- }
-- PR_INIT_CLIST(&keyPair->link);
-- keyPair->group = groupDef;
-- keyPair->keys = ssl_GetKeyPairRef(hybridPair->keys);
-- }
-+ keyPair = tls13_FindHybridKeyPair(ss, groupDef);
-+ if (keyPair) {
-+ keyPair = tls13_CopyDHEphemeralKeyPair(keyPair, groupDef);
- }
- if (!keyPair) {
- rv = ssl_CreateECDHEphemeralKeyPair(ss, groupDef, &keyPair);
-@@ -519,11 +623,27 @@ tls13_CreateKeyShare(sslSocket *ss, cons
- // If we're creating an ECDH + KEM hybrid share and we're the client, then
- // we still need to generate the KEM key pair. Otherwise we're done.
- if (groupDef->keaType == ssl_kea_ecdh_hybrid && !ss->sec.isServer) {
-+#ifdef notdef
-+ sslKeyPair *kemPair = NULL;
-+ kemPair = tls13_FindKEMKeyPairFromHybrid(ss, groupDef);
-+ if (kemPair) {
-+ kemPair = ssl_GetKeyPairRef(kemPair);
-+ }
-+ if (!kemPair) {
-+ rv = tls13_CreateKEMKeyPair(ss, groupDef, &kemPair);
-+ if (rv != SECSuccess) {
-+ ssl_FreeEphemeralKeyPair(keyPair);
-+ return SECFailure;
-+ }
-+ }
-+ keyPair->kemKeys = kemPair;
-+#else
- rv = tls13_CreateKEMKeyPair(ss, groupDef, &keyPair->kemKeys);
- if (rv != SECSuccess) {
- ssl_FreeEphemeralKeyPair(keyPair);
- return SECFailure;
- }
-+#endif
- }
-
- *outKeyPair = keyPair;
-@@ -706,12 +826,17 @@ tls13_ImportKEMKeyShare(SECKEYPublicKey
- size_t expected_len;
-
- switch (entry->group->name) {
-+#ifndef NSS_DISABLE_KYBER
- case ssl_grp_kem_xyber768d00:
- expected_len = X25519_PUBLIC_KEY_BYTES + KYBER768_PUBLIC_KEY_BYTES;
- break;
-+#endif
- case ssl_grp_kem_mlkem768x25519:
- expected_len = X25519_PUBLIC_KEY_BYTES + KYBER768_PUBLIC_KEY_BYTES;
- break;
-+ case ssl_grp_kem_secp256r1mlkem768:
-+ expected_len = SECP256_PUBLIC_KEY_BYTES + KYBER768_PUBLIC_KEY_BYTES;
-+ break;
- default:
- PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
- return SECFailure;
-@@ -723,6 +848,7 @@ tls13_ImportKEMKeyShare(SECKEYPublicKey
- }
-
- switch (entry->group->name) {
-+#ifndef NSS_DISABLE_KYBER
- case ssl_grp_kem_xyber768d00:
- peerKey->keyType = kyberKey;
- peerKey->u.kyber.params = params_kyber768_round3;
-@@ -730,6 +856,7 @@ tls13_ImportKEMKeyShare(SECKEYPublicKey
- pk.data = entry->key_exchange.data + X25519_PUBLIC_KEY_BYTES;
- pk.len = KYBER768_PUBLIC_KEY_BYTES;
- break;
-+#endif
- case ssl_grp_kem_mlkem768x25519:
- peerKey->keyType = kyberKey;
- peerKey->u.kyber.params = params_ml_kem768;
-@@ -737,6 +864,13 @@ tls13_ImportKEMKeyShare(SECKEYPublicKey
- pk.data = entry->key_exchange.data;
- pk.len = KYBER768_PUBLIC_KEY_BYTES;
- break;
-+ case ssl_grp_kem_secp256r1mlkem768:
-+ peerKey->keyType = kyberKey;
-+ peerKey->u.kyber.params = params_ml_kem768;
-+ /* key_exchange.data is `secp256 || mlkem768` */
-+ pk.data = entry->key_exchange.data + SECP256_PUBLIC_KEY_BYTES;
-+ pk.len = KYBER768_PUBLIC_KEY_BYTES;
-+ break;
- default:
- PORT_Assert(0);
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-@@ -759,6 +893,7 @@ tls13_HandleKEMCiphertext(sslSocket *ss,
- SECStatus rv;
-
- switch (entry->group->name) {
-+#ifndef NSS_DISABLE_KYBER
- case ssl_grp_kem_xyber768d00:
- if (entry->key_exchange.len != X25519_PUBLIC_KEY_BYTES + KYBER768_CIPHERTEXT_BYTES) {
- ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
-@@ -767,6 +902,7 @@ tls13_HandleKEMCiphertext(sslSocket *ss,
- ct.data = entry->key_exchange.data + X25519_PUBLIC_KEY_BYTES;
- ct.len = KYBER768_CIPHERTEXT_BYTES;
- break;
-+#endif
- case ssl_grp_kem_mlkem768x25519:
- if (entry->key_exchange.len != X25519_PUBLIC_KEY_BYTES + KYBER768_CIPHERTEXT_BYTES) {
- ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
-@@ -775,13 +911,22 @@ tls13_HandleKEMCiphertext(sslSocket *ss,
- ct.data = entry->key_exchange.data;
- ct.len = KYBER768_CIPHERTEXT_BYTES;
- break;
-+ case ssl_grp_kem_secp256r1mlkem768:
-+ if (entry->key_exchange.len != SECP256_PUBLIC_KEY_BYTES + KYBER768_CIPHERTEXT_BYTES) {
-+ ssl_MapLowLevelError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
-+ return SECFailure;
-+ }
-+ ct.data = entry->key_exchange.data + SECP256_PUBLIC_KEY_BYTES;
-+ ct.len = KYBER768_CIPHERTEXT_BYTES;
-+ break;
- default:
- PORT_Assert(0);
- ssl_MapLowLevelError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
-
-- rv = PK11_Decapsulate(keyPair->privKey, &ct, CKM_HKDF_DERIVE, PK11_ATTR_SESSION | PK11_ATTR_INSENSITIVE, CKF_DERIVE, outKey);
-+ rv = PK11_Decapsulate(keyPair->privKey, &ct, CKM_HKDF_DERIVE, PK11_ATTR_SESSION,
-+ CKF_DERIVE, outKey);
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_KEY_EXCHANGE_FAILURE);
- }
-@@ -813,9 +958,12 @@ tls13_HandleKEMKey(sslSocket *ss,
- goto loser;
- }
-
-- PK11SlotInfo *slot = PK11_GetBestSlot(CKM_NSS_KYBER, ss->pkcs11PinArg);
-+ PK11SlotInfo *slot = PK11_GetBestSlot(CKM_ML_KEM, ss->pkcs11PinArg);
- if (!slot) {
-- goto loser;
-+ slot = PK11_GetBestSlot(CKM_NSS_ML_KEM, ss->pkcs11PinArg);
-+ if (!slot) {
-+ goto loser;
-+ }
- }
-
- handle = PK11_ImportPublicKey(slot, peerKey, PR_FALSE);
-@@ -825,7 +973,7 @@ tls13_HandleKEMKey(sslSocket *ss,
- }
-
- rv = PK11_Encapsulate(peerKey,
-- CKM_HKDF_DERIVE, PK11_ATTR_SESSION | PK11_ATTR_INSENSITIVE | PK11_ATTR_PUBLIC,
-+ CKM_HKDF_DERIVE, PK11_ATTR_SESSION,
- CKF_DERIVE, key, ciphertext);
-
- /* Destroy the imported public key */
-@@ -855,6 +1003,8 @@ tls13_HandleKeyShare(sslSocket *ss,
- unsigned char *ec_data;
- SECStatus rv;
- int keySize = 0;
-+ const sslNamedGroupDef *dhGroup = NULL;
-+ int dhLen = 0;
-
- PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE);
- peerKey = PORT_ArenaZNew(&arena.arena, SECKEYPublicKey);
-@@ -868,17 +1018,31 @@ tls13_HandleKeyShare(sslSocket *ss,
- switch (entry->group->keaType) {
- case ssl_kea_ecdh_hybrid:
- switch (entry->group->name) {
-+#ifndef NSS_DISABLE_KYBER
- case ssl_grp_kem_xyber768d00:
-+ dhLen = X25519_PUBLIC_KEY_BYTES;
- // x25519 share is at the beginning
-- ec_data = entry->key_exchange.len < X25519_PUBLIC_KEY_BYTES
-+ ec_data = entry->key_exchange.len < dhLen
- ? NULL
- : entry->key_exchange.data;
-+ dhGroup = ssl_LookupNamedGroup(ssl_grp_ec_curve25519);
- break;
-+#endif
- case ssl_grp_kem_mlkem768x25519:
-+ dhLen = X25519_PUBLIC_KEY_BYTES;
- // x25519 share is at the end
-- ec_data = entry->key_exchange.len < X25519_PUBLIC_KEY_BYTES
-+ ec_data = entry->key_exchange.len < dhLen
- ? NULL
-- : entry->key_exchange.data + entry->key_exchange.len - X25519_PUBLIC_KEY_BYTES;
-+ : entry->key_exchange.data + entry->key_exchange.len - dhLen;
-+ dhGroup = ssl_LookupNamedGroup(ssl_grp_ec_curve25519);
-+ break;
-+ case ssl_grp_kem_secp256r1mlkem768:
-+ dhLen = SECP256_PUBLIC_KEY_BYTES;
-+ /* secp256 share is at the beginning */
-+ ec_data = entry->key_exchange.len < dhLen
-+ ? NULL
-+ : entry->key_exchange.data;
-+ dhGroup = ssl_LookupNamedGroup(ssl_grp_ec_secp256r1);
- break;
- default:
- ec_data = NULL;
-@@ -888,10 +1052,7 @@ tls13_HandleKeyShare(sslSocket *ss,
- PORT_SetError(SSL_ERROR_RX_MALFORMED_HYBRID_KEY_SHARE);
- goto loser;
- }
-- rv = ssl_ImportECDHKeyShare(peerKey,
-- ec_data,
-- X25519_PUBLIC_KEY_BYTES,
-- ssl_LookupNamedGroup(ssl_grp_ec_curve25519));
-+ rv = ssl_ImportECDHKeyShare(peerKey, ec_data, dhLen, dhGroup);
- mechanism = CKM_ECDH1_DERIVE;
- break;
- case ssl_kea_ecdh:
-@@ -927,7 +1088,7 @@ tls13_HandleKeyShare(sslSocket *ss,
-
- *out = key;
- PORT_DestroyCheapArena(&arena);
-- return SECSuccess;
-+ return rv;
-
- loser:
- PORT_DestroyCheapArena(&arena);
-@@ -2762,12 +2923,17 @@ tls13_HandleClientKeyShare(sslSocket *ss
- goto loser; /* Error set by tls13_HandleKEMKey */
- }
- switch (peerShare->group->name) {
-+#ifndef NSS_DISABLE_KYBER
- case ssl_grp_kem_xyber768d00:
- ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
- break;
-+#endif
- case ssl_grp_kem_mlkem768x25519:
- ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(kemSecret, dheSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
- break;
-+ case ssl_grp_kem_secp256r1mlkem768:
-+ ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
-+ break;
- default:
- PORT_Assert(0);
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-@@ -3621,12 +3787,17 @@ tls13_HandleServerKeyShare(sslSocket *ss
- goto loser; /* Error set by tls13_HandleKEMCiphertext */
- }
- switch (entry->group->name) {
-+#ifndef NSS_DISABLE_KYBER
- case ssl_grp_kem_xyber768d00:
- ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
- break;
-+#endif
- case ssl_grp_kem_mlkem768x25519:
- ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(kemSecret, dheSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
- break;
-+ case ssl_grp_kem_secp256r1mlkem768:
-+ ss->ssl3.hs.dheSecret = PK11_ConcatSymKeys(dheSecret, kemSecret, CKM_HKDF_DERIVE, CKA_DERIVE);
-+ break;
- default:
- PORT_Assert(0);
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-diff -up ./lib/ssl/tls13exthandle.c.mlkem_p256 ./lib/ssl/tls13exthandle.c
---- ./lib/ssl/tls13exthandle.c.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/ssl/tls13exthandle.c 2025-06-25 16:47:19.382363018 -0700
-@@ -80,19 +80,30 @@ tls13_SizeOfKeyShareEntry(const sslEphem
-
- if (keyPair->kemKeys) {
- PORT_Assert(!keyPair->kemCt);
-- PORT_Assert(keyPair->group->name == ssl_grp_kem_xyber768d00 || keyPair->group->name == ssl_grp_kem_mlkem768x25519);
-+ PORT_Assert(
-+#ifndef NSS_DISABLE_KYBER
-+ keyPair->group->name == ssl_grp_kem_xyber768d00 ||
-+#endif
-+ keyPair->group->name == ssl_grp_kem_mlkem768x25519 ||
-+ keyPair->group->name == ssl_grp_kem_secp256r1mlkem768);
- pubKey = keyPair->kemKeys->pubKey;
- size += pubKey->u.kyber.publicValue.len;
- }
- if (keyPair->kemCt) {
- PORT_Assert(!keyPair->kemKeys);
-- PORT_Assert(keyPair->group->name == ssl_grp_kem_xyber768d00 || keyPair->group->name == ssl_grp_kem_mlkem768x25519);
-+ PORT_Assert(
-+#ifndef NSS_DISABLE_KYBER
-+ keyPair->group->name == ssl_grp_kem_xyber768d00 ||
-+#endif
-+ keyPair->group->name == ssl_grp_kem_mlkem768x25519 ||
-+ keyPair->group->name == ssl_grp_kem_secp256r1mlkem768);
- size += keyPair->kemCt->len;
- }
-
- return size;
- }
-
-+#ifndef NSS_DISABLE_KYBER
- static SECStatus
- tls13_WriteXyber768D00KeyExchangeInfo(sslBuffer *buf, sslEphemeralKeyPair *keyPair)
- {
-@@ -119,6 +130,34 @@ tls13_WriteXyber768D00KeyExchangeInfo(ss
- }
- return rv;
- }
-+#endif
-+
-+static SECStatus
-+tls13_WriteMLKEM768Secp256r1KeyExchangeInfo(sslBuffer *buf, sslEphemeralKeyPair *keyPair)
-+ {
-+ PORT_Assert(keyPair->group->name == ssl_grp_kem_secp256r1mlkem768);
-+ PORT_Assert(keyPair->keys->pubKey->keyType == ecKey);
-+
-+ // Encode the p256 key first, then the Kyber768 key or ciphertext.
-+ SECStatus rv;
-+ rv = sslBuffer_Append(buf, keyPair->keys->pubKey->u.ec.publicValue.data,
-+ keyPair->keys->pubKey->u.ec.publicValue.len);
-+ if (rv != SECSuccess) {
-+ return rv;
-+ }
-+
-+ if (keyPair->kemKeys) {
-+ PORT_Assert(!keyPair->kemCt);
-+ rv = sslBuffer_Append(buf, keyPair->kemKeys->pubKey->u.kyber.publicValue.data, keyPair->kemKeys->pubKey->u.kyber.publicValue.len);
-+ } else if (keyPair->kemCt) {
-+ rv = sslBuffer_Append(buf, keyPair->kemCt->data, keyPair->kemCt->len);
-+ } else {
-+ PORT_Assert(0);
-+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
-+ rv = SECFailure;
-+ }
-+ return rv;
-+}
-
- static SECStatus
- tls13_WriteMLKEM768X25519KeyExchangeInfo(sslBuffer *buf, sslEphemeralKeyPair *keyPair)
-@@ -187,12 +226,18 @@ tls13_EncodeKeyShareEntry(sslBuffer *buf
- }
-
- switch (keyPair->group->name) {
-+#ifndef NSS_DISABLE_KYBER
-+ case ssl_grp_kem_xyber768d00:
-+ rv = tls13_WriteXyber768D00KeyExchangeInfo(buf, keyPair);
-+ break;
-+#endif
- case ssl_grp_kem_mlkem768x25519:
- rv = tls13_WriteMLKEM768X25519KeyExchangeInfo(buf, keyPair);
- break;
-- case ssl_grp_kem_xyber768d00:
-- rv = tls13_WriteXyber768D00KeyExchangeInfo(buf, keyPair);
-+ case ssl_grp_kem_secp256r1mlkem768:
-+ rv = tls13_WriteMLKEM768Secp256r1KeyExchangeInfo(buf, keyPair);
- break;
-+
- default:
- rv = tls13_WriteKeyExchangeInfo(buf, keyPair);
- break;
-diff -up ./lib/util/eccutil.h.mlkem_p256 ./lib/util/eccutil.h
---- ./lib/util/eccutil.h.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/util/eccutil.h 2025-06-25 16:47:19.382363018 -0700
-@@ -6,6 +6,7 @@
- #define _FREEBL_H_
-
- #define X25519_PUBLIC_KEY_BYTES 32U
-+#define SECP256_PUBLIC_KEY_BYTES 65U
-
- /* deprecated */
- typedef enum {
-diff -up ./lib/util/pkcs11n.h.mlkem_p256 ./lib/util/pkcs11n.h
-diff -up ./lib/util/pkcs11t.h.mlkem_p256 ./lib/util/pkcs11t.h
---- ./lib/util/pkcs11t.h.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/util/pkcs11t.h 2025-06-25 16:47:19.382363018 -0700
-@@ -755,6 +755,21 @@ typedef CK_ULONG CK_MECHANISM_TYPE;
- #define CKM_DSA_SHA3_384 0x0000001AUL
- #define CKM_DSA_SHA3_512 0x0000001BUL
-
-+/* subset of pkcs11v3.2 defines needed for
-+ * mlkem support */
-+#define CKM_ML_KEM 0x00000017UL
-+#define CKM_ML_KEM_KEY_PAIR_GEN 0x0000000fUL
-+#define CKK_ML_KEM 0x00000049UL
-+typedef CK_ULONG CK_ML_KEM_PARAMETER_SET_TYPE;
-+#define CKP_ML_KEM_512 0x00000001UL
-+#define CKP_ML_KEM_768 0x00000002UL
-+#define CKP_ML_KEM_1024 0x00000003UL
-+#define CKA_PARAMETER_SET 0x0000061dUL
-+#define CKA_ENCAPSULATE 0x00000633UL
-+#define CKA_DECAPSULATE 0x00000634UL
-+#define CKF_DECAPSULATE 0x20000000UL
-+#define CKF_ENCAPSULATE 0x10000000UL
-+
- #define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020UL
- #define CKM_DH_PKCS_DERIVE 0x00000021UL
-
-diff -up ./lib/util/secoid.c.mlkem_p256 ./lib/util/secoid.c
---- ./lib/util/secoid.c.mlkem_p256 2025-06-25 16:47:19.354362658 -0700
-+++ ./lib/util/secoid.c 2025-06-25 16:47:19.382363018 -0700
-@@ -1900,6 +1900,12 @@ const static SECOidData oids[SEC_OID_TOT
- "ML-KEM-768+X25519 key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
- ODE(SEC_OID_TLS_REQUIRE_EMS,
- "TLS Require EMS", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
-+/* this will change upstream. for now apps shouldn't use it */
-+/* we need it for the policy code. */
-+ ODE(SEC_OID_PRIVATE_1,
-+ "ML-KEM-768+SECP256 key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
-+ ODE(SEC_OID_PRIVATE_2,
-+ "ML-KEM-1024+SECP256 key exchange", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
-
- };
-
-diff -up ./lib/util/secoidt.h.mlkem_p256 ./lib/util/secoidt.h
---- ./lib/util/secoidt.h.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/util/secoidt.h 2025-06-25 16:47:19.382363018 -0700
-@@ -536,6 +536,12 @@ typedef enum {
-
- SEC_OID_TLS_REQUIRE_EMS = 390,
-
-+ /* these will change upstream. for now apps shouldn't use it */
-+ /* give it an obscure name here */
-+
-+ SEC_OID_PRIVATE_1 = 391,
-+ SEC_OID_PRIVATE_2 = 392,
-+
- SEC_OID_TOTAL
- } SECOidTag;
-
-diff -up ./lib/util/utilmodt.h.mlkem_p256 ./lib/util/utilmodt.h
---- ./lib/util/utilmodt.h.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/util/utilmodt.h 2025-06-25 16:47:19.382363018 -0700
-@@ -28,6 +28,7 @@
- #define SECMOD_CAMELLIA_FLAG 0x00010000L /* = PUBLIC_MECH_CAMELLIA_FLAG */
- #define SECMOD_SEED_FLAG 0x00020000L
- #define SECMOD_ECC_FLAG 0x00040000L
-+#define SECMOD_MLKEM_FLAG 0x00080000L
- /* reserved bit for future, do not use */
- #define SECMOD_RESERVED_FLAG 0X08000000L
- #define SECMOD_FRIENDLY_FLAG 0x10000000L
-diff -up ./lib/util/utilpars.c.mlkem_p256 ./lib/util/utilpars.c
---- ./lib/util/utilpars.c.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/util/utilpars.c 2025-06-25 16:47:19.382363018 -0700
-@@ -609,6 +609,7 @@ static struct nssutilArgSlotFlagTable ns
- NSSUTIL_ARG_ENTRY(SEED, SECMOD_SEED_FLAG),
- NSSUTIL_ARG_ENTRY(PublicCerts, SECMOD_FRIENDLY_FLAG),
- NSSUTIL_ARG_ENTRY(RANDOM, SECMOD_RANDOM_FLAG),
-+ NSSUTIL_ARG_ENTRY(MLKEM, SECMOD_MLKEM_FLAG),
- NSSUTIL_ARG_ENTRY(Disable, SECMOD_DISABLE_FLAG),
- };
-
-diff -up ./lib/util/utilparst.h.mlkem_p256 ./lib/util/utilparst.h
---- ./lib/util/utilparst.h.mlkem_p256 2025-05-23 06:07:49.000000000 -0700
-+++ ./lib/util/utilparst.h 2025-06-25 16:47:19.382363018 -0700
-@@ -43,7 +43,7 @@
- #define NSSUTIL_DEFAULT_INTERNAL_INIT3 \
- " askpw=any timeout=30})\""
- #define NSSUTIL_DEFAULT_SFTKN_FLAGS \
-- "slotFlags=[ECC,RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512]"
-+ "slotFlags=[ECC,RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,MLKEM,SHA256,SHA512]"
-
- #define NSSUTIL_DEFAULT_CIPHER_ORDER 0
- #define NSSUTIL_DEFAULT_TRUST_ORDER 50
-diff -up ./tests/ssl/sslcov.txt.mlkem_p256 ./tests/ssl/sslcov.txt
---- ./tests/ssl/sslcov.txt.mlkem_p256 2025-06-25 16:47:19.370362863 -0700
-+++ ./tests/ssl/sslcov.txt 2025-06-25 16:47:19.383363031 -0700
-@@ -4,7 +4,7 @@
- #
- # This file enables test coverage of the various SSL ciphers
- #
--# Enable Enable Cipher Test Name
-+# Enable Enable Cipher Test Name
- # EC TLS
- #
- noECC SSL3 c SSL3_RSA_WITH_RC4_128_MD5
-@@ -147,3 +147,9 @@
- ECC TLS13 :1301 TLS13_ECDHE_WITH_AES_128_GCM_SHA256
- ECC TLS13 :1302 TLS13_ECDHE_WITH_AES_256_GCM_SHA384
- ECC TLS13 :1303 TLS13_ECDHE_WITH_CHACHA20_POLY1305_SHA256
-+MLKEM256 TLS13 :1301 TLS13_MLKEMP256_WITH_AES_128_GCM_SHA256
-+MLKEM256 TLS13 :1302 TLS13_MLKEMP256_WITH_AES_256_GCM_SHA384
-+MLKEM256 TLS13 :1303 TLS13_MLKEMP256_WITH_CHACHA20_POLY1305_SHA256
-+MLKEM219 TLS13 :1301 TLS13_MLKEMX25519_WITH_AES_128_GCM_SHA256
-+MLKEM219 TLS13 :1302 TLS13_MLKEMX25519_WITH_AES_256_GCM_SHA384
-+MLKEM219 TLS13 :1303 TLS13_MLKEMX25519_WITH_CHACHA20_POLY1305_SHA256
-diff -up ./tests/ssl/ssl.sh.mlkem_p256 ./tests/ssl/ssl.sh
---- ./tests/ssl/ssl.sh.mlkem_p256 2025-06-25 16:47:19.370362863 -0700
-+++ ./tests/ssl/ssl.sh 2025-06-25 16:47:19.383363031 -0700
-@@ -121,8 +121,12 @@ ssl_init()
- CIPHER_SUITES="-c ${EC_SUITES}${NON_EC_SUITES}"
- TLS13_CIPHER_SUITES="-c ${TLS13_SUITES}${EC_SUITES}${NON_EC_SUITES}"
-
-+ # FIPS specific options for both clients and servers
-+ FIPS_OPTIONS=""
- # in fips mode, turn off curve25519 until it's NIST approved
-- FIPS_OPTIONS="-I P256,P384,P521,FF2048,FF3072,FF4096,FF6144,FF8192"
-+ ALL_GROUPS="P256,P384,P521,x25519,FF2048,FF3072,FF4096,FF6144,FF8192,mlkem768secp256r1,mlkem768x25519"
-+ NON_PQ_GROUPS="P256,P384,P521,x25519,FF2048,FF3072,FF4096,FF6144,FF8192"
-+ FIPS_GROUPS="P256,P384,P521,FF2048,FF3072,FF4096,FF6144,FF8192,mlkem768secp256r1,mlkem768x25519"
-
- # in non-fips mode, tstclnt may run without the db password in some
- # cases, but in fips mode it's always needed
-@@ -312,10 +316,12 @@ ssl_cov()
-
- SAVE_SERVER_OPTIONS=${SERVER_OPTIONS}
- if [ "${SERVER_MODE}" = "fips" ] ; then
-- SERVER_OPTIONS="${SERVER_OPTIONS} ${FIPS_OPTIONS}"
-+ SERVER_OPTIONS="${SERVER_OPTIONS} -I ${FIPS_GROUPS} ${FIPS_OPTIONS}"
- fi
- SAVE_CLIENT_OPTIONS=${CLIENT_OPTIONS}
-+ CLIENT_GROUPS=${NON_PQ_GROUPS}
- if [ "${CLIENT_MODE}" = "fips" ] ; then
-+ CLIENT_GROUPS=${FIPS_GROUPS}
- CLIENT_OPTIONS="${CLIENT_OPTIONS} ${FIPS_OPTIONS}"
- fi
-
-@@ -340,7 +346,7 @@ ssl_cov()
- ;;
- esac
-
-- echo "$SCRIPTNAME: running $testname ----------------------------"
-+ echo "$SCRIPTNAME: running $testname ------------------"
- VMAX="ssl3"
- if [ "$testmax" = "TLS10" ]; then
- VMAX="tls1.0"
-@@ -375,13 +381,19 @@ ssl_cov()
- VMIN="ssl3"
- fi
-
-+ TLS_GROUPS=${CLIENT_GROUPS}
-+ if [ "$ectype" = "MLKEM256" ]; then
-+ TLS_GROUPS="mlkem768secp256r1"
-+ elif [ "$ectype" = "MLKEM219" ]; then
-+ TLS_GROUPS="mlkem768x25519"
-+ fi
-+ echo "TLS_GROUPS=${TLS_GROUPS}"
-
--
-- echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} \\"
-+ echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -I \"${TLS_GROUPS}\" -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} \\"
- echo " -f -d ${P_R_CLIENTDIR} $verbose -w nss < ${REQUEST_FILE}"
-
- rm ${TMP}/$HOST.tmp.$$ 2>/dev/null
-- ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} -f \
-+ ${PROFTOOL} ${BINDIR}/tstclnt -4 -p ${PORT} -h ${HOSTADDR} -c ${param} -I "${TLS_GROUPS}" -V ${VMIN}:${VMAX} ${CLIENT_OPTIONS} -f \
- -d ${P_R_CLIENTDIR} $verbose -w nss < ${REQUEST_FILE} \
- >${TMP}/$HOST.tmp.$$ 2>&1
- ret=$?
diff --git a/nss-3.112-update-fixes.patch b/nss-3.112-update-fixes.patch
deleted file mode 100644
index 6c4508a..0000000
--- a/nss-3.112-update-fixes.patch
+++ /dev/null
@@ -1,928 +0,0 @@
-# HG changeset patch
-# User Robert Relyea
-# Date 1762542092 28800
-# Fri Nov 07 11:01:32 2025 -0800
-# Branch RHEL_8
-# Node ID 5b6833262609c6a2567d234a645be532bde27ef7
-# Parent 04ad729ed140ac94ab37d012dd2fec6c575bba2b
-nss-3.112-update-fixes.patch
-
-diff --git a/lib/cryptohi/keythi.h b/lib/cryptohi/keythi.h
---- a/lib/cryptohi/keythi.h
-+++ b/lib/cryptohi/keythi.h
-@@ -243,16 +243,27 @@ struct SECKEYPrivateKeyStr {
- PK11SlotInfo *pkcs11Slot; /* pkcs11 slot this key lives in */
- CK_OBJECT_HANDLE pkcs11ID; /* ID of pkcs11 object */
- PRBool pkcs11IsTemp; /* temp pkcs11 object, delete it when done */
- void *wincx; /* context for errors and pw prompts */
- PRUint32 staticflags; /* bit flag of cached PKCS#11 attributes */
- };
- typedef struct SECKEYPrivateKeyStr SECKEYPrivateKey;
-
-+#define SECKEYPRIVATEKEY_IS_TEMP_FLAG 0x01
-+#define SECKEYPRIVATEKEY_IS_OWNED_FLAG 0x02
-+#define SECKEYPRIVATEKEY_IS_TEMP(key) \
-+ ((PRBool)((key)->pkcs11IsTemp&SECKEYPRIVATEKEY_IS_TEMP_FLAG)==SECKEYPRIVATEKEY_IS_TEMP_FLAG)
-+#define SECKEYPRIVATEKEY_IS_OWNED(key) \
-+ ((PRBool)((key)->pkcs11IsTemp&SECKEYPRIVATEKEY_IS_OWNED_FLAG)==SECKEYPRIVATEKEY_IS_OWNED_FLAG)
-+#define SECKEYPRIVATEKEY_SET_TEMP(key,isTemp) (key)->pkcs11IsTemp = ((key)->pkcs11IsTemp & ~SECKEYPRIVATEKEY_IS_TEMP_FLAG) | \
-+ ((isTemp) ? SECKEYPRIVATEKEY_IS_TEMP_FLAG : 0)
-+#define SECKEYPRIVATEKEY_SET_OWNED(key,isOwned) (key)->pkcs11IsTemp = ((key)->pkcs11IsTemp & ~SECKEYPRIVATEKEY_IS_OWNED_FLAG) | \
-+ ((isOwned) ? SECKEYPRIVATEKEY_IS_OWNED_FLAG : 0)
-+
- typedef struct {
- PRCList links;
- SECKEYPrivateKey *key;
- } SECKEYPrivateKeyListNode;
-
- typedef struct {
- PRCList list;
- PLArenaPool *arena;
-diff --git a/lib/cryptohi/seckey.c b/lib/cryptohi/seckey.c
---- a/lib/cryptohi/seckey.c
-+++ b/lib/cryptohi/seckey.c
-@@ -416,17 +416,17 @@ SECKEY_CreateEDPrivateKey(SECKEYECParams
- return (privk);
- }
-
- void
- SECKEY_DestroyPrivateKey(SECKEYPrivateKey *privk)
- {
- if (privk) {
- if (privk->pkcs11Slot) {
-- if (privk->pkcs11IsTemp) {
-+ if (SECKEYPRIVATEKEY_IS_OWNED(privk)) {
- PK11_DestroyObject(privk->pkcs11Slot, privk->pkcs11ID);
- }
- PK11_FreeSlot(privk->pkcs11Slot);
- }
- if (privk->arena) {
- PORT_FreeArena(privk->arena, PR_TRUE);
- }
- }
-@@ -1418,27 +1418,31 @@ SECKEY_CopyPrivateKey(const SECKEYPrivat
- copyk = (SECKEYPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(SECKEYPrivateKey));
- if (copyk) {
- copyk->arena = arena;
- copyk->keyType = privk->keyType;
-
- /* copy the PKCS #11 parameters */
- copyk->pkcs11Slot = PK11_ReferenceSlot(privk->pkcs11Slot);
- /* if the key we're referencing was a temparary key we have just
-- * created, that we want to go away when we're through, we need
-+ * it may go away when we're through, we need
- * to make a copy of it */
-- if (privk->pkcs11IsTemp) {
-+ copyk->pkcs11IsTemp = privk->pkcs11IsTemp;
-+ if (SECKEYPRIVATEKEY_IS_TEMP(privk)) {
- copyk->pkcs11ID =
- PK11_CopyKey(privk->pkcs11Slot, privk->pkcs11ID);
- if (copyk->pkcs11ID == CK_INVALID_HANDLE)
- goto fail;
-+ /* since we made a copy, we own that copy (even if we
-+ * didn't own the original */
-+ SECKEYPRIVATEKEY_SET_OWNED(copyk, PR_TRUE);
- } else {
- copyk->pkcs11ID = privk->pkcs11ID;
-+ SECKEYPRIVATEKEY_SET_OWNED(copyk, PR_FALSE);
- }
-- copyk->pkcs11IsTemp = privk->pkcs11IsTemp;
- copyk->wincx = privk->wincx;
- copyk->staticflags = privk->staticflags;
- return copyk;
- } else {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- }
-
- fail:
-diff --git a/lib/cryptohi/secvfy.c b/lib/cryptohi/secvfy.c
---- a/lib/cryptohi/secvfy.c
-+++ b/lib/cryptohi/secvfy.c
-@@ -436,17 +436,17 @@ sec_DecodeSigAlg(const SECKEYPublicKey *
- const SECItem *param, SECOidTag *encalgp, SECOidTag *hashalg,
- CK_MECHANISM_TYPE *mechp, SECItem *mechparamsp)
- {
- unsigned int len;
- PLArenaPool *arena;
- SECStatus rv;
- SECItem oid;
- SECOidTag encalg;
-- PRBool comboRequired = PR_TRUE;
-+ PRBool comboRequired = PR_FALSE;
- char *evp;
-
- PR_ASSERT(hashalg != NULL);
- PR_ASSERT(encalgp != NULL);
- PR_ASSERT(mechp != NULL);
- /* Get the expected combined mechanism from the signature OID
- * We'll override it in the table below if necessary */
- *mechp = PK11_AlgtagToMechanism(sigAlg);
-diff --git a/lib/freebl/leancrypto/lc_sha3.h b/lib/freebl/leancrypto/lc_sha3.h
---- a/lib/freebl/leancrypto/lc_sha3.h
-+++ b/lib/freebl/leancrypto/lc_sha3.h
-@@ -20,17 +20,20 @@
- struct lc_hash_ctx _##name ; \
- _##name.hash= type_; \
- _##name.buf= NULL; \
- _##name.stream = false; \
- _##name.u.ctx_ptr = NULL; \
- struct lc_hash_ctx *name= &_##name;
-
- #define LC_HASH_SET_CTX(name, type_) \
-- name->hash= type_;
-+ name->hash= type_; \
-+ name->stream = true; \
-+ name->u.ctx_ptr = NULL; \
-+ name->buf = NULL;
-
- #define LC_SHAKE_256_CTX(name) \
- LC_HASH_SET_CTX(name, lc_shake256);
-
- typedef enum {
- lc_shake128,
- lc_shake256,
- } sha3Type;
-diff --git a/lib/pk11wrap/pk11akey.c b/lib/pk11wrap/pk11akey.c
---- a/lib/pk11wrap/pk11akey.c
-+++ b/lib/pk11wrap/pk11akey.c
-@@ -1002,34 +1002,39 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot
- return pubKey;
- }
-
- /*
- * Build a Private Key structure from raw PKCS #11 information.
- */
- SECKEYPrivateKey *
- PK11_MakePrivKey(PK11SlotInfo *slot, KeyType keyType,
-- PRBool isTemp, CK_OBJECT_HANDLE privID, void *wincx)
-+ PRBool isOwner, CK_OBJECT_HANDLE privID, void *wincx)
- {
- PLArenaPool *arena;
- SECKEYPrivateKey *privKey;
- PRBool isPrivate;
- SECStatus rv;
-+ PRBool isTemp = isOwner;
-
- /* don't know? look it up */
- if (keyType == nullKey) {
- CK_KEY_TYPE pk11Type = CKK_RSA;
-
- pk11Type = PK11_ReadULongAttribute(slot, privID, CKA_KEY_TYPE);
- isTemp = (PRBool)!PK11_HasAttributeSet(slot, privID, CKA_TOKEN, PR_FALSE);
- keyType = pk11_GetKeyTypeFromPKCS11KeyType(pk11Type);
- if (keyType == nullKey) {
- return NULL;
- }
- }
-+ /* we can never own a perm key, make sure we don't set owner */
-+ if (!isTemp) {
-+ isOwner = PR_FALSE;
-+ }
-
- /* if the key is private, make sure we are authenticated to the
- * token before we try to use it */
- isPrivate = (PRBool)PK11_HasAttributeSet(slot, privID, CKA_PRIVATE, PR_FALSE);
- if (isPrivate) {
- rv = PK11_Authenticate(slot, PR_TRUE, wincx);
- if (rv != SECSuccess) {
- return NULL;
-@@ -1047,17 +1052,19 @@ PK11_MakePrivKey(PK11SlotInfo *slot, Key
- PORT_FreeArena(arena, PR_FALSE);
- return NULL;
- }
-
- privKey->arena = arena;
- privKey->keyType = keyType;
- privKey->pkcs11Slot = PK11_ReferenceSlot(slot);
- privKey->pkcs11ID = privID;
-- privKey->pkcs11IsTemp = isTemp;
-+ privKey->pkcs11IsTemp = 0;
-+ SECKEYPRIVATEKEY_SET_TEMP(privKey, isTemp);
-+ SECKEYPRIVATEKEY_SET_OWNED(privKey, isOwner);
- privKey->wincx = wincx;
-
- return privKey;
- }
-
- PK11SlotInfo *
- PK11_GetSlotFromPrivateKey(SECKEYPrivateKey *key)
- {
-@@ -2635,17 +2642,17 @@ PK11_CopyTokenPrivKeyToSessionPrivKey(PK
- 1, &newKeyID);
- PK11_ExitSlotMonitor(destSlot);
-
- if (crv != CKR_OK) {
- PORT_SetError(PK11_MapError(crv));
- return NULL;
- }
-
-- return PK11_MakePrivKey(destSlot, privKey->keyType, PR_TRUE /*isTemp*/,
-+ return PK11_MakePrivKey(destSlot, privKey->keyType, PR_TRUE /*isOwner*/,
- newKeyID, privKey->wincx);
- }
-
- SECKEYPrivateKey *
- PK11_ConvertSessionPrivKeyToTokenPrivKey(SECKEYPrivateKey *privk, void *wincx)
- {
- PK11SlotInfo *slot = privk->pkcs11Slot;
- CK_ATTRIBUTE template[1];
-@@ -2668,17 +2675,17 @@ PK11_ConvertSessionPrivKeyToTokenPrivKey
- template, 1, &newKeyID);
- PK11_RestoreROSession(slot, rwsession);
-
- if (crv != CKR_OK) {
- PORT_SetError(PK11_MapError(crv));
- return NULL;
- }
-
-- return PK11_MakePrivKey(slot, nullKey /*KeyType*/, PR_FALSE /*isTemp*/,
-+ return PK11_MakePrivKey(slot, nullKey /*KeyType*/, PR_FALSE /*isOwner*/,
- newKeyID, NULL /*wincx*/);
- }
-
- /*
- * destroy a private key if there are no matching certs.
- * this function also frees the privKey structure.
- */
- SECStatus
-@@ -2731,17 +2738,17 @@ pk11_DoKeys(PK11SlotInfo *slot, CK_OBJEC
- {
- SECStatus rv = SECSuccess;
- SECKEYPrivateKey *privKey;
- pk11KeyCallback *keycb = (pk11KeyCallback *)arg;
- if (!arg) {
- return SECFailure;
- }
-
-- privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, keycb->wincx);
-+ privKey = PK11_MakePrivKey(slot, nullKey, PR_FALSE, keyHandle, keycb->wincx);
-
- if (privKey == NULL) {
- return SECFailure;
- }
-
- if (keycb->callback) {
- rv = (*keycb->callback)(privKey, keycb->callbackArg);
- }
-@@ -2823,17 +2830,17 @@ PK11_FindKeyByKeyID(PK11SlotInfo *slot,
- {
- CK_OBJECT_HANDLE keyHandle;
- SECKEYPrivateKey *privKey;
-
- keyHandle = pk11_FindPrivateKeyFromCertID(slot, keyID);
- if (keyHandle == CK_INVALID_HANDLE) {
- return NULL;
- }
-- privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx);
-+ privKey = PK11_MakePrivKey(slot, nullKey, PR_FALSE, keyHandle, wincx);
- return privKey;
- }
-
- /*
- * Generate a CKA_ID from the relevant public key data. The CKA_ID is generated
- * from the pubKeyData by SHA1_Hashing it to produce a smaller CKA_ID (to make
- * smart cards happy.
- */
-@@ -3011,15 +3018,15 @@ PK11_ListPrivKeysInSlot(PK11SlotInfo *sl
- keys = SECKEY_NewPrivateKeyList();
- if (keys == NULL) {
- PORT_Free(key_ids);
- return NULL;
- }
-
- for (i = 0; i < objCount; i++) {
- SECKEYPrivateKey *privKey =
-- PK11_MakePrivKey(slot, nullKey, PR_TRUE, key_ids[i], wincx);
-+ PK11_MakePrivKey(slot, nullKey, PR_FALSE, key_ids[i], wincx);
- SECKEY_AddPrivateKeyToListTail(keys, privKey);
- }
-
- PORT_Free(key_ids);
- return keys;
- }
-diff --git a/lib/pk11wrap/pk11cert.c b/lib/pk11wrap/pk11cert.c
---- a/lib/pk11wrap/pk11cert.c
-+++ b/lib/pk11wrap/pk11cert.c
-@@ -1313,17 +1313,18 @@ PK11_FindPrivateKeyFromCert(PK11SlotInfo
- if (rv != SECSuccess) {
- return NULL;
- }
- keyh = PK11_MatchItem(slot, certh, CKO_PRIVATE_KEY);
- }
- if (keyh == CK_INVALID_HANDLE) {
- return NULL;
- }
-- return PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyh, wincx);
-+
-+ return PK11_MakePrivKey(slot, nullKey, PR_FALSE, keyh, wincx);
- }
-
- /*
- * import a cert for a private key we have already generated. Set the label
- * on both to be the nickname. This is for the Key Gen, orphaned key case.
- */
- PK11SlotInfo *
- PK11_KeyForCertExists(CERTCertificate *cert, CK_OBJECT_HANDLE *keyPtr,
-@@ -2085,17 +2086,17 @@ PK11_FindKeyByAnyCert(CERTCertificate *c
- SEC_ERROR_TOKEN_NOT_LOGGED_IN == err)) {
- /* authenticate and try again */
- rv = PK11_Authenticate(slot, PR_TRUE, wincx);
- if (rv == SECSuccess) {
- keyHandle = PK11_MatchItem(slot, certHandle, CKO_PRIVATE_KEY);
- }
- }
- if (keyHandle != CK_INVALID_HANDLE) {
-- privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx);
-+ privKey = PK11_MakePrivKey(slot, nullKey, PR_FALSE, keyHandle, wincx);
- }
- if (slot) {
- PK11_FreeSlot(slot);
- }
- return privKey;
- }
-
- CK_OBJECT_HANDLE
-@@ -2492,17 +2493,17 @@ PK11_FindKeyByDERCert(PK11SlotInfo *slot
- return NULL;
- }
-
- keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx);
- if (keyHandle == CK_INVALID_HANDLE) {
- return NULL;
- }
-
-- return PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx);
-+ return PK11_MakePrivKey(slot, nullKey, PR_FALSE, keyHandle, wincx);
- }
-
- SECStatus
- PK11_ImportCertForKeyToSlot(PK11SlotInfo *slot, CERTCertificate *cert,
- char *nickname,
- PRBool addCertUsage, void *wincx)
- {
- CK_OBJECT_HANDLE keyHandle;
-diff --git a/lib/pk11wrap/pk11kea.c b/lib/pk11wrap/pk11kea.c
---- a/lib/pk11wrap/pk11kea.c
-+++ b/lib/pk11wrap/pk11kea.c
-@@ -86,17 +86,17 @@ pk11_KeyExchange(PK11SlotInfo *slot, CK_
- goto rsa_failed;
- }
- rsaParams.keySizeInBits = 1024;
- rsaParams.pe = 0x10001;
- privKey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
- &rsaParams, &pubKey, PR_FALSE, PR_TRUE, symKey->cx);
- } else {
- /* if keys exist, build SECKEY data structures for them */
-- privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, privKeyHandle,
-+ privKey = PK11_MakePrivKey(slot, nullKey, PR_FALSE, privKeyHandle,
- symKey->cx);
- if (privKey != NULL) {
- pubKey = PK11_ExtractPublicKey(slot, rsaKey, pubKeyHandle);
- if (pubKey && pubKey->pkcs11Slot) {
- PK11_FreeSlot(pubKey->pkcs11Slot);
- pubKey->pkcs11Slot = NULL;
- pubKey->pkcs11ID = CK_INVALID_HANDLE;
- }
-diff --git a/lib/pk11wrap/pk11skey.c b/lib/pk11wrap/pk11skey.c
---- a/lib/pk11wrap/pk11skey.c
-+++ b/lib/pk11wrap/pk11skey.c
-@@ -433,17 +433,17 @@ PK11_VerifyKeyOK(PK11SymKey *key)
- return PR_FALSE;
- }
- return (PRBool)(key->series == key->slot->series);
- }
-
- static PK11SymKey *
- pk11_ImportSymKeyWithTempl(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
- PK11Origin origin, PRBool isToken, CK_ATTRIBUTE *keyTemplate,
-- unsigned int templateCount, SECItem *key, void *wincx)
-+ unsigned int templateCount, SECItem *key, PRBool force, void *wincx)
- {
- PK11SymKey *symKey;
- SECStatus rv;
-
- symKey = pk11_CreateSymKey(slot, type, !isToken, PR_TRUE, wincx);
- if (symKey == NULL) {
- return NULL;
- }
-@@ -458,22 +458,71 @@ pk11_ImportSymKeyWithTempl(PK11SlotInfo
- return NULL;
- }
-
- symKey->origin = origin;
-
- /* import the keys */
- rv = PK11_CreateNewObject(slot, symKey->session, keyTemplate,
- templateCount, isToken, &symKey->objectID);
-- if (rv != SECSuccess) {
-+ if (rv == SECSuccess) {
-+ return symKey;
-+ }
-+ /* we failed to create the key, if force isn't set, we just fail now */
-+ if (!force) {
-+ PK11_FreeSymKey(symKey);
-+ return NULL;
-+ }
-+ /* if force is set, we are simulating an unwrap, probably from another token, we
-+ * are probably here because we are trying to import into a FIPS token. Normally
-+ * we would want this to fail, but the application got here because they are using
-+ * unwrap, which is the correct way to do this, so try to import the key into
-+ * the FIPS token my hand */
-+ /* first generate a seed key */
-+ PK11SymKey *seedKey = PK11_KeyGen(slot, CKM_SHA256_HMAC, NULL, 256, wincx);
-+
-+ if (seedKey == NULL) {
- PK11_FreeSymKey(symKey);
- return NULL;
- }
-
-- return symKey;
-+ /* now append our key data to the seed key and truncate the seed key */
-+ CK_KEY_DERIVATION_STRING_DATA params = { 0 };
-+ CK_MECHANISM mechanism = { 0, NULL, 0 };
-+ params.pData = key->data;
-+ params.ulLen = key->len;
-+ mechanism.mechanism = CKM_CONCATENATE_DATA_AND_BASE;
-+ mechanism.pParameter = ¶ms;
-+ mechanism.ulParameterLen = sizeof(params);
-+
-+ /* derive removed the CKA_VALUE_LEN before it called us, but now we need
-+ * it back. We know there is space in the template because derive leaves
-+ * space for the CKA_VALUE_LEN attribute. Any other callers that set force
-+ * should also make sure there is space for the CKA_VALUE_LEN */
-+ CK_ULONG valueLen; /* Don't define this in the 'if' statement, because it
-+ * would go out of scope before we use it */
-+ if (!pk11_FindAttrInTemplate(keyTemplate, templateCount, CKA_VALUE_LEN)) {
-+ valueLen = (CK_ULONG)key->len;
-+ keyTemplate[templateCount].type = CKA_VALUE_LEN;
-+ keyTemplate[templateCount].pValue = (void *)&valueLen;
-+ keyTemplate[templateCount].ulValueLen = sizeof(valueLen);
-+ templateCount++;
-+ }
-+
-+ CK_RV crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, &mechanism,
-+ seedKey->objectID, keyTemplate,
-+ templateCount,
-+ &symKey->objectID);
-+ PK11_FreeSymKey(seedKey);
-+ if (crv == CKR_OK) {
-+ return symKey;
-+ }
-+
-+ PK11_FreeSymKey(symKey);
-+ return NULL;
- }
-
- /*
- * turn key bits into an appropriate key object
- */
- PK11SymKey *
- PK11_ImportSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
- PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key, void *wincx)
-@@ -501,17 +550,17 @@ PK11_ImportSymKey(PK11SlotInfo *slot, CK
- attrs++;
- PK11_SETATTRS(attrs, operation, &cktrue, 1);
- attrs++;
- templateCount = attrs - keyTemplate;
- PR_ASSERT(templateCount + 1 <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
-
- keyType = PK11_GetKeyType(type, key->len);
- symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, PR_FALSE,
-- keyTemplate, templateCount, key, wincx);
-+ keyTemplate, templateCount, key, PR_FALSE, wincx);
- return symKey;
- }
- /* Import a PKCS #11 data object and return it as a key. This key is
- * only useful in a limited number of mechanisms, such as HKDF. */
- PK11SymKey *
- PK11_ImportDataKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, PK11Origin origin,
- CK_ATTRIBUTE_TYPE operation, SECItem *key, void *wincx)
- {
-@@ -580,17 +629,17 @@ PK11_ImportSymKeyWithFlags(PK11SlotInfo
- PK11_SETATTRS(attrs, operation, &cktrue, sizeof(cktrue));
- attrs++;
- }
- templateCount = attrs - keyTemplate;
- PR_ASSERT(templateCount + 1 <= sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE));
-
- keyType = PK11_GetKeyType(type, key->len);
- symKey = pk11_ImportSymKeyWithTempl(slot, type, origin, isPerm,
-- keyTemplate, templateCount, key, wincx);
-+ keyTemplate, templateCount, key, PR_FALSE, wincx);
- if (symKey && isPerm) {
- symKey->owner = PR_FALSE;
- }
- return symKey;
- }
-
- PK11SymKey *
- PK11_FindFixedKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *keyID,
-@@ -2670,29 +2719,29 @@ pk11_HandUnwrap(PK11SlotInfo *slot, CK_O
- }
-
- outKey.len = (key_size == 0) ? len : key_size;
- outKey.type = siBuffer;
-
- if (PK11_DoesMechanism(slot, target)) {
- symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap,
- isPerm, keyTemplate,
-- templateCount, &outKey, wincx);
-+ templateCount, &outKey, PR_TRUE, wincx);
- } else {
- slot = PK11_GetBestSlot(target, wincx);
- if (slot == NULL) {
- PORT_SetError(SEC_ERROR_NO_MODULE);
- PORT_Free(outKey.data);
- if (crvp)
- *crvp = CKR_DEVICE_ERROR;
- return NULL;
- }
- symKey = pk11_ImportSymKeyWithTempl(slot, target, PK11_OriginUnwrap,
- isPerm, keyTemplate,
-- templateCount, &outKey, wincx);
-+ templateCount, &outKey, PR_TRUE, wincx);
- PK11_FreeSlot(slot);
- }
- PORT_Free(outKey.data);
-
- if (crvp)
- *crvp = symKey ? CKR_OK : CKR_DEVICE_ERROR;
- return symKey;
- }
-diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c
---- a/lib/softoken/pkcs11.c
-+++ b/lib/softoken/pkcs11.c
-@@ -1031,36 +1031,40 @@ sftk_handleCrlObject(SFTKSession *sessio
-
- /*
- * check the consistancy and initialize a Public Key Object
- */
- static CK_RV
- sftk_handlePublicKeyObject(SFTKSession *session, SFTKObject *object,
- CK_KEY_TYPE key_type)
- {
-- CK_BBOOL encrypt = CK_TRUE;
-- CK_BBOOL recover = CK_TRUE;
-- CK_BBOOL wrap = CK_TRUE;
-+ CK_BBOOL encrypt = CK_FALSE;
-+ CK_BBOOL recover = CK_FALSE;
-+ CK_BBOOL wrap = CK_FALSE;
- CK_BBOOL derive = CK_FALSE;
-- CK_BBOOL verify = CK_TRUE;
-+ CK_BBOOL verify = CK_FALSE;
- CK_BBOOL encapsulate = CK_FALSE;
- CK_ULONG paramSet = 0;
- CK_RV crv;
-
- switch (key_type) {
- case CKK_RSA:
- crv = sftk_ConstrainAttribute(object, CKA_MODULUS,
- RSA_MIN_MODULUS_BITS, 0, 0);
- if (crv != CKR_OK) {
- return crv;
- }
- crv = sftk_ConstrainAttribute(object, CKA_PUBLIC_EXPONENT, 2, 0, 0);
- if (crv != CKR_OK) {
- return crv;
- }
-+ encrypt = CK_TRUE;
-+ recover = CK_TRUE;
-+ wrap = CK_TRUE;
-+ verify = CK_TRUE;
- break;
- case CKK_DSA:
- crv = sftk_ConstrainAttribute(object, CKA_SUBPRIME,
- DSA_MIN_Q_BITS, DSA_MAX_Q_BITS, 0);
- if (crv != CKR_OK) {
- return crv;
- }
- crv = sftk_ConstrainAttribute(object, CKA_PRIME,
-@@ -1071,92 +1075,73 @@ sftk_handlePublicKeyObject(SFTKSession *
- crv = sftk_ConstrainAttribute(object, CKA_BASE, 2, DSA_MAX_P_BITS, 0);
- if (crv != CKR_OK) {
- return crv;
- }
- crv = sftk_ConstrainAttribute(object, CKA_VALUE, 2, DSA_MAX_P_BITS, 0);
- if (crv != CKR_OK) {
- return crv;
- }
-- encrypt = CK_FALSE;
-- recover = CK_FALSE;
-- wrap = CK_FALSE;
-+ verify = CK_TRUE;
- break;
- case CKK_DH:
- crv = sftk_ConstrainAttribute(object, CKA_PRIME,
- DH_MIN_P_BITS, DH_MAX_P_BITS, 0);
- if (crv != CKR_OK) {
- return crv;
- }
- crv = sftk_ConstrainAttribute(object, CKA_BASE, 2, DH_MAX_P_BITS, 0);
- if (crv != CKR_OK) {
- return crv;
- }
- crv = sftk_ConstrainAttribute(object, CKA_VALUE, 2, DH_MAX_P_BITS, 0);
- if (crv != CKR_OK) {
- return crv;
- }
-- verify = CK_FALSE;
- derive = CK_TRUE;
-- encrypt = CK_FALSE;
-- recover = CK_FALSE;
-- wrap = CK_FALSE;
- break;
- case CKK_EC_MONTGOMERY:
- case CKK_EC_EDWARDS:
- case CKK_EC:
- if (!sftk_hasAttribute(object, CKA_EC_PARAMS)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
- if (!sftk_hasAttribute(object, CKA_EC_POINT)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
- /* for ECDSA and EDDSA. Change if the structure of any of them is modified. */
- derive = (key_type == CKK_EC_EDWARDS) ? CK_FALSE : CK_TRUE; /* CK_TRUE for ECDH */
- verify = (key_type == CKK_EC_MONTGOMERY) ? CK_FALSE : CK_TRUE; /* for ECDSA and EDDSA */
-- encrypt = CK_FALSE;
-- recover = CK_FALSE;
-- wrap = CK_FALSE;
- break;
- #ifndef NSS_DISABLE_KYBER
- case CKK_NSS_KYBER:
- #endif
- case CKK_NSS_ML_KEM:
- case CKK_ML_KEM:
- if (!sftk_hasAttribute(object, CKA_PARAMETER_SET)) {
- if (!sftk_hasAttribute(object, CKA_NSS_PARAMETER_SET)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
- }
-- derive = CK_FALSE;
-- verify = CK_FALSE;
-- encrypt = CK_FALSE;
-- recover = CK_FALSE;
-- wrap = CK_FALSE;
- encapsulate = CK_TRUE;
- break;
- #ifdef NSS_ENABLE_ML_DSA
- case CKK_ML_DSA:
- if (!sftk_hasAttribute(object, CKA_PARAMETER_SET)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
- crv = sftk_GetULongAttribute (object, CKA_PARAMETER_SET,
- ¶mSet);
- if (crv != CKR_OK) {
- return crv;
- }
- if (sftk_MLDSAGetSigLen(paramSet) == 0) {
- return CKR_ATTRIBUTE_VALUE_INVALID;
- }
-- derive = CK_FALSE;
- verify = CK_TRUE;
-- encrypt = CK_FALSE;
-- recover = CK_FALSE;
-- wrap = CK_FALSE;
-- encapsulate = CK_FALSE;
- break;
- #endif
- default:
- return CKR_ATTRIBUTE_VALUE_INVALID;
- }
-
- /* make sure the required fields exist */
- crv = sftk_defaultAttribute(object, CKA_SUBJECT, NULL, 0);
-@@ -1224,21 +1209,21 @@ sftk_verifyRSAPrivateKey(SFTKObject *obj
-
- /*
- * check the consistancy and initialize a Private Key Object
- */
- static CK_RV
- sftk_handlePrivateKeyObject(SFTKSession *session, SFTKObject *object, CK_KEY_TYPE key_type)
- {
- CK_BBOOL cktrue = CK_TRUE;
-- CK_BBOOL encrypt = CK_TRUE;
-+ CK_BBOOL encrypt = CK_FALSE;
- CK_BBOOL sign = CK_FALSE;
-- CK_BBOOL recover = CK_TRUE;
-- CK_BBOOL wrap = CK_TRUE;
-- CK_BBOOL derive = CK_TRUE;
-+ CK_BBOOL recover = CK_FALSE;
-+ CK_BBOOL wrap = CK_FALSE;
-+ CK_BBOOL derive = CK_FALSE;
- CK_BBOOL decapsulate = CK_FALSE;
- CK_BBOOL ckfalse = CK_FALSE;
- PRBool createObjectInfo = PR_TRUE;
- PRBool fillPrivateKey = PR_FALSE;
- CK_ULONG paramSet = 0;
- int missing_rsa_mod_component = 0;
- int missing_rsa_exp_component = 0;
- int missing_rsa_crt_component = 0;
-@@ -1300,71 +1285,74 @@ sftk_handlePrivateKeyObject(SFTKSession
- crv = sftk_forceAttribute(object, CKA_NSS_DB,
- sftk_item_expand(&mod));
- if (mod.data)
- SECITEM_ZfreeItem(&mod, PR_FALSE);
- if (crv != CKR_OK)
- return crv;
-
- sign = CK_TRUE;
-- derive = CK_FALSE;
-+ wrap = CK_TRUE;
-+ encrypt = CK_TRUE;
- break;
- case CKK_DSA:
- if (!sftk_hasAttribute(object, CKA_SUBPRIME)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
-+ if (!sftk_hasAttribute(object, CKA_PRIME)) {
-+ return CKR_TEMPLATE_INCOMPLETE;
-+ }
-+ if (!sftk_hasAttribute(object, CKA_BASE)) {
-+ return CKR_TEMPLATE_INCOMPLETE;
-+ }
-+ if (!sftk_hasAttribute(object, CKA_VALUE)) {
-+ return CKR_TEMPLATE_INCOMPLETE;
-+ }
- sign = CK_TRUE;
-- derive = CK_FALSE;
-- /* fall through */
-+ break;
- case CKK_DH:
- if (!sftk_hasAttribute(object, CKA_PRIME)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
- if (!sftk_hasAttribute(object, CKA_BASE)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
- if (!sftk_hasAttribute(object, CKA_VALUE)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
- /* allow subprime to be set after the fact */
- crv = sftk_defaultAttribute(object, CKA_SUBPRIME, NULL, 0);
- if (crv != CKR_OK) {
- return crv;
- }
-- encrypt = CK_FALSE;
-- recover = CK_FALSE;
-- wrap = CK_FALSE;
-+ derive = CK_TRUE;
- break;
- case CKK_EC:
- case CKK_EC_EDWARDS:
- case CKK_EC_MONTGOMERY:
- if (!sftk_hasAttribute(object, CKA_EC_PARAMS)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
- if (!sftk_hasAttribute(object, CKA_VALUE)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
- /* for ECDSA and EDDSA. Change if the structure of any of them is modified. */
- derive = (key_type == CKK_EC_EDWARDS) ? CK_FALSE : CK_TRUE; /* CK_TRUE for ECDH */
- sign = (key_type == CKK_EC_MONTGOMERY) ? CK_FALSE : CK_TRUE; /* for ECDSA and EDDSA */
-- encrypt = CK_FALSE;
-- recover = CK_FALSE;
-- wrap = CK_FALSE;
- break;
- case CKK_NSS_JPAKE_ROUND1:
- if (!sftk_hasAttribute(object, CKA_PRIME) ||
- !sftk_hasAttribute(object, CKA_SUBPRIME) ||
- !sftk_hasAttribute(object, CKA_BASE)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
- /* fall through */
- case CKK_NSS_JPAKE_ROUND2:
- /* CKA_NSS_JPAKE_SIGNERID and CKA_NSS_JPAKE_PEERID are checked in
- the J-PAKE code. */
-- encrypt = sign = recover = wrap = CK_FALSE;
- derive = CK_TRUE;
- createObjectInfo = PR_FALSE;
- break;
- #ifndef NSS_DISABLE_KYBER
- case CKK_NSS_KYBER:
- #endif
- case CKK_NSS_ML_KEM:
- case CKK_ML_KEM:
-@@ -1374,17 +1362,16 @@ sftk_handlePrivateKeyObject(SFTKSession
- if (!sftk_hasAttribute(object, CKA_VALUE)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
- if (!sftk_hasAttribute(object, CKA_PARAMETER_SET)) {
- if (!sftk_hasAttribute(object, CKA_NSS_PARAMETER_SET)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
- }
-- encrypt = sign = recover = wrap = CK_FALSE;
- decapsulate = CK_TRUE;
- break;
- #ifdef NSS_ENABLE_ML_DSA
- case CKK_ML_DSA:
- if (!sftk_hasAttribute(object, CKA_KEY_TYPE)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
- /* make sure we have a CKA_PARAMETER_SET */
-@@ -1452,17 +1439,16 @@ sftk_handlePrivateKeyObject(SFTKSession
- }
- }
- sftk_DeleteAttributeType(object, CKA_NSS_SEED_OK);
- /* if we got this far, we should have a CKA_VALUE, either but
- * one given to us, or by it being generated above */
- if (!sftk_hasAttribute(object, CKA_VALUE)) {
- return CKR_TEMPLATE_INCOMPLETE;
- }
-- encrypt = decapsulate = recover = wrap = CK_FALSE;
- sign = CK_TRUE;
- break;
- #endif
- default:
- return CKR_ATTRIBUTE_VALUE_INVALID;
- }
- crv = sftk_defaultAttribute(object, CKA_SUBJECT, NULL, 0);
- if (crv != CKR_OK)
-diff --git a/lib/softoken/sftkdb.c b/lib/softoken/sftkdb.c
---- a/lib/softoken/sftkdb.c
-+++ b/lib/softoken/sftkdb.c
-@@ -54,16 +54,17 @@ sftkdb_isULONGAttribute(CK_ATTRIBUTE_TYP
- case CKA_KEY_GEN_MECHANISM:
- case CKA_KEY_TYPE:
- case CKA_MECHANISM_TYPE:
- case CKA_MODULUS_BITS:
- case CKA_PRIME_BITS:
- case CKA_SUBPRIME_BITS:
- case CKA_VALUE_BITS:
- case CKA_VALUE_LEN:
-+ case CKA_PARAMETER_SET:
-
- case CKA_TRUST_DIGITAL_SIGNATURE:
- case CKA_TRUST_NON_REPUDIATION:
- case CKA_TRUST_KEY_ENCIPHERMENT:
- case CKA_TRUST_DATA_ENCIPHERMENT:
- case CKA_TRUST_KEY_AGREEMENT:
- case CKA_TRUST_KEY_CERT_SIGN:
- case CKA_TRUST_CRL_SIGN:
-@@ -386,17 +387,25 @@ sftkdb_fixupTemplateOut(CK_ATTRIBUTE *te
- CK_ULONG value;
-
- value = sftk_SDBULong2ULong(ntemplate[i].pValue);
- if (length < sizeof(CK_ULONG)) {
- template[i].ulValueLen = -1;
- crv = CKR_BUFFER_TOO_SMALL;
- continue;
- }
-- PORT_Memcpy(template[i].pValue, &value, sizeof(CK_ULONG));
-+ /* handle the case where the CKA_PARAMETER_SET was
-+ * incorrectly encoded */
-+ if ((value > 0xff) &&
-+ (template[i].type == CKA_PARAMETER_SET)) {
-+ PORT_Memcpy(template[i].pValue, ntemplate[i].pValue,
-+ ntemplate[i].ulValueLen);
-+ } else {
-+ PORT_Memcpy(template[i].pValue, &value, sizeof(CK_ULONG));
-+ }
- }
- template[i].ulValueLen = sizeof(CK_ULONG);
- }
- }
-
- /* if no data was retrieved, no need to process encrypted or signed
- * attributes */
- if ((template[i].pValue == NULL) || (template[i].ulValueLen == -1)) {
-@@ -1580,16 +1589,18 @@ sftkdb_DestroyObject(SFTKDBHandle *handl
- (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
- CKA_PRIME_2);
- (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
- CKA_EXPONENT_1);
- (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
- CKA_EXPONENT_2);
- (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
- CKA_COEFFICIENT);
-+ (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
-+ CKA_SEED);
- } else {
- keydb = SFTK_GET_SDB(handle->peerDB);
- }
- /* now destroy any authenticated attributes that may exist */
- (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
- CKA_MODULUS);
- (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
- CKA_PUBLIC_EXPONENT);
-diff --git a/lib/softoken/sftkpwd.c b/lib/softoken/sftkpwd.c
---- a/lib/softoken/sftkpwd.c
-+++ b/lib/softoken/sftkpwd.c
-@@ -1205,16 +1205,17 @@ sftk_updateEncrypted(PLArenaPool *arena,
- CK_ATTRIBUTE_TYPE privAttrTypes[] = {
- CKA_VALUE,
- CKA_PRIVATE_EXPONENT,
- CKA_PRIME_1,
- CKA_PRIME_2,
- CKA_EXPONENT_1,
- CKA_EXPONENT_2,
- CKA_COEFFICIENT,
-+ CKA_SEED,
- };
- const CK_ULONG privAttrCount = sizeof(privAttrTypes) / sizeof(privAttrTypes[0]);
-
- // We don't know what attributes this object has, so we update them one at a
- // time.
- unsigned int i;
- for (i = 0; i < privAttrCount; i++) {
- // Read the old attribute in the clear.
diff --git a/nss-3.118-ml-dsa-leancrypto.patch b/nss-3.118-ml-dsa-leancrypto.patch
new file mode 100644
index 0000000..cf181d6
--- /dev/null
+++ b/nss-3.118-ml-dsa-leancrypto.patch
@@ -0,0 +1,21025 @@
+diff --git a/lib/freebl/Makefile b/lib/freebl/Makefile
+--- a/lib/freebl/Makefile
++++ b/lib/freebl/Makefile
+@@ -605,10 +605,26 @@
+
+ VERIFIED_SRCS += Hacl_Hash_SHA3.c Hacl_P256.c Hacl_P384.c Hacl_P521.c libcrux_sha3_portable.c libcrux_mlkem768_portable.c libcrux_mlkem1024_portable.c libcrux_mlkem_portable.c libcrux_core.c
+ VERIFIED_SRCS += Hacl_Ed25519.c
+ VERIFIED_SRCS += Hacl_Curve25519_51.c
+
++INCLUDES += -Ileancrypto
++ML_DSA_SRCS += ml_dsa_44_ntt.c
++ML_DSA_SRCS += ml_dsa_44_poly.c
++ML_DSA_SRCS += ml_dsa_44_rounding.c
++ML_DSA_SRCS += ml_dsa_44_signature_c.c
++ML_DSA_SRCS += ml_dsa_65_ntt.c
++ML_DSA_SRCS += ml_dsa_65_poly.c
++ML_DSA_SRCS += ml_dsa_65_rounding.c
++ML_DSA_SRCS += ml_dsa_65_signature_c.c
++ML_DSA_SRCS += ml_dsa_87_ntt.c
++ML_DSA_SRCS += ml_dsa_87_poly.c
++ML_DSA_SRCS += ml_dsa_87_rounding.c
++ML_DSA_SRCS += ml_dsa_87_signature_c.c
++ML_DSA_SRCS += signature_domain_separation.c
++ML_DSA_SRCS += mldsa_zetas.c
++
+ # Bug 1918767 / Bug 1918711 - by setting KRML_MUSTINLINE=inline here, we
+ # avoid it being defined to `inline __forceinline` (for msvc) or `inline
+ # __attribute__((always_inline))` (for gcc/clang) in
+ # verified/karamel/include/krml/internal/target.h. These other
+ # configurations can cause excessive stack usage.
+@@ -642,12 +658,12 @@
+ rijndael_tables:
+ $(CC) -o $(OBJDIR)/make_rijndael_tab rijndael_tables.c \
+ $(DEFINES) $(INCLUDES) $(OBJDIR)/libfreebl.a
+ $(OBJDIR)/make_rijndael_tab
+
+-vpath %.h mpi ecl verified deprecated
+-vpath %.c mpi ecl verified deprecated
++vpath %.h mpi ecl verified oqs leancrypto deprecated
++vpath %.c mpi ecl verified oqs leancrypto deprecated
+ vpath %.S mpi ecl
+ vpath %.s mpi ecl
+ vpath %.asm mpi ecl
+ INCLUDES += -Impi -Iecl -Iverified -Iverified/internal -Iverified/karamel/include -Iverified/karamel/krmllib/dist/minimal -Iverified/eurydice -Ideprecated
+
+diff --git a/lib/freebl/freebl.gyp b/lib/freebl/freebl.gyp
+--- a/lib/freebl/freebl.gyp
++++ b/lib/freebl/freebl.gyp
+@@ -762,10 +762,11 @@
+ ],
+ 'target_defaults': {
+ 'include_dirs': [
+ 'mpi',
+ 'ecl',
++ 'leancrypto',
+ 'verified',
+ 'verified/internal',
+ 'verified/karamel/include',
+ 'verified/karamel/krmllib/dist/minimal',
+ 'deprecated',
+diff --git a/lib/freebl/freebl_base.gypi b/lib/freebl/freebl_base.gypi
+--- a/lib/freebl/freebl_base.gypi
++++ b/lib/freebl/freebl_base.gypi
+@@ -62,10 +62,24 @@
+ 'verified/Hacl_P521.c',
+ 'sha3.c',
+ 'shake.c',
+ 'verified/Hacl_Curve25519_51.c',
+ 'verified/Hacl_Ed25519.c',
++ 'leancrypto/ml_dsa_44_ntt.c',
++ 'leancrypto/ml_dsa_44_poly.c',
++ 'leancrypto/ml_dsa_44_rounding.c',
++ 'leancrypto/ml_dsa_44_signature_c.c',
++ 'leancrypto/ml_dsa_65_ntt.c',
++ 'leancrypto/ml_dsa_65_poly.c',
++ 'leancrypto/ml_dsa_65_rounding.c',
++ 'leancrypto/ml_dsa_65_signature_c.c',
++ 'leancrypto/ml_dsa_87_ntt.c',
++ 'leancrypto/ml_dsa_87_poly.c',
++ 'leancrypto/ml_dsa_87_rounding.c',
++ 'leancrypto/ml_dsa_87_signature_c.c',
++ 'leancrypto/signature_domain_separation.c',
++ 'leancrypto/mldsa_zetas.c',
+ ],
+ 'defines': [
+ # For kyber-pqcrystals-ref.c. If we ever decide to support Kyber512 or
+ # Kyber1024, we'll need to build separate static libraries with different
+ # values of KYBER_K.
+diff --git a/lib/freebl/leancrypto/alignment.h b/lib/freebl/leancrypto/alignment.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/alignment.h
+@@ -0,0 +1,69 @@
++/*
++ * Copyright (C) 2022 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++/*
++ * This code is derived in parts from the code distribution provided with
++ * https://github.com/pq-crystals/dilithium
++ *
++ * That code is released under Public Domain
++ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
++ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
++ */
++
++#ifndef ALIGNMENT_H
++#define ALIGNMENT_H
++
++#include "ext_headers.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#if defined(__GNUC__)
++#define __align(x) __attribute__((aligned(x)))
++#elif defined(_MSC_VER)
++//#define __align(x) __declspec(align(x))
++#define __align(x) __attribute__((aligned(x)))
++#elif defined(__ARMCC_VERSION)
++/* Nothing, the used macro is known to the compiler */
++#else
++#define __align(x)
++#endif
++
++#define ALIGNED_UINT8_COEFFS(N) N
++#define ALIGNED_UINT8_UINT64(N) ((N + 7) / 8)
++
++#define BUF_ALIGNED_UINT8_UINT64(N) \
++ union { \
++ uint8_t coeffs[ALIGNED_UINT8_COEFFS(N)]; \
++ uint64_t vec[ALIGNED_UINT8_UINT64(N)]; \
++ }
++
++static inline int
++aligned(const uint8_t *ptr, uint32_t alignmask)
++{
++ if ((uintptr_t)ptr & alignmask)
++ return 0;
++ return 1;
++}
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* ALIGNMENT_H */
+diff --git a/lib/freebl/leancrypto/atomic.h b/lib/freebl/leancrypto/atomic.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/atomic.h
+@@ -0,0 +1,268 @@
++/*
++ * Copyright (C) 2018 - 2025, Stephan Mueller
++ *
++ * License: see COPYING file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef _ATOMIC_H
++#define _ATOMIC_H
++
++#ifndef LINUX_KERNEL
++
++/*
++ * Atomic operations only work on:
++ * GCC >= 4.1
++ * Clang / LLVM
++ */
++
++/**
++ * Atomic type and operations equivalent to the Linux kernel.
++ */
++typedef struct {
++ volatile int counter;
++} atomic_t;
++
++/**
++ * Memory barrier
++ */
++static inline void
++mb(void)
++{
++ __sync_synchronize();
++}
++
++#define ATOMIC_INIT(i) \
++ { \
++ (i) \
++ }
++
++/**
++ * Read atomic variable
++ * @param v atomic variable
++ * @return variable content
++ */
++static inline int
++atomic_read(const atomic_t *v)
++{
++ int i;
++
++ mb();
++ i = ((v)->counter);
++ mb();
++
++ return i;
++}
++
++/**
++ * Set atomic variable
++ * @param v atomic variable
++ * @param i value to be set
++ */
++static inline void
++atomic_set(atomic_t *v, int i)
++{
++ mb();
++ ((v)->counter) = i;
++ mb();
++}
++
++/**
++ * Atomic add operation
++ * @param i integer value to add
++ * @param v atomic variable
++ * @return variable content after operation
++ */
++static inline int
++atomic_add(int i, atomic_t *v)
++{
++ return __sync_add_and_fetch(&v->counter, i);
++}
++
++/**
++ * Atomic add value from variable and test for zero
++ * @param i integer value to add
++ * @param v atomic variable
++ * @return true if the result is zero, or false for all other cases.
++ */
++static inline int
++atomic_add_and_test(int i, atomic_t *v)
++{
++ return !(__sync_add_and_fetch(&v->counter, i));
++}
++
++/**
++ * Atomic increment by 1
++ * @param v atomic variable
++ * @return variable content after operation
++ */
++static inline int
++atomic_inc(atomic_t *v)
++{
++ return atomic_add(1, v);
++}
++
++/**
++ * Atomic increment and test for zero
++ * @param v pointer of type atomic_t
++ * @return true if the result is zero, or false for all other cases.
++ */
++static inline int
++atomic_inc_and_test(atomic_t *v)
++{
++ return atomic_add_and_test(1, v);
++}
++
++/**
++ * Atomic subtract operation
++ * @param i integer value to subtract
++ * @param v atomic variable
++ * @return variable content after operation
++ */
++static inline int
++atomic_sub(int i, atomic_t *v)
++{
++ return __sync_sub_and_fetch(&v->counter, i);
++}
++
++/**
++ * Atomic subtract value from variable and test for zero
++ * @param i integer value to subtract
++ * @param v atomic variable
++ * @return true if the result is zero, or false for all other cases.
++ */
++static inline int
++atomic_sub_and_test(int i, atomic_t *v)
++{
++ return !(__sync_sub_and_fetch(&v->counter, i));
++}
++
++/**
++ * Atomic decrement by 1
++ * @param v atomic variable
++ * @return variable content after operation
++ */
++static inline int
++atomic_dec(atomic_t *v)
++{
++ return atomic_sub(1, v);
++}
++
++/**
++ * Atomic decrement by 1 and test for zero
++ * @param v atomic variable
++ * @return true if the result is zero, or false for all other cases.
++ */
++static inline int
++atomic_dec_and_test(atomic_t *v)
++{
++ return atomic_sub_and_test(1, v);
++}
++
++/**
++ * Atomic or operation
++ * @param i integer value to or
++ * @param v atomic variable
++ * @return variable content after operation
++ */
++static inline int
++atomic_or(int i, atomic_t *v)
++{
++ return __sync_or_and_fetch(&v->counter, i);
++}
++
++/**
++ * Atomic xor operation
++ * @param i integer value to xor
++ * @param v atomic variable
++ * @return variable content after operation
++ */
++static inline int
++atomic_xor(int i, atomic_t *v)
++{
++ return __sync_xor_and_fetch(&v->counter, i);
++}
++
++/**
++ * Atomic and operation
++ * @param i integer value to and
++ * @param v atomic variable
++ * @return variable content after operation
++ */
++static inline int
++atomic_and(int i, atomic_t *v)
++{
++ return __sync_and_and_fetch(&v->counter, i);
++}
++
++#ifdef __clang__
++#pragma clang diagnostic push
++#pragma clang diagnostic ignored "-Wsync-fetch-and-nand-semantics-changed"
++#endif
++/**
++ * Atomic nand operation
++ * @param i integer value to nand
++ * @param v atomic variable
++ * @return variable content after operation
++ */
++static inline int
++atomic_nand(int i, atomic_t *v)
++{
++ return __sync_nand_and_fetch(&v->counter, i);
++}
++#ifdef __clang__
++#pragma clang diagnostic pop
++#endif
++
++/**
++ * Atomic compare and exchange operation (if current value of atomic
++ * variable is equal to the old value, set the new value)
++ * @param v atomic variable
++ * @param old integer value to compare with
++ * @param new integer value to set atomic variable to
++ * @return original value if comparison is successful and new was written
++ * To verify that the exchange was successful, the caller must compare
++ * the return value with the old value.
++ */
++static inline int
++atomic_cmpxchg(atomic_t *v, int old, int new)
++{
++ return __sync_val_compare_and_swap(&v->counter, old, new);
++}
++
++/**
++ * Atomic operation with a caller-provided function to derive the new
++ * value from the old value. Note, the caller-provided function may be called
++ * multiple times.
++ *
++ * @param v atomic variable
++ * @param data parameter that is given to the check function to maintain a state
++ * @param check_func Function that returns the new value to be set. The function
++ * is invoked with the old value as input parameter.
++ */
++static inline void
++atomic_update_with_func(atomic_t *v, void *data,
++ int (*check_func)(void *data,
++ int old))
++{
++ int old;
++
++ do {
++ old = atomic_read(v);
++ } while (atomic_cmpxchg(v, old, check_func(data, old)) != old);
++}
++
++#endif /* LINUX_KERNEL */
++#endif /* _ATOMIC_H */
+diff --git a/lib/freebl/leancrypto/atomic_bool.h b/lib/freebl/leancrypto/atomic_bool.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/atomic_bool.h
+@@ -0,0 +1,116 @@
++/*
++ * Copyright (C) 2018 - 2025, Stephan Mueller
++ *
++ * License: see COPYING file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef _ATOMIC_BOOL_H
++#define _ATOMIC_BOOL_H
++
++#include "bool.h"
++
++/*
++ * Atomic operations only work on:
++ * GCC >= 4.1
++ * Clang / LLVM
++ */
++
++/**
++ * Atomic type and operations equivalent to the Linux kernel.
++ */
++typedef struct {
++ volatile bool counter;
++} atomic_bool_t;
++
++/**
++ * Memory barrier
++ */
++static inline void
++atomic_bool_mb(void)
++{
++ __sync_synchronize();
++}
++
++#define ATOMIC_BOOL_INIT(i) \
++ { \
++ (i) \
++ }
++
++/**
++ * Read atomic variable
++ * @param v atomic variable
++ * @return variable content
++ */
++static inline bool
++atomic_bool_read(const atomic_bool_t *v)
++{
++ bool i;
++
++ atomic_bool_mb();
++ i = ((v)->counter);
++ atomic_bool_mb();
++
++ return i;
++}
++
++/**
++ * Set atomic variable
++ * @param i value to be set
++ * @param v atomic variable
++ */
++static inline void
++atomic_bool_set(bool i, atomic_bool_t *v)
++{
++ atomic_bool_mb();
++ ((v)->counter) = i;
++ atomic_bool_mb();
++}
++
++/**
++ * Set atomic variable to true
++ * @param v atomic variable
++ */
++static inline void
++atomic_bool_set_true(atomic_bool_t *v)
++{
++ atomic_bool_set(true, v);
++}
++
++/**
++ * Set atomic variable to false
++ * @param v atomic variable
++ */
++static inline void
++atomic_bool_set_false(atomic_bool_t *v)
++{
++ atomic_bool_set(false, v);
++}
++
++/**
++ * Atomic compare and exchange operation (if current value of atomic
++ * variable is equal to the old value, set the new value)
++ * @param v atomic variable
++ * @param old integer value to compare with
++ * @param new integer value to set atomic variable to
++ * @return true if comparison is successful and new was written
++ */
++static inline int
++atomic_bool_cmpxchg(atomic_bool_t *v, bool old, bool new)
++{
++ return __sync_bool_compare_and_swap(&v->counter, old, new);
++}
++
++#endif /* _ATOMIC_BOOL_H */
+diff --git a/lib/freebl/leancrypto/binhexbin.h b/lib/freebl/leancrypto/binhexbin.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/binhexbin.h
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2018 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef _BINHEXBIN_H
++#define _BINHEXBIN_H
++
++#include "ext_headers.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++void hex2bin(const char *hex, const size_t hexlen, uint8_t *bin,
++ const size_t binlen);
++int hex2bin_alloc(const char *hex, const size_t hexlen, uint8_t **bin,
++ size_t *binlen);
++int bin2hex_alloc(const uint8_t *bin, const size_t binlen, char **hex,
++ size_t *hexlen);
++void bin2print(const unsigned char *bin, const size_t binlen, FILE *out,
++ const char *explanation);
++void bin2hex(const uint8_t *bin, const size_t binlen, char *hex,
++ const size_t hexlen, const int u);
++
++int bin2hex_html(const char *str, const size_t strlen, char *html,
++ const size_t htmllen);
++int bin2hex_html_from_url(const char *str, const size_t strlen, char *html,
++ const size_t htmllen);
++int bin2hex_html_alloc(const char *str, const size_t strlen, char **html,
++ size_t *htmllen);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _BINHEXBIN_H */
+diff --git a/lib/freebl/leancrypto/bitshift.h b/lib/freebl/leancrypto/bitshift.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/bitshift.h
+@@ -0,0 +1,91 @@
++/* Conversion of a pointer value to an integer
++ *
++ * Copyright (C) 2022 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef BITSHIFT_H
++#define BITSHIFT_H
++
++#include "bitshift_le.h"
++#include "bitshift_be.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++
++static inline uint64_t
++ptr_to_64(const uint8_t *p)
++{
++ return ptr_to_be64(p);
++}
++
++static inline uint32_t
++ptr_to_32(const uint8_t *p)
++{
++ return ptr_to_be32(p);
++}
++
++static inline void
++val64_to_ptr(uint8_t *p, const uint64_t value)
++{
++ be64_to_ptr(p, value);
++}
++
++static inline void
++val32_to_ptr(uint8_t *p, const uint32_t value)
++{
++ be32_to_ptr(p, value);
++}
++
++#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
++
++static inline uint64_t
++ptr_to_64(const uint8_t *p)
++{
++ return ptr_to_le64(p);
++}
++
++static inline uint32_t
++ptr_to_32(const uint8_t *p)
++{
++ return ptr_to_le32(p);
++}
++
++static inline void
++val64_to_ptr(uint8_t *p, const uint64_t value)
++{
++ le64_to_ptr(p, value);
++}
++
++static inline void
++val32_to_ptr(uint8_t *p, const uint32_t value)
++{
++ le32_to_ptr(p, value);
++}
++
++#else
++#error "Endianess not defined"
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* BITSHIFT_H */
+diff --git a/lib/freebl/leancrypto/bitshift_be.h b/lib/freebl/leancrypto/bitshift_be.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/bitshift_be.h
+@@ -0,0 +1,66 @@
++/*
++ * Copyright (C) 2020 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef BITSHIFT_BE_H
++#define BITSHIFT_BE_H
++
++#include "ext_headers.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/*
++ * Conversion of Big-Endian representations in byte streams - the data
++ * representation in the integer values is the host representation.
++ */
++static inline uint32_t
++ptr_to_be32(const uint8_t *p)
++{
++ return (uint32_t)p[0] << 24 | (uint32_t)p[1] << 16 |
++ (uint32_t)p[2] << 8 | (uint32_t)p[3];
++}
++
++static inline uint64_t
++ptr_to_be64(const uint8_t *p)
++{
++ return (uint64_t)ptr_to_be32(p) << 32 | (uint64_t)ptr_to_be32(p + 4);
++}
++
++static inline void
++be32_to_ptr(uint8_t *p, const uint32_t value)
++{
++ p[0] = (uint8_t)(value >> 24);
++ p[1] = (uint8_t)(value >> 16);
++ p[2] = (uint8_t)(value >> 8);
++ p[3] = (uint8_t)(value);
++}
++
++static inline void
++be64_to_ptr(uint8_t *p, const uint64_t value)
++{
++ be32_to_ptr(p, (uint32_t)(value >> 32));
++ be32_to_ptr(p + 4, (uint32_t)(value));
++}
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* BITSHIFT_BE_H */
+diff --git a/lib/freebl/leancrypto/bitshift_le.h b/lib/freebl/leancrypto/bitshift_le.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/bitshift_le.h
+@@ -0,0 +1,66 @@
++/*
++ * Copyright (C) 2020 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef BITSHIFT_LE_H
++#define BITSHIFT_LE_H
++
++#include "ext_headers.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/*
++ * Conversion of Little-Endian representations in byte streams - the data
++ * representation in the integer values is the host representation.
++ */
++static inline uint32_t
++ptr_to_le32(const uint8_t *p)
++{
++ return (uint32_t)p[0] | (uint32_t)p[1] << 8 | (uint32_t)p[2] << 16 |
++ (uint32_t)p[3] << 24;
++}
++
++static inline uint64_t
++ptr_to_le64(const uint8_t *p)
++{
++ return (uint64_t)ptr_to_le32(p) | (uint64_t)ptr_to_le32(p + 4) << 32;
++}
++
++static inline void
++le32_to_ptr(uint8_t *p, const uint32_t value)
++{
++ p[0] = (uint8_t)(value);
++ p[1] = (uint8_t)(value >> 8);
++ p[2] = (uint8_t)(value >> 16);
++ p[3] = (uint8_t)(value >> 24);
++}
++
++static inline void
++le64_to_ptr(uint8_t *p, const uint64_t value)
++{
++ le32_to_ptr(p + 4, (uint32_t)(value >> 32));
++ le32_to_ptr(p, (uint32_t)(value));
++}
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* BITSHIFT_LE_H */
+diff --git a/lib/freebl/leancrypto/bool.h b/lib/freebl/leancrypto/bool.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/bool.h
+@@ -0,0 +1,42 @@
++/*
++ * Copyright (C) 2018 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef BOOL_H
++#define BOOL_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#ifndef LINUX_KERNEL
++
++#if defined(__STDC_VERSION__) && __STDC_VERSION__ < 202311L && !defined(false)
++/* Boolean variable */
++enum { false,
++ true };
++typedef _Bool bool;
++#endif
++
++#endif /* LINUX_KERNEL */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* BOOL_H */
+diff --git a/lib/freebl/leancrypto/build_bug_on.h b/lib/freebl/leancrypto/build_bug_on.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/build_bug_on.h
+@@ -0,0 +1,27 @@
++/*
++ * Copyright (C) 2018 - 2023, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef _BUILD_BUG_ON_H
++#define _BUILD_BUG_ON_H
++
++#ifndef LINUX_KERNEL
++#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2 * !!(condition)]))
++#endif
++
++#endif /* _BUILD_BUG_ON_H */
+diff --git a/lib/freebl/leancrypto/compare.h b/lib/freebl/leancrypto/compare.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/compare.h
+@@ -0,0 +1,53 @@
++/*
++ * Copyright (C) 2022 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef COMPARE_H
++#define COMPARE_H
++
++#include "ext_headers.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++int get_current_selftest_level(void);
++
++#ifdef LC_SELFTEST_ENABLED
++#define LC_SELFTEST_RUN(x) \
++ if (*x == get_current_selftest_level()) \
++ return; \
++ *x = get_current_selftest_level();
++#else /* LC_SELFTEST_ENABLED */
++#define LC_SELFTEST_RUN(x) \
++ (void)x; \
++ if (1) \
++ return;
++#endif /* LC_SELFTEST_ENABLED */
++
++int lc_compare(const uint8_t *act, const uint8_t *exp, const size_t len,
++ const char *info);
++void lc_compare_selftest(const uint8_t *act, const uint8_t *exp,
++ const size_t len, const char *info);
++void lc_disable_selftest(void);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* COMPARE_H */
+diff --git a/lib/freebl/leancrypto/conv_be_le.h b/lib/freebl/leancrypto/conv_be_le.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/conv_be_le.h
+@@ -0,0 +1,157 @@
++/* Conversion functions from LE to BE and vice versa
++ *
++ * Copyright (C) 2015 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef CONV_BE_LE_H
++#define CONV_BE_LE_H
++
++#include "ext_headers.h"
++#include "rotate.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#if !defined(CONVERSION_TEST) && (defined(__gcc__) || defined(__clang__))
++#define __HAVE_BUILTIN_BSWAP16__
++#define __HAVE_BUILTIN_BSWAP32__
++#define __HAVE_BUILTIN_BSWAP64__
++#endif
++
++/* Byte swap for 16-bit, 32-bit and 64-bit integers. */
++#ifndef __HAVE_BUILTIN_BSWAP16__
++static inline uint16_t
++_lc_bswap16(uint16_t x)
++{
++ return (uint16_t)((rol16(x, 8) & 0x00ff) | (ror16(x, 8) & 0xff00));
++}
++#define _lc_swap16(x) _lc_bswap16((uint16_t)(x))
++#else
++#define _lc_swap16(x) (uint16_t) __builtin_bswap16((uint16_t)(x))
++#endif
++
++#if !defined(__HAVE_BUILTIN_BSWAP32__) || !defined(__HAVE_BUILTIN_BSWAP64__)
++static inline uint32_t
++_lc_bswap32(uint32_t x)
++{
++ return ((rol32(x, 8) & 0x00ff00ffL) | (ror32(x, 8) & 0xff00ff00L));
++}
++#define _lc_swap32(x) _lc_bswap32((uint32_t)(x))
++#else
++#define _lc_swap32(x) (uint32_t) __builtin_bswap32((uint32_t)(x))
++#endif
++
++#ifndef __HAVE_BUILTIN_BSWAP64__
++static inline uint64_t
++_lc_bswap64(uint64_t x)
++{
++ return ((uint64_t)_lc_bswap32((uint32_t)x) << 32) |
++ (_lc_bswap32((uint32_t)(x >> 32)));
++}
++#define _lc_swap64(x) _lc_bswap64((uint64_t)(x))
++#else
++#define _lc_swap64(x) (uint64_t) __builtin_bswap64((uint64_t)(x))
++#endif
++
++/* Endian dependent byte swap operations. */
++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
++
++static inline uint16_t
++le_bswap16(uint16_t x)
++{
++ return _lc_swap16(x);
++}
++
++static inline uint16_t
++be_bswap16(uint16_t x)
++{
++ return x;
++}
++
++static inline uint32_t
++le_bswap32(uint32_t x)
++{
++ return _lc_swap32(x);
++}
++
++static inline uint32_t
++be_bswap32(uint32_t x)
++{
++ return x;
++}
++
++static inline uint64_t
++le_bswap64(uint64_t x)
++{
++ return _lc_swap64(x);
++}
++
++static inline uint64_t
++be_bswap64(uint64_t x)
++{
++ return x;
++}
++
++#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
++
++static inline uint16_t
++le_bswap16(uint16_t x)
++{
++ return x;
++}
++
++static inline uint16_t
++be_bswap16(uint16_t x)
++{
++ return _lc_swap16(x);
++}
++
++static inline uint32_t
++le_bswap32(uint32_t x)
++{
++ return x;
++}
++
++static inline uint32_t
++be_bswap32(uint32_t x)
++{
++ return _lc_swap32(x);
++}
++
++static inline uint64_t
++le_bswap64(uint64_t x)
++{
++ return x;
++}
++
++static inline uint64_t
++be_bswap64(uint64_t x)
++{
++ return _lc_swap64(x);
++}
++
++#else
++#error "Endianess not defined"
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* CONV_BE_LE_H */
+diff --git a/lib/freebl/leancrypto/dilithium_debug.h b/lib/freebl/leancrypto/dilithium_debug.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_debug.h
+@@ -0,0 +1,94 @@
++/*
++ * Copyright (C) 2023 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef DILITHIUM_DEBUG_H
++#define DILITHIUM_DEBUG_H
++
++#include "dilithium_type.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#ifdef LC_DILITHIUM_DEBUG
++
++/* Disable selftests */
++#define LC_DILITHIUM_TEST_INIT 1
++
++void dilithium_print_buffer(const uint8_t *buffer, const size_t bufferlen,
++ const char *explanation);
++void dilithium_print_polyvecl_k(polyvecl mat[LC_DILITHIUM_K],
++ const char *explanation);
++void dilithium_print_polyvecl(polyvecl *polyvec, const char *explanation);
++void dilithium_print_polyveck(polyveck *polyvec, const char *explanation);
++void dilithium_print_poly(poly *vec, const char *explanation);
++
++#else /* LC_DILITHIUM_DEBUG */
++
++/* Enable selftests */
++#define LC_DILITHIUM_TEST_INIT 0
++
++static inline void
++dilithium_print_buffer(const uint8_t *buffer,
++ const size_t bufferlen,
++ const char *explanation)
++{
++ (void)buffer;
++ (void)bufferlen;
++ (void)explanation;
++}
++
++static inline void
++dilithium_print_polyvecl_k(polyvecl mat[LC_DILITHIUM_K],
++ const char *explanation)
++{
++ (void)mat;
++ (void)explanation;
++}
++
++static inline void
++dilithium_print_polyvecl(polyvecl *polyvec,
++ const char *explanation)
++{
++ (void)polyvec;
++ (void)explanation;
++}
++
++static inline void
++dilithium_print_polyveck(polyveck *polyvec,
++ const char *explanation)
++{
++ (void)polyvec;
++ (void)explanation;
++}
++
++static inline void
++dilithium_print_poly(poly *vec, const char *explanation)
++{
++ (void)vec;
++ (void)explanation;
++}
++
++#endif /* LC_DILITHIUM_DEBUG */
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_DEBUG_H */
+diff --git a/lib/freebl/leancrypto/dilithium_ntt.h b/lib/freebl/leancrypto/dilithium_ntt.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_ntt.h
+@@ -0,0 +1,45 @@
++/*
++ * Copyright (C) 2022 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++/*
++ * This code is derived in parts from the code distribution provided with
++ * https://github.com/pq-crystals/dilithium
++ *
++ * That code is released under Public Domain
++ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
++ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
++ */
++
++#ifndef DILITHIUM_NTT_H
++#define DILITHIUM_NTT_H
++
++#include "ext_headers.h"
++#include "dilithium_type.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++void ntt(int32_t a[LC_DILITHIUM_N]);
++void invntt_tomont(int32_t a[LC_DILITHIUM_N]);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_NTT_H */
+diff --git a/lib/freebl/leancrypto/dilithium_pack.h b/lib/freebl/leancrypto/dilithium_pack.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_pack.h
+@@ -0,0 +1,315 @@
++/*
++ * Copyright (C) 2022 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++/*
++ * This code is derived in parts from the code distribution provided with
++ * https://github.com/pq-crystals/dilithium
++ *
++ * That code is released under Public Domain
++ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
++ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
++ */
++
++#ifndef DILITHIUM_PACK_H
++#define DILITHIUM_PACK_H
++
++#include "build_bug_on.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/*******************************************************************************
++ * Pack / Unpack public key
++ ******************************************************************************/
++static inline void
++pack_pk_rho(struct lc_dilithium_pk *pk,
++ const uint8_t rho[LC_DILITHIUM_SEEDBYTES])
++{
++ memcpy(pk->pk, rho, LC_DILITHIUM_SEEDBYTES);
++}
++
++static inline void
++pack_pk_t1(struct lc_dilithium_pk *pk, const polyveck *t1)
++{
++ unsigned int i;
++ uint8_t *pubkey = pk->pk + LC_DILITHIUM_SEEDBYTES;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ polyt1_pack(pubkey + i * LC_DILITHIUM_POLYT1_PACKEDBYTES,
++ &t1->vec[i]);
++}
++
++static inline void
++unpack_pk_rho(uint8_t rho[LC_DILITHIUM_SEEDBYTES],
++ const struct lc_dilithium_pk *pk)
++{
++ memcpy(rho, pk->pk, LC_DILITHIUM_SEEDBYTES);
++}
++
++static inline void
++unpack_pk_t1(polyveck *t1, const struct lc_dilithium_pk *pk)
++{
++ unsigned int i;
++ const uint8_t *pubkey = pk->pk + LC_DILITHIUM_SEEDBYTES;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ polyt1_unpack(&t1->vec[i],
++ pubkey + i * LC_DILITHIUM_POLYT1_PACKEDBYTES);
++}
++
++/*******************************************************************************
++ * Pack / Unpack secret key
++ ******************************************************************************/
++static inline void
++pack_sk_rho(struct lc_dilithium_sk *sk,
++ const uint8_t rho[LC_DILITHIUM_SEEDBYTES])
++{
++ memcpy(sk->sk, rho, LC_DILITHIUM_SEEDBYTES);
++}
++
++static inline void
++pack_sk_key(struct lc_dilithium_sk *sk,
++ const uint8_t key[LC_DILITHIUM_SEEDBYTES])
++{
++ memcpy(sk->sk + LC_DILITHIUM_SEEDBYTES, key, LC_DILITHIUM_SEEDBYTES);
++}
++
++static inline void
++pack_sk_tr(struct lc_dilithium_sk *sk,
++ const uint8_t tr[LC_DILITHIUM_TRBYTES])
++{
++ memcpy(sk->sk + 2 * LC_DILITHIUM_SEEDBYTES, tr, LC_DILITHIUM_TRBYTES);
++}
++
++static inline void
++pack_sk_s1(struct lc_dilithium_sk *sk, const polyvecl *s1)
++{
++ unsigned int i;
++ uint8_t *seckey =
++ sk->sk + 2 * LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_TRBYTES;
++
++ for (i = 0; i < LC_DILITHIUM_L; ++i)
++ polyeta_pack(seckey + i * LC_DILITHIUM_POLYETA_PACKEDBYTES,
++ &s1->vec[i]);
++}
++
++static inline void
++pack_sk_s2(struct lc_dilithium_sk *sk, const polyveck *s2)
++{
++ unsigned int i;
++ uint8_t *seckey = sk->sk + 2 * LC_DILITHIUM_SEEDBYTES +
++ LC_DILITHIUM_TRBYTES +
++ LC_DILITHIUM_L * LC_DILITHIUM_POLYETA_PACKEDBYTES;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ polyeta_pack(seckey + i * LC_DILITHIUM_POLYETA_PACKEDBYTES,
++ &s2->vec[i]);
++}
++
++static inline void
++pack_sk_t0(struct lc_dilithium_sk *sk, const polyveck *t0)
++{
++ unsigned int i;
++ uint8_t *seckey = sk->sk + 2 * LC_DILITHIUM_SEEDBYTES +
++ LC_DILITHIUM_TRBYTES +
++ LC_DILITHIUM_L * LC_DILITHIUM_POLYETA_PACKEDBYTES +
++ LC_DILITHIUM_K * LC_DILITHIUM_POLYETA_PACKEDBYTES;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ polyt0_pack(seckey + i * LC_DILITHIUM_POLYT0_PACKEDBYTES,
++ &t0->vec[i]);
++}
++
++static inline void
++unpack_sk_rho(uint8_t rho[LC_DILITHIUM_SEEDBYTES],
++ const struct lc_dilithium_sk *sk)
++{
++ memcpy(rho, sk->sk, LC_DILITHIUM_SEEDBYTES);
++}
++
++static inline void
++unpack_sk_key(uint8_t key[LC_DILITHIUM_SEEDBYTES],
++ const struct lc_dilithium_sk *sk)
++{
++ memcpy(key, sk->sk + LC_DILITHIUM_SEEDBYTES, LC_DILITHIUM_SEEDBYTES);
++}
++
++static inline void
++unpack_sk_tr(uint8_t tr[LC_DILITHIUM_TRBYTES],
++ const struct lc_dilithium_sk *sk)
++{
++ memcpy(tr, sk->sk + 2 * LC_DILITHIUM_SEEDBYTES, LC_DILITHIUM_TRBYTES);
++}
++
++static inline void
++unpack_sk_s1(polyvecl *s1, const struct lc_dilithium_sk *sk)
++{
++ unsigned int i;
++ const uint8_t *seckey =
++ sk->sk + 2 * LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_TRBYTES;
++
++ for (i = 0; i < LC_DILITHIUM_L; ++i)
++ polyeta_unpack(&s1->vec[i],
++ seckey + i * LC_DILITHIUM_POLYETA_PACKEDBYTES);
++}
++
++static inline void
++unpack_sk_s2(polyveck *s2, const struct lc_dilithium_sk *sk)
++{
++ unsigned int i;
++ const uint8_t *seckey =
++ sk->sk + 2 * LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_TRBYTES +
++ LC_DILITHIUM_L * LC_DILITHIUM_POLYETA_PACKEDBYTES;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ polyeta_unpack(&s2->vec[i],
++ seckey + i * LC_DILITHIUM_POLYETA_PACKEDBYTES);
++}
++
++static inline void
++unpack_sk_t0(polyveck *t0, const struct lc_dilithium_sk *sk)
++{
++ unsigned int i;
++ const uint8_t *seckey =
++ sk->sk + 2 * LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_TRBYTES +
++ LC_DILITHIUM_L * LC_DILITHIUM_POLYETA_PACKEDBYTES +
++ LC_DILITHIUM_K * LC_DILITHIUM_POLYETA_PACKEDBYTES;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ polyt0_unpack(&t0->vec[i],
++ seckey + i * LC_DILITHIUM_POLYT0_PACKEDBYTES);
++}
++
++/**
++ * @brief pack_sig - Bit-pack signature sig = (c, z, h).
++ *
++ * NOTE: A signature is the concatenation of sig = (c || packed z || packed h).
++ * As c is already present in the first bytes of sig, this function does
++ * not need to copy it yet again to the right location. This implies that
++ * this function does not process c.
++ *
++ * @param [out] sig signature
++ * @param [in] z pointer to vector z
++ * @param [in] h pointer to hint vector h
++ */
++static inline void
++pack_sig(struct lc_dilithium_sig *sig, const polyvecl *z,
++ const polyveck *h)
++{
++ unsigned int i, j, k;
++ /* Skip c */
++ uint8_t *signature = sig->sig + LC_DILITHIUM_CTILDE_BYTES;
++
++ BUILD_BUG_ON((1ULL << (sizeof(j) << 3)) < LC_DILITHIUM_N);
++ BUILD_BUG_ON((1ULL << (sizeof(k) << 3)) < LC_DILITHIUM_N);
++
++ for (i = 0; i < LC_DILITHIUM_L; ++i)
++ polyz_pack(signature + i * LC_DILITHIUM_POLYZ_PACKEDBYTES,
++ &z->vec[i]);
++ signature += LC_DILITHIUM_L * LC_DILITHIUM_POLYZ_PACKEDBYTES;
++
++ /* Encode h */
++ memset(signature, 0, LC_DILITHIUM_OMEGA + LC_DILITHIUM_K);
++
++ k = 0;
++ for (i = 0; i < LC_DILITHIUM_K; ++i) {
++ for (j = 0; j < LC_DILITHIUM_N; ++j)
++ if (h->vec[i].coeffs[j] != 0)
++ signature[k++] = (uint8_t)j;
++
++ signature[LC_DILITHIUM_OMEGA + i] = (uint8_t)k;
++ }
++}
++
++/**
++ * @brief unpack_sig_z - Unpack z part of signature sig = (c, z, h).
++ *
++ * NOTE: The c value is not unpacked as it can be used right from the signature.
++ * To access it, a caller simply needs to use the first
++ * LC_DILITHIUM_CTILDE_BYTES of the signature.
++ *
++ * @param [out] z pointer to output vector z
++ * @param [in] sig signature
++ */
++static inline void
++unpack_sig_z(polyvecl *z, const struct lc_dilithium_sig *sig)
++{
++ unsigned int i;
++ /* Skip c */
++ const uint8_t *signature = sig->sig + LC_DILITHIUM_CTILDE_BYTES;
++
++ for (i = 0; i < LC_DILITHIUM_L; ++i)
++ polyz_unpack(&z->vec[i],
++ signature + i * LC_DILITHIUM_POLYZ_PACKEDBYTES);
++}
++
++/**
++ * @brief unpack_sig - Unpack h value of signature sig = (c, z, h).
++ *
++ * NOTE: The c value is not unpacked as it can be used right from the signature.
++ * To access it, a caller simply needs to use the first
++ * LC_DILITHIUM_CTILDE_BYTES of the signature.
++ *
++ * @param [out] h pointer to output hint vector h
++ * @param [in] sig signature
++ *
++ * @return 1 in case of malformed signature; otherwise 0.
++ */
++static inline int
++unpack_sig_h(polyveck *h, const struct lc_dilithium_sig *sig)
++{
++ unsigned int i, j, k;
++ /* Skip c */
++ const uint8_t *signature =
++ sig->sig + LC_DILITHIUM_CTILDE_BYTES +
++ LC_DILITHIUM_L * LC_DILITHIUM_POLYZ_PACKEDBYTES;
++
++ /* Decode h */
++ k = 0;
++ for (i = 0; i < LC_DILITHIUM_K; ++i) {
++ for (j = 0; j < LC_DILITHIUM_N; ++j)
++ h->vec[i].coeffs[j] = 0;
++
++ if (signature[LC_DILITHIUM_OMEGA + i] < k ||
++ signature[LC_DILITHIUM_OMEGA + i] > LC_DILITHIUM_OMEGA)
++ return 1;
++
++ for (j = k; j < signature[LC_DILITHIUM_OMEGA + i]; ++j) {
++ /* Coefficients are ordered for strong unforgeability */
++ if (j > k && signature[j] <= signature[j - 1])
++ return 1;
++ h->vec[i].coeffs[signature[j]] = 1;
++ }
++
++ k = signature[LC_DILITHIUM_OMEGA + i];
++ }
++
++ /* Extra indices are zero for strong unforgeability */
++ for (j = k; j < LC_DILITHIUM_OMEGA; ++j)
++ if (signature[j])
++ return 1;
++
++ return 0;
++}
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_PACK_H */
+diff --git a/lib/freebl/leancrypto/dilithium_pct.h b/lib/freebl/leancrypto/dilithium_pct.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_pct.h
+@@ -0,0 +1,65 @@
++/*
++ * Copyright (C) 2024 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef DILITHIUM_PCT_H
++#define DILITHIUM_PCT_H
++
++#include "fips_mode.h"
++#include "ret_checkers.h"
++#include "small_stack_support.h"
++#include "visibility.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++static inline int
++_lc_dilithium_pct_fips(const struct lc_dilithium_pk *pk,
++ const struct lc_dilithium_sk *sk)
++{
++ struct workspace {
++ uint8_t m[32];
++ struct lc_dilithium_sig sig;
++ };
++ int ret;
++ LC_DECLARE_MEM(ws, struct workspace, sizeof(uint64_t));
++
++ CKINT(lc_dilithium_sign(&ws->sig, ws->m, sizeof(ws->m), sk,
++ lc_seeded_rng));
++ CKINT(lc_dilithium_verify(&ws->sig, ws->m, sizeof(ws->m), pk));
++
++out:
++ LC_RELEASE_MEM(ws);
++ return ret;
++}
++
++static inline int
++lc_dilithium_pct_fips(const struct lc_dilithium_pk *pk,
++ const struct lc_dilithium_sk *sk)
++{
++ FIPS140_PCT_LOOP(_lc_dilithium_pct_fips(pk, sk))
++
++ return 0;
++}
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_PCT_H */
+diff --git a/lib/freebl/leancrypto/dilithium_poly.h b/lib/freebl/leancrypto/dilithium_poly.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_poly.h
+@@ -0,0 +1,206 @@
++/*
++ * Copyright (C) 2022 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++/*
++ * This code is derived in parts from the code distribution provided with
++ * https://github.com/pq-crystals/dilithium
++ *
++ * That code is released under Public Domain
++ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
++ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
++ */
++
++#ifndef DILITHIUM_POLY_H
++#define DILITHIUM_POLY_H
++
++#include "dilithium_type.h"
++#include "dilithium_reduce.h"
++#include "dilithium_rounding.h"
++#include "ext_headers.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++typedef struct {
++ int32_t coeffs[LC_DILITHIUM_N];
++} poly;
++
++/**
++ * @brief poly_add - Add polynomials. No modular reduction is performed.
++ *
++ * @param [out] c pointer to output polynomial
++ * @param [in] a pointer to first summand
++ * @param [in] b pointer to second summand
++ */
++static inline void
++poly_add(poly *c, const poly *a, const poly *b)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_N; ++i)
++ c->coeffs[i] = a->coeffs[i] + b->coeffs[i];
++}
++
++/**
++ * @brief poly_sub - Subtract polynomials. No modular reduction is
++ * performed.
++ *
++ * @param [out] c pointer to output polynomial
++ * @param [in] a pointer to first input polynomial
++ * @param [in] b pointer to second input polynomial to be subtraced from first
++ * input polynomial
++ */
++static inline void
++poly_sub(poly *c, const poly *a, const poly *b)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_N; ++i)
++ c->coeffs[i] = a->coeffs[i] - b->coeffs[i];
++}
++
++/**
++ * @brief poly_shiftl - Multiply polynomial by 2^D without modular reduction.
++ * Assumes input coefficients to be less than 2^{31-D} in
++ * absolute value.
++ *
++ * @param [in,out] a pointer to input/output polynomial
++ */
++static inline void
++poly_shiftl(poly *a)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_N; ++i)
++ a->coeffs[i] <<= LC_DILITHIUM_D;
++}
++
++/**
++ * @brief poly_decompose - For all coefficients c of the input polynomial,
++ * compute high and low bits c0, c1 such
++ * c mod Q = c1*ALPHA + c0 with
++ * -ALPHA/2 < c0 <= ALPHA/2 except c1 = (Q-1)/ALPHA
++ * where we set c1 = 0 and
++ * -ALPHA/2 <= c0 = c mod Q - Q < 0.
++ * Assumes coefficients to be standard representatives.
++ *
++ * @param [out] a1 pointer to output polynomial with coefficients c1
++ * @param [out] a0 pointer to output polynomial with coefficients c0
++ * @param [in] a pointer to input polynomial
++ */
++static inline void
++poly_decompose(poly *a1, poly *a0, const poly *a)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_N; ++i)
++ a1->coeffs[i] = decompose(&a0->coeffs[i], a->coeffs[i]);
++}
++
++/**
++ * @brief poly_make_hint - Compute hint polynomial. The coefficients of which
++ * indicate whether the low bits of the corresponding
++ * coefficient of the input polynomial overflow into the
++ * high bits.
++ *
++ * @param [out] h pointer to output hint polynomial
++ * @param [in] a0 pointer to low part of input polynomial
++ * @param [in] a1 pointer to high part of input polynomial
++ *
++ * @return number of 1 bits.
++ */
++static inline unsigned int
++poly_make_hint(poly *h, const poly *a0,
++ const poly *a1)
++{
++ unsigned int i, s = 0;
++
++ for (i = 0; i < LC_DILITHIUM_N; ++i) {
++ h->coeffs[i] = make_hint(a0->coeffs[i], a1->coeffs[i]);
++ s += (unsigned int)h->coeffs[i];
++ }
++
++ return s;
++}
++
++/**
++ * @brief poly_use_hint - Use hint polynomial to correct the high bits of a
++ * polynomial.
++ *
++ * @param [out] b pointer to output polynomial with corrected high bits
++ * @param [in] a pointer to input polynomial
++ * @param [in] h pointer to input hint polynomial
++ */
++static inline void
++poly_use_hint(poly *b, const poly *a, const poly *h)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_N; ++i)
++ b->coeffs[i] = use_hint(a->coeffs[i], h->coeffs[i]);
++}
++
++int poly_chknorm(const poly *a, int32_t B);
++
++#define POLY_UNIFORM_NBLOCKS \
++ ((768 + LC_SHAKE_128_SIZE_BLOCK - 1) / LC_SHAKE_128_SIZE_BLOCK)
++void poly_uniform(poly *a, const uint8_t seed[LC_DILITHIUM_SEEDBYTES],
++ uint16_t nonce, void *ws_buf);
++
++#if LC_DILITHIUM_ETA == 2
++#define POLY_UNIFORM_ETA_NBLOCKS \
++ ((136 + LC_SHAKE_256_SIZE_BLOCK - 1) / LC_SHAKE_256_SIZE_BLOCK)
++#elif LC_DILITHIUM_ETA == 4
++#define POLY_UNIFORM_ETA_NBLOCKS \
++ ((227 + LC_SHAKE_256_SIZE_BLOCK - 1) / LC_SHAKE_256_SIZE_BLOCK)
++#else
++#error "Undefined LC_DILITHIUM_ETA"
++#endif
++#define POLY_UNIFORM_ETA_BYTES POLY_UNIFORM_ETA_NBLOCKS *LC_SHAKE_256_SIZE_BLOCK
++void poly_uniform_eta(poly *a, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
++ uint16_t nonce, void *ws_buf);
++
++#define POLY_UNIFORM_GAMMA1_NBLOCKS \
++ ((LC_DILITHIUM_POLYZ_PACKEDBYTES + LC_SHAKE_256_SIZE_BLOCK - 1) / \
++ LC_SHAKE_256_SIZE_BLOCK)
++#define POLY_UNIFORM_GAMMA1_BYTES \
++ POLY_UNIFORM_GAMMA1_NBLOCKS *LC_SHAKE_256_SIZE_BLOCK
++
++#define POLY_CHALLENGE_BYTES LC_SHAKE_256_SIZE_BLOCK
++void poly_challenge(poly *c, const uint8_t seed[LC_DILITHIUM_CTILDE_BYTES],
++ void *ws_buf);
++
++void polyeta_pack(uint8_t *r, const poly *a);
++void polyeta_unpack(poly *r, const uint8_t *a);
++
++void polyt1_pack(uint8_t *r, const poly *a);
++
++void polyt0_pack(uint8_t *r, const poly *a);
++void polyt0_unpack(poly *r, const uint8_t *a);
++
++void polyz_pack(uint8_t *r, const poly *a);
++void polyz_unpack(poly *r, const uint8_t *a);
++
++void polyw1_pack(uint8_t *r, const poly *a);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_POLY_H */
+diff --git a/lib/freebl/leancrypto/dilithium_poly_c.h b/lib/freebl/leancrypto/dilithium_poly_c.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_poly_c.h
+@@ -0,0 +1,157 @@
++/*
++ * Copyright (C) 2023 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef DILITHIUM_POLY_C_H
++#define DILITHIUM_POLY_C_H
++
++#include "dilithium_ntt.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * @brief poly_reduce - Inplace reduction of all coefficients of polynomial to
++ * representative in [-6283009,6283007].
++ *
++ * @param [in,out] a pointer to input/output polynomial
++ */
++static inline void
++poly_reduce(poly *a)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_N; ++i)
++ a->coeffs[i] = reduce32(a->coeffs[i]);
++}
++
++/**
++ * @brief poly_caddq - For all coefficients of in/out polynomial add Q if
++ * coefficient is negative.
++ *
++ * @param [in,out] a pointer to input/output polynomial
++ */
++static inline void
++poly_caddq(poly *a)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_N; ++i)
++ a->coeffs[i] = caddq(a->coeffs[i]);
++}
++
++/**
++ * @brief poly_pointwise_montgomery - Pointwise multiplication of polynomials in
++ * NTT domain representation and
++ * multiplication of resulting polynomial
++ * by 2^{-32}.
++ *
++ * @param [out] c pointer to output polynomial
++ * @param [in] a pointer to first input polynomial
++ * @param [in] b pointer to second input polynomial
++ */
++static inline void
++poly_pointwise_montgomery(poly *c, const poly *a,
++ const poly *b)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_N; ++i)
++ c->coeffs[i] =
++ montgomery_reduce((int64_t)a->coeffs[i] * b->coeffs[i]);
++}
++
++/**
++ * @brief poly_power2round - For all coefficients c of the input polynomial,
++ * compute c0, c1 such that c mod Q = c1*2^D + c0
++ * with -2^{D-1} < c0 <= 2^{D-1}. Assumes coefficients
++ * to be standard representatives.
++ *
++ * @param [out] a1 pointer to output polynomial with coefficients c1
++ * @param [out] a0 pointer to output polynomial with coefficients c0
++ * @param [in] a pointer to input polynomial
++ */
++static inline void
++poly_power2round(poly *a1, poly *a0, const poly *a)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_N; ++i)
++ a1->coeffs[i] = power2round(&a0->coeffs[i], a->coeffs[i]);
++}
++
++/**
++ * @brief polyt1_unpack - Unpack polynomial t1 with 10-bit coefficients.
++ * Output coefficients are standard representatives.
++ *
++ * @param [out] r pointer to output polynomial
++ * @param [in] a byte array with bit-packed polynomial
++ */
++static inline void
++polyt1_unpack(poly *r, const uint8_t *a)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_N / 4; ++i) {
++ r->coeffs[4 * i + 0] =
++ ((a[5 * i + 0] >> 0) | ((uint32_t)a[5 * i + 1] << 8)) &
++ 0x3FF;
++ r->coeffs[4 * i + 1] =
++ ((a[5 * i + 1] >> 2) | ((uint32_t)a[5 * i + 2] << 6)) &
++ 0x3FF;
++ r->coeffs[4 * i + 2] =
++ ((a[5 * i + 2] >> 4) | ((uint32_t)a[5 * i + 3] << 4)) &
++ 0x3FF;
++ r->coeffs[4 * i + 3] =
++ ((a[5 * i + 3] >> 6) | ((uint32_t)a[5 * i + 4] << 2)) &
++ 0x3FF;
++ }
++}
++
++/**
++ * @brief poly_ntt - Inplace forward NTT. Coefficients can grow by
++ * 8*Q in absolute value.
++ *
++ * @param [in,out] a pointer to input/output polynomial
++ */
++static inline void
++poly_ntt(poly *a)
++{
++ ntt(a->coeffs);
++}
++
++/**
++ * @brief poly_invntt_tomont - Inplace inverse NTT and multiplication by 2^{32}.
++ * Input coefficients need to be less than Q in
++ * absolute value and output coefficients are again
++ * bounded by Q.
++ *
++ * @param [in,out] a pointer to input/output polynomial
++ */
++static inline void
++poly_invntt_tomont(poly *a)
++{
++ invntt_tomont(a->coeffs);
++}
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_POLY_C_H */
+diff --git a/lib/freebl/leancrypto/dilithium_poly_common.h b/lib/freebl/leancrypto/dilithium_poly_common.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_poly_common.h
+@@ -0,0 +1,44 @@
++/*
++ * Copyright (C) 2022 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++/*
++ * This code is derived in parts from the code distribution provided with
++ * https://github.com/pq-crystals/dilithium
++ *
++ * That code is released under Public Domain
++ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
++ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
++ */
++
++#ifndef DILITHIUM_POLY_COMMON_H
++#define DILITHIUM_POLY_COMMON_H
++
++#include "dilithium_type.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++void poly_uniform_gamma1(poly *a, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
++ uint16_t nonce, void *ws_buf);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_POLY_COMMON_H */
+diff --git a/lib/freebl/leancrypto/dilithium_polyvec.h b/lib/freebl/leancrypto/dilithium_polyvec.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_polyvec.h
+@@ -0,0 +1,392 @@
++/*
++ * Copyright (C) 2022 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++/*
++ * This code is derived in parts from the code distribution provided with
++ * https://github.com/pq-crystals/dilithium
++ *
++ * That code is released under Public Domain
++ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
++ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
++ */
++
++#ifndef DILITHIUM_POLYVEC_H
++#define DILITHIUM_POLYVEC_H
++
++#include "conv_be_le.h"
++#include "dilithium_type.h"
++#include "dilithium_poly.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++typedef struct {
++ poly vec[LC_DILITHIUM_L];
++} polyvecl;
++
++/* Vectors of polynomials of length K */
++typedef struct {
++ poly vec[LC_DILITHIUM_K];
++} polyveck;
++
++/**************************************************************/
++/************ Vectors of polynomials of length L **************/
++/**************************************************************/
++
++static inline void
++polyvecl_reduce(polyvecl *v)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_L; ++i)
++ poly_reduce(&v->vec[i]);
++}
++
++/**
++ * @brief polyvecl_add - Add vectors of polynomials of length L.
++ * No modular reduction is performed.
++ *
++ * @param [out] w pointer to output vector
++ * @param [in] u pointer to first summand
++ * @param [in] v pointer to second summand
++ */
++static inline void
++polyvecl_add(polyvecl *w, const polyvecl *u,
++ const polyvecl *v)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_L; ++i)
++ poly_add(&w->vec[i], &u->vec[i], &v->vec[i]);
++}
++
++/**
++ * @brief polyvecl_ntt - Forward NTT of all polynomials in vector of length L.
++ * Output coefficients can be up to 16*Q larger than input
++ * coefficients.
++ *
++ * @param [in,out] v pointer to input/output vector
++ */
++static inline void
++polyvecl_ntt(polyvecl *v)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_L; ++i)
++ poly_ntt(&v->vec[i]);
++}
++
++static inline void
++polyvecl_invntt_tomont(polyvecl *v)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_L; ++i)
++ poly_invntt_tomont(&v->vec[i]);
++}
++
++static inline void
++polyvecl_pointwise_poly_montgomery(polyvecl *r,
++ const poly *a,
++ const polyvecl *v)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_L; ++i)
++ poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]);
++}
++
++/**
++ * @brief polyvecl_chknorm - Check infinity norm of polynomials in vector of
++ * length L. Assumes input polyvecl to be reduced by
++ * polyvecl_reduce().
++ *
++ * @param [in] v pointer to vector
++ * @param [in] bound norm bound
++ *
++ * @return 0 if norm of all polynomials is strictly smaller than B <= (Q-1)/8
++ * and 1 otherwise.
++ */
++static inline int
++polyvecl_chknorm(const polyvecl *v, int32_t bound)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_L; ++i)
++ if (poly_chknorm(&v->vec[i], bound))
++ return 1;
++
++ return 0;
++}
++
++/**************************************************************/
++/************ Vectors of polynomials of length K **************/
++/**************************************************************/
++
++/**
++ * @brief polyveck_reduce - Reduce coefficients of polynomials in vector of
++ * length LC_DILITHIUM_K to representatives in
++ * [-6283009,6283007].
++ *
++ * @param [in,out] v pointer to input/output vector
++ */
++static inline void
++polyveck_reduce(polyveck *v)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ poly_reduce(&v->vec[i]);
++}
++
++/**
++ * @brief polyveck_caddq - For all coefficients of polynomials in vector of
++ * length LC_DILITHIUM_K add LC_DILITHIUM_Q if
++ * coefficient is negative.
++ *
++ * @param [in,out] v pointer to input/output vector
++ */
++static inline void
++polyveck_caddq(polyveck *v)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ poly_caddq(&v->vec[i]);
++}
++
++/**
++ * @brief polyveck_add - Add vectors of polynomials of length LC_DILITHIUM_K.
++ * No modular reduction is performed.
++ *
++ * @param [out] w pointer to output vector
++ * @param [in] u pointer to first summand
++ * @param [in] v pointer to second summand
++ */
++static inline void
++polyveck_add(polyveck *w, const polyveck *u,
++ const polyveck *v)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ poly_add(&w->vec[i], &u->vec[i], &v->vec[i]);
++}
++
++/**
++ * @brief olyveck_sub - Subtract vectors of polynomials of length
++ * LC_DILITHIUM_K. No modular reduction is performed.
++ *
++ * @param [out] w pointer to output vector
++ * @param [in] u pointer to first input vector
++ * @param [in] v pointer to second input vector to be subtracted from first
++ * input vector
++ */
++static inline void
++polyveck_sub(polyveck *w, const polyveck *u,
++ const polyveck *v)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ poly_sub(&w->vec[i], &u->vec[i], &v->vec[i]);
++}
++
++/**
++ * @brief polyveck_shiftl - Multiply vector of polynomials of Length K by
++ * 2^D without modular reduction. Assumes input
++ * coefficients to be less than 2^{31-D}.
++ *
++ * @param [in,out] v pointer to input/output vector
++ */
++static inline void
++polyveck_shiftl(polyveck *v)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ poly_shiftl(&v->vec[i]);
++}
++
++/**
++ * @brief polyveck_ntt - Forward NTT of all polynomials in vector of length K.
++ * Output coefficients can be up to 16*Q larger than input
++ * coefficients.
++ *
++ * @param [in,out] v pointer to input/output vector
++ */
++static inline void
++polyveck_ntt(polyveck *v)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ poly_ntt(&v->vec[i]);
++}
++
++/**
++ * @brief polyveck_invntt_tomont - Inverse NTT and multiplication by 2^{32} of
++ * polynomials in vector of length K. Input
++ * coefficients need to be less than 2*Q.
++ *
++ * @param [in,out] v pointer to input/output vector
++ */
++static inline void
++polyveck_invntt_tomont(polyveck *v)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ poly_invntt_tomont(&v->vec[i]);
++}
++
++static inline void
++polyveck_pointwise_poly_montgomery(polyveck *r,
++ const poly *a,
++ const polyveck *v)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ poly_pointwise_montgomery(&r->vec[i], a, &v->vec[i]);
++}
++
++/**
++ * @brief polyveck_chknorm - Check infinity norm of polynomials in vector of
++ * length K. Assumes input polyveck to be reduced by
++ * polyveck_reduce().
++ *
++ * @param [in] v pointer to vector
++ * @param [in] bound norm bound
++ *
++ * @return 0 if norm of all polynomials are strictly smaller than B <= (Q-1)/8
++ * and 1 otherwise.
++ */
++static inline int
++polyveck_chknorm(const polyveck *v, int32_t bound)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ if (poly_chknorm(&v->vec[i], bound))
++ return 1;
++
++ return 0;
++}
++
++/**
++ * @brief polyveck_power2round - For all coefficients a of polynomials in vector
++ * of length K, compute a0, a1 such that
++ * a mod^+ Q = a1*2^D + a0 with
++ * -2^{D-1} < a0 <= 2^{D-1}. Assumes coefficients
++ * to be standard representatives.
++ *
++ * @param [out] v1 pointer to output vector of polynomials with coefficients a1
++ * @param [in] v0 pointer to output vector of polynomials with coefficients a0
++ * @param [in] v pointer to input vector
++ */
++static inline void
++polyveck_power2round(polyveck *v1, polyveck *v0,
++ const polyveck *v)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ poly_power2round(&v1->vec[i], &v0->vec[i], &v->vec[i]);
++}
++
++/**
++ * @brief polyveck_decompose - For all coefficients a of polynomials in vector
++ * of length K, compute high and low bits a0, a1
++ * such a mod^+ Q = a1*ALPHA + a0 with
++ * -ALPHA/2 < a0 <= ALPHA/2 except a1 = (Q-1)/ALPHA
++ * where we set a1 = 0 and
++ * -ALPHA/2 <= a0 = a mod Q - Q < 0. Assumes
++ * coefficients to be standard representatives.
++ *
++ * @param [out] v1 pointer to output vector of polynomials with coefficients a1
++ * @param [in] v0 pointer to output vector of polynomials with coefficients a0
++ * @param [in] v pointer to input vector
++ */
++static inline void
++polyveck_decompose(polyveck *v1, polyveck *v0,
++ const polyveck *v)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ poly_decompose(&v1->vec[i], &v0->vec[i], &v->vec[i]);
++}
++
++/**
++ * @brief polyveck_make_hint - Compute hint vector.
++ *
++ * @param [out] h pointer to output vector
++ * @param [in] v0 pointer to low part of input vector
++ * @param [in] v1 pointer to high part of input vector
++ *
++ * @return number of 1 bits.
++ */
++static inline unsigned int
++polyveck_make_hint(polyveck *h, const polyveck *v0,
++ const polyveck *v1)
++{
++ unsigned int i, s = 0;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ s += poly_make_hint(&h->vec[i], &v0->vec[i], &v1->vec[i]);
++
++ return s;
++}
++
++/**
++ * @brief polyveck_use_hint - Use hint vector to correct the high bits of input
++ * vector.
++ *
++ * @param [out] w pointer to output vector of polynomials with corrected high
++ * bits
++ * @param [in] u pointer to input vector
++ * @param [in] h pointer to input hint vector
++ */
++static inline void
++polyveck_use_hint(polyveck *w, const polyveck *u,
++ const polyveck *h)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ poly_use_hint(&w->vec[i], &u->vec[i], &h->vec[i]);
++}
++
++static inline void
++polyveck_pack_w1(uint8_t r[LC_DILITHIUM_K * LC_DILITHIUM_POLYW1_PACKEDBYTES],
++ const polyveck *w1)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ polyw1_pack(&r[i * LC_DILITHIUM_POLYW1_PACKEDBYTES],
++ &w1->vec[i]);
++}
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_POLYVEC_H */
+diff --git a/lib/freebl/leancrypto/dilithium_polyvec_c.h b/lib/freebl/leancrypto/dilithium_polyvec_c.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_polyvec_c.h
+@@ -0,0 +1,124 @@
++/*
++ * Copyright (C) 2023 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef DILITHIUM_POLYVEC_C_H
++#define DILITHIUM_POLYVEC_C_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++static inline void
++polyvecl_uniform_eta(polyvecl *v, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
++ uint16_t nonce, void *ws_buf)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_L; ++i)
++ poly_uniform_eta(&v->vec[i], seed, le_bswap16(nonce++), ws_buf);
++}
++
++static inline void
++polyvecl_uniform_gamma1(polyvecl *v, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
++ uint16_t nonce, void *ws_buf)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_L; ++i)
++ poly_uniform_gamma1(
++ &v->vec[i], seed,
++ le_bswap16((uint16_t)(LC_DILITHIUM_L * nonce + i)),
++ ws_buf);
++}
++
++static inline void
++polyveck_uniform_eta(polyveck *v, const uint8_t seed[LC_DILITHIUM_CRHBYTES],
++ uint16_t nonce, void *ws_buf)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ poly_uniform_eta(&v->vec[i], seed, le_bswap16(nonce++), ws_buf);
++}
++
++/**
++ * @brief expand_mat - Implementation of ExpandA. Generates matrix A with
++ * uniformly random coefficients a_{i,j} by performing
++ * rejection sampling on the output stream of
++ * SHAKE128(rho|j|i).
++ *
++ * @param [out] mat output matrix
++ * @param [in] rho byte array containing seed rho
++ */
++static inline void
++polyvec_matrix_expand(polyvecl mat[LC_DILITHIUM_K],
++ const uint8_t rho[LC_DILITHIUM_SEEDBYTES], void *ws_buf)
++{
++ unsigned int i, j;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ for (j = 0; j < LC_DILITHIUM_L; ++j)
++ poly_uniform(
++ &mat[i].vec[j], rho,
++ le_bswap16((uint16_t)(i << 8) + (uint16_t)j),
++ ws_buf);
++}
++
++/**
++ * @brief polyvecl_pointwise_acc_montgomery -
++ * Pointwise multiply vectors of polynomials of length L, multiply
++ * resulting vector by 2^{-32} and add (accumulate) polynomials
++ * in it. Input/output vectors are in NTT domain representation.
++ *
++ * @param [out] w output polynomial
++ * @param [in] u pointer to first input vector
++ * @param [in] v pointer to second input vector
++ */
++static inline void
++polyvecl_pointwise_acc_montgomery(poly *w, const polyvecl *u,
++ const polyvecl *v,
++ void *ws_buf)
++{
++ unsigned int i;
++ poly *t = ws_buf;
++
++ poly_pointwise_montgomery(w, &u->vec[0], &v->vec[0]);
++ for (i = 1; i < LC_DILITHIUM_L; ++i) {
++ poly_pointwise_montgomery(t, &u->vec[i], &v->vec[i]);
++ poly_add(w, w, t);
++ }
++}
++
++static inline void
++polyvec_matrix_pointwise_montgomery(polyveck *t,
++ const polyvecl mat[LC_DILITHIUM_K],
++ const polyvecl *v, void *ws_buf)
++{
++ unsigned int i;
++
++ for (i = 0; i < LC_DILITHIUM_K; ++i)
++ polyvecl_pointwise_acc_montgomery(&t->vec[i], &mat[i], v,
++ ws_buf);
++}
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_POLYVEC_C_H */
+diff --git a/lib/freebl/leancrypto/dilithium_reduce.h b/lib/freebl/leancrypto/dilithium_reduce.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_reduce.h
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2022 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++/*
++ * This code is derived in parts from the code distribution provided with
++ * https://github.com/pq-crystals/dilithium
++ *
++ * That code is released under Public Domain
++ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
++ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
++ */
++
++#ifndef DILITHIUM_REDUCE_H
++#define DILITHIUM_REDUCE_H
++
++#include "dilithium_type.h"
++#include "ext_headers.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#define MONT -4186625 // 2^32 % Q
++#define QINV 58728449 // q^(-1) mod 2^32
++
++/**
++ * @brief montgomery_reduce - For finite field element a with
++ * -2^{31}Q <= a <= Q*2^31,
++ * compute r \equiv a*2^{-32} (mod Q) such that
++ * -Q < r < Q.
++ *
++ * @param [in] a finite field element
++ *
++ * @return r
++ */
++static inline int32_t
++montgomery_reduce(int64_t a)
++{
++ int32_t t;
++
++ t = (int32_t)(a * QINV);
++ t = (int32_t)((a - (int64_t)t * LC_DILITHIUM_Q) >> 32);
++ return t;
++}
++
++/**
++ * @brief reduce32 - For finite field element a with a <= 2^{31} - 2^{22} - 1,
++ * compute r \equiv a (mod Q) such that
++ * -6283009 <= r <= 6283007.
++ *
++ * @param [in] a finite field element
++ *
++ * @return r
++ */
++static inline int32_t
++reduce32(int32_t a)
++{
++ int32_t t;
++
++ t = (a + (1 << 22)) >> 23;
++ t = a - t * LC_DILITHIUM_Q;
++ return t;
++}
++
++/**
++ * @brief caddq - Add Q if input coefficient is negative.
++ *
++ * @param [in] a finite field element
++ *
++ * @return r
++ */
++static inline int32_t
++caddq(int32_t a)
++{
++ a += (a >> 31) & LC_DILITHIUM_Q;
++ return a;
++}
++
++/**
++ * @brief freeze - For finite field element a, compute standard representative
++ * r = a mod^+ Q.
++ *
++ * @param [in] a finite field element a
++ *
++ * @return r
++ */
++static inline int32_t
++freeze(int32_t a)
++{
++ a = reduce32(a);
++ a = caddq(a);
++ return a;
++}
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_REDUCE_H */
+diff --git a/lib/freebl/leancrypto/dilithium_rounding.h b/lib/freebl/leancrypto/dilithium_rounding.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_rounding.h
+@@ -0,0 +1,47 @@
++/*
++ * Copyright (C) 2022 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++/*
++ * This code is derived in parts from the code distribution provided with
++ * https://github.com/pq-crystals/dilithium
++ *
++ * That code is released under Public Domain
++ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
++ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
++ */
++
++#ifndef DILITHIUM_ROUNDING_H
++#define DILITHIUM_ROUNDING_H
++
++#include "dilithium_type.h"
++#include "ext_headers.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++int32_t power2round(int32_t *a0, int32_t a);
++int32_t decompose(int32_t *a0, int32_t a);
++int32_t make_hint(int32_t a0, int32_t a1);
++int32_t use_hint(int32_t a, int32_t hint);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_ROUNDING_H */
+diff --git a/lib/freebl/leancrypto/dilithium_service_helpers.h b/lib/freebl/leancrypto/dilithium_service_helpers.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_service_helpers.h
+@@ -0,0 +1,110 @@
++/*
++ * Copyright (C) 2022 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef DILITHIUM_SERVICE_HELPERS_H
++#define DILITHIUM_SERVICE_HELPERS_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * @brief rej_uniform - Sample uniformly random coefficients in [0, Q-1] by
++ * performing rejection sampling on array of random bytes.
++ *
++ * @param [out] a pointer to output array (allocated)
++ * @param [in] len number of coefficients to be sampled
++ * @param [in] buf array of random bytes
++ * @param [in] buflen length of array of random bytes
++ *
++ * @return number of sampled coefficients. Can be smaller than len if not enough
++ * random bytes were given.
++ */
++static inline unsigned int
++rej_uniform(int32_t *a, unsigned int len,
++ const uint8_t *buf, unsigned int buflen)
++{
++ unsigned int ctr, pos;
++ uint32_t t;
++
++ ctr = pos = 0;
++ while (ctr < len && pos + 3 <= buflen) {
++ t = buf[pos++];
++ t |= (uint32_t)buf[pos++] << 8;
++ t |= (uint32_t)buf[pos++] << 16;
++ t &= 0x7FFFFF;
++
++ if (t < LC_DILITHIUM_Q)
++ a[ctr++] = (int32_t)t;
++ }
++
++ return ctr;
++}
++
++/**
++ * @brief rej_eta - Sample uniformly random coefficients in [-ETA, ETA] by
++ * performing rejection sampling on array of random bytes.
++ *
++ * @param [out] a pointer to output array (allocated)
++ * @param [in] len number of coefficients to be sampled
++ * @param [in] buf array of random bytes
++ * @param [in] buflen length of array of random bytes
++ *
++ * @return number of sampled coefficients. Can be smaller than len if not enough
++ * random bytes were given.
++ */
++static inline unsigned int
++rej_eta(int32_t *a, unsigned int len,
++ const uint8_t *buf, unsigned int buflen)
++{
++ unsigned int ctr, pos;
++ int32_t t0, t1;
++
++ ctr = pos = 0;
++ while (ctr < len && pos < buflen) {
++ t0 = buf[pos] & 0x0F;
++ t1 = buf[pos++] >> 4;
++
++#if LC_DILITHIUM_ETA == 2
++ if (t0 < 15) {
++ t0 = t0 - (205 * t0 >> 10) * 5;
++ a[ctr++] = 2 - t0;
++ }
++ if (t1 < 15 && ctr < len) {
++ t1 = t1 - (205 * t1 >> 10) * 5;
++ a[ctr++] = 2 - t1;
++ }
++#elif LC_DILITHIUM_ETA == 4
++ if (t0 < 9)
++ a[ctr++] = 4 - t0;
++ if (t1 < 9 && ctr < len)
++ a[ctr++] = 4 - t1;
++#else
++#error "Undefined LC_DILITHIUM_ETA"
++#endif
++ }
++
++ return ctr;
++}
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_SERVICE_HELPERS_H */
+diff --git a/lib/freebl/leancrypto/dilithium_signature_c.h b/lib/freebl/leancrypto/dilithium_signature_c.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_signature_c.h
+@@ -0,0 +1,70 @@
++/*
++ * Copyright (C) 2022 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef DILITHIUM_SIGNATURE_C_H
++#define DILITHIUM_SIGNATURE_C_H
++
++#include "dilithium_type.h"
++#include "lc_rng.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++int lc_dilithium_keypair_c(struct lc_dilithium_pk *pk,
++ struct lc_dilithium_sk *sk,
++ struct lc_rng_ctx *rng_ctx);
++int lc_dilithium_keypair_from_seed_c(struct lc_dilithium_pk *pk,
++ struct lc_dilithium_sk *sk,
++ const uint8_t *seed, size_t seedlen);
++
++int lc_dilithium_sign_c(struct lc_dilithium_sig *sig, const uint8_t *m,
++ size_t mlen, const struct lc_dilithium_sk *sk,
++ struct lc_rng_ctx *rng_ctx);
++int lc_dilithium_sign_ctx_c(struct lc_dilithium_sig *sig,
++ struct lc_dilithium_ctx *ctx, const uint8_t *m,
++ size_t mlen, const struct lc_dilithium_sk *sk,
++ struct lc_rng_ctx *rng_ctx);
++int lc_dilithium_sign_init_c(struct lc_dilithium_ctx *ctx,
++ const struct lc_dilithium_sk *sk);
++int lc_dilithium_sign_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
++ size_t mlen);
++int lc_dilithium_sign_final_c(struct lc_dilithium_sig *sig,
++ struct lc_dilithium_ctx *ctx,
++ const struct lc_dilithium_sk *sk,
++ struct lc_rng_ctx *rng_ctx);
++
++int lc_dilithium_verify_c(const struct lc_dilithium_sig *sig, const uint8_t *m,
++ size_t mlen, const struct lc_dilithium_pk *pk);
++int lc_dilithium_verify_ctx_c(const struct lc_dilithium_sig *sig,
++ struct lc_dilithium_ctx *ctx, const uint8_t *m,
++ size_t mlen, const struct lc_dilithium_pk *pk);
++int lc_dilithium_verify_init_c(struct lc_dilithium_ctx *ctx,
++ const struct lc_dilithium_pk *pk);
++int lc_dilithium_verify_update_c(struct lc_dilithium_ctx *ctx, const uint8_t *m,
++ size_t mlen);
++int lc_dilithium_verify_final_c(const struct lc_dilithium_sig *sig,
++ struct lc_dilithium_ctx *ctx,
++ const struct lc_dilithium_pk *pk);
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_SIGNATURE_C_H */
+diff --git a/lib/freebl/leancrypto/dilithium_signature_impl.h b/lib/freebl/leancrypto/dilithium_signature_impl.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_signature_impl.h
+@@ -0,0 +1,1039 @@
++/*
++ * Copyright (C) 2022 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++/*
++ * This code is derived in parts from the code distribution provided with
++ * https://github.com/pq-crystals/dilithium
++ *
++ * That code is released under Public Domain
++ * (https://creativecommons.org/share-your-work/public-domain/cc0/);
++ * or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html).
++ */
++
++#ifndef DILITHIUM_SIGNATURE_IMPL_H
++#define DILITHIUM_SIGNATURE_IMPL_H
++
++#include "alignment.h"
++#include "build_bug_on.h"
++#include "dilithium_type.h"
++#include "dilithium_debug.h"
++#include "dilithium_pack.h"
++#include "lc_hash.h"
++#include "lc_memcmp_secure.h"
++#include "lc_sha3.h"
++#include "ret_checkers.h"
++#include "signature_domain_separation.h"
++#include "small_stack_support.h"
++#include "static_rng.h"
++#include "timecop.h"
++#include "visibility.h"
++#include "binhexbin.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/*
++ * Enable this macro to report the rejection code paths taken with the
++ * signature generation operation. When disabled, the compiler should
++ * eliminate this code which means that the counting code is folded away.
++ */
++#undef REJECTION_TEST_SAMPLING
++
++#define _WS_POLY_UNIFORM_BUF_SIZE \
++ (POLY_UNIFORM_NBLOCKS * LC_SHAKE_128_SIZE_BLOCK + 2)
++
++#ifndef LC_POLY_UNIFOR_BUF_SIZE_MULTIPLIER
++#error "LC_POLY_UNIFOR_BUF_SIZE_MULTIPLIER is not defined"
++#endif
++
++#define WS_POLY_UNIFORM_BUF_SIZE \
++ (_WS_POLY_UNIFORM_BUF_SIZE * LC_POLY_UNIFOR_BUF_SIZE_MULTIPLIER)
++
++static int lc_dilithium_keypair_from_seed_impl(struct lc_dilithium_pk *pk,
++ struct lc_dilithium_sk *sk,
++ const uint8_t *seed,
++ size_t seedlen);
++
++static int
++lc_dilithium_keypair_impl(struct lc_dilithium_pk *pk,
++ struct lc_dilithium_sk *sk,
++ struct lc_rng_ctx *rng_ctx)
++{
++ struct workspace {
++ union {
++ polyvecl s1, s1hat;
++ } s1;
++ union {
++ polyvecl mat[LC_DILITHIUM_K];
++ polyveck t0;
++ } matrix;
++ polyveck s2, t1;
++ uint8_t seedbuf[2 * LC_DILITHIUM_SEEDBYTES +
++ LC_DILITHIUM_CRHBYTES];
++ union {
++ poly polyvecl_pointwise_acc_montgomery_buf;
++ uint8_t poly_uniform_buf[WS_POLY_UNIFORM_BUF_SIZE];
++ uint8_t poly_uniform_eta_buf[POLY_UNIFORM_ETA_BYTES];
++ uint8_t tr[LC_DILITHIUM_TRBYTES];
++ } tmp;
++ };
++ static const uint8_t dimension[2] = { LC_DILITHIUM_K, LC_DILITHIUM_L };
++ const uint8_t *rho, *rhoprime, *key;
++ int ret;
++ LC_HASH_CTX_ON_STACK(shake256_ctx, lc_shake256);
++ LC_DECLARE_MEM(ws, struct workspace, sizeof(uint64_t));
++
++ CKNULL(pk, -EINVAL);
++ CKNULL(sk, -EINVAL);
++
++ lc_rng_check(&rng_ctx);
++
++ /* Get randomness for rho, rhoprime and key */
++ CKINT(lc_rng_generate(rng_ctx, NULL, 0, ws->seedbuf,
++ LC_DILITHIUM_SEEDBYTES));
++ dilithium_print_buffer(ws->seedbuf, LC_DILITHIUM_SEEDBYTES,
++ "Keygen - Seed");
++
++ lc_hash_init(shake256_ctx);
++ lc_hash_update(shake256_ctx, ws->seedbuf, LC_DILITHIUM_SEEDBYTES);
++ lc_hash_update(shake256_ctx, dimension, sizeof(dimension));
++ lc_hash_set_digestsize(shake256_ctx, sizeof(ws->seedbuf));
++ lc_hash_final(shake256_ctx, ws->seedbuf);
++ lc_hash_zero(shake256_ctx);
++
++ rho = ws->seedbuf;
++ dilithium_print_buffer(ws->seedbuf, LC_DILITHIUM_SEEDBYTES,
++ "Keygen - RHO");
++ pack_pk_rho(pk, rho);
++ pack_sk_rho(sk, rho);
++
++ /*
++ * Timecop: RHO' is a random number which is enlarged to sample the
++ * vectors S1 and S2 from. The sampling operation is not considered
++ * relevant for the side channel operation as (a) an attacker does not
++ * have access to the random number and (b) only the result after the
++ * sampling operation of S1 and S2 is released.
++ */
++ rhoprime = rho + LC_DILITHIUM_SEEDBYTES;
++ dilithium_print_buffer(rhoprime, LC_DILITHIUM_CRHBYTES,
++ "Keygen - RHOPrime");
++
++ key = rhoprime + LC_DILITHIUM_CRHBYTES;
++ dilithium_print_buffer(key, LC_DILITHIUM_SEEDBYTES, "Keygen - Key");
++
++ /* Timecop: key goes into the secret key */
++ poison(key, LC_DILITHIUM_SEEDBYTES);
++
++ pack_sk_key(sk, key);
++
++ /* Sample short vectors s1 and s2 */
++
++ polyvecl_uniform_eta(&ws->s1.s1, rhoprime, 0,
++ ws->tmp.poly_uniform_eta_buf);
++ polyveck_uniform_eta(&ws->s2, rhoprime, LC_DILITHIUM_L,
++ ws->tmp.poly_uniform_eta_buf);
++
++ /* Timecop: s1 and s2 are secret */
++ poison(&ws->s1.s1, sizeof(polyvecl));
++ poison(&ws->s2, sizeof(polyveck));
++
++ dilithium_print_polyvecl(&ws->s1.s1,
++ "Keygen - S1 L x N matrix after ExpandS:");
++ dilithium_print_polyveck(&ws->s2,
++ "Keygen - S2 K x N matrix after ExpandS:");
++
++ pack_sk_s1(sk, &ws->s1.s1);
++ pack_sk_s2(sk, &ws->s2);
++
++ polyvecl_ntt(&ws->s1.s1hat);
++ dilithium_print_polyvecl(&ws->s1.s1hat,
++ "Keygen - S1 L x N matrix after NTT:");
++
++ /* Expand matrix */
++ polyvec_matrix_expand(ws->matrix.mat, rho, ws->tmp.poly_uniform_buf);
++ dilithium_print_polyvecl_k(
++ ws->matrix.mat, "Keygen - MAT K x L x N matrix after ExpandA:");
++
++ polyvec_matrix_pointwise_montgomery(
++ &ws->t1, ws->matrix.mat, &ws->s1.s1hat,
++ &ws->tmp.polyvecl_pointwise_acc_montgomery_buf);
++ dilithium_print_polyveck(&ws->t1,
++ "Keygen - T K x N matrix after A*NTT(s1):");
++
++ polyveck_reduce(&ws->t1);
++ dilithium_print_polyveck(
++ &ws->t1, "Keygen - T K x N matrix reduce after A*NTT(s1):");
++
++ polyveck_invntt_tomont(&ws->t1);
++ dilithium_print_polyveck(&ws->t1,
++ "Keygen - T K x N matrix after NTT-1:");
++
++ /* Add error vector s2 */
++ polyveck_add(&ws->t1, &ws->t1, &ws->s2);
++ dilithium_print_polyveck(&ws->t1,
++ "Keygen - T K x N matrix after add S2:");
++
++ /* Extract t1 and write public key */
++ polyveck_caddq(&ws->t1);
++ dilithium_print_polyveck(&ws->t1, "Keygen - T K x N matrix caddq:");
++
++ polyveck_power2round(&ws->t1, &ws->matrix.t0, &ws->t1);
++ dilithium_print_polyveck(&ws->matrix.t0,
++ "Keygen - T0 K x N matrix after power2round:");
++ dilithium_print_polyveck(&ws->t1,
++ "Keygen - T1 K x N matrix after power2round:");
++
++ pack_sk_t0(sk, &ws->matrix.t0);
++ pack_pk_t1(pk, &ws->t1);
++ dilithium_print_buffer(pk->pk, LC_DILITHIUM_PUBLICKEYBYTES,
++ "Keygen - PK after pkEncode:");
++
++ /* Compute H(rho, t1) and write secret key */
++ lc_xof(lc_shake256, pk->pk, sizeof(pk->pk), ws->tmp.tr,
++ sizeof(ws->tmp.tr));
++ dilithium_print_buffer(ws->tmp.tr, sizeof(ws->tmp.tr), "Keygen - TR:");
++ pack_sk_tr(sk, ws->tmp.tr);
++
++ dilithium_print_buffer(sk->sk, LC_DILITHIUM_SECRETKEYBYTES,
++ "Keygen - SK:");
++
++ /* Timecop: pk and sk are not relevant for side-channels any more. */
++ unpoison(pk->pk, sizeof(pk->pk));
++ unpoison(sk->sk, sizeof(sk->sk));
++
++out:
++ LC_RELEASE_MEM(ws);
++ return ret;
++}
++
++static int
++lc_dilithium_keypair_from_seed_impl(struct lc_dilithium_pk *pk,
++ struct lc_dilithium_sk *sk,
++ const uint8_t *seed,
++ size_t seedlen)
++{
++ struct lc_static_rng_data s_rng_state;
++ LC_STATIC_DRNG_ON_STACK(s_drng, &s_rng_state);
++ int ret;
++
++ if (seedlen != LC_DILITHIUM_SEEDBYTES)
++ return -EINVAL;
++
++ /* Set the seed that the key generation can pull via the RNG. */
++ s_rng_state.seed = seed;
++ s_rng_state.seedlen = seedlen;
++
++ /* Generate the key pair from the seed. */
++ CKINT(lc_dilithium_keypair_impl(pk, sk, &s_drng));
++
++out:
++ return ret;
++}
++
++static int
++lc_dilithium_sign_internal_ahat(struct lc_dilithium_sig *sig,
++ const struct lc_dilithium_sk *sk,
++ struct lc_dilithium_ctx *ctx,
++ struct lc_rng_ctx *rng_ctx)
++{
++ struct workspace_sign {
++ polyvecl s1, y, z;
++ polyveck t0, s2, w1, w0, h;
++ poly cp;
++ uint8_t seedbuf[LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_RNDBYTES +
++ LC_DILITHIUM_CRHBYTES];
++ union {
++ uint8_t poly_uniform_gamma1_buf[WS_POLY_UNIFORM_BUF_SIZE];
++ uint8_t poly_challenge_buf[POLY_CHALLENGE_BYTES];
++ } tmp;
++ };
++ unsigned int n;
++ uint8_t *key, *mu, *rhoprime, *rnd;
++ const polyvecl *mat = ctx->ahat;
++ uint16_t nonce = 0;
++ int ret = 0;
++ struct lc_hash_ctx *hash_ctx = &ctx->dilithium_hash_ctx;
++ uint8_t __maybe_unused rej_total = 0;
++ LC_DECLARE_MEM(ws, struct workspace_sign, sizeof(uint64_t));
++
++ /* AHat must be present at this time */
++ CKNULL(mat, -EINVAL);
++
++ key = ws->seedbuf;
++ rnd = key + LC_DILITHIUM_SEEDBYTES;
++ mu = rnd + LC_DILITHIUM_RNDBYTES;
++
++ /*
++ * If the external mu is provided, use this verbatim, otherwise
++ * calculate the mu value.
++ */
++ if (ctx->external_mu) {
++ if (ctx->external_mu_len != LC_DILITHIUM_CRHBYTES)
++ return -EINVAL;
++ memcpy(mu, ctx->external_mu, LC_DILITHIUM_CRHBYTES);
++ } else {
++ /*
++ * Set the digestsize - for SHA512 this is a noop, for SHAKE256,
++ * it sets the value. The BUILD_BUG_ON is to check that the
++ * SHA-512 output size is identical to the expected length.
++ */
++ BUILD_BUG_ON(LC_DILITHIUM_CRHBYTES != LC_SHA3_512_SIZE_DIGEST);
++ lc_hash_set_digestsize(hash_ctx, LC_DILITHIUM_CRHBYTES);
++ lc_hash_final(hash_ctx, mu);
++ }
++ dilithium_print_buffer(mu, LC_DILITHIUM_CRHBYTES, "Siggen - MU:");
++
++ if (rng_ctx) {
++ CKINT(lc_rng_generate(rng_ctx, NULL, 0, rnd,
++ LC_DILITHIUM_RNDBYTES));
++ } else {
++ memset(rnd, 0, LC_DILITHIUM_RNDBYTES);
++ }
++ dilithium_print_buffer(rnd, LC_DILITHIUM_RNDBYTES, "Siggen - RND:");
++
++ unpack_sk_key(key, sk);
++
++ /* Timecop: key is secret */
++ poison(key, LC_DILITHIUM_SEEDBYTES);
++
++ /* Re-use the ws->seedbuf, but making sure that mu is unchanged */
++ BUILD_BUG_ON(LC_DILITHIUM_CRHBYTES >
++ LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_RNDBYTES);
++ rhoprime = key;
++
++ lc_xof(lc_shake256, key,
++ LC_DILITHIUM_SEEDBYTES + LC_DILITHIUM_RNDBYTES +
++ LC_DILITHIUM_CRHBYTES,
++ rhoprime, LC_DILITHIUM_CRHBYTES);
++ dilithium_print_buffer(rhoprime, LC_DILITHIUM_CRHBYTES,
++ "Siggen - RHOPrime:");
++
++ /*
++ * Timecop: RHO' is the hash of the secret value of key which is
++ * enlarged to sample the intermediate vector y from. Due to the hashing
++ * any side channel on RHO' cannot allow the deduction of the original
++ * key.
++ */
++ unpoison(rhoprime, LC_DILITHIUM_CRHBYTES);
++
++ unpack_sk_s1(&ws->s1, sk);
++
++ /* Timecop: s1 is secret */
++ poison(&ws->s1, sizeof(polyvecl));
++
++ polyvecl_ntt(&ws->s1);
++ dilithium_print_polyvecl(&ws->s1,
++ "Siggen - S1 L x N matrix after NTT:");
++
++ unpack_sk_s2(&ws->s2, sk);
++
++ /* Timecop: s2 is secret */
++ poison(&ws->s2, sizeof(polyveck));
++
++ polyveck_ntt(&ws->s2);
++ dilithium_print_polyveck(&ws->s2,
++ "Siggen - S2 K x N matrix after NTT:");
++
++ unpack_sk_t0(&ws->t0, sk);
++ polyveck_ntt(&ws->t0);
++ dilithium_print_polyveck(&ws->t0,
++ "Siggen - T0 K x N matrix after NTT:");
++
++rej:
++ /* Sample intermediate vector y */
++ polyvecl_uniform_gamma1(&ws->y, rhoprime, nonce++,
++ ws->tmp.poly_uniform_gamma1_buf);
++ dilithium_print_polyvecl(
++ &ws->y,
++ "Siggen - Y L x N matrix after ExpandMask - start of loop");
++
++ /* Timecop: s2 is secret */
++ poison(&ws->y, sizeof(polyvecl));
++
++ /* Matrix-vector multiplication */
++ ws->z = ws->y;
++ polyvecl_ntt(&ws->z);
++
++ /* Use the cp for this operation as it is not used here so far. */
++ polyvec_matrix_pointwise_montgomery(&ws->w1, mat, &ws->z, &ws->cp);
++ polyveck_reduce(&ws->w1);
++ polyveck_invntt_tomont(&ws->w1);
++ dilithium_print_polyveck(&ws->w1,
++ "Siggen - W K x N matrix after NTT-1");
++
++ /* Decompose w and call the random oracle */
++ polyveck_caddq(&ws->w1);
++ polyveck_decompose(&ws->w1, &ws->w0, &ws->w1);
++
++ /* Timecop: the signature component w1 is not sensitive any more. */
++ unpoison(&ws->w1, sizeof(polyveck));
++ polyveck_pack_w1(sig->sig, &ws->w1);
++ dilithium_print_buffer(sig->sig,
++ LC_DILITHIUM_K * LC_DILITHIUM_POLYW1_PACKEDBYTES,
++ "Siggen - w1Encode of W1");
++
++ lc_hash_init(hash_ctx);
++ lc_hash_update(hash_ctx, mu, LC_DILITHIUM_CRHBYTES);
++ lc_hash_update(hash_ctx, sig->sig,
++ LC_DILITHIUM_K * LC_DILITHIUM_POLYW1_PACKEDBYTES);
++ lc_hash_set_digestsize(hash_ctx, LC_DILITHIUM_CTILDE_BYTES);
++ lc_hash_final(hash_ctx, sig->sig);
++ lc_hash_zero(hash_ctx);
++ dilithium_print_buffer(sig->sig, LC_DILITHIUM_CTILDE_BYTES,
++ "Siggen - ctilde");
++
++ poly_challenge(&ws->cp, sig->sig, ws->tmp.poly_challenge_buf);
++ dilithium_print_poly(&ws->cp, "Siggen - c after SampleInBall");
++ poly_ntt(&ws->cp);
++ dilithium_print_poly(&ws->cp, "Siggen - c after NTT");
++
++ /* Compute z, reject if it reveals secret */
++ polyvecl_pointwise_poly_montgomery(&ws->z, &ws->cp, &ws->s1);
++ polyvecl_invntt_tomont(&ws->z);
++ polyvecl_add(&ws->z, &ws->z, &ws->y);
++ dilithium_print_polyvecl(&ws->z, "Siggen - z <- y + cs1");
++
++ polyvecl_reduce(&ws->z);
++ dilithium_print_polyvecl(&ws->z, "Siggen - z reduction");
++
++ /* Timecop: the signature component z is not sensitive any more. */
++ unpoison(&ws->z, sizeof(polyvecl));
++
++ if (polyvecl_chknorm(&ws->z, LC_DILITHIUM_GAMMA1 - LC_DILITHIUM_BETA)) {
++ dilithium_print_polyvecl(&ws->z, "Siggen - z rejection");
++ rej_total |= 1 << 0;
++ goto rej;
++ }
++
++ /*
++ * Check that subtracting cs2 does not change high bits of w and low
++ * bits do not reveal secret information.
++ */
++ polyveck_pointwise_poly_montgomery(&ws->h, &ws->cp, &ws->s2);
++ polyveck_invntt_tomont(&ws->h);
++ polyveck_sub(&ws->w0, &ws->w0, &ws->h);
++ polyveck_reduce(&ws->w0);
++
++ /* Timecop: verification data w0 is not sensitive any more. */
++ unpoison(&ws->w0, sizeof(polyveck));
++
++ if (polyveck_chknorm(&ws->w0,
++ LC_DILITHIUM_GAMMA2 - LC_DILITHIUM_BETA)) {
++ dilithium_print_polyveck(&ws->w0, "Siggen - r0 rejection");
++ rej_total |= 1 << 1;
++ goto rej;
++ }
++
++ /* Compute hints for w1 */
++ polyveck_pointwise_poly_montgomery(&ws->h, &ws->cp, &ws->t0);
++ polyveck_invntt_tomont(&ws->h);
++ polyveck_reduce(&ws->h);
++
++ /* Timecop: the signature component h is not sensitive any more. */
++ unpoison(&ws->h, sizeof(polyveck));
++
++ if (polyveck_chknorm(&ws->h, LC_DILITHIUM_GAMMA2)) {
++ dilithium_print_polyveck(&ws->h, "Siggen - ct0 rejection");
++ rej_total |= 1 << 2;
++ goto rej;
++ }
++
++ polyveck_add(&ws->w0, &ws->w0, &ws->h);
++
++ n = polyveck_make_hint(&ws->h, &ws->w0, &ws->w1);
++ if (n > LC_DILITHIUM_OMEGA) {
++ dilithium_print_polyveck(&ws->w0, "Siggen - h rejection");
++ rej_total |= 1 << 3;
++ goto rej;
++ }
++
++ /* Write signature */
++ dilithium_print_buffer(sig->sig, LC_DILITHIUM_CTILDE_BYTES,
++ "Siggen - Ctilde:");
++ dilithium_print_polyvecl(&ws->z, "Siggen - Z L x N matrix:");
++ dilithium_print_polyveck(&ws->h, "Siggen - H K x N matrix:");
++
++ pack_sig(sig, &ws->z, &ws->h);
++
++ dilithium_print_buffer(sig->sig, LC_DILITHIUM_CRYPTO_BYTES,
++ "Siggen - Signature:");
++
++out:
++ LC_RELEASE_MEM(ws);
++#ifdef REJECTION_TEST_SAMPLING
++ return ret ? ret : rej_total;
++#else
++ return ret;
++#endif
++}
++
++static int
++lc_dilithium_sign_internal_noahat(struct lc_dilithium_sig *sig,
++ const struct lc_dilithium_sk *sk,
++ struct lc_dilithium_ctx *ctx,
++ struct lc_rng_ctx *rng_ctx)
++{
++ struct workspace_sign {
++ polyvecl mat[LC_DILITHIUM_K];
++ uint8_t poly_uniform_buf[WS_POLY_UNIFORM_BUF_SIZE];
++ };
++ /* The first bytes of the key is rho. */
++ const uint8_t *rho = sk->sk;
++ int ret = 0;
++ LC_DECLARE_MEM(ws, struct workspace_sign, LC_DILITHIUM_AHAT_ALIGNMENT);
++
++ polyvec_matrix_expand(ws->mat, rho, ws->poly_uniform_buf);
++
++ /* Temporarily set the pointer */
++ ctx->ahat = ws->mat;
++
++ CKINT(lc_dilithium_sign_internal_ahat(sig, sk, ctx, rng_ctx));
++
++out:
++ ctx->ahat = NULL;
++ LC_RELEASE_MEM(ws);
++ return ret;
++}
++
++static int
++lc_dilithium_sk_expand_impl(const struct lc_dilithium_sk *sk,
++ struct lc_dilithium_ctx *ctx)
++{
++ struct workspace_sign {
++ uint8_t poly_uniform_buf[WS_POLY_UNIFORM_BUF_SIZE];
++ };
++ /* The first bytes of the key is rho. */
++ const uint8_t *rho = sk->sk;
++ polyvecl *mat = ctx->ahat;
++ int ret = 0;
++ LC_DECLARE_MEM(ws, struct workspace_sign, sizeof(uint64_t));
++
++ /*
++ * The compile time sanity check links API header file with
++ * Dilithium-internal definitions.
++ *
++ * Runtime sanity check ensures that the allocated context has
++ * sufficient size (e.g. not that caller used, say,
++ * LC_DILITHIUM_44_CTX_ON_STACK_AHAT with a ML-DSA 65 or 87 key)
++ */
++#if LC_DILITHIUM_MODE == 2
++ BUILD_BUG_ON(LC_DILITHIUM_44_AHAT_SIZE !=
++ sizeof(polyvecl) * LC_DILITHIUM_K);
++ if (ctx->ahat_size < LC_DILITHIUM_44_AHAT_SIZE) {
++ ret = -EOVERFLOW;
++ goto out;
++ }
++#elif LC_DILITHIUM_MODE == 3
++ BUILD_BUG_ON(LC_DILITHIUM_65_AHAT_SIZE !=
++ sizeof(polyvecl) * LC_DILITHIUM_K);
++ if (ctx->ahat_size < LC_DILITHIUM_65_AHAT_SIZE) {
++ ret = -EOVERFLOW;
++ goto out;
++ }
++#elif LC_DILITHIUM_MODE == 5
++ BUILD_BUG_ON(LC_DILITHIUM_87_AHAT_SIZE !=
++ sizeof(polyvecl) * LC_DILITHIUM_K);
++ if (ctx->ahat_size < LC_DILITHIUM_87_AHAT_SIZE) {
++ ret = -EOVERFLOW;
++ goto out;
++ }
++#else
++#error "Undefined LC_DILITHIUM_MODE"
++#endif
++
++ polyvec_matrix_expand(mat, rho, ws->poly_uniform_buf);
++ dilithium_print_polyvecl_k(mat,
++ "AHAT - A K x L x N matrix after ExpandA:");
++
++ ctx->ahat_expanded = 1;
++
++out:
++ LC_RELEASE_MEM(ws);
++ return ret;
++}
++
++static int
++lc_dilithium_sign_internal(struct lc_dilithium_sig *sig,
++ const struct lc_dilithium_sk *sk,
++ struct lc_dilithium_ctx *ctx,
++ struct lc_rng_ctx *rng_ctx)
++{
++ int ret;
++
++ if (!ctx->ahat)
++ return lc_dilithium_sign_internal_noahat(sig, sk, ctx, rng_ctx);
++
++ if (!ctx->ahat_expanded)
++ CKINT(lc_dilithium_sk_expand_impl(sk, ctx));
++
++ CKINT(lc_dilithium_sign_internal_ahat(sig, sk, ctx, rng_ctx));
++
++out:
++ return ret;
++}
++
++static int
++lc_dilithium_sign_ctx_impl(struct lc_dilithium_sig *sig,
++ struct lc_dilithium_ctx *ctx,
++ const uint8_t *m, size_t mlen,
++ const struct lc_dilithium_sk *sk,
++ struct lc_rng_ctx *rng_ctx)
++{
++ uint8_t tr[LC_DILITHIUM_TRBYTES];
++ int ret = 0;
++
++ /* rng_ctx is allowed to be NULL as handled below */
++ if (!sig || !sk || !ctx)
++ return -EINVAL;
++ /* Either the message or the external mu must be provided */
++ if (!m && !ctx->external_mu)
++ return -EINVAL;
++
++ dilithium_print_buffer(m, mlen, "Siggen - Message");
++
++ unpack_sk_tr(tr, sk);
++
++ if (m) {
++ /* Compute mu = CRH(tr, msg) */
++ struct lc_hash_ctx *hash_ctx = &ctx->dilithium_hash_ctx;
++
++ lc_hash_init(hash_ctx);
++ lc_hash_update(hash_ctx, tr, LC_DILITHIUM_TRBYTES);
++
++ CKINT(signature_domain_separation(
++ &ctx->dilithium_hash_ctx, ctx->ml_dsa_internal,
++ ctx->dilithium_prehash_type, ctx->userctx,
++ ctx->userctxlen, m, mlen, ctx->randomizer,
++ ctx->randomizerlen, LC_DILITHIUM_NIST_CATEGORY));
++ }
++
++ ret = lc_dilithium_sign_internal(sig, sk, ctx, rng_ctx);
++
++out:
++ lc_memset_secure(tr, 0, sizeof(tr));
++ return ret;
++}
++
++static int
++lc_dilithium_sign_impl(struct lc_dilithium_sig *sig,
++ const uint8_t *m, size_t mlen,
++ const struct lc_dilithium_sk *sk,
++ struct lc_rng_ctx *rng_ctx)
++{
++ LC_DILITHIUM_CTX_ON_STACK(dilithium_ctx);
++ int ret = lc_dilithium_sign_ctx_impl(sig, dilithium_ctx, m, mlen, sk,
++ rng_ctx);
++
++ lc_dilithium_ctx_zero(dilithium_ctx);
++ return ret;
++}
++
++static int
++lc_dilithium_sign_init_impl(struct lc_dilithium_ctx *ctx,
++ const struct lc_dilithium_sk *sk)
++{
++ uint8_t tr[LC_DILITHIUM_TRBYTES];
++ struct lc_hash_ctx *hash_ctx;
++
++ /* rng_ctx is allowed to be NULL as handled below */
++ if (!ctx || !sk)
++ return -EINVAL;
++
++ hash_ctx = &ctx->dilithium_hash_ctx;
++
++ /* Require the use of SHAKE256 */
++ if (hash_ctx->hash != lc_shake256)
++ return -EOPNOTSUPP;
++
++ unpack_sk_tr(tr, sk);
++
++ /* Compute mu = CRH(tr, msg) */
++ lc_hash_init(hash_ctx);
++ lc_hash_update(hash_ctx, tr, LC_DILITHIUM_TRBYTES);
++ lc_memset_secure(tr, 0, sizeof(tr));
++
++ return signature_domain_separation(
++ &ctx->dilithium_hash_ctx, ctx->ml_dsa_internal,
++ ctx->dilithium_prehash_type, ctx->userctx, ctx->userctxlen,
++ NULL, 0, ctx->randomizer, ctx->randomizerlen,
++ LC_DILITHIUM_NIST_CATEGORY);
++}
++
++static int
++lc_dilithium_sign_update_impl(struct lc_dilithium_ctx *ctx,
++ const uint8_t *m, size_t mlen)
++{
++ if (!ctx || !m)
++ return -EINVAL;
++
++ /* Compute CRH(tr, msg) */
++ lc_hash_update(&ctx->dilithium_hash_ctx, m, mlen);
++
++ return 0;
++}
++
++static int
++lc_dilithium_sign_final_impl(struct lc_dilithium_sig *sig,
++ struct lc_dilithium_ctx *ctx,
++ const struct lc_dilithium_sk *sk,
++ struct lc_rng_ctx *rng_ctx)
++{
++ int ret = 0;
++
++ /* rng_ctx is allowed to be NULL as handled below */
++ if (!sig || !ctx || !sk) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ ret = lc_dilithium_sign_internal(sig, sk, ctx, rng_ctx);
++
++out:
++ lc_dilithium_ctx_zero(ctx);
++ return ret;
++}
++
++static int
++lc_dilithium_verify_internal_ahat(const struct lc_dilithium_sig *sig,
++ const struct lc_dilithium_pk *pk,
++ struct lc_dilithium_ctx *ctx)
++{
++ struct workspace_verify {
++ union {
++ poly cp;
++ } matrix;
++ polyveck w1;
++ union {
++ polyveck t1, h;
++ polyvecl z;
++ uint8_t mu[LC_DILITHIUM_CRHBYTES];
++ BUF_ALIGNED_UINT8_UINT64(LC_DILITHIUM_CTILDE_BYTES)
++ c2;
++ } buf;
++
++ union {
++ poly polyvecl_pointwise_acc_montgomery_buf;
++ uint8_t buf[LC_DILITHIUM_K *
++ LC_DILITHIUM_POLYW1_PACKEDBYTES];
++ uint8_t poly_challenge_buf[POLY_CHALLENGE_BYTES];
++ } tmp;
++ };
++ /* The first bytes of the signature is c~ and thus contains c1. */
++ const uint8_t *c1 = sig->sig;
++ const polyvecl *mat = ctx->ahat;
++ struct lc_hash_ctx *hash_ctx = &ctx->dilithium_hash_ctx;
++ int ret = 0;
++ LC_DECLARE_MEM(ws, struct workspace_verify, sizeof(uint64_t));
++
++ /* AHat must be present at this time */
++ CKNULL(mat, -EINVAL);
++
++ unpack_sig_z(&ws->buf.z, sig);
++ if (polyvecl_chknorm(&ws->buf.z,
++ LC_DILITHIUM_GAMMA1 - LC_DILITHIUM_BETA)) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ polyvecl_ntt(&ws->buf.z);
++ polyvec_matrix_pointwise_montgomery(
++ &ws->w1, mat, &ws->buf.z,
++ &ws->tmp.polyvecl_pointwise_acc_montgomery_buf);
++
++ /* Matrix-vector multiplication; compute Az - c2^dt1 */
++ poly_challenge(&ws->matrix.cp, c1, ws->tmp.poly_challenge_buf);
++ poly_ntt(&ws->matrix.cp);
++
++ unpack_pk_t1(&ws->buf.t1, pk);
++ polyveck_shiftl(&ws->buf.t1);
++ polyveck_ntt(&ws->buf.t1);
++ polyveck_pointwise_poly_montgomery(&ws->buf.t1, &ws->matrix.cp,
++ &ws->buf.t1);
++
++ polyveck_sub(&ws->w1, &ws->w1, &ws->buf.t1);
++ polyveck_reduce(&ws->w1);
++ polyveck_invntt_tomont(&ws->w1);
++
++ /* Reconstruct w1 */
++ polyveck_caddq(&ws->w1);
++ dilithium_print_polyveck(&ws->w1,
++ "Sigver - W K x N matrix before hint:");
++
++ if (unpack_sig_h(&ws->buf.h, sig))
++ return -EINVAL;
++ dilithium_print_polyveck(&ws->buf.h, "Siggen - H K x N matrix:");
++
++ polyveck_use_hint(&ws->w1, &ws->w1, &ws->buf.h);
++ dilithium_print_polyveck(&ws->w1,
++ "Sigver - W K x N matrix after hint:");
++ polyveck_pack_w1(ws->tmp.buf, &ws->w1);
++ dilithium_print_buffer(ws->tmp.buf,
++ LC_DILITHIUM_K * LC_DILITHIUM_POLYW1_PACKEDBYTES,
++ "Sigver - W after w1Encode");
++
++ if (ctx->external_mu) {
++ if (ctx->external_mu_len != LC_DILITHIUM_CRHBYTES)
++ return -EINVAL;
++
++ /* Call random oracle and verify challenge */
++ lc_hash_init(hash_ctx);
++ lc_hash_update(hash_ctx, ctx->external_mu,
++ LC_DILITHIUM_CRHBYTES);
++ } else {
++ lc_hash_set_digestsize(hash_ctx, LC_DILITHIUM_CRHBYTES);
++ lc_hash_final(hash_ctx, ws->buf.mu);
++
++ /* Call random oracle and verify challenge */
++ lc_hash_init(hash_ctx);
++ lc_hash_update(hash_ctx, ws->buf.mu, LC_DILITHIUM_CRHBYTES);
++ }
++
++ lc_hash_update(hash_ctx, ws->tmp.buf,
++ LC_DILITHIUM_K * LC_DILITHIUM_POLYW1_PACKEDBYTES);
++ lc_hash_set_digestsize(hash_ctx, LC_DILITHIUM_CTILDE_BYTES);
++ lc_hash_final(hash_ctx, ws->buf.c2.coeffs);
++ lc_hash_zero(hash_ctx);
++
++ /* Signature verification operation */
++ if (lc_memcmp_secure(c1, LC_DILITHIUM_CTILDE_BYTES, ws->buf.c2.coeffs,
++ LC_DILITHIUM_CTILDE_BYTES))
++ ret = -EBADMSG;
++
++out:
++ LC_RELEASE_MEM(ws);
++ return ret;
++}
++
++static int
++lc_dilithium_verify_internal_noahat(const struct lc_dilithium_sig *sig,
++ const struct lc_dilithium_pk *pk,
++ struct lc_dilithium_ctx *ctx)
++{
++ struct workspace_verify {
++ polyvecl mat[LC_DILITHIUM_K];
++ uint8_t poly_uniform_buf[WS_POLY_UNIFORM_BUF_SIZE];
++ };
++ /* The first bytes of the key is rho. */
++ const uint8_t *rho = pk->pk;
++ int ret = 0;
++ LC_DECLARE_MEM(ws, struct workspace_verify, sizeof(uint64_t));
++
++ polyvec_matrix_expand(ws->mat, rho, ws->poly_uniform_buf);
++
++ /* Temporarily set the pointer */
++ ctx->ahat = ws->mat;
++
++ CKINT(lc_dilithium_verify_internal_ahat(sig, pk, ctx));
++
++out:
++ ctx->ahat = NULL;
++ LC_RELEASE_MEM(ws);
++ return ret;
++}
++
++static int
++lc_dilithium_pk_expand_impl(const struct lc_dilithium_pk *pk,
++ struct lc_dilithium_ctx *ctx)
++{
++ struct workspace_verify {
++ uint8_t poly_uniform_buf[WS_POLY_UNIFORM_BUF_SIZE];
++ };
++ /* The first bytes of the key is rho. */
++ const uint8_t *rho = pk->pk;
++ polyvecl *mat = ctx->ahat;
++ int ret = 0;
++ LC_DECLARE_MEM(ws, struct workspace_verify, sizeof(uint64_t));
++
++ /*
++ * Runtime sanity check ensures that the allocated context has
++ * sufficient size (e.g. not that caller used, say,
++ * LC_DILITHIUM_44_CTX_ON_STACK_AHAT with a ML-DSA 65 or 87 key)
++ */
++#if LC_DILITHIUM_MODE == 2
++ if (ctx->ahat_size < LC_DILITHIUM_44_AHAT_SIZE) {
++ ret = -EOVERFLOW;
++ goto out;
++ }
++#elif LC_DILITHIUM_MODE == 3
++ if (ctx->ahat_size < LC_DILITHIUM_65_AHAT_SIZE) {
++ ret = -EOVERFLOW;
++ goto out;
++ }
++#elif LC_DILITHIUM_MODE == 5
++ if (ctx->ahat_size < LC_DILITHIUM_87_AHAT_SIZE) {
++ ret = -EOVERFLOW;
++ goto out;
++ }
++#else
++#error "Undefined LC_DILITHIUM_MODE"
++#endif
++
++ polyvec_matrix_expand(mat, rho, ws->poly_uniform_buf);
++ ctx->ahat_expanded = 1;
++
++out:
++ LC_RELEASE_MEM(ws);
++ return ret;
++}
++
++static int
++lc_dilithium_verify_internal(const struct lc_dilithium_sig *sig,
++ const struct lc_dilithium_pk *pk,
++ struct lc_dilithium_ctx *ctx)
++{
++ int ret;
++
++ if (!ctx->ahat)
++ return lc_dilithium_verify_internal_noahat(sig, pk, ctx);
++
++ if (!ctx->ahat_expanded)
++ CKINT(lc_dilithium_pk_expand_impl(pk, ctx));
++
++ CKINT(lc_dilithium_verify_internal_ahat(sig, pk, ctx));
++
++out:
++ return ret;
++}
++
++static int
++lc_dilithium_verify_ctx_impl(const struct lc_dilithium_sig *sig,
++ struct lc_dilithium_ctx *ctx,
++ const uint8_t *m, size_t mlen,
++ const struct lc_dilithium_pk *pk)
++{
++ uint8_t tr[LC_DILITHIUM_TRBYTES];
++ int ret = 0;
++
++ if (!sig || !pk || !ctx)
++ return -EINVAL;
++
++ /* Either the message or the external mu must be provided */
++ if (!m && !ctx->external_mu)
++ return -EINVAL;
++
++ /* Make sure that ->mu is large enough for ->tr */
++ BUILD_BUG_ON(LC_DILITHIUM_TRBYTES > LC_DILITHIUM_CRHBYTES);
++
++ /* Compute CRH(H(rho, t1), msg) */
++ lc_xof(lc_shake256, pk->pk, LC_DILITHIUM_PUBLICKEYBYTES, tr,
++ LC_DILITHIUM_TRBYTES);
++
++ if (m) {
++ struct lc_hash_ctx *hash_ctx = &ctx->dilithium_hash_ctx;
++
++ lc_hash_init(hash_ctx);
++ lc_hash_update(hash_ctx, tr, LC_DILITHIUM_TRBYTES);
++ CKINT(signature_domain_separation(
++ &ctx->dilithium_hash_ctx, ctx->ml_dsa_internal,
++ ctx->dilithium_prehash_type, ctx->userctx,
++ ctx->userctxlen, m, mlen, ctx->randomizer,
++ ctx->randomizerlen, LC_DILITHIUM_NIST_CATEGORY));
++ }
++
++ ret = lc_dilithium_verify_internal(sig, pk, ctx);
++
++out:
++ lc_memset_secure(tr, 0, sizeof(tr));
++ return ret;
++}
++
++static int
++lc_dilithium_verify_impl(const struct lc_dilithium_sig *sig,
++ const uint8_t *m, size_t mlen,
++ const struct lc_dilithium_pk *pk)
++{
++ LC_DILITHIUM_CTX_ON_STACK(ctx);
++ int ret = lc_dilithium_verify_ctx_impl(sig, ctx, m, mlen, pk);
++
++ lc_dilithium_ctx_zero(ctx);
++ return ret;
++}
++
++static int
++lc_dilithium_verify_init_impl(struct lc_dilithium_ctx *ctx,
++ const struct lc_dilithium_pk *pk)
++{
++ uint8_t mu[LC_DILITHIUM_TRBYTES];
++ struct lc_hash_ctx *hash_ctx;
++
++ /* rng_ctx is allowed to be NULL as handled below */
++ if (!ctx || !pk)
++ return -EINVAL;
++
++ hash_ctx = &ctx->dilithium_hash_ctx;
++
++ /* Require the use of SHAKE256 */
++ if (hash_ctx->hash != lc_shake256)
++ return -EOPNOTSUPP;
++
++ /* Compute CRH(H(rho, t1), msg) */
++ lc_xof(lc_shake256, pk->pk, LC_DILITHIUM_PUBLICKEYBYTES, mu,
++ LC_DILITHIUM_TRBYTES);
++
++ lc_hash_init(hash_ctx);
++ lc_hash_update(hash_ctx, mu, LC_DILITHIUM_TRBYTES);
++ lc_memset_secure(mu, 0, sizeof(mu));
++
++ return signature_domain_separation(
++ &ctx->dilithium_hash_ctx, ctx->ml_dsa_internal,
++ ctx->dilithium_prehash_type, ctx->userctx, ctx->userctxlen,
++ NULL, 0, ctx->randomizer, ctx->randomizerlen,
++ LC_DILITHIUM_NIST_CATEGORY);
++}
++
++static int
++lc_dilithium_verify_update_impl(struct lc_dilithium_ctx *ctx,
++ const uint8_t *m, size_t mlen)
++{
++ struct lc_hash_ctx *hash_ctx;
++
++ if (!ctx || !m)
++ return -EINVAL;
++
++ /* Compute CRH(H(rho, t1), msg) */
++ hash_ctx = &ctx->dilithium_hash_ctx;
++ lc_hash_update(hash_ctx, m, mlen);
++
++ return 0;
++}
++
++static int
++lc_dilithium_verify_final_impl(const struct lc_dilithium_sig *sig,
++ struct lc_dilithium_ctx *ctx,
++ const struct lc_dilithium_pk *pk)
++{
++ int ret = 0;
++
++ if (!sig || !ctx || !pk) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ ret = lc_dilithium_verify_internal(sig, pk, ctx);
++
++out:
++ lc_dilithium_ctx_zero(ctx);
++ return ret;
++}
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_SIGNATURE_IMPL_H */
+diff --git a/lib/freebl/leancrypto/dilithium_type.h b/lib/freebl/leancrypto/dilithium_type.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_type.h
+@@ -0,0 +1,349 @@
++/*
++ * Copyright (C) 2024 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef DILITHIUM_TYPE_H
++#define DILITHIUM_TYPE_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/* Prevent Dilithium macros from getting undefined */
++#define LC_DILITHIUM_INTERNAL
++
++/*
++ * This define replaces all symbol names accordingly to allow double compilation
++ * of the same code base.
++ *
++ * Due to the replacement operation, this header file must be included as the
++ * first header file in the entire stack.
++ *
++ * This file can easily be replaced with lc_dilithium.h to achieve the common
++ * functionality without symbol duplication. But in this case, only the
++ * Dilithium security strength is compiled defined in lc_dilithium.h. Duplicate
++ * compilation different sizes would not be possible.
++ */
++#ifdef LC_DILITHIUM_TYPE_65
++#define DILITHIUM_F(name) lc_dilithium_65_##name
++#define lc_dilithium_pk lc_dilithium_65_pk
++#define lc_dilithium_sk lc_dilithium_65_sk
++#define lc_dilithium_sig lc_dilithium_65_sig
++#define lc_dilithium_ed25519_pk lc_dilithium_65_ed25519_pk
++#define lc_dilithium_ed25519_sk lc_dilithium_65_ed25519_sk
++#define lc_dilithium_ed25519_sig lc_dilithium_65_ed25519_sig
++#define lc_dilithium_ed25519_ctx lc_dilithium_65_ed25519_ctx
++#define lc_dilithium_ed448_pk lc_dilithium_65_ed448_pk
++#define lc_dilithium_ed448_sk lc_dilithium_65_ed448_sk
++#define lc_dilithium_ed448_sig lc_dilithium_65_ed448_sig
++#define lc_dilithium_ed448_ctx lc_dilithium_65_ed448_ctx
++
++#include "lc_dilithium_65.h"
++
++#elif defined LC_DILITHIUM_TYPE_44
++#define DILITHIUM_F(name) lc_dilithium_44_##name
++#define lc_dilithium_pk lc_dilithium_44_pk
++#define lc_dilithium_sk lc_dilithium_44_sk
++#define lc_dilithium_sig lc_dilithium_44_sig
++#define lc_dilithium_ed25519_pk lc_dilithium_44_ed25519_pk
++#define lc_dilithium_ed25519_sk lc_dilithium_44_ed25519_sk
++#define lc_dilithium_ed25519_sig lc_dilithium_44_ed25519_sig
++#define lc_dilithium_ed25519_ctx lc_dilithium_44_ed25519_ctx
++#define lc_dilithium_ed448_pk lc_dilithium_44_ed448_pk
++#define lc_dilithium_ed448_sk lc_dilithium_44_ed448_sk
++#define lc_dilithium_ed448_sig lc_dilithium_44_ed448_sig
++#define lc_dilithium_ed448_ctx lc_dilithium_44_ed448_ctx
++
++#include "lc_dilithium_44.h"
++
++#else
++#define DILITHIUM_F(name) lc_dilithium_87_##name
++#define lc_dilithium_pk lc_dilithium_87_pk
++#define lc_dilithium_sk lc_dilithium_87_sk
++#define lc_dilithium_sig lc_dilithium_87_sig
++#define lc_dilithium_ed25519_pk lc_dilithium_87_ed25519_pk
++#define lc_dilithium_ed25519_sk lc_dilithium_87_ed25519_sk
++#define lc_dilithium_ed25519_sig lc_dilithium_87_ed25519_sig
++#define lc_dilithium_ed25519_ctx lc_dilithium_87_ed25519_ctx
++#define lc_dilithium_ed448_pk lc_dilithium_87_ed448_pk
++#define lc_dilithium_ed448_sk lc_dilithium_87_ed448_sk
++#define lc_dilithium_ed448_sig lc_dilithium_87_ed448_sig
++#define lc_dilithium_ed448_ctx lc_dilithium_87_ed448_ctx
++
++#include "lc_dilithium_87.h"
++
++#endif
++
++/*
++ * The following defines simply allow duplicate compilation of the
++ * respective functions.
++ */
++#define lc_dilithium_keypair DILITHIUM_F(keypair)
++#define lc_dilithium_keypair_from_seed DILITHIUM_F(keypair_from_seed)
++#define lc_dilithium_sign DILITHIUM_F(sign)
++#define lc_dilithium_sign_ctx DILITHIUM_F(sign_ctx)
++#define lc_dilithium_sign_init DILITHIUM_F(sign_init)
++#define lc_dilithium_sign_update DILITHIUM_F(sign_update)
++#define lc_dilithium_sign_final DILITHIUM_F(sign_final)
++#define lc_dilithium_verify DILITHIUM_F(verify)
++#define lc_dilithium_verify_ctx DILITHIUM_F(verify_ctx)
++#define lc_dilithium_verify_init DILITHIUM_F(verify_init)
++#define lc_dilithium_verify_update DILITHIUM_F(verify_update)
++#define lc_dilithium_verify_final DILITHIUM_F(verify_final)
++#define lc_dilithium_ctx_alloc DILITHIUM_F(ctx_alloc)
++#define lc_dilithium_ctx_alloc_ahat DILITHIUM_F(ctx_alloc_ahat)
++#define lc_dilithium_ctx_zero_free DILITHIUM_F(ctx_zero_free)
++#define lc_dilithium_ctx_zero DILITHIUM_F(ctx_zero)
++
++#define lc_dilithium_keypair_c DILITHIUM_F(keypair_c)
++#define lc_dilithium_keypair_from_seed_c DILITHIUM_F(keypair_from_seed_c)
++#define lc_dilithium_sign_c DILITHIUM_F(sign_c)
++#define lc_dilithium_sign_ctx_c DILITHIUM_F(sign_ctx_c)
++#define lc_dilithium_sign_init_c DILITHIUM_F(sign_init_c)
++#define lc_dilithium_sign_update_c DILITHIUM_F(sign_update_c)
++#define lc_dilithium_sign_final_c DILITHIUM_F(sign_final_c)
++#define lc_dilithium_verify_c DILITHIUM_F(verify_c)
++#define lc_dilithium_verify_ctx_c DILITHIUM_F(verify_ctx_c)
++#define lc_dilithium_verify_init_c DILITHIUM_F(verify_init_c)
++#define lc_dilithium_verify_update_c DILITHIUM_F(verify_update_c)
++#define lc_dilithium_verify_final_c DILITHIUM_F(verify_final_c)
++
++#define lc_dilithium_ed25519_keypair DILITHIUM_F(ed25519_keypair)
++#define lc_dilithium_ed25519_sign DILITHIUM_F(ed25519_sign)
++#define lc_dilithium_ed25519_sign_ctx DILITHIUM_F(ed25519_sign_ctx)
++#define lc_dilithium_ed25519_sign_init DILITHIUM_F(ed25519_sign_init)
++#define lc_dilithium_ed25519_sign_update DILITHIUM_F(ed25519_sign_update)
++#define lc_dilithium_ed25519_sign_final DILITHIUM_F(ed25519_sign_final)
++#define lc_dilithium_ed25519_verify DILITHIUM_F(ed25519_verify)
++#define lc_dilithium_ed25519_verify_ctx DILITHIUM_F(ed25519_verify_ctx)
++#define lc_dilithium_ed25519_verify_init DILITHIUM_F(ed25519_verify_init)
++#define lc_dilithium_ed25519_verify_update DILITHIUM_F(ed25519_verify_update)
++#define lc_dilithium_ed25519_verify_final DILITHIUM_F(ed25519_verify_final)
++#define lc_dilithium_ed25519_ctx_alloc DILITHIUM_F(ed25519_ctx_alloc)
++#define lc_dilithium_ed25519_ctx_zero_free DILITHIUM_F(ed25519_ctx_zero_free)
++#define lc_dilithium_ed25519_ctx_zero DILITHIUM_F(ed25519_ctx_zero)
++
++#define lc_dilithium_ed448_keypair DILITHIUM_F(ed448_keypair)
++#define lc_dilithium_ed448_sign DILITHIUM_F(ed448_sign)
++#define lc_dilithium_ed448_sign_ctx DILITHIUM_F(ed448_sign_ctx)
++#define lc_dilithium_ed448_sign_init DILITHIUM_F(ed448_sign_init)
++#define lc_dilithium_ed448_sign_update DILITHIUM_F(ed448_sign_update)
++#define lc_dilithium_ed448_sign_final DILITHIUM_F(ed448_sign_final)
++#define lc_dilithium_ed448_verify DILITHIUM_F(ed448_verify)
++#define lc_dilithium_ed448_verify_ctx DILITHIUM_F(ed448_verify_ctx)
++#define lc_dilithium_ed448_verify_init DILITHIUM_F(ed448_verify_init)
++#define lc_dilithium_ed448_verify_update DILITHIUM_F(ed448_verify_update)
++#define lc_dilithium_ed448_verify_final DILITHIUM_F(ed448_verify_final)
++#define lc_dilithium_ed448_ctx_alloc DILITHIUM_F(ed448_ctx_alloc)
++#define lc_dilithium_ed448_ctx_zero_free DILITHIUM_F(ed448_ctx_zero_free)
++#define lc_dilithium_ed448_ctx_zero DILITHIUM_F(ed448_ctx_zero)
++
++#define dilithium_keypair_tester DILITHIUM_F(keypair_tester)
++#define dilithium_siggen_tester DILITHIUM_F(siggen_tester)
++#define dilithium_sigver_tester DILITHIUM_F(sigver_tester)
++
++#define ntt DILITHIUM_F(ntt)
++#define invntt_tomont DILITHIUM_F(invntt_tomont)
++#define poly_chknorm DILITHIUM_F(poly_chknorm)
++#define poly_uniform DILITHIUM_F(poly_uniform)
++#define poly_uniform_eta DILITHIUM_F(poly_uniform_eta)
++#define poly_uniform_gamma1 DILITHIUM_F(poly_uniform_gamma1)
++#define polyz_unpack DILITHIUM_F(polyz_unpack)
++#define poly_challenge DILITHIUM_F(poly_challenge)
++#define polyeta_pack DILITHIUM_F(polyeta_pack)
++#define polyeta_unpack DILITHIUM_F(polyeta_unpack)
++#define polyt1_pack DILITHIUM_F(polyt1_pack)
++#define polyt0_pack DILITHIUM_F(polyt0_pack)
++#define polyt0_unpack DILITHIUM_F(polyt0_unpack)
++#define polyz_pack DILITHIUM_F(polyz_pack)
++#define polyw1_pack DILITHIUM_F(polyw1_pack)
++#define power2round DILITHIUM_F(power2round)
++#define decompose DILITHIUM_F(decompose)
++#define make_hint DILITHIUM_F(make_hint)
++#define use_hint DILITHIUM_F(use_hint)
++
++#define dilithium_print_buffer DILITHIUM_F(print_buffer)
++#define dilithium_print_polyvecl_k DILITHIUM_F(print_polyvecl_k)
++#define dilithium_print_polyvecl DILITHIUM_F(print_polyvecl)
++#define dilithium_print_polyveck DILITHIUM_F(print_polyveck)
++#define dilithium_print_poly DILITHIUM_F(print_poly)
++
++/* AVX2 Implementation */
++#define dilithium_invntt_avx DILITHIUM_F(invntt_avx)
++#define dilithium_ntt_avx DILITHIUM_F(ntt_avx)
++#define dilithium_nttunpack_avx DILITHIUM_F(nttunpack_avx)
++#define dilithium_pointwise_avx DILITHIUM_F(pointwise_avx)
++#define dilithium_pointwise_acc_avx DILITHIUM_F(pointwise_acc_avx)
++#define poly_reduce_avx DILITHIUM_F(poly_reduce_avx)
++#define poly_caddq_avx DILITHIUM_F(poly_caddq_avx)
++#define poly_add_avx DILITHIUM_F(poly_add_avx)
++#define poly_sub_avx DILITHIUM_F(poly_sub_avx)
++#define poly_shiftl_avx DILITHIUM_F(poly_shiftl_avx)
++#define poly_chknorm_avx DILITHIUM_F(poly_chknorm_avx)
++#define poly_uniform_4x_avx DILITHIUM_F(poly_uniform_4x_avx)
++#define poly_uniform_eta_4x_avx DILITHIUM_F(poly_uniform_eta_4x_avx)
++#define poly_uniform_gamma1_4x_avx DILITHIUM_F(poly_uniform_gamma1_4x_avx)
++#define polyz_unpack_avx DILITHIUM_F(polyz_unpack_avx)
++#define poly_challenge_avx DILITHIUM_F(poly_challenge_avx)
++#define polyeta_pack_avx DILITHIUM_F(polyeta_pack_avx)
++#define polyeta_unpack_avx DILITHIUM_F(polyeta_unpack_avx)
++#define polyt1_pack_avx DILITHIUM_F(polyt1_pack_avx)
++#define polyt1_unpack_avx DILITHIUM_F(polyt1_unpack_avx)
++#define polyt0_pack_avx DILITHIUM_F(polyt0_pack_avx)
++#define polyt0_unpack_avx DILITHIUM_F(polyt0_unpack_avx)
++#define polyz_pack_avx DILITHIUM_F(polyz_pack_avx)
++#define polyw1_pack_avx DILITHIUM_F(polyw1_pack_avx)
++#define polyvec_matrix_expand DILITHIUM_F(polyvec_matrix_expand)
++#define polyvec_matrix_expand_row0 DILITHIUM_F(polyvec_matrix_expand_row0)
++#define polyvec_matrix_expand_row1 DILITHIUM_F(polyvec_matrix_expand_row1)
++#define polyvec_matrix_expand_row2 DILITHIUM_F(polyvec_matrix_expand_row2)
++#define polyvec_matrix_expand_row3 DILITHIUM_F(polyvec_matrix_expand_row3)
++#define polyvec_matrix_expand_row4 DILITHIUM_F(polyvec_matrix_expand_row4)
++#define polyvec_matrix_expand_row5 DILITHIUM_F(polyvec_matrix_expand_row5)
++#define polyvec_matrix_expand_row6 DILITHIUM_F(polyvec_matrix_expand_row6)
++#define polyvec_matrix_expand_row7 DILITHIUM_F(polyvec_matrix_expand_row7)
++#define rej_uniform_avx DILITHIUM_F(rej_uniform_avx)
++#define rej_eta_avx DILITHIUM_F(rej_eta_avx)
++#define idxlut DILITHIUM_F(idxlut)
++#define power2round_avx DILITHIUM_F(power2round_avx)
++#define decompose_avx DILITHIUM_F(decompose_avx)
++#define make_hint_avx DILITHIUM_F(make_hint_avx)
++#define use_hint_avx DILITHIUM_F(use_hint_avx)
++#define lc_dilithium_keypair_avx2 DILITHIUM_F(keypair_avx2)
++#define lc_dilithium_keypair_from_seed_avx2 DILITHIUM_F(keypair_from_seed_avx2)
++#define lc_dilithium_sign_avx2 DILITHIUM_F(sign_avx2)
++#define lc_dilithium_sign_ctx_avx2 DILITHIUM_F(sign_ctx_avx2)
++#define lc_dilithium_sign_init_avx2 DILITHIUM_F(sign_init_avx2)
++#define lc_dilithium_sign_update_avx2 DILITHIUM_F(sign_update_avx2)
++#define lc_dilithium_sign_final_avx2 DILITHIUM_F(sign_final_avx2)
++#define lc_dilithium_verify_avx2 DILITHIUM_F(verify_avx2)
++#define lc_dilithium_verify_ctx_avx2 DILITHIUM_F(verify_ctx_avx2)
++#define lc_dilithium_verify_init_avx2 DILITHIUM_F(verify_init_avx2)
++#define lc_dilithium_verify_update_avx2 DILITHIUM_F(verify_update_avx2)
++#define lc_dilithium_verify_final_avx2 DILITHIUM_F(verify_final_avx2)
++
++/* ARMv8 Implementation */
++#define intt_SIMD_top_armv8 DILITHIUM_F(intt_SIMD_top_armv8)
++#define intt_SIMD_bot_armv8 DILITHIUM_F(intt_SIMD_bot_armv8)
++#define ntt_SIMD_top_armv8 DILITHIUM_F(ntt_SIMD_top_armv8)
++#define ntt_SIMD_bot_armv8 DILITHIUM_F(ntt_SIMD_bot_armv8)
++#define poly_uniformx2 DILITHIUM_F(poly_uniformx2)
++#define poly_uniform_etax2 DILITHIUM_F(poly_uniform_etax2)
++#define poly_uniform_gamma1x2 DILITHIUM_F(poly_uniform_gamma1x2)
++#define armv8_10_to_32 DILITHIUM_F(armv8_10_to_32)
++#define poly_reduce_armv8 DILITHIUM_F(poly_reduce_armv8)
++#define poly_caddq_armv8 DILITHIUM_F(poly_caddq_armv8)
++#define poly_power2round_armv8 DILITHIUM_F(poly_power2round_armv8)
++#define poly_pointwise_montgomery_armv8 \
++ DILITHIUM_F(poly_pointwise_montgomery_armv8)
++#define polyvecl_pointwise_acc_montgomery_armv8 \
++ DILITHIUM_F(polyvecl_pointwise_acc_montgomery_armv8)
++#define lc_dilithium_keypair_armv8 DILITHIUM_F(keypair_armv8)
++#define lc_dilithium_keypair_from_seed_armv8 \
++ DILITHIUM_F(keypair_from_seed_armv8)
++#define lc_dilithium_sign_armv8 DILITHIUM_F(sign_armv8)
++#define lc_dilithium_sign_ctx_armv8 DILITHIUM_F(sign_ctx_armv8)
++#define lc_dilithium_sign_init_armv8 DILITHIUM_F(sign_init_armv8)
++#define lc_dilithium_sign_update_armv8 DILITHIUM_F(sign_update_armv8)
++#define lc_dilithium_sign_final_armv8 DILITHIUM_F(sign_final_armv8)
++#define lc_dilithium_verify_armv8 DILITHIUM_F(verify_armv8)
++#define lc_dilithium_verify_ctx_armv8 DILITHIUM_F(verify_ctx_armv8)
++#define lc_dilithium_verify_init_armv8 DILITHIUM_F(verify_init_armv8)
++#define lc_dilithium_verify_update_armv8 DILITHIUM_F(verify_update_armv8)
++#define lc_dilithium_verify_final_armv8 DILITHIUM_F(verify_final_armv8)
++
++/* ARMv7 Implementation */
++#define armv7_ntt_asm_smull DILITHIUM_F(armv7_ntt_asm_smull)
++#define armv7_inv_ntt_asm_smull DILITHIUM_F(armv7_inv_ntt_asm_smull)
++#define armv7_poly_pointwise_invmontgomery_asm_smull \
++ DILITHIUM_F(armv7_poly_pointwise_invmontgomery_asm_smull)
++#define armv7_poly_pointwise_acc_invmontgomery_asm_smull \
++ DILITHIUM_F(armv7_poly_pointwise_acc_invmontgomery_asm_smull)
++#define poly_uniform_armv7 DILITHIUM_F(poly_uniform_armv7)
++#define armv7_poly_reduce_asm DILITHIUM_F(armv7_poly_reduce_asm)
++#define armv7_rej_uniform_asm DILITHIUM_F(armv7_rej_uniform_asm)
++#define lc_dilithium_keypair_armv7 DILITHIUM_F(keypair_armv7)
++#define lc_dilithium_keypair_from_seed_armv7 \
++ DILITHIUM_F(keypair_from_seed_armv7)
++#define lc_dilithium_sign_armv7 DILITHIUM_F(sign_armv7)
++#define lc_dilithium_sign_ctx_armv7 DILITHIUM_F(sign_ctx_armv7)
++#define lc_dilithium_sign_init_armv7 DILITHIUM_F(sign_init_armv7)
++#define lc_dilithium_sign_update_armv7 DILITHIUM_F(sign_update_armv7)
++#define lc_dilithium_sign_final_armv7 DILITHIUM_F(sign_final_armv7)
++#define lc_dilithium_verify_armv7 DILITHIUM_F(verify_armv7)
++#define lc_dilithium_verify_ctx_armv7 DILITHIUM_F(verify_ctx_armv7)
++#define lc_dilithium_verify_init_armv7 DILITHIUM_F(verify_init_armv7)
++#define lc_dilithium_verify_update_armv7 DILITHIUM_F(verify_update_armv7)
++#define lc_dilithium_verify_final_armv7 DILITHIUM_F(verify_final_armv7)
++
++/* RISCV 64 ASM Implementation */
++#define lc_dilithium_keypair_riscv64 DILITHIUM_F(keypair_riscv64)
++#define lc_dilithium_keypair_from_seed_riscv64 \
++ DILITHIUM_F(keypair_from_seed_riscv64)
++#define lc_dilithium_sign_riscv64 DILITHIUM_F(sign_riscv64)
++#define lc_dilithium_sign_ctx_riscv64 DILITHIUM_F(sign_ctx_riscv64)
++#define lc_dilithium_sign_init_riscv64 DILITHIUM_F(sign_init_riscv64)
++#define lc_dilithium_sign_update_riscv64 DILITHIUM_F(sign_update_riscv64)
++#define lc_dilithium_sign_final_riscv64 DILITHIUM_F(sign_final_riscv64)
++#define lc_dilithium_verify_riscv64 DILITHIUM_F(verify_riscv64)
++#define lc_dilithium_verify_ctx_riscv64 DILITHIUM_F(verify_ctx_riscv64)
++#define lc_dilithium_verify_init_riscv64 DILITHIUM_F(verify_init_riscv64)
++#define lc_dilithium_verify_update_riscv64 DILITHIUM_F(verify_update_riscv64)
++#define lc_dilithium_verify_final_riscv64 DILITHIUM_F(verify_final_riscv64)
++#define dilithium_ntt_8l_rv64im DILITHIUM_F(ntt_8l_rv64im)
++#define dilithium_intt_8l_rv64im DILITHIUM_F(intt_8l_rv64im)
++#define dilithium_poly_basemul_8l_init_rv64im \
++ DILITHIUM_F(poly_basemul_8l_init_rv64im)
++#define dilithium_poly_basemul_8l_acc_rv64im \
++ DILITHIUM_F(poly_basemul_8l_acc_rv64im)
++#define dilithium_poly_basemul_8l_acc_end_rv64im \
++ DILITHIUM_F(poly_basemul_8l_acc_end_rv64im)
++#define dilithium_poly_basemul_8l_rv64im DILITHIUM_F(poly_basemul_8l_rv64im)
++#define dilithium_poly_reduce_rv64im DILITHIUM_F(poly_reduce_rv64im)
++
++/* RISCV 64 RVV Implementation */
++#define lc_dilithium_keypair_riscv64_rvv DILITHIUM_F(keypair_riscv64_rvv)
++#define lc_dilithium_keypair_from_seed_riscv64_rvv \
++ DILITHIUM_F(keypair_from_seed_riscv64_rvv)
++#define lc_dilithium_sign_riscv64_rvv DILITHIUM_F(sign_riscv64_rvv)
++#define lc_dilithium_sign_ctx_riscv64_rvv DILITHIUM_F(sign_ctx_riscv64_rvv)
++#define lc_dilithium_sign_init_riscv64_rvv DILITHIUM_F(sign_init_riscv64_rvv)
++#define lc_dilithium_sign_update_riscv64_rvv \
++ DILITHIUM_F(sign_update_riscv64_rvv)
++#define lc_dilithium_sign_final_riscv64_rvv DILITHIUM_F(sign_final_riscv64_rvv)
++#define lc_dilithium_verify_riscv64_rvv DILITHIUM_F(verify_riscv64_rvv)
++#define lc_dilithium_verify_ctx_riscv64_rvv DILITHIUM_F(verify_ctx_riscv64_rvv)
++#define lc_dilithium_verify_init_riscv64_rvv \
++ DILITHIUM_F(verify_init_riscv64_rvv)
++#define lc_dilithium_verify_update_riscv64_rvv \
++ DILITHIUM_F(verify_update_riscv64_rvv)
++#define lc_dilithium_verify_final_riscv64_rvv \
++ DILITHIUM_F(verify_final_riscv64_rvv)
++#define dilithium_ntt_8l_rvv DILITHIUM_F(ntt_8l_rvv)
++#define dilithium_intt_8l_rvv DILITHIUM_F(intt_8l_rvv)
++#define dilithium_poly_basemul_8l_rvv DILITHIUM_F(poly_basemul_8l_rvv)
++#define dilithium_poly_basemul_acc_8l_rvv DILITHIUM_F(poly_basemul_acc_8l_rvv)
++#define dilithium_ntt2normal_order_8l_rvv DILITHIUM_F(ntt2normal_order_8l_rvv)
++#define dilithium_normal2ntt_order_8l_rvv DILITHIUM_F(normal2ntt_order_8l_rvv)
++#define dilithium_poly_reduce_rvv DILITHIUM_F(poly_reduce_rvv)
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_TYPE_H */
+diff --git a/lib/freebl/leancrypto/dilithium_zetas.h b/lib/freebl/leancrypto/dilithium_zetas.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/dilithium_zetas.h
+@@ -0,0 +1,35 @@
++/*
++ * Copyright (C) 2024 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef DILITHIUM_ZETAS_H
++#define DILITHIUM_ZETAS_H
++
++#include "dilithium_type.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++extern const int32_t dilithium_zetas[LC_DILITHIUM_N];
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* DILITHIUM_ZETAS_H */
+diff --git a/lib/freebl/leancrypto/errno_private-base.h b/lib/freebl/leancrypto/errno_private-base.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/errno_private-base.h
+@@ -0,0 +1,40 @@
++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
++#ifndef _ASM_GENERIC_ERRNO_BASE_H
++#define _ASM_GENERIC_ERRNO_BASE_H
++
++#define EPERM 1 /* Operation not permitted */
++#define ENOENT 2 /* No such file or directory */
++#define ESRCH 3 /* No such process */
++#define EINTR 4 /* Interrupted system call */
++#define EIO 5 /* I/O error */
++#define ENXIO 6 /* No such device or address */
++#define E2BIG 7 /* Argument list too long */
++#define ENOEXEC 8 /* Exec format error */
++#define EBADF 9 /* Bad file number */
++#define ECHILD 10 /* No child processes */
++#define EAGAIN 11 /* Try again */
++#define ENOMEM 12 /* Out of memory */
++#define EACCES 13 /* Permission denied */
++#define EFAULT 14 /* Bad address */
++#define ENOTBLK 15 /* Block device required */
++#define EBUSY 16 /* Device or resource busy */
++#define EEXIST 17 /* File exists */
++#define EXDEV 18 /* Cross-device link */
++#define ENODEV 19 /* No such device */
++#define ENOTDIR 20 /* Not a directory */
++#define EISDIR 21 /* Is a directory */
++#define EINVAL 22 /* Invalid argument */
++#define ENFILE 23 /* File table overflow */
++#define EMFILE 24 /* Too many open files */
++#define ENOTTY 25 /* Not a typewriter */
++#define ETXTBSY 26 /* Text file busy */
++#define EFBIG 27 /* File too large */
++#define ENOSPC 28 /* No space left on device */
++#define ESPIPE 29 /* Illegal seek */
++#define EROFS 30 /* Read-only file system */
++#define EMLINK 31 /* Too many links */
++#define EPIPE 32 /* Broken pipe */
++#define EDOM 33 /* Math argument out of domain of func */
++#define ERANGE 34 /* Math result not representable */
++
++#endif
+diff --git a/lib/freebl/leancrypto/errno_private.h b/lib/freebl/leancrypto/errno_private.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/errno_private.h
+@@ -0,0 +1,123 @@
++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
++#ifndef _ASM_GENERIC_ERRNO_H
++#define _ASM_GENERIC_ERRNO_H
++
++#include "errno_private-base.h"
++
++#define EDEADLK 35 /* Resource deadlock would occur */
++#define ENAMETOOLONG 36 /* File name too long */
++#define ENOLCK 37 /* No record locks available */
++
++/*
++ * This error code is special: arch syscall entry code will return
++ * -ENOSYS if users try to call a syscall that doesn't exist. To keep
++ * failures of syscalls that really do exist distinguishable from
++ * failures due to attempts to use a nonexistent syscall, syscall
++ * implementations should refrain from returning -ENOSYS.
++ */
++#define ENOSYS 38 /* Invalid system call number */
++
++#define ENOTEMPTY 39 /* Directory not empty */
++#define ELOOP 40 /* Too many symbolic links encountered */
++#define EWOULDBLOCK EAGAIN /* Operation would block */
++#define ENOMSG 42 /* No message of desired type */
++#define EIDRM 43 /* Identifier removed */
++#define ECHRNG 44 /* Channel number out of range */
++#define EL2NSYNC 45 /* Level 2 not synchronized */
++#define EL3HLT 46 /* Level 3 halted */
++#define EL3RST 47 /* Level 3 reset */
++#define ELNRNG 48 /* Link number out of range */
++#define EUNATCH 49 /* Protocol driver not attached */
++#define ENOCSI 50 /* No CSI structure available */
++#define EL2HLT 51 /* Level 2 halted */
++#define EBADE 52 /* Invalid exchange */
++#define EBADR 53 /* Invalid request descriptor */
++#define EXFULL 54 /* Exchange full */
++#define ENOANO 55 /* No anode */
++#define EBADRQC 56 /* Invalid request code */
++#define EBADSLT 57 /* Invalid slot */
++
++#define EDEADLOCK EDEADLK
++
++#define EBFONT 59 /* Bad font file format */
++#define ENOSTR 60 /* Device not a stream */
++#define ENODATA 61 /* No data available */
++#define ETIME 62 /* Timer expired */
++#define ENOSR 63 /* Out of streams resources */
++#define ENONET 64 /* Machine is not on the network */
++#define ENOPKG 65 /* Package not installed */
++#define EREMOTE 66 /* Object is remote */
++#define ENOLINK 67 /* Link has been severed */
++#define EADV 68 /* Advertise error */
++#define ESRMNT 69 /* Srmount error */
++#define ECOMM 70 /* Communication error on send */
++#define EPROTO 71 /* Protocol error */
++#define EMULTIHOP 72 /* Multihop attempted */
++#define EDOTDOT 73 /* RFS specific error */
++#define EBADMSG 74 /* Not a data message */
++#define EOVERFLOW 75 /* Value too large for defined data type */
++#define ENOTUNIQ 76 /* Name not unique on network */
++#define EBADFD 77 /* File descriptor in bad state */
++#define EREMCHG 78 /* Remote address changed */
++#define ELIBACC 79 /* Can not access a needed shared library */
++#define ELIBBAD 80 /* Accessing a corrupted shared library */
++#define ELIBSCN 81 /* .lib section in a.out corrupted */
++#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
++#define ELIBEXEC 83 /* Cannot exec a shared library directly */
++#define EILSEQ 84 /* Illegal byte sequence */
++#define ERESTART 85 /* Interrupted system call should be restarted */
++#define ESTRPIPE 86 /* Streams pipe error */
++#define EUSERS 87 /* Too many users */
++#define ENOTSOCK 88 /* Socket operation on non-socket */
++#define EDESTADDRREQ 89 /* Destination address required */
++#define EMSGSIZE 90 /* Message too long */
++#define EPROTOTYPE 91 /* Protocol wrong type for socket */
++#define ENOPROTOOPT 92 /* Protocol not available */
++#define EPROTONOSUPPORT 93 /* Protocol not supported */
++#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
++#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
++#define EPFNOSUPPORT 96 /* Protocol family not supported */
++#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
++#define EADDRINUSE 98 /* Address already in use */
++#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
++#define ENETDOWN 100 /* Network is down */
++#define ENETUNREACH 101 /* Network is unreachable */
++#define ENETRESET 102 /* Network dropped connection because of reset */
++#define ECONNABORTED 103 /* Software caused connection abort */
++#define ECONNRESET 104 /* Connection reset by peer */
++#define ENOBUFS 105 /* No buffer space available */
++#define EISCONN 106 /* Transport endpoint is already connected */
++#define ENOTCONN 107 /* Transport endpoint is not connected */
++#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
++#define ETOOMANYREFS 109 /* Too many references: cannot splice */
++#define ETIMEDOUT 110 /* Connection timed out */
++#define ECONNREFUSED 111 /* Connection refused */
++#define EHOSTDOWN 112 /* Host is down */
++#define EHOSTUNREACH 113 /* No route to host */
++#define EALREADY 114 /* Operation already in progress */
++#define EINPROGRESS 115 /* Operation now in progress */
++#define ESTALE 116 /* Stale file handle */
++#define EUCLEAN 117 /* Structure needs cleaning */
++#define ENOTNAM 118 /* Not a XENIX named type file */
++#define ENAVAIL 119 /* No XENIX semaphores available */
++#define EISNAM 120 /* Is a named type file */
++#define EREMOTEIO 121 /* Remote I/O error */
++#define EDQUOT 122 /* Quota exceeded */
++
++#define ENOMEDIUM 123 /* No medium found */
++#define EMEDIUMTYPE 124 /* Wrong medium type */
++#define ECANCELED 125 /* Operation Canceled */
++#define ENOKEY 126 /* Required key not available */
++#define EKEYEXPIRED 127 /* Key has expired */
++#define EKEYREVOKED 128 /* Key has been revoked */
++#define EKEYREJECTED 129 /* Key was rejected by service */
++
++/* for robust mutexes */
++#define EOWNERDEAD 130 /* Owner died */
++#define ENOTRECOVERABLE 131 /* State not recoverable */
++
++#define ERFKILL 132 /* Operation not possible due to RF-kill */
++
++#define EHWPOISON 133 /* Memory page has hardware error */
++
++#endif
+diff --git a/lib/freebl/leancrypto/ext_headers.h b/lib/freebl/leancrypto/ext_headers.h
+new file mode 100644
+--- /dev/null
++++ b/lib/freebl/leancrypto/ext_headers.h
+@@ -0,0 +1,463 @@
++/*
++ * Copyright (C) 2022 - 2025, Stephan Mueller
++ *
++ * License: see LICENSE file in root directory
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
++ * DAMAGE.
++ */
++
++#ifndef EXT_HEADERS_H
++#define EXT_HEADERS_H
++
++/******************************************************************************
++ * Generic Definitions
++ ******************************************************************************/
++#ifdef _WIN32
++#define LC_PURE
++#else
++#define LC_PURE __attribute__((pure))
++#endif
++
++/**
++ * @brief Return the size of a member variable of a data structure
++ *
++ * @param [in] struct data structure containing the member variable
++ * @param [in] member member variable name whose size shall be obtained
++ *
++ * @return size of the variable
++ */
++#define lc_member_size(struct, member) (sizeof(((struct *)0)->member))
++
++#ifdef LINUX_KERNEL
++/******************************************************************************
++ * Linux Kernel
++ ******************************************************************************/
++
++#include
++#include
++#include
++#include
++
++/* POSIX Support */
++unsigned long getauxval(unsigned long type);
++
++static inline int
++mlock(const void *ptr, size_t len)
++{
++ (void)ptr;
++ (void)len;
++ return 0;
++}
++
++extern const int errno;
++
++static inline pid_t
++getpid(void)
++{
++ return 0;
++}
++
++#define restrict
++
++#define printf printk
++
++#ifndef assert
++#define assert(x) WARN_ON(!(x))
++#endif
++
++#define PRIu64 "lu"
++
++#define LC_DEFINE_CONSTRUCTOR(_func) void _func(void)
++#define LC_DEFINE_DESTRUCTOR(_func) void _func(void)
++
++#define SYSV_ABI
++
++typedef s64 time64_t;
++
++static inline int
++lc_get_time(time64_t *time_since_epoch)
++{
++ if (!time_since_epoch)
++ return -EINVAL;
++
++ *time_since_epoch = (time64_t)(jiffies / HZ);
++
++ return 0;
++}
++
++#define LC_FIPS_RODATA_SECTION
++
++#elif (defined(LC_EFI_ENVIRONMENT))
++/******************************************************************************
++ * UEFI support
++ ******************************************************************************/
++
++/* POSIX Support */
++#include
++#include
++
++#include "errno_private.h"
++
++#define LC_DEFINE_CONSTRUCTOR(_func) \
++ void __attribute__((constructor)) _func(void)
++#define LC_DEFINE_DESTRUCTOR(_func) void __attribute__((destructor)) _func(void)
++
++#if !defined __ILP32__
++#define __WORDSIZE 64
++#else
++#define __WORDSIZE 32
++#endif
++
++typedef int pid_t;
++typedef long time_t;
++typedef long long time64_t;
++
++#ifndef offsetof
++#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
++#endif
++
++#if __WORDSIZE == 64
++
++typedef unsigned long uintptr_t;
++
++#ifndef _SIZE_T
++typedef unsigned long size_t;
++#define _SIZE_T
++#endif
++
++#ifndef _SSIZE_T
++typedef long ssize_t;
++#define _SSIZE_T
++#endif
++
++#elif __WORDSIZE == 32
++
++#ifndef _UINTPTR_T
++typedef unsigned int uintptr_t;
++#define _UINTPTR_T
++#endif
++
++#error
++#ifndef _SIZE_T
++typedef unsigned int size_t;
++#define _SIZE_T
++#endif
++
++#ifndef _SSIZE_T
++typedef int ssize_t;
++#define _SSIZE_T
++#endif
++
++#endif
++
++#include "lc_memcpy_secure.h"
++
++void *memset(void *d, int c, unsigned long long n);
++
++static inline int
++mlock(const void *ptr, size_t len)
++{
++ (void)ptr;
++ (void)len;
++ return 0;
++}
++
++static inline pid_t
++getpid(void)
++{
++ return 0;
++}
++
++static inline int
++snprintf(char *restrict str, size_t size,
++ const char *restrict format, ...)
++{
++ (void)format;
++ if (size) {
++ memset(str, 0, size);
++ return (int)size - 1;
++ }
++ return 0;
++}
++
++static inline void *
++memcpy(void *d, const void *s, size_t n)
++{
++ return lc_memcpy_secure(d, n, s, n);
++}
++
++static inline size_t
++strlen(const char *str)
++{
++ size_t len = 0;
++
++ while (*str != '\0') {
++ str++;
++ len++;
++ }
++
++ return len;
++}
++
++static inline int
++lc_get_time(time64_t *time_since_epoch)
++{
++ if (!time_since_epoch)
++ return -EINVAL;
++
++ *time_since_epoch = -1;
++
++ return -EOPNOTSUPP;
++}
++
++#define SYSV_ABI __attribute__((sysv_abi))
++
++/*
++ * See https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html#Statement-Attributes
++ */
++#if __has_attribute(__fallthrough__)
++#define fallthrough __attribute__((__fallthrough__))
++#else
++#define fallthrough \
++ do { \
++ } while (0)
++#endif
++
++#ifndef assert
++#define assert(x) \
++ if (x) { \
++ Exit(EFI_ABORTED, 0, NULL); \
++ }
++#endif
++
++#ifndef INT_MAX
++#define INT_MAX 2147483647
++#endif
++
++#define stdout NULL
++
++#define printf(...) Print(L##__VA_ARGS__)
++
++#undef errno
++#define errno errno_private
++static const int errno_private = 0;
++
++#define LC_FIPS_RODATA_SECTION
++
++#define noinline __attribute__((__noinline__))
++
++#elif (defined(__CYGWIN__) || defined(_WIN32))
++/******************************************************************************
++ * Windows
++ ******************************************************************************/
++
++#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
++
++#define LC_DEFINE_CONSTRUCTOR(_func) \
++ void __attribute__((constructor)) _func(void)
++#define LC_DEFINE_DESTRUCTOR(_func) void __attribute__((destructor)) _func(void)
++
++#else
++
++/* not used in our case */
++#define LC_DEFINE_CONSTRUCTOR(_func) void _func(void)
++#define LC_DEFINE_DESTRUCTOR(_func) void _func(void)
++
++#endif
++
++/*
++ * Replace GCC-specific alternative keywords
++ * see https://gcc.gnu.org/onlinedocs/gcc/Alternate-Keywords.html
++ */
++#ifndef __GNUC__
++#define __asm__ asm
++#define __volatile__ volatile
++#endif
++
++#ifndef _POSIX_C_SOURCE
++#define _POSIX_C_SOURCE 200112L
++#endif
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include