From c1653d9a0dc39b55762c4deaa707518a3f4217bb Mon Sep 17 00:00:00 2001 From: MauroFab Date: Thu, 2 Jul 2026 16:38:39 -0300 Subject: [PATCH] stark: borrow trace rows in place for prover transition eval The LDE buffers have been row-major since the row-major LDE rework, but the evaluator still gather-copied every main and aux column of every transition offset into an owned Frame on each LDE point (~150-200 element clones per row per table) before the constraint body ran. Replace the Prover context's frame with RowFrame: one borrowed (main, aux) row-slice pair per transition offset, taken straight from the row-major storage with the same cyclic row arithmetic. The folder and the IR interpreter read rows[offset][col] directly; the per-thread preallocated Frame and fill_from_lde are deleted (single-row steps only - the sole shape since virtual columns were removed; asserted). Frame stays for the verifier/OOD path and debug validation, which bridges via Frame::as_row_frame. Reads the same values from the same memory - proofs are unchanged. --- crypto/stark/src/constraint_ir/interp.rs | 7 +- crypto/stark/src/constraint_ir/tests.rs | 49 +++++- crypto/stark/src/constraints/builder.rs | 18 +- crypto/stark/src/constraints/builder_tests.rs | 31 +++- crypto/stark/src/constraints/evaluator.rs | 42 ++--- crypto/stark/src/debug.rs | 2 +- crypto/stark/src/frame.rs | 164 +++++++++++------- crypto/stark/src/lookup.rs | 2 +- crypto/stark/src/trace.rs | 12 ++ crypto/stark/src/traits.rs | 10 +- prover/src/tests/constraint_emit_tests.rs | 9 +- prover/src/tests/constraint_set_tests_a.rs | 9 +- prover/src/tests/constraint_set_tests_b.rs | 9 +- prover/src/tests/cpu32_tests.rs | 8 +- prover/src/tests/ec_scalar_tests.rs | 8 +- prover/src/tests/ecdas_tests.rs | 8 +- prover/src/tests/ecsm_tests.rs | 8 +- 17 files changed, 254 insertions(+), 142 deletions(-) diff --git a/crypto/stark/src/constraint_ir/interp.rs b/crypto/stark/src/constraint_ir/interp.rs index 9bb049c27..a03044066 100644 --- a/crypto/stark/src/constraint_ir/interp.rs +++ b/crypto/stark/src/constraint_ir/interp.rs @@ -175,7 +175,7 @@ pub fn eval_program( E: IsField, { let TransitionEvaluationContext::Prover { - frame, + rows, rap_challenges, logup_alpha_powers, logup_table_offset, @@ -188,12 +188,11 @@ pub fn eval_program( let values = run( prog, |main, offset, row, col| { - let step: &TableView = frame.get_evaluation_step(offset as usize); debug_assert_eq!(row, 0, "tables read row 0 of each frame step"); if main { - Value::Base(step.get_main_evaluation_element(0, col as usize).clone()) + Value::Base(rows.main(offset as usize, col as usize).clone()) } else { - Value::Ext(step.get_aux_evaluation_element(0, col as usize).clone()) + Value::Ext(rows.aux(offset as usize, col as usize).clone()) } }, |idx| rap_challenges[idx as usize].clone(), diff --git a/crypto/stark/src/constraint_ir/tests.rs b/crypto/stark/src/constraint_ir/tests.rs index 57a2bef39..bbb52fa6b 100644 --- a/crypto/stark/src/constraint_ir/tests.rs +++ b/crypto/stark/src/constraint_ir/tests.rs @@ -200,7 +200,13 @@ fn frame_offset_reads_next_step() { let alpha: Vec = vec![]; let offset = ExtE::zero(); let shifts = PackingShifts::::new(); - let ctx = TransitionEvaluationContext::new_prover(&frame, &rap, &alpha, &offset, &shifts); + let ctx = TransitionEvaluationContext::new_prover( + frame.as_row_frame(), + &rap, + &alpha, + &offset, + &shifts, + ); let mut base_evals = vec![FpE::zero()]; let mut ext_evals: Vec = vec![]; @@ -234,7 +240,13 @@ fn mixed_base_ext_auto_embeds() { let alpha: Vec = vec![]; let offset = ExtE::zero(); let shifts = PackingShifts::::new(); - let ctx = TransitionEvaluationContext::new_prover(&frame, &rap, &alpha, &offset, &shifts); + let ctx = TransitionEvaluationContext::new_prover( + frame.as_row_frame(), + &rap, + &alpha, + &offset, + &shifts, + ); let mut base_evals: Vec = vec![]; let mut ext_evals = vec![ExtE::zero(), ExtE::zero()]; @@ -267,7 +279,13 @@ fn explicit_embed_and_ext_neg() { let alpha: Vec = vec![]; let offset = ExtE::zero(); let shifts = PackingShifts::::new(); - let ctx = TransitionEvaluationContext::new_prover(&frame, &rap, &alpha, &offset, &shifts); + let ctx = TransitionEvaluationContext::new_prover( + frame.as_row_frame(), + &rap, + &alpha, + &offset, + &shifts, + ); let mut base_evals: Vec = vec![]; let mut ext_evals = vec![ExtE::zero()]; @@ -317,7 +335,13 @@ fn all_leaf_kinds_logup_shaped() { let step = TableView::::new(vec![main_row], vec![aux_row]); let frame = Frame::::new(vec![step]); let shifts = PackingShifts::::new(); - let ctx = TransitionEvaluationContext::new_prover(&frame, &rap, &alpha, &offset, &shifts); + let ctx = TransitionEvaluationContext::new_prover( + frame.as_row_frame(), + &rap, + &alpha, + &offset, + &shifts, + ); let mut base_evals: Vec = vec![]; let mut ext_evals = vec![ExtE::zero()]; @@ -354,7 +378,13 @@ fn prover_entry_point_splits_base_and_ext() { let alpha = vec![ext3(3, 3, 3)]; let offset = ExtE::zero(); let shifts = PackingShifts::::new(); - let ctx = TransitionEvaluationContext::new_prover(&frame, &rap, &alpha, &offset, &shifts); + let ctx = TransitionEvaluationContext::new_prover( + frame.as_row_frame(), + &rap, + &alpha, + &offset, + &shifts, + ); let mut base_evals = vec![FpE::zero()]; let mut ext_evals = vec![ExtE::zero(), ExtE::zero()]; @@ -485,8 +515,13 @@ fn non_goldilocks_reflexive_tower_builds_and_interprets() { let alpha: Vec = vec![]; let offset = g(0); let shifts = PackingShifts::::new(); - let ctx = - TransitionEvaluationContext::::new_prover(&frame, &rap, &alpha, &offset, &shifts); + let ctx = TransitionEvaluationContext::::new_prover( + frame.as_row_frame(), + &rap, + &alpha, + &offset, + &shifts, + ); let mut base_evals = vec![GE::zero()]; let mut ext_evals = vec![GE::zero(), GE::zero()]; eval_program(&prog, &ctx, &mut base_evals, &mut ext_evals); diff --git a/crypto/stark/src/constraints/builder.rs b/crypto/stark/src/constraints/builder.rs index 8437ef907..ec68736d9 100644 --- a/crypto/stark/src/constraints/builder.rs +++ b/crypto/stark/src/constraints/builder.rs @@ -26,7 +26,7 @@ use math::field::element::FieldElement; use math::field::traits::{IsField, IsSubFieldOf}; use crate::constraint_ir::{ConstraintProgram, Dim, IrBuilder}; -use crate::frame::Frame; +use crate::frame::{Frame, RowFrame}; use crate::traits::TransitionEvaluationContext; // ============================================================================= @@ -381,7 +381,7 @@ where F: IsSubFieldOf, E: IsField, { - frame: &'a Frame, + rows: RowFrame<'a, F, E>, challenges: &'a [FieldElement], alphas: &'a [FieldElement], logup_table_offset: &'a FieldElement, @@ -406,7 +406,7 @@ where ext_out: &'a mut [FieldElement], ) -> Self { let TransitionEvaluationContext::Prover { - frame, + rows, rap_challenges, logup_alpha_powers, logup_table_offset, @@ -417,7 +417,7 @@ where }; let num_constraints = base_out.len().max(ext_out.len()); Self { - frame, + rows: *rows, challenges: rap_challenges, alphas: logup_alpha_powers, logup_table_offset, @@ -443,16 +443,10 @@ where type ExprE = FieldElement; fn main(&self, offset: usize, col: usize) -> FieldElement { - self.frame - .get_evaluation_step(offset) - .get_main_evaluation_element(0, col) - .clone() + self.rows.main(offset, col).clone() } fn aux(&self, offset: usize, col: usize) -> FieldElement { - self.frame - .get_evaluation_step(offset) - .get_aux_evaluation_element(0, col) - .clone() + self.rows.aux(offset, col).clone() } fn challenge(&self, idx: usize) -> FieldElement { self.challenges[idx].clone() diff --git a/crypto/stark/src/constraints/builder_tests.rs b/crypto/stark/src/constraints/builder_tests.rs index e48776422..7e2b30970 100644 --- a/crypto/stark/src/constraints/builder_tests.rs +++ b/crypto/stark/src/constraints/builder_tests.rs @@ -188,7 +188,7 @@ fn prover_folder_matches_direct_arithmetic() { let challenges = vec![t.challenge0]; let alphas = vec![t.alpha0]; let ctx = TransitionEvaluationContext::new_prover( - &frame, + frame.as_row_frame(), &challenges, &alphas, &t.offset, @@ -226,7 +226,7 @@ fn prover_folder_matches_interpreted_capture() { let challenges = vec![t.challenge0]; let alphas = vec![t.alpha0]; let ctx = TransitionEvaluationContext::new_prover( - &frame, + frame.as_row_frame(), &challenges, &alphas, &t.offset, @@ -360,8 +360,13 @@ fn prover_folder_missing_emit_asserts() { let challenges: Vec = vec![]; let alphas: Vec = vec![]; let offset = ExtE::zero(); - let ctx = - TransitionEvaluationContext::new_prover(&frame, &challenges, &alphas, &offset, &shifts); + let ctx = TransitionEvaluationContext::new_prover( + frame.as_row_frame(), + &challenges, + &alphas, + &offset, + &shifts, + ); let mut base_out = vec![FpE::zero(); 2]; let mut ext_out = vec![ExtE::zero(); 2]; @@ -381,8 +386,13 @@ fn prover_folder_double_emit_asserts() { let challenges: Vec = vec![]; let alphas: Vec = vec![]; let offset = ExtE::zero(); - let ctx = - TransitionEvaluationContext::new_prover(&frame, &challenges, &alphas, &offset, &shifts); + let ctx = TransitionEvaluationContext::new_prover( + frame.as_row_frame(), + &challenges, + &alphas, + &offset, + &shifts, + ); let mut base_out = vec![FpE::zero(); 2]; let mut ext_out = vec![ExtE::zero(); 2]; @@ -594,8 +604,13 @@ fn next_row_aux_and_multi_alpha_folder_matches_capture() { .map(|s| TableView::new(vec![rows[s].clone()], vec![auxs[s].clone()])) .collect(); let frame = Frame::::new(steps); - let ctx = - TransitionEvaluationContext::new_prover(&frame, &challenges, &alphas, &offset, &shifts); + let ctx = TransitionEvaluationContext::new_prover( + frame.as_row_frame(), + &challenges, + &alphas, + &offset, + &shifts, + ); let mut folder_base = vec![FpE::zero(); num_base]; let mut folder_ext = vec![ExtE::zero(); meta.len()]; diff --git a/crypto/stark/src/constraints/evaluator.rs b/crypto/stark/src/constraints/evaluator.rs index 9f77abcb1..f02ac34de 100644 --- a/crypto/stark/src/constraints/evaluator.rs +++ b/crypto/stark/src/constraints/evaluator.rs @@ -1,6 +1,6 @@ use super::boundary::BoundaryConstraints; use crate::domain::Domain; -use crate::frame::Frame; +use crate::frame::RowFrame; use crate::lookup::{BusPublicInputs, LOGUP_CHALLENGE_ALPHA, PackingShifts, compute_alpha_powers}; use crate::trace::LDETraceTable; use crate::traits::{AIR, TransitionEvaluationContext, ZerofierEvaluations}; @@ -61,29 +61,21 @@ where // Precompute packing shift constants once for all LDE domain points. let packing_shifts = PackingShifts::::new(); - // Per-thread buffers via map_init: each Rayon worker allocates once, - // then reuses for all iterations assigned to that thread. - // The Frame is pre-allocated and filled in-place to avoid Vec allocations - // on every LDE point (a significant fraction of total CPU time). - let blowup_factor = lde_trace.blowup_factor; - let lde_step_size = lde_trace.lde_step_size; - let rows_per_step = lde_step_size / blowup_factor; - let num_main_cols = lde_trace.num_main_cols(); - let num_aux_cols = lde_trace.num_aux_cols(); - let num_offsets = offsets.len(); - + // Per-thread output buffers via map_init: each Rayon worker allocates + // once, then reuses for all iterations assigned to that thread. The + // trace rows themselves are BORROWED in place per LDE point (the LDE + // buffers are row-major) — no per-row gather copy. // Per-row evaluation, shared by the parallel and sequential paths below: - // fill the frame, evaluate transition constraints, accumulate with zerofiers. + // borrow the rows, evaluate transition constraints, accumulate with zerofiers. let eval_row = |i: usize, boundary: FieldElement, transition_buf: &mut [FieldElement], - base_buf: &mut [FieldElement], - frame: &mut Frame| + base_buf: &mut [FieldElement]| -> FieldElement { - frame.fill_from_lde(lde_trace, i, offsets); + let rows = RowFrame::from_lde(lde_trace, i, offsets); let ctx = TransitionEvaluationContext::new_prover( - frame, + rows, rap_challenges, &logup_alpha_powers, logup_table_offset, @@ -145,16 +137,10 @@ where ( vec![FieldElement::::zero(); num_transition], vec![FieldElement::::zero(); num_base], - Frame::preallocate( - num_offsets, - rows_per_step, - num_main_cols, - num_aux_cols, - ), ) }, - |(transition_buf, base_buf, frame), (i, boundary)| { - eval_row(i, boundary, transition_buf, base_buf, frame) + |(transition_buf, base_buf), (i, boundary)| { + eval_row(i, boundary, transition_buf, base_buf) }, ) .collect() @@ -164,15 +150,11 @@ where { let mut transition_buf = vec![FieldElement::::zero(); num_transition]; let mut base_buf = vec![FieldElement::::zero(); num_base]; - let mut frame = - Frame::preallocate(num_offsets, rows_per_step, num_main_cols, num_aux_cols); boundary_evaluation .into_iter() .enumerate() - .map(|(i, boundary)| { - eval_row(i, boundary, &mut transition_buf, &mut base_buf, &mut frame) - }) + .map(|(i, boundary)| eval_row(i, boundary, &mut transition_buf, &mut base_buf)) .collect() } } diff --git a/crypto/stark/src/debug.rs b/crypto/stark/src/debug.rs index 04ce1cf62..d2f049190 100644 --- a/crypto/stark/src/debug.rs +++ b/crypto/stark/src/debug.rs @@ -104,7 +104,7 @@ pub fn validate_trace< for step in 0..lde_trace.num_steps() { let frame = Frame::read_step_from_lde(&lde_trace, step, &air.context().transition_offsets); let transition_evaluation_context = TransitionEvaluationContext::new_prover( - &frame, + frame.as_row_frame(), rap_challenges, &logup_alpha_powers, &logup_table_offset, diff --git a/crypto/stark/src/frame.rs b/crypto/stark/src/frame.rs index 952a3a110..deaf4e5ed 100644 --- a/crypto/stark/src/frame.rs +++ b/crypto/stark/src/frame.rs @@ -3,6 +3,80 @@ use itertools::Itertools; use math::field::element::FieldElement; use math::field::traits::{IsField, IsSubFieldOf}; +/// Maximum number of transition offsets a [`RowFrame`] can hold. Every +/// production table uses two (`[0, 1]`); the widest example AIR uses three. +pub const MAX_TRANSITION_OFFSETS: usize = 4; + +/// Borrowed per-row view of the trace for prover-side transition +/// evaluation: one contiguous `(main, aux)` row-slice pair per transition +/// offset, taken IN PLACE from the row-major storage. Replaces the per-row +/// gather-copy into an owned [`Frame`] on the evaluator hot path — the LDE +/// buffers are row-major, so a step is just two borrowed slices. +/// +/// Requires single-row steps (step_size 1) — the only shape since +/// virtual columns were removed. +pub struct RowFrame<'a, F: IsSubFieldOf, E: IsField> { + mains: [&'a [FieldElement]; MAX_TRANSITION_OFFSETS], + auxs: [&'a [FieldElement]; MAX_TRANSITION_OFFSETS], + num_offsets: usize, +} + +// Manual impls: the derives would demand `F: Copy`/`E: Copy`, but every field +// is a shared reference (or usize), which is Copy for any field type. +impl, E: IsField> Clone for RowFrame<'_, F, E> { + fn clone(&self) -> Self { + *self + } +} +impl, E: IsField> Copy for RowFrame<'_, F, E> {} + +impl<'a, F: IsSubFieldOf, E: IsField> RowFrame<'a, F, E> { + /// Borrow the rows for LDE point `row` at each transition offset, + /// wrapping cyclically at the domain end (same row arithmetic as + /// [`Frame::fill_from_lde`] with single-row steps). + pub fn from_lde(lde_trace: &'a LDETraceTable, row: usize, offsets: &[usize]) -> Self { + debug_assert_eq!( + lde_trace.lde_step_size, lde_trace.blowup_factor, + "RowFrame requires single-row steps (step_size 1)" + ); + assert!( + offsets.len() <= MAX_TRANSITION_OFFSETS, + "RowFrame supports at most {MAX_TRANSITION_OFFSETS} transition offsets" + ); + let num_rows = lde_trace.num_rows(); + let mut mains: [&'a [FieldElement]; MAX_TRANSITION_OFFSETS] = + [&[]; MAX_TRANSITION_OFFSETS]; + let mut auxs: [&'a [FieldElement]; MAX_TRANSITION_OFFSETS] = + [&[]; MAX_TRANSITION_OFFSETS]; + for (k, &offset) in offsets.iter().enumerate() { + let idx = (row + offset * lde_trace.lde_step_size) % num_rows; + mains[k] = lde_trace.main_row(idx); + auxs[k] = lde_trace.aux_row(idx); + } + Self { + mains, + auxs, + num_offsets: offsets.len(), + } + } + + /// The main-trace element at (offset position, column). + #[inline(always)] + pub fn main(&self, offset: usize, col: usize) -> &FieldElement { + &self.mains[offset][col] + } + + /// The aux-trace element at (offset position, column). + #[inline(always)] + pub fn aux(&self, offset: usize, col: usize) -> &FieldElement { + &self.auxs[offset][col] + } + + pub fn num_offsets(&self) -> usize { + self.num_offsets + } +} + /// A frame represents a collection of trace steps. /// The collected steps are all the necessary steps for /// all transition constraints over a trace to be evaluated. @@ -23,6 +97,31 @@ impl, E: IsField> Frame { &self.steps[step] } + /// Borrow this frame's single-row steps as a [`RowFrame`] — the bridge + /// for callers that own a `Frame` (debug validation, tests); the + /// evaluator hot loop uses [`RowFrame::from_lde`] directly. + pub fn as_row_frame(&self) -> RowFrame<'_, F, E> { + assert!( + self.steps.len() <= MAX_TRANSITION_OFFSETS, + "RowFrame supports at most {MAX_TRANSITION_OFFSETS} transition offsets" + ); + let mut mains: [&[FieldElement]; MAX_TRANSITION_OFFSETS] = [&[]; MAX_TRANSITION_OFFSETS]; + let mut auxs: [&[FieldElement]; MAX_TRANSITION_OFFSETS] = [&[]; MAX_TRANSITION_OFFSETS]; + for (k, step) in self.steps.iter().enumerate() { + debug_assert!( + step.data.len() <= 1 && step.aux_data.len() <= 1, + "RowFrame requires single-row steps (step_size 1)" + ); + mains[k] = step.data.first().map(|r| r.as_slice()).unwrap_or(&[]); + auxs[k] = step.aux_data.first().map(|r| r.as_slice()).unwrap_or(&[]); + } + RowFrame { + mains, + auxs, + num_offsets: self.steps.len(), + } + } + /// Build a Frame by gathering row data from a column-major LDETraceTable. /// /// Each step gathers elements from columns into owned Vecs. For the typical @@ -74,69 +173,4 @@ impl, E: IsField> Frame { let row = lde_trace.step_to_row(step); Self::read_from_lde(lde_trace, row, offsets) } - - /// Pre-allocate a Frame with the right dimensions for reuse in hot loops. - /// - /// The frame will have `offsets.len()` steps, each containing - /// `step_size / blowup_factor` rows (typically 1) of main and aux columns. - pub fn preallocate( - num_offsets: usize, - rows_per_step: usize, - num_main_cols: usize, - num_aux_cols: usize, - ) -> Self { - let steps = (0..num_offsets) - .map(|_| { - let main_data: Vec>> = (0..rows_per_step) - .map(|_| vec![FieldElement::zero(); num_main_cols]) - .collect(); - let aux_data: Vec>> = (0..rows_per_step) - .map(|_| vec![FieldElement::zero(); num_aux_cols]) - .collect(); - TableView::new(main_data, aux_data) - }) - .collect(); - Frame { steps } - } - - /// Fill a pre-allocated frame from LDE data, without allocating. - /// - /// The frame must have been created with `preallocate` with matching dimensions. - pub fn fill_from_lde( - &mut self, - lde_trace: &LDETraceTable, - row: usize, - offsets: &[usize], - ) { - let blowup_factor = lde_trace.blowup_factor; - let num_rows = lde_trace.num_rows(); - let step_size = lde_trace.lde_step_size; - let num_main_cols = lde_trace.num_main_cols(); - let num_aux_cols = lde_trace.num_aux_cols(); - - for (step_idx, &offset) in offsets.iter().enumerate() { - let initial_step_row = row + offset * step_size; - let end_step_row = initial_step_row + step_size; - let step = &mut self.steps[step_idx]; - - let mut sub_row_idx = 0; - let mut step_row = initial_step_row; - while step_row < end_step_row { - let step_row_idx = step_row % num_rows; - - // Overwrite main row elements - for col in 0..num_main_cols { - step.data[sub_row_idx][col] = lde_trace.get_main(step_row_idx, col).clone(); - } - - // Overwrite aux row elements - for col in 0..num_aux_cols { - step.aux_data[sub_row_idx][col] = lde_trace.get_aux(step_row_idx, col).clone(); - } - - sub_row_idx += 1; - step_row += blowup_factor; - } - } - } } diff --git a/crypto/stark/src/lookup.rs b/crypto/stark/src/lookup.rs index 0ed4b56ad..b046eccdb 100644 --- a/crypto/stark/src/lookup.rs +++ b/crypto/stark/src/lookup.rs @@ -2338,7 +2338,7 @@ mod logup_single_source_tests { let table_offset = rand_fp3(&mut rng); let prover_ctx = TransitionEvaluationContext::new_prover( - &frame, + frame.as_row_frame(), &rap_challenges, &alpha_powers, &table_offset, diff --git a/crypto/stark/src/trace.rs b/crypto/stark/src/trace.rs index 0782ea245..831b95284 100644 --- a/crypto/stark/src/trace.rs +++ b/crypto/stark/src/trace.rs @@ -453,6 +453,18 @@ where &self.aux_data[row * self.num_aux_cols + col] } + /// Borrow a full main-trace row as a contiguous slice (row-major buffer). + #[inline] + pub fn main_row(&self, row: usize) -> &[FieldElement] { + &self.main_data[row * self.num_main_cols..(row + 1) * self.num_main_cols] + } + + /// Borrow a full aux-trace row as a contiguous slice (row-major buffer). + #[inline] + pub fn aux_row(&self, row: usize) -> &[FieldElement] { + &self.aux_data[row * self.num_aux_cols..(row + 1) * self.num_aux_cols] + } + /// Gather a full main-trace row into an owned Vec. /// Used by `open_trace_polys` (called ~30 times per table, allocation is negligible). pub fn gather_main_row(&self, row_idx: usize) -> Vec> { diff --git a/crypto/stark/src/traits.rs b/crypto/stark/src/traits.rs index 4818d8be4..747290cdb 100644 --- a/crypto/stark/src/traits.rs +++ b/crypto/stark/src/traits.rs @@ -15,7 +15,7 @@ use crate::{ use super::{ config::Commitment, constraints::boundary::BoundaryConstraints, context::AirContext, - frame::Frame, proof::options::ProofOptions, trace::TraceTable, + frame::Frame, frame::RowFrame, proof::options::ProofOptions, trace::TraceTable, }; /// Deduplicated zerofier evaluations: unique zerofier vectors indexed by constraint. @@ -71,7 +71,9 @@ where E: IsField, { Prover { - frame: &'a Frame, + /// Borrowed row view straight into the row-major trace storage — + /// the prover hot path never copies rows into an owned frame. + rows: RowFrame<'a, F, E>, rap_challenges: &'a [FieldElement], logup_alpha_powers: &'a [FieldElement], logup_table_offset: &'a FieldElement, @@ -92,14 +94,14 @@ where E: IsField, { pub fn new_prover( - frame: &'a Frame, + rows: RowFrame<'a, F, E>, rap_challenges: &'a [FieldElement], logup_alpha_powers: &'a [FieldElement], logup_table_offset: &'a FieldElement, packing_shifts: &'a PackingShifts, ) -> Self { Self::Prover { - frame, + rows, rap_challenges, logup_alpha_powers, logup_table_offset, diff --git a/prover/src/tests/constraint_emit_tests.rs b/prover/src/tests/constraint_emit_tests.rs index 5439d4635..c9a6410ca 100644 --- a/prover/src/tests/constraint_emit_tests.rs +++ b/prover/src/tests/constraint_emit_tests.rs @@ -115,8 +115,13 @@ fn check_emit(label: &str, body: &T, meta: &[ConstraintMeta]) { // --- ProverEvalFolder (base) --- let frame = Frame::::new(vec![TableView::new(vec![row.clone()], vec![vec![]])]); - let ctx = - TransitionEvaluationContext::new_prover(&frame, &no_ch, &no_ch, &offset_e, &shifts); + let ctx = TransitionEvaluationContext::new_prover( + frame.as_row_frame(), + &no_ch, + &no_ch, + &offset_e, + &shifts, + ); let mut base_out = vec![FE::zero(); n]; let mut ext_out = vec![Fp3::zero(); n]; let mut folder = ProverEvalFolder::new(&ctx, &mut base_out, &mut ext_out); diff --git a/prover/src/tests/constraint_set_tests_a.rs b/prover/src/tests/constraint_set_tests_a.rs index 2387f0cad..7be6d4359 100644 --- a/prover/src/tests/constraint_set_tests_a.rs +++ b/prover/src/tests/constraint_set_tests_a.rs @@ -100,8 +100,13 @@ where // --- ProverEvalFolder (base) --- let frame = Frame::::new(vec![TableView::new(vec![row.clone()], vec![vec![]])]); - let ctx = - TransitionEvaluationContext::new_prover(&frame, &no_ch, &no_ch, &offset_e, &shifts); + let ctx = TransitionEvaluationContext::new_prover( + frame.as_row_frame(), + &no_ch, + &no_ch, + &offset_e, + &shifts, + ); let mut base_out = vec![FE::zero(); n]; let mut ext_out = vec![Fp3::zero(); n]; let mut folder = ProverEvalFolder::new(&ctx, &mut base_out, &mut ext_out); diff --git a/prover/src/tests/constraint_set_tests_b.rs b/prover/src/tests/constraint_set_tests_b.rs index c81a03008..492d6dad8 100644 --- a/prover/src/tests/constraint_set_tests_b.rs +++ b/prover/src/tests/constraint_set_tests_b.rs @@ -93,8 +93,13 @@ fn check_table>(label: &str, set: &CS, num_cols: usiz // --- ProverEvalFolder (base) --- let frame = Frame::::new(vec![TableView::new(vec![row.clone()], vec![vec![]])]); - let ctx = - TransitionEvaluationContext::new_prover(&frame, &no_ch, &no_ch, &offset_e, &shifts); + let ctx = TransitionEvaluationContext::new_prover( + frame.as_row_frame(), + &no_ch, + &no_ch, + &offset_e, + &shifts, + ); let mut base_out = vec![FE::zero(); n]; let mut ext_out = vec![Fp3::zero(); n]; let mut folder = ProverEvalFolder::new(&ctx, &mut base_out, &mut ext_out); diff --git a/prover/src/tests/cpu32_tests.rs b/prover/src/tests/cpu32_tests.rs index 8627e107a..37f2bfec2 100644 --- a/prover/src/tests/cpu32_tests.rs +++ b/prover/src/tests/cpu32_tests.rs @@ -25,7 +25,13 @@ fn eval_cpu32(row: &[FE]) -> Vec { let shifts = PackingShifts::::new(); let no_e: Vec> = vec![]; let offset_e = FieldElement::::zero(); - let ctx = TransitionEvaluationContext::new_prover(&frame, &no_e, &no_e, &offset_e, &shifts); + let ctx = TransitionEvaluationContext::new_prover( + frame.as_row_frame(), + &no_e, + &no_e, + &offset_e, + &shifts, + ); let mut base = vec![FE::zero(); n]; let mut ext = vec![FieldElement::::zero(); n]; let mut folder = ProverEvalFolder::new(&ctx, &mut base, &mut ext); diff --git a/prover/src/tests/ec_scalar_tests.rs b/prover/src/tests/ec_scalar_tests.rs index 01afec94e..b8a60edc5 100644 --- a/prover/src/tests/ec_scalar_tests.rs +++ b/prover/src/tests/ec_scalar_tests.rs @@ -27,7 +27,13 @@ fn eval_row(trace: &TraceTable, row: usize let shifts = PackingShifts::::new(); let no_e: Vec> = vec![]; let offset_e = FieldElement::::zero(); - let ctx = TransitionEvaluationContext::new_prover(&frame, &no_e, &no_e, &offset_e, &shifts); + let ctx = TransitionEvaluationContext::new_prover( + frame.as_row_frame(), + &no_e, + &no_e, + &offset_e, + &shifts, + ); let mut base = vec![FE::zero(); n]; let mut ext = vec![FieldElement::::zero(); n]; let mut folder = ProverEvalFolder::new(&ctx, &mut base, &mut ext); diff --git a/prover/src/tests/ecdas_tests.rs b/prover/src/tests/ecdas_tests.rs index bb5083323..b692d5c4a 100644 --- a/prover/src/tests/ecdas_tests.rs +++ b/prover/src/tests/ecdas_tests.rs @@ -58,7 +58,13 @@ fn eval_row(trace: &TraceTable, row: usize let shifts = PackingShifts::::new(); let no_e: Vec> = vec![]; let offset_e = FieldElement::::zero(); - let ctx = TransitionEvaluationContext::new_prover(&frame, &no_e, &no_e, &offset_e, &shifts); + let ctx = TransitionEvaluationContext::new_prover( + frame.as_row_frame(), + &no_e, + &no_e, + &offset_e, + &shifts, + ); let mut base = vec![FE::zero(); n]; let mut ext = vec![FieldElement::::zero(); n]; let mut folder = ProverEvalFolder::new(&ctx, &mut base, &mut ext); diff --git a/prover/src/tests/ecsm_tests.rs b/prover/src/tests/ecsm_tests.rs index 7ba04dc7d..3b671a8fd 100644 --- a/prover/src/tests/ecsm_tests.rs +++ b/prover/src/tests/ecsm_tests.rs @@ -54,7 +54,13 @@ fn eval_row(trace: &TraceTable, row: usize let shifts = PackingShifts::::new(); let no_e: Vec> = vec![]; let offset_e = FieldElement::::zero(); - let ctx = TransitionEvaluationContext::new_prover(&frame, &no_e, &no_e, &offset_e, &shifts); + let ctx = TransitionEvaluationContext::new_prover( + frame.as_row_frame(), + &no_e, + &no_e, + &offset_e, + &shifts, + ); let mut base = vec![FE::zero(); n]; let mut ext = vec![FieldElement::::zero(); n]; let mut folder = ProverEvalFolder::new(&ctx, &mut base, &mut ext);