Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 poly_commit/src/batching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ where
for (tilde_g, tilde_eq) in tilde_gs.iter().zip(tilde_eqs.into_iter()) {
sumcheck_poly.add_pair(tilde_g.clone(), tilde_eq);
}
let proof = SumCheck::<C::Scalar>::prove(&sumcheck_poly, transcript);
let proof = SumCheck::<C::Scalar>::prove(sumcheck_poly, transcript);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Changing SumCheck::<C::Scalar>::prove to take sumcheck_poly by value (move semantics) directly addresses the PR's goal of reducing memory consumption by avoiding an implicit clone. This is a crucial optimization for large polynomial workloads.

timer.stop();

let a2 = proof.export_point_to_expander();
Expand Down
5 changes: 3 additions & 2 deletions sumcheck/src/sumcheck_generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,14 @@ impl<F: Field> SumCheck<F> {
/// Generate proof of the sum of polynomial over {0,1}^`num_vars`
///
/// The polynomial is represented in the form of a VirtualPolynomial.
/// Takes ownership of poly_list to avoid cloning internally.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Updating the doc comment to explicitly state that poly_list takes ownership is crucial for understanding the new memory semantics and the motivation behind this change.

pub fn prove(
poly_list: &SumOfProductsPoly<F>,
poly_list: SumOfProductsPoly<F>,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Changing the poly_list parameter from a reference (&SumOfProductsPoly<F>) to a value (SumOfProductsPoly<F>) is the core change enabling move semantics. This directly addresses the memory optimization goal by transferring ownership and preventing an implicit clone within the prove function.

transcript: &mut impl Transcript,
) -> IOPProof<F> {
let num_vars = poly_list.num_vars();

let mut prover_state = IOPProverState::prover_init(poly_list);
let mut prover_state = IOPProverState::prover_init_owned(poly_list);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Calling prover_init_owned instead of prover_init ensures that the SumOfProductsPoly is moved into the prover state, avoiding a costly clone operation. This is a direct implementation of the PR's memory optimization objective.

let mut challenge = None;
let mut prover_msgs = Vec::with_capacity(num_vars);
for _ in 0..num_vars {
Expand Down
26 changes: 26 additions & 0 deletions sumcheck/src/sumcheck_generic/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,32 @@ impl<F: Field> IOPProverState<F> {
}
}

/// Initialize the prover state by taking ownership of the polynomials,
/// avoiding the clone in `prover_init`.
Comment on lines +34 to +35
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The doc comment for prover_init_owned clearly explains its purpose: to initialize the prover state by taking ownership of polynomials and avoiding an internal clone. This is good documentation for a new, optimized function.

pub fn prover_init_owned(polynomials: SumOfProductsPoly<F>) -> Self {
let num_vars = polynomials.num_vars();
let init_sum_of_vals: Vec<F> = polynomials
.f_and_g_pairs
.par_iter()
.map(|(f, g)| {
f.coeffs
.iter()
.zip(g.coeffs.iter())
.map(|(&f, &g)| f * g)
.sum::<F>()
})
.collect();
let eq_prefix = vec![F::one(); polynomials.f_and_g_pairs.len()];
Self {
challenges: Vec::with_capacity(num_vars),
round: 0,
init_num_vars: num_vars,
mle_list: polynomials,
init_sum_of_vals,
eq_prefix,
}
Comment on lines +36 to +57
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The prover_init_owned function is correctly implemented to accept polynomials by value, directly moving it into mle_list. This is the key mechanism for the memory optimization, as it prevents the SumOfProductsPoly from being cloned, which was identified as a significant memory consumer.

}

/// Receive message from verifier, generate prover message, and proceed to
/// next round.
///
Expand Down
6 changes: 3 additions & 3 deletions sumcheck/src/sumcheck_generic/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ fn test_sumcheck_e2e() {

// prover
let mut transcript = BytesHashTranscript::<Keccak256hasher>::new();
let proof = SumCheck::<Fr>::prove(&mle_list, &mut transcript);
let proof = SumCheck::<Fr>::prove(mle_list.clone(), &mut transcript);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The addition of .clone() here is necessary because mle_list is used again later in the test for evaluation (mle_list.evaluate(&subclaim.point)). This correctly adapts the test to the new prove signature while preserving the original test logic.


// verifier
let mut transcript = BytesHashTranscript::<Keccak256hasher>::new();
Expand Down Expand Up @@ -119,7 +119,7 @@ fn test_sumcheck_generic_padding_helper<F: Field, T: Transcript>() {
};
let claimed_sum = mle_list.sum();

let proof = SumCheck::prove(&mle_list, &mut T::new());
let proof = SumCheck::prove(mle_list.clone(), &mut T::new());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Similar to the previous comment, mle_list.clone() is correctly added here because mle_list is needed for subsequent operations in the test, such as creating padded_mle_list and evaluating against subclaim.point.


let padded_mle_list = SumOfProductsPoly {
f_and_g_pairs: mle_list
Expand All @@ -135,7 +135,7 @@ fn test_sumcheck_generic_padding_helper<F: Field, T: Transcript>() {
.collect(),
};

let proof_with_padded_mle_list = SumCheck::prove(&padded_mle_list, &mut T::new());
let proof_with_padded_mle_list = SumCheck::prove(padded_mle_list, &mut T::new());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Passing padded_mle_list directly (by value) is correct here because padded_mle_list is not used after this call. This demonstrates the intended use of the new prove signature, where ownership is transferred, and no unnecessary cloning occurs.


assert_eq!(proof, proof_with_padded_mle_list);

Expand Down
Loading