Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b4aafd0
refactor(stm): move read-only IVC asset layer out of the test tree fo…
hjeljeli32 Jul 21, 2026
f3586e5
feat(stm): add additive genesis benchmark fixture asset for IVC bench…
hjeljeli32 Jul 21, 2026
3967eb2
feat(stm): add production-backed IVC recursive benchmark façade
hjeljeli32 Jul 21, 2026
05ab2d7
feat(stm): add warm-start SRS measurement and symmetric cold/warm nam…
hjeljeli32 Jul 23, 2026
b92c83e
feat(stm): add recursive IVC circuit prover benchmarks
hjeljeli32 Jul 23, 2026
3e1412e
feat(stm): add verify/fold benchmarks and a single-observation IVC re…
hjeljeli32 Jul 23, 2026
e19934c
fix(stm): reject value-taking options in the IVC bench CLI and clarif…
hjeljeli32 Jul 23, 2026
b8174e8
refactor(stm): move IVC bench CLI parsing into a unit-tested bench_cl…
hjeljeli32 Jul 23, 2026
c567c59
feat(stm): add cold/warm setup cache benchmarks (SRS and certificate+…
hjeljeli32 Jul 23, 2026
a1a9350
fix(stm): use a plain code span for RECURSIVE_CIRCUIT_DEGREE in the I…
hjeljeli32 Jul 23, 2026
433df14
refactor(stm): apply IVC bench review fixes (unwrap-free asset decode…
hjeljeli32 Jul 23, 2026
7871a7e
refactor(stm): group IVC and certificate bench code into dedicated be…
hjeljeli32 Jul 26, 2026
60f3a3c
refactor(stm): split the IVC benchmark façade and tidy its comments
hjeljeli32 Jul 26, 2026
b537c8e
docs(stm): add benches README for the IVC and certificate circuits
hjeljeli32 Jul 26, 2026
379b866
test(stm): hoist golden-test imports to module scope
hjeljeli32 Jul 26, 2026
ef006fc
refactor(stm): drop the unused Ignored bench-CLI variant
hjeljeli32 Jul 26, 2026
573f936
refactor(stm): remove the unused measure_full_setup bench helper
hjeljeli32 Jul 26, 2026
1699448
style(stm): format the benches README with prettier
hjeljeli32 Jul 26, 2026
7e32bf7
feat(stm): log IVC benchmark progress to stderr during long runs
hjeljeli32 Jul 27, 2026
ec40622
chore(stm): update changelog and bump version to 0.11.4
hjeljeli32 Jul 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion mithril-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ fixed = "1.31.0"
hex = { workspace = true }
kes-summed-ed25519 = { version = "0.2.1", features = ["serde_enabled", "sk_clone_enabled"] }
mithril-merkle-tree = { path = "../internal/mithril-merkle-tree", version = "0.1.4" }
mithril-stm = { path = "../mithril-stm", version = "0.11.3", default-features = false }
mithril-stm = { path = "../mithril-stm", version = "0.11.4", default-features = false }
nom = "8.0.0"
rand_chacha = { workspace = true }
rand_core = { workspace = true }
Expand Down
7 changes: 7 additions & 0 deletions mithril-stm/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 0.11.4 (07-27-2026)

### Added

- Added benchmarks for the recursive IVC (SNARK) circuit covering proving (Poseidon and Blake2b transcripts), verification, and off-circuit accumulator folding across the genesis, same-epoch, and next-epoch transition paths, plus cold/warm setup measurements for the SRS and circuit keys, all driven through a `benchmark-internals` façade over the production proof system.
- Added a `mithril-stm/benches/README.md` documenting the recursive IVC and non-recursive certificate benchmarks and the IVC harness's fail-closed CLI.

## 0.11.3 (07-22-2026)

### Changed
Expand Down
7 changes: 6 additions & 1 deletion mithril-stm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mithril-stm"
version = "0.11.3"
version = "0.11.4"
edition = { workspace = true }
authors = { workspace = true }
homepage = { workspace = true }
Expand Down Expand Up @@ -114,6 +114,11 @@ name = "halo2_prover_modes"
harness = false
required-features = ["future_snark", "benchmark-internals"]

[[bench]]
name = "ivc_halo2_snark"
harness = false
required-features = ["future_snark", "benchmark-internals"]

[[bench]]
name = "stm"
harness = false
Expand Down
145 changes: 145 additions & 0 deletions mithril-stm/benches/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# `mithril-stm` benchmarks

This folder holds the benchmark harnesses for `mithril-stm`. The two Halo2 **circuit** benchmark suites are
the focus of this document:

- the **recursive IVC circuit** — [`ivc_halo2_snark`](ivc_halo2_snark.rs), which ships a small **CLI** to
list and select what runs;
- the **non-recursive certificate circuit** — [`halo2_snark`](halo2_snark.rs) and
[`halo2_prover_modes`](halo2_prover_modes.rs).

Every harness is declared `harness = false` in `Cargo.toml` (a custom `main`, or a Criterion-generated
`main`), and each delegates to a **benchmark-only façade** in the library —
`circuits::halo2_ivc::bench::helpers` and `circuits::halo2::bench::helpers` — so the measured operations run
the same production code paths. (The one exception is the IVC `verify/kzg_opening` diagnostic, which
reproduces just the KZG-opening sub-step of `IvcProof::verify`.) The façades live in the library (not here)
because they call `pub(crate)`/private production code; these harness files are the thin public-API
front-ends.

## Prerequisites

- **Toolchain:** the crate's dev-dependencies require `rustc ≥ 1.88`. The commands below pin `+1.88.0`; use
any installed toolchain `≥ 1.88`, or set it as the default and drop the `+1.88.0`.
- **Features:** all circuit benches require `--features future_snark,benchmark-internals`.
- **Resources:** the recursive circuit runs at degree 19 (GB-scale RAM, minutes per proof); the non-recursive
`production` tier needs ≥ 70 GB RAM (server-class). Scope your run accordingly.

General invocation:

```bash
cargo +1.88.0 bench -p mithril-stm --features future_snark,benchmark-internals --bench <name> -- <args>
```

Everything after `--` is passed to the benchmark binary.

## Benchmark index

| Bench | Circuit / area | What it measures | Selection |
| ------------------------------------------------- | -------------------------------------- | --------------------------------------------------------------------------------- | --------------------------------------------------- |
| `ivc_halo2_snark` | recursive IVC circuit | prove / verify / fold per transition path + setup (cold/warm), single observation | **custom CLI** (`--list`, literal id/prefix filter) |
| `halo2_snark` | non-recursive certificate circuit | constraints, VK size, proof size, prove & verify time across parameter tiers | Criterion (filter `certificate/<tier>`) |
| `halo2_prover_modes` | non-recursive certificate circuit | mock-prover vs real-prover cost projected to an e2e run, across `k` tiers | no arguments |
| `multi_sig`, `schnorr_sig`, `stm`, `size_benches` | other crate areas (not Halo2 circuits) | see each file | — |

---

## Recursive IVC circuit — `ivc_halo2_snark`

Exercises the recursive IVC prover/verifier at its production degree (19), using the small committed
certificate as the inner proof. It measures, for each of the three transition **paths** — `genesis`,
`same_epoch`, `next_epoch`:

- **prove** with each transcript: `prove/poseidon`, `prove/blake2b`;
- **verify**: `verify/full` (message binding + KZG opening + folded-accumulator pairing) and
`verify/kzg_opening` (the isolated opening);
- **fold**: the off-circuit accumulator fold (`genesis` has none — it is a passthrough);

plus **setup** measured cold vs warm: `setup/srs` and `setup/keys`. Each measurement is a single
observation, printed as a small table when the run finishes.

### The CLI

Because a full run is expensive, this harness parses its own arguments (fail-closed, so a stray option can
never silently trigger a multi-minute key generation). Arguments go after `--`:

```bash
# List every benchmark id — no benchmark setup or key generation (Cargo may still compile the target):
cargo +1.88.0 bench -p mithril-stm --features future_snark,benchmark-internals --bench ivc_halo2_snark -- --list

# Show usage:
cargo +1.88.0 bench -p mithril-stm --features future_snark,benchmark-internals --bench ivc_halo2_snark -- --help

# Run everything (tens of minutes; performs TWO recursive key generations — the shared per-path
# environment and the cold setup/keys measurement — then all proofs):
cargo +1.88.0 bench -p mithril-stm --features future_snark,benchmark-internals --bench ivc_halo2_snark

# Run a subset: pass ONE literal id or prefix (substring match against the ids from --list).
# One transition path (prove + verify + fold):
cargo +1.88.0 bench -p mithril-stm --features future_snark,benchmark-internals --bench ivc_halo2_snark -- ivc/same_epoch
# One path's verification only:
cargo +1.88.0 bench -p mithril-stm --features future_snark,benchmark-internals --bench ivc_halo2_snark -- ivc/genesis/verify
# SRS cold vs warm (no key generation):
cargo +1.88.0 bench -p mithril-stm --features future_snark,benchmark-internals --bench ivc_halo2_snark -- ivc/setup/srs
# Keys cold vs warm (cold performs a full recursive key generation):
cargo +1.88.0 bench -p mithril-stm --features future_snark,benchmark-internals --bench ivc_halo2_snark -- ivc/setup/keys
```

The filter is a **literal** substring, not a regex. The parser rejects (rather than silently ignores):
regex metacharacters in the filter, any value-taking option (`--sample-size`, `--color`, `--save-baseline`,
…), and `--exact` / `--test` / `--profile-time` (the last two would force a recursive keygen). Valueless
flags that `cargo bench` injects (`--bench`, `--nocapture`, `--quiet`, `--verbose`) are tolerated.

Benchmark ids:

```
ivc/{genesis,same_epoch,next_epoch}/prove/{poseidon,blake2b}
ivc/{genesis,same_epoch,next_epoch}/verify/{full,kzg_opening}
ivc/{same_epoch,next_epoch}/fold # genesis has no fold
ivc/setup/{srs,keys}
```

Filtering to a subset still builds the shared environment it needs (one recursive keygen), so isolated
verify/fold runs pay that cost up front.

---

## Non-recursive certificate circuit — `halo2_snark`, `halo2_prover_modes`

### `halo2_snark`

For each parameter **tier** it reports constraint rows vs `2^k`, advice columns, VK size, proof size, and
proving/verification time. The two cheap tiers (`small`, `medium`) are **Criterion-sampled** (10 samples);
the two expensive tiers (`large`, `production`) print a **single manually-timed observation** (10 Criterion
samples would be prohibitive).

**Always pass a `certificate/<tier>` filter.** The harness runs every tier that a positional filter does not
exclude, so a bare invocation — or a run whose only arguments are Criterion control flags such as `--list`,
which are not positional filters — executes **all four tiers, including `production` (≥ 70 GB RAM)**.
Criterion's list/filter modes do **not** gate the manually-timed `large`/`production` tiers; only a
positional `certificate/<tier>` filter does.

```bash
cargo +1.88.0 bench -p mithril-stm --features future_snark,benchmark-internals --bench halo2_snark -- certificate/small
cargo +1.88.0 bench -p mithril-stm --features future_snark,benchmark-internals --bench halo2_snark -- certificate/medium
cargo +1.88.0 bench -p mithril-stm --features future_snark,benchmark-internals --bench halo2_snark -- certificate/large
cargo +1.88.0 bench -p mithril-stm --features future_snark,benchmark-internals --bench halo2_snark -- certificate/production
```

| Tier | Quorum | `k` | Measurement |
| ------------ | ------ | --- | --------------------- |
| `small` | 3 | 13 | Criterion, 10 samples |
| `medium` | 32 | 16 | Criterion, 10 samples |
| `large` | 1024 | 21 | single observation |
| `production` | 1944 | 22 | single observation |

`small` is the lightest and a good smoke test after touching the circuit or the façade. `production` requires
≥ 70 GB RAM (server only).

### `halo2_prover_modes`

Takes no arguments — it sweeps a range of `k` tiers and prints, for each, the mock-prover vs real-prover
timings projected onto a standard e2e run (~80 certificates):

```bash
cargo +1.88.0 bench -p mithril-stm --features future_snark,benchmark-internals --bench halo2_prover_modes
```
2 changes: 1 addition & 1 deletion mithril-stm/benches/halo2_prover_modes.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::time::Instant;

use mithril_stm::circuits::halo2::bench_helpers::{BenchEnv, compute_circuit_degree};
use mithril_stm::circuits::halo2::bench::helpers::{BenchEnv, compute_circuit_degree};

fn fmt_ms(ms: u128) -> String {
if ms >= 1000 {
Expand Down
2 changes: 1 addition & 1 deletion mithril-stm/benches/halo2_snark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::time::Instant;
use criterion::{Criterion, SamplingMode, criterion_group, criterion_main};
use std::time::Duration;

use mithril_stm::circuits::halo2::bench_helpers::BenchEnv;
use mithril_stm::circuits::halo2::bench::helpers::BenchEnv;

struct Tier {
name: &'static str,
Expand Down
Loading
Loading