# Documentation

> Hekate documentation: install the Rust zero-knowledge proof engine, write a first program, then learn its tables, chiplets, LogUp buses and prover.

- URL: https://oumuamua.dev/hekate/docs
- Published: 2026-05-12T09:42:54+07:00
- Updated: 2026-10-19T17:29:39+07:00

Hekate documentation: install the Rust zero-knowledge proof engine, write a first program, then learn its tables, chiplets, LogUp buses and prover.

Hekate proves computations in GF(2^128) using Sumcheck + Brakedown PCS with O(N) prover time and O(N) memory.
100 proven bits of soundness.

## The Hekate Ecosystem

Hekate is not one crate. The prover is the engine; the math core, hardware chiplets, mobile toolchain, and fuzzer ship
separately, to compose as needed.

| Crate               | Role                                                                                                        |
|:--------------------|:------------------------------------------------------------------------------------------------------------|
| `hekate-math`       | Binary tower field arithmetic, constant-time, PMULL on aarch64. The mathematical core.                      |
| `hekate-crypto`     | Hash functions, Merkle trees and the Fiat-Shamir transcript. BLAKE3 by default, SHA-256 or SHA3-256 by feature. |
| `hekate-core`       | Configuration, execution traces and proof types: `Config`, `TraceBuilder` and `InnerProof`.                 |
| `hekate-program`    | The circuit DSL: columns, constraints, fixed columns, public inputs, chiplets, LogUp buses and program ids. |
| `hekate-sdk`        | Preflight diagnostics and the proof wire format. Preflight names what fails before you spend a proof.       |
| `hekate-verifier`   | The verifier, in pure Rust. Checks a program's constraints, pinned cells and bus relations over the committed tables. |
| `hekate-prover-sys` | Open FFI shim. Links the signed prover cdylib over a stable C ABI; the only crate that can call the prover. |
| `hekate-gadgets`    | Base AIR chiplets and atoms: 32- and 64-bit integer arithmetic, RAM, ROM and the bignum modexp the RSA chiplet builds on. |
| `hekate-keccak`     | Keccak-f[1600] chiplet plus SHA-3 / SHAKE, with virtual packing.                                            |
| `hekate-aes`        | AES-128 / AES-256 round-function chiplet (FIPS 197) with an S-box ROM.                                      |
| `hekate-sha2`       | SHA-256 round chiplet (FIPS 180-4). Bit-expanded B32 columns, degree 2, 1, 2, 4, 8 or 16 rounds per row.    |
| `hekate-rsa`        | RSA-2048 PKCS#1 v1.5 signature statements (RFC 8017) over the modexp and SHA-256 chiplets.                  |
| `hekate-pqc`        | ML-KEM KeyGen, Encaps and Decaps and ML-DSA verification (FIPS 203 / 204) over NTT, Sampler, Codec tables.  |
| `hekate-mobile`     | Wraps a Rust prover into a signed iOS `.xcframework` / Android `.aar` with a typed Swift / Kotlin API.      |
| `hekate-scribble`   | Trace-mutation fuzzer. Tampers a valid trace, panics if your constraints miss the tamper.                   |

## What It Does

**Binary tower field arithmetic**, GF(2^8) through GF(2^128), recursive tower extension, hardware-accelerated via
PMULL on aarch64. Constant-time by default.

**Chiplet architecture**, Independent AIR tables (Keccak, AES, RAM, NTT, ML-KEM, ML-DSA) with own traces under
one commitment. No column waste, no forced padding. Tables linked by LogUp bus.

**Virtual packing**, Keccak stores 1600 bits in 25 physical B64 columns instead of 1600 bit columns. Bits expand JIT in
registers.

**Linear-code commitments**, Brakedown PCS: O(N) prover, O(N) memory. MDS Reed-Solomon row code via additive
binary-field FFT, exact distance δ = 1 − rate. Merkle tree over encoded columns only (raw trace never hashed, true ZK).

**Post-quantum crypto suite**, ML-DSA (Dilithium) signature verification, ML-KEM (Kyber) key generation,
encapsulation and decapsulation, AES-128/256. AES and Keccak are native to binary fields; lattice arithmetic
mod q runs on bit-decomposed carry chains.

### Hardware Support

| Architecture | Status     | Instructions                          |
|:-------------|:-----------|:--------------------------------------|
| aarch64      | Production | PMULL, NEON                           |
| x86_64       | Fallback   | Software fallback (PCLMULQDQ roadmap) |
| WASM         | Planned    | Software multiply                     |

## Quick Example

Real 32-bit-integer Fibonacci. The CPU side holds five columns, the two Fibonacci transition
constraints and an opcode pin. Every `u32` ADD is offloaded to the `IntArithmeticChiplet`, its own trace and
own ZeroCheck under the shared commitment and evaluation argument, and is wired in by a LogUp bus
(`(val_a, val_b, val_res, opcode)` keys; the `t`-th request meets the `t`-th response by emit
rank). The result reaches the verdict through `publish`: a boundary pin to the public input on a
row whose schedule a fixed column forces, with the transition chain determined from the pinned
origins.

```rust
use hekate_core::errors;
use hekate_gadgets::IntArithmeticChiplet;
use hekate_math::{Block128, TowerField};
use hekate_program::FixedShape;
use hekate_program::chiplet::ChipletDef;
use hekate_program::circuit::{Circuit, CircuitProgram, Col};
use hekate_program::define_columns;

type F = Block128;

define_columns! {
    ProgColumns {
        VAL_A: B32,
        VAL_B: B32,
        VAL_RES: B32,
        OPCODE: B32,
        SELECTOR: Bit,
    }
}

fn build_program(num_rows: usize) -> errors::Result<CircuitProgram<F>> {
    let mut cx = Circuit::<F>::new("Fibonacci", num_rows)?;

    let cpu = cx.schema(&ProgColumns::build_layout());
    let selector = cpu.at(ProgColumns::SELECTOR);
    let a = cpu.at(ProgColumns::VAL_A);
    let b = cpu.at(ProgColumns::VAL_B);
    let res = cpu.at(ProgColumns::VAL_RES);
    let opcode = cpu.at(ProgColumns::OPCODE);

    let cs = cx.cs();
    let col = |c: Col| cs.col(c.index());
    let next = |c: Col| cs.next(c.index());

    cs.constrain(col(selector) * (next(a) + col(b))); // next(a) = b
    cs.constrain(col(selector) * (next(b) + col(res))); // next(b) = res = a + b
    cs.constrain(col(opcode)); // opcode = ADD

    cx.call(
        &IntArithmeticChiplet::service(),
        &[a, b, res, opcode],
        selector,
    )?;

    cx.attach(ChipletDef::from_air(&IntArithmeticChiplet::new(
        32,
        num_rows,
        num_rows - 1,
    )?)?);

    cx.fix(
        selector,
        FixedShape::Cadence {
            stride: 1,
            count: num_rows - 1,
            origin: 0,
            values: vec![F::ONE],
        },
    );

    cx.boundary(a, 0, F::ZERO);
    cx.boundary(b, 0, F::ONE);

    cx.publish(b, num_rows - 1);

    cx.compile()
}
```

Trace generation builds the CPU columns and the chiplet trace independently; they meet on the bus.

```rust
use hekate_core::trace::{ColumnTrace, TraceBuilder};
use hekate_gadgets::{
    ArithmeticOpcode, IntArithmeticLayout, IntArithmeticOp, generate_arithmetic_trace,
};
use hekate_math::{Bit, Block32};

fn generate_traces(num_rows: usize) -> errors::Result<(ColumnTrace, ColumnTrace, u32)> {
    let num_vars = num_rows.trailing_zeros() as usize;

    let mut tb = TraceBuilder::new(&ProgColumns::build_layout(), num_vars)?;
    let mut ops: Vec<IntArithmeticOp> = Vec::with_capacity(num_rows - 1);

    let mut a: u32 = 0;
    let mut b: u32 = 1;

    for i in 0..num_rows - 1 {
        let res = a.wrapping_add(b);

        tb.set_b32(ProgColumns::VAL_A, i, Block32::from(a))?;
        tb.set_b32(ProgColumns::VAL_B, i, Block32::from(b))?;
        tb.set_b32(ProgColumns::VAL_RES, i, Block32::from(res))?;
        tb.set_b32(ProgColumns::OPCODE, i, Block32::from(ArithmeticOpcode::ADD as u32))?;
        tb.set_bit(ProgColumns::SELECTOR, i, Bit::ONE)?;

        ops.push(IntArithmeticOp::U32 {
            op: ArithmeticOpcode::ADD,
            a,
            b,
        });

        a = b;
        b = res;
    }

    // Padding row:
    // selector = 0, val_b carries fib[N-1] for the boundary pin.
    tb.set_b32(ProgColumns::VAL_A, num_rows - 1, Block32::from(a))?;
    tb.set_b32(ProgColumns::VAL_B, num_rows - 1, Block32::from(b))?;

    let cpu_trace = tb.build();

    let arith_layout = IntArithmeticLayout::compute(32);
    let arith_trace = generate_arithmetic_trace(&ops, &arith_layout, num_rows)?;

    Ok((cpu_trace, arith_trace, b))
}
```

The chiplet computes the operation the opcode names, boolean-checks its own selectors and zero-pins
shadow columns when its row is idle. With `opcode` pinned to ADD, the LogUp bus guarantees
`res = a + b` for every row where `selector = 1`.

Wire up the program, instance, and witness, then prove with `hekate-prover-sys` and verify with
`hekate-verifier`. The transcript label and `Config` must match across both sides, the driver builds
one `config` and reuses it. `verify` returns `true` only if every Sumcheck round, the LogUp bus sums,
and the evaluation openings hold.

```rust
use hekate_core::config::Config;
use hekate_crypto::DefaultHasher;
use hekate_crypto::transcript::Transcript;
use hekate_program::{ProgramInstance, ProgramWitness};
use hekate_prover_sys::prove;
use hekate_verifier::HekateVerifier;
use rand::{TryRng, rngs::SysRng};

fn run(num_rows: usize, audited_id: &[u8; 32]) -> Result<bool, Box<dyn core::error::Error>> {
    let (cpu, arith, fib_n) = generate_traces(num_rows)?;

    let program = build_program(num_rows)?;
    let instance = ProgramInstance::new(num_rows, vec![F::from(fib_n as u128)]);
    let witness = ProgramWitness::new(cpu).with_chiplets(vec![arith]);

    let config = Config::default();

    let mut blinding_seed = [0u8; 32];
    SysRng.try_fill_bytes(&mut blinding_seed)?;

    let proof = prove(
        b"Fibonacci",
        &program,
        &instance,
        &witness,
        &config,
        blinding_seed,
        None,
    )?;

    let mut transcript = Transcript::<DefaultHasher>::new(b"Fibonacci");

    // `audited_id` is a constant of the verifying build,
    // printed once by `digest::program_id_hex`.
    Ok(HekateVerifier::<F, DefaultHasher>::verify(
        audited_id,
        &program,
        &instance,
        &proof,
        &mut transcript,
        &config,
    )?)
}
```

## Performance

Proving time, verification time, proof size and peak memory per workload, with zero knowledge on and off, are on
[Benchmarks](https://oumuamua.dev/hekate/benchmarks) together with the command that reproduces each run.

## Next Steps

- [Installation](https://oumuamua.dev/hekate/docs/getting-started/installation), crates, prover variants, targets
- [Your First ZK Program](https://oumuamua.dev/hekate/docs/getting-started/your-first-zk-program), first proof end-to-end
- [System Architecture](https://oumuamua.dev/hekate/docs/basics/system-architecture), binary tower fields, Sumcheck, Brakedown, LogUp
- [AIR Constraints](https://oumuamua.dev/hekate/docs/basics/air-constraints), constraint DSL, boundary conditions
- [Cryptographic Chiplets](https://oumuamua.dev/hekate/docs/basics/cryptographic-chiplets), independent tables, virtual packing, bus integration
- [Soundness and Security](https://oumuamua.dev/hekate/docs/advanced/soundness-and-security), threat model, adversarial test suite, Fiat-Shamir binding

## Status

The verifier, core SDK, and cryptographic chiplets are open-source under AGPL-3.0-only. The prover and compression
engine stay proprietary, shipped as free signed binaries for macOS, Linux, iOS and Android on ARM64. Linking the two is
covered by the prover linking exception.

The workspace is under aggressive development: APIs, ABIs, and cryptographic signatures will break without notice, and
it has not been independently audited. Do not deploy to mainnet.

## Contact

[info@oumuamua.dev](mailto:info@oumuamua.dev)