Oumuamua Labs

Installation

What You Install

Hekate ships in two halves: an open-source toolkit of Rust crates you compile against, and a closed prover cdylib distributed as a signed binary, one per (target, variant) pair.

Verify-only consumers (rollup nodes, light clients, recursive verifiers) depend on hekate-verifier and skip hekate-prover-sys entirely. No native binary in the dependency tree.

Prove:   Program -> hekate_prover_sys::prove(...) -> InnerProof<Block128>
Verify:  Program -> HekateVerifier::verify(...) -> bool

The witness rides through the FFI as borrowed column views; the cdylib never copies it. You hold the trace buffers; you free them.


Requirements


Dependencies

[dependencies]
hekate-prover-sys = { version = "0.27", features = ["ct", "blake3"] }   # omit on verify-only builds
hekate-verifier   = "0.27"
hekate-program    = "0.27"
hekate-core       = "0.27"
hekate-math       = "0.6"
hekate-gadgets    = "0.27"   # only if you use built-in chiplets (Keccak, AES, RAM, ROM, NTT, IntArith, BaseMul, ML-KEM, ML-DSA, …)
hekate-sdk        = "0.27"   # only if you call the bundle wire-format helpers directly

hekate-prover-sys re-exports nothing the verifier needs. Verify-only builds drop it cleanly.

Variants — pick exactly one

hekate-prover-sys requires exactly one of ct or public. The build fails fast if neither or both are set.

FeatureWitness dataPerformanceUse for
ctPrivateBaselineAny prover touching secrets (PQC, RAM, user data)
publicPublic onlyFaster via variable-time table-mathRollup batch provers, recursive verifiers, public-input-only programs

public leaks the witness through timing side channels. Never use it on a private witness. The variant selection is enforced at link time — a ct-feature binary links the ct cdylib; a public-feature binary links the public cdylib. Mixing is rejected by build.rs.

Hash backend

Pick the one your verifier uses. Default is blake3.

FeatureAlgorithm
blake3BLAKE3 (default)
sha2SHA-256
sha3SHA-3-256

Mismatch between prover and verifier hash backend silently fails verification — they must match.


How the cdylib is resolved at build time

hekate-prover-sys/build.rs walks three sources in order. First hit wins.

  1. HEKATE_PROVER_DYLIB_DIR — absolute path to a directory containing libhekate_prover_cdylib.{dylib,so}. Skips cache and download. Use this for local development against an unreleased build.
  2. Cache~/.cache/hekate-prover-sys/<version>/<variant>/<triple>/<filename>. Override the root with HEKATE_PROVER_CACHE_DIR.
  3. CDN download — HTTPS GET to the URL pinned in artifacts/manifest.toml, atomic-renamed into the cache.

Every resolved cdylib is verified before linking:

Both pubkey PEMs are embedded in the shim's pinned manifest. The build fails loudly on any mismatch — there is no --insecure flag, no opt-out.


Proving

use hekate_core::config::Config;
use hekate_math::Block128;
use hekate_prover_sys::{prove, CancelToken};
use rand::{TryRngCore, rngs::OsRng};

let mut config = Config::default();
OsRng.try_fill_bytes(&mut config.matrix_seed).unwrap();

let mut blinding_seed = [0u8; 32];
OsRng.try_fill_bytes(&mut blinding_seed).unwrap();

let proof = prove(
    b"my-program-v1",   // Fiat-Shamir domain separator; must match the verifier
    &program,           // &impl Program<Block128>
    &instance,          // &ProgramInstance<Block128>
    &witness,           // &ProgramWitness<Block128>
    &config,
    blinding_seed,
    None,               // CancelToken; pass Some(&token) to wire cancellation
)?;

prove returns Result<InnerProof<Block128>, Error>. The cdylib only ever sees Block128 — the type is monomorphized inside it. The shim builds a bundle for the small payload (program + instance + config + chiplet defs) and threads the witness columns through as borrowed views; no defensive copies on the witness path.


Verifying

Verification is pure Rust, no cdylib. The call is identical whether the proof came from hekate-prover-sys, a peer, or a remote service.

use hekate_crypto::DefaultHasher;
use hekate_crypto::transcript::Transcript;
use hekate_math::Block128;
use hekate_verifier::HekateVerifier;

let mut transcript = Transcript::<DefaultHasher>::new(b"my-program-v1");
let ok = HekateVerifier::<Block128, DefaultHasher>::verify(
    &program,
    &instance,
    &proof,
    &mut transcript,
    &config,
)?;

The transcript label must byte-match the prover's transcript_label. The hash type must match the prover's DefaultHasher (selected by the blake3 / sha2 / sha3 feature).


Cancellation

CancelToken is a cooperative token allocated on the cdylib side. The prover checks it at sumcheck round boundaries, Brakedown phase boundaries, and evaluator phase boundaries — granularity is tens to hundreds of milliseconds. Cancellation is best-effort: a request may run up to one checkpoint before prove returns Error::Ffi { code: ErrorCode::Cancelled, .. }.

CancelToken is Send + Sync; share it across threads through Arc.

use std::sync::Arc;
use std::thread;
use hekate_prover_sys::{CancelToken, Error, ErrorCode, prove};

let token = Arc::new(CancelToken::new());

let canceler = {
    let token = token.clone();
    thread::spawn(move || {
        // request cancellation after some condition
        token.request();
    })
};

let result = prove(b"my-program-v1", &program, &instance, &witness, &config, seed, Some(&token));
canceler.join().unwrap();

match result {
    Err(e) if e.code() == Some(ErrorCode::Cancelled) => { /* user-initiated abort */ }
    Err(e) => return Err(e),
    Ok(proof) => { /* use proof */ }
}

The cdylib never frees witness buffers — even on cancel, the dev's allocations are untouched.


Supported targets

The 0.5.0 release ships these (triple, variant) pairs. Both variants for every triple.

Target triplePlatformArtifact extension
aarch64-apple-darwinmacOS, Apple Silicon.dylib
aarch64-apple-iosiOS, ARM64.dylib
aarch64-unknown-linux-gnuLinux ARM64, glibc.so
aarch64-linux-androidAndroid ARM64.so

See Releases for per-version SHA-256s and download links.


Next Steps