// Generated by tool/gen/fn/generate.py; do not edit.
// schema_sha256=787c413dea5e27098bec8d4778942ded65ed94c4cfffda39e20fac88581b05f1
// Private FIPS 203 adapter; C++ oaPqc.md has no live donor.
// Serial correctness route; secret spills and physical timing remain unqualified.
import attributes;
import mlkem_kem;
struct PushConstants {
uint private_index;
uint ciphertext_index;
uint shared_index;
uint k;
};
[[vk::push_constant]] PushConstants push;
[[vk::binding(0, 0)]] RWByteAddressBuffer storage_buffers[];
[kernel_name("ml_kem_decaps")]
[domain("cryptography")]
[variant("generic")]
[dtype("u8")]
[status("experimental")]
[shader("compute")]
[numthreads(1, 1, 1)]
void main(uint3 tid : SV_DispatchThreadID) {
if (any(tid != uint3(0u, 0u, 0u)) || push.k < 2u || push.k > 4u) return;
uint el = 384u * push.k + 32u;
uint cl = 32u * (push.k == 4u ? 11u * push.k + 5u : 10u * push.k + 4u);
uint private_size, ciphertext_size, shared_size;
storage_buffers[push.private_index].GetDimensions(private_size);
storage_buffers[push.ciphertext_index].GetDimensions(ciphertext_size);
storage_buffers[push.shared_index].GetDimensions(shared_size);
if (private_size != 768u * push.k + 96u || ciphertext_size != cl || shared_size != 32u) return;
// Only internally generated retained keys are admitted by the private owner.
uint dk[3168], ciphertext[1568], key[32];
for (uint i = 0u; i < 3168u; ++i) dk[i] = 0u;
for (uint i = 0u; i < 1568u; ++i) ciphertext[i] = 0u;
for (uint i = 0u; i < private_size; ++i) {
uint word = storage_buffers[push.private_index].Load(i & ~3u);
dk[i] = (word >> (8u * (i & 3u))) & 255u;
}
for (uint i = 0u; i < cl; ++i) {
uint word = storage_buffers[push.ciphertext_index].Load(i & ~3u);
ciphertext[i] = (word >> (8u * (i & 3u))) & 255u;
}
mlkem_decaps_internal(dk, ciphertext, push.k, key);
for (uint i = 0u; i < 32u; i += 4u)
storage_buffers[push.shared_index].Store(i, key[i] | (key[i+1u] << 8u) | (key[i+2u] << 16u) | (key[i+3u] << 24u));
}