The Keccak chiplet proves the Keccak-f[1600] permutation: for every call, the output state is Keccak-f[1600] of the
input state. Host helpers run SHA3-256, SHA3-512, SHAKE128 and SHAKE256 as sponges over the permutation and return the
calls to prove. The ML-DSA and ML-KEM chiplets hash through it.
Each call permutes the 1600-bit state, 25 lanes of 64 bits. The host trace holds call k's input lanes on row 25k and
its output lanes on row 25k + 24, and the chiplet proves every output is Keccak-f[1600] of its input.
The state is virtually packed: 25 physical 64-bit columns hold the 1600 state bits, which expand into bits in
registers during constraint evaluation. A layout with one column per bit would need 1600 columns.
The permutation is the whole statement. A SHA-3 digest says something about a message only when the host program
chains the calls: each call's input is the previous output with the next message block XORed into its rate lanes, and
the digest is read from the last output. sha3_256, sha3_512, shake128 and shake256 compute the digest and
return the calls in that order; the constraints that tie the calls together belong to the host program.
Sponge chaining and padding, which the host program constrains.
Other Keccak-based functions. There are no named helpers for SHA3-224, SHA3-384, Keccak-256 (the
pre-standard padding Ethereum uses), cSHAKE or KMAC. A host program that builds their sponge, with
KeccakSpongeNative or its own code, can still prove the permutation calls.
hekate/examples/keccak.rs mounts the permutation in the CPU trace and publishes the digest as the first
4 lanes of the final state. From a hekate checkout:
bash
HEKATE_NUM_VARS=20just example keccak public
HEKATE_NUM_VARS sets the trace to 2^n rows. public builds the variable-time table-math prover that the README's
measurements use. Without it the recipe builds the constant-time prover, the one to use when the witness is private.
The program below turns the example into a full SHA3-256 statement: the prover knows a 200-byte message whose SHA3-256
digest is the published value. It takes three files:
src/program.rs mounts the chiplet and adds the constraints that bind the digest to a message. The first call's
capacity lanes start at zero. The second call's input is the first call's output with the second block XORed into
the rate: lanes 0 to 7 carry the last 64 message bytes and stay free, lanes 8 to 16 carry the padding (0x06 in
lane 8, 0x80 in the top byte of lane 16), and the capacity lanes pass through unchanged. The digest is published
from the last output.
src/trace.rs writes each call's input and output into the host table and appends the chiplet's columns.
src/main.rs hashes a random message with sha3_256, which returns the digest and both calls, then proves and
verifies.
Start from the crates in Installation and add hekate-keccak and rand.
The message stays in the witness. The padding pins fit the 200 bytes in MESSAGE_LEN, and another length fails
preflight until its pins change. Your First ZK Program binds
single-block messages the same way.
Zero-knowledge proofs, measured on Apple M3 Max, 16 cores. Build: --release, std parallel blake3 table-math public. Best of three on an otherwise idle machine. The Benchmarks page has the base-protocol figures and the command for each run.
hekate-keccak is AGPL-3.0-only. Commercial licenses are available from Oumuamua Labs at
info@oumuamua.dev. The README's Usage section builds the permutation calls of one
SHA3-256 hash, and the API reference is on docs.rs.