From 2e7754604527144fc411f3d89f53ddc2c67fefea Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sun, 31 May 2026 07:49:56 +0300 Subject: [PATCH 01/12] quotient is a vec now --- w3f-plonk-common/src/lib.rs | 7 ++++--- w3f-plonk-common/src/piop.rs | 4 ++++ w3f-plonk-common/src/prover.rs | 26 ++++++++++++++---------- w3f-plonk-common/src/q_chunking.rs | 32 ++++++++++++++++++++++++++++++ w3f-plonk-common/src/verifier.rs | 6 ++++-- 5 files changed, 60 insertions(+), 15 deletions(-) create mode 100644 w3f-plonk-common/src/q_chunking.rs diff --git a/w3f-plonk-common/src/lib.rs b/w3f-plonk-common/src/lib.rs index 7f0f89d..78a232d 100644 --- a/w3f-plonk-common/src/lib.rs +++ b/w3f-plonk-common/src/lib.rs @@ -17,6 +17,7 @@ pub mod prover; pub mod test_helpers; pub mod transcript; pub mod verifier; +mod q_chunking; pub trait Column { fn domain(&self) -> GeneralEvaluationDomain; @@ -103,7 +104,7 @@ where { pub column_commitments: Commitments, pub columns_at_zeta: Evaluations, - pub quotient_commitment: CS::C, + pub quotient_chunks: Vec, pub lin_at_zeta_omega: F, pub agg_at_zeta_proof: CS::Proof, pub lin_at_zeta_omega_proof: CS::Proof, @@ -120,7 +121,7 @@ where { pub column_commitments: Commitments, pub columns_at_zeta: Evaluations, - pub quotient_commitment: C, + pub quotient_chunks: Vec, pub lin_at_zeta_omega: F, } @@ -135,7 +136,7 @@ where PiopProof { column_commitments: self.column_commitments.clone(), columns_at_zeta: self.columns_at_zeta.clone(), - quotient_commitment: self.quotient_commitment.clone(), + quotient_chunks: self.quotient_chunks.clone(), lin_at_zeta_omega: self.lin_at_zeta_omega, } } diff --git a/w3f-plonk-common/src/piop.rs b/w3f-plonk-common/src/piop.rs index fd9ec12..ecb3019 100644 --- a/w3f-plonk-common/src/piop.rs +++ b/w3f-plonk-common/src/piop.rs @@ -32,6 +32,10 @@ pub trait ProverPiop> { // Constraint polynomials in evaluation form. fn constraints(&self) -> Vec>; + fn quotient_chunks(&self, alphas: &[F]) -> Option>> { + self.compute_quotient(alphas).map(|q|vec![q]) + } + fn compute_quotient(&self, alphas: &[F]) -> Option> { let constraints = self.constraints(); // Aggregate constraint polynomials in evaluation form... diff --git a/w3f-plonk-common/src/prover.rs b/w3f-plonk-common/src/prover.rs index 0779926..dcbc6ce 100644 --- a/w3f-plonk-common/src/prover.rs +++ b/w3f-plonk-common/src/prover.rs @@ -69,15 +69,21 @@ impl, T: PlonkTranscript> PlonkProver end_timer!(t_commit_cols); // ROUND 2 + // The prover commits to the quotient polynomial... let alphas = transcript.get_constraints_aggregation_coeffs(P::N_CONSTRAINTS); - let quotient_poly = piop.compute_quotient(&alphas).unwrap(); + let quotient_chunks = piop.quotient_chunks(&alphas).unwrap(); let t_commit_q = start_timer!(|| format!( - "Committing to the degree-{} quotient", - quotient_poly.degree() + "Committing to {} degree-{} quotient chunks", quotient_chunks.len(), + quotient_chunks[0].degree() )); - // The prover commits to the quotient polynomial... - let quotient_commitment = CS::commit(&self.pcs_ck, "ient_poly).unwrap(); - transcript.add_quotient_commitment("ient_commitment); + let quotient_chunks_committed: Vec<_> = quotient_chunks.iter() + .map(|qi| CS::commit(&self.pcs_ck, qi).unwrap()) + .collect(); + for qi_committed in quotient_chunks_committed.iter() { + transcript.add_quotient_commitment(&qi_committed); + } + // let quotient_commitment = CS::commit(&self.pcs_ck, "ient_poly).unwrap(); + // transcript.add_quotient_commitment("ient_commitment); end_timer!(t_commit_q); // and receives the evaluation point in response @@ -94,11 +100,11 @@ impl, T: PlonkTranscript> PlonkProver transcript.add_evaluations(&columns_at_zeta, &lin_at_zeta_omega); let piop_proof = PiopProof { column_commitments, - quotient_commitment, + quotient_chunks: quotient_chunks_committed, columns_at_zeta, lin_at_zeta_omega, }; - let polys_at_zeta = [columns_to_open, vec![quotient_poly]].concat(); + let polys_at_zeta = [columns_to_open, quotient_chunks].concat(); let pcs_openings = PcsOpeningAt2Points { polys_at_zeta, polys_at_zeta_omega: vec![lin], @@ -122,7 +128,7 @@ impl, T: PlonkTranscript> PlonkProver let lin = &polys_at_zeta_omega[0]; let PiopProof { column_commitments, - quotient_commitment, + quotient_chunks: quotient_commitment, columns_at_zeta, lin_at_zeta_omega, } = piop_proof; @@ -137,7 +143,7 @@ impl, T: PlonkTranscript> PlonkProver end_timer!(_t_open_zeta_omega); Proof { column_commitments, - quotient_commitment, + quotient_chunks: quotient_commitment, columns_at_zeta, lin_at_zeta_omega, agg_at_zeta_proof, diff --git a/w3f-plonk-common/src/q_chunking.rs b/w3f-plonk-common/src/q_chunking.rs new file mode 100644 index 0000000..33623a2 --- /dev/null +++ b/w3f-plonk-common/src/q_chunking.rs @@ -0,0 +1,32 @@ +use ark_ff::{Field, PrimeField}; +use ark_poly::DenseUVPolynomial; +use ark_poly::univariate::DensePolynomial; +use w3f_pcs::pcs::Commitment; +use w3f_pcs::utils; + +fn chunk_quotient(q: DensePolynomial, n: usize) -> Vec> { + q.coeffs + .chunks(n) + .map(|coeffs| DensePolynomial::from_coefficients_slice(coeffs)) + .collect() +} + +fn fold_quotient_chunks(chunks: &[DensePolynomial], z_to_n: F) -> DensePolynomial { + chunks.iter() + .zip(utils::powers(z_to_n)) + .map(|(chunk, coeff)| chunk * coeff) + .reduce(|acc, new| acc + new) + .unwrap() +} + +fn quotient_commitment>(chunks: &[C], z_to_n: F) -> C { + chunks.iter() + .zip(utils::powers(z_to_n)) + .map(|(chunk, coeff)| chunk.mul(coeff)) + .sum() +} + +#[cfg(test)] +mod tests { + +} \ No newline at end of file diff --git a/w3f-plonk-common/src/verifier.rs b/w3f-plonk-common/src/verifier.rs index 4561559..14e9edf 100644 --- a/w3f-plonk-common/src/verifier.rs +++ b/w3f-plonk-common/src/verifier.rs @@ -53,7 +53,7 @@ impl, T: PlonkTranscript> PlonkVerifier, T: PlonkTranscript> PlonkVerifier Date: Sun, 31 May 2026 16:44:07 +0300 Subject: [PATCH 02/12] fmt --- w3f-plonk-common/src/lib.rs | 2 +- w3f-plonk-common/src/piop.rs | 2 +- w3f-plonk-common/src/prover.rs | 6 ++++-- w3f-plonk-common/src/q_chunking.rs | 12 ++++++------ 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/w3f-plonk-common/src/lib.rs b/w3f-plonk-common/src/lib.rs index 78a232d..9167cd9 100644 --- a/w3f-plonk-common/src/lib.rs +++ b/w3f-plonk-common/src/lib.rs @@ -14,10 +14,10 @@ pub mod gadgets; pub mod kzg_acc; pub mod piop; pub mod prover; +mod q_chunking; pub mod test_helpers; pub mod transcript; pub mod verifier; -mod q_chunking; pub trait Column { fn domain(&self) -> GeneralEvaluationDomain; diff --git a/w3f-plonk-common/src/piop.rs b/w3f-plonk-common/src/piop.rs index ecb3019..d0f693f 100644 --- a/w3f-plonk-common/src/piop.rs +++ b/w3f-plonk-common/src/piop.rs @@ -33,7 +33,7 @@ pub trait ProverPiop> { fn constraints(&self) -> Vec>; fn quotient_chunks(&self, alphas: &[F]) -> Option>> { - self.compute_quotient(alphas).map(|q|vec![q]) + self.compute_quotient(alphas).map(|q| vec![q]) } fn compute_quotient(&self, alphas: &[F]) -> Option> { diff --git a/w3f-plonk-common/src/prover.rs b/w3f-plonk-common/src/prover.rs index dcbc6ce..af73118 100644 --- a/w3f-plonk-common/src/prover.rs +++ b/w3f-plonk-common/src/prover.rs @@ -73,10 +73,12 @@ impl, T: PlonkTranscript> PlonkProver let alphas = transcript.get_constraints_aggregation_coeffs(P::N_CONSTRAINTS); let quotient_chunks = piop.quotient_chunks(&alphas).unwrap(); let t_commit_q = start_timer!(|| format!( - "Committing to {} degree-{} quotient chunks", quotient_chunks.len(), + "Committing to {} degree-{} quotient chunks", + quotient_chunks.len(), quotient_chunks[0].degree() )); - let quotient_chunks_committed: Vec<_> = quotient_chunks.iter() + let quotient_chunks_committed: Vec<_> = quotient_chunks + .iter() .map(|qi| CS::commit(&self.pcs_ck, qi).unwrap()) .collect(); for qi_committed in quotient_chunks_committed.iter() { diff --git a/w3f-plonk-common/src/q_chunking.rs b/w3f-plonk-common/src/q_chunking.rs index 33623a2..32e099c 100644 --- a/w3f-plonk-common/src/q_chunking.rs +++ b/w3f-plonk-common/src/q_chunking.rs @@ -1,6 +1,6 @@ use ark_ff::{Field, PrimeField}; -use ark_poly::DenseUVPolynomial; use ark_poly::univariate::DensePolynomial; +use ark_poly::DenseUVPolynomial; use w3f_pcs::pcs::Commitment; use w3f_pcs::utils; @@ -12,7 +12,8 @@ fn chunk_quotient(q: DensePolynomial, n: usize) -> Vec(chunks: &[DensePolynomial], z_to_n: F) -> DensePolynomial { - chunks.iter() + chunks + .iter() .zip(utils::powers(z_to_n)) .map(|(chunk, coeff)| chunk * coeff) .reduce(|acc, new| acc + new) @@ -20,13 +21,12 @@ fn fold_quotient_chunks(chunks: &[DensePolynomial], z_to_n: F) -> D } fn quotient_commitment>(chunks: &[C], z_to_n: F) -> C { - chunks.iter() + chunks + .iter() .zip(utils::powers(z_to_n)) .map(|(chunk, coeff)| chunk.mul(coeff)) .sum() } #[cfg(test)] -mod tests { - -} \ No newline at end of file +mod tests {} From 376fd917f604a7174c2a88b8636ac3edb5fb0cdb Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sun, 31 May 2026 23:43:24 +0300 Subject: [PATCH 03/12] pub q_chunking --- w3f-plonk-common/src/lib.rs | 2 +- w3f-plonk-common/src/q_chunking.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/w3f-plonk-common/src/lib.rs b/w3f-plonk-common/src/lib.rs index 9167cd9..8e22961 100644 --- a/w3f-plonk-common/src/lib.rs +++ b/w3f-plonk-common/src/lib.rs @@ -14,7 +14,7 @@ pub mod gadgets; pub mod kzg_acc; pub mod piop; pub mod prover; -mod q_chunking; +pub mod q_chunking; pub mod test_helpers; pub mod transcript; pub mod verifier; diff --git a/w3f-plonk-common/src/q_chunking.rs b/w3f-plonk-common/src/q_chunking.rs index 32e099c..1b5243f 100644 --- a/w3f-plonk-common/src/q_chunking.rs +++ b/w3f-plonk-common/src/q_chunking.rs @@ -4,14 +4,14 @@ use ark_poly::DenseUVPolynomial; use w3f_pcs::pcs::Commitment; use w3f_pcs::utils; -fn chunk_quotient(q: DensePolynomial, n: usize) -> Vec> { +pub fn chunk_quotient(q: DensePolynomial, n: usize) -> Vec> { q.coeffs .chunks(n) .map(|coeffs| DensePolynomial::from_coefficients_slice(coeffs)) .collect() } -fn fold_quotient_chunks(chunks: &[DensePolynomial], z_to_n: F) -> DensePolynomial { +pub fn fold_quotient_chunks(chunks: &[DensePolynomial], z_to_n: F) -> DensePolynomial { chunks .iter() .zip(utils::powers(z_to_n)) @@ -20,7 +20,7 @@ fn fold_quotient_chunks(chunks: &[DensePolynomial], z_to_n: F) -> D .unwrap() } -fn quotient_commitment>(chunks: &[C], z_to_n: F) -> C { +pub fn compose_quotient>(chunks: &[C], z_to_n: F) -> C { chunks .iter() .zip(utils::powers(z_to_n)) From ba9a06f159f995e5c5d612949df321523c7be05e Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sun, 31 May 2026 23:44:42 +0300 Subject: [PATCH 04/12] chunking integrated --- w3f-plonk-common/src/domain.rs | 2 ++ w3f-plonk-common/src/prover.rs | 6 ++++-- w3f-plonk-common/src/verifier.rs | 8 ++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/w3f-plonk-common/src/domain.rs b/w3f-plonk-common/src/domain.rs index b7858f6..0114e3b 100644 --- a/w3f-plonk-common/src/domain.rs +++ b/w3f-plonk-common/src/domain.rs @@ -205,6 +205,7 @@ pub struct EvaluatedDomain { pub l_first: F, pub l_last: F, pub vanishing_polynomial_inv: F, + pub z_n: F, // z^N } impl EvaluatedDomain { @@ -243,6 +244,7 @@ impl EvaluatedDomain { l_first, l_last, vanishing_polynomial_inv, + z_n, } } diff --git a/w3f-plonk-common/src/prover.rs b/w3f-plonk-common/src/prover.rs index af73118..33e4430 100644 --- a/w3f-plonk-common/src/prover.rs +++ b/w3f-plonk-common/src/prover.rs @@ -11,7 +11,7 @@ use w3f_pcs::pcs::PCS; use crate::piop::ProverPiop; use crate::transcript::PlonkTranscript; -use crate::{PiopProof, Proof}; +use crate::{q_chunking, PiopProof, Proof}; pub struct PlonkProver, T: PlonkTranscript> { // Polynomial commitment scheme committer's key. @@ -92,6 +92,8 @@ impl, T: PlonkTranscript> PlonkProver // ROUND 3 let zeta = transcript.get_evaluation_point(); + let z_n = zeta.pow([piop.domain().domain_size() as u64]); + let q_folded = q_chunking::fold_quotient_chunks("ient_chunks, z_n); let columns_to_open = piop.columns(); let columns_at_zeta = piop.columns_evaluated(&zeta); let constraint_polys_linearized = piop.constraints_lin(&zeta); @@ -106,7 +108,7 @@ impl, T: PlonkTranscript> PlonkProver columns_at_zeta, lin_at_zeta_omega, }; - let polys_at_zeta = [columns_to_open, quotient_chunks].concat(); + let polys_at_zeta = [columns_to_open, vec![q_folded]].concat(); let pcs_openings = PcsOpeningAt2Points { polys_at_zeta, polys_at_zeta_omega: vec![lin], diff --git a/w3f-plonk-common/src/verifier.rs b/w3f-plonk-common/src/verifier.rs index 14e9edf..b91da46 100644 --- a/w3f-plonk-common/src/verifier.rs +++ b/w3f-plonk-common/src/verifier.rs @@ -6,7 +6,7 @@ use w3f_pcs::pcs::{Commitment, PcsParams, PCS}; use crate::piop::VerifierPiop; use crate::transcript::PlonkTranscript; -use crate::{ColumnsCommited, ColumnsEvaluated, PiopProof, Proof}; +use crate::{q_chunking, ColumnsCommited, ColumnsEvaluated, PiopProof, Proof}; pub struct PlonkVerifier, T: PlonkTranscript> { // Polynomial commitment scheme verifier's key. @@ -53,7 +53,11 @@ impl, T: PlonkTranscript> PlonkVerifier Date: Sun, 31 May 2026 23:54:17 +0300 Subject: [PATCH 05/12] chunking supported by piop --- w3f-plonk-common/src/piop.rs | 26 ++++++++++++++++++++------ w3f-plonk-common/src/prover.rs | 2 +- w3f-plonk-common/src/q_chunking.rs | 5 ++++- w3f-plonk-common/src/verifier.rs | 3 ++- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/w3f-plonk-common/src/piop.rs b/w3f-plonk-common/src/piop.rs index d0f693f..727f67c 100644 --- a/w3f-plonk-common/src/piop.rs +++ b/w3f-plonk-common/src/piop.rs @@ -1,13 +1,13 @@ +use crate::domain::{Domain, EvaluatedDomain}; +use crate::{q_chunking, ColumnsCommited, ColumnsEvaluated}; use ark_ff::{FftField, PrimeField}; use ark_poly::univariate::DensePolynomial; use ark_poly::Evaluations; +use ark_poly::Polynomial; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::vec::Vec; use w3f_pcs::pcs::Commitment; -use crate::domain::{Domain, EvaluatedDomain}; -use crate::{ColumnsCommited, ColumnsEvaluated}; - pub trait ProverPiop> { const N_COLUMNS: usize; const N_CONSTRAINTS: usize; @@ -32,11 +32,25 @@ pub trait ProverPiop> { // Constraint polynomials in evaluation form. fn constraints(&self) -> Vec>; - fn quotient_chunks(&self, alphas: &[F]) -> Option>> { - self.compute_quotient(alphas).map(|q| vec![q]) + fn _quotient_chunks(&self, alphas: &[F]) -> Option>> { + let q = Self::_compute_quotient(self, alphas); + q.map(|q| { + let q_deg = q.degree(); + let q_chunks = q_chunking::chunk_quotient(q, self.domain().domain_size()); + println!( + "Chunking deg {} polynomial into {} chunks", + q_deg, + q_chunks.len() + ); + q_chunks + }) + } + + fn quotient(&self, alphas: &[F]) -> Option>> { + self._compute_quotient(alphas).map(|q| vec![q]) } - fn compute_quotient(&self, alphas: &[F]) -> Option> { + fn _compute_quotient(&self, alphas: &[F]) -> Option> { let constraints = self.constraints(); // Aggregate constraint polynomials in evaluation form... let agg_constraint = aggregate_evaluations(&constraints, &alphas); diff --git a/w3f-plonk-common/src/prover.rs b/w3f-plonk-common/src/prover.rs index 33e4430..ba923e4 100644 --- a/w3f-plonk-common/src/prover.rs +++ b/w3f-plonk-common/src/prover.rs @@ -71,7 +71,7 @@ impl, T: PlonkTranscript> PlonkProver // ROUND 2 // The prover commits to the quotient polynomial... let alphas = transcript.get_constraints_aggregation_coeffs(P::N_CONSTRAINTS); - let quotient_chunks = piop.quotient_chunks(&alphas).unwrap(); + let quotient_chunks = piop.quotient(&alphas).unwrap(); let t_commit_q = start_timer!(|| format!( "Committing to {} degree-{} quotient chunks", quotient_chunks.len(), diff --git a/w3f-plonk-common/src/q_chunking.rs b/w3f-plonk-common/src/q_chunking.rs index 1b5243f..23ac8ef 100644 --- a/w3f-plonk-common/src/q_chunking.rs +++ b/w3f-plonk-common/src/q_chunking.rs @@ -11,7 +11,10 @@ pub fn chunk_quotient(q: DensePolynomial, n: usize) -> Vec(chunks: &[DensePolynomial], z_to_n: F) -> DensePolynomial { +pub fn fold_quotient_chunks( + chunks: &[DensePolynomial], + z_to_n: F, +) -> DensePolynomial { chunks .iter() .zip(utils::powers(z_to_n)) diff --git a/w3f-plonk-common/src/verifier.rs b/w3f-plonk-common/src/verifier.rs index b91da46..187f47e 100644 --- a/w3f-plonk-common/src/verifier.rs +++ b/w3f-plonk-common/src/verifier.rs @@ -56,7 +56,8 @@ impl, T: PlonkTranscript> PlonkVerifier Date: Sun, 31 May 2026 23:54:36 +0300 Subject: [PATCH 06/12] chunking implemented for pasta-tree --- pasta-tree/src/circuit_fat/prover.rs | 4 ++++ pasta-tree/src/circuit_tall/prover.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/pasta-tree/src/circuit_fat/prover.rs b/pasta-tree/src/circuit_fat/prover.rs index a5aa88a..97b2d21 100644 --- a/pasta-tree/src/circuit_fat/prover.rs +++ b/pasta-tree/src/circuit_fat/prover.rs @@ -166,6 +166,10 @@ impl> type Evaluations = ProofEvals; type Instance = G; + fn quotient(&self, alphas: &[C::ScalarField]) -> Option>> { + >>::_quotient_chunks(self, alphas) + } + fn committed_columns) -> WrappedAffine>( &self, commit: Fun, diff --git a/pasta-tree/src/circuit_tall/prover.rs b/pasta-tree/src/circuit_tall/prover.rs index 4ac3b60..c045dc9 100644 --- a/pasta-tree/src/circuit_tall/prover.rs +++ b/pasta-tree/src/circuit_tall/prover.rs @@ -107,6 +107,10 @@ impl> type Evaluations = ProofEvals; type Instance = G; + fn quotient(&self, alphas: &[C::ScalarField]) -> Option>> { + >>::_quotient_chunks(self, alphas) + } + fn committed_columns) -> WrappedAffine>( &self, commit: Fun, From 68e850595e15c417940000e2bdab4e450c251b6a Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sun, 31 May 2026 23:54:48 +0300 Subject: [PATCH 07/12] tests --- pasta-tree/src/lib.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index b9353a4..b579f29 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -243,6 +243,26 @@ mod tests { } } + #[test] + fn test_circuit_tall() { + _test_proof::< + ark_pallas::Projective, + ark_vesta::Projective, + CircuitParamsTall, + CircuitParamsTall, + >(9, 2); + } + + #[test] + fn test_circuit_fat() { + _test_proof::< + ark_pallas::Projective, + ark_vesta::Projective, + CircuitParamsFat, + CircuitParamsFat, + >(8, 4); + } + // cargo test test_bench_curve_tree --release --features="print-trace" -- --show-output // cargo test test_bench_curve_tree --release --features="print-trace parallel" -- --show-output #[test] From f5ca67106f88d9807aaab87a4cea79c63579a401 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Mon, 1 Jun 2026 00:12:28 +0300 Subject: [PATCH 08/12] kzg_acc supports chunking --- w3f-plonk-common/src/kzg_acc.rs | 20 +++++++++++++++----- w3f-plonk-common/src/q_chunking.rs | 8 ++++++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/w3f-plonk-common/src/kzg_acc.rs b/w3f-plonk-common/src/kzg_acc.rs index 0b7bbeb..306cb4c 100644 --- a/w3f-plonk-common/src/kzg_acc.rs +++ b/w3f-plonk-common/src/kzg_acc.rs @@ -1,6 +1,6 @@ use crate::piop::VerifierPiop; use crate::verifier::Challenges; -use crate::{ColumnsCommited, ColumnsEvaluated, Proof}; +use crate::{q_chunking, ColumnsCommited, ColumnsEvaluated, Proof}; use ark_ec::pairing::Pairing; use ark_ec::{CurveGroup, VariableBaseMSM}; use ark_ff::{PrimeField, Zero}; @@ -93,8 +93,8 @@ impl KzgAccumulator { let zeta_omega = zeta * piop.domain_evaluated().omega(); let lin_comm = piop.lin_poly_commitment(&challenges.alphas); - // Openning at `z` - // TODO: try to get rid of the commitment wrapper in flonk + // Openning at `z`. Columns and the quotient are aggregated using `nu`s. + let mut r_nus = challenges.nus.iter().map(|nu| r * nu); self.acc_points.extend( piop.precommitted_columns() .iter() @@ -109,9 +109,19 @@ impl KzgAccumulator { .map(|c| c.0) .collect::>(), ); - self.acc_points.push(proof.quotient_commitment.clone().0); self.acc_scalars - .extend(challenges.nus.iter().map(|nu| *nu * r).collect::>()); // numbers should match here + .extend(r_nus.by_ref().take(Piop::N_COLUMNS)); + + // quotient (chunks) at `z` + let r_nu_last = r_nus.next().unwrap(); + let z_n = piop.domain_evaluated().z_n; + self.acc_points + .extend(proof.quotient_chunks.iter().map(|c| c.0)); + self.acc_scalars.extend( + q_chunking::chunk_coeffs(z_n) + .map(|c| r_nu_last * c) + .take(proof.quotient_chunks.len()), + ); self.acc_points.push(proof.agg_at_zeta_proof); self.acc_scalars.push(zeta * r); diff --git a/w3f-plonk-common/src/q_chunking.rs b/w3f-plonk-common/src/q_chunking.rs index 23ac8ef..ee71d6f 100644 --- a/w3f-plonk-common/src/q_chunking.rs +++ b/w3f-plonk-common/src/q_chunking.rs @@ -11,13 +11,17 @@ pub fn chunk_quotient(q: DensePolynomial, n: usize) -> Vec(z_to_n: F) -> impl Iterator { + utils::powers(z_to_n) +} + pub fn fold_quotient_chunks( chunks: &[DensePolynomial], z_to_n: F, ) -> DensePolynomial { chunks .iter() - .zip(utils::powers(z_to_n)) + .zip(chunk_coeffs(z_to_n)) .map(|(chunk, coeff)| chunk * coeff) .reduce(|acc, new| acc + new) .unwrap() @@ -26,7 +30,7 @@ pub fn fold_quotient_chunks( pub fn compose_quotient>(chunks: &[C], z_to_n: F) -> C { chunks .iter() - .zip(utils::powers(z_to_n)) + .zip(chunk_coeffs(z_to_n)) .map(|(chunk, coeff)| chunk.mul(coeff)) .sum() } From f941cdc5b6ca813217138653cca7f717347b3ad7 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Mon, 1 Jun 2026 01:05:19 +0300 Subject: [PATCH 09/12] chunk sizes asserted --- pasta-tree/src/circuit_fat/prover.rs | 7 ++++++- pasta-tree/src/circuit_tall/prover.rs | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/pasta-tree/src/circuit_fat/prover.rs b/pasta-tree/src/circuit_fat/prover.rs index 97b2d21..3e5ad95 100644 --- a/pasta-tree/src/circuit_fat/prover.rs +++ b/pasta-tree/src/circuit_fat/prover.rs @@ -7,6 +7,7 @@ use ark_ec::CurveGroup; use ark_ff::One; use ark_ff::{FftField, PrimeField, Zero}; use ark_poly::Evaluations; +use ark_poly::Polynomial; use ark_poly::univariate::DensePolynomial; use ark_std::{vec, vec::Vec}; use w3f_pcs::pcs::commitment::WrappedAffine; @@ -167,7 +168,11 @@ impl> type Instance = G; fn quotient(&self, alphas: &[C::ScalarField]) -> Option>> { - >>::_quotient_chunks(self, alphas) + let chunks = + >>::_quotient_chunks(self, alphas); + debug_assert_eq!(chunks.as_ref().unwrap().len(), 4); + debug_assert_eq!(chunks.as_ref().unwrap()[3].degree(), 0); + chunks } fn committed_columns) -> WrappedAffine>( diff --git a/pasta-tree/src/circuit_tall/prover.rs b/pasta-tree/src/circuit_tall/prover.rs index c045dc9..c5faca8 100644 --- a/pasta-tree/src/circuit_tall/prover.rs +++ b/pasta-tree/src/circuit_tall/prover.rs @@ -108,7 +108,11 @@ impl> type Instance = G; fn quotient(&self, alphas: &[C::ScalarField]) -> Option>> { - >>::_quotient_chunks(self, alphas) + let chunks = + >>::_quotient_chunks(self, alphas); + debug_assert_eq!(chunks.as_ref().unwrap().len(), 4); + debug_assert_eq!(chunks.as_ref().unwrap()[3].degree(), 0); + chunks } fn committed_columns) -> WrappedAffine>( From e6ba1ef2ccabb6a710a44eb0447701727b2ce704 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Mon, 1 Jun 2026 01:12:12 +0300 Subject: [PATCH 10/12] pretty-print --- pasta-tree/src/lib.rs | 46 ++++++++++++++++----------------- pasta-tree/src/prover.rs | 52 ++++++++++++++++++++------------------ pasta-tree/src/verifier.rs | 41 +++++++++++++++++------------- 3 files changed, 74 insertions(+), 65 deletions(-) diff --git a/pasta-tree/src/lib.rs b/pasta-tree/src/lib.rs index b579f29..1c11f44 100644 --- a/pasta-tree/src/lib.rs +++ b/pasta-tree/src/lib.rs @@ -260,11 +260,11 @@ mod tests { ark_vesta::Projective, CircuitParamsFat, CircuitParamsFat, - >(8, 4); + >(8, 2); } - // cargo test test_bench_curve_tree --release --features="print-trace" -- --show-output - // cargo test test_bench_curve_tree --release --features="print-trace parallel" -- --show-output + // cargo test test_bench_curve_tree --release --features="print-trace" -- --show-output --ignored + // cargo test test_bench_curve_tree --release --features="print-trace parallel" -- --show-output --ignored #[test] #[ignore] fn test_bench_curve_tree() { @@ -278,25 +278,25 @@ mod tests { >(log_n, h); println!(); - let (log_n, h) = (9, 2); - println!("n = {}, height = {h}, TALL", 1 << log_n); - _test_proof::< - ark_pallas::Projective, - ark_vesta::Projective, - CircuitParamsTall, - CircuitParamsTall, - >(log_n, h); - println!(); - - let (log_n, h) = (10, 2); - println!("n = {}, height = {h}, TALL", 1 << log_n); - _test_proof::< - ark_pallas::Projective, - ark_vesta::Projective, - CircuitParamsTall, - CircuitParamsTall, - >(log_n, h); - println!(); + // let (log_n, h) = (9, 2); + // println!("n = {}, height = {h}, TALL", 1 << log_n); + // _test_proof::< + // ark_pallas::Projective, + // ark_vesta::Projective, + // CircuitParamsTall, + // CircuitParamsTall, + // >(log_n, h); + // println!(); + + // let (log_n, h) = (10, 2); + // println!("n = {}, height = {h}, TALL", 1 << log_n); + // _test_proof::< + // ark_pallas::Projective, + // ark_vesta::Projective, + // CircuitParamsTall, + // CircuitParamsTall, + // >(log_n, h); + // println!(); let (log_n, h) = (8, 4); println!("n = {}, height = {h}, FAT", 1 << log_n); @@ -308,7 +308,7 @@ mod tests { >(log_n, h); println!(); - let (log_n, h) = (9, 4); + let (log_n, h) = (10, 4); println!("n = {}, height = {h}, TALL", 1 << log_n); _test_proof::< ark_pallas::Projective, diff --git a/pasta-tree/src/prover.rs b/pasta-tree/src/prover.rs index 1095d77..69fdae9 100644 --- a/pasta-tree/src/prover.rs +++ b/pasta-tree/src/prover.rs @@ -56,15 +56,22 @@ impl, P: CircuitParams< witness: Vec>, rng: &mut R, ) -> CycleSideProof { - let curve_name = &std::any::type_name::()[70..]; + let curve_name = &std::any::type_name::()[53..]; // println!("\n\nprover {curve_name}\nchildren={blinded_path:?}\n"); + let n_levels = witness.len(); // number of tree levels on this side + debug_assert_eq!(blinded_path.len(), n_levels); + let mut piop_proofs = Vec::with_capacity(n_levels); - debug_assert_eq!(blinded_path.len(), witness.len()); - let n_polys = P::VerifierCircuit::N_COLUMNS + 2; // plus the quotient and the linearization polys - let mut piop_proofs = Vec::with_capacity(witness.len()); - let mut polys = Vec::with_capacity(witness.len() * n_polys); - let mut coords = Vec::with_capacity(witness.len() * n_polys); - let mut bfs = Vec::with_capacity(witness.len() * n_polys); + // per tree level + let n_columns = P::VerifierCircuit::N_COLUMNS; + let n_to_commit = n_columns + 4; // plus the quotient chunks + let n_to_open = n_columns + 2; // plus the (folded) quotient (chunks) and the linearization polynomial + + // per side + let n_openings = n_levels * n_to_open; + let mut polys_to_open = Vec::with_capacity(n_openings); + let mut at_coords = Vec::with_capacity(n_openings); + let mut with_bfs = Vec::with_capacity(n_openings); let plonk_prover = PlonkProver::, _>::init( self.pcs_params.ck(), @@ -73,11 +80,10 @@ impl, P: CircuitParams< ); let t_commit_side = start_timer!(|| format!( - "Committing to {} polynomials at {curve_name}", - witness.len() * (n_polys - 1) + "Committing {n_levels} x {n_to_commit} polynomials to {curve_name}" )); for (level, blinded_node) in witness.into_iter().zip(blinded_path.into_iter()) { - let t_commit_level = start_timer!(|| format!("Committing to {} polynomials", n_polys)); + // let t_commit_level = start_timer!(|| format!("Committing {n_to_commit} polynomials")); let piop: P::ProverCircuit =

>::prover_circuit(&self.piop_params, level.clone()); let result = @@ -98,31 +104,29 @@ impl, P: CircuitParams< // polys_at_zeta[polys_at_zeta.len() - 1].evaluate(&zeta) // ); - coords.extend(vec![BTreeSet::from([zeta]); polys_at_zeta.len()]); - polys.extend(polys_at_zeta); - coords.extend(vec![ + at_coords.extend(vec![BTreeSet::from([zeta]); polys_at_zeta.len()]); + polys_to_open.extend(polys_at_zeta); + at_coords.extend(vec![ BTreeSet::from([zeta_omega]); polys_at_zeta_omega.len() ]); - polys.extend(polys_at_zeta_omega); - bfs.push(level.parent_bf); - bfs.resize(polys.len(), C::ScalarField::zero()); - end_timer!(t_commit_level); + polys_to_open.extend(polys_at_zeta_omega); + with_bfs.push(level.parent_bf); + with_bfs.resize(polys_to_open.len(), C::ScalarField::zero()); + // end_timer!(t_commit_level); } end_timer!(t_commit_side); - let max_degree = polys.iter().map(|p| p.degree()).max().unwrap(); let t_open = start_timer!(|| format!( - "Opening {} polynomials with maximal degree-{}", - polys.len(), - max_degree + "Opening {n_openings} polynomials, max_degree = {}", + polys_to_open.iter().map(|p| p.degree()).max().unwrap() )); let todo = Coeffs(C::ScalarField::rand(rng), C::ScalarField::rand(rng)); let pcs_proof = Shplonk::>::open_many_hiding( &self.pcs_params, - &polys, - &bfs, - &coords, + &polys_to_open, + &with_bfs, + &at_coords, &mut todo.clone(), rng, ); diff --git a/pasta-tree/src/verifier.rs b/pasta-tree/src/verifier.rs index 33419bd..7072530 100644 --- a/pasta-tree/src/verifier.rs +++ b/pasta-tree/src/verifier.rs @@ -48,21 +48,26 @@ impl, P: CircuitParams< parents: Vec, side_proof: CycleSideProof, ) -> bool { - // let mut s = std::any::type_name::(); - // s = &s[65..s.len()]; - // println!("\n\nverifier {s}\nchildren={children:?}\nparents={parents:?}\n"); + // let curve_name = &std::any::type_name::()[53..]; + // println!("\n\nverifier {curve_name}\nchildren={children:?}\nparents={parents:?}\n"); + + // number of tree levels on this side + let n_levels = side_proof.piop_proofs.len(); + // per tree level + let n_to_open = P::VerifierCircuit::N_COLUMNS + 2; // plus the (folded) quotient (chunks) and the linearization polynomial + // per side + let n_openings = n_levels * n_to_open; + + let mut polys_to_open = Vec::with_capacity(n_openings); + let mut at_coords = Vec::with_capacity(n_openings); + let mut to_values = Vec::with_capacity(n_openings); let plonk_verifier: PlonkVerifier, _> = PlonkVerifier::init( self.pcs_params.vk(), - &(), + &(), // TODO ArkTranscript::new(b"pasta-tree-level-proof"), ); - let n_polys = P::VerifierCircuit::N_COLUMNS + 2; // plus the quotient and the linearization polys - let mut polys = Vec::with_capacity(side_proof.piop_proofs.len() * n_polys); - let mut coords = Vec::with_capacity(side_proof.piop_proofs.len() * n_polys); - let mut vals = Vec::with_capacity(side_proof.piop_proofs.len() * n_polys); - //TODO: precompute let fixed_cols = self.commit_fixed_columns(); @@ -99,21 +104,21 @@ impl, P: CircuitParams< // vals_at_zeta[vals_at_zeta.len() - 1] // ); - coords.extend(vec![vec![zeta]; open_at_zeta.len()]); - polys.extend(open_at_zeta); - coords.extend(vec![vec![zeta_omega]; open_at_zeta_omega.len()]); - polys.extend(open_at_zeta_omega); - vals.extend(vals_at_zeta.into_iter().map(|v| vec![v])); - vals.extend(vals_at_zeta_omega.into_iter().map(|v| vec![v])); + at_coords.extend(vec![vec![zeta]; open_at_zeta.len()]); + polys_to_open.extend(open_at_zeta); + at_coords.extend(vec![vec![zeta_omega]; open_at_zeta_omega.len()]); + polys_to_open.extend(open_at_zeta_omega); + to_values.extend(vals_at_zeta.into_iter().map(|v| vec![v])); + to_values.extend(vals_at_zeta_omega.into_iter().map(|v| vec![v])); } let mut todo = side_proof.todo; let valid = Shplonk::>::verify_many( &self.pcs_params.vk(), - &polys, + &polys_to_open, side_proof.pcs_proof, - &coords, - &vals, + &at_coords, + &to_values, &mut todo, ); valid From 9b5df48e612f2e1ad13639c9aa25203daf6d6026 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Mon, 1 Jun 2026 23:06:06 +0300 Subject: [PATCH 11/12] no-std fixes --- Cargo.toml | 4 ++-- w3f-plonk-common/src/piop.rs | 6 ++++-- w3f-plonk-common/src/q_chunking.rs | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bf87c71..eb2d201 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,8 @@ ark-ec = { version = "0.6", default-features = false } ark-poly = { version = "0.6", default-features = false } ark-serialize = { version = "0.6", default-features = false, features = ["derive"] } #w3f-pcs = { version = "0.0.6", default-features = false } -#w3f-pcs = { path = "../fflonk", default-features = false } -w3f-pcs = { version = "0.0.6", git = "https://github.com/paritytech/fflonk/", branch = "ipa-pcs", default-features = false } +w3f-pcs = { path = "../fflonk", default-features = false } +#w3f-pcs = { version = "0.0.6", git = "https://github.com/paritytech/fflonk/", branch = "ipa-pcs", default-features = false } #w3f-plonk-common = { version = "0.0.7", default-features = false } w3f-plonk-common = { path = "w3f-plonk-common", default-features = false } rayon = { version = "1", default-features = false } diff --git a/w3f-plonk-common/src/piop.rs b/w3f-plonk-common/src/piop.rs index 727f67c..c3bc3e0 100644 --- a/w3f-plonk-common/src/piop.rs +++ b/w3f-plonk-common/src/piop.rs @@ -5,6 +5,7 @@ use ark_poly::univariate::DensePolynomial; use ark_poly::Evaluations; use ark_poly::Polynomial; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::vec; use ark_std::vec::Vec; use w3f_pcs::pcs::Commitment; @@ -35,11 +36,12 @@ pub trait ProverPiop> { fn _quotient_chunks(&self, alphas: &[F]) -> Option>> { let q = Self::_compute_quotient(self, alphas); q.map(|q| { - let q_deg = q.degree(); + let _q_deg = q.degree(); let q_chunks = q_chunking::chunk_quotient(q, self.domain().domain_size()); + #[cfg(feature = "std")] println!( "Chunking deg {} polynomial into {} chunks", - q_deg, + _q_deg, q_chunks.len() ); q_chunks diff --git a/w3f-plonk-common/src/q_chunking.rs b/w3f-plonk-common/src/q_chunking.rs index ee71d6f..31c9e3f 100644 --- a/w3f-plonk-common/src/q_chunking.rs +++ b/w3f-plonk-common/src/q_chunking.rs @@ -1,6 +1,7 @@ use ark_ff::{Field, PrimeField}; use ark_poly::univariate::DensePolynomial; use ark_poly::DenseUVPolynomial; +use ark_std::vec::Vec; use w3f_pcs::pcs::Commitment; use w3f_pcs::utils; From 0f73d2822ede2bdeb7a4c02139cb8239627ee359 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Mon, 1 Jun 2026 23:11:49 +0300 Subject: [PATCH 12/12] Cargo.toml restored --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index eb2d201..bf87c71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,8 @@ ark-ec = { version = "0.6", default-features = false } ark-poly = { version = "0.6", default-features = false } ark-serialize = { version = "0.6", default-features = false, features = ["derive"] } #w3f-pcs = { version = "0.0.6", default-features = false } -w3f-pcs = { path = "../fflonk", default-features = false } -#w3f-pcs = { version = "0.0.6", git = "https://github.com/paritytech/fflonk/", branch = "ipa-pcs", default-features = false } +#w3f-pcs = { path = "../fflonk", default-features = false } +w3f-pcs = { version = "0.0.6", git = "https://github.com/paritytech/fflonk/", branch = "ipa-pcs", default-features = false } #w3f-plonk-common = { version = "0.0.7", default-features = false } w3f-plonk-common = { path = "w3f-plonk-common", default-features = false } rayon = { version = "1", default-features = false }