oarust 0.8.6

GPU-first semantic computing engine written in Rust
// Streaming public-data SHAKE-256, FIPS 202. Reuses OA's proven permutation.
// Adaptation: new composition helper; historical PQC absorb code lost position.
// Caller preflights buffer ranges and provides final-word padding. No secret
// execution or constant-time claim is attached to this helper.
import keccak;

struct PqcShake256 {
	uint2 state[25];
	uint position;
};

void pqc_shake256_init(out PqcShake256 sponge) {
	for (uint i = 0u; i < 25u; ++i) sponge.state[i] = uint2(0u, 0u);
	sponge.position = 0u;
}

void pqc_shake256_absorb_byte(inout PqcShake256 sponge, uint value) {
	uint lane = sponge.position / 8u;
	uint shift = (sponge.position % 4u) * 8u;
	if ((sponge.position % 8u) < 4u) sponge.state[lane].x ^= (value & 255u) << shift;
	else sponge.state[lane].y ^= (value & 255u) << shift;
	++sponge.position;
	if (sponge.position == 136u) {
		keccak_f1600_u32(sponge.state);
		sponge.position = 0u;
	}
}

void pqc_shake256_absorb_buffer(
	inout PqcShake256 sponge, RWByteAddressBuffer buffer, uint base, uint length
) {
	for (uint i = 0u; i < length; ++i) {
		uint address = base + i;
		uint value = buffer.Load(address & ~3u) >> ((address & 3u) * 8u);
		pqc_shake256_absorb_byte(sponge, value);
	}
}

void pqc_shake256_absorb_digest(inout PqcShake256 sponge, uint2 digest[8]) {
	for (uint i = 0u; i < 64u; ++i) {
		uint word = ((i % 8u) < 4u) ? digest[i / 8u].x : digest[i / 8u].y;
		pqc_shake256_absorb_byte(sponge, word >> ((i % 4u) * 8u));
	}
}

// Switch from absorption to squeezing once; do not absorb after this boundary.
void pqc_shake256_finalize(inout PqcShake256 sponge) {
	uint lane = sponge.position / 8u;
	uint shift = (sponge.position % 4u) * 8u;
	if ((sponge.position % 8u) < 4u) sponge.state[lane].x ^= 31u << shift;
	else sponge.state[lane].y ^= 31u << shift;
	sponge.state[16].y ^= 0x80000000u;
	keccak_f1600_u32(sponge.state);
	sponge.position = 0u;
}

// Sequential output has no fixed length or silently truncating block limit.
uint pqc_shake256_squeeze_byte(inout PqcShake256 sponge) {
	if (sponge.position == 136u) {
		keccak_f1600_u32(sponge.state);
		sponge.position = 0u;
	}
	uint position = sponge.position++;
	uint word = position % 8u < 4u ? sponge.state[position / 8u].x
		: sponge.state[position / 8u].y;
	return (word >> ((position % 4u) * 8u)) & 255u;
}

// Existing fixed-digest interface, destructive finalization exactly once.
void pqc_shake256_finish(inout PqcShake256 sponge, out uint2 digest[8]) {
	pqc_shake256_finalize(sponge);
	for (uint i = 0u; i < 8u; ++i) digest[i] = sponge.state[i];
	sponge.position = 64u;
}

// Subtraction-based checks avoid overflow before any byte-addressed access.
// Physical buffers must include their complete final word, even for odd tails.
bool pqc_buffer_range(RWByteAddressBuffer buffer, uint base, uint length) {
	uint size;
	buffer.GetDimensions(size);
	if ((size & 3u) != 0u) return false;
	return base <= size && length <= size - base;
}