Skip to content
Open
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
9 changes: 9 additions & 0 deletions pasta-tree/src/circuit_fat/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -166,6 +167,14 @@ impl<C: CurveGroup, G: AffineRepr<BaseField = C::ScalarField>>
type Evaluations = ProofEvals<C::ScalarField>;
type Instance = G;

fn quotient(&self, alphas: &[C::ScalarField]) -> Option<Vec<DensePolynomial<C::ScalarField>>> {
let chunks =
<Self as ProverPiop<C::ScalarField, WrappedAffine<C>>>::_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<Fun: Fn(&DensePolynomial<C::ScalarField>) -> WrappedAffine<C>>(
&self,
commit: Fun,
Expand Down
8 changes: 8 additions & 0 deletions pasta-tree/src/circuit_tall/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ impl<C: CurveGroup, G: AffineRepr<BaseField = C::ScalarField>>
type Evaluations = ProofEvals<C::ScalarField>;
type Instance = G;

fn quotient(&self, alphas: &[C::ScalarField]) -> Option<Vec<DensePolynomial<C::ScalarField>>> {
let chunks =
<Self as ProverPiop<C::ScalarField, WrappedAffine<C>>>::_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<Fun: Fn(&DensePolynomial<C::ScalarField>) -> WrappedAffine<C>>(
&self,
commit: Fun,
Expand Down
62 changes: 41 additions & 21 deletions pasta-tree/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,41 +243,61 @@ mod tests {
}
}

// 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]
#[ignore]
fn test_bench_curve_tree() {
let (log_n, h) = (8, 2);
println!("n = {}, height = {h}, FAT", 1 << log_n);
fn test_circuit_tall() {
_test_proof::<
ark_pallas::Projective,
ark_vesta::Projective,
CircuitParamsFat<ark_vesta::Affine>,
CircuitParamsFat<ark_pallas::Affine>,
>(log_n, h);
println!();
CircuitParamsTall<ark_vesta::Affine>,
CircuitParamsTall<ark_pallas::Affine>,
>(9, 2);
}

let (log_n, h) = (9, 2);
println!("n = {}, height = {h}, TALL", 1 << log_n);
#[test]
fn test_circuit_fat() {
_test_proof::<
ark_pallas::Projective,
ark_vesta::Projective,
CircuitParamsTall<ark_vesta::Affine>,
CircuitParamsTall<ark_pallas::Affine>,
>(log_n, h);
println!();
CircuitParamsFat<ark_vesta::Affine>,
CircuitParamsFat<ark_pallas::Affine>,
>(8, 2);
}

let (log_n, h) = (10, 2);
println!("n = {}, height = {h}, TALL", 1 << log_n);
// 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() {
let (log_n, h) = (8, 2);
println!("n = {}, height = {h}, FAT", 1 << log_n);
_test_proof::<
ark_pallas::Projective,
ark_vesta::Projective,
CircuitParamsTall<ark_vesta::Affine>,
CircuitParamsTall<ark_pallas::Affine>,
CircuitParamsFat<ark_vesta::Affine>,
CircuitParamsFat<ark_pallas::Affine>,
>(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<ark_vesta::Affine>,
// CircuitParamsTall<ark_pallas::Affine>,
// >(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<ark_vesta::Affine>,
// CircuitParamsTall<ark_pallas::Affine>,
// >(log_n, h);
// println!();

Comment on lines +281 to +300
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
// let (log_n, h) = (9, 2);
// println!("n = {}, height = {h}, TALL", 1 << log_n);
// _test_proof::<
// ark_pallas::Projective,
// ark_vesta::Projective,
// CircuitParamsTall<ark_vesta::Affine>,
// CircuitParamsTall<ark_pallas::Affine>,
// >(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<ark_vesta::Affine>,
// CircuitParamsTall<ark_pallas::Affine>,
// >(log_n, h);
// println!();

let (log_n, h) = (8, 4);
println!("n = {}, height = {h}, FAT", 1 << log_n);
_test_proof::<
Expand All @@ -288,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,
Expand Down
52 changes: 28 additions & 24 deletions pasta-tree/src/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,22 @@ impl<C: CurveGroup, G: AffineRepr<BaseField = C::ScalarField>, P: CircuitParams<
witness: Vec<LevelWitnessWithBlinding<G>>,
rng: &mut R,
) -> CycleSideProof<C, G, P> {
let curve_name = &std::any::type_name::<C>()[70..];
let curve_name = &std::any::type_name::<C>()[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
Copy link
Copy Markdown
Member

@davxy davxy Jun 1, 2026

Choose a reason for hiding this comment

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

IIUC 4 is the number of chunks the commitment quotient is split into for Pasta.
Nit: what about defining a global constant instead of a magic number?
something like: pub const MAX_QUOTIENT_CHUNKS = 4 in the pasta-tree/src/lib.rs?

For what concerns KZG commitment, we stick to 1 chunk, correct?
I.e. we're using the ProverPiop::quotient() default implementation. If so, AFAICT the proof remains backward compat?

Copy link
Copy Markdown
Contributor Author

@swasilyev swasilyev Jun 1, 2026

Choose a reason for hiding this comment

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

Thanks for the review, Davide! You're right, currently it's 4, i even assert it elsewhere, but... The highest constraint degree we've is ec_add (no matter sw/te) that is 4n + 3. We also have ZK_ROWS = 3 that makes effective vanishing polynomial degree n - 3. That makes the quotient degree deg(q) = (4n + 3) - (n - 3) = 3n. So the quotient has 3n + 1 coefficients that don't fit into 3 n-sized chunks.

Given that IP commitment is hiding, we can reduce to ZK_ROWS = 2. But chunking requires masking every chunk (see https://eprint.iacr.org/2024/848), that again raises the degree (by 1 i guess). But may be it can be dealt with in monomial form. So it's all a bit undecided right now.

Re KZG, here #84 i've benchmarks that chunking also improves a bit prover time (and, what may be more important, the CRS size) at the price of 2 (or 3) more points in the proof, so we can consider introducing it separately.

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::<C::ScalarField, HidingIpa<C>, _>::init(
self.pcs_params.ck(),
Expand All @@ -73,11 +80,10 @@ impl<C: CurveGroup, G: AffineRepr<BaseField = C::ScalarField>, 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 =
<P as CircuitParams<C, G>>::prover_circuit(&self.piop_params, level.clone());
let result =
Expand All @@ -98,31 +104,29 @@ impl<C: CurveGroup, G: AffineRepr<BaseField = C::ScalarField>, 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::<C::ScalarField, HidingIpa<C>>::open_many_hiding(
&self.pcs_params,
&polys,
&bfs,
&coords,
&polys_to_open,
&with_bfs,
&at_coords,
&mut todo.clone(),
rng,
);
Expand Down
41 changes: 23 additions & 18 deletions pasta-tree/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,26 @@ impl<C: CurveGroup, G: AffineRepr<BaseField = C::ScalarField>, P: CircuitParams<
parents: Vec<C::Affine>,
side_proof: CycleSideProof<C, G, P>,
) -> bool {
// let mut s = std::any::type_name::<C>();
// s = &s[65..s.len()];
// println!("\n\nverifier {s}\nchildren={children:?}\nparents={parents:?}\n");
// let curve_name = &std::any::type_name::<C>()[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<C::ScalarField, HidingIpa<C>, _> = 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();

Expand Down Expand Up @@ -99,21 +104,21 @@ impl<C: CurveGroup, G: AffineRepr<BaseField = C::ScalarField>, 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::<C::ScalarField, HidingIpa<C>>::verify_many(
&self.pcs_params.vk(),
&polys,
&polys_to_open,
side_proof.pcs_proof,
&coords,
&vals,
&at_coords,
&to_values,
&mut todo,
);
valid
Expand Down
2 changes: 2 additions & 0 deletions w3f-plonk-common/src/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ pub struct EvaluatedDomain<F: FftField> {
pub l_first: F,
pub l_last: F,
pub vanishing_polynomial_inv: F,
pub z_n: F, // z^N
}

impl<F: FftField> EvaluatedDomain<F> {
Expand Down Expand Up @@ -243,6 +244,7 @@ impl<F: FftField> EvaluatedDomain<F> {
l_first,
l_last,
vanishing_polynomial_inv,
z_n,
}
}

Expand Down
20 changes: 15 additions & 5 deletions w3f-plonk-common/src/kzg_acc.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -93,8 +93,8 @@ impl<E: Pairing> KzgAccumulator<E> {
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()
Expand All @@ -109,9 +109,19 @@ impl<E: Pairing> KzgAccumulator<E> {
.map(|c| c.0)
.collect::<Vec<_>>(),
);
self.acc_points.push(proof.quotient_commitment.clone().0);
self.acc_scalars
.extend(challenges.nus.iter().map(|nu| *nu * r).collect::<Vec<_>>()); // 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);
Expand Down
7 changes: 4 additions & 3 deletions w3f-plonk-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod gadgets;
pub mod kzg_acc;
pub mod piop;
pub mod prover;
pub mod q_chunking;
pub mod test_helpers;
pub mod transcript;
pub mod verifier;
Expand Down Expand Up @@ -103,7 +104,7 @@ where
{
pub column_commitments: Commitments,
pub columns_at_zeta: Evaluations,
pub quotient_commitment: CS::C,
pub quotient_chunks: Vec<CS::C>,
pub lin_at_zeta_omega: F,
pub agg_at_zeta_proof: CS::Proof,
pub lin_at_zeta_omega_proof: CS::Proof,
Expand All @@ -120,7 +121,7 @@ where
{
pub column_commitments: Commitments,
pub columns_at_zeta: Evaluations,
pub quotient_commitment: C,
pub quotient_chunks: Vec<C>,
pub lin_at_zeta_omega: F,
}

Expand All @@ -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,
}
}
Expand Down
Loading
Loading