oarust 0.8.6

GPU-first semantic computing engine written in Rust
// 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;
}