# Installation

> Add Hekate to a Rust project: the open-source crates, the signed prover binary that hekate-prover-sys downloads and verifies, and the platforms it runs on.

- URL: https://oumuamua.dev/hekate/docs/getting-started/installation
- Published: 2026-05-10T12:45:14+07:00
- Updated: 2026-10-05T16:11:25+07:00

Hekate is a set of Rust crates on crates.io plus one native library, the prover. The crates describe programs and
verify proofs on every platform they compile for. `hekate-prover-sys` fetches the signed prover binary for your
platform at build time, checks its signatures and links it.

## Requirements

- **Rust** 1.88 or newer, stable, edition 2024.
- **An ARM64 target to prove on**: macOS, Linux with glibc, iOS or Android, as listed under
  [Supported targets](https://oumuamua.dev/hekate/docs/getting-started/installation#supported-targets). The prover has no x86_64 build. The open crates, the verifier among them,
  also build for x86_64, where field multiplication runs a software fallback.
- **Xcode Command Line Tools on macOS.** The build script runs `install_name_tool` on the prover library.
- **Network access on the first build**, which downloads the prover binary. Later builds reuse the cached copy.

## Add the crates

A program that proves and verifies needs six core crates, the prover shim and `rand` for the seed:

```bash
cargo add hekate-core hekate-crypto hekate-math hekate-program hekate-sdk hekate-verifier
cargo add hekate-prover-sys --features ct
cargo add rand
```

A service that only verifies proofs stops after the first line, and no native library enters its build.

| Crate               | Role                                                                   |
|:--------------------|:-----------------------------------------------------------------------|
| `hekate-math`       | Binary tower field arithmetic, the fields the proofs work in           |
| `hekate-crypto`     | Hash functions, Merkle trees and the Fiat-Shamir transcript            |
| `hekate-core`       | Configuration, execution traces and proof types                        |
| `hekate-program`    | The circuit DSL: columns, constraints, chiplets, buses and program ids |
| `hekate-sdk`        | Preflight diagnostics and the proof wire format                        |
| `hekate-verifier`   | The verifier, pure Rust                                                |
| `hekate-prover-sys` | Links the prover binary and exposes `prove`                            |

Chiplet crates add ready-made tables for standard cryptography. Add the ones your program calls:

| Crate             | Proves                                                                        |
|:------------------|:------------------------------------------------------------------------------|
| `hekate-gadgets`  | Integer arithmetic, RAM and ROM, and the modular exponentiation behind RSA    |
| `hekate-keccak`   | Keccak-f[1600], with SHA3-256, SHA3-512, SHAKE128 and SHAKE256 host helpers   |
| `hekate-sha2`     | The SHA-256 compression function                                              |
| `hekate-aes`      | AES-128 and AES-256 encryption                                                |
| `hekate-rsa`      | RSA-2048 PKCS#1 v1.5 signature verification                                   |
| `hekate-pqc`      | ML-KEM key generation, encapsulation and decapsulation, and ML-DSA verification |

`hekate-scribble` is a test tool: it tampers with a valid trace and fails when your constraints miss the change.

## Choose the prover variant

`hekate-prover-sys` needs exactly one of two features. With neither or both, the build stops with an error that names
them.

| Feature  | Arithmetic                     | Use it for                                               |
|:---------|:-------------------------------|:---------------------------------------------------------|
| `ct`     | Constant-time                  | Any witness that holds private data                      |
| `public` | Variable-time tables, faster   | Public data only: the timing of a run leaks the witness  |

The feature picks the binary: a `ct` build links the constant-time prover, a `public` build the variable-time one.

## Keep the BLAKE3 hash

Every Hekate crate hashes with BLAKE3 by default, and the published prover binaries use BLAKE3 too. Leave the default
on.

The `sha2` and `sha3` features switch `DefaultHasher`, the hash behind the transcript and the Merkle trees, to SHA-256
or SHA3-256. Cargo turns a feature on for the whole build as soon as one crate asks for it, and SHA3-256 then wins
over SHA-256, which wins over BLAKE3. A verifier on another hash than the prover's derives different challenges, and
the proof fails to verify.

## How the prover binary reaches your build

`hekate-prover-sys` pins one prover binary per variant and target, and its build script links only a file that
matches the pin. It looks in three places, in this order:

1. `HEKATE_PROVER_DYLIB_DIR`, a directory that holds the binary, for builds without network access. When set, it is
   the only place searched.
2. The cache, `~/.cache/hekate-prover-sys/<prover version>/<variant>/<target>/`. `HEKATE_PROVER_CACHE_DIR` moves its
   root. A cached file with the wrong SHA-256 is deleted and fetched again.
3. The release server, at the URL pinned in the crate's manifest. The download lands in the cache.

Wherever the file comes from, the script checks it before linking: its SHA-256 against the manifest, then an Ed25519
signature and an ML-DSA-65 signature (FIPS 204) against publisher keys pinned in the crate. Any mismatch fails the
build, and a release build has no way around the checks.

The script copies the library into the build directory and links your program to it there, which lets `cargo run` and
`cargo test` find it with no setup. A program you run on another machine needs the library shipped with it. For iOS and
Android apps, [`hekate-mobile`](https://oumuamua.dev/mobile) packages the prover into an `.xcframework` or an `.aar`.

`hekate_prover_sys::version()` and `build_id()` report which binary your program linked.

## Prove

`prove` takes a transcript label, the program, its public instance, the private witness, a `Config`, a fresh seed and an optional cancel
token, and returns the proof.

```rust
use hekate_core::config::Config;
use hekate_core::proofs::InnerProof;
use hekate_math::Block128;
use hekate_program::{Program, ProgramInstance, ProgramWitness};
use hekate_prover_sys::prove;
use rand::{TryRng, rngs::SysRng};
use std::error::Error;

fn prove_once<P: Program<Block128>>(
    program: &P,
    instance: &ProgramInstance<Block128>,
    witness: &ProgramWitness<Block128>,
    config: &Config,
) -> Result<InnerProof<Block128>, Box<dyn Error>> {
    let mut seed = [0; 32];
    SysRng.try_fill_bytes(&mut seed)?;

    Ok(prove(b"my-program", program, instance, witness, config, seed, None)?)
}
```

The label keeps your program's transcript apart from every other program's, and the verifier must use the same bytes.
The seed blinds the proof: draw it fresh for every proof, because one seed used for two different witnesses discloses
them. `hekate_sdk::serialize_proof_bytes` turns the proof into bytes for the wire, and `deserialize_proof` reads them
back.

To stop a proof early, pass `Some(&token)` with a `CancelToken` and call `token.request()` from another thread. The
token is `Send` and `Sync`, and the prover stops at its next check of it: `prove` then returns an error whose `code()`
is `Some(ErrorCode::Cancelled)`.

## Verify

Verification is pure Rust and needs no prover binary.

```rust
use hekate_core::config::Config;
use hekate_core::proofs::InnerProof;
use hekate_crypto::DefaultHasher;
use hekate_crypto::transcript::Transcript;
use hekate_math::Block128;
use hekate_program::{Program, ProgramInstance};
use hekate_verifier::HekateVerifier;

fn accept<P: Program<Block128> + Sync>(
    program_id: &[u8; 32],
    program: &P,
    instance: &ProgramInstance<Block128>,
    proof: &InnerProof<Block128>,
    config: &Config,
) -> bool {
    let mut transcript = Transcript::<DefaultHasher>::new(b"my-program");

    let verdict = HekateVerifier::<Block128, DefaultHasher>::verify(
        program_id,
        program,
        instance,
        proof,
        &mut transcript,
        config,
    );

    matches!(verdict, Ok(true))
}
```

`program_id` is the hash of your circuit, from `hekate_program::digest::program_id`. Compute it once and keep it in the
verifier as a constant: a proof made for any other circuit then fails. The label and the `Config` must match the
prover's. Only `Ok(true)` accepts a proof; `Ok(false)` and every error reject it.

## Supported targets

Each prover release ships both variants for each of these targets.

| Target                      | Platform                       | Library  |
|:----------------------------|:-------------------------------|:---------|
| `aarch64-apple-darwin`      | macOS on Apple Silicon         | `.dylib` |
| `aarch64-apple-ios`         | iOS                            | `.dylib` |
| `aarch64-apple-ios-sim`     | iOS Simulator on Apple Silicon | `.dylib` |
| `aarch64-unknown-linux-gnu` | Linux on ARM64, glibc          | `.so`    |
| `aarch64-linux-android`     | Android on ARM64               | `.so`    |

[Prover Releases](https://oumuamua.dev/hekate/releases/prover) lists every version with its files and their SHA-256.

## Next steps

- [Your First ZK Program](https://oumuamua.dev/hekate/docs/getting-started/your-first-zk-program): a private payment, proved and verified
  end to end.
- [Primitives](https://oumuamua.dev/primitives): what each chiplet proves, and what stays outside the proof.
- [Prover Releases](https://oumuamua.dev/hekate/releases/prover): the signed binaries behind `hekate-prover-sys`.