Skip to content

perf(prover): port optimized Akita to the modular prover - #1732

Draft
markosg04 wants to merge 94 commits into
mainfrom
perf/akita-prover-opt
Draft

perf(prover): port optimized Akita to the modular prover#1732
markosg04 wants to merge 94 commits into
mainfrom
perf/akita-prover-opt

Conversation

@markosg04

@markosg04 markosg04 commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

The modular prover lacks an Akita path and still materializes several trace-sized tables that the optimized backend can derive or stream. Stacked on #1731, this ports the optimized kernel families, adds modular Akita proving and reconstruction, streams packed commitments, compacts witness storage, and releases large tables after their final stage.

Local sha2-chain acceptance runs at the default minimum-payload schedules reached 51.67 s / 26.22 GiB at 2^26 and 205.45 s / 76.41 GiB at 2^28; the 2^28 run completed without swapouts. (The payload-slack planner policy that previously improved these to 49.78 s and 173.48 s was dropped from the stack per upstream planner review — LayerZero-Labs/akita#344 is closed; the measured trade is recorded in the acceptance spec for a future planner-native mechanism.)

The akita dependency has since been reconciled with akita main (flattened setup, compressed payloads, catalog-row schedule selection), and the jolt side ported: committed groups are self-describing (verify takes each group's profile from the trusted catalog row; proofs carry payload coefficients only), and since the verifier now accepts only cataloged rows, every provable shape is an approved row — D128 one-hot and dense advice/program objects gain their own generated catalogs. Under upstream's evolved sizing the min-payload planner natively selects D64 rank 6 (P=2^20) and D128 rank 3 (P=2^19) — most of the geometry the retired slack policy bought — and the D128 setup capacity drops from 11 GiB to 4.125 GiB with prefix-exact accounting. The byte-diff suites confirm the modular prover still matches the legacy prover on the reconciled substrate. The 2^26/2^28 numbers above predate the reconciliation; the acceptance ladder needs a re-run before merge.

Changes

  • Add the modular Akita prover path and Dory/Akita shared stage recipes.
  • Wire the optimized backend across all prover stages with reference-path parity tests.
  • Add profiling coverage and explicit memory-lifetime controls for large traces.

Testing

  • Ran tests for modified crates
  • cargo clippy and cargo fmt pass

Akita e2e and byte-parity suites, 122 optimized-kernel tests, RAM fallback tests, and both required clippy feature modes pass.

Security Considerations

The protocol and verifier changes are reviewed in #1731. Differential kernel tests compare optimized outputs with the reference backend, and the e2e suites verify the resulting proofs rather than only comparing intermediate values.

Breaking Changes

Inherits the Akita proof/setup changes from #1731. The modular prover's internal backend and stage APIs change to support Akita and streamed witness sources.

@github-actions github-actions Bot added spec Tracking issue for a feature spec implementation PR contains implementation of a spec labels Aug 1, 2026
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Benchmark comparison (crates)

group                           main_run                               pr_run
-----                           --------                               ------
EqPolynomial::evals/17          1.00  1912.8±39.40µs        ? ?/sec    1.09      2.1±0.03ms        ? ?/sec
EqPolynomial::evals/19          1.00      7.2±0.11ms        ? ?/sec    1.10      7.9±0.06ms        ? ?/sec
EqPolynomial::evals/20          1.00     15.1±0.09ms        ? ?/sec    1.06     16.1±0.27ms        ? ?/sec
EqPolynomial::evals/22          1.00     57.6±0.35ms        ? ?/sec    1.09     62.7±0.35ms        ? ?/sec
EqPolynomial::evaluations/14    1.00   536.6±21.17µs        ? ?/sec    1.17   626.5±53.89µs        ? ?/sec
EqPolynomial::evaluations/18    1.00      6.5±0.05ms        ? ?/sec    1.13      7.3±0.10ms        ? ?/sec
Fr::from_bytes                  1.00    155.3±1.58ns        ? ?/sec    1.06    165.2±3.07ns        ? ?/sec
Fr::mul_u128                    1.00     22.6±0.22ns        ? ?/sec    1.10     24.8±0.95ns        ? ?/sec
Fr::to_bytes                    1.00     17.6±0.18ns        ? ?/sec    1.14     20.0±0.12ns        ? ?/sec
Polynomial::bind/14             1.00    130.0±7.92µs        ? ?/sec    1.18    154.0±5.36µs        ? ?/sec
Polynomial::bind/18             1.00  1932.9±26.46µs        ? ?/sec    1.13      2.2±0.04ms        ? ?/sec
Polynomial::bind/20             1.00      7.7±0.17ms        ? ?/sec    1.11      8.6±0.23ms        ? ?/sec
Polynomial::evaluate/20         1.00     40.9±0.47ms        ? ?/sec    1.09     44.4±0.29ms        ? ?/sec
append_bytes/Blake2b/256B       1.00    324.0±5.41ns        ? ?/sec    1.06    343.4±3.92ns        ? ?/sec
append_bytes/Keccak/256B        1.00   827.7±12.76ns        ? ?/sec    1.10    914.6±6.54ns        ? ?/sec
append_bytes/Poseidon/32B       1.00     92.5±1.31µs        ? ?/sec    1.06     98.1±2.51µs        ? ?/sec
challenge/Blake2b               1.00    656.0±9.48ns        ? ?/sec    1.11   727.0±13.83ns        ? ?/sec
challenge/Keccak                1.00    395.5±3.60ns        ? ?/sec    1.11    439.2±2.87ns        ? ?/sec
challenge/Poseidon              1.00     46.2±0.94µs        ? ?/sec    1.06     49.1±0.50µs        ? ?/sec
g1_add                          1.00    407.3±2.69ns        ? ?/sec    1.14    464.6±5.04ns        ? ?/sec
g1_deserialize_bincode          1.00      9.2±0.06µs        ? ?/sec    1.06      9.7±0.18µs        ? ?/sec
g1_double                       1.00    213.2±2.25ns        ? ?/sec    1.10    234.9±3.07ns        ? ?/sec
g1_msm/1024                     1.00     12.7±0.02ms        ? ?/sec    1.10     14.0±0.08ms        ? ?/sec
g1_msm/16                       1.00    533.6±3.64µs        ? ?/sec    1.12    598.9±6.77µs        ? ?/sec
g1_msm/256                      1.00      4.3±0.08ms        ? ?/sec    1.10      4.7±0.01ms        ? ?/sec
g1_msm/4                        1.00    254.3±1.24µs        ? ?/sec    1.12    284.7±3.17µs        ? ?/sec
g1_scalar_mul                   1.00     64.9±1.49µs        ? ?/sec    1.12     72.4±1.76µs        ? ?/sec
g1_serialize_bincode            1.00    110.1±0.69ns        ? ?/sec    1.09    119.9±1.40ns        ? ?/sec
g2_msm/256                      1.00     15.5±0.05ms        ? ?/sec    1.13     17.5±0.04ms        ? ?/sec
g2_msm/4                        1.00   778.1±11.85µs        ? ?/sec    1.11    863.7±8.55µs        ? ?/sec
g2_msm/64                       1.00      5.6±0.03ms        ? ?/sec    1.13      6.3±0.12ms        ? ?/sec
g2_scalar_mul                   1.00    323.9±3.71µs        ? ?/sec    1.12    361.3±4.74µs        ? ?/sec
gt_scalar_mul                   1.15    893.1±9.28µs        ? ?/sec    1.00    778.0±8.15µs        ? ?/sec
multi_pairing/16                1.00      5.8±0.03ms        ? ?/sec    1.09      6.3±0.09ms        ? ?/sec
multi_pairing/2                 1.17  1247.0±23.81µs        ? ?/sec    1.00  1063.0±16.66µs        ? ?/sec
multi_pairing/4                 1.00  1833.6±13.39µs        ? ?/sec    1.07  1962.1±27.99µs        ? ?/sec
multi_pairing/8                 1.00      3.2±0.01ms        ? ?/sec    1.10      3.5±0.08ms        ? ?/sec
pairing                         1.16   926.2±24.16µs        ? ?/sec    1.00   801.1±12.94µs        ? ?/sec
pedersen_commit/1024            1.00     12.8±0.01ms        ? ?/sec    1.11     14.2±0.25ms        ? ?/sec
pedersen_commit/16              1.00   602.4±11.99µs        ? ?/sec    1.13   678.1±19.87µs        ? ?/sec
pedersen_commit/256             1.00      4.3±0.02ms        ? ?/sec    1.11      4.8±0.02ms        ? ?/sec
pedersen_commit/4               1.00    318.6±3.42µs        ? ?/sec    1.12    357.4±6.57µs        ? ?/sec

markosg04 and others added 6 commits August 3, 2026 13:54
…rove seam, byte-diff + e2e harnesses

Reorganize the crate as two parallel prover paths sharing the root
orchestration (config/preprocessing/driver/error): src/dory (the
homomorphic elliptic-curve pipeline, was src/prover.rs + src/stages)
and src/akita (the packed lattice pipeline, port in progress). Like
jolt-verifier, one compiled prover proves exactly one protocol: the
akita feature swaps the wire types to the packed envelope, so exactly
one path module compiles per build.

- akita::prove stub (returns ProverError::Unsupported) pins the packed
  seam: backend-first signature over a JoltAkitaBackend registry-to-be,
  generic over the scheme — concrete Akita types bind at call sites.
  JoltAkitaBackend is a parallel struct rather than cfg-gated
  JoltBackend fields: jolt-kernels deliberately has no akita feature
  (see jolt-claims' CANONICAL_INSTRUCTION_ADDRESS).
- tests/akita_byte_diff.rs: legacy-vs-new whole-proof ratchets
  (muldiv, advice consumer, committed muldiv x {1,2} chunks), all
  #[ignore]d until the port lands; component-wise asserts give
  per-stage granularity on the packed wire fields.
- tests/akita_e2e.rs: analogs of the legacy packed e2e suite (muldiv,
  forced-K256, advice, full-advice, committed program), #[ignore]d;
  un-ignoring them is the port's acceptance gate.
- tests/dory_byte_diff.rs (was byte_diff.rs): modules re-gated
  all(prover-fixtures, not(akita)) — the two harnesses are mutually
  exclusive by feature.
- jolt-kernels: the bytecode read-raf reference kernel takes the
  jolt-claims NUM_BYTECODE_VAL_STAGES seam (5 base / 6 akita) and
  guards its base-five fold at runtime; byte-neutral in base mode
  (the dory_byte_diff muldiv ratchet passes).
- Cargo: akita = [jolt-verifier/akita, jolt-claims/akita,
  jolt-field/akita, jolt-prover-legacy/akita] — legacy must flip
  together with the verifier; the verifier's own akita edge to it is a
  dev-dep edge that does not propagate.
- CI: clippy lanes for -p jolt-prover --features
  akita[,prover-fixtures] so the ignored suites keep compiling.

Verified: clippy -D warnings on {default, prover-fixtures, akita,
akita+prover-fixtures}; workspace clippy under host and host,zk;
nextest default and akita lanes; dory_byte_diff muldiv end-to-end.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@0xAndoroid
0xAndoroid force-pushed the perf/akita-prover-opt branch from c10b269 to cbf59c9 Compare August 6, 2026 19:07
0xAndoroid and others added 2 commits August 6, 2026 21:08
The Akita port removed the last jolt_utils usage from jolt-witness
(cargo-machete failure). The parallel feature's jolt-utils/parallel
forward goes with it: jolt-kernels, the only jolt-witness/parallel
consumer, already enables jolt-utils/parallel directly.
@0xAndoroid
0xAndoroid force-pushed the perf/akita-prover-opt branch from 9201dc7 to 816d3af Compare August 7, 2026 03:16
0xAndoroid and others added 16 commits August 6, 2026 23:22
# Conflicts:
#	crates/jolt-verifier/src/stages/stage8/reconstruction.rs
Regenerated with JOLT_FS_BLESS=1 cargo nextest run -p jolt-verifier
--test fs_obligations --features fs-audit after merging main (which
brought #1702's gate to this branch). Unlike a mechanical re-spell,
these diffs are this PR's intentional protocol-surface changes; for
the security review they group as:

- Packed-opening redesign: the jolt-openings packing.rs batch absorbs
  and its three challenge draws are replaced by the prefix.rs
  PrefixPackedLayout::reduce_claims schedule (layout digest + logical
  num_vars/slot capacity absorbs, one challenge_vector draw).
- Akita domain separation: append_verifier_setup now absorbs the
  b"akita/fp128" label plus a runtime ring_dimension instead of the
  baked d64 label/AKITA_D constant; AkitaCommitment additionally
  absorbs ring_dimension before backend_coeff_len and the bytes.
- Committed-program plurals: absorb_commitments defers to new
  absorb_packed_commitments/absorb_packed_program_commitments helpers
  over program_one_hot_commitments (source schema:
  program_one_hot_commitment(s)/program_one_hot_setup(s) renames).
Upstream review (akita#344, closed) rejected baking a payload-slack
policy into catalog identity. Remove the preset slack overrides, pin
akita at upstream main, and regenerate the K16/K256 catalogs under the
default min-payload objective. Geometry pin tests now assert D64 rank 7
(P=2^20) and D128 rank 4 (P=2^18, 11 GiB setup envelope).
# Conflicts:
#	crates/jolt-claims/src/protocols/jolt/lattice/packing.rs
#	crates/jolt-openings/Cargo.toml
#	crates/jolt-openings/src/packing.rs
#	crates/jolt-prover-legacy/src/zkvm/packed.rs
jolt-utils now owns the Math trait; the generated catalog headers are
rustfmt-formatted (the emitter's fixed import list is not fmt-stable),
gen_jolt_schedules formats its output, and the drift oracle compares
schedule data with the import boilerplate stripped.
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	crates/jolt-akita/Cargo.toml
#	crates/jolt-akita/src/adapters.rs
#	crates/jolt-akita/src/configs.rs
#	crates/jolt-akita/src/native_batching.rs
#	crates/jolt-akita/src/schedules/jolt_fp128_d64_onehot_k16.rs
#	crates/jolt-akita/src/schedules/jolt_fp128_d64_onehot_k256.rs
#	crates/jolt-akita/src/scheme.rs
#	crates/jolt-claims/src/protocols/jolt/lattice/packing.rs
#	crates/jolt-prover-legacy/src/zkvm/packed.rs
#	crates/jolt-verifier/src/stages/stage8/packed.rs
#	crates/jolt-verifier/src/verifier.rs
The prefix-packed statement adds a fifth constructor argument; the
Dory-shape fixture carries no packed RAM hamming weight.
# Conflicts:
#	crates/jolt-prover-legacy/src/zkvm/packed.rs
Pins akita at the reconciled prover stack (flattened setup, compressed
payloads, catalog-row schedule selection). The adapter moves to
self-describing committed groups — verify reconstructs each group's
profile from the trusted catalog row while proofs carry payload
coefficients only — and batched prove/verify thread the public
row-digest selection.

The verifier accepts only cataloged rows now, so every provable shape
is an approved row: the D64 one-hot grids extend down to the adapter
test shapes, and D128 one-hot and dense advice/program families gain
their own generated catalogs (the dense fp128 D64 floor is nv=14;
smaller objects pad up). Geometry pins re-derived under upstream's
evolved sizing: D64 K256 selects rank 6 at P=2^20 and D128 rank 3 at
P=2^19 natively — most of the retired payload-slack policy's geometry
returns as the min-payload choice — and the D128 setup capacity drops
11 GiB -> 4.125 GiB under prefix-exact accounting.
Pin Jolt to the current LayerZero Akita commit and migrate the fixed-dimension configs, generated catalog identity, CPU backend, grouped root commitment, wide-ring, and sparse challenge APIs.

Preserve Jolt's shared matrix cache release boundaries with Akita's explicit root-fold policy while leaving compression NTT state resident. Propagate cleanup failures through the prover error path.
Merge main at 84bf9f2. Keep the PR's consolidated registers test support and renamed Dory harness, then port main's advice tape contract into those current locations.

Preserve captured advice tape data through padded and field inline trace reconstruction instead of discarding it.
Advance every Akita workspace dependency and lockfile source to fc948f942, the PR #375 merge commit stacked on benchmark report PR #378. The existing adapter API remains unchanged and passes the focused Akita prover and verifier acceptance suites.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

implementation PR contains implementation of a spec spec Tracking issue for a feature spec

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants