Skip to content

Conversation

@quangvdao
Copy link
Contributor

@quangvdao quangvdao commented Jan 14, 2026

Experimental change: replace Stage 4 RAM ValEvaluation + ValFinal sumchecks with a single fused sumcheck instance, while preserving the same cached opening IDs/points (RamValEvaluation, RamValFinalEvaluation) so downstream protocols (notably RA reduction) remain unchanged.

Precise protocol / identity

We batch two existing RAM value identities into one log(T)-round sumcheck using an explicit fusion challenge γ sampled from the transcript immediately before Stage 4 (label: ram_val_fused_gamma).

Let:

  • (r_address_rw, r_cycle) be the point from VirtualPolynomial::RamVal under SumcheckId::RamReadWriteChecking.
  • r_address_raf be the point from VirtualPolynomial::RamValFinal under SumcheckId::RamOutputCheck.
  • inc(j) be the per-cycle RAM increment witness (CommittedPolynomial::RamInc).
  • wa_rw(j) := eq(r_address_rw, addr_j) and wa_raf(j) := eq(r_address_raf, addr_j) where addr_j is the remapped RAM address at cycle j.

Then the fused sumcheck proves:

(Val(r_address_rw, r_cycle) − Val_init(r_address_rw))

  • γ · (Val_final(r_address_raf) − Val_init(r_address_raf))
    = Σ_j inc(j) · ( wa_rw(j) · LT(j, r_cycle) + γ · wa_raf(j) )

Degree bound is 3 (dominated by the inc · wa_rw · LT term).

Implementation approach (how we share work)

  • A single prover/verifier pair lives in jolt-core/src/zkvm/ram/val_fused.rs.
  • We build one inc MLE witness and one LtPolynomial (for LT(j, r_cycle)).
  • We build one shared wa_indices: Arc<Vec<Option<usize>>> from the trace (the remapped address index per cycle), and construct two RaPolynomials from it:
    • wa_rw = RaPolynomial(wa_indices, eq(r_address_rw, ·))
    • wa_raf = RaPolynomial(wa_indices, eq(r_address_raf, ·))

This mirrors ValEvaluation’s “indices + eq-table” design and avoids ever materializing a dense wa: Vec<F>.

Openings / compatibility with existing pipeline

Even though Stage 4 now runs a single instance, we still cache the exact same openings under the existing sumcheck IDs:

  • Under SumcheckId::RamValEvaluation:
    • CommittedPolynomial::RamInc opened at r_cycle′
    • VirtualPolynomial::RamRa opened at (r_address_rw || r_cycle′) with claim = wa_rw(r_cycle′)
  • Under SumcheckId::RamValFinalEvaluation:
    • CommittedPolynomial::RamInc opened at r_cycle′
    • VirtualPolynomial::RamRa opened at (r_address_raf || r_cycle′) with claim = wa_raf(r_cycle′)

This preserves the coincidence constraints described in jolt-core/src/zkvm/ram/mod.rs for the later RA reduction sumcheck.

Precise memory savings

Compared to the baseline (two separate Stage-4 RAM sumcheck provers):

  • Eliminates one full dense wa: Vec<F> of length T (previously allocated by ValFinalSumcheckProver).
  • Eliminates one full dense inc: Vec<F> of length T (previously allocated twice: once in ValEvaluation, once in ValFinal).

Net: ~2·T field elements less live heap memory during Stage 4.

  • In bytes: approximately 2 * T * size_of::<F>() (plus Vec/MLP overhead). For BN254-sized fields (~32 bytes/elem), this is ~64*T bytes.

Perf (single run, sha2-chain trace)

From Chrome traces, summing only the relevant spans:

  • Fused (RamValFusedSumcheckProver::{initialize,compute_message,ingest_challenge}): 308.490 ms
  • Baseline (RamValEvaluationSumcheckProver::* + ValFinalSumcheckProver::*): 340.591 ms
  • Δ: -32.101 ms (~9.4%)

Notes

  • Draft PR: this is experimental; adoption is uncertain.

@quangvdao
Copy link
Contributor Author

Pushed follow-up commit removing the legacy separate RAM val sumchecks now that Stage 4 uses . Commit: 4b237af.

@quangvdao
Copy link
Contributor Author

Follow-up: removed the legacy separate RAM val_evaluation / val_final sumcheck modules now that Stage 4 uses the fused sumcheck in val_fused.rs.

Commit: 4b237af

@quangvdao quangvdao changed the title DRAFT: fuse RAM ValEvaluation + ValFinal sumchecks (stage4) fuse RAM ValEvaluation + ValFinal sumchecks (stage4) Jan 27, 2026
@quangvdao quangvdao marked this pull request as ready for review January 27, 2026 19:43
Stage 4 verifier referenced `ram::gen_ram_initial_memory_state` without importing the module.
Use the fully qualified `crate::zkvm::ram::...` path so the workspace builds in CI.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant