Skip to content

Commit dc85036

Browse files
authored
fix(sumcheck): scale polynomial evals for phase1 gap rounds in RAF and output check (#1385)
When phase1_num_rounds < log_T, the input_claim for RafEvaluation and OutputCheck sumchecks is pre-scaled by 2^(phase3_cycle_rounds) to pre-compensate for the gap-round halvings. However, the raw polynomial evaluations computed from the witness data sum to the unscaled claim. This mismatch causes UniPoly reconstruction to produce an incorrect polynomial, failing the verifier's poly(0) + poly(1) == previous_claim check. Scale the raw evaluations by 2^(phase3_cycle_rounds) before polynomial reconstruction so they are consistent with the pre-scaled previous_claim. Made-with: Cursor
1 parent 78134ca commit dc85036

File tree

2 files changed

+25
-2
lines changed

2 files changed

+25
-2
lines changed

jolt-core/src/zkvm/ram/output_check.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,20 @@ impl<F: JoltField, T: Transcript> SumcheckInstanceProver<F, T> for OutputSumchec
308308
[c0, e]
309309
});
310310

311-
eq_r_address.gruen_poly_deg_3(q_constant, q_quadratic, previous_claim)
311+
// When phase1_num_rounds < log_T, the input_claim is pre-scaled by
312+
// 2^(phase3_cycle_rounds) to compensate for the gap-round halvings that follow.
313+
// The raw q_constant and q_quadratic sum to the unscaled claim, so we must
314+
// scale them by the same factor to satisfy poly(0) + poly(1) == previous_claim.
315+
let gap = self.params.phase3_cycle_rounds();
316+
if gap > 0 {
317+
eq_r_address.gruen_poly_deg_3(
318+
q_constant.mul_pow_2(gap),
319+
q_quadratic.mul_pow_2(gap),
320+
previous_claim,
321+
)
322+
} else {
323+
eq_r_address.gruen_poly_deg_3(q_constant, q_quadratic, previous_claim)
324+
}
312325
}
313326

314327
#[tracing::instrument(skip_all, name = "OutputSumcheckProver::ingest_challenge")]

jolt-core/src/zkvm/ram/raf_evaluation.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,17 @@ impl<F: JoltField, T: Transcript> SumcheckInstanceProver<F, T> for RafEvaluation
306306
)
307307
.map(F::reduce_product_accum);
308308

309-
UniPoly::from_evals_and_hint(previous_claim, &evals)
309+
// When phase1_num_rounds < log_T, the input_claim is pre-scaled by
310+
// 2^(phase3_cycle_rounds) to compensate for the gap-round halvings that follow.
311+
// The raw polynomial evals sum to the unscaled claim, so we must scale them
312+
// by the same factor to satisfy poly(0) + poly(1) == previous_claim.
313+
let gap = self.params.phase3_cycle_rounds();
314+
if gap > 0 {
315+
let scaled: Vec<F> = evals.iter().map(|e| e.mul_pow_2(gap)).collect();
316+
UniPoly::from_evals_and_hint(previous_claim, &scaled)
317+
} else {
318+
UniPoly::from_evals_and_hint(previous_claim, &evals)
319+
}
310320
}
311321

312322
#[tracing::instrument(skip_all, name = "RamRafEvaluationSumcheckProver::ingest_challenge")]

0 commit comments

Comments
 (0)