diff --git a/ALGORITHMS.md b/ALGORITHMS.md
index 61669e524c..9efbda7c04 100644
--- a/ALGORITHMS.md
+++ b/ALGORITHMS.md
@@ -46,7 +46,7 @@ The **OQS tier** column records OQS's own support commitment for each algorithm.
| MAYO | Under [NIST](https://csrc.nist.gov/Projects/pqc-dig-sig/round-3-additional-signatures) consideration | [`PQCMayo/MAYO-C@74de637`](https://github.com/PQCMayo/MAYO-C/commit/74de637a7c4a7f9fafa888183bc05f5cf920cd2d) | [Actively maintained](https://github.com/PQCMayo/MAYO-C) | Tier 3 (Community) | 1, 3, 5 | ✓ | — | portable, ARM64_V8, x86_64 (avx2) |
| ML-DSA | Standardized by [NIST](https://csrc.nist.gov/pubs/fips/204/final) | [`pq-code-package/mldsa-native@834a90d`](https://github.com/pq-code-package/mldsa-native/commit/834a90d5e846ffa1e1611bd24e160bb2e9b86d35) | [Actively maintained](https://github.com/pq-code-package/mldsa-native) | Tier 2 (Supported) | 2, 3, 5 | ✓ | — | portable, ARM64_V8, x86_64 (avx2+bmi2+popcnt) |
| MQOM | Under [NIST](https://csrc.nist.gov/projects/pqc-dig-sig) consideration | [`mqom/mqom-v3@df26239`](https://github.com/mqom/mqom-v3/commit/df26239dd22f194371003f403ec1a9920772b769) | [Actively maintained](https://github.com/mqom/mqom-v3/blob/main/integration/liboqs/SUPPORT.md) | Tier 3 (Community) | 1, 3, 5 | ✓ | — | portable, ARM64_V8 (sha3), x86_64 (aes+avx2) |
-| SLH-DSA | Standardized by [NIST](https://csrc.nist.gov/pubs/fips/205/final) | [`pq-code-package/slhdsa-c@a0fc1ff`](https://github.com/pq-code-package/slhdsa-c/commit/a0fc1ff253930060d0246aebca06c2538eb92b88) | Best effort | Tier 3 (Community) | 1, 3, 5 | — | — | portable |
+| SLH-DSA | Standardized by [NIST](https://csrc.nist.gov/pubs/fips/205/final) | [`pq-code-package/slhdsa-c@d25ccc6`](https://github.com/pq-code-package/slhdsa-c/commit/d25ccc6a2c6512dd44cfaf81e44181a3010757b1) | Best effort | Tier 3 (Community) | 1, 3, 5 | — | — | portable |
| SNOVA | Under [NIST](https://csrc.nist.gov/csrc/media/Projects/pqc-dig-sig/documents/round-3/spec-files/snova-spec-round3-web.pdf) consideration | [`PQCLAB-SNOVA/S@9b29c1e`](https://github.com/PQCLAB-SNOVA/S/commit/9b29c1e332cbd85757c8d6362a57b9a8c8298a38) | Best effort | Tier 3 (Community) | 1, 3, 5 | ✓ | — | portable, ARM64_V8, x86_64 (avx2) |
| UOV | Under [NIST](https://csrc.nist.gov/Projects/pqc-dig-sig/round-3-additional-signatures) consideration | [`pqov/pqov@fac2ec1`](https://github.com/pqov/pqov/commit/fac2ec1fe6d8ea508eab4b98eb5341e1eed930a4) | Best effort | Tier 3 (Community) | 1, 3, 5 | ✓ | — | portable, ARM64_V8, x86_64 (avx2) |
diff --git a/README.md b/README.md
index 6fbb527344..4b716fc645 100644
--- a/README.md
+++ b/README.md
@@ -69,7 +69,7 @@ Names of algorithms standardized by NIST — [`ML-KEM`](https://csrc.nist.gov/pu
| MAYO | Under [NIST](https://csrc.nist.gov/Projects/pqc-dig-sig/round-3-additional-signatures) consideration | [`PQCMayo/MAYO-C@74de637`](https://github.com/PQCMayo/MAYO-C/commit/74de637a7c4a7f9fafa888183bc05f5cf920cd2d) | [Actively maintained](https://github.com/PQCMayo/MAYO-C) | Tier 3 (Community) |
| ML-DSA | Standardized by [NIST](https://csrc.nist.gov/pubs/fips/204/final) | [`pq-code-package/mldsa-native@834a90d`](https://github.com/pq-code-package/mldsa-native/commit/834a90d5e846ffa1e1611bd24e160bb2e9b86d35) | [Actively maintained](https://github.com/pq-code-package/mldsa-native) | Tier 2 (Supported) |
| MQOM | Under [NIST](https://csrc.nist.gov/projects/pqc-dig-sig) consideration | [`mqom/mqom-v3@df26239`](https://github.com/mqom/mqom-v3/commit/df26239dd22f194371003f403ec1a9920772b769) | [Actively maintained](https://github.com/mqom/mqom-v3/blob/main/integration/liboqs/SUPPORT.md) | Tier 3 (Community) |
-| SLH-DSA | Standardized by [NIST](https://csrc.nist.gov/pubs/fips/205/final) | [`pq-code-package/slhdsa-c@a0fc1ff`](https://github.com/pq-code-package/slhdsa-c/commit/a0fc1ff253930060d0246aebca06c2538eb92b88) | Best effort | Tier 3 (Community) |
+| SLH-DSA | Standardized by [NIST](https://csrc.nist.gov/pubs/fips/205/final) | [`pq-code-package/slhdsa-c@d25ccc6`](https://github.com/pq-code-package/slhdsa-c/commit/d25ccc6a2c6512dd44cfaf81e44181a3010757b1) | Best effort | Tier 3 (Community) |
| SNOVA | Under [NIST](https://csrc.nist.gov/csrc/media/Projects/pqc-dig-sig/documents/round-3/spec-files/snova-spec-round3-web.pdf) consideration | [`PQCLAB-SNOVA/S@9b29c1e`](https://github.com/PQCLAB-SNOVA/S/commit/9b29c1e332cbd85757c8d6362a57b9a8c8298a38) | Best effort | Tier 3 (Community) |
| UOV | Under [NIST](https://csrc.nist.gov/Projects/pqc-dig-sig/round-3-additional-signatures) consideration | [`pqov/pqov@fac2ec1`](https://github.com/pqov/pqov/commit/fac2ec1fe6d8ea508eab4b98eb5341e1eed930a4) | Best effort | Tier 3 (Community) |
diff --git a/docs/algorithms/sig/slh_dsa.md b/docs/algorithms/sig/slh_dsa.md
index 2b323f281d..ae99fa39b1 100644
--- a/docs/algorithms/sig/slh_dsa.md
+++ b/docs/algorithms/sig/slh_dsa.md
@@ -7,11 +7,11 @@
- **Authors' website**: https://csrc.nist.gov/pubs/fips/205/final
- **Specification version**: SLH-DSA.
- **Primary Source**:
- - **Source**: https://github.com/pq-code-package/slhdsa-c/commit/a0fc1ff253930060d0246aebca06c2538eb92b88
+ - **Source**: https://github.com/pq-code-package/slhdsa-c/commit/d25ccc6a2c6512dd44cfaf81e44181a3010757b1
- **Implementation license (SPDX-Identifier)**: MIT or ISC or Apache 2.0
- **Optimized Implementation sources**:
- **slhdsa-c**:
- - **Source**: https://github.com/pq-code-package/slhdsa-c/commit/a0fc1ff253930060d0246aebca06c2538eb92b88
+ - **Source**: https://github.com/pq-code-package/slhdsa-c/commit/d25ccc6a2c6512dd44cfaf81e44181a3010757b1
- **Implementation license (SPDX-Identifier)**: MIT or ISC or Apache 2.0
diff --git a/docs/algorithms/sig/slh_dsa.yml b/docs/algorithms/sig/slh_dsa.yml
index 904121c073..58b1df78bd 100644
--- a/docs/algorithms/sig/slh_dsa.yml
+++ b/docs/algorithms/sig/slh_dsa.yml
@@ -32,7 +32,7 @@ oqs-support-tier: 3
spec-version: SLH-DSA
spdx-license-identifier: MIT or ISC or Apache 2.0
primary-upstream:
- source: https://github.com/pq-code-package/slhdsa-c/commit/a0fc1ff253930060d0246aebca06c2538eb92b88
+ source: https://github.com/pq-code-package/slhdsa-c/commit/d25ccc6a2c6512dd44cfaf81e44181a3010757b1
spdx-license-identifier: MIT or ISC or Apache 2.0
upstream-ancestors:
- https://github.com/pq-code-package/slhdsa-c
diff --git a/scripts/copy_from_upstream/copy_from_slh_dsa_c.py b/scripts/copy_from_upstream/copy_from_slh_dsa_c.py
index d332802747..2eaa83c6ef 100644
--- a/scripts/copy_from_upstream/copy_from_slh_dsa_c.py
+++ b/scripts/copy_from_upstream/copy_from_slh_dsa_c.py
@@ -250,7 +250,7 @@ def main():
alg_support_path, oqsconfig_path
# This commit hash will need to be updated
- commit_hash = "a0fc1ff253930060d0246aebca06c2538eb92b88"
+ commit_hash = "d25ccc6a2c6512dd44cfaf81e44181a3010757b1"
# internal paths
slh_dir = os.path.join(os.environ['LIBOQS_DIR'], 'src/sig/slh_dsa')
diff --git a/src/sig/slh_dsa/slh_dsa_c/cbmc.h b/src/sig/slh_dsa/slh_dsa_c/cbmc.h
index 452390f6ce..83046fca70 100644
--- a/src/sig/slh_dsa/slh_dsa_c/cbmc.h
+++ b/src/sig/slh_dsa/slh_dsa_c/cbmc.h
@@ -138,6 +138,10 @@
#define array_abs_bound(arr, lb, ub, k) \
array_bound((arr), (lb), (ub), -((int)(k)) + 1, (k))
+#define VALID_SLH_VAR_T(var) \
+ (memory_no_alias(var, sizeof(slh_var_t)) && memory_no_alias(var->prm, sizeof(slh_param_t)) && \
+ memory_no_alias(var->adrs, sizeof(adrs_t)))
+
#endif /* CBMC */
#endif /* !SLH_CBMC_H */
diff --git a/src/sig/slh_dsa/slh_dsa_c/sha2_256.c b/src/sig/slh_dsa/slh_dsa_c/sha2_256.c
index 1102f0e472..c4bc36b7a0 100644
--- a/src/sig/slh_dsa/slh_dsa_c/sha2_256.c
+++ b/src/sig/slh_dsa/slh_dsa_c/sha2_256.c
@@ -142,7 +142,12 @@ void sha2_256_compress(void *v)
/* initialize */
-static void sha2_256_init_h0(sha2_256_t *sha, const uint8_t *h0)
+static void sha2_256_init_h0(sha2_256_t *sha, const uint8_t h0[32])
+__contract__(
+ requires(memory_no_alias(sha, sizeof(sha2_256_t)))
+ requires(memory_no_alias(h0, 32))
+ assigns(object_whole(sha))
+)
{
memcpy(sha->s, h0, 32);
sha->i = 0;
diff --git a/src/sig/slh_dsa/slh_dsa_c/sha3_api.c b/src/sig/slh_dsa/slh_dsa_c/sha3_api.c
index e756fb3460..22d7d9e62a 100644
--- a/src/sig/slh_dsa/slh_dsa_c/sha3_api.c
+++ b/src/sig/slh_dsa/slh_dsa_c/sha3_api.c
@@ -5,19 +5,17 @@
/* === FIPS 202: SHA-3 hash and SHAKE eXtensible Output Functions (XOF) */
+#include
#include "sha3_api.h"
+#include "cbmc.h"
/* These functions have not been optimized for performance. */
/* initialize the context for SHA3 */
void sha3_init(sha3_var_t *c, size_t md_sz)
{
- size_t i;
-
- for (i = 0; i < 25; i++)
- {
- c->st.d[i] = 0;
- }
+ memset(c->st.d, 0, 25*sizeof(uint64_t));
+
c->md_sz = md_sz; /* in SHAKE; if 0, padding done */
c->r_sz = 200 - 2 * md_sz;
c->pt = 0;
diff --git a/src/sig/slh_dsa/slh_dsa_c/sha3_api.h b/src/sig/slh_dsa/slh_dsa_c/sha3_api.h
index a47baa8179..6c1a4ec084 100644
--- a/src/sig/slh_dsa/slh_dsa_c/sha3_api.h
+++ b/src/sig/slh_dsa/slh_dsa_c/sha3_api.h
@@ -15,6 +15,7 @@ extern "C"
#include
#include
+#include "cbmc.h"
typedef struct
{ /* state context */
@@ -31,7 +32,13 @@ extern "C"
/* incremental interfece */
void sha3_init(sha3_var_t *c,
- size_t md_sz); /* md_sz = hash output in bytes */
+ size_t md_sz) /* md_sz = hash output in bytes */
+ __contract__(
+ requires(memory_no_alias(c, sizeof(sha3_var_t)))
+ requires(md_sz <= 64)
+ assigns(object_whole(c))
+ );
+
void sha3_update(sha3_var_t *c, const void *data, size_t data_sz);
void sha3_final(sha3_var_t *c, uint8_t *md); /* digest goes to md */
diff --git a/src/sig/slh_dsa/slh_dsa_c/slh_adrs.h b/src/sig/slh_dsa/slh_dsa_c/slh_adrs.h
index 8bd0ac86cb..2799934d09 100644
--- a/src/sig/slh_dsa/slh_dsa_c/slh_adrs.h
+++ b/src/sig/slh_dsa/slh_dsa_c/slh_adrs.h
@@ -126,6 +126,10 @@ static SLH_INLINE uint32_t adrs_get_tree_index(const slh_var_t *var)
/* === Set WOTS+ hash address. */
static SLH_INLINE void adrs_set_hash_address(slh_var_t *var, uint32_t x)
+__contract__(
+ requires(VALID_SLH_VAR_T(var))
+ assigns(var->adrs->u32[7])
+)
{
var->adrs->u32[7] = rev8_be32(x);
}
diff --git a/src/sig/slh_dsa/slh_dsa_c/slh_dsa.c b/src/sig/slh_dsa/slh_dsa_c/slh_dsa.c
index 07052e729a..afc446239e 100644
--- a/src/sig/slh_dsa/slh_dsa_c/slh_dsa.c
+++ b/src/sig/slh_dsa/slh_dsa_c/slh_dsa.c
@@ -688,6 +688,10 @@ OQS_API int slh_verify_internal(const uint8_t *m, size_t m_sz, const uint8_t *si
slh_var_t var;
uint8_t digest[SLH_MAX_M];
+ if (sig_sz != slh_sig_sz(prm))
+ {
+ return 0; /* false */
+ }
/* use Hmsg directly */
prm->mk_var(&var, pk, NULL, prm);
prm->h_msg(&var, digest, sig, m, m_sz, NULL, SLH_CTX_SZ_NO_CONTEXT);
@@ -710,6 +714,11 @@ int slh_verify(const uint8_t *m, size_t m_sz, const uint8_t *sig, size_t sig_sz,
return 0; /* false */
}
+ if (sig_sz != slh_sig_sz(prm))
+ {
+ return 0; /* false */
+ }
+
/* create the "pure" hash (with context) */
prm->mk_var(&var, pk, NULL, prm);
prm->h_msg(&var, digest, sig, m, m_sz, ctx, ctx_sz);
diff --git a/tests/test_sig.c b/tests/test_sig.c
index 67c9f098fc..06971f628d 100644
--- a/tests/test_sig.c
+++ b/tests/test_sig.c
@@ -123,6 +123,24 @@ static OQS_STATUS sig_test_correctness(const char *method_name, bool bitflips_al
goto err;
}
+ /* A signature shorter than the SLH-DSA parameter set's n-byte randomizer must
+ be rejected before Hmsg reads it; verifying against a 1-byte buffer used to
+ read out of bounds in the slh_dsa verify path. */
+ if (!strncmp(sig->method_name, "SLH_DSA", 7)) {
+ uint8_t *short_sig = OQS_MEM_malloc(1);
+ if (short_sig == NULL) {
+ fprintf(stderr, "ERROR: OQS_MEM_malloc failed\n");
+ goto err;
+ }
+ short_sig[0] = 0;
+ rc = OQS_SIG_verify(sig, message, message_len, short_sig, 1, public_key);
+ OQS_MEM_insecure_free(short_sig);
+ if (rc != OQS_ERROR) {
+ fprintf(stderr, "ERROR: OQS_SIG_verify accepted a truncated signature\n");
+ goto err;
+ }
+ }
+
if (extended_tests) {
rc = test_sig_bitflip(sig, message, message_len, signature, signature_len, public_key, bitflips_all, bitflips, false, NULL, 0);
OQS_TEST_CT_DECLASSIFY(&rc, sizeof(rc));