// Generated by tool/gen/fn/generate.py; do not edit.
// schema_sha256=787c413dea5e27098bec8d4778942ded65ed94c4cfffda39e20fac88581b05f1
// FIPS 204 hash selector/OID/extent authority: cryptography_pqc.json.
// No OA C++ HashML-DSA composition donor exists. Reuses checked digest formulas.
// Private public-data composition; not Engine or secret-operation admission.
import mldsa_prehash_layout;
import sha2_u32;
import sha2_u32_pair;
import sha3;
import shake;
import shake_prehash;
// Packed little-endian digest words; leave the unused tail and rejected output
// untouched. Selector 11/12 fixes SHAKE output to 32/64 bytes per FIPS 204.
bool mldsa_prehash_digest(
RWByteAddressBuffer messages,
uint base,
uint length,
uint algorithm,
inout uint digest[16]
) {
if (mldsa_prehash_bytes(algorithm) == 0u || !pqc_buffer_range(messages, base, length)) return false;
switch (algorithm) {
case 1u: {
uint words[8];
if (!sha2_u32_digest(messages, base, length, 256u, words)) return false;
for (uint i = 0u; i < 8u; ++i) digest[i] = words[i];
break;
}
case 2u: {
return sha2_u32_pair_digest(messages, base, length, 384u, digest);
}
case 3u: {
return sha2_u32_pair_digest(messages, base, length, 512u, digest);
}
case 4u: {
uint words[8];
if (!sha2_u32_digest(messages, base, length, 224u, words)) return false;
for (uint i = 0u; i < 7u; ++i) digest[i] = words[i];
break;
}
case 5u: {
return sha2_u32_pair_digest(messages, base, length, 224u, digest);
}
case 6u: {
return sha2_u32_pair_digest(messages, base, length, 256u, digest);
}
case 7u: {
uint2 state[25];
for (uint i = 0u; i < 25u; ++i) state[i] = uint2(0u, 0u);
if (!sha3_absorb(state, messages, base, length, SHA3_224_RATE_BYTES)) return false;
for (uint i = 0u; i < 7u; ++i) digest[i] = (i & 1u) == 0u ? state[i / 2u].x : state[i / 2u].y;
break;
}
case 8u: {
uint2 state[25];
for (uint i = 0u; i < 25u; ++i) state[i] = uint2(0u, 0u);
if (!sha3_absorb(state, messages, base, length, SHA3_256_RATE_BYTES)) return false;
for (uint i = 0u; i < 8u; ++i) digest[i] = (i & 1u) == 0u ? state[i / 2u].x : state[i / 2u].y;
break;
}
case 9u: {
uint2 state[25];
for (uint i = 0u; i < 25u; ++i) state[i] = uint2(0u, 0u);
if (!sha3_absorb(state, messages, base, length, SHA3_384_RATE_BYTES)) return false;
for (uint i = 0u; i < 12u; ++i) digest[i] = (i & 1u) == 0u ? state[i / 2u].x : state[i / 2u].y;
break;
}
case 10u: {
uint2 state[25];
for (uint i = 0u; i < 25u; ++i) state[i] = uint2(0u, 0u);
if (!sha3_absorb(state, messages, base, length, SHA3_512_RATE_BYTES)) return false;
for (uint i = 0u; i < 16u; ++i) digest[i] = (i & 1u) == 0u ? state[i / 2u].x : state[i / 2u].y;
break;
}
case 11u: {
return pqc_shake_prehash(messages, base, length, 128u, digest);
}
case 12u: {
return pqc_shake_prehash(messages, base, length, 256u, digest);
}
default: return false;
}
return true;
}
// Compute mu = SHAKE256(tr || 1 || ctx_len || ctx || OID || PH(M), 64).
// Digest stays local: no intermediate storage allocation or host observation.
// All ranges are checked before hashing. Rejected output remains untouched.
bool mldsa_prehash_mu(
RWByteAddressBuffer messages,
uint message_base,
uint message_length,
RWByteAddressBuffer tr,
uint tr_base,
RWByteAddressBuffer contexts,
uint context_base,
uint context_length,
uint algorithm,
inout uint mu[16]
) {
uint digest_length = mldsa_prehash_bytes(algorithm);
if (digest_length == 0u || context_length > 255u
|| !pqc_buffer_range(tr, tr_base, 64u)
|| !pqc_buffer_range(contexts, context_base, context_length)) return false;
uint digest[16];
if (!mldsa_prehash_digest(messages, message_base, message_length, algorithm, digest)) return false;
PqcShake256 sponge;
pqc_shake256_init(sponge);
pqc_shake256_absorb_buffer(sponge, tr, tr_base, 64u);
mldsa_absorb_prehash_header(sponge, contexts, context_base, context_length, algorithm);
for (uint i = 0u; i < digest_length; ++i)
pqc_shake256_absorb_byte(sponge, digest[i / 4u] >> ((i & 3u) * 8u));
pqc_shake256_finalize(sponge);
for (uint word = 0u; word < 16u; ++word) {
uint value = 0u;
for (uint byte = 0u; byte < 4u; ++byte)
value |= pqc_shake256_squeeze_byte(sponge) << (byte * 8u);
mu[word] = value;
}
return true;
}