From 96e95d07b5cb7ace6f629a6c361db8dcd99cd072 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sun, 17 May 2026 06:46:07 +0300 Subject: [PATCH 1/4] ring piop prover generic over curve model --- w3f-ring-proof/src/piop/prover.rs | 140 +++++++++++++++++++++++------- w3f-ring-proof/src/ring_prover.rs | 2 +- 2 files changed, 112 insertions(+), 30 deletions(-) diff --git a/w3f-ring-proof/src/piop/prover.rs b/w3f-ring-proof/src/piop/prover.rs index ddec2ba..6540f81 100644 --- a/w3f-ring-proof/src/piop/prover.rs +++ b/w3f-ring-proof/src/piop/prover.rs @@ -1,4 +1,6 @@ -use ark_ec::twisted_edwards::{Affine, TECurveConfig}; +use ark_ec::AffineRepr; +use ark_ec::twisted_edwards::{Affine as TeAffine, TECurveConfig}; +use ark_ec::short_weierstrass::{Affine as SwAffine, SWCurveConfig}; use ark_ff::PrimeField; use ark_poly::univariate::DensePolynomial; use ark_poly::Evaluations; @@ -22,10 +24,10 @@ use w3f_plonk_common::FieldColumn; // The 'table': columns representing the execution trace of the computation // and the constraints -- polynomials that vanish on every 2 consecutive rows. -pub struct PiopProver> { +pub struct PiopProver> { domain: Domain, /// Advice (public input) columns - points: AffineColumn>, + points: AffineColumn, ring_selector: FieldColumn, // Private input column. bits: BitColumn, @@ -33,17 +35,17 @@ pub struct PiopProver> { booleanity: Booleanity, inner_prod: InnerProd, inner_prod_acc: FixedCells, - cond_add: CondAdd>, + cond_add: CondAdd, cond_add_acc_x: FixedCells, cond_add_acc_y: FixedCells, } -impl> PiopProver { +impl> PiopProver { pub fn build( - params: &PiopParams>, - fixed_columns: FixedColumns>, + params: &PiopParams, + fixed_columns: FixedColumns, prover_index_in_keys: usize, - secret: Curve::ScalarField, + secret: G::ScalarField, ) -> Self { let domain = params.domain.clone(); let FixedColumns { @@ -73,9 +75,9 @@ impl> PiopProver { // TODO: move to params? fn bits_column( - params: &PiopParams>, + params: &PiopParams, index_in_keys: usize, - secret: Curve::ScalarField, + secret: G::ScalarField, ) -> BitColumn { let mut keyset_part = vec![false; params.keyset_part_size]; keyset_part[index_in_keys] = true; @@ -84,29 +86,18 @@ impl> PiopProver { assert_eq!(bits.len(), params.domain.capacity - 1); BitColumn::init(bits, ¶ms.domain) } -} - -impl ProverPiop for PiopProver -where - F: PrimeField, - C: Commitment, - Curve: TECurveConfig, -{ - type Commitments = RingCommitments; - type Evaluations = RingEvaluations; - type Instance = Affine; - fn committed_columns) -> C>( + fn _committed_columns, Fun: Fn(&DensePolynomial) -> C>( &self, commit: Fun, - ) -> Self::Commitments { + ) -> RingCommitments { let bits = commit(self.bits.as_poly()); let cond_add_acc = [ commit(self.cond_add.acc.xs.as_poly()), commit(self.cond_add.acc.ys.as_poly()), ]; let inn_prod_acc = commit(self.inner_prod.acc.as_poly()); - Self::Commitments { + RingCommitments { bits, cond_add_acc, inn_prod_acc, @@ -116,7 +107,7 @@ where // Should return polynomials in the consistent with // Self::Evaluations::to_vec() and Self::Commitments::to_vec(). - fn columns(&self) -> Vec> { + fn _columns(&self) -> Vec> { vec![ self.points.xs.as_poly().clone(), self.points.ys.as_poly().clone(), @@ -128,7 +119,7 @@ where ] } - fn columns_evaluated(&self, zeta: &F) -> Self::Evaluations { + fn _columns_evaluated(&self, zeta: &F) -> RingEvaluations { let points = [self.points.xs.evaluate(zeta), self.points.ys.evaluate(zeta)]; let ring_selector = self.ring_selector.evaluate(zeta); let bits = self.bits.evaluate(zeta); @@ -137,7 +128,7 @@ where self.cond_add.acc.xs.evaluate(zeta), self.cond_add.acc.ys.evaluate(zeta), ]; - Self::Evaluations { + RingEvaluations { points, ring_selector, bits, @@ -145,6 +136,34 @@ where cond_add_acc, } } +} + +impl ProverPiop for PiopProver> +where + F: PrimeField, + C: Commitment, + Curve: TECurveConfig, +{ + type Commitments = RingCommitments; + type Evaluations = RingEvaluations; + type Instance = TeAffine; + + fn committed_columns) -> C>( + &self, + commit: Fun, + ) -> Self::Commitments { + self._committed_columns(commit) + } + + // Should return polynomials in the consistent with + // Self::Evaluations::to_vec() and Self::Commitments::to_vec(). + fn columns(&self) -> Vec> { + self._columns() + } + + fn columns_evaluated(&self, zeta: &F) -> Self::Evaluations { + self._columns_evaluated(zeta) + } fn constraints(&self) -> Vec> { vec![ @@ -155,7 +174,7 @@ where self.cond_add_acc_y.constraints(), self.inner_prod_acc.constraints(), ] - .concat() + .concat() } fn constraints_lin(&self, zeta: &F) -> Vec> { @@ -167,7 +186,7 @@ where self.cond_add_acc_y.constraints_linearized(zeta), self.inner_prod_acc.constraints_linearized(zeta), ] - .concat() + .concat() } fn domain(&self) -> &Domain { @@ -178,3 +197,66 @@ where self.cond_add.result() } } + +impl ProverPiop for PiopProver> +where + F: PrimeField, + C: Commitment, + Curve: SWCurveConfig, +{ + type Commitments = RingCommitments; + type Evaluations = RingEvaluations; + type Instance = SwAffine; + + fn committed_columns) -> C>( + &self, + commit: Fun, + ) -> Self::Commitments { + self._committed_columns(commit) + } + + // Should return polynomials in the consistent with + // Self::Evaluations::to_vec() and Self::Commitments::to_vec(). + fn columns(&self) -> Vec> { + self._columns() + } + + fn columns_evaluated(&self, zeta: &F) -> Self::Evaluations { + self._columns_evaluated(zeta) + } + + fn constraints(&self) -> Vec> { + vec![ + self.inner_prod.constraints(), + self.cond_add.constraints(), + self.booleanity.constraints(), + self.cond_add_acc_x.constraints(), + self.cond_add_acc_y.constraints(), + self.inner_prod_acc.constraints(), + ] + .concat() + } + + fn constraints_lin(&self, zeta: &F) -> Vec> { + vec![ + self.inner_prod.constraints_linearized(zeta), + self.cond_add.constraints_linearized(zeta), + self.booleanity.constraints_linearized(zeta), + self.cond_add_acc_x.constraints_linearized(zeta), + self.cond_add_acc_y.constraints_linearized(zeta), + self.inner_prod_acc.constraints_linearized(zeta), + ] + .concat() + } + + fn domain(&self) -> &Domain { + &self.domain + } + + fn result(&self) -> Self::Instance { + self.cond_add.result() + } +} + + + diff --git a/w3f-ring-proof/src/ring_prover.rs b/w3f-ring-proof/src/ring_prover.rs index 7aabea6..2a3647e 100644 --- a/w3f-ring-proof/src/ring_prover.rs +++ b/w3f-ring-proof/src/ring_prover.rs @@ -70,7 +70,7 @@ where r: Curve::ScalarField, ) -> (Affine, RingProof) { let piop = PiopProver::build(&self.piop_params, self.fixed_columns.clone(), k, r); - let blinded_pk = as ProverPiop>::result(&piop); + let blinded_pk = > as ProverPiop>::result(&piop); let proof = self.plonk_prover.prove(piop); (blinded_pk, proof) } From 7eef961fad8c693212b6ef412504d87b42c2e9eb Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sun, 17 May 2026 07:02:15 +0300 Subject: [PATCH 2/4] ring generic over curve model --- w3f-ring-proof/src/piop/mod.rs | 14 +++++++------- w3f-ring-proof/src/ring.rs | 29 ++++++++++++++--------------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/w3f-ring-proof/src/piop/mod.rs b/w3f-ring-proof/src/piop/mod.rs index 0cd73c3..72cf581 100644 --- a/w3f-ring-proof/src/piop/mod.rs +++ b/w3f-ring-proof/src/piop/mod.rs @@ -1,5 +1,5 @@ use ark_ec::pairing::Pairing; -use ark_ec::twisted_edwards::{Affine, TECurveConfig}; +// use ark_ec::twisted_edwards::{Affine, TECurveConfig}; use ark_ec::AffineRepr; use ark_ff::PrimeField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; @@ -97,7 +97,7 @@ impl> FixedColumnsCommitted { } impl FixedColumnsCommitted> { - pub fn from_ring>( + pub fn from_ring>( ring: &Ring, ) -> Self { let cx = KzgCommitment(ring.cx); @@ -159,7 +159,7 @@ impl> Clone for VerifierKey { } impl VerifierKey> { - pub fn from_ring_and_kzg_vk>( + pub fn from_ring_and_kzg_vk>( ring: &Ring, kzg_vk: RawKzgVerifierKey, ) -> Self { @@ -181,11 +181,11 @@ impl VerifierKey> { } } -pub fn index, Curve: TECurveConfig>( +pub fn index, G: AffineRepr>( pcs_params: &CS::Params, - piop_params: &PiopParams>, - keys: &[Affine], -) -> (ProverKey>, VerifierKey) { + piop_params: &PiopParams, + keys: &[G], +) -> (ProverKey, VerifierKey) { let pcs_ck = pcs_params.ck(); let pcs_raw_vk = pcs_params.raw_vk(); let fixed_columns = piop_params.fixed_columns(&keys); diff --git a/w3f-ring-proof/src/ring.rs b/w3f-ring-proof/src/ring.rs index 527a6c0..67ec5d4 100644 --- a/w3f-ring-proof/src/ring.rs +++ b/w3f-ring-proof/src/ring.rs @@ -1,5 +1,4 @@ use ark_ec::pairing::Pairing; -use ark_ec::twisted_edwards::{Affine, TECurveConfig}; use ark_ec::{AffineRepr, CurveGroup, VariableBaseMSM}; use ark_ff::PrimeField; use ark_poly::EvaluationDomain; @@ -36,7 +35,7 @@ const IDLE_ROWS: usize = ZK_ROWS + 1; pub struct Ring< F: PrimeField, KzgCurve: Pairing, - VrfCurveConfig: TECurveConfig, + G: AffineRepr, > { /// KZG commitment to the x coordinates of the described vector. pub cx: KzgCurve::G1Affine, @@ -49,14 +48,14 @@ pub struct Ring< /// Number of keys "stored" in this commitment. pub curr_keys: usize, // Padding point. - pub padding: Affine, + pub padding: G, } impl< F: PrimeField, KzgCurve: Pairing, - VrfCurveConfig: TECurveConfig, - > fmt::Debug for Ring + G: AffineRepr, + > fmt::Debug for Ring { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( @@ -70,8 +69,8 @@ impl< impl< F: PrimeField, KzgCurve: Pairing, - VrfCurveConfig: TECurveConfig, - > Ring + G: AffineRepr, + > Ring { /// Builds the commitment to the vector /// `padding, ..., padding, H, 2H, ..., 2^(s-1)H, 0, 0, 0, 0`. @@ -85,7 +84,7 @@ impl< /// - `srs`: Should return `srs[range]` for `range = (piop_params.keyset_part_size..domain_size)` /// - `g`: Generator used in the SRS pub fn empty( - piop_params: &PiopParams>, + piop_params: &PiopParams, srs: impl Fn(Range) -> Result, ()>, g: KzgCurve::G1, ) -> Self { @@ -130,7 +129,7 @@ impl< /// - `srs`: Should return `srs[range]` for `range = (self.curr_keys..self.curr_keys + keys.len())` pub fn append( &mut self, - keys: &[Affine], + keys: &[G], srs: impl Fn(Range) -> Result, ()>, ) { let new_size = self.curr_keys + keys.len(); @@ -162,8 +161,8 @@ impl< /// - `piop_params`: SNARK parameters. /// - `srs`: full-size Lagrangian SRS. pub fn with_keys( - piop_params: &PiopParams>, - keys: &[Affine], + piop_params: &PiopParams, + keys: &[G], srs: &RingBuilderKey, ) -> Self { let (padding_x, padding_y) = piop_params.padding.xy().unwrap(); // panics on inf, never happens @@ -222,10 +221,10 @@ impl< cx: KzgCurve::G1Affine, cy: KzgCurve::G1Affine, selector: KzgCurve::G1Affine, - padding: Affine, + padding: G, ) -> Self { let max_keys = - domain_size - (VrfCurveConfig::ScalarField::MODULUS_BIT_SIZE as usize + IDLE_ROWS); + domain_size - (G::ScalarField::MODULUS_BIT_SIZE as usize + IDLE_ROWS); Self { cx, cy, @@ -257,7 +256,7 @@ impl> RingBuilderKey; + type TestRing = Ring; #[test] fn test_ring_mgmt() { From f84654cee13c99d101c48d15fa475d7883b0dd60 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sun, 17 May 2026 07:07:11 +0300 Subject: [PATCH 3/4] ring piop generic over curve model --- w3f-ring-proof/src/piop/mod.rs | 1 - w3f-ring-proof/src/piop/verifier.rs | 53 +++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/w3f-ring-proof/src/piop/mod.rs b/w3f-ring-proof/src/piop/mod.rs index 72cf581..c791d6a 100644 --- a/w3f-ring-proof/src/piop/mod.rs +++ b/w3f-ring-proof/src/piop/mod.rs @@ -1,5 +1,4 @@ use ark_ec::pairing::Pairing; -// use ark_ec::twisted_edwards::{Affine, TECurveConfig}; use ark_ec::AffineRepr; use ark_ff::PrimeField; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; diff --git a/w3f-ring-proof/src/piop/verifier.rs b/w3f-ring-proof/src/piop/verifier.rs index 8eb663f..e529819 100644 --- a/w3f-ring-proof/src/piop/verifier.rs +++ b/w3f-ring-proof/src/piop/verifier.rs @@ -1,5 +1,6 @@ -use ark_ec::twisted_edwards::{Affine, TECurveConfig}; use ark_ec::AffineRepr; +use ark_ec::short_weierstrass::{Affine as SwAffine, SWCurveConfig}; +use ark_ec::twisted_edwards::{Affine as TeAffine, TECurveConfig}; use ark_ff::PrimeField; use ark_std::marker::PhantomData; use ark_std::{vec, vec::Vec}; @@ -102,7 +103,7 @@ impl, P: AffineRepr> PiopVerifier } impl, Jubjub: TECurveConfig> VerifierPiop - for PiopVerifier> + for PiopVerifier> { const N_CONSTRAINTS: usize = 7; const N_COLUMNS: usize = 7; @@ -148,3 +149,51 @@ impl, Jubjub: TECurveConfig> Veri &self.domain_evals } } + +impl, Jubjub: SWCurveConfig> VerifierPiop +for PiopVerifier> +{ + const N_CONSTRAINTS: usize = 7; + const N_COLUMNS: usize = 7; + + fn precommitted_columns(&self) -> Vec { + self.fixed_columns_committed.as_vec() + } + + fn evaluate_constraints_main(&self) -> Vec { + vec![ + self.inner_prod.evaluate_constraints_main(), + self.cond_add.evaluate_constraints_main(), + self.booleanity.evaluate_constraints_main(), + self.cond_add_acc_x.evaluate_constraints_main(), + self.cond_add_acc_y.evaluate_constraints_main(), + self.inner_prod_acc.evaluate_constraints_main(), + ] + .concat() + } + + fn lin_poly_commitment(&self, agg_coeffs: &[F]) -> (Vec, Vec) { + assert_eq!(agg_coeffs.len(), Self::N_CONSTRAINTS); + + let inner_prod_acc = self.witness_columns_committed.inn_prod_acc.clone(); + let inner_prod_coeff = agg_coeffs[0] * self.inner_prod.not_last; + + let cond_add_acc_x = self.witness_columns_committed.cond_add_acc[0].clone(); + let cond_add_acc_y = self.witness_columns_committed.cond_add_acc[1].clone(); + let (c_acc_x, c_acc_y) = self.cond_add.acc_coeffs_1(); + let mut cond_add_x_coeff = agg_coeffs[1] * c_acc_x; + let mut cond_add_y_coeff = agg_coeffs[1] * c_acc_y; + let (c_acc_x, c_acc_y) = self.cond_add.acc_coeffs_2(); + cond_add_x_coeff += agg_coeffs[2] * c_acc_x; + cond_add_y_coeff += agg_coeffs[2] * c_acc_y; + + ( + vec![inner_prod_coeff, cond_add_x_coeff, cond_add_y_coeff], + vec![inner_prod_acc.clone(), cond_add_acc_x, cond_add_acc_y], + ) + } + + fn domain_evaluated(&self) -> &EvaluatedDomain { + &self.domain_evals + } +} \ No newline at end of file From dd56e51aa3cbb8345cda19f8a96560d574b658f2 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Sun, 17 May 2026 07:55:33 +0300 Subject: [PATCH 4/4] fmt --- w3f-ring-proof/src/piop/prover.rs | 17 +++++++---------- w3f-ring-proof/src/piop/verifier.rs | 8 ++++---- w3f-ring-proof/src/ring.rs | 25 +++++++------------------ 3 files changed, 18 insertions(+), 32 deletions(-) diff --git a/w3f-ring-proof/src/piop/prover.rs b/w3f-ring-proof/src/piop/prover.rs index 6540f81..ca06cea 100644 --- a/w3f-ring-proof/src/piop/prover.rs +++ b/w3f-ring-proof/src/piop/prover.rs @@ -1,6 +1,6 @@ -use ark_ec::AffineRepr; -use ark_ec::twisted_edwards::{Affine as TeAffine, TECurveConfig}; use ark_ec::short_weierstrass::{Affine as SwAffine, SWCurveConfig}; +use ark_ec::twisted_edwards::{Affine as TeAffine, TECurveConfig}; +use ark_ec::AffineRepr; use ark_ff::PrimeField; use ark_poly::univariate::DensePolynomial; use ark_poly::Evaluations; @@ -162,7 +162,7 @@ where } fn columns_evaluated(&self, zeta: &F) -> Self::Evaluations { - self._columns_evaluated(zeta) + self._columns_evaluated(zeta) } fn constraints(&self) -> Vec> { @@ -174,7 +174,7 @@ where self.cond_add_acc_y.constraints(), self.inner_prod_acc.constraints(), ] - .concat() + .concat() } fn constraints_lin(&self, zeta: &F) -> Vec> { @@ -186,7 +186,7 @@ where self.cond_add_acc_y.constraints_linearized(zeta), self.inner_prod_acc.constraints_linearized(zeta), ] - .concat() + .concat() } fn domain(&self) -> &Domain { @@ -234,7 +234,7 @@ where self.cond_add_acc_y.constraints(), self.inner_prod_acc.constraints(), ] - .concat() + .concat() } fn constraints_lin(&self, zeta: &F) -> Vec> { @@ -246,7 +246,7 @@ where self.cond_add_acc_y.constraints_linearized(zeta), self.inner_prod_acc.constraints_linearized(zeta), ] - .concat() + .concat() } fn domain(&self) -> &Domain { @@ -257,6 +257,3 @@ where self.cond_add.result() } } - - - diff --git a/w3f-ring-proof/src/piop/verifier.rs b/w3f-ring-proof/src/piop/verifier.rs index e529819..eeb53b0 100644 --- a/w3f-ring-proof/src/piop/verifier.rs +++ b/w3f-ring-proof/src/piop/verifier.rs @@ -1,6 +1,6 @@ -use ark_ec::AffineRepr; use ark_ec::short_weierstrass::{Affine as SwAffine, SWCurveConfig}; use ark_ec::twisted_edwards::{Affine as TeAffine, TECurveConfig}; +use ark_ec::AffineRepr; use ark_ff::PrimeField; use ark_std::marker::PhantomData; use ark_std::{vec, vec::Vec}; @@ -151,7 +151,7 @@ impl, Jubjub: TECurveConfig> Veri } impl, Jubjub: SWCurveConfig> VerifierPiop -for PiopVerifier> + for PiopVerifier> { const N_CONSTRAINTS: usize = 7; const N_COLUMNS: usize = 7; @@ -169,7 +169,7 @@ for PiopVerifier> self.cond_add_acc_y.evaluate_constraints_main(), self.inner_prod_acc.evaluate_constraints_main(), ] - .concat() + .concat() } fn lin_poly_commitment(&self, agg_coeffs: &[F]) -> (Vec, Vec) { @@ -196,4 +196,4 @@ for PiopVerifier> fn domain_evaluated(&self) -> &EvaluatedDomain { &self.domain_evals } -} \ No newline at end of file +} diff --git a/w3f-ring-proof/src/ring.rs b/w3f-ring-proof/src/ring.rs index 67ec5d4..a69843f 100644 --- a/w3f-ring-proof/src/ring.rs +++ b/w3f-ring-proof/src/ring.rs @@ -32,11 +32,7 @@ const IDLE_ROWS: usize = ZK_ROWS + 1; /// Thus, the vector of points we commit to coordinatewise is /// `pk1, ..., pkn, padding, ..., padding, H, 2H, ..., 2^(s-1)H, 0, 0, 0, 0` #[derive(Clone, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)] -pub struct Ring< - F: PrimeField, - KzgCurve: Pairing, - G: AffineRepr, -> { +pub struct Ring, G: AffineRepr> { /// KZG commitment to the x coordinates of the described vector. pub cx: KzgCurve::G1Affine, /// KZG commitment to the y coordinates of the described vector. @@ -51,11 +47,8 @@ pub struct Ring< pub padding: G, } -impl< - F: PrimeField, - KzgCurve: Pairing, - G: AffineRepr, - > fmt::Debug for Ring +impl, G: AffineRepr> fmt::Debug + for Ring { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( @@ -66,11 +59,8 @@ impl< } } -impl< - F: PrimeField, - KzgCurve: Pairing, - G: AffineRepr, - > Ring +impl, G: AffineRepr> + Ring { /// Builds the commitment to the vector /// `padding, ..., padding, H, 2H, ..., 2^(s-1)H, 0, 0, 0, 0`. @@ -223,8 +213,7 @@ impl< selector: KzgCurve::G1Affine, padding: G, ) -> Self { - let max_keys = - domain_size - (G::ScalarField::MODULUS_BIT_SIZE as usize + IDLE_ROWS); + let max_keys = domain_size - (G::ScalarField::MODULUS_BIT_SIZE as usize + IDLE_ROWS); Self { cx, cy, @@ -256,7 +245,7 @@ impl> RingBuilderKey